@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,299 @@
1
+ /**
2
+ * Guards for a harness-enforced bounded loop.
3
+ *
4
+ * `road-to-skill-ecosystem-runtime-enforcement` Phase 5, Steps 2-4. Three
5
+ * primitives the stop-event loop needs and did not have, each closing a failure
6
+ * that is invisible while it happens.
7
+ *
8
+ * Extracted rather than added to `run_continuation_hook.ts`: that file is 1,504
9
+ * lines and `check_source_size_budget` charges every line above 1,500, so the
10
+ * same code there would cost a budget it does not cost here. The seam also makes
11
+ * all three testable without a host payload.
12
+ */
13
+ import * as fs from 'node:fs';
14
+ import * as path from 'node:path';
15
+
16
+ /**
17
+ * Write JSON atomically: temp file in the same directory, then rename.
18
+ *
19
+ * WHY THIS IS NOT A STYLE CHOICE. The file being written is the loop's
20
+ * ITERATION BUDGET. A direct `writeFileSync` that is interrupted — a crash, a
21
+ * full disk, a killed process — leaves a truncated file, the parser rejects it,
22
+ * and the loop reads "no state": the counter restarts at zero and **the cap
23
+ * stops bounding anything**. The failure mode of a non-atomic budget write is an
24
+ * unbounded loop, which is the exact thing the budget exists to prevent.
25
+ *
26
+ * Same directory for the temp file because `rename` is only atomic within a
27
+ * filesystem; a temp in `/tmp` can land on another one and degrade to copy+unlink.
28
+ *
29
+ * Never throws — a budget writer that throws turns an observability concern into
30
+ * a turn-end failure. Returns whether the write landed, and that return is
31
+ * load-bearing: a loop that could not persist its counter must not BLOCK,
32
+ * because there the ladder cannot bound it.
33
+ */
34
+ export function atomicWriteJson(file: string, value: unknown): boolean {
35
+ const tmp = `${file}.${String(process.pid)}.tmp`;
36
+ try {
37
+ fs.mkdirSync(path.dirname(file), { recursive: true });
38
+ fs.writeFileSync(tmp, `${JSON.stringify(value)}\n`, 'utf8');
39
+ fs.renameSync(tmp, file);
40
+ return true;
41
+ } catch {
42
+ try {
43
+ fs.unlinkSync(tmp);
44
+ } catch {
45
+ /* the temp may never have been created; nothing to clean */
46
+ }
47
+ return false;
48
+ }
49
+ }
50
+
51
+ /**
52
+ * Whole-LINE match against a marker — never a substring.
53
+ *
54
+ * The hazard is specific and cheap to hit: a transcript contains everything the
55
+ * agent said, INCLUDING quoted examples of the marker. A substring match lets a
56
+ * sentence like *"exit when you print RUN-COMPLETE"* terminate the run, and — the
57
+ * worse direction — lets a quoted marker inside a code fence extend one.
58
+ *
59
+ * Trailing whitespace is trimmed because a terminal or a JSON round-trip adds it;
60
+ * leading whitespace is trimmed for the same reason. Nothing ELSE on the line is
61
+ * tolerated: `RUN-COMPLETE (probably)` is not the marker.
62
+ */
63
+ export function matchesWholeLine(text: string, marker: string): boolean {
64
+ if (marker === '') return false;
65
+ for (const line of text.split('\n')) {
66
+ if (line.trim() === marker) return true;
67
+ }
68
+ return false;
69
+ }
70
+
71
+ /** A dependency the loop cannot obtain, and therefore cannot iterate toward. */
72
+ export interface UnavailableDependency {
73
+ kind: 'credential' | 'binary' | 'permission' | 'quota' | 'service';
74
+ evidence: string;
75
+ }
76
+
77
+ /**
78
+ * Patterns that name a dependency the loop CANNOT close by trying again.
79
+ *
80
+ * Every entry corresponds to a hard-blocker class the rules already name
81
+ * (`context-hygiene` § hard-blocker classes). The list is deliberately short and
82
+ * literal: a general "looks like an error" heuristic would end runs on ordinary
83
+ * test failures, which is the opposite of the intent — those are exactly what a
84
+ * loop SHOULD iterate on.
85
+ */
86
+ const DEPENDENCY_PATTERNS: readonly { kind: UnavailableDependency['kind']; re: RegExp }[] = [
87
+ { kind: 'binary', re: /\b(?:command not found|is not recognized as an internal or external command)\b/i },
88
+ { kind: 'credential', re: /\b(?:not (?:authenticated|logged in)|authentication (?:failed|required)|no credentials found)\b/i },
89
+ { kind: 'credential', re: /\b(?:missing|unset|not set)\b[^\n]{0,40}\b(?:credential|token|api[_ -]?key|secret)\b/i },
90
+ { kind: 'permission', re: /\b(?:permission denied|forbidden|403 forbidden)\b/i },
91
+ { kind: 'quota', re: /\b(?:rate limit(?:ed| exceeded| reached)?|quota exceeded|429 too many requests|spend (?:cap|limit) reached)\b/i },
92
+ { kind: 'service', re: /\b(?:5\d\d (?:internal )?server error|service unavailable|connection refused)\b/i },
93
+ ];
94
+
95
+ /**
96
+ * How much of the transcript tail a caller should read before scanning it.
97
+ *
98
+ * The detector takes text, not a file, so the BYTE bound belongs to the read
99
+ * and the LINE bound (`tailLines`) belongs to the scan. Both exist and they
100
+ * bound different things: 64 KiB keeps an arbitrarily long transcript from
101
+ * being loaded whole, and the line count then keeps a stale failure from
102
+ * halting a run that already recovered.
103
+ *
104
+ * Exported rather than inlined at the one call site so the bound is visible
105
+ * beside the detector it feeds. A caller that reads the whole file and then
106
+ * passes it here is not wrong, only wasteful — the line bound still applies.
107
+ */
108
+ export const DEPENDENCY_SCAN_BYTES = 64 * 1024;
109
+
110
+ /**
111
+ * Find a dependency the run cannot obtain, from recent transcript text.
112
+ *
113
+ * Returns the FIRST match with the line that produced it, so a halt event can
114
+ * name what is missing instead of saying "blocked". A halt with no named
115
+ * dependency is a report the reader has to reconstruct.
116
+ *
117
+ * Scans the LAST `tailLines` lines only: an authentication failure from an hour
118
+ * ago that was then fixed must not halt the run now, and a transcript is
119
+ * append-only so recency is the whole signal.
120
+ */
121
+ export function detectUnavailableDependency(
122
+ transcriptTail: string,
123
+ tailLines = 200,
124
+ ): UnavailableDependency | null {
125
+ const lines = transcriptTail.split('\n');
126
+ const window = lines.slice(Math.max(0, lines.length - tailLines));
127
+ for (const line of window) {
128
+ for (const { kind, re } of DEPENDENCY_PATTERNS) {
129
+ if (re.test(line)) {
130
+ return { kind, evidence: line.trim().slice(0, 200) };
131
+ }
132
+ }
133
+ }
134
+ return null;
135
+ }
136
+
137
+ /**
138
+ * The machine-readable stall signal, derived from a run's open-step history.
139
+ *
140
+ * `road-to-skill-ecosystem-runtime-enforcement` Phase 6 Step 6, and it is what
141
+ * makes Phase 4's progress-primary ordering usable rather than aspirational: a
142
+ * consumer asking "is this run still making progress" had to re-derive the
143
+ * answer from a history array and a window constant, so every reader could
144
+ * derive it differently.
145
+ *
146
+ * Three levels rather than a boolean, because the ordering they enable is
147
+ * different:
148
+ *
149
+ * `progressing` — the newest reading is a NEW MINIMUM. This is the primary
150
+ * signal Phase 4 names: the budget may keep running.
151
+ * `flat` — no new minimum, but the window is not yet full or not yet
152
+ * uniform. Not stalled; simply not evidence of progress either.
153
+ * `stalled` — a full window of IDENTICAL readings. More of the same will
154
+ * not help, and raising the budget is the WRONG response — which is exactly
155
+ * what separates `stagnated` from `exhausted` in the terminal-state
156
+ * vocabulary.
157
+ *
158
+ * Pure over the history array, so a reader and the ladder cannot disagree.
159
+ */
160
+ export type StallLevel = 'progressing' | 'flat' | 'stalled';
161
+
162
+ export interface StallSignal {
163
+ level: StallLevel;
164
+ /** How many of the most recent readings are identical. */
165
+ flatRun: number;
166
+ /** The lowest reading seen, i.e. the best progress this run has made. */
167
+ minimum: number | null;
168
+ /** True when the LAST reading equals the minimum and is strictly below the one before it. */
169
+ newMinimum: boolean;
170
+ }
171
+
172
+ export function stallSignal(history: readonly number[], window = 3): StallSignal {
173
+ if (history.length === 0) {
174
+ return { level: 'flat', flatRun: 0, minimum: null, newMinimum: false };
175
+ }
176
+ const last = history[history.length - 1] as number;
177
+ const minimum = Math.min(...history);
178
+ // Strictly below every EARLIER reading — not merely below the one before it.
179
+ // The weaker form calls a return to an already-reached minimum progress, so an
180
+ // oscillating run (5, 9, 5, 9, …) would look like it was advancing forever
181
+ // while closing nothing.
182
+ const earlier = history.slice(0, -1);
183
+ const newMinimum = earlier.length > 0 && last < Math.min(...earlier);
184
+
185
+ let flatRun = 1;
186
+ for (let i = history.length - 2; i >= 0; i -= 1) {
187
+ if (history[i] !== last) break;
188
+ flatRun += 1;
189
+ }
190
+ if (newMinimum) return { level: 'progressing', flatRun, minimum, newMinimum };
191
+ if (flatRun >= window) return { level: 'stalled', flatRun, minimum, newMinimum };
192
+ return { level: 'flat', flatRun, minimum, newMinimum };
193
+ }
194
+
195
+ /**
196
+ * Read the transcript tail and name a dependency the run cannot obtain.
197
+ *
198
+ * Lives here rather than at the call site, beside the detector and the byte
199
+ * bound it uses. EXPORTED so the wiring is testable,
200
+ * which is the half that was actually broken: the inline version referenced a
201
+ * constant that did not exist, and because the read sits inside a `catch`
202
+ * that fail-opens to `null`, the ReferenceError was swallowed on every fire.
203
+ * The rung was dead and every pure `ladder()` test stayed green — a test over
204
+ * the decision function cannot see a caller that never computes the input.
205
+ *
206
+ * Fail-open is deliberate and unchanged: a detector that cannot read must not
207
+ * manufacture a halt. What changed is that "cannot read" is now the only way
208
+ * to reach `null` by accident.
209
+ */
210
+ export function readUnavailableDependency(transcriptPath: string): UnavailableDependency | null {
211
+ try {
212
+ const raw = fs.readFileSync(transcriptPath, 'utf8');
213
+ return detectUnavailableDependency(raw.slice(-DEPENDENCY_SCAN_BYTES));
214
+ } catch {
215
+ return null;
216
+ }
217
+ }
218
+
219
+ // ---------------------------------------------------------------------------
220
+ // Rejected-tactic repetition
221
+ // ---------------------------------------------------------------------------
222
+
223
+ /**
224
+ * Window and threshold for the repetition guard.
225
+ *
226
+ * Named constants, NOT a settings block. A configurable strategy preset is the
227
+ * shape this roadmap kills by name: presets multiply the states a reader has to
228
+ * reason about while the underlying question — "is this run going in circles?" —
229
+ * has one answer. Two numbers with a stated meaning are auditable; a tuning
230
+ * surface is not.
231
+ */
232
+ export const SUPPRESSION_WINDOW = 8;
233
+ export const SUPPRESSION_REPEATS = 3;
234
+
235
+ /**
236
+ * One attempt the run has already made, reduced to what a detector may see.
237
+ *
238
+ * `tactic_id` is ID-SHAPED and that is the load-bearing property. `stallSignal`
239
+ * above keys on a NUMBER (the open-step count); this keys on an identity. The
240
+ * failure it catches is one the numeric detector cannot see at all: an agent
241
+ * that retries the same rejected approach while the surrounding prose changes
242
+ * every time. The open-step count moves, the wording moves, and the tactic is
243
+ * identical.
244
+ */
245
+ export interface TacticAttempt {
246
+ /** Stable id for the approach tried. Lowercase alnum + hyphens; never prose. */
247
+ tactic_id: string;
248
+ /** Whether this attempt was rejected (by a gate, a test, a review, a human). */
249
+ rejected: boolean;
250
+ }
251
+
252
+ export interface RepetitionSignal {
253
+ /** True when a rejected tactic has recurred at or above the threshold in-window. */
254
+ suppress: boolean;
255
+ /** The tactic that tripped it, or `null`. */
256
+ tactic_id: string | null;
257
+ /** How many rejected attempts of that tactic are in the window. */
258
+ repeats: number;
259
+ }
260
+
261
+ /**
262
+ * Has the run repeated a tactic that was already rejected?
263
+ *
264
+ * Counts only REJECTED attempts. A tactic tried three times and accepted twice
265
+ * is not a loop, it is a tactic that works — counting every attempt would fire
266
+ * on productive repetition, which is the false positive that gets a guard
267
+ * switched off.
268
+ *
269
+ * Deliberately blind to any signal string. The verify line this satisfies asks
270
+ * for suppression "even when the signal string differs", which is only
271
+ * achievable by keying on something else — so this function is given no text to
272
+ * read, rather than being trusted to ignore it.
273
+ */
274
+ export function rejectedTacticRepeat(
275
+ history: readonly TacticAttempt[],
276
+ window: number = SUPPRESSION_WINDOW,
277
+ threshold: number = SUPPRESSION_REPEATS,
278
+ ): RepetitionSignal {
279
+ const recent = history.slice(-window);
280
+ const counts = new Map<string, number>();
281
+ for (const a of recent) {
282
+ if (!a.rejected) continue;
283
+ counts.set(a.tactic_id, (counts.get(a.tactic_id) ?? 0) + 1);
284
+ }
285
+
286
+ let worst: string | null = null;
287
+ let worstCount = 0;
288
+ for (const [id, n] of counts) {
289
+ if (n > worstCount) {
290
+ worst = id;
291
+ worstCount = n;
292
+ }
293
+ }
294
+
295
+ if (worst !== null && worstCount >= threshold) {
296
+ return { suppress: true, tactic_id: worst, repeats: worstCount };
297
+ }
298
+ return { suppress: false, tactic_id: null, repeats: worstCount };
299
+ }
@@ -0,0 +1,129 @@
1
+ /**
2
+ * Loss classes — names for what the tree already does, before they constrain
3
+ * what comes next (`road-to-runtime-context-floors` Phase 3).
4
+ *
5
+ * The tree already practises loss classes implicitly and has for a while:
6
+ * `fold_intake` folds intake batches into an ADDITIVE archive page with
7
+ * per-child link-backs and never mutates the children, and `hot_context_hook`
8
+ * deliberately DROPS lines the low-impact redactor refuses, unrecoverably, for
9
+ * privacy. Those are two different guarantees wearing the same word
10
+ * "compression", and nothing distinguished them.
11
+ *
12
+ * So the vocabulary is written AGAINST those two first, and checked against
13
+ * their own source docblocks, before any lint exists to fail on anything.
14
+ *
15
+ * THE FIVE CLASSES, each defined by the recovery it guarantees:
16
+ *
17
+ * exact output is byte-identical to input; nothing is lost
18
+ * lossless output differs but the input is fully reconstructible
19
+ * from the output alone
20
+ * recoverable-lossy output is smaller and the original is retrievable via a
21
+ * declared RECOVERY LOCATOR (a path, a range, an id)
22
+ * ephemeral-lossy output is smaller and the dropped content is gone —
23
+ * deliberately, and the deliberateness is the point
24
+ * forbidden this transform must not run on this path at all
25
+ *
26
+ * `recoverable-lossy` is the only class that owes a locator, and it owes one
27
+ * because without it the class is indistinguishable from `ephemeral-lossy` by
28
+ * anything except its author's intention.
29
+ */
30
+
31
+ export const LOSS_CLASSES = ['exact', 'lossless', 'recoverable-lossy', 'ephemeral-lossy', 'forbidden'] as const;
32
+ export type LossClass = (typeof LOSS_CLASSES)[number];
33
+
34
+ export function isLossClass(v: unknown): v is LossClass {
35
+ return typeof v === 'string' && (LOSS_CLASSES as readonly string[]).includes(v);
36
+ }
37
+
38
+ export interface LossDeclaration {
39
+ lossClass: LossClass;
40
+ /** Where the original is retrievable. Required for `recoverable-lossy`. */
41
+ recovery: string | null;
42
+ }
43
+
44
+ export type DeclarationProblem =
45
+ | { kind: 'missing' }
46
+ | { kind: 'unknown-class'; value: string }
47
+ | { kind: 'missing-recovery' };
48
+
49
+ /**
50
+ * Read a declaration out of a module's own source.
51
+ *
52
+ * The declaration lives in a docblock, not in a sidecar registry, deliberately:
53
+ * a class describes what THIS code does to its input, and a registry entry
54
+ * beside it is a second statement that can drift from the first. Shape:
55
+ *
56
+ * loss_class: recoverable-lossy
57
+ * loss_recovery: agents/knowledge/intake/<file>:<first-line>-<last-line>
58
+ */
59
+ export function parseLossDeclaration(source: string): LossDeclaration | DeclarationProblem {
60
+ // `[A-Za-z_-]+`, not `[A-Za-z-]+`: an underscore misspelling
61
+ // (`recoverable_lossy`) must be reported as `unknown-class`, not fall
62
+ // through to `missing`. Both reject, so the exit code is the same — but
63
+ // "declares no loss_class" sends an author who declared one hunting the
64
+ // wrong defect, which is the failure a diagnostic exists to prevent.
65
+ const cls = /^[\s*/]*loss_class:\s*([A-Za-z_-]+)\s*$/m.exec(source);
66
+ if (cls === null) return { kind: 'missing' };
67
+ const value = (cls[1] ?? '').trim();
68
+ if (!isLossClass(value)) return { kind: 'unknown-class', value };
69
+
70
+ const rec = /^[\s*/]*loss_recovery:\s*(\S.*?)\s*$/m.exec(source);
71
+ const recovery = rec === null ? null : (rec[1] ?? '').trim();
72
+ if (value === 'recoverable-lossy' && (recovery === null || recovery.length === 0)) {
73
+ return { kind: 'missing-recovery' };
74
+ }
75
+ return { lossClass: value, recovery };
76
+ }
77
+
78
+ export function isProblem(v: LossDeclaration | DeclarationProblem): v is DeclarationProblem {
79
+ return 'kind' in v;
80
+ }
81
+
82
+ // -------------------------------------------------------- passthrough (3.3)
83
+
84
+ /** Why a transform declined to transform. Never `null` on a passthrough. */
85
+ export type PassthroughReason = 'unparseable-input' | 'recovery-unavailable' | 'not-smaller';
86
+
87
+ export interface TransformOutcome {
88
+ output: string;
89
+ /** `null` when the transform actually ran. */
90
+ passthrough: PassthroughReason | null;
91
+ }
92
+
93
+ export interface TransformHooks {
94
+ /** Returns the shortened form, or `null` when the input cannot be parsed. */
95
+ transform: (input: string) => string | null;
96
+ /**
97
+ * Persist the recovery for `recoverable-lossy`. Returns `false` when the
98
+ * recovery cannot be stored. Omit for classes that owe no recovery.
99
+ */
100
+ storeRecovery?: (input: string) => boolean;
101
+ }
102
+
103
+ /**
104
+ * The passthrough invariant.
105
+ *
106
+ * > A transform that cannot parse its input, cannot store the recovery, or does
107
+ * > not make the input smaller returns the input unchanged.
108
+ *
109
+ * Degradation is never silent and never lossy. The two halves matter equally and
110
+ * are easy to get half-right: returning a partial parse is lossy degradation;
111
+ * returning the input while reporting success is silent degradation. This helper
112
+ * returns the input bytes AND the reason, so a caller cannot have one without the
113
+ * other.
114
+ *
115
+ * The `not-smaller` branch is the one that looks pedantic and is not. A
116
+ * "compression" that grew the input has paid the cost of the transform, lost
117
+ * whatever the transform dropped, and bought nothing — keeping the original is
118
+ * strictly better on every axis, so there is no case in which emitting the
119
+ * larger output is right.
120
+ */
121
+ export function applyTransform(input: string, hooks: TransformHooks): TransformOutcome {
122
+ const out = hooks.transform(input);
123
+ if (out === null) return { output: input, passthrough: 'unparseable-input' };
124
+ if (hooks.storeRecovery !== undefined && !hooks.storeRecovery(input)) {
125
+ return { output: input, passthrough: 'recovery-unavailable' };
126
+ }
127
+ if (out.length >= input.length) return { output: input, passthrough: 'not-smaller' };
128
+ return { output: out, passthrough: null };
129
+ }
@@ -0,0 +1,51 @@
1
+ /**
2
+ * Did a human type this turn?
3
+ *
4
+ * ```
5
+ * UNKNOWN ANSWERS YES. AN UNRECOGNISED PAYLOAD FALLS BACK TO TREATING THE TURN
6
+ * AS HUMAN — NEVER TO TREATING IT AS MACHINE. EVERY CONSUMER OF THIS PREDICATE
7
+ * GUARDS A PER-TURN RECORD, AND A RECORD WRONGLY RETAINED OUTLIVES THE TURN
8
+ * THAT AUTHORISED IT.
9
+ * ```
10
+ *
11
+ * **Why this lives in `_lib` rather than in one hook.** The misclassification is
12
+ * a property of the `user_prompt_submit` SLOT, not of any one concern: the host
13
+ * delivers a background task notification on the same slot as a typed prompt,
14
+ * so every concern that consumes or replaces per-turn state has the same defect.
15
+ * Two are known — the git-authorization ledger with its pending-refusal record,
16
+ * and the suggestion-capture latch. A predicate private to one of them would
17
+ * have repaired one and left the other, which is risk 4 of
18
+ * `road-to-turn-bound-authorization-integrity`.
19
+ *
20
+ * **The discriminator, quoted from a captured payload rather than from
21
+ * documentation.** `agents/runtime/.agent-chat-history` records prompts tagged
22
+ * `"source": "hook:claude:UserPromptSubmit"` — what the hook RECEIVED, not what
23
+ * the host stored in its transcript, and those are not guaranteed to be the same
24
+ * text. Measured 2026-08-27 in this project's capture: **9 of 16** hook-sourced
25
+ * user records begin with the literal `<task-notification>`, carrying
26
+ * `<task-id>`, `<tool-use-id>`, `<status>` and `<summary>` children. A typed
27
+ * turn carries none of them.
28
+ *
29
+ * **Prefix, not substring, and that is the whole care in this file.** A
30
+ * notification is a synthetic turn the host constructs, so the element opens it.
31
+ * Matching anywhere in the text would make the question "why did this
32
+ * `<task-notification>` clear my authorization?" clear it again — the user would
33
+ * lose the very turn they were asking about.
34
+ */
35
+
36
+ /** Wake shapes the host delivers on `user_prompt_submit` that no human typed. */
37
+ export const MACHINE_WAKE_PREFIXES: readonly string[] = [
38
+ '<task-notification>',
39
+ '<system-reminder>',
40
+ ];
41
+
42
+ /** @see MACHINE_WAKE_PREFIXES — unknown shapes answer `true`, deliberately. */
43
+ export function humanTypedThisTurn(prompt: string): boolean {
44
+ const head = prompt.trimStart();
45
+ for (const prefix of MACHINE_WAKE_PREFIXES) {
46
+ if (head.startsWith(prefix)) {
47
+ return false;
48
+ }
49
+ }
50
+ return true;
51
+ }
@@ -0,0 +1,177 @@
1
+ /**
2
+ * Shared markdown line classifier — the frontmatter / fence / indented-code /
3
+ * marker skip machinery that decides which lines of a `.md` file are PROSE.
4
+ *
5
+ * ## Why this exists
6
+ *
7
+ * `check_md_language.ts` has carried this machinery since it was ported from
8
+ * Python (ADR-200), and its CLI contract is pinned byte-for-byte. When
9
+ * `road-to-canonical-terms` 2.2 called for a second prose-scanning gate it said
10
+ * explicitly: reuse that machinery "rather than a second copy of it". A second
11
+ * copy is how two gates end up disagreeing about what a fence is — one of them
12
+ * flags a word inside a code block and the other does not, and nobody can say
13
+ * which is right because there is no single definition to consult.
14
+ *
15
+ * So the classifier moved here verbatim and both callers read it. The
16
+ * behaviour is unchanged on purpose: `check_md_language`'s test suite pins the
17
+ * exact finding list, and this extraction is a refactor that must not move it.
18
+ *
19
+ * ## What counts as a skip, and what does not
20
+ *
21
+ * - **frontmatter** — a `---` fence opening on line 1 and everything to its close.
22
+ * - **fence** — ``` or ~~~ toggles, and every line between them. The fence
23
+ * markers themselves are skipped too.
24
+ * - **indented-code** — four leading spaces on a line that does not start a
25
+ * list item. Markdown's indented-code rule, with the list carve-out this
26
+ * tree's own deeply-nested bullets need.
27
+ * - **marker** — a caller-supplied per-line opt-out (`<!-- x: ignore -->`) or a
28
+ * labelled bilingual anchor. Callers pass their own patterns; the module has
29
+ * no opinion about which markers exist.
30
+ *
31
+ * Everything else is prose, and prose carries `text` with inline code spans
32
+ * blanked out — because a word named inside backticks is being QUOTED, not used.
33
+ */
34
+
35
+ /** What a classifier pass decided about one line. */
36
+ export type MarkdownLineKind =
37
+ | 'frontmatter'
38
+ | 'fence'
39
+ | 'indented-code'
40
+ | 'marker'
41
+ | 'prose';
42
+
43
+ export interface MarkdownLine {
44
+ /** 1-based line number, matching every editor and every gate message. */
45
+ lineno: number;
46
+ /** The line exactly as it appears in the file. */
47
+ raw: string;
48
+ kind: MarkdownLineKind;
49
+ /**
50
+ * Scannable text — the raw line with inline code spans removed. Only
51
+ * meaningful when `kind === 'prose'`; empty string otherwise.
52
+ */
53
+ text: string;
54
+ }
55
+
56
+ export interface MarkdownScanOptions {
57
+ /**
58
+ * Per-line skip patterns tested against the RAW line. A match classifies
59
+ * the line `marker`. Callers own their own markers; this module ships none.
60
+ */
61
+ markers?: readonly RegExp[];
62
+ }
63
+
64
+ /** Inline code spans — a term inside backticks is named, not used. */
65
+ const INLINE_CODE_RE = /`[^`]*`/g;
66
+
67
+ /**
68
+ * Python `str.splitlines()` — universal-newline split with no trailing empty
69
+ * element. Kept identical to the version `check_md_language` was ported with,
70
+ * because its line numbers are part of that gate's pinned output.
71
+ */
72
+ export function splitlines(text: string): string[] {
73
+ if (text === '') return [];
74
+ const lines: string[] = [];
75
+ let current = '';
76
+ for (let i = 0; i < text.length; i++) {
77
+ const ch = text[i] as string;
78
+ const code = text.charCodeAt(i);
79
+ if (ch === '\r') {
80
+ lines.push(current);
81
+ current = '';
82
+ if (text[i + 1] === '\n') i += 1; // \r\n consumed as one
83
+ continue;
84
+ }
85
+ if (
86
+ ch === '\n' ||
87
+ code === 0x0b ||
88
+ code === 0x0c ||
89
+ code === 0x1c ||
90
+ code === 0x1d ||
91
+ code === 0x1e ||
92
+ code === 0x85 ||
93
+ code === 0x2028 ||
94
+ code === 0x2029
95
+ ) {
96
+ lines.push(current);
97
+ current = '';
98
+ continue;
99
+ }
100
+ current += ch;
101
+ }
102
+ if (current !== '') lines.push(current);
103
+ return lines;
104
+ }
105
+
106
+ /** Blank out inline code spans so a quoted term is not read as a used one. */
107
+ export function stripInlineCode(text: string): string {
108
+ return text.replace(INLINE_CODE_RE, '');
109
+ }
110
+
111
+ function lstrip(s: string): string {
112
+ return s.replace(/^\s+/, '');
113
+ }
114
+
115
+ /**
116
+ * Classify every line of a markdown document.
117
+ *
118
+ * Pure over the content string — no filesystem access — so a caller can test
119
+ * the classification from a literal without a repo.
120
+ */
121
+ export function classifyMarkdownLines(
122
+ content: string,
123
+ opts: MarkdownScanOptions = {},
124
+ ): MarkdownLine[] {
125
+ const markers = opts.markers ?? [];
126
+ const out: MarkdownLine[] = [];
127
+ const lines = splitlines(content);
128
+
129
+ let inFence = false;
130
+ let inFrontmatter = false;
131
+
132
+ for (let idx = 0; idx < lines.length; idx++) {
133
+ const raw = lines[idx] as string;
134
+ const lineno = idx + 1;
135
+ const stripped = lstrip(raw);
136
+
137
+ // YAML frontmatter at the top of the file.
138
+ if (lineno === 1 && stripped === '---') {
139
+ inFrontmatter = true;
140
+ out.push({ lineno, raw, kind: 'frontmatter', text: '' });
141
+ continue;
142
+ }
143
+ if (inFrontmatter) {
144
+ if (stripped === '---') inFrontmatter = false;
145
+ out.push({ lineno, raw, kind: 'frontmatter', text: '' });
146
+ continue;
147
+ }
148
+
149
+ // Fenced code blocks — the markers themselves are skipped too.
150
+ if (stripped.startsWith('```') || stripped.startsWith('~~~')) {
151
+ inFence = !inFence;
152
+ out.push({ lineno, raw, kind: 'fence', text: '' });
153
+ continue;
154
+ }
155
+ if (inFence) {
156
+ out.push({ lineno, raw, kind: 'fence', text: '' });
157
+ continue;
158
+ }
159
+
160
+ // Indented code blocks (4+ leading spaces, non-list).
161
+ const listStarts = ['-', '*', '+', '1', '2', '3', '4', '5', '6', '7', '8', '9'];
162
+ if (raw.startsWith(' ') && !listStarts.some((c) => stripped.startsWith(c))) {
163
+ out.push({ lineno, raw, kind: 'indented-code', text: '' });
164
+ continue;
165
+ }
166
+
167
+ // Caller-supplied per-line markers.
168
+ if (markers.some((re) => { re.lastIndex = 0; return re.test(raw); })) {
169
+ out.push({ lineno, raw, kind: 'marker', text: '' });
170
+ continue;
171
+ }
172
+
173
+ out.push({ lineno, raw, kind: 'prose', text: stripInlineCode(raw) });
174
+ }
175
+
176
+ return out;
177
+ }