shapeup-sdlc 1.6.3 → 1.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 (85) hide show
  1. package/.claude-plugin/plugin.json +1 -1
  2. package/AGENTS.md +36 -103
  3. package/README.md +60 -67
  4. package/SECURITY.md +31 -16
  5. package/bin/init.mjs +24 -69
  6. package/commands/build.md +19 -0
  7. package/commands/eval.md +5 -4
  8. package/commands/scopes.md +5 -4
  9. package/commands/shape.md +1 -1
  10. package/commands/ship.md +37 -4
  11. package/hooks/anti-rationalization.mjs +7 -13
  12. package/hooks/compact-snapshot.mjs +5 -5
  13. package/hooks/gate-deadline.mjs +12 -16
  14. package/hooks/gate-intake.mjs +13 -14
  15. package/hooks/gate-l2.mjs +3 -3
  16. package/hooks/gate-zerowork.mjs +97 -16
  17. package/hooks/lib/decision.mjs +21 -13
  18. package/hooks/safety-spine.mjs +1 -1
  19. package/hooks/sandbox-guard.mjs +83 -47
  20. package/hooks/session-rehydrate.mjs +8 -9
  21. package/hooks/slop-cleaner.mjs +1 -1
  22. package/oracles/_shared.mjs +1 -1
  23. package/oracles/http-oracle.mjs +1 -1
  24. package/oracles/index.mjs +1 -1
  25. package/oracles/process-oracle.mjs +1 -1
  26. package/oracles/snapshot-oracle.mjs +1 -1
  27. package/oracles/test-oracle.mjs +1 -1
  28. package/package.json +3 -7
  29. package/skills/ba-pitch-analyzer/SKILL.md +20 -15
  30. package/skills/ba-pitch-analyzer/references/doc-schemas.md +1 -1
  31. package/skills/ba-pitch-analyzer/references/task-generation.md +6 -6
  32. package/skills/ba-pitch-analyzer/references/test-surface.md +1 -1
  33. package/skills/ba-pitch-analyzer/scripts/board-derive.mjs +5 -5
  34. package/skills/ba-pitch-analyzer/scripts/spec-lint.mjs +2 -2
  35. package/skills/coach/SKILL.md +3 -3
  36. package/skills/orient/SKILL.md +2 -1
  37. package/skills/qa-edge-hunter/SKILL.md +9 -39
  38. package/skills/scope-architect/SKILL.md +17 -12
  39. package/skills/scope-hammer/SKILL.md +5 -5
  40. package/skills/shapeup/SKILL.md +3 -3
  41. package/skills/shapeup/resources/context-compaction.md +4 -3
  42. package/skills/solution-architect/SKILL.md +18 -11
  43. package/skills/spec-evaluator/SKILL.md +12 -5
  44. package/skills/spec-evaluator/references/dimensions/_registry.md +2 -2
  45. package/skills/spec-evaluator/references/dimensions/completeness.md +1 -1
  46. package/skills/spec-evaluator/references/dimensions/integration.md +98 -67
  47. package/skills/spec-evaluator/references/dimensions/spec-conformance.md +4 -4
  48. package/skills/spec-evaluator/references/dimensions/test-surface-conformance.md +1 -1
  49. package/skills/spec-evaluator/references/probing.md +42 -23
  50. package/skills/spec-evaluator/references/report-schema.md +2 -2
  51. package/skills/spec-evaluator/scripts/verdict-ledger.mjs +1 -1
  52. package/skills/task-executor/SKILL.md +25 -12
  53. package/skills/tech-lead/SKILL.md +115 -438
  54. package/skills/tech-lead/references/delegation.md +38 -31
  55. package/skills/tech-lead/references/gates.md +75 -33
  56. package/skills/tech-lead/references/hard-rules.md +34 -0
  57. package/skills/tech-lead/references/invocation.md +2 -2
  58. package/skills/tech-lead/references/ledger-schema.md +17 -18
  59. package/skills/tech-lead/references/round-protocol.md +77 -27
  60. package/skills/tech-lead/references/state-model.md +1 -1
  61. package/skills/tech-lead/schemas/domain.schema.json +320 -148
  62. package/skills/tech-lead/schemas/gate-answers.schema.json +2 -2
  63. package/skills/tech-lead/schemas/work-result.schema.json +55 -17
  64. package/skills/tech-lead/scripts/aegis-digest.mjs +1 -1
  65. package/skills/tech-lead/scripts/budget-check.mjs +7 -13
  66. package/skills/tech-lead/scripts/compile-order.mjs +69 -22
  67. package/skills/tech-lead/scripts/fit-check.mjs +10 -10
  68. package/skills/tech-lead/scripts/gate-answers.mjs +11 -12
  69. package/skills/tech-lead/scripts/hill-derive.mjs +133 -0
  70. package/skills/tech-lead/scripts/ingest-result.mjs +7 -19
  71. package/skills/tech-lead/scripts/init-run.mjs +60 -18
  72. package/skills/tech-lead/scripts/lib/argv.mjs +1 -1
  73. package/skills/tech-lead/scripts/lib/contract-md.mjs +10 -10
  74. package/skills/tech-lead/scripts/lib/is-main.mjs +11 -12
  75. package/skills/tech-lead/scripts/lib/paths.mjs +15 -13
  76. package/skills/tech-lead/scripts/resume-state.mjs +387 -0
  77. package/skills/tech-lead/scripts/run-snapshot.mjs +1 -6
  78. package/skills/tech-lead/scripts/run-workflow.mjs +381 -0
  79. package/skills/tech-lead/scripts/ship-report.mjs +33 -2
  80. package/skills/tech-lead/scripts/stats.mjs +9 -10
  81. package/skills/tech-lead/scripts/t0-verify.mjs +4 -4
  82. package/skills/tech-lead/scripts/trace-lint.mjs +2 -2
  83. package/skills/tech-lead/workflows/shapeup-run.js +911 -0
  84. package/skills/translator/SKILL.md +2 -2
  85. package/skills/advisor-protocol/SKILL.md +0 -171
