@event4u/agent-config 14.12.0 → 14.13.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 (466) hide show
  1. package/.augment-plugin/marketplace.json +3 -3
  2. package/.augment-plugin/plugin.json +1 -1
  3. package/.claude-plugin/marketplace.json +1 -1
  4. package/CHANGELOG.md +234 -0
  5. package/CONTRIBUTING.md +38 -0
  6. package/CREDITS.md +135 -0
  7. package/NOTICE +13 -0
  8. package/README.md +8 -6
  9. package/dist/agent-src/commands/analyze/inbox.md +109 -2
  10. package/dist/agent-src/commands/feature/dev.md +7 -2
  11. package/dist/agent-src/commands/ghostwriter/write.md +5 -1
  12. package/dist/agent-src/commands/implement-ticket.md +1 -1
  13. package/dist/agent-src/commands/mission/upgrade.md +1 -1
  14. package/dist/agent-src/commands/orchestrate.md +2 -2
  15. package/dist/agent-src/commands/post-as/me.md +5 -1
  16. package/dist/agent-src/commands/pr/merge.md +19 -6
  17. package/dist/agent-src/commands/roadmap/process-full.md +19 -5
  18. package/dist/agent-src/commands/tdd/red.md +12 -2
  19. package/dist/agent-src/commands/work.md +1 -1
  20. package/dist/agent-src/contexts/communication/rules-auto/token-efficiency-mechanics.md +40 -0
  21. package/dist/agent-src/contexts/execution/auto-dispatch-classification.md +5 -2
  22. package/dist/agent-src/contexts/execution/autonomy-mechanics.md +21 -0
  23. package/dist/agent-src/contexts/execution/orchestration-telemetry.md +1 -0
  24. package/dist/agent-src/contexts/execution/subagent-response-contract.md +40 -0
  25. package/dist/agent-src/contexts/execution/subagent-steering.md +13 -1
  26. package/dist/agent-src/contexts/execution/terminal-states.md +96 -0
  27. package/dist/agent-src/rules/artifact-drafting-protocol.md +1 -1
  28. package/dist/agent-src/rules/broken-access-control.md +4 -0
  29. package/dist/agent-src/rules/code-provenance.md +4 -0
  30. package/dist/agent-src/rules/design-fidelity.md +1 -1
  31. package/dist/agent-src/rules/domain-safety-pii.md +4 -0
  32. package/dist/agent-src/rules/domain-safety-retention.md +4 -0
  33. package/dist/agent-src/rules/engineering-safety-floor.md +2 -0
  34. package/dist/agent-src/rules/external-code-graph-interop.md +14 -12
  35. package/dist/agent-src/rules/improve-before-implement.md +6 -8
  36. package/dist/agent-src/rules/laravel-routing.md +1 -1
  37. package/dist/agent-src/rules/lethal-trifecta-guard.md +4 -0
  38. package/dist/agent-src/rules/secret-vcs-guard.md +2 -0
  39. package/dist/agent-src/rules/security-sensitive-stop.md +2 -0
  40. package/dist/agent-src/rules/source-confidentiality.md +12 -34
  41. package/dist/agent-src/rules/symfony-routing.md +1 -1
  42. package/dist/agent-src/rules/token-efficiency.md +14 -0
  43. package/dist/agent-src/rules/tool-safety.md +4 -0
  44. package/dist/agent-src/rules/untrusted-input-defense.md +4 -0
  45. package/dist/agent-src/scripts/archive_completed_roadmaps.ts +247 -3
  46. package/dist/agent-src/scripts/guarded_baseline.ts +328 -0
  47. package/dist/agent-src/scripts/roadmap_set_step.ts +253 -0
  48. package/dist/agent-src/scripts/stub_queue.ts +82 -0
  49. package/dist/agent-src/scripts/stubs_due.ts +400 -0
  50. package/dist/agent-src/scripts/ticket_bundles.ts +84 -0
  51. package/dist/agent-src/scripts/update_roadmap_progress.ts +8 -4
  52. package/dist/agent-src/skills/brand-asset-generation/SKILL.md +17 -4
  53. package/dist/agent-src/skills/brand-audit/SKILL.md +33 -0
  54. package/dist/agent-src/skills/code-intelligence/SKILL.md +57 -0
  55. package/dist/agent-src/skills/database/SKILL.md +8 -0
  56. package/dist/agent-src/skills/dependency-upgrade/SKILL.md +27 -0
  57. package/dist/agent-src/skills/design-review/SKILL.md +1 -1
  58. package/dist/agent-src/skills/doc-coauthoring/SKILL.md +1 -1
  59. package/dist/agent-src/skills/existing-ui-audit/SKILL.md +17 -1
  60. package/dist/agent-src/skills/feature-planning/SKILL.md +9 -2
  61. package/dist/agent-src/skills/frontend-render-security/SKILL.md +44 -0
  62. package/dist/agent-src/skills/git-workflow/SKILL.md +1 -1
  63. package/dist/agent-src/skills/js-library-packaging/scripts/check_package_surface.ts +38 -4
  64. package/dist/agent-src/skills/judge-artifact-completeness/rubrics/ticket-quality-score.json +2 -2
  65. package/dist/agent-src/skills/laravel/SKILL.md +35 -0
  66. package/dist/agent-src/skills/laravel-migration/SKILL.md +57 -3
  67. package/dist/agent-src/skills/monorepo-workspace/SKILL.md +26 -0
  68. package/dist/agent-src/skills/playbook-authoring/SKILL.md +28 -1
  69. package/dist/agent-src/skills/react-shadcn-ui/SKILL.md +1 -1
  70. package/dist/agent-src/skills/skill-writing/references/procedure.md +5 -5
  71. package/dist/agent-src/skills/sql-writing/SKILL.md +7 -1
  72. package/dist/agent-src/skills/standards-from-config/SKILL.md +27 -4
  73. package/dist/agent-src/skills/supply-chain-intake/SKILL.md +11 -4
  74. package/dist/agent-src/skills/symfony-workflow/SKILL.md +35 -0
  75. package/dist/agent-src/skills/test-case-discovery/SKILL.md +85 -0
  76. package/dist/agent-src/skills/test-driven-development/SKILL.md +33 -9
  77. package/dist/agent-src/skills/testing-anti-patterns/SKILL.md +1 -1
  78. package/dist/agent-src/skills/testing-anti-patterns/process-anti-patterns.md +37 -0
  79. package/dist/agent-src/skills/ui-component-architect/SKILL.md +45 -2
  80. package/dist/agent-src/skills/upstream-contribute/SKILL.md +38 -1
  81. package/dist/agent-src/skills/verify-repair-loop/SKILL.md +9 -4
  82. package/dist/agent-src/templates/agents/agent-project-settings.example.yml +1 -1
  83. package/dist/agent-src/templates/roadmaps.md +97 -3
  84. package/dist/agent-src/templates/scripts/check_memory.ts +258 -17
  85. package/dist/agent-src/templates/scripts/check_memory_proposal.ts +9 -3
  86. package/dist/agent-src/templates/scripts/memory_lookup.ts +86 -0
  87. package/dist/agent-src/templates/scripts/memory_signal.ts +44 -0
  88. package/dist/agent-src/templates/scripts/work_engine/directives/backend/implement.ts +90 -0
  89. package/dist/agent-src/templates/scripts/work_engine/directives/backend/index.ts +11 -0
  90. package/dist/agent-src/templates/scripts/work_engine/directives/backend/test.ts +23 -1
  91. package/dist/agent-src/templates/scripts/work_engine/directives/backend/verify.ts +10 -1
  92. package/dist/agent-src/templates/scripts/work_engine/directives/mixed/stitch.ts +5 -1
  93. package/dist/agent-src/templates/scripts/work_engine/stack/runner.ts +102 -14
  94. package/dist/cli/commands/uiAudit.js +124 -5
  95. package/dist/cli/registry.js +2 -0
  96. package/dist/cli-delegate/{chunk-HYWSRNUX.js → chunk-2DK2VJWG.js} +3 -3
  97. package/dist/cli-delegate/{chunk-JCW7ZLHK.js → chunk-4FS4WRXP.js} +5 -0
  98. package/dist/cli-delegate/{chunk-OMIVVCG2.js → chunk-A4QJ6ENT.js} +24 -0
  99. package/dist/cli-delegate/{chunk-JJA2QEWA.js → chunk-AKJGUQNO.js} +466 -285
  100. package/dist/cli-delegate/{chunk-E46KPN6K.js → chunk-BTWUYDGN.js} +424 -363
  101. package/dist/cli-delegate/{chunk-K4FFODTS.js → chunk-ILMUPLGW.js} +1227 -316
  102. package/dist/cli-delegate/{chunk-FF7WAFMR.js → chunk-KPBWFOPZ.js} +5 -1
  103. package/dist/cli-delegate/cmd_adr_effective.js +102 -0
  104. package/dist/cli-delegate/cmd_conformance.js +42 -10
  105. package/dist/cli-delegate/cmd_doctor.js +3 -3
  106. package/dist/cli-delegate/cmd_export.js +3 -2
  107. package/dist/cli-delegate/cmd_fleet.js +2 -2
  108. package/dist/cli-delegate/cmd_handoff.js +1 -1
  109. package/dist/cli-delegate/cmd_preflight.js +2 -2
  110. package/dist/cli-delegate/cmd_prune.js +3 -2
  111. package/dist/cli-delegate/cmd_settings_get.js +1 -1
  112. package/dist/cli-delegate/cmd_settings_migrate.js +3 -2
  113. package/dist/cli-delegate/cmd_settings_set.js +2 -2
  114. package/dist/cli-delegate/cmd_sync.js +3 -2
  115. package/dist/cli-delegate/cmd_uninstall.js +3 -2
  116. package/dist/cli-delegate/cmd_validate.js +3 -2
  117. package/dist/discovery/deprecation-report.md +1 -1
  118. package/dist/discovery/discovery-manifest.json +57 -57
  119. package/dist/discovery/discovery-manifest.json.sha256 +1 -1
  120. package/dist/discovery/discovery-manifest.summary.md +1 -1
  121. package/dist/discovery/dormancy-report.md +1 -1
  122. package/dist/discovery/orphan-report.md +1 -1
  123. package/dist/discovery/packs.json +2 -2
  124. package/dist/discovery/trust-report.md +1 -1
  125. package/dist/discovery/workspaces.json +2 -2
  126. package/dist/hooks/dispatch.js +1836 -712
  127. package/dist/install/claudeRuleRewrite.js +254 -0
  128. package/dist/install/detect.js +29 -16
  129. package/dist/install/detect_php_shape.js +159 -0
  130. package/dist/install/install.mjs +634 -428
  131. package/dist/mcp/awesome-mcp-servers.row.md +1 -1
  132. package/dist/mcp/mcp-cloudflare-catalogue.json +1 -1
  133. package/dist/mcp/registry-manifest.json +3 -3
  134. package/dist/mcp/server.json +3 -3
  135. package/dist/mcp/server.mjs +4818 -2645
  136. package/dist/server/schemas/settings.js +3 -0
  137. package/dist/ui/assets/index-D0jaCRPM.js +29 -0
  138. package/dist/ui/index.html +1 -1
  139. package/docs/MIGRATION.md +1 -1
  140. package/docs/THIRD-PARTY-NOTICES.md +25 -0
  141. package/docs/contracts/provider-lifecycle.md +1 -1
  142. package/docs/contracts/settings-classes.md +10 -4
  143. package/docs/guidelines/agent-infra/5w2h-analysis.md +3 -3
  144. package/docs/guidelines/agent-infra/agent-interaction-and-decision-quality.md +1 -0
  145. package/docs/guidelines/agent-infra/artifact-drafting-protocol-mechanics.md +58 -3
  146. package/docs/guidelines/agent-infra/ask-when-uncertain-demos.md +2 -2
  147. package/docs/guidelines/agent-infra/asking-and-brevity-examples.md +3 -3
  148. package/docs/guidelines/agent-infra/break-glass-usage.md +7 -7
  149. package/docs/guidelines/agent-infra/carve-out-predicates.md +3 -3
  150. package/docs/guidelines/agent-infra/comparison-matrix.md +1 -1
  151. package/docs/guidelines/agent-infra/critical-thinking.md +4 -4
  152. package/docs/guidelines/agent-infra/direct-answers-demos.md +2 -2
  153. package/docs/guidelines/agent-infra/domain-eval-anti-pattern.md +1 -1
  154. package/docs/guidelines/agent-infra/engineering-memory-data-format.md +3 -3
  155. package/docs/guidelines/agent-infra/existence-question-verdicts.md +80 -0
  156. package/docs/guidelines/agent-infra/first-principles.md +2 -2
  157. package/docs/guidelines/agent-infra/framework-neutrality-patterns.md +2 -2
  158. package/docs/guidelines/agent-infra/guarded-baseline.md +39 -0
  159. package/docs/guidelines/agent-infra/inversion-thinking.md +5 -5
  160. package/docs/guidelines/agent-infra/language-and-tone-examples.md +1 -1
  161. package/docs/guidelines/agent-infra/layered-settings.md +10 -10
  162. package/docs/guidelines/agent-infra/memory-access.md +1 -1
  163. package/docs/guidelines/agent-infra/mental-models.md +3 -3
  164. package/docs/guidelines/agent-infra/reuse-verdict-mechanics.md +71 -0
  165. package/docs/guidelines/agent-infra/review-routing-data-format.md +7 -7
  166. package/docs/guidelines/agent-infra/roadmap-progress-mechanics.md +13 -7
  167. package/docs/guidelines/agent-infra/role-contracts.md +2 -2
  168. package/docs/guidelines/agent-infra/role-mode-router.md +3 -3
  169. package/docs/guidelines/agent-infra/rule-type-governance.md +2 -2
  170. package/docs/guidelines/agent-infra/scqa-framework.md +5 -5
  171. package/docs/guidelines/agent-infra/self-improvement-pipeline.md +6 -6
  172. package/docs/guidelines/agent-infra/simplicity-and-goal-demos.md +2 -2
  173. package/docs/guidelines/agent-infra/six-hats.md +3 -3
  174. package/docs/guidelines/agent-infra/skill-quality-checklist.md +6 -6
  175. package/docs/guidelines/agent-infra/source-confidentiality-mechanics.md +109 -0
  176. package/docs/guidelines/agent-infra/systems-thinking.md +1 -1
  177. package/docs/guidelines/agent-infra/verify-before-complete-demos.md +2 -2
  178. package/docs/guidelines/augment-portability-patterns.md +6 -4
  179. package/docs/guidelines/component-oriented-and-oop-development.md +3 -2
  180. package/docs/guidelines/cross-role-handoff.md +2 -2
  181. package/docs/guidelines/design-fidelity-mechanics.md +1 -1
  182. package/docs/guidelines/docs/readme-size-and-splitting.md +3 -3
  183. package/docs/guidelines/php/database.md +90 -7
  184. package/docs/guidelines/prompt-templates.md +7 -7
  185. package/llms.txt +2 -2
  186. package/package.json +5 -2
  187. package/src/agent-src/scripts/archive_completed_roadmaps.ts +247 -3
  188. package/src/agent-src/scripts/guarded_baseline.ts +328 -0
  189. package/src/agent-src/scripts/roadmap_set_step.ts +253 -0
  190. package/src/agent-src/scripts/stub_queue.ts +82 -0
  191. package/src/agent-src/scripts/stubs_due.ts +400 -0
  192. package/src/agent-src/scripts/ticket_bundles.ts +84 -0
  193. package/src/agent-src/scripts/update_roadmap_progress.ts +8 -4
  194. package/src/agent-src/templates/scripts/check_memory.ts +258 -17
  195. package/src/agent-src/templates/scripts/check_memory_proposal.ts +9 -3
  196. package/src/agent-src/templates/scripts/memory_lookup.ts +86 -0
  197. package/src/agent-src/templates/scripts/memory_signal.ts +44 -0
  198. package/src/agent-src/templates/scripts/work_engine/directives/backend/implement.ts +90 -0
  199. package/src/agent-src/templates/scripts/work_engine/directives/backend/index.ts +11 -0
  200. package/src/agent-src/templates/scripts/work_engine/directives/backend/test.ts +23 -1
  201. package/src/agent-src/templates/scripts/work_engine/directives/backend/verify.ts +10 -1
  202. package/src/agent-src/templates/scripts/work_engine/directives/mixed/stitch.ts +5 -1
  203. package/src/agent-src/templates/scripts/work_engine/stack/runner.ts +102 -14
  204. package/src/config/agent-settings.template.yml +32 -3
  205. package/src/config/assurance-capability-registry.json +21 -9
  206. package/src/config/canonical-terms.yml +119 -0
  207. package/src/config/capability-native-outcome-bars.json +81 -0
  208. package/src/config/ci-local-parity.yml +80 -0
  209. package/src/config/drafting-channels.yml +43 -0
  210. package/src/config/estate-count-budget.json +38 -36
  211. package/src/config/evaluator-budgets.json +14 -14
  212. package/src/config/gate-coverage.yml +579 -63
  213. package/src/config/gate-reachability-exemptions.json +21 -0
  214. package/src/config/gate-violation-baselines.json +37 -19
  215. package/src/config/harness-evolution-budget.json +25 -0
  216. package/src/config/lapsed-beta-baseline.json +96 -0
  217. package/src/config/memory-twin-verdicts.yml +129 -0
  218. package/src/config/metric-registry.yml +124 -0
  219. package/src/config/pack-size-budget.json +16 -15
  220. package/src/config/preamble-payload-budget.json +8 -8
  221. package/src/config/profiles/balanced.ini +27 -0
  222. package/src/config/profiles/full.ini +27 -0
  223. package/src/config/profiles/minimal.ini +27 -0
  224. package/src/config/publish-surface.json +9 -2
  225. package/src/config/routing-coverage-seed.json +16 -2
  226. package/src/config/rule-stub-ceilings.json +126 -112
  227. package/src/config/turnaround-budget.json +66 -0
  228. package/src/install/claudeRuleRewrite.ts +288 -0
  229. package/src/install/detect.ts +60 -17
  230. package/src/install/detect_php_shape.ts +191 -0
  231. package/src/scripts/_cli/cmd_doctor.ts +27 -112
  232. package/src/scripts/_dispatch.bash +27 -0
  233. package/src/scripts/_lib/activation_ladder.ts +211 -0
  234. package/src/scripts/_lib/activation_states.ts +88 -0
  235. package/src/scripts/_lib/adherence_detectors.ts +143 -0
  236. package/src/scripts/_lib/arith_claims.ts +181 -0
  237. package/src/scripts/_lib/arm_ranking.ts +62 -0
  238. package/src/scripts/_lib/asset_delivery_ledger.ts +303 -0
  239. package/src/scripts/_lib/audit_field_provenance.ts +54 -0
  240. package/src/scripts/_lib/auto_dispatch.ts +32 -3
  241. package/src/scripts/_lib/bench_ab_size_claim.ts +98 -4
  242. package/src/scripts/_lib/benchmark_cache_fields.ts +158 -0
  243. package/src/scripts/_lib/candidate_proposer.ts +402 -0
  244. package/src/scripts/_lib/candidate_record.ts +601 -0
  245. package/src/scripts/_lib/capture_rate.ts +319 -0
  246. package/src/scripts/_lib/collector_denominator.ts +771 -0
  247. package/src/scripts/_lib/collector_record.ts +340 -0
  248. package/src/scripts/_lib/collector_store.ts +664 -0
  249. package/src/scripts/_lib/collector_supervision.ts +827 -0
  250. package/src/scripts/_lib/concern_estate.ts +77 -0
  251. package/src/scripts/_lib/config_chain.ts +477 -0
  252. package/src/scripts/_lib/config_cost.ts +209 -0
  253. package/src/scripts/_lib/council_settings_block.ts +6 -0
  254. package/src/scripts/_lib/curator_ops.ts +172 -0
  255. package/src/scripts/_lib/delivery_arm_experiment.ts +266 -0
  256. package/src/scripts/_lib/delivery_criticality.ts +126 -0
  257. package/src/scripts/_lib/doctor_runtime_checks.ts +70 -0
  258. package/src/scripts/_lib/empty_cycles.ts +88 -0
  259. package/src/scripts/_lib/eval_publication.ts +354 -0
  260. package/src/scripts/_lib/evaluation_vector.ts +283 -0
  261. package/src/scripts/_lib/evaluator_promotion.ts +225 -0
  262. package/src/scripts/_lib/evidence_basis.ts +118 -0
  263. package/src/scripts/_lib/exec_evidence.ts +8 -0
  264. package/src/scripts/_lib/experience_card.ts +272 -0
  265. package/src/scripts/_lib/experience_report.ts +151 -0
  266. package/src/scripts/_lib/experiment_freeze.ts +112 -0
  267. package/src/scripts/_lib/generated_by.ts +66 -0
  268. package/src/scripts/_lib/harness_evolution_guards.ts +229 -0
  269. package/src/scripts/_lib/hook_effect_probe.ts +141 -0
  270. package/src/scripts/_lib/host_denominator.ts +687 -0
  271. package/src/scripts/_lib/host_projection_reach.ts +157 -0
  272. package/src/scripts/_lib/ignored_blocker.ts +148 -0
  273. package/src/scripts/_lib/install_reach_checks.ts +495 -0
  274. package/src/scripts/_lib/json_duplicate_keys.ts +150 -0
  275. package/src/scripts/_lib/judge_hygiene.ts +228 -0
  276. package/src/scripts/_lib/legacy_boundary_map.ts +228 -0
  277. package/src/scripts/_lib/loop_guards.ts +299 -0
  278. package/src/scripts/_lib/loss_class.ts +129 -0
  279. package/src/scripts/_lib/machine_wake.ts +51 -0
  280. package/src/scripts/_lib/md_prose_lines.ts +177 -0
  281. package/src/scripts/_lib/minimality_tiebreak.ts +168 -0
  282. package/src/scripts/_lib/one_resolver_invariant.ts +449 -0
  283. package/src/scripts/_lib/orchestration_record.ts +253 -5
  284. package/src/scripts/_lib/outcome_envelope.ts +227 -0
  285. package/src/scripts/_lib/outcome_vocabularies.ts +125 -0
  286. package/src/scripts/_lib/paired_stats.ts +245 -0
  287. package/src/scripts/_lib/paired_verdict.ts +226 -0
  288. package/src/scripts/_lib/prefix_stable_surfaces.ts +123 -0
  289. package/src/scripts/_lib/privacy_class.ts +47 -0
  290. package/src/scripts/_lib/regression_neighbourhood.ts +259 -0
  291. package/src/scripts/_lib/repeated_failure.ts +105 -0
  292. package/src/scripts/_lib/repo_root.ts +111 -0
  293. package/src/scripts/_lib/review_skipped_record.ts +37 -0
  294. package/src/scripts/_lib/role_split.ts +338 -0
  295. package/src/scripts/_lib/runtime_journal.ts +1499 -0
  296. package/src/scripts/_lib/runtime_wiring_checks.ts +430 -0
  297. package/src/scripts/_lib/skill_catalogue.ts +11 -1
  298. package/src/scripts/_lib/source_digest.ts +200 -0
  299. package/src/scripts/_lib/source_redact.ts +260 -0
  300. package/src/scripts/_lib/source_shape.ts +502 -0
  301. package/src/scripts/_lib/source_snapshot_dedup.ts +199 -0
  302. package/src/scripts/_lib/strip_comments.d.mts +8 -0
  303. package/src/scripts/_lib/strip_comments.mjs +65 -0
  304. package/src/scripts/_lib/test_red_state.ts +154 -0
  305. package/src/scripts/_lib/trigger_shift.ts +144 -0
  306. package/src/scripts/_lib/untrusted_content.ts +82 -7
  307. package/src/scripts/adoption_report.ts +1 -1
  308. package/src/scripts/adr/evidence_census.ts +1 -1
  309. package/src/scripts/adr/regenerate_index.ts +26 -2
  310. package/src/scripts/adr_cite_check.ts +164 -1
  311. package/src/scripts/ai_council/blind_review.ts +11 -1
  312. package/src/scripts/ai_council/clients.ts +4 -0
  313. package/src/scripts/ai_council/config.ts +3 -0
  314. package/src/scripts/ai_council/consensus.ts +28 -8
  315. package/src/scripts/ai_council/consensus_round.ts +226 -0
  316. package/src/scripts/ai_council/disagreement_signal.ts +338 -0
  317. package/src/scripts/ai_council/inline_findings.ts +340 -0
  318. package/src/scripts/ai_council/judge_position_bias.ts +197 -0
  319. package/src/scripts/ai_council/orchestrator.ts +16 -203
  320. package/src/scripts/ai_council/orchestrator_results.ts +23 -3
  321. package/src/scripts/ai_council/pricing.ts +106 -0
  322. package/src/scripts/ai_council/prompts.ts +74 -7
  323. package/src/scripts/ai_council/provider_leakage_bench.ts +327 -0
  324. package/src/scripts/ai_council/py_format.ts +14 -3
  325. package/src/scripts/ai_council/recouncil_guard.ts +293 -0
  326. package/src/scripts/ai_council/response_record.ts +50 -0
  327. package/src/scripts/ai_council/topology_bench_manifest.ts +860 -0
  328. package/src/scripts/ai_council/topology_vocabulary.ts +175 -0
  329. package/src/scripts/asset_delivery_ledger.ts +157 -0
  330. package/src/scripts/attest_artifact.ts +193 -0
  331. package/src/scripts/audit_auto_rules.ts +2 -1
  332. package/src/scripts/audit_command_surface.ts +1 -1
  333. package/src/scripts/audit_mcp_tools.ts +2 -2
  334. package/src/scripts/audit_skill_overlap_allowlist.json +6 -1
  335. package/src/scripts/audit_user_type_axis.ts +2 -1
  336. package/src/scripts/bench_ab_clone.ts +215 -10
  337. package/src/scripts/bench_ab_integrity.ts +119 -5
  338. package/src/scripts/bench_ab_v2_stats.ts +40 -213
  339. package/src/scripts/build_archive_index.ts +1 -1
  340. package/src/scripts/build_linear_digest.ts +1 -1
  341. package/src/scripts/build_proof.ts +11 -4
  342. package/src/scripts/build_rule_trigger_matrix.ts +1 -1
  343. package/src/scripts/build_source_digests.ts +157 -0
  344. package/src/scripts/cache_realization_report.ts +103 -0
  345. package/src/scripts/check_adr_frontmatter.ts +126 -0
  346. package/src/scripts/check_benchmark_report_fields.ts +207 -0
  347. package/src/scripts/check_beta_review_markers.ts +235 -6
  348. package/src/scripts/check_bundle_path_leakage.ts +34 -1
  349. package/src/scripts/check_claims.ts +576 -6
  350. package/src/scripts/check_composite_arming.ts +35 -0
  351. package/src/scripts/check_concern_admissions.ts +365 -0
  352. package/src/scripts/check_enforcement_coverage.ts +28 -0
  353. package/src/scripts/check_estate_count.ts +142 -1
  354. package/src/scripts/check_gate_reachability.ts +383 -0
  355. package/src/scripts/check_host_loadability.ts +104 -0
  356. package/src/scripts/check_loss_class_declared.ts +308 -0
  357. package/src/scripts/check_md_language.ts +15 -98
  358. package/src/scripts/check_memory_proposal.ts +18 -11
  359. package/src/scripts/check_no_currency_in_cost_surfaces.ts +225 -0
  360. package/src/scripts/check_no_external_sources.ts +281 -6
  361. package/src/scripts/check_pack_conformance_fixture.ts +11 -1
  362. package/src/scripts/check_pack_size.ts +59 -2
  363. package/src/scripts/check_preamble_payload_budget.ts +114 -3
  364. package/src/scripts/check_prefix_stable_mutation.ts +372 -0
  365. package/src/scripts/check_publish_surface.ts +10 -1
  366. package/src/scripts/check_references.ts +24 -1
  367. package/src/scripts/check_rule_evidence_declaration.ts +316 -0
  368. package/src/scripts/check_rule_projection_integrity.ts +14 -4
  369. package/src/scripts/check_score_contract.ts +26 -3
  370. package/src/scripts/check_static_parity.ts +285 -0
  371. package/src/scripts/check_supervision_claim_atomicity.ts +498 -0
  372. package/src/scripts/check_suppression_hygiene.ts +15 -0
  373. package/src/scripts/ci_settle.ts +39 -2
  374. package/src/scripts/code_graph/build.ts +60 -3
  375. package/src/scripts/code_graph/extract.ts +44 -0
  376. package/src/scripts/code_graph/types.ts +24 -0
  377. package/src/scripts/collector_daemon.ts +714 -0
  378. package/src/scripts/config_cost_report.ts +302 -0
  379. package/src/scripts/consumer_matrix.ts +74 -1
  380. package/src/scripts/cost/budget.mjs +10 -3
  381. package/src/scripts/cost/track.mjs +10 -3
  382. package/src/scripts/council_cli.ts +37 -54
  383. package/src/scripts/dispatch_r2_reviewer.ts +46 -5
  384. package/src/scripts/evolution_lab.ts +980 -0
  385. package/src/scripts/external_sources_denylist.json +5 -18
  386. package/src/scripts/extract_audit_patterns.ts +21 -0
  387. package/src/scripts/fold_intake.ts +12 -1
  388. package/src/scripts/gen_discovery_baseline.ts +1 -1
  389. package/src/scripts/generate_capabilities_index.ts +12 -5
  390. package/src/scripts/generate_capability_matrix.ts +3 -3
  391. package/src/scripts/generate_command_flows.ts +2 -2
  392. package/src/scripts/generate_cookbook.ts +2 -2
  393. package/src/scripts/generate_index.ts +8 -1
  394. package/src/scripts/generate_knowledge_index.ts +2 -1
  395. package/src/scripts/generate_ownership_matrix.ts +2 -1
  396. package/src/scripts/generate_pack_manifests.ts +10 -2
  397. package/src/scripts/generate_role_experiences_catalog.ts +2 -2
  398. package/src/scripts/generate_settings_reference.ts +1 -1
  399. package/src/scripts/git_authorization_hook.ts +22 -1
  400. package/src/scripts/grade_target_readiness.ts +48 -5
  401. package/src/scripts/hook_effect_doctor.ts +261 -0
  402. package/src/scripts/hook_manifest.json +1 -1
  403. package/src/scripts/hook_manifest.yaml +98 -11
  404. package/src/scripts/hooks/block_speaking_inbox_dir.ts +271 -0
  405. package/src/scripts/hooks/block_unauthorized_git.ts +18 -0
  406. package/src/scripts/hooks/concern_registry.ts +4 -0
  407. package/src/scripts/hooks/dispatch_hook.ts +32 -0
  408. package/src/scripts/hooks/journal_record_hook.ts +345 -0
  409. package/src/scripts/hooks/prepush_metadata_sources.sh +110 -0
  410. package/src/scripts/hooks/run_continuation_hook.ts +44 -9
  411. package/src/scripts/hooks/shims/install.sh +61 -0
  412. package/src/scripts/hooks/shims/php +101 -0
  413. package/src/scripts/hooks/suggestion_capture_hook.ts +10 -0
  414. package/src/scripts/hot_context_hook.ts +16 -0
  415. package/src/scripts/install-hooks.sh +20 -5
  416. package/src/scripts/install.ts +17 -35
  417. package/src/scripts/inventory_frontmatter.ts +2 -1
  418. package/src/scripts/lint_adr_sweep_routing.ts +12 -0
  419. package/src/scripts/lint_canonical_terms.ts +604 -0
  420. package/src/scripts/lint_composition_review.ts +619 -0
  421. package/src/scripts/lint_consolidation_lineage.ts +666 -0
  422. package/src/scripts/lint_eval_specs.ts +593 -0
  423. package/src/scripts/lint_hook_manifest.ts +19 -0
  424. package/src/scripts/lint_host_portability.ts +373 -0
  425. package/src/scripts/lint_judge_prompt_expectation.ts +27 -1
  426. package/src/scripts/lint_memory_twin_parity.ts +335 -0
  427. package/src/scripts/lint_metric_consumers.ts +355 -0
  428. package/src/scripts/lint_skill_descriptions.ts +18 -1
  429. package/src/scripts/lint_skill_frontmatter_safety.ts +58 -0
  430. package/src/scripts/lint_skill_link_reach.ts +252 -0
  431. package/src/scripts/lint_skill_trigger_corpus.ts +426 -23
  432. package/src/scripts/lint_ticket_buildable.ts +17 -1
  433. package/src/scripts/mcp_server/consumer_tool_catalog.json +1 -1
  434. package/src/scripts/mcp_server/tool_catalog_source.ts +1 -1
  435. package/src/scripts/measure_docs_dead_links.ts +348 -0
  436. package/src/scripts/measure_host_capture.ts +461 -0
  437. package/src/scripts/migration_status.ts +3 -3
  438. package/src/scripts/model_rule_injection.ts +60 -0
  439. package/src/scripts/orchestration_record.ts +14 -0
  440. package/src/scripts/preamble_byte_census.ts +139 -10
  441. package/src/scripts/prepack-check.mjs +4 -1
  442. package/src/scripts/probe_turnaround.ts +384 -0
  443. package/src/scripts/probe_unblocked_ask.ts +279 -0
  444. package/src/scripts/render_benchmark_md.ts +1 -1
  445. package/src/scripts/rule_activation_census.ts +70 -9
  446. package/src/scripts/rule_backlinks.ts +1 -1
  447. package/src/scripts/run_lifecycle_suite.ts +208 -0
  448. package/src/scripts/run_skill_evals.ts +40 -0
  449. package/src/scripts/schemas/delivery-manifest.schema.json +43 -0
  450. package/src/scripts/schemas/drafting-channels.schema.json +43 -0
  451. package/src/scripts/schemas/evals.schema.json +24 -1
  452. package/src/scripts/schemas/rule.schema.json +52 -1
  453. package/src/scripts/schemas/skill.schema.json +17 -2
  454. package/src/scripts/skill_overlap.ts +7 -1
  455. package/src/scripts/skill_tools/run_block_d_eval.ts +8 -1
  456. package/src/scripts/skill_tools/score_skill_relevance.ts +84 -3
  457. package/src/scripts/skill_tools/suggest_skill_for_task.ts +8 -1
  458. package/src/scripts/skill_usage_report.ts +2 -1
  459. package/src/scripts/stubs_due.ts +211 -0
  460. package/src/scripts/sweep_source_surfaces.ts +678 -0
  461. package/src/scripts/sync_pr_branch.ts +3 -3
  462. package/src/scripts/trigger_eval_grandfather.json +202 -222
  463. package/src/scripts/utilization_report.ts +22 -2
  464. package/src/server/schemas/settings.ts +5 -0
  465. package/src/templates/marketing-copy.yml +1 -1
  466. package/dist/ui/assets/index-Cxgy63kz.js +0 -26
