@event4u/agent-config 14.5.0 → 14.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (203) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/CHANGELOG.md +384 -3
  3. package/README.md +1 -1
  4. package/dist/agent-src/commands/analyze/decision.md +7 -0
  5. package/dist/agent-src/commands/analyze/inbox.md +264 -10
  6. package/dist/agent-src/commands/analyze.md +1 -1
  7. package/dist/agent-src/commands/optimize/project.md +10 -0
  8. package/dist/agent-src/commands/roadmap/process-full.md +132 -4
  9. package/dist/agent-src/contexts/execution/roadmap-execution-contract.md +31 -0
  10. package/dist/agent-src/contexts/execution/roadmap-process-loop.md +161 -1
  11. package/dist/agent-src/rules/context-hygiene.md +2 -0
  12. package/dist/agent-src/rules/decision-revisit-gate.md +111 -7
  13. package/dist/agent-src/rules/fix-what-you-see.md +108 -0
  14. package/dist/agent-src/rules/no-roadmap-references.md +0 -5
  15. package/dist/agent-src/rules/recurring-criticism.md +110 -0
  16. package/dist/agent-src/rules/roadmap-progress-sync.md +1 -1
  17. package/dist/agent-src/rules/rule-type-governance.md +0 -2
  18. package/dist/agent-src/rules/self-repair-loop.md +17 -0
  19. package/dist/agent-src/rules/skill-quality.md +0 -2
  20. package/dist/agent-src/rules/source-confidentiality.md +37 -7
  21. package/dist/agent-src/scripts/archival_sweep.ts +117 -0
  22. package/dist/agent-src/scripts/archive_completed_roadmaps.ts +19 -3
  23. package/dist/agent-src/scripts/gate_budget.ts +282 -0
  24. package/dist/agent-src/scripts/gate_execute.ts +72 -31
  25. package/dist/agent-src/scripts/roadmap_gates.ts +74 -3
  26. package/dist/agent-src/scripts/update_roadmap_progress.ts +251 -7
  27. package/dist/agent-src/skills/adr-create/SKILL.md +25 -3
  28. package/dist/agent-src/skills/ai-council/SKILL.md +48 -807
  29. package/dist/agent-src/skills/ai-council/references/advanced-modes.md +320 -0
  30. package/dist/agent-src/skills/ai-council/references/cost-and-redaction.md +99 -0
  31. package/dist/agent-src/skills/ai-council/references/execution-modes.md +162 -0
  32. package/dist/agent-src/skills/ai-council/references/output-and-synthesis.md +125 -0
  33. package/dist/agent-src/skills/ai-council/references/procedure.md +143 -0
  34. package/dist/agent-src/skills/decision-review/SKILL.md +18 -0
  35. package/dist/agent-src/skills/quality-tools/SKILL.md +34 -326
  36. package/dist/agent-src/skills/quality-tools/references/js-ts-tools.md +113 -0
  37. package/dist/agent-src/skills/quality-tools/references/php-tools.md +222 -0
  38. package/dist/agent-src/skills/roadmap-management/SKILL.md +15 -409
  39. package/dist/agent-src/skills/roadmap-management/references/archival.md +226 -0
  40. package/dist/agent-src/skills/roadmap-management/references/authoring.md +107 -0
  41. package/dist/agent-src/skills/roadmap-management/references/dashboard.md +47 -0
  42. package/dist/agent-src/skills/roadmap-management/references/lifecycle.md +58 -0
  43. package/dist/agent-src/skills/skill-writing/SKILL.md +34 -570
  44. package/dist/agent-src/skills/skill-writing/references/procedure.md +275 -0
  45. package/dist/agent-src/skills/skill-writing/references/read-only-scripts.md +18 -0
  46. package/dist/agent-src/skills/skill-writing/references/section-patterns.md +298 -0
  47. package/dist/agent-src/templates/agents/agent-project-settings.example.yml +1 -1
  48. package/dist/agent-src/templates/roadmaps.md +45 -2
  49. package/dist/agent-src/templates/scripts/telemetry/flush_sender.mjs +163 -0
  50. package/dist/agent-src/templates/scripts/telemetry/remote.ts +160 -7
  51. package/dist/agent-src/templates/scripts/telemetry/transport.ts +169 -0
  52. package/dist/cli/registry.js +1 -1
  53. package/dist/cli/registry.js.map +1 -1
  54. package/dist/cli-delegate/chunk-2GNWGMAL.js +172 -0
  55. package/dist/cli-delegate/{chunk-RLN73PR5.js → chunk-4VR4ORQ6.js} +10 -7
  56. package/dist/cli-delegate/chunk-6EOCNQAM.js +402 -0
  57. package/dist/cli-delegate/{chunk-XURJ4AQC.js → chunk-74E3TKWV.js} +381 -280
  58. package/dist/cli-delegate/{chunk-3UCJWMMP.js → chunk-7F3VYSM2.js} +4 -4
  59. package/dist/cli-delegate/{chunk-BKO2AZ7Z.js → chunk-B2ERU2VA.js} +1 -1
  60. package/dist/cli-delegate/{chunk-NXFWFAYV.js → chunk-G23AT6GD.js} +1 -0
  61. package/dist/cli-delegate/{chunk-63WSP6YZ.js → chunk-GJ5BVHXM.js} +72 -165
  62. package/dist/cli-delegate/{chunk-ZPSXJTLI.js → chunk-JZ4NR2TW.js} +353 -1
  63. package/dist/cli-delegate/chunk-MWRD5YOH.js +100 -0
  64. package/dist/cli-delegate/{chunk-GRRPEPRN.js → chunk-T7L2QK3K.js} +24 -5
  65. package/dist/cli-delegate/{chunk-EVTY7ISR.js → chunk-YM4GZDJG.js} +9 -1
  66. package/dist/cli-delegate/cmd_conformance.js +459 -709
  67. package/dist/cli-delegate/cmd_doctor.js +6 -6
  68. package/dist/cli-delegate/cmd_explain.js +1 -1
  69. package/dist/cli-delegate/cmd_export.js +7 -6
  70. package/dist/cli-delegate/cmd_handoff.js +6 -6
  71. package/dist/cli-delegate/cmd_packs_active.js +1 -1
  72. package/dist/cli-delegate/cmd_preflight.js +2 -2
  73. package/dist/cli-delegate/cmd_prune.js +7 -6
  74. package/dist/cli-delegate/cmd_session_recycle.js +840 -30
  75. package/dist/cli-delegate/cmd_settings_migrate.js +7 -6
  76. package/dist/cli-delegate/cmd_settings_set.js +1 -1
  77. package/dist/cli-delegate/cmd_sync.js +7 -6
  78. package/dist/cli-delegate/cmd_uninstall.js +9 -7
  79. package/dist/cli-delegate/cmd_update.js +1 -1
  80. package/dist/cli-delegate/cmd_upgrade.js +1 -1
  81. package/dist/cli-delegate/cmd_validate.js +7 -6
  82. package/dist/discovery/deprecation-report.md +1 -1
  83. package/dist/discovery/discovery-manifest.json +72 -29
  84. package/dist/discovery/discovery-manifest.json.sha256 +1 -1
  85. package/dist/discovery/discovery-manifest.summary.md +4 -4
  86. package/dist/discovery/dormancy-report.md +1 -1
  87. package/dist/discovery/orphan-report.md +1 -1
  88. package/dist/discovery/packs.json +10 -8
  89. package/dist/discovery/trust-report.md +3 -3
  90. package/dist/discovery/workspaces.json +8 -6
  91. package/dist/hooks/dispatch.js +3127 -2022
  92. package/dist/install/claudePathsPlan.js +187 -0
  93. package/dist/install/claudePathsPlan.js.map +1 -0
  94. package/dist/install/hostLayerFingerprint.js +136 -0
  95. package/dist/install/hostLayerFingerprint.js.map +1 -0
  96. package/dist/install/install.mjs +553 -425
  97. package/dist/install/partitionEligibility.js +276 -0
  98. package/dist/install/partitionEligibility.js.map +1 -0
  99. package/dist/mcp/registry-manifest.json +3 -3
  100. package/dist/mcp/server.json +2 -2
  101. package/dist/mcp/server.mjs +1744 -1191
  102. package/dist/router.json +1 -1
  103. package/dist/scripts/_lib/agent_src.js +41 -0
  104. package/dist/scripts/_lib/agent_src.js.map +1 -1
  105. package/dist/scripts/_lib/install_layout.js +83 -0
  106. package/dist/scripts/_lib/install_layout.js.map +1 -0
  107. package/dist/scripts/_lib/installed_lock.js +444 -0
  108. package/dist/scripts/_lib/installed_lock.js.map +1 -0
  109. package/dist/scripts/condense.js +13 -164
  110. package/dist/scripts/condense.js.map +1 -1
  111. package/dist/server/schemas/settings.js +4 -0
  112. package/dist/server/schemas/settings.js.map +1 -1
  113. package/docs/contracts/settings-classes.md +12 -6
  114. package/docs/guidelines/agent-infra/agent-interaction-and-decision-quality.md +8 -3
  115. package/docs/guidelines/agent-infra/context-hygiene-mechanics.md +26 -0
  116. package/docs/guidelines/agent-infra/engineering-memory-data-format.md +49 -0
  117. package/docs/guidelines/agent-infra/memory-access.md +17 -0
  118. package/docs/guidelines/agent-infra/recurring-criticism-mechanics.md +96 -0
  119. package/package.json +1 -1
  120. package/src/agent-src/scripts/archival_sweep.ts +117 -0
  121. package/src/agent-src/scripts/archive_completed_roadmaps.ts +19 -3
  122. package/src/agent-src/scripts/gate_budget.ts +282 -0
  123. package/src/agent-src/scripts/gate_execute.ts +72 -31
  124. package/src/agent-src/scripts/roadmap_gates.ts +74 -3
  125. package/src/agent-src/scripts/update_roadmap_progress.ts +251 -7
  126. package/src/agent-src/templates/scripts/telemetry/flush_sender.mjs +163 -0
  127. package/src/agent-src/templates/scripts/telemetry/remote.ts +160 -7
  128. package/src/agent-src/templates/scripts/telemetry/transport.ts +169 -0
  129. package/src/config/agent-settings.template.yml +27 -2
  130. package/src/config/ci-local-parity.yml +18 -0
  131. package/src/config/estate-count-budget.json +367 -3
  132. package/src/config/gate-violation-baselines.json +41 -41
  133. package/src/config/pack-size-budget.json +3 -2
  134. package/src/config/rule-activation-census.json +14 -6
  135. package/src/config/rule-stub-ceilings.json +19 -6
  136. package/src/install/claudePathsPlan.ts +196 -0
  137. package/src/install/hostLayerFingerprint.ts +145 -0
  138. package/src/install/partitionEligibility.ts +325 -0
  139. package/src/scripts/_cli/cmd_session_recycle.ts +9 -1
  140. package/src/scripts/_dispatch.bash +6 -1
  141. package/src/scripts/_lib/ac_heading.ts +30 -0
  142. package/src/scripts/_lib/agent_src.ts +42 -0
  143. package/src/scripts/_lib/bench_ab_pinned_repo.ts +162 -0
  144. package/src/scripts/_lib/bench_ab_workspace.ts +10 -1
  145. package/src/scripts/_lib/envelope_grounding.ts +38 -8
  146. package/src/scripts/_lib/installed_lock.ts +50 -5
  147. package/src/scripts/_lib/layer_overlap_notice.ts +85 -0
  148. package/src/scripts/_lib/md_section.ts +129 -0
  149. package/src/scripts/_lib/scope_guard.sh +86 -4
  150. package/src/scripts/_lib/self_repair.ts +19 -0
  151. package/src/scripts/_lib/self_repair_class_b.ts +171 -0
  152. package/src/scripts/_lib/subagent_capsule.ts +81 -1
  153. package/src/scripts/adr/regenerate_index.ts +13 -2
  154. package/src/scripts/adr_cite_check.ts +424 -0
  155. package/src/scripts/ai_council/cli_help.ts +55 -0
  156. package/src/scripts/before_complete_hook.ts +153 -28
  157. package/src/scripts/bench_ab_v2_complexity.ts +27 -7
  158. package/src/scripts/check_adr_frontmatter.ts +187 -1
  159. package/src/scripts/check_references.ts +60 -0
  160. package/src/scripts/check_release_published.ts +32 -11
  161. package/src/scripts/check_single_delivery.ts +517 -0
  162. package/src/scripts/ci_settle.ts +170 -0
  163. package/src/scripts/condense.ts +20 -170
  164. package/src/scripts/council_cli.ts +3 -3
  165. package/src/scripts/dispatch_r2_reviewer.ts +6 -14
  166. package/src/scripts/hook_manifest.json +1 -1
  167. package/src/scripts/hook_manifest.yaml +77 -14
  168. package/src/scripts/hooks/block_no_verify.ts +61 -10
  169. package/src/scripts/hooks/block_unauthorized_git.ts +1 -1
  170. package/src/scripts/hooks/concern_registry.ts +4 -0
  171. package/src/scripts/hooks/rtk_wrap_hook.ts +8 -3
  172. package/src/scripts/hooks/run_continuation_hook.ts +887 -68
  173. package/src/scripts/hooks/ship_diff_volume_hook.ts +81 -15
  174. package/src/scripts/hooks/source_first_gate_hook.ts +464 -0
  175. package/src/scripts/hooks/state_io.ts +782 -20
  176. package/src/scripts/hooks/subagent_ledger_hook.ts +44 -15
  177. package/src/scripts/hooks/telemetry_flush_hook.ts +139 -0
  178. package/src/scripts/hooks/telemetry_self_repair.ts +128 -0
  179. package/src/scripts/hooks/telemetry_usage_hook.ts +22 -4
  180. package/src/scripts/hooks/turn_end_gate_hook.ts +81 -15
  181. package/src/scripts/install.sh +12 -2
  182. package/src/scripts/install.ts +16 -11
  183. package/src/scripts/language_mirror_hook.ts +561 -25
  184. package/src/scripts/lint_framework_leakage_allowlist.json +2 -2
  185. package/src/scripts/lint_plan_risk_register.ts +4 -3
  186. package/src/scripts/lint_skill_router_head.ts +4 -4
  187. package/src/scripts/mcp_server/tools.ts +2 -2
  188. package/src/scripts/memory_consolidation.ts +189 -0
  189. package/src/scripts/memory_eviction.ts +384 -0
  190. package/src/scripts/new_roadmap.ts +136 -0
  191. package/src/scripts/pack_mcp_content.ts +20 -5
  192. package/src/scripts/release.ts +37 -38
  193. package/src/scripts/report_layer_overlap.ts +78 -0
  194. package/src/scripts/report_memory_pointers.ts +622 -0
  195. package/src/scripts/self_repair_hook.ts +37 -5
  196. package/src/scripts/session_register_hook.ts +115 -15
  197. package/src/scripts/skill_usage_collect.ts +11 -1
  198. package/src/scripts/skill_usage_report.ts +278 -8
  199. package/src/scripts/sync_pr_branch.ts +7 -0
  200. package/src/server/schemas/settings.ts +8 -0
  201. package/dist/cli-delegate/chunk-EJITJBJX.js +0 -172
  202. package/dist/cli-delegate/chunk-PZWRPRWP.js +0 -38
  203. /package/dist/cli-delegate/{chunk-RYNADUFG.js → chunk-LWTYTX6F.js} +0 -0
