@event4u/agent-config 9.13.0 → 9.15.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 (280) hide show
  1. package/.claude-plugin/marketplace.json +1 -1
  2. package/CHANGELOG.md +113 -67
  3. package/README.md +9 -1
  4. package/dist/agent-src/commands/agents/audit.md +7 -7
  5. package/dist/agent-src/commands/agents/optimize.md +1 -1
  6. package/dist/agent-src/commands/analyze/reference-repo.md +1 -1
  7. package/dist/agent-src/commands/chat-history.md +1 -0
  8. package/dist/agent-src/commands/context.md +1 -0
  9. package/dist/agent-src/commands/council.md +1 -1
  10. package/dist/agent-src/commands/ghostwriter.md +1 -1
  11. package/dist/agent-src/commands/memory.md +2 -1
  12. package/dist/agent-src/commands/module.md +1 -0
  13. package/dist/agent-src/commands/optimize/agents-dir.md +1 -1
  14. package/dist/agent-src/commands/optimize/deep.md +150 -0
  15. package/dist/agent-src/commands/optimize/skills.md +5 -5
  16. package/dist/agent-src/commands/optimize.md +12 -6
  17. package/dist/agent-src/commands/override.md +1 -0
  18. package/dist/agent-src/commands/prediction-pool.md +4 -4
  19. package/dist/agent-src/commands/research/deep.md +1 -1
  20. package/dist/agent-src/commands/roadmap.md +2 -1
  21. package/dist/agent-src/commands/rule-compliance-audit.md +1 -1
  22. package/dist/agent-src/commands/tdd.md +1 -0
  23. package/dist/agent-src/commands/tests.md +1 -0
  24. package/dist/agent-src/commands/upstream-contribute.md +5 -5
  25. package/dist/agent-src/commands/video/from-script.md +1 -1
  26. package/dist/agent-src/commands/video/from-song.md +1 -1
  27. package/dist/agent-src/commands/video/scene.md +1 -1
  28. package/dist/agent-src/commands/video/stitch.md +1 -1
  29. package/dist/agent-src/commands/video/storyboard.md +1 -1
  30. package/dist/agent-src/commands/worktree/create.md +2 -1
  31. package/dist/agent-src/contexts/augment-infrastructure.md +1 -1
  32. package/dist/agent-src/contexts/contracts/artifact-engagement-flow.md +5 -5
  33. package/dist/agent-src/contexts/contracts/command-suggestion-flow.md +3 -3
  34. package/dist/agent-src/contexts/contracts/emergency-triage-block.md +2 -2
  35. package/dist/agent-src/contexts/execution/roadmap-process-loop.md +4 -3
  36. package/dist/agent-src/contexts/execution/subagent-routing.md +19 -0
  37. package/dist/agent-src/contexts/override-system.md +1 -1
  38. package/dist/agent-src/ghostwriter/fictional-fixture-v1.md +1 -1
  39. package/dist/agent-src/rules/augment-edit-discipline.md +1 -1
  40. package/dist/agent-src/rules/autonomous-execution.md +2 -1
  41. package/dist/agent-src/rules/brand-consistency.md +1 -0
  42. package/dist/agent-src/rules/brand-source-of-truth.md +1 -0
  43. package/dist/agent-src/rules/code-comment-discipline.md +2 -0
  44. package/dist/agent-src/rules/communication-through-line.md +1 -0
  45. package/dist/agent-src/rules/content-quoting-floor.md +1 -0
  46. package/dist/agent-src/rules/cross-source-consistency.md +0 -1
  47. package/dist/agent-src/rules/downstream-changes.md +1 -0
  48. package/dist/agent-src/rules/external-code-graph-interop.md +1 -0
  49. package/dist/agent-src/rules/external-reference-deep-dive.md +1 -0
  50. package/dist/agent-src/rules/fast-path-marker-visibility.md +1 -0
  51. package/dist/agent-src/rules/finance-safety-floor.md +0 -1
  52. package/dist/agent-src/rules/icon-consistency.md +1 -0
  53. package/dist/agent-src/rules/image-likeness-and-rights.md +1 -0
  54. package/dist/agent-src/rules/improve-before-implement.md +1 -1
  55. package/dist/agent-src/rules/invite-challenge.md +1 -0
  56. package/dist/agent-src/rules/lethal-trifecta-guard.md +1 -0
  57. package/dist/agent-src/rules/low-impact-corpus-privacy-floor.md +1 -0
  58. package/dist/agent-src/rules/markdown-safe-codeblocks.md +1 -0
  59. package/dist/agent-src/rules/media-governance-routing.md +4 -3
  60. package/dist/agent-src/rules/media-sync-ground-truth.md +1 -0
  61. package/dist/agent-src/rules/no-attribution-footers.md +1 -0
  62. package/dist/agent-src/rules/no-decorative-emojis-in-git-surfaces.md +1 -0
  63. package/dist/agent-src/rules/no-pr-progress-comments.md +1 -0
  64. package/dist/agent-src/rules/onboarding-gate.md +1 -0
  65. package/dist/agent-src/rules/output-discipline.md +1 -0
  66. package/dist/agent-src/rules/prefer-enums-over-literals.md +1 -0
  67. package/dist/agent-src/rules/preservation-guard.md +1 -0
  68. package/dist/agent-src/rules/question-not-instruction.md +1 -0
  69. package/dist/agent-src/rules/roadmap-ci-steps-policy.md +1 -0
  70. package/dist/agent-src/rules/role-mode-adherence.md +1 -0
  71. package/dist/agent-src/rules/runtime-safety.md +1 -0
  72. package/dist/agent-src/rules/security-sensitive-stop.md +1 -0
  73. package/dist/agent-src/rules/session-canary.md +9 -2
  74. package/dist/agent-src/rules/source-confidentiality.md +1 -0
  75. package/dist/agent-src/rules/source-of-truth.md +1 -0
  76. package/dist/agent-src/rules/spreadsheet-source-quality.md +1 -0
  77. package/dist/agent-src/rules/think-before-action.md +1 -0
  78. package/dist/agent-src/rules/token-budget-discipline.md +1 -0
  79. package/dist/agent-src/rules/token-efficiency.md +1 -0
  80. package/dist/agent-src/rules/token-optimizer-maintenance.md +5 -5
  81. package/dist/agent-src/rules/tool-safety.md +1 -0
  82. package/dist/agent-src/rules/untrusted-input-defense.md +2 -0
  83. package/dist/agent-src/rules/user-interaction.md +1 -0
  84. package/dist/agent-src/rules/user-interrupt-priority.md +1 -0
  85. package/dist/agent-src/skills/adr-create/SKILL.md +1 -1
  86. package/dist/agent-src/skills/check-refs/SKILL.md +1 -1
  87. package/dist/agent-src/skills/competitive-positioning/SKILL.md +1 -1
  88. package/dist/agent-src/skills/condense-memory/SKILL.md +1 -1
  89. package/dist/agent-src/skills/context-authoring/SKILL.md +1 -1
  90. package/dist/agent-src/skills/copilot-agents-optimization/SKILL.md +1 -1
  91. package/dist/agent-src/skills/description-assist/SKILL.md +1 -1
  92. package/dist/agent-src/skills/github-ci/SKILL.md +1 -0
  93. package/dist/agent-src/skills/guideline-writing/SKILL.md +1 -1
  94. package/dist/agent-src/skills/lint-skills/SKILL.md +1 -1
  95. package/dist/agent-src/skills/readme-reviewer/SKILL.md +1 -1
  96. package/dist/agent-src/skills/roadmap-management/SKILL.md +8 -1
  97. package/dist/agent-src/skills/roadmap-writing/SKILL.md +1 -1
  98. package/dist/agent-src/skills/skill-improvement-pipeline/SKILL.md +1 -1
  99. package/dist/agent-src/skills/skill-writing/SKILL.md +4 -4
  100. package/dist/agent-src/skills/token-optimizer/SKILL.md +4 -4
  101. package/dist/agent-src/skills/upstream-contribute/SKILL.md +6 -6
  102. package/dist/agent-src/skills/using-git-worktrees/SKILL.md +25 -0
  103. package/dist/agent-src/templates/AGENTS.md +1 -1
  104. package/dist/agent-src/templates/agents/agent-project-settings.example.yml +1 -1
  105. package/dist/agent-src/templates/command.md +1 -1
  106. package/dist/agent-src/templates/copilot-instructions.md +3 -3
  107. package/dist/agent-src/templates/rule.md +2 -2
  108. package/dist/agent-src/templates/scripts/work_engine/orchestration.ts +1 -1
  109. package/dist/agent-src/templates/skill-archive-note.md +5 -5
  110. package/dist/agent-src/templates/skill.md +1 -1
  111. package/dist/cli/agent-config.js +66 -19
  112. package/dist/cli/agent-config.js.map +1 -1
  113. package/dist/cli/main.js +9 -4
  114. package/dist/cli/main.js.map +1 -1
  115. package/dist/cli/python/workspace_drive.js +2 -0
  116. package/dist/cli/python/workspace_drive.js.map +1 -1
  117. package/dist/cli/python/workspace_drive_health.js +2 -0
  118. package/dist/cli/python/workspace_drive_health.js.map +1 -1
  119. package/dist/cli/python/workspace_hosts.js +2 -0
  120. package/dist/cli/python/workspace_hosts.js.map +1 -1
  121. package/dist/cli/python/workspace_sessions.js +2 -0
  122. package/dist/cli/python/workspace_sessions.js.map +1 -1
  123. package/dist/cli/registry.js +1 -0
  124. package/dist/cli/registry.js.map +1 -1
  125. package/dist/cli-delegate/{chunk-A3HJ6NTI.js → chunk-63WSP6YZ.js} +2 -1
  126. package/dist/cli-delegate/{chunk-EJYIGZ3T.js → chunk-BKO2AZ7Z.js} +1 -1
  127. package/dist/cli-delegate/{chunk-QFKQLQ7X.js → chunk-H574KOUH.js} +340 -462
  128. package/dist/cli-delegate/chunk-NXFWFAYV.js +339 -0
  129. package/dist/cli-delegate/{chunk-TEGJU2JX.js → chunk-ZXXJLL5K.js} +2 -2
  130. package/dist/cli-delegate/cmd_conformance.js +29 -23
  131. package/dist/cli-delegate/cmd_doctor.js +3 -3
  132. package/dist/cli-delegate/cmd_export.js +4 -4
  133. package/dist/cli-delegate/cmd_preflight.js +2 -2
  134. package/dist/cli-delegate/cmd_prune.js +4 -4
  135. package/dist/cli-delegate/cmd_settings_migrate.js +4 -4
  136. package/dist/cli-delegate/cmd_sync.js +4 -4
  137. package/dist/cli-delegate/cmd_uninstall.js +4 -4
  138. package/dist/cli-delegate/cmd_validate.js +4 -4
  139. package/dist/discovery/deprecation-report.md +1 -1
  140. package/dist/discovery/discovery-manifest.json +163 -103
  141. package/dist/discovery/discovery-manifest.json.sha256 +1 -1
  142. package/dist/discovery/discovery-manifest.summary.md +3 -3
  143. package/dist/discovery/orphan-report.md +1 -1
  144. package/dist/discovery/packs.json +6 -5
  145. package/dist/discovery/trust-report.md +3 -3
  146. package/dist/discovery/workspaces.json +5 -4
  147. package/dist/hooks/dispatch.js +729 -430
  148. package/dist/install/install.mjs +700 -625
  149. package/dist/install/rule_scope.js +18 -2
  150. package/dist/install/rule_scope.js.map +1 -1
  151. package/dist/mcp/registry-manifest.json +3 -3
  152. package/dist/mcp/server.json +2 -2
  153. package/dist/mcp/server.mjs +564 -424
  154. package/dist/router.json +1 -1
  155. package/dist/scripts/_lib/claude_settings_hooks.js +30 -5
  156. package/dist/scripts/_lib/claude_settings_hooks.js.map +1 -1
  157. package/dist/scripts/_lib/scoped_projection.js +223 -0
  158. package/dist/scripts/_lib/scoped_projection.js.map +1 -0
  159. package/dist/scripts/_lib/surface_tiers.js +125 -0
  160. package/dist/scripts/_lib/surface_tiers.js.map +1 -0
  161. package/dist/scripts/_lib/token_count.js +166 -0
  162. package/dist/scripts/_lib/token_count.js.map +1 -0
  163. package/dist/scripts/_lib/trigger_eval_floors.js +8 -0
  164. package/dist/scripts/_lib/trigger_eval_floors.js.map +1 -1
  165. package/dist/scripts/condense.js +139 -9
  166. package/dist/scripts/condense.js.map +1 -1
  167. package/dist/scripts/project_thin_rules.js +450 -0
  168. package/dist/scripts/project_thin_rules.js.map +1 -0
  169. package/dist/server/routes/workspace.js +2 -0
  170. package/dist/server/routes/workspace.js.map +1 -1
  171. package/dist/server/schemas/settings.js +9 -3
  172. package/dist/server/schemas/settings.js.map +1 -1
  173. package/dist/ui/assets/index-DJY_vQVn.js +40 -0
  174. package/dist/ui/assets/index-DJY_vQVn.js.map +1 -0
  175. package/dist/ui/index.html +1 -1
  176. package/docs/guidelines/agent-infra/roadmap-progress-mechanics.md +1 -1
  177. package/package.json +11 -11
  178. package/src/agent-src/templates/AGENTS.md +1 -1
  179. package/src/agent-src/templates/scripts/work_engine/orchestration.ts +1 -1
  180. package/src/config/agent-settings.template.yml +59 -11
  181. package/src/config/ci-local-parity.yml +8 -0
  182. package/src/config/discovery/unassigned-artefacts.yml +23 -25
  183. package/src/config/evaluator-budgets.json +35 -5
  184. package/src/config/gate-coverage.yml +147 -0
  185. package/src/config/gate-violation-baselines.json +25 -0
  186. package/src/install/rule_scope.ts +27 -2
  187. package/src/scripts/_cli/cmd_conformance.ts +13 -24
  188. package/src/scripts/_dispatch.bash +10 -0
  189. package/src/scripts/_lib/claude_settings_hooks.ts +30 -4
  190. package/src/scripts/_lib/exec_evidence.ts +5 -0
  191. package/src/scripts/_lib/gate_baseline.ts +213 -0
  192. package/src/scripts/_lib/scoped_projection.ts +262 -0
  193. package/src/scripts/_lib/tier_budget_routing.ts +234 -0
  194. package/src/scripts/_lib/tool_adapter_registry.ts +8 -1
  195. package/src/scripts/_lib/trigger_eval_floors.ts +9 -0
  196. package/src/scripts/_lib/trigger_routers.ts +17 -5
  197. package/src/scripts/adr/regenerate_index.ts +4 -3
  198. package/src/scripts/ai-video/lib/parse-blueprint.sh +1 -1
  199. package/src/scripts/ai_council/compile_corpus.ts +1 -1
  200. package/src/scripts/audit_cloud_compatibility.ts +37 -2
  201. package/src/scripts/audit_initial_context.ts +53 -19
  202. package/src/scripts/audit_likelihood.ts +31 -2
  203. package/src/scripts/audit_user_type_axis.ts +58 -11
  204. package/src/scripts/bench_hook_latency.ts +172 -41
  205. package/src/scripts/build_mcp_catalog.ts +12 -1
  206. package/src/scripts/check_always_budget.ts +122 -11
  207. package/src/scripts/check_artefact_count_messaging.ts +128 -15
  208. package/src/scripts/check_augment_description_cap.ts +24 -3
  209. package/src/scripts/check_ci_strict_superset.ts +150 -0
  210. package/src/scripts/check_cluster_patterns.ts +100 -0
  211. package/src/scripts/check_consumer_scope_flip.ts +26 -4
  212. package/src/scripts/check_evaluator_budgets.ts +198 -19
  213. package/src/scripts/check_gate_coverage.ts +337 -1
  214. package/src/scripts/check_generator_output_coverage.ts +2 -1
  215. package/src/scripts/check_iron_law_prominence.ts +1 -1
  216. package/src/scripts/check_kernel_rule_bundle.ts +1 -1
  217. package/src/scripts/check_no_new_legacy_path.ts +167 -3
  218. package/src/scripts/check_pack_size.ts +18 -4
  219. package/src/scripts/check_portability.ts +37 -7
  220. package/src/scripts/check_references.ts +19 -3
  221. package/src/scripts/check_release_pr_shape.ts +13 -0
  222. package/src/scripts/check_token_regression.ts +9 -2
  223. package/src/scripts/condense.ts +155 -12
  224. package/src/scripts/cost/budget.mjs +63 -2
  225. package/src/scripts/count_scoped_projection.ts +104 -0
  226. package/src/scripts/evaluator_umbrella.sh +34 -1
  227. package/src/scripts/generate_capability_matrix.ts +8 -0
  228. package/src/scripts/generate_router_coverage_from_matrix.ts +155 -0
  229. package/src/scripts/hook_manifest.yaml +17 -3
  230. package/src/scripts/hooks/block_config_weakening.ts +337 -0
  231. package/src/scripts/hooks/concern_registry.ts +2 -0
  232. package/src/scripts/hooks/probe_throttle.ts +75 -0
  233. package/src/scripts/install-hooks.sh +24 -2
  234. package/src/scripts/install.ts +15 -92
  235. package/src/scripts/lint_agents_md.ts +9 -3
  236. package/src/scripts/lint_archived_skills.ts +1 -1
  237. package/src/scripts/lint_artefact_frontmatter.ts +185 -37
  238. package/src/scripts/lint_command_routing.ts +21 -52
  239. package/src/scripts/lint_command_verbs.ts +47 -28
  240. package/src/scripts/lint_context_spine_usage.ts +38 -12
  241. package/src/scripts/lint_framework_leakage.ts +25 -6
  242. package/src/scripts/lint_handoffs.ts +49 -2
  243. package/src/scripts/lint_media_policy_linkage.ts +62 -30
  244. package/src/scripts/lint_namespace.ts +92 -7
  245. package/src/scripts/lint_new_skill_gate.ts +39 -31
  246. package/src/scripts/lint_originality_shingles.ts +7 -1
  247. package/src/scripts/lint_override_kernel_guard.ts +21 -3
  248. package/src/scripts/lint_pack_boundaries.ts +461 -91
  249. package/src/scripts/lint_pack_dependencies.ts +24 -57
  250. package/src/scripts/lint_persona_governance.ts +1 -1
  251. package/src/scripts/lint_role_experiences.ts +34 -5
  252. package/src/scripts/lint_trigger_precision.ts +142 -0
  253. package/src/scripts/mcp_server/consumer_tool_catalog.json +12 -201
  254. package/src/scripts/mcp_server/tools.ts +1 -1
  255. package/src/scripts/prepack-check.mjs +40 -1
  256. package/src/scripts/prepack_router_targets.d.mts +7 -0
  257. package/src/scripts/prepack_router_targets.mjs +93 -0
  258. package/src/scripts/print_required_checks.ts +72 -18
  259. package/src/scripts/profile_staleness_hook.ts +12 -0
  260. package/src/scripts/record_evaluator_measurements.mjs +105 -0
  261. package/src/scripts/recruit_preflight.sh +1 -1
  262. package/src/scripts/release.ts +105 -1
  263. package/src/scripts/router_target_paths.d.mts +4 -0
  264. package/src/scripts/router_target_paths.mjs +69 -0
  265. package/src/scripts/router_telemetry.ts +52 -1
  266. package/src/scripts/routing_doctor.ts +485 -0
  267. package/src/scripts/rule_trigger_eval.ts +403 -0
  268. package/src/scripts/schemas/rule.schema.json +5 -1
  269. package/src/scripts/session_canary_hook.ts +96 -5
  270. package/src/scripts/skill_linter.ts +90 -42
  271. package/src/scripts/smoke/skills.sh +1 -1
  272. package/src/scripts/sweep_dead_scan_roots.ts +356 -10
  273. package/src/scripts/trigger_coverage.ts +13 -2
  274. package/src/scripts/update_counts.ts +91 -12
  275. package/src/scripts/validate_telegraph_carveouts.ts +1 -1
  276. package/src/scripts/wrapper_freshness_hook.ts +14 -0
  277. package/src/server/schemas/settings.ts +19 -5
  278. package/dist/cli-delegate/chunk-TJIAM5FW.js +0 -133
  279. package/dist/ui/assets/index-BpSQt5vm.js +0 -40
  280. package/dist/ui/assets/index-BpSQt5vm.js.map +0 -1