@@ -0,0 +1,328 @@
1
+ /**
2
+ * `guarded-baseline` — the third machine-readable step state, and its evidence
3
+ * contract (AI council 2026-08-31, 2/2 convergent: anthropic/claude-sonnet-4-5 +
4
+ * openai/codex-default, option C).
5
+ *
6
+ * A roadmap step whose `verify:` asserts a property of a mechanism that DOES NOT
7
+ * YET EXIST may not close `[x]` — that overstates the evidence. It keeps the
8
+ * canonical unchecked box, carries an annotation, and carries a structured
9
+ * evidence record next to it:
10
+ *
11
+ * - [ ] <!-- roadmap-status: guarded-baseline -->
12
+ * **7.3** …step text…
13
+ * ```yaml
14
+ * guarded_baseline:
15
+ * category: future-mechanism
16
+ * scope: src/scripts/ai_council/**
17
+ * command: npx vitest run tests/scripts/x.test.ts
18
+ * red_proof: sabotage run 2026-08-31 — 2 failed
19
+ * sabotage_model: added a `--topology` flag to the option table
20
+ * recheck_when: src/scripts/ai_council/topology_selector.ts
21
+ * discharged_ac: the baseline is pinned and RED-proven
22
+ * pending_ac: the constraint under real topology selection
23
+ * ```
24
+ *
25
+ * BOTH SEATS MADE THE TOOLING A CONDITION OF THE VERDICT — "C is acceptable only
26
+ * if its tooling lands atomically; otherwise use ordinary `[ ]` with structured
27
+ * evidence" — so the annotation is worth nothing without the five semantics
28
+ * below, and they live here rather than duplicated in the two consumers:
29
+ *
30
+ * 1. reported separately and NEVER counted as done — the canonical box stays
31
+ * `[ ]`, so `count_checkboxes` already excludes it; `reportGuardedBaselines`
32
+ * is the separate surface that makes the state visible rather than silent;
33
+ * 2. `archive_completed_roadmaps` treats it as incomplete and refuses archival;
34
+ * 3. a `recheck_when` trigger that now RESOLVES in the tree marks the evidence
35
+ * STALE — the guard was written against an absence that has since ended;
36
+ * 4. only verification against the real mechanism permits `[x]`;
37
+ * 5. a baseline that has not demonstrably gone RED is an ordinary open item —
38
+ * hence `red_proof` is mandatory and its absence REJECTS the annotation.
39
+ *
40
+ * The two legal categories are the council's own split. An `absence-assertion`
41
+ * step asserts something directly observable today and MAY close `[x]` once
42
+ * sabotage-verified; a `future-mechanism` step is what this state exists for. No
43
+ * third value is accepted and absence is not defaulted: defaulting would silently
44
+ * promote the strict case into the lax one, which is the overstatement the whole
45
+ * verdict is against.
46
+ */
47
+
48
+ import * as fs from 'node:fs';
49
+ import * as path from 'node:path';
50
+
51
+ /** The annotation itself. Tolerant of internal spacing, nothing else. */
52
+ export const GUARDED_BASELINE_RE = /<!--[ \t]*roadmap-status:[ \t]*guarded-baseline[ \t]*-->/;
53
+
54
+ /** The only two legal `category:` values — see the header on why absence is not a default. */
55
+ export const GUARDED_CATEGORIES: readonly string[] = ['future-mechanism', 'absence-assertion'];
56
+
57
+ /**
58
+ * `- [<glyph>] …` at any indent, with `-` or `*`.
59
+ *
60
+ * Deliberately neither of the two checkbox patterns already in this directory:
61
+ * the dashboard's `CHECKBOX_RE` is `g`-sticky and requires trailing whitespace,
62
+ * and the sweep's `DEFERRED_STEP_RE` pins `[~]`. This one has to CAPTURE the
63
+ * glyph an annotation sits on — including `[x]` — because refusing that case is
64
+ * the whole point of the validator below.
65
+ */
66
+ const ANY_CHECKBOX_RE = /^[ \t]*[-*][ \t]+\[([ xX~-])\]/;
67
+
68
+ /** A following step or any heading ends the annotated step's span. */
69
+ const SPAN_END_RE = /^[ \t]*[-*][ \t]+\[[ xX~-]\]|^#{1,6}[ \t]/;
70
+
71
+ const BLOCK_START_RE = /^[ \t]*guarded_baseline:[ \t]*$/;
72
+ const FIELD_RE = /^[ \t]*([a-z_]+):[ \t]*(.*)$/;
73
+ const FENCE_RE = /^[ \t]*(?:```|~~~)/;
74
+
75
+ /**
76
+ * A record annotates a STEP, so it is only recognised on a list item.
77
+ *
78
+ * Measured, not defensive: without this the very roadmap that SPECIFIES this
79
+ * state reddened its own dashboard, because its verdict paragraph names the
80
+ * annotation in prose. Same discipline `parse_blockers` already applies with
81
+ * `_stripFencedCode` — a documentation example of a shape is not an instance of
82
+ * it — extended to the two prose forms that actually occur, an inline code span
83
+ * and a fenced example.
84
+ */
85
+ const LIST_ITEM_RE = /^[ \t]*[-*][ \t]+/;
86
+ const INLINE_CODE_RE = /`[^`]*`/g;
87
+
88
+ /** One annotated step, as both consumers need it. */
89
+ export interface GuardedBaselineItem {
90
+ /** 1-based line of the annotated line, for the messages. */
91
+ line: number;
92
+ /** Step text, from the annotated line or its first continuation line. */
93
+ label: string;
94
+ /**
95
+ * The checkbox glyph the annotation actually sits on, or `null` when the
96
+ * annotation is not on a checkbox line at all. Both non-`' '` and `null` are
97
+ * rejections — recorded rather than normalised, so the message can say which.
98
+ */
99
+ glyph: string | null;
100
+ /** Did the span carry a `guarded_baseline:` block at all? */
101
+ hasBlock: boolean;
102
+ fields: Readonly<Record<string, string>>;
103
+ }
104
+
105
+ function _label(annotatedLine: string, lines: readonly string[], i: number): string {
106
+ const own = annotatedLine
107
+ .replace(ANY_CHECKBOX_RE, '')
108
+ .replace(GUARDED_BASELINE_RE, '')
109
+ .replace(/\*\*/g, '')
110
+ .trim();
111
+ if (own !== '') {
112
+ return own;
113
+ }
114
+ // The council's mechanical form puts the step text on the NEXT line.
115
+ for (let j = i + 1; j < lines.length; j++) {
116
+ const next = (lines[j] as string).trim();
117
+ if (next === '') {
118
+ continue;
119
+ }
120
+ if (SPAN_END_RE.test(lines[j] as string)) {
121
+ break;
122
+ }
123
+ return next.replace(/\*\*/g, '').trim();
124
+ }
125
+ return '(unlabelled)';
126
+ }
127
+
128
+ /** Every `guarded-baseline`-annotated step in one roadmap, with its evidence block. */
129
+ export function parseGuardedBaselines(text: string): GuardedBaselineItem[] {
130
+ const lines = text.split('\n');
131
+ const out: GuardedBaselineItem[] = [];
132
+ let inFence = false;
133
+ for (let i = 0; i < lines.length; i++) {
134
+ const raw = lines[i] as string;
135
+ if (FENCE_RE.test(raw)) {
136
+ inFence = !inFence;
137
+ }
138
+ // Inside a fence it is an example; inside backticks it is prose; off a
139
+ // list item it is not a step at all. See LIST_ITEM_RE for the measurement.
140
+ if (inFence || !LIST_ITEM_RE.test(raw)) {
141
+ continue;
142
+ }
143
+ if (!GUARDED_BASELINE_RE.test(raw.replace(INLINE_CODE_RE, ''))) {
144
+ continue;
145
+ }
146
+ const box = ANY_CHECKBOX_RE.exec(raw);
147
+ const fields: Record<string, string> = {};
148
+ let hasBlock = false;
149
+ for (let j = i + 1; j < lines.length; j++) {
150
+ const line = lines[j] as string;
151
+ if (SPAN_END_RE.test(line)) {
152
+ break; // the next step — this one's span is over
153
+ }
154
+ if (FENCE_RE.test(line)) {
155
+ continue; // a ```yaml wrapper is optional, and not the data
156
+ }
157
+ if (!hasBlock) {
158
+ hasBlock = BLOCK_START_RE.test(line);
159
+ continue;
160
+ }
161
+ const f = FIELD_RE.exec(line);
162
+ if (f) {
163
+ fields[f[1] as string] = (f[2] as string).trim();
164
+ }
165
+ }
166
+ out.push({
167
+ line: i + 1,
168
+ label: _label(raw, lines, i),
169
+ glyph: box ? (box[1] as string) : null,
170
+ hasBlock,
171
+ fields,
172
+ });
173
+ }
174
+ return out;
175
+ }
176
+
177
+ /**
178
+ * Every reason this annotation is REJECTED. Empty means the record is well
179
+ * formed — never that the acceptance criterion is discharged.
180
+ */
181
+ export function guardedBaselineProblems(items: readonly GuardedBaselineItem[]): string[] {
182
+ const problems: string[] = [];
183
+ for (const it of items) {
184
+ const at = `line ${it.line} (${it.label})`;
185
+ if (it.glyph === null) {
186
+ problems.push(
187
+ `${at}: the guarded-baseline annotation is not on a checkbox step — ` +
188
+ 'it is only legal on an unchecked `- [ ]` line',
189
+ );
190
+ } else if (it.glyph !== ' ') {
191
+ problems.push(
192
+ `${at}: the guarded-baseline annotation sits on \`[${it.glyph}]\` — ` +
193
+ 'the canonical checkbox stays UNCHECKED; only verification against ' +
194
+ 'the real mechanism permits `[x]`',
195
+ );
196
+ }
197
+ if (!it.hasBlock) {
198
+ problems.push(`${at}: carries no adjacent \`guarded_baseline:\` evidence block`);
199
+ }
200
+ if ((it.fields['red_proof'] ?? '') === '') {
201
+ problems.push(
202
+ `${at}: records no \`red_proof\` — a baseline that has not demonstrably ` +
203
+ 'gone RED is an ordinary open item, not a guarded one',
204
+ );
205
+ }
206
+ const category = it.fields['category'] ?? '';
207
+ if (category === '') {
208
+ problems.push(
209
+ `${at}: records no \`category\` — one of ${GUARDED_CATEGORIES.join(', ')} ` +
210
+ 'is required, and absence is not defaulted',
211
+ );
212
+ } else if (!GUARDED_CATEGORIES.includes(category)) {
213
+ problems.push(
214
+ `${at}: records category \`${category}\`, which is not one of ` +
215
+ GUARDED_CATEGORIES.join(', '),
216
+ );
217
+ }
218
+ }
219
+ return problems;
220
+ }
221
+
222
+ /**
223
+ * Which records are STALE, i.e. whose `recheck_when` trigger now resolves in the
224
+ * tree — the mechanism the baseline was written against has arrived, so the
225
+ * evidence describes a world that no longer exists.
226
+ *
227
+ * HONEST SCOPE. Only a PATH trigger is machine-checkable: a token containing `/`
228
+ * is resolved against the repo root and stale iff it exists. A bare symbol name
229
+ * cannot be decided from a path, so it is returned as `unverifiable` rather than
230
+ * silently reading as "not stale" — an unchecked trigger that looks checked is
231
+ * the failure this whole state exists to avoid.
232
+ */
233
+ export function guardedBaselineStaleness(
234
+ items: readonly GuardedBaselineItem[],
235
+ repo_root: string,
236
+ ): { stale: string[]; unverifiable: string[] } {
237
+ const stale: string[] = [];
238
+ const unverifiable: string[] = [];
239
+ for (const it of items) {
240
+ const trigger = it.fields['recheck_when'] ?? '';
241
+ if (trigger === '') {
242
+ continue;
243
+ }
244
+ for (const token of trigger.split(/[\s,]+/).filter((t) => t !== '')) {
245
+ if (!token.includes('/')) {
246
+ unverifiable.push(`line ${it.line} (${it.label}): recheck_when \`${token}\``);
247
+ } else if (fs.existsSync(path.join(repo_root, token))) {
248
+ stale.push(
249
+ `line ${it.line} (${it.label}): recheck_when \`${token}\` now exists — ` +
250
+ 're-verify against the real mechanism',
251
+ );
252
+ }
253
+ }
254
+ }
255
+ return { stale, unverifiable };
256
+ }
257
+
258
+ /** One roadmap, as the report needs it — structural, so `RoadmapStats` fits as-is. */
259
+ export interface GuardedBaselineHost {
260
+ readonly rel: string;
261
+ readonly path: string;
262
+ }
263
+
264
+ export interface GuardedBaselineReport {
265
+ /** Dashboard section, appended to the rendered markdown. `''` when nothing is annotated. */
266
+ section: string;
267
+ /** Rejections across every roadmap — `--check` must fail on these. */
268
+ problems: number;
269
+ }
270
+
271
+ /**
272
+ * Report every guarded baseline in the estate: a dashboard section, and the
273
+ * rejections + staleness on stderr. Side-effecting on purpose, and named for it
274
+ * — the sibling `_warn_merge_gated` does the same, and it keeps the caller at
275
+ * one line in a file that sits at its size cap.
276
+ */
277
+ export function reportGuardedBaselines(
278
+ roadmaps: readonly GuardedBaselineHost[],
279
+ repo_root: string,
280
+ write: (s: string) => void = (s) => process.stderr.write(s),
281
+ ): GuardedBaselineReport {
282
+ const rows: string[] = [];
283
+ let problems = 0;
284
+ for (const r of roadmaps) {
285
+ let items: GuardedBaselineItem[];
286
+ try {
287
+ items = parseGuardedBaselines(fs.readFileSync(r.path, { encoding: 'utf-8' }));
288
+ } catch {
289
+ continue;
290
+ }
291
+ if (items.length === 0) {
292
+ continue;
293
+ }
294
+ const bad = guardedBaselineProblems(items);
295
+ const { stale, unverifiable } = guardedBaselineStaleness(items, repo_root);
296
+ problems += bad.length;
297
+ rows.push(
298
+ `| [${r.rel}](roadmaps/${r.rel}) | ${items.length} | ${stale.length} | ${bad.length} |`,
299
+ );
300
+ write(
301
+ `🛡️ ${r.rel}: ${items.length} guarded-baseline step(s) — RED-proven, ` +
302
+ 'NOT complete, and blocking archival:\n',
303
+ );
304
+ for (const it of items) {
305
+ write(` - ${it.label} (category ${it.fields['category'] ?? '—'})\n`);
306
+ }
307
+ for (const p of bad) write(` ❌ ${p}\n`);
308
+ for (const s of stale) write(` ⚠️ ${s}\n`);
309
+ for (const u of unverifiable) write(` · not machine-checkable: ${u}\n`);
310
+ }
311
+ if (rows.length === 0) {
312
+ return { section: '', problems };
313
+ }
314
+ return {
315
+ section:
316
+ '\n## 🛡️ Guarded baselines — RED-proven, not complete\n\n' +
317
+ 'These steps carry `<!-- roadmap-status: guarded-baseline -->`: an ' +
318
+ 'executable guard exists and has been shown to go RED under a named ' +
319
+ 'sabotage, but the acceptance criterion names a mechanism that does not ' +
320
+ 'exist yet. They are **not** done, they are **not** counted as done, and ' +
321
+ 'they **block archival** until the real mechanism is verified (council ' +
322
+ '2026-08-31, 2/2 convergent).\n\n' +
323
+ '| Roadmap | Guarded | Stale | Rejected |\n|---|---:|---:|---:|\n' +
324
+ rows.join('\n') +
325
+ '\n',
326
+ problems,
327
+ };
328
+ }
@@ -0,0 +1,253 @@
1
+ #!/usr/bin/env tsx
2
+ /**
3
+ * The single sanctioned writer of a roadmap checkbox glyph.
4
+ *
5
+ * `road-to-skill-ecosystem-runtime-enforcement` Phase 6. Every mechanism here
6
+ * exists because of a recorded way a concurrent writer destroys work, and each
7
+ * one is listed with the failure it closes rather than as a good practice:
8
+ *
9
+ * 1. **Advisory lock + atomic rename.** Two writers read, edit and write the
10
+ * same file; the second write lands last and the first writer's step is
11
+ * gone, with no error to either. A torn write is worse still: a
12
+ * half-rewritten plan parses as a plan with fewer steps.
13
+ * 2. **Anchor on the step's OWN LINE.** A greedy multi-line pattern across a
14
+ * multi-entry file is the recorded mechanism by which one substitution
15
+ * overwrites later entries — the regex matches from the first step to the
16
+ * last and replaces everything between.
17
+ * 3. **Structural invariant against the LIVE pre-write file.** Asserting the
18
+ * step count against an in-memory snapshot confirms what you INTENDED to
19
+ * write while destroying what a parallel writer wrote in between. The
20
+ * re-read is the whole point: the file is checked at the moment of writing.
21
+ * 4. **Post-write survival check.** In a concurrent overwrite the loser gets
22
+ * no error, so a successful write is not evidence the write survived.
23
+ * Grep for the mutated step afterwards and confirm exactly one occurrence.
24
+ * 5. **Fail closed on ambiguity.** Two roadmaps in scope — one in the working
25
+ * directory, one nested — resolve NEITHER and name both. Silently choosing
26
+ * is how a step gets flipped in the wrong plan.
27
+ *
28
+ * Exit codes: 0 written · 1 refused (ambiguity, invariant, survival) · 2 usage.
29
+ */
30
+ import * as fs from 'node:fs';
31
+ import * as path from 'node:path';
32
+ import process from 'node:process';
33
+ import { fileURLToPath, pathToFileURL } from 'node:url';
34
+
35
+ const _HERE = fileURLToPath(import.meta.url);
36
+
37
+ /** The four glyphs a roadmap step may carry. */
38
+ export const GLYPHS = ['x', ' ', '~', '-'] as const;
39
+ export type Glyph = (typeof GLYPHS)[number];
40
+
41
+ /** A lock older than this is treated as abandoned. A crashed writer must not wedge the file. */
42
+ export const LOCK_STALE_MS = 60_000;
43
+
44
+ export class RoadmapWriteError extends Error {}
45
+
46
+ /** Every checkbox line in the file, as `[lineIndex, glyph, text]`. */
47
+ export function scanSteps(content: string): { line: number; glyph: string; text: string }[] {
48
+ const out: { line: number; glyph: string; text: string }[] = [];
49
+ const lines = content.split('\n');
50
+ for (let i = 0; i < lines.length; i += 1) {
51
+ const m = /^(\s*-\s\[)([ x~-])(\]\s?)(.*)$/.exec(lines[i] as string);
52
+ if (m !== null) out.push({ line: i, glyph: m[2] as string, text: m[4] as string });
53
+ }
54
+ return out;
55
+ }
56
+
57
+ /**
58
+ * Locate the ONE step whose text starts with `stepId`.
59
+ *
60
+ * Refuses on zero and on more than one. A prefix that matches two steps is an
61
+ * ambiguous address, and picking the first is the same silent-choice failure as
62
+ * resolving an ambiguous plan.
63
+ */
64
+ export function findStep(content: string, stepId: string): { line: number; glyph: string; text: string } {
65
+ const needle = stepId.trim();
66
+ if (needle === '') throw new RoadmapWriteError('step id is empty');
67
+ // Match against the raw text AND its bold-stripped form, so `**1.2` and `1.2`
68
+ // both address the same step. Stripping only ONE side is the bug this shape
69
+ // replaces: a needle carrying `**` then matched nothing at all.
70
+ const strip = (t: string): string => t.replace(/^\*\*/, '');
71
+ const hits = scanSteps(content).filter(
72
+ (s) => s.text.startsWith(needle) || strip(s.text).startsWith(strip(needle)),
73
+ );
74
+ if (hits.length === 0) {
75
+ throw new RoadmapWriteError(`no step whose text starts with "${needle}"`);
76
+ }
77
+ if (hits.length > 1) {
78
+ throw new RoadmapWriteError(
79
+ `"${needle}" matches ${String(hits.length)} steps (lines ${hits.map((h) => h.line + 1).join(', ')}) — ` +
80
+ 'refusing rather than picking the first. Give a longer prefix.',
81
+ );
82
+ }
83
+ return hits[0]!;
84
+ }
85
+
86
+ /**
87
+ * Rewrite ONE line's glyph. Line-anchored by construction: the function is given
88
+ * a line index and touches only `lines[index]`, so there is no pattern that can
89
+ * span entries even in principle.
90
+ */
91
+ export function setGlyphOnLine(content: string, lineIndex: number, glyph: Glyph): string {
92
+ const lines = content.split('\n');
93
+ const line = lines[lineIndex];
94
+ if (line === undefined) throw new RoadmapWriteError(`line ${String(lineIndex)} is out of range`);
95
+ const m = /^(\s*-\s\[)([ x~-])(\].*)$/.exec(line);
96
+ if (m === null) throw new RoadmapWriteError(`line ${String(lineIndex + 1)} is not a checkbox line`);
97
+ lines[lineIndex] = `${m[1]}${glyph}${m[3]}`;
98
+ return lines.join('\n');
99
+ }
100
+
101
+ /** Acquire an advisory lock, or throw. `O_EXCL` is the exclusion; the mtime is the staleness clock. */
102
+ export function acquireLock(file: string, nowMs = Date.now()): string {
103
+ const lock = `${file}.lock`;
104
+ try {
105
+ fs.writeFileSync(lock, `${String(process.pid)}\n`, { flag: 'wx' });
106
+ return lock;
107
+ } catch {
108
+ let age = 0;
109
+ try {
110
+ age = nowMs - fs.statSync(lock).mtimeMs;
111
+ } catch {
112
+ // The holder released it between our failed create and this stat —
113
+ // retry once rather than reporting a lock that no longer exists.
114
+ fs.writeFileSync(lock, `${String(process.pid)}\n`, { flag: 'wx' });
115
+ return lock;
116
+ }
117
+ if (age > LOCK_STALE_MS) {
118
+ // A crashed writer must not wedge the file forever. Breaking a stale
119
+ // lock is safe precisely because every write below re-validates the
120
+ // live file — the lock reduces collisions, it does not carry
121
+ // correctness on its own.
122
+ fs.rmSync(lock, { force: true });
123
+ fs.writeFileSync(lock, `${String(process.pid)}\n`, { flag: 'wx' });
124
+ return lock;
125
+ }
126
+ throw new RoadmapWriteError(
127
+ `${path.basename(file)} is locked by another writer (${String(Math.round(age / 1000))}s old) — refusing`,
128
+ );
129
+ }
130
+ }
131
+
132
+ export interface SetStepResult {
133
+ file: string;
134
+ line: number;
135
+ from: string;
136
+ to: Glyph;
137
+ stepsBefore: number;
138
+ stepsAfter: number;
139
+ }
140
+
141
+ /**
142
+ * Flip one step's glyph, safely.
143
+ *
144
+ * The ordering is the contract: lock → RE-READ → locate → invariant → write →
145
+ * survival check → unlock. The re-read after the lock is what makes the
146
+ * invariant meaningful; checking a snapshot taken before the lock would confirm
147
+ * an intention rather than a fact.
148
+ */
149
+ export function setStep(file: string, stepId: string, glyph: Glyph, nowMs = Date.now()): SetStepResult {
150
+ const lock = acquireLock(file, nowMs);
151
+ try {
152
+ // LIVE read, inside the lock. Any snapshot taken earlier is stale by
153
+ // definition — a parallel writer may have landed between then and now.
154
+ const before = fs.readFileSync(file, 'utf8');
155
+ const stepsBefore = scanSteps(before).length;
156
+ const target = findStep(before, stepId);
157
+ const after = setGlyphOnLine(before, target.line, glyph);
158
+
159
+ const stepsAfter = scanSteps(after).length;
160
+ if (stepsAfter !== stepsBefore) {
161
+ throw new RoadmapWriteError(
162
+ `structural invariant failed: ${String(stepsBefore)} step(s) before, ${String(stepsAfter)} after. ` +
163
+ 'A glyph flip may not change the step count — this is the signature of a pattern ' +
164
+ 'that spanned entries.',
165
+ );
166
+ }
167
+
168
+ const tmp = `${file}.${String(process.pid)}.tmp`;
169
+ fs.writeFileSync(tmp, after, 'utf8');
170
+ fs.renameSync(tmp, file);
171
+
172
+ // SURVIVAL, not success. In a concurrent overwrite the loser receives no
173
+ // error, so the write returning is not evidence the write is on disk.
174
+ const verify = fs.readFileSync(file, 'utf8');
175
+ const survivors = scanSteps(verify).filter(
176
+ (s) => s.line === target.line && s.glyph === glyph && s.text === target.text,
177
+ );
178
+ if (survivors.length !== 1) {
179
+ throw new RoadmapWriteError(
180
+ `write did not survive: expected exactly 1 occurrence of the mutated step, found ` +
181
+ `${String(survivors.length)}. A parallel writer very likely landed after ours.`,
182
+ );
183
+ }
184
+ return { file, line: target.line + 1, from: target.glyph, to: glyph, stepsBefore, stepsAfter };
185
+ } finally {
186
+ fs.rmSync(lock, { force: true });
187
+ }
188
+ }
189
+
190
+ /**
191
+ * Resolve the roadmap to write, FAILING CLOSED on ambiguity.
192
+ *
193
+ * When the working directory carries an active roadmap and a nested directory
194
+ * carries its own, neither is resolved and both are named. Choosing silently is
195
+ * how a step gets flipped in the wrong plan — and the wrong plan's author gets
196
+ * no signal at all.
197
+ */
198
+ export function resolvePlan(roots: readonly string[]): string {
199
+ const found: string[] = [];
200
+ for (const root of roots) {
201
+ const dir = path.join(root, 'agents', 'roadmaps');
202
+ if (!fs.existsSync(dir)) continue;
203
+ for (const name of fs.readdirSync(dir)) {
204
+ if (name.endsWith('.md') && name !== 'README.md') found.push(path.join(dir, name));
205
+ }
206
+ }
207
+ if (found.length === 0) throw new RoadmapWriteError('no active roadmap found under any candidate root');
208
+ if (found.length > 1) {
209
+ throw new RoadmapWriteError(
210
+ `ambiguous plan — ${String(found.length)} active roadmaps in scope:\n ${found.join('\n ')}\n` +
211
+ 'Refusing to choose. Name the file explicitly with --file.',
212
+ );
213
+ }
214
+ return found[0]!;
215
+ }
216
+
217
+ export function main(argv: string[] = process.argv.slice(2)): number {
218
+ const usage =
219
+ 'usage: roadmap_set_step --file <roadmap.md> --step <id-prefix> --glyph <x| |~|->\n' +
220
+ ' Refuses on: an ambiguous step prefix, a changed step count, a write that did not survive.\n';
221
+ if (argv.includes('-h') || argv.includes('--help')) {
222
+ process.stdout.write(usage);
223
+ return 0;
224
+ }
225
+ const val = (flag: string): string | null => {
226
+ const i = argv.indexOf(flag);
227
+ return i !== -1 && i + 1 < argv.length ? (argv[i + 1] as string) : null;
228
+ };
229
+ const file = val('--file');
230
+ const step = val('--step');
231
+ const glyph = val('--glyph');
232
+ if (file === null || step === null || glyph === null || !(GLYPHS as readonly string[]).includes(glyph)) {
233
+ process.stderr.write(`roadmap_set_step: error: --file, --step and a valid --glyph are required\n${usage}`);
234
+ return 2;
235
+ }
236
+ try {
237
+ const r = setStep(path.resolve(file), step, glyph as Glyph);
238
+ process.stdout.write(
239
+ `✅ ${path.basename(r.file)}:${String(r.line)} [${r.from}] → [${r.to}] · ` +
240
+ `${String(r.stepsAfter)} step(s) intact\n`,
241
+ );
242
+ return 0;
243
+ } catch (e) {
244
+ process.stderr.write(`❌ ${e instanceof Error ? e.message : String(e)}\n`);
245
+ return e instanceof RoadmapWriteError ? 1 : 2;
246
+ }
247
+ }
248
+
249
+ /* c8 ignore start */
250
+ if (process.argv[1] !== undefined && pathToFileURL(path.resolve(process.argv[1])).href === pathToFileURL(_HERE).href) {
251
+ process.exit(main());
252
+ }
253
+ /* c8 ignore stop */
@@ -0,0 +1,82 @@
1
+ /**
2
+ * The parked estate's two integers, for the dashboard header.
3
+ *
4
+ * `road-to-inbox-harvest-2026-08-f-owner-decision-queue` Phase 2.3. Split out of
5
+ * `update_roadmap_progress.ts` rather than left inline, and the reason is
6
+ * mechanical: that file is past the 1500-line ceiling
7
+ * `check_source_size_budget` charges, so lines added to it are paid back by
8
+ * extraction rather than by a baseline bump.
9
+ *
10
+ * **Two integers are not an inventory.** No row, no link, nothing to conflict
11
+ * on — which is exactly the distinction that keeps this clear of the 2026-08-21
12
+ * council verdict that deleted the hand-maintained index in `stubs/README.md`,
13
+ * and of `check_no_stub_inventory_table`, which refuses its return.
14
+ *
15
+ * The dashboard excludes `stubs/` on purpose and that does not change. What was
16
+ * missing is that a maintainer had no way to learn a stub had gone unread
17
+ * without listing the directory.
18
+ */
19
+ import * as fs from 'node:fs';
20
+ import * as path from 'node:path';
21
+
22
+ /** Frontmatter block, matching the parent script's own pattern. */
23
+ const FRONTMATTER_RE = /^---\n([\s\S]*?)\n---[ \t\n\r\f\v]*\n/;
24
+
25
+ /**
26
+ * Phrases that mean "a person has to decide this".
27
+ *
28
+ * A literal list, never a heuristic: a general "looks like a decision" match
29
+ * would count every stub that mentions the word, and a count that over-reports
30
+ * is a count nobody trusts twice. Kept in sync with `stubs_due.ts` by the test
31
+ * that asserts both readers agree on the same corpus.
32
+ */
33
+ const OWNER_ROUTING = [
34
+ 'owner-reserved',
35
+ 'owner reserved',
36
+ 'owner: maintainer',
37
+ 'reserved to the owner',
38
+ 'requires owner',
39
+ 'maintainer decision',
40
+ 'owner decision',
41
+ 'owner sign-off',
42
+ 'awaiting the owner',
43
+ ];
44
+
45
+ /**
46
+ * Count overdue stubs and stubs routing a decision to a person.
47
+ *
48
+ * Returns `null` on any failure — a dashboard is not the place to surface a
49
+ * parse error, and an absent `stubs/` directory in a consumer install is normal
50
+ * rather than a fault. `today` is a parameter so the count is testable.
51
+ */
52
+ export function stub_queue_counts(
53
+ roadmap_root: string,
54
+ today: string = new Date().toISOString().slice(0, 10),
55
+ ): { overdue: number; owner: number } | null {
56
+ const dir = path.join(roadmap_root, 'stubs');
57
+ let names: string[];
58
+ try {
59
+ names = fs.readdirSync(dir).filter((n) => n.endsWith('.md') && n !== 'README.md');
60
+ } catch {
61
+ return null;
62
+ }
63
+ if (names.length === 0) return null;
64
+ let overdue = 0;
65
+ let owner = 0;
66
+ for (const n of names) {
67
+ let source: string;
68
+ try {
69
+ source = fs.readFileSync(path.join(dir, n), 'utf-8');
70
+ } catch {
71
+ continue;
72
+ }
73
+ const fm = FRONTMATTER_RE.exec(source);
74
+ const due = /^review_by:\s*(\d{4}-\d{2}-\d{2})\s*$/m.exec(fm?.[1] ?? '');
75
+ // An ABSENT date counts as overdue: the contract requires it, so missing
76
+ // means nobody scheduled a read — the state the count exists to surface.
77
+ if (due === null || (due[1] as string) <= today) overdue += 1;
78
+ const lower = source.toLowerCase();
79
+ if (OWNER_ROUTING.some((phrase) => lower.includes(phrase))) owner += 1;
80
+ }
81
+ return { overdue, owner };
82
+ }