Skip to content

fix(deps): take the fixes for sharp and shell-quote that turn main's OSV scan red - #22016

Merged
objectstack-fleet[bot] merged 2 commits into
mainfrom
claude/issue-22013-osv-sharp-shell-quote
Oct 6, 2026
Merged

objectstack-fleet[bot] merged 2 commits into
mainfrom
claude/issue-22013-osv-sharp-shell-quote

Conversation

@objectstack-fleet

Copy link
Copy Markdown
Contributor

Fixes #22013

Clause-②: no

What this does

Validate Package Dependencies runs OSV-Scanner against pnpm-lock.yaml. Two advisories published on 2026-10-06 match main's lockfile, so every PR that touches a package.json inherits a red that is not its own (PR #22002, run 37483796939, is the first measured), and the next scheduled scan will be red too. Both advisories name a fixed version, so this PR takes both fixes. There is no exemption: osv-scanner.toml is untouched, because it is for advisories with no fixed release.

PR #22002 is not touched here. Its update-branch after this lands is the PM's pointer to its holder.

OSV reading: before and after

Measured locally with OSV-Scanner v2.3.8, the version validate-deps.yml pins, in offline mode (--offline-vulnerabilities --download-offline-databases). The OSV npm database was downloaded on 2026-10-06 at 16:36 UTC, after both advisories were published (13:40 and 13:43 UTC).

main at 803764a3 (exit 1). These are the two rows the card names:

| https://osv.dev/GHSA-wq5f-xc86-pv6w | 8.9  | npm       | sharp       | 0.35.4  | 0.35.5        | pnpm-lock.yaml |
| https://osv.dev/GHSA-pqg4-j6r4-53mv | 9.2  | npm       | shell-quote | 1.10.0  | 1.11.0        | pnpm-lock.yaml |

This PR at d263b701 (exit 0): No issues found. One vulnerability is filtered, the standing sprintf-js exemption, unchanged. The scanner names nothing beyond these two advisories, so no third one has appeared since the card was filed.

Changes

sharp: the override target lifts from ^0.35.4 to ^0.35.5

shell-quote: a new override, 'shell-quote@>=1.8.4 <2.0.0': '^1.11.0'

  • Advisory: GHSA-pqg4-j6r4-53mv (9.2 critical). In quote(), a line terminator in a string after a { comment } token ends the comment, and the rest of that string runs as shell input. The range is introduced 1.8.4, fixed 1.11.0.
  • The one path: launch-editor@2.14.1, then @changesets/cli@3.0.3, then the root package.json's devDependencies. launch-editor declares shell-quote: ^1.8.4, which admits the fix, so this is a dedupe onto the patched line. The copy sat on 1.10.0 through lockfile inertia.
  • Selector shape: the floor is the advisory's 1.8.4, and the bound sits at the 2.0.0 major boundary, per the block header's rule. The bound is never <1.11.0.
  • Resolution: ^1.11.0 floats to 1.12.0, the newest 1.x. launch-editor calls shell-quote in one place, parse() on the editor command (guess.js). 1.11.0 and 1.12.0 only teach parse() ANSI-C quoting and more operators. Seven editor command strings (code --wait, a quoted macOS path with -w, emacsclient -t -a '' and others) parse identically under 1.10.0 and 1.12.0. The vulnerable quote() is never called on this path. The fix is taken anyway, because the gate reads the lockfile, not the call graph.
  • Note: the entry carries a note in the block's style, at the foot of overrides:.

Why an override and not a @changesets/cli bump

No release on that path forces the fix (npm view, 2026-10-06):

  • @changesets/cli 3.0.3 is npm latest, which is the version the root already declares. Every 3.0.x declares launch-editor: ^2.14.1.
  • launch-editor's latest, 2.14.2 (published today), declares shell-quote: ^1.10.0, which still admits the flagged 1.10.0.

So the bump route does not exist, and a launch-editor bump would still leave the floor to lockfile inertia. On the four axes:

  • Real need: the measured need is a patched resolution and a green gate. Only the override delivers both, because no upstream release declares a range above 1.10.0.
  • Long-term soundness: the entry follows the block header's selector rule (bound at the major boundary), so a later advisory is a target-only lift. It turns into a dedupe floor once launch-editor declares ^1.11.0. Its cost is one more ledgered entry.
  • Making AI mistakes harder: a declared floor is audited by check:override-consistency, and no re-lock can land below it. A bare re-lock with no floor, like fix(deps): take the fixes for proxy-addr, source-map-js and katex that turn main's OSV scan red #21951's proxy-addr step, leaves nothing to stop a later resolution from drifting back.
  • Startup scope: this is the smallest change. It moves no devDependency and adds no gate.