@@ -5,7 +5,7 @@
5
5
  *
6
6
  * Ported from the retired Python `src/scripts/check_iron_law_prominence.py` (ADR-200,
7
7
  * Phase 4 / Wave 4c). The CLI contract is pinned — positional
8
- * paths (default `.agent-src.uncondensed/rules`), `--format` / `--quiet`
8
+ * paths (default `src/rules`), `--format` / `--quiet`
9
9
  * flags, exit codes (0 clean, 1 violations, 3 internal error),
10
10
  * stdout/stderr split, byte-identical finding messages, and the same
11
11
  * heading parse / code-fence skipping. No behaviour changes — latent bugs
@@ -11,7 +11,7 @@
11
11
  * historical quirks preserved (consumers pin the exact behaviour).
12
12
  *
13
13
  * Fails when a single PR (or commit range) modifies more than one
14
- * kernel rule under `.agent-src.uncondensed/rules/`. Override via the
14
+ * kernel rule under `src/rules/`. Override via the
15
15
  * PR label `bundled-always-rules-acknowledged`.
16
16
  *
17
17
  * Kernel set is the locked 9-rule list in
@@ -45,12 +45,20 @@ import * as fs from 'node:fs';
45
45
  import * as path from 'node:path';
46
46
  import { fileURLToPath, pathToFileURL } from 'node:url';
