@aiwg/cli 2026.9.0 → 2026.9.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (107) hide show
  1. package/agentic/code/providers/capability-matrix.yaml +41 -0
  2. package/agentic/code/providers/model-capabilities.v1.json +11 -0
  3. package/agentic/code/providers/model-catalog.v1.json +8 -0
  4. package/agentic/code/providers/pi/aiwg-bridge.ts +26 -0
  5. package/bin/aiwg.mjs +15 -3
  6. package/dist/src/api/index.d.ts +3 -0
  7. package/dist/src/api/index.js +3 -0
  8. package/dist/src/auth/credential-store.js +6 -0
  9. package/dist/src/channel/manager.mjs +2 -2
  10. package/dist/src/cli/handlers/dataset.js +186 -0
  11. package/dist/src/cli/handlers/help.js +2 -1
  12. package/dist/src/cli/handlers/index.js +5 -1
  13. package/dist/src/cli/handlers/init.js +1 -0
  14. package/dist/src/cli/handlers/output-mode.js +18 -1
  15. package/dist/src/cli/handlers/run.js +11 -3
  16. package/dist/src/cli/handlers/schema.js +221 -0
  17. package/dist/src/cli/handlers/sessions.js +30 -12
  18. package/dist/src/cli/handlers/steward.js +11 -1
  19. package/dist/src/cli/handlers/use.js +6 -2
  20. package/dist/src/cli/hooks/builtin/activity-log-hook.js +6 -0
  21. package/dist/src/cli/router.js +1 -1
  22. package/dist/src/cli/scope-resolver.js +22 -0
  23. package/dist/src/dataset/adapter-sdk.d.ts +41 -0
  24. package/dist/src/dataset/adapter-sdk.js +147 -0
  25. package/dist/src/dataset/adapter-types.d.ts +179 -0
  26. package/dist/src/dataset/adapter-types.js +2 -0
  27. package/dist/src/dataset/adapters.d.ts +104 -0
  28. package/dist/src/dataset/adapters.js +518 -0
  29. package/dist/src/dataset/conformance-types.d.ts +84 -0
  30. package/dist/src/dataset/conformance-types.js +3 -0
  31. package/dist/src/dataset/conformance.d.ts +13 -0
  32. package/dist/src/dataset/conformance.js +90 -0
  33. package/dist/src/dataset/contracts.d.ts +17 -0
  34. package/dist/src/dataset/contracts.js +236 -0
  35. package/dist/src/dataset/file-orchestration-repository.d.ts +19 -0
  36. package/dist/src/dataset/file-orchestration-repository.js +68 -0
  37. package/dist/src/dataset/fortemi-execution-bridge.d.ts +33 -0
  38. package/dist/src/dataset/fortemi-execution-bridge.js +35 -0
  39. package/dist/src/dataset/index.d.ts +21 -0
  40. package/dist/src/dataset/index.js +21 -0
  41. package/dist/src/dataset/ledger-types.d.ts +141 -0
  42. package/dist/src/dataset/ledger-types.js +2 -0
  43. package/dist/src/dataset/ledger.d.ts +27 -0
  44. package/dist/src/dataset/ledger.js +100 -0
  45. package/dist/src/dataset/local-execution-backend.d.ts +10 -0
  46. package/dist/src/dataset/local-execution-backend.js +32 -0
  47. package/dist/src/dataset/orchestration-repository.d.ts +29 -0
  48. package/dist/src/dataset/orchestration-repository.js +34 -0
  49. package/dist/src/dataset/orchestration-service.d.ts +56 -0
  50. package/dist/src/dataset/orchestration-service.js +466 -0
  51. package/dist/src/dataset/orchestration-types.d.ts +83 -0
  52. package/dist/src/dataset/orchestration-types.js +2 -0
  53. package/dist/src/dataset/presentation.d.ts +3 -0
  54. package/dist/src/dataset/presentation.js +8 -0
  55. package/dist/src/dataset/projections.d.ts +42 -0
  56. package/dist/src/dataset/projections.js +192 -0
  57. package/dist/src/dataset/schema-governance.d.ts +71 -0
  58. package/dist/src/dataset/schema-governance.js +135 -0
  59. package/dist/src/dataset/standards-types.d.ts +66 -0
  60. package/dist/src/dataset/standards-types.js +10 -0
  61. package/dist/src/dataset/standards.d.ts +13 -0
  62. package/dist/src/dataset/standards.js +291 -0
  63. package/dist/src/dataset/types.d.ts +258 -0
  64. package/dist/src/dataset/types.js +2 -0
  65. package/dist/src/extensions/commands/definitions.js +27 -1
  66. package/dist/src/installation/manager.mjs +5 -1
  67. package/dist/src/models/model-capabilities.v1.json +11 -0
  68. package/dist/src/models/model-catalog.v1.json +8 -0
  69. package/dist/src/models/model-discovery.js +32 -0
  70. package/dist/src/models/provider-policy.js +3 -2
  71. package/dist/src/output-modes/index.js +4 -0
  72. package/dist/src/output-modes/registry.js +68 -24
  73. package/dist/src/output-modes/runtime.js +10 -8
  74. package/dist/src/plugin/skill-command-translator.js +1 -0
  75. package/dist/src/providers/capability-matrix.yaml +41 -0
  76. package/dist/src/providers/provider-definitions.js +72 -0
  77. package/dist/src/providers/provider-inventory.js +1 -0
  78. package/dist/src/schema/catalog.js +234 -0
  79. package/dist/src/schema/compatibility.js +42 -0
  80. package/dist/src/schema/diagnostics.js +36 -0
  81. package/dist/src/schema/index.js +8 -0
  82. package/dist/src/schema/policy.js +58 -0
  83. package/dist/src/schema/resolver.js +76 -0
  84. package/dist/src/schema/types.js +2 -0
  85. package/dist/src/schema/validator.js +82 -0
  86. package/dist/src/sessions/adapters/pi.js +141 -0
  87. package/dist/src/sessions/contracts.js +1 -1
  88. package/dist/src/sessions/index.js +1 -0
  89. package/dist/src/sessions/workspace-discovery.js +10 -0
  90. package/dist/src/storage/backends/fortemi.js +6 -0
  91. package/dist/src/storage/config.js +18 -4
  92. package/dist/src/storage/fortemi-qualification.js +106 -0
  93. package/dist/src/storage/index.js +1 -0
  94. package/dist/src/storage/types.js +1 -1
  95. package/package.json +3 -1
  96. package/schemas/dataset/conformance-manifest.v1.schema.json +35 -0
  97. package/schemas/dataset/conformance-receipt.v1.schema.json +22 -0
  98. package/schemas/dataset/dataset-contracts.v1.schema.json +117 -0
  99. package/schemas/dataset/dataset-deprecations.v1.schema.json +37 -0
  100. package/schemas/dataset/dataset-schema-governance.v1.schema.json +92 -0
  101. package/schemas/dataset/dataset-standards-exchange.v1.schema.json +59 -0
  102. package/schemas/dataset/profiles/openlineage-1.0.0.schema.json +15 -0
  103. package/schemas/dataset/profiles/prov-json-20130430.schema.json +12 -0
  104. package/schemas/dataset/run-ledger.v1.schema.json +39 -0
  105. package/schemas/dataset/source-adapter.v1.schema.json +112 -0
  106. package/tools/agents/deploy-agents.mjs +9 -3
  107. package/tools/agents/providers/pi.mjs +176 -0
