its-magic 0.1.3-1 → 0.1.3-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.
- package/installer.ps1 +8 -0
- package/installer.py +8 -0
- package/installer.sh +1 -0
- package/package.json +1 -1
- package/template/.cursor/commands/auto.md +90 -0
- package/template/.cursor/commands/execute.md +26 -0
- package/template/.cursor/commands/refresh-context.md +32 -0
- package/template/.cursor/commands/sovereign-critic.md +104 -0
- package/template/.cursor/rules/sovereign-role-manifest.mdc.example +27 -0
- package/template/.cursor/scratchpad.md +141 -0
- package/template/.cursor/sovereign-role-manifest.yaml.example +53 -0
- package/template/decisions/DEC-0104.md +279 -0
- package/template/decisions/DEC-0105.md +231 -0
- package/template/decisions/DEC-0107.md +246 -0
- package/template/docs/engineering/architecture.md +78 -0
- package/template/docs/engineering/auto-orchestration-reference.md +7 -0
- package/template/docs/engineering/context/installer-owned-paths.manifest +8 -0
- package/template/docs/engineering/reason_codes.md +411 -0
- package/template/docs/engineering/runbook.md +922 -0
- package/template/docs/engineering/sovereign-memory/.gitkeep +0 -0
- package/template/docs/engineering/sovereign-memory/retrospectives/.gitkeep +0 -0
- package/template/handoffs/sovereign_decisions/.gitkeep +0 -0
- package/template/handoffs/sovereign_deferrals/.gitkeep +0 -0
- package/template/handoffs/sovereign_role_reviews.jsonl +0 -0
- package/template/scripts/__pycache__/decision_ledger_lib.cpython-312.pyc +0 -0
- package/template/scripts/check_intake_template_parity.py +119 -0
- package/template/scripts/decision_ledger_lib.py +732 -0
- package/template/scripts/ledger_validate.py +153 -0
- package/template/scripts/parallel_dev_arbiter.py +923 -0
- package/template/scripts/release_trigger_adapters.py +843 -0
- package/template/scripts/self_healing_deploy_lib.py +463 -0
- package/template/scripts/self_healing_deploy_validate.py +78 -0
- package/template/scripts/sovereign_convergence_lib.py +994 -0
- package/template/scripts/sovereign_convergence_validate.py +206 -0
- package/template/scripts/sovereign_critic_lib.py +629 -0
- package/template/scripts/sovereign_critic_validate.py +131 -0
- package/template/scripts/sovereign_loop_lib.py +828 -0
- package/template/scripts/sovereign_loop_validate.py +122 -0
- package/template/scripts/sovereign_memory_lib.py +869 -0
- package/template/scripts/sovereign_memory_validate.py +153 -0
- package/template/scripts/sovereign_role_manifest_lib.py +547 -0
- package/template/scripts/sovereign_role_manifest_validate.py +105 -0
- package/template/tests/us0108_contract_test.py +207 -0
- package/template/tests/us0109_contract_test.py +209 -0
- package/template/tests/us0109_us0110_compose_test.py +34 -0
- package/template/tests/us0111_contract_test.py +345 -0
|
@@ -938,6 +938,83 @@ If the default set is insufficient, escalate with an explicit note citing
|
|
|
938
938
|
- If unresolved after bounded expansion, answer with explicit "not found in
|
|
939
939
|
current artifacts" rather than broad speculative reads.
|
|
940
940
|
|
|
941
|
+
## Model-catalog example preset delivery (US-0112 / DEC-0112)
|
|
942
|
+
|
|
943
|
+
**Default state**: 8 committed `model-catalog.local.example*.json` presets ship with the
|
|
944
|
+
`its-magic` framework and are delivered to operator repos via the installer manifest
|
|
945
|
+
(`docs/engineering/context/installer-owned-paths.manifest` [install_include_paths]) under
|
|
946
|
+
**framework-file semantics** (US-0018 / US-0057 / US-0075 precedence).
|
|
947
|
+
|
|
948
|
+
### Eight preset filenames (manifest rows)
|
|
949
|
+
|
|
950
|
+
1. `.cursor/model-catalog.local.example.json` — base placeholder (three tiers, opaque vendor slugs)
|
|
951
|
+
2. `.cursor/model-catalog.local.example.cursor-only.json` — Cursor-first alias mapping
|
|
952
|
+
3. `.cursor/model-catalog.local.example.level-1-easy.json` — easy complexity tier set
|
|
953
|
+
4. `.cursor/model-catalog.local.example.level-2-complex.json` — moderate complexity tier set
|
|
954
|
+
5. `.cursor/model-catalog.local.example.level-3-mega.json` — heavy complexity tier set
|
|
955
|
+
6. `.cursor/model-catalog.local.example.level-4-super.json` — maximal complexity tier set
|
|
956
|
+
7. `.cursor/model-catalog.local.example.role-based-balanced.json` — role-catalog balanced preset
|
|
957
|
+
8. `.cursor/model-catalog.local.example.role-based-highend.json` — role-catalog high-end preset
|
|
958
|
+
|
|
959
|
+
### Installer behavior (framework-file semantics)
|
|
960
|
+
|
|
961
|
+
- **`missing` mode** (default new install): copies the 8 example presets into the target
|
|
962
|
+
`.cursor/` directory when absent; deterministic status log per file (names only; no content
|
|
963
|
+
inspection); same semantics as `scratchpad.local.example.md` per US-0075.
|
|
964
|
+
- **`upgrade` mode**: refreshes the example presets when the packaged template version
|
|
965
|
+
differs (byte-compare); skips byte-identical files; never modifies or removes the active
|
|
966
|
+
operator-owned `.cursor/model-catalog.local.json` (gitignored; not in manifest).
|
|
967
|
+
- **Triple installer parity**: `installer.py`, `installer.ps1`, `installer.sh` all read the
|
|
968
|
+
single manifest `[install_include_paths]` as source of truth; framework classification
|
|
969
|
+
for `.cursor/model-catalog.local.example*.json` is identical across Python / PowerShell /
|
|
970
|
+
Bash `classify_file` paths.
|
|
971
|
+
|
|
972
|
+
### Operator usage recipe
|
|
973
|
+
|
|
974
|
+
1. Inspect the 8 presets under `.cursor/` (shipped automatically by install or upgrade).
|
|
975
|
+
2. Choose a preset matching your intent — complexity-based (levels 1–4) or role-based
|
|
976
|
+
(balanced / highend) for `MODEL_RESOLVE=role_catalog`; cursor-only alias mapping; or
|
|
977
|
+
base template for custom tiers.
|
|
978
|
+
3. Copy the chosen preset: `cp .cursor/model-catalog.local.example.<preset>.json .cursor/model-catalog.local.json`.
|
|
979
|
+
4. Edit real vendor slugs into `.cursor/model-catalog.local.json` (placeholder values
|
|
980
|
+
substituted; vendor-specific).
|
|
981
|
+
5. Set `MODEL_RESOLVE=local_catalog` (or `role_catalog` for role-based presets) in
|
|
982
|
+
`.cursor/scratchpad.local.md`.
|
|
983
|
+
6. Validate: `python scripts/model_tier_validate.py --repo .`.
|
|
984
|
+
7. Parity: `python scripts/check_intake_template_parity.py --scope=model-catalog-examples`.
|
|
985
|
+
|
|
986
|
+
**Active catalog protection invariant**: `.cursor/model-catalog.local.json` remains
|
|
987
|
+
gitignored and outside `install_include_paths` + `clean_paths`. The installer never
|
|
988
|
+
auto-populates it. No installer mode copies, merges, or replaces the active catalog.
|
|
989
|
+
This is a DEC-0086 / DEC-0087 boundary (US-0101 catalog schema + US-0102 role precedence
|
|
990
|
+
remain unaltered; US-0112 only completes delivery path).
|
|
991
|
+
|
|
992
|
+
### Parity scope
|
|
993
|
+
|
|
994
|
+
```bash
|
|
995
|
+
python scripts/check_intake_template_parity.py --scope=model-catalog-examples
|
|
996
|
+
```
|
|
997
|
+
|
|
998
|
+
Validates active vs template byte-parity for `installer-owned-paths.manifest` (16 manifest
|
|
999
|
+
rows total across active + template paths). On mismatch → `MODEL_CATALOG_EXAMPLE_PARITY_SCOPE_MISMATCH`.
|
|
1000
|
+
On pass → `[MODEL_CATALOG_EXAMPLE_PARITY_SCOPE_OK]`.
|
|
1001
|
+
|
|
1002
|
+
### Reason codes
|
|
1003
|
+
|
|
1004
|
+
| Code | Trigger |
|
|
1005
|
+
|------|---------|
|
|
1006
|
+
| `MODEL_CATALOG_EXAMPLE_PARITY_SCOPE_OK` | Active vs template manifest byte-parity pass for 8 model-catalog.example paths |
|
|
1007
|
+
| `MODEL_CATALOG_EXAMPLE_PARITY_SCOPE_MISMATCH` | Active vs template manifest byte-parity fail |
|
|
1008
|
+
|
|
1009
|
+
### Validation commands
|
|
1010
|
+
|
|
1011
|
+
- `python scripts/check_intake_template_parity.py --scope=model-catalog-examples`
|
|
1012
|
+
- `pytest -k us0112 tests/us0112_contract_test.py`
|
|
1013
|
+
|
|
1014
|
+
Normative architecture: `docs/engineering/architecture.md` (**# US-0112**); decision: **`DEC-0112`** (Accepted).
|
|
1015
|
+
|
|
1016
|
+
Binding decision: `decisions/DEC-0112.md`. Research anchor: `docs/engineering/research.md` **R-0090**.
|
|
1017
|
+
|
|
941
1018
|
## Configurable multi-target publish mode (US-0054 / DEC-0036)
|
|
942
1019
|
|
|
943
1020
|
Post-release publish orchestration is configurable and default-safe:
|
|
@@ -2579,6 +2656,851 @@ Single-writer drift safety:
|
|
|
2579
2656
|
sourcing `.env` — the process inherits normal environment variables.
|
|
2580
2657
|
- Referencing env var **names** (not values) in documentation and handoffs.
|
|
2581
2658
|
|
|
2659
|
+
## AI Decision Ledger (US-0103 / DEC-0103)
|
|
2660
|
+
|
|
2661
|
+
**Default-off sovereign-loop audit layer**. When `AI_DECISION_LEDGER=0` (default),
|
|
2662
|
+
zero overhead — no files read or written. When `AI_DECISION_LEDGER=1`, every
|
|
2663
|
+
autonomous AI deviation is recorded in an append-only JSONL ledger under
|
|
2664
|
+
`handoffs/sovereign_decisions/<orchestrator_run_id>.jsonl`.
|
|
2665
|
+
|
|
2666
|
+
### Scratchpad keys
|
|
2667
|
+
|
|
2668
|
+
| Key | Values | Default | Behavior when off |
|
|
2669
|
+
|-----|--------|---------|-------------------|
|
|
2670
|
+
| `AI_DECISION_LEDGER` | `0` \| `1` | `0` | No reads / writes / schema checks. |
|
|
2671
|
+
| `AUTO_PLAN_FIDELITY` | `strict` \| `relaxed` \| `extended` | `strict` | Active only when ledger enabled. |
|
|
2672
|
+
|
|
2673
|
+
Set in `.cursor/scratchpad.local.md` (gitignored) or `.cursor/scratchpad.md`.
|
|
2674
|
+
|
|
2675
|
+
### Enable / disable
|
|
2676
|
+
|
|
2677
|
+
```bash
|
|
2678
|
+
# Enable ledger auditing
|
|
2679
|
+
echo "AI_DECISION_LEDGER=1" >> .cursor/scratchpad.local.md
|
|
2680
|
+
|
|
2681
|
+
# Switch fidelity mode (relaxed allows AC drop/reorder; extended allows scope add)
|
|
2682
|
+
echo "AUTO_PLAN_FIDELITY=relaxed" >> .cursor/scratchpad.local.md
|
|
2683
|
+
|
|
2684
|
+
# Disable (zero overhead)
|
|
2685
|
+
echo "AI_DECISION_LEDGER=0" >> .cursor/scratchpad.local.md
|
|
2686
|
+
```
|
|
2687
|
+
|
|
2688
|
+
### Audit ledger entries
|
|
2689
|
+
|
|
2690
|
+
```bash
|
|
2691
|
+
# Validate all ledger files in handoffs/sovereign_decisions/
|
|
2692
|
+
python scripts/ledger_validate.py --repo .
|
|
2693
|
+
|
|
2694
|
+
# Validate a single ledger file
|
|
2695
|
+
python scripts/ledger_validate.py --file handoffs/sovereign_decisions/auto-20260628-01.jsonl
|
|
2696
|
+
|
|
2697
|
+
# Print QA findings block (JSON)
|
|
2698
|
+
python scripts/ledger_validate.py --qa-find --orchestrator-run-id auto-20260628-01
|
|
2699
|
+
|
|
2700
|
+
# Validate with fail-closed enforcement
|
|
2701
|
+
python scripts/ledger_validate.py --repo . --enforce
|
|
2702
|
+
|
|
2703
|
+
# Library self-test
|
|
2704
|
+
python scripts/decision_ledger_lib.py --self-test
|
|
2705
|
+
```
|
|
2706
|
+
|
|
2707
|
+
### Plan-fidelity modes
|
|
2708
|
+
|
|
2709
|
+
| Mode | Behavior | When to use |
|
|
2710
|
+
|------|----------|-------------|
|
|
2711
|
+
| `strict` | Any unapproved deviation from `resolved_phase_plan` → **`PLAN_FIDELITY_VIOLATION` hard stop**. Operator must approve override or revert. | Default. Production runs, high-risk stories. |
|
|
2712
|
+
| `relaxed` | AI may drop/reorder existing ACs with ledger entry + QA-verifiable; new ACs/stories → `PLAN_FIDELITY_SCOPE_GATE` hard stop. | Iterative development where AC refinement is expected. |
|
|
2713
|
+
| `extended` | AI may extend scope with new stories/features; documented non-blocking in ledger as `PLAN_FIDELITY_EXTENSION`. QA still cross-checks. | Exploratory work, prototyping, scope discovery. |
|
|
2714
|
+
|
|
2715
|
+
### Typical audit workflow
|
|
2716
|
+
|
|
2717
|
+
1. **Enable ledger** before long `/auto` run: set `AI_DECISION_LEDGER=1` in scratchpad.
|
|
2718
|
+
2. **Run `/auto`** to completion — ledger writes accumulate in `handoffs/sovereign_decisions/<run_id>.jsonl`.
|
|
2719
|
+
3. **Run `/qa`** — phase reads ledger, emits `ledger_findings` block in `sprints/Sxxxx/qa-findings.md` with decision counts, risk tier distribution, and fail-closed code summary.
|
|
2720
|
+
4. **Inspect findings** — look for `violation_count > 0` (unapproved deviations) or `schema_invalid` status (corrupt ledger).
|
|
2721
|
+
5. **Remediate or approve** — if deviations justified, set `AUTO_PLAN_FIDELITY=relaxed` or `=extended` and re-run; otherwise revert changes.
|
|
2722
|
+
|
|
2723
|
+
### Common failure scenarios and recovery
|
|
2724
|
+
|
|
2725
|
+
| Reason code | Symptom | Recovery |
|
|
2726
|
+
|-------------|---------|----------|
|
|
2727
|
+
| `LEDGER_FILE_MISSING` | `AI_DECISION_LEDGER=1` but no ledger file for current run | Create `handoffs/sovereign_decisions/<run_id>.jsonl` or set `AI_DECISION_LEDGER=0` |
|
|
2728
|
+
| `LEDGER_SCHEMA_INVALID` | JSONL line fails 12-field schema validation | Open ledger, locate invalid line (validator prints line number), fix JSON syntax; if unrecoverable, truncate to last valid line |
|
|
2729
|
+
| `LEDGER_CORRUPT` | Whole file non-UTF-8 or broken JSON | Manual repair required; consider `git restore` from prior commit or truncate to known-good prefix |
|
|
2730
|
+
| `LEDGER_APPEND_FAILED` | Disk full, permission error, I/O error | Check disk space (`df -h`), file permissions (`ls -la handoffs/sovereign_decisions/`); retry after remediation |
|
|
2731
|
+
| `PLAN_FIDELITY_VIOLATION` | Unapproved deviation under strict mode | Review ledger last entry; if justified, switch to `AUTO_PLAN_FIDELITY=relaxed` in scratchpad and re-run `/execute`; otherwise revert AC changes |
|
|
2732
|
+
| `PLAN_FIDELITY_SCOPE_GATE` | New scope request under strict/relaxed mode | If scope-add intentional, switch to `AUTO_PLAN_FIDELITY=extended` and document in `sprints/Sxxxx/extension-report.md`; otherwise drop new scope |
|
|
2733
|
+
| `LEDGER_DISABLED` | Informational — `AI_DECISION_LEDGER=0` | No action required; zero overhead when off. Opt-in via scratchpad if ledger auditing desired. |
|
|
2734
|
+
|
|
2735
|
+
### Parity enforcement
|
|
2736
|
+
|
|
2737
|
+
```bash
|
|
2738
|
+
# Verify active ↔ template byte-parity for ledger scripts + scratchpad
|
|
2739
|
+
python scripts/check_intake_template_parity.py --scope=sovereign-ledger
|
|
2740
|
+
```
|
|
2741
|
+
|
|
2742
|
+
Pair table (`SOVEREIGN_LEDGER_PAIRS` + scratchpad):
|
|
2743
|
+
- `scripts/decision_ledger_lib.py` ↔ `template/scripts/decision_ledger_lib.py`
|
|
2744
|
+
- `scripts/ledger_validate.py` ↔ `template/scripts/ledger_validate.py`
|
|
2745
|
+
- `.cursor/scratchpad.md` ↔ `template/.cursor/scratchpad.md`
|
|
2746
|
+
- `.cursor/scratchpad.local.example.md` ↔ `template/.cursor/scratchpad.local.example.md`
|
|
2747
|
+
|
|
2748
|
+
### Related artifacts
|
|
2749
|
+
|
|
2750
|
+
- **Architecture**: `docs/engineering/architecture.md` `# US-0103`
|
|
2751
|
+
- **Reason codes**: `docs/engineering/reason_codes.md` § US-0103
|
|
2752
|
+
- **Decision record**: `decisions/DEC-0103.md`
|
|
2753
|
+
- **Contract tests**: `tests/us0103_contract_test.py` (8 tests)
|
|
2754
|
+
|
|
2755
|
+
## Goal-Based Convergence (US-0110 / DEC-0110)
|
|
2756
|
+
|
|
2757
|
+
**Default-off sovereign-loop terminal predicate**. When `SOVEREIGN_GOAL_MODE=phase_driven`
|
|
2758
|
+
(default), zero overhead — no evaluation, no `goal_progress` block, no partial-delivery write.
|
|
2759
|
+
When `goal_convergence`, `evaluate_convergence` reads composed surfaces (backlog, deferrals,
|
|
2760
|
+
critic, smoke, ledger) and emits progress/timeout artifacts only.
|
|
2761
|
+
|
|
2762
|
+
### Scratchpad keys
|
|
2763
|
+
|
|
2764
|
+
| Key | Values | Default | Behavior when off |
|
|
2765
|
+
|-----|--------|---------|-------------------|
|
|
2766
|
+
| `SOVEREIGN_GOAL_MODE` | `phase_driven` \| `goal_convergence` | `phase_driven` | No evaluation side effects. |
|
|
2767
|
+
| `SOVEREIGN_GOAL` | free-text | *(empty)* | Explicit goal wins over vision derive. |
|
|
2768
|
+
| `SOVEREIGN_GOAL_TOP_N` | int ≥ 1 | `3` | Vision paragraph count for auto-derive. |
|
|
2769
|
+
| `SOVEREIGN_GOAL_MAX_CHARS` | int ≥ 64 | `512` | Truncation cap for goal text. |
|
|
2770
|
+
| `SOVEREIGN_GOAL_TIMEOUT_MAX` | int ≥ 0 | `0` | Iteration-count cap (`0` = disabled). |
|
|
2771
|
+
|
|
2772
|
+
### Enable / disable
|
|
2773
|
+
|
|
2774
|
+
```bash
|
|
2775
|
+
# Enable goal-driven convergence
|
|
2776
|
+
echo "SOVEREIGN_GOAL_MODE=goal_convergence" >> .cursor/scratchpad.local.md
|
|
2777
|
+
echo "SOVEREIGN_GOAL=Ship sovereign-loop batch with zero regressions" >> .cursor/scratchpad.local.md
|
|
2778
|
+
|
|
2779
|
+
# Disable (zero overhead — US-0088/US-0092/US-0095/US-0044 stop matrix unchanged)
|
|
2780
|
+
echo "SOVEREIGN_GOAL_MODE=phase_driven" >> .cursor/scratchpad.local.md
|
|
2781
|
+
```
|
|
2782
|
+
|
|
2783
|
+
### Evaluate convergence
|
|
2784
|
+
|
|
2785
|
+
```bash
|
|
2786
|
+
# Library self-test
|
|
2787
|
+
python scripts/sovereign_convergence_lib.py --self-test
|
|
2788
|
+
|
|
2789
|
+
# Evaluate five-conjunct predicate (JSON)
|
|
2790
|
+
python scripts/sovereign_convergence_lib.py --evaluate --repo . --orchestrator-run-id auto-20260628-04
|
|
2791
|
+
|
|
2792
|
+
# Dump goal_progress block
|
|
2793
|
+
python scripts/sovereign_convergence_lib.py --dump-progress --repo . --orchestrator-run-id auto-20260628-04
|
|
2794
|
+
|
|
2795
|
+
# Validator self-test + schema fixtures
|
|
2796
|
+
python scripts/sovereign_convergence_validate.py --self-test
|
|
2797
|
+
|
|
2798
|
+
# Validate artifacts in repo
|
|
2799
|
+
python scripts/sovereign_convergence_validate.py --repo . --enforce
|
|
2800
|
+
```
|
|
2801
|
+
|
|
2802
|
+
### Interpret `goal_progress` block
|
|
2803
|
+
|
|
2804
|
+
Curator **`/refresh-context`** emits a fenced JSON block under **`### goal_progress`** in
|
|
2805
|
+
`handoffs/resume_brief.md` when `SOVEREIGN_GOAL_MODE=goal_convergence` and the sovereign loop
|
|
2806
|
+
is active. Placement: after the latest orchestration pointer, before prior pointers.
|
|
2807
|
+
|
|
2808
|
+
Fields: `goal_text`, `goal_source`, `mode`, `converged`, `unmet_conditions[]`, `blocked_by[]`,
|
|
2809
|
+
`conjuncts`, `evaluated_at`, `orchestrator_run_id`, `schema_version`.
|
|
2810
|
+
|
|
2811
|
+
### Partial delivery on timeout
|
|
2812
|
+
|
|
2813
|
+
When `SOVEREIGN_GOAL_TIMEOUT_MAX > 0` and iteration count reaches the cap without
|
|
2814
|
+
`converged=true`, the evaluator emits **`SOVEREIGN_GOAL_TIMEOUT`** and writes
|
|
2815
|
+
`handoffs/sovereign_partial_delivery.md` (sections: Goal, Evaluated At, Unmet Conditions,
|
|
2816
|
+
Blocked By, Completed Stories, Open Stories, Deferrals Summary, Remediation).
|
|
2817
|
+
|
|
2818
|
+
### Troubleshooting reason codes
|
|
2819
|
+
|
|
2820
|
+
See `docs/engineering/reason_codes.md` § US-0110 for the 10-code inventory and remediation.
|
|
2821
|
+
|
|
2822
|
+
| Reason code | Symptom | Recovery |
|
|
2823
|
+
|-------------|---------|----------|
|
|
2824
|
+
| `CONVERGENCE_OPEN_STORIES_REMAIN` | OPEN stories in backlog | Complete stories or adjust goal scope |
|
|
2825
|
+
| `CONVERGENCE_SMOKE_PROBE_FAIL` | `tests/report.md` Fail > 0 or UAT smoke step failed | Fix tests; re-run `/verify-work` |
|
|
2826
|
+
| `SOVEREIGN_GOAL_TIMEOUT` | Iteration cap exhausted | Read partial-delivery report; increase cap or resolve blockers |
|
|
2827
|
+
| `SOVEREIGN_GOAL_DERIVE_FAILED` | Empty/unreadable vision | Set explicit `SOVEREIGN_GOAL` |
|
|
2828
|
+
|
|
2829
|
+
### Parity enforcement
|
|
2830
|
+
|
|
2831
|
+
```bash
|
|
2832
|
+
python scripts/check_intake_template_parity.py --scope=sovereign-convergence
|
|
2833
|
+
```
|
|
2834
|
+
|
|
2835
|
+
Pair table (`SOVEREIGN_CONVERGENCE_PAIRS`):
|
|
2836
|
+
- `scripts/sovereign_convergence_lib.py` ↔ `template/scripts/sovereign_convergence_lib.py`
|
|
2837
|
+
- `scripts/sovereign_convergence_validate.py` ↔ `template/scripts/sovereign_convergence_validate.py`
|
|
2838
|
+
|
|
2839
|
+
### Related artifacts
|
|
2840
|
+
|
|
2841
|
+
- **Architecture**: `docs/engineering/architecture.md` `# US-0110`
|
|
2842
|
+
- **Reason codes**: `docs/engineering/reason_codes.md` § US-0110
|
|
2843
|
+
- **Decision record**: `decisions/DEC-0110.md`
|
|
2844
|
+
- **Contract tests**: `tests/us0110_contract_test.py` (8 tests)
|
|
2845
|
+
|
|
2846
|
+
### Cross-Model Adversarial Critic (US-0104)
|
|
2847
|
+
|
|
2848
|
+
**Default-off cross-model review**. When `CROSS_MODEL_REVIEW=0` (default), zero overhead — no
|
|
2849
|
+
critic spawn, no findings writes, no anti-slop gate. When `1`, `/auto` spawns `/sovereign-critic`
|
|
2850
|
+
after each producer phase.
|
|
2851
|
+
|
|
2852
|
+
#### Scratchpad keys
|
|
2853
|
+
|
|
2854
|
+
| Key | Values | Default | Behavior when off |
|
|
2855
|
+
|-----|--------|---------|-------------------|
|
|
2856
|
+
| `CROSS_MODEL_REVIEW` | `0` \| `1` | `0` | No critic spawn or findings writes. |
|
|
2857
|
+
| `CROSS_MODEL_ANTISLOP_THRESHOLD` | int 0–10 | `6` | Aggregate below → rework loop. |
|
|
2858
|
+
| `CROSS_MODEL_REWORK_MAX` | int ≥ 0 | `2` | Max producer re-spawns per `(run, phase)`. |
|
|
2859
|
+
|
|
2860
|
+
#### Enable / disable
|
|
2861
|
+
|
|
2862
|
+
```bash
|
|
2863
|
+
# Enable cross-model critic
|
|
2864
|
+
echo "CROSS_MODEL_REVIEW=1" >> .cursor/scratchpad.local.md
|
|
2865
|
+
|
|
2866
|
+
# Disable (zero overhead)
|
|
2867
|
+
echo "CROSS_MODEL_REVIEW=0" >> .cursor/scratchpad.local.md
|
|
2868
|
+
```
|
|
2869
|
+
|
|
2870
|
+
#### Validate findings JSONL
|
|
2871
|
+
|
|
2872
|
+
```bash
|
|
2873
|
+
python scripts/sovereign_critic_lib.py --self-test
|
|
2874
|
+
python scripts/sovereign_critic_validate.py --self-test
|
|
2875
|
+
python scripts/sovereign_critic_validate.py --repo . --enforce
|
|
2876
|
+
python scripts/sovereign_critic_validate.py --open-blocking --repo .
|
|
2877
|
+
```
|
|
2878
|
+
|
|
2879
|
+
#### Interpret findings JSONL
|
|
2880
|
+
|
|
2881
|
+
Canonical path: `handoffs/sovereign_critic_findings.jsonl` (append-only, 15-field v1 schema).
|
|
2882
|
+
Each line includes `lens` (`challenger` \| `architect` \| `subtractor`), `severity`, `confidence`
|
|
2883
|
+
(set by reconciliation), `anti_slop_score`, `blocking`, and `degraded_mode`.
|
|
2884
|
+
|
|
2885
|
+
Reconciliation: ≥2 lenses share `issue_key` → `confidence=high`; single lens → `medium`.
|
|
2886
|
+
|
|
2887
|
+
#### Anti-slop rework remediation
|
|
2888
|
+
|
|
2889
|
+
When aggregate `min(lens_scores) < CROSS_MODEL_ANTISLOP_THRESHOLD` and blocking findings exist:
|
|
2890
|
+
|
|
2891
|
+
1. Producer phase re-spawns with fresh context (bounded by `CROSS_MODEL_REWORK_MAX`).
|
|
2892
|
+
2. Reason **`CROSS_MODEL_ANTISLOP_FAIL`** during rework; **`CROSS_MODEL_REWORK_CAP_EXHAUSTED`**
|
|
2893
|
+
at cap → operator decision gate (waive or abort).
|
|
2894
|
+
|
|
2895
|
+
#### Degraded fallback troubleshooting
|
|
2896
|
+
|
|
2897
|
+
When `select_critic_model` resolves the same slug as producer (or catalog miss), framework sets
|
|
2898
|
+
`degraded_mode=true` and runs three sequential lens spawns on the same model. Informational reason
|
|
2899
|
+
**`CROSS_MODEL_DEGRADED_MODE`** — not a hard stop. Documented limitation per **R-0088**.
|
|
2900
|
+
|
|
2901
|
+
#### Isolation `model_id` v2
|
|
2902
|
+
|
|
2903
|
+
When `CROSS_MODEL_REVIEW=1`, producer **and** critic isolation evidence rows require additive
|
|
2904
|
+
`model_id`. Missing → **`ISOLATION_EVIDENCE_MODEL_ID_MISSING`**.
|
|
2905
|
+
|
|
2906
|
+
#### Parity enforcement
|
|
2907
|
+
|
|
2908
|
+
```bash
|
|
2909
|
+
python scripts/check_intake_template_parity.py --scope=sovereign-critic
|
|
2910
|
+
```
|
|
2911
|
+
|
|
2912
|
+
Pair table (`SOVEREIGN_CRITIC_PAIRS`): lib, validator, command, scratchpad, `DEC-0104.md`.
|
|
2913
|
+
|
|
2914
|
+
#### Related artifacts
|
|
2915
|
+
|
|
2916
|
+
- **Architecture**: `docs/engineering/architecture.md` `# US-0104`
|
|
2917
|
+
- **Reason codes**: `docs/engineering/reason_codes.md` § US-0104
|
|
2918
|
+
- **Decision record**: `decisions/DEC-0104.md`
|
|
2919
|
+
- **Contract tests**: `tests/us0104_contract_test.py` (8 tests + 2 compose guards)
|
|
2920
|
+
|
|
2921
|
+
### Sovereign Memory (US-0105)
|
|
2922
|
+
|
|
2923
|
+
**Default-off institutional memory**. When `SOVEREIGN_MEMORY=0` (default), zero overhead —
|
|
2924
|
+
no JSONL writes, no injection reads, no spawn digest assembly. When `1`, bounded learnings
|
|
2925
|
+
inject into phase spawns via `scripts/sovereign_memory_lib.py`.
|
|
2926
|
+
|
|
2927
|
+
#### Scratchpad keys
|
|
2928
|
+
|
|
2929
|
+
| Key | Values | Default | Behavior when off |
|
|
2930
|
+
|-----|--------|---------|-------------------|
|
|
2931
|
+
| `SOVEREIGN_MEMORY` | `0` \| `1` | `0` | No reads / writes / digest assembly. |
|
|
2932
|
+
| `SOVEREIGN_MEMORY_TOP_N` | int ≥ 0 | `5` | Recent pool size (all four JSONL families). |
|
|
2933
|
+
| `SOVEREIGN_MEMORY_TOP_K` | int ≥ 0 | `3` | High-impact pool (`patterns` + `mistakes`). |
|
|
2934
|
+
| `SOVEREIGN_MEMORY_MAX_CHARS` | int ≥ 0 | `2048` | Hard cap on assembled `digest_text`. |
|
|
2935
|
+
| `SOVEREIGN_MEMORY_JSONL_MAX_LINES` | int ≥ 1 | `500` | Active JSONL line cap before archive rollover. |
|
|
2936
|
+
|
|
2937
|
+
#### Enable / disable
|
|
2938
|
+
|
|
2939
|
+
```bash
|
|
2940
|
+
# Enable sovereign memory
|
|
2941
|
+
echo "SOVEREIGN_MEMORY=1" >> .cursor/scratchpad.local.md
|
|
2942
|
+
|
|
2943
|
+
# Disable (zero overhead)
|
|
2944
|
+
echo "SOVEREIGN_MEMORY=0" >> .cursor/scratchpad.local.md
|
|
2945
|
+
```
|
|
2946
|
+
|
|
2947
|
+
#### JSONL families vs per-run ledger
|
|
2948
|
+
|
|
2949
|
+
| Artifact | Path | Scope | Injected v1? |
|
|
2950
|
+
|----------|------|-------|--------------|
|
|
2951
|
+
| Decisions log | `docs/engineering/sovereign-memory/decisions-log.jsonl` | Cross-run distilled learnings | yes |
|
|
2952
|
+
| Mistakes | `docs/engineering/sovereign-memory/mistakes.jsonl` | Orchestrator mistake hooks | yes (top-K) |
|
|
2953
|
+
| Patterns | `docs/engineering/sovereign-memory/patterns.jsonl` | Phase/curator consolidation | yes (top-K) |
|
|
2954
|
+
| Plan drift | `docs/engineering/sovereign-memory/plan-drift-register.jsonl` | Fidelity/scope hooks | yes (top-N) |
|
|
2955
|
+
| Retrospectives | `sovereign-memory/retrospectives/<sprint_id>.md` | Curator `/refresh-context` | **no** |
|
|
2956
|
+
| Per-run ledger (**US-0103**) | `handoffs/sovereign_decisions/<run_id>.jsonl` | Per-run audit | no (optional promotion) |
|
|
2957
|
+
|
|
2958
|
+
Promotion at `/refresh-context` copies ledger highlights to `decisions-log.jsonl` with
|
|
2959
|
+
`provenance_ref=ledger:<decision_id>` when both `SOVEREIGN_MEMORY=1` and `AI_DECISION_LEDGER=1`.
|
|
2960
|
+
|
|
2961
|
+
#### Validate / self-test
|
|
2962
|
+
|
|
2963
|
+
```bash
|
|
2964
|
+
python scripts/sovereign_memory_lib.py --self-test
|
|
2965
|
+
python scripts/sovereign_memory_validate.py --self-test
|
|
2966
|
+
python scripts/sovereign_memory_validate.py --repo . --enforce
|
|
2967
|
+
```
|
|
2968
|
+
|
|
2969
|
+
#### Injection char-cap troubleshooting
|
|
2970
|
+
|
|
2971
|
+
When digest appears truncated:
|
|
2972
|
+
|
|
2973
|
+
1. Check `SOVEREIGN_MEMORY_MAX_CHARS` (default **2048**).
|
|
2974
|
+
2. Reduce `SOVEREIGN_MEMORY_TOP_N` / `SOVEREIGN_MEMORY_TOP_K` if too many entries compete.
|
|
2975
|
+
3. Informational **`SOVEREIGN_MEMORY_READ_BOUND`** when tail read truncates — digest still emitted.
|
|
2976
|
+
|
|
2977
|
+
#### Archive rollover remediation
|
|
2978
|
+
|
|
2979
|
+
When append fails with **`SOVEREIGN_MEMORY_ARCHIVE_REQUIRED`**:
|
|
2980
|
+
|
|
2981
|
+
1. Check permissions on `docs/engineering/sovereign-memory-archive/`.
|
|
2982
|
+
2. Verify disk space; active file rollover moves to `<basename>-<YYYYMMDDTHHMMSSZ>.jsonl`.
|
|
2983
|
+
3. Rollover is **not** triad compaction (**US-0072** unchanged).
|
|
2984
|
+
|
|
2985
|
+
#### Parity enforcement
|
|
2986
|
+
|
|
2987
|
+
```bash
|
|
2988
|
+
python scripts/check_intake_template_parity.py --scope=sovereign-memory
|
|
2989
|
+
```
|
|
2990
|
+
|
|
2991
|
+
Pair table (`SOVEREIGN_MEMORY_PAIRS`): lib, validator, scratchpad, `.gitkeep`, `DEC-0105.md`.
|
|
2992
|
+
|
|
2993
|
+
#### Related artifacts
|
|
2994
|
+
|
|
2995
|
+
- **Architecture**: `docs/engineering/architecture.md` `# US-0105`
|
|
2996
|
+
- **Reason codes**: `docs/engineering/reason_codes.md` § US-0105
|
|
2997
|
+
- **Decision record**: `decisions/DEC-0105.md`
|
|
2998
|
+
- **Contract tests**: `tests/us0105_contract_test.py` (8 tests + 2 compose guards)
|
|
2999
|
+
|
|
3000
|
+
### Sovereign Loop Mode (US-0107)
|
|
3001
|
+
|
|
3002
|
+
**Default-off project orchestration**. When `AUTO_SOVEREIGN=0` (default), zero overhead — no
|
|
3003
|
+
deferral reads/writes, no advance, no notifications. When enabled, requires
|
|
3004
|
+
`SOVEREIGN_GOAL_MODE=goal_convergence` (fail-closed **`SOVEREIGN_LOOP_GOAL_MODE_REQUIRED`**).
|
|
3005
|
+
|
|
3006
|
+
#### Scratchpad keys
|
|
3007
|
+
|
|
3008
|
+
| Key | Values | Default | Notes |
|
|
3009
|
+
|-----|--------|---------|-------|
|
|
3010
|
+
| `AUTO_SOVEREIGN` | `0` \| `1` | `0` | Master enable gate. |
|
|
3011
|
+
| `AUTO_SOVEREIGN_DEFERRAL_MAX` | int ≥ 1 | `50` | Max open deferral rows. |
|
|
3012
|
+
| `AUTO_SOVEREIGN_DRAIN_GENERATE_MAX` | int ≥ 0 | `3` | Drain-generate iterations per run. |
|
|
3013
|
+
| `AUTO_SOVEREIGN_DEFERRAL_POLICY` | `stop` \| `skip` \| `resolve_first` | `resolve_first` | Deferral gate policy. |
|
|
3014
|
+
| `SOVEREIGN_NOTIFY_TARGET` | `off` \| `ntfy` \| `email` \| `hook` | `off` | Notification adapter. |
|
|
3015
|
+
| `SOVEREIGN_NOTIFY_NTFY_TOPIC` | string | *(empty)* | Local-only ntfy topic. |
|
|
3016
|
+
| `SOVEREIGN_NOTIFY_NTFY_BASE` | URL | *(empty)* | Optional ntfy base override — local-only. |
|
|
3017
|
+
| `SOVEREIGN_NOTIFY_HOOK_URL` | URL | *(empty)* | Webhook POST target — local-only. |
|
|
3018
|
+
| `SOVEREIGN_NOTIFY_EMAIL_TO` | email | *(empty)* | Email v1 deferred. |
|
|
3019
|
+
|
|
3020
|
+
#### Enable / disable
|
|
3021
|
+
|
|
3022
|
+
```bash
|
|
3023
|
+
# Enable sovereign loop (both keys required)
|
|
3024
|
+
echo "AUTO_SOVEREIGN=1" >> .cursor/scratchpad.local.md
|
|
3025
|
+
echo "SOVEREIGN_GOAL_MODE=goal_convergence" >> .cursor/scratchpad.local.md
|
|
3026
|
+
|
|
3027
|
+
# Disable (zero overhead)
|
|
3028
|
+
echo "AUTO_SOVEREIGN=0" >> .cursor/scratchpad.local.md
|
|
3029
|
+
```
|
|
3030
|
+
|
|
3031
|
+
Notification topic/URL values belong in `.cursor/scratchpad.local.md` only — never commit secrets.
|
|
3032
|
+
|
|
3033
|
+
#### Deferral register operator workflow
|
|
3034
|
+
|
|
3035
|
+
| Action | Command / API |
|
|
3036
|
+
|--------|----------------|
|
|
3037
|
+
| Append deferral | `append_deferral(...)` via `sovereign_loop_lib.py` |
|
|
3038
|
+
| Resolve deferral | `resolve_deferral(repo, deferral_id, orchestrator_run_id=...)` |
|
|
3039
|
+
| List open rows | `list_open_deferrals(repo, scratchpad=...)` (latest-state-wins) |
|
|
3040
|
+
| Validate JSONL | `python scripts/sovereign_loop_validate.py --repo . --enforce` |
|
|
3041
|
+
|
|
3042
|
+
Path: `handoffs/sovereign_deferrals.jsonl` (create-on-first-write; bootstrap `.gitkeep` only).
|
|
3043
|
+
Sidecar: `handoffs/sovereign_loop_state.json` v1 — per-run drain-generate iteration counter.
|
|
3044
|
+
|
|
3045
|
+
#### Drain-generate decision gate
|
|
3046
|
+
|
|
3047
|
+
When backlog has zero OPEN stories but convergence is not met and iterations remain under cap,
|
|
3048
|
+
`/auto` spawns a fresh **PO** subagent (spawn-only **US-0095**) with ephemeral id
|
|
3049
|
+
`drain-gen-{orchestrator_run_id}-{iteration}`. PO proposes up to **3** candidates per iteration.
|
|
3050
|
+
|
|
3051
|
+
**Mandatory per-candidate decision gate**: accept → `/intake` or controlled backlog append;
|
|
3052
|
+
reject → discard. No auto-append without operator gate.
|
|
3053
|
+
|
|
3054
|
+
#### US-0109 integration (`DEPLOY_DEFERRED`)
|
|
3055
|
+
|
|
3056
|
+
**US-0109** (deploy smoke) is the downstream writer for `DEPLOY_DEFERRED` deferral rows when
|
|
3057
|
+
deploy smoke cap is exhausted. Schema v1 fields: `work_item_kind=deploy`, standard deferral
|
|
3058
|
+
register fields per **DEC-0107** §2. US-0107 owns schema, validator, and read paths only — no
|
|
3059
|
+
deploy smoke logic in this story.
|
|
3060
|
+
|
|
3061
|
+
#### Validate / self-test
|
|
3062
|
+
|
|
3063
|
+
```bash
|
|
3064
|
+
python scripts/sovereign_loop_lib.py --self-test
|
|
3065
|
+
python scripts/sovereign_loop_validate.py --self-test
|
|
3066
|
+
python scripts/sovereign_loop_validate.py --repo . --enforce
|
|
3067
|
+
pytest -k us0107
|
|
3068
|
+
```
|
|
3069
|
+
|
|
3070
|
+
#### Parity enforcement
|
|
3071
|
+
|
|
3072
|
+
```bash
|
|
3073
|
+
python scripts/check_intake_template_parity.py --scope=sovereign-loop
|
|
3074
|
+
```
|
|
3075
|
+
|
|
3076
|
+
Pair table (`SOVEREIGN_LOOP_PAIRS`): lib, validator, scratchpad, deferrals `.gitkeep`, `DEC-0107.md`.
|
|
3077
|
+
|
|
3078
|
+
#### Related artifacts
|
|
3079
|
+
|
|
3080
|
+
- **Architecture**: `docs/engineering/architecture.md` `# US-0107`
|
|
3081
|
+
- **Reason codes**: `docs/engineering/reason_codes.md` § US-0107
|
|
3082
|
+
- **Decision record**: `decisions/DEC-0107.md`
|
|
3083
|
+
- **Contract tests**: `tests/us0107_contract_test.py` (8 tests + 2 compose guards)
|
|
3084
|
+
|
|
3085
|
+
### Sovereign Role-Behavior Manifest (US-0106)
|
|
3086
|
+
|
|
3087
|
+
**Default-off per-role objective + inter-role review obligations**. When `SOVEREIGN_ROLE_MANIFEST=0` (default),
|
|
3088
|
+
zero overhead — no manifest reads, no objective injection, no review dispatch. Review spawns are
|
|
3089
|
+
supplementary post-phase hooks — they never substitute for the US-0069 producer role.
|
|
3090
|
+
|
|
3091
|
+
#### Scratchpad keys
|
|
3092
|
+
|
|
3093
|
+
| Key | Values | Default | Notes |
|
|
3094
|
+
|-----|--------|---------|-------|
|
|
3095
|
+
| `SOVEREIGN_ROLE_MANIFEST` | `0` \| `1` | `0` | Master enable gate. |
|
|
3096
|
+
| `SOVEREIGN_ROLE_OBJECTIVE_MAX_CHARS` | int ≥ 1 | `512` | Hard truncate for injection block. |
|
|
3097
|
+
| `SOVEREIGN_ROLE_REVIEW_MAX_PER_PHASE` | int ≥ 0 | `2` | Per-phase review dispatch cap. |
|
|
3098
|
+
| `SOVEREIGN_ROLE_REVIEW_REWORK_MAX` | int ≥ 0 | `1` | Bounded rework before decision gate. |
|
|
3099
|
+
|
|
3100
|
+
#### Enable / disable
|
|
3101
|
+
|
|
3102
|
+
```bash
|
|
3103
|
+
# Enable sovereign role manifest
|
|
3104
|
+
echo "SOVEREIGN_ROLE_MANIFEST=1" >> .cursor/scratchpad.local.md
|
|
3105
|
+
|
|
3106
|
+
# Disable (zero overhead)
|
|
3107
|
+
echo "SOVEREIGN_ROLE_MANIFEST=0" >> .cursor/scratchpad.local.md
|
|
3108
|
+
```
|
|
3109
|
+
|
|
3110
|
+
#### Manifest edit operator workflow
|
|
3111
|
+
|
|
3112
|
+
1. Open `.cursor/sovereign-role-manifest.yaml` (active) or `template/.cursor/sovereign-role-manifest.yaml.example` (template).
|
|
3113
|
+
2. Add role: append `role_id` ∈ {`po`, `tech-lead`, `dev`, `qa`, `release`, `curator`} with `objective_function` (≤ 1024 chars at file; truncated at injection to `SOVEREIGN_ROLE_OBJECTIVE_MAX_CHARS`).
|
|
3114
|
+
3. Add obligation: `obligation_id` (unique slug), `reviewer_role`, `target_role`, `trigger_phase` ∈ canonical phase ids, `review_focus` ∈ {`user_value_drift`, `testability`, `buildability`, `deployability`}, `artifact_refs[]`, optional `blocking` (default `false`).
|
|
3115
|
+
4. Edit `cross_model_policy.default_order` ∈ {`role_review_first`, `critic_first`, `critic_only`, `role_review_only`} to set critic vs role-review ordering.
|
|
3116
|
+
5. Edit `escalation_rules.rework_max` for bounded rework cap.
|
|
3117
|
+
6. Run validator: `python scripts/sovereign_role_manifest_validate.py --repo . --enforce`.
|
|
3118
|
+
|
|
3119
|
+
#### Validator invocation
|
|
3120
|
+
|
|
3121
|
+
```bash
|
|
3122
|
+
# Validate single manifest file
|
|
3123
|
+
python scripts/sovereign_role_manifest_validate.py --file .cursor/sovereign-role-manifest.yaml
|
|
3124
|
+
|
|
3125
|
+
# Validate repo active + template pair
|
|
3126
|
+
python scripts/sovereign_role_manifest_validate.py --repo . --enforce
|
|
3127
|
+
|
|
3128
|
+
# Lib self-test
|
|
3129
|
+
python scripts/sovereign_role_manifest_validate.py --self-test
|
|
3130
|
+
```
|
|
3131
|
+
|
|
3132
|
+
Success: `[SOVEREIGN_ROLE_MANIFEST_VALIDATION_OK]`.
|
|
3133
|
+
Fail: reason codes `SOVEREIGN_ROLE_*` — `SCHEMA_INVALID`, `UNKNOWN_ROLE`, `UNKNOWN_PHASE`, `SECRET_DETECTED`, `OBJECTIVE_OVERFLOW`.
|
|
3134
|
+
|
|
3135
|
+
#### Review dispatch troubleshooting
|
|
3136
|
+
|
|
3137
|
+
| Reason code | Symptom | Remediation |
|
|
3138
|
+
|-------------|---------|-------------|
|
|
3139
|
+
| `SOVEREIGN_ROLE_MANIFEST_DISABLED` | `SOVEREIGN_ROLE_MANIFEST=0` — no dispatch | Set `SOVEREIGN_ROLE_MANIFEST=1` to enable |
|
|
3140
|
+
| `ROLE_REVIEW_DISPATCH_FAILED` | JSONL append I/O error | Check file permissions on `handoffs/sovereign_role_reviews.jsonl` |
|
|
3141
|
+
| `ROLE_REVIEW_SPAWN_FAILED` | Subagent spawn error | Retry spawn; check Task tool availability |
|
|
3142
|
+
| `ROLE_REVIEW_BLOCKED` | Blocking review verdict `fail` | Apply escalation: rework (bounded by `SOVEREIGN_ROLE_REVIEW_REWORK_MAX`) or operator decision gate |
|
|
3143
|
+
| `ROLE_REVIEW_DEFERRAL_FAILED` | US-0107 deferral append error | Check `handoffs/sovereign_deferrals.jsonl` permissions; fail-open logged |
|
|
3144
|
+
| `ROLE_REVIEW_REWORK_CAP` | Rework max exhausted | Operator decision gate: waive findings or abort |
|
|
3145
|
+
|
|
3146
|
+
Reviews JSONL: `handoffs/sovereign_role_reviews.jsonl` (v1 schema: `schema_version`, `obligation_id`, `reviewer_role`, `target_role`, `trigger_phase`, `review_focus`, `producer_evidence_ref`, `orchestrator_run_id`, `ts`, `verdict`, `blocking`, `findings_ref`).
|
|
3147
|
+
|
|
3148
|
+
#### Validate / self-test
|
|
3149
|
+
|
|
3150
|
+
```bash
|
|
3151
|
+
python scripts/sovereign_role_manifest_lib.py --self-test
|
|
3152
|
+
python scripts/sovereign_role_manifest_validate.py --self-test
|
|
3153
|
+
python scripts/sovereign_role_manifest_validate.py --repo . --enforce
|
|
3154
|
+
pytest -k us0106
|
|
3155
|
+
```
|
|
3156
|
+
|
|
3157
|
+
#### Parity enforcement
|
|
3158
|
+
|
|
3159
|
+
```bash
|
|
3160
|
+
python scripts/check_intake_template_parity.py --scope=sovereign-role-manifest
|
|
3161
|
+
```
|
|
3162
|
+
|
|
3163
|
+
Pair table (`SOVEREIGN_ROLE_MANIFEST_PAIRS`): scratchpad keys, manifest YAML, example manifest, validator, lib, reviews JSONL, template validator, template lib.
|
|
3164
|
+
|
|
3165
|
+
#### Related artifacts
|
|
3166
|
+
|
|
3167
|
+
- **Architecture**: `docs/engineering/architecture.md` `# US-0106`
|
|
3168
|
+
- **Reason codes**: `docs/engineering/reason_codes.md` § US-0106
|
|
3169
|
+
- **Decision record**: `decisions/DEC-0106.md`
|
|
3170
|
+
- **Contract tests**: `tests/us0106_contract_test.py` (8 tests + 2 compose guards)
|
|
3171
|
+
|
|
3172
|
+
### Parallel Instance Arbitrage (US-0108)
|
|
3173
|
+
|
|
3174
|
+
**Default-off parallel execute-phase instance orchestration**. When `SOVEREIGN_PARALLEL_DEV=0` (default),
|
|
3175
|
+
zero overhead — no worktrees, no parallel QA, no pick JSON, no resource guard.
|
|
3176
|
+
|
|
3177
|
+
#### Scratchpad keys
|
|
3178
|
+
|
|
3179
|
+
| Key | Values | Default | Notes |
|
|
3180
|
+
|-----|--------|---------|-------|
|
|
3181
|
+
| `SOVEREIGN_PARALLEL_DEV` | `0` \| `1` | `0` | Master enable gate. |
|
|
3182
|
+
| `AUTO_SOVEREIGN_PARALLEL_N` | int ≥ 1 | `3` | Instances per execute cycle. |
|
|
3183
|
+
| `AUTO_SOVEREIGN_PARALLEL_MAX_TOTAL` | int ≥ 1 | `6` | System-wide instance cap. |
|
|
3184
|
+
| `AUTO_SOVEREIGN_MERGE_RESOLVE` | `first_pass_wins` \| `last_pass_wins` \| `winner_takes_all` \| `manual` | `first_pass_wins` | Merge policy. |
|
|
3185
|
+
| `AUTO_SOVEREIGN_WORKTREE_KEEP` | `0` \| `1` | `0` | Retain loser worktrees for debugging. |
|
|
3186
|
+
| `AUTO_SOVEREIGN_PARALLEL_QA` | `0` \| `1` | `0` | Enable parallel QA cross-review (v2). |
|
|
3187
|
+
| `AUTO_SOVEREIGN_PARALLEL_QA_ARBITER` | `critic_first_pass` \| `majority_vote` | `critic_first_pass` | QA arbitration strategy. |
|
|
3188
|
+
| `AUTO_SOVEREIGN_PARALLEL_ANTI_SLOP_THRESHOLD` | int 0-10 | `6` | Anti-slop floor. |
|
|
3189
|
+
| `AUTO_SOVEREIGN_PARALLEL_REWORK_MAX` | int ≥ 0 | `2` | Per-instance rework cap. |
|
|
3190
|
+
| `AUTO_SOVEREIGN_PARALLEL_MERGE_TIMEOUT_SEC` | int ≥ 10 | `60` | Merge timeout. |
|
|
3191
|
+
| `AUTO_SOVEREIGN_PARALLEL_MODEL_<idx>` | model slug | *(empty)* | Per-instance model override (optional). |
|
|
3192
|
+
| `AUTO_SOVEREIGN_PARALLEL_LENS_<idx>` | lens config | *(empty)* | Per-instance lens override (optional). |
|
|
3193
|
+
|
|
3194
|
+
#### Enable / disable
|
|
3195
|
+
|
|
3196
|
+
```bash
|
|
3197
|
+
# Enable parallel dev (N=3 instances)
|
|
3198
|
+
echo "SOVEREIGN_PARALLEL_DEV=1" >> .cursor/scratchpad.local.md
|
|
3199
|
+
echo "AUTO_SOVEREIGN_PARALLEL_N=3" >> .cursor/scratchpad.local.md
|
|
3200
|
+
|
|
3201
|
+
# Disable (zero overhead)
|
|
3202
|
+
echo "SOVEREIGN_PARALLEL_DEV=0" >> .cursor/scratchpad.local.md
|
|
3203
|
+
```
|
|
3204
|
+
|
|
3205
|
+
#### Parallel dev workflow
|
|
3206
|
+
|
|
3207
|
+
1. **Create worktrees** (T-002/T-003): `create_worktrees(story_id, n_instances, base_branch)` → isolated
|
|
3208
|
+
`.git/worktrees/us0108-<story_id>-<idx>/` per instance.
|
|
3209
|
+
2. **Simulated execute** in each worktree (T-008 step 25).
|
|
3210
|
+
3. **Simulated QA** in each worktree (T-008 step 26).
|
|
3211
|
+
4. **Select winner** (T-004): `select_winner(qa_results[])` → filter `qa_verdict=pass` → sort `-anti_slop_score`
|
|
3212
|
+
→ tie-break earliest `proof_issued_at` → single winner.
|
|
3213
|
+
5. **Read anti-slop score** (T-005): `read_anti_slop_score(lens_scores[])` via
|
|
3214
|
+
`sovereign_critic_lib.compute_anti_slop_aggregate` (read-only, US-0104 unchanged).
|
|
3215
|
+
6. **Merge winner** (T-006): `merge_winner(winner_ctx, main_branch)` with bounded retry ≤2, then
|
|
3216
|
+
`PARALLEL_DEV_MERGE_CONFLICT` halt. Write-once `handoffs/parallel_dev_pick.json` v1.
|
|
3217
|
+
7. **Cleanup** (T-003): winner removed; losers per `AUTO_SOVEREIGN_WORKTREE_KEEP`.
|
|
3218
|
+
|
|
3219
|
+
Pick JSON schema v1:
|
|
3220
|
+
```json
|
|
3221
|
+
{
|
|
3222
|
+
"schema_version": 1,
|
|
3223
|
+
"story_id": "US-0108",
|
|
3224
|
+
"winner_instance_id": "US-0108-inst0",
|
|
3225
|
+
"worktree_path": ".git/worktrees/us0108-US-0108-0",
|
|
3226
|
+
"qa_verdict": "pass",
|
|
3227
|
+
"anti_slop_score": 8,
|
|
3228
|
+
"proof_issued_at": "2026-06-29T22:00:00Z",
|
|
3229
|
+
"merge_policy": "first_pass_wins",
|
|
3230
|
+
"runner_ts_utc": "2026-06-29T22:30:00Z",
|
|
3231
|
+
"orchestrator_run_id": "auto-20260628-04",
|
|
3232
|
+
"loser_instance_ids": ["US-0108-inst1", "US-0108-inst2"]
|
|
3233
|
+
}
|
|
3234
|
+
```
|
|
3235
|
+
|
|
3236
|
+
#### Reason codes
|
|
3237
|
+
|
|
3238
|
+
| Code | Meaning |
|
|
3239
|
+
|------|---------|
|
|
3240
|
+
| `PARALLEL_DEV_DISABLED` | Feature off — backward compat path. |
|
|
3241
|
+
| `PARALLEL_DEV_WORKTREE_CREATE_FAILED` | Worktree creation error. |
|
|
3242
|
+
| `PARALLEL_DEV_WORKTREE_CLEANUP_FAILED` | Cleanup error (fail-open). |
|
|
3243
|
+
| `PARALLEL_DEV_SELECTION_NO_PASS` | No QA pass verdict in any instance. |
|
|
3244
|
+
| `PARALLEL_DEV_MERGE_CONFLICT` | Merge conflict after bounded retry. |
|
|
3245
|
+
| `PARALLEL_DEV_RESOURCE_CAP_EXHAUSTED` | System-wide cap reached. |
|
|
3246
|
+
| `PARALLEL_DEV_RESOURCE_LOCK_FAILED` | Lockfile error. |
|
|
3247
|
+
| `PARALLEL_DEV_EXECUTE_FAILED` | Instance execution error. |
|
|
3248
|
+
| `PARALLEL_DEV_ANTI_SLOP_BELOW_THRESHOLD` | Winner score below floor. |
|
|
3249
|
+
| `PARALLEL_DEV_MERGE_TIMEOUT` | Merge operation timeout. |
|
|
3250
|
+
| `PARALLEL_DEV_MANUAL_HALT` | Manual intervention required (`merge_resolve=manual`). |
|
|
3251
|
+
| `PARALLEL_DEV_PICK_SCHEMA_INVALID` | Pick JSON schema violation. |
|
|
3252
|
+
|
|
3253
|
+
#### Resource guard
|
|
3254
|
+
|
|
3255
|
+
- Lockfile: `.git/us0108_parallel_dev.lock`
|
|
3256
|
+
- `acquire_parallel_slot(slot_id, repo_root, max_total)` / `release_parallel_slot(slot_id, repo_root)`
|
|
3257
|
+
- System cap: `AUTO_SOVEREIGN_PARALLEL_MAX_TOTAL` (default 6)
|
|
3258
|
+
- Fail-fast `PARALLEL_DEV_RESOURCE_CAP_EXHAUSTED` when cap reached
|
|
3259
|
+
|
|
3260
|
+
#### Validator / self-test
|
|
3261
|
+
|
|
3262
|
+
```bash
|
|
3263
|
+
# Self-test
|
|
3264
|
+
python scripts/parallel_dev_arbiter.py --self-test
|
|
3265
|
+
|
|
3266
|
+
# Contract tests
|
|
3267
|
+
python -m pytest tests/us0108_contract_test.py -v
|
|
3268
|
+
|
|
3269
|
+
# Parity check
|
|
3270
|
+
python scripts/check_intake_template_parity.py --scope=sovereign-parallel-dev
|
|
3271
|
+
```
|
|
3272
|
+
|
|
3273
|
+
#### Compose guards (non-negotiable)
|
|
3274
|
+
|
|
3275
|
+
| Compose surface | Rule |
|
|
3276
|
+
|-----------------|------|
|
|
3277
|
+
| US-0047 (bulk execute) | Step 22 unchanged; system cap checked **after** bulk cap. |
|
|
3278
|
+
| US-0092 (full autonomy) | Outer driver unchanged; parallel is execute-phase internal. |
|
|
3279
|
+
| US-0103 (ledger) | Schema unchanged; US-0108 reads ledger only. |
|
|
3280
|
+
| US-0104 (critic) | Schema unchanged; US-0108 reads `anti_slop_score` only. |
|
|
3281
|
+
| US-0107 (sovereign loop) | Deferral register unchanged; US-0108 appends winner/loser outcomes as consumer. |
|
|
3282
|
+
|
|
3283
|
+
#### Related artifacts
|
|
3284
|
+
|
|
3285
|
+
- **Architecture**: `docs/engineering/architecture.md` `# US-0108`
|
|
3286
|
+
- **Reason codes**: `docs/engineering/reason_codes.md` § US-0108
|
|
3287
|
+
- **Decision record**: `decisions/DEC-0108.md`
|
|
3288
|
+
- **Contract tests**: `tests/us0108_contract_test.py` (8 tests)
|
|
3289
|
+
- **Standalone runbook**: `docs/sovereign-runbook-md/US-0108.md`
|
|
3290
|
+
|
|
3291
|
+
---
|
|
3292
|
+
|
|
3293
|
+
## Self-Healing Deploy Loop (US-0109 / DEC-0109)
|
|
3294
|
+
|
|
3295
|
+
**Default-off** (`AUTO_SOVEREIGN_SELF_HEALING_DEPLOY=0`) — zero overhead when off. When enabled,
|
|
3296
|
+
adds a post-deploy smoke probe + bounded retry loop on top of US-0054 publish chain.
|
|
3297
|
+
|
|
3298
|
+
### Scratchpad keys (schema_v1)
|
|
3299
|
+
|
|
3300
|
+
| Key | Values | Default | Notes |
|
|
3301
|
+
|-----|--------|---------|-------|
|
|
3302
|
+
| `AUTO_SOVEREIGN_SELF_HEALING_DEPLOY` | `0` \| `1` | `0` | Global gate. When `0`, zero overhead — byte-identical US-0054 publish path. |
|
|
3303
|
+
| `AUTO_SOVEREIGN_DEPLOY_RETRY_MAX` | int ≥ 1 | `3` | Max retry attempts after probe FAIL. |
|
|
3304
|
+
| `AUTO_SOVEREIGN_DEPLOY_SMOKE_TIMEOUT_SEC` | int ≥ 1 | `30` | Per-stage HTTP timeout for health probe. |
|
|
3305
|
+
| `AUTO_SOVEREIGN_DEPLOY_PROBE_KIND` | `health_endpoint` \| `acceptance_smoke` \| `both` | `both` | Which stages run during smoke probe. |
|
|
3306
|
+
| `SOVEREIGN_DEPLOY_ACCEPTANCE_SMOKE_PATH` | repo-relative path | `tests/deploy_smoke/` | Acceptance smoke tests directory (pytest runner). |
|
|
3307
|
+
| `AUTO_SOVEREIGN_DEPLOY_HEALTH_ENDPOINT` | names-only env ref | *(empty)* | Key name in `os.environ` — value is a key name, NOT a URL literal. |
|
|
3308
|
+
|
|
3309
|
+
Fail-closed `DEPLOY_HEALING_PROBE_TARGET_MISSING` when health endpoint unresolvable.
|
|
3310
|
+
|
|
3311
|
+
### Execute steps 29-31
|
|
3312
|
+
|
|
3313
|
+
| Step | Action |
|
|
3314
|
+
|------|--------|
|
|
3315
|
+
| **29 post-deploy smoke probe** | Two-stage chain `[DEPLOY_SMOKE_PROBE_OK]`. Skip when `0`. |
|
|
3316
|
+
| **30 retry loop** | Re-enter publish PASS path on probe FAIL; cap exhaustion → step 31. |
|
|
3317
|
+
| **31 DEPLOY_DEFERRED** | Via US-0107 `append_deferral(work_item_kind=deploy)`. Orchestrator continues. |
|
|
3318
|
+
|
|
3319
|
+
### Operator remediation
|
|
3320
|
+
|
|
3321
|
+
| Reason code | Operator action |
|
|
3322
|
+
|-------------|-----------------|
|
|
3323
|
+
| `DEPLOY_HEALING_DISABLED` | No action; expected default. Set `=1` to enable. |
|
|
3324
|
+
| `DEPLOY_HEALING_SMOKE_HEALTH_FAIL` | Verify env key in scratchpad.local resolves to reachable URL. Re-run probe. |
|
|
3325
|
+
| `DEPLOY_HEALING_SMOKE_ACCEPTANCE_FAIL` | Inspect `SOVEREIGN_DEPLOY_ACCEPTANCE_SMOKE_PATH` smoke tests. Fix failures. |
|
|
3326
|
+
| `DEPLOY_HEALING_RETRY_ATTEMPT` | Informational per-attempt log; no action required. |
|
|
3327
|
+
| `DEPLOY_HEALING_RETRY_CAP_EXHAUSTED` | Raise `AUTO_SOVEREIGN_DEPLOY_RETRY_MAX` if transient; otherwise resolve root cause. |
|
|
3328
|
+
| `DEPLOY_HEALING_DEFERRED` | Resolve in `handoffs/sovereign_deferrals.jsonl`; re-run `/release` after fix. |
|
|
3329
|
+
| `DEPLOY_HEALING_PROBE_TARGET_MISSING` | Set `AUTO_SOVEREIGN_DEPLOY_HEALTH_ENDPOINT` to valid env key; ensure env var has URL. |
|
|
3330
|
+
| `DEPLOY_HEALING_TIMEOUT` | Raise `AUTO_SOVEREIGN_DEPLOY_SMOKE_TIMEOUT_SEC`; investigate startup latency. |
|
|
3331
|
+
|
|
3332
|
+
### Validate / self-test
|
|
3333
|
+
|
|
3334
|
+
```bash
|
|
3335
|
+
python scripts/self_healing_deploy_validate.py --self-test
|
|
3336
|
+
python scripts/self_healing_deploy_validate.py --repo . --enforce
|
|
3337
|
+
```
|
|
3338
|
+
|
|
3339
|
+
### Parity enforcement
|
|
3340
|
+
|
|
3341
|
+
```bash
|
|
3342
|
+
python scripts/check_intake_template_parity.py --scope=sovereign-self-healing-deploy
|
|
3343
|
+
```
|
|
3344
|
+
|
|
3345
|
+
Pair table (`SOVEREIGN_SELF_HEALING_DEPLOY_PAIRS`): scratchpad, lib, validator,
|
|
3346
|
+
contract tests, runbook, reason_codes — 6 pairs (active + template).
|
|
3347
|
+
|
|
3348
|
+
### Compose surfaces (read-only)
|
|
3349
|
+
|
|
3350
|
+
| Composed story | US-0109 boundary |
|
|
3351
|
+
|----------------|------------------|
|
|
3352
|
+
| US-0054 (publish) | Re-enters publish PASS only; publish targets/schema/release-notes UNCHANGED. |
|
|
3353
|
+
| US-0100 (changelog) | No changelog writes triggered by US-0109. |
|
|
3354
|
+
| US-0103 (ledger) | Schema UNCHANGED; optional `deploy_deferral_id` additive (v1). |
|
|
3355
|
+
| US-0107 (sovereign loop) | Consumer of `append_deferral(...)` API only; `work_item_kind=deploy`. |
|
|
3356
|
+
| US-0110 (convergence) | Predicate UNCHANGED; US-0110 reads open deferrals (no new logic). |
|
|
3357
|
+
|
|
3358
|
+
### Related artifacts
|
|
3359
|
+
|
|
3360
|
+
- **Architecture**: `docs/engineering/architecture.md` `# US-0109`
|
|
3361
|
+
- **Reason codes**: `docs/engineering/reason_codes.md` § US-0109
|
|
3362
|
+
- **Decision record**: `decisions/DEC-0109.md`
|
|
3363
|
+
- **Library**: `scripts/self_healing_deploy_lib.py`
|
|
3364
|
+
- **Validator**: `scripts/self_healing_deploy_validate.py`
|
|
3365
|
+
- **Contract tests**: `tests/us0109_contract_test.py` + `tests/us0109_us0110_compose_test.py`
|
|
3366
|
+
|
|
3367
|
+
---
|
|
3368
|
+
|
|
3369
|
+
## Release Trigger Adapters (US-0111 / DEC-0111)
|
|
3370
|
+
|
|
3371
|
+
**Default source**: `RELEASE_TRIGGER_SOURCE=manual` (zero behavior change vs pre-US-0111 /release path — byte-identical).
|
|
3372
|
+
|
|
3373
|
+
### Adapter registry and dispatch
|
|
3374
|
+
|
|
3375
|
+
`scripts/release_trigger_adapters.py` provides four adapters:
|
|
3376
|
+
- **GitHub webhook** (`github`): Parse `release.tag_name`; query GitHub API for previous tag via `GET /repos/{owner}/{repo}/releases?per_page=100` (sorted by `created_at` desc, skip current); fallback `git ls-remote --tags origin` filtered for semver.
|
|
3377
|
+
- **npm publish** (`npm`): Read `npm_package_version` env var; query `npm view {pkg} versions --json` with `RELEASE_TRIGGER_TIMEOUT_SEC` (default 10s); offline fallback `package-lock.json` when `RELEASE_TRIGGER_FALLBACK_TO_LOCAL=1`.
|
|
3378
|
+
- **Git tag push** (`git_tag`): Parse `GITHUB_REF=refs/tags/vX.Y.Z` or local `git describe --tags --abbrev=0`; compute previous via `git for-each-ref --sort=-version:refname refs/tags` (semver sort, not date — handles annotated vs lightweight tags).
|
|
3379
|
+
- **Manual /release** (`manual`): `TriggerContext(source="manual", version=current, previous_version=None)` — byte-identical to pre-US-0111 /release.
|
|
3380
|
+
|
|
3381
|
+
Dispatch via `dispatch_to_adapter(source, env_vars)` → `TriggerContext`. Invalid source → `RELEASE_TRIGGER_SOURCE_INVALID` (fail-closed).
|
|
3382
|
+
|
|
3383
|
+
### Scratchpad keys
|
|
3384
|
+
|
|
3385
|
+
| Key | Values | Default |
|
|
3386
|
+
|-----|--------|---------|
|
|
3387
|
+
| `RELEASE_TRIGGER_SOURCE` | `manual` \| `github` \| `npm` \| `git_tag` \| `auto` | `manual` |
|
|
3388
|
+
| `RELEASE_TRIGGER_TIMEOUT_SEC` | int ≥ 1 | `10` |
|
|
3389
|
+
| `RELEASE_TRIGGER_FALLBACK_TO_LOCAL` | `0` \| `1` | `0` |
|
|
3390
|
+
|
|
3391
|
+
### TriggerContext dataclass
|
|
3392
|
+
|
|
3393
|
+
```python
|
|
3394
|
+
@dataclass
|
|
3395
|
+
class TriggerContext:
|
|
3396
|
+
version: str
|
|
3397
|
+
previous_version: Optional[str]
|
|
3398
|
+
source: str # manual | github | npm | git_tag
|
|
3399
|
+
metadata: Dict[str, Any]
|
|
3400
|
+
```
|
|
3401
|
+
|
|
3402
|
+
### Version comparison integration (AC-6)
|
|
3403
|
+
|
|
3404
|
+
`compare_versions_from_trigger(trigger)` normalizes `trigger.version` and `trigger.previous_version` via `release_changelog_lib.normalize_semver()`. Fail-closed: `RELEASE_TRIGGER_COMPARE_VERSIONS_FAILED` on invalid semver.
|
|
3405
|
+
|
|
3406
|
+
### Atomic promotion (AC-7, AC-8)
|
|
3407
|
+
|
|
3408
|
+
- **CHANGELOG.md promotion**: `promote_changelog_version(semver, sprint_ids, repo_root)` reuses `release_changelog_lib.promote_unreleased()` unchanged (US-0100 compose). Atomic write via `os.replace(temp, target)` with Windows best-effort retry (0.1s × 2). Fail-closed: `RELEASE_TRIGGER_ATOMIC_PROMOTION_FAILED`.
|
|
3409
|
+
- **Per-version notes**: `write_per_version_notes(semver, sprint_ids, repo_root)` writes `handoffs/releases/vX.Y.Z-release-notes.md` atomically. Reuses `release_changelog_lib.build_version_doc()` read-only compose. Fail-closed: `RELEASE_TRIGGER_NOTES_WRITE_FAILED`.
|
|
3410
|
+
|
|
3411
|
+
### Ledger event emit (AC-9)
|
|
3412
|
+
|
|
3413
|
+
`emit_version_derivation_event(trigger, norm_version, norm_previous, repo_root, scratchpad)`:
|
|
3414
|
+
1. Write `handoffs/release_events/{iso-timestamp}-{semver}.json` atomically.
|
|
3415
|
+
2. Append to US-0103 ledger via `decision_ledger_lib.append_entry(ledger_path, entry, scratchpad)` with `decision_type="version_derivation"`. Ledger schema unchanged (consumer-only append compose).
|
|
3416
|
+
3. Fail-closed: `RELEASE_TRIGGER_EVENT_EMIT_FAILED`.
|
|
3417
|
+
|
|
3418
|
+
### Reason codes (9 total — DEC-0111 §7)
|
|
3419
|
+
|
|
3420
|
+
| Code | Trigger | Blocking? |
|
|
3421
|
+
|------|---------|-----------|
|
|
3422
|
+
| `RELEASE_TRIGGER_ADAPTER_FAILED` | Adapter dispatch error | **Yes** |
|
|
3423
|
+
| `RELEASE_TRIGGER_TAG_MISSING` | Cannot resolve current tag | **Yes** |
|
|
3424
|
+
| `RELEASE_TRIGGER_PREVIOUS_MISSING` | Cannot resolve previous tag | **Yes** |
|
|
3425
|
+
| `RELEASE_TRIGGER_PACKAGE_JSON_MISSING` | npm adapter: package.json missing | **Yes** |
|
|
3426
|
+
| `RELEASE_TRIGGER_ATOMIC_PROMOTION_FAILED` | Atomic write failed (Windows lock, I/O) | **Yes** |
|
|
3427
|
+
| `RELEASE_TRIGGER_NOTES_WRITE_FAILED` | Per-version notes write failed | **Yes** |
|
|
3428
|
+
| `RELEASE_TRIGGER_EVENT_EMIT_FAILED` | Ledger/event emit failed | **Yes** |
|
|
3429
|
+
| `RELEASE_TRIGGER_COMPARE_VERSIONS_FAILED` | Semver compare failed | **Yes** |
|
|
3430
|
+
| `RELEASE_TRIGGER_SOURCE_INVALID` | Unknown source value | **Yes** |
|
|
3431
|
+
|
|
3432
|
+
### Operator troubleshooting
|
|
3433
|
+
|
|
3434
|
+
| Symptom | Diagnosis | Remediation |
|
|
3435
|
+
|---------|-----------|-------------|
|
|
3436
|
+
| `RELEASE_TRIGGER_SOURCE_INVALID` on startup | Invalid `RELEASE_TRIGGER_SOURCE` in scratchpad | Set to `manual` (default), `github`, `npm`, `git_tag`, or `auto` |
|
|
3437
|
+
| `RELEASE_TRIGGER_TAG_MISSING` in CI | `GITHUB_REF` not set or non-semver | Ensure CI passes `GITHUB_REF=refs/tags/vX.Y.Z` or run `git tag vX.Y.Z && git push --tags` |
|
|
3438
|
+
| `RELEASE_TRIGGER_ATOMIC_PROMOTION_FAILED` on Windows | File lock or antivirus holding CHANGELOG.md | Close IDE tabs; retry; check antivirus exclusion list |
|
|
3439
|
+
| `RELEASE_TRIGGER_EVENT_EMIT_FAILED` with ledger enabled | Ledger file permissions or schema mismatch | Check `handoffs/sovereign_decisions/decisions.jsonl` writable; verify 12-field schema |
|
|
3440
|
+
|
|
3441
|
+
### Compose surfaces (read-only)
|
|
3442
|
+
|
|
3443
|
+
| Composed story | US-0111 boundary |
|
|
3444
|
+
|----------------|------------------|
|
|
3445
|
+
| US-0100 (changelog) | Reuses `promote_unreleased()` and `build_version_doc()` unchanged; no API modifications. |
|
|
3446
|
+
| US-0054 (publish) | Dispatches before `/release` path; `release-all.sh` UNCHANGED. |
|
|
3447
|
+
| US-0103 (ledger) | Consumer of `append_entry()` API only; `decision_type="version_derivation"` additive. |
|
|
3448
|
+
| US-0040 (runbook) | No runbook structure changes; adds new section. |
|
|
3449
|
+
| US-0008 (release-all.sh) | UNCHANGED; US-0111 is pre-release dispatch. |
|
|
3450
|
+
| US-0107 (sovereign loop) | No sovereign loop changes; US-0111 emits events to ledger. |
|
|
3451
|
+
| US-0110 (convergence) | `list_open_deferrals` UNCHANGED; no convergence predicate changes. |
|
|
3452
|
+
|
|
3453
|
+
### Parity enforcement
|
|
3454
|
+
|
|
3455
|
+
```bash
|
|
3456
|
+
python scripts/check_intake_template_parity.py --scope=release-trigger-adapter
|
|
3457
|
+
```
|
|
3458
|
+
|
|
3459
|
+
Pair table (`RELEASE_TRIGGER_ADAPTER_PAIRS`): lib + template lib + contract tests + runbook + reason_codes + scratchpad + parity itself — 7 pairs (active + template).
|
|
3460
|
+
|
|
3461
|
+
### Related artifacts
|
|
3462
|
+
|
|
3463
|
+
- **Architecture**: `docs/engineering/architecture.md` `# US-0111`
|
|
3464
|
+
- **Reason codes**: `docs/engineering/reason_codes.md` § US-0111
|
|
3465
|
+
- **Decision record**: `decisions/DEC-0111.md`
|
|
3466
|
+
- **Library**: `scripts/release_trigger_adapters.py`
|
|
3467
|
+
- **Contract tests**: `tests/us0111_contract_test.py` (12 tests)
|
|
3468
|
+
|
|
3469
|
+
---
|
|
3470
|
+
|
|
3471
|
+
## Compose Guards: US-0054, US-0100, US-0110 (read-only boundaries)
|
|
3472
|
+
|
|
3473
|
+
Contract tests enforce US-0109 does not modify these upstream surfaces:
|
|
3474
|
+
|
|
3475
|
+
### US-0054 — Publish Targets
|
|
3476
|
+
|
|
3477
|
+
`test_us0109_us0054_compose_no_publish_semantics_change` verifies:
|
|
3478
|
+
- No `RELEASE_PUBLISH_OK` token written by US-0109 code
|
|
3479
|
+
- No `release_publish` function calls
|
|
3480
|
+
- No `publish_targets` schema modifications
|
|
3481
|
+
|
|
3482
|
+
US-0109 reads publish status as an observer; publish logic remains in `scripts/release_publish.py`.
|
|
3483
|
+
|
|
3484
|
+
### US-0100 — Changelog / Unreleased Promotion
|
|
3485
|
+
|
|
3486
|
+
`test_us0109_us0100_compose_no_changelog_change` verifies:
|
|
3487
|
+
- No `changelog` string literals in US-0109 code
|
|
3488
|
+
- No `[Unreleased]` version promotion
|
|
3489
|
+
- No `changelog_lib` or `version_changelog` imports
|
|
3490
|
+
|
|
3491
|
+
US-0109 does not write changelog entries or promote versions.
|
|
3492
|
+
|
|
3493
|
+
### US-0110 — Convergence Predicate
|
|
3494
|
+
|
|
3495
|
+
`test_us0109_us0110_compose_no_convergence_change` verifies:
|
|
3496
|
+
- No `convergence` string literals in US-0109 code
|
|
3497
|
+
- No `evaluate_convergence` function calls
|
|
3498
|
+
- No imports from `sovereign_convergence_lib`
|
|
3499
|
+
|
|
3500
|
+
US-0109 does not participate in convergence evaluation.
|
|
3501
|
+
|
|
3502
|
+
---
|
|
3503
|
+
|
|
2582
3504
|
## Project run steps
|
|
2583
3505
|
|
|
2584
3506
|
### Prerequisites
|