@@ -88,3 +88,29 @@ Exit code is always 0 — hooks must never block the agent loop.
88
88
 
89
89
  - `context-hygiene` (rule) — thresholds, 3-failure rule, tool-loop cap, read-loop Iron Law.
90
90
  - `systematic-debugging` § Debug micro-loop — the one-test-one-fix-one-rerun procedure.
91
+
92
+ ## The CI waiter — use the helper, never the hand-written loop
93
+
94
+ `./scripts-run src/scripts/ci_settle <pr> [--timeout-min N] [--interval-sec N]`
95
+
96
+ Exit codes: **0** settled green · **1** settled red, with the failing checks
97
+ named · **2** did not settle, or the API could not be read — never a verdict.
98
+
99
+ Four states classify as *not settled*, and each one is a way the hand-written
100
+ form goes wrong: an API error, a non-zero `gh` exit, unparseable output, and
101
+ **zero registered checks** (a run that has not registered its checks yet looks
102
+ exactly like a finished one with nothing to report).
103
+
104
+ **Why it exists.** Measured 2026-08-20:
105
+
106
+ ```bash
107
+ until ! gh pr checks 1459 | grep -q "pending"; do sleep 60; done
108
+ ```
109
+
110
+ The API then failed. Its error text — `error connecting to api.github.com` —
111
+ contains no `pending`, so the loop exited, the session reported a settle that
112
+ had not happened, and the claim had to be retracted to the user in the next
113
+ reply. The bug is not the sleep or the grep: **absence of the word `pending`
114
+ was treated as evidence of completion**, and an error is neither settled nor
115
+ pending. The exit condition is the part that is easy to get wrong, so it lives
116
+ in one place rather than in every agent's head.
@@ -44,6 +44,29 @@ rejects entries missing any required field.
44
44
  | `review_after_days` | yes | integer | triggers staleness warning |