47
47
 
48
+ import { checkRatchet } from './_lib/gate_baseline.js';
49
+
48
50
  const LEGACY = '.agent-src.uncondensed/';
49
51
  const EXEMPT: ReadonlySet<string> = new Set([
50
52
  'src/scripts/_lib/agent_src.py',
51
53
  'src/scripts/check_references.py',
52
54
  'src/scripts/check_condensed_paths.py',
53
55
  'src/scripts/check_no_new_legacy_path.py', // this file documents the literal
56
+ // The `.ts` twin needs its own entry now: the docstring above says the
57
+ // faithful-twin rule covers it, but that rule reads a `.py` sibling from
58
+ // disk and the py2ts final deletion removed every sibling — so since then
59
+ // ANY edit to this guard's own message strings flags the guard. Surfaced
60
+ // by the Phase-5 edit that added the existing-literal pass below.
61
+ 'src/scripts/check_no_new_legacy_path.ts',
54
62
  'src/scripts/check_source_pointer_freshness.ts', // forbidden-substring detector for the legacy tree
55
63
  ]);
56
64
 
@@ -131,6 +139,154 @@ function find_offenders(diffText: string, twinCheck: TwinCheck = _is_faithful_tw
131
139
  return offenders;
132
140
  }
133
141
 
142
+ // ---------------------------------------------------------------------------
143
+ // Pass 2 — EXISTING hardcoded legacy scan roots (ratcheted).
144
+ //
145
+ // The diff pass above stops the debt from growing. It is structurally blind to
146
+ // the debt that is already there — and every one of the 14 dead gates found in
147
+ // 2026-07 was pre-existing, so a new-violations-only check could never have
148
+ // seen them (road-to-gates-that-can-fail Phase 5).
149
+ //
150
+ // WHY THIS IS NOT THE FULL-TREE LINT THAT WAS ALREADY REJECTED. The note in
151
+ // `find_offenders` records a measured rejection: a full-tree lint over `tests/`
152
+ // hits 44 files / 213 lines, most of them legitimate (the legacy detectors'
153
+ // own test data, `validator_ignore` substrings, synthetic tmpdir fixtures), so
154
+ // the signal drowns. That measurement stands and this pass does not repeat it.
155
+ // Three things make this scope different:
156
+ //
157
+ // 1. It reads EXECUTABLE code only — `src/scripts/**/*.{ts,mts,mjs}`. No
158
+ // prose, no docs, no tests, no fixtures.
159
+ // 2. It counts only lines that CONSTRUCT A PATH — the literal must reach
160
+ // `path.join(...)` inside a string. A detector holding the literal as
161
+ // data to match, strip, or print is not a scan root and is not counted.
162
+ // Measured on 2026-08-02: 236 raw mentions in src/scripts → 147 string
163
+ // literals → 70 path-constructing lines. The narrowing is the point.
164
+ // 3. It is a RATCHET, not a hard fail. The current count is committed to
165
+ // `src/config/gate-violation-baselines.json`; the gate goes red only when
166
+ // the count RISES. Every Phase-1 repair lowers it, and the baseline's
167
+ // 56-day expiry (see `_lib/gate_baseline.ts`) stops a stalled number from
168
+ // hardening into configuration.
169
+ // ---------------------------------------------------------------------------
170
+
171
+ /** Gate key in `src/config/gate-violation-baselines.json`. */
172
+ export const HARDCODED_ROOT_GATE = 'check_no_new_legacy_path:hardcoded-scan-roots';
173
+
174
+ /** The executable-code root this pass reads. */
175
+ export const HARDCODED_ROOT_SCAN_DIR = 'src/scripts';
176
+
177
+ /** Bare directory name — the form that appears inside a `path.join(...)` call. */
178
+ const LEGACY_DIRNAME = LEGACY.replace(/\/+$/, '');
179
+
180
+ /**
181
+ * Files allowed to construct a legacy path forever.
182
+ *
183
+ * `_lib/agent_src.ts` is the shared resolver — owning the constant is its whole
184
+ * job, and every gate that routes through it survived the ADR-051 move. Exempting
185
+ * it is what makes the count mean "gates that bypassed the resolver".
186
+ */
187
+ const HARDCODED_ROOT_EXEMPT: ReadonlySet<string> = new Set(['src/scripts/_lib/agent_src.ts']);
188
+
189
+ const _STRING_LITERAL_LEGACY = new RegExp(
190
+ `['"\`][^'"\`]*${LEGACY_DIRNAME.replace(/\./g, '\\.')}`,
191
+ );
192
+
193
+ function _isCommentLine(trimmed: string): boolean {
194
+ return (
195
+ trimmed.startsWith('//') ||
196
+ trimmed.startsWith('*') ||
197
+ trimmed.startsWith('/*') ||
198
+ trimmed.startsWith('#')
199
+ );
200
+ }
201
+
202
+ function* _walkScripts(dir: string): Generator<string> {
203
+ let entries: fs.Dirent[];
204
+ try {
205
+ entries = fs.readdirSync(dir, { withFileTypes: true });
206
+ } catch {
207
+ return;
208
+ }
209
+ for (const e of entries) {
210
+ const full = path.join(dir, e.name);
211
+ if (e.isDirectory()) {
212
+ yield* _walkScripts(full);
213
+ } else if (/\.(ts|mts|mjs)$/.test(e.name) && !/\.d\.m?ts$/.test(e.name)) {
214
+ yield full;
215
+ }
216
+ }
217
+ }
218
+
219
+ /**
220
+ * Lines under `src/scripts/` that build a filesystem path against the retired
221
+ * tree. Returns `file:line: <source>` strings, sorted by path.
222
+ *
223
+ * `repoRoot` defaults to cwd (CI runs the guard at the repo root) and is
224
+ * injectable so tests can point at a fixture tree.
225
+ */
226
+ export function find_hardcoded_scan_roots(
227
+ repoRoot: string = process.cwd(),
228
+ twinCheck: TwinCheck = _is_faithful_twin,
229
+ ): string[] {
230
+ const root = path.join(repoRoot, HARDCODED_ROOT_SCAN_DIR);
231
+ const findings: string[] = [];
232
+ for (const abs of _walkScripts(root)) {
233
+ const rel = path.relative(repoRoot, abs).split(path.sep).join('/');
234
+ if (EXEMPT.has(rel) || HARDCODED_ROOT_EXEMPT.has(rel) || twinCheck(rel)) {
235
+ continue;
236
+ }
237
+ let text: string;
238
+ try {
239
+ text = fs.readFileSync(abs, 'utf-8');
240
+ } catch {
241
+ continue;
242
+ }
243
+ if (!text.includes(LEGACY_DIRNAME)) {
244
+ continue;
245
+ }
246
+ text.split('\n').forEach((line, i) => {
247
+ if (!line.includes(LEGACY_DIRNAME)) return;
248
+ const trimmed = line.trim();
249
+ if (_isCommentLine(trimmed)) return;
250
+ if (!/path\.join\s*\(/.test(line)) return;
251
+ if (!_STRING_LITERAL_LEGACY.test(line)) return;
252
+ findings.push(`${rel}:${i + 1}: ${trimmed.slice(0, 100)}`);
253
+ });
254
+ }
255
+ findings.sort();
256
+ return findings;
257
+ }
258
+
259
+ /**
260
+ * Run the existing-literal pass and judge it against the committed baseline.
261
+ * Returns 0 when the count is at or below the baseline (and the baseline is
262
+ * fresh), 1 otherwise. Prints either way — a passing ratchet still reports the
263
+ * live number, which is the whole point of committing it.
264
+ */
265
+ export function checkHardcodedScanRoots(repoRoot: string = process.cwd()): number {
266
+ const findings = find_hardcoded_scan_roots(repoRoot);
267
+ const verdict = checkRatchet({
268
+ gate: HARDCODED_ROOT_GATE,
269
+ actual: findings.length,
270
+ repoRoot,
271
+ });
272
+ if (verdict.ok) {
273
+ process.stdout.write(`✅ ${verdict.message}\n`);
274
+ return 0;
275
+ }
276
+ process.stdout.write(
277
+ `❌ Hardcoded \`${LEGACY}\` scan root(s) under ${HARDCODED_ROOT_SCAN_DIR}/ ` +
278
+ 'above the recorded baseline:\n',
279
+ );
280
+ for (const f of findings.slice(0, 20)) {
281
+ process.stdout.write(` 🔴 ${f}\n`);
282
+ }
283
+ if (findings.length > 20) {
284
+ process.stdout.write(` … and ${findings.length - 20} more\n`);
285
+ }
286
+ process.stdout.write(`\n${verdict.message}\n`);
287
+ return 1;
288
+ }
289
+
134
290
  function main(): number {
135
291
  // --stdin: read a unified diff from stdin (CI pipes `gh pr diff` — auth-safe,
136
292
  // no `git fetch <base>` extraheader race on shallow PR-merge checkouts, the
@@ -170,6 +326,7 @@ function main(): number {
170
326
  offenders = find_offenders((proc.stdout as string | null) ?? '');
171
327
  }
172
328
 
329
+ let rc = 0;
173
330
  if (offenders.length) {
174
331
  process.stdout.write(
175
332
  '❌ New `.agent-src.uncondensed/` reference(s) added under src/ ' +
@@ -182,11 +339,18 @@ function main(): number {
182
339
  '\nFix: reference the real `src/` target. Existing stale prose is ' +
183
340
  'migrated opportunistically; do not ADD new dead-path references.\n',
184
341
  );
185
- return 1;
342
+ rc = 1;
343
+ } else {
344
+ process.stdout.write('✅ No new `.agent-src.uncondensed/` references added under src/.\n');
186
345
  }
187
346
 
188
- process.stdout.write('✅ No new `.agent-src.uncondensed/` references added under src/.\n');
189
- return 0;
347
+ // Pass 2 — the pre-existing hardcoded scan roots the diff pass cannot see.
348
+ // Skippable for the golden-parity harness, which compares this guard's
349
+ // diff behaviour against a pinned reference implementation.
350
+ if (!process.argv.includes('--no-existing')) {
351
+ rc = Math.max(rc, checkHardcodedScanRoots());
352
+ }
353
+ return rc;
190
354
  }
191
355
 
192
356
  const _HERE = fileURLToPath(import.meta.url);
@@ -55,12 +55,26 @@ export interface PackSizeBudget {
55
55
  /**
56
56
  * Parse `npm pack --json` stdout. npm runs the `prepare` lifecycle script even
57
57
  * under `--ignore-scripts` on some versions, and this repo's `prepare` prints a
58
- * banner — straight into the stream we parse. Slice from the first `[` so a
59
- * lifecycle banner is tolerated instead of becoming a SyntaxError.
58
+ * banner — straight into the stream we parse. Slice from a `[` so a lifecycle
59
+ * banner is tolerated instead of becoming a SyntaxError.
60
+ *
61
+ * Not the FIRST `[`: npm echoes the lifecycle command line, and this repo's own
62
+ * `prepare` is `[ -d .git ] && bash src/scripts/install-hooks.sh || true` — its
63
+ * `[` precedes the payload's. Try each candidate offset in order and keep the
64
+ * first that actually parses (road-to-gates-that-can-fail Phase 6.2).
60
65
  */
61
66
  export function parsePackJson(stdout: string): PackResult {
62
- const start = stdout.indexOf('[');
63
- const parsed = JSON.parse(start >= 0 ? stdout.slice(start) : stdout) as PackResult[];
67
+ let parsed: PackResult[] | null = null;
68
+ for (let i = stdout.indexOf('['); i >= 0; i = stdout.indexOf('[', i + 1)) {
69
+ try {
70
+ parsed = JSON.parse(stdout.slice(i)) as PackResult[];
71
+ break;
72
+ } catch {
73
+ // Not the payload — a banner bracket. Keep scanning.
74
+ }
75
+ }
76
+ // No candidate parsed: reproduce the original SyntaxError from the raw text.
77
+ parsed ??= JSON.parse(stdout) as PackResult[];
64
78
  const first = parsed[0];
65
79
  if (first === undefined) throw new Error('npm pack --json returned an empty array');
66
80
  return first;
@@ -8,7 +8,7 @@
8
8
  * same finding text, same scan scope and file-walk order. No behaviour
9
9
  * changes; latent bugs are replicated and flagged as divergence candidates.
10
10
  *
11
- * Scans dist/agent-src/ and .agent-src.uncondensed/ for project-specific
11
+ * Scans src/ and dist/agent-src/ for project-specific
12
12
  * references that violate package portability (the package must work in ANY
13
13
  * project).
14
14
  *
@@ -271,10 +271,25 @@ const ALLOWLIST: string[] = [
271
271
  'package repository', // "package repository" concept
272
272
  'src/scripts/mcp_server/', // MCP server module path (road-to-mcp-server.md Phase 1)
273
273
  String.raw`scripts\.mcp_server`, // MCP server Python module entrypoint
274
+ // ── Revealed 2026-08-02 when `src/` entered SCAN_DIRS (dead-root repair,
275
+ // road-to-renewal-foundation Phase 1). Both live under `src/templates/`,
276
+ // which is never projected into `dist/agent-src/`, so this gate had never
277
+ // seen them. Neither is a CONSUMER-project leak — they are the package's
278
+ // own published identifiers, which a consumer must type verbatim:
279
+ String.raw`plugin install agent-conf@`, // real marketplace install command
280
+ String.raw`\.event4u-bridge\.yml`, // real shipped anchor filename (src/scripts/install.ts, lint_agents_layout.ts)
274
281
  ];
275
282
 
276
- // Directories to scan (only package files, not project-specific agents/)
277
- const SCAN_DIRS = ['dist/agent-src', '.agent-src.uncondensed'];
283
+ // Directories to scan (only package files, not project-specific agents/).
284
+ //
285
+ // DEAD-ROOT REPAIR (road-to-renewal-foundation Phase 1): the second entry was
286
+ // `.agent-src.uncondensed`, deleted by ADR-051. The loops below `continue` on a
287
+ // missing directory, so half this gate's declared corpus — the whole authoring
288
+ // tree — was silently skipped. A project identifier authored in `src/` was only
289
+ // ever caught once a condense run projected it into `dist/agent-src/`, i.e. one
290
+ // step later than the gate claims to catch it. `src/` is the source of truth
291
+ // now and is scanned directly.
292
+ const SCAN_DIRS = ['src', 'dist/agent-src'];
278
293
 
279
294
  // Additional root-level files shipped by the package that must also stay
280
295
  // portable. These are read by agents working on the package itself and —
@@ -608,11 +623,20 @@ function check_cli_invocations(filepath: string): Violation[] {
608
623
  return violations;
609
624
  }
610
625
 
611
- function scan_all(root: string): { violations: Violation[]; detected: string[] } {
626
+ function scan_all(root: string): {
627
+ violations: Violation[];
628
+ detected: string[];
629
+ scanned: number;
630
+ } {
612
631
  const { patterns, detected } = _compile_patterns(root);
613
632
  const forbidden = _compile_forbidden_patterns();
614
633
  const allowlist = _compile_allowlist();
615
634
  const violations: Violation[] = [];
635
+ // Distinct files actually read, for the gate-coverage contract
636
+ // (src/config/gate-coverage.yml): a gate that inspected nothing has not
637
+ // passed. Counted as a set because the layer-3/4 passes revisit files the
638
+ // layer-1 pass already read.
639
+ const scannedFiles = new Set<string>();
616
640
 
617
641
  // Layer 1 + 2: full package content
618
642
  for (const scanDir of SCAN_DIRS) {
@@ -621,6 +645,7 @@ function scan_all(root: string): { violations: Violation[]; detected: string[] }
621
645
  continue;
622
646
  }
623
647
  for (const f of _rglobMdSorted(d)) {
648
+ scannedFiles.add(f);
624
649
  violations.push(...check_file(f, [...patterns, ...forbidden], allowlist));
625
650
  }
626
651
  }
@@ -629,6 +654,7 @@ function scan_all(root: string): { violations: Violation[]; detected: string[] }
629
654
  for (const rel of SCAN_ROOT_FILES) {
630
655
  const f = path.join(root, rel);
631
656
  if (_isFile(f)) {
657
+ scannedFiles.add(f);
632
658
  violations.push(...check_file(f, forbidden, allowlist));
633
659
  }
634
660
  }
@@ -664,7 +690,7 @@ function scan_all(root: string): { violations: Violation[]; detected: string[] }
664
690
  }
665
691
  }
666
692
 
667
- return { violations, detected };
693
+ return { violations, detected, scanned: scannedFiles.size };
668
694
  }
669
695
 
670
696
  function format_text(violations: Violation[], detected: string[]): string {
@@ -816,7 +842,7 @@ function parseArgs(argv: readonly string[]): ParsedArgs {
816
842
  function main(): number {
817
843
  const args = parseArgs(process.argv.slice(2));
818
844
 
819
- let result: { violations: Violation[]; detected: string[] };
845
+ let result: { violations: Violation[]; detected: string[]; scanned: number };
820
846
  try {
821
847
  result = scan_all(args.root);
822
848
  } catch (e) {
@@ -825,7 +851,11 @@ function main(): number {
825
851
  return 3;
826
852
  }
827
853
 
828
- const { violations, detected } = result;
854
+ const { violations, detected, scanned } = result;
855
+ // gate-coverage contract (src/config/gate-coverage.yml): one machine-readable
856
+ // count on stderr so `check_gate_coverage` can assert this gate read a real
857
+ // corpus. It scanned a deleted root for months and still exited 0.
858
+ process.stderr.write(`scanned: ${String(scanned)}\n`);
829
859
  if (args.format === 'json') {
830
860
  const payload = { detected, violations };
831
861
  process.stdout.write(`${JSON.stringify(payload, null, 2)}\n`);
@@ -452,9 +452,12 @@ function _extract_personas_frontmatter(text: string): Array<[number, string]> {
452
452
 
453
453
  function _find_suggestion(p: string, root: string): string {
454
454
  const name = path.basename(p);
455
+ // DEAD-ROOT REPAIR (road-to-renewal-foundation Phase 1): the middle entry
456
+ // was `.agent-src.uncondensed`, deleted by ADR-051. `src/` is the source of
457
+ // truth, so a file that exists only there produced no suggestion at all.
455
458
  for (const d of [
456
459
  path.join(root, 'dist/agent-src'),
457
- path.join(root, '.agent-src.uncondensed'),
460
+ path.join(root, 'src'),
458
461
  path.join(root, 'agents'),
459
462
  ]) {
460
463
  if (_exists(d)) {
@@ -586,10 +589,15 @@ function check_file(filepath: string, artifacts: Artifacts, root: string): Broke
586
589
  } else {
587
590
  // Strip leading ./ and try with prefixes
588
591
  const ref = rawRef.replace(/^[./]+/, '');
592
+ // DEAD-ROOT REPAIR: `.agent-src.uncondensed` (ADR-051) never
593
+ // resolved, so a reference that only exists under the source of
594
+ // truth was reported BROKEN. `src/` and its category roots
595
+ // replace it.
589
596
  for (const prefix of [
590
597
  root,
591
598
  path.join(root, 'dist/agent-src'),
592
- path.join(root, '.agent-src.uncondensed'),
599
+ path.join(root, 'src'),
600
+ path.join(root, 'src/agent-src'),
593
601
  ]) {
594
602
  if (_exists(path.join(prefix, ref))) {
595
603
  resolved = true;
@@ -605,7 +613,7 @@ function check_file(filepath: string, artifacts: Artifacts, root: string): Broke
605
613
  const rel = rawRef.slice('.augment/'.length);
606
614
  for (const prefix of [
607
615
  path.join(root, 'dist/agent-src'),
608
- path.join(root, '.agent-src.uncondensed'),
616
+ path.join(root, 'src/agent-src'),
609
617
  ]) {
610
618
  if (_exists(path.join(prefix, rel))) {
611
619
  resolved = true;
@@ -774,6 +782,10 @@ function check_memory_yaml(filepath: string, artifacts: Artifacts, root: string)
774
782
  function scan_all(root: string): BrokenRef[] {
775
783
  const artifacts = collect_artifacts(root);
776
784
  const broken: BrokenRef[] = [];
785
+ // gate-coverage contract (src/config/gate-coverage.yml): a machine-readable
786
+ // count of files actually read, so `check_gate_coverage` can assert this
787
+ // gate saw a real corpus rather than a moved root.
788
+ let scannedFiles = 0;
777
789
  for (const scanDir of SCAN_DIRS) {
778
790
  const d = path.join(root, scanDir);
779
791
  if (!_exists(d)) {
@@ -785,18 +797,22 @@ function scan_all(root: string): BrokenRef[] {
785
797
  if (SKIP_DIRS.some((skip) => f.startsWith(path.join(root, skip)))) {
786
798
  continue;
787
799
  }
800
+ scannedFiles += 1;
788
801
  broken.push(...check_file(f, artifacts, root));
789
802
  }
790
803
  }
791
804
  const memoryDir = path.join(root, MEMORY_YAML_ROOT);
792
805
  if (_isDir(memoryDir)) {
793
806
  for (const f of _rglob(memoryDir, '.yml').sort()) {
807
+ scannedFiles += 1;
794
808
  broken.push(...check_memory_yaml(f, artifacts, root));
795
809
  }
796
810
  for (const f of _rglob(memoryDir, '.yaml').sort()) {
811
+ scannedFiles += 1;
797
812
  broken.push(...check_memory_yaml(f, artifacts, root));
798
813
  }
799
814
  }
815
+ process.stderr.write(`scanned: ${String(scannedFiles)}\n`);
800
816
  return broken;
801
817
  }
802
818
 
@@ -24,6 +24,9 @@ const _HERE = fileURLToPath(import.meta.url);
24
24
 
25
25
  const ALLOWLIST_GLOBS = [
26
26
  'package.json',
27
+ // Lockfile version fields — bumped by release.ts set_lockfile_version in
28
+ // lockstep with package.json (road-to-gates-that-can-fail Phase 5).
29
+ 'package-lock.json',
27
30
  'CHANGELOG.md',
28
31
  '.claude-plugin/marketplace.json',
29
32
  'src/packs/*/pack.yaml',
@@ -131,6 +134,16 @@ function check(files: readonly string[]): number {
131
134
  for (const f of bad) {
132
135
  process.stdout.write(`OUT-OF-SHAPE: ${f}\n`);
133
136
  }
137
+ process.stdout.write(
138
+ '\n' +
139
+ 'A release PR may only contain the version-bump allowlist — the heavy\n' +
140
+ 'test matrix skips on release/* heads, so code must not ride a release PR\n' +
141
+ '(docs/contracts/release-pr-gating.md § Mid-release fixes).\n' +
142
+ 'Fix: land the files above on main via their own PR, then\n' +
143
+ ' git checkout release/X.Y.Z && git merge origin/main && git push\n' +
144
+ '— their release-PR diff becomes empty and this check goes green.\n' +
145
+ 'Then resume with: task release -- --resume --yes\n',
146
+ );
134
147
  return 1;
135
148
  }
136
149
  process.stdout.write(
@@ -17,7 +17,9 @@
17
17
  * - thin_rule_load — thin_projection.thin_gpt
18
18
  * - skill_descriptions — description_catalog.skills_core_source.tokens_gpt
19
19
  * - command_descriptions — description_catalog.commands_core_source.tokens_gpt
20
- * - mcp_schemas — Σ mcp_tool_schemas[*].tokens_gpt
20
+ * - mcp_schemas — max mcp_tool_schemas[*].tokens_gpt (per-transport;
21
+ * a client connects over ONE transport, so Σ would
22
+ * double-bill the tools both transports serve)
21
23
  *
22
24
  * A baseline captured under a different `token_method` (e.g. proxy → exact)
23
25
  * is a legitimate reset, not a regression — the gate WARNS and asks for a
@@ -74,10 +76,15 @@ function _num(obj: unknown, ...keys: string[]): number {
74
76
 
75
77
  /** Extract the flat gated-metric map from a projection-cost report. */
76
78
  function extract_metrics(report: Json): Metrics {
79
+ // MAX, not Σ. The report keys one entry per SERVER-TRANSPORT pair, and a
80
+ // client connects over exactly one transport of a given server — summing
81
+ // `agent-config (stdio)` and `agent-config (worker)` would bill the 19
82
+ // shared tools twice and read as a regression the moment the transports were
83
+ // split apart. The gated metric is what the worst-case single client loads.
77
84
  const mcp = (report['mcp_tool_schemas'] as Json) ?? {};
78
85
  let mcp_total = 0;
79
86
  for (const server of Object.values(mcp)) {
80
- mcp_total += _num(server, 'tokens_gpt');
87
+ mcp_total = Math.max(mcp_total, _num(server, 'tokens_gpt'));
81
88
  }
82
89
  return {
83
90
  token_method: String(report['token_method'] ?? 'unknown'),