@@ -0,0 +1,192 @@
1
+ import { computeLedgerEventDigest, createLedgerEvent } from './ledger.js';
2
+ function result(profile, value, items) { return { value, loss: { profile, lossless: items.length === 0, items } }; }
3
+ function loss(path, reason, severity = 'information', context) {
4
+ return {
5
+ path,
6
+ reason,
7
+ severity,
8
+ ...(context?.privacy ? { sourcePrivacy: context.privacy } : {}),
9
+ ...(context?.retentionPolicy ? { retentionPolicy: context.retentionPolicy } : {}),
10
+ };
11
+ }
12
+ function event(record, sequence, context) {
13
+ return createLedgerEvent({ eventId: `urn:aiwg:event:${encodeURIComponent(record.id)}`, sequence, recordedAt: context.recordedAt, producer: context.producer, ...(context.runId ? { runId: context.runId } : {}), record });
14
+ }
15
+ function fileLocator(path, line) { return line === undefined ? { scheme: 'file', value: path } : { scheme: 'line-column', value: path, line }; }
16
+ const PRIVACY_ORDER = { public: 0, internal: 1, confidential: 2, restricted: 3 };
17
+ export function preventPrivacyDowngrade(source, projected) {
18
+ if (PRIVACY_ORDER[projected] < PRIVACY_ORDER[source])
19
+ throw new Error(`PROVENANCE_PRIVACY_DOWNGRADE: ${source} cannot be projected as ${projected}`);
20
+ }
21
+ export function projectResearchProvenance(record, context) {
22
+ const privacy = context.privacy ?? 'internal';
23
+ const events = [];
24
+ events.push(event({ recordType: 'agent', id: record.agent.id, principalKind: record.agent.type === 'software_agent' ? 'software' : 'person' }, 1, context));
25
+ events.push(event({ recordType: 'entity', id: record.entity.id, entityType: record.entity.type, privacy, ...(context.retentionPolicy ? { retentionPolicy: context.retentionPolicy } : {}) }, 2, context));
26
+ events.push(event({ recordType: 'activity', id: record.activity.id, activityType: record.activity.type, startedAt: record.activity.startedAt, endedAt: record.activity.endedAt, ...(context.runId ? { runId: context.runId } : {}) }, 3, context));
27
+ for (const sourceId of record.relationships.wasDerivedFrom ?? []) {
28
+ if (!events.some((item) => item.record.id === sourceId))
29
+ events.push(event({ recordType: 'entity', id: sourceId, entityType: 'research-source', privacy, ...(context.retentionPolicy ? { retentionPolicy: context.retentionPolicy } : {}) }, events.length + 1, context));
30
+ }
31
+ if (record.relationships.wasGeneratedBy && record.relationships.wasGeneratedBy !== record.activity.id)
32
+ events.push(event({ recordType: 'activity', id: record.relationships.wasGeneratedBy, activityType: 'referenced-research-activity' }, events.length + 1, context));
33
+ for (const agentId of [record.relationships.wasAttributedTo, record.relationships.wasAssociatedWith]) {
34
+ if (agentId && !events.some((item) => item.record.id === agentId))
35
+ events.push(event({ recordType: 'agent', id: agentId, principalKind: 'software' }, events.length + 1, context));
36
+ }
37
+ const assertions = [];
38
+ if (record.relationships.wasGeneratedBy)
39
+ assertions.push({ subjectId: record.entity.id, predicate: 'wasGeneratedBy', objectId: record.relationships.wasGeneratedBy, activityId: record.activity.id });
40
+ for (const sourceId of record.relationships.wasDerivedFrom ?? [])
41
+ assertions.push({ subjectId: record.entity.id, predicate: 'wasDerivedFrom', objectId: sourceId, activityId: record.activity.id });
42
+ if (record.relationships.wasAttributedTo)
43
+ assertions.push({ subjectId: record.entity.id, predicate: 'wasAttributedTo', objectId: record.relationships.wasAttributedTo });
44
+ if (record.relationships.wasAssociatedWith)
45
+ assertions.push({ subjectId: record.activity.id, predicate: 'wasAssociatedWith', objectId: record.relationships.wasAssociatedWith, activityId: record.activity.id });
46
+ for (const [index, assertion] of assertions.entries())
47
+ events.push(event({ recordType: 'assertion', id: `assertion:${record.id}:${index + 1}`, ...assertion, basis: 'imported', evidenceIds: [], privacy, ...(context.retentionPolicy ? { retentionPolicy: context.retentionPolicy } : {}) }, events.length + 1, context));
48
+ return result('research-provenance/v1', events, [loss('/entity/attributes', 'arbitrary research entity attributes are not in the canonical vocabulary', 'information', context), loss('/activity/attributes', 'arbitrary research activity attributes require a governed extension', 'information', context)]);
49
+ }
50
+ export function projectMarketplaceProvenance(graph, context) {
51
+ const privacy = context.privacy ?? 'internal';
52
+ const events = [];
53
+ const items = [];
54
+ let sequence = 1;
55
+ for (const agent of graph.agents)
56
+ events.push(event({ recordType: 'agent', id: agent.id, principalKind: agent.type === 'catalog' ? 'service' : agent.type }, sequence++, context));
57
+ for (const entity of graph.entities)
58
+ events.push(event({ recordType: 'entity', id: entity.id, entityType: entity.type, privacy, ...(context.retentionPolicy ? { retentionPolicy: context.retentionPolicy } : {}), ...(entity.digest ? { digest: { algorithm: 'sha256', value: entity.digest.replace(/^sha256:/, '') } } : {}) }, sequence++, context));
59
+ for (const activity of graph.activities)
60
+ events.push(event({ recordType: 'activity', id: activity.id, activityType: activity.type, startedAt: activity.startedAt, endedAt: activity.endedAt }, sequence++, context));
61
+ for (const relation of graph.relations)
62
+ events.push(event({ recordType: 'assertion', id: `marketplace:${sequence}:${relation.subject}:${relation.object}`, subjectId: relation.subject, predicate: relation.type, objectId: relation.object, basis: 'imported', evidenceIds: [], privacy, ...(context.retentionPolicy ? { retentionPolicy: context.retentionPolicy } : {}) }, sequence++, context));
63
+ if (graph.entities.some((entry) => entry.attributes))
64
+ items.push(loss('/entities/*/attributes', 'non-core marketplace attributes require a governed extension', 'information', context));
65
+ return result('marketplace-provenance/v1', events, items);
66
+ }
67
+ export function projectFortemiProvenance(record, context) {
68
+ const privacy = record.privacy.classification === 'public' ? 'public' : record.privacy.classification === 'private' ? 'confidential' : 'internal';
69
+ const events = [];
70
+ const items = [];
71
+ let sequence = 1;
72
+ events.push(event({ recordType: 'agent', id: context.producer.id, principalKind: 'software', version: context.producer.version }, sequence++, context));
73
+ events.push(event({ recordType: 'entity', id: record.id, entityType: record.type, revision: record.source.checksum, privacy, ...(context.retentionPolicy ? { retentionPolicy: context.retentionPolicy } : {}) }, sequence++, context));
74
+ const agentIds = new Set((record.provenance_events ?? []).flatMap((item) => item.agent ? [item.agent] : []));
75
+ agentIds.delete(context.producer.id);
76
+ for (const id of agentIds)
77
+ events.push(event({ recordType: 'agent', id, principalKind: 'software' }, sequence++, context));
78
+ for (const item of record.provenance_events ?? []) {
79
+ const activityId = item.id ?? `activity:${record.id}:${sequence}`;
80
+ events.push(event({ recordType: 'activity', id: activityId, activityType: item.activity, startedAt: item.started_at, endedAt: item.ended_at, ...(context.runId ? { runId: context.runId } : {}) }, sequence++, context));
81
+ if (item.agent)
82
+ events.push(event({ recordType: 'assertion', id: `assertion:${activityId}:agent`, subjectId: activityId, predicate: 'wasAssociatedWith', objectId: item.agent, basis: 'imported', evidenceIds: [], privacy, ...(context.retentionPolicy ? { retentionPolicy: context.retentionPolicy } : {}) }, sequence++, context));
83
+ if (item.attributes)
84
+ items.push(loss(`/provenance_events/${activityId}/attributes`, 'Fortemi activity attributes require a governed extension', 'information', { ...context, privacy }));
85
+ }
86
+ const sourceEntities = new Set();
87
+ for (const item of record.provenance) {
88
+ const sourceEntityId = `urn:aiwg:source:${encodeURIComponent(item.path)}`;
89
+ if (!sourceEntities.has(sourceEntityId)) {
90
+ events.push(event({ recordType: 'entity', id: sourceEntityId, entityType: 'source-record', privacy, ...(context.retentionPolicy ? { retentionPolicy: context.retentionPolicy } : {}) }, sequence++, context));
91
+ sourceEntities.add(sourceEntityId);
92
+ }
93
+ const evidenceId = `evidence:${record.id}:${sequence}`;
94
+ events.push(event({ recordType: 'evidence', id: evidenceId, source: fileLocator(item.path), target: { scheme: 'json-pointer', value: record.id, field: item.field }, method: `fortemi-field-provenance:${item.source}`, confidence: item.confidence === 'source' || item.confidence === 'reviewed' ? 1 : 0.5, privacy, ...(context.retentionPolicy ? { retentionPolicy: context.retentionPolicy } : {}), ...(context.runId ? { runId: context.runId } : {}), responsibleAgentId: context.producer.id, observedAt: context.recordedAt }, sequence++, context));
95
+ events.push(event({ recordType: 'assertion', id: `assertion:${record.id}:${sequence}`, subjectId: record.id, predicate: 'wasDerivedFrom', objectId: sourceEntityId, basis: context.runId ? 'observed' : 'imported', evidenceIds: [evidenceId], ...(context.runId ? { runId: context.runId } : {}), field: item.field, privacy, ...(context.retentionPolicy ? { retentionPolicy: context.retentionPolicy } : {}) }, sequence++, context));
96
+ }
97
+ items.push(loss('/search', 'search projection is not provenance', 'information', { ...context, privacy }));
98
+ if (record.relationships.length)
99
+ items.push(loss('/relationships', 'relationships require separate evidence-bearing conversion when source evidence is absent', 'semantic', { ...context, privacy }));
100
+ return result('fortemi-index-export/v2', events, items);
101
+ }
102
+ export function projectOperationalState(state, recordId, context) {
103
+ const items = [];
104
+ const privacy = context.privacy ?? 'internal';
105
+ const agentId = state.observer ?? context.producer.id;
106
+ const locator = state.evidence_path ? fileLocator(state.evidence_path) : state.evidence_url ? { scheme: 'uri', value: state.evidence_url } : undefined;
107
+ if (!locator)
108
+ items.push(loss('/evidence', 'operational state has no evidence locator', 'semantic', context));
109
+ if (state.supersedes?.length)
110
+ items.push(loss('/supersedes', 'referenced operational revisions require separately imported ledger entities', 'semantic', context));
111
+ if (state.contradicts?.length)
112
+ items.push(loss('/contradicts', 'referenced operational revisions require separately imported ledger entities', 'semantic', context));
113
+ const events = [event({ recordType: 'agent', id: agentId, principalKind: 'software' }, 1, context), event({ recordType: 'entity', id: recordId, entityType: state.source_kind ?? 'operational-state', privacy, ...(context.retentionPolicy ? { retentionPolicy: context.retentionPolicy } : {}) }, 2, context)];
114
+ if (locator)
115
+ events.push(event({ recordType: 'evidence', id: `evidence:${recordId}`, source: locator, method: 'operational-observation', confidence: state.confidence === 'source' || state.confidence === 'reviewed' ? 1 : 0.5, privacy, ...(context.retentionPolicy ? { retentionPolicy: context.retentionPolicy } : {}), ...(context.runId ? { runId: context.runId } : {}), responsibleAgentId: agentId, observedAt: state.observed_at ?? context.recordedAt }, 3, context));
116
+ return result('operational-state/v1', events, items);
117
+ }
118
+ export function projectMentionEdge(edge, context) {
119
+ const privacy = context.privacy ?? 'internal';
120
+ const agentId = context.producer.id;
121
+ return result('mention-edge/v1', [
122
+ event({ recordType: 'agent', id: agentId, principalKind: 'software', version: context.producer.version }, 1, context),
123
+ event({ recordType: 'entity', id: edge.sourcePath, entityType: 'file', privacy, ...(context.retentionPolicy ? { retentionPolicy: context.retentionPolicy } : {}) }, 2, context),
124
+ event({ recordType: 'entity', id: edge.targetPath, entityType: 'file', privacy, ...(context.retentionPolicy ? { retentionPolicy: context.retentionPolicy } : {}) }, 3, context),
125
+ event({ recordType: 'evidence', id: `evidence:mention:${edge.sourcePath}:${edge.targetPath}`, source: fileLocator(edge.sourcePath, edge.line), target: fileLocator(edge.targetPath), method: edge.method ?? 'mention', confidence: edge.confidence ?? 1, privacy, ...(context.retentionPolicy ? { retentionPolicy: context.retentionPolicy } : {}), ...(context.runId ? { runId: context.runId } : {}), responsibleAgentId: agentId, observedAt: context.recordedAt }, 4, context),
126
+ event({ recordType: 'assertion', id: `assertion:mention:${edge.sourcePath}:${edge.targetPath}`, subjectId: edge.sourcePath, predicate: edge.method === 'markdown-link' ? 'links-to' : 'mentions', objectId: edge.targetPath, basis: 'inferred', evidenceIds: [`evidence:mention:${edge.sourcePath}:${edge.targetPath}`], ...(context.runId ? { runId: context.runId } : {}), privacy, ...(context.retentionPolicy ? { retentionPolicy: context.retentionPolicy } : {}) }, 5, context),
127
+ ], []);
128
+ }
129
+ export function projectSdlcTraceLink(link, context) {
130
+ const projected = projectMentionEdge({ sourcePath: link.targetPath, targetPath: link.requirementId, method: 'mention', line: link.line, confidence: link.confidence }, context);
131
+ const assertion = projected.value.at(-1);
132
+ const observed = link.verified && context.runId !== undefined;
133
+ assertion.record = { ...assertion.record, predicate: `implements:${link.targetType}`, basis: observed ? 'observed' : 'inferred' };
134
+ const { eventDigest: _eventDigest, ...content } = assertion;
135
+ assertion.eventDigest = computeLedgerEventDigest(content);
136
+ return result('sdlc-traceability/v1', projected.value, [
137
+ ...projected.loss.items,
138
+ ...(link.verified && !context.runId ? [loss('/runId', 'verified SDLC link lacks run identity and remains inferred', 'semantic', context)] : []),
139
+ ]);
140
+ }
141
+ export function projectLedgerToDependencyGraph(events) {
142
+ const graph = {};
143
+ const items = [];
144
+ for (const event of events)
145
+ if (event.record.recordType === 'assertion') {
146
+ const assertion = event.record;
147
+ graph[assertion.subjectId] ??= { upstream: [], downstream: [] };
148
+ graph[assertion.objectId] ??= { upstream: [], downstream: [] };
149
+ graph[assertion.subjectId].upstream.push({ path: assertion.objectId, type: assertion.predicate });
150
+ graph[assertion.objectId].downstream.push({ path: assertion.subjectId, type: assertion.predicate });
151
+ items.push({ ...loss(`/events/${event.eventId}`, 'DependencyGraph drops basis, evidence, run, field, privacy, and retention', 'semantic'), sourcePrivacy: assertion.privacy, ...(assertion.retentionPolicy ? { retentionPolicy: assertion.retentionPolicy } : {}) });
152
+ }
153
+ return result('dependency-graph/v1', graph, items);
154
+ }
155
+ export function projectLedgerToW3cProv(events) {
156
+ const value = { entity: {}, activity: {}, agent: {}, wasDerivedFrom: [], wasGeneratedBy: [], used: [], wasAssociatedWith: [], wasAttributedTo: [] };
157
+ const items = [];
158
+ for (const event of events) {
159
+ const record = event.record;
160
+ if (record.recordType === 'entity') {
161
+ value.entity[record.id] = { type: record.entityType, revision: record.revision, privacy: record.privacy };
162
+ if (record.digest || record.retentionPolicy)
163
+ items.push({ ...loss(`/records/${record.id}`, 'core W3C projection omits canonical digest or retention metadata', 'information'), sourcePrivacy: record.privacy, ...(record.retentionPolicy ? { retentionPolicy: record.retentionPolicy } : {}) });
164
+ }
165
+ else if (record.recordType === 'activity')
166
+ value.activity[record.id] = { type: record.activityType, startedAt: record.startedAt, endedAt: record.endedAt };
167
+ else if (record.recordType === 'agent')
168
+ value.agent[record.id] = { type: record.principalKind, version: record.version };
169
+ else if (record.recordType === 'evidence')
170
+ items.push({ ...loss(`/records/${record.id}`, 'core W3C relation view references evidence IDs but omits canonical locator and observation detail', 'information'), sourcePrivacy: record.privacy, ...(record.retentionPolicy ? { retentionPolicy: record.retentionPolicy } : {}) });
171
+ else if (record.recordType === 'assertion') {
172
+ if (record.predicate === 'wasDerivedFrom')
173
+ value.wasDerivedFrom.push({ generatedEntity: record.subjectId, usedEntity: record.objectId, evidence: record.evidenceIds });
174
+ else if (record.predicate === 'wasGeneratedBy')
175
+ value.wasGeneratedBy.push({ entity: record.subjectId, activity: record.objectId });
176
+ else if (record.predicate === 'used')
177
+ value.used.push({ activity: record.subjectId, entity: record.objectId, evidence: record.evidenceIds });
178
+ else if (record.predicate === 'wasAssociatedWith')
179
+ value.wasAssociatedWith.push({ activity: record.subjectId, agent: record.objectId });
180
+ else if (record.predicate === 'wasAttributedTo')
181
+ value.wasAttributedTo.push({ entity: record.subjectId, agent: record.objectId });
182
+ else
183
+ items.push(loss(`/records/${record.id}`, `predicate ${record.predicate} has no core W3C projection`, 'semantic'));
184
+ if (record.basis !== 'declared' || record.runId || record.field || record.retentionPolicy)
185
+ items.push({ ...loss(`/records/${record.id}/qualifiers`, 'core W3C relation view omits canonical basis, run, field, or retention qualifiers', 'information'), sourcePrivacy: record.privacy, ...(record.retentionPolicy ? { retentionPolicy: record.retentionPolicy } : {}) });
186
+ }
187
+ else if (record.recordType === 'correction' || record.recordType === 'supersession')
188
+ items.push(loss(`/records/${record.id}`, 'ledger history operation requires an extension namespace'));
189
+ }
190
+ return result('w3c-prov/core', value, items);
191
+ }
192
+ //# sourceMappingURL=projections.js.map
@@ -0,0 +1,71 @@
1
+ import { SchemaResolver } from '../schema/index.js';
2
+ import type { CompatibilityStatus } from '../schema/compatibility.js';
3
+ import type { SchemaBinding, DatasetDiagnostic, Digest } from './types.js';
4
+ export declare const DATASET_CONTRACT_SCHEMA_ID = "https://aiwg.io/schemas/dataset/dataset-contracts.v1.schema.json";
5
+ export declare const DATASET_GOVERNANCE_SCHEMA_ID = "https://aiwg.io/schemas/dataset/dataset-schema-governance.v1.schema.json";
6
+ export declare const DATASET_GOVERNANCE_VERSION: "aiwg.dataset-schema-governance/v1";
7
+ export type DatasetBoundary = 'adapter-config' | 'discovered-record' | 'checkpoint' | 'processing-plan' | 'processing-run' | 'run-receipt' | 'lineage' | 'exchange';
8
+ export interface DatasetSchemaCandidate {
9
+ schemaVersion: typeof DATASET_GOVERNANCE_VERSION;
10
+ kind: 'DatasetSchemaCandidate';
11
+ id: string;
12
+ status: 'candidate';
13
+ sourceRevisionId: string;
14
+ inferredSchema: Record<string, unknown>;
15
+ inferredSchemaDigest: Digest;
16
+ inference: {
17
+ method: string;
18
+ tool: string;
19
+ toolVersion: string;
20
+ runId?: string;
21
+ };
22
+ observedAt: string;
23
+ }
24
+ export interface DatasetSchemaPromotionReceipt {
25
+ schemaVersion: typeof DATASET_GOVERNANCE_VERSION;
26
+ kind: 'DatasetSchemaPromotionReceipt';
27
+ id: string;
28
+ status: 'promoted';
29
+ candidateId: string;
30
+ candidateDigest: Digest;
31
+ promotedSchema: Required<SchemaBinding>;
32
+ reviewer: string;
33
+ reviewedAt: string;
34
+ decisionEvidence: string;
35
+ compatibility: {
36
+ status: CompatibilityStatus;
37
+ baseline?: string;
38
+ reasons: string[];
39
+ };
40
+ }
41
+ export interface DatasetSchemaImpactTarget {
42
+ target: 'adapter' | 'checkpoint-state' | 'processing-plan' | 'index' | 'derived-artifact' | 'consumer';
43
+ disposition: 'compatible' | 'review-required' | 'migration-required';
44
+ reason: string;
45
+ }
46
+ export interface DatasetSchemaImpactReport {
47
+ schemaVersion: typeof DATASET_GOVERNANCE_VERSION;
48
+ kind: 'DatasetSchemaImpactReport';
49
+ schemaId: string;
50
+ baseline: string;
51
+ compatibility: {
52
+ status: CompatibilityStatus;
53
+ reasons: string[];
54
+ };
55
+ targets: DatasetSchemaImpactTarget[];
56
+ }
57
+ export type DatasetSchemaGovernanceRecord = DatasetSchemaCandidate | DatasetSchemaPromotionReceipt | DatasetSchemaImpactReport;
58
+ export declare function createDatasetSchemaCandidate(input: Omit<DatasetSchemaCandidate, 'schemaVersion' | 'kind' | 'status' | 'inferredSchemaDigest'>): DatasetSchemaCandidate;
59
+ export declare function promoteDatasetSchemaCandidate(candidate: DatasetSchemaCandidate, review: Omit<DatasetSchemaPromotionReceipt, 'schemaVersion' | 'kind' | 'status' | 'candidateId' | 'candidateDigest'>): DatasetSchemaPromotionReceipt;
60
+ export declare function assessDatasetSchemaImpact(schemaId: string, baseline: string, before: unknown, after: unknown): DatasetSchemaImpactReport;
61
+ export declare function validateDatasetGovernanceRecord(value: unknown): DatasetDiagnostic[];
62
+ /** Catalog-backed validation for every dataset trust boundary. */
63
+ export declare class DatasetBoundaryValidator {
64
+ readonly rootDir: string;
65
+ readonly resolver: SchemaResolver;
66
+ private readonly validator;
67
+ constructor(rootDir?: string);
68
+ validate(boundary: DatasetBoundary, binding: SchemaBinding, value: unknown): DatasetDiagnostic[];
69
+ validateBinding(boundary: DatasetBoundary, binding: SchemaBinding): DatasetDiagnostic[];
70
+ }
71
+ //# sourceMappingURL=schema-governance.d.ts.map
@@ -0,0 +1,135 @@
1
+ import { createHash } from 'node:crypto';
2
+ import { readFileSync } from 'node:fs';
3
+ import { dirname, join, resolve } from 'node:path';
4
+ import { fileURLToPath } from 'node:url';
5
+ import Ajv2020 from 'ajv/dist/2020.js';
6
+ import addFormats from 'ajv-formats';
7
+ import { analyzeBackwardCompatibility, loadSchemaCatalog, SchemaResolver, SchemaValidator } from '../schema/index.js';
8
+ export const DATASET_CONTRACT_SCHEMA_ID = 'https://aiwg.io/schemas/dataset/dataset-contracts.v1.schema.json';
9
+ export const DATASET_GOVERNANCE_SCHEMA_ID = 'https://aiwg.io/schemas/dataset/dataset-schema-governance.v1.schema.json';
10
+ export const DATASET_GOVERNANCE_VERSION = 'aiwg.dataset-schema-governance/v1';
11
+ function packageRoot(start) {
12
+ let current = resolve(start);
13
+ for (;;) {
14
+ try {
15
+ const pkg = JSON.parse(readFileSync(join(current, 'package.json'), 'utf8'));
16
+ // The release packager renames the installed package to `@aiwg/cli`.
17
+ // Keep schema lookup valid in both the source and packaged layouts.
18
+ if (pkg.name === 'aiwg' || pkg.name === '@aiwg/cli')
19
+ return current;
20
+ }
21
+ catch { /* keep walking */ }
22
+ const parent = dirname(current);
23
+ if (parent === current)
24
+ throw new Error('dataset schema governance: could not locate package root');
25
+ current = parent;
26
+ }
27
+ }
28
+ const defaultRoot = packageRoot(dirname(fileURLToPath(import.meta.url)));
29
+ const governanceSchema = JSON.parse(readFileSync(join(defaultRoot, 'schemas/dataset/dataset-schema-governance.v1.schema.json'), 'utf8'));
30
+ const governanceAjv = new Ajv2020({ strict: true, allErrors: true });
31
+ addFormats(governanceAjv);
32
+ const validateGovernanceSchema = governanceAjv.compile(governanceSchema);
33
+ function diagnostic(code, message, path) {
34
+ return { code, message, ...(path ? { path } : {}) };
35
+ }
36
+ function sha256(value) {
37
+ const canonical = JSON.stringify(canonicalize(value));
38
+ return { algorithm: 'sha256', value: createHash('sha256').update(canonical).digest('hex') };
39
+ }
40
+ function canonicalize(value) {
41
+ if (Array.isArray(value))
42
+ return value.map(canonicalize);
43
+ if (typeof value !== 'object' || value === null)
44
+ return value;
45
+ return Object.fromEntries(Object.keys(value).sort().map(key => [key, canonicalize(value[key])]));
46
+ }
47
+ export function createDatasetSchemaCandidate(input) {
48
+ return {
49
+ schemaVersion: DATASET_GOVERNANCE_VERSION,
50
+ kind: 'DatasetSchemaCandidate',
51
+ status: 'candidate',
52
+ ...input,
53
+ inferredSchemaDigest: sha256(input.inferredSchema),
54
+ };
55
+ }
56
+ export function promoteDatasetSchemaCandidate(candidate, review) {
57
+ if (candidate.status !== 'candidate')
58
+ throw new Error('DATASET_SCHEMA_NOT_CANDIDATE');
59
+ const actual = sha256(candidate.inferredSchema);
60
+ if (actual.value !== candidate.inferredSchemaDigest.value)
61
+ throw new Error('DATASET_SCHEMA_CANDIDATE_DIGEST_MISMATCH');
62
+ if (!review.reviewer || !review.decisionEvidence)
63
+ throw new Error('DATASET_SCHEMA_REVIEW_REQUIRED');
64
+ if (!review.promotedSchema.digest)
65
+ throw new Error('DATASET_SCHEMA_BINDING_DIGEST_REQUIRED');
66
+ if (review.compatibility.status === 'unknown' && review.compatibility.reasons.length === 0)
67
+ throw new Error('DATASET_SCHEMA_COMPATIBILITY_EVIDENCE_REQUIRED');
68
+ return {
69
+ schemaVersion: DATASET_GOVERNANCE_VERSION,
70
+ kind: 'DatasetSchemaPromotionReceipt',
71
+ status: 'promoted',
72
+ candidateId: candidate.id,
73
+ candidateDigest: candidate.inferredSchemaDigest,
74
+ ...review,
75
+ };
76
+ }
77
+ export function assessDatasetSchemaImpact(schemaId, baseline, before, after) {
78
+ const compatibility = analyzeBackwardCompatibility(before, after);
79
+ const disposition = compatibility.status === 'compatible' ? 'compatible' : compatibility.status === 'breaking' ? 'migration-required' : 'review-required';
80
+ const targets = ['adapter', 'checkpoint-state', 'processing-plan', 'index', 'derived-artifact', 'consumer'];
81
+ return {
82
+ schemaVersion: DATASET_GOVERNANCE_VERSION,
83
+ kind: 'DatasetSchemaImpactReport',
84
+ schemaId,
85
+ baseline,
86
+ compatibility: { status: compatibility.status, reasons: compatibility.reasons },
87
+ targets: targets.map(target => ({ target, disposition, reason: `${target} must be assessed against ${schemaId}; ${compatibility.reasons.join('; ')}` })),
88
+ };
89
+ }
90
+ export function validateDatasetGovernanceRecord(value) {
91
+ const valid = validateGovernanceSchema(value);
92
+ if (!valid)
93
+ return (validateGovernanceSchema.errors ?? []).map((error) => diagnostic('DATASET_GOVERNANCE_SCHEMA_INVALID', error.message ?? 'governance record is invalid', error.instancePath || '/'));
94
+ const record = value;
95
+ if (record.kind === 'DatasetSchemaCandidate') {
96
+ const actual = sha256(record.inferredSchema);
97
+ if (actual.value !== record.inferredSchemaDigest.value)
98
+ return [diagnostic('DATASET_SCHEMA_CANDIDATE_DIGEST_MISMATCH', 'candidate digest does not match the inferred schema', '/inferredSchemaDigest')];
99
+ }
100
+ return [];
101
+ }
102
+ /** Catalog-backed validation for every dataset trust boundary. */
103
+ export class DatasetBoundaryValidator {
104
+ rootDir;
105
+ resolver;
106
+ validator;
107
+ constructor(rootDir = defaultRoot) {
108
+ this.rootDir = rootDir;
109
+ const loaded = loadSchemaCatalog({ rootDir });
110
+ if (!loaded.valid || !loaded.catalog)
111
+ throw new Error(`DATASET_SCHEMA_CATALOG_INVALID: ${loaded.diagnostics.map(item => item.code).join(',')}`);
112
+ this.resolver = new SchemaResolver(loaded.catalog, { rootDir });
113
+ this.validator = new SchemaValidator(this.resolver, { rootDir });
114
+ }
115
+ validate(boundary, binding, value) {
116
+ const bindingDiagnostics = this.validateBinding(boundary, binding);
117
+ if (bindingDiagnostics.length)
118
+ return bindingDiagnostics;
119
+ return this.validator.validate(binding.id, value).diagnostics.map(item => diagnostic(item.code, item.message, item.path));
120
+ }
121
+ validateBinding(boundary, binding) {
122
+ const entry = this.resolver.resolve(binding.id);
123
+ if (!entry)
124
+ return [diagnostic('DATASET_SCHEMA_BINDING_UNKNOWN', `unknown schema binding ${binding.id}`, '/schema/id')];
125
+ if (binding.version !== entry.artifact.version)
126
+ return [diagnostic('DATASET_SCHEMA_BINDING_VERSION_MISMATCH', `schema binding version ${binding.version} does not match governed version ${entry.artifact.version}`, '/schema/version')];
127
+ if (!binding.digest)
128
+ return [diagnostic('DATASET_SCHEMA_BINDING_DIGEST_REQUIRED', `schema digest is required at ${boundary} boundary`, '/schema/digest')];
129
+ const expected = entry.digest?.replace(/^sha256:/, '');
130
+ if (!expected || binding.digest.algorithm !== 'sha256' || binding.digest.value !== expected)
131
+ return [diagnostic('DATASET_SCHEMA_BINDING_DIGEST_MISMATCH', `schema digest does not match governed authority at ${boundary} boundary`, '/schema/digest')];
132
+ return [];
133
+ }
134
+ }
135
+ //# sourceMappingURL=schema-governance.js.map
@@ -0,0 +1,66 @@
1
+ import type { RunLedgerSnapshot } from './ledger-types.js';
2
+ export declare const STANDARDS_EXCHANGE_VERSION: "aiwg.dataset-standards-exchange/v1";
3
+ export type StandardId = 'w3c-prov-json' | 'openlineage' | 'dcat' | 'croissant' | 'data-package' | 'ro-crate';
4
+ export type ProfileDirection = 'import' | 'export' | 'round-trip';
5
+ export type ProfileMaturity = 'stable' | 'candidate' | 'descriptor-only';
6
+ export type UnknownExtensionPolicy = 'preserve' | 'report' | 'reject';
7
+ export interface GovernedSchemaReference {
8
+ id: string;
9
+ version: string;
10
+ }
11
+ export interface StandardsProfileDescriptor {
12
+ id: string;
13
+ standard: StandardId;
14
+ version: string;
15
+ direction: ProfileDirection;
16
+ inputSchema: GovernedSchemaReference;
17
+ outputSchema: GovernedSchemaReference;
18
+ mappingImplementation: string;
19
+ supportedFeatures: readonly string[];
20
+ roundTripFields: readonly string[];
21
+ extensionNamespace: string;
22
+ unknownExtensionPolicy: UnknownExtensionPolicy;
23
+ maturity: ProfileMaturity;
24
+ useCases: readonly string[];
25
+ coverageBoundary: string;
26
+ }
27
+ export type LossCategory = 'mapped' | 'omitted' | 'synthesized' | 'unsupported' | 'extension-carried';
28
+ export interface StandardsLossItem {
29
+ category: LossCategory;
30
+ sourcePath?: string;
31
+ targetPath?: string;
32
+ reason: string;
33
+ extensionNamespace?: string;
34
+ }
35
+ export interface StandardsLossReport {
36
+ schemaVersion: typeof STANDARDS_EXCHANGE_VERSION;
37
+ profileId: string;
38
+ profileVersion: string;
39
+ direction: 'import' | 'export';
40
+ sourceDigest: {
41
+ algorithm: 'sha256';
42
+ value: string;
43
+ };
44
+ items: StandardsLossItem[];
45
+ counts: Record<LossCategory, number>;
46
+ }
47
+ export interface StandardsExchange<T> {
48
+ schemaVersion: typeof STANDARDS_EXCHANGE_VERSION;
49
+ profile: {
50
+ id: string;
51
+ version: string;
52
+ };
53
+ value: T;
54
+ loss: StandardsLossReport;
55
+ }
56
+ export interface StandardAdapter {
57
+ descriptor: StandardsProfileDescriptor;
58
+ importDocument(document: unknown): StandardsExchange<RunLedgerSnapshot>;
59
+ exportDocument(snapshot: RunLedgerSnapshot): StandardsExchange<unknown>;
60
+ }
61
+ export type StandardsDiagnosticCode = 'DATASET_STANDARD_PROFILE_NOT_FOUND' | 'DATASET_STANDARD_UNSUPPORTED_VERSION' | 'DATASET_STANDARD_UNSUPPORTED_CAPABILITY' | 'DATASET_STANDARD_INVALID_INPUT' | 'DATASET_STANDARD_INVALID_OUTPUT' | 'DATASET_STANDARD_EXTENSION_COLLISION' | 'DATASET_STANDARD_IDENTITY_CONFLICT' | 'DATASET_STANDARD_EVIDENCE_ESCALATION';
62
+ export declare class StandardsProfileError extends Error {
63
+ readonly code: StandardsDiagnosticCode;
64
+ constructor(code: StandardsDiagnosticCode, message: string);
65
+ }
66
+ //# sourceMappingURL=standards-types.d.ts.map
@@ -0,0 +1,10 @@
1
+ export const STANDARDS_EXCHANGE_VERSION = 'aiwg.dataset-standards-exchange/v1';
2
+ export class StandardsProfileError extends Error {
3
+ code;
4
+ constructor(code, message) {
5
+ super(`${code}: ${message}`);
6
+ this.code = code;
7
+ this.name = 'StandardsProfileError';
8
+ }
9
+ }
10
+ //# sourceMappingURL=standards-types.js.map
@@ -0,0 +1,13 @@
1
+ import type { RunLedgerSnapshot } from './ledger-types.js';
2
+ import { type StandardAdapter, type StandardId, type StandardsExchange, type StandardsProfileDescriptor } from './standards-types.js';
3
+ export declare const PROV_PROFILE: StandardsProfileDescriptor;
4
+ export declare const OPENLINEAGE_PROFILE: StandardsProfileDescriptor;
5
+ export declare const DESCRIPTOR_ONLY_PROFILES: readonly StandardsProfileDescriptor[];
6
+ export declare const provAdapter: StandardAdapter;
7
+ export declare const openLineageAdapter: StandardAdapter;
8
+ export declare const standardsProfiles: readonly StandardsProfileDescriptor[];
9
+ export declare function listStandardsProfiles(): readonly StandardsProfileDescriptor[];
10
+ export declare function resolveStandardsProfile(standard: StandardId, version: string, capability?: 'import' | 'export'): StandardAdapter;
11
+ export declare function importStandard(standard: StandardId, version: string, document: unknown): StandardsExchange<RunLedgerSnapshot>;
12
+ export declare function exportStandard(standard: StandardId, version: string, snapshot: RunLedgerSnapshot): StandardsExchange<unknown>;
13
+ //# sourceMappingURL=standards.d.ts.map