@deftai/directive-content 0.104.0 → 0.105.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 (34) hide show
  1. package/Taskfile.yml +12 -6
  2. package/UPGRADING.md +4 -0
  3. package/coding/coding.md +2 -2
  4. package/commands.md +26 -6
  5. package/docs/directive-lifecycle.md +12 -4
  6. package/docs/project-invariants.md +79 -0
  7. package/docs/scope-provenance.md +53 -8
  8. package/main.md +2 -0
  9. package/meta/ralph.md +1 -1
  10. package/package.json +1 -1
  11. package/packs/rules/rules-pack-0.1.json +3 -3
  12. package/packs/skills/skills-pack-0.1.json +15 -9
  13. package/scm/github.md +34 -1
  14. package/skills/deft-directive-build/SKILL.md +26 -1
  15. package/skills/deft-directive-gh-slice/SKILL.md +2 -2
  16. package/skills/deft-directive-refinement/SKILL.md +1 -1
  17. package/skills/deft-directive-review-cycle/SKILL.md +37 -11
  18. package/skills/deft-directive-setup/SKILL.md +2 -0
  19. package/skills/deft-directive-swarm/SKILL.md +21 -5
  20. package/skills/deft-directive-swarm/references/core-ops.md +3 -1
  21. package/skills/deft-directive-swarm/references/core-phase-0.md +1 -0
  22. package/skills/deft-directive-swarm/references/core-phase-3.md +1 -1
  23. package/skills/deft-directive-swarm/references/core-phase-4.md +27 -11
  24. package/skills/deft-directive-swarm/references/core-phase-5-6.md +4 -1
  25. package/skills/deft-directive-sync/SKILL.md +1 -1
  26. package/tasks/engine.yml +2 -0
  27. package/tasks/occupancy.yml +17 -0
  28. package/tasks/scm.yml +13 -7
  29. package/tasks/vbrief.yml +3 -2
  30. package/tasks/verify.yml +22 -2
  31. package/tasks/xbrief.yml +43 -0
  32. package/templates/agent-prompt-preamble.md +12 -3
  33. package/templates/agents-entry.md +7 -2
  34. package/vbrief/schemas/vbrief-core.schema.json +72 -0
package/Taskfile.yml CHANGED
@@ -142,9 +142,12 @@ includes:
142
142
  vbrief:
143
143
  taskfile: ./tasks/vbrief.yml
144
144
  optional: false
145
+ # Non-optional (#3483): the swarm skill names xbrief:validate / xbrief:activate
146
+ # / xbrief:preflight at MUST/⊗ level, so a silently-omitted include would
147
+ # reproduce the opaque exit-200 "task does not exist" failure at cohort close.
145
148
  xbrief:
146
149
  taskfile: ./tasks/xbrief.yml
147
- optional: true
150
+ optional: false
148
151
  prd:
149
152
  taskfile: ./tasks/prd.yml
150
153
  optional: true
@@ -172,6 +175,9 @@ includes:
172
175
  session:
173
176
  taskfile: ./tasks/session.yml
174
177
  optional: true
178
+ occupancy:
179
+ taskfile: ./tasks/occupancy.yml
180
+ optional: true
175
181
  lifecycle:
176
182
  taskfile: ./tasks/lifecycle.yml
177
183
  optional: true
@@ -1063,10 +1069,10 @@ tasks:
1063
1069
  CLI_ARGS: "{{.CLI_ARGS}}"
1064
1070
 
1065
1071
  # N7 (#1147): slice:record-existing backfill verb. Retrofits a
1066
- # vbrief/.eval/slices.jsonl entry for hand-filed umbrella cohorts that
1067
- # D13's writer (#1132) never saw because they were filed via
1068
- # `gh issue create` / `issue_write` MCP rather than via a slicing
1069
- # skill. Companion `slice:list` exposes the read surface.
1072
+ # <lifecycle-root>/.triage-cache/slices.jsonl entry for hand-filed
1073
+ # umbrella cohorts that D13's writer (#1132) never saw because they
1074
+ # were filed via `gh issue create` / `issue_write` MCP rather than via
1075
+ # a slicing skill. Companion `slice:list` exposes the read surface.
1070
1076
  slice:record-existing:
1071
1077
  desc: "Retrofit a slices.jsonl entry for a hand-filed cohort (#1147 / N7). -- task slice:record-existing -- --umbrella=N --children=A,B,C [--wave-1=A,B] [--wave-2=C] [--actor=manual:operator] [--expected-close-signal=all-children-merged] [--sliced-at=ISO] [--notes=TEXT] [--dry-run] [--force] [--skip-validation] [--repo OWNER/NAME]"
1072
1078
  cmds:
@@ -1075,7 +1081,7 @@ tasks:
1075
1081
  CLI_ARGS: "{{.CLI_ARGS}}"
1076
1082
 
1077
1083
  slice:list:
1078
- desc: "List recorded slices in vbrief/.eval/slices.jsonl (#1147 / N7). -- task slice:list [-- --json]"
1084
+ desc: "List recorded slices in <lifecycle-root>/.triage-cache/slices.jsonl (#1147 / N7). -- task slice:list [-- --json]"
1079
1085
  cmds:
1080
1086
  - task: slice-record:list
1081
1087
  vars:
package/UPGRADING.md CHANGED
@@ -217,6 +217,8 @@ the configured mirror.
217
217
 
