from __future__ import annotations from typing import Any from .registry import TABLE_SPECS _JSON_SCHEMA = "https://json-schema.org/draft/2020-12/schema" def _record_schema(title: str, required: tuple[str, ...]) -> dict[str, Any]: return { "$schema": _JSON_SCHEMA, "title": title, "type": "object", "required": list(required), "properties": { field: { "type": ["string", "number", "integer", "boolean", "array", "object", "null"] } for field in required }, "additionalProperties": True, } def _domain_schema(title: str, table_names: tuple[str, ...]) -> dict[str, Any]: return { "$schema": _JSON_SCHEMA, "title": title, "type": "object", "required": list(table_names), "properties": { name: { "type": "array", "items": {"$ref": f"tables/{name}.schema.json"}, } for name in table_names }, "additionalProperties": False, } def _manifest_schema() -> dict[str, Any]: return { "$schema": _JSON_SCHEMA, "title": "Beihai synthetic shipyard APS dataset manifest", "type": "object", "required": [ "datasetType", "organizationScenario", "generatedAt", "generatorVersion", "schemaVersion", "randomSeed", "businessDigest", "fileCount", "files", ], "properties": { "datasetType": {"const": "SYNTHETIC"}, "organizationScenario": {"const": "BEIHAI_SHIPYARD_APS"}, "generatedAt": {"type": "string", "format": "date-time"}, "generatorVersion": {"type": "string"}, "schemaVersion": {"type": "string"}, "randomSeed": {"type": "integer"}, "businessDigest": {"type": "string", "minLength": 64, "maxLength": 64}, "fileCount": {"type": "integer", "minimum": 1}, "files": { "type": "array", "items": { "type": "object", "required": ["path", "bytes", "sha256"], "properties": { "path": {"type": "string", "minLength": 1}, "kind": {"type": "string"}, "rowCount": {"type": ["integer", "null"], "minimum": 0}, "bytes": {"type": "integer", "minimum": 0}, "sha256": { "type": "string", "minLength": 64, "maxLength": 64, }, }, "additionalProperties": False, }, }, }, "additionalProperties": True, } def _skill_schema() -> dict[str, Any]: required = ( "skillId", "name", "description", "inputSchema", "outputSchema", "requiredData", "algorithmCandidates", "hardConstraints", "softConstraints", "fallbackAlgorithm", "timeoutSeconds", "validationRules", "evidenceFields", "version", ) schema = _record_schema("Shipyard APS skill", required) schema["properties"].update( { "skillId": {"type": "string", "pattern": "^ship-[a-z0-9-]+$"}, "timeoutSeconds": {"type": "integer", "minimum": 1}, "requiredData": {"type": "array", "items": {"type": "string"}}, "algorithmCandidates": {"type": "array", "items": {"type": "string"}}, "hardConstraints": {"type": "array", "items": {"type": "string"}}, "softConstraints": {"type": "array", "items": {"type": "string"}}, "validationRules": {"type": "array", "items": {"type": "string"}}, "evidenceFields": {"type": "array", "items": {"type": "string"}}, } ) return schema def _knowledge_schema() -> dict[str, Any]: required = ( "knowledgeId", "title", "category", "content", "applicableShipTypes", "applicableWorkshops", "tags", "sourceType", "version", "effectiveDate", "confidence", "relatedResourceIds", "relatedMaterialGroups", "relatedOperationCodes", ) schema = _record_schema("Synthetic shipbuilding knowledge asset", required) schema["properties"].update( { "sourceType": {"const": "SYNTHETIC_KNOWLEDGE"}, "confidence": {"type": "number", "minimum": 0, "maximum": 1}, "effectiveDate": {"type": "string", "format": "date"}, "applicableShipTypes": {"type": "array", "items": {"type": "string"}}, "applicableWorkshops": {"type": "array", "items": {"type": "string"}}, "tags": {"type": "array", "items": {"type": "string"}}, "relatedResourceIds": {"type": "array", "items": {"type": "string"}}, "relatedMaterialGroups": {"type": "array", "items": {"type": "string"}}, "relatedOperationCodes": {"type": "array", "items": {"type": "string"}}, } ) return schema def build_schema_documents() -> dict[str, dict[str, Any]]: """Return deterministic JSON Schema documents keyed below the schemas directory.""" groups: tuple[tuple[str, str, tuple[str, ...]], ...] = ( ( "project.schema.json", "Project and contract domain", ("contracts", "ship-projects", "milestones"), ), ("wbs.schema.json", "Shipyard WBS domain", ("wbs", "blocks", "zones", "work-packages")), ( "engineering.schema.json", "Engineering and routing domain", ( "drawings", "ebom", "pbom", "mbom", "routings", "routing-operations", "engineering-releases", ), ), ( "material.schema.json", "Material and inventory domain", ( "materials", "inventory", "inventory-allocations", "substitutes", "planned-receipts", "material-requirements", "kit-readiness", ), ), ( "planning.schema.json", "Planning domain", ( "production-orders", "work-orders", "operations", "purchase-suggestions", "outsource-suggestions", "capacity-demands", "schedule-versions", "schedule-slots", "resource-loads", "conflicts", "kpis", ), ), ( "execution.schema.json", "Execution domain", ("mes-orders", "operation-reports", "material-issues"), ), ( "quality.schema.json", "Quality domain", ("quality-inspections", "nonconformities", "rework-orders"), ), ) documents: dict[str, dict[str, Any]] = { "manifest.schema.json": _manifest_schema(), "world.schema.json": { "$schema": _JSON_SCHEMA, "title": "Synthetic shipyard APS world", "type": "object", "required": ["datasetMetadata", "shipyardTables", "planningSourceHash"], "properties": { "datasetMetadata": {"type": "object"}, "shipyardTables": {"type": "object"}, "planningSourceHash": {"type": "string"}, }, "additionalProperties": True, }, "scenario.schema.json": _record_schema( "Shipyard planning scenario", ("scenarioId", "status", "datasetType"), ), "skill.schema.json": _skill_schema(), "knowledge-asset.schema.json": _knowledge_schema(), "validation-report.schema.json": { "$schema": _JSON_SCHEMA, "title": "Synthetic dataset validation report", "type": "object", "required": ["valid", "blockingIssues"], "properties": { "valid": {"type": "boolean"}, "blockingIssues": {"type": "array", "items": {"type": "string"}}, "metrics": {"type": "object"}, }, "additionalProperties": True, }, } for path, title, tables in groups: documents[path] = _domain_schema(title, tables) for name, spec in TABLE_SPECS.items(): documents[f"tables/{name}.schema.json"] = _record_schema( f"{name} row", spec.required, ) return {key: documents[key] for key in sorted(documents)}