45
45
  | `priority` | no | `critical` \| `normal` \| `low` | tier-0 surfacing; defaults to `normal` |
46
46
  | `ts_week` | no | ISO-week string `YYYY-Www` | promotion week stamp; convention, not enforced |
47
+ | `verified_at_commit` | no | 7-40 char lowercase hex | the tree revision the entry was **semantically verified against** — not the commit that last edited the YAML |
48
+ | `semantic_verdict` | no | `still-true` \| `stale` \| `unverifiable` | a recorded **human** reading of the entry against that tree |
49
+ | `semantic_verdict_at` | no | ISO date | when that reading was taken |
50
+
51
+ ### Verification stamps (`verified_at_commit` / `semantic_verdict`)
52
+
53
+ A date alone cannot be tied to a tree state, and that gap is not theoretical:
54
+ spike cf02 measured the curated store at **21.5 % stale against the tree** while
55
+ the shipped instrument reported **0.0 %**, because all 107 entries carried one
56
+ `last_validated` and one 365-day window, so the check could not fire before
57
+ 2027. `verified_at_commit` is what makes a stamp falsifiable — with it, a reader
58
+ can ask whether anything the entry cites has changed since it was last read.
59
+
60
+ `semantic_verdict` records the outcome of that read. It is **human-written**,
61
+ deliberately: no mechanical signal predicts it. Pointer liveness was built and
62
+ measured for exactly this job and came in at 0.00x lift over the base rate
63
+ (cf04) — a dead citation is documentation debt, not a false claim.
64
+
65
+ A `stale` verdict demotes the entry immediately, regardless of age
66
+ (`memory_eviction.ts`, "contradiction outranks retention"). An `unverifiable`
67
+ entry — one about an external system, a past event, or a recorded preference —
68
+ is surfaced on age but never quarantined on it, because the tree can never
69
+ discharge the reason.
47
70
 