@@ -3,7 +3,7 @@
3
3
  "title": "HarnessDomain",
4
4
  "description": "The CENTRAL domain registry of the pure-skill architecture. Every shared field that crosses a skill boundary is defined here exactly once, with its meaning, owner, and storage tier annotated — work-order.schema.json and work-result.schema.json $ref into $defs below instead of re-defining records inline, and no skill may introduce a cross-boundary field that is not registered here first. Annotation keys: x-tier = SHARED (committed under shapeup/, survives clone+crash) | LOCAL (gitignored under .shapeup/, regenerable run-trace) | EMBEDDED (a record type that only lives inside another entity); x-location = the canonical path; x-writer = the single component allowed to write it; x-readers = who consumes it. The x-erd block is the machine-readable entity-relationship map; x-payload-by-worker is the authoritative table of which WorkOrder payload fields each worker may rely on.",
5
5
  "x-erd": {
6
- "description": "Relationship map. Cardinality reads left-to-right (WorkOrder 1:1 WorkResult = every order has exactly one result). Join keys: <slug> (the feature) is the aggregate root every path is keyed off; scope_id is the STABLE cross-machine key (boards regenerate; hill shards, T0 history and branches join on it); TASK-NNN ids are machine-local and must never be joined across machines (generate-board joins on scope, not task id).",
6
+ "description": "Relationship map. Cardinality reads left-to-right (WorkOrder 1:1 WorkResult = every order has exactly one result). Join keys: <slug> (the feature) is the aggregate root every path is keyed off; scope_id is the STABLE cross-machine key (boards regenerate; hill shards, T0 history and branches join on it); TASK-NNN ids are machine-local and must never be joined across machines (board regeneration joins on scope, not task id).",
7
7
  "relationships": [
8
8
  {
9
9
  "from": "WorkOrder",
@@ -101,20 +101,6 @@
101
101
  "via": "discoveries[]",
102
102
  "note": "ingest appends to discovery/ledger.md — three producers (executor +, QA ~, planner overflow), zero direct writers"
103
103
  },
104
- {
105
- "from": "WorkResult",
106
- "to": "Escalate",
107
- "cardinality": "1:N",
108
- "via": "escalates[]",
109
- "note": "ingest queues to escalates/<order>.json; advisor-protocol adjudicates into a Decision"
110
- },
111
- {
112
- "from": "Escalate",
113
- "to": "Decision",
114
- "cardinality": "1:0..1",
115
- "via": "advisor-protocol adjudication",
116
- "note": "persisted to the committed round-ledger the instant it is answered (zero-memory handoff)"
117
- },
118
104
  {
119
105
  "from": "WorkResult",
120
106
  "to": "Verdict",
@@ -181,7 +167,7 @@
181
167
  "to": "ScopeContract",
182
168
  "cardinality": "1:N",
183
169
  "via": "superseded_by[]",
184
- "note": "set by split-scope — supersede-never-delete keeps branch and T0 history attributable"
170
+ "note": "set by map-scopes — supersede-never-delete keeps branch and T0 history attributable"
185
171
  },
186
172
  {
187
173
  "from": "T0Artifact",
@@ -254,15 +240,12 @@
254
240
  "spec_folder",
255
241
  "feature",
256
242
  "discovered_ledger",
257
- "kb_rules_path",
258
- "requirements"
243
+ "kb_rules_path"
259
244
  ],
260
245
  "scope-architect": [
261
246
  "feature",
262
247
  "spec_folder",
263
- "tasks",
264
- "discovered_ledger",
265
- "scope_id"
248
+ "tasks"
266
249
  ],
267
250
  "solution-architect": [
268
251
  "feature",
@@ -304,12 +287,6 @@
304
287
  ],
305
288
  "coach": [
306
289
  "feedback"
307
- ],
308
- "advisor-protocol": [
309
- "ledger",
310
- "escalate",
311
- "scope_id",
312
- "round"
313
290
  ]
314
291
  },
315
292
  "x-result-by-worker": {
@@ -317,7 +294,6 @@
317
294
  "task-executor": [
318
295
  "task_results",
319
296
  "files_touched",
320
- "escalates",
321
297
  "discoveries",
322
298
  "artifacts",
323
299
  "assumptions",
@@ -332,21 +308,18 @@
332
308
  ],
333
309
  "ba-pitch-analyzer": [
334
310
  "discoveries",
335
- "escalates",
336
311
  "files_touched",
337
312
  "artifacts",
338
313
  "assumptions",
339
314
  "deviations"
340
315
  ],
341
316
  "scope-architect": [
342
- "escalates",
343
317
  "files_touched",
344
318
  "artifacts",
345
319
  "assumptions",
346
320
  "deviations"
347
321
  ],
348
322
  "solution-architect": [
349
- "escalates",
350
323
  "files_touched",
351
324
  "artifacts",
352
325
  "assumptions",
@@ -382,12 +355,6 @@
382
355
  "artifacts",
383
356
  "assumptions",
384
357
  "deviations"
385
- ],
386
- "advisor-protocol": [
387
- "files_touched",
388
- "artifacts",
389
- "assumptions",
390
- "deviations"
391
358
  ]
392
359
  },
393
360
  "$defs": {
@@ -404,34 +371,28 @@
404
371
  "qa-edge-hunter",
405
372
  "translator",
406
373
  "scope-hammer",
407
- "coach",
408
- "advisor-protocol"
374
+ "coach"
409
375
  ]
410
376
  },
