test(components): re-express the two element:* spec-parity contrast probes pin-aware for GA's strict flip (#4910) - #4920
Merged
Conversation
… pin-aware (#4910) @objectstack/spec 17.0.0 GA flipped the element:* props schemas from strip mode to strict (objectstack#4001 batch A). Both probes asserted the strip-mode half as their control; they now probe the installed spec's refusal mode behaviourally and assert the same verdict under either mode. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DbRmJD3iPhXjKr6vhd4Qkv
Contributor
✅ Console Performance Budget
📦 Bundle Size Report
Size Limits
|
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.
Fixes #4910
Implements the adjudicated option A — assert the rejection, expressed PIN-AWARE. Both
probes now read the installed spec's refusal mode behaviourally and assert the same
verdict under either mode, never branching off a version string. Option B (dropping the
probe) is not taken. This inherits the disposition the maintainer accepted on #4648's open
question 2, landed as PR #4671's adapted plugin-detail gates.
The premise, re-verified on this branch
Both halves of the card reproduce exactly.
And the two named assertions are the only things that were red, at exactly the two lines
the card names —
record-picker…:101andtext-input…:83:What each probe became
The contrast probe parses a payload carrying a key no spec declares, then branches on a
module-level behavioural reading:
unrecognized_keysamongthe issue codes, and the refused
keysnamingnotASpecKey. A bare "it failed" isdeliberately not enough — it would be satisfied just as well by a rejection of the
declared key, which is the half that has to stay valid, so the arm also asserts
defaultValue/filter/objectare not among the refused keys.dataon a green parse: thesilent drop the comments currently pin, kept verbatim as behaviour.
Two changes beyond a straight port, both load-bearing:
{ defaultValue: 'acme', notASpecKey: 1 },{ ...withFilter({status:'open'}), notASpecKey: 1 }) ratherthan alone. That is what makes either arm attributable to
notASpecKeyinstead of tothe declared key having gone bad — and the green parse asserted immediately above is
what proves the base fixture is valid.
the falsified strip-mode premise, as the card requires. The header comment on each
probe records why it is behavioural rather than version-sniffed, and cites the sibling
recordHighlightsInputs.spec-parity.test.tsthat took this shape first.Neither arm is vacuous, and neither reads a pin it does not observe.
Ruled widening scan
The strict flip is schema-wide, so the scan was run in two halves — static across
spellings, then empirically under the GA overlay, which is the half that cannot miss a
spelling nobody thought of.
Static. Four spellings over
packages apps examples scripts:The last one is the high-signal spelling: a payload carrying a key the props type does not
declare needs a type escape to be written at all. Its only hits repo-wide are the two
files this PR changes — which doubles as the positive control that the scan reaches them.
The one other identifier hit,
clientValidation.optOuts.test.ts'snotAKeyAnySchemaDeclares, is already an assert-the-refusal probe (bogus.okis assertedfalse) on a metadata schema, not a strip-mode premise.Empirical. Every test file importing
@objectstack/spec— 220 files — run underthe GA overlay. Before this branch:
At this branch's HEAD:
Hit list for this card: exactly the two named files. No third file needed adapting.
The remaining failure is a different GA change — GA's
FieldOperatorsSchemaadds$like/$ilike, which the builder cannot author (expected [ '$like', '$ilike' ] to deeply equal []). Not the strip flip, no undeclared-key parse involved. It is already filed as#4911, which is not addressed here and remains open.
Verification — both pins, at
846ec5dd8(working tree clean)GA readings use PR #4660's npm-pack overlay, re-derived:
npm pack @objectstack/spec@17.0.0unpacked over the pnpm store directory every one of the 34@objectstack/specsymlinks already resolves to, so all 34 arm at once and none isrepointed or restored wrongly. That placement is also the peer-link repair PR #4901's
report records:
aiandzodlive one level up inside the same store entry, so they aremirrored by construction rather than by hand. rc.6 restored afterwards, and the installed
version plus the raw refusal mode were printed before every run.
@object-ui/componentsfull suite@objectstack/spec-importing test (220 files)type-check—@object-ui/componentseslint --quiet, 2 changed filescheck:control-bytescheck-changeset-presence/-fixed/-no-majorcheck:self-importThe dependency closure was built first (
pnpm --workspace-concurrency=2 --filter '@object-ui/components^...' build) before either type-check.Reverse verification — direction predicted first, one ablation per arm
Predicted before running, and the point of using two: each ablation must redden on
exactly one pin, which is what proves each arm actually judges under its own pin and is
genuinely dormant under the other. Run from the committed state.
Ablation A — break only the strict arm (
refusedmust contain a key that is notthere), in
text-input. Predicted GA red, rc.6 green.Ablation B — break only the strip arm (the surviving
filtervalue), inrecord-picker. Predicted rc.6 red, GA green.Observed, exactly and symmetrically:
So: the strict arm judges under GA and the strip arm judges under rc.6, each dormant on
the other pin. Ablation A's message is also the direct positive control that the strict
arm truly receives the named key — the refused set really is
[ 'notASpecKey' ].Both restored with
git checkoutfrom the branch;git statusclean, i.e.byte-identical, and re-run green on both pins.
Changeset
An empty-frontmatter changeset — the repo's tests-only exemption, per precedent PRs
#4641 / #4666 / #4671. No runtime source, no registration and no gate was touched; only the
two test files. The gate confirms it rather than my reading of it:
No
skip-changesetlabel is applied or created — that label does not exist in this repo(#4912).
Scope
Three files: the two parity tests and the changeset. No production code, no gate weakening,
no
content/docs/releases/. In-flight siblings untouched.One finding filed unassigned rather than fixed here: #4918 — two
plugin-detailparity tests still narrate rc.6 strip mode as present-tense fact in prose only. No
assertion depends on it, so both files are green under the GA overlay and no gate can catch
it; it falls outside this card's claimed surface, which is bounded to tests that assert a
green
safeParsewith an undeclared key.Generated by Claude Code