@khoavu882/doflow 2.0.0-beta.4 → 2.0.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 (497) hide show
  1. package/README.md +12 -11
  2. package/bin/doflow.js +21 -11
  3. package/core/.antigravity-plugin/plugin.json +1 -3
  4. package/core/.claude-plugin/plugin.json +1 -1
  5. package/core/.codex-plugin/plugin.json +1 -1
  6. package/core/.plugin/plugin.json +1 -1
  7. package/core/harnesses/claude/hooks/lib.sh +43 -24
  8. package/core/harnesses/claude/hooks/mcp-tool-guard.sh +7 -17
  9. package/core/harnesses/claude/hooks/permission-audit.sh +3 -0
  10. package/core/harnesses/claude/hooks/post-compact.sh +35 -32
  11. package/core/harnesses/claude/hooks/post-edit-lint.sh +2 -0
  12. package/core/harnesses/claude/hooks/post-shell-observe.sh +48 -0
  13. package/core/harnesses/claude/hooks/post-tool-failure.sh +3 -0
  14. package/core/harnesses/claude/hooks/pre-bash-guard.sh +7 -17
  15. package/core/harnesses/claude/hooks/pre-compact.sh +23 -27
  16. package/core/harnesses/claude/hooks/pre-implement-gate.sh +7 -18
  17. package/core/harnesses/claude/hooks/session-end.sh +23 -10
  18. package/core/harnesses/claude/hooks/session-start.sh +5 -3
  19. package/core/harnesses/claude/hooks/skill-config-audit.sh +3 -0
  20. package/core/harnesses/claude/hooks/stop-check.sh +5 -3
  21. package/core/harnesses/claude/hooks/subagent-audit.sh +5 -5
  22. package/core/harnesses/claude/hooks/user-prompt-submit.sh +5 -3
  23. package/core/harnesses/claude/settings/settings.json +18 -0
  24. package/core/harnesses/claude/statusline/doflow-statusline.sh +1 -0
  25. package/core/harnesses/codex/agents/core-implementer.toml +1 -0
  26. package/core/harnesses/codex/agents/delivery-lead.toml +10 -0
  27. package/core/harnesses/codex/agents/quality-guardian.toml +1 -1
  28. package/core/harnesses/codex/agents/research-writer.toml +1 -1
  29. package/core/harnesses/codex/agents/reviewer.toml +10 -0
  30. package/core/harnesses/codex/agents/spec-analyst.toml +1 -1
  31. package/core/harnesses/codex/agents/system-architect.toml +1 -1
  32. package/core/harnesses/codex/hooks/lib.sh +44 -25
  33. package/core/harnesses/codex/hooks/mcp-tool-guard.sh +7 -15
  34. package/core/harnesses/codex/hooks/post-edit-lint.impl.sh +3 -1
  35. package/core/harnesses/codex/hooks/pre-bash-guard.sh +7 -15
  36. package/core/harnesses/codex/hooks/pre-compact.impl.sh +29 -26
  37. package/core/harnesses/codex/hooks/pre-implement-gate.sh +7 -16
  38. package/core/harnesses/codex/hooks/session-end.impl.sh +23 -10
  39. package/core/harnesses/codex/hooks/session-start.sh +5 -3
  40. package/core/harnesses/codex/hooks/stop-check.sh +6 -5
  41. package/core/harnesses/codex/hooks/subagent-audit.sh +18 -6
  42. package/core/harnesses/codex/hooks/user-prompt-submit.sh +5 -4
  43. package/core/harnesses/copilot/hooks/doflow-lib.sh +93 -0
  44. package/core/harnesses/copilot/hooks/doflow-mcp-tool-guard.sh +9 -0
  45. package/core/harnesses/copilot/hooks/doflow-pre-bash-guard.sh +9 -0
  46. package/core/harnesses/copilot/hooks/doflow-pre-implement-gate.sh +9 -0
  47. package/core/harnesses/copilot/hooks/doflow-session-start.sh +9 -0
  48. package/core/harnesses/copilot/hooks/doflow-stop-check.sh +9 -0
  49. package/core/harnesses/copilot/hooks/doflow-subagent-start.sh +9 -0
  50. package/core/harnesses/copilot/hooks/doflow-subagent-stop.sh +9 -0
  51. package/core/harnesses/copilot/hooks/doflow.json +57 -0
  52. package/core/harnesses/kiro/agents/doflow.json +1 -1
  53. package/core/harnesses/kiro/hooks/lib.sh +26 -6
  54. package/core/harnesses/kiro/hooks/mcp-tool-guard.sh +21 -5
  55. package/core/harnesses/kiro/hooks/pre-bash-guard.sh +21 -5
  56. package/core/harnesses/kiro/hooks/pre-implement-gate.sh +21 -5
  57. package/core/harnesses/kiro/hooks/session-start.sh +12 -5
  58. package/core/harnesses/kiro/hooks/stop-check.sh +22 -30
  59. package/core/harnesses/pi/extensions/doflow-guard.js +167 -0
  60. package/core/harnesses/shared/hooks/ENVELOPE_MIGRATION.md +27 -12
  61. package/core/harnesses/shared/hooks/adapters/antigravity.js +14 -57
  62. package/core/harnesses/shared/hooks/bridge/bridge.sh +277 -0
  63. package/core/harnesses/shared/hooks/bridge/envelope.jq +129 -0
  64. package/core/harnesses/shared/hooks/bridge/observe-model.sh +75 -0
  65. package/core/harnesses/shared/hooks/bridge/respond.sh +70 -0
  66. package/core/harnesses/shared/hooks/policies/blocked-patterns.conf +28 -14
  67. package/core/harnesses/shared/hooks/policies/capture-failure.sh +51 -16
  68. package/core/harnesses/shared/hooks/policies/compact-text.sh +46 -0
  69. package/core/harnesses/shared/hooks/policies/contract.sh +78 -0
  70. package/core/harnesses/shared/hooks/policies/deny-json.sh +35 -9
  71. package/core/harnesses/shared/hooks/policies/emission-rules.sh +37 -0
  72. package/core/harnesses/shared/hooks/policies/emission.jq +209 -0
  73. package/core/harnesses/shared/hooks/policies/emission.sh +383 -0
  74. package/core/harnesses/shared/hooks/policies/identity.sh +177 -0
  75. package/core/harnesses/shared/hooks/policies/lib.sh +65 -40
  76. package/core/harnesses/shared/hooks/policies/mcp-tool-guard.sh +48 -35
  77. package/core/harnesses/shared/hooks/policies/pre-bash-guard.sh +284 -33
  78. package/core/harnesses/shared/hooks/policies/pre-implementation-gate.sh +180 -110
  79. package/core/harnesses/shared/hooks/policies/session-context.sh +66 -7
  80. package/core/harnesses/shared/hooks/policies/stop-check.sh +61 -23
  81. package/core/harnesses/shared/hooks/policies/subagent-audit.sh +39 -6
  82. package/core/harnesses/shared/hooks/policies/summary-store.sh +347 -0
  83. package/core/harnesses/shared/hooks/policies/user-prompt-submit.sh +97 -159
  84. package/core/harnesses/shared/hooks/stream-hook-runner.js +114 -187
  85. package/core/harnesses/shared/locator/doflow-run +2 -3
  86. package/core/registry/advice.json +3 -3
  87. package/core/registry/assets.json +72 -80
  88. package/core/registry/capabilities.json +12 -0
  89. package/core/registry/contracts.json +60 -33
  90. package/core/registry/contribution-points.json +32 -0
  91. package/core/registry/gates.json +32 -0
  92. package/core/registry/guidance-caps.json +40 -0
  93. package/core/registry/harnesses.json +1542 -277
  94. package/core/registry/lifecycle.json +2837 -37
  95. package/core/registry/mcp.json +5 -1
  96. package/core/registry/models.json +7 -1
  97. package/core/registry/package-templates/README.md +19 -0
  98. package/core/registry/package-templates/agent/files/agent.md +9 -0
  99. package/core/registry/package-templates/agent/template.json +4 -0
  100. package/core/registry/package-templates/capability-provider/files/provider.json +9 -0
  101. package/core/registry/package-templates/capability-provider/template.json +11 -0
  102. package/core/registry/package-templates/debate-preset/files/preset.json +26 -0
  103. package/core/registry/package-templates/debate-preset/template.json +4 -0
  104. package/core/registry/package-templates/review-preset/files/preset.json +30 -0
  105. package/core/registry/package-templates/review-preset/template.json +4 -0
  106. package/core/registry/package-templates/skill/files/SKILL.md +8 -0
  107. package/core/registry/package-templates/skill/template.json +4 -0
  108. package/core/registry/package-templates/worker/files/worker.json +92 -0
  109. package/core/registry/package-templates/worker/template.json +11 -0
  110. package/core/registry/packages/doflow/doflow-package.json +15 -0
  111. package/core/registry/packages/doflow/presets/debate-3.json +26 -0
  112. package/core/registry/protocols.json +61 -0
  113. package/core/registry/routes.json +17 -0
  114. package/core/registry/rules.json +431 -0
  115. package/core/registry/settings.json +276 -0
  116. package/core/registry/storage.json +701 -30
  117. package/core/registry/telemetry.json +236 -0
  118. package/core/registry/transcripts.json +142 -0
  119. package/core/registry/verification.json +76 -1
  120. package/core/registry/workflows.json +55 -0
  121. package/core/shared/agent-specs/core-implementer.md +3 -0
  122. package/core/shared/agent-specs/delivery-lead.md +68 -0
  123. package/core/shared/agent-specs/quality-guardian.md +5 -1
  124. package/core/shared/agent-specs/research-writer.md +10 -3
  125. package/core/shared/agent-specs/reviewer.md +53 -0
  126. package/core/shared/agent-specs/spec-analyst.md +5 -6
  127. package/core/shared/agent-specs/system-architect.md +5 -1
  128. package/core/shared/guidance/DOFLOW_CORE.md +1 -5
  129. package/core/shared/guidance/modes/MODE_DeepResearch.md +1 -1
  130. package/core/shared/guidance/modes/MODE_Orchestration.md +4 -3
  131. package/core/shared/guidance/modes/MODE_Task_Management.md +14 -14
  132. package/core/shared/guidance/pointers/codex.md +1 -4
  133. package/core/shared/guidance/references/ARTIFACT_FORMAT.md +30 -16
  134. package/core/shared/guidance/references/ARTIFACT_VOICE.md +3 -2
  135. package/core/shared/guidance/references/CONSTITUTION_BASE.md +17 -15
  136. package/core/shared/guidance/references/DIAGRAM_GUIDE.md +1 -1
  137. package/core/shared/guidance/references/DOFLOW_CHAIN.md +17 -19
  138. package/core/shared/guidance/references/EVIDENCE_LEDGER.md +7 -8
  139. package/core/shared/guidance/references/MODEL_SELECTION.md +5 -3
  140. package/core/shared/guidance/references/ORCHESTRATION.md +1 -2
  141. package/core/shared/guidance/rules/RULES.md +45 -0
  142. package/core/shared/scripts/doflow/bash/do-args.sh +37 -0
  143. package/core/shared/scripts/doflow/bash/do-exec-paths.sh +4 -0
  144. package/core/shared/scripts/doflow/bash/do-git-state.sh +15 -4
  145. package/core/shared/scripts/doflow/bash/do-parallel-check.sh +4 -0
  146. package/core/shared/scripts/doflow/bash/do-paths.sh +40 -2
  147. package/core/shared/scripts/doflow/bash/do-prereqs.sh +2 -1
  148. package/core/shared/scripts/doflow/bash/do-review-package.sh +4 -0
  149. package/core/shared/scripts/doflow/bash/do-task-brief.sh +58 -16
  150. package/core/shared/scripts/doflow/bash/render-audit.sh +26 -2
  151. package/core/shared/scripts/doflow/bash/render-diagrams.sh +1 -0
  152. package/core/shared/scripts/doflow/bash/render-puml.sh +2 -1
  153. package/core/shared/scripts/doflow/bash/validate-artifacts.sh +48 -4
  154. package/core/shared/scripts/doflow/bin/doflow-run +154 -35
  155. package/core/shared/skills/do/SKILL.md +12 -10
  156. package/core/shared/skills/do/references/advice_calls.md +26 -0
  157. package/core/shared/skills/do/references/pm_routing.md +1 -2
  158. package/core/shared/skills/do/references/program_mode.md +31 -0
  159. package/core/shared/skills/do-brainstorm/SKILL.md +20 -74
  160. package/core/shared/skills/do-brainstorm/references/handoff_branches.md +35 -0
  161. package/core/shared/skills/do-brainstorm/references/intent_seed.md +21 -0
  162. package/core/shared/skills/do-brainstorm/references/round_log.md +17 -0
  163. package/core/shared/skills/do-code-review/SKILL.md +41 -144
  164. package/core/shared/skills/do-code-review/content-types/markdown.md +24 -2
  165. package/core/shared/skills/do-code-review/references/tools.md +90 -0
  166. package/core/shared/skills/do-code-review/scripts/doc_quality_checker.py +549 -7
  167. package/core/shared/skills/do-design/SKILL.md +24 -23
  168. package/core/shared/skills/do-diagnose/SKILL.md +14 -4
  169. package/core/shared/skills/do-document/SKILL.md +11 -1
  170. package/core/shared/skills/do-document/references/deep_research.md +1 -2
  171. package/core/shared/skills/do-document/references/embedded-research.md +18 -6
  172. package/core/shared/skills/do-document/references/implementation-flow.md +5 -6
  173. package/core/shared/skills/do-execute-plan/SKILL.md +17 -59
  174. package/core/shared/skills/do-execute-plan/references/handoff_record.md +7 -2
  175. package/core/shared/skills/do-execute-plan/references/parallel_dispatch.md +13 -0
  176. package/core/shared/skills/do-execute-plan/references/readiness_gate.md +28 -1
  177. package/core/shared/skills/do-execute-plan/references/run_position.md +13 -1
  178. package/core/shared/skills/do-execute-plan/references/scaffold.md +17 -9
  179. package/core/shared/skills/do-execute-plan/references/state_checkpoint.md +11 -0
  180. package/core/shared/skills/do-execute-plan/references/task_attempts.md +78 -24
  181. package/core/shared/skills/do-flow/SKILL.md +8 -9
  182. package/core/shared/skills/do-flow/references/task_classes.md +2 -2
  183. package/core/shared/skills/do-git/SKILL.md +4 -0
  184. package/core/shared/skills/do-implement/SKILL.md +7 -9
  185. package/core/shared/skills/do-plan/SKILL.md +29 -19
  186. package/core/shared/skills/do-test/SKILL.md +7 -4
  187. package/core/shared/templates/doflow/constitution-template.md +9 -3
  188. package/core/shared/templates/doflow/data-model-template.md +1 -1
  189. package/core/shared/templates/doflow/design-template.md +113 -16
  190. package/core/shared/templates/doflow/plan-template.md +11 -10
  191. package/core/shared/templates/doflow/question-log-template.md +14 -2
  192. package/core/shared/templates/doflow/requirement-template.md +1 -1
  193. package/core/worker-evidence/antigravity/checks.json +14 -0
  194. package/core/worker-evidence/codex/2026-10-18-cli-check.json +107 -0
  195. package/core/worker-evidence/codex/2026-10-18-live-run-edit.json +73 -0
  196. package/core/worker-evidence/codex/2026-10-18-live-run-read-only.json +62 -0
  197. package/core/worker-evidence/codex/2026-10-24-cli-check.json +126 -0
  198. package/core/worker-evidence/codex/checks.json +38 -0
  199. package/package.json +10 -6
  200. package/src/adapters/antigravity/index.js +226 -113
  201. package/src/adapters/claude/index.js +39 -5
  202. package/src/adapters/codex/agents.js +25 -15
  203. package/src/adapters/codex/hooks.js +40 -5
  204. package/src/adapters/codex/index.js +100 -22
  205. package/src/adapters/codex/native-projection.js +6 -2
  206. package/src/adapters/copilot/index.js +58 -23
  207. package/src/adapters/copy-tree.js +294 -48
  208. package/src/adapters/guidance-manifest.js +71 -0
  209. package/src/adapters/guidance-pointer.js +19 -0
  210. package/src/adapters/hook-commands.js +6 -10
  211. package/src/adapters/index.js +1 -0
  212. package/src/adapters/kiro/index.js +38 -13
  213. package/src/adapters/opencode/index.js +8 -8
  214. package/src/adapters/pi/hooks.js +120 -0
  215. package/src/adapters/pi/index.js +48 -16
  216. package/src/adapters/resolve-source.js +26 -2
  217. package/src/cli/commands/install.js +3 -2
  218. package/src/cli/commands/reconcile.js +53 -9
  219. package/src/cli/commands/remove.js +2 -2
  220. package/src/cli/commands/rollback.js +6 -3
  221. package/src/cli/commands/self-update.js +18 -9
  222. package/src/cli/commands/status.js +21 -2
  223. package/src/cli/commands/ui.js +99 -0
  224. package/src/cli/commands/update.js +3 -2
  225. package/src/cli/index.js +338 -33
  226. package/src/cli/runtime-commands.js +243 -52
  227. package/src/cli/shared.js +0 -2
  228. package/src/helper/git.js +1 -1
  229. package/src/helper/guardrails.js +1 -1
  230. package/src/helper/marker-merge.js +31 -13
  231. package/src/helper/package-ids.js +37 -0
  232. package/src/helper/semver.js +94 -0
  233. package/src/install/backup.js +105 -15
  234. package/src/install/context.js +1 -1
  235. package/src/install/targets.js +31 -16
  236. package/src/lifecycle/coverage.js +74 -0
  237. package/src/lifecycle/hook-step.js +61 -0
  238. package/src/lifecycle/hook-tier.js +160 -0
  239. package/src/lifecycle/index.js +434 -86
  240. package/src/lifecycle/retired-harnesses.js +318 -0
  241. package/src/lifecycle/view.js +35 -15
  242. package/src/registry/index.js +686 -32
  243. package/src/registry/worker-ids.js +45 -0
  244. package/src/release/build-package.js +0 -3
  245. package/src/release/docs-blocks.js +492 -0
  246. package/src/release/preflight.js +425 -0
  247. package/src/release/rehearse.js +401 -0
  248. package/src/release/release-workflow.js +733 -0
  249. package/src/release/sync-plugin-versions.js +43 -7
  250. package/src/runtime/advice/bench-gate.js +25 -0
  251. package/src/runtime/advice/cli.js +59 -16
  252. package/src/runtime/advice/client.js +32 -9
  253. package/src/runtime/advice/config.js +98 -133
  254. package/src/runtime/advice/doctor.js +1 -1
  255. package/src/runtime/advice/elevation.js +97 -0
  256. package/src/runtime/advice/endpoint-guard.js +9 -3
  257. package/src/runtime/advice/mode.js +37 -0
  258. package/src/runtime/advice/record.js +18 -5
  259. package/src/runtime/advice/registry.js +4 -1
  260. package/src/runtime/advice/shadow-config.js +229 -0
  261. package/src/runtime/advice/shadow-dispatcher.js +276 -0
  262. package/src/runtime/brief-rules.js +81 -0
  263. package/src/runtime/brief-tools.js +111 -34
  264. package/src/runtime/candidate.js +514 -0
  265. package/src/runtime/capabilities/executor.js +450 -0
  266. package/src/runtime/capabilities/loopback.js +41 -0
  267. package/src/runtime/capabilities/sanitizer.js +88 -0
  268. package/src/runtime/capability-router.js +135 -3
  269. package/src/runtime/checkouts.js +73 -11
  270. package/src/runtime/claims.js +27 -12
  271. package/src/runtime/cli-result.js +11 -4
  272. package/src/runtime/cli.js +221 -277
  273. package/src/runtime/config-home.js +42 -0
  274. package/src/runtime/context/arbitrate.js +767 -0
  275. package/src/runtime/context/budget.js +203 -0
  276. package/src/runtime/context/compose.js +1367 -0
  277. package/src/runtime/context/delivery-store.js +100 -0
  278. package/src/runtime/context/emission-rules.js +118 -0
  279. package/src/runtime/context/identity.js +227 -0
  280. package/src/runtime/context/mandatory.js +594 -0
  281. package/src/runtime/context/pointer.js +142 -0
  282. package/src/runtime/context/primary-command.js +117 -0
  283. package/src/runtime/context/primary.js +344 -0
  284. package/src/runtime/context/summary-store.js +655 -0
  285. package/src/runtime/context-pack.js +1106 -245
  286. package/src/runtime/decision-register.js +13 -4
  287. package/src/runtime/dispatch/admission.js +392 -0
  288. package/src/runtime/dispatch/attempt-end.js +274 -0
  289. package/src/runtime/dispatch/command.js +628 -0
  290. package/src/runtime/dispatch/controls.js +904 -0
  291. package/src/runtime/dispatch/envelope.js +276 -0
  292. package/src/runtime/dispatch/grants.js +310 -0
  293. package/src/runtime/dispatch/integrate.js +617 -0
  294. package/src/runtime/dispatch/loop.js +1835 -0
  295. package/src/runtime/dispatch/store.js +352 -0
  296. package/src/runtime/dispatch/verify-run.js +201 -0
  297. package/src/runtime/evidence-fields.js +39 -0
  298. package/src/runtime/evidence-ledger.js +41 -7
  299. package/src/runtime/failure/capture.js +3 -1
  300. package/src/runtime/failure/cli.js +25 -9
  301. package/src/runtime/failure/home.js +57 -30
  302. package/src/runtime/failure/store.js +7 -2
  303. package/src/runtime/feature-pointer.js +174 -0
  304. package/src/runtime/feature-resolve.js +13 -2
  305. package/src/runtime/fleet/command.js +77 -0
  306. package/src/runtime/fleet/projects.js +178 -0
  307. package/src/runtime/fleet/tree.js +383 -0
  308. package/src/runtime/freshness.js +77 -10
  309. package/src/runtime/git-memo.js +46 -0
  310. package/src/runtime/guidance/ablation.js +427 -0
  311. package/src/runtime/health.js +565 -17
  312. package/src/runtime/history-compactor.js +13 -3
  313. package/src/runtime/implementation-gate.js +277 -22
  314. package/src/runtime/inventory/coverage.js +1 -1
  315. package/src/runtime/inventory/index.js +1 -1
  316. package/src/runtime/inventory/precedence.js +2 -2
  317. package/src/runtime/inventory/siblings.js +6 -4
  318. package/src/runtime/knowledge/code-corpus.js +277 -0
  319. package/src/runtime/knowledge/code-lexical.js +130 -0
  320. package/src/runtime/knowledge/code-retrieval.js +307 -0
  321. package/src/runtime/knowledge/code-validation.js +106 -0
  322. package/src/runtime/knowledge/gp3-gate.js +74 -0
  323. package/src/runtime/knowledge/graph-adapter.js +288 -0
  324. package/src/runtime/knowledge/graph-fallback.js +394 -0
  325. package/src/runtime/knowledge/hybrid.js +136 -8
  326. package/src/runtime/knowledge/retrieval.js +34 -1
  327. package/src/runtime/knowledge/rtk-compress.js +77 -0
  328. package/src/runtime/knowledge/semble-bridge.py +106 -0
  329. package/src/runtime/knowledge/semble-lifecycle.js +114 -0
  330. package/src/runtime/knowledge/semble-provider.js +365 -0
  331. package/src/runtime/lifecycle/cli.js +16 -6
  332. package/src/runtime/lifecycle/event-store.js +8 -6
  333. package/src/runtime/lifecycle/followup.js +6 -1
  334. package/src/runtime/lifecycle/overview.js +24 -1
  335. package/src/runtime/lifecycle/report-store.js +8 -10
  336. package/src/runtime/lifecycle/retention.js +95 -31
  337. package/src/runtime/lifecycle/root.js +9 -1
  338. package/src/runtime/lifecycle/status.js +34 -17
  339. package/src/runtime/lifecycle/store-upkeep.js +56 -7
  340. package/src/runtime/mask.js +134 -7
  341. package/src/runtime/mcp-consultations.js +40 -6
  342. package/src/runtime/model-router.js +79 -7
  343. package/src/runtime/models/catalogue.js +191 -0
  344. package/src/runtime/models/command.js +153 -0
  345. package/src/runtime/off-words.js +12 -0
  346. package/src/runtime/outcome.js +3 -3
  347. package/src/runtime/packages/command.js +1009 -0
  348. package/src/runtime/packages/contributions.js +116 -0
  349. package/src/runtime/packages/digest.js +132 -0
  350. package/src/runtime/packages/fetch.js +182 -0
  351. package/src/runtime/packages/grants.js +192 -0
  352. package/src/runtime/packages/index-file.js +134 -0
  353. package/src/runtime/packages/instruction.js +90 -0
  354. package/src/runtime/packages/manifest.js +331 -0
  355. package/src/runtime/packages/points.js +477 -0
  356. package/src/runtime/packages/programs.js +216 -0
  357. package/src/runtime/packages/scaffold.js +277 -0
  358. package/src/runtime/packages/source.js +90 -0
  359. package/src/runtime/packages/state.js +164 -0
  360. package/src/runtime/packages/store.js +449 -0
  361. package/src/runtime/packages/tar.js +106 -0
  362. package/src/runtime/packages/view.js +406 -0
  363. package/src/runtime/plan-check.js +59 -0
  364. package/src/runtime/plan-content.js +324 -0
  365. package/src/runtime/policy-init.js +118 -0
  366. package/src/runtime/profiles/doctor.js +96 -0
  367. package/src/runtime/profiles/resolve.js +244 -0
  368. package/src/runtime/profiles/rollback.js +254 -0
  369. package/src/runtime/profiles/sampler.js +41 -0
  370. package/src/runtime/readiness-record.js +16 -11
  371. package/src/runtime/readiness.js +127 -16
  372. package/src/runtime/research-request.js +50 -25
  373. package/src/runtime/retrieval-plan.js +402 -73
  374. package/src/runtime/retrieval-record.js +293 -0
  375. package/src/runtime/review/command.js +246 -0
  376. package/src/runtime/review/dominance.js +68 -0
  377. package/src/runtime/review/findings.js +434 -0
  378. package/src/runtime/review/identity.js +255 -0
  379. package/src/runtime/review/protocol-command.js +109 -0
  380. package/src/runtime/review/protocols.js +405 -0
  381. package/src/runtime/review/resolve-protocol.js +302 -0
  382. package/src/runtime/review/start.js +530 -0
  383. package/src/runtime/roadmap/facts.js +479 -0
  384. package/src/runtime/roadmap/gates.js +270 -0
  385. package/src/runtime/roadmap/loop.js +1636 -0
  386. package/src/runtime/roadmap/merge.js +381 -0
  387. package/src/runtime/roadmap/rows.js +1113 -0
  388. package/src/runtime/roadmap/seed.js +951 -0
  389. package/src/runtime/rules-report.js +336 -0
  390. package/src/runtime/scaffold/artifacts.js +63 -9
  391. package/src/runtime/scaffold/generate.js +21 -9
  392. package/src/runtime/settings/autopilot.js +106 -0
  393. package/src/runtime/settings/cli.js +280 -0
  394. package/src/runtime/settings/config-write.js +314 -0
  395. package/src/runtime/settings/files.js +271 -0
  396. package/src/runtime/settings/legacy.js +154 -0
  397. package/src/runtime/settings/lexical.js +56 -0
  398. package/src/runtime/settings/prepared-run.js +269 -0
  399. package/src/runtime/settings/project-layers.js +118 -0
  400. package/src/runtime/settings/refs.js +288 -0
  401. package/src/runtime/settings/registry.js +553 -0
  402. package/src/runtime/settings/resolve.js +713 -0
  403. package/src/runtime/settings/shared.js +37 -0
  404. package/src/runtime/settings/worker-billing.js +107 -0
  405. package/src/runtime/settings/write.js +269 -0
  406. package/src/runtime/slot-command.js +78 -0
  407. package/src/runtime/slots.js +671 -0
  408. package/src/runtime/source-version.js +290 -0
  409. package/src/runtime/state-root.js +217 -0
  410. package/src/runtime/storage/cli.js +12 -5
  411. package/src/runtime/storage/engine.js +9 -2
  412. package/src/runtime/storage/registry.js +14 -1
  413. package/src/runtime/storage/roots.js +66 -16
  414. package/src/runtime/storage/rules.js +82 -10
  415. package/src/runtime/storage/upkeep.js +10 -2
  416. package/src/runtime/storage/work-status.js +245 -26
  417. package/src/runtime/task-attempts.js +589 -69
  418. package/src/runtime/task-classifier.js +47 -11
  419. package/src/runtime/task-graph.js +373 -0
  420. package/src/runtime/task-run.js +778 -0
  421. package/src/runtime/task-scope.js +202 -56
  422. package/src/runtime/task-sources.js +147 -0
  423. package/src/runtime/task-state.js +440 -65
  424. package/src/runtime/team/admission.js +301 -0
  425. package/src/runtime/team/envelope.js +324 -0
  426. package/src/runtime/team/review-guard.js +156 -0
  427. package/src/runtime/trace/analyze.js +427 -0
  428. package/src/runtime/trace/baseline.js +770 -0
  429. package/src/runtime/trace/ledger.js +63 -140
  430. package/src/runtime/trace/otlp-export.js +568 -0
  431. package/src/runtime/trace/otlp-map.js +481 -0
  432. package/src/runtime/trace/spans.js +745 -0
  433. package/src/runtime/trace/telemetry.js +225 -0
  434. package/src/runtime/trace/views.js +1 -0
  435. package/src/runtime/transcripts/command.js +98 -0
  436. package/src/runtime/transcripts/cursor.js +326 -0
  437. package/src/runtime/transcripts/read.js +126 -0
  438. package/src/runtime/transcripts/readers/claude-jsonl.js +74 -0
  439. package/src/runtime/transcripts/readers/codex-rollout.js +70 -0
  440. package/src/runtime/transcripts/readers/copilot-events.js +90 -0
  441. package/src/runtime/transcripts/readers/kiro-jsonl.js +77 -0
  442. package/src/runtime/transcripts/readers/pi-jsonl.js +59 -0
  443. package/src/runtime/transcripts/registry.js +161 -0
  444. package/src/runtime/transcripts/stats.js +161 -0
  445. package/src/runtime/verification/check-key.js +628 -0
  446. package/src/runtime/verification/contract-runner.js +546 -11
  447. package/src/runtime/verification/engine.js +499 -9
  448. package/src/runtime/verification/impact.js +617 -0
  449. package/src/runtime/verification/inflight.js +205 -0
  450. package/src/runtime/verification/registry.js +176 -0
  451. package/src/runtime/verification/reuse.js +184 -0
  452. package/src/runtime/verification/telemetry-emit.js +254 -0
  453. package/src/runtime/verification/test-selection.js +67 -7
  454. package/src/runtime/worker/active.js +90 -0
  455. package/src/runtime/worker/cancel.js +222 -0
  456. package/src/runtime/worker/catalogue.js +122 -0
  457. package/src/runtime/worker/command.js +677 -0
  458. package/src/runtime/worker/evidence.js +288 -0
  459. package/src/runtime/worker/launch.js +288 -0
  460. package/src/runtime/worker/models.js +137 -0
  461. package/src/runtime/worker/parsers.js +218 -0
  462. package/src/runtime/worker/probes/index.js +706 -0
  463. package/src/runtime/worker/process-tree.js +415 -0
  464. package/src/runtime/worker/quota.js +43 -0
  465. package/src/runtime/worker/readiness.js +713 -0
  466. package/src/runtime/worker/run-store.js +166 -0
  467. package/src/runtime/worker/supervisor.js +541 -0
  468. package/src/runtime/worker/worktree-check.js +252 -0
  469. package/src/runtime/workflow-engine.js +5 -1
  470. package/src/runtime/workflow-orchestrator.js +578 -63
  471. package/src/runtime/worktree.js +149 -22
  472. package/src/state/index.js +1 -1
  473. package/src/state/lockfile.js +64 -10
  474. package/src/state/run-lock.js +1 -1
  475. package/types/node-commonjs.d.ts +106 -7
  476. package/core/.antigravity-plugin/hooks.json +0 -39
  477. package/core/harnesses/gemini/hooks/hooks.json +0 -77
  478. package/core/harnesses/gemini/hooks/lib.sh +0 -302
  479. package/core/harnesses/gemini/hooks/mcp-tool-guard.sh +0 -21
  480. package/core/harnesses/gemini/hooks/post-edit-lint.sh +0 -39
  481. package/core/harnesses/gemini/hooks/pre-bash-guard.sh +0 -21
  482. package/core/harnesses/gemini/hooks/pre-compact.sh +0 -38
  483. package/core/harnesses/gemini/hooks/pre-implement-gate.sh +0 -22
  484. package/core/harnesses/gemini/hooks/session-end.impl.sh +0 -89
  485. package/core/harnesses/gemini/hooks/session-end.sh +0 -5
  486. package/core/harnesses/gemini/hooks/session-start.sh +0 -5
  487. package/core/harnesses/gemini/settings/adapter-defaults.json +0 -4
  488. package/core/harnesses/shared/hooks/adapters/arg-fields.js +0 -19
  489. package/core/harnesses/shared/hooks/adapters/gemini.js +0 -114
  490. package/core/harnesses/shared/hooks/hooks.json +0 -47
  491. package/core/shared/guidance/FLAGS.md +0 -25
  492. package/core/shared/guidance/rules/RULE_01_SAFETY.md +0 -25
  493. package/core/shared/guidance/rules/RULE_02_WORKFLOW.md +0 -23
  494. package/core/shared/guidance/rules/RULE_03_QUALITY.md +0 -14
  495. package/core/shared/guidance/rules/RULE_04_QUESTIONS.md +0 -46
  496. package/src/adapters/gemini/hooks.js +0 -210
  497. package/src/adapters/gemini/index.js +0 -390