411
377
  "Operation": {
412
- "description": "The full operation vocabulary. Replaces lifecycle flags (--tasks-only, --from-discovered, --remap …): the caller knows the pipeline position; the worker never re-derives it. Ownership: execute/fix/spike = task-executor · analyze/generate-board/reconcile/retrofit-surface/coverage = ba-pitch-analyzer · map-scopes/remap/split-scope = scope-architect · wire = solution-architect · evaluate = spec-evaluator · orient = orient · hunt/recheck = qa-edge-hunter · translate = translator · hammer = scope-hammer · coach = coach · adjudicate = advisor-protocol.",
378
+ "description": "The full operation vocabulary. Replaces lifecycle flags (--tasks-only, --from-discovered, --map-scopes …): the caller knows the pipeline position; the worker never re-derives it. Ownership: execute/fix/spike = task-executor · analyze/reconcile/retrofit-surface/coverage = ba-pitch-analyzer · map-scopes = scope-architect · wire = solution-architect · evaluate = spec-evaluator · orient = orient · hunt = qa-edge-hunter · translate = translator · hammer = scope-hammer · coach = coach.",
413
379
  "type": "string",
414
380
  "enum": [
415
381
  "execute",
416
382
  "fix",
417
383
  "spike",
418
384
  "analyze",
419
- "generate-board",
420
385
  "reconcile",
421
386
  "retrofit-surface",
422
387
  "coverage",
423
388
  "map-scopes",
424
- "remap",
425
- "split-scope",
426
389
  "wire",
427
390
  "evaluate",
428
391
  "orient",
429
392
  "hunt",
430
- "recheck",
431
393
  "translate",
432
394
  "hammer",
433
- "coach",
434
- "adjudicate"
395
+ "coach"
435
396
  ]
436
397
  },
437
398
  "Substrate": {
@@ -477,7 +438,7 @@
477
438
  "properties": {
478
439
  "pause_gates": {
479
440
  "type": "boolean",
480
- "description": "true (standalone default): pause at the worker's phase checkpoints. false: run straight through, surfacing questions as assumptions[]/escalates[]."
441
+ "description": "true (standalone default): pause at the worker's phase checkpoints. false: run straight through, surfacing questions as assumptions[] — or, when one genuinely blocks, deviations[] with status 'escalated'."
481
442
  },
482
443
  "max_questions": {
483
444
  "type": "integer",
@@ -549,7 +510,7 @@
549
510
  "items": {
550
511
  "type": "string"
551
512
  },
552
- "description": "Explicit dependencies. The inverse (unlocks) is ALWAYS derived by board-derive.mjs, never hand-authored (KB-BA-001)."
513
+ "description": "Explicit dependencies. The inverse (unlocks) is ALWAYS derived by board-derive.mjs, never hand-authored — hand-authored inverses drift asymmetric, observed repeatedly."
553
514
  },
554
515
  "use_case_refs": {
555
516
  "type": "array",
@@ -564,7 +525,7 @@
564
525
  "description": "One adjudicated ESCALATE answer as carried inside a WorkOrder — binding precedent the worker must apply. Compiled from the committed round-ledger.md Decisions table (columns: Round | Scope | Kind | Question | Answer | Resolved by) filtered to this scope. The full row lives in the ledger; the envelope carries the minimal {id, answer} projection.",
565
526
  "x-tier": "EMBEDDED (projection of the SHARED round-ledger.md Decisions row)",
566
527
  "x-location": ".shapeup/<slug>/round-ledger.md",
567
- "x-writer": "advisor-protocol (via tech-lead) — promoted the instant an answer is given",
528
+ "x-writer": "tech-lead — promoted the instant the PO gives an answer",
568
529
  "type": "object",
569
530
  "required": [
570
531
  "id",
@@ -732,14 +693,14 @@
732
693
  "DOWNHILL_EXECUTION",
733
694
  "FINISHED"
734
695
  ],
735
- "description": "ALWAYS authored as UPHILL_UNKNOWN (DD-10). The live phase is DERIVED from T0/T1/seesaw facts into hill/<scope-id>.yml — facts move dots, not authors."
696
+ "description": "ALWAYS authored as UPHILL_UNKNOWN — self-reported confidence is the risk this closes. The live phase is DERIVED from T0/T1/seesaw facts into hill/<scope-id>.yml — facts move dots, not authors."
736
697
  },
737
698
  "superseded_by": {
738
699
  "type": "array",
739
700
  "items": {
740
701
  "type": "string"
741
702
  },
742
- "description": "Set by split-scope: the replacing scope ids. Supersede-never-delete."
703
+ "description": "Set by map-scopes: the replacing scope ids. Supersede-never-delete."
743
704
  },
744
705
  "business_goal": {
745
706
  "type": "string",
@@ -831,87 +792,12 @@
831
792
  }
832
793
  }
833
794
  },