48
71
  ### Priority semantics (`critical` / `normal` / `low`)
49
72
 
@@ -143,6 +166,32 @@ path if the guardrail is absent.
143
166
  `(today - last_validated) > review_after_days`. Stale entries stay
144
167
  active — the report is informational, not a gate.
145
168
 
169
+ **The window is per store, and the numbers are derived rather than chosen.**
170
+ cf02 measured decay over the same 39-day span in three stores:
171
+ `historical-patterns` 45.8 %, `incident-learnings` 17.6 %, `product-rules`
172
+ 13.6 % — a 3.4× spread that one uniform window cannot serve. Extrapolated
173
+ linearly, the days each store needs to reach the 10 % threshold are 9, 22 and
174
+ 29. The shipped windows are **30 / 90 / 90**: the same ratio, rounded to
175
+ operational units, because cf02 also showed decay arrives in *batches* (two
176
+ upstream changes caused 11 of 22 stale entries), which makes a linear day count
177
+ the wrong shape for a deadline even though it is the right shape for a ratio.
178
+
179
+ ## Eviction ladder
180
+
181
+ `memory_eviction.ts` acts on two signals and no others:
182
+
183
+ | State | Trigger | Effect |
184
+ |---|---|---|
185
+ | `due` | past `last_validated + review_after_days` | surfaced, stays in the store |
186
+ | `quarantine` | `semantic_verdict: stale`, **or** past two windows unverified | moved to `agents/memory-quarantine/<type>.yml`, no longer injected, still readable |
187
+ | `delete` | three windows while in quarantine | removed |
188
+
189
+ Quarantine is a **move between tracked files**, never an in-place status flip:
190
+ an entry has to leave the injected store to stop being read as fact, and it has
191
+ to stay readable to be appealable. Re-verify an entry and it returns.
192
+
193
+ Dry-run by default; `--apply` is the only path that writes.
194
+
146
195
  ## Anti-patterns
