Found by the per-edge audit on #14013 (provenance; that card is an audit, ⛔ not a fix, so this is filed separately per its triage fence). Measured on a39b02a6b.
The edge
scripts/objectui-changeset-digest.mjs (the file behind check:objectui-changeset) copies scripts/bump-objectui.sh into a throwaway repo and then EXECUTES the copy — four spawn sites, all of the same shape:
execFileSync('bash', [join(fwDegraded, 'scripts', 'bump-objectui.sh'), '--no-commit', head], …)
spawnSync('bash', [join(fwTrunc, 'scripts', 'bump-objectui.sh'), '--no-commit', c6to], …)
spawnSync('bash', [join(fwTrunc2, 'scripts', 'bump-objectui.sh'), '--no-commit', c6to], …)
spawnSync('bash', [join(fwDir, 'scripts', 'bump-objectui.sh'), ...args], …)
Neither follow traverses it:
⇒ The digest genuinely performs bump-objectui.sh's work, and inherits 0 of the 6 hints that file spells.
This is the same family as #13000 (whose specimen was the digest staging a copy of check-adr-0087-registration.mjs) one turn further: #13000 closed the case where the card edits the STAGED FILE ITSELF; the case where the card edits something in the staged program's own population is still open.
Measured cost, stated honestly
Small, and the thinness is part of the report rather than a reason to withhold it. The 6 hints scripts/bump-objectui.sh spells are .changeset/*.md, scripts/bump-objectui.selftest.sh, .github/workflows/cut-rc.yml, docs/releases-maintenance.md, .changeset/console-82a94170c405.md, packages/console/dist. Two of those are already under .changeset, which the family declares itself; packages/console/dist is a build output. So the novel-and-plausible lead is essentially scripts/bump-objectui.selftest.sh.
⛔ That is a reason to price this carefully, not to close it as a one-off: the shape — copy a program to a scratch path, execute the copy — is what a sandboxing gate does, and it is invisible to both follows by construction rather than by accident.
⛔ What the repair is NOT
Not this gate's name in a table (ruled against four times in this lane), and ⛔ not admitting a basename literal as a read target — readProgramTargetsInSource's own docblock refuses that explicitly ("Do not close that by admitting the basename literal: that is the grep above", measured at 924 mentions in 451 files).
The shape that would fit the #14012 precedent: intersect two scans that already run over the SAME file — a spawn site whose base is unresolvable but whose trailing segments equal a target the read scan already resolved to a tracked path — and let the followed program declare what a follower inherits (declaredInheritedPopulation). That is an intersection inside one file, not a grep over the corpus. ⚠️ Note that scripts/bump-objectui.sh carries no inherited-population marker today, so a declaration-gated version of this follow ships 0 live leads until that marker is added; whether the marker or the follow comes first is the design question this card owes.
Re-check
node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --residue scripts/objectui-changeset-digest.mjs
⚠️ scripts/pm/dispatch-gates.mjs changes several times a day — re-derive rather than quoting any figure above.
Found by the per-edge audit on #14013 (provenance; that card is an audit, ⛔ not a fix, so this is filed separately per its triage fence). Measured on
a39b02a6b.The edge
scripts/objectui-changeset-digest.mjs(the file behindcheck:objectui-changeset) copiesscripts/bump-objectui.shinto a throwaway repo and then EXECUTES the copy — four spawn sites, all of the same shape:Neither follow traverses it:
spawnedProgramTargets, [finding] dispatch-gates does not derive check:pm-dispatch-gates for a .github/workflows/** change — so a dev following the derived list cannot run the one gate that judges their new workflow #13511/Derive a gate for the surface the program it RUNS reads #14012) refuses the site: the base is amkdtempscratch directory, soresolvePathExpressionreturns nothing in-tree and the target is not tracked. Correct refusal, by its own documented narrowing.readProgramTargetsInSource, dispatch-gates cannot see runtime staging dependencies between gate scripts (digest sandbox broke on a staged gate's new import) #13000) DOES resolve the tracked original —check:objectui-changeset -> scripts/bump-objectui.shis a liveentry.readspair today — but it contributes an IDENTITY key only, never a population.⇒ The digest genuinely performs
bump-objectui.sh's work, and inherits 0 of the 6 hints that file spells.This is the same family as #13000 (whose specimen was the digest staging a copy of
check-adr-0087-registration.mjs) one turn further: #13000 closed the case where the card edits the STAGED FILE ITSELF; the case where the card edits something in the staged program's own population is still open.Measured cost, stated honestly
Small, and the thinness is part of the report rather than a reason to withhold it. The 6 hints
scripts/bump-objectui.shspells are.changeset/*.md,scripts/bump-objectui.selftest.sh,.github/workflows/cut-rc.yml,docs/releases-maintenance.md,.changeset/console-82a94170c405.md,packages/console/dist. Two of those are already under.changeset, which the family declares itself;packages/console/distis a build output. So the novel-and-plausible lead is essentiallyscripts/bump-objectui.selftest.sh.⛔ That is a reason to price this carefully, not to close it as a one-off: the shape — copy a program to a scratch path, execute the copy — is what a sandboxing gate does, and it is invisible to both follows by construction rather than by accident.
⛔ What the repair is NOT
Not this gate's name in a table (ruled against four times in this lane), and ⛔ not admitting a basename literal as a read target —
readProgramTargetsInSource's own docblock refuses that explicitly ("Do not close that by admitting the basename literal: that is the grep above", measured at 924 mentions in 451 files).The shape that would fit the #14012 precedent: intersect two scans that already run over the SAME file — a spawn site whose base is unresolvable but whose trailing segments equal a target the read scan already resolved to a tracked path — and let the followed program declare what a follower inherits (⚠️ Note that
declaredInheritedPopulation). That is an intersection inside one file, not a grep over the corpus.scripts/bump-objectui.shcarries noinherited-populationmarker today, so a declaration-gated version of this follow ships 0 live leads until that marker is added; whether the marker or the follow comes first is the design question this card owes.Re-check
scripts/pm/dispatch-gates.mjschanges several times a day — re-derive rather than quoting any figure above.