Repository navigation
Commit 500c1b5
fix(devx): assert the seed escape depth a tree-scoped walk is rooted at (#18340)
Fixes #15565
Clause-②: no
Reason: no spec surface is narrowed or widened here. The diff is one
gate script under `scripts/`; `packages/spec` is read by the gate, never
edited.
## What this adds
A sixth limb to `check:cross-package-test-inputs`, judged on the SEED a
directory descent is rooted at rather than on the names the descent
produces.
The five existing limbs are package-scoped or name-scoped, and a
`readdirSync` descending on a loop variable is neither: it names no
literal (limb 3 blind), adds no glob (limbs 4 and 5 blind), and inside a
package that already carries a table entry the two package-scoped limbs
are already satisfied. So the tree-scoped absence pin the ADR-0049
retirement playbook mandates could land in `packages/spec` with its
whole radius unhashed while this gate exited 0 naming nothing.
The input was already there: the escape verdict is computed from the
seed's DEPTH, and an argument this scan cannot read costs the NAME and
keeps the DEPTH.
## The narrowed mandate, in the source
Triage ruled 「**先收窄 mandate,再断言收窄后的半径**」 and the maintainer's batch
ruling returned the card to the queue on the grounds that it restores an
invariant with no product-semantics fork. The narrowed mandate is
written into the gate's own header docblock (not only here), and it is
what the limb asserts:
> A tree-scoped pin descends from NAMED ROOTS, and every root it
descends from is a directory some declared glob REACHES — as is every
directory below that root. It does not descend from the repo root
itself.
Stated at the grain the limb judges at: declaring one FILE under
`docs/audits/` reaches INTO `docs/` and no further, so a walk rooted at
`docs/` is judged by its children. The header records both bounds it
accepts (directory REACH rather than file coverage; dot-directories
skipped as the pins skip them).
## Measurements — every one paired, none recalled
Baseline re-taken on `objectstack-ai/objectstack` at `a09725dde`
(today's `main`), because the card's readings were `8e18931dd`. Each
limb was fired by one anchored mutation, the gate's exit code captured
to disk before anything read it, and each file restored by blob equality
against HEAD plus an empty `git diff HEAD`.
| limb | firing mutation | exit |
|---|---|---|
| 1 escaping package, no entry | delete the
`@objectstack/metadata-protocol` entry | 1, names the package |
| 2 stale entry | add an entry for a non-escaping package | 1, names it
stale |
| 3 named path no glob covers | add a quoted
`scripts/js-comment-mask.mjs` to a test | 1, names path and test |
| 4 glob nothing holds | add a glob to the entry AND to `turbo.json` |
1, names the glob |
| 5 `turbo.json` missing input | delete one `$TURBO_ROOT$` input | 1,
names the input |
| **6 the blind spot** | add one undeclared root to the live pin's walk
| **0, names nothing** |
That last row is the card's claim, re-taken rather than recalled. The
same mutation on this branch:
- **RED** — one root (`docs`) added to the live #15513 pin's folded
array and nothing else: exit 1, naming the seven `docs/` subtrees no
glob reaches, and NOT `docs/audits`.
- **GREEN** — the same edit plus `docs/**` on the entry and in
`turbo.json`: exit 0, and the printed walked-root count moves 13 to 14.
The green is a root that was JUDGED, not one that stopped resolving.
- **REVERSE CONTROL** — an anonymous descent added to a test in another
package and rooted INSIDE it: exit 0, count still 13. Moving only the
ROOT of that same descent out of the package reds. One file, one
descent, one variable — which is what separates this from a limb that
reds on directory walks in general.
- **ledger staleness** — an accepted radius nothing owes reds in the
same pass, so the ledger can only shrink.
Ablation discipline: no `sed -i` / `perl -i`. Every mutation went
through an anchored replacement that exits non-zero when the anchor is
absent or not unique, printing the occurrence-count delta and the
byte-length delta; every restore is proved by `git hash-object` equality
with the HEAD blob and an empty `git diff HEAD`, never by an exit code;
every driver carries `trap … EXIT INT TERM`.
## What the limb accepts today, and why it is not the allowance the
ruling refused
`ACCEPTED_WALK_RADII` records THREE pre-existing census and corpus
sweeps in other packages — none of them a retirement pin, each already
carrying its own written bound in its test's header. The MANDATED shape
is enforced from the first run: the live pin's five roots are all
reached by `@objectstack/spec`'s globs, and a new pin whose root they do
not reach reds. Option C — a dated allowance for the mandated shape — is
what triage refused, and is not what this is. Buying the three radius
widenings instead would be three cost decisions nobody has ruled on, in
three packages outside this card.
## A defect this branch found in its own first draft
The ledger originally spelled three test paths and one nested root
whole, and named the bare recursive packages glob in backticks inside a
reason string. `scripts/pm/dispatch-gates.mjs` reads every quoted span
in a gate's MODULE BODY as a path that gate watches — a backticked span
INSIDE a quoted sentence included — so those four literals put five
watch hints on this gate that it does not read, and two of them turned
pins red in `check:pm-dispatch-gates`. Rows are now segments joined at
runtime and reasons name globs in words. Measured both sides: this
gate's hint population is 140 with 0 declared here, on `main` and on
this branch alike.
## Gates
`node scripts/pm/dispatch-gates.mjs --commands --repo
objectstack-ai/objectstack` derived 33 runnable commands for this path.
All 33 run green. The `--ran` reconciliation and the NOT-MEASURED
families CI owns are listed in the dispatch report.
No changeset: nothing published moves. Measured rather than assumed — 70
manifests carry a `files[]`, none names anything under the repo-root
`scripts/` directory, and the positive control is that all 70 name
`dist`.
## Acceptance notes
- `repoRelativeLiterals()`'s top-level alternation is
`packages|apps|examples|content|scripts|skills` — it has no `docs`,
while `docs/...` IS a declarable glob (`@objectstack/spec` declares one
audit file there). So a test that quotes a whole `docs/...` path is
invisible to the flat collector, the same shape as the missing `skills/`
the gate's own header records. Measured with a lit control: the `docs/`
literal collects nothing, the `scripts/` literal collects. Filed
separately rather than widened here — it is a different limb's data set.
- `symlinkSync` is absent from `NON_DESCENT_CALLEES` while its siblings
`cpSync` / `renameSync` / `rmSync` are present, so a symlinked directory
reads as a walk root. On this tree that is `scripts` for
`@objectstack/spec`, already declared and arguably a real input (the
test runs a build through that symlink). Noted, not filed: no PR and no
author is heading for this file.
Authored by the `domain:devx` executor seat in session
`session_017ef78bLdybu3AffehKkhfk`
(https://claude.ai/code/session_017ef78bLdybu3AffehKkhfk) — recorded in
prose because this body was edited after creation, and the edit channel
appends its own footer block.
---
_Generated by [Claude Code](https://claude.ai/code)_
---------
Co-authored-by: Claude <noreply@anthropic.com>1 parent 3dbb49c commit 500c1b5
1 file changed
Lines changed: 659 additions & 4 deletions
0 commit comments