147
196
 
148
197
  - **Do NOT** merge `ownership-map.yml` semantics into these files.
@@ -8,6 +8,23 @@ abstraction backed by `scripts/memory_lookup.ts` (TypeScript, run via
8
8
  tsx). It reads curated YAML under `agents/memory/<type>/` and the
9
9
  agent-written `agents/memory/intake/*.jsonl` signal log.
10
10
 
11
+ ## Index by the moment, not only by the topic
12
+
13
+ Every entry answers **"what was I about to do when this would have helped"** — a
14
+ verb and its object (`author a roadmap`, `wait on CI`, `push a branch`, `edit a
15
+ markdown section with a script`) — and the index carries a trigger-moment
16
+ section keyed on those verbs beside the topic grouping.
17
+
18
+ A store indexed only by subject is an index for *browsing*, and browsing is not
19
+ the failure mode: an agent does not go looking for a trap it does not know
20
+ exists. Measured 2026-08-20 on one instrumented session — of eleven error
21
+ classes, **nine already had an entry** and all nine were read *after* the
22
+ failure. The deficit was delivery, not knowledge.
23
+
24
+ Writing the trigger key is part of writing the entry. A second index maintained
25
+ separately from the entries rots, and a rotted index is worse than none because
26
+ it still looks authoritative.
27
+
11
28
  ## The contract
12
29
 
13
30
  Consumers reach it via the CLI (`agent-config memory:lookup`) or the