@@ -7,6 +7,8 @@ const path = require('node:path');
7
7
  const crypto = require('node:crypto');
8
8
  const { execFileSync } = require('node:child_process');
9
9
  const { REPO_ROOT } = require('../helper/repo-root.js');
10
+ const { measureTreeState } = require('./source-version.js');
11
+
10
12
 
11
13
  // Freshness is measured against the bytes observed, not whether the file was clean at HEAD.
12
14
  // Git identity remains provenance and a conservative fallback for older records without hashes.
@@ -19,23 +21,58 @@ function fileHash(root , locator ) {
19
21
  } catch { return null; }
20
22
  }
21
23
 
22
- function measureFreshness(root , locator , gitCommit ) {
23
- return { gitCommit, fileHash: fileHash(root, locator), observedAt: new Date().toISOString(), status: 'FRESH' };
24
+ /**
25
+ * IC-007: the root a relative locator.file is read in: sourceRoot, except for a locator under
26
+ * `agent-docs/doflow/<slug>/` whose folder is absent in sourceRoot and present in the state root
27
+ * (the IC-005 `feature_root` case), which resolves in the state root. Any other missing file stays
28
+ * missing in sourceRoot (=> STALE/missing as today for a non-redirected file).
29
+ */
30
+ function fileRootFor(sourceRoot , stateRoot , locator ) {
31
+ const file = locator?.file;
32
+ if (typeof file !== 'string' || file === '' || path.isAbsolute(file) || path.resolve(sourceRoot) === path.resolve(stateRoot)) return sourceRoot;
33
+ const normalized = path.normalize(file).replace(/\\/g, '/');
34
+ const match = normalized.match(/^agent-docs\/doflow\/([^/]+)\/.+/);
35
+ if (match) {
36
+ const slug = match[1];
37
+ const folder = path.join('agent-docs', 'doflow', slug);
38
+ const isDir = (root ) => {
39
+ try { return fs.statSync(path.resolve(root, folder)).isDirectory(); } catch { return false; }
40
+ };
41
+ if (!isDir(sourceRoot) && isDir(stateRoot)) {
42
+ return stateRoot;
43
+ }
44
+ }
45
+ return sourceRoot;
46
+ }
47
+
48
+ // IC-007: a relative locator.file is hashed in sourceRoot, the checkout the verb runs in; `root`
49
+ // (the record store) is only the default. An absolute locator.file is hashed as is.
50
+ function measureFreshness(root , locator , gitCommit , sourceRoot = root) {
51
+ return { gitCommit, fileHash: fileHash(fileRootFor(sourceRoot, root, locator), locator), observedAt: new Date().toISOString(), status: 'FRESH' };
24
52
  }
25
53
 
26
54
  class FreshnessValidator {
27
55
  repoRoot ;
56
+ treeRoot ;
57
+ sourceRoot ;
28
58
  gitRunner ;
29
59
 
60
+
61
+ validatingLedger ;
30
62
 
31
63
  /**
32
64
  * @param {Object} [options]
33
65
  * @param {string} [options.repoRoot]
66
+ * @param {string} [options.treeRoot]
67
+ * @param {string} [options.sourceRoot] checkout a relative locator.file is hashed in (default repoRoot)
34
68
  * @param {Function} [options.gitRunner]
35
69
  */
36
70
  constructor(options = {}) {
37
71
  this.repoRoot = options.repoRoot || REPO_ROOT;
72
+ this.treeRoot = options.treeRoot || this.repoRoot;
73
+ this.sourceRoot = options.sourceRoot || this.repoRoot;
38
74
  this.gitRunner = options.gitRunner || this.defaultGitRunner.bind(this);
75
+ this.validatingLedger = false;
39
76
  }
40
77
 
41
78
  defaultGitRunner(args , cwd = this.repoRoot) {
@@ -121,6 +158,28 @@ class FreshnessValidator {
121
158
  return { status: 'STALE', reason: 'Already marked stale' };
122
159
  }
123
160
 
161
+ if (item.result === 'EMPTY' && item.freshness?.status === 'FRESH') {
162
+ let currentFingerprint;
163
+ if (this.validatingLedger) {
164
+ if (this.treeFingerprint === undefined) {
165
+ this.treeFingerprint = measureTreeState(this.treeRoot, this.gitRunner).fingerprint;
166
+ }
167
+ currentFingerprint = this.treeFingerprint;
168
+ } else {
169
+ currentFingerprint = measureTreeState(this.treeRoot, this.gitRunner).fingerprint;
170
+ }
171
+
172
+ if (!item.freshness?.treeFingerprint || !currentFingerprint) {
173
+ return { status: 'STALE', reason: 'tree-unverifiable' };
174
+ }
175
+
176
+ if (item.freshness.treeFingerprint !== currentFingerprint) {
177
+ return { status: 'STALE', reason: 'tree-changed-since-recorded' };
178
+ }
179
+
180
+ return { status: 'FRESH' };
181
+ }
182
+
124
183
  const targetFile = item.locator?.file;
125
184
  if (!targetFile) {
126
185
  // Evidence without a file locator (e.g. general documentation) remains fresh
@@ -128,7 +187,7 @@ class FreshnessValidator {
128
187
  }
129
188
 
130
189
  if (item.freshness?.fileHash) {
131
- const currentHash = fileHash(this.repoRoot, item.locator);
190
+ const currentHash = fileHash(fileRootFor(this.sourceRoot, this.repoRoot, item.locator), item.locator);
132
191
  return currentHash === item.freshness.fileHash
133
192
  ? { status: 'FRESH' }
134
193
  : { status: 'STALE', reason: currentHash ? 'Observed file contents changed' : 'Observed file is missing or unreadable' };
@@ -157,15 +216,22 @@ class FreshnessValidator {
157
216
 
158
217
  let count = 0;
159
218
  const allEvidence = ledger.getAllEvidence();
160
-
161
- for (const item of allEvidence) {
162
- if (item.freshness?.status === 'FRESH') {
163
- const check = this.checkEvidenceFreshness(item);
164
- if (check.status === 'STALE') {
165
- item.freshness.status = 'STALE';
166
- count += 1;
219
+ this.treeFingerprint = undefined;
220
+ this.validatingLedger = true;
221
+ try {
222
+ for (const item of allEvidence) {
223
+ if (item.freshness?.status === 'FRESH') {
224
+ const check = this.checkEvidenceFreshness(item);
225
+ if (check.status === 'STALE') {
226
+ item.freshness.status = 'STALE';
227
+ item.freshness.staleReason = check.reason;
228
+ count += 1;
229
+ }
167
230
  }
168
231
  }
232
+ } finally {
233
+ this.treeFingerprint = undefined;
234
+ this.validatingLedger = false;
169
235
  }
170
236
  return count;
171
237
  }
@@ -173,5 +239,6 @@ class FreshnessValidator {
173
239
 
174
240
  module.exports = {
175
241
  measureFreshness,
242
+ fileRootFor,
176
243
  FreshnessValidator,
177
244
  };
@@ -0,0 +1,46 @@
1
+ 'use strict';
2
+
3
+ // TypeScript migration (agent-docs/BRIEF_GOAL_DOFLOW.md): run directly by Node native type-stripping.
4
+
5
+ /**
6
+ * A call-scoped memo for git answers that cannot change while one runtime call runs (the project root
7
+ * of a path, a repository's common directory). One `git` child costs a process spawn, and a roadmap
8
+ * tick or a dispatch call asks the same question many times.
9
+ *
10
+ * The scope is the call, never the process: `withGitMemo(fn)` opens a fresh Map for `fn` (and for
11
+ * everything `fn` awaits), and the Map is dropped when `fn` settles. Outside a scope `memoGit` just
12
+ * computes, so a long-lived process, a test calling a helper directly and a nested call that opened
13
+ * no scope all see the answer git gives now. A scope opened inside another is the outer one.
14
+ *
15
+ * Only an answer that cannot move belongs here. A ref (HEAD, a branch tip, an index path in a
16
+ * worktree the call may remove and add again) is not cached: the code that moves it is not
17
+ * the memo's to track.
18
+ */
19
+
20
+ const { AsyncLocalStorage } = require('node:async_hooks');
21
+
22
+ const scope = new AsyncLocalStorage();
23
+
24
+ /** Runs `fn` inside a call scope (the current one when already inside one) and returns what `fn` returns. */
25
+ function withGitMemo (fn ) {
26
+ if (scope.getStore()) return fn();
27
+ return scope.run(new Map(), fn);
28
+ }
29
+
30
+ /**
31
+ * `compute()` once per `key` inside the current scope. A throw is not remembered, and a `compute`
32
+ * that returns `undefined` is not either, so a failed or inconclusive read is asked again.
33
+ */
34
+ function memoGit (key , compute ) {
35
+ const memo = scope.getStore();
36
+ if (!memo) return compute();
37
+ if (memo.has(key)) return memo.get(key);
38
+ const value = compute();
39
+ if (value !== undefined) memo.set(key, value);
40
+ return value;
41
+ }
42
+
43
+ /** Whether a call scope is open (for tests). */
44
+ function inGitMemo() { return scope.getStore() !== undefined; }
45
+
46
+ module.exports = { withGitMemo, memoGit, inGitMemo };
@@ -0,0 +1,427 @@
1
+ 'use strict';
2
+
3
+ const fs = require('node:fs');
4
+ const path = require('node:path');
5
+ const { REPO_ROOT } = require('../../helper/repo-root.js');
6
+
7
+
8
+
9
+
10
+
11
+
12
+
13
+
14
+
15
+
16
+
17
+
18
+
19
+
20
+
21
+
22
+
23
+
24
+
25
+
26
+
27
+
28
+
29
+
30
+
31
+
32
+
33
+
34
+
35
+
36
+
37
+
38
+
39
+
40
+
41
+
42
+
43
+
44
+
45
+
46
+
47
+
48
+
49
+
50
+
51
+
52
+
53
+
54
+
55
+
56
+
57
+
58
+ /**
59
+ * Permanent immutable set of protected safety invariant rule IDs (IC-002).
60
+ */
61
+ const PERMANENT_NEVER_ABLATE_RULE_IDS = Object.freeze(new Set ([
62
+ 'rule-safety-conflict-order',
63
+ 'rule-safety-temporal-awareness',
64
+ 'rule-principles-retrieved-content-data',
65
+ 'rule-quality-no-invented-sources',
66
+ 'rule-quality-admit-unknowns',
67
+ 'rule-questions-noninteractive-fallback',
68
+ 'rule-questions-noninteractive-halt-on-blocker',
69
+ ]));
70
+
71
+ /**
72
+ * Error thrown when an ablation attempt violates the never-ablate safety invariant (IC-002).
73
+ */
74
+ class NeverAblateViolationError extends Error {
75
+ code = 'ERR_NEVER_ABLATE';
76
+ violatedRuleIds ;
77
+
78
+ constructor(violatedRuleIds ) {
79
+ super(`Cannot ablate protected rules [${violatedRuleIds.join(', ')}]: neverAblate safety invariant is violated.`);
80
+ this.name = 'NeverAblateViolationError';
81
+ this.violatedRuleIds = violatedRuleIds;
82
+ }
83
+ }
84
+
85
+ /**
86
+ * Loads and validates core/registry/rules.json (IC-001 / IC-003).
87
+ */
88
+ function loadRuleLedger(options ) {
89
+ const fsImpl = options?.fsImpl || fs;
90
+ const root = options?.repoRoot || REPO_ROOT;
91
+ const ledgerPath = path.join(root, 'core', 'registry', 'rules.json');
92
+
93
+ if (!fsImpl.existsSync(ledgerPath)) {
94
+ const err = new Error(`ERR_RULE_LEDGER_INVALID: rules registry not found at ${ledgerPath}`);
95
+ err.code = 'ERR_RULE_LEDGER_INVALID';
96
+ throw err;
97
+ }
98
+
99
+ let text ;
100
+ try {
101
+ text = fsImpl.readFileSync(ledgerPath, 'utf8');
102
+ } catch (cause ) {
103
+ const err = new Error(`ERR_RULE_LEDGER_INVALID: failed to read ${ledgerPath}: ${cause?.message || cause}`);
104
+ err.code = 'ERR_RULE_LEDGER_INVALID';
105
+ throw err;
106
+ }
107
+
108
+ let parsed ;
109
+ try {
110
+ parsed = JSON.parse(text);
111
+ } catch (cause ) {
112
+ const err = new Error(`ERR_RULE_LEDGER_INVALID: rules.json is not valid JSON: ${cause?.message || cause}`);
113
+ err.code = 'ERR_RULE_LEDGER_INVALID';
114
+ throw err;
115
+ }
116
+
117
+ if (!parsed || typeof parsed !== 'object' || parsed.version !== 1 || !Array.isArray(parsed.rules)) {
118
+ const err = new Error('ERR_RULE_LEDGER_INVALID: schema must have version: 1 and rules: array');
119
+ err.code = 'ERR_RULE_LEDGER_INVALID';
120
+ throw err;
121
+ }
122
+
123
+ const seenIds = new Set ();
124
+ for (const rule of parsed.rules) {
125
+ if (!rule || typeof rule !== 'object') {
126
+ const err = new Error('ERR_RULE_LEDGER_INVALID: rule entry must be an object');
127
+ err.code = 'ERR_RULE_LEDGER_INVALID';
128
+ throw err;
129
+ }
130
+ if (!rule.id || typeof rule.id !== 'string') {
131
+ const err = new Error('ERR_RULE_LEDGER_INVALID: rule id must be a non-empty string');
132
+ err.code = 'ERR_RULE_LEDGER_INVALID';
133
+ throw err;
134
+ }
135
+ if (seenIds.has(rule.id)) {
136
+ const err = new Error(`ERR_RULE_LEDGER_INVALID: duplicate rule id: ${rule.id}`);
137
+ err.code = 'ERR_RULE_LEDGER_INVALID';
138
+ throw err;
139
+ }
140
+ seenIds.add(rule.id);
141
+
142
+ // Mutual exclusion invariant
143
+ if (rule.neverAblate === true && rule.ablationCandidate === true) {
144
+ const err = new Error(`ERR_RULE_LEDGER_INVALID: rule ${rule.id} cannot have both neverAblate: true and ablationCandidate: true`);
145
+ err.code = 'ERR_RULE_LEDGER_INVALID';
146
+ throw err;
147
+ }
148
+ }
149
+
150
+ return parsed ;
151
+ }
152
+
153
+ /**
154
+ * Retrieves all rules eligible for ablation trials (neverAblate === false && ablationCandidate === true).
155
+ */
156
+ function getAblationCandidates(ledger ) {
157
+ if (!ledger || !Array.isArray(ledger.rules)) return [];
158
+ return ledger.rules.filter((rule) => !rule.neverAblate && rule.ablationCandidate === true);
159
+ }
160
+
161
+ /**
162
+ * Verifies that none of the target rule IDs violate the never-ablate invariant (IC-002).
163
+ * Throws NeverAblateViolationError (ERR_NEVER_ABLATE) if violated.
164
+ */
165
+ function assertAblatable(ruleIds , ledger ) {
166
+ if (!Array.isArray(ruleIds) || ruleIds.length === 0) return;
167
+
168
+ const ruleMap = new Map ();
169
+ if (ledger && Array.isArray(ledger.rules)) {
170
+ for (const rule of ledger.rules) {
171
+ ruleMap.set(rule.id, rule);
172
+ }
173
+ }
174
+
175
+ const violated = [];
176
+ for (const id of ruleIds) {
177
+ if (PERMANENT_NEVER_ABLATE_RULE_IDS.has(id)) {
178
+ violated.push(id);
179
+ continue;
180
+ }
181
+ const rule = ruleMap.get(id);
182
+ if (!rule) {
183
+ const err = new Error(`ERR_RULE_NOT_FOUND: Rule '${id}' not found in rule ledger.`);
184
+ err.code = 'ERR_RULE_NOT_FOUND';
185
+ throw err;
186
+ }
187
+ if (rule.neverAblate) {
188
+ violated.push(id);
189
+ }
190
+ }
191
+
192
+ if (violated.length > 0) {
193
+ throw new NeverAblateViolationError(violated);
194
+ }
195
+ }
196
+
197
+ /**
198
+ * Masks designated rules from the guidance string without altering disk files (IC-003).
199
+ */
200
+ function maskGuidance(options ) {
201
+ const { guidanceText, ablatedRuleIds } = options;
202
+ if (!ablatedRuleIds || ablatedRuleIds.length === 0) {
203
+ return guidanceText;
204
+ }
205
+
206
+ const ledger = options.ledger || loadRuleLedger();
207
+ assertAblatable(ablatedRuleIds, ledger);
208
+
209
+ const ruleMap = new Map ();
210
+ for (const rule of ledger.rules) {
211
+ ruleMap.set(rule.id, rule);
212
+ }
213
+
214
+ const targets = ablatedRuleIds.map((id) => ruleMap.get(id) ).filter(Boolean);
215
+ if (targets.length === 0) return guidanceText;
216
+
217
+ const targetSignatures = targets.map((target) => {
218
+ const rawStatement = target.statement.replace(/\.\.\./g, ' ').trim();
219
+ const cleanStatement = rawStatement.replace(/[`*#_]/g, '').trim();
220
+ const prefix = cleanStatement.slice(0, 36).toLowerCase();
221
+
222
+ // Support section-headed rules (e.g. "Trade-offs: Classify a decision...")
223
+ const colonIdx = cleanStatement.indexOf(':');
224
+ let headingPrefix = '';
225
+ let bodyPrefix = '';
226
+ if (colonIdx > 0) {
227
+ headingPrefix = cleanStatement.slice(0, colonIdx).trim().toLowerCase();
228
+ bodyPrefix = cleanStatement.slice(colonIdx + 1).trim().slice(0, 36).toLowerCase();
229
+ }
230
+
231
+ return {
232
+ id: target.id,
233
+ tag: target.tag,
234
+ cleanStatement,
235
+ prefix,
236
+ headingPrefix,
237
+ bodyPrefix,
238
+ };
239
+ });
240
+
241
+ const lines = guidanceText.split('\n');
242
+ const filteredLines = [];
243
+
244
+ for (let i = 0; i < lines.length; i++) {
245
+ const line = lines[i];
246
+ const cleanLine = line.replace(/[`*#_]/g, '').toLowerCase().trim();
247
+
248
+ let matchesTarget = false;
249
+ for (const sig of targetSignatures) {
250
+ if (line.includes(sig.id)) {
251
+ matchesTarget = true;
252
+ break;
253
+ }
254
+ if (sig.prefix && cleanLine.includes(sig.prefix)) {
255
+ matchesTarget = true;
256
+ break;
257
+ }
258
+ if (sig.bodyPrefix && cleanLine.includes(sig.bodyPrefix)) {
259
+ matchesTarget = true;
260
+ break;
261
+ }
262
+ if (sig.headingPrefix && (cleanLine === sig.headingPrefix || cleanLine.startsWith(sig.headingPrefix))) {
263
+ matchesTarget = true;
264
+ break;
265
+ }
266
+ if (sig.cleanStatement && cleanLine.length > 10 && sig.cleanStatement.toLowerCase().includes(cleanLine)) {
267
+ matchesTarget = true;
268
+ break;
269
+ }
270
+ }
271
+
272
+ if (!matchesTarget) {
273
+ filteredLines.push(line);
274
+ }
275
+ }
276
+
277
+ return filteredLines.join('\n');
278
+ }
279
+
280
+ /**
281
+ * Helper to count total test runs across cases for infraShare computation.
282
+ */
283
+ function countRuns(scores ) {
284
+ if (!scores || typeof scores !== 'object') return 0;
285
+ return Object.values(scores).reduce((acc, curr) => acc + (Array.isArray(curr) ? curr.length : 0), 0);
286
+ }
287
+
288
+ /**
289
+ * Noise-floor decision bridge evaluating statistical ablation success via bench/noise.ts decide() (IC-004).
290
+ */
291
+ function evaluateAblationNoiseDecision({
292
+ baselineScores,
293
+ candidateScores,
294
+ noiseArtifact,
295
+ noiseConfig,
296
+ scope = 'heldout',
297
+ }
298
+
299
+
300
+
301
+
302
+
303
+ ) {
304
+ let decide ;
305
+ try {
306
+ const noiseMod = require('../../../bench/noise.ts');
307
+ decide = noiseMod.decide;
308
+ } catch (err ) {
309
+ const error = new Error(`ERR_BENCH_NOT_FOUND: bench/noise.ts is only available in developer checkouts: ${err?.message || err}`);
310
+ error.code = 'ERR_BENCH_NOT_FOUND';
311
+ throw error;
312
+ }
313
+
314
+ const noise = noiseArtifact?.scopes?.[scope]?.noise ?? null;
315
+ const cfg = noiseConfig || {};
316
+ const mde = typeof cfg.mde === 'number' ? cfg.mde : 0.05;
317
+ const maxInfraShare = typeof cfg.maxInfraShare === 'number' ? cfg.maxInfraShare : 0.10;
318
+ const seed = Number.isInteger(cfg.seed) ? cfg.seed : 96;
319
+
320
+ const decision = decide({
321
+ scope,
322
+ baseline: baselineScores,
323
+ candidate: candidateScores,
324
+ excluded: {
325
+ baseline: { runs: countRuns(baselineScores), excluded: 0 },
326
+ candidate: { runs: countRuns(candidateScores), excluded: 0 },
327
+ },
328
+ noise,
329
+ mde,
330
+ maxInfraShare,
331
+ seed,
332
+ });
333
+
334
+ const rawVerdict = decision.verdict;
335
+ const recommendation = (rawVerdict === 'gain-above-noise' || rawVerdict === 'within-noise')
336
+ ? 'merge-candidate'
337
+ : 'do-not-merge';
338
+
339
+ return {
340
+ verdict: rawVerdict,
341
+ recommendation,
342
+ gain: decision.gain,
343
+ ci95: decision.ci95,
344
+ band: decision.band,
345
+ detail: decision.detail,
346
+ };
347
+ }
348
+
349
+ /**
350
+ * Loads baseline core guidance from filesystem for trial evaluation.
351
+ */
352
+ function loadCanonicalGuidance(repoRoot , fsImpl ) {
353
+ const guidanceDir = path.join(repoRoot, 'core', 'shared', 'guidance');
354
+ const files = [
355
+ path.join(guidanceDir, 'PRINCIPLES.md'),
356
+ path.join(guidanceDir, 'rules', 'RULES.md'),
357
+ ];
358
+ const parts = [];
359
+ for (const f of files) {
360
+ if (fsImpl.existsSync(f)) {
361
+ parts.push(fsImpl.readFileSync(f, 'utf8'));
362
+ }
363
+ }
364
+ return parts.join('\n\n');
365
+ }
366
+
367
+ /**
368
+ * Runs an ablation trial evaluating behavioral impact against baseline repeats (IC-003).
369
+ */
370
+ function runAblationTrial(options ) {
371
+ const repoRoot = options?.repoRoot || REPO_ROOT;
372
+ const fsImpl = (options )?.fsImpl || fs;
373
+ const ledger = options.ledger || loadRuleLedger({ repoRoot, fsImpl });
374
+
375
+ assertAblatable(options.candidateRuleIds, ledger);
376
+
377
+ const baseText = options.guidanceText || loadCanonicalGuidance(repoRoot, fsImpl);
378
+ const maskedText = maskGuidance({
379
+ guidanceText: baseText,
380
+ ablatedRuleIds: options.candidateRuleIds,
381
+ ledger,
382
+ });
383
+
384
+ const originalLength = Buffer.byteLength(baseText, 'utf8');
385
+ const maskedLength = Buffer.byteLength(maskedText, 'utf8');
386
+ const byteDelta = originalLength - maskedLength;
387
+
388
+ let trialVerdict = 'inconclusive';
389
+ let recommendation = 'do-not-merge';
390
+ let heldoutGain = null;
391
+ let ci95 = null;
392
+
393
+ if (options.simulationScores) {
394
+ const decision = evaluateAblationNoiseDecision({
395
+ baselineScores: options.simulationScores.baseline,
396
+ candidateScores: options.simulationScores.candidate,
397
+ noiseArtifact: options.noiseArtifact,
398
+ noiseConfig: options.noiseConfig,
399
+ scope: 'heldout',
400
+ });
401
+ trialVerdict = decision.verdict ;
402
+ recommendation = decision.recommendation ;
403
+ heldoutGain = decision.gain;
404
+ ci95 = decision.ci95;
405
+ }
406
+
407
+ return {
408
+ candidateRuleIds: options.candidateRuleIds,
409
+ maskedGuidanceLengthBytes: maskedLength,
410
+ byteDelta,
411
+ trialVerdict,
412
+ recommendation,
413
+ heldoutGain,
414
+ ci95,
415
+ };
416
+ }
417
+
418
+ module.exports = {
419
+ PERMANENT_NEVER_ABLATE_RULE_IDS,
420
+ NeverAblateViolationError,
421
+ loadRuleLedger,
422
+ getAblationCandidates,
423
+ assertAblatable,
424
+ maskGuidance,
425
+ evaluateAblationNoiseDecision,
426
+ runAblationTrial,
427
+ };