archctx-contracts 0.6.2 → 0.7.0

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 (29) hide show
  1. package/fixtures/invalid/recommendation-v3-structural-before-evidence.json +59 -0
  2. package/fixtures/valid/archctx-capabilities.json +3 -3
  3. package/fixtures/valid/product-version-manifest.json +6 -6
  4. package/fixtures/valid/projection-manifest.json +175 -0
  5. package/fixtures/valid/projection-result.json +5 -5
  6. package/fixtures/valid/recommendation-v3.json +69 -0
  7. package/fixtures/valid/runtime-recommendation-show.json +312 -0
  8. package/fixtures/valid/runtime-refactor-scan.json +542 -0
  9. package/package.json +1 -1
  10. package/schemas/runtime/archctx-capabilities.schema.json +7 -2
  11. package/schemas/runtime/architecture-refresh-signal.schema.json +27 -0
  12. package/schemas/runtime/changeset.schema.json +42 -16
  13. package/schemas/runtime/projection-apply-readback.schema.json +351 -10
  14. package/schemas/runtime/projection-apply-recovery.schema.json +24 -3
  15. package/schemas/runtime/projection-manifest.schema.json +491 -0
  16. package/schemas/runtime/projection-request.schema.json +11 -2
  17. package/schemas/runtime/projection-result.schema.json +108 -8
  18. package/schemas/runtime/recommendation-v3.schema.json +1166 -0
  19. package/schemas/runtime/runtime-recommendation-show.schema.json +2449 -0
  20. package/schemas/runtime/runtime-refactor-scan.schema.json +2489 -0
  21. package/schemas/runtime/structural-observation-payload.schema.json +578 -0
  22. package/src/index.ts +1 -0
  23. package/src/ledger.ts +26 -10
  24. package/src/product-version.ts +2 -2
  25. package/src/projection-manifest.ts +346 -0
  26. package/src/projection.ts +338 -6
  27. package/src/refactor.ts +268 -1
  28. package/src/schema.ts +20 -4
  29. package/src/validator.ts +87 -15