834
- "Escalate": {
835
- "description": "The worker's ONE outward port: a decision it cannot make alone. Ingest queues these to escalates/<order>.json; advisor-protocol adjudicates (budget ≤3/scope/round) and the answer returns as a Decision in the next order. The advisor-side grammar adds scope_id/round/attempt/options/default_if_silent (see EscalateBlock).",
836
- "x-tier": "EMBEDDED",
837
- "type": "object",
838
- "required": [
839
- "kind",
840
- "question"
841
- ],
842
- "properties": {
843
- "kind": {
844
- "type": "string",
845
- "enum": [
846
- "design-decision",
847
- "spec-ambiguity",
848
- "substrate-expansion"
849
- ],
850
- "description": "Three kinds, three resolution paths: design/spec go to the PO (or default_if_silent unattended); substrate-expansion is NEVER silently approved — it routes to a scope-architect remap order."
851
- },
852
- "question": {
853
- "type": "string",
854
- "description": "One checkable question."
855
- },
856
- "blocked_ac": {
857
- "type": "string",
858
- "description": "Which AC waits on this — work on unrelated ACs continues."
859
- },
860
- "context": {
861
- "type": "string",
862
- "description": "The two interpretations / the file and why it's needed."
863
- }
864
- }
865
- },
866
- "EscalateBlock": {
867
- "description": "The advisor-protocol adjudication grammar — an Escalate enriched with run coordinates and options, as passed to /advisor-protocol --escalate. The answer is persisted to the committed round-ledger.md Decisions table the instant it's given (zero-memory handoff: escalation memory lives in files, not chat).",
868
- "x-tier": "EMBEDDED",
869
- "x-readers": "advisor-protocol",
870
- "type": "object",
871
- "required": [
872
- "kind",
873
- "question"
874
- ],
875
- "properties": {
876
- "scope_id": {
877
- "type": "string"
878
- },
879
- "round": {
880
- "type": "integer"
881
- },
882
- "attempt": {
883
- "type": "integer"
884
- },
885
- "kind": {
886
- "type": "string",
887
- "enum": [
888
- "design-decision",
889
- "spec-ambiguity",
890
- "substrate-expansion"
891
- ]
892
- },
893
- "question": {
894
- "type": "string"
895
- },
896
- "options": {
897
- "type": "array",
898
- "items": {
899
- "type": "string"
900
- },
901
- "description": "Proposed answers, each with its rationale."
902
- },
903
- "default_if_silent": {
904
- "type": "string",
905
- "description": "Optional low-risk fallback — applied under --unattended (logged + flagged for GATE H); the advisor is never forced to accept it."
906
- }
907
- }
908
- },
909
795
  "Discovery": {
910
796
  "description": "The universal currency of surprise: one raw discovered line. Producers: task-executor (marker +, P3.7), qa-edge-hunter (always ~, repro required), ba-pitch-analyzer (overflow reports). NO producer writes the ledger — ingest-result appends every entry to discovery/ledger.md (single-writer, mechanically). Promotion ~ → must-have is always a human act at SHIP S.0/GATE H.",
911
797
  "x-tier": "EMBEDDED (projection into the LOCAL discovery ledger)",
912
798
  "x-location": ".shapeup/<slug>/discovery/ledger.md",
913
799
  "x-writer": "ingest-result.mjs",
914
- "x-readers": "ba-pitch-analyzer (reconcile), scope-architect (remap), scope-hammer (census), qa-edge-hunter (covered-territory context)",
800
+ "x-readers": "ba-pitch-analyzer (reconcile), scope-architect (map-scopes), scope-hammer (census), qa-edge-hunter (covered-territory context)",
915
801
  "type": "object",
916
802
  "required": [
917
803
  "marker",
@@ -961,7 +847,7 @@
961
847
  }
962
848
  },
963
849
  "T0Citation": {
964
- "description": "The judge's pointer to a mechanical T0 artifact. The evaluator RECOMPUTES sha256 from disk — a handed hash is never trusted; a verdict on a scoped spec without a citation is structurally invalid (PA4/DD-7: T0 is a machine fact the generator cannot fabricate).",
850
+ "description": "The judge's pointer to a mechanical T0 artifact. The evaluator RECOMPUTES sha256 from disk — a handed hash is never trusted; a verdict on a scoped spec without a citation is structurally invalid: T0 is a machine fact the generator cannot fabricate.",
965
851
  "x-tier": "EMBEDDED",
966
852
  "type": "object",
967
853
  "required": [
@@ -1071,7 +957,7 @@
1071
957
  "evidence": {
1072
958
  "type": "string",
1073
959
  "pattern": "[\\w./\\-]+:[0-9]+",
1074
- "description": "A FAIL must carry a file:line locator. Was stated 5x in spec-evaluator/SKILL.md prose and enforced 0x; a measured run returned a correct FAIL verdict with bugs[] null and no locator anywhere, so the finding could not be acted on without re-investigating. Now mechanical: validate-envelope rejects it before ingest."
960
+ "description": "A FAIL must carry a file:line locator. The rule used to live in prose and be enforced nowhere a correct FAIL verdict with no locator anywhere is unactionable without re-investigating (observed, not theorized). Now mechanical: the ingest-side schema validation rejects it before any write."
1075
961
  },
1076
962
  "traces_to": {
1077
963
  "type": "array",
@@ -1390,7 +1276,7 @@
1390
1276
  ]
1391
1277
  },
1392
1278
  "SeesawRegistry": {
1393
- "description": "The fixture registry of every FINISHED scope — what seesawCheck re-runs on each later attempt so a new scope cannot silently break a shipped one (PA5).",
1279
+ "description": "The fixture registry of every FINISHED scope — what seesawCheck re-runs on each later attempt so a new scope cannot silently break a shipped one — a regression mistaken for progress is the pathology the seesaw exists for.",
1394
1280
  "x-tier": "LOCAL",
1395
1281
  "x-location": ".shapeup/<slug>/seesaw/registry.json",
1396
1282
  "x-writer": "tech-lead (when a scope reaches FINISHED)",
@@ -1460,10 +1346,10 @@
1460
1346
  }
1461
1347
  },
