@event4u/agent-config 14.12.0 → 14.14.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 (521) 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 +118 -155
  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 +145 -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-comment-discipline.md +6 -0
  30. package/dist/agent-src/rules/code-provenance.md +4 -0
  31. package/dist/agent-src/rules/design-fidelity.md +1 -1
  32. package/dist/agent-src/rules/domain-safety-pii.md +4 -0
  33. package/dist/agent-src/rules/domain-safety-retention.md +4 -0
  34. package/dist/agent-src/rules/engineering-safety-floor.md +2 -0
  35. package/dist/agent-src/rules/external-code-graph-interop.md +14 -12
  36. package/dist/agent-src/rules/improve-before-implement.md +6 -8
  37. package/dist/agent-src/rules/laravel-routing.md +1 -1
  38. package/dist/agent-src/rules/lethal-trifecta-guard.md +4 -0
  39. package/dist/agent-src/rules/secret-vcs-guard.md +2 -0
  40. package/dist/agent-src/rules/security-sensitive-stop.md +2 -0
  41. package/dist/agent-src/rules/source-confidentiality.md +12 -34
  42. package/dist/agent-src/rules/symfony-routing.md +1 -1
  43. package/dist/agent-src/rules/token-efficiency.md +14 -0
  44. package/dist/agent-src/rules/tool-safety.md +4 -0
  45. package/dist/agent-src/rules/untrusted-input-defense.md +4 -0
  46. package/dist/agent-src/scripts/archive_completed_roadmaps.ts +252 -8
  47. package/dist/agent-src/scripts/guarded_baseline.ts +343 -0
  48. package/dist/agent-src/scripts/roadmap_set_step.ts +253 -0
  49. package/dist/agent-src/scripts/stub_queue.ts +82 -0
  50. package/dist/agent-src/scripts/stubs_due.ts +516 -0
  51. package/dist/agent-src/scripts/ticket_bundles.ts +84 -0
  52. package/dist/agent-src/scripts/update_roadmap_progress.ts +16 -12
  53. package/dist/agent-src/skills/brand-asset-generation/SKILL.md +17 -4
  54. package/dist/agent-src/skills/brand-audit/SKILL.md +33 -0
  55. package/dist/agent-src/skills/code-intelligence/SKILL.md +57 -0
  56. package/dist/agent-src/skills/database/SKILL.md +8 -0
  57. package/dist/agent-src/skills/dependency-upgrade/SKILL.md +27 -0
  58. package/dist/agent-src/skills/design-review/SKILL.md +1 -1
  59. package/dist/agent-src/skills/doc-coauthoring/SKILL.md +1 -1
  60. package/dist/agent-src/skills/existing-ui-audit/SKILL.md +17 -1
  61. package/dist/agent-src/skills/feature-planning/SKILL.md +9 -2
  62. package/dist/agent-src/skills/frontend-render-security/SKILL.md +44 -0
  63. package/dist/agent-src/skills/git-workflow/SKILL.md +1 -1
  64. package/dist/agent-src/skills/js-library-packaging/scripts/check_package_surface.ts +38 -4
  65. package/dist/agent-src/skills/judge-artifact-completeness/rubrics/ticket-quality-score.json +2 -2
  66. package/dist/agent-src/skills/laravel/SKILL.md +35 -0
  67. package/dist/agent-src/skills/laravel-migration/SKILL.md +57 -3
  68. package/dist/agent-src/skills/monorepo-workspace/SKILL.md +26 -0
  69. package/dist/agent-src/skills/playbook-authoring/SKILL.md +28 -1
  70. package/dist/agent-src/skills/react-shadcn-ui/SKILL.md +1 -1
  71. package/dist/agent-src/skills/skill-writing/references/procedure.md +5 -5
  72. package/dist/agent-src/skills/sql-writing/SKILL.md +7 -1
  73. package/dist/agent-src/skills/standards-from-config/SKILL.md +27 -4
  74. package/dist/agent-src/skills/supply-chain-intake/SKILL.md +11 -4
  75. package/dist/agent-src/skills/symfony-workflow/SKILL.md +35 -0
  76. package/dist/agent-src/skills/test-case-discovery/SKILL.md +85 -0
  77. package/dist/agent-src/skills/test-driven-development/SKILL.md +33 -9
  78. package/dist/agent-src/skills/testing-anti-patterns/SKILL.md +1 -1
  79. package/dist/agent-src/skills/testing-anti-patterns/process-anti-patterns.md +37 -0
  80. package/dist/agent-src/skills/ui-component-architect/SKILL.md +45 -2
  81. package/dist/agent-src/skills/upstream-contribute/SKILL.md +38 -1
  82. package/dist/agent-src/skills/verify-repair-loop/SKILL.md +9 -4
  83. package/dist/agent-src/templates/agents/agent-project-settings.example.yml +1 -1
  84. package/dist/agent-src/templates/roadmaps.md +97 -3
  85. package/dist/agent-src/templates/scripts/check_memory.ts +258 -17
  86. package/dist/agent-src/templates/scripts/check_memory_proposal.ts +9 -3
  87. package/dist/agent-src/templates/scripts/memory_lookup.ts +86 -0
  88. package/dist/agent-src/templates/scripts/memory_signal.ts +44 -0
  89. package/dist/agent-src/templates/scripts/work_engine/directives/backend/implement.ts +90 -0
  90. package/dist/agent-src/templates/scripts/work_engine/directives/backend/index.ts +11 -0
  91. package/dist/agent-src/templates/scripts/work_engine/directives/backend/test.ts +23 -1
  92. package/dist/agent-src/templates/scripts/work_engine/directives/backend/verify.ts +10 -1
  93. package/dist/agent-src/templates/scripts/work_engine/directives/mixed/stitch.ts +5 -1
  94. package/dist/agent-src/templates/scripts/work_engine/stack/runner.ts +102 -14
  95. package/dist/cli/commands/uiAudit.js +124 -5
  96. package/dist/cli/registry.js +2 -0
  97. package/dist/cli-delegate/{chunk-HYWSRNUX.js → chunk-2DK2VJWG.js} +3 -3
  98. package/dist/cli-delegate/{chunk-JCW7ZLHK.js → chunk-4FS4WRXP.js} +5 -0
  99. package/dist/cli-delegate/{chunk-OMIVVCG2.js → chunk-A4QJ6ENT.js} +24 -0
  100. package/dist/cli-delegate/{chunk-JJA2QEWA.js → chunk-AKJGUQNO.js} +466 -285
  101. package/dist/cli-delegate/{chunk-E46KPN6K.js → chunk-BTWUYDGN.js} +424 -363
  102. package/dist/cli-delegate/{chunk-K4FFODTS.js → chunk-ILMUPLGW.js} +1227 -316
  103. package/dist/cli-delegate/{chunk-FF7WAFMR.js → chunk-KPBWFOPZ.js} +5 -1
  104. package/dist/cli-delegate/cmd_adr_effective.js +102 -0
  105. package/dist/cli-delegate/cmd_conformance.js +80 -11
  106. package/dist/cli-delegate/cmd_doctor.js +3 -3
  107. package/dist/cli-delegate/cmd_export.js +3 -2
  108. package/dist/cli-delegate/cmd_fleet.js +2 -2
  109. package/dist/cli-delegate/cmd_handoff.js +1 -1
  110. package/dist/cli-delegate/cmd_preflight.js +2 -2
  111. package/dist/cli-delegate/cmd_prune.js +3 -2
  112. package/dist/cli-delegate/cmd_settings_get.js +1 -1
  113. package/dist/cli-delegate/cmd_settings_migrate.js +3 -2
  114. package/dist/cli-delegate/cmd_settings_set.js +2 -2
  115. package/dist/cli-delegate/cmd_sync.js +3 -2
  116. package/dist/cli-delegate/cmd_uninstall.js +3 -2
  117. package/dist/cli-delegate/cmd_validate.js +3 -2
  118. package/dist/discovery/deprecation-report.md +1 -1
  119. package/dist/discovery/discovery-manifest.json +58 -58
  120. package/dist/discovery/discovery-manifest.json.sha256 +1 -1
  121. package/dist/discovery/discovery-manifest.summary.md +1 -1
  122. package/dist/discovery/dormancy-report.md +1 -1
  123. package/dist/discovery/orphan-report.md +1 -1
  124. package/dist/discovery/packs.json +2 -2
  125. package/dist/discovery/trust-report.md +1 -1
  126. package/dist/discovery/workspaces.json +2 -2
  127. package/dist/hooks/dispatch.js +2900 -1049
  128. package/dist/install/claudeRuleRewrite.js +254 -0
  129. package/dist/install/detect.js +29 -16
  130. package/dist/install/detect_php_shape.js +159 -0
  131. package/dist/install/install.mjs +634 -428
  132. package/dist/mcp/awesome-mcp-servers.row.md +1 -1
  133. package/dist/mcp/mcp-cloudflare-catalogue.json +1 -1
  134. package/dist/mcp/registry-manifest.json +3 -3
  135. package/dist/mcp/server.json +3 -3
  136. package/dist/mcp/server.mjs +4895 -2627
  137. package/dist/server/schemas/settings.js +3 -0
  138. package/dist/ui/assets/index-D0jaCRPM.js +29 -0
  139. package/dist/ui/index.html +1 -1
  140. package/docs/MIGRATION.md +1 -1
  141. package/docs/THIRD-PARTY-NOTICES.md +25 -0
  142. package/docs/contracts/provider-lifecycle.md +1 -1
  143. package/docs/contracts/settings-classes.md +10 -4
  144. package/docs/guidelines/agent-infra/5w2h-analysis.md +3 -3
  145. package/docs/guidelines/agent-infra/agent-interaction-and-decision-quality.md +1 -0
  146. package/docs/guidelines/agent-infra/artifact-drafting-protocol-mechanics.md +58 -3
  147. package/docs/guidelines/agent-infra/ask-when-uncertain-demos.md +2 -2
  148. package/docs/guidelines/agent-infra/asking-and-brevity-examples.md +3 -3
  149. package/docs/guidelines/agent-infra/break-glass-usage.md +7 -7
  150. package/docs/guidelines/agent-infra/carve-out-predicates.md +3 -3
  151. package/docs/guidelines/agent-infra/comparison-matrix.md +1 -1
  152. package/docs/guidelines/agent-infra/critical-thinking.md +4 -4
  153. package/docs/guidelines/agent-infra/direct-answers-demos.md +2 -2
  154. package/docs/guidelines/agent-infra/domain-eval-anti-pattern.md +1 -1
  155. package/docs/guidelines/agent-infra/engineering-memory-data-format.md +3 -3
  156. package/docs/guidelines/agent-infra/existence-question-verdicts.md +80 -0
  157. package/docs/guidelines/agent-infra/first-principles.md +2 -2
  158. package/docs/guidelines/agent-infra/framework-neutrality-patterns.md +2 -2
  159. package/docs/guidelines/agent-infra/guarded-baseline.md +39 -0
  160. package/docs/guidelines/agent-infra/inversion-thinking.md +5 -5
  161. package/docs/guidelines/agent-infra/language-and-tone-examples.md +1 -1
  162. package/docs/guidelines/agent-infra/layered-settings.md +10 -10
  163. package/docs/guidelines/agent-infra/memory-access.md +1 -1
  164. package/docs/guidelines/agent-infra/mental-models.md +3 -3
  165. package/docs/guidelines/agent-infra/reuse-verdict-mechanics.md +71 -0
  166. package/docs/guidelines/agent-infra/review-routing-data-format.md +7 -7
  167. package/docs/guidelines/agent-infra/roadmap-progress-mechanics.md +13 -7
  168. package/docs/guidelines/agent-infra/role-contracts.md +2 -2
  169. package/docs/guidelines/agent-infra/role-mode-router.md +3 -3
  170. package/docs/guidelines/agent-infra/rule-type-governance.md +2 -2
  171. package/docs/guidelines/agent-infra/scqa-framework.md +5 -5
  172. package/docs/guidelines/agent-infra/self-improvement-pipeline.md +6 -6
  173. package/docs/guidelines/agent-infra/simplicity-and-goal-demos.md +2 -2
  174. package/docs/guidelines/agent-infra/six-hats.md +3 -3
  175. package/docs/guidelines/agent-infra/skill-quality-checklist.md +6 -6
  176. package/docs/guidelines/agent-infra/source-confidentiality-mechanics.md +109 -0
  177. package/docs/guidelines/agent-infra/systems-thinking.md +1 -1
  178. package/docs/guidelines/agent-infra/verify-before-complete-demos.md +2 -2
  179. package/docs/guidelines/augment-portability-patterns.md +6 -4
  180. package/docs/guidelines/code-clarity.md +18 -0
  181. package/docs/guidelines/component-oriented-and-oop-development.md +3 -2
  182. package/docs/guidelines/cross-role-handoff.md +2 -2
  183. package/docs/guidelines/design-fidelity-mechanics.md +1 -1
  184. package/docs/guidelines/docs/readme-size-and-splitting.md +3 -3
  185. package/docs/guidelines/php/database.md +90 -7
  186. package/docs/guidelines/prompt-templates.md +7 -7
  187. package/llms.txt +2 -2
  188. package/package.json +5 -2
  189. package/src/agent-src/scripts/archive_completed_roadmaps.ts +252 -8
  190. package/src/agent-src/scripts/guarded_baseline.ts +343 -0
  191. package/src/agent-src/scripts/roadmap_set_step.ts +253 -0
  192. package/src/agent-src/scripts/stub_queue.ts +82 -0
  193. package/src/agent-src/scripts/stubs_due.ts +516 -0
  194. package/src/agent-src/scripts/ticket_bundles.ts +84 -0
  195. package/src/agent-src/scripts/update_roadmap_progress.ts +16 -12
  196. package/src/agent-src/templates/scripts/check_memory.ts +258 -17
  197. package/src/agent-src/templates/scripts/check_memory_proposal.ts +9 -3
  198. package/src/agent-src/templates/scripts/memory_lookup.ts +86 -0
  199. package/src/agent-src/templates/scripts/memory_signal.ts +44 -0
  200. package/src/agent-src/templates/scripts/work_engine/directives/backend/implement.ts +90 -0
  201. package/src/agent-src/templates/scripts/work_engine/directives/backend/index.ts +11 -0
  202. package/src/agent-src/templates/scripts/work_engine/directives/backend/test.ts +23 -1
  203. package/src/agent-src/templates/scripts/work_engine/directives/backend/verify.ts +10 -1
  204. package/src/agent-src/templates/scripts/work_engine/directives/mixed/stitch.ts +5 -1
  205. package/src/agent-src/templates/scripts/work_engine/stack/runner.ts +102 -14
  206. package/src/config/agent-settings.template.yml +32 -3
  207. package/src/config/assurance-capability-registry.json +21 -9
  208. package/src/config/canonical-terms.yml +119 -0
  209. package/src/config/capability-native-outcome-bars.json +81 -0
  210. package/src/config/ci-local-parity.yml +80 -0
  211. package/src/config/drafting-channels.yml +43 -0
  212. package/src/config/estate-count-budget.json +57 -36
  213. package/src/config/evaluator-budgets.json +14 -14
  214. package/src/config/gate-coverage.yml +729 -63
  215. package/src/config/gate-reachability-exemptions.json +21 -0
  216. package/src/config/gate-violation-baselines.json +42 -19
  217. package/src/config/harness-evolution-budget.json +25 -0
  218. package/src/config/lapsed-beta-baseline.json +96 -0
  219. package/src/config/memory-twin-verdicts.yml +129 -0
  220. package/src/config/metric-registry.yml +124 -0
  221. package/src/config/pack-size-budget.json +16 -15
  222. package/src/config/preamble-payload-budget.json +12 -4
  223. package/src/config/profiles/balanced.ini +27 -0
  224. package/src/config/profiles/full.ini +27 -0
  225. package/src/config/profiles/minimal.ini +27 -0
  226. package/src/config/publish-surface.json +9 -2
  227. package/src/config/routing-coverage-seed.json +16 -2
  228. package/src/config/rule-stub-ceilings.json +133 -112
  229. package/src/config/turnaround-budget.json +66 -0
  230. package/src/install/claudeRuleRewrite.ts +288 -0
  231. package/src/install/detect.ts +60 -17
  232. package/src/install/detect_php_shape.ts +191 -0
  233. package/src/scripts/_cli/cmd_doctor.ts +27 -112
  234. package/src/scripts/_dispatch.bash +23 -0
  235. package/src/scripts/_lib/activation_ladder.ts +255 -0
  236. package/src/scripts/_lib/activation_receipt_producer.ts +341 -0
  237. package/src/scripts/_lib/activation_states.ts +88 -0
  238. package/src/scripts/_lib/adherence_detectors.ts +143 -0
  239. package/src/scripts/_lib/adr_frontmatter.ts +26 -0
  240. package/src/scripts/_lib/arith_claims.ts +181 -0
  241. package/src/scripts/_lib/arm_ranking.ts +62 -0
  242. package/src/scripts/_lib/asset_delivery_ledger.ts +303 -0
  243. package/src/scripts/_lib/audit_field_provenance.ts +54 -0
  244. package/src/scripts/_lib/auto_dispatch.ts +32 -3
  245. package/src/scripts/_lib/bench_ab_size_claim.ts +98 -4
  246. package/src/scripts/_lib/benchmark_cache_fields.ts +158 -0
  247. package/src/scripts/_lib/candidate_pair_delta.ts +349 -0
  248. package/src/scripts/_lib/candidate_proposer.ts +402 -0
  249. package/src/scripts/_lib/candidate_record.ts +601 -0
  250. package/src/scripts/_lib/capture_rate.ts +319 -0
  251. package/src/scripts/_lib/carrier_status.ts +118 -0
  252. package/src/scripts/_lib/cascade_stage_enumeration.ts +92 -0
  253. package/src/scripts/_lib/collector_denominator.ts +771 -0
  254. package/src/scripts/_lib/collector_record.ts +340 -0
  255. package/src/scripts/_lib/collector_store.ts +664 -0
  256. package/src/scripts/_lib/collector_supervision.ts +827 -0
  257. package/src/scripts/_lib/concern_estate.ts +77 -0
  258. package/src/scripts/_lib/config_chain.ts +477 -0
  259. package/src/scripts/_lib/config_cost.ts +209 -0
  260. package/src/scripts/_lib/corpus_manifest.ts +726 -0
  261. package/src/scripts/_lib/council_settings_block.ts +6 -0
  262. package/src/scripts/_lib/curator_ops.ts +172 -0
  263. package/src/scripts/_lib/delivery_arm_experiment.ts +282 -0
  264. package/src/scripts/_lib/delivery_criticality.ts +126 -0
  265. package/src/scripts/_lib/doctor_runtime_checks.ts +70 -0
  266. package/src/scripts/_lib/empty_cycles.ts +88 -0
  267. package/src/scripts/_lib/estate_carrier_cases.ts +72 -0
  268. package/src/scripts/_lib/eval_publication.ts +354 -0
  269. package/src/scripts/_lib/evaluation_cascade.ts +452 -0
  270. package/src/scripts/_lib/evaluation_vector.ts +283 -0
  271. package/src/scripts/_lib/evaluator_promotion.ts +225 -0
  272. package/src/scripts/_lib/evidence_basis.ts +118 -0
  273. package/src/scripts/_lib/evolution_roi.ts +562 -0
  274. package/src/scripts/_lib/exec_evidence.ts +8 -0
  275. package/src/scripts/_lib/experience_card.ts +272 -0
  276. package/src/scripts/_lib/experience_report.ts +151 -0
  277. package/src/scripts/_lib/experiment_freeze.ts +112 -0
  278. package/src/scripts/_lib/generated_by.ts +66 -0
  279. package/src/scripts/_lib/harness_evolution_guards.ts +239 -0
  280. package/src/scripts/_lib/hook_effect_probe.ts +141 -0
  281. package/src/scripts/_lib/host_denominator.ts +687 -0
  282. package/src/scripts/_lib/host_projection_reach.ts +157 -0
  283. package/src/scripts/_lib/ignored_blocker.ts +148 -0
  284. package/src/scripts/_lib/install_reach_checks.ts +495 -0
  285. package/src/scripts/_lib/json_duplicate_keys.ts +150 -0
  286. package/src/scripts/_lib/judge_hygiene.ts +228 -0
  287. package/src/scripts/_lib/legacy_boundary_map.ts +228 -0
  288. package/src/scripts/_lib/lexical_shortlist.ts +215 -0
  289. package/src/scripts/_lib/llm_candidate_proposer.ts +461 -0
  290. package/src/scripts/_lib/llm_proposer_transport.ts +153 -0
  291. package/src/scripts/_lib/loop_guards.ts +299 -0
  292. package/src/scripts/_lib/loss_class.ts +129 -0
  293. package/src/scripts/_lib/machine_wake.ts +51 -0
  294. package/src/scripts/_lib/md_prose_lines.ts +177 -0
  295. package/src/scripts/_lib/minimality_tiebreak.ts +168 -0
  296. package/src/scripts/_lib/one_resolver_invariant.ts +449 -0
  297. package/src/scripts/_lib/orchestration_record.ts +253 -5
  298. package/src/scripts/_lib/outcome_envelope.ts +227 -0
  299. package/src/scripts/_lib/outcome_vocabularies.ts +125 -0
  300. package/src/scripts/_lib/paired_stats.ts +245 -0
  301. package/src/scripts/_lib/paired_verdict.ts +226 -0
  302. package/src/scripts/_lib/pathology_archive.ts +393 -0
  303. package/src/scripts/_lib/prefix_stable_surfaces.ts +123 -0
  304. package/src/scripts/_lib/privacy_class.ts +47 -0
  305. package/src/scripts/_lib/promotion_capability.ts +315 -0
  306. package/src/scripts/_lib/promotion_evidence.ts +414 -0
  307. package/src/scripts/_lib/promotion_review.ts +294 -0
  308. package/src/scripts/_lib/prompt_shape.ts +92 -0
  309. package/src/scripts/_lib/regression_neighbourhood.ts +259 -0
  310. package/src/scripts/_lib/release_highlights.ts +70 -1
  311. package/src/scripts/_lib/release_material.ts +125 -2
  312. package/src/scripts/_lib/repeated_failure.ts +105 -0
  313. package/src/scripts/_lib/repo_root.ts +111 -0
  314. package/src/scripts/_lib/review_skipped_record.ts +37 -0
  315. package/src/scripts/_lib/role_split.ts +338 -0
  316. package/src/scripts/_lib/routing_corpus.ts +307 -0
  317. package/src/scripts/_lib/routing_index_input.ts +104 -0
  318. package/src/scripts/_lib/rule_injection.ts +22 -1
  319. package/src/scripts/_lib/runtime_journal.ts +1499 -0
  320. package/src/scripts/_lib/runtime_wiring_checks.ts +430 -0
  321. package/src/scripts/_lib/semantic_noop.ts +167 -0
  322. package/src/scripts/_lib/skill_catalogue.ts +11 -1
  323. package/src/scripts/_lib/source_digest.ts +200 -0
  324. package/src/scripts/_lib/source_redact.ts +260 -0
  325. package/src/scripts/_lib/source_shape.ts +502 -0
  326. package/src/scripts/_lib/source_snapshot_dedup.ts +199 -0
  327. package/src/scripts/_lib/strip_comments.d.mts +8 -0
  328. package/src/scripts/_lib/strip_comments.mjs +65 -0
  329. package/src/scripts/_lib/test_red_state.ts +154 -0
  330. package/src/scripts/_lib/trigger_shift.ts +144 -0
  331. package/src/scripts/_lib/untrusted_content.ts +82 -7
  332. package/src/scripts/activation_receipt.ts +258 -0
  333. package/src/scripts/adoption_report.ts +1 -1
  334. package/src/scripts/adr/evidence_census.ts +1 -1
  335. package/src/scripts/adr/regenerate_index.ts +26 -2
  336. package/src/scripts/adr_cite_check.ts +164 -1
  337. package/src/scripts/ai_council/blind_review.ts +11 -1
  338. package/src/scripts/ai_council/clients.ts +4 -0
  339. package/src/scripts/ai_council/config.ts +3 -0
  340. package/src/scripts/ai_council/consensus.ts +28 -8
  341. package/src/scripts/ai_council/consensus_round.ts +226 -0
  342. package/src/scripts/ai_council/cross_exam.ts +128 -0
  343. package/src/scripts/ai_council/disagreement_signal.ts +338 -0
  344. package/src/scripts/ai_council/explain_route.ts +157 -0
  345. package/src/scripts/ai_council/information_gain.ts +293 -0
  346. package/src/scripts/ai_council/inline_findings.ts +340 -0
  347. package/src/scripts/ai_council/judge_position_bias.ts +197 -0
  348. package/src/scripts/ai_council/leakage_corpus.ts +385 -0
  349. package/src/scripts/ai_council/leakage_patterns.ts +453 -0
  350. package/src/scripts/ai_council/minority_retention.ts +171 -0
  351. package/src/scripts/ai_council/orchestrator.ts +16 -203
  352. package/src/scripts/ai_council/orchestrator_results.ts +23 -3
  353. package/src/scripts/ai_council/pricing.ts +106 -0
  354. package/src/scripts/ai_council/prompts.ts +74 -7
  355. package/src/scripts/ai_council/provider_leakage_bench.ts +327 -0
  356. package/src/scripts/ai_council/py_format.ts +14 -3
  357. package/src/scripts/ai_council/recouncil_guard.ts +293 -0
  358. package/src/scripts/ai_council/recouncil_savings.ts +299 -0
  359. package/src/scripts/ai_council/replay_route.ts +223 -0
  360. package/src/scripts/ai_council/response_record.ts +50 -0
  361. package/src/scripts/ai_council/reviewer_assignment.ts +279 -0
  362. package/src/scripts/ai_council/routing_training_row.ts +197 -0
  363. package/src/scripts/ai_council/synthesis_strategy.ts +159 -0
  364. package/src/scripts/ai_council/topology_bench_manifest.ts +860 -0
  365. package/src/scripts/ai_council/topology_vocabulary.ts +175 -0
  366. package/src/scripts/asset_delivery_ledger.ts +157 -0
  367. package/src/scripts/attest_artifact.ts +193 -0
  368. package/src/scripts/audit_auto_rules.ts +2 -1
  369. package/src/scripts/audit_command_surface.ts +1 -1
  370. package/src/scripts/audit_mcp_tools.ts +2 -2
  371. package/src/scripts/audit_skill_overlap_allowlist.json +6 -1
  372. package/src/scripts/audit_user_type_axis.ts +2 -1
  373. package/src/scripts/bench_ab_clone.ts +215 -10
  374. package/src/scripts/bench_ab_integrity.ts +119 -5
  375. package/src/scripts/bench_ab_v2_stats.ts +40 -213
  376. package/src/scripts/build_archive_index.ts +1 -1
  377. package/src/scripts/build_linear_digest.ts +1 -1
  378. package/src/scripts/build_proof.ts +11 -4
  379. package/src/scripts/build_rule_trigger_matrix.ts +1 -1
  380. package/src/scripts/build_source_digests.ts +157 -0
  381. package/src/scripts/cache_realization_report.ts +103 -0
  382. package/src/scripts/check_adr_frontmatter.ts +131 -10
  383. package/src/scripts/check_benchmark_report_fields.ts +207 -0
  384. package/src/scripts/check_beta_review_markers.ts +235 -6
  385. package/src/scripts/check_bundle_path_leakage.ts +34 -1
  386. package/src/scripts/check_claims.ts +576 -6
  387. package/src/scripts/check_composite_arming.ts +35 -0
  388. package/src/scripts/check_concern_admissions.ts +365 -0
  389. package/src/scripts/check_enforcement_coverage.ts +28 -0
  390. package/src/scripts/check_estate_count.ts +347 -25
  391. package/src/scripts/check_gate_reachability.ts +383 -0
  392. package/src/scripts/check_host_loadability.ts +104 -0
  393. package/src/scripts/check_loss_class_declared.ts +308 -0
  394. package/src/scripts/check_md_language.ts +15 -98
  395. package/src/scripts/check_memory_proposal.ts +18 -11
  396. package/src/scripts/check_no_currency_in_cost_surfaces.ts +225 -0
  397. package/src/scripts/check_no_external_sources.ts +281 -6
  398. package/src/scripts/check_pack_conformance_fixture.ts +11 -1
  399. package/src/scripts/check_pack_size.ts +59 -2
  400. package/src/scripts/check_preamble_payload_budget.ts +114 -3
  401. package/src/scripts/check_prefix_stable_mutation.ts +372 -0
  402. package/src/scripts/check_publish_surface.ts +10 -1
  403. package/src/scripts/check_references.ts +24 -1
  404. package/src/scripts/check_release_highlights.ts +96 -13
  405. package/src/scripts/check_roadmap_trackable.ts +17 -2
  406. package/src/scripts/check_rule_evidence_declaration.ts +316 -0
  407. package/src/scripts/check_rule_projection_integrity.ts +14 -4
  408. package/src/scripts/check_score_contract.ts +26 -3
  409. package/src/scripts/check_static_parity.ts +285 -0
  410. package/src/scripts/check_supervision_claim_atomicity.ts +498 -0
  411. package/src/scripts/check_suppression_hygiene.ts +15 -0
  412. package/src/scripts/ci_settle.ts +39 -2
  413. package/src/scripts/code_graph/build.ts +60 -3
  414. package/src/scripts/code_graph/extract.ts +44 -0
  415. package/src/scripts/code_graph/types.ts +24 -0
  416. package/src/scripts/collector_daemon.ts +714 -0
  417. package/src/scripts/config_cost_report.ts +302 -0
  418. package/src/scripts/consumer_matrix.ts +74 -1
  419. package/src/scripts/corpus_manifest.ts +235 -0
  420. package/src/scripts/cost/budget.mjs +10 -3
  421. package/src/scripts/cost/track.mjs +10 -3
  422. package/src/scripts/council_cli.ts +37 -54
  423. package/src/scripts/dispatch_r2_reviewer.ts +46 -5
  424. package/src/scripts/evolution_lab.ts +1153 -0
  425. package/src/scripts/external_sources_denylist.json +5 -18
  426. package/src/scripts/extract_audit_patterns.ts +21 -0
  427. package/src/scripts/fold_intake.ts +12 -1
  428. package/src/scripts/gen_discovery_baseline.ts +1 -1
  429. package/src/scripts/generate_capabilities_index.ts +12 -5
  430. package/src/scripts/generate_capability_matrix.ts +3 -3
  431. package/src/scripts/generate_command_flows.ts +2 -2
  432. package/src/scripts/generate_cookbook.ts +2 -2
  433. package/src/scripts/generate_index.ts +8 -1
  434. package/src/scripts/generate_knowledge_index.ts +2 -1
  435. package/src/scripts/generate_ownership_matrix.ts +2 -1
  436. package/src/scripts/generate_pack_manifests.ts +10 -2
  437. package/src/scripts/generate_role_experiences_catalog.ts +2 -2
  438. package/src/scripts/generate_settings_reference.ts +1 -1
  439. package/src/scripts/git_authorization_hook.ts +22 -1
  440. package/src/scripts/grade_target_readiness.ts +48 -5
  441. package/src/scripts/hook_effect_doctor.ts +261 -0
  442. package/src/scripts/hook_manifest.json +1 -1
  443. package/src/scripts/hook_manifest.yaml +125 -16
  444. package/src/scripts/hooks/block_speaking_inbox_dir.ts +271 -0
  445. package/src/scripts/hooks/block_unauthorized_git.ts +18 -0
  446. package/src/scripts/hooks/comment_discipline_hook.ts +146 -0
  447. package/src/scripts/hooks/concern_registry.ts +6 -0
  448. package/src/scripts/hooks/dispatch_hook.ts +32 -0
  449. package/src/scripts/hooks/journal_record_hook.ts +345 -0
  450. package/src/scripts/hooks/prepush_metadata_sources.sh +110 -0
  451. package/src/scripts/hooks/run_continuation_hook.ts +44 -9
  452. package/src/scripts/hooks/shims/install.sh +61 -0
  453. package/src/scripts/hooks/shims/php +101 -0
  454. package/src/scripts/hooks/suggestion_capture_hook.ts +10 -0
  455. package/src/scripts/hooks/turn_end_gate_hook.ts +9 -1
  456. package/src/scripts/hot_context_hook.ts +16 -0
  457. package/src/scripts/install-hooks.sh +20 -5
  458. package/src/scripts/install.ts +17 -35
  459. package/src/scripts/inventory_frontmatter.ts +2 -1
  460. package/src/scripts/language_mirror_hook.ts +14 -2
  461. package/src/scripts/lint_adr_sweep_routing.ts +12 -0
  462. package/src/scripts/lint_canonical_terms.ts +604 -0
  463. package/src/scripts/lint_carrier_integrity.ts +820 -0
  464. package/src/scripts/lint_code_comments.ts +643 -0
  465. package/src/scripts/lint_composition_review.ts +619 -0
  466. package/src/scripts/lint_consolidation_lineage.ts +666 -0
  467. package/src/scripts/lint_eval_specs.ts +593 -0
  468. package/src/scripts/lint_hook_manifest.ts +19 -0
  469. package/src/scripts/lint_host_portability.ts +373 -0
  470. package/src/scripts/lint_judge_prompt_expectation.ts +27 -1
  471. package/src/scripts/lint_memory_twin_parity.ts +335 -0
  472. package/src/scripts/lint_metric_consumers.ts +355 -0
  473. package/src/scripts/lint_plan_risk_register.ts +39 -19
  474. package/src/scripts/lint_promotion_paths.ts +779 -0
  475. package/src/scripts/lint_skill_descriptions.ts +18 -1
  476. package/src/scripts/lint_skill_frontmatter_safety.ts +58 -0
  477. package/src/scripts/lint_skill_link_reach.ts +252 -0
  478. package/src/scripts/lint_skill_trigger_corpus.ts +426 -23
  479. package/src/scripts/lint_ticket_buildable.ts +17 -1
  480. package/src/scripts/llm_propose.ts +256 -0
  481. package/src/scripts/mcp_server/consumer_tool_catalog.json +1 -1
  482. package/src/scripts/mcp_server/tool_catalog_source.ts +1 -1
  483. package/src/scripts/measure_delivery_sets.ts +361 -0
  484. package/src/scripts/measure_docs_dead_links.ts +348 -0
  485. package/src/scripts/measure_host_capture.ts +461 -0
  486. package/src/scripts/measure_routing_signal.ts +307 -0
  487. package/src/scripts/migration_status.ts +3 -3
  488. package/src/scripts/model_rule_injection.ts +76 -0
  489. package/src/scripts/orchestration_record.ts +14 -0
  490. package/src/scripts/preamble_byte_census.ts +139 -10
  491. package/src/scripts/prepack-check.mjs +4 -1
  492. package/src/scripts/probe_council_retention.ts +495 -0
  493. package/src/scripts/probe_turnaround.ts +384 -0
  494. package/src/scripts/probe_unblocked_ask.ts +279 -0
  495. package/src/scripts/release.ts +21 -37
  496. package/src/scripts/release_drill.ts +143 -0
  497. package/src/scripts/release_env.ts +35 -0
  498. package/src/scripts/release_publication.ts +84 -0
  499. package/src/scripts/render_benchmark_md.ts +1 -1
  500. package/src/scripts/rule_activation_census.ts +70 -9
  501. package/src/scripts/rule_backlinks.ts +1 -1
  502. package/src/scripts/run_lifecycle_suite.ts +208 -0
  503. package/src/scripts/run_skill_evals.ts +40 -0
  504. package/src/scripts/schemas/delivery-manifest.schema.json +43 -0
  505. package/src/scripts/schemas/drafting-channels.schema.json +43 -0
  506. package/src/scripts/schemas/evals.schema.json +24 -1
  507. package/src/scripts/schemas/rule.schema.json +52 -1
  508. package/src/scripts/schemas/skill.schema.json +17 -2
  509. package/src/scripts/skill_overlap.ts +7 -1
  510. package/src/scripts/skill_tools/run_block_d_eval.ts +8 -1
  511. package/src/scripts/skill_tools/score_skill_relevance.ts +84 -3
  512. package/src/scripts/skill_tools/suggest_skill_for_task.ts +8 -1
  513. package/src/scripts/skill_usage_report.ts +2 -1
  514. package/src/scripts/stubs_due.ts +211 -0
  515. package/src/scripts/sweep_source_surfaces.ts +678 -0
  516. package/src/scripts/sync_pr_branch.ts +3 -3
  517. package/src/scripts/trigger_eval_grandfather.json +202 -222
  518. package/src/scripts/utilization_report.ts +22 -2
  519. package/src/server/schemas/settings.ts +5 -0
  520. package/src/templates/marketing-copy.yml +1 -1
  521. package/dist/ui/assets/index-Cxgy63kz.js +0 -26