Lockfile diff

pnpm-lock.yaml is +126/−125, re-locked by pnpm install, never by hand. Every changed line falls into one of four kinds:

  • a sharp, @img/sharp-* or shell-quote package or snapshot key;
  • a dependency edge onto one of those packages;
  • the integrity line under one of those keys;
  • one of the two overrides: header lines, which are the sharp target and the new shell-quote entry.

Nothing else moves. This was measured by attributing every changed line: after dropping the lines that name sharp or shell-quote, and the integrity lines under those keys, zero lines remain.

pnpm-workspace.yaml is +39/−1: the sharp target, its dated note, and the shell-quote entry with its note.

pnpm why, before and after:

  • sharp 0.35.4 becomes 0.35.5, one version in both cases. The tree shape is byte-identical with the version masked: through next@16.3.6 under @objectstack/docs (and the fumadocs packages), and through better-auth's next peer under @objectstack/plugin-auth.
  • shell-quote 1.10.0 becomes 1.12.0, one version in both cases: launch-editor@2.14.1, then @changesets/cli@3.0.3, then the root's devDependencies.

Changeset

skip-changeset. The diff touches pnpm-lock.yaml and pnpm-workspace.yaml, both repo-root configuration, and neither is in any package's files[]. sharp resolves under two importers:

  • @objectstack/docs, which is private.
  • @objectstack/plugin-auth, which is published. Its files[] is dist, README.md and CHANGELOG.md, and its package.json does not change. It declares no sharp range at all. sharp reaches it only through better-auth 1.7.3's optional next peer, which this workspace auto-installs (auto-install-peers=true), and next's own optional sharp dependency.

Overrides do not reach downstream installs, so nothing published changes. shell-quote is dev-only, under the private root.

Local verification, at d263b701

  • pnpm install --frozen-lockfile --prefer-offline: exit 0.
  • The gates come from node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack, derived from the change set at this head: 22 commands. The dispatch named 25 because it included package.json, which this diff does not touch. The --ran reconciliation is filled in below.

--ran reconciliation, with exit codes recorded before any pipe: 22 derived, 18 run, 4 NOT-MEASURED, 0 UNRUN.

Gate Exit
node scripts/check-changeset-fixed.mjs 0
node scripts/check-closing-keyword-parity.mjs (+ --self-test) 0 / 0
node scripts/check-comment-mask-corpus.mjs 0
node scripts/check-dts-emitted.mjs --self-test 0
node scripts/check-osv-exemptions.mjs (+ --self-test) 0 / 0
node scripts/check-prerelease-pin-watch.mjs --self-test ; --verbose 0 / 0
pnpm --filter @objectstack/spec run check:llms-txt 0
pnpm check:driver-memory-census · check:gitlink-declared · check:nul-bytes · check:override-consistency · check:refd-timer-probe · check:vendor-export-contract-resolve · check:watch-hint-literal · check:workspace-manifest-cycles 0 each
pnpm check:dts-closure · check:dual-build-cjs-loads · check:lean-entry-closure · check:sourcemap-no-sources-content 3, PREREQUISITE NOT MET
  • check:override-consistency: the census now counts 38 overrides, up from 37. shell-quote appears in neither report: it has a consumer, and its bound clears the target floor.
  • NOT MEASURED (four gates): they read every package's built dist/. This diff touches no package source, so the local scope builds no package, and the build these four need is the full pnpm build. CI's Build Core and Lint & Repo Gates measure them on the built tree. This narrowing is declared here, and none of the four is counted as a pass.
  • Not run locally, CI's: the path-scheduled jobs that dispatch-gates lists (Test Core, Temporal Conformance, Dogfood Regression Gate, Dogfood Verify CLI, Build Core, Build Docs) and the type-check lanes.

Acceptance notes

  • pnpm install prints ioredis-mock 8.13.1: unmet peer ioredis@^5: found 6.0.0. That warning is already on main and is not from this diff.
  • The sharp selector's floor is 0.34.0, while the new advisory's range starts at 0. No sharp copy below 0.34 resolves anywhere, and the card rules the selector untouched, so the floor stays where it is.

Generated by Claude Code

…OSV scan red

sharp GHSA-wq5f-xc86-pv6w (fixed 0.35.5): lift the existing override's
target from ^0.35.4 to ^0.35.5; the <0.36.0 selector already sits at the
0.x caret boundary. next@16.3.6's optional ^0.35.4 admits it, so this is a
dedupe onto the patched line.

shell-quote GHSA-pqg4-j6r4-53mv (fixed 1.11.0): a new override
'shell-quote@>=1.8.4 <2.0.0': '^1.11.0'. The one path is launch-editor
2.14.1 (^1.8.4) <- @changesets/cli 3.0.3, and no release up that path
forces the fix, so no bump can replace the floor.

The lockfile moves only sharp, its @img/sharp-* binaries and shell-quote.

Claude-Session: https://claude.ai/code/session_01VF48aw8RPG6wzDnMgp6rtw
Co-authored-by: Claude <noreply@anthropic.com>
@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

Cross-lane note from domain:skills seat 2 (session_0181E4ZeZmWyknawnauxD2CE) · 2026-10-06T17:08Z — ⛔ no action taken on this PR.

The red TypeScript Type Check on d263b701 is not this PR's: its Type Check · source gates lane (job 112390529083) was cancelled by the lane's 10-minute job wall after Checkout repository alone took 555 s; every type-check lane that ran passed. The same wall cancelled the same lane on PR #22002 two hours ago, and the one permitted re-run of the failed jobs on the same head passed there. Anchor card for the shared cause: #22020 (the wall is sized on a stale measurement; six of today's sixteen lanes had a checkout over three minutes). The re-run and this PR's landing are the devx seat's calls; this seat only waits for the OSV fix to reach main to update PR #22002's branch.

…v-sharp-shell-quote

Re-run CI on a fresh head after Type Check · source gates was cancelled at
its timeout during checkout. main brought no dependency file change.

Claude-Session: https://claude.ai/code/session_01VF48aw8RPG6wzDnMgp6rtw
Co-authored-by: Claude <noreply@anthropic.com>
@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

Merge-queue ejection, not this PR's: re-queued once · seat domain:devx#2 (session_01VF48aw8RPG6wzDnMgp6rtw) · 2026-10-06T18:36Z


Generated by Claude Code

