devflow-kit 3.0.0 → 3.1.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 (134) hide show
  1. package/CHANGELOG.md +22 -0
  2. package/dist/agents/git.md +2 -2
  3. package/dist/cli/agents-view/index.js +1 -1
  4. package/dist/cli/agents-view/render.js +2 -2
  5. package/dist/cli/agents-view/state.js +2 -2
  6. package/dist/cli/agents-view/terminal.js +5 -5
  7. package/dist/cli/commands/agents.js +7 -6
  8. package/dist/cli/commands/ambient.js +1 -1
  9. package/dist/cli/commands/attribution-prompts.js +8 -8
  10. package/dist/cli/commands/capture.js +1 -1
  11. package/dist/cli/commands/compliance-prompts.js +8 -8
  12. package/dist/cli/commands/compliance.js +8 -7
  13. package/dist/cli/commands/flags.js +33 -31
  14. package/dist/cli/commands/hud.js +1 -1
  15. package/dist/cli/commands/init-seed.js +9 -9
  16. package/dist/cli/commands/init.js +34 -32
  17. package/dist/cli/commands/install-report.js +10 -10
  18. package/dist/cli/commands/learning.js +267 -129
  19. package/dist/cli/commands/memory.js +1 -1
  20. package/dist/cli/commands/proxy.js +23 -23
  21. package/dist/cli/commands/rules.js +6 -5
  22. package/dist/cli/commands/tracker-prompts.js +6 -6
  23. package/dist/cli/commands/tracker.js +9 -9
  24. package/dist/cli/commands/uninstall.js +20 -20
  25. package/dist/cli/flags-view/render.js +5 -5
  26. package/dist/cli/flags-view/state.js +9 -9
  27. package/dist/cli/flags-view/terminal.js +4 -4
  28. package/dist/cli/tui/cells.js +1 -1
  29. package/dist/cli/tui/terminal.js +6 -6
  30. package/dist/commands/dynamic-build.md +18 -4
  31. package/dist/commands/dynamic-plan.md +19 -5
  32. package/dist/commands/dynamic-profile.md +17 -3
  33. package/dist/commands/dynamic-tickets.md +18 -4
  34. package/dist/commands/release.md +15 -1
  35. package/dist/commands/research.md +1 -1
  36. package/dist/commands/resolve.md +8 -9
  37. package/dist/core/agent-frontmatter.js +3 -3
  38. package/dist/core/agent-models.js +6 -6
  39. package/dist/core/agent-state.js +2 -2
  40. package/dist/core/ansi.js +2 -2
  41. package/dist/core/cache.js +7 -8
  42. package/dist/core/codex-auth-inspect.js +4 -4
  43. package/dist/core/compliance-compose.js +3 -3
  44. package/dist/core/compliance.js +3 -4
  45. package/dist/core/evidence-policy.js +14 -13
  46. package/dist/core/external-models.js +1 -1
  47. package/dist/core/feature-config.js +3 -3
  48. package/dist/core/feature-switch.js +3 -3
  49. package/dist/core/flags.js +25 -25
  50. package/dist/core/fs-atomic.js +6 -7
  51. package/dist/core/learning-queue-cleanup.js +16 -80
  52. package/dist/core/learning-store.js +61 -0
  53. package/dist/core/manifest.js +5 -5
  54. package/dist/core/mds-variants.js +13 -13
  55. package/dist/core/model-discovery.js +8 -8
  56. package/dist/core/observations.js +17 -101
  57. package/dist/core/orphan-sweep.js +4 -4
  58. package/dist/core/plugins.js +4 -5
  59. package/dist/core/project-paths.js +9 -13
  60. package/dist/core/proxy-log.js +8 -8
  61. package/dist/core/proxy-state.js +3 -3
  62. package/dist/core/reference-sweep.js +6 -6
  63. package/dist/core/teammate-mode-cleanup.js +1 -1
  64. package/dist/core/tracker.js +14 -14
  65. package/dist/hud/colors.js +2 -2
  66. package/dist/hud/components/learning-counts.js +2 -16
  67. package/dist/hud/components/version-badge.js +1 -1
  68. package/dist/skills/git/references/pr/resolve-review-threads.md +2 -2
  69. package/dist/targets/claude-code/compliance-install.js +17 -15
  70. package/dist/targets/claude-code/hooks.js +2 -2
  71. package/dist/targets/claude-code/installer.js +24 -24
  72. package/dist/targets/claude-code/legacy.js +1 -1
  73. package/dist/targets/claude-code/post-install.js +25 -11
  74. package/dist/targets/claude-code/tracker-install.js +2 -2
  75. package/package.json +1 -1
  76. package/src/assets/agents/code.md +1 -4
  77. package/src/assets/agents/design.md +2 -2
  78. package/src/assets/agents/diagnose.md +1 -1
  79. package/src/assets/agents/git.mds +2 -2
  80. package/src/assets/agents/knowledge.md +3 -3
  81. package/src/assets/agents/learning.md +281 -196
  82. package/src/assets/agents/research.md +1 -1
  83. package/src/assets/agents/review.md +3 -3
  84. package/src/assets/agents/scrutinize.md +1 -1
  85. package/src/assets/agents/skim.md +1 -1
  86. package/src/assets/agents/triage.md +9 -9
  87. package/src/assets/commands/_partials/_decisions.mds +8 -3
  88. package/src/assets/commands/_partials/_docs_root.mds +3 -3
  89. package/src/assets/commands/_partials/_engine.mds +1 -1
  90. package/src/assets/commands/_partials/_preamble.mds +6 -2
  91. package/src/assets/commands/_partials/_settings.mds +2 -2
  92. package/src/assets/commands/dynamic-build.mds +1 -1
  93. package/src/assets/commands/dynamic-plan.mds +3 -3
  94. package/src/assets/commands/dynamic-profile.mds +1 -1
  95. package/src/assets/commands/dynamic-tickets.mds +2 -2
  96. package/src/assets/commands/release.md +15 -1
  97. package/src/assets/commands/research.mds +1 -1
  98. package/src/assets/commands/resolve.mds +8 -9
  99. package/src/assets/mds/git/_pr.mds +3 -3
  100. package/src/assets/mds/tracker/_common.mds +1 -1
  101. package/src/assets/mds/tracker/_github.mds +1 -1
  102. package/src/assets/mds/tracker/_jira.mds +1 -1
  103. package/src/assets/mds/tracker/_linear.mds +1 -1
  104. package/src/assets/mds/tracker/_mcp.mds +6 -5
  105. package/src/assets/scripts/hooks/assets/orchestrator-charter.md +1 -0
  106. package/src/assets/scripts/hooks/background-memory-update +28 -22
  107. package/src/assets/scripts/hooks/capture-turn +1 -17
  108. package/src/assets/scripts/hooks/ensure-devflow-init +1 -1
  109. package/src/assets/scripts/hooks/ensure-proxy +5 -6
  110. package/src/assets/scripts/hooks/ensure-root-gitignore +1 -1
  111. package/src/assets/scripts/hooks/is-hex-sha +1 -1
  112. package/src/assets/scripts/hooks/json-helper.cjs +348 -814
  113. package/src/assets/scripts/hooks/json-parse +3 -2
  114. package/src/assets/scripts/hooks/lib/decisions-format.cjs +205 -156
  115. package/src/assets/scripts/hooks/lib/learning-store.cjs +3102 -0
  116. package/src/assets/scripts/hooks/lib/mkdir-lock.cjs +7 -5
  117. package/src/assets/scripts/hooks/lib/project-paths.cjs +13 -19
  118. package/src/assets/scripts/hooks/lib/render-decisions.cjs +253 -226
  119. package/src/assets/scripts/hooks/queue-append +2 -2
  120. package/src/assets/scripts/hooks/resolve-project-root +3 -4
  121. package/src/assets/scripts/hooks/session-start-context +40 -18
  122. package/src/assets/scripts/lib/project-config.cjs +2 -2
  123. package/src/assets/scripts/pr-evidence.cjs +3 -3
  124. package/src/assets/scripts/redact-secrets.cjs +20 -20
  125. package/src/assets/scripts/release-trace.cjs +1 -1
  126. package/src/assets/scripts/resolve-evidence-policy.cjs +3 -3
  127. package/src/assets/scripts/resolve-settings.cjs +3 -3
  128. package/src/assets/scripts/verify-evidence.cjs +2 -2
  129. package/src/assets/skills/apply-decisions/SKILL.md +37 -17
  130. package/src/assets/skills/docs-framework/SKILL.md +2 -2
  131. package/src/assets/skills/feature-knowledge/SKILL.md +6 -5
  132. package/src/targets/claude-code/templates/managed-settings.json +3 -3
  133. package/dist/core/observation-io.js +0 -50
  134. package/src/assets/scripts/hooks/decisions-usage-scan.cjs +0 -131
