test(cli): repoint the #5341 union specimen at a door that is still a union - #18043
Merged
Merged
Conversation
… union
`views[].list.sort` stopped being a `z.union` when the bare-string arm was
retired: a two-arm union minus one arm is the surviving arm, so the door now
emits that arm's own issues directly — `invalid_value` at
`views.0.list.sort.0.order` plus `unrecognized_keys` at `views.0.list.sort.0` —
and neither is `invalid_union`. The three assertions built on that specimen were
pinning a shape the spec no longer produces: deterministically red on `main`, on
every tree, in both `pull_request` and `merge_group` events.
The specimen moves to `views[].list.gantt.tooltipFields[]`, which is the same
two-arm shape the retired one had — `z.union([z.string(), <strict { field,
label } entry>])` — and whose entry declares the aliases `name` -> `field` /
`fieldName` -> `field` / `text` -> `label` / `title` -> `label`. Like
`direction` -> `order` before it, that is a prescription edit distance cannot
reach, on a key whose misspelling is otherwise dropped silently.
Deliberately NOT done: retuning the assertions to the post-retirement two-issue
shape. That spelling is green and guards nothing — the guarantee this file holds
is that a rejection BEHIND A UNION reaches the terminal, and a specimen that no
longer fails as a union cannot exercise it. The first assertion now carries a
failure message that says so and prints the issues the bare count discards, so
the next retirement is answered with a repoint rather than a retune.
Co-authored-by: Claude <noreply@anthropic.com>
Contributor
📓 Docs Drift CheckNothing 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): |
hotlong
marked this pull request as ready for review
September 13, 2026 14:38
This was referenced Sep 13, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #18032
Clause-②: no
The diff is exactly one path —
packages/cli/test/format-zod-union.test.ts(
git diff origin/main...claude/issue-18032-stale-union-assertion --name-only). Nopackages/spec/src/**hit, so no
needs:contract-reviewhold. No governed surface either (today's register:docs/adr/**·.claude/**·skills/**·AGENTS.md·CLAUDE.md).What was red, and why it is not a flake
test/format-zod-union.test.tshas been ejecting PRs from the merge queue and reddening ordinarypull_requestbuilds. It is a deterministic SEMANTIC failure, reproduced here on a dedicated worktree cutfrom
origin/mainat0252320ae, with zero PR content in the tree:Printed rather than inferred — the two issues the specimen really produces:
Root cause, confirmed at the source rather than by attribution:
ListViewSchema.sortinpackages/spec/src/ui/view.zod.tsis now a barez.array(strictObject(...)). #17053 / PR #17914 retired thebare-string arm, and a two-arm union minus one arm is the surviving arm — so that door cannot emit
invalid_unionat all any more, and the[#5341]test name's premise died with it. Shard composition,worker count and queue stacking are all non-load-bearing: they were correlations read off a deterministic red
through a narrowing filter.
The route taken — and why NOT the cheap one
⛔ Not retuning the assertions to the post-retirement two-issue shape. That spelling is green and guards
nothing. The guarantee this file holds is that a rejection behind a union reaches the terminal; a specimen
that no longer fails as a union cannot exercise it, and #5341's guarantee would go unwatched — exactly what it
was built to prevent.
⭐ The specimen is repointed at a door that is still a union, with the same anatomy the retired one had:
views[].list.sortviews[].list.gantt.tooltipFields[]direction->ordername->field(alsofieldName->field,text->label,title->label)invalid_unioninvalid_union(measured)The asymmetry that makes the test meaningful is preserved too: the string arm complains once (wrong kind of
value, no prescription) while the aimed-at arm complains twice (missing
fieldplus the aliased key), so thebranch-selection logic is genuinely exercised rather than short-circuited.
The first assertion now carries a failure message that prints the issues the bare count discards and names
the remedy — repoint, do not retune — so the next arm retirement is answered correctly by whoever is standing
there, without re-deriving any of this.
Ablation — the new specimen is not a vacuous green
Committed first, then mutated, then restored. The mutation deletes the mechanism #5341 added: the
'invalid_union'member ofEXPANDABLE_ISSUE_CODESinpackages/cli/src/utils/format.ts.Tests 13 passed (13), exit 0git diff HEAD --name-only0 -> 1 lineTests 6 failed | 7 passed (13), exit 1git hash-objectequals theHEADblob (e3dda5c85…);git diff HEAD --name-onlyback to 0The decisive line under mutation is the new live-specimen terminal assertion:
AssertionError: expected '\n◆ Validate\n…' to contain '+ "name->field" +'. No rebuild leg is owed:packages/cli/bin/run-dev.jsruns the CLI fromsrc/through tsx, so the mutation reached the spawned childdirectly, with no
dist/in the resolution path.Direction declared before the run, and observed: turns red (the ordinary direction). Two assertions stayed
green under mutation on purpose — the schema-level one and the
--jsonone measure the payload, not theterminal, which is the division of labour the file documents.
Gates
Declared narrowing — verification ran UNLOCKED.
scripts/pm/os-verify-lock.shcould not take the sharedverify lock on this host: no usable
flock. The shared verify lock is declared Linux-only (flockisutil-linux, and a stock macOS does not ship it), so the commands below were run directly, without the lock —
a declared narrowing, not a silent one. No serialization guarantee held for these runs, nor for any sibling
agent in this container while they ran.
pnpm --filter @objectstack/cli exec vitest run test/format-zod-union.test.tspnpm --filter @objectstack/cli buildpnpm --filter @objectstack/cli typecheckcheck:test-typecheck: OK)pnpm --filter @objectstack/cli test(both tiers)253 files · 3387 tests;format-zod-union.test.tsPASSES; 4 unrelated files red for a host reason — see belowscripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstackpnpm check:dual-build-cjs-loadsPREREQUISITE NOT MET — this gate reads built output, and some package has no dist/; it needs a whole-repopnpm buildand reads only packages this diff does not touch. CI builds, so CI measures it.The 4 unrelated red files are a darwin artifact, not a finding of this branch. All of them assert on
tmpdir()paths and compare/var/...against the/private/var/...the OS resolves to, or read adarwin+node-26
chalkESM warning:published-subpath-console.pin.test.ts,published-subpath-hook-body.pin.test.ts,published-entry-node-env-source-reroute.test.ts,serve-runtime-state-project-key.test.ts. This diff touches none of them and none of them imports the file ittouches, so by construction they are not this branch's — they are green on CI's Linux runners.
Changeset
skip-changeset, measured rather than assumed.packages/cli's manifest publishes["dist","README.md", "CHANGELOG.md"]; afterpnpm --filter @objectstack/cli build, the symbol this diff introduces(
TOOLTIP_ALIAS_STACK) has 0 hits across those paths, while the positive controlformatZodErrorshas6. Nothing published moves.
Acceptance notes
(
/varvs/private/var), reachable by anyone running this package's suite on macOS. Taker: nobody inflight — CI is Linux and never sees it. Out of this card's scope, and ⛔ not weakened or skipped here.
both directions
os validate/os build用的是 CLI 自己的 formatZodErrors,它同样把 union 分支的处方裁掉 —— #4971 修的不是这条路径 #5341 pinned.Generated by Claude Code