218
218
  **Prettier / format gate (#2534):** managed `.deft/core/` is outside your consumer Prettier gate. `directive init` and `directive update` idempotently deposit or heal a root `.prettierignore` entry for `.deft/core/` so `prettier --check .` (and `task check` when Prettier is wired) does not fail on the vendored framework payload. You do not need to reformat `.deft/core/` after upgrade.
219
219
 
220
+ **Schema rewrite / format before the upgrade PR (#3395):** `deft update` may rewrite consumer-owned `xbrief/schemas/*`. It does **not** run your repo formatter. When the update summary lists rewritten consumer-owned paths, run `task fmt` (or your formatter) **before** opening the upgrade PR so Prettier / `task check` stay green.
221
+
220
222
  > **`deft update` is the single canonical upgrade verb (#2064).** The older `deft install-upgrade` (and its `task upgrade` maintainer alias) now print a one-line notice and delegate to this exact `deft update` path — they no longer have their own semantics. Previously `install-upgrade` only rewrote the marker/manifest without swapping the payload, so on a stale deposit it reported a false "Project already at X. Nothing to do." Use `deft update`; there is nothing `install-upgrade` does that `deft update` does not.
221
223
 
222
224
  3. **Stamp npm provenance (one-time, idempotent):**
@@ -282,6 +284,8 @@ A normal framework upgrade is **one PR**, not two stacked PRs. The deposited `de
282
284
 
283
285
  **Do not** split a routine version bump into “deposit-only” then “pin/GENERATION” PRs — that re-creates engine / deposit / pin skew between merges. **Do** keep product feature work on a separate branch/PR from the framework upgrade. Consumers should **not** hand-roll a forked `deft-core-guard.yml` for normal upgrades — the deposited workflow already enforces pin-only + lock follow-through.
284
286
 
287
+ **Format before you open the PR (#3395):** if `deft update` listed rewritten consumer-owned `xbrief/schemas/*` paths, run `task fmt` (or your repo formatter) first. Update does not invoke the consumer formatter.
288
+
285
289
  **Load fix (#3345):** if GitHub Actions shows workflow name as the path string `.github/workflows/deft-core-guard.yml` (not `deft-core-guard`), or historical runs are 0s/0 jobs and the required check `no-mixed-core-and-app` never appears on PRs, the deposited workflow failed to load (invalid YAML from an unindented Python heredoc). Run `deft update` (or re-init deposit) so the fixed workflow is rewritten, then open a normal upgrade PR — classic branch protection that requires `no-mixed-core-and-app` can clear once the job posts.
286
290
 
287
291
  Refs: [#3127](https://github.com/deftai/directive/issues/3127), [#3193](https://github.com/deftai/directive/issues/3193), [#1430](https://github.com/deftai/directive/issues/1430), [#3117](https://github.com/deftai/directive/issues/3117), [#3345](https://github.com/deftai/directive/issues/3345).
package/coding/coding.md CHANGED
@@ -47,7 +47,7 @@ See [../scm/git.md](../scm/git.md) for:
47
47
 
48
48
  **Modularity:**
49
49
  - ! One responsibility per file/module
50
- - ~ Files <300 lines ideal; <500 lines recommended; <1000 lines a review trigger split when exceeded unless genuinely single-responsibility (size is a smell, not a hard cap; #1488)
50
+ - ~ Keep files small. Ideal, recommended, and review-trigger line counts are FILE_SIZE_IDEAL_LINES, FILE_SIZE_RECOMMENDED_LINES, and FILE_SIZE_REVIEW_TRIGGER_LINES in the file-size-thresholds policy module (packages/core/src/policy/file-size-thresholds.ts). Split when a file exceeds the review trigger unless it is genuinely single-responsibility (size is a smell, not a hard cap; #1488 / #3424)
51
51
  - ! Explicit scope in task descriptions
52
52
  - ~ DRY: extract shared abstractions when logic is duplicated across 2+ call sites
53
53
  - ⊗ Copy-paste logic with minor variations — parameterise instead
@@ -234,7 +234,7 @@ See [debugging.md](debugging.md) for the full four-phase process, evidence disci
234
234
 
235
235
  - ⊗ Secrets in code or version control
236
236
  - ⊗ Claiming checks passed without running them
237
- - ⊗ Single files mixing multiple responsibilities (large line count, e.g. >1000 lines, is a trigger to check cohesion — not a defect by itself; #1488)
237
+ - ⊗ Single files mixing multiple responsibilities (line count at or above FILE_SIZE_REVIEW_TRIGGER_LINES is a cohesion review trigger — not a defect by itself; #1488 / #3424)
238
238
  - ⊗ Skipping quality checks
239
239
  - ⊗ Breaking changes without explicit approval
240
240
  - ⊗ Using `grep` command when `rg` or Warp grep available
package/commands.md CHANGED
@@ -158,7 +158,7 @@ task verify:story-ready -- --vbrief-path xbrief/active/<file>.xbrief.json
158
158
  deft xbrief:preflight -- xbrief/active/<file>.xbrief.json
159
159
  ```
160
160
 
161
- Gate 0 `task verify:story-ready` machine-checks working-tree cleanliness (or `--allow-dirty`), the target xBRIEF in `xbrief/active/` with `plan.status == "running"`, and the dispatch envelope's `## Allocation context` consent token (#1378). A `swarm-cohort` section is ready only when `allocation_plan_id` AND `batching_rationale` are non-null. Complete stories with `task scope:complete -- <active-story-path>`.
161
+ Gate 0 `task verify:story-ready` machine-checks working-tree cleanliness (or `--allow-dirty`), the target xBRIEF in `xbrief/active/` with `plan.status == "running"`, and the dispatch envelope's `## Allocation context` consent token (#1378). A `swarm-cohort` section is ready only when `allocation_plan_id` AND `batching_rationale` are non-null. Both `verify:story-ready` and `xbrief:preflight` also fail closed when an applicable `plan.policy.projectInvariants` ID has no `coverage_map` disposition (list as of check time; completeness only). See `content/docs/project-invariants.md`. Complete stories with `task scope:complete -- <active-story-path>`.
162
162
 
163
163
  **Story Start Gate (#1378):** Before starting any new implementation story or switching stories, run `git status --short --branch`. If the working tree is dirty, stop and summarize the current branch, modified/untracked files, and whether the changes appear related to the next story — ask the operator to choose: commit existing work, stash existing work, include existing work in the current story, or stop. ⊗ Do not begin a new story while unrelated dirty work is present without explicit operator approval. When invoked as part of a swarm cohort dispatch, the approved Phase 5 allocation plan satisfies batching consent (#954); between stories checkpoint-commit it and proceed — do not pause to ask the operator mid-cohort. Promote/activate via `task scope:promote -- <path>` (or `task scope:promote -- --batch` for multi-scope pins, #3011) / `task scope:activate -- <path>`; preflight with `deft xbrief:preflight -- <active-story-path>`.
164
164
 
@@ -189,6 +189,24 @@ flowchart TD
189
189
 
190
190
  ---
191
191
 
192
+ ## Default-branch sync (`scm:sync-default`, #3391)
193
+
194
+ Open dest-targeted sync PRs from typed `baseBranch` to `deliveryBranch`. Consumes the shared detector (#3388) and `syncMaxFiles` (#3390).
195
+
196
+ ```bash
197
+ task scm:sync-default -- --dry-run
198
+ task scm:sync-default -- --max-files 100
199
+ ```
200
+
201
+ - Under the file-count limit: one new PR from source tip to dest.
202
+ - Over the limit: merge-commit cuts; each dest-based leg is a new branch and a new PR. After a leg merges, run the verb again.
203
+ - ⊗ `gh pr edit --base` or close-reopen of an oversized PR. Each leg must be new when the reviewer first sees it.
204
+ - Required checks stay on except the Wave 1 core-guard sync exemption.
205
+
206
+ Docs: [scm/github.md](./scm/github.md) § Default-branch sync.
207
+
208
+ ---
209
+
192
210
  ## Structured decision log (#1396)
193
211
 
194
212
  Lightweight intent-debt records for **significant** choices (architecture, product behavior, security, public/private boundary, data model, runtime topology, hard-to-reverse process). Not every trivial scope. Not ADR migration; leave `docs/decisions/ADR-*.md` alone. Split from lessons (#1513).
@@ -273,8 +291,8 @@ Current status: the validation, extractor, provider, registry, generated MAP, an
273
291
  - `task verify:xbrief-conformance` -- validate xBRIEF conformance surfaces.
274
292
  - `task verify:cache-fresh` -- validate cache freshness where required.
275
293
  - `task verify:capacity`, `task verify:wip-cap`, and `task verify:judgment-gates` -- policy/capacity gates.
276
- - `task verify:orphan-active` -- fail closed when active/running xBRIEFs still point at closed issues or merged PRs (#2321).
277
- - `task verify:completed-tracked` -- fail closed when closed scoped issues lack a tracked `xbrief/completed/` or `xbrief/cancelled/` artifact on the delivery tip (#3264); remediate with `task swarm:finalize-cohort` or a lifecycle PR. Standalone verb (not part of `task check`); use `--tip HEAD` when validating an in-flight land branch.
294
+ - `task verify:orphan-active` -- fail closed when active/running xBRIEFs still point at closed issues or merged PRs (#2321). After merge, `task verify:orphan-active -- --issue N` scans briefs that reference that issue. Confirmed shipped prints `task scope:complete -- <path>`; unresolved lookup prints a retry remediation and still exits 1 (#3429). PR-only briefs stay on the unscoped scan or `task swarm:complete-cohort`.
295
+ - `task verify:completed-tracked` -- fail closed when closed scoped issues lack a tracked `xbrief/completed/` or `xbrief/cancelled/` artifact on the delivery tip (#3264 / #3476); remediate with `task swarm:finalize-cohort` or a lifecycle PR. `task verify:completed-tracked -- --issue N` is the drive-to DONE form (delivery tip `origin/<deliveryBranch>`, not feature HEAD). Standalone verb (not part of `task check`); use `--tip HEAD` when validating an in-flight land branch. An unresolvable delivery tip fails closed (no silent HEAD fallback) -- fetch the delivery branch or pass an explicit `--tip`. Under `--skip-gh`, a named `--issue` with no cached state fails closed; the unscoped corpus scan keeps the offline allowance. Lifecycle-only lands (completed/cancelled xBRIEFs + optional CHANGELOG) use that verb plus finalize-cohort or the lifecycle PR. ⊗ Full `task check` / the TypeScript suite. ⊗ The drive-to story envelope (pre-pr + review-cycle + suite) for a file-copy land.
278
296
  - `task verify:ac` -- product-first acceptance gate (#3284). Runs `plan.acceptance.commands` (or #3267 literal ledger) **verbatim** before done; records AC-source rung (`stated`/`derived`/`project_floor`). Empty commands require `none_stated: true`. Empty resolution is not a green run when the project has no suite floor (`soft_empty` + stamp-acceptance remedy, #3334). Primary name used first in `task check` (fail-fast); `--soft-missing-xbrief` for check composition. Rapid ceremony = AC-only; pressure/degraded makes hygiene advisory. `--capture-only` lists resolved commands without executing. Extends #3267 / #973.
279
297
  - `task verify:literal-ac` -- #3267 mechanism alias for verbatim stated-command run (same flags/cwd); prefer `verify:ac` for product-first done-gate.
280
298
  - `task coverage:hotspots` / `deft coverage:hotspots` -- read the latest coverage report, compare global metrics to the project's vitest thresholds, fail closed below the branch floor or below configured headroom (default 0.3pp), and list lowest modules plus uncovered branch samples for git-diff paths (`--json` for agents). Complements `deft verify:forward-coverage` (#1310) and `--allow-coverage-debt=#N` (#2573); does not replace them.
@@ -375,6 +393,7 @@ After CLI/deposit upgrade, disk can show the new generation while a long-lived s
375
393
  - ! **USER.md path (#2544):** resolve via `deft session:start` output (`USER.md resolved …`); default platform paths: Windows `%APPDATA%\deft\USER.md`, Unix `~/.config/deft/USER.md`; override `$DEFT_USER_PATH`; workspace `<project>/.deft/USER.md`. ⊗ Invent or search `~/.config/deft` on Windows — AppData Roaming is canonical.
376
394
  - ! At mutation boundaries (code-writing, scope lifecycle moves, `start_agent`, commits, pushes, PR-from-local-changes, release work): run the mutable quick tier then gated verifier below before proceeding.
377
395
  - ? Explicit read-only alignment only: `deft session:start -- --read-only` (no ritual-state write).
396
+ - ! **Worktree occupancy (#3433):** mutation `session:start` / `session:ready` claim a gitignored `.deft/occupancy.json` lease. A second mutation session on the same tree with a different `DEFT_SESSION_ID` fails closed (occupant id, intent, heartbeat age + remediation). Same-session re-arm heartbeats and keeps that id — it does not mint a new UUID. Steal with `occupancy:steal --confirm --occupant <id>` (or `session:start --steal --confirm --occupant <id>`). Expired heartbeat (20 min) is free. `--read-only` does not claim. Join (`occupancy:request`) is named in the remediation only. `swarm:launch` persists `occupancy_session_id` in a cohort-keyed record; close-out must use that cohort's entry (or `DEFT_SESSION_ID`), never a slot another launch can overwrite and never the live lease file.
378
397
  - ~ Operators MAY still explicitly request full `deft session:start`, `deft triage:welcome`, sync, or doctor in read-only sessions.
379
398
 
380
399
  ### Assist / research posture (#1802)
@@ -402,7 +421,7 @@ Cross-link: spawn three postures and deny recoveries live under § Agent-host di
402
421
 
403
422
  ### Mutable ritual (mutation posture)
404
423
 
405
- - ! On **mutation** session start, run `deft session:start` (or `task session:start` in framework source) after loading AGENTS.md. Records quick-tier ritual in `.deft/ritual-state.json`: alignment confirmation, branch-policy disclosure, `deft verify:tools` guidance, default-branch sync warnings, and `deft triage:welcome` one-liner. State is worktree- and HEAD-bound; stale after `plan.policy.sessionRitualStalenessHours` hours (default 4).
424
+ - ! On **mutation** session start, run `deft session:start` (or `task session:start` in framework source) after loading AGENTS.md. Records quick-tier ritual in `.deft/ritual-state.json`: alignment confirmation, branch-policy disclosure, `deft verify:tools` guidance, default-branch sync warnings, and `deft triage:welcome` one-liner. State is worktree- and HEAD-bound; stale after `plan.policy.sessionRitualStalenessHours` hours (default 4). Mutation start also claims the worktree occupancy lease (`.deft/occupancy.json`); see Session routing (#3433).
406
425
  - ! **Orientation compression Now (#3286):** mutation cold `session:start` composes `doctor` + #3282 toolchain preflight (and deposit-sha fast-paths for `agents:refresh` / `verify:cache-fresh`) as inline sections with per-section status lines — composition of existing steps, not a new monolith. When the deposit fingerprint (payload + templates + engine) is unchanged, refresh surfaces print one-line `unchanged - sha match` no-ops. Opt-in compact output: `deft session:start -- --compact` or `DEFT_SESSION_COMPACT=1` (verbose remains the default). #2176 read-only default is unchanged. Dual-path Later (`deft orient`) stays open until run-summary telemetry shows ritual+gate share ≥ 25% after Now ships (#2899).
407
426
  - ! Cold `session:start` does **not** run the live agent-hook probe. Functional readiness belongs to the gated mutation path so cold ceremony retains the #2990/#2991 latency profile.
408
427
  - ! **Hot path latency (#2991):** by default, mutation `session:start` does **not** block ritual-state write on optional network. It skips the npm release-availability probe and triage cache empty-hydrate / self-heal (`ensureTriageCacheHydrated` / `maybeSelfHealCache`). Targets (operator-facing, not CI-hard): warm hot path typically under a few seconds once tools are on PATH; cold path dominated by local `verify:tools` and git, usually well under ~30s when optional network is off. Empty-cache GitHub fetch-all and npm `view` previously accounted for multi-minute hangs in the WWYSYDH pilot — those stay off the critical path unless opted in.
@@ -587,9 +606,10 @@ flowchart TD
587
606
  - `task pr:check-closing-keywords` -- Layer 0 FP lint (#737) **plus intent mode** (#3015 class D). Default `--mode both`: fails on negation/quote/example/code-block hits **and** on any real `Closes|Fixes|Resolves #N` unless allowlisted via `--allow-close N,M` (CLI only; body trailers are not an authorization path). Offline: `--body-file` / `--commits-file`. Prefer `Tracking: #N` / `Refs #N` until full issue DoD.
588
607
  - `task release:*` -- release, publish, rollback, and e2e release rehearsal.
589
608
  - Step 3 (`Pre-flight vBRIEF lifecycle sync`) fetches GitHub issue states via REST. On HTTP 403 rate-limit exhaustion it sleeps once (capped at 120s) and retries before failing.
590
- - When Step 3 still fails with rate-limit exhaustion, stderr includes a `gh api rate_limit` probe (`core.remaining`, reset time) and recovery guidance. After local `task vbrief:validate` (or `task xbrief:validate`) exits 0, operators may pass `--allow-vbrief-drift` to skip Step 3 for that cut — reserved for transient SCM bucket stalls, not unreviewed lifecycle drift.
609
+ - When Step 3 still fails with rate-limit exhaustion, stderr includes a `gh api rate_limit` probe (`core.remaining`, reset time) and recovery guidance. After local `task xbrief:validate` exits 0, operators may pass `--allow-vbrief-drift` to skip Step 3 for that cut — reserved for transient SCM bucket stalls, not unreviewed lifecycle drift.
591
610
  - `task swarm:*` -- readiness, launch, pre-dispatch deny gate (#3228), review-clean verification, and cohort completion.
592
- - **Operator follow-up after dual-stop / hard stop (#3273):** when a dual-stop or conf-hold halt report lands, re-authorize one residual pass with phrases *pursue residual* / *follow-up hard-stop* / *same as conf-hold* / *continue dual-stopped PR* steps in `skills/deft-directive-swarm` and `skills/deft-directive-review-cycle` § Operator follow-up after dual-stop / hard stop (not a separate task verb).
611
+ - **Operator follow-up after dual-stop / hard stop (#3273 / #3448):** one-shot *pursue residual* / *follow-up hard-stop* / *same as conf-hold* / *continue dual-stopped PR* is one pass then re-stop. Standing *until floor or loop* / *until greptile meets policy* / *pursue residuals until told otherwise* keeps class A leftovers on open cohort/plan units moving until the resolved `#3095` floor or the **Same-fingerprint stop** in `skills/deft-directive-review-cycle/SKILL.md` Dual stop (not a separate task verb). Steps in `skills/deft-directive-swarm` and `skills/deft-directive-review-cycle` § Operator follow-up after dual-stop / hard stop.
612
+
593
613
  - `task slice:*` -- feature-slice helpers.
594
614
  - `task policy:*` and `task capacity:*` -- policy inspection and allocation helpers.
595
615
 
@@ -65,14 +65,22 @@ framework:
65
65
  | **Ship** | PR merge and release — `task pr:*` and [`deft-directive-release`](../skills/deft-directive-release/SKILL.md). |
66
66
  | **Issues / Features** | GitHub issues and feature requests mirrored into `.deft-cache/` and surfaced as triage candidates. |
67
67
 
68
- ## Delivery integrity vs deploy / UAT (#3041)
68
+ ## Delivery integrity vs deploy / UAT (#3041 / #3380)
69
69
 
70
70
  `scope:complete` and swarm cohort completion mark **lifecycle bookkeeping**, not environment
71
71
  green. For **code-bearing** scopes, delivered completion requires durable proof that the
72
72
  implementation reached the configured **delivery branch** (`plan.policy.deliveryBranch`,
73
- defaulting to the repo default branch) typically: PR `base.ref` equals that branch, and the
74
- merge commit is an ancestor of the refreshed remote delivery ref. A merge into an intermediate
75
- feature/integration branch is **not** delivery.
73
+ defaulting to the repo default branch). Ancestry on the refreshed remote delivery ref
74
+ (`origin/<deliveryBranch>`) is delivery. PR `base.ref` / `prBase` is provenance only: a
75
+ develop-targeted scope PR can still complete as delivered when its merge commit is already
76
+ an ancestor of `origin/<deliveryBranch>`. `merged_to_integration` applies only when that
77
+ ancestry fails.
78
+
79
+ Squash-sync from develop to main can rewrite commits so a develop merge SHA is no longer
80
+ an ancestor of `origin/main`. Wait until the work is reachable on the delivery ref, or
81
+ type `plan.policy.deliveryBranch` to the branch you actually ship from
82
+ (`task policy:show --field=deliveryBranch`). This document does not prescribe a squash-sync
83
+ repair.
76
84
 
77
85
  Handoff states that Git can assert are distinct: `implemented` → `pr_open` →
78
86
  `merged_to_integration` → `delivered`. **Deployed** and **UAT verified** are separate evidence
@@ -0,0 +1,79 @@
1
+ # Project invariants (`plan.policy.projectInvariants`)
2
+
3
+ Refs: #3425 · Related: #3238 `coverage_map`, #3241 parent lineage, #516 / #3145 `file_scope`
4
+
5
+ Authored must-not-break contracts for a shared product. Every running story must
6
+ declare how it treats the invariants that apply to its `file_scope`. Empty or
7
+ absent list is a no-op.
8
+
9
+ ## Authored list
10
+
11
+ SoT is PROJECT-DEFINITION `plan.policy.projectInvariants`. Inspect with
12
+ `task policy:show --field=projectInvariants`.
13
+
14
+ Each entry:
15
+
16
+ - `id` — stable key reused on the scope `coverage_map`
17
+ - `statement` — the contract in operator language
18
+ - contract surface — `paths` and/or `moduleIds` (module ids resolve through
19
+ `plan.architecture.codeStructure.modules[].pathGlobs`)
20
+
21
+ ## Scope coverage
22
+
23
+ Reuse the #3238 `coverage_map` shape against **applicable** project IDs:
24
+
25
+ | Disposition | Required side field |
26
+ | --- | --- |
27
+ | `covered` | none |
28
+ | `deferred` | `provenance.reason` + target |
29
+ | `behavioral_delta` | `delta_id` linked in `behavioral_deltas` |
30
+ | `not_applicable` | `reason` |
31
+
32
+ `split` is excluded at project level.
33
+
34
+ Applicability is contract surface × the story's `file_scope`. Empty intersection
35
+ means no disposition is required for that ID.
36
+
37
+ ## Gate
38
+
39
+ `task xbrief:preflight` and `task verify:story-ready` fail closed when an
40
+ applicable ID has no disposition. The message names the omitted ID. Slice-scoped
41
+ and worktree-scoped stories use the same check.
42
+
43
+ The check evaluates the list **as of preflight time**. An ID added after a story
44
+ was authored fails that story on its next preflight and names the new ID.
45
+
46
+ ## Honesty limit
47
+
48
+ The gate verifies **completeness of declarations**, not truth. A scope cannot
49
+ break an *undeclared* applicable contract without failing preflight. A declared
50
+ `covered` is not executed or scored. Truth-checking is review-cycle / follow-up.
51
+
52
+ This slice does **not** load the list at session-start or in the preamble.
53
+
54
+ ## Authored examples (not framework oracles)
55
+
56
+ Operators author product entries. Directive never runs Visage or scores
57
+ "module purpose." Two shapes that belong in a consumer PROJECT-DEFINITION, not
58
+ in Directive itself:
59
+
60
+ ```json
61
+ {
62
+ "plan": {
63
+ "policy": {
64
+ "projectInvariants": [
65
+ {
66
+ "id": "visage-load-save",
67
+ "statement": "Launch-prep must not change a project folder so Visage can no longer load it.",
68
+ "paths": ["src/launch-prep/**"]
69
+ },
70
+ {
71
+ "id": "sibling-purpose",
72
+ "statement": "Existing modules stay independently useful. Integration with a new module is optional; independence is required.",
73
+ "moduleIds": ["project-io", "canvas"]
74
+ }
75
+ ]
76
+ }
77
+ }
78
+ }
79
+ ```
@@ -58,32 +58,77 @@ Authority comes from the approval record in the **merge base**, not from whether
58
58
 
59
59
  ## Operator command: `scope:record-approved-scope`
60
60
 
61
- Deposit a human-origin digest (first adoption or renewal):
61
+ Deposit a human-origin digest (first adoption or renewal). Mint on a real TTY, then commit the approval artifacts to the merge base (or a prior PR) before implement.
62
62
 
63
63
  ```bash
64
- task scope:record-approved-scope -- xbrief/pending/story.xbrief.json --actor scott
64
+ task scope:record-approved-scope -- xbrief/pending/story.xbrief.json --actor scott --confirm
65
65
  # or after expansion review:
66
- task scope:record-approved-scope -- xbrief/active/story.xbrief.json --actor scott --kind renewed-approval
66
+ task scope:record-approved-scope -- xbrief/active/story.xbrief.json --actor scott --kind renewed-approval --confirm
67
67
  ```
68
68
 
69
+ `--actor` is **display only**. It never authorizes mint. `--actor Flynn` from an agent or CI shell cannot mint.
70
+
71
+ Mint uses the shared #3110 human-presence gate (same module as `authz`):
72
+
73
+ - Interactive TTY (stdin + stdout) and a controlling terminal (`/dev/tty` or `CONIN$`)
74
+ - Explicit `--confirm`
75
+ - Typed phrase `mint` on the controlling TTY
76
+ - Agent/CI env markers (`AUTHZ_AGENT_SHELL_ENV_MARKERS`) refuse fail-closed
77
+ - An active UAT lease refuses mint with no TTY / `--confirm` / phrase escape
78
+
79
+ No authz grant is written. `verify:scope-provenance` does not read `.deft/authz/grants`.
80
+
69
81
  Flags:
70
82
 
71
83
  | Flag | Required | Notes |
72
84
  | --- | --- | --- |
73
85
  | `<xbrief-path>` | yes | pending or active xBRIEF JSON |
74
- | `--actor` | yes | human operator identity (agent actors refused) |
86
+ | `--actor` | yes | display-only human identity (never authorization) |
87
+ | `--confirm` | yes | required; flag alone never authorizes mint |
75
88
  | `--kind` | no | default `operator`; also `human`, `renewed-approval`, … |
76
89
  | `--project-root` | no | defaults via Taskfile to consumer CWD |
77
90
  | `--xbrief-rel-path` | no | override path binding; default maps `pending/` → `active/` |
91
+ | `--repo` | no | `owner/name` seed for preimage `approvedRepos` (same source as `issue:emit`) |
92
+
93
+ Commit **both** `.deft/approved-scope/<plan-id>.json` and `<plan-id>.intent.json` on the **merge base** (or a prior PR) before the implementation PR activates or expands the scoped xBRIEF. Read the preimage before you commit — that file is the approved intent.
94
+
95
+ ## Three layers (do not mix)
96
+
97
+ | Layer | What it is | Who writes it |
98
+ | --- | --- | --- |
99
+ | **Product intent** | What the story asks for — titles, narratives, acceptance, architecture, items, edges, origin refs | Human in the xBRIEF |
100
+ | **Approved derivation** | The extracted preimage + path digest frozen at mint | `scope:record-approved-scope` on a TTY |
101
+ | **Implementation choice** | How the worker codes the story | The implementation PR; must not rewrite pinned intent |
102
+
103
+ `verify:scope-provenance` compares live extraction to the **base-committed** preimage. It never treats working-tree copies, `xbriefBodyDigest`, or authz grants as authority.
104
+
105
+ ## Wave 2 intent pin (#3385)
106
+
107
+ Mint writes one record and one preimage as a fail-closed pair under a per-plan lock. Both dests land as `.next` first, then dests copy from that pair. A crash mid-publish is recovered without a remint: finish the flip from `.next`, or restore the bak pair (or neither dest). Dead-owner lock files are reclaimed. A dest-write failure restores the previous pair or leaves neither dest. If restore also fails, leftover dests are cleared and the mint error names both failures. `intentDigest` is a checksum of `.deft/approved-scope/<plan-id>.intent.json` (`intent-extract-v1`).
108
+
109
+ Extracted: `plan.title`, `plan.narratives.*`, `plan.acceptance`, `plan.architecture`, `plan.items[]` `{id,title,summary,narrative,type}`, `plan.id`, resolved parent id (`planRef` raw path is machine), origin `references[]` (no `TrustLevel`), `plan.edges`, swarm `file_scope` plus free-text swarm notes, and any unknown `plan.*` key (pinned wholesale). `plan.tags` is machine.
110
+
111
+ Verify:
112
+
113
+ 1. `git show <base>:` for record **and** preimage
114
+ 2. Recompute preimage digest vs `intentDigest`
115
+ 3. Re-extract the live brief and compare
116
+ 4. Same-PR rewrite of record or preimage fails
117
+ 5. Duplicate object keys need a real tokenizer (not `JSON.parse`)
118
+ 6. `Decisions` and `references[]` are append-only; new github-issue URLs must be in the base `approvedRepos`
119
+
120
+ First activation with nonempty `file_scope` needs that base-committed pin. Same-PR mint + activate fails.
121
+
122
+ ### Wave 1 records are legacy under Wave 2 (#3384 / #3385)
78
123
 
79
- Commit the written `.deft/approved-scope/<plan-id>.json` on the **merge base** (or a prior PR) before the implementation PR activates or expands the scoped xBRIEF.
124
+ Wave 1 mints write the path record with a human-looking stamp. They do **not** write `xbriefBodyDigest` and they carry **no** `intentDigest`. Under Wave 2 those records are **legacy**: they authorize **paths only**. Intent edits warn this release, then fail; gated remint is the remediation. That is intended, not a bug. No silent backfill.
80
125
 
81
126
  ## First-adoption flow (single consumer upgrade)
82
127
 
83
128
  When the first non-empty `file_scope` story and the 0.97+/0.98 gate land together:
84
129
 
85
130
  1. Author the pending xBRIEF with the intended `file_scope`
86
- 2. Run `task scope:record-approved-scope -- <pending-xbrief> --actor <you>`
131
+ 2. Run `task scope:record-approved-scope -- <pending-xbrief> --actor <you> --confirm`
87
132
  3. **Commit and merge** the approval record (and preferably the pending xBRIEF) first — multi-PR bootstrap
88
133
  4. In a follow-up PR, activate (`pending/` → `active/`) without rewriting the approval
89
134
  5. `task verify:scope-provenance -- --base-ref origin/master --enforce` exits 0
@@ -105,8 +150,8 @@ Emptying `file_scope` to soft-warn past the gate is **not** the supported migrat
105
150
  ## Remediation
106
151
 
107
152
  ```bash
108
- task scope:record-approved-scope -- <xbrief-path> --actor <you>
109
- git add .deft/approved-scope/<plan-id>.json
153
+ task scope:record-approved-scope -- <xbrief-path> --actor <you> --confirm
154
+ git add .deft/approved-scope/<plan-id>.json .deft/approved-scope/<plan-id>.intent.json
110
155
  # merge that commit before (or without) co-changing the active xBRIEF expansion
111
156
  ```
112
157
 
package/main.md CHANGED
@@ -200,10 +200,12 @@ Propagation: the canonical orchestrator preamble at [templates/agent-prompt-prea
200
200
  - ! Scope vBRIEFs live in lifecycle folders: `proposed/`, `pending/`, `active/`, `completed/`, `cancelled/`
201
201
  - ! Scope vBRIEF filenames MUST follow: `YYYY-MM-DD-descriptive-slug.vbrief.json` (slug rules: [`conventions/vbrief-filenames.md`](./content/conventions/vbrief-filenames.md))
202
202
  - ! Playbooks use `playbook-{name}.vbrief.json` (named, not ULID-suffixed)
203
+ - ! Completed xBRIEFs are evidence of what was built — full standing as a record of *what is*, zero authority over *what to build next* (#3383). The current contract is the active xBRIEF plus the human operator's live instruction. Both halves are required.
203
204
  - ⊗ Use ULID-suffixed filenames for plan, todo, or continue files
204
205
  - ⊗ Place vBRIEF files at workspace root
205
206
  - ⊗ Write `SPECIFICATION.md` directly — it MUST be generated from `specification.vbrief.json`
206
207
  - ⊗ Move scope vBRIEFs between lifecycle folders without updating `plan.status`
208
+ - ⊗ Treat a completed xBRIEF as the next-build contract, or let it override the active story or the live human instruction
207
209
 
208
210
  ### Schema version: v0.6 (canonical)
209
211
 
package/meta/ralph.md CHANGED
@@ -115,7 +115,7 @@ For each code generation, check:
115
115
  - [ ] **Documentation complete**
116
116
  - [ ] **No obvious security issues**
117
117
  - [ ] **Dependencies justified**
118
- - [ ] **Files <500 lines** (must be <1000)
118
+ - [ ] **Files stay small** (review trigger, not a hard cap; see file-size-thresholds policy module / #1488 / #3424)
119
119
 
120
120
  ## 🛠️ Implementation in Warp (TBD)
121
121
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@deftai/directive-content",
3
- "version": "0.104.0",
3
+ "version": "0.105.0",
4
4
  "deftConsumerDeposit": true,
5
5
  "description": "Shippable Directive framework content in the consumer .deft/core/ layout (C1 flatten), plus the engine surfaces (.githooks/, Taskfile.yml, tasks/) the deposit wires. Python-free per #2022 Phase 3. Refs #11, #1669, #1967.",
6
6
  "license": "MIT",
@@ -65,7 +65,7 @@
65
65
  "domain": "coding",
66
66
  "text": "All *.md in `docs/` directory (except README.md, AGENTS.md, WARP.md)",
67
67
  "path": "coding/coding.md",
68
- "body": "# Coding Guidelines\n\nSoftware development specific guidelines for AI agents.\n\nLegend (from RFC2119): !=MUST, ~=SHOULD, \u2249=SHOULD NOT, \u2297=MUST NOT, ?=MAY.\n\n**\u26a0\ufe0f See also** (load only when needed):\n- [../main.md](../../main.md) - General AI behavior and agent persona\n- [PROJECT.md](../../PROJECT.md) - For project-specific overrides\n- [../tools/telemetry.md](../tools/telemetry.md) - When implementing logging/tracing/metrics\n\n## Code Organization\n\n**Documentation:**\n- ! All *.md in `docs/` directory (except README.md, AGENTS.md, WARP.md)\n- ! Prior tasks/plans in `history/`\n- ! When code changes user-visible behavior, update matching user-facing docs in the same PR \u2014 see [docs.md](docs.md) (#447; lazy-load, not AGENTS always-on)\n\n**Filenames:**\n- ~ Use hyphens not underscores (unless language idiom)\n\n**Secrets:**\n- ! ALL secrets in `secrets/` dir as .env files\n- \u2297 Secrets in code\n\n## Code Search\n\n- ! use `rg`, or `ast-grep` (when available) instead of grep\n- ! Use Warp's built-in grep (which is rg) when running on warp\n- ~ Install if missing\n- ? Fall back to `grep` command only if tools cannot be installed\n\n## Version Control\n\nSee [../scm/git.md](../scm/git.md) for:\n- Commit conventions (Conventional Commits)\n- Safety rules (no force-push without permission)\n- Branch workflows\n\n## Code Design\n\n**Modularity:**\n- ! One responsibility per file/module\n- ~ Files <300 lines ideal; <500 lines recommended; <1000 lines a review trigger \u2014 split when exceeded unless genuinely single-responsibility (size is a smell, not a hard cap; #1488)\n- ! Explicit scope in task descriptions\n- ~ DRY: extract shared abstractions when logic is duplicated across 2+ call sites\n- \u2297 Copy-paste logic with minor variations \u2014 parameterise instead\n\n**Dependency Direction:**\n- \u2297 Circular imports between modules/packages\n- ~ Layered architecture: high-level modules depend on low-level ones, never the reverse\n- ! Use dependency inversion (interfaces/protocols) to break coupling across layers\n- See [hygiene.md](hygiene.md) for detection tools (madge, pydeps, Go compiler)\n\n**Contract-First:**\n- ! Define interfaces/types/protocols before implementation\n- ! Changes to public interfaces require explicit versioning or deprecation path\n- ! Document all public API contracts clearly\n\n**Immutability:**\n- ~ Prefer immutable data + pure functions\n- ~ When mutation needed, use narrow owned scopes (context managers, RAII)\n- \u2297 Global or singleton mutable state (almost always)\n\n**Error Handling:**\n- ~ Prefer Result/Option types or explicit exceptions over None/null/undefined\n- ! Document possible exceptions/error codes for all public functions\n- ! Validate all inputs at API boundaries\n- \u2297 Trust caller without validation\n- \u2297 Empty catch/except/recover blocks that swallow errors silently\n- \u2297 Returning neutral/zero values (None, {}, [], 0, false, \"\") to mask errors \u2014 propagate explicitly\n- \u2297 Log-and-continue: catching an error and proceeding as if it didn't happen, unless provably non-fatal and documented\n- See [hygiene.md](hygiene.md) for full error-hiding anti-pattern catalogue\n\n**Readability:**\n- ! Follow language idioms strictly\n- ! Meaningful names over short names\n- ! Comments explain **why**, code shows **what**\n- \u2297 Clever code over clear code\n\n**State & Data Modeling (#1695):**\n- ! A field MUST encode exactly one fact. Do NOT overload a field's value \u2014 or its presence/absence \u2014 to also signal a second orthogonal concern. Smuggling decision-, config-, lifecycle-, or control-state through a data field is *in-band signaling*; give that signal its own out-of-band field.\n- ! \"Absence is not a decision.\" Distinguish \"unset / never considered\" from \"deliberately set to the default.\" If a workflow must know a human made a choice, record the choice explicitly \u2014 never infer it from whether a value-field is present.\n- ~ Orthogonality test: if two facts can vary independently (e.g. value==default while decided \u2208 {true,false}), they MUST live in separate slots. If one fact strictly implies the other (true Optional<T>, tombstones), sharing a slot is fine.\n- \u2297 Infer decision / onboarding / configuration state from the presence of a value field. Use an explicit out-of-band marker \u2014 cf. the resolver `source` provenance pattern (typed | default | default-on-error) directive already uses for *value*-provenance.\n- See [../patterns/in-band-signaling.md](../patterns/in-band-signaling.md) for the full model, orthogonality procedure, and the wipCap worked example (#1694).\n\n## Quality Standards\n\n**General:**\n- ! Run all relevant checks (lint, fmt, quality, build, test) before submitting changes\n- \u2297 Claim checks passed without running them\n- ! If checks cannot run, explicitly state why and what would have been executed\n- ~ Prioritize code quality and readability over backwards compatibility\n\n**Testing:**\n- ! Implementation is INCOMPLETE until tests written AND `task test:coverage` passes\n- See [../coding/testing.md](../coding/testing.md) for universal requirements\n\n**Security:**\n- ! Apply baseline security standards to every project from day one\n- See [../coding/security.md](../coding/security.md) for input validation, authn/authz, secrets, dependency, TOCTOU / mutable-external-resource rules (#1938), and agent-specific threats (#661)\n\n**Review process (#1471 / #212):**\n- ! Apply tool-agnostic review-cycle principles on every PR review response\n- See [review.md](review.md) for read-all-findings, severity P0/P1/P2, single batch commit, cross-file grep, no mid-review push, exit on no P0/P1, and post-merge closing-keyword verification\n- Greptile/GitHub adapter: [../skills/deft-directive-review-cycle/SKILL.md](../skills/deft-directive-review-cycle/SKILL.md)\n\n**Codebase Hygiene:**\n- See [hygiene.md](hygiene.md) for: dead code removal, circular dependency detection, error hiding patterns, legacy/deprecated code cleanup\n\n**Telemetry:**\n- See [../tools/telemetry.md](../tools/telemetry.md) for recommendations\n- ~ Structured logging for production\n- ~ Error tracking (Sentry.io or equivalent)\n- ? Distributed tracing for complex systems\n\n## Fail Loud: Completion Claims Require Outcome Verification (#1006)\n\nThe failure mode is the agent stating completion at the level of **intent** (\"I ran the migration\", \"the tests pass\", \"the feature works\") rather than at the level of **outcome verification** (\"all 167 records migrated, 0 skipped\", \"42 tests collected, 42 passed, 0 skipped, 0 xfailed\", \"the edge case asked about was reproduced and now returns the expected value\"). Outcome-blind completion claims hide silent skips, swallowed exceptions, suppressed errors, and unverified edge cases behind successful-sounding language. The example from the source: a database migration that completed \"successfully\" had silently skipped 14% of records on a constraint violation; the skip was logged but not surfaced; the bad reports were discovered 11 days later.\n\nThis rule is the OPERATIONAL complement to the EPISTEMIC honesty rules elsewhere in the framework (`main.md` morals section: don't present speculation as fact; label unverified claims). Morals.md says \"don't lie\". Fail-loud says \"count the records, check the logs, run the edge case, **then** claim completion.\" It is also the output-side complement to [goal-gate-determinism](../patterns/goal-gate-determinism.md) (#852 \u2014 the gate specifies what evidence is required) and machine-verifiable-spec (verification commands prevent silent skips) -- without fail-loud, an agent can satisfy the letter of a gate (\"tests pass\") while hiding the gap (\"some tests were skipped\").\n\n- ! Before claiming a batch operation succeeded, MUST verify the record count and surface it in the claim (\"migrated 167/167 records, 0 skipped, 0 errored\" -- not \"migration completed\")\n- ! Before claiming \"tests pass\", MUST report the count of collected / passed / skipped / xfailed / errored tests (\"42 collected, 42 passed, 0 skipped\" -- not \"tests pass\"). A skipped or xfailed test is NOT a passing test for the purpose of this claim\n- ! Before claiming \"the feature works\", MUST report the specific edge case that was verified (if the user asked about a specific edge case, that edge case MUST be in the verification report; \"the happy path works\" is not equivalent to \"the feature works\")\n- ! Before claiming a migration / data transform / batch job completed, MUST check the error log AND the skip log AND the constraint-violation surface; surface the counts even when zero (\"0 skipped, 0 errored\" is the load-bearing claim, not silence)\n- ! When uncertainty exists about whether something worked, MUST surface the uncertainty explicitly (\"the migration completed and reported success but I have not verified the per-record count -- recommend running `<verification-command>` before declaring done\")\n- \u2297 MUST NOT claim \"tests pass\" when any test was skipped, xfailed, or run with errors suppressed -- report the full counts instead\n- \u2297 MUST NOT claim \"migration completed\" / \"batch succeeded\" / \"job finished\" without checking and reporting the per-record outcome counts\n- \u2297 MUST NOT claim \"feature works\" when only the happy path was verified -- name the edge case that was tested, or surface that it wasn't\n- \u2297 MUST NOT use successful-sounding completion phrasing to paper over uncertainty -- default to surfacing uncertainty, not hiding it\n- \u2297 MUST NOT suppress error output (`2>$null`, `2>/dev/null`, `try/except: pass` around the verification command) and then claim completion based on the resulting silence\n\n- ! Before claiming \"feature complete\", \"ready for real users\", \"production-ready\", or equivalent area-complete language for a surface that has open graduations (Now+Later dual-path locks; #2899), MUST name the open `graduationRef`s, **or** explicitly state that graduation review was skipped and why \u2014 otherwise the claim is outcome-blind under this rule\n- \u2297 MUST NOT claim \"feature complete\" / \"production-ready\" / \"ready for real users\" for an area with open graduations without naming those `graduationRef`s or an explicit skip-with-reason\n\nThe rule applies to agent completion claims during task execution. It applies equally to claims to the user, claims in commit messages, claims in PR bodies, claims in CHANGELOG entries, and claims in status messages to a parent agent. A short, honest \"the migration completed; I did not verify the per-record count\" is strictly preferred over a confident \"migration completed successfully\" that hides the gap.\n\n**Cross-references:** strategies discuss/probe Graduation dual-path locks (#2899); `## Quality Standards` above (`\u2297 Claim checks passed without running them` -- the sibling rule that this expands from process to outcome); `hygiene.md` `## Error Handling: No Hiding` (the same hiding pattern at the code-write level, not the claim level); [`patterns/goal-gate-determinism.md`](../patterns/goal-gate-determinism.md) (#852 \u2014 rigid goals/gates, flexible path); `skills/deft-directive-pre-pr/SKILL.md` (pre-PR verification claims); `skills/deft-directive-build/SKILL.md` Step 4 Quality Gates (task-completion claims); `skills/deft-directive-review-cycle/SKILL.md` (Greptile adapter; universal review principles in [review.md](review.md); the adapter explicitly checks for hidden incompleteness in fix-batch completion claims).\n\n## Calling LLM APIs (#481)\n\nWhen the project calls LLM APIs (OpenAI, Anthropic, Cohere, local models, etc.) or builds agentic functionality, the architectural standards in `patterns/llm-app.md` apply alongside the coding rules above. In the directive maintainer repo this section is **guidance for consumer projects** \u2014 provider names are illustrative labels under the framework instruction hierarchy, not runtime SDK surfaces (#2414; see `meta/security.md` `## Informational AppSec findings`). The short form:\n\n- ! User input is NEVER placed in the system prompt; the system prompt is the trust boundary\n- ! External content is ALWAYS wrapped in explicit delimiters (`<user_input>`, `<document>`, `<tool_result>`) and surfaces its trust tier\n- ! Tool call arguments are validated against a schema BEFORE execution (the LLM is a confused deputy)\n- ! LLM outputs are validated against expected schemas before being acted upon (no eval-of-output, no shell-of-output, no SQL-of-output)\n- \u2297 MUST NOT write LLM outputs back into the retrieval corpus in the same session without validation (RAG poisoning vector)\n\nSee [../patterns/llm-app.md](../patterns/llm-app.md) for the full standards: prompt construction, trust tiers, tool/function-call validation, RAG hygiene, output handling, multi-agent orchestration, and LLM-specific observability. See [../tools/telemetry.md](../tools/telemetry.md) `## LLM-specific observability (#481)` for the matching observability surface.\n\n## Debugging and Root-Cause Investigation (#1621)\n\nWhen a bug, failure, or unexpected behaviour needs diagnosis, the root-cause standards in `debugging.md` apply. The short form:\n\n- ! No fixes without root-cause investigation first (the Iron Law)\n- ! Reproduce the failure consistently before proposing a fix \u2014 a non-reproducible bug is not yet understood\n- ! Every factual claim cites evidence; an uncited claim is a `[HYPOTHESIS]`, not a finding (evidence before narrative)\n- ! Runtime/config values are proven from the runtime, never inferred from source code (config is not code)\n- \u2297 MUST NOT present a duration or an exit status (\"slow because phase X took N minutes\", \"failed because it timed out\") as a root cause \u2014 name a mechanism (no tautologies)\n- ! After 3 failed distinct fixes, STOP and escalate for architectural review (the 3-fix gate)\n\nSee [debugging.md](debugging.md) for the full four-phase process, evidence discipline, Fact vs Hypothesis labeling (#1580), the observability-gap loop, and the rationalization table. For a sustained multi-agent investigation posture, see the `deft-directive-debug` skill.\n\n## Build Automation\n\n**Taskfile:**\n- ! Use Task ([go-task](https://taskfile.dev)) for all repeatable operations\n- ! If `task` not found, attempt to install go-task\n- ! If installation fails, stop and ask user for help\n- See [../tools/taskfile.md](../tools/taskfile.md) for standards and common commands\n\n**Toolchain Validation:**\n- See [../coding/toolchain.md](../coding/toolchain.md) for rules on verifying required tools are installed before implementation begins\n\n**Build Output Validation:**\n- See [../coding/build-output.md](../coding/build-output.md) for rules on verifying `dist/` artifacts and non-compiled assets after custom build scripts run\n\n## Change Management\n\n**Impact Awareness:**\n- ! Before changing shared code, identify affected downstream modules/files\n- ~ Prefer additive changes (new functions, fields with defaults) over breaking renames\n- ! Make small, reversible changes\n- ! Explain impact and migration path for breaking changes\n\n**Production Safety:**\n- ! Assume production impact unless stated otherwise\n- ! Call out risk when touching: auth, billing, data, APIs, build systems\n- \u2297 Silent breaking behavior\n- ~ Test changes in staging/dev environment when possible\n\n## Language-Specific Guidelines\n\n**Languages:**\n- C++: [../languages/cpp.md](../languages/cpp.md)\n- Go: [../languages/go.md](../languages/go.md)\n- Office.js: [../languages/officejs.md](../languages/officejs.md)\n- Python: [../languages/python.md](../languages/python.md)\n- TypeScript: [../languages/typescript.md](../languages/typescript.md)\n- VBA: [../languages/vba.md](../languages/vba.md)\n\n**Interface Types:**\n- CLI: [../interfaces/cli.md](../interfaces/cli.md)\n- TUI: [../interfaces/tui.md](../interfaces/tui.md)\n- Web: [../interfaces/web.md](../interfaces/web.md)\n- REST API: [../interfaces/rest.md](../interfaces/rest.md)\n\n## Development Workflow\n\n**Localhost:**\n- No permission needed for curl localhost\n\n**Plans:**\n- ~ Create both:\n 1. Warp plan (using `create_plan` tool)\n 2. Archive copy in `history/plan-YYYY-MM-DD-description.md`\n\n## Project Context\n\n- ! Check [PROJECT.md](../../PROJECT.md) for project-specific overrides\n- ~ Inspect project config (package.json, pyproject.toml, etc.) for available scripts\n- ! Follow project-specific testing, coverage, and quality requirements\n\n## Anti-Patterns\n\n- \u2297 Secrets in code or version control\n- \u2297 Claiming checks passed without running them\n- \u2297 Single files mixing multiple responsibilities (large line count, e.g. >1000 lines, is a trigger to check cohesion \u2014 not a defect by itself; #1488)\n- \u2297 Skipping quality checks\n- \u2297 Breaking changes without explicit approval\n- \u2297 Using `grep` command when `rg` or Warp grep available\n- \u2297 Implementing code without tests\n- \u2297 Claiming \"done\" before running test:coverage\n- \u2297 Ignoring coverage drops\n- \u2297 Weak types (`any`, `interface{}`, untyped `object`) where concrete types are knowable\n- \u2297 Dead code: unused functions, unreachable branches, stale feature flags, commented-out blocks\n- \u2297 Error hiding: empty catch blocks, silent fallbacks, swallowed exceptions\n- \u2297 Circular imports between modules\n- \u2297 Duplicate logic across 2+ call sites without shared abstraction\n- \u2297 Outcome-blind completion claims: \"tests pass\" with skipped tests, \"migration completed\" without per-record counts, \"feature works\" without naming the verified edge case (#1006 -- see `## Fail Loud` above)\n- \u2297 Outcome-blind \"feature complete\" / \"production-ready\" claims that ignore open graduations (`graduationRef`s) without naming them or an explicit skip (#2899 / #1006 -- see `## Fail Loud` above)\n- \u2297 Averaging contradicting codebase patterns: writing new code that satisfies both of two conflicting patterns simultaneously (#1005 -- see `hygiene.md` `## Surface Conflicts`)\n- \u2297 Debugging by guess-and-check: fixing before reproducing, treating the first plausible hypothesis as confirmed, or presenting a duration/exit-status as a root cause (#1621 -- see `debugging.md`)\n"
68
+ "body": "# Coding Guidelines\n\nSoftware development specific guidelines for AI agents.\n\nLegend (from RFC2119): !=MUST, ~=SHOULD, \u2249=SHOULD NOT, \u2297=MUST NOT, ?=MAY.\n\n**\u26a0\ufe0f See also** (load only when needed):\n- [../main.md](../../main.md) - General AI behavior and agent persona\n- [PROJECT.md](../../PROJECT.md) - For project-specific overrides\n- [../tools/telemetry.md](../tools/telemetry.md) - When implementing logging/tracing/metrics\n\n## Code Organization\n\n**Documentation:**\n- ! All *.md in `docs/` directory (except README.md, AGENTS.md, WARP.md)\n- ! Prior tasks/plans in `history/`\n- ! When code changes user-visible behavior, update matching user-facing docs in the same PR \u2014 see [docs.md](docs.md) (#447; lazy-load, not AGENTS always-on)\n\n**Filenames:**\n- ~ Use hyphens not underscores (unless language idiom)\n\n**Secrets:**\n- ! ALL secrets in `secrets/` dir as .env files\n- \u2297 Secrets in code\n\n## Code Search\n\n- ! use `rg`, or `ast-grep` (when available) instead of grep\n- ! Use Warp's built-in grep (which is rg) when running on warp\n- ~ Install if missing\n- ? Fall back to `grep` command only if tools cannot be installed\n\n## Version Control\n\nSee [../scm/git.md](../scm/git.md) for:\n- Commit conventions (Conventional Commits)\n- Safety rules (no force-push without permission)\n- Branch workflows\n\n## Code Design\n\n**Modularity:**\n- ! One responsibility per file/module\n- ~ Keep files small. Ideal, recommended, and review-trigger line counts are FILE_SIZE_IDEAL_LINES, FILE_SIZE_RECOMMENDED_LINES, and FILE_SIZE_REVIEW_TRIGGER_LINES in the file-size-thresholds policy module (packages/core/src/policy/file-size-thresholds.ts). Split when a file exceeds the review trigger unless it is genuinely single-responsibility (size is a smell, not a hard cap; #1488 / #3424)\n- ! Explicit scope in task descriptions\n- ~ DRY: extract shared abstractions when logic is duplicated across 2+ call sites\n- \u2297 Copy-paste logic with minor variations \u2014 parameterise instead\n\n**Dependency Direction:**\n- \u2297 Circular imports between modules/packages\n- ~ Layered architecture: high-level modules depend on low-level ones, never the reverse\n- ! Use dependency inversion (interfaces/protocols) to break coupling across layers\n- See [hygiene.md](hygiene.md) for detection tools (madge, pydeps, Go compiler)\n\n**Contract-First:**\n- ! Define interfaces/types/protocols before implementation\n- ! Changes to public interfaces require explicit versioning or deprecation path\n- ! Document all public API contracts clearly\n\n**Immutability:**\n- ~ Prefer immutable data + pure functions\n- ~ When mutation needed, use narrow owned scopes (context managers, RAII)\n- \u2297 Global or singleton mutable state (almost always)\n\n**Error Handling:**\n- ~ Prefer Result/Option types or explicit exceptions over None/null/undefined\n- ! Document possible exceptions/error codes for all public functions\n- ! Validate all inputs at API boundaries\n- \u2297 Trust caller without validation\n- \u2297 Empty catch/except/recover blocks that swallow errors silently\n- \u2297 Returning neutral/zero values (None, {}, [], 0, false, \"\") to mask errors \u2014 propagate explicitly\n- \u2297 Log-and-continue: catching an error and proceeding as if it didn't happen, unless provably non-fatal and documented\n- See [hygiene.md](hygiene.md) for full error-hiding anti-pattern catalogue\n\n**Readability:**\n- ! Follow language idioms strictly\n- ! Meaningful names over short names\n- ! Comments explain **why**, code shows **what**\n- \u2297 Clever code over clear code\n\n**State & Data Modeling (#1695):**\n- ! A field MUST encode exactly one fact. Do NOT overload a field's value \u2014 or its presence/absence \u2014 to also signal a second orthogonal concern. Smuggling decision-, config-, lifecycle-, or control-state through a data field is *in-band signaling*; give that signal its own out-of-band field.\n- ! \"Absence is not a decision.\" Distinguish \"unset / never considered\" from \"deliberately set to the default.\" If a workflow must know a human made a choice, record the choice explicitly \u2014 never infer it from whether a value-field is present.\n- ~ Orthogonality test: if two facts can vary independently (e.g. value==default while decided \u2208 {true,false}), they MUST live in separate slots. If one fact strictly implies the other (true Optional<T>, tombstones), sharing a slot is fine.\n- \u2297 Infer decision / onboarding / configuration state from the presence of a value field. Use an explicit out-of-band marker \u2014 cf. the resolver `source` provenance pattern (typed | default | default-on-error) directive already uses for *value*-provenance.\n- See [../patterns/in-band-signaling.md](../patterns/in-band-signaling.md) for the full model, orthogonality procedure, and the wipCap worked example (#1694).\n\n## Quality Standards\n\n**General:**\n- ! Run all relevant checks (lint, fmt, quality, build, test) before submitting changes\n- \u2297 Claim checks passed without running them\n- ! If checks cannot run, explicitly state why and what would have been executed\n- ~ Prioritize code quality and readability over backwards compatibility\n\n**Testing:**\n- ! Implementation is INCOMPLETE until tests written AND `task test:coverage` passes\n- See [../coding/testing.md](../coding/testing.md) for universal requirements\n\n**Security:**\n- ! Apply baseline security standards to every project from day one\n- See [../coding/security.md](../coding/security.md) for input validation, authn/authz, secrets, dependency, TOCTOU / mutable-external-resource rules (#1938), and agent-specific threats (#661)\n\n**Review process (#1471 / #212):**\n- ! Apply tool-agnostic review-cycle principles on every PR review response\n- See [review.md](review.md) for read-all-findings, severity P0/P1/P2, single batch commit, cross-file grep, no mid-review push, exit on no P0/P1, and post-merge closing-keyword verification\n- Greptile/GitHub adapter: [../skills/deft-directive-review-cycle/SKILL.md](../skills/deft-directive-review-cycle/SKILL.md)\n\n**Codebase Hygiene:**\n- See [hygiene.md](hygiene.md) for: dead code removal, circular dependency detection, error hiding patterns, legacy/deprecated code cleanup\n\n**Telemetry:**\n- See [../tools/telemetry.md](../tools/telemetry.md) for recommendations\n- ~ Structured logging for production\n- ~ Error tracking (Sentry.io or equivalent)\n- ? Distributed tracing for complex systems\n\n## Fail Loud: Completion Claims Require Outcome Verification (#1006)\n\nThe failure mode is the agent stating completion at the level of **intent** (\"I ran the migration\", \"the tests pass\", \"the feature works\") rather than at the level of **outcome verification** (\"all 167 records migrated, 0 skipped\", \"42 tests collected, 42 passed, 0 skipped, 0 xfailed\", \"the edge case asked about was reproduced and now returns the expected value\"). Outcome-blind completion claims hide silent skips, swallowed exceptions, suppressed errors, and unverified edge cases behind successful-sounding language. The example from the source: a database migration that completed \"successfully\" had silently skipped 14% of records on a constraint violation; the skip was logged but not surfaced; the bad reports were discovered 11 days later.\n\nThis rule is the OPERATIONAL complement to the EPISTEMIC honesty rules elsewhere in the framework (`main.md` morals section: don't present speculation as fact; label unverified claims). Morals.md says \"don't lie\". Fail-loud says \"count the records, check the logs, run the edge case, **then** claim completion.\" It is also the output-side complement to [goal-gate-determinism](../patterns/goal-gate-determinism.md) (#852 \u2014 the gate specifies what evidence is required) and machine-verifiable-spec (verification commands prevent silent skips) -- without fail-loud, an agent can satisfy the letter of a gate (\"tests pass\") while hiding the gap (\"some tests were skipped\").\n\n- ! Before claiming a batch operation succeeded, MUST verify the record count and surface it in the claim (\"migrated 167/167 records, 0 skipped, 0 errored\" -- not \"migration completed\")\n- ! Before claiming \"tests pass\", MUST report the count of collected / passed / skipped / xfailed / errored tests (\"42 collected, 42 passed, 0 skipped\" -- not \"tests pass\"). A skipped or xfailed test is NOT a passing test for the purpose of this claim\n- ! Before claiming \"the feature works\", MUST report the specific edge case that was verified (if the user asked about a specific edge case, that edge case MUST be in the verification report; \"the happy path works\" is not equivalent to \"the feature works\")\n- ! Before claiming a migration / data transform / batch job completed, MUST check the error log AND the skip log AND the constraint-violation surface; surface the counts even when zero (\"0 skipped, 0 errored\" is the load-bearing claim, not silence)\n- ! When uncertainty exists about whether something worked, MUST surface the uncertainty explicitly (\"the migration completed and reported success but I have not verified the per-record count -- recommend running `<verification-command>` before declaring done\")\n- \u2297 MUST NOT claim \"tests pass\" when any test was skipped, xfailed, or run with errors suppressed -- report the full counts instead\n- \u2297 MUST NOT claim \"migration completed\" / \"batch succeeded\" / \"job finished\" without checking and reporting the per-record outcome counts\n- \u2297 MUST NOT claim \"feature works\" when only the happy path was verified -- name the edge case that was tested, or surface that it wasn't\n- \u2297 MUST NOT use successful-sounding completion phrasing to paper over uncertainty -- default to surfacing uncertainty, not hiding it\n- \u2297 MUST NOT suppress error output (`2>$null`, `2>/dev/null`, `try/except: pass` around the verification command) and then claim completion based on the resulting silence\n\n- ! Before claiming \"feature complete\", \"ready for real users\", \"production-ready\", or equivalent area-complete language for a surface that has open graduations (Now+Later dual-path locks; #2899), MUST name the open `graduationRef`s, **or** explicitly state that graduation review was skipped and why \u2014 otherwise the claim is outcome-blind under this rule\n- \u2297 MUST NOT claim \"feature complete\" / \"production-ready\" / \"ready for real users\" for an area with open graduations without naming those `graduationRef`s or an explicit skip-with-reason\n\nThe rule applies to agent completion claims during task execution. It applies equally to claims to the user, claims in commit messages, claims in PR bodies, claims in CHANGELOG entries, and claims in status messages to a parent agent. A short, honest \"the migration completed; I did not verify the per-record count\" is strictly preferred over a confident \"migration completed successfully\" that hides the gap.\n\n**Cross-references:** strategies discuss/probe Graduation dual-path locks (#2899); `## Quality Standards` above (`\u2297 Claim checks passed without running them` -- the sibling rule that this expands from process to outcome); `hygiene.md` `## Error Handling: No Hiding` (the same hiding pattern at the code-write level, not the claim level); [`patterns/goal-gate-determinism.md`](../patterns/goal-gate-determinism.md) (#852 \u2014 rigid goals/gates, flexible path); `skills/deft-directive-pre-pr/SKILL.md` (pre-PR verification claims); `skills/deft-directive-build/SKILL.md` Step 4 Quality Gates (task-completion claims); `skills/deft-directive-review-cycle/SKILL.md` (Greptile adapter; universal review principles in [review.md](review.md); the adapter explicitly checks for hidden incompleteness in fix-batch completion claims).\n\n## Calling LLM APIs (#481)\n\nWhen the project calls LLM APIs (OpenAI, Anthropic, Cohere, local models, etc.) or builds agentic functionality, the architectural standards in `patterns/llm-app.md` apply alongside the coding rules above. In the directive maintainer repo this section is **guidance for consumer projects** \u2014 provider names are illustrative labels under the framework instruction hierarchy, not runtime SDK surfaces (#2414; see `meta/security.md` `## Informational AppSec findings`). The short form:\n\n- ! User input is NEVER placed in the system prompt; the system prompt is the trust boundary\n- ! External content is ALWAYS wrapped in explicit delimiters (`<user_input>`, `<document>`, `<tool_result>`) and surfaces its trust tier\n- ! Tool call arguments are validated against a schema BEFORE execution (the LLM is a confused deputy)\n- ! LLM outputs are validated against expected schemas before being acted upon (no eval-of-output, no shell-of-output, no SQL-of-output)\n- \u2297 MUST NOT write LLM outputs back into the retrieval corpus in the same session without validation (RAG poisoning vector)\n\nSee [../patterns/llm-app.md](../patterns/llm-app.md) for the full standards: prompt construction, trust tiers, tool/function-call validation, RAG hygiene, output handling, multi-agent orchestration, and LLM-specific observability. See [../tools/telemetry.md](../tools/telemetry.md) `## LLM-specific observability (#481)` for the matching observability surface.\n\n## Debugging and Root-Cause Investigation (#1621)\n\nWhen a bug, failure, or unexpected behaviour needs diagnosis, the root-cause standards in `debugging.md` apply. The short form:\n\n- ! No fixes without root-cause investigation first (the Iron Law)\n- ! Reproduce the failure consistently before proposing a fix \u2014 a non-reproducible bug is not yet understood\n- ! Every factual claim cites evidence; an uncited claim is a `[HYPOTHESIS]`, not a finding (evidence before narrative)\n- ! Runtime/config values are proven from the runtime, never inferred from source code (config is not code)\n- \u2297 MUST NOT present a duration or an exit status (\"slow because phase X took N minutes\", \"failed because it timed out\") as a root cause \u2014 name a mechanism (no tautologies)\n- ! After 3 failed distinct fixes, STOP and escalate for architectural review (the 3-fix gate)\n\nSee [debugging.md](debugging.md) for the full four-phase process, evidence discipline, Fact vs Hypothesis labeling (#1580), the observability-gap loop, and the rationalization table. For a sustained multi-agent investigation posture, see the `deft-directive-debug` skill.\n\n## Build Automation\n\n**Taskfile:**\n- ! Use Task ([go-task](https://taskfile.dev)) for all repeatable operations\n- ! If `task` not found, attempt to install go-task\n- ! If installation fails, stop and ask user for help\n- See [../tools/taskfile.md](../tools/taskfile.md) for standards and common commands\n\n**Toolchain Validation:**\n- See [../coding/toolchain.md](../coding/toolchain.md) for rules on verifying required tools are installed before implementation begins\n\n**Build Output Validation:**\n- See [../coding/build-output.md](../coding/build-output.md) for rules on verifying `dist/` artifacts and non-compiled assets after custom build scripts run\n\n## Change Management\n\n**Impact Awareness:**\n- ! Before changing shared code, identify affected downstream modules/files\n- ~ Prefer additive changes (new functions, fields with defaults) over breaking renames\n- ! Make small, reversible changes\n- ! Explain impact and migration path for breaking changes\n\n**Production Safety:**\n- ! Assume production impact unless stated otherwise\n- ! Call out risk when touching: auth, billing, data, APIs, build systems\n- \u2297 Silent breaking behavior\n- ~ Test changes in staging/dev environment when possible\n\n## Language-Specific Guidelines\n\n**Languages:**\n- C++: [../languages/cpp.md](../languages/cpp.md)\n- Go: [../languages/go.md](../languages/go.md)\n- Office.js: [../languages/officejs.md](../languages/officejs.md)\n- Python: [../languages/python.md](../languages/python.md)\n- TypeScript: [../languages/typescript.md](../languages/typescript.md)\n- VBA: [../languages/vba.md](../languages/vba.md)\n\n**Interface Types:**\n- CLI: [../interfaces/cli.md](../interfaces/cli.md)\n- TUI: [../interfaces/tui.md](../interfaces/tui.md)\n- Web: [../interfaces/web.md](../interfaces/web.md)\n- REST API: [../interfaces/rest.md](../interfaces/rest.md)\n\n## Development Workflow\n\n**Localhost:**\n- No permission needed for curl localhost\n\n**Plans:**\n- ~ Create both:\n 1. Warp plan (using `create_plan` tool)\n 2. Archive copy in `history/plan-YYYY-MM-DD-description.md`\n\n## Project Context\n\n- ! Check [PROJECT.md](../../PROJECT.md) for project-specific overrides\n- ~ Inspect project config (package.json, pyproject.toml, etc.) for available scripts\n- ! Follow project-specific testing, coverage, and quality requirements\n\n## Anti-Patterns\n\n- \u2297 Secrets in code or version control\n- \u2297 Claiming checks passed without running them\n- \u2297 Single files mixing multiple responsibilities (line count at or above FILE_SIZE_REVIEW_TRIGGER_LINES is a cohesion review trigger \u2014 not a defect by itself; #1488 / #3424)\n- \u2297 Skipping quality checks\n- \u2297 Breaking changes without explicit approval\n- \u2297 Using `grep` command when `rg` or Warp grep available\n- \u2297 Implementing code without tests\n- \u2297 Claiming \"done\" before running test:coverage\n- \u2297 Ignoring coverage drops\n- \u2297 Weak types (`any`, `interface{}`, untyped `object`) where concrete types are knowable\n- \u2297 Dead code: unused functions, unreachable branches, stale feature flags, commented-out blocks\n- \u2297 Error hiding: empty catch blocks, silent fallbacks, swallowed exceptions\n- \u2297 Circular imports between modules\n- \u2297 Duplicate logic across 2+ call sites without shared abstraction\n- \u2297 Outcome-blind completion claims: \"tests pass\" with skipped tests, \"migration completed\" without per-record counts, \"feature works\" without naming the verified edge case (#1006 -- see `## Fail Loud` above)\n- \u2297 Outcome-blind \"feature complete\" / \"production-ready\" claims that ignore open graduations (`graduationRef`s) without naming them or an explicit skip (#2899 / #1006 -- see `## Fail Loud` above)\n- \u2297 Averaging contradicting codebase patterns: writing new code that satisfies both of two conflicting patterns simultaneously (#1005 -- see `hygiene.md` `## Surface Conflicts`)\n- \u2297 Debugging by guess-and-check: fixing before reproducing, treating the first plausible hypothesis as confirmed, or presenting a duration/exit-status as a root cause (#1621 -- see `debugging.md`)\n"
69
69
  },
70
70
  {
71
71
  "id": "coding-002",
@@ -151,7 +151,7 @@
151
151
  "id": "coding-012",
152
152
  "tier": "SHOULD",
153
153
  "domain": "coding",
154
- "text": "Files <300 lines ideal; <500 lines recommended; <1000 lines a review trigger \u2014 split when exceeded unless genuinely single-responsibility (size is a smell, not a hard cap; #1488)",
154
+ "text": "Keep files small. Ideal, recommended, and review-trigger line counts are FILE_SIZE_IDEAL_LINES, FILE_SIZE_RECOMMENDED_LINES, and FILE_SIZE_REVIEW_TRIGGER_LINES in the file-size-thresholds policy module (packages/core/src/policy/file-size-thresholds.ts). Split when a file exceeds the review trigger unless it is genuinely single-responsibility (size is a smell, not a hard cap; #1488 / #3424)",
155
155
  "path": "coding/coding.md",
156
156
  "body": null
157
157
  },
@@ -775,7 +775,7 @@
775
775
  "id": "coding-090",
776
776
  "tier": "MUST_NOT",
777
777
  "domain": "coding",
778
- "text": "Single files mixing multiple responsibilities (large line count, e.g. >1000 lines, is a trigger to check cohesion \u2014 not a defect by itself; #1488)",
778
+ "text": "Single files mixing multiple responsibilities (line count at or above FILE_SIZE_REVIEW_TRIGGER_LINES is a cohesion review trigger \u2014 not a defect by itself; #1488 / #3424)",
779
779
  "path": "coding/coding.md",
780
780
  "body": null
781
781
  },