1462
1348
  "HillShard": {
1463
- "description": "One scope's hill position — DERIVED, never self-reported (DD-10): UPHILL_UNKNOWN (open unknowns > 0) → UPHILL_SOLVED (unknowns 0, no T0-green yet) → DOWNHILL_EXECUTION (≥1 T0-green; T1/seesaw pending) → FINISHED (T1 PASS ∧ seesaw green ∧ merged). Single-writer = whoever holds that scope's branch. Progress is reported by hill position, never task counts.",
1349
+ "description": "One scope's hill position — DERIVED, never self-reported: UPHILL_UNKNOWN (open unknowns > 0) → UPHILL_SOLVED (unknowns 0, no T0-green yet) → DOWNHILL_EXECUTION (≥1 T0-green; T1/seesaw pending) → FINISHED (T1 PASS ∧ seesaw green ∧ merged). Single-writer = whoever holds that scope's branch. Progress is reported by hill position, never task counts.",
1464
1350
  "x-tier": "SHARED",
1465
1351
  "x-location": "shapeup/<slug>/hill/<scope-id>.yml",
1466
- "x-writer": "tech-lead (GATE L2.4 derivation)",
1352
+ "x-writer": "tech-lead (GATE L2 derivation)",
1467
1353
  "x-readers": "tech-lead (GATE L3 hill report), scope-hammer (census), GATE L1b sequencing",
1468
1354
  "type": "object",
1469
1355
  "properties": {
@@ -1486,7 +1372,7 @@
1486
1372
  "x-tier": "SHARED",
1487
1373
  "x-location": ".shapeup/metrics/<machine-id>.jsonl",
1488
1374
  "x-writer": "tech-lead (SHIP S.6)",
1489
- "x-readers": "tier-3 e2e benchmark tooling, stats.mjs (read-only projection)",
1375
+ "x-readers": "tier-3 e2e tooling, stats.mjs (read-only projection)",
1490
1376
  "type": "object",
1491
1377
  "properties": {
1492
1378
  "schema_version": {
@@ -1755,9 +1641,6 @@
1755
1641
  }
1756
1642
  }
1757
1643
  },
1758
- "open_escalates": {
1759
- "type": "integer"
1760
- },
1761
1644
  "pending_orders": {
1762
1645
  "type": "array",
1763
1646
  "items": {
@@ -1923,8 +1806,8 @@
1923
1806
  }
1924
1807
  },
1925
1808
  "Lane": {
1926
- "description": "v1.2 DESIGN DRAFT reserves the name and makes the policy reviewable; no envelope references it yet and no runtime reads it. See docs/design/04-functional-design.md §4.7. When implemented, the lane is pipeline knowledge: the orchestrator compiles it away into existing registered knobs (payload.lens, payload.dimensions, interaction gate policy) — it NEVER rides in WorkOrderPayload, so workers stay pipeline-blind.",
1927
- "x-tier": "EMBEDDED (when implemented: recorded in harness-run.md frontmatter `lane:` — never a WorkOrderPayload field)",
1809
+ "description": "The run's lane (full|tiny), computed by fit-check.mjs at GATE L0.3 and recorded in harness-run.md frontmatter `lane:` (with its evidence, and marked overridden when --lane/--tiny outranks the recommendation); RunArgs.lane carries it to the workflow launch. The lane is pipeline knowledge: the orchestrator compiles it away into existing registered knobs (lens, budgets, gate policy) — it NEVER rides in WorkOrderPayload, so workers stay pipeline-blind.",
1810
+ "x-tier": "EMBEDDED (recorded in harness-run.md frontmatter `lane:` — never a WorkOrderPayload field)",
1928
1811
  "x-writer": "tech-lead (GATE L0 lane selection)",
1929
1812
  "x-readers": "tech-lead only",
1930
1813
  "x-lane-policy": {
@@ -1970,7 +1853,7 @@
1970
1853
  ]
1971
1854
  },
1972
1855
  "RequirementClause": {
1973
- "description": "One atomic customer requirement, frozen with a STABLE id — the covers-closure input truth (spine v1.3). Extracted from the REQ source (Open Decision A: pitch / customer-requirements doc / use-case bodies) by ba-pitch-analyzer's `coverage` operation; extraction is judgment (LLM), but ids are assigned ONCE and never renumber (they behave like scope_id, not TASK-NNN — every covers: link would rot otherwise). Supersede-never-delete: a dropped clause is marked CUT (PO-approved), never removed, so the registry stays auditable on a fresh clone. The original REQ source is never edited — the registry is a separate derived, committed file.",
1856
+ "description": "One atomic customer requirement, frozen with a STABLE id — the covers-closure input truth (spine v1.3). Extracted from the REQ source (pitch / customer-requirements doc / use-case bodies) by the planner extraction is judgment (LLM), but ids are assigned ONCE and never renumber (they behave like scope_id, not TASK-NNN — every covers: link would rot otherwise). Supersede-never-delete: a dropped clause is marked CUT (PO-approved), never removed, so the registry stays auditable on a fresh clone. The original REQ source is never edited — the registry is a separate derived, committed file.",
1974
1857
  "x-tier": "SHARED",
1975
1858
  "x-location": "shapeup/<slug>/requirements.md",
1976
1859
  "x-writer": "ba-pitch-analyzer (operation: coverage) — extraction only; CUT status is a PO governance edit (same class as a round-ledger Decision)",
@@ -2200,11 +2083,11 @@
2200
2083
  },
2201
2084
  "discovered_ledger": {
2202
2085
  "type": "string",
2203
- "description": "ba-pitch-analyzer (reconcile) / scope-architect (remap): the discovery ledger path whose raw [+]/~ lines get folded in."
2086
+ "description": "ba-pitch-analyzer (reconcile) / scope-architect (map-scopes): the discovery ledger path whose raw [+]/~ lines get folded in."
2204
2087
  },
2205
2088
  "requirements": {
2206
2089
  "type": "string",
2207
- "description": "ba-pitch-analyzer (operation: coverage): the REQ source to extract atomic clauses from (Open Decision A — pitch / customer-requirements doc / use-case bodies). Absent → the planner defaults to the pitch and records the choice in assumptions[]. The written registry lands at shapeup/<slug>/requirements.md (RequirementClause rows)."
2090
+ "description": "ba-pitch-analyzer: the REQ source to extract atomic clauses from (Open Decision A — pitch / customer-requirements doc / use-case bodies). Absent → the planner defaults to the pitch and records the choice in assumptions[]. The written registry lands at shapeup/<slug>/requirements.md (RequirementClause rows)."
2208
2091
  },
2209
2092
  "project_profile": {
2210
2093
  "type": "string",
@@ -2212,7 +2095,7 @@
2212
2095
  },
2213
2096
  "scope_id": {
2214
2097
  "type": "string",
2215
- "description": "scope-architect (split-scope): the stuck scope · scope-hammer (--breaker inner): the exhausted scope · advisor-protocol: budget scope."
2098
+ "description": "scope-architect (map-scopes): the stuck scope · scope-hammer (--breaker inner): the exhausted scope."
2216
2099
  },
2217
2100
  "dimensions": {
2218
2101
  "type": "array",
@@ -2251,15 +2134,11 @@
2251
2134
  },
2252
2135
  "ledger": {
2253
2136
  "type": "string",
2254
- "description": "qa-edge-hunter: discovery ledger path (READ-ONLY context) · advisor-protocol: the committed round-ledger.md decisions persist to."
2255
- },
2256
- "escalate": {
2257
- "$ref": "#/$defs/EscalateBlock",
2258
- "description": "advisor-protocol: the worker's ESCALATE block to adjudicate."
2137
+ "description": "qa-edge-hunter: discovery ledger path (READ-ONLY context)."
2259
2138
  },
2260
2139
  "round": {
2261
2140
  "type": "integer",
2262
- "description": "advisor-protocol: the round the budget/decision is counted against."
2141
+ "description": "the round this order is counted against."
2263
2142
  },
2264
2143
  "baseline": {
2265
2144
  "type": "string",
@@ -2289,6 +2168,299 @@
2289
2168
  "description": "translator: existing glossary.md to reuse as the base term map."
2290
2169
  }
2291
2170
  }