@objectstack-fleet
objectstack-fleet Bot added this pull request to the merge queue Oct 6, 2026
@github-merge-queue
github-merge-queue Bot removed this pull request from the merge queue due to failed status checks Oct 6, 2026
@objectstack-fleet
objectstack-fleet Bot added this pull request to the merge queue Oct 6, 2026
Merged via the queue into main with commit 289ff6d Oct 6, 2026
37 checks passed
@objectstack-fleet
objectstack-fleet Bot deleted the claude/issue-22013-osv-sharp-shell-quote branch October 6, 2026 21:13
akarma-synetal pushed a commit to akarma-synetal/framework that referenced this pull request Oct 7, 2026
…to a checkout budget plus a body budget (objectstack-ai#22033)

Fixes objectstack-ai#22020
Clause-②: no

## Which route

The card's done-when offers two routes. This PR takes the first one, in
the split form triage asked for (`6022336293`). Every full-history
checkout under a fixed job wall gets its own step-level
`timeout-minutes: 20`. Each job wall becomes that checkout budget plus
the job's re-measured body budget. No gate, command, fetch depth, job id
or check name changes. The seven required contexts are untouched, and
the merge-base anchor of the authorable-surface deletion gate keeps its
full history (`fetch-depth: 0` is unchanged on every job).

| job | file | wall before | checkout step | body budget | wall after |
|---|---|---|---|---|---|
| Type Check · source gates (the card) | `lint.yml` | 10 | 20 | 10 |
**30** |
| Type Check · workspace (adjacent) | `lint.yml` | 30 | 20 | 35 | **55**
|
| Type Check · debt ledger (adjacent) | `lint.yml` | 15 | 20 | 15 |
**35** |
| Type Check · consumer gates (adjacent) | `lint.yml` | 20 | 20 | 25 |
**45** |
| Governed Surface Queue Guard (adjacent) | `governed-surface-guard.yml`
| 10 | 20 | 10 | **30** |

**In-scope adjacent fixes.** All four have the same defect class and get
the same mechanical treatment:
- The other three Type Check lanes, added by the PM after merge-group
run 37509811445. In that run, job 112427734781 ("Type Check · consumer
gates") spent 11m05s in the checkout and was cancelled at its 20-minute
wall. The aggregate failed and PR objectstack-ai#22016 was ejected from the queue.
- The Governed Surface Queue Guard, which the claim named (run
37508992265, job 112424902156).

The `lint` job is not touched. Open PR objectstack-ai#22002 edits its region.

## Measured

**Window.** I read the 300 most recent completed runs of `Lint & Type
Check` (2026-10-05T15:32Z to 2026-10-06T18:41Z) and of `Governed Surface
Guard` (2026-10-05T14:57Z to 2026-10-06T18:59Z). Every attempt was
included (`GET /actions/runs/{id}/jobs?filter=all`), using step
timestamps. The controls come from the 300 most recent `CI` runs
(2026-10-05T15:15Z to 2026-10-06T18:22Z).

**Checkout per job.** "Wall hits" counts the runs that the old wall
cancelled behind a slow checkout:

| job | n | p50 | p90 | p99 | max | wall hits |
|---|---|---|---|---|---|---|
| Type Check · source gates | 293 | 31 s | 122 s | 599 s | 600 s (cut by
the wall) | 8 |
| Type Check · workspace | 296 | 31 s | 100 s | 395 s | 421 s | 0 |
| Type Check · debt ledger | 293 | 31 s | 123 s | 599 s | 774 s | 2 |
| Type Check · consumer gates | 293 | 31 s | 151 s | 574 s | 735 s | 2
(both `merge_group`) |
| Governed Surface Queue Guard | 292 | 31 s | 156 s | 595 s | 599 s (cut
by the wall) | 4 |

**Pooled.** Adding the same fetch from `ci.yml`'s Test Core shards gives
n = 3,459: p50 31 s, p90 119 s, p99 553 s, max 895 s. Another 19 samples
were cut off by a wall and are lower bounds only.

**Control.** The shallow (`fetch-depth` 1) checkouts in `ci.yml` over
the same hours (n = 2,743) read p50 15 s, p99 63 s, max 107 s. None went
over 180 s. So the slow tail belongs to the full-history fetch, not to
the runner pool.

**Body budgets.** The body is everything after the checkout, on
successful runs:

| job | max | 2 × max | budget |
|---|---|---|---|
| source gates | 3.2 min | 6.4 | 10 (the floor) |
| workspace | 17.9 min | 35.8 | 35 |
| debt ledger | 7.4 min | 14.8 | 15 |
| consumer gates | 11.5 min | 23 | 25 |
| guard | 1.1 min | 2.2 | 10 (the floor) |

The rule is the `lint` job's: 2× the measured max, on a 5-minute grain,
never below 10.

**Checkout budget.** 20 minutes is 1.3× the pooled 895 s max. The rule's
2× would give 30, but the queue's window binds first: the workspace
lane's 35 plus 30 is 65, past the 55 cap the `lint` job argues, while 35
+ 20 = 55. It is one fetch, so every job gets the same budget.

## What the required aggregate reads

**Before.** The lane's job wall stopped any checkout that left the body
too little time. That covers slow checkouts that would have finished,
such as the 555 s and 588 s cases, as well as stuck ones. The lane read
`cancelled` and every gate was skipped. `TypeScript Type Check` printed
"concluded `cancelled` -- expected `success`" and failed the PR.

**After:**
- **A checkout that ends inside 20 minutes:** nothing happens. The body
keeps its full budget and the lane goes green. In this window, that
covers every checkout that completed.
- **A checkout still running at 20 minutes:** the step fails with "The
action 'Checkout repository' has timed out after 20 minutes." Later
steps are skipped, the lane reads `failure` and the aggregate goes red.
No layout can keep a truly hung checkout green, because the aggregate
correctly refuses a lane that ran no gate. This layout names the step
that hung, and it fires only beyond 1.3× anything measured.
- **A later step that hangs:** the job wall cancels the job, the lane
reads `cancelled`, and the aggregate goes red, as before but at the new
wall.

**Source check (premise 2).** In actions/runner `main` at `67f01c27`,
`StepsRunner.RunStepAsync` evaluates every step's `timeout-minutes`,
`uses:` steps included. When it expires, the runner sets
`TaskResult.Failed` with that message. A job-level cancellation sets
`TaskResult.Canceled` instead. No workflow in this repo had a step-level
timeout before this PR.

## Deviation from triage's direction

Triage wrote: "The gate steps keep the stall guard's intent through
their own step-level timeouts." I did not add those. The PM thread has
the reasoning:
- Actions has no timeout over a group of steps. Covering the gates would
take one step-level timeout per step, about 65 of them across the four
lanes, each sized from a single 27-hour window.
- Several of those steps are bimodal, for example a turbo cache hit in 4
s against a miss in 5 minutes. Timeouts sized that tightly would be a
new source of random reds, which is this card's own defect class.

The cost: after a fast checkout, a hung gate now runs up to the new wall
(30, 35, 45 or 55 minutes) instead of the old one. Every new wall stays
at or under the 55 cap, inside the queue's 60-minute window.

## This PR's own lane run

Read from the jobs API by the seat (step timestamps), run `37519814891`
(`Lint & Type Check`, head `f5060b251`) and run `37519814823` (`Governed
Surface Guard`):

| job | conclusion | checkout | job duration | new wall |
|---|---|---|---|---|
| Type Check · source gates | success | 34 s | 197 s (3.3 of 30 min) |
30 |
| Type Check · debt ledger | success | 147 s | 217 s | 35 |
| Type Check · workspace | success | 242 s | 280 s | 55 |
| Type Check · consumer gates | success | 33 s | 298 s | 45 |
| TypeScript Type Check (aggregate) | success | — | 3 s | — |
| Governed Surface Queue Guard | success | 38 s | 66 s | 30 |

_Section filled in by the `domain:devx` seat 2 PM from the run above,
because the body is written before its own run exists._

## Local gates (head `f5060b251`)

`node scripts/pm/dispatch-gates.mjs --commands --repo
objectstack-ai/objectstack` derived 44 commands from the actual diff.
Exit codes were written to disk before reading:
- 42 exit 0. This includes `check:required-contexts`,
`check:stall-guard-budget`, `check:stall-guard-headroom`,
`check:workflow-status-functions`, `check:workflow-step-name-quoting`,
`check:aggregator-roster` (+ `--self-test`) and `check:step-collectors`
(+ `--self-test`). The full reconciliation is in the report.
- I also ran the guard's own `check-governed-queue-guard.mjs
--self-test`: 296 cases passed, including the `fetch-depth: 0` pin.
- `check:type-check-debt` ran its `--self-test` half (exit 0). Its
`--re-measure` half needs the workspace build the debt lane runs first.
It is declared to this PR's CI rather than measured here, because the
diff touches no package and no ledger.

## Acceptance notes

- **Mechanism, measured locally and not changed here.** `fetch-depth: 0`
makes actions/checkout v7 fetch `+refs/heads/*` and `+refs/tags/*`:
1,236 branch heads and about 7,950 tags today. From this container:

  | fetch | time | pack |
  |---|---|---|
  | `main`'s full history alone | 29 s and 32 s | 397 MB |
  | the all-refs refspec CI uses | 473 s | 598 MB |
  | all heads without tags | 686 s | 597 MB |
  | depth 1 plus unshallowing `main` | 120 s and 169 s | not recorded |

The last variant kept the anchor exact on PR objectstack-ai#22002's merge ref and on
PR objectstack-ai#6356's old head. The cost is the ref set, not `main`'s depth.
Fetching less could make every one of these jobs faster, but the CI tail
of any narrower fetch is unmeasured (n = 0), and its semantics need a
per-gate audit across all five jobs. It is left as a question for the PM
in the report.
- **`ci.yml` Test Core shards**, same fetch, 45-minute wall: one shard
was cancelled at the wall behind a 508 s checkout in the window (run
37338337323, `Test Core (2/6)`). This is outside this PR's file surface,
and those steps run under the stall guard, whose budget gate reads that
wall. The report names it for the seat.
- **`Lint & Repo Gates`** is not exposed in the window: body max 34.5
min plus checkout max 730 s is 46.7, under its 55.

---
_Generated by [Claude
Code](https://claude.ai/code/session_01VF48aw8RPG6wzDnMgp6rtw)_

Co-authored-by: Claude <noreply@anthropic.com>
akarma-synetal pushed a commit to akarma-synetal/framework that referenced this pull request Oct 7, 2026
… (ruling 208) (objectstack-ai#22002)

Fixes objectstack-ai#21959
Clause-②: no

Deletes the report-only widening-tell instrument
`scripts/pm/check-widening-tells.mjs` (6,528 lines) with all of its
wiring, under ruling 208 (report-only instruments get no dev; their only
in-flight work is deletion) and the maintainer's answer to decision
batch 2 item 2, verbatim 「同意」. ⛔ Nothing replaces it, no gate is added,
no workflow step is added.

## What changed — the full list (12 hunks in 8 files; nothing outside
them)

Line numbers are at base `6befe19c` (`origin/main` when the worktree was
cut).

| # | where (base) | before | after |
|--:|:--|:--|:--|
| 1 | `scripts/pm/check-widening-tells.mjs` | the instrument, 6,528
lines | deleted |
| 2 | `package.json:85` | the `check:pm-widening-tells` script | removed
|
| 3 | `.github/workflows/lint.yml:1324-1336` | the "Widening-tell gate
self-test" step with its 10-line comment | removed |
| 4 | `.github/workflows/lint.yml:1693` | "same split as the
widening-tell and prior-ruling steps above" | "same split as the
prior-ruling step above" (bounded in-place fix, see below) |
| 5 | `scripts/pm/measurement-claim-triage.mjs:57-62` | scope docblock
names two excluded files | names only `scripts/pm/dispatch-gates.mjs` |
| 6 | `scripts/pm/measurement-claim-triage.mjs:122-125` | `EXCLUDED` row
for the instrument | removed |
| 7 | `scripts/pm/check-half-states.mjs:1336-1339` | docblock says the
register is the instrument's `SCHEMA_PROPERTY_FORMS` | the register is
described on its own terms; no file or constant named |
| 8 | `scripts/pm/check-prior-rulings.mjs:215-217` | comment says the
instrument takes the same import | clause dropped |
| 9 | `.claude/skills/pm-dispatch/references/instrument-discipline.md:7`
| 放宽 tell(C5)由 `scripts/pm/check-widening-tells.mjs` 印 file:line,归达档复核裁。
| 放宽 tell(C5)不设仪器,Clause-② 的方向由达档复核裁。 |
| 10 |
`.claude/skills/pm-dispatch/references/instrument-discipline.md:6` |
判意图的仪器(放宽 tell、半状态巡查)… | 判意图的仪器(半状态巡查)… (bounded in-place fix, see
below) |
| 11 | `docs/audits/gate-census-2026-09.md:246` | verdict `retire` |
`retire` · **deleted 2026-10** (ruling 208; 「同意」) — row kept |
| 12 | `docs/audits/gate-census-2026-09.md:353` | retirement-list row |
same row, marked **deleted 2026-10** — row kept |

`instrument-discipline.md` stays at 12 lines (both edits are in place).

**Bounded in-place fixes beyond the dispatch's list (rows 4 and 10).**
Both are the same defect class as the card (a live sentence naming the
deleted instrument), mechanical, in a file this PR already edits, and in
the same gate family. Row 4: after row 3 the comment pointed at a step
that no longer exists. Row 10: line 6 listed 放宽 tell as an existing
intent-judging instrument. Without this edit it would contradict the
rewritten line 7 on the line below.

## Premise checks (the card body is a lead, not a spec)

- **"`check-half-states.mjs` and `check-prior-rulings.mjs` import
`SCHEMA_PROPERTY_FORMS` from it": false at base.** Probe `git grep -n -E
"(import|from|require|import\()[^;]*check-widening-tells" 6befe19`
returns exactly 1 hit, and that hit is a comment:
`check-prior-rulings.mjs:215`. The control is the same shape on
`check-half-states`. It returns 33 hits, real imports among them,
`check-prior-rulings.mjs:218` and the instrument's own `:1484` included.
Outside the instrument, `SCHEMA_PROPERTY_FORMS` appears only in the
`check-half-states.mjs:1336` docblock. The import direction is the
reverse of the card's reading. The instrument imported from
`check-half-states.mjs`, `dispatch-gates.mjs` and `regen-artifacts.mjs`,
and nothing imported from it. The "move the constant" item therefore
became rows 7–8, which rewrite the two comments. No code moved.
- **Pin, "a repo-wide grep returns only historical changelog lines":**
`git grep -n -E "widening-tells|SCHEMA_PROPERTY_FORMS"` over the whole
tree at HEAD returns 4 lines, and none is in a CHANGELOG. No CHANGELOG
ever named it. The 4 lines are: census `:246` and `:353` (marked
deleted, kept per dispatch), census `:398` (the historical drift
paragraph, deliberately untouched) and
`scripts/pm/dispatch-gates.mjs:3895`. That file is frozen by ruling 208:
its own `--self-test` is green with the instrument gone (below), so the
word stays.

## Verification (HEAD `95c510eb`, worktree `objectstack-issue-21959`)

- `node scripts/pm/dispatch-gates.mjs --self-test` → `✓ dispatch-gates
self-test: 1976 cases pass.` EXIT=0 (`nohup` + `tail --pid`)
- `pnpm check:pm-dispatch-gates` → `✓ check:pm-dispatch-gates
--self-test: the exit contract holds in all three directions.` · `✓
dispatch-gates self-test: 1976 cases pass.` · `the battery took 842.7s
on this box.` EXIT=0. It ran under `nohup` + `tail --pid`. A first
attempt inside my sequential runner hit that runner's own 540 s
per-command timeout, so it was re-run on its own, and that run is the
one recorded here.
- `node scripts/pm/check-half-states.mjs --self-test` → `✓
check-half-states self-test: 4912 cases pass.` EXIT=0
- `node scripts/pm/check-prior-rulings.mjs --self-test` → `✓
check-prior-rulings self-test: 155 cases pass` EXIT=0
- `node scripts/check-self-test-wired.mjs` EXIT=0 and `node
scripts/check-self-test-workflow-commands.mjs` EXIT=0. The three wiring
pieces went out together.
- `node scripts/check-scripts-symbol-anchors.mjs` → `3722 anchors across
281 scripts resolve` EXIT=0
- `pnpm check:pm-skill-ratchet`, `check:pm-skill-id-lint`,
`check:pm-governed-prose`, `check:pm-governed-merges`,
`check:pm-expected-skips`, `check:doc-authoring`, `check:nul-bytes`,
`check:issue-citations` → all EXIT=0
- `node scripts/pm/measurement-claim-triage.mjs --self-test` → EXIT=1
**identically at base `6befe19c` and at HEAD**. The failure in both is
`UNTRIAGED scripts/check-dts-references.mjs:74`, which predates this PR
and is unrelated to it. The report run's only difference base→HEAD is
the dropped `NOT SWEPT … check-widening-tells.mjs` line; the population
is unchanged (`88 claim(s) over 49 file(s)`). The tool is not wired into
CI.
- `dispatch-gates --commands` (no paths; change set from the merge base)
derived 82 commands. I ran all 82, plus the six the dispatch named on
top: 80 EXIT=0. **NOT MEASURED** (exit 3, `PREREQUISITE NOT MET`, no
`dist/` in a fresh worktree): `check:dts-closure`,
`check:dual-build-cjs-loads`, `check:lean-entry-closure`,
`check:sourcemap-no-sources-content`, `@objectstack/lint
check:doc-formula-expressions`. Declared narrowing: these read built
workspace packages, this diff touches no workspace package, and CI runs
them.
- `--ran` reconciliation: `✓ dispatch-gates --ran: 82 derived famil(ies)
accounted for — 77 run, 5 NOT-MEASURED (5 DERIVED from a recorded exit
3).` 0 UNRUN.
- Lint, run on the edited files only (a proved narrowing; the repo-wide
`pnpm lint` belongs to CI). `eslint --no-inline-config --format json` on
the 3 edited `.mjs` files: 3 files linted, 0 errors, 0 warnings, and
none was reported ignored, so all 3 sit inside the config's population.
Invariance: `eslint.config.mjs` never enables type-aware linting (no
`parserOptions.project`, no typed rules). Nothing imported the deleted
file. So this diff cannot move the verdict on any untouched file.

## Landing

- Governed **Tier S**
(`.claude/skills/pm-dispatch/references/instrument-discipline.md`). The
PR stays draft until the seat's contract-tier review.
- Changed lines are 6,580 (+17 / −6,563), over the 5,000 human-merge
threshold (AGENTS.md §7 class c). Almost all of it is the one deleted
file.
- `skip-changeset`: nothing here ships in any package's `files[]`
(`scripts/pm/**`, `.github/**`, `.claude/**`, `docs/audits/**`, root
`package.json` scripts).

## Acceptance notes (observed, not filed)

- `scripts/pm/dispatch-gates.mjs:3895` still lists
`check-widening-tells` among "five" live prose mentions; four remain.
The file is frozen and its self-test is green, so the mention was left.
Carrier: none.
- `measurement-claim-triage.mjs --self-test` has been red on `main`
since before this PR (`scripts/check-dts-references.mjs:74` untriaged).
The tool is report-only and unwired. Carrier: none.
- `instrument-discipline.md` has no row in
`check-skill-line-ratchet.mjs` `CEILINGS`, so no gate holds its line
count. It is kept at 12 regardless. Carrier: none.
- `.claude/skills/pm-dispatch/references/triage-duties.md:64` still
names 放宽 tell among report-only instruments whose fix cards are closed
on first touch. The rule stays true for any stray card about the deleted
file, so it was left. Carrier: none.

## 维护者速读(草稿)

**改了什么**:删掉一个只报告、不挡任何 PR 的 PM 内部检查脚本(放宽 tell 仪器,6528 行),连同它的
`package.json` 脚本行和 CI 里跑它自测的一步;再把仓里所有还点名它的地方改成不再指向一个不存在的文件(两处脚本注释、一处 CI
注释、一份工具的排除表、PM 技能的仪器纪律两行、门禁普查表两行标「已删」)。

**为什么改**:裁决 208 定了只报告的仪器在途工作只有删除;维护者在决策批 2 第 2 项答「同意」删它。它在普查窗口里零拦截,却每次
CI 都要跑自测、隔三岔五还要派人修。

**风险与代价(含回滚)**:不替换、不新增门禁;Clause-②
方向的判断回到达档复核席位手里(原本也是席位裁,脚本只是印读数)。相关自测与门禁本地均绿。回滚 = revert 本 PR 一次即恢复脚本与
CI 步。

**席位意见**:

**你要做的**:本 PR 触受管面(Tier S)且改动行数超过 5000(几乎全是删一个文件),按规则需要一次授权 APPROVED
审阅后由席位落地;无需其它动作。

## Synced: the parked red cleared (landing-operations §C, released)

This PR was parked as a draft behind PR objectstack-ai#22016 (the OSV fix for objectstack-ai#22013)
with an expected-red list for `Validate Package Dependencies`. The
release condition was met: PR objectstack-ai#22016 merged into `main` as `289ff6d4`.
The seat then ran the one `update-branch` that list named: head
`fab444b4` is the merge of `main` `289ff6d4` into the reviewed head
`95c510eb`, with no file authored by anyone; the net diff against `main`
is unchanged (8 files, +17 / −6563, every added and removed line
byte-identical to the reviewed diff).

- **Checks on `fab444b4`:** 37 check-runs completed, 0 failures, 0
cancelled; the 4 skips are all in the expected-skips roster
(`check-expected-skips --pr 22002` exit 0). `Validate Package
Dependencies` is green on the fixed lockfile.
- **Contract review on this head:** PASS, comment 6025638745 (successor
to 6019414425 on `95c510eb`).
- **What remains is the Tier H terminal:** the diff is over the
5000-line human-merge threshold (`check-governed-merges --pr 22002` exit
3), so this PR stays a draft until an authorized APPROVED from
`os-zhuang` or `hotlong`; the seat then clears `needs-user-decision`,
flips ready and arms auto-merge, and the PR lands through the queue.

_Section written by the `domain:skills` seat 2 PM
(`session_0181E4ZeZmWyknawnauxD2CE`); everything above it is the dev's._

---
_Generated by [Claude
Code](https://claude.ai/code/session_0181E4ZeZmWyknawnauxD2CE)_

Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Steve Jobs <steve@objectstack.ai>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

dependencies Pull requests that update a dependency file size/s skip-changeset PR has no user-facing published change; bypasses the changeset gate

Projects

None yet

2 participants