@@ -0,0 +1,96 @@
1
+ # Recurring-criticism mechanics
2
+
3
+ > Depth for the `recurring-criticism` rule — the past-disposition store list, the mechanism-is-the-defect classification, the hardening floor, and the failure-mode catalog.
4
+
5
+ _No YAML frontmatter, deliberately: every other guideline under `docs/guidelines/`
6
+ is frontmatter-less, and a `name:` key here makes the two MCP resource loaders
7
+ derive different URIs for the same file — one from the key
8
+ (`guideline://recurring-criticism-mechanics`), one from the path
9
+ (`guideline://agent-infra/recurring-criticism-mechanics`). That is a
10
+ `mcp_parity_smoke` drift, and it only surfaces once `dist/cli/agent-config.js`
11
+ is built, so the local suite passes and CI does not._
12
+
13
+ Depth for [`recurring-criticism`](../../../src/rules/recurring-criticism.md). The
14
+ rule carries the obligation; this carries the lookup addresses and the reasoning
15
+ that would otherwise be paid in every session — that rule is phrase-triggered, and
16
+ a phrase-triggered rule is unconditionally loaded on Claude (the emitter writes no
17
+ `paths:` when any non-path trigger is present), so every line in it is a line every
18
+ session pays for. This file is read on demand.
19
+
20
+ ## Look it up before re-deriving it
21
+
22
+ Without a mechanism that forces a reference to the earlier disposition, every
23
+ recurrence becomes a fresh investigation even where the answer already exists
24
+ <!-- harvest:forced-lookup-of-past-root-causes -->. The stores are fragmented and
25
+ only partly queryable, so **name which one you checked**:
26
+
27
+ | Store | Path | Queryable? |
28
+ |---|---|---|
29
+ | ADRs + index | `docs/decisions/` + `INDEX.md`, via `adr_cite_check <ADR-NNN>` | yes — status, `review_trigger` state, successors |
30
+ | Estate / activation / low-impact dispositions | `agents/decisions/*.yml`, `agents/decisions/low-impact-decisions.md` | yes, closed vocabularies |
31
+ | Roadmap dispositions | `agents/roadmaps/{archive,skipped,later}/` | `later/` only; `skipped/` carries its reason as header prose |
32
+ | Curated memory | `agents/memory/*.yml` | yes |
33
+ | Analysis documents | `agents/evidence/analysis/` | grep only |
34
+ | Harvest / borrow ledgers | `provenance/*.jsonl` | yes, but `adopt`/`adapt` only |
35
+
36
+ **Rejections are the weak spot, and by design.** `provenance/README.md` states that
37
+ a `reject` verdict lives in the analysis document rather than a ledger, because
38
+ nothing in the tree cites it. So "I found nothing" here means *unstructured prose
39
+ was grepped*, never *nothing was decided*. Say which of the two you mean — the
40
+ difference decides whether the recurrence is new information or a lookup failure.
41
+
42
+ ## The mechanism is the candidate defect, not the item
43
+
44
+ Classify what was missing before choosing an artefact — the taxonomy in
45
+ [`skill-improvement-pipeline`](../../../src/skills/skill-improvement-pipeline/SKILL.md)
46
+ § Classify the missing component (instruction · source-of-truth · tool · validator ·
47
+ permission · sandbox · evaluation · recovery-path) is the one to use, because "add
48
+ another rule" is the answer that feels right and is usually wrong.
49
+
50
+ Then land the learning where it **constrains** the next run, per
51
+ [`learning-to-rule-or-skill`](../../../src/skills/learning-to-rule-or-skill/SKILL.md).
52
+ A lesson that does not narrow the next attempt produces thrashing rather than
53
+ convergence <!-- harvest:unconstraining-lesson-thrashes -->; a learning that lives
54
+ only in a reply is not a learning, it is a note.
55
+
56
+ **Third recurrence of the same class escalates to structure** —
57
+ [`decision-review`](../../../src/skills/decision-review/SKILL.md) § Escalation owns
58
+ the threshold, and its point is worth restating: a louder restatement of a rule the
59
+ agent keeps missing is the one response already known not to work. At that point
60
+ the choice is a deterministic gate or deletion, not more prose.
61
+
62
+ ## The hardening floor
63
+
64
+ Self-improvement loops can regress the artefact they improve
65
+ <!-- harvest:self-improvement-can-self-regress -->. Two consequences:
66
+
67
+ - A hardening change carries the **same evidence bar** as any other change. "We
68
+ learned something" is not a licence, and a mechanism proposed in response to a
69
+ recurrence still needs a measured false-positive rate before it becomes CI.
70
+ - It never arrives as a **weakened** gate, a widened allowlist, a lifted Hard
71
+ Floor, or a loosened ratchet. If the only available hardening lowers a floor, the
72
+ recurrence escalates to the owner instead — that transition is owner-reserved per
73
+ [`decision-revisit-gate`](../../../src/rules/decision-revisit-gate.md) § Who
74
+ decides.
75
+
76
+ ## Failure modes
77
+
78
+ - **Resolving on the count.** "You have said it three times, so you are right" is
79
+ the sycophancy failure with a procedure attached. The count opens the question.
80
+ - **Resolving on the count, inverted.** "It is only the second time, so the old
81
+ call stands" — the repetition still shifted the burden of proof.
82
+ - **Naming no outcome.** A resolution that does not say which of the three applies
83
+ (decision wrong · never recorded · unreachable) has not resolved anything.
84
+ - **Grepping prose and reporting absence.** See the rejection note above.
85
+ - **Treating a resemblance as a recurrence.** Mechanism-match runs first; a new
86
+ complaint that tests a different mechanism is a new finding.
87
+ - **Hardening the item instead of the mechanism.** Fixing the one instance leaves
88
+ the surface that dismissed it intact, which is what produces the fourth
89
+ recurrence.
90
+ - **Writing the learning into the reply.** It has to land in an artefact.
91
+
92
+ ## See also
93
+
94
+ - [`recurring-criticism`](../../../src/rules/recurring-criticism.md) — the obligation.
95
+ - [`decision-revisit-gate`](../../../src/rules/decision-revisit-gate.md) — the other entrance (a lock blocking a change), the five steps, the owner-reserved table.
96
+ - [`self-repair-loop`](../../../src/rules/self-repair-loop.md) — the single-occurrence intake and the `occurrences` counter this rule consumes.
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@event4u/agent-config",
3
3
  "mcpName": "io.github.event4u-app/agent-config",