@@ -0,0 +1,308 @@
1
+ #!/usr/bin/env tsx
2
+ /**
3
+ * An undeclared lossy transform on a model-facing path fails
4
+ * (`road-to-runtime-context-floors` step 3.2).
5
+ *
6
+ * STRICTNESS — decided, not assumed
7
+ * ---------------------------------
8
+ * Council 2026-08-28 (2/2 convergent, anthropic + openai, 2 rounds) resolved the
9
+ * `how-strict-the-loss-class-lint-is` blocker as option (b): FAIL on transforms
10
+ * whose output reaches the model, WARN elsewhere. Option (a) — fail everywhere in
11
+ * `src/` — buys a first-run backlog whose usual answer is a broad allowlist, and
12
+ * this repository has a measured history of an allowlist emptying a gate. Option
13
+ * (c) — warn everywhere, ratchet later — is the shape this repository has
14
+ * measurably never ratcheted.
15
+ *
16
+ * Both seats added the same refinement, adopted here: **unknown reachability is
17
+ * classified as model-reaching.** Ambiguity must not become an accidental
18
+ * exemption.
19
+ *
20
+ * WHAT COUNTS AS MODEL-FACING
21
+ * ---------------------------
22
+ * A hook concern bound on a slot whose output can reach the model, whose script
23
+ * BOTH emits a context payload AND applies a lossy operation to content. Both
24
+ * halves are read from code with comments stripped — the first cut of this
25
+ * detector matched `truncat` inside three docblocks that describe truncation
26
+ * without performing any, and a gate that fires on prose about a defect rather
27
+ * than the defect is how a real corpus of one becomes a pro-forma corpus of four.
28
+ *
29
+ * Measured at landing: **1** module qualifies — `hot_context_hook`, which is
30
+ * exactly the `ephemeral-lossy` exemplar the contract classifies. A corpus of one
31
+ * is the honest state of this tree, not a broken detector; the gate fires the day
32
+ * a second lands.
33
+ *
34
+ * Exit codes: 0 clean (warnings allowed) · 1 an undeclared model-facing
35
+ * transform · 2 misuse / unreadable manifest.
36
+ *
37
+ * Usage:
38
+ * ./scripts-run src/scripts/check_loss_class_declared [--root <dir>] [--json] [--quiet]
39
+ * ./scripts-run src/scripts/check_loss_class_declared --self-test
40
+ */
41
+ import { spawnSync } from 'node:child_process';
42
+ import * as fs from 'node:fs';
43
+ import * as os from 'node:os';
44
+ import * as path from 'node:path';
45
+
46
+ import { GateLedger } from './_lib/gate_ledger.js';
47
+ import { runGateCli, runSelfTest, type SelfTestCase } from './_lib/gate_self_test.js';
48
+ import { isProblem, parseLossDeclaration, type DeclarationProblem } from './_lib/loss_class.js';
49
+ import { DeadScopeError, reportScanned } from './_lib/scan_scope.js';
50
+
51
+ const HERE = path.dirname(new URL(import.meta.url).pathname);
52
+ const REPO_ROOT = path.resolve(HERE, '..', '..');
53
+
54
+ /** Slots whose output can reach the model. */
55
+ const MODEL_FACING_SLOTS = [
56
+ 'session_start',
57
+ 'user_prompt_submit',
58
+ 'pre_compact',
59
+ 'stop',
60
+ 'post_tool_use',
61
+ 'pre_tool_use',
62
+ ] as const;
63
+
64
+ /** Emitting a context payload — the "reaches the model" half. */
65
+ const EMIT_PATTERNS = [/\bcontext\s*:/, /additionalContext/, /hookSpecificOutput/];
66
+
67
+ /** Shortening, redacting or capping content — the "lossy" half. */
68
+ const LOSSY_PATTERNS = [/\bredact/i, /\btruncat/i, /\b(?:WORD|CHAR|MAX)_(?:CAP|CHARS|LEN|WORDS)\b/];
69
+
70
+ export interface LossFinding {
71
+ concern: string;
72
+ script: string;
73
+ tier: 'fail' | 'warn';
74
+ problem: DeclarationProblem;
75
+ }
76
+
77
+ export interface LossVerdict {
78
+ scanned: number;
79
+ modelFacing: number;
80
+ findings: LossFinding[];
81
+ }
82
+
83
+ /** Strip block and line comments so the detector reads CODE, never prose about code. */
84
+ export function stripComments(src: string): string {
85
+ return src
86
+ .replace(/\/\*[\s\S]*?\*\//g, '')
87
+ .replace(/^\s*\/\/.*$/gm, '');
88
+ }
89
+
90
+ export function emitsContext(codeOnly: string): boolean {
91
+ return EMIT_PATTERNS.some((p) => p.test(codeOnly));
92
+ }
93
+
94
+ export function isLossy(codeOnly: string): boolean {
95
+ return LOSSY_PATTERNS.some((p) => p.test(codeOnly));
96
+ }
97
+
98
+ function loadManifest(root: string): { concerns: Record<string, { script?: unknown }>; platforms: Record<string, Record<string, string[]>> } {
99
+ const file = path.join(root, 'src', 'scripts', 'hook_manifest.yaml');
100
+ const raw = fs.readFileSync(file, 'utf-8');
101
+ const out = spawnSync(
102
+ process.execPath,
103
+ ['-e', 'const y=require("js-yaml");let s="";process.stdin.on("data",d=>s+=d).on("end",()=>{const d=y.load(s);process.stdout.write(JSON.stringify({concerns:d.concerns||{},platforms:d.platforms||{}}))})'],
104
+ { input: raw, encoding: 'utf-8', cwd: REPO_ROOT, maxBuffer: 64 * 1024 * 1024 },
105
+ );
106
+ if (out.status !== 0 || !out.stdout) throw new Error(`hook_manifest.yaml could not be parsed: ${out.stderr || 'no output'}`);
107
+ return JSON.parse(out.stdout) as { concerns: Record<string, { script?: unknown }>; platforms: Record<string, Record<string, string[]>> };
108
+ }
109
+
110
+ /**
111
+ * Which concerns sit on a model-facing slot.
112
+ *
113
+ * A concern bound on NO slot this gate recognises is `unknown` reachability, and
114
+ * per the council refinement it is treated as model-facing rather than skipped.
115
+ */
116
+ export function modelFacingConcerns(platforms: Record<string, Record<string, string[]>>): Set<string> {
117
+ const out = new Set<string>();
118
+ for (const slots of Object.values(platforms)) {
119
+ if (slots === null || typeof slots !== 'object') continue;
120
+ for (const [slot, names] of Object.entries(slots)) {
121
+ if (!Array.isArray(names)) continue;
122
+ const facing = (MODEL_FACING_SLOTS as readonly string[]).includes(slot);
123
+ for (const n of names) if (facing) out.add(n);
124
+ }
125
+ }
126
+ return out;
127
+ }
128
+
129
+ export function evaluate(root: string = REPO_ROOT, ledger?: GateLedger): LossVerdict {
130
+ const { concerns, platforms } = loadManifest(root);
131
+ const facing = modelFacingConcerns(platforms);
132
+ const bound = new Set<string>();
133
+ for (const slots of Object.values(platforms)) {
134
+ if (slots === null || typeof slots !== 'object') continue;
135
+ for (const names of Object.values(slots)) if (Array.isArray(names)) for (const n of names) bound.add(n);
136
+ }
137
+
138
+ const findings: LossFinding[] = [];
139
+ let scanned = 0;
140
+ let modelFacing = 0;
141
+
142
+ ledger?.plan(Object.keys(concerns));
143
+
144
+ for (const [name, spec] of Object.entries(concerns)) {
145
+ const rel = typeof spec?.script === 'string' ? spec.script : null;
146
+ if (rel === null) {
147
+ ledger?.skip(name, 'manifest_absent');
148
+ continue;
149
+ }
150
+ const abs = path.join(root, rel);
151
+ if (!fs.existsSync(abs)) {
152
+ ledger?.skip(name, 'no_applicable_files');
153
+ continue;
154
+ }
155
+ scanned += 1;
156
+
157
+ const source = fs.readFileSync(abs, 'utf-8');
158
+ const code = stripComments(source);
159
+ if (!isLossy(code) || !emitsContext(code)) {
160
+ // Not a lossy model-facing transform: the check does not apply to it.
161
+ ledger?.outOfScope(name, 'not_applicable_kind');
162
+ continue;
163
+ }
164
+
165
+ // Unknown reachability fails closed: a bound concern this gate cannot
166
+ // place on a known slot is treated as model-reaching.
167
+ const reaches = facing.has(name) || !bound.has(name);
168
+ if (reaches) modelFacing += 1;
169
+
170
+ const decl = parseLossDeclaration(source);
171
+ if (!isProblem(decl)) {
172
+ ledger?.complete(name);
173
+ continue;
174
+ }
175
+ findings.push({ concern: name, script: rel, tier: reaches ? 'fail' : 'warn', problem: decl });
176
+ ledger?.fail(name, `undeclared or malformed loss_class (${decl.kind})`);
177
+ }
178
+ return { scanned, modelFacing, findings };
179
+ }
180
+
181
+ // ---------------------------------------------------------------- self-test
182
+
183
+ const LOSSY_EMITTER = `
184
+ const WORD_CAP = 400;
185
+ export function run() {
186
+ const kept = redactLines(body).slice(0, WORD_CAP);
187
+ return { context: kept.join('\\n') };
188
+ }
189
+ `;
190
+
191
+ function plant(dir: string, header: string, body: string, slot = 'session_start'): void {
192
+ fs.mkdirSync(path.join(dir, 'src', 'scripts'), { recursive: true });
193
+ fs.writeFileSync(path.join(dir, 'src', 'scripts', 'fixture_hook.ts'), header + body);
194
+ fs.writeFileSync(
195
+ path.join(dir, 'src', 'scripts', 'hook_manifest.yaml'),
196
+ `schema_version: 1\nconcerns:\n fixture:\n script: src/scripts/fixture_hook.ts\nplatforms:\n claude:\n ${slot}:\n - fixture\n`,
197
+ );
198
+ }
199
+
200
+ const NO_DECL = '';
201
+ const DECL_RECOVERABLE = '/**\n * loss_class: recoverable-lossy\n * loss_recovery: agents/knowledge/intake/<file>:<a>-<b>\n */\n';
202
+ const DECL_RECOVERABLE_NO_LOCATOR = '/**\n * loss_class: recoverable-lossy\n */\n';
203
+ const DECL_EPHEMERAL = '/**\n * loss_class: ephemeral-lossy\n */\n';
204
+ const DECL_TYPO = '/**\n * loss_class: recoverable_lossy\n */\n';
205
+
206
+ function selfTestCases(): SelfTestCase[] {
207
+ const mk = (name: string, expect: 'reject' | 'accept', header: string, body: string, slot?: string): SelfTestCase => ({
208
+ name,
209
+ expect,
210
+ run: () => {
211
+ const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'lcd-'));
212
+ try {
213
+ plant(dir, header, body, slot);
214
+ return runGateCli(REPO_ROOT, 'src/scripts/check_loss_class_declared.ts', ['--root', dir, '--quiet'], REPO_ROOT);
215
+ } finally {
216
+ fs.rmSync(dir, { recursive: true, force: true });
217
+ }
218
+ },
219
+ });
220
+ return [
221
+ mk('model-facing lossy transform with no declaration → reject', 'reject', NO_DECL, LOSSY_EMITTER),
222
+ mk('same transform with recoverable-lossy + locator → accept', 'accept', DECL_RECOVERABLE, LOSSY_EMITTER),
223
+ mk('recoverable-lossy WITHOUT a locator → reject', 'reject', DECL_RECOVERABLE_NO_LOCATOR, LOSSY_EMITTER),
224
+ mk('ephemeral-lossy (owes no locator) → accept', 'accept', DECL_EPHEMERAL, LOSSY_EMITTER),
225
+ mk('a misspelled class is not honoured → reject', 'reject', DECL_TYPO, LOSSY_EMITTER),
226
+ mk('non-lossy emitter needs no declaration → accept', 'accept', NO_DECL, `export function run(){return {context:'hi'};}`),
227
+ mk('lossy but emits no context → accept', 'accept', NO_DECL, `const WORD_CAP=5;export function run(){return body.slice(0,WORD_CAP);}`),
228
+ mk('prose about truncation is not truncation → accept', 'accept', NO_DECL, `/* we deliberately never truncate or redact here */\nexport function run(){return {context:'hi'};}`),
229
+ ];
230
+ }
231
+
232
+ // ---------------------------------------------------------------------- CLI
233
+
234
+ export function main(argv: string[] = process.argv.slice(2)): number {
235
+ if (argv.includes('--self-test')) {
236
+ return runSelfTest({ gate: 'check_loss_class_declared', cases: selfTestCases(), minCases: 7, minRejectCases: 3 });
237
+ }
238
+ const quiet = argv.includes('--quiet');
239
+ const json = argv.includes('--json');
240
+ const ri = argv.indexOf('--root');
241
+ const rootArg = ri !== -1 ? argv[ri + 1] : undefined;
242
+ const root = rootArg !== undefined ? path.resolve(rootArg) : REPO_ROOT;
243
+
244
+ const ledger = new GateLedger('check_loss_class_declared');
245
+ let v: LossVerdict;
246
+ try {
247
+ v = evaluate(root, ledger);
248
+ } catch (err) {
249
+ process.stderr.write(`❌ check_loss_class_declared: ${(err as Error).message}\n`);
250
+ return 2;
251
+ }
252
+
253
+ try {
254
+ reportScanned({ gate: 'check_loss_class_declared', scanned: v.scanned, units: 'hook script(s)', roots: ['src/scripts/hook_manifest.yaml'] });
255
+ } catch (err) {
256
+ if (err instanceof DeadScopeError) {
257
+ process.stderr.write(`❌ check_loss_class_declared: ${err.message}\n`);
258
+ return 2;
259
+ }
260
+ throw err;
261
+ }
262
+
263
+ ledger.report();
264
+
265
+ if (json) {
266
+ process.stdout.write(JSON.stringify(v, null, 2) + '\n');
267
+ return v.findings.some((f) => f.tier === 'fail') ? 1 : 0;
268
+ }
269
+
270
+ const say = (f: LossFinding): string => {
271
+ switch (f.problem.kind) {
272
+ case 'missing':
273
+ return 'declares no loss_class';
274
+ case 'unknown-class':
275
+ return `declares loss_class: ${f.problem.value}, which is not one of the five`;
276
+ case 'missing-recovery':
277
+ return 'declares recoverable-lossy but no loss_recovery locator — without one the class is indistinguishable from ephemeral-lossy';
278
+ }
279
+ };
280
+
281
+ for (const f of v.findings) {
282
+ const stream = f.tier === 'fail' ? process.stderr : process.stdout;
283
+ stream.write(`${f.tier === 'fail' ? '❌' : '⚠️ '} ${f.concern} (${f.script}) shortens content on a model-facing path and ${say(f)}\n`);
284
+ }
285
+
286
+ if (v.findings.some((f) => f.tier === 'fail')) {
287
+ process.stderr.write(
288
+ `\n Add a declaration to the module's own docblock:\n` +
289
+ ` loss_class: exact | lossless | recoverable-lossy | ephemeral-lossy | forbidden\n` +
290
+ ` loss_recovery: <where the original is retrievable> # recoverable-lossy only\n` +
291
+ ` Contract: docs/contracts/loss-classes.md\n`,
292
+ );
293
+ return 1;
294
+ }
295
+ if (!quiet) {
296
+ process.stdout.write(
297
+ `✅ every model-facing lossy transform declares its loss class ` +
298
+ `(${String(v.modelFacing)} model-facing of ${String(v.scanned)} hook script(s)).\n`,
299
+ );
300
+ }
301
+ return 0;
302
+ }
303
+
304
+ if (process.env['GATE_SELF_TEST_CHILD'] !== '1' || process.argv.includes('--root')) {
305
+ if (process.argv[1] !== undefined && import.meta.url === `file://${process.argv[1]}`) {
306
+ process.exit(main());
307
+ }
308
+ }
@@ -20,6 +20,7 @@ import * as fs from 'node:fs';
20
20
  import * as path from 'node:path';