@@ -0,0 +1,578 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://archcontext.dev/schemas/runtime/structural-observation-payload.schema.json",
4
+ "title": "StructuralObservationPayloadV1",
5
+ "type": "object",
6
+ "additionalProperties": false,
7
+ "required": [
8
+ "assessmentDigest",
9
+ "kind",
10
+ "affectedNodeIds",
11
+ "baselineSnapshotDigest",
12
+ "derivedOutcomes",
13
+ "metrics",
14
+ "signalIds",
15
+ "evidence"
16
+ ],
17
+ "properties": {
18
+ "assessmentDigest": {
19
+ "$ref": "#/$defs/sha256"
20
+ },
21
+ "kind": {
22
+ "enum": [
23
+ "cycle",
24
+ "direction-violation",
25
+ "evidence-gap",
26
+ "ownership-ambiguous",
27
+ "undeclared-footprint",
28
+ "unowned-paths"
29
+ ]
30
+ },
31
+ "affectedNodeIds": {
32
+ "type": "array",
33
+ "items": {
34
+ "type": "string"
35
+ }
36
+ },
37
+ "baselineSnapshotDigest": {
38
+ "$ref": "#/$defs/sha256"
39
+ },
40
+ "derivedOutcomes": {
41
+ "type": "array",
42
+ "items": {
43
+ "$ref": "#/$defs/targetOutcome"
44
+ }
45
+ },
46
+ "metrics": {
47
+ "$ref": "#/$defs/observationMetrics"
48
+ },
49
+ "signalIds": {
50
+ "type": "array",
51
+ "uniqueItems": true,
52
+ "items": {
53
+ "type": "string"
54
+ }
55
+ },
56
+ "evidence": {
57
+ "$ref": "#/$defs/observationEvidence"
58
+ }
59
+ },
60
+ "allOf": [
61
+ {
62
+ "if": {
63
+ "properties": {
64
+ "kind": {
65
+ "const": "cycle"
66
+ }
67
+ }
68
+ },
69
+ "then": {
70
+ "properties": {
71
+ "evidence": {
72
+ "properties": {
73
+ "kind": {
74
+ "const": "cycle"
75
+ }
76
+ }
77
+ }
78
+ }
79
+ }
80
+ },
81
+ {
82
+ "if": {
83
+ "properties": {
84
+ "kind": {
85
+ "const": "direction-violation"
86
+ }
87
+ }
88
+ },
89
+ "then": {
90
+ "properties": {
91
+ "evidence": {
92
+ "properties": {
93
+ "kind": {
94
+ "const": "direction-violation"
95
+ }
96
+ }
97
+ }
98
+ }
99
+ }
100
+ },
101
+ {
102
+ "if": {
103
+ "properties": {
104
+ "kind": {
105
+ "const": "evidence-gap"
106
+ }
107
+ }
108
+ },
109
+ "then": {
110
+ "properties": {
111
+ "evidence": {
112
+ "properties": {
113
+ "kind": {
114
+ "const": "evidence-gap"
115
+ }
116
+ }
117
+ }
118
+ }
119
+ }
120
+ },
121
+ {
122
+ "if": {
123
+ "properties": {
124
+ "kind": {
125
+ "const": "ownership-ambiguous"
126
+ }
127
+ }
128
+ },
129
+ "then": {
130
+ "properties": {
131
+ "evidence": {
132
+ "properties": {
133
+ "kind": {
134
+ "const": "ownership-ambiguous"
135
+ }
136
+ }
137
+ }
138
+ }
139
+ }
140
+ },
141
+ {
142
+ "if": {
143
+ "properties": {
144
+ "kind": {
145
+ "const": "undeclared-footprint"
146
+ }
147
+ }
148
+ },
149
+ "then": {
150
+ "properties": {
151
+ "evidence": {
152
+ "properties": {
153
+ "kind": {
154
+ "const": "undeclared-footprint"
155
+ }
156
+ }
157
+ }
158
+ }
159
+ }
160
+ },
161
+ {
162
+ "if": {
163
+ "properties": {
164
+ "kind": {
165
+ "const": "unowned-paths"
166
+ }
167
+ }
168
+ },
169
+ "then": {
170
+ "properties": {
171
+ "evidence": {
172
+ "properties": {
173
+ "kind": {
174
+ "const": "unowned-paths"
175
+ }
176
+ }
177
+ }
178
+ }
179
+ }
180
+ }
181
+ ],
182
+ "$defs": {
183
+ "sha256": {
184
+ "type": "string",
185
+ "pattern": "^sha256:[a-f0-9]{64}$"
186
+ },
187
+ "repoRelativePath": {
188
+ "type": "string",
189
+ "minLength": 1,
190
+ "pattern": "^(?!/)(?!.*\\\\)(?!(?:.*/)?\\.\\.(?:/|$)).+$"
191
+ },
192
+ "evidenceLine": {
193
+ "type": [
194
+ "integer",
195
+ "null"
196
+ ],
197
+ "minimum": 1
198
+ },
199
+ "evidenceSpecifier": {
200
+ "type": "string",
201
+ "minLength": 1,
202
+ "maxLength": 512,
203
+ "pattern": "^[^\\u0000-\\u001f\\u007f]+$"
204
+ },
205
+ "evidenceIdList": {
206
+ "type": "array",
207
+ "maxItems": 32,
208
+ "uniqueItems": true,
209
+ "items": {
210
+ "type": "string"
211
+ }
212
+ },
213
+ "observationMetrics": {
214
+ "type": "object",
215
+ "additionalProperties": {
216
+ "type": [
217
+ "number",
218
+ "null"
219
+ ]
220
+ }
221
+ },
222
+ "evidenceImportEdge": {
223
+ "type": "object",
224
+ "additionalProperties": false,
225
+ "required": [
226
+ "fromPath",
227
+ "fromLine",
228
+ "toPath",
229
+ "specifier",
230
+ "fromNodeId",
231
+ "toNodeId"
232
+ ],
233
+ "properties": {
234
+ "fromPath": {
235
+ "$ref": "#/$defs/repoRelativePath"
236
+ },
237
+ "fromLine": {
238
+ "$ref": "#/$defs/evidenceLine"
239
+ },
240
+ "toPath": {
241
+ "$ref": "#/$defs/repoRelativePath"
242
+ },
243
+ "specifier": {
244
+ "$ref": "#/$defs/evidenceSpecifier"
245
+ },
246
+ "fromNodeId": {
247
+ "type": "string",
248
+ "minLength": 1,
249
+ "pattern": "\\S"
250
+ },
251
+ "toNodeId": {
252
+ "type": "string",
253
+ "minLength": 1,
254
+ "pattern": "\\S"
255
+ }
256
+ }
257
+ },
258
+ "evidenceDirectionViolation": {
259
+ "type": "object",
260
+ "additionalProperties": false,
261
+ "required": [
262
+ "fromPath",
263
+ "fromLine",
264
+ "toPath",
265
+ "specifier",
266
+ "fromNodeId",
267
+ "toNodeId",
268
+ "constraintId"
269
+ ],
270
+ "properties": {
271
+ "fromPath": {
272
+ "$ref": "#/$defs/repoRelativePath"
273
+ },
274
+ "fromLine": {
275
+ "$ref": "#/$defs/evidenceLine"
276
+ },
277
+ "toPath": {
278
+ "$ref": "#/$defs/repoRelativePath"
279
+ },
280
+ "specifier": {
281
+ "$ref": "#/$defs/evidenceSpecifier"
282
+ },
283
+ "fromNodeId": {
284
+ "type": "string",
285
+ "minLength": 1,
286
+ "pattern": "\\S"
287
+ },
288
+ "toNodeId": {
289
+ "type": "string",
290
+ "minLength": 1,
291
+ "pattern": "\\S"
292
+ },
293
+ "constraintId": {
294
+ "type": "string"
295
+ }
296
+ }
297
+ },
298
+ "evidencePath": {
299
+ "type": "object",
300
+ "additionalProperties": false,
301
+ "required": [
302
+ "path",
303
+ "candidateOwnerNodeIds",
304
+ "candidateOwnerCount"
305
+ ],
306
+ "properties": {
307
+ "path": {
308
+ "$ref": "#/$defs/repoRelativePath"
309
+ },
310
+ "candidateOwnerNodeIds": {
311
+ "$ref": "#/$defs/evidenceIdList"
312
+ },
313
+ "candidateOwnerCount": {
314
+ "type": "integer",
315
+ "minimum": 0
316
+ }
317
+ }
318
+ },
319
+ "evidenceUnresolvedImport": {
320
+ "type": "object",
321
+ "additionalProperties": false,
322
+ "required": [
323
+ "fromPath",
324
+ "fromLine",
325
+ "specifier"
326
+ ],
327
+ "properties": {
328
+ "fromPath": {
329
+ "$ref": "#/$defs/repoRelativePath"
330
+ },
331
+ "fromLine": {
332
+ "$ref": "#/$defs/evidenceLine"
333
+ },
334
+ "specifier": {
335
+ "$ref": "#/$defs/evidenceSpecifier"
336
+ }
337
+ }
338
+ },
339
+ "observationEvidence": {
340
+ "oneOf": [
341
+ {
342
+ "type": "object",
343
+ "additionalProperties": false,
344
+ "required": [
345
+ "kind",
346
+ "memberNodeIds",
347
+ "edges",
348
+ "totalCount",
349
+ "truncated"
350
+ ],
351
+ "properties": {
352
+ "kind": {
353
+ "const": "cycle"
354
+ },
355
+ "memberNodeIds": {
356
+ "$ref": "#/$defs/evidenceIdList"
357
+ },
358
+ "edges": {
359
+ "type": "array",
360
+ "maxItems": 20,
361
+ "items": {
362
+ "$ref": "#/$defs/evidenceImportEdge"
363
+ }
364
+ },
365
+ "totalCount": {
366
+ "type": "integer",
367
+ "minimum": 0
368
+ },
369
+ "truncated": {
370
+ "type": "boolean"
371
+ }
372
+ }
373
+ },
374
+ {
375
+ "type": "object",
376
+ "additionalProperties": false,
377
+ "required": [
378
+ "kind",
379
+ "constraintIds",
380
+ "constraintCount",
381
+ "violations",
382
+ "totalCount",
383
+ "truncated"
384
+ ],
385
+ "properties": {
386
+ "kind": {
387
+ "const": "direction-violation"
388
+ },
389
+ "constraintIds": {
390
+ "$ref": "#/$defs/evidenceIdList"
391
+ },
392
+ "constraintCount": {
393
+ "type": "integer",
394
+ "minimum": 0
395
+ },
396
+ "violations": {
397
+ "type": "array",
398
+ "maxItems": 20,
399
+ "items": {
400
+ "$ref": "#/$defs/evidenceDirectionViolation"
401
+ }
402
+ },
403
+ "totalCount": {
404
+ "type": "integer",
405
+ "minimum": 0
406
+ },
407
+ "truncated": {
408
+ "type": "boolean"
409
+ }
410
+ }
411
+ },
412
+ {
413
+ "type": "object",
414
+ "additionalProperties": false,
415
+ "required": [
416
+ "kind",
417
+ "paths",
418
+ "totalCount",
419
+ "truncated"
420
+ ],
421
+ "properties": {
422
+ "kind": {
423
+ "enum": [
424
+ "ownership-ambiguous",
425
+ "undeclared-footprint",
426
+ "unowned-paths"
427
+ ]
428
+ },
429
+ "paths": {
430
+ "type": "array",
431
+ "maxItems": 20,
432
+ "items": {
433
+ "$ref": "#/$defs/evidencePath"
434
+ }
435
+ },
436
+ "totalCount": {
437
+ "type": "integer",
438
+ "minimum": 0
439
+ },
440
+ "truncated": {
441
+ "type": "boolean"
442
+ }
443
+ }
444
+ },
445
+ {
446
+ "type": "object",
447
+ "additionalProperties": false,
448
+ "required": [
449
+ "kind",
450
+ "coverage",
451
+ "reasonCodes",
452
+ "unresolvedImports",
453
+ "totalCount",
454
+ "truncated"
455
+ ],
456
+ "properties": {
457
+ "kind": {
458
+ "const": "evidence-gap"
459
+ },
460
+ "coverage": {
461
+ "enum": [
462
+ "complete",
463
+ "partial",
464
+ "unknown"
465
+ ]
466
+ },
467
+ "reasonCodes": {
468
+ "type": "array",
469
+ "uniqueItems": true,
470
+ "items": {
471
+ "enum": [
472
+ "caller-coverage-unknown",
473
+ "code-facts-missing",
474
+ "code-facts-truncated",
475
+ "major-change-detected",
476
+ "multi-node-scope",
477
+ "node-footprint-undeclared",
478
+ "ownership-ambiguous",
479
+ "single-node-scope",
480
+ "target-unresolved",
481
+ "unowned-paths"
482
+ ]
483
+ }
484
+ },
485
+ "unresolvedImports": {
486
+ "type": "array",
487
+ "maxItems": 20,
488
+ "items": {
489
+ "$ref": "#/$defs/evidenceUnresolvedImport"
490
+ }
491
+ },
492
+ "totalCount": {
493
+ "type": "integer",
494
+ "minimum": 0
495
+ },
496
+ "truncated": {
497
+ "type": "boolean"
498
+ }
499
+ }
500
+ }
501
+ ]
502
+ },
503
+ "targetOutcome": {
504
+ "type": "object",
505
+ "additionalProperties": false,
506
+ "required": [
507
+ "outcomeId",
508
+ "metric",
509
+ "subjectSelectorId",
510
+ "nodeId",
511
+ "operator",
512
+ "value",
513
+ "required"
514
+ ],
515
+ "properties": {
516
+ "outcomeId": {
517
+ "type": "string"
518
+ },
519
+ "metric": {
520
+ "type": "string",
521
+ "minLength": 1,
522
+ "pattern": "\\S"
523
+ },
524
+ "subjectSelectorId": {
525
+ "type": "string"
526
+ },
527
+ "nodeId": {
528
+ "type": [
529
+ "string",
530
+ "null"
531
+ ]
532
+ },
533
+ "operator": {
534
+ "enum": [
535
+ "absent",
536
+ "equals",
537
+ "greater_than",
538
+ "less_than",
539
+ "present"
540
+ ]
541
+ },
542
+ "value": {
543
+ "type": [
544
+ "number",
545
+ "null"
546
+ ]
547
+ },
548
+ "required": {
549
+ "type": "boolean"
550
+ }
551
+ },
552
+ "if": {
553
+ "properties": {
554
+ "operator": {
555
+ "enum": [
556
+ "absent",
557
+ "present"
558
+ ]
559
+ }
560
+ }
561
+ },
562
+ "then": {
563
+ "properties": {
564
+ "value": {
565
+ "type": "null"
566
+ }
567
+ }
568
+ },
569
+ "else": {
570
+ "properties": {
571
+ "value": {
572
+ "type": "number"
573
+ }
574
+ }
575
+ }
576
+ }
577
+ }
578
+ }
package/src/index.ts CHANGED
@@ -6,6 +6,7 @@ export * from "./ledger";
6
6
  export * from "./ports";