2171
+ },
2172
+ "ResumeState": {
2173
+ "description": "The fast-forward derivation: which phase a launch resumes at, derived from artifacts on disk and NEVER from stored state or conversation memory. Produced by skills/tech-lead/scripts/resume-state.mjs on stdout and consumed by shapeup-run.js's preamble on every launch, fresh or relaunch alike. Every phase predicate is an artifact test — `has_orient_artifacts` exists because the ORIENT branch was once gated on the ledger's stored `status` instead, which a silent courier failure left stale, and a completed ORIENT phase was re-dispatched on resume. `next_phase` is a convenience derived from the same booleans, which all travel too: a caller is never forced to trust a summary it cannot re-derive.",
2174
+ "x-tier": "EMBEDDED",
2175
+ "x-location": "stdout of resume-state.mjs — never written to disk (the run's state IS the artifacts this record reports on)",
2176
+ "x-writer": "resume-state.mjs (deriving; the same script's --set-status / --set-active-scope operations write, and report their own outcome record instead)",
2177
+ "x-readers": "shapeup-run.js (the fast-forward preamble, one call per launch)",
2178
+ "type": "object",
2179
+ "required": [
2180
+ "intake_path",
2181
+ "status",
2182
+ "has_orient_artifacts",
2183
+ "has_spec_tree",
2184
+ "has_wiring_map",
2185
+ "scope_files",
2186
+ "pending_orders",
2187
+ "eval_rounds_done",
2188
+ "next_phase"
2189
+ ],
2190
+ "properties": {
2191
+ "intake_path": {
2192
+ "type": "string",
2193
+ "description": "Resolved path to the run's intake — the pitch a fresh ORIENT dispatch is compiled against."
2194
+ },
2195
+ "spec_folder": {
2196
+ "type": [
2197
+ "string",
2198
+ "null"
2199
+ ],
2200
+ "description": "From harness-run.md frontmatter; null before the ledger names one."
2201
+ },
2202
+ "status": {
2203
+ "type": [
2204
+ "string",
2205
+ "null"
2206
+ ],
2207
+ "description": "The ledger's stored status, reported for the readers that legitimately hold a MID_RUN set over it (run-snapshot.mjs, hooks/anti-rationalization.mjs). NOT a resume predicate: no phase decision in shapeup-run.js may branch on this field."
2208
+ },
2209
+ "has_orient_artifacts": {
2210
+ "type": "boolean",
2211
+ "description": "ORIENT finished: orient/ carries code-surface.md, discovered-seed.md, hill-signal.md and at least one spike-*.md (skills/orient/SKILL.md §Outputs). The ORIENT skip gates on THIS."
2212
+ },
2213
+ "has_spec_tree": {
2214
+ "type": "boolean",
2215
+ "description": "ANALYZE finished: the spec folder's usecases/ carries at least one use case that is not _index.md. WIRE reads these — one wiring-map entry per use case — which is why ANALYZE precedes WIRE in the phase chain: dispatched against an empty spec folder, WIRE escalates on every launch."
2216
+ },
2217
+ "has_wiring_map": {
2218
+ "type": "boolean",
2219
+ "description": "WIRE finished: shapeup/<slug>/wiring-map.md exists."
2220
+ },
2221
+ "project_profile_path": {
2222
+ "type": "string"
2223
+ },
2224
+ "has_project_profile": {
2225
+ "type": "boolean",
2226
+ "description": "tech-lead writes project-profile.md at GATE L0, before the launch; trace-lint resolves reachability by its archetype."
2227
+ },
2228
+ "scope_files": {
2229
+ "type": "array",
2230
+ "description": "MAP SCOPES finished when non-empty. Each entry carries a RESOLVED path, never a bare filename — compile-order.mjs and t0-verify.mjs resolve --scope against cwd, and a bare id makes compile-order exit 2, which the attempt loop reads as the stagnation breaker.",
2231
+ "items": {
2232
+ "type": "object",
2233
+ "required": [
2234
+ "scope_id",
2235
+ "path"
2236
+ ],
2237
+ "properties": {
2238
+ "scope_id": {
2239
+ "type": "string"
2240
+ },
2241
+ "path": {
2242
+ "type": "string"
2243
+ }
2244
+ }
2245
+ }
2246
+ },
2247
+ "pending_orders": {
2248
+ "type": "array",
2249
+ "items": {
2250
+ "type": "string"
2251
+ },
2252
+ "description": "Order files with no result beside them. Diagnostic only — build orders carry no scope id, so this set is not an audit trail of build dispatches (see compile-order.mjs's order-id note)."
2253
+ },
2254
+ "eval_rounds_done": {
2255
+ "type": "array",
2256
+ "items": {
2257
+ "type": "integer"
2258
+ },
2259
+ "description": "Round numbers with an evaluate-r<n>.json result — the resumed run's round counter starts one past the maximum."
2260
+ },
2261
+ "next_phase": {
2262
+ "type": "string",
2263
+ "enum": [
2264
+ "orient",
2265
+ "analyze",
2266
+ "wire",
2267
+ "map-scopes",
2268
+ "build"
2269
+ ],
2270
+ "description": "The first phase whose artifacts are incomplete. Derived from the booleans above, in that order. The same table (resume-state.mjs PHASE_ARTIFACT) answers `--require <phase>`, the post-condition shapeup-run.js checks after every phase dispatch — resume and completion are ONE predicate by construction."
2271
+ }
2272
+ }
2273
+ },
2274
+ "RunArgs": {
2275
+ "description": "C1 — the launch half of the workflow's only conversation. Compiled ONCE by tech-lead at GATE L0 from init-run.mjs output + the L0.8 model matrix + budgets, written to .shapeup/<slug>/run-args.json and handed to the run-workflow.mjs launch as one JSON literal — the workflow cannot ask follow-ups and cannot read config files itself, so everything a run will ever need travels in this one record. A workflow script validates its own subset of this shape in code (no runtime schema check at the C1 boundary itself); this entry is the central-registry definition the workflow script and the tech-lead skill both read as the one true shape.",
2276
+ "x-tier": "EMBEDDED",
2277
+ "x-location": ".shapeup/<slug>/run-args.json — written fresh by tech-lead on every launch and relaunch; the workflow receives it as its args and never reads other config",
2278
+ "x-writer": "tech-lead (GATE L0, on every launch AND every relaunch after a paused gate)",
2279
+ "x-readers": "the Workflow runtime (shapeup-run, and shapeup-run's own inner round dispatch)",
2280
+ "x-not-here": "Run config the LEDGER already carries does NOT get a second home in RunArgs — eval_dimensions, lens, spec_folder, stack, run_cmd, app_url are read off harness-run.md frontmatter by resume-state on every launch AND every relaunch, so a copy here would be a second source that can disagree with the first. RunArgs carries what a workflow cannot derive from disk (identity, budgets, the model matrix, pluginRoot, startedAt) plus noEval, which no frontmatter line holds.",
2281
+ "type": "object",
2282
+ "required": [
2283
+ "slug",
2284
+ "autoLevel",
2285
+ "models",
2286
+ "budgets",
2287
+ "pluginRoot",
2288
+ "startedAt"
2289
+ ],
2290
+ "properties": {
2291
+ "slug": {
2292
+ "type": "string",
2293
+ "description": "The feature slug this run builds — the aggregate root every path is keyed off."
2294
+ },
2295
+ "autoLevel": {
2296
+ "type": "string",
2297
+ "enum": [
2298
+ "interactive",
2299
+ "auto",
2300
+ "unattended"
2301
+ ],
2302
+ "description": "Resolved once at GATE L0; governs which gates pre-approve and what on_missing does (gate-answers.mjs)."
2303
+ },
2304
+ "answers": {
2305
+ "type": "string",
2306
+ "description": "A gate-answers preset name (ci|guarded|interactive) or a path to a gate-answers.json file — the ONLY thing that decides whether a gate crosses, pauses, or aborts."
2307
+ },
2308
+ "models": {
2309
+ "type": "object",
2310
+ "description": "The L0.8 role -> model matrix, resolved once. The model floor: sonnet or above on every role, including mechanical couriers — no exceptions.",
2311
+ "properties": {
2312
+ "exec": {
2313
+ "type": "string"
2314
+ },
2315
+ "eval": {
2316
+ "type": "string"
2317
+ },
2318
+ "qa": {
2319
+ "type": "string"
2320
+ }
2321
+ }
2322
+ },
2323
+ "budgets": {
2324
+ "type": "object",
2325
+ "description": "The three-level circuit breaker's own limits (AGENTS.md) — outer round_budget, inner attempt_budget, and the opt-in wall-clock breaker.",
2326
+ "properties": {
2327
+ "maxRounds": {
2328
+ "type": "integer"
2329
+ },
2330
+ "attemptBudget": {
2331
+ "type": "integer"
2332
+ },
2333
+ "wallClockS": {
2334
+ "type": "integer"
2335
+ }
2336
+ }
2337
+ },
2338
+ "pluginRoot": {
2339
+ "type": "string",
2340
+ "description": "${CLAUDE_PLUGIN_ROOT} — the only thing a workflow script may ever root a path in (a workflow has no filesystem of its own; every path it resolves is either rooted here or produced by a prior call's stdout)."
2341
+ },
2342
+ "startedAt": {
2343
+ "type": "string",
2344
+ "description": "ISO timestamp, passed in because Date.now() is unavailable inside a workflow script by design — the deadline breaker (budget-check.mjs) computes elapsed time itself, in Node, where the clock lives."
2345
+ },
2346
+ "lane": {
2347
+ "$ref": "#/$defs/Lane",
2348
+ "description": "The fit-check verdict (full|tiny) — compiles away into existing knobs; never rides in WorkOrderPayload."
2349
+ },
2350
+ "noEval": {
2351
+ "type": "boolean",
2352
+ "description": "If true, skips the EVAL phase completely. Rides here rather than in the ledger because there is no frontmatter line that carries it — contrast eval_dimensions, which does."
2353
+ }
2354
+ }
2355
+ },
2356
+ "RunReturn": {
2357
+ "description": "C1 — the return half of the workflow's only conversation. The ONLY way the workflow speaks back to tech-lead, so it is a tagged union keyed on `status` — the skill branches on the tag, never on prose (the same exit-code discipline gate-answers.mjs already applies to gate sign-off, extended to the orchestrator's own return value). A gate resolved 'ask' (exit 4) always returns `paused`; a gate resolved 'abort' (exit 5) always returns `aborted`; any circuit breaker tripping (outer round_budget, inner attempt_budget, or the deadline breaker) returns `gate_h`; a full run whose final EVAL passes returns `shipped`. The union is written as a superset of what one inner round can itself produce (`paused`, `aborted`, `gate_h`, or a round-complete carrying a verdict) — `shipped` belongs only to a full run. It is deliberately NOT narrowed, because the round-scoped subset is what a `workflow()` child would return if the fan-out this design anticipates ever spends that nesting level.",
2358
+ "x-tier": "EMBEDDED",
2359
+ "x-location": "in-memory only — a Workflow return value, never written to disk",
2360
+ "x-writer": "the workflow runtime (shapeup-run — the sole writer)",
2361
+ "x-readers": "tech-lead (branches on `status`, emits `block` verbatim on a pause, never re-summarizes it)",
2362
+ "type": "object",
2363
+ "required": [
2364
+ "status"
2365
+ ],
2366
+ "properties": {
2367
+ "status": {
2368
+ "type": "string",
2369
+ "enum": [
2370
+ "shipped",
2371
+ "paused",
2372
+ "aborted",
2373
+ "gate_h",
2374
+ "ok"
2375
+ ],
2376
+ "description": "shipped = the happy ending (outer run only) · paused = a gate resolved 'ask', relaunch after a recorded decision · aborted = a gate resolved 'abort', attributable stop · gate_h = a circuit breaker tripped, ship what is green · ok = one inner round completed (build+eval), not itself a ship — the outer loop decides whether to loop again."
2377
+ },
2378
+ "verdict": {
2379
+ "type": "string",
2380
+ "enum": [
2381
+ "pass",
2382
+ "fail"
2383
+ ],
2384
+ "description": "shipped | ok: the round or run's EVAL verdict, lowercased from spec-evaluator's PASS|FAIL."
2385
+ },
2386
+ "rounds_used": {
2387
+ "type": "integer"
2388
+ },
2389
+ "dims_not_evaluated": {
2390
+ "type": "array",
2391
+ "items": {
2392
+ "type": "string"
2393
+ }
2394
+ },
2395
+ "qa_findings": {
2396
+ "type": "integer"
2397
+ },
2398
+ "report": {
2399
+ "type": "string",
2400
+ "description": "shipped: shapeup/<slug>/REPORT.md path."
2401
+ },
2402
+ "state_warnings": {
2403
+ "type": "array",
2404
+ "items": {
2405
+ "type": "string"
2406
+ },
2407
+ "description": "shipped | gate_h: bookkeeping writes that did not take (a ledger status that read back wrong), carried on the ONE channel a headless launch preserves. The workflow's own log() goes to the progress narrator and `claude -p` stdout carries only the final message, so a run that returned `shipped` over a ledger still reading `evaluating` could not be told from one that warned about it. Absent when every state write took. Diagnostic, never a status: a lost bookkeeping write is a degraded digest, not a corrupted build."
2408
+ },
2409
+ "round": {
2410
+ "type": "integer",
2411
+ "description": "ok: which round this return describes."
2412
+ },
2413
+ "paused_at": {
2414
+ "type": "string",
2415
+ "description": "paused: the gate id that resolved 'ask' (e.g. L1b, L2, L3)."
2416
+ },
2417
+ "block": {
2418
+ "type": "string",
2419
+ "description": "paused: the ⏸ gate block, emitted VERBATIM by the skill — the block is the handoff contract; re-phrasing it is the paraphrase channel this design exists to close."
2420
+ },
2421
+ "valid_decisions": {
2422
+ "type": "array",
2423
+ "items": {
2424
+ "type": "string"
2425
+ },
2426
+ "description": "paused: the decisions VALID_BY_GATE allows at this gate (gate-answers.mjs)."
2427
+ },
2428
+ "context": {
2429
+ "type": "object",
2430
+ "description": "paused: whatever facts the paused gate needs the PO to see (round, scope counts, spec_lint status, …)."
2431
+ },
2432
+ "aborted_at": {
2433
+ "type": "string",
2434
+ "description": "aborted: the gate id that resolved 'abort'."
2435
+ },
2436
+ "reason": {
2437
+ "type": "string",
2438
+ "description": "aborted: the attributable reason (gate-answers.mjs's own `reason` field, carried through verbatim)."
2439
+ },
2440
+ "breaker": {
2441
+ "type": "string",
2442
+ "enum": [
2443
+ "outer",
2444
+ "inner",
2445
+ "deadline"
2446
+ ],
2447
+ "description": "gate_h: which of the three breakers fired (AGENTS.md's three-level circuit breaker)."
2448
+ },
2449
+ "hammer_proposals": {
2450
+ "type": "array",
2451
+ "items": {
2452
+ "type": "string"
2453
+ },
2454
+ "description": "gate_h | ok: scope ids queued for GATE H's census (scope-hammer) — an exhausted scope never blocks the round, it proposes."
2455
+ },
2456
+ "green_scopes": {
2457
+ "type": "array",
2458
+ "items": {
2459
+ "type": "string"
2460
+ },
2461
+ "description": "gate_h | ok: scope ids that reached T0-green this round."
2462
+ }
2463
+ }
2292
2464
  }
2293
2465
  }
2294
2466
  }