21
21
  import { fileURLToPath, pathToFileURL } from 'node:url';
22
22
 
23
+ import { classifyMarkdownLines } from './_lib/md_prose_lines.js';
23
24
  import { assertScanned, DeadScopeError } from './_lib/scan_scope.js';
24
25
 
25
26
  // Umlauts and German-only characters.
@@ -52,9 +53,6 @@ function _escapeRegExp(s: string): string {
52
53
  // Labeled bilingual anchor: lines starting with "DE:" or "- DE:" (and EN).
53
54
  const DE_ANCHOR_RE = /^\s*[-*]?\s*(DE|EN):\s/i;
54
55
 
55
- // Inline code spans.
56
- const INLINE_CODE_RE = /`[^`]*`/g;
57
-
58
56
  // Per-line escape marker.
59
57
  const IGNORE_RE = /<!--\s*md-language-check:\s*ignore\s*-->/i;
60
58
 
@@ -66,120 +64,39 @@ export interface Violation {
66
64
  context: string;
67
65
  }
68
66
 
69
- function _strip_inline_code(text: string): string {
70
- return text.replace(INLINE_CODE_RE, '');
71
- }
72
-
73
- /** Python `str.splitlines()` — universal-newline split, no trailing empty element. */
74
- function splitlines(text: string): string[] {
75
- if (text === '') return [];
76
- const lines: string[] = [];
77
- let current = '';
78
- for (let i = 0; i < text.length; i++) {
79
- const ch = text[i] as string;
80
- const code = text.charCodeAt(i);
81
- if (ch === '\r') {
82
- lines.push(current);
83
- current = '';
84
- if (text[i + 1] === '\n') i += 1; // \r\n consumed as one
85
- continue;
86
- }
87
- if (
88
- ch === '\n' ||
89
- code === 0x0b ||
90
- code === 0x0c ||
91
- code === 0x1c ||
92
- code === 0x1d ||
93
- code === 0x1e ||
94
- code === 0x85 ||
95
- code === 0x2028 ||
96
- code === 0x2029
97
- ) {
98
- lines.push(current);
99
- current = '';
100
- continue;
101
- }
102
- current += ch;
103
- }
104
- if (current !== '') lines.push(current);
105
- return lines;
106
- }
107
-
108
67
  export function scan_file(p: string): Violation[] {
109
68
  const violations: Violation[] = [];
110
- let lines: string[];
69
+ let content: string;
111
70
  try {
112
- lines = splitlines(fs.readFileSync(p, 'utf-8'));
71
+ content = fs.readFileSync(p, 'utf-8');
113
72
  } catch (exc) {
114
73
  const msg = exc instanceof Error ? exc.message : String(exc);
115
- process.stderr.write(`⚠️ Cannot read ${p}: ${msg}\n`);
74
+ process.stderr.write(`\u26a0\ufe0f Cannot read ${p}: ${msg}\n`);
116
75
  return violations;
117
76
  }
118
77
 
119
- let in_fence = false;
120
- let in_frontmatter = false;
121
- for (let idx = 0; idx < lines.length; idx++) {
122
- const raw = lines[idx] as string;
123
- const lineno = idx + 1;
124
- const stripped = _lstrip(raw);
125
-
126
- // YAML frontmatter at top of file.
127
- if (lineno === 1 && stripped === '---') {
128
- in_frontmatter = true;
129
- continue;
130
- }
131
- if (in_frontmatter) {
132
- if (stripped === '---') {
133
- in_frontmatter = false;
134
- }
135
- continue;
136
- }
137
-
138
- // Fenced code blocks.
139
- if (stripped.startsWith('```') || stripped.startsWith('~~~')) {
140
- in_fence = !in_fence;
141
- continue;
142
- }
143
- if (in_fence) {
144
- continue;
145
- }
146
-
147
- // Indented code blocks (4+ leading spaces, non-list).
148
- const listStarts = ['-', '*', '+', '1', '2', '3', '4', '5', '6', '7', '8', '9'];
149
- if (raw.startsWith(' ') && !listStarts.some((c) => stripped.startsWith(c))) {
150
- continue;
151
- }
152
-
153
- // Labeled bilingual anchor.
154
- if (DE_ANCHOR_RE.test(raw)) {
155
- continue;
156
- }
157
-
158
- // Per-line opt-out marker.
159
- if (IGNORE_RE.test(raw)) {
160
- continue;
161
- }
162
-
163
- // Strip inline code spans before scanning.
164
- const scan_text = _strip_inline_code(raw);
165
- const ctx = _rstrip(raw);
78
+ // Frontmatter / fence / indented-code / marker skipping is shared with
79
+ // `lint_canonical_terms` via `_lib/md_prose_lines` — see that module's
80
+ // header for why a second copy was refused. The classification is the same
81
+ // code this function used to carry inline; the DE:/EN: anchor and the
82
+ // per-line ignore marker are passed in as this gate's own markers.
83
+ for (const line of classifyMarkdownLines(content, { markers: [DE_ANCHOR_RE, IGNORE_RE] })) {
84
+ if (line.kind !== 'prose') continue;
85
+ const scan_text = line.text;
86
+ const ctx = _rstrip(line.raw);
166
87
 
167
88
  for (const m of scan_text.matchAll(UMLAUT_RE)) {
168
- violations.push({ file: p, line: lineno, kind: 'umlaut', match: m[0], context: ctx });
89
+ violations.push({ file: p, line: line.lineno, kind: 'umlaut', match: m[0], context: ctx });
169
90
  }
170
91
 
171
92
  for (const m of scan_text.matchAll(DE_WORD_RE)) {
172
- violations.push({ file: p, line: lineno, kind: 'de_word', match: m[0], context: ctx });
93
+ violations.push({ file: p, line: line.lineno, kind: 'de_word', match: m[0], context: ctx });
173
94
  }
174
95
  }
