its-magic 0.1.3-2 → 0.1.3-4

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "its-magic",
3
- "version": "0.1.3-2",
3
+ "version": "0.1.3-4",
4
4
  "description": "its-magic - AI dev team workflow for Cursor.",
5
5
  "license": "MIT",
6
6
  "bin": {
@@ -13,6 +13,11 @@ Scoped modes (DEC-0073 §10 / US-0090):
13
13
  --scope=us-0096 DEC-0082 delivery modes surfaces (US-0096).
14
14
  --scope=project-readme DEC-0083 project README bootstrap surfaces (US-0097).
15
15
  --scope=dev-environment DEC-0084 dev auto-launch profile surfaces (US-0098).
16
+ --scope=sovereign-parallel-dev DEC-0108 parallel instance arbitrage surfaces (US-0108).
17
+ --scope=sovereign-self-healing-deploy DEC-0109 self-healing deploy loop surfaces (US-0109).
18
+ --scope=release-trigger-adapter DEC-0111 release trigger adapter surfaces (US-0111).
19
+ --scope=us-0119 DEC-0119 autonomous-autonomy preset surfaces (US-0119).
20
+ --scope=us-0120 US-0120 dedicated /closure phase surfaces.
16
21
  --scope=all union of all tables.
17
22
  """
18
23
 
@@ -297,6 +302,178 @@ DOWNSTREAM_CI_GUARD_PAIRS: tuple[tuple[str, str], ...] = (
297
302
  ),
298
303
  )
299
304
 
305
+ SOVEREIGN_ROLE_MANIFEST_PAIRS: tuple[tuple[str, str], ...] = (
306
+ (
307
+ ".cursor/sovereign-role-manifest.yaml",
308
+ "template/.cursor/sovereign-role-manifest.yaml.example",
309
+ ),
310
+ (
311
+ ".cursor/scratchpad.md",
312
+ "template/.cursor/scratchpad.md",
313
+ ),
314
+ (
315
+ "scripts/sovereign_role_manifest_validate.py",
316
+ "template/scripts/sovereign_role_manifest_validate.py",
317
+ ),
318
+ (
319
+ "scripts/sovereign_role_manifest_lib.py",
320
+ "template/scripts/sovereign_role_manifest_lib.py",
321
+ ),
322
+ (
323
+ "docs/engineering/runbook.md",
324
+ "template/docs/engineering/runbook.md",
325
+ ),
326
+ (
327
+ "docs/engineering/reason_codes.md",
328
+ "template/docs/engineering/reason_codes.md",
329
+ ),
330
+ (
331
+ "handoffs/sovereign_role_reviews.jsonl",
332
+ "template/handoffs/sovereign_role_reviews.jsonl",
333
+ ),
334
+ )
335
+
336
+ SOVEREIGN_PARALLEL_DEV_PAIRS: tuple[tuple[str, str], ...] = (
337
+ (
338
+ ".cursor/scratchpad.md",
339
+ "template/.cursor/scratchpad.md",
340
+ ),
341
+ (
342
+ "scripts/parallel_dev_arbiter.py",
343
+ "template/scripts/parallel_dev_arbiter.py",
344
+ ),
345
+ (
346
+ "tests/us0108_contract_test.py",
347
+ "template/tests/us0108_contract_test.py",
348
+ ),
349
+ (
350
+ "docs/engineering/runbook.md",
351
+ "template/docs/engineering/runbook.md",
352
+ ),
353
+ (
354
+ "docs/engineering/reason_codes.md",
355
+ "template/docs/engineering/reason_codes.md",
356
+ ),
357
+ (
358
+ "scripts/check_intake_template_parity.py",
359
+ "template/scripts/check_intake_template_parity.py",
360
+ ),
361
+ )
362
+
363
+ SOVEREIGN_SELF_HEALING_DEPLOY_PAIRS: tuple[tuple[str, str], ...] = (
364
+ (
365
+ ".cursor/scratchpad.md",
366
+ "template/.cursor/scratchpad.md",
367
+ ),
368
+ (
369
+ "scripts/self_healing_deploy_lib.py",
370
+ "template/scripts/self_healing_deploy_lib.py",
371
+ ),
372
+ (
373
+ "scripts/self_healing_deploy_validate.py",
374
+ "template/scripts/self_healing_deploy_validate.py",
375
+ ),
376
+ (
377
+ "tests/us0109_contract_test.py",
378
+ "template/tests/us0109_contract_test.py",
379
+ ),
380
+ (
381
+ "docs/engineering/runbook.md",
382
+ "template/docs/engineering/runbook.md",
383
+ ),
384
+ (
385
+ "docs/engineering/reason_codes.md",
386
+ "template/docs/engineering/reason_codes.md",
387
+ ),
388
+ )
389
+
390
+ # US-0111 release trigger adapter parity pairs
391
+ RELEASE_TRIGGER_ADAPTER_PAIRS: tuple[tuple[str, str], ...] = (
392
+ (
393
+ "scripts/release_trigger_adapters.py",
394
+ "template/scripts/release_trigger_adapters.py",
395
+ ),
396
+ (
397
+ "tests/us0111_contract_test.py",
398
+ "template/tests/us0111_contract_test.py",
399
+ ),
400
+ (
401
+ "docs/engineering/runbook.md",
402
+ "template/docs/engineering/runbook.md",
403
+ ),
404
+ (
405
+ "docs/engineering/reason_codes.md",
406
+ "template/docs/engineering/reason_codes.md",
407
+ ),
408
+ (
409
+ "scripts/check_intake_template_parity.py",
410
+ "template/scripts/check_intake_template_parity.py",
411
+ ),
412
+ )
413
+
414
+ # DEC-0118 §6 / US-0118 — Work-kind routing surface pairs. Contents must
415
+ # be byte-identical between active and template paths; installer delivers
416
+ # template copies (BUG-0003 / DEC-0066). 6 surface pairs per R-0106 Q6
417
+ # LOCKED. Note: scratchpad key parity is structural (key presence) via
418
+ # BUG-0013 test, NOT byte-parity (active scratchpad carries project-local
419
+ # overrides like DELIVERY_MODE=ultra_lean that must not leak to template).
420
+ WORK_KIND_ROUTING_PAIRS: tuple[tuple[str, str], ...] = (
421
+ (
422
+ "scripts/work_kind_classify_lib.py",
423
+ "template/scripts/work_kind_classify_lib.py",
424
+ ),
425
+ (
426
+ "scripts/work_kind_routing_lib.py",
427
+ "template/scripts/work_kind_routing_lib.py",
428
+ ),
429
+ (
430
+ "tests/us0118_contract_test.py",
431
+ "template/tests/us0118_contract_test.py",
432
+ ),
433
+ (".cursor/commands/auto.md", "template/.cursor/commands/auto.md"),
434
+ (".cursor/commands/intake.md", "template/.cursor/commands/intake.md"),
435
+ (
436
+ "docs/engineering/runbook.md",
437
+ "template/docs/engineering/runbook.md",
438
+ ),
439
+ (
440
+ "docs/engineering/context/installer-owned-paths.manifest",
441
+ "template/docs/engineering/context/installer-owned-paths.manifest",
442
+ ),
443
+ (
444
+ "scripts/check_intake_template_parity.py",
445
+ "template/scripts/check_intake_template_parity.py",
446
+ ),
447
+ )
448
+
449
+ # DEC-0119 §6 / US-0119 — Autonomous-autonomy preset surfaces. Contents must
450
+ # be byte-identical between active and template paths. 8 surface pairs.
451
+ AUTONOMY_PRESET_PAIRS: tuple[tuple[str, str], ...] = (
452
+ ("scripts/autonomy_preset_lib.py", "template/scripts/autonomy_preset_lib.py"),
453
+ ("scripts/validate_autonomy_stop_matrix.py", "template/scripts/validate_autonomy_stop_matrix.py"),
454
+ ("docs/engineering/autonomy-stop-matrix.md", "template/docs/engineering/autonomy-stop-matrix.md"),
455
+ ("docs/engineering/context/installer-owned-paths.manifest", "template/docs/engineering/context/installer-owned-paths.manifest"),
456
+ ("docs/engineering/runbook.md", "template/docs/engineering/runbook.md"),
457
+ (".cursor/commands/auto.md", "template/.cursor/commands/auto.md"),
458
+ ("tests/us0119_autonomy_preset_test.py", "template/tests/us0119_autonomy_preset_test.py"),
459
+ )
460
+
461
+ # US-0120 — Dedicated /closure phase surfaces. Contents must be byte-identical
462
+ # between active and template paths.
463
+ CLOSURE_PHASE_PAIRS: tuple[tuple[str, str], ...] = (
464
+ (".cursor/commands/closure.md", "template/.cursor/commands/closure.md"),
465
+ (".cursor/commands/release.md", "template/.cursor/commands/release.md"),
466
+ (".cursor/commands/auto.md", "template/.cursor/commands/auto.md"),
467
+ (
468
+ "scripts/validate_closure_verification.py",
469
+ "template/scripts/validate_closure_verification.py",
470
+ ),
471
+ (
472
+ "scripts/check_intake_template_parity.py",
473
+ "template/scripts/check_intake_template_parity.py",
474
+ ),
475
+ )
476
+
300
477
  SCOPES: dict[str, tuple[tuple[str, str], ...]] = {
301
478
  "intake": INTAKE_TEMPLATE_PAIRS,
302
479
  "caveman-compress": CAVEMAN_COMPRESS_PAIRS,
@@ -312,6 +489,13 @@ SCOPES: dict[str, tuple[tuple[str, str], ...]] = {
312
489
  "release-changelog": RELEASE_CHANGELOG_PAIRS,
313
490
  "model-tier": MODEL_TIER_PAIRS,
314
491
  "model-tier-overrides": MODEL_TIER_OVERRIDES_PAIRS,
492
+ "sovereign-role-manifest": SOVEREIGN_ROLE_MANIFEST_PAIRS,
493
+ "sovereign-parallel-dev": SOVEREIGN_PARALLEL_DEV_PAIRS,
494
+ "sovereign-self-healing-deploy": SOVEREIGN_SELF_HEALING_DEPLOY_PAIRS,
495
+ "release-trigger-adapter": RELEASE_TRIGGER_ADAPTER_PAIRS,
496
+ "work-kind-routing": WORK_KIND_ROUTING_PAIRS,
497
+ "us-0119": AUTONOMY_PRESET_PAIRS,
498
+ "us-0120": CLOSURE_PHASE_PAIRS,
315
499
  "all": (
316
500
  INTAKE_TEMPLATE_PAIRS
317
501
  + CAVEMAN_COMPRESS_PAIRS
@@ -327,6 +511,12 @@ SCOPES: dict[str, tuple[tuple[str, str], ...]] = {
327
511
  + RELEASE_CHANGELOG_PAIRS
328
512
  + MODEL_TIER_PAIRS
329
513
  + MODEL_TIER_OVERRIDES_PAIRS
514
+ + SOVEREIGN_ROLE_MANIFEST_PAIRS
515
+ + SOVEREIGN_SELF_HEALING_DEPLOY_PAIRS
516
+ + RELEASE_TRIGGER_ADAPTER_PAIRS
517
+ + WORK_KIND_ROUTING_PAIRS
518
+ + AUTONOMY_PRESET_PAIRS
519
+ + CLOSURE_PHASE_PAIRS
330
520
  ),
331
521
  }
332
522
 
@@ -271,14 +271,20 @@ override governance is satisfied.
271
271
  | `qa` | `qa` | `qa` |
272
272
  | `verify-work` | `qa` | `qa` |
273
273
  | `release` | `release` | `release` |
274
+ | `closure` | `qe`, `curator` | `qe` |
274
275
  | `refresh-context` | `curator`, `po` | `curator` |
275
276
 
276
277
  Alternate-role keys (merged scratchpad): `AUTO_ROLE_RESEARCH`, `AUTO_ROLE_PLAN_VERIFY`,
277
- `AUTO_ROLE_REFRESH_CONTEXT` — single-valued resolution per **DEC-0051** (see reference).
278
+ `AUTO_ROLE_REFRESH_CONTEXT`, `AUTO_ROLE_CLOSURE` — single-valued resolution per **DEC-0051** (see reference).
278
279
 
279
280
  Execute override: requires `AUTO_EXECUTE_ROLE_OVERRIDE=allowed_non_dev_execute` **and**
280
281
  parseable `EXECUTE_OVERRIDE_GOVERNANCE_REF`.
281
282
 
283
+ Closure role (US-0120): `AUTO_ROLE_CLOSURE` scratchpad key accepts `qe` (default) or
284
+ `curator` override. When empty, default is `qe`. `curator` override must not write
285
+ qa-owned surfaces per DEC-0051 §3 preflight capability gate. Fail-closed:
286
+ `PHASE_CAPABILITY_MISSING` when role cannot perform closure duties.
287
+
282
288
  Role reason codes: `PHASE_ROLE_CAPABILITY_MISSING`, `PHASE_ROLE_MISMATCH`.
283
289
 
284
290
  ## Mode-scoped delivery resolver — step 0 (US-0096 / DEC-0082)
@@ -287,6 +293,19 @@ Role reason codes: `PHASE_ROLE_CAPABILITY_MISSING`, `PHASE_ROLE_MISMATCH`.
287
293
  from precedence: argv `delivery-mode=` → backlog row `delivery_mode` (when
288
294
  `AUTO_DELIVERY_ROUTING=backlog_then_scratchpad`) → scratchpad `DELIVERY_MODE` → **`standard`**.
289
295
 
296
+ ### Work-kind routing hook (US-0118 / DEC-0118) — step 0a
297
+
298
+ When `WORK_KIND_ROUTING=1` (default `0` — zero overhead when off), step 0
299
+ calls `scripts/work_kind_routing_lib.resolve_delivery_mode_with_work_kind(...)`
300
+ **after** the existing delivery-mode resolver. The hook implements the **L8
301
+ precedence chain**: `start-from` (always wins) > explicit `DELIVERY_MODE` >
302
+ explicit `AUTO_PHASE_*` > `WORK_KIND_ROUTING`-derived > current default.
303
+ When `WORK_KIND_ROUTING=0`, the hook is a no-op (early-return
304
+ `(standard, full_plan, "WORK_KIND_ROUTING_OFF")` — byte-identical to
305
+ pre-US-0118). When both `WORK_KIND_ROUTING=1` and explicit `DELIVERY_MODE`
306
+ are set, explicit wins and `WORK_KIND_DELIVERY_MODE_CONFLICT` is emitted.
307
+ The classifier reuses `scripts/dev_environment_lib.classify_touched_files`
308
+ (tier A/B/C + `TIER_C_SKIP_PREFIXES`) — import, do not reinvent (Q9 LOCKED).
290
309
  | `delivery_mode` | `resolved_phase_plan` | `reinstatement_mode` | `memory_layer` |
291
310
  |-----------------|----------------------|---------------------|----------------|
292
311
  | `standard` | Full **DEC-0052** chain | `dec0052_default` | `standard` |
@@ -311,7 +330,7 @@ Four macro-phases — **no** eleven-phase reinstatement when `delivery_mode=ultr
311
330
  | **`spec`** | intake + discovery | **po** |
312
331
  | **`plan`** | research + architecture + sprint-plan | **tech-lead** |
313
332
  | **`build+verify`** | execute + qa + verify-work | **dev** / **qa** |
314
- | **`ship`** | release + refresh-context | **release** / **curator** |
333
+ | **`ship`** | release + closure + refresh-context | **release** / **qe** / **curator** |
315
334
 
316
335
  **`AUTO_IMPLEMENTATION_LOOP`** preserved inside **`build+verify`**. QA merges AC checklist + UAT
317
336
  in one spawn.
@@ -340,7 +359,7 @@ Treat **resolved phase plan** as fail-closed schedule from merged scratchpad **b
340
359
  resume / `start-from` intersection. Canonical lifecycle:
341
360
 
342
361
  `intake` → `discovery` → `research` → `architecture` → `sprint-plan` →
343
- `plan-verify` → `execute` → `qa` → `verify-work` → `release` → `refresh-context`
362
+ `plan-verify` → `execute` → `qa` → `verify-work` → `release` → `closure` → `refresh-context`
344
363
 
345
364
  Selectors and reinstatement: see reference. Phase-plan reason codes include
346
365
  `PHASE_POLICY_CONFLICT`, `PHASE_PLAN_UNKNOWN_PHASE`, `START_FROM_PHASE_PLAN_EMPTY_INTERSECTION`.
@@ -447,7 +466,7 @@ Phase-completion boundary evaluation only. **Guarded auto-push eligibility chain
447
466
  ## Canonical `start-from` phase IDs
448
467
 
449
468
  `intake`, `discovery`, `research`, `architecture`, `sprint-plan`, `plan-verify`,
450
- `execute`, `qa`, `verify-work`, `release`, `refresh-context` — aliases invalid.
469
+ `execute`, `qa`, `verify-work`, `release`, `closure`, `refresh-context` — aliases invalid.
451
470
 
452
471
  ## Deterministic resume-source precedence
453
472
 
@@ -621,3 +640,34 @@ applies for `/auto` continuation.
621
640
 
622
641
  Follow `docs/engineering/artifact-ordering-policy.md` (`state.md` append-bottom, etc.);
623
642
  `ARTIFACT_ORDERING_ANCHOR_AMBIGUOUS` fail-closed.
643
+
644
+ ## Autonomy presets (US-0119 / DEC-0119)
645
+
646
+ Default-off autonomy preset expansion + stop-policy dispatch layer.
647
+
648
+ When `AUTONOMY_PRESET={none|balanced|full}` is set (default `none`), the orchestrator
649
+ calls `scripts/autonomy_preset_lib.expand_autonomy_preset(preset, overrides)` before
650
+ phase dispatch to expand the single preset flag into 8 (balanced) or 12 (full) per-feature
651
+ autonomy flags. Precedence: explicit per-flag override in scratchpad always wins over
652
+ preset expansion. Expansion is deterministic; no LLM, no network, no `.env` reads
653
+ (R-0107 Q3 LOCKED).
654
+
655
+ When `AUTONOMY_STOP_POLICY={block|auto_repair_then_block|auto_repair_then_skip}` is
656
+ set (default `block`), stop dispatch classifies every fail-closed reason code as
657
+ `security_hard` (never auto-resolved; block immediately — `auto_repair_kind=n/a`; cap=0)
658
+ or `autonomy_resolvable` (bounded auto-repair permitted when policy != `block`; cap per
659
+ (run, reason_code) from `scripts/data/autonomy_stop_matrix.yaml`; default 3 per Q3 LOCKED).
660
+
661
+ When `AUTONOMY_STOP_POLICY != block`, bounded auto-repair attempts are logged to
662
+ append-only ledger at `handoffs/autonomy_repair_ledger/<orchestrator_run_id>.jsonl`.
663
+ Cap exhaustion emits terminal stop `AUTONOMY_REPAIR_CAP_EXHAUSTED` (distinct from
664
+ `BLOCK_RETRY_CAP_EXHAUSTED`; run-level vs story-level per Q9 LOCKED).
665
+
666
+ Operator audit breadcrumb: `autonomy_relaxed: <reason_code> -> <auto_repair_kind>`
667
+ emitted in `docs/engineering/state.md` at phase boundary (one line per soft-stop per
668
+ Q10 LOCKED — not aggregated).
669
+
670
+ Compose do-not-amend guards: `/intake`, `/execute`, `/qa`, `/release` consume US-0119
671
+ flags additively; their pre-existing contract surfaces are NOT rewritten.
672
+ `scripts/validate_autonomy_stop_matrix.py --self-test` enforces matrix invariants.
673
+ Byte-stability surface at `its_magic/README.md` 7th sub-block `### Autonomy preset keys`.
@@ -0,0 +1,184 @@
1
+ # /closure — dedicated story closure phase
2
+
3
+ ## Phase role
4
+
5
+ - **phase_id**: `closure`
6
+ - **role**: `qe`
7
+ - **override**: `AUTO_ROLE_CLOSURE` scratchpad key allows `qe` or `curator`; default `qe` when empty (DEC-0052, §2 override, §3 preflight capability gate).
8
+
9
+ ## Phase responsibility
10
+
11
+ Story Closure holds exclusive responsibility for:
12
+
13
+ 1. Status flip in `docs/product/backlog.md` (canonical status owner per US-0045): `Status: OPEN` → `Status: DONE`
14
+ 2. Acceptance checkbox in `docs/product/acceptance.md`: `- [ ]` → `- [x]`
15
+ 3. Closure checkpoint append to `docs/engineering/state.md` (append-bottom per US-0058 / DEC-0040)
16
+ 4. Creation of per-sprint closure verification artifact: `sprints/Sxxxx/closure-verification.md`
17
+
18
+ `/closure` runs AFTER `/release` completes with PASS verdict and BEFORE `/refresh-context`.
19
+
20
+ ## Phase ordering (ship macro per DEC-0082)
21
+
22
+ | Position | Phase | Role |
23
+ |----------|-------|------|
24
+ | 1 | `/release` | `release` |
25
+ | 2 | `/closure` | `qe` |
26
+ | 3 | `/refresh-context` | `curator` |
27
+
28
+ `/closure` is now the **second** phase of the `ship` macro. `/release` no longer performs backlog reconciliation (steps 10-12 removed).
29
+
30
+ ## Inputs
31
+
32
+ The `/closure` phase consumes the following release artifacts as input evidence (all three are FAIL-gated input prerequisites):
33
+
34
+ | Artifact | Path | Required |
35
+ |----------|------|----------|
36
+ | Release queue row | `handoffs/release_queue.md` (target sprint, `status=released`) | YES |
37
+ | Release notes | `handoffs/releases/Sxxxx-release-notes.md` (with PASS verdict) | YES |
38
+ | QA findings | `sprints/Sxxxx/qa-findings.md` | YES |
39
+ | UAT (optional) | `sprints/Sxxxx/uat.json` / `sprints/Sxxxx/uat.md` | OPTIONAL |
40
+ | Release findings (optional) | `sprints/Sxxxx/release-findings.md` | OPTIONAL |
41
+
42
+ ## Outputs (artifacts)
43
+
44
+ `/closure` produces the following artifacts:
45
+
46
+ | Artifact | Path | Responsibility |
47
+ |----------|------|----------------|
48
+ | Closure verification | `sprints/Sxxxx/closure-verification.md` | Per-sprint closure execution record |
49
+ | Backlog status flip | `docs/product/backlog.md` (target story block only) | `Status: OPEN` → `Status: DONE` |
50
+ | Acceptance tick | `docs/product/acceptance.md` (target row only) | `- [ ]` → `- [x]` |
51
+ | Closure checkpoint | `docs/engineering/state.md` (append-bottom) | Phase boundary + isolation evidence + runtime proof |
52
+
53
+ ## Stop conditions
54
+
55
+ - Release evidence missing for target sprint → `CLOSURE_RELEASE_EVIDENCE_MISSING`
56
+ - Canonical status source contradictory (release evidence vs backlog state) → `CANONICAL_STATUS_CONFLICT`
57
+ - Multiple candidate stories ambiguous for closure → `CLOSURE_AMBIGUOUS_TARGET`
58
+ - Target story not found in backlog.md → `CLOSURE_TARGET_NOT_FOUND`
59
+
60
+ ## Input prerequisites (fail-gated)
61
+
62
+ The following MUST be true before `/closure` can proceed. Fail closed with `CLOSURE_RELEASE_EVIDENCE_MISSING` if any check fails:
63
+
64
+ 1. `handoffs/release_queue.md` contains a row for the target sprint with `status=released`.
65
+ 2. `handoffs/releases/Sxxxx-release-notes.md` EXISTS and contains PASS verdict.
66
+ 3. `sprints/Sxxxx/qa-findings.md` EXISTS (QA completion evidence).
67
+
68
+ If any prerequisite fails:
69
+ - Do not mutate backlog.md, acceptance.md, or state.md.
70
+ - Append `CLOSURE_RELEASE_EVIDENCE_MISSING` with specific missing-prerequisite list to `sprints/Sxxxx/closure-verification.md` (partial artifact — marks the attempt and the gap).
71
+ - Stop and require operator remediation before retry.
72
+
73
+ ## Backlog reconciliation contract (US-0043 / DEC-0021)
74
+
75
+ `/closure` now holds exclusive responsibility for backlog reconciliation.
76
+
77
+ Canonical evidence precedence:
78
+ 1. `handoffs/release_queue.md` target sprint row (`status=released` required)
79
+ 2. `handoffs/releases/Sxxxx-release-notes.md` gate summary
80
+ 3. `sprints/Sxxxx/qa-findings.md`
81
+ 4. `sprints/Sxxxx/uat.json` and `sprints/Sxxxx/uat.md`
82
+ 5. `sprints/Sxxxx/release-findings.md` (if present)
83
+
84
+ Deterministic reconciliation behavior:
85
+ - Mutate only target sprint story blocks in `docs/product/backlog.md`
86
+ - Set target story `Status: DONE` when mandatory release evidence is PASS
87
+ - Reconcile target story acceptance checkboxes to checked state in `docs/product/acceptance.md`
88
+ - Never mutate unrelated backlog stories
89
+
90
+ ## Canonical status source and global drift guard (US-0045 / DEC-0025)
91
+
92
+ Canonical ownership:
93
+ - Story status (`OPEN|DONE`) is authoritative in `docs/product/backlog.md`.
94
+ - `docs/product/acceptance.md` and `docs/engineering/state.md` are derived views.
95
+
96
+ Deterministic reconciliation precedence:
97
+ 1. `docs/product/backlog.md` story status (canonical status owner)
98
+ 2. Target sprint release evidence
99
+ 3. Derived-view updates (`docs/product/acceptance.md`, `docs/engineering/state.md`)
100
+
101
+ ## Orchestrator post-closure verification protocol
102
+
103
+ After `/closure` subagent returns, the orchestrator runs direct `rg` verification (materialization fidelity check):
104
+
105
+ 1. `rg "^- Status: DONE$" docs/product/backlog.md` constrained to target story block
106
+ 2. `rg "^\- \[x\] US-xxxx:" docs/product/acceptance.md` targeted row
107
+ 3. State.md: `rg "phase_id=closure" docs/engineering/state.md` combined with `rg "story_id=US-xxxx"`
108
+ 4. `rg "story_id.*US-xxxx" sprints/Sxxxx/closure-verification.md`
109
+
110
+ If ANY check fails → escalate `CLOSURE_VERIFICATION_FAILED` with specific check that failed.
111
+
112
+ ## closure-verification.md schema
113
+
114
+ Required fields (in `sprints/Sxxxx/closure-verification.md`):
115
+ - `story_id` (US-xxxx)
116
+ - `closure_date` (ISO-8601 UTC)
117
+ - `closure_role` (qe|curator)
118
+ - `pre_closure_status` (OPEN)
119
+ - `post_closure_status` (DONE)
120
+ - `release_evidence_refs[]` (array of paths)
121
+ - `isolation_evidence{}` (object per US-0048 / DEC-0029)
122
+ - `runtime_proof{}` (object per US-0056 / DEC-0038)
123
+
124
+ Optional fields:
125
+ - `normalization_notes` — edge cases
126
+ - `backward_compat_note` — for in-flight story closure
127
+
128
+ Validate with: `python scripts/validate_closure_verification.py --file sprints/Sxxxx/closure-verification.md`
129
+
130
+ ## Artifact ordering contract (US-0058 / DEC-0040)
131
+
132
+ `/closure` mutations follow strict ordering:
133
+ 1. `docs/product/backlog.md` (status flip — canonical status owner)
134
+ 2. `docs/product/acceptance.md` (checkbox tick — derived view)
135
+ 3. `docs/engineering/state.md` (closure checkpoint append — append-bottom only)
136
+ 4. `sprints/Sxxxx/closure-verification.md` (new artifact)
137
+
138
+ ## Cross-phase ownership guard (US-0061 / DEC-0043)
139
+
140
+ `/closure` owns ONLY:
141
+ - Status flip in `docs/product/backlog.md` (target story block)
142
+ - Checkbox tick in `docs/product/acceptance.md` (target row)
143
+ - Closure checkpoint append in `docs/engineering/state.md`
144
+ - `sprints/Sxxxx/closure-verification.md` creation
145
+
146
+ `/closure` must NOT touch:
147
+ - Release artifacts (`handoffs/releases/Sxxxx-release-notes.md`, `handoffs/release_queue.md`)
148
+ - QA artifacts (`sprints/Sxxxx/qa-findings.md`, `handoffs/qa_to_dev.md`)
149
+ - Execute artifacts (`sprints/Sxxxx/summary.md`, code changes)
150
+
151
+ ## Drain hook backward compatibility (AC-10)
152
+
153
+ For in-flight stories at US-0120 ship boundary (stories that completed `/release` before `/closure` existed):
154
+ - 3-signal detection: (i) release_queue row `status=released`, (ii) backlog.md `Status: OPEN`, (iii) acceptance.md `[ ]` unchecked → closure SKIPPED → orchestrator spawn `/closure` backfill.
155
+ - For `Status: DONE` stories: SKIP (already closed).
156
+ - Pre-US-0120 stories with all three signals: emit `CLOSURE_LEGACY_DRIFT` + manual reconciliation guidance.
157
+
158
+ ## Fail-safe reason codes and remediation guidance
159
+
160
+ | Reason code | Condition | Remediation |
161
+ |---|---|---|
162
+ | `CLOSURE_RELEASE_EVIDENCE_MISSING` | Input prerequisite not met | Complete `/release` first |
163
+ | `CLOSURE_VERIFICATION_FAILED` | Orchestrator post-verification rg check failed | Re-run `/closure` |
164
+ | `CANONICAL_STATUS_CONFLICT` | Backlog status contradicts release evidence | Resolve contradiction manually |
165
+ | `BACKLOG_STATUS_DRIFT` | Backlog not reconciled after closure | Re-run `/closure` |
166
+ | `PHASE_OWNERSHIP_VIOLATION` | `/closure` tried to mutate non-owned artifact | Check cross-phase ownership guard |
167
+ | `PHASE_OVERRIDE_EVIDENCE_MISSING` | Override path configured but evidence missing | Provide override evidence or disable override |
168
+ | `CLOSURE_LEGACY_DRIFT` | Pre-US-0120 story with released+OPEN | Manual reconciliation or backfill closure |
169
+
170
+ ## Strict runtime proof (DEC-0038)
171
+
172
+ Each `/closure` execution must produce own strict runtime proof with unique `runtime_proof_id`:
173
+ - runtime_proof_id (unique per closure run)
174
+ - proof_hash (SHA-256 of canonical payload)
175
+ - proof_ttl_seconds (3600)
176
+ - proof_issued_at (ISO-8601 UTC)
177
+
178
+ ## Isolation evidence (US-0048 / DEC-0029)
179
+
180
+ Each `/closure` execution must produce own isolation evidence:
181
+ - phase_id=closure, role=qe (or curator)
182
+ - fresh_context_marker (unique per run per BUG-0006)
183
+ - timestamp (ISO-8601 UTC)
184
+ - evidence_ref (sprints/Sxxxx/closure-verification.md)
@@ -241,6 +241,32 @@ and assumption binding. **Do not** mutate `docs/product/backlog.md` or
241
241
  `assumptions_confirmed`, `topic_coverage`, assumption ref fields per
242
242
  **DEC-0060**, and first-intake coverage fields (`plan_area_inventory`,
243
243
  `plan_area_coverage`, `coverage_complete`) in relevant intake artifacts.
244
+
245
+ 4b. **Work-kind classifier hook (US-0118 / DEC-0118)** — after the
246
+ decomposition evaluator (step 4) and before persistence (step 5+):
247
+ - Read `WORK_KIND_ROUTING` from `.cursor/scratchpad.md` (`0|1`, default
248
+ `0`). When `0`, skip the classifier proposal entirely (zero overhead —
249
+ byte-identical to pre-US-0118). When `1`, proceed.
250
+ - Run `scripts/work_kind_classify_lib.classify_work_kind(story_prose,
251
+ acceptance_criteria, touched_file_hints, component_scope)` — pure
252
+ stdlib, no LLM, no network, no `.env` reads (Q3 LOCKED).
253
+ - Present the proposed `work_kind` (`doc|mini|code`) and
254
+ `recommended_delivery_mode` (`standard|ultra_lean|mega_quick`) to the
255
+ operator for accept/override (Q9 LOCKED). Operator decision recorded in
256
+ the intake evidence bundle.
257
+ - On `accept`: persist `- work_kind: <value>` and
258
+ `- recommended_delivery_mode: <value>` rows in the backlog story block
259
+ + `work_kind`, `recommended_delivery_mode`,
260
+ `work_kind_operator_decision=accept` in the intake evidence bundle.
261
+ - On `override`: operator may set a different
262
+ `work_kind`/`recommended_delivery_mode` (or leave both unset to defer
263
+ routing to `DELIVERY_MODE`/`AUTO_PHASE_*`); record
264
+ `work_kind_operator_decision=override` in the evidence bundle.
265
+ - Absence of `work_kind`/`recommended_delivery_mode` is valid (classifier
266
+ not run or operator declined) — no forced reclassification.
267
+ - **US-0078 evidence gate still runs before any backlog/acceptance
268
+ write** (step 5 — L10 unchanged).
269
+
244
270
  6. Optional fresh-project ID namespace bootstrap (US-0052 / DEC-0034):
245
271
  - Read `ID_NAMESPACE_BOOTSTRAP` from `.cursor/scratchpad.md` (`0|1`,
246
272
  default `0`).
@@ -331,31 +331,22 @@ Guardrails:
331
331
  9. On successful finalization, transition only target sprint:
332
332
  `unreleased -> released`.
333
333
  - Update `last_updated`, `release_version` (when available), and gate summary.
334
- 10. Reconcile target story backlog status + acceptance checkboxes in
335
- `docs/product/backlog.md` using US-0043 and US-0045 contracts.
336
- - Apply only to target sprint-linked stories.
337
- - If contradictory states remain after reconciliation attempt, fail closed
338
- with `BACKLOG_STATUS_DRIFT` or `CANONICAL_STATUS_CONFLICT`, write
339
- remediation guidance, and stop.
340
- 11. Reconcile derived status views from canonical backlog status:
341
- - update linked rows/checklists in `docs/product/acceptance.md`,
342
- - append deterministic status checkpoint in `docs/engineering/state.md`,
343
- - preserve non-target entries unchanged.
344
- 12. If one-time normalization baseline is missing, run the documented
345
- normalization pass and write auditable report rows to
346
- `docs/engineering/status-normalization-report.md` (story id, prior values,
347
- resolved values, evidence refs, timestamp).
348
- 13. Update backward-compatible legacy file `handoffs/release_notes.md` as
334
+ 10. Backlog reconciliation is now handled by the dedicated `/closure` phase —
335
+ see `.cursor/commands/closure.md`. Story Closure holds exclusive responsibility
336
+ for status flip (OPEN→DONE in `docs/product/backlog.md`), acceptance tick
337
+ ([ ]→[x] in `docs/product/acceptance.md`), closure checkpoint append to
338
+ `docs/engineering/state.md`, and creation of `sprints/Sxxxx/closure-verification.md`.
339
+ 11. Update backward-compatible legacy file `handoffs/release_notes.md` as
349
340
  latest-release pointer and summary:
350
341
  - include latest released sprint id,
351
342
  - include pointer to canonical sprint-scoped notes file,
352
343
  - include visibility section for unreleased queue entries.
353
- 14. Update runbook/state readiness and evidence references for release outcome.
344
+ 12. Update runbook/state readiness and evidence references for release outcome.
354
345
  - On pass, ensure `sprints/Sxxxx/release-findings.md` records release outcome
355
346
  (`PASS`) and references final evidence artifacts.
356
- 15. If `AUTO_RELEASE_NOTES=1` in `.cursor/scratchpad.md`, generation logic must
347
+ 13. If `AUTO_RELEASE_NOTES=1` in `.cursor/scratchpad.md`, generation logic must
357
348
  still target sprint-scoped notes first and update legacy pointer second.
358
- 16. Optional configurable publish targets (US-0054 / DEC-0036):
349
+ 14. Optional configurable publish targets (US-0054 / DEC-0036):
359
350
  - Read `.cursor/scratchpad.md`:
360
351
  - `RELEASE_PUBLISH_MODE=disabled|confirm|auto`
361
352
  - `RELEASE_TARGETS_FILE`
@@ -379,7 +370,7 @@ Guardrails:
379
370
  `PUBLISH_TARGET_CONFIG_INVALID`.
380
371
  - If target execution fails, emit `PUBLISH_TARGET_EXECUTION_FAILED` with
381
372
  target ID and remediation; do not mutate unrelated release artifacts.
382
- 17. Remote runtime connectivity contract (US-0064 / DEC-0044):
373
+ 15. Remote runtime connectivity contract (US-0064 / DEC-0044):
383
374
  - Extend target interpretation with runtime metadata from
384
375
  `RELEASE_TARGETS_FILE`:
385
376
  - `runtime.mode` (`local|remote`),
@@ -394,7 +385,7 @@ Guardrails:
394
385
  and local vs remote execution context.
395
386
  - In release output/handoffs, include operator connection guidance
396
387
  (where hosted, how to connect) without exposing secrets.
397
- 18. Release operator Run/Connect/Verify hints contract (US-0067 / DEC-0049):
388
+ 16. Release operator Run/Connect/Verify hints contract (US-0067 / DEC-0049):
398
389
  - `handoffs/releases/Sxxxx-release-notes.md` must include a deterministic
399
390
  operator section order and required fields:
400
391
  1) `## Run`:
@@ -425,20 +416,20 @@ Guardrails:
425
416
  - `RELEASE_OPERATOR_HINTS_SECRET_EXPOSURE`
426
417
  - Remediation: populate required fields in canonical sprint notes with
427
418
  sanitized env-ref-only credential guidance, then rerun `/release`.
428
- 19. Version changelog derivation (US-0100 / DEC-0085):
419
+ 17. Version changelog derivation (US-0100 / DEC-0085):
429
420
  - Runs **only after** step **9** successful finalization (`unreleased → released`)
430
- and step **18** operator hints (**US-0067**). Doc writes are **not** publish
421
+ and step **16** operator hints (**US-0067**). Doc writes are **not** publish
431
422
  execution — **`RELEASE_PUBLISH_MODE=disabled`** remains valid (**US-0054**).
432
- - **19a — Resolve semver**: read target queue row **`release_version`**; when
423
+ - **17a — Resolve semver**: read target queue row **`release_version`**; when
433
424
  blank, workflow-only release → **`[Unreleased]`** path only (no per-version file).
434
- - **19b — Derive work items**: `derive_work_items` for target sprint + coalesce
425
+ - **17b — Derive work items**: `derive_work_items` for target sprint + coalesce
435
426
  peer **`released`** rows sharing normalized semver when semver known
436
427
  (`coalesce_sprints_by_semver`).
437
- - **19c — Write docs**: when semver known → `build_version_doc` +
428
+ - **17c — Write docs**: when semver known → `build_version_doc` +
438
429
  `promote_unreleased` + `bind_queue_release_version`; else `append_unreleased`
439
430
  only. Per-version SOT = `handoffs/releases/{semver}-release-notes.md` (stem
440
431
  without leading **`v`**). Never pass `Sxxxx-release-notes.md` to **`gh -F`**.
441
- - **19d — Validate (optional enforce)**: when scratchpad
432
+ - **17d — Validate (optional enforce)**: when scratchpad
442
433
  **`RELEASE_CHANGELOG_ENFORCE=1`** (default **`1`** post-bootstrap), run
443
434
  `python scripts/release_changelog_validate.py --repo . --enforce`; record
444
435
  outcome in `sprints/Sxxxx/release-findings.md` § version-doc gates. When