@@ -65,7 +65,21 @@ The `budget` global governs depth. Scale Review agent roster and verification vo
65
65
 
66
66
  ### DECISIONS_CONTEXT — obtain BEFORE authoring
67
67
 
68
- Before you author the workflow script, read `.devflow/learning/index.md` for the current worktree. If the file is absent or empty, set `DECISIONS_CONTEXT` to `(none)`; otherwise use the file content as `DECISIONS_CONTEXT`.
68
+ The decisions ledger belongs to the repository, not to one checkout: in a linked worktree it lives in the main worktree, and a session started in a subdirectory reads the copy at the repository root. Locate it with ONE git call, run from the start directory — `WORKTREE_PATH` if provided, otherwise cwd (`devflow:worktree-support`):
69
+
70
+ ```bash
71
+ git -C "{start}" rev-parse --path-format=absolute --show-toplevel --git-common-dir
72
+ ```
73
+
74
+ Line 1 is the checkout's toplevel, line 2 the repository's common git directory. A git older than 2.31 echoes `--path-format=absolute` back as a line of its own first. `{ledger}` is the first of these that applies:
75
+
76
+ 1. **The main worktree** — line 2 without its trailing `/.git`, when the output is exactly two lines each beginning with `/`, line 2 ends in `/.git`, and the directory left once it is removed is not your home directory and contains a `.devflow/` directory.
77
+ 2. **The toplevel** — line 1, or on an older git the line after the echoed flag.
78
+ 3. **The start directory itself** — when the command failed or printed no absolute toplevel (outside a git repository).
79
+
80
+ This is the rule the learning hooks apply (D-LEDGER-MAIN-WORKTREE, D-PROMPT-ROOT), so you read the index the Learning agent writes.
81
+
82
+ Before you author the workflow script, read `{ledger}/.devflow/learning/index.md`. If the file is absent or empty, set `DECISIONS_CONTEXT` to `(none)`; otherwise use the file content as `DECISIONS_CONTEXT`.
69
83
 
70
84
  The script body cannot perform this read — you (the main model) do it before authoring. Then inject the relevant DECISIONS_CONTEXT into agent prompts using the `devflow:apply-decisions` consumption algorithm (scan index → Read relevant entries → cite verbatim IDs in agent prompts). Only agents that need architectural context (Code agent, Evaluate agent, Review agent, Scrutinize agent) need DECISIONS_CONTEXT injected; lightweight agents (Validate agent, Simplify agent) do not.
71
85
 
@@ -73,7 +87,7 @@ The script body cannot perform this read — you (the main model) do it before a
73
87
 
74
88
  When a ticket requires multiple sequential Code agent phases, each Code agent writes `{toplevel}/.devflow/docs/handoff-{branch_slug}.md` (branch-scoped to prevent concurrent session clobber), `{toplevel}` being `git rev-parse --show-toplevel` in the checkout the ticket's branch is in — never a subdirectory. The next Code agent reads it via HANDOFF_FILE input. PRIOR_PHASE_SUMMARY is the compact in-context form; the handoff file is the durable form that survives context compaction. Always read the handoff file directly — code is authoritative, summaries are supplementary.
75
89
 
76
- ### IRON RULE (ADR-008: LLM-vs-plumbing)
90
+ ### IRON RULE (LLM-vs-plumbing)
77
91
 
78
92
  **Author ZERO deterministic feature code.** No parsers, no schedulers, no topological-sort, no dependency-graph helpers, no confidence formulas. ALL issue reading, dependency reasoning, and scheduling decisions are LLM judgment at runtime, performed by the workflow's agents. The recipe is instructions. The workflow script Claude authors IS the runtime logic — keep it free of hand-coded feature algorithms.
79
93
 