175
96
 
176
97
  return violations;
177
98
  }
178
99
 
179
- function _lstrip(s: string): string {
180
- return s.replace(/^\s+/, '');
181
- }
182
-
183
100
  function _rstrip(s: string): string {
184
101
  return s.replace(/\s+$/, '');
185
102
  }
@@ -230,14 +230,24 @@ function parse_args(argv: readonly string[]): ParsedArgs {
230
230
  let quiet = false;
231
231
  for (let i = 0; i < argv.length; i++) {
232
232
  const arg = argv[i]!;
233
- if (arg === '--intake-id') {
234
- intake_id = _need(argv, ++i, '--intake-id');
235
- } else if (arg.startsWith('--intake-id=')) {
236
- intake_id = arg.slice('--intake-id='.length);
237
- } else if (arg === '--proposal') {
238
- proposal = _need(argv, ++i, '--proposal');
239
- } else if (arg.startsWith('--proposal=')) {
240
- proposal = arg.slice('--proposal='.length);
233
+ // Mutual exclusion is checked INLINE, at the second flag, and the error
234
+ // names the flag that arrived second. That is what argparse does with a
235
+ // mutually exclusive group, and this file mirrors argparse's messages
236
+ // exactly — the post-loop check it replaced was order-stable and always
237
+ // blamed `--proposal`, which inverts the blame when `--proposal` came
238
+ // first. Reconciled toward the TEMPLATE side (road-to-memory-twin
239
+ // -reconciliation 2.1): the copy that looked like the drift was the
240
+ // faithful one.
241
+ if (arg === '--intake-id' || arg.startsWith('--intake-id=')) {
242
+ if (proposal !== null) {
243
+ _argparse_error('argument --intake-id: not allowed with argument --proposal');
244
+ }
245
+ intake_id = arg === '--intake-id' ? _need(argv, ++i, '--intake-id') : arg.slice('--intake-id='.length);
246
+ } else if (arg === '--proposal' || arg.startsWith('--proposal=')) {
247
+ if (intake_id !== null) {
248
+ _argparse_error('argument --proposal: not allowed with argument --intake-id');
249
+ }
250
+ proposal = arg === '--proposal' ? _need(argv, ++i, '--proposal') : arg.slice('--proposal='.length);
241
251
  } else if (arg === '--format') {
242
252
  const v = _need(argv, ++i, '--format');
243
253
  format = _checkFormat(v);
@@ -255,9 +265,6 @@ function parse_args(argv: readonly string[]): ParsedArgs {
255
265
  _argparse_error(`unrecognized arguments: ${arg}`);
256
266
  }
257
267
  }
258
- if (intake_id !== null && proposal !== null) {
259
- _argparse_error('argument --proposal: not allowed with argument --intake-id');
260
- }
261
268
  if (intake_id === null && proposal === null) {
262
269
  _argparse_error('one of the arguments --intake-id --proposal is required');
263
270
  }