{ "$schema": "https://json-schema.org/draft/2020-12/schema", "$id": "https://hwlab.pikastech.local/protocol/schema-drift-map.json", "title": "HWLAB Schema Drift Map", "version": 1, "sources": { "protocol": "protocol/schemas", "dbMigration": "internal/db/migrations/0001_cloud_core_skeleton.sql", "audit": "protocol/schemas/audit-event.schema.json", "evidenceChain": "protocol/evidence-chain.md", "evidence": "protocol/schemas/evidence-record.schema.json", "deployManifest": "deploy/deploy.yaml", "deploy": "deploy/deploy.schema.json" }, "summary": { "aligned": [ "projectId", "operationId", "auditId", "traceId", "evidenceId", "serviceId", "environment", "resourceId", "sessionId" ], "gapCount": 12, "notes": [ "This map describes naming drift only and does not change any storage implementation.", "A field can be aligned at the protocol level while still requiring a DB migration rename or mapping layer before real persistence." ] }, "entities": [ { "name": "hardware_operation", "protocol": "protocol/schemas/hardware-operation.schema.json", "dbTable": "hardware_operations", "drift": [ { "field": "operationId", "protocolField": "operationId", "dbColumn": "id", "status": "aligned" }, { "field": "projectId", "protocolField": "projectId", "dbColumn": "project_id", "status": "aligned" }, { "field": "gatewaySessionId", "protocolField": "gatewaySessionId", "dbColumn": "gateway_session_id", "status": "aligned" }, { "field": "agentSessionId", "protocolField": "agentSessionId", "dbColumn": "agent_session_id", "status": "aligned" }, { "field": "workerSessionId", "protocolField": "workerSessionId", "dbColumn": "worker_session_id", "status": "aligned" }, { "field": "resourceId", "protocolField": "resourceId", "dbColumn": "operation_json.resourceId", "status": "gap", "gap": "The skeleton table has no dedicated resource column and currently stores the operation payload as opaque JSON." }, { "field": "capabilityId", "protocolField": "capabilityId", "dbColumn": "operation_json.capabilityId", "status": "gap", "gap": "The skeleton table has no dedicated capability column and currently stores the operation payload as opaque JSON." }, { "field": "requestedBy", "protocolField": "requestedBy", "dbColumn": "requested_by", "status": "aligned" }, { "field": "status", "protocolField": "status", "dbColumn": "status", "status": "aligned" }, { "field": "environment", "protocolField": "environment", "dbColumn": "operation_json.environment", "status": "gap", "gap": "The skeleton table does not carry a dedicated environment column for the operation row." }, { "field": "requestedAt", "protocolField": "requestedAt", "dbColumn": "requested_at", "status": "aligned" }, { "field": "updatedAt", "protocolField": "updatedAt", "dbColumn": "updated_at", "status": "aligned" } ] }, { "name": "audit_event", "protocol": "protocol/schemas/audit-event.schema.json", "dbTable": "audit_events", "drift": [ { "field": "auditId", "protocolField": "auditId", "dbColumn": "id", "status": "aligned" }, { "field": "traceId", "protocolField": "traceId", "dbColumn": "request_id", "status": "gap", "gap": "The migration still uses request_id instead of traceId." }, { "field": "actorType", "protocolField": "actorType", "dbColumn": "actor", "status": "gap", "gap": "The migration stores a single actor string instead of a typed actorType field." }, { "field": "actorId", "protocolField": "actorId", "dbColumn": "source", "status": "gap", "gap": "The migration stores source instead of a stable actorId." }, { "field": "action", "protocolField": "action", "dbColumn": "operation", "status": "gap", "gap": "The migration uses operation instead of the protocol action name." }, { "field": "targetType", "protocolField": "targetType", "dbColumn": "target", "status": "gap", "gap": "The migration stores a single target string instead of targetType and targetId." }, { "field": "targetId", "protocolField": "targetId", "dbColumn": "target", "status": "gap", "gap": "The migration stores a single target string instead of targetType and targetId." }, { "field": "projectId", "protocolField": "projectId", "dbColumn": "event_json.projectId", "status": "aligned", "notes": "Present in protocol and fixtures, but not a dedicated migration column." }, { "field": "gatewaySessionId", "protocolField": "gatewaySessionId", "dbColumn": "event_json.gatewaySessionId", "status": "aligned", "notes": "Optional correlation field in protocol; still payload-only in the skeleton." }, { "field": "workerSessionId", "protocolField": "workerSessionId", "dbColumn": "event_json.workerSessionId", "status": "aligned", "notes": "Optional correlation field in protocol; still payload-only in the skeleton." }, { "field": "operationId", "protocolField": "operationId", "dbColumn": "event_json.operationId", "status": "aligned", "notes": "Present in protocol and fixtures, but not a dedicated migration column." }, { "field": "serviceId", "protocolField": "serviceId", "dbColumn": "event_json.serviceId", "status": "aligned", "notes": "Frozen service ID appears in payload only." }, { "field": "environment", "protocolField": "environment", "dbColumn": "event_json.environment", "status": "aligned", "notes": "MVP environment is carried in payload only." }, { "field": "occurredAt", "protocolField": "occurredAt", "dbColumn": "timestamp", "status": "gap", "gap": "The migration uses timestamp instead of occurredAt." } ] }, { "name": "evidence_chain", "protocol": "protocol/evidence-chain.md", "dbTable": null, "drift": [ { "field": "chainId", "protocolField": "chainId", "dbColumn": "n/a", "status": "aligned" }, { "field": "schemaVersion", "protocolField": "schemaVersion", "dbColumn": "n/a", "status": "aligned" }, { "field": "scenario", "protocolField": "scenario", "dbColumn": "n/a", "status": "aligned" }, { "field": "title", "protocolField": "title", "dbColumn": "n/a", "status": "aligned" }, { "field": "projectId", "protocolField": "projectId", "dbColumn": "n/a", "status": "aligned" }, { "field": "operationId", "protocolField": "operationId", "dbColumn": "n/a", "status": "aligned" }, { "field": "traceId", "protocolField": "traceId", "dbColumn": "n/a", "status": "aligned" }, { "field": "environment", "protocolField": "environment", "dbColumn": "n/a", "status": "aligned" }, { "field": "gatewaySessionId", "protocolField": "gatewaySessionId", "dbColumn": "n/a", "status": "aligned" }, { "field": "agentSessionId", "protocolField": "agentSessionId", "dbColumn": "n/a", "status": "aligned" }, { "field": "workerSessionId", "protocolField": "workerSessionId", "dbColumn": "n/a", "status": "aligned" }, { "field": "resourceId", "protocolField": "resourceId", "dbColumn": "n/a", "status": "aligned" }, { "field": "capabilityId", "protocolField": "capabilityId", "dbColumn": "n/a", "status": "aligned" }, { "field": "hardwareOperation", "protocolField": "hardwareOperation", "dbColumn": "protocol/schemas/hardware-operation.schema.json", "status": "aligned" }, { "field": "auditEvents", "protocolField": "auditEvents", "dbColumn": "protocol/schemas/audit-event.schema.json", "status": "aligned" }, { "field": "traceEvents", "protocolField": "traceEvents", "dbColumn": "protocol/schemas/trace-event.schema.json", "status": "aligned" }, { "field": "evidenceRecords", "protocolField": "evidenceRecords", "dbColumn": "protocol/schemas/evidence-record.schema.json", "status": "aligned" } ] }, { "name": "trace_event", "protocol": "protocol/schemas/trace-event.schema.json", "dbTable": "agent_trace_events", "drift": [ { "field": "traceEventId", "protocolField": "traceEventId", "dbColumn": "id", "status": "aligned" }, { "field": "traceId", "protocolField": "traceId", "dbColumn": "trace_id", "status": "aligned" }, { "field": "projectId", "protocolField": "projectId", "dbColumn": "event_json.projectId", "status": "aligned", "notes": "Project scope is payload-only in the skeleton." }, { "field": "agentSessionId", "protocolField": "agentSessionId", "dbColumn": "agent_session_id", "status": "aligned" }, { "field": "workerSessionId", "protocolField": "workerSessionId", "dbColumn": "worker_session_id", "status": "aligned" }, { "field": "operationId", "protocolField": "operationId", "dbColumn": "event_json.operationId", "status": "aligned", "notes": "Operation scope is payload-only in the skeleton." }, { "field": "serviceId", "protocolField": "serviceId", "dbColumn": "event_json.serviceId", "status": "aligned" }, { "field": "level", "protocolField": "level", "dbColumn": "level", "status": "aligned" }, { "field": "message", "protocolField": "message", "dbColumn": "message", "status": "aligned" }, { "field": "environment", "protocolField": "environment", "dbColumn": "event_json.environment", "status": "aligned" }, { "field": "occurredAt", "protocolField": "occurredAt", "dbColumn": "occurred_at", "status": "aligned" } ] }, { "name": "evidence_record", "protocol": "protocol/schemas/evidence-record.schema.json", "dbTable": "evidence_records", "drift": [ { "field": "evidenceId", "protocolField": "evidenceId", "dbColumn": "id", "status": "aligned" }, { "field": "projectId", "protocolField": "projectId", "dbColumn": "project_id", "status": "aligned" }, { "field": "operationId", "protocolField": "operationId", "dbColumn": "operation_id", "status": "aligned" }, { "field": "agentSessionId", "protocolField": "agentSessionId", "dbColumn": "metadata_json.agentSessionId", "status": "aligned", "notes": "Optional in protocol and currently payload-only in the skeleton." }, { "field": "workerSessionId", "protocolField": "workerSessionId", "dbColumn": "metadata_json.workerSessionId", "status": "aligned", "notes": "Optional in protocol and currently payload-only in the skeleton." }, { "field": "kind", "protocolField": "kind", "dbColumn": "evidence_type", "status": "gap", "gap": "The migration uses evidence_type, but the protocol requires kind." }, { "field": "uri", "protocolField": "uri", "dbColumn": "uri", "status": "aligned" }, { "field": "sha256", "protocolField": "sha256", "dbColumn": "metadata_json.sha256", "status": "gap", "gap": "The migration has no dedicated sha256 column." }, { "field": "serviceId", "protocolField": "serviceId", "dbColumn": "metadata_json.serviceId", "status": "aligned", "notes": "Frozen service ID is present in protocol and fixtures." }, { "field": "environment", "protocolField": "environment", "dbColumn": "metadata_json.environment", "status": "aligned" }, { "field": "createdAt", "protocolField": "createdAt", "dbColumn": "created_at", "status": "aligned" } ] }, { "name": "deploy_manifest", "protocol": "deploy/deploy.schema.json", "dbTable": null, "drift": [ { "field": "manifestVersion", "protocolField": "manifestVersion", "dbColumn": "n/a", "status": "aligned" }, { "field": "environment", "protocolField": "environment", "dbColumn": "n/a", "status": "aligned" }, { "field": "commitId", "protocolField": "commitId", "dbColumn": "n/a", "status": "aligned" }, { "field": "profiles.dev.name", "protocolField": "profiles.dev.name", "dbColumn": "n/a", "status": "aligned" }, { "field": "services[].serviceId", "protocolField": "services[].serviceId", "dbColumn": "n/a", "status": "aligned" }, { "field": "services[].replicas", "protocolField": "services[].replicas", "dbColumn": "n/a", "status": "aligned" } ] } ], "requiredKeyCoverage": { "projectId": { "protocol": [ "hardware-operation", "audit-event", "trace-event", "evidence-record", "deploy-manifest" ], "dbMigration": [ "projects.project_id", "gateway_sessions.project_id", "box_resources.project_id", "wiring_configs.project_id", "hardware_operations.project_id", "agent_sessions.project_id", "audit_events.event_json.projectId", "agent_trace_events.event_json.projectId", "evidence_records.project_id" ] }, "operationId": { "protocol": [ "hardware-operation", "audit-event", "trace-event", "evidence-record" ], "dbMigration": [ "hardware_operations.id", "audit_events.event_json.operationId", "agent_trace_events.event_json.operationId", "evidence_records.operation_id" ] }, "auditId": { "protocol": [ "audit-event", "evidence-record.metadata.producedByAuditId", "trace-event.metadata.auditId" ], "dbMigration": [ "audit_events.id", "audit_events.event_json.auditId", "agent_trace_events.event_json.auditId", "evidence_records.metadata_json.producedByAuditId" ] }, "traceId": { "protocol": [ "audit-event", "trace-event", "evidence-record.metadata.traceId" ], "dbMigration": [ "audit_events.request_id", "agent_trace_events.trace_id", "evidence_records.metadata_json.traceId" ] }, "evidenceId": { "protocol": [ "evidence-record", "audit-event.targetId", "trace-event.metadata.evidenceId" ], "dbMigration": [ "evidence_records.id", "audit_events.event_json.evidenceId", "agent_trace_events.event_json.evidenceId" ] }, "serviceId": { "protocol": [ "audit-event", "trace-event", "evidence-record", "deploy-manifest.services[].serviceId" ], "dbMigration": [ "audit_events.event_json.serviceId", "agent_trace_events.event_json.serviceId", "evidence_records.metadata_json.serviceId", "gateway_sessions.gateway_service_id" ] }, "environment": { "protocol": [ "hardware-operation", "audit-event", "trace-event", "evidence-record", "deploy-manifest" ], "dbMigration": [ "hardware_operations.operation_json.environment", "audit_events.event_json.environment", "agent_trace_events.event_json.environment", "evidence_records.metadata_json.environment" ] }, "resourceId": { "protocol": [ "hardware-operation", "audit-event.metadata.resourceId", "evidence-record.metadata.resourceId" ], "dbMigration": [ "box_resources.id", "hardware_operations.operation_json.resourceId", "audit_events.event_json.resourceId", "evidence_records.metadata_json.resourceId" ] }, "sessionId": { "protocol": [ "gatewaySessionId", "agentSessionId", "workerSessionId" ], "dbMigration": [ "gateway_sessions.id", "agent_sessions.id", "worker_sessions.id", "hardware_operations.gateway_session_id", "agent_trace_events.agent_session_id", "agent_trace_events.worker_session_id", "evidence_records.metadata_json.agentSessionId", "evidence_records.metadata_json.workerSessionId" ] } }, "missingToFixBeforeRealPersistence": [ { "field": "audit_events.request_id", "reason": "Must be renamed or mapped to traceId before audit rows are treated as protocol-shaped records." }, { "field": "audit_events.actor", "reason": "Must be split into actorType and actorId or mapped through a persisted envelope." }, { "field": "audit_events.source", "reason": "Must be renamed or mapped to actorId." }, { "field": "audit_events.operation", "reason": "Must be renamed or mapped to action." }, { "field": "audit_events.target", "reason": "Must be split into targetType and targetId." }, { "field": "audit_events.timestamp", "reason": "Must be renamed or mapped to occurredAt." }, { "field": "evidence_records.evidence_type", "reason": "Must be renamed or mapped to kind." }, { "field": "evidence_records.metadata_json.sha256", "reason": "Must become a first-class persisted field or a tested mapping target." }, { "field": "hardware_operations.operation_json.resourceId", "reason": "Must be exposed through a real column or tested extraction path." }, { "field": "hardware_operations.operation_json.capabilityId", "reason": "Must be exposed through a real column or tested extraction path." } ] }