docs: add schema drift map

This commit is contained in:
HWLAB Code Queue
2026-05-21 15:34:33 +00:00
parent 277bdb0d44
commit 2ae6e15df3
3 changed files with 902 additions and 0 deletions
+700
View File
@@ -0,0 +1,700 @@
{
"$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.json",
"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."
}
]
}