its-magic 0.1.3-0 → 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.
Files changed (61) hide show
  1. package/installer.ps1 +8 -0
  2. package/installer.py +8 -0
  3. package/installer.sh +1 -0
  4. package/package.json +1 -1
  5. package/scripts/check_intake_template_parity.py +62 -0
  6. package/template/.cursor/agents/curator.mdc +1 -0
  7. package/template/.cursor/agents/po.mdc +1 -0
  8. package/template/.cursor/agents/release.mdc +1 -0
  9. package/template/.cursor/commands/auto.md +90 -0
  10. package/template/.cursor/commands/execute.md +26 -0
  11. package/template/.cursor/commands/refresh-context.md +32 -0
  12. package/template/.cursor/commands/sovereign-critic.md +104 -0
  13. package/template/.cursor/model-catalog.local.example.cursor-only.json +9 -0
  14. package/template/.cursor/model-catalog.local.example.json +9 -0
  15. package/template/.cursor/model-catalog.local.example.level-1-easy.json +9 -0
  16. package/template/.cursor/model-catalog.local.example.level-2-complex.json +9 -0
  17. package/template/.cursor/model-catalog.local.example.level-3-mega.json +9 -0
  18. package/template/.cursor/model-catalog.local.example.level-4-super.json +9 -0
  19. package/template/.cursor/model-catalog.local.example.role-based-balanced.json +18 -0
  20. package/template/.cursor/model-catalog.local.example.role-based-highend.json +18 -0
  21. package/template/.cursor/rules/sovereign-role-manifest.mdc.example +27 -0
  22. package/template/.cursor/scratchpad.local.example.md +55 -0
  23. package/template/.cursor/scratchpad.md +203 -0
  24. package/template/.cursor/sovereign-role-manifest.yaml.example +53 -0
  25. package/template/decisions/DEC-0104.md +279 -0
  26. package/template/decisions/DEC-0105.md +231 -0
  27. package/template/decisions/DEC-0107.md +246 -0
  28. package/template/docs/engineering/architecture.md +78 -0
  29. package/template/docs/engineering/auto-orchestration-reference.md +7 -0
  30. package/template/docs/engineering/context/installer-owned-paths.manifest +8 -0
  31. package/template/docs/engineering/reason_codes.md +411 -0
  32. package/template/docs/engineering/runbook.md +1119 -0
  33. package/template/docs/engineering/sovereign-memory/.gitkeep +0 -0
  34. package/template/docs/engineering/sovereign-memory/retrospectives/.gitkeep +0 -0
  35. package/template/handoffs/sovereign_decisions/.gitkeep +0 -0
  36. package/template/handoffs/sovereign_deferrals/.gitkeep +0 -0
  37. package/template/handoffs/sovereign_role_reviews.jsonl +0 -0
  38. package/template/scripts/__pycache__/decision_ledger_lib.cpython-312.pyc +0 -0
  39. package/template/scripts/check_intake_template_parity.py +181 -0
  40. package/template/scripts/decision_ledger_lib.py +732 -0
  41. package/template/scripts/ledger_validate.py +153 -0
  42. package/template/scripts/model_tier_lib.py +680 -0
  43. package/template/scripts/model_tier_validate.py +368 -0
  44. package/template/scripts/parallel_dev_arbiter.py +923 -0
  45. package/template/scripts/release_trigger_adapters.py +843 -0
  46. package/template/scripts/self_healing_deploy_lib.py +463 -0
  47. package/template/scripts/self_healing_deploy_validate.py +78 -0
  48. package/template/scripts/sovereign_convergence_lib.py +994 -0
  49. package/template/scripts/sovereign_convergence_validate.py +206 -0
  50. package/template/scripts/sovereign_critic_lib.py +629 -0
  51. package/template/scripts/sovereign_critic_validate.py +131 -0
  52. package/template/scripts/sovereign_loop_lib.py +828 -0
  53. package/template/scripts/sovereign_loop_validate.py +122 -0
  54. package/template/scripts/sovereign_memory_lib.py +869 -0
  55. package/template/scripts/sovereign_memory_validate.py +153 -0
  56. package/template/scripts/sovereign_role_manifest_lib.py +547 -0
  57. package/template/scripts/sovereign_role_manifest_validate.py +105 -0
  58. package/template/tests/us0108_contract_test.py +207 -0
  59. package/template/tests/us0109_contract_test.py +209 -0
  60. package/template/tests/us0109_us0110_compose_test.py +34 -0
  61. package/template/tests/us0111_contract_test.py +345 -0
@@ -0,0 +1,231 @@
1
+ # DEC-0105: Sovereign Memory (US-0105)
2
+
3
+ - **Date**: 2026-06-29
4
+ - **Status**: Accepted
5
+ - **Story**: `US-0105`
6
+ - **Composes on**: **US-0029** (external research — do not amend), **US-0080** / **DEC-0062** (token-cost — lib-side digest only), **US-0103** (per-run ledger — optional promotion), **US-0072** / **DEC-0054** (triad — sovereign-memory explicitly excluded), **US-0096** (lean memory layers — distinct cross-run substrate)
7
+ - **Related**: `R-0093` (research anchor), **US-0107** (drain-generate consumer — read API stability), **US-0110** (convergence — orthogonal), **US-0045** (status authority), **US-0017** (template parity)
8
+ - **Supersedes**: none
9
+ - **Default-off**: `SOVEREIGN_MEMORY=0` — zero overhead when off
10
+
11
+ ## Context
12
+
13
+ Project-level institutional memory for the sovereign-loop batch. Cross-run learnings (decisions, mistakes, patterns, plan drift) persist in bounded JSONL artifacts under `docs/engineering/sovereign-memory/` and inject into phase spawns as a char-capped digest. **US-0029** / **US-0080** / **US-0103** / **US-0072** / **US-0096 are UNCHANGED** — US-0105 adds a new directory surface, scratchpad keys, lib API, and compose hooks only.
14
+
15
+ Research basis: `R-0093` Q1–Q7 closed.
16
+
17
+ ## Decision
18
+
19
+ ### §1 — Scratchpad keys (AC-1)
20
+
21
+ | Key | Values | Default | Notes |
22
+ |-----|--------|---------|-------|
23
+ | **`SOVEREIGN_MEMORY`** | **`0`** \| **`1`** | **`0`** | When `0`, no JSONL writes, no injection reads, no digest assembly — **zero overhead**. |
24
+ | **`SOVEREIGN_MEMORY_TOP_N`** | int ≥ **0** | **`5`** | Global recent pool size (all four JSONL families). |
25
+ | **`SOVEREIGN_MEMORY_TOP_K`** | int ≥ **0** | **`3`** | High-impact pool size (`patterns` + `mistakes` only). |
26
+ | **`SOVEREIGN_MEMORY_MAX_CHARS`** | int ≥ **0** | **`2048`** | Hard cap on assembled `digest_text`. |
27
+ | **`SOVEREIGN_MEMORY_JSONL_MAX_LINES`** | int ≥ **1** | **`500`** | Active JSONL line cap before archive rollover. |
28
+
29
+ Published in **`.cursor/scratchpad.md`** (+ **`template/.cursor/scratchpad.md`** byte-parity per **US-0017**).
30
+
31
+ **Lib constant** (not scratchpad): **`SOVEREIGN_MEMORY_READ_TAIL`** default **500** — max tail lines read per file during digest assembly.
32
+
33
+ **Rejected**: always-on memory (**rejected** — token/latency cost; default-off discipline).
34
+ **Rejected**: empty tracked JSONL seed files (**rejected** — create-on-first-write; ship `.gitkeep` only per **R-0093** Q1).
35
+ **Rejected**: per-file round-robin injection (**rejected** — global time/score merge simpler and more predictable).
36
+ **Rejected**: external memory package dependency (**rejected** — stdlib-only; **R-0093** eml-memory evaluation).
37
+
38
+ ### §2 — Directory surface + bootstrap (AC-2)
39
+
40
+ **Active path**: **`docs/engineering/sovereign-memory/`** (+ **`template/docs/engineering/sovereign-memory/`** mirror).
41
+
42
+ | Artifact | Path | Write owner | Injected v1? |
43
+ |----------|------|-------------|--------------|
44
+ | Decisions log | `decisions-log.jsonl` | Curator promotion; explicit phase append | yes |
45
+ | Mistakes | `mistakes.jsonl` | Orchestrator mistake hooks | yes (top-K) |
46
+ | Patterns | `patterns.jsonl` | Phase roles; curator consolidation | yes (top-K) |
47
+ | Plan drift | `plan-drift-register.jsonl` | Plan-fidelity / scope hooks | yes (top-N) |
48
+ | Retrospectives | `retrospectives/<sprint_id>.md` | Curator `/refresh-context` | **no** (human audit) |
49
+
50
+ **Archive path**: **`docs/engineering/sovereign-memory-archive/<basename>-<YYYYMMDDTHHMMSSZ>.jsonl`** — distinct from **US-0072** triad archives.
51
+
52
+ **Bootstrap**: **create-on-first-write** for JSONL; ship **`.gitkeep`** + **`retrospectives/.gitkeep`** only — no empty tracked JSONL seeds.
53
+
54
+ ### §3 — JSONL v1 schemas (AC-2)
55
+
56
+ Four append-only families sharing base fields:
57
+
58
+ | Field | Type | Required | Notes |
59
+ |-------|------|----------|-------|
60
+ | **`schema_version`** | int | yes | **`1`** |
61
+ | **`ts`** | ISO 8601 UTC | yes | sortable |
62
+ | **`entry_id`** | UUIDv4 | yes | globally unique |
63
+ | **`source_orchestrator_run_id`** | string | no | provenance |
64
+ | **`source_story_id`** | string | no | e.g. `US-0105` |
65
+ | **`phase_id`** | string | no | **DEC-0086** canonical id |
66
+ | **`impact_score`** | int **0..100** | yes | high-impact pool sort key |
67
+ | **`text`** | non-empty string | yes | max **2000** chars |
68
+ | **`tags`** | string[] | yes | max **10** × **40** chars each |
69
+ | **`status`** | enum | yes | `active` \| `superseded` \| `archived` (default **`active`**) |
70
+ | **`provenance_ref`** | string | no | e.g. `R-0093`, `ledger:<decision_id>` |
71
+
72
+ **Family extensions**:
73
+
74
+ - **`decisions-log.jsonl`**: `decision_key` (SHA-256 prefix **16** hex), `decision_text`, `rationale` (max **2000** chars).
75
+ - **`mistakes.jsonl`**: `mistake_tag` ∈ {`fix_failed`, `revert_applied`, `plan_fidelity_violation`, `test_regression`, `scope_creep`}, `failure_reason_code`.
76
+ - **`patterns.jsonl`**: `pattern_id` (slug max **64**), `applies_to` (string[]).
77
+ - **`plan-drift-register.jsonl`**: `drift_type` ∈ {`ac_drop`, `ac_reorder`, `scope_add`, `plan_change`, `acceptance_drift`}, `from_artifact`, `to_artifact`; optional `ledger_decision_id`.
78
+
79
+ **Secret scan**: reject append when `text` / `rationale` / `decision_text` match **`SOVEREIGN_MEMORY_SECRET_DETECTED`** heuristics (mirror **US-0103** `LEDGER_SECRET_DETECTED`: `api_key=`, PEM blocks, `sk-`, `ghp_` prefixes).
80
+
81
+ **Validator**: **`scripts/sovereign_memory_validate.py`** (+ template mirror) — `--file`, `--repo`, `--family {decisions|mistakes|patterns|plan-drift|all}`, `--self-test`, `--enforce`. Exit **0/1/2** mirrors **DEC-0103** / **DEC-0104**. Success token: **`[SOVEREIGN_MEMORY_VALIDATION_OK]`**.
82
+
83
+ ### §4 — Helper library API (AC-3, AC-5, AC-6)
84
+
85
+ **Script**: **`scripts/sovereign_memory_lib.py`** (+ template mirror).
86
+
87
+ | Function | Purpose |
88
+ |----------|---------|
89
+ | `is_sovereign_memory_enabled(scratchpad) -> bool` | `SOVEREIGN_MEMORY=1` gate |
90
+ | `resolve_memory_dir(repo_root) -> Path` | `docs/engineering/sovereign-memory/` |
91
+ | `resolve_jsonl_path(family, repo_root) -> Path` | Per-family JSONL path |
92
+ | `read_entries(family, *, tail_n, active_only=True) -> (list, reason\|None)` | Bounded tail read; **`SOVEREIGN_MEMORY_READ_BOUND`** when truncated |
93
+ | `schema_check(entry, family) -> (bool, error\|None)` | Per-family v1 + secret scan |
94
+ | `compute_decision_key(decision_text) -> str` | Normalized SHA-256 prefix |
95
+ | `dedupe_decision(text, existing_keys) -> (key, is_duplicate)` | Pre-append dedup probe |
96
+ | `append_decision` / `append_mistake` / `append_pattern` / `append_drift` | Append-only + fsync + pre-append rollover hook |
97
+ | `build_injection_digest(repo, scratchpad) -> InjectionDigest` | §5 bounded digest |
98
+ | `promote_from_ledger(run_id, *, decision_types) -> (entry_ids, reason\|None)` | Refresh-context when **`AI_DECISION_LEDGER=1`** |
99
+ | `write_retrospective(sprint_id, body) -> (path\|None, reason\|None)` | Curator markdown under **`retrospectives/`** |
100
+ | `maybe_archive_jsonl(family) -> (ok, reason\|None)` | Line-cap rollover (§7) |
101
+ | `scan_secrets(text) -> ReasonCode\|None` | Pre-append secret guard |
102
+ | `self_test() -> bool` | **`[SOVEREIGN_MEMORY_SELF_TEST_OK]`** |
103
+
104
+ Research stub ships schemas + injection + self-test; append/rollover/promotion bodies finalized at execute.
105
+
106
+ ### §5 — Injection merge algorithm (AC-3, AC-4)
107
+
108
+ `build_injection_digest(repo, scratchpad) -> InjectionDigest` with `{digest_text, entry_ids[], char_count}`:
109
+
110
+ 1. **`SOVEREIGN_MEMORY=0`** → empty digest (`digest_text=""`, `entry_ids=[]`, `char_count=0`) — zero overhead.
111
+ 2. **Empty corpus** → placeholder **`(no sovereign memory entries)`**; non-fatal.
112
+ 3. **Read bound**: at most **`SOVEREIGN_MEMORY_READ_TAIL`** (default **500**) lines per file tail; emit **`SOVEREIGN_MEMORY_READ_BOUND`** as warning only.
113
+ 4. **Top-N recent**: merge all four families' `status=active` entries; sort **`ts` desc**, tie-break **`entry_id` asc**; take first **N** unique `entry_id`s.
114
+ 5. **Top-K high-impact**: from **`patterns`** + **`mistakes`** only; sort **`impact_score` desc**, tie-break **`ts` desc**, then **`entry_id` asc**; skip ids already in recent pool; take **K** more.
115
+ 6. **Digest layout**: `## Recent learnings` then `## High-impact patterns`; each line: `- [family] entry_id: text` (per-line text truncated to **160** chars before global cap).
116
+ 7. **Global cap**: hard truncate assembled digest to **`SOVEREIGN_MEMORY_MAX_CHARS`** (suffix **`...`** if truncated).
117
+ 8. **Retrospectives**: **not injected v1**.
118
+
119
+ **Phase spawn hook** (AC-4): when `SOVEREIGN_MEMORY=1`, spawn assembler appends read-only **`sovereign_memory_digest`** block after phase-context narrow-read, before role instructions. **US-0023** fresh-context boundary unchanged — digest is bounded additive input.
120
+
121
+ ### §6 — Mistake-tagging hooks (AC-6)
122
+
123
+ All hooks **no-op when `SOVEREIGN_MEMORY=0`**. Writes call `append_mistake()` with closed **`mistake_tag`** + orchestrator **`failure_reason_code`**.
124
+
125
+ | Trigger | `mistake_tag` | `failure_reason_code` | Wiring surface |
126
+ |---------|---------------|----------------------|----------------|
127
+ | Execute auto-loop exhausts fix attempts | `fix_failed` | `FIX_FAILED` | **`/auto`** post-execute when **`AUTO_IMPLEMENTATION_LOOP=1`** |
128
+ | Git revert / rollback in execute findings | `revert_applied` | `REVERT_APPLIED` | **`/execute`** rollback sub-step |
129
+ | Plan-fidelity hard stop | `plan_fidelity_violation` | `PLAN_FIDELITY_VIOLATION` | Compose **`decision_ledger_lib.classify_deviation`** — optional import |
130
+ | QA regression after green execute | `test_regression` | `TEST_REGRESSION` | **`/qa`** fail-closed (optional v1.1 defer allowed) |
131
+ | Extended-mode scope add without override | `scope_creep` | `PLAN_FIDELITY_SCOPE_GATE` | Same fidelity hook family |
132
+
133
+ **Dedup** (AC-6): `append_decision()` computes `decision_key = sha256(normalize(decision_text))[:16]`; duplicate → **`SOVEREIGN_MEMORY_DECISION_DUPLICATE`** (non-fatal skip).
134
+
135
+ ### §7 — JSONL rollover vs US-0072 (AC-2)
136
+
137
+ - **Not triad**: sovereign-memory JSONL **excluded** from **US-0072** / **DEC-0054** triad hot surfaces.
138
+ - **Rollover trigger**: on mutating append when active file line count **>** `SOVEREIGN_MEMORY_JSONL_MAX_LINES` → atomically move to archive path, create fresh empty file.
139
+ - **Fail-closed**: rollover I/O failure → **`SOVEREIGN_MEMORY_ARCHIVE_REQUIRED`** (block append).
140
+ - **Idempotency**: second rollover in same boundary must not duplicate archive packs.
141
+ - **Contrast**: triad rollover compacts hot phase context; sovereign-memory archive compacts cold institutional learnings.
142
+
143
+ ### §8 — Curator retrospective + ledger promotion (AC-5)
144
+
145
+ At **`/refresh-context`** after release segment close:
146
+
147
+ 1. `write_retrospective(sprint_id, body)` → `retrospectives/<sprint_id>.md` with `{sprint_id, story_ids[], release_ref, summary, learnings[], promoted_entry_ids[]}`.
148
+ 2. When both **`SOVEREIGN_MEMORY=1`** and **`AI_DECISION_LEDGER=1`**: `promote_from_ledger(run_id, decision_types=...)` copies subset to `decisions-log.jsonl` with `provenance_ref=ledger:<decision_id>`.
149
+ 3. When ledger off or filter empty → **`SOVEREIGN_MEMORY_PROMOTION_SKIPPED`** (info).
150
+
151
+ **US-0103 compose**: ledger remains per-run audit; promotion **reads** ledger context but **does not** mutate ledger schema.
152
+
153
+ ### §9 — Reason code inventory (AC-8)
154
+
155
+ | Code | Blocking? | Surface |
156
+ |------|-----------|---------|
157
+ | **`SOVEREIGN_MEMORY_DISABLED`** | no (info) | scratchpad gate off |
158
+ | **`SOVEREIGN_MEMORY_SCHEMA_INVALID`** | yes | validator / append |
159
+ | **`SOVEREIGN_MEMORY_APPEND_FAILED`** | yes | I/O / permission |
160
+ | **`SOVEREIGN_MEMORY_DECISION_DUPLICATE`** | no (skip append) | dedup on `decision_key` |
161
+ | **`SOVEREIGN_MEMORY_SECRET_DETECTED`** | yes | pre-append scan |
162
+ | **`SOVEREIGN_MEMORY_ARCHIVE_REQUIRED`** | yes | rollover fail-closed |
163
+ | **`SOVEREIGN_MEMORY_READ_BOUND`** | no (warning) | tail read truncated |
164
+ | **`SOVEREIGN_MEMORY_PROMOTION_SKIPPED`** | no (info) | ledger off or filter empty |
165
+
166
+ ### §10 — Contract tests + parity (AC-7, AC-8)
167
+
168
+ Eight **`test_us0105_*`** markers in **`tests/us0105_contract_test.py`**:
169
+
170
+ 1. `test_us0105_scratchpad_keys_literals`
171
+ 2. `test_us0105_sovereign_memory_directory_contract`
172
+ 3. `test_us0105_jsonl_schema_contract`
173
+ 4. `test_us0105_injection_digest_char_cap`
174
+ 5. `test_us0105_decision_dedup_branch`
175
+ 6. `test_us0105_mistake_tagging_literals`
176
+ 7. `test_us0105_zero_overhead_default`
177
+ 8. `test_us0105_compose_guards`
178
+
179
+ Compose regression guards (AC-8):
180
+
181
+ - `test_us0105_us0029_compose_no_research_schema_change`
182
+ - `test_us0105_us0080_injection_respects_char_cap`
183
+
184
+ **`SOVEREIGN_MEMORY_PAIRS`** for `check_intake_template_parity.py --scope=sovereign-memory`:
185
+
186
+ - `scripts/sovereign_memory_lib.py` ↔ `template/scripts/sovereign_memory_lib.py`
187
+ - `scripts/sovereign_memory_validate.py` ↔ `template/scripts/sovereign_memory_validate.py`
188
+ - `.cursor/scratchpad.md` ↔ `template/.cursor/scratchpad.md` (`SOVEREIGN_MEMORY_*` block)
189
+ - `docs/engineering/sovereign-memory/.gitkeep` ↔ `template/docs/engineering/sovereign-memory/.gitkeep`
190
+ - `decisions/DEC-0105.md` ↔ `template/decisions/DEC-0105.md`
191
+
192
+ ### §11 — Composition rules
193
+
194
+ | Story | Compose rule |
195
+ |-------|--------------|
196
+ | **US-0029** | `research.md` schema unchanged; `provenance_ref=R-xxxx` only in memory entries. |
197
+ | **US-0080** / **DEC-0062** | Lib-side digest truncation; **`TOKEN_PROFILE`** / slim-command manifests unchanged. |
198
+ | **US-0103** | Per-run ledger unchanged; optional `promote_from_ledger()` at refresh-context only. |
199
+ | **US-0072** / **DEC-0054** | Triad hot surfaces unchanged; sovereign-memory archive is separate path family. |
200
+ | **US-0096** | `pack.json` / `active-context.md` distinct; sovereign memory is cross-run project layer. |
201
+ | **US-0107** | Read API (`read_entries`, `build_injection_digest`) stable via `schema_version`. |
202
+ | **US-0023** | Fresh-context semantics unchanged; digest is read-only additive spawn input. |
203
+ | **US-0045** | US-0105 remains **OPEN** until release closure. |
204
+
205
+ ### §12 — Risks
206
+
207
+ | Risk | Mitigation |
208
+ |------|------------|
209
+ | **R1** Token bloat | Char cap + tail read + lib-side digest §5 |
210
+ | **R2** Research vs learnings overlap | `provenance_ref` only; no **`research.md`** schema change |
211
+ | **R3** Ledger vs decisions-log confusion | Distinct paths/schemas + runbook operator table |
212
+ | **R4** Stale injection | `status` supersession enum on all entries |
213
+ | **R5** Secret leakage | `SOVEREIGN_MEMORY_SECRET_DETECTED` scan on free-text fields |
214
+ | **R6** **US-0107** read API coupling | Stable lib surface; version via `schema_version` |
215
+
216
+ ### §13 — Implementation tranche order
217
+
218
+ 1. **Tranche A** — scratchpad keys + reason codes + `DEC-0105` template mirror + directory `.gitkeep`
219
+ 2. **Tranche B** — **`sovereign_memory_lib.py`** read/injection core + self-test
220
+ 3. **Tranche C** — append/dedup/rollover/promotion bodies + **`sovereign_memory_validate.py`**
221
+ 4. **Tranche D** — phase spawn digest hook + mistake-tagging orchestrator wiring
222
+ 5. **Tranche E** — curator retrospective + eight `test_us0105_*` + parity + runbook + architecture `# US-0105`
223
+
224
+ ## References
225
+
226
+ - `docs/engineering/research.md` — **`R-0093`**
227
+ - `docs/product/backlog.md` — **`## US-0105`**
228
+ - `handoffs/intake_evidence/intake-sovereign-20260627-01.json`
229
+ - `scripts/sovereign_memory_lib.py` — research stub + self-test
230
+ - `scripts/decision_ledger_lib.py` — promotion compose (read-only)
231
+ - `handoffs/archive/po-to-tl-pack-20260628-f.md` — discovery L1–L12
@@ -0,0 +1,246 @@
1
+ # DEC-0107: Sovereign Loop Mode (US-0107)
2
+
3
+ - **Date**: 2026-06-29
4
+ - **Status**: Accepted
5
+ - **Story**: `US-0107`
6
+ - **Composes on**: **US-0088** (quiet mode), **US-0092** (full-autonomy outer driver), **US-0095** (native-chain segments), **US-0044** (backlog drain), **US-0103** (decision ledger), **US-0105** (sovereign memory), **US-0110** (goal convergence) — **do not amend**; US-0107 **layers** orchestration only
7
+ - **Related**: `R-0094` (research anchor), **US-0109** (deploy smoke — downstream deferral writer), **US-0069** (spawn-only), **US-0045** (status authority), **US-0017** (template parity)
8
+ - **Supersedes**: none
9
+ - **Default-off**: `AUTO_SOVEREIGN=0` — zero overhead when off
10
+
11
+ ## Context
12
+
13
+ Project-level autonomous delivery orchestration for the sovereign-loop batch. When operators enable **`AUTO_SOVEREIGN`**, the outer driver owns **deferral register**, **drain-generate** (PO proposals when backlog empty but not converged), **notification dispatch** on terminal events, and **convergence hooks** via **US-0110**. **US-0088 / US-0092 / US-0095 / US-0044 / US-0103 / US-0105 / US-0110 are UNCHANGED** — US-0107 adds scratchpad keys, JSONL deferral register, loop lib API, sidecar run-state, and compose hooks only.
14
+
15
+ Research basis: `R-0094` Q1–Q7 closed.
16
+
17
+ ## Decision
18
+
19
+ ### §1 — Scratchpad keys + goal-mode coupling (AC-1)
20
+
21
+ | Key | Values | Default | Notes |
22
+ |-----|--------|---------|-------|
23
+ | **`AUTO_SOVEREIGN`** | **`0`** \| **`1`** | **`0`** | When `0`, zero overhead — no deferral reads/writes, no advance, no notifications. |
24
+ | **`AUTO_SOVEREIGN_DEFERRAL_MAX`** | int ≥ **1** | **`50`** | Max open deferral rows; append rejected at cap. |
25
+ | **`AUTO_SOVEREIGN_DRAIN_GENERATE_MAX`** | int ≥ **0** | **`3`** | Max drain-generate PO iterations per `orchestrator_run_id`. |
26
+ | **`AUTO_SOVEREIGN_DEFERRAL_POLICY`** | **`stop`** \| **`skip`** \| **`resolve_first`** | **`resolve_first`** | How open deferrals gate advance. |
27
+ | **`SOVEREIGN_NOTIFY_TARGET`** | **`off`** \| **`ntfy`** \| **`email`** \| **`hook`** | **`off`** | Notification adapter selection. |
28
+ | **`SOVEREIGN_NOTIFY_NTFY_TOPIC`** | string | *(empty)* | ntfy topic — **local-only** value. |
29
+ | **`SOVEREIGN_NOTIFY_NTFY_BASE`** | URL | *(empty)* | Optional ntfy base URL override — **local-only**. |
30
+ | **`SOVEREIGN_NOTIFY_HOOK_URL`** | URL | *(empty)* | Webhook POST target — **local-only**. |
31
+ | **`SOVEREIGN_NOTIFY_EMAIL_TO`** | email | *(empty)* | Email v1 deferred — **local-only** name. |
32
+
33
+ Published in **`.cursor/scratchpad.md`** (+ **`template/.cursor/scratchpad.md`** byte-parity per **US-0017**). Config key **names** in committed scratchpad; **values** in `.cursor/scratchpad.local.md` or env vars only.
34
+
35
+ **Goal-mode coupling (fail-closed)**: `is_sovereign_loop_enabled(scratchpad)` requires **`AUTO_SOVEREIGN=1` AND `SOVEREIGN_GOAL_MODE=goal_convergence`** (via `is_goal_convergence_enabled()` from **US-0110**). When sovereign flag on but goal mode `phase_driven` → `advance_sovereign_loop` returns `action=blocked`, `reason_code=SOVEREIGN_LOOP_GOAL_MODE_REQUIRED` **before** convergence eval.
36
+
37
+ **Rejected**: auto-enable `goal_convergence` when `AUTO_SOVEREIGN=1` — silently changes terminal semantics without operator intent (**R1**).
38
+ **Rejected**: sovereign loop without goal mode — undefined terminal condition.
39
+
40
+ **Operator recipe**: set both `AUTO_SOVEREIGN=1` and `SOVEREIGN_GOAL_MODE=goal_convergence` in `.cursor/scratchpad.local.md`.
41
+
42
+ ### §2 — Deferral register JSONL v1 (AC-2)
43
+
44
+ **Path**: **`handoffs/sovereign_deferrals.jsonl`** (+ template **`handoffs/sovereign_deferrals/`** `.gitkeep` only).
45
+
46
+ **Bootstrap**: **create-on-first-write**; ship **`.gitkeep`** — no empty tracked JSONL seed.
47
+
48
+ **Required fields** (each JSONL line):
49
+
50
+ | Field | Type | Notes |
51
+ |-------|------|-------|
52
+ | **`schema_version`** | int | **`1`** |
53
+ | **`deferral_id`** | UUIDv4 | Stable id across lifecycle rows |
54
+ | **`ts`** | ISO 8601 UTC | Sortable timestamp |
55
+ | **`reason_code`** | string | Orchestrator reason (e.g. `DEPLOY_DEFERRED`, `BLOCK_RETRY_CAP_EXHAUSTED`) |
56
+ | **`work_item_kind`** | enum | **`story`** \| **`bug`** \| **`deploy`** \| **`block`** |
57
+ | **`work_item_ref`** | string | Max **128** chars — `US-xxxx`, `BUG-xxxx`, deploy target, phase token |
58
+ | **`state`** | enum | **`open`** \| **`resolved`** \| **`superseded`** |
59
+ | **`source_orchestrator_run_id`** | string | Non-empty provenance |
60
+ | **`remediation_hint`** | string | Non-empty, max **512** chars |
61
+
62
+ **Optional fields**: `blocked_by_phase` (canonical phase id), `retry_count` (int ≥ 0), `ledger_decision_id` (UUID — **US-0103** provenance only; no ledger schema change).
63
+
64
+ **Lifecycle (append-only)**: `append_deferral` writes `state=open`; `resolve_deferral(deferral_id)` appends new row with same `deferral_id`, `state=resolved`, fresh `ts`; supersede uses `state=superseded`. **Latest-state-wins** per `deferral_id` when computing open set.
65
+
66
+ **Open-row cap**: reject append when `len(list_open_deferrals()) >= AUTO_SOVEREIGN_DEFERRAL_MAX` → **`SOVEREIGN_DEFERRAL_CAP_EXCEEDED`**.
67
+
68
+ **Secret scan**: reject when `remediation_hint` or `work_item_ref` match secret heuristics (mirror **US-0103** / **US-0105**: `api_key=`, PEM, `sk-`, `ghp_`).
69
+
70
+ **Sidecar run-state**: **`handoffs/sovereign_loop_state.json`** v1 — per-`orchestrator_run_id` drain-generate iteration counter (not git-tracked content in template; schema documented only).
71
+
72
+ **Rejected**: in-place mutation of deferral rows (**rejected** — breaks audit trail).
73
+ **Rejected**: empty tracked JSONL seed (**rejected** — create-on-first-write).
74
+
75
+ ### §3 — Validator CLI (AC-2, AC-7)
76
+
77
+ **Script**: **`scripts/sovereign_loop_validate.py`** (+ template mirror).
78
+
79
+ | Flag | Purpose |
80
+ |------|---------|
81
+ | **`--file`** | Validate single JSONL file |
82
+ | **`--repo`** | Validate repo deferrals path |
83
+ | **`--self-test`** | Contract self-test |
84
+ | **`--enforce`** | Fail-closed exit on first invalid line |
85
+
86
+ Exit **0/1/2** mirrors **DEC-0103** / **DEC-0105**. Success token: **`[SOVEREIGN_LOOP_VALIDATION_OK]`**.
87
+
88
+ Lib helper: `schema_check_deferral(entry) -> (bool, error|None)`.
89
+
90
+ ### §4 — Helper library API (AC-3)
91
+
92
+ **Script**: **`scripts/sovereign_loop_lib.py`** (+ template mirror). Research stub ships schemas, gates, dataclasses + self-test (`[SOVEREIGN_LOOP_SELF_TEST_OK]`); advance/dispatch bodies finalized at execute tranche B.
93
+
94
+ **`SovereignLoopStepResult` v1** fields: `schema_version=1`, `action` ∈ {`noop`,`continue`,`defer`,`drain_generate`,`terminal_converged`,`terminal_timeout`,`terminal_cap`,`blocked`}, optional `reason_code`, optional `stop_reason` (native-chain breadcrumb), `orchestrator_run_id`, `evaluated_at` (ISO UTC), optional `deferral_id`, optional `drain_generate_bundle`, optional `notification_dispatched` (bool), optional `convergence` (embedded **US-0110** `ConvergenceResult.to_dict()` snapshot).
95
+
96
+ | Function | Purpose |
97
+ |----------|---------|
98
+ | **`is_sovereign_loop_enabled(scratchpad) -> bool`** | `AUTO_SOVEREIGN=1` **and** `is_goal_convergence_enabled(scratchpad)` |
99
+ | **`resolve_deferrals_path(repo_root) -> Path`** | `handoffs/sovereign_deferrals.jsonl` |
100
+ | **`schema_check_deferral(entry) -> (bool, error\|None)`** | v1 field validation + secret scan |
101
+ | **`list_open_deferrals(repo, *, scratchpad) -> (rows, reason\|None)`** | Latest-state-wins open rows; empty when disabled |
102
+ | **`append_deferral(repo, scratchpad, *, fields...) -> (deferral_id\|None, reason\|None)`** | Append-only + cap enforcement |
103
+ | **`resolve_deferral(repo, deferral_id, *, orchestrator_run_id) -> (ok, reason\|None)`** | Append resolved row |
104
+ | **`count_drain_generate_iterations(repo, orchestrator_run_id) -> int`** | Per-run counter from sidecar |
105
+ | **`advance_sovereign_loop(repo, scratchpad, *, orchestrator_run_id, iteration=None) -> SovereignLoopStepResult`** | Main orchestrator advance — §5 |
106
+ | **`build_drain_generate_spawn_inputs(repo, scratchpad, convergence) -> dict`** | Vision narrow-read + optional memory digest |
107
+ | **`dispatch_notification(scratchpad, event_type, payload) -> (ok, reason\|None)`** | Fail-open adapters — §7 |
108
+ | **`self_test() -> bool`** | **`[SOVEREIGN_LOOP_SELF_TEST_OK]`** |
109
+
110
+ ### §5 — `advance_sovereign_loop` algorithm (AC-3)
111
+
112
+ 1. If `AUTO_SOVEREIGN≠1` → `action=noop` (zero overhead; do not import convergence).
113
+ 2. If `SOVEREIGN_GOAL_MODE≠goal_convergence` → `action=blocked`, `reason_code=SOVEREIGN_LOOP_GOAL_MODE_REQUIRED`.
114
+ 3. `result = evaluate_convergence(repo, scratchpad, orchestrator_run_id=...)`.
115
+ 4. If `result.converged` → `action=terminal_converged` + `dispatch_notification(convergence)` + sovereign terminal stop **`converged`**.
116
+ 5. If `check_timeout(scratchpad, iteration)` → `action=terminal_timeout` + `write_partial_delivery_report` (**US-0110**) + notification.
117
+ 6. Apply **`AUTO_SOVEREIGN_DEFERRAL_POLICY`**: `stop` → block advance when open deferrals; `skip` → informational only; `resolve_first` → block until open deferrals empty (default).
118
+ 7. If backlog has OPEN stories → `action=continue` (delegate to native **US-0044** drain — no bypass).
119
+ 8. If OPEN stories **0** and `not result.converged` and iterations `< AUTO_SOVEREIGN_DRAIN_GENERATE_MAX` → `action=drain_generate` + spawn bundle (§6).
120
+ 9. Else cap/terminal paths → `SOVEREIGN_DRAIN_GENERATE_CAP` or deferral cap + notification.
121
+
122
+ **Sovereign terminal stops** (additive to **US-0088**/**US-0092** matrix): `converged`, `SOVEREIGN_GOAL_TIMEOUT`, `SOVEREIGN_DEFERRAL_CAP_EXCEEDED`, `SOVEREIGN_DRAIN_GENERATE_CAP` — do **not** replace `decision_gate`, `loop_max`, `security deny`, or `BLOCK_RETRY_CAP_EXHAUSTED`.
123
+
124
+ **`drain_terminated`**: set only on sovereign terminal stops — **not** on OPEN-story exhaustion alone (**R5**).
125
+
126
+ ### §6 — Drain-generate contract (AC-4)
127
+
128
+ **Trigger** (all required): `is_sovereign_loop_enabled`, backlog OPEN story count **0**, `evaluate_convergence(...).converged=false`, drain-generate iterations `< AUTO_SOVEREIGN_DRAIN_GENERATE_MAX`, no blocking deferral policy conflict.
129
+
130
+ **Spawn surface**: **`/auto`** outer driver spawns fresh **PO** subagent (spawn-only per **US-0095** / **US-0069**) with ephemeral work item id `drain-gen-{orchestrator_run_id}-{iteration}` — **not** a backlog row until accepted.
131
+
132
+ **PO inputs** (`build_drain_generate_spawn_inputs`): narrow-read `docs/product/vision.md` (exclude Discovery/Intake note sections — same skip rules as **US-0110** goal derive); optional `sovereign_memory_digest` when **`SOVEREIGN_MEMORY=1`** via `build_injection_digest_block()` only; attach `unmet_conditions[]`, `blocked_by[]`, `goal_text` from convergence eval.
133
+
134
+ **`DrainGenerateCandidateBundle` v1** (ephemeral — **not persisted** pre-gate): `schema_version=1`, `orchestrator_run_id`, `iteration`, `generated_at`, `candidates[]` (max **3** per iteration) each with `candidate_id` (UUIDv4), `title` (max **120**), `summary` (max **512**), `ac_sketch` (string[], max **8** items × **256** chars), optional `plan_area_id`, `priority` (default **`P2`**), `provenance` ∈ {`vision`,`memory`,`both`}.
135
+
136
+ **Decision gate (mandatory per candidate)**: PO output → standard **`decision_gate`** in **`/auto`** — operator accept → **`/intake`** or controlled backlog append; reject → discard candidate. **Rejected**: auto-append without gate — violates **US-0092** hard gates (**R2**).
137
+
138
+ **Cap exhausted**: `SOVEREIGN_DRAIN_GENERATE_CAP` sovereign terminal + optional `dispatch_notification(drain_generate_cap)`.
139
+
140
+ ### §7 — Notification adapters (AC-5)
141
+
142
+ **`SOVEREIGN_NOTIFY_TARGET`**: `off` (zero overhead) \| `ntfy` \| `hook` \| `email`.
143
+
144
+ **Event types**: `convergence`, `timeout`, `deferral_cap`, `drain_generate_cap`.
145
+
146
+ **Payload envelope v1**: `{schema_version, event_type, ts, orchestrator_run_id, reason_code, unmet_conditions[], blocked_by[], goal_progress}` where `goal_progress` embeds **US-0110** block when available.
147
+
148
+ **ntfy v1**: stdlib `urllib.request` POST plain-text body to `{SOVEREIGN_NOTIFY_NTFY_BASE or https://ntfy.sh}/{SOVEREIGN_NOTIFY_NTFY_TOPIC}`; headers `Title`, `Priority` (4 for cap/timeout, 3 for convergence), `Tags: sovereign,auto`; timeout **10s**.
149
+
150
+ **hook v1**: POST `application/json` to `SOVEREIGN_NOTIFY_HOOK_URL` with payload envelope; timeout **10s**.
151
+
152
+ **email v1**: **deferred** — `dispatch_notification` returns `(False, SOVEREIGN_NOTIFY_TARGET_INVALID)` with info log; runbook documents v1.1 SMTP stub. **Rejected**: stdlib SMTP in v1 (credential handling + deliverability risk).
153
+
154
+ **Fail-open**: any adapter exception → log **`SOVEREIGN_NOTIFY_DISPATCH_FAILED`**, return `(True, None)` — notification must not block loop.
155
+
156
+ **Secret handling (R4)**: topic/URL values local-only; never write into git-tracked handoffs or JSONL.
157
+
158
+ ### §8 — US-0109 integration declaration (AC-6)
159
+
160
+ **US-0109** implements post-deploy smoke + bounded repair. On cap exhaustion writes **`DEPLOY_DEFERRED`** row to **`sovereign_deferrals.jsonl`** using §2 schema (`work_item_kind=deploy`). **US-0107** owns register schema, validator, read paths, and documents integration contract — **no** deploy smoke logic in US-0107 scope.
161
+
162
+ **`DEPLOY_DEFERRED`**: reserved reason_code for **US-0109** writer; non-blocking deferral row (not advance-block by itself unless policy applies).
163
+
164
+ ### §9 — Reason code inventory (AC-8)
165
+
166
+ | Code | Blocking? | Surface |
167
+ |------|-----------|---------|
168
+ | **`SOVEREIGN_LOOP_DISABLED`** | no (info) | `AUTO_SOVEREIGN=0` zero overhead |
169
+ | **`SOVEREIGN_LOOP_GOAL_MODE_REQUIRED`** | yes | sovereign on without `goal_convergence` |
170
+ | **`SOVEREIGN_DEFERRAL_CAP_EXCEEDED`** | yes | append cap / sovereign terminal |
171
+ | **`SOVEREIGN_DEFERRAL_SCHEMA_INVALID`** | yes | validator / append |
172
+ | **`SOVEREIGN_DEFERRAL_APPEND_FAILED`** | yes | I/O |
173
+ | **`SOVEREIGN_DRAIN_GENERATE_CAP`** | yes | drain-generate iterations exhausted |
174
+ | **`SOVEREIGN_DRAIN_GENERATE_BLOCKED`** | yes | policy/deferral gate blocks spawn |
175
+ | **`SOVEREIGN_NOTIFY_DISPATCH_FAILED`** | no (fail-open log) | adapter errors |
176
+ | **`SOVEREIGN_NOTIFY_TARGET_INVALID`** | no | unknown target / email v1 defer |
177
+ | **`SOVEREIGN_NOTIFY_CONFIG_MISSING`** | no (skip notify) | target on but config absent |
178
+ | **`SOVEREIGN_LOOP_ADVANCE_BLOCKED`** | yes | deferral policy `stop`/`resolve_first` |
179
+ | **`DEPLOY_DEFERRED`** | no (deferral row) | **US-0109** writer (integration) |
180
+
181
+ ### §10 — Contract tests + parity (AC-7, AC-8)
182
+
183
+ Eight **`test_us0107_*`** markers in **`tests/us0107_contract_test.py`**:
184
+
185
+ 1. `test_us0107_scratchpad_keys_literals`
186
+ 2. `test_us0107_deferral_jsonl_schema_contract`
187
+ 3. `test_us0107_advance_deferral_policy_literals`
188
+ 4. `test_us0107_drain_generate_gate_contract`
189
+ 5. `test_us0107_notification_fail_open_literals`
190
+ 6. `test_us0107_goal_mode_coupling_fail_closed`
191
+ 7. `test_us0107_zero_overhead_default`
192
+ 8. `test_us0107_compose_no_stop_matrix_change`
193
+
194
+ Compose regression guards (AC-8):
195
+
196
+ - `test_us0107_us0110_convergence_import_contract`
197
+ - `test_us0107_us0095_spawn_only_regression_guard`
198
+
199
+ **`SOVEREIGN_LOOP_PAIRS`** for `check_intake_template_parity.py --scope=sovereign-loop`:
200
+
201
+ - `scripts/sovereign_loop_lib.py` ↔ `template/scripts/sovereign_loop_lib.py`
202
+ - `scripts/sovereign_loop_validate.py` ↔ `template/scripts/sovereign_loop_validate.py`
203
+ - `.cursor/scratchpad.md` ↔ `template/.cursor/scratchpad.md` (`AUTO_SOVEREIGN_*` + `SOVEREIGN_NOTIFY_*` block)
204
+ - `handoffs/sovereign_deferrals/.gitkeep` ↔ `template/handoffs/sovereign_deferrals/.gitkeep`
205
+ - `decisions/DEC-0107.md` ↔ `template/decisions/DEC-0107.md`
206
+ - `scripts/check_intake_template_parity.py` ↔ `template/scripts/check_intake_template_parity.py` (scope registration)
207
+
208
+ ### §11 — Composition rules
209
+
210
+ | Story | Compose rule |
211
+ |-------|--------------|
212
+ | **US-0088** / **US-0092** / **US-0095** | Stop matrix, spawn-only, native chain **unchanged**; sovereign terminal stops additive only. |
213
+ | **US-0044** / **US-0087** | Drain mutex unchanged; sovereign advance consults deferrals before story selection. |
214
+ | **US-0103** | Optional deferral provenance via `ledger_decision_id`; ledger schema unchanged. |
215
+ | **US-0105** | Drain-generate reads `build_injection_digest_block()` only when `SOVEREIGN_MEMORY=1`. |
216
+ | **US-0110** | Import `evaluate_convergence`, `is_goal_convergence_enabled`, `build_goal_progress_block`, `check_timeout`, `write_partial_delivery_report`; export `list_open_deferrals()` for `zero_deferrals` conjunct wiring — **do not amend** five-conjunct set or **DEC-0110**. |
217
+ | **US-0109** | Downstream `DEPLOY_DEFERRED` writer — schema stable in US-0107 first (**R6**). |
218
+ | **US-0069** | Spawn-only PO for drain-generate — no in-chat chain bypass. |
219
+ | **US-0045** | US-0107 remains **OPEN** until release closure. |
220
+
221
+ ### §12 — Risks
222
+
223
+ | Risk | Mitigation |
224
+ |------|------------|
225
+ | **R1** Goal-mode coupling | Fail-closed **`SOVEREIGN_LOOP_GOAL_MODE_REQUIRED`**; operator recipe in runbook §1 |
226
+ | **R2** Drain-generate scope creep | Max **3** candidates/iteration + mandatory decision gate per candidate §6 |
227
+ | **R3** Deferral cap vs **`CONVERGENCE_DEFERRALS_PENDING`** | Shared `list_open_deferrals()` latest-state-wins; cap blocks append, open rows block convergence |
228
+ | **R4** Notification secrets | Local-only config; payload excludes hook URLs/topics |
229
+ | **R5** Sovereign terminal vs **US-0095** segments | Terminal stops additive post-segment eval; `drain_terminated` only on sovereign terminal |
230
+ | **R6** **US-0109** ordering | Deferral v1 schema + validator stable in US-0107; **`DEPLOY_DEFERRED`** reserved |
231
+
232
+ ### §13 — Implementation tranche order
233
+
234
+ 1. **Tranche A** — scratchpad keys + reason codes + `DEC-0107` template mirror + deferrals `.gitkeep`
235
+ 2. **Tranche B** — **`sovereign_loop_lib.py`** deferral CRUD + `list_open_deferrals` + self-test core
236
+ 3. **Tranche C** — **`advance_sovereign_loop`** + **`sovereign_loop_validate.py`** + sidecar run-state
237
+ 4. **Tranche D** — drain-generate spawn inputs + notification adapters + **`/auto`** advance wiring + **US-0110** `zero_deferrals` compose
238
+ 5. **Tranche E** — eight `test_us0107_*` + compose guards + **`SOVEREIGN_LOOP_PAIRS`** parity + runbook + architecture `# US-0107`
239
+
240
+ ## References
241
+
242
+ - `docs/engineering/research.md` — **`R-0094`**
243
+ - `docs/product/backlog.md` — **`## US-0107`**
244
+ - `handoffs/intake_evidence/intake-sovereign-20260627-01.json`
245
+ - `scripts/sovereign_loop_lib.py` — research stub + self-test
246
+ - Shipped compose: `scripts/sovereign_convergence_lib.py` (**US-0110**), `scripts/sovereign_memory_lib.py` (**US-0105**), `scripts/decision_ledger_lib.py` (**US-0103**)
@@ -7,3 +7,81 @@
7
7
  ## Risks
8
8
 
9
9
  ## Decisions
10
+
11
+ # US-0112 — Model-catalog example preset delivery
12
+
13
+ **Story**: US-0112 (Ship model-catalog example presets on install/upgrade)
14
+ **Decision**: DEC-0112 (Accepted)
15
+ **Research anchor**: R-0090 (delivered, Q1–Q8 closed)
16
+
17
+ ## Framework vs operator boundary
18
+
19
+ The 8 `model-catalog.local.example*.json` presets are **framework files** under installer manifest control. They ship on install/upgrade and are refreshed when stale (same semantics as `scratchpad.local.example.md` per US-0075/US-0018/US-0057).
20
+
21
+ The active operator-owned `.cursor/model-catalog.local.json` is **gitignored**, outside `install_include_paths` and `clean_paths`, and never touched by any installer mode. This is a DEC-0086/DEC-0087 boundary — US-0112 completes delivery of existing presets without altering catalog schema (US-0101) or role precedence (US-0102).
22
+
23
+ ## Manifest rows (8 paths)
24
+
25
+ Under `[install_include_paths]` in both `docs/engineering/context/installer-owned-paths.manifest` and `template/docs/engineering/context/installer-owned-paths.manifest` (16 rows total, byte-parity):
26
+
27
+ 1. `.cursor/model-catalog.local.example.json`
28
+ 2. `.cursor/model-catalog.local.example.cursor-only.json`
29
+ 3. `.cursor/model-catalog.local.example.level-1-easy.json`
30
+ 4. `.cursor/model-catalog.local.example.level-2-complex.json`
31
+ 5. `.cursor/model-catalog.local.example.level-3-mega.json`
32
+ 6. `.cursor/model-catalog.local.example.level-4-super.json`
33
+ 7. `.cursor/model-catalog.local.example.role-based-balanced.json`
34
+ 8. `.cursor/model-catalog.local.example.role-based-highend.json`
35
+
36
+ ## Upgrade classification (framework files)
37
+
38
+ - **Missing mode**: copies all 8 examples when absent; no-op when present; deterministic log/status per file.
39
+ - **Upgrade mode**: refreshes stale framework files (template content differs); skips byte-identical files; never touches `.cursor/model-catalog.local.json`.
40
+ - **Triple installer parity**: `installer.py`, `installer.ps1`, `installer.sh` all classify `.cursor/model-catalog.local.example*.json` as `framework` via explicit enumeration in `FRAMEWORK_EXACT` (Python) / `$frameworkExact` (PowerShell) / case pattern (Bash).
41
+
42
+ ## DEC-0086 / DEC-0087 compose
43
+
44
+ US-0112 does **not** amend:
45
+ - US-0101 (catalog schema, DEC-0086)
46
+ - US-0102 (role catalog precedence, DEC-0087)
47
+ - US-0054 (publish confirmation gates)
48
+ - US-0057 (example-first refresh)
49
+ - US-0075 (scratchpad example-first)
50
+
51
+ US-0112 only extends the installer manifest to include the 8 example presets as framework files, completing DEC-0086/DEC-0087 delivery path.
52
+
53
+ ## Active catalog protection invariant
54
+
55
+ `.cursor/model-catalog.local.json` is:
56
+ - Gitignored (not tracked)
57
+ - Outside `install_include_paths` (not manifest-copied)
58
+ - Outside `clean_paths` (not manifest-cleaned)
59
+ - Never auto-populated by any installer mode
60
+ - Operator-owned; installer respects DEC-0086/DEC-0087 ownership boundary
61
+
62
+ ## Test markers (8+)
63
+
64
+ `tests/us0112_contract_test.py` provides:
65
+ - `test_us0112_manifest_lists_eight_paths` (active + template)
66
+ - `test_us0112_missing_mode_adds_absent_framework_files` (Python/PS1/Bash)
67
+ - `test_us0112_upgrade_mode_refreshes_stale_framework_files`
68
+ - `test_us0112_upgrade_mode_preserves_unchanged_files`
69
+ - `test_us0112_upgrade_mode_never_touches_local_catalog`
70
+ - `test_us0112_active_catalog_protection_invariant`
71
+ - `test_us0112_parity_scope_model_catalog_examples`
72
+ - `test_us0112_runbook_lists_eight_preset_literals`
73
+
74
+ ## Parity scope
75
+
76
+ `scripts/check_intake_template_parity.py --scope=model-catalog-examples` validates active vs template byte-parity for the manifest rows (16 rows total). Constant: `MODEL_CATALOG_EXAMPLE_PAIRS` includes the manifest pair.
77
+
78
+ ## Reason codes
79
+
80
+ - `MODEL_CATALOG_EXAMPLE_PARITY_SCOPE_OK`
81
+ - `MODEL_CATALOG_EXAMPLE_PARITY_SCOPE_MISMATCH`
82
+
83
+ ## Compose guards (non-negotiable)
84
+
85
+ DO NOT amend: US-0008, US-0018, US-0040, US-0054, US-0057, US-0075, US-0100, US-0101, US-0102, US-0103, US-0107, US-0110.
86
+
87
+ US-0112 is additive only — extends manifest + installer classification; no schema/precedence changes.
@@ -1126,6 +1126,13 @@ when stack cannot be resolved. Connect block fields align with
1126
1126
  `AUTO_ROLE_REFRESH_CONTEXT`), enforce execute default deny / override
1127
1127
  contract, and run the preflight capability gate; on failure stop with
1128
1128
  `PHASE_ROLE_CAPABILITY_MISSING` (no unrelated-role spawn).
1129
+ - **US-0105 / DEC-0105**: When `SOVEREIGN_MEMORY=1`, after phase-context
1130
+ narrow-read and **before** role instructions, append read-only
1131
+ **`sovereign_memory_digest`** block assembled via
1132
+ `build_injection_digest_block(...)` from `scripts/sovereign_memory_lib.py`
1133
+ (bounded top-N/top-K merge; char cap `SOVEREIGN_MEMORY_MAX_CHARS`). When
1134
+ `SOVEREIGN_MEMORY=0` (default), skip with zero overhead — **US-0023**
1135
+ fresh-context boundary unchanged.
1129
1136
  - **US-0069 / DEC-0051**: After each phase completes, validate isolation
1130
1137
  `role` and strict-proof `role` against the preflight-resolved expected
1131
1138
  role; on conflict stop with `PHASE_ROLE_MISMATCH`.
@@ -14,6 +14,14 @@
14
14
  .cursor/hooks
15
15
  .cursor/hooks.json
16
16
  .cursor/scratchpad.local.example.md
17
+ .cursor/model-catalog.local.example.json
18
+ .cursor/model-catalog.local.example.cursor-only.json
19
+ .cursor/model-catalog.local.example.level-1-easy.json
20
+ .cursor/model-catalog.local.example.level-2-complex.json
21
+ .cursor/model-catalog.local.example.level-3-mega.json
22
+ .cursor/model-catalog.local.example.level-4-super.json
23
+ .cursor/model-catalog.local.example.role-based-balanced.json
24
+ .cursor/model-catalog.local.example.role-based-highend.json
17
25
  docs
18
26
  sprints
19
27
  handoffs