@@ -680,7 +694,7 @@ Code(agentType:"Code", prompt: full task + plan + DECISIONS_CONTEXT + handoff if
680
694
  → gate2_acceptance() ← Gate 2 runs HERE — before the review pass, not after
681
695
  ```
682
696
 
683
- The Code agent prompt must include: task description, implementation plan (if one exists), relevant DECISIONS_CONTEXT (from `.devflow/learning/index.md`), the compliance lens (`COMPLIANCE_FRAMEWORKS` — every Code prompt carries it, fix prompts included), and any PRIOR_PHASE_SUMMARY / HANDOFF_FILE for sequential multi-phase tickets.
697
+ The Code agent prompt must include: task description, implementation plan (if one exists), relevant DECISIONS_CONTEXT (the index you loaded before authoring), the compliance lens (`COMPLIANCE_FRAMEWORKS` — every Code prompt carries it, fix prompts included), and any PRIOR_PHASE_SUMMARY / HANDOFF_FILE for sequential multi-phase tickets.
684
698
 
685
699
  Gate 2 runs at implementation acceptance — this matches devflow's deliberate placement: "evaluation is part of implementation acceptance, not post-review" (§6.1).
686
700
 
@@ -1240,4 +1254,4 @@ Update the wave PR's test-plan block and post its evidence comment."
1240
1254
 
1241
1255
  ### Maintenance note
1242
1256
 
1243
- This recipe encodes the current `/implement` + `/code-review` + `/resolve` orchestration shape as of the authoring date (2026-06-12). When those base commands change their orchestration, update this recipe to match. No tooling detects drift — by design (ADR-008 Iron Rule). The reminder lives in the design doc §16.
1257
+ This recipe encodes the current `/implement` + `/code-review` + `/resolve` orchestration shape as of the authoring date (2026-06-12). When those base commands change their orchestration, update this recipe to match. No tooling detects drift — by design (the LLM-vs-plumbing Iron Rule). The reminder lives in the design doc §16.
@@ -65,7 +65,21 @@ The `budget` global governs depth. Scale Review agent roster and verification vo
65
65
 
66
66
  ### DECISIONS_CONTEXT — obtain BEFORE authoring
67
67
 
68
- Before you author the workflow script, read `.devflow/learning/index.md` for the current worktree. If the file is absent or empty, set `DECISIONS_CONTEXT` to `(none)`; otherwise use the file content as `DECISIONS_CONTEXT`.
68
+ The decisions ledger belongs to the repository, not to one checkout: in a linked worktree it lives in the main worktree, and a session started in a subdirectory reads the copy at the repository root. Locate it with ONE git call, run from the start directory — `WORKTREE_PATH` if provided, otherwise cwd (`devflow:worktree-support`):
69
+
70
+ ```bash
71
+ git -C "{start}" rev-parse --path-format=absolute --show-toplevel --git-common-dir
72
+ ```
73
+
74
+ Line 1 is the checkout's toplevel, line 2 the repository's common git directory. A git older than 2.31 echoes `--path-format=absolute` back as a line of its own first. `{ledger}` is the first of these that applies:
75
+
76
+ 1. **The main worktree** — line 2 without its trailing `/.git`, when the output is exactly two lines each beginning with `/`, line 2 ends in `/.git`, and the directory left once it is removed is not your home directory and contains a `.devflow/` directory.
77
+ 2. **The toplevel** — line 1, or on an older git the line after the echoed flag.
78
+ 3. **The start directory itself** — when the command failed or printed no absolute toplevel (outside a git repository).
79
+
80
+ This is the rule the learning hooks apply (D-LEDGER-MAIN-WORKTREE, D-PROMPT-ROOT), so you read the index the Learning agent writes.
81
+
82
+ Before you author the workflow script, read `{ledger}/.devflow/learning/index.md`. If the file is absent or empty, set `DECISIONS_CONTEXT` to `(none)`; otherwise use the file content as `DECISIONS_CONTEXT`.
69
83
 
70
84
  The script body cannot perform this read — you (the main model) do it before authoring. Then inject the relevant DECISIONS_CONTEXT into agent prompts using the `devflow:apply-decisions` consumption algorithm (scan index → Read relevant entries → cite verbatim IDs in agent prompts). Only agents that need architectural context (Code agent, Evaluate agent, Review agent, Scrutinize agent) need DECISIONS_CONTEXT injected; lightweight agents (Validate agent, Simplify agent) do not.
71
85
 
@@ -73,7 +87,7 @@ The script body cannot perform this read — you (the main model) do it before a
73
87
 
74
88
  When a ticket requires multiple sequential Code agent phases, each Code agent writes `{toplevel}/.devflow/docs/handoff-{branch_slug}.md` (branch-scoped to prevent concurrent session clobber), `{toplevel}` being `git rev-parse --show-toplevel` in the checkout the ticket's branch is in — never a subdirectory. The next Code agent reads it via HANDOFF_FILE input. PRIOR_PHASE_SUMMARY is the compact in-context form; the handoff file is the durable form that survives context compaction. Always read the handoff file directly — code is authoritative, summaries are supplementary.
75
89
 
76
- ### IRON RULE (ADR-008: LLM-vs-plumbing)
90
+ ### IRON RULE (LLM-vs-plumbing)
77
91
 
78
92
  **Author ZERO deterministic feature code.** No parsers, no schedulers, no topological-sort, no dependency-graph helpers, no confidence formulas. ALL issue reading, dependency reasoning, and scheduling decisions are LLM judgment at runtime, performed by the workflow's agents. The recipe is instructions. The workflow script Claude authors IS the runtime logic — keep it free of hand-coded feature algorithms.
79
93
 
@@ -233,7 +247,7 @@ const plans = await phase("plan-parallel", () =>
233
247
  parallel((tickets || []).map(ticket => () =>
234
248
  agent(`Write an implementation plan for this ticket.
235
249
  Ticket: ${JSON.stringify(ticket)}
236
- Decisions context (apply devflow:apply-decisions; cite ADR/PF IDs): ${DECISIONS_CONTEXT}
250
+ Decisions context (apply devflow:apply-decisions; a plan file can be posted to the tracker, so state each decision in words, never by ID): ${DECISIONS_CONTEXT}
237
251
  The plan must cover: approach overview, affected files and modules, key design decisions, implementation sequence (what to build first), risks and mitigations, and any open questions you cannot resolve from the ticket alone.
238
252
  Write a thorough but tight plan — every section must earn its place for a Code agent who has no other context.
239
253
  Return: { ticketTitle, planMarkdown, openDecisions (array of genuine unknowns requiring user input) }.`, { agentType: "Design" })
@@ -324,7 +338,7 @@ For each ticket, write ${OUTDIR}/{ticket-slug}-plan.md containing:
324
338
  - ## Acceptance Criteria (numbered, positive + negative)
325
339
  - ## Test Plan — the challenger's testPlan lines, verbatim, one per line, and nothing else: no prose, no blank line between them, no setup or outcome
326
340
  - ## Test Scenarios — one line per TP, in TP order: TP-n: its setup, then its expected outcome, from testScenarios
327
- - ## Auto-Resolved Decisions (if any — list each as: decision → resolution → source)
341
+ - ## Auto-Resolved Decisions (if any — list each as: decision → resolution → source, naming a recorded decision in words, never by ID)
328
342
 
329
343
  Then write ${OUTDIR}/DECISIONS-NEEDED.md:
330
344
  - ## Auto-Resolved Decisions — list each silently-resolved decision as: decision → resolution → source (preference profile / ADR-NNN), so auto-resolution is auditable and reversible. If none, write "None."
@@ -430,4 +444,4 @@ After the workflow returns: check each plan's test plan (step 1 of the F4 list a
430
444
 
431
445
  ### Maintenance note
432
446
 
433
- This recipe encodes the planning pipeline as of the authoring date (2026-06-12). The plan-challenge verbatim intent (§5.1) is load-bearing — do not paraphrase it when authoring the challenger agent prompt. The "Acceptance criteria + test plan contract" section above is the shared shape with `/devflow:dynamic-build` Gate 2; any change must be kept in sync. No tooling detects drift — by design (ADR-008 Iron Rule).
447
+ This recipe encodes the planning pipeline as of the authoring date (2026-06-12). The plan-challenge verbatim intent (§5.1) is load-bearing — do not paraphrase it when authoring the challenger agent prompt. The "Acceptance criteria + test plan contract" section above is the shared shape with `/devflow:dynamic-build` Gate 2; any change must be kept in sync. No tooling detects drift — by design (the LLM-vs-plumbing Iron Rule).
@@ -65,7 +65,21 @@ The `budget` global governs depth. Scale Review agent roster and verification vo
65
65
 
66
66
  ### DECISIONS_CONTEXT — obtain BEFORE authoring
67
67
 
68
- Before you author the workflow script, read `.devflow/learning/index.md` for the current worktree. If the file is absent or empty, set `DECISIONS_CONTEXT` to `(none)`; otherwise use the file content as `DECISIONS_CONTEXT`.
68
+ The decisions ledger belongs to the repository, not to one checkout: in a linked worktree it lives in the main worktree, and a session started in a subdirectory reads the copy at the repository root. Locate it with ONE git call, run from the start directory — `WORKTREE_PATH` if provided, otherwise cwd (`devflow:worktree-support`):
69
+
70
+ ```bash
71
+ git -C "{start}" rev-parse --path-format=absolute --show-toplevel --git-common-dir
72
+ ```
73
+
74
+ Line 1 is the checkout's toplevel, line 2 the repository's common git directory. A git older than 2.31 echoes `--path-format=absolute` back as a line of its own first. `{ledger}` is the first of these that applies:
75
+
76
+ 1. **The main worktree** — line 2 without its trailing `/.git`, when the output is exactly two lines each beginning with `/`, line 2 ends in `/.git`, and the directory left once it is removed is not your home directory and contains a `.devflow/` directory.
77
+ 2. **The toplevel** — line 1, or on an older git the line after the echoed flag.
78
+ 3. **The start directory itself** — when the command failed or printed no absolute toplevel (outside a git repository).
79
+
80
+ This is the rule the learning hooks apply (D-LEDGER-MAIN-WORKTREE, D-PROMPT-ROOT), so you read the index the Learning agent writes.
81
+
82
+ Before you author the workflow script, read `{ledger}/.devflow/learning/index.md`. If the file is absent or empty, set `DECISIONS_CONTEXT` to `(none)`; otherwise use the file content as `DECISIONS_CONTEXT`.
69
83
 
70
84
  The script body cannot perform this read — you (the main model) do it before authoring. Then inject the relevant DECISIONS_CONTEXT into agent prompts using the `devflow:apply-decisions` consumption algorithm (scan index → Read relevant entries → cite verbatim IDs in agent prompts). Only agents that need architectural context (Code agent, Evaluate agent, Review agent, Scrutinize agent) need DECISIONS_CONTEXT injected; lightweight agents (Validate agent, Simplify agent) do not.
71
85
 
@@ -73,7 +87,7 @@ The script body cannot perform this read — you (the main model) do it before a
73
87
 
74
88
  When a ticket requires multiple sequential Code agent phases, each Code agent writes `{toplevel}/.devflow/docs/handoff-{branch_slug}.md` (branch-scoped to prevent concurrent session clobber), `{toplevel}` being `git rev-parse --show-toplevel` in the checkout the ticket's branch is in — never a subdirectory. The next Code agent reads it via HANDOFF_FILE input. PRIOR_PHASE_SUMMARY is the compact in-context form; the handoff file is the durable form that survives context compaction. Always read the handoff file directly — code is authoritative, summaries are supplementary.
75
89
 
76
- ### IRON RULE (ADR-008: LLM-vs-plumbing)
90
+ ### IRON RULE (LLM-vs-plumbing)
77
91
 
78
92
  **Author ZERO deterministic feature code.** No parsers, no schedulers, no topological-sort, no dependency-graph helpers, no confidence formulas. ALL issue reading, dependency reasoning, and scheduling decisions are LLM judgment at runtime, performed by the workflow's agents. The recipe is instructions. The workflow script Claude authors IS the runtime logic — keep it free of hand-coded feature algorithms.
79
93
 
@@ -217,4 +231,4 @@ Next steps:
217
231
 
218
232
  ### Maintenance note
219
233
 
220
- This command mines ALL projects' history on this machine. The bounded-reading discipline (grep/rg + sample — never full-read) is mandatory and must be preserved in every revision. The agent writes prose; no extraction or clustering algorithm is authored here. Per ADR-008 Iron Rule: the agent does the reading and summarizing — not a script we maintain.
234
+ This command mines ALL projects' history on this machine. The bounded-reading discipline (grep/rg + sample — never full-read) is mandatory and must be preserved in every revision. The agent writes prose; no extraction or clustering algorithm is authored here. Per the LLM-vs-plumbing Iron Rule: the agent does the reading and summarizing — not a script we maintain.
@@ -65,7 +65,21 @@ The `budget` global governs depth. Scale Review agent roster and verification vo
65
65
 
66
66
  ### DECISIONS_CONTEXT — obtain BEFORE authoring
67
67
 
68
- Before you author the workflow script, read `.devflow/learning/index.md` for the current worktree. If the file is absent or empty, set `DECISIONS_CONTEXT` to `(none)`; otherwise use the file content as `DECISIONS_CONTEXT`.
68
+ The decisions ledger belongs to the repository, not to one checkout: in a linked worktree it lives in the main worktree, and a session started in a subdirectory reads the copy at the repository root. Locate it with ONE git call, run from the start directory — `WORKTREE_PATH` if provided, otherwise cwd (`devflow:worktree-support`):
69
+
70
+ ```bash
71
+ git -C "{start}" rev-parse --path-format=absolute --show-toplevel --git-common-dir
72
+ ```
73
+
74
+ Line 1 is the checkout's toplevel, line 2 the repository's common git directory. A git older than 2.31 echoes `--path-format=absolute` back as a line of its own first. `{ledger}` is the first of these that applies:
75
+
76
+ 1. **The main worktree** — line 2 without its trailing `/.git`, when the output is exactly two lines each beginning with `/`, line 2 ends in `/.git`, and the directory left once it is removed is not your home directory and contains a `.devflow/` directory.
77
+ 2. **The toplevel** — line 1, or on an older git the line after the echoed flag.
78
+ 3. **The start directory itself** — when the command failed or printed no absolute toplevel (outside a git repository).
79
+
80
+ This is the rule the learning hooks apply (D-LEDGER-MAIN-WORKTREE, D-PROMPT-ROOT), so you read the index the Learning agent writes.
81
+
82
+ Before you author the workflow script, read `{ledger}/.devflow/learning/index.md`. If the file is absent or empty, set `DECISIONS_CONTEXT` to `(none)`; otherwise use the file content as `DECISIONS_CONTEXT`.
69
83
 
70
84
  The script body cannot perform this read — you (the main model) do it before authoring. Then inject the relevant DECISIONS_CONTEXT into agent prompts using the `devflow:apply-decisions` consumption algorithm (scan index → Read relevant entries → cite verbatim IDs in agent prompts). Only agents that need architectural context (Code agent, Evaluate agent, Review agent, Scrutinize agent) need DECISIONS_CONTEXT injected; lightweight agents (Validate agent, Simplify agent) do not.
71
85
 
@@ -73,7 +87,7 @@ The script body cannot perform this read — you (the main model) do it before a
73
87
 
74
88
  When a ticket requires multiple sequential Code agent phases, each Code agent writes `{toplevel}/.devflow/docs/handoff-{branch_slug}.md` (branch-scoped to prevent concurrent session clobber), `{toplevel}` being `git rev-parse --show-toplevel` in the checkout the ticket's branch is in — never a subdirectory. The next Code agent reads it via HANDOFF_FILE input. PRIOR_PHASE_SUMMARY is the compact in-context form; the handoff file is the durable form that survives context compaction. Always read the handoff file directly — code is authoritative, summaries are supplementary.
75
89
 
76
- ### IRON RULE (ADR-008: LLM-vs-plumbing)
90
+ ### IRON RULE (LLM-vs-plumbing)
77
91
 
78
92
  **Author ZERO deterministic feature code.** No parsers, no schedulers, no topological-sort, no dependency-graph helpers, no confidence formulas. ALL issue reading, dependency reasoning, and scheduling decisions are LLM judgment at runtime, performed by the workflow's agents. The recipe is instructions. The workflow script Claude authors IS the runtime logic — keep it free of hand-coded feature algorithms.
79
93
 
@@ -210,7 +224,7 @@ const drafts = await phase("draft", () =>
210
224
  agent(`Draft ticket for initiative: "${initiative}"
211
225
  Ticket: ${JSON.stringify(c)}
212
226
  Constraints: ${constraints}
213
- Decisions context (apply devflow:apply-decisions; cite ADR/PF IDs): ${DECISIONS_CONTEXT}
227
+ Decisions context (apply devflow:apply-decisions; the ticket is filed to the tracker, so state each decision in words, never by ID): ${DECISIONS_CONTEXT}
214
228
  Write the ticket body following the ticket_body_template structure (Wave/Depends-on header, Summary, Scope with In/Out + anti-features, Invariants, numbered Acceptance Criteria with at least one negative criterion, Open Questions).
215
229
  Return a JSON object with: title (string), summary (string), wave (number), dependsOn (array), bodyMarkdown (string), openQuestions (array).`, { agentType: "Design" })
216
230
  ))
@@ -641,4 +655,4 @@ The tracking-issue path and any open questions are the primary handoff to `/devf
641
655
 
642
656
  ### Maintenance note
643
657
 
644
- This recipe encodes the ticket-factory shape as of the authoring date (2026-06-12). The pipeline structure (`draft → [2-lens review] → revise → whole-set critic → amend → tracking-issue`) is the load-bearing invariant. Per ADR-008, no deterministic ticket-parsing logic is added — ticket slates are proposed by the model and confirmed by the user. When the devflow agent roster changes, update the `agentType` values above. No tooling detects drift — by design (ADR-008 Iron Rule).
658
+ This recipe encodes the ticket-factory shape as of the authoring date (2026-06-12). The pipeline structure (`draft → [2-lens review] → revise → whole-set critic → amend → tracking-issue`) is the load-bearing invariant. Per the LLM-vs-plumbing Iron Rule, no deterministic ticket-parsing logic is added — ticket slates are proposed by the model and confirmed by the user. When the devflow agent roster changes, update the `agentType` values above. No tooling detects drift — by design, under the same rule.
@@ -48,7 +48,21 @@ Read `.release/RELEASE-FLOW.md`:
48
48
 
49
49
  **Produces:** DECISIONS_CONTEXT, FEATURE_KNOWLEDGE
50
50
 
51
- Read `.devflow/learning/index.md`. If the file is absent or empty, set `DECISIONS_CONTEXT` to `(none)`; otherwise use the file content as `DECISIONS_CONTEXT`.
51
+ The decisions ledger belongs to the repository, not to one checkout: in a linked worktree it lives in the main worktree, and a session started in a subdirectory reads the copy at the repository root. Locate it with ONE git call, run from the start directory — `WORKTREE_PATH` if provided, otherwise cwd (`devflow:worktree-support`):
52
+
53
+ ```bash
54
+ git -C "{start}" rev-parse --path-format=absolute --show-toplevel --git-common-dir
55
+ ```
56
+
57
+ Line 1 is the checkout's toplevel, line 2 the repository's common git directory. A git older than 2.31 echoes `--path-format=absolute` back as a line of its own first. `{ledger}` is the first of these that applies:
58
+
59
+ 1. **The main worktree** — line 2 without its trailing `/.git`, when the output is exactly two lines each beginning with `/`, line 2 ends in `/.git`, and the directory left once it is removed is not your home directory and contains a `.devflow/` directory.
60
+ 2. **The toplevel** — line 1, or on an older git the line after the echoed flag.
61
+ 3. **The start directory itself** — when the command failed or printed no absolute toplevel (outside a git repository).
62
+
63
+ This is the rule the learning hooks apply (D-LEDGER-MAIN-WORKTREE, D-PROMPT-ROOT), so you read the index the Learning agent writes.
64
+
65
+ Read `{ledger}/.devflow/learning/index.md`. If the file is absent or empty, set `DECISIONS_CONTEXT` to `(none)`; otherwise use the file content as `DECISIONS_CONTEXT`.
52
66
 
53
67
  Load feature knowledge: Attempt to read `.devflow/features/index.md` (the regenerable cache). If absent or empty, glob `.devflow/features/*/KNOWLEDGE.md` and read each file's YAML frontmatter (`name`, `description`, `directories`) as the relevance surface. Pick release-relevant KBs by matching their documented area against the release context. For each selected KB, read the full `KNOWLEDGE.md` — trust current code over KB content on any mismatch. Concatenate under slug headers and set `FEATURE_KNOWLEDGE` (or `(none)` if no KBs exist or none are relevant). No `index.json`, no subprocess, no `.cjs` script.
54
68
 
@@ -64,7 +64,7 @@ The index is one direct file read, written at render time by `render-decisions.c
64
64
 
65
65
  When `DECISIONS_CONTEXT` is not `(none)`, follow `devflow:apply-decisions` to scan the index, identify plausibly-relevant entries, Read full entry bodies on demand, and cite verbatim IDs in downstream agent prompts and reasoning.
66
66
 
67
- Use `DECISIONS_CONTEXT` locally when framing research — prior decisions and pitfalls suggest areas to investigate. Follow `devflow:apply-decisions` to Read full entry bodies on demand. Pass `DECISIONS_CONTEXT` to each Research agent in Phase 4 so they can cite relevant decisions in findings.
67
+ Use `DECISIONS_CONTEXT` locally when framing research — prior decisions and pitfalls suggest areas to investigate. Follow `devflow:apply-decisions` to Read full entry bodies on demand. Pass `DECISIONS_CONTEXT` to each Research agent in Phase 4 so their findings can account for relevant decisions.
68
68
 
69
69
  ### Load Feature Knowledge
70
70
 
@@ -266,14 +266,14 @@ Wait for Triage agent to complete before proceeding. Parse verdict ledger from T
266
266
  - **ESCALATED**: Security issues requiring human escalation
267
267
  - **FIX_NOW**: Valid issues assigned to Code agents (with risk tier: Standard | Careful)
268
268
  - **FALSE_POSITIVE**: Issues the Review agent got wrong (with cited evidence)
269
- - **BY_DESIGN**: Intentional code (with ADR or code doc citation)
269
+ - **BY_DESIGN**: Intentional code (with a recorded decision, stated in words, or a code doc citation)
270
270
  - **FIX_SEPARATE**: Valid but out of blast-radius scope (must become manage-debt ticket)
271
271
  - **TECH_DEBT**: Architectural overhaul only — LAST RESORT
272
272
  - **DUPLICATE**: Collapsed duplicate issue — carries `duplicate_of: <primary-id>` referencing the non-DUPLICATE primary; inherits the primary's outcome
273
273
 
274
- Collect all decisions citations (ADR-NNN / PF-NNN) from Triage agent Reasoning columns.
274
+ Collect every decision and pitfall the Triage agent's Reasoning columns state, in its words — the resolution summary is posted, so it never carries an ADR/PF ID.
275
275
 
276
- **Triage agent completeness assertion (avoids PF-002):** Verify the parsed ledger against ISSUES before proceeding:
276
+ **Triage agent completeness assertion:** Verify the parsed ledger against ISSUES before proceeding:
277
277
  1. Every issue `id` from ISSUES must appear in exactly one verdict bucket — none may vanish, none may appear in multiple buckets. DUPLICATE is a valid bucket; a valid DUPLICATE entry must name its `duplicate_of` primary (the `Duplicate Of` column of the ledger's DUPLICATE table) and that primary must be a non-DUPLICATE issue id. A missing `duplicate_of` or one that chains to another DUPLICATE is a **Triage agent failure** (retry-then-abort as below).
278
278
  2. If the Triage agent output is empty, contains a skill re-entrancy guard string (e.g., contains `already running`), or is missing any issue IDs from ISSUES: treat as a **Triage agent failure**:
279
279
  - Retry the Triage agent once with the same inputs.
@@ -487,7 +487,7 @@ Run this step only when `EVIDENCE_POLICY` is `required` and THREAD_MAP is non-em
487
487
 
488
488
  Prepare THREAD_MAP with verdicts from triage/code agent results:
489
489
  - For each `ext-{N}`: match to an issue verdict (FIXED, FALSE_POSITIVE, BY_DESIGN, ESCALATED) by `file:line` correlation
490
- - If the matched issue has verdict DUPLICATE, use the **primary's** verdict and verification status for the reply — do not expose DUPLICATE to the thread author (avoids PF-024; caller-side mapping — git.md contracts unchanged)
490
+ - If the matched issue has verdict DUPLICATE, use the **primary's** verdict and verification status for the reply — do not expose DUPLICATE to the thread author (caller-side mapping: the Git agent's verdict set has no DUPLICATE, so its contract stays unchanged)
491
491
  - Include `commit_sha` from Code agent results for FIXED verdicts
492
492
  - If `fork_no_push` is set: drop FIXED entries from THREAD_MAP — their commits never reached the PR — and record each as `DEGRADED` in `## Third-Party Threads`
493
493
  - Unmatched threads: ESCALATED (human review)
@@ -793,8 +793,7 @@ Written in Phase 5 (Collect Results) to `{TARGET_DIR}/resolution-summary.md`:
793
793
 
794
794
  ## Decisions Citations
795
795
 
796
- - applies ADR-{NNN} — {batch-id}, {issue-id}
797
- - avoids PF-{NNN} — {batch-id}, {issue-id}
796
+ - {decision applied or pitfall avoided, stated in words — never its ID} — {batch-id}, {issue-id}
798
797
 
799
798
  (Omit section if no citations were made)
800
799
 
@@ -832,9 +831,9 @@ Final gate: PASS | FAILED after {n} attempts
832
831
  | {description} | {file}:{line} | {why} |
833
832
 
834
833
  ## By Design
835
- | Issue | File:Line | Rationale (ADR/doc) |
836
- |-------|-----------|---------------------|
837
- | {description} | {file}:{line} | {applies ADR-NNN or code comment} |
834
+ | Issue | File:Line | Rationale (decision/doc) |
835
+ |-------|-----------|--------------------------|
836
+ | {description} | {file}:{line} | {the decision, in words, or code comment} |
838
837
 
839
838
  ## Fix Separately
840
839
  | Issue | File:Line | Reason | Tracked |
@@ -4,8 +4,8 @@
4
4
  * Pure module — zero I/O. All functions take content strings and return
5
5
  * new content strings; callers own file reads and writes.
6
6
  *
7
- * applies ADR-013: pure core-layer module, no Claude Code adapter concerns.
8
- * avoids PF-014: no process.exit(); all fallible paths return Result.
7
+ * Pure core-layer module, no Claude Code adapter concerns.
8
+ * No process.exit(); all fallible paths return Result.
9
9
  *
10
10
  * Regex scoping guarantee: ALL operations are confined to the FIRST `---…---`
11
11
  * block. Model/effort lines in the document body are never touched.
@@ -156,7 +156,7 @@ export function rewriteAgentFrontmatter(content, opts) {
156
156
  if (currentEffort !== opts.effort) {
157
157
  // Use a replacement function — NOT a string — so that $&, $`, $',
158
158
  // and $1 in opts.effort are written verbatim rather than expanded as
159
- // replacement patterns (avoids PF-018).
159
+ // replacement patterns.
160
160
  newBody = newBody.replace(EFFORT_RE, () => `effort: ${opts.effort}`);
161
161
  }
162
162
  }
@@ -2,8 +2,8 @@
2
2
  * Agent model mapping engine — schema, persistence, and convergence for the
3
3
  * per-agent model configuration feature.
4
4
  *
5
- * applies ADR-013: pure core-layer module, no Claude Code adapter concerns.
6
- * avoids PF-014: all fallible operations return Result, no process.exit().
5
+ * Pure core-layer module, no Claude Code adapter concerns.
6
+ * All fallible operations return Result, no process.exit().
7
7
  *
8
8
  * Mapping file: ~/.devflow/agent-models.json
9
9
  * { version: 1, agents: { [name]: { model?, effort? } } }
@@ -48,7 +48,7 @@ export const EFFORT_LEVELS = ['low', 'medium', 'high', 'xhigh', 'max'];
48
48
  /**
49
49
  * Membership set typed as ReadonlySet<string> so .has() accepts a plain
50
50
  * string argument without a cast — TypeScript's Set<T>.has() requires T, and
51
- * EFFORT_LEVELS[number] is a literal union, not string (applies ADR-003).
51
+ * EFFORT_LEVELS[number] is a literal union, not string.
52
52
  */
53
53
  const EFFORT_LEVELS_SET = new Set(EFFORT_LEVELS);
54
54
  // ---------------------------------------------------------------------------
@@ -288,7 +288,7 @@ export async function readAgentMapping(devflowDir, opts) {
288
288
  * A missing directory returns an empty set rather than throwing (ENOENT is
289
289
  * not an error — the install dir may not exist on a fresh machine before
290
290
  * `devflow init` runs). Any other OS error also returns an empty set
291
- * (degrade-not-throw per PF-009) — a transient or misconfigured path must
291
+ * (degrade-not-throw) — a transient or misconfigured path must
292
292
  * not prevent the TUI or --list from starting.
293
293
  *
294
294
  * @param installDir - Path to ~/.claude/agents/devflow (or equivalent).
@@ -411,7 +411,7 @@ async function readDirDefaults(dir) {
411
411
  * keep rendering (`devflow agents --list`), so it warns instead. Staying silent
412
412
  * is what makes the gap dangerous: resolveEffective returns an undefined model,
413
413
  * reapplyAgentMapping buckets the agent 'unchanged', and disabling the proxy
414
- * leaves an externally-pinned agent unreverted with nothing said (PF-022).
414
+ * leaves an externally-pinned agent unreverted with nothing said.
415
415
  *
416
416
  * @param dirs - Agent directories, most-preferred first. Injectable so tests can
417
417
  * prove the precedence against a temp tree; all real callers use the default.
@@ -480,7 +480,7 @@ export async function reapplyAgentMapping(opts) {
480
480
  // Guard: reject mapping keys that would read/write outside the install directory.
481
481
  // A corrupted or adversarial agent-models.json could contain path-traversal keys
482
482
  // such as '../../etc/passwd'; this check prevents any filesystem access beyond
483
- // opts.installDir. Per PF-009 (degrade-not-throw), this emits a warning and skips gracefully.
483
+ // opts.installDir. Degrade-not-throw: this emits a warning and skips gracefully.
484
484
  if (!isContainedIn(opts.installDir, mdFileName(agentName))) {
485
485
  localWarn(`reapplyAgentMapping: agent name "${agentName}" resolves outside the install ` +
486
486
  `directory — skipped (containment guard)`);
@@ -2,10 +2,10 @@
2
2
  * Agent installation-state classification.
3
3
  *
4
4
  * Single source of truth for the STATE column shared by `--list` and the TUI.
5
- * Centralised here (core layer) per ADR-013 so neither cli/commands nor
5
+ * Centralised here (core layer) so neither cli/commands nor
6
6
  * cli/agents-view owns the vocabulary.
7
7
  *
8
- * applies ADR-013: pure core-layer module, no CLI-adapter concerns.
8
+ * Pure core-layer module, no CLI-adapter concerns.
9
9
  */
10
10
  import { isDormantExternalModel } from './external-models.js';
11
11
  // ---------------------------------------------------------------------------
package/dist/core/ansi.js CHANGED
@@ -6,9 +6,9 @@
6
6
  * feature module (src/hud/). Re-exported verbatim from src/hud/colors.ts
7
7
  * so all existing HUD call sites remain untouched.
8
8
  *
9
- * applies ADR-013: src/core/ = agent-neutral logic; ANSI primitives have no
9
+ * src/core/ = agent-neutral logic; ANSI primitives have no
10
10
  * feature coupling and belong here, not in a feature module.
11
- * applies PF-017 corollary: one shared definition over per-consumer copies.
11
+ * One shared definition over per-consumer copies.
12
12
  */
13
13
  const ESC = '\x1b[';
14
14
  const RESET = `${ESC}0m`;
@@ -15,8 +15,9 @@
15
15
  * path.join()'s normalization of ".." components. safeEntryPath() enforces
16
16
  * containment and returns null on violation; all callers treat null as a miss.
17
17
  *
18
- * applies ADR-013: core-layer module, no Claude Code adapter concerns.
19
- * avoids PF-011: entries written via tmp→rename (writeFileAtomicExclusive).
18
+ * Core-layer module, no Claude Code adapter concerns.
19
+ * Entries are written via tmp→rename (writeFileAtomicExclusive), so a reader
20
+ * sees the old entry or the new one, never a missing or partial file.
20
21
  */
21
22
  import * as fs from 'node:fs';
22
23
  import { promises as fsAsync } from 'node:fs';
@@ -38,9 +39,9 @@ export const MAX_TTL_MS = 7 * 24 * 60 * 60 * 1000;
38
39
  // All callers that write or read the model-discovery catalog AND the uninstall
39
40
  // removal target derive their directory paths from these functions. Keeping
40
41
  // write-site and removal-site in the same module prevents silent orphaning of
41
- // cache data on future relocations (avoids PF-013).
42
+ // cache data on future relocations.
42
43
  //
43
- // applies ADR-013: path layout owned by the core module, not scattered across
44
+ // Path layout owned by the core module, not scattered across
44
45
  // callers in src/cli/ or src/hud/.
45
46
  /**
46
47
  * Returns the model-discovery cache directory for the given devflowDir.
@@ -137,8 +138,6 @@ export function readCache(cacheDir, key, validate) {
137
138
  * The single canonical envelope parser — used by readCacheEntry (which adds
138
139
  * the expiry check on top) and exported for model-discovery.ts (stale-fallback
139
140
  * and prune sorters) so all callers share one parser and cannot drift.
140
- *
141
- * applies ADR-003: eliminated private parseEnvelope duplicate; one parser, one truth.
142
141
  */
143
142
  export function parseRawEnvelope(raw) {
144
143
  let parsed;
@@ -166,7 +165,7 @@ export function parseRawEnvelope(raw) {
166
165
  * Write a value to cache with a TTL in milliseconds.
167
166
  *
168
167
  * - Creates cacheDir at mode 0700 if absent (owner-only access).
169
- * - Writes the entry via atomic tmp→rename (avoids PF-011 delete-then-write window).
168
+ * - Writes the entry via atomic tmp→rename (no delete-then-write window).
170
169
  * - Hardens the entry to 0600 after the write (owner-only read/write for cache data
171
170
  * that will feed agent frontmatter in later phases).
172
171
  * - TTL is clamped to MAX_TTL_MS before storage.
@@ -196,7 +195,7 @@ export async function writeCache(cacheDir, key, data, ttlMs) {
196
195
  }
197
196
  // Harden entry to 0600 after the atomic write. writeFileAtomicExclusive
198
197
  // preserves the existing mode on re-writes; this chmod bootstraps 0600 on
199
- // the first write to a fresh entry. Best-effort, non-fatal (avoids PF-009).
198
+ // the first write to a fresh entry. Best-effort, non-fatal.
200
199
  try {
201
200
  await fsAsync.chmod(filePath, 0o600);
202
201
  }
@@ -1,8 +1,8 @@
1
1
  /**
2
2
  * Codex credential-file inspection for `devflow proxy --status`.
3
3
  *
4
- * applies ADR-013: pure core-layer module — no Claude Code adapter concerns and
5
- * no presentation (colour/format lives with the other CLI formatters).
4
+ * Pure core-layer module — no Claude Code adapter concerns and
5
+ * no presentation (colour/format lives with the other CLI formatters).
6
6
  *
7
7
  * WHY THIS EXISTS RATHER THAN IMPORTING THE ROUTING RUNTIME
8
8
  * The routing runtime validates this same file and exposes an equivalent
@@ -62,8 +62,8 @@ function jwtAccountId(token) {
62
62
  /**
63
63
  * Classify an I/O error from reading ~/.codex/auth.json into a CodexAuthState.
64
64
  *
65
- * applies ADR-013: pure classification logic belongs in src/core/, not in the
66
- * CLI presentation layer that calls it.
65
+ * Pure classification logic belongs in src/core/, not in the
66
+ * CLI presentation layer that calls it.
67
67
  *
68
68
  * ENOENT is the ordinary "not signed in" case: the file has never been written
69
69
  * by `codex login`. Every other error (EACCES, EISDIR, EMFILE, …) is a real
@@ -5,8 +5,8 @@
5
5
  * fragment files, so installed artifacts differ by selection rather than being
6
6
  * static all-six blobs.
7
7
  *
8
- * Applies ADR-013: pure helpers in src/core/, no I/O.
9
- * Applies PF-009: warn-not-throw for per-item failures.
8
+ * Pure helpers in src/core/, no I/O.
9
+ * Warn-not-throw for per-item failures.
10
10
  */
11
11
  import { COMPLIANCE_FRAMEWORKS, stampComplianceRule } from './compliance.js';
12
12
  // ── Constants ──────────────────────────────────────────────────────────────────
@@ -278,7 +278,7 @@ function buildReferences(activeFrameworks, fragments) {
278
278
  * Strict boundary parser: validates all required sections (## Mapping / ##
279
279
  * Reference / ## Checklist / ## Rule) and their structural constraints.
280
280
  * CRLF-tolerant: Windows line endings are normalised before parsing.
281
- * Never throws (PF-009): all errors return { ok: false, error }.
281
+ * Never throws: all errors return { ok: false, error }.
282
282
  */
283
283
  export function parseComplianceFragment(id, raw) {
284
284
  // CRLF tolerance
@@ -2,7 +2,7 @@
2
2
  * Core compliance framework registry and utilities.
3
3
  *
4
4
  * Pure module — no I/O, no side effects.
5
- * Applies ADR-013: pure helpers in src/core/, I/O orchestration in src/targets/.
5
+ * Pure helpers in src/core/, I/O orchestration in src/targets/.
6
6
  */
7
7
  /**
8
8
  * Canonical compliance framework registry.
@@ -26,7 +26,7 @@ export const COMPLIANCE_RULE_PLACEHOLDER = '${DEVFLOW_COMPLIANCE_FRAMEWORKS}';
26
26
  * detection.md — generic detection heuristics
27
27
  * sources.md — authoritative source index
28
28
  *
29
- * Exported (ADR-013: pure constant in src/core/) so both compliance-install.ts
29
+ * Exported (pure constant in src/core/) so both compliance-install.ts
30
30
  * (install) and compliance.ts CLI (status/drift detection) share a single
31
31
  * definition. Adding a third always-present ref requires only one change here.
32
32
  */
@@ -60,7 +60,7 @@ function normalizeId(s) {
60
60
  * This is the trust boundary for framework IDs that did not come through
61
61
  * `parseFrameworkList` — most importantly `manifest.features.compliance.frameworks`,
62
62
  * which `normalizeComplianceFeature` only type-checks (it cannot reject unknown IDs
63
- * without violating the ADR-014 self-heal contract). Every framework ID that is about
63
+ * without violating the self-heal contract). Every framework ID that is about
64
64
  * to become an fs path segment or be written into an installed artifact must pass
65
65
  * through here first (AC-35, AC-36).
66
66
  *
@@ -111,7 +111,6 @@ export function parseFrameworkList(input) {
111
111
  *
112
112
  * Absent, null, malformed, or partially-valid → {enabled:false, frameworks:[]}.
113
113
  * Preserves valid {enabled: boolean, frameworks: string[]}.
114
- * (Applies ADR-014 self-heal idiom)
115
114
  */
116
115
  export function normalizeComplianceFeature(raw) {
117
116
  const DEFAULT = { enabled: false, frameworks: [] };
@@ -3,7 +3,7 @@
3
3
  * `resolve-evidence-policy.cjs`, never a second implementation of it.
4
4
  *
5
5
  * D-POLICY-CJS-SEAM: the resolver is plain CommonJS under src/assets/scripts/,
6
- * outside every tsconfig (PF-043, PF-069), so the interfaces below are
6
+ * outside every tsconfig, so the interfaces below are
7
7
  * TRANSCRIBED from its JSDoc typedefs and are the only shape authority on this
8
8
  * side — open those typedefs before changing anything here. The module is loaded
9
9
  * with `require()` from `scriptsDir()`, which resolves under the package root both
@@ -20,7 +20,7 @@
20
20
  * `lib/project-config.cjs` (loadProjectConfigLib), so the CLI judges a config
21
21
  * file's bytes exactly as the resolvers do.
22
22
  *
23
- * D-POLICY-NO-WRITE (applies ADR-024): `.devflow/project.json` is team-owned, and
23
+ * D-POLICY-NO-WRITE: `.devflow/project.json` is team-owned, and
24
24
  * devflow never writes or replaces a shared file it cannot prove it wrote. This
25
25
  * module therefore imports no fs API; the CLI only PRINTS the bytes a team may
26
26
  * choose to commit (`evidencePolicySuggestion`, and the migration lines of
@@ -101,23 +101,24 @@ function surfaceMismatches(value, surface) {
101
101
  * require() one package script and shape-check it against `surface`. Never
102
102
  * throws: a missing file is `not-found`; a module that throws on load or lacks a
103
103
  * surface key is `unusable`. The caller's type parameter is justified by the
104
- * surface check, which `satisfies` ties to the interface's keys.
104
+ * surface check, which `satisfies` ties to the interface's keys. Exported for
105
+ * src/core/learning-store.ts, which loads the learning store the same way.
105
106
  */
106
- function loadScript(file, surface) {
107
+ export function loadScript(scriptPath, surface) {
107
108
  let loaded;
108
109
  try {
109
- loaded = createRequire(import.meta.url)(file);
110
+ loaded = createRequire(import.meta.url)(scriptPath);
110
111
  }
111
112
  catch (err) {
112
113
  const code = err.code;
113
114
  if (code === 'MODULE_NOT_FOUND')
114
- return { ok: false, error: { kind: 'not-found', path: file } };
115
+ return { ok: false, error: { kind: 'not-found', path: scriptPath } };
115
116
  const detail = err instanceof Error ? err.message : String(err);
116
- return { ok: false, error: { kind: 'unusable', path: file, detail } };
117
+ return { ok: false, error: { kind: 'unusable', path: scriptPath, detail } };
117
118
  }
118
119
  const mismatches = surfaceMismatches(loaded, surface);
119
120
  if (mismatches.length > 0) {
120
- return { ok: false, error: { kind: 'unusable', path: file, detail: `missing or mistyped: ${mismatches.join(', ')}` } };
121
+ return { ok: false, error: { kind: 'unusable', path: scriptPath, detail: `missing or mistyped: ${mismatches.join(', ')}` } };
121
122
  }
122
123
  return { ok: true, value: loaded };
123
124
  }
@@ -167,10 +168,10 @@ export function formatEvidencePolicyUnavailable(error) {
167
168
  /**
168
169
  * The `compliance --status` line: the resolved policy for `opts.dir`, or the
169
170
  * unavailable line when the loader failed — that line is the whole handling
170
- * (ADR-028). The caller passes the compliance state it already read, so the
171
- * manifest is never read twice. `resolve()` makes at most three `gh` calls and
172
- * bounds every subprocess with a timeout, so an offline machine degrades to a
173
- * flagged result rather than a hang.
171
+ * (only a damaged package fails the load). The caller passes the compliance
172
+ * state it already read, so the manifest is never read twice. `resolve()` makes
173
+ * at most three `gh` calls and bounds every subprocess with a timeout, so an
174
+ * offline machine degrades to a flagged result rather than a hang.
174
175
  */
175
176
  export function evidencePolicyStatusLine(loaded, opts) {
176
177
  if (!loaded.ok)
@@ -198,7 +199,7 @@ function suggestedFrameworks(complianceState) {
198
199
  * count); `null` otherwise. The bytes come
199
200
  * from the settings resolver's `serializeProjectSuggestion`, which returns them
200
201
  * only when they read back through the shared parser as exactly what was asked.
201
- * Nothing is written (D-POLICY-NO-WRITE, applies ADR-024).
202
+ * Nothing is written (D-POLICY-NO-WRITE).
202
203
  */
203
204
  export function evidencePolicySuggestion(complianceState, policy, settings) {
204
205
  if (policy.complianceDefault(complianceState) !== 'required')
@@ -9,7 +9,7 @@
9
9
  * in src/core/model-discovery.ts. The TUI picker and --set validation use the
10
10
  * ExternalModelCatalog returned by those functions.
11
11
  *
12
- * applies ADR-013: pure core-layer module, no Claude Code adapter concerns.
12
+ * Pure core-layer module, no Claude Code adapter concerns.
13
13
  *
14
14
  * NOTE: the internal routing runtime package name must NEVER appear in
15
15
  * user-visible strings, CLI output, or error messages. User-facing vocabulary: