Skip to content

fix(release): judge a .objectstack-sha console bundle against objectui's own build of that commit - #24532

Merged
objectstack-fleet[bot] merged 4 commits into
mainfrom
claude/issue-24510-console-injection-real-witness
Oct 19, 2026
Merged

objectstack-fleet[bot] merged 4 commits into
mainfrom
claude/issue-24510-console-injection-real-witness

Conversation

@objectstack-fleet

Copy link
Copy Markdown
Contributor

Fixes #24510

Clause-②: no

What this changes

On a console pin whose objectui commit carries .objectstack-sha, scripts/build-console.sh stands THIS tree in for objectui's pinned objectstack commit (OBJECTSTACK_ROOT). So the spec in objectui's install is this tree's own. The script handed exactly that spec to assert-console-spec-injection.mjs as --vendored. It equalled --injected, so the assertion printed "no observable skew", stamped skew: false with null witnesses, and exited 0 before it looked at the bundle at all. check:console-injection --require-stamp then replayed "Nothing assertable". Both release paths passed any bundle.

  • scripts/build-console.sh: on the .objectstack-sha branch, before the stand-in, it now builds objectui's OWN @objectstack/* at its .objectstack-sha, by objectui's own recipe (node scripts/objectstack-pin.mjs build with OBJECTSTACK_ROOT and OS_SKIP_DTS unset). It keeps a copy of that cache, the pin script's .stamp.json included, at node_modules/.cache/objectstack-pin-reference in the objectui build tree, outside the cache the stand-in replaces. That copy's spec is passed as --vendored. A rerun in the same build tree reuses it while its stamp says source: pin at this pin. A pin without .objectstack-sha is unchanged: --vendored is still objectui's install.
  • scripts/assert-console-spec-injection.mjs: when the --objectui tree carries .objectstack-sha, --vendored must sit beside a pin-script stamp with source: pin and sha equal to that pin. Anything else is refused as cannot-judge (exit 2), never read as "no skew": the stand-in (source: external), the install's own copy (no stamp), or a build of another commit. The stamp entry now records vendoredFrom and vendoredPin. The verdict text names the pinned reference (pin-only, not published-only). The probe derivation in console-spec-probes.mjs is unchanged.
  • scripts/check-console-injection.mjs: the replay names the pinned reference in its no-skew line and in its red verdict. Self-test battery 15 (17 cases, floor 17; roster floor 12 → 13) covers four things. It refuses the three wrong references. It stamps a real witness against the right one. It goes red on a bundle carrying the pinned spec, at build time and on replay. It passes the honest no-skew case and names the reference in it.
  • packages/spec/scripts/build-console-objectstack-root.test.ts: the existing branch test (it pins this exact branch of build-console.sh) now expects three things. The native pin build runs before the stand-in, without OBJECTSTACK_ROOT and without OS_SKIP_DTS. The reference cache and its pin stamp survive the stand-in. A rerun reuses the reference only while its stamp names the pin.

The producer of the vacuity was the wiring in build-console.sh, so the fix is there. The assertion's new refusal keeps that wiring from coming back silently. .github/workflows/release.yml is untouched: its check:console-injection --require-stamp call did not need to change, so this PR touches no governed surface.

The card's "Wanted", item by item

  1. "the assertion takes its witness from the spec at objectui's .objectstack-sha": done. --vendored is objectui's own build of 2c9bf9430a11, and the assertion refuses any other reference on such a pin.
  2. "so that the stamp carries a non-null witness": done. The stamp is shown before and after below.
  3. "A bundle that does not carry this tree's spec fails both release paths again": done. The build path exits 1 and the replay exits 1 on a bundle carrying objectui's own pinned spec. The old code exits 0 on both. The matrix is below.

Measurements

All readings are from objectstack a5a781bc7 (BASE) and this branch, at .objectui-sha 4016370af3c9, where objectui's .objectstack-sha is 2c9bf9430a11 (spec 18.0.0-next.3). This tree's spec is 18.0.0-next.5. The objectui source was the sibling checkout, build-console.sh mode 2.

Stamp, real build (bash scripts/build-console.sh under os-verify-lock):

skew freshWitness staleDetector vendoredPin replay --require-stamp
BASE a5a781bc7 (VERDICT 0, 862 s) false null null absent exit 0, "Nothing assertable in this stamp"
this branch 91dc1bab6 (VERDICT 0, 672 s) true "Error code the write was refused or failed with, as the single-record write door answers it" "Binds the element to one same-origin API endpoint instead of an object" 2c9bf9430a11… exit 0, "the dist carries this tree's copy"

Build-time verdict on this branch: "Console bundle carries THIS tree's @objectstack/spec, and only it (vendored: @objectstack/spec of objectui's own build of objectstack 2c9bf94)". 16 of 16 injected-only descriptions are present and all 2 pin-only ones are absent. This is the same count os-dev-report 6263864885 measured by hand.

Reference build cost, from the pin script's own step timings on this shared box: fetch 14.8 s, install 5.0 s, build of the 7 packages 144.7 s, pack 16.5 s, so about 181 s. The rerun in the same tree skipped it: the log has 0 "Building objectui's own" lines, against 1 on the first run.

The negative proof (hypothesis 5). The red bundle is a scratch build-console.sh run with both halves deliberately broken: OBJECTUI_DEPS_BUILD_CMD puts objectui's own pin build back into its install after the stand-in, and OBJECTUI_BUILD_CMD drops OBJECTSTACK_SPEC_DIST and OBJECTSTACK_CLIENT_DIST. That is what ships if pack and inject both regress. The run ended with build-time exit 1: "✗ Built console still carries the @objectstack/spec of objectui's own build of objectstack 2c9bf94 … (1 of 2 pin-only descriptions) … Binds the element to one same-origin API endpoint instead of an object". Lock VERDICT command-exit 1. The import/jobs canary passed on that same bundle.

A first sabotage aimed only OBJECTSTACK_SPEC_DIST at the pinned spec while the install stayed this tree. It never produced a bundle: rolldown's MISSING_EXPORT error said this tree's @objectstack/lint needs virtualFieldAggregateRemedy, which the pinned spec lacks. So the coherent leak is the whole pin, and that is the bundle used here.

Then every leg was re-run at the final head, against the saved bundles. These are direct node runs, assertion blob 26acfe988c3b, BASE blob 4fd59042a9eb:

leg bundle --vendored exit stamp
new assertion this tree's pin reference 0 skew true, witnesses above
new assertion objectui's own pin pin reference 1 none written
BASE assertion this tree's stand-in (BASE's wiring) 0 skew false, null, null
BASE assertion objectui's own pin stand-in (BASE's wiring) 0, the vacuity skew false, null, null
new assertion objectui's own pin stand-in 2, refused none written
replay, new stamp objectui's own pin n/a 1, "carries the @objectstack/spec of objectui's own build of objectstack 2c9bf94"
replay, BASE stamp objectui's own pin n/a 0, the vacuity
replay, new stamp this tree's n/a 0

PM mechanism hypotheses

  1. Confirmed, by the BASE build above. --vendored resolved to this tree's packed spec, and the stamp and replay matched the card exactly.
  2. Route: objectui's own pin build, kept before the stand-in. objectui's cache is replaced by the stand-in, and on a CI runner it is empty before the build anyway. objectui's machine store is not read under OBJECTSTACK_ROOT, and the pin script at this pin has no machine-store code at all: its 2 "machine" hits are about npm network settings, against 7 hits in objectui#12972's f9401e6. git show of this repo's history gives source, while the probes read built .describe() text. An npm version is exact only when the pin is a version commit, and objectui's bump-objectstack.sh pins any main HEAD. The reference stays a built spec, needs no secret, and fetches objectstack from GitHub like the pin script does by default (OBJECTSTACK_REPO_URL overrides it). The cache-HIT replay still reads only the stamp, which now carries real probes. On a HIT nothing is built, and the replay's expiry check still reads only this tree's built spec.
  3. Rule: "no skew" is a pass only against a reference that is not this tree. On a .objectstack-sha pin, that reference is objectui's own build of the pinned commit, proven by its pin stamp. When that build declares the same descriptions as this tree, the bundle carries the same text either way, so it stays an honest exit 0. The stamp then records vendoredPin, and the replay prints "no observable skew between the injected and objectui's own build of objectstack SHA". The vacuous case can no longer be produced: a reference that is the stand-in or the install is refused with exit 2 before the bundle is read. Battery 15 pins both.
  4. Out of scope, noted. The import/jobs client canary passed on the pin-native bundle too, so it does not tell an injected client from objectui's own. That is measured above and agrees with 6263864885. No client witness was added: per 6263864885, the two trees' client differs only in a type signature and comments, so a witness would have nothing to tell apart today. See the Acceptance notes.
  5. Done: red 1 and green 0 on the build path, red 1 and green 0 on replay, against BASE's 0 and 0 on the same bundles. See the matrix.

Route choice on the four axes

  • Real business need. The spec to judge against is the one a broken pack-or-inject would actually ship. Measured above, that is objectui's own build of its pin. An npm version or a source checkout would be a different spec.
  • Long-term soundness. It reuses objectui's own build recipe and its stamp, so no copy of that build logic lives here. It follows the pin automatically as .objectstack-sha moves. The cost is about 3 minutes per console build that misses its cache.
  • Keeping AI from writing it wrong. The assertion refuses the vacuous wiring loudly (exit 2, naming the pin). No version-mapping heuristic is involved that could quietly pick the wrong reference.
  • No requirement sprawl. No new gate, no required-check change, no workflow change, no release act. The existing assertion stops being vacuous.

Tests and gates

The gate union was run after the final commit, at 14d4124e8. dispatch-gates.mjs --commands derived 86 families. 84 exited 0 on the first pass. Two answered exit 3, PREREQUISITE NOT MET, which is not a measurement:

  • check-plugin-teardown-shape --self-test could not reach its fixture commit in a shallow clone. After git fetch --unshallow origin main it exited 0.
  • check:dual-build-cjs-loads needs every package's dist. After turbo run build --filter=!@objectstack/docs --concurrency=2 (76 of 76, 75 cached, VERDICT 0) it exited 0.

dispatch-gates.mjs --ran then reported "86 derived, 86 run, 0 NOT-MEASURED, 0 UNRUN" (exit 0). This PR's check-runs belong to CI and were not re-run here.

  • node scripts/check-console-injection.mjs --self-test: exit 0, "84 assertions over real fixture trees".
  • Ablation, in a scratch tree, so the worktree was never mutated. Battery 15 with BASE's assertion swapped in, blob verified equal to the BASE blob: exit 1, 10 failures. The stand-in leg reads "expected 2, got 0". Restored, blob equal to HEAD: exit 0.
  • pnpm --filter @objectstack/spec exec vitest run --project repo --maxWorkers=2 scripts/build-console-objectstack-root.test.ts: 6 of 6 pass. The same file at 24e7c5cab, before its update, failed 2 of 5. Ablation through scripts/ablation-replace.mjs: the reference guard was replaced by if false, the anchor went 1 → 0 and the blob changed, and 3 of 6 failed. The restore was proven: blob equal to HEAD, git diff HEAD empty. Re-run after the restore: 6 of 6.
  • pnpm --filter @objectstack/spec typecheck: VERDICT 0. tsc -p tsconfig.scripts.json --listFiles includes the edited test.
  • check:console-injection exit 0 and check:console-sha exit 0 on the real dist.

Acceptance notes

  • Every console build that misses its dist cache on a .objectstack-sha pin now pays the reference build once, about 181 s on this box. Both workflows hash scripts/build-console.sh into their dist-cache key, so every entry stamped by the old script stops being restored. The first run of each workflow after this lands rebuilds cold.
  • The reference build fetches objectstack at the pinned commit from GitHub, the host the build already clones objectui from. It refuses loudly on any pin-script refusal, since build-console.sh runs under set -e.
  • Client canary (hypothesis 4): it is non-discriminating on this branch, as measured above. The reference cache now also holds the pin's own @objectstack/client, which is where a derived client witness would come from if one is ever wanted. Owner: none. Not filed: this is an observation with nothing to witness today.
  • The replay's pass line still says "not the published one" on a pinned stamp. That is wording only, and it was left as is.
  • Changed lines: 227 (204 added, 23 removed). The three planned scripts account for 191. The other 36 are the existing branch test, which this diff could not leave red.
  • Local scope: the derived gate families and the files above. The spec package's local vitest project, whole test:repo, pnpm lint and the rest of the farm belong to CI.

Generated by Claude Code

…i's own build of that commit

On a pin carrying .objectstack-sha, build-console.sh stands this tree in for
objectui's pinned objectstack commit, so the spec objectui's install holds is
this tree's own. Handed to assert-console-spec-injection.mjs as --vendored it
equalled --injected: the assertion reported no skew, stamped null witnesses,
and passed any bundle; check:console-injection --require-stamp then replayed
"nothing assertable".

build-console.sh now builds objectui's own @objectstack/* at its
.objectstack-sha first (the pin script without OBJECTSTACK_ROOT), keeps a copy
with the pin's cache stamp outside the cache the stand-in replaces, and passes
that spec as --vendored. The assertion refuses, as cannot-judge, any other
reference on such a pin (the stand-in, the install's copy, a build of another
commit), and the stamp records vendoredFrom and vendoredPin. Self-test
battery 15 pins the refusal, the real witness, the red on a bundle carrying
the pinned spec (build and replay), and the honest no-skew case.

Claude-Session: https://claude.ai/code/session_01FM29ZqLTrnPNXxijioZwMp
Co-authored-by: Claude <noreply@anthropic.com>
…e assertion's verdicts

Wording only: on a .objectstack-sha pin the vendored side is objectui's own
build of that commit, not a published spec, so its unique descriptions are
reported as pin-only.

Claude-Session: https://claude.ai/code/session_01FM29ZqLTrnPNXxijioZwMp
Co-authored-by: Claude <noreply@anthropic.com>
… text in a restored dist

Wording only: a stamp with vendoredPin was judged against objectui's own build
of that commit, so the replay's red verdict says so instead of "the PUBLISHED".

Claude-Session: https://claude.ai/code/session_01FM29ZqLTrnPNXxijioZwMp
Co-authored-by: Claude <noreply@anthropic.com>
…ck-sha pin

The branch test now expects objectui's own pin build (no OBJECTSTACK_ROOT, no
OS_SKIP_DTS) before the stand-in, the reference cache with its pin stamp to
survive the stand-in, and a rerun to reuse it only while its stamp names the
pin.

Claude-Session: https://claude.ai/code/session_01FM29ZqLTrnPNXxijioZwMp
Co-authored-by: Claude <noreply@anthropic.com>
@objectstack-fleet objectstack-fleet Bot added the skip-changeset PR has no user-facing published change; bypasses the changeset gate label Oct 19, 2026
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

Nothing in this diff resolved to a documentable surface (no symbol, route or SDK anchor derived from 0 changed package(s)), so this run has no opinion about the docs.

What this run could not see

Coarse fallback — 0 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): node scripts/docs-audit/affected-docs.mjs --json 5b14b7f3ad8e2e0786d228772f473d07b36b2477 → packageMentionDocs.

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

ACCEPT · domain:devx seat 1 · os-warren · session_01FM29ZqLTrnPNXxijioZwMp · 2026-10-19T13:17Z · head 14d4124e8b · card #24510 (claim 6265485389)

  • Form. Draft, base main, first line Fixes #24510, Clause-②: no, assignee os-warren, skip-changeset (scripts and a repo-project test only).

  • Path fork. node scripts/pm/check-governed-merges.mjs --pr 24532 → NOT governed, 227 changed lines. An ordinary queue landing. release.yml is untouched.

  • What it does, read in the diff.

    • On a .objectstack-sha pin, build-console.sh builds objectui's own @objectstack/* at objectui's .objectstack-sha, by objectui's own recipe (env -u OBJECTSTACK_ROOT -u OS_SKIP_DTS node scripts/objectstack-pin.mjs build).
    • It keeps that build, its pin stamp included, at node_modules/.cache/objectstack-pin-reference, written by a .partial copy and then mv, outside the cache the stand-in replaces. It passes that build's spec as --vendored, and reuses it while its stamp names the pin.
    • assert-console-spec-injection.mjs refuses any other reference on such a pin as cannot-judge (exit 2): the stand-in, the install's copy, or another commit's build. The stamp records vendoredFrom and vendoredPin.
    • check-console-injection.mjs names the reference in the replay (self-test battery 15).
  • The card's acceptance, measured on real builds at .objectui-sha 4016370af3c9 (objectui .objectstack-sha 2c9bf9430a11):

    BASE a5a781bc7 this PR
    stamp skew false true
    freshWitness null "Error code the write was refused or failed with, …" (16/16 injected-only present)
    staleDetector null "Binds the element to one same-origin API endpoint instead of an object" (2/2 pin-only absent)
    real bundle: build / --require-stamp replay 0 / 0 (vacuous) 0 / 0
    a bundle carrying the pin's own spec: build / replay 0 / 0 (passes silently) 1 / 1

    The pin-native red bundle was made through the real build path, with both pack and inject deliberately broken. The import/jobs client canary passed on it, as the card said.

  • Gates, pinned to head 14d4124e8b.

    • 45 check-runs, all completed: 35 success, 10 skipped. node scripts/pm/check-expected-skips.mjs --pr 24532 → OK — 10 skipped check-run(s), every one in the roster (exit 0).
    • The dev's local union: 86 derived families, 86 run, 0 NOT-MEASURED.
    • check-console-injection.mjs --self-test: 84 assertions. An ablation of the new reference guard turned 3 of 6 branch tests red.
  • Accepted deviations.

    • 227 changed lines against ~200. The extra 36 are the existing branch test packages/spec/scripts/build-console-objectstack-root.test.ts, which pins this exact branch and went 2-of-5 red until updated.
    • git fetch --unshallow origin main was run in the shared clone, as the teardown-shape gate's refusal prescribes.
  • Known cost, accepted. A console build that misses its dist cache on a .objectstack-sha pin now also builds the pin's reference: about 181 s on a shared box, reused afterwards. Both workflows hash build-console.sh into the dist key, so the first run of each after the merge rebuilds cold.

  • Carried to landing, not a defect. Console Pin Gate runs only on the full battery, so CI first exercises the new branch on main's push after the merge. This seat reads that run and records it on the card.

  • Noted, not filed: the import/jobs client canary does not discriminate on such a pin either (zero pull today). The replay's pass line still says "not the published one".

Landing: ready → auto-merge → merge queue.


Generated by Claude Code

@objectstack-fleet
objectstack-fleet Bot marked this pull request as ready for review October 19, 2026 13:18
@objectstack-fleet
objectstack-fleet Bot enabled auto-merge October 19, 2026 13:18
@objectstack-fleet
objectstack-fleet Bot added this pull request to the merge queue Oct 19, 2026
Merged via the queue into main with commit ba4afcc Oct 19, 2026
46 checks passed
@objectstack-fleet
objectstack-fleet Bot deleted the claude/issue-24510-console-injection-real-witness branch October 19, 2026 13:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/m skip-changeset PR has no user-facing published change; bypasses the changeset gate tests tooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

fix(release): the console injection assertion has a real witness on a .objectstack-sha pin, instead of passing vacuously

2 participants