@@ -26,6 +26,34 @@ reason to ask what model the batch will run on.
2626If a dispatch genuinely needs a different model, pass `model` on the Agent call:
2727that override takes precedence over this line, so pinning here costs nothing and
2828removes the silent-inheritance failure mode. Removing this line puts it back.
29+
30+ THE PIN IS A FLOOR FOR THE UNSPECIFIED CASE, NOT A CEILING ON THE DISPATCHER —
31+ read this before concluding that a tiering policy cannot take effect. Claude Code
32+ resolves a subagent's model in FOUR steps, in this order (verified 2026-08-09
33+ against the subagent documentation, "Claude Code resolves the subagent's model in
34+ this order"):
35+
36+ 1. the `CLAUDE_CODE_SUBAGENT_MODEL` environment variable, when set
37+ 2. the per-invocation `model` parameter on the Agent call
38+ 3. this definition's `model:` frontmatter
39+ 4. the main conversation's model
40+
41+ So a dispatch passing `model: "sonnet"` DOES run on sonnet: step 2 outranks step
42+ 3. This line decides only what happens when the dispatcher says nothing — which is
43+ the incident above, and the only case it was ever meant to decide. The PM's
44+ S-class tiering policy (`.claude/skills/pm-dispatch/SKILL.md` §5, "Model tiering")
45+ therefore takes effect as written; it is not defeated by this pin.
46+
47+ Two adjacent traps worth knowing, both from the same table:
48+
49+ • `CLAUDE_CODE_SUBAGENT_MODEL` outranks BOTH the argument and this line. It is
50+ not set in the dispatch container today (checked 2026-08-09) — but if it ever
51+ is, it silently overrides every per-dispatch tier choice the PM makes, and
52+ nothing in this repo would show it. Check the environment before concluding a
53+ dispatched tier is what actually ran.
54+ • A value your organization's `availableModels` allowlist blocks does not fall
55+ back to THIS line — it falls back to the INHERITED model, i.e. straight back
56+ into the silent-inheritance failure this pin exists to stop.
2957-->
3058
3159
@@ -170,15 +198,89 @@ build/test runs OOM it.** Binding rules:
170198 of the pinned fakes the gate lists on a green run instead
171199 (` service-automation/src/builtin/crud-bulk-intent.test.ts ` is the fullest).
172200
201+ ** Local verification scope — targeted gates locally, the full farm is CI's job.**
202+ Do ** not** enumerate every ` check:* ` step out of ` .github/workflows/lint.yml ` and
203+ run all 55+ locally. That rule (#5738 era) was written before "wait for CI
204+ convergence" existed, and stacking the two makes every dispatch pay for the same
205+ farm twice: once on a shared container, once on the runners that were always going
206+ to run it anyway. Your local pass is:
207+
208+ 1 . ** Build closure first** — see toolchain trap 2; this is the first command in a
209+ fresh worktree, before typecheck or test.
210+ 2 . ** The affected packages' own suites** — ` pnpm test ` / ` pnpm typecheck ` , scoped
211+ by ` --filter ` per resource rule 3.
212+ 3 . ** The gate families that touch your card's surface, and those only** — the
213+ dispatch prompt names them; add any you can see are implicated (a new fake
214+ engine ⇒ ` check:engine-double-contract ` ; a new error code ⇒
215+ ` check:error-code-casing ` ; ` .claude/agents/** ` ⇒ ` check:agent-model-declared ` ;
216+ any edit at all ⇒ ` check:nul-bytes ` ). Naming one is cheap; running all of them
217+ is what was expensive.
218+
219+ ⚠️ ** The accepted cost is a lap, and the safety half is NOT optional.** Scoping the
220+ local farm means a non-obvious gate can go red in CI that you would previously have
221+ caught on your own machine — an occasional extra push-fix lap, deliberately traded
222+ for not paying the full farm on every dispatch. That trade is only sound because
223+ you still ** wait for CI to converge before reporting** (see the CI-convergence item
224+ in Definition of done, which this rule makes load-bearing rather than redundant).
225+ ⛔ This is not licence to report before CI converges — it is the opposite: the
226+ local farm was the thing that could be dropped precisely because the CI wait
227+ cannot be. A red gate in CI is still yours to fix in this task.
228+
229+ ** Standard clauses live HERE, not in your dispatch prompt.** The prompt used to
230+ repeat ~ 1.5k tokens of these verbatim on every dispatch; it now carries only the
231+ * deltas* for your card (ruling quotes, the 裁决 / PM-机制假设 partition,
232+ card-specific clauses, same-day churn). So the clauses below are binding on you
233+ whether or not your prompt mentions them — a prompt's silence about any of them is
234+ the expected shape, never permission:
235+
236+ - ** Build before you judge anything (#6371 ).** In a fresh worktree the first
237+ verification command is ` pnpm --filter '@objectstack/<your-pkg>^...' build `
238+ (suffix ` ^... ` = the packages it depends on). Skip it and tsc reads whatever
239+ stale ` dist/*.d.ts ` someone left behind — and it lies in ** both** directions:
240+ false red burns laps chasing a non-existent problem, false green lets a narrowed
241+ export type read as "consumers are clean" when the consumer never saw the new
242+ ` .d.ts ` at all.
243+ - ** The consumer sweep's filter direction is a PREFIX (#6218 ).**
244+ ` pnpm --filter '...@objectstack/<pkg>' ` is the ** downstream consumers** ;
245+ ` '@objectstack/<pkg>...' ` (suffix) is the upstream dependencies — the opposite
246+ direction. Signature narrowing, exported-type changes and contract tightening
247+ always land downstream. When your report says "N packages green", it ** must also
248+ say which direction you used** , or the sentence cannot be reviewed: #6210 's "25
249+ packages green" was a suffix sweep, and CI went red on ` @objectstack/dogfood `
250+ immediately.
251+ - ** A cross-package type change needs a reverse verification, not just a green.**
252+ Paste a key the new type rejects, confirm it goes red, restore it — that is what
253+ proves you actually read the rebuilt ` .d.ts ` rather than a cached one.
254+ - ** ` packages/spec ` : the anchor rewrite is a product, and MERGE state is a trap.**
255+ A spec build (` gen:schema ` ) ** rewrites** ` authorable-surface.base.json ` — that is
256+ the expected artifact; ⛔ never revert it, never hand-edit it to make some
257+ equality hold (hand-editing it is exactly the attack #4650 closed). The assertion
258+ that counts is ` pnpm --filter @objectstack/spec check:authorable-surface ` being
259+ green; ` baseRev ` is ** allowed to lag** and a lag prints one informational line,
260+ not an error. ⛔ ** Never run ` gen:schema ` while the tree is in MERGE state**
261+ (#5370 ): HEAD is still the pre-merge branch tip, so the anchor is silently rolled
262+ back to the old fork point — and the rolled-back anchor is still * authentic* , so
263+ every gate passes while a landed advance is quietly undone. Commit the merge
264+ first, then regenerate. Sister trap: ` gen:schema ` 's ` rmSync ` also wipes
265+ ` gen:openapi ` 's output, which shows up as ~ 5 bogus ` expected 503 to be 200 `
266+ failures in ` @objectstack/rest ` ; restore with
267+ ` pnpm --filter @objectstack/spec gen:openapi ` .
268+
173269Definition of done, in order:
174270
175271- Implementation matches the issue's acceptance criteria.
176272- Tests: new/updated tests covering the change; run the affected packages'
177- ` pnpm test ` and ` pnpm typecheck ` and capture real output for the report.
273+ ` pnpm test ` and ` pnpm typecheck ` and capture real output for the report —
274+ scoped per "Local verification scope" above, not as a whole-repo sweep.
178275- Changeset added when the change is user-visible.
179276- Pushed with ` git push -u origin claude/issue-<n>-<slug> ` (retry on network
180277 failure with backoff).
181- - ** Draft** PR to ` main ` , body starting ` Fixes #<n> ` , ** title and explanatory
278+ - ** Draft** PR to ` main ` , body starting ` Fixes #<n> ` — ** but ` Part of #<n> ` when
279+ merging it would not close the card.** If you implemented only half of it (the
280+ other half is ` needs_decision ` awaiting a ruling, or was deliberately excluded by
281+ scope), the first line reads ` Part of #<n> ` and the body says which half you
282+ left; ⛔ never use ` Fixes ` to close a card that is still in the decision box.
283+ Also ** title and explanatory
182284 prose in English** — GitHub artifacts (issue and PR titles, bodies, comments)
183285 are English per the maintainer ruling of 2026-08-08 quoted in AGENTS.md
184286 §Communication; Chinese is for talking to the maintainer in Claude Code, not
0 commit comments