7
7
  export * from "./practices";
8
8
  export * from "./projection";
9
+ export * from "./projection-manifest";
9
10
  export * from "./product-version";
10
11
  export * from "./refactor";
11
12
  export * from "./schema";
package/src/ledger.ts CHANGED
@@ -2,6 +2,7 @@ import type { ArchitectureMajorChangeReasonCode } from "./projection";
2
2
  import type {
3
3
  ArchitectureTargetDeltaV1,
4
4
  RefactorKillListEntryV1,
5
+ RefactorObservationEvidenceV1,
5
6
  RefactorObservationKind,
6
7
  RefactorScale,
7
8
  RefactorTargetOutcomeV1
@@ -30,16 +31,18 @@ export type ArchitectureLedgerMode = "yaml" | "dual" | "dual-compare" | "ledger-
30
31
  export type ArchitectureActorKind = "developer" | "daemon" | "hook" | "cli" | "mcp" | "subagent" | "migration" | "system";
31
32
  export type ArchitectureActorSource = "cli" | "mcp" | "manual" | "daemon" | "system" | "subagent";
32
33
  export type RecommendationCategory = (typeof RECOMMENDATION_CATEGORIES)[number];
33
- export type RecommendationStatus =
34
- | "open"
35
- | "acknowledged"
36
- | "accepted"
37
- | "rejected"
38
- | "deferred"
39
- | "waived"
40
- | "resolved"
41
- | "superseded"
42
- | "expired";
34
+ export const RECOMMENDATION_STATUSES = [
35
+ "open",
36
+ "acknowledged",
37
+ "accepted",
38
+ "rejected",
39
+ "deferred",
40
+ "waived",
41
+ "resolved",
42
+ "superseded",
43
+ "expired"
44
+ ] as const;
45
+ export type RecommendationStatus = (typeof RECOMMENDATION_STATUSES)[number];
43
46
  export type ArchitectureEventSource =
44
47
  | "prepare_task"
45
48
  | "checkpoint"
@@ -695,12 +698,25 @@ export interface PracticeRecommendationPayloadV1 {
695
698
  baselineDigest: string | null;
696
699
  }
697
700
 
701
+ /**
702
+ * Self-contained: `metrics`, `signalIds` and `evidence` are copied verbatim from the assessed
703
+ * `RefactorObservationV1`, so a reader never has to join a recorded record back to an in-memory
704
+ * assessment by kind and subject. None of them is part of the fingerprint.
705
+ *
706
+ * A record written by archctx 0.6.3 or earlier (before #262) has none of the three, and the ledger
707
+ * keeps it as written, so `recommendations show` and `list` can return it. A reader detects such a
708
+ * record by the absence of `evidence`. It does not validate against
709
+ * `schemas/runtime/recommendation-v3.schema.json`, which describes the record 0.7.0 writes.
710
+ */
698
711
  export interface StructuralObservationPayloadV1 {
699
712
  assessmentDigest: string;
700
713
  kind: RefactorObservationKind;
701
714
  affectedNodeIds: string[];
702
715
  baselineSnapshotDigest: string;
703
716
  derivedOutcomes: RefactorTargetOutcomeV1[];
717
+ metrics: Record<string, number | null>;
718
+ signalIds: string[];
719
+ evidence: RefactorObservationEvidenceV1;
704
720
  }
705
721
 
706
722
  export interface RefactorProposalPayloadV1 {
@@ -1,6 +1,6 @@
1
1
  export const ARCHCONTEXT_PRODUCT_NAME = "archctx";
2
- export const ARCHCONTEXT_PRODUCT_VERSION = "0.6.2";
3
- export const ARCHCONTEXT_PACKAGE_MANAGER = "bun@1.4.0";
2
+ export const ARCHCONTEXT_PRODUCT_VERSION = "0.7.0";
3
+ export const ARCHCONTEXT_PACKAGE_MANAGER = "bun@1.4.3";
4
4
  export const ARCHCONTEXT_NODE_RANGE = ">=22.22 <26";
5
5
  export const LOCAL_RUNTIME_RPC_SCHEMA_VERSION = "archcontext.runtime-rpc/v1";
6
6
  export const ARCHCONTEXT_SCHEMA_SET_VERSION = "2026-07-11.explorer-view-v2";