4
- "version": "14.5.0",
4
+ "version": "14.7.0",
5
5
  "description": "Governed skills, rules and commands for AI coding tools (Claude Code, Cursor, Windsurf, Copilot) — every claim machine-checked, including \"zero runtime daemon\".",
6
6
  "license": "MIT",
7
7
  "private": false,
@@ -0,0 +1,117 @@
1
+ /**
2
+ * Archival-sweep spawner for the roadmap dashboard.
3
+ *
4
+ * Split out of `update_roadmap_progress.ts` rather than authored there: that
5
+ * file sits at the 1500-line source ceiling `check_source_size_budget`
6
+ * ratchets, and the sweep plus its contract is the newest and most separable
7
+ * thing in it. The contract below is that text, moved intact.
8
+ *
9
+ * `--archive` (opt-in; wired into `task roadmap-progress` and
10
+ * `agent-config roadmap:progress`) runs the archival sweep before rendering
11
+ * instead of printing "Completed roadmaps not yet archived" and leaving the
12
+ * work to a human who has been ignoring the line for weeks. It is a flag rather
13
+ * than the default because the PostToolUse hook re-runs the WRITE path once per
14
+ * turn on every roadmap edit, and a hook that silently `git mv`s files mid-work
15
+ * is a bigger problem than the warning it would remove. `--check` never
16
+ * archives — see `run_archival_sweep`.
17
+ *
18
+ * WHY the warning existed at all, since this is the one place a reader of the
19
+ * flag will look: the sweep's own default is `--changed-only`, so a PR archives
20
+ * exactly the roadmaps it completed. A roadmap completed by a PR whose sweep did
21
+ * not run is then complete, on the trunk, and OUTSIDE every later branch's
22
+ * history — no `--changed-only` sweep finds it again. Measured 2026-08-20: six
23
+ * such roadmaps, with every regen reprinting the warning at whoever ran it.
24
+ * `/create-pr` § 1c keeps `--changed-only`; repo-wide reconciliation is this
25
+ * flag's job and nothing else's.
26
+ *
27
+ * This layout is deliberate rather than convenient: the prose homes for it are
28
+ * both at their ceilings (`roadmap-progress-mechanics.md` sits 122 chars under
29
+ * the 16,000-char depth ceiling, and `roadmap-management/SKILL.md` tips
30
+ * `skill_too_large` on any prose block), so the contract lives with the code it
31
+ * governs. Moving it out means making room first.
32
+ *
33
+ * AI council 2026-08-20 (anthropic + openai, blind peer review): both seats
34
+ * converged on explicit opt-in + `--all` scope + hook archival-free, and both
35
+ * independently required the `--check` exclusion, the archive-before-render
36
+ * order, and that a failed sweep must not render. RECORDED DISSENT: one seat
37
+ * argued for flipping the sweep's own default to `--all` instead. Rejected —
38
+ * that makes every PR a potential estate-wide cleanup, which is exactly what
39
+ * `--changed-only` exists to prevent.
40
+ */
41
+
42
+ import { spawnSync } from 'node:child_process';
43
+ import * as fs from 'node:fs';
44
+ import * as path from 'node:path';
45
+ import { fileURLToPath } from 'node:url';
46
+
47
+ // Same directory as `update_roadmap_progress.ts`, so the `path.dirname` below
48
+ // resolves the sweep script exactly as it did before the split.
49
+ const _HERE = fileURLToPath(import.meta.url);
50
+
51
+ function _isFile(p: string): boolean {
52
+ try {
53
+ return fs.statSync(p).isFile();
54
+ } catch {
55
+ return false;
56
+ }
57
+ }
58
+
59
+ /**
60
+ * Run the archival sweep for every complete roadmap, in-place.
61
+ *
62
+ * Spawned rather than imported: `archive_completed_roadmaps.ts` imports
63
+ * `collect` from `update_roadmap_progress.ts`, so a static import back would close a cycle, and
64
+ * `main()` is synchronous so a dynamic `await import()` is not available either.
65
+ * The sweep is the same twin `_regen_dashboard` already spawns in the other
66
+ * direction, so the spawn shape is the established one in this pair.
67
+ *
68
+ * No recursion: the sweep re-runs this script with NO flags, so its inner
69
+ * dashboard pass has archival off and terminates at depth 2.
70
+ *
71
+ * `--all`, not the sweep's `--changed-only` default. The default exists so a PR
72
+ * archives exactly the roadmaps it completed; here the caller asked the
73
+ * repo-wide dashboard to reconcile the estate, and the roadmaps that leak are
74
+ * by construction the ones NOT in this branch's history — six had accumulated
75
+ * on the trunk while the warning printed every regen. A roadmap the sweep
76
+ * refuses (open blockers) stays put and is still reported below.
77
+ */
78
+ export function run_archival_sweep(root: string): SweepResult {
79
+ const script = path.join(path.dirname(_HERE), 'archive_completed_roadmaps.ts');
80
+ if (!_isFile(script)) {
81
+ // A consumer install without the sweep script: nothing to run, and that
82
+ // is a normal state — the warning below still reports the roadmaps.
83
+ return { ran: false, ok: true, stdout: '', stderr: '' };
84
+ }
85
+ const argv = [script, '--all', '--repo-root', root];
86
+ const binName = process.platform === 'win32' ? 'tsx.cmd' : 'tsx';
87
+ let dir = path.dirname(_HERE);
88
+ for (;;) {
89
+ const candidate = path.join(dir, 'node_modules', '.bin', binName);
90
+ if (fs.existsSync(candidate)) {
91
+ return _sweepResult(spawnSync(candidate, argv, { cwd: root, encoding: 'utf-8' }));
92
+ }
93
+ const parent = path.dirname(dir);
94
+ if (parent === dir) {
95
+ break;
96
+ }
97
+ dir = parent;
98
+ }
99
+ return _sweepResult(spawnSync('npx', ['tsx', ...argv], { cwd: root, encoding: 'utf-8' }));
100
+ }
101
+
102
+ export interface SweepResult {
103
+ ran: boolean;
104
+ ok: boolean;
105
+ stdout: string;
106
+ stderr: string;
107
+ }
108
+
109
+ function _sweepResult(r: ReturnType<typeof spawnSync>): SweepResult {
110
+ return {
111
+ ran: true,
112
+ ok: r.status === 0,
113
+ stdout: String(r.stdout ?? ''),
114
+ stderr: String(r.stderr ?? ''),
115
+ };
116
+ }
117
+
@@ -31,6 +31,7 @@
31
31
  * ./scripts-run src/scripts/archive_completed_roadmaps # --changed-only (default)
32
32
  * ./scripts-run src/scripts/archive_completed_roadmaps --all
33
33
  * ./scripts-run src/scripts/archive_completed_roadmaps --base origin/main --dry-run
34
+ * ./scripts-run src/scripts/archive_completed_roadmaps --repo-root /path/to/proj
34
35
  *
35
36
  * --- Parity notes (ADR-200) ---
36
37
  *
@@ -462,19 +463,21 @@ function _runTwin(root: string, script: string): void {
462
463
  const _PROG = 'archive_completed_roadmaps.py';
463
464
 
464
465
  function _usage(): string {
465
- return `usage: ${_PROG} [-h] [--all] [--base BASE] [--dry-run]\n`;
466
+ return `usage: ${_PROG} [-h] [--all] [--base BASE] [--dry-run] [--repo-root REPO_ROOT]\n`;
466
467
  }
467
468
 
468
469
  interface Args {
469
470
  all: boolean;
470
471
  base: string;
471
472
  dry_run: boolean;
473
+ repo_root: string | null;
472
474
  }
473
475
 
474
476
  function _parseArgs(argv: readonly string[]): Args {
475
477
  let all = false;
476
478
  let base = 'origin/main';
477
479
  let dry_run = false;
480
+ let repo_root: string | null = null;
478
481
  const emitError = (msg: string): never => {
479
482
  process.stderr.write(_usage());
480
483
  process.stderr.write(`${_PROG}: error: ${msg}\n`);
@@ -502,17 +505,30 @@ function _parseArgs(argv: readonly string[]): Args {
502
505
  } else if (tok.startsWith('--base=')) {
503
506
  base = tok.slice('--base='.length);
504
507
  i += 1;
508
+ } else if (tok === '--repo-root') {
509
+ const val = argv[i + 1];
510
+ if (val === undefined) {
511
+ emitError('argument --repo-root: expected one argument');
512
+ }
513
+ repo_root = val as string;
514
+ i += 2;
515
+ } else if (tok.startsWith('--repo-root=')) {
516
+ repo_root = tok.slice('--repo-root='.length);
517
+ i += 1;
505
518
  } else {
506
519
  emitError(`unrecognized arguments: ${tok}`);
507
520
  }
508
521
  }
509
- return { all, base, dry_run };
522
+ return { all, base, dry_run, repo_root };
510
523
  }
511
524
 
512
525
  function main(argv?: readonly string[]): number {
513
526
  const ns = _parseArgs(argv ?? process.argv.slice(2));
514
527
 
515
- const root = _repo_root();
528
+ // An explicit `--repo-root` wins over the `git rev-parse` resolution. The
529
+ // dashboard generator passes it so a monorepo sub-project sweep cannot walk
530
+ // up to the enclosing repo and archive the PARENT's roadmaps.
531
+ const root = ns.repo_root ?? _repo_root();
516
532
  const archived = archive_completed(root, {
517
533
  changed_only: !ns.all,
518
534
  base: ns.base,