Three surveyed VOCABULARY rows for the teaching-corpus claim ratchet: the (NoSQL) portability gloss, the retired $regex spelling, and #13532's section visibleWhen claims - #14604
Merged
Conversation
…aim ratchet #13582 shipped `scripts/check-corpus-claim-drift.mjs` with exactly one row and a self-test assertion pinning that, because a row is only as good as the survey of legitimate usages someone did before adding it. This is the follow-up card that pays three such surveys, one candidate at a time and none of them batched. - `exists-portability` — the `(NoSQL)` gloss. A DIFFERENT claim from key presence (portability, not presence), hence a row of its own. Survey: 8 NoSQL hits over 7 corpus files; two of them sit within 4 lines of `$exists` and BOTH are legitimate — the repaired "portable, not a NoSQL-only operator" sentence and a skills column header — so the claim is the parenthesised gloss and an unnegated "NoSQL-only" / "MongoDB-only", never the word. 0 baseline entries. - `regex-retired` — the retired `$regex` spelling. Survey: 5 hits over 3 corpus files, ALL legitimate retirement notices, so the claim is the live-operator phrasing and never the mention. 0 baseline entries. - `section-visiblewhen-unbound` — #13532's section-binding claims. Survey: 88 `visibleWhen` hits over 21 corpus files, 0 firing at any window from 4 to 40. Window 9, measured on the pre-repair tree: it is the smallest width reaching the binding-root table row, and 9..40 yield an identical ledger. 0 baseline entries. The one-row cap moves to an EXACT ENUMERATION of the shipped row ids in order, never a floor, with a discrimination leg proving a smuggled row still fails it. Every row ships its pre-repair fixtures, its repaired/legitimate green legs and a discrimination leg. The baseline file is untouched and byte-identical. Part of #13745 Co-authored-by: Claude <noreply@anthropic.com>
…rpus-claim-ratchet-rows
…eration The enumeration assertion records each shipped row's survey. The `regex-retired` line said 5 hits; the measured figure over `content/docs` + `skills` (generated `references/` excluded, as the gate excludes it) is 8 hit-lines over 3 files — `deployment/troubleshooting.mdx` 1, `protocol/objectql/query-syntax.mdx` 6, `releases/v17.mdx` 1. Every one of them is still a legitimate retirement notice and the baseline cost is still zero; only the recorded number was wrong, and a survey figure that is wrong in the record is worth exactly nothing. Part of #13745 Co-authored-by: Claude <noreply@anthropic.com>
baozhoutao
marked this pull request as ready for review
September 2, 2026 14:49
3 tasks
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 #13745
Three new
VOCABULARYrows forscripts/check-corpus-claim-drift.mjs, the shrink-only lexicalanti-drift ratchet #13582 shipped with exactly one row. Each candidate was surveyed separately
and none was batched, per the triage ruling: "⛔ 不要把三个候选行打包成一次「加三个词」".
All three ship. Zero baseline entries, zero corpus prose edited,
scripts/corpus-claim-drift-baseline.jsonbyte-identical tomain.The whole diff is one file. ⛔
ROOTSunchanged (content/docs,skills). ⛔packages/specuntouched —
filter.zod.tswas #13709's, and it is already repaired (git grep 'primarily for NoSQL' -- packages/specreturns nothing on this base; PR #14050 merged). ⛔ No.github/**, nosibling ratchet, no
content/docs/releases/**.Candidate 1 —
exists-portability: the(NoSQL)glossMeasurement handed over on #13582 / PR #13742 and ⛔ not re-derived. Re-confirmed on this base
because the card said verify, do not assume about the baseline cost.
Survey
git grep -n -i -E 'NoSQL' -- content/docs skills(generatedreferences/excluded, as the gateexcludes it) → 8 hit-lines over 7 files. (The #13588 handover recorded 9/7 at
cc837dbf; thecorpus has moved since — the scan is 224 files today, 190 + 34, against 225 = 189 + 36 then.)
getting-started/glossary.mdx:132"a Collection in NoSQL"$existsin filegetting-started/glossary.mdx:140"SQL/NoSQL queries"$existsin filekernel/contracts/index.mdx:20"Swap SQL for NoSQL"$existsin filekernel/contracts/index.mdx:35"adapter (SQL, NoSQL, API)"$existsin fileprotocol/diagram.mdx:173"SQL / NoSQL Operation"$existsin fileprotocol/objectql/index.mdx:8"across SQL, NoSQL, Graph"$existsin fileprotocol/objectql/query-syntax.mdx:526"it is portable, not a NoSQL-only operator"$existson lines 524, 525, 528skills/objectstack-query/SKILL.md:154| Operator | Purpose | SQL / NoSQL |$existson line 157, three lines away⇒ Live false claims: 0. Baseline entries: 0. Two legitimate hits are inside the window, so
they cannot be kept green structurally — they are kept green by the claim, which is why a bare
/NoSQL/member (the shape #13582's dev declined to ship) is unshippable: it reddens the repairedsentence that exists to state the truth.
The row as shipped
The claim is the restriction — a parenthesised gloss, or an unnegated "NoSQL-only" /
"MongoDB-only" — never the word. A new row rather than a member on
exists-key-presencebecause itis a different claim (portability, not presence): its own
truth, its own ledger key, its ownseparable debt.
Fixtures
Pre-repair (verbatim, the same
75b3bdc86^/e51c78f0c^text the existingWAS_*constantscarry): the table row, the
//comment inside theos:checkblock, the shipped skills row and thefilters axis row are all portability sites — and each is asserted to be one portability site
and one key-presence site, i.e. two rows, two ledger keys. The
packages/spectwin's longergloss (
(primarily for NoSQL)) is pinned too, so the row is known to reach the wording #13709repaired even though that file is outside
ROOTS.WAS_HTTPis asserted not to be aportability site — the two rows do not report the same thing.
Green legs: the repaired portability sentence, two other negation spellings, and six legitimate
NoSQL usages, the skills column header quoted with the two rows under it so
$existsreally isthree lines away (a one-line fixture would have been green for the wrong reason). Discrimination:
that same header block goes RED the instant
| Purpose |becomes| Purpose (NoSQL) |.Candidate 2 —
regex-retired: the retired$regexspelling⛔ Unmeasured before this card. Survey is this card's work.
What the retirement actually was, established first
packages/spec/src/data/filter.zod.ts:2390andpackages/spec/src/data/filter-operator-vocabulary.test.ts:114(read-only):$regexand$optionsare the two members of
RETIRED_FILTER_OPERATORS;$regexis absent fromFILTER_OPERATORSandwas never declared. Retired under #4706 / #5701 / #5702; refused everywhere with
code: INVALID_FILTER/status: 400naming the replacement —$icontainscase-insensitive,$containscase-sensitive,$startsWith/$endsWithanchored. The row'struthsays that, andonly that.
Survey
git grep -n -F '$regex' -- content/docs skills(references/excluded) → 8 hit-lines over 3files, and every one is a retirement notice:
deployment/troubleshooting.mdx:140| $regex | $icontains |under ❌ Wrong / ✅ Correctprotocol/objectql/query-syntax.mdx:352### $regex — removedprotocol/objectql/query-syntax.mdx:354"was never a declared operator and is retired"protocol/objectql/query-syntax.mdx:365-368the four rewrite-table rowsreleases/v17.mdx:3110historical note on$options: 'i'content/docs/releases/**is off-limits in a code PR⇒ Live false claims: 0. Baseline entries: 0. This row is a regression pin: there is nothing
to repair, and the difficulty is entirely that the pages teaching the retirement say the word on
every line.
The row as shipped
⭐
declaredis deliberately NOT in the operator-list member, and the survey is what removed it:query-syntax.mdx:371says "narrow the query with the declared operators" three lines under a$regexrewrite row, and:354says "was never a declared operator" on the same line as thespelling. A member carrying
declaredreddens the page that teaches the retirement. It survivesonly in the copula form (
$regexis declared), which is a claim and not a mention.Fixtures
Red:
$regexinside a**Supported operators:**list, inside a**Field Operators:**list, "Use$regexfor pattern matching", "supports$regexon every backend", "$regexis stillsupported on MongoDB". Green: the retirement page's rewrite table quoted at its real spacing
including the "declared operators" sentence, the
### $regex — removedheading, the "never adeclared operator" line, and the troubleshooting ❌/✅ table. Discrimination: that same rewrite-table
block goes RED when the one word
declaredbecomessupported.Candidate 3 —
section-visiblewhen-unbound: #13532's claims⛔ Unmeasured before this card.
Survey
git grep -n -F 'visibleWhen' -- content/docs skills(references/excluded) → 88 hit-lines over21 files — an ordinary, heavily used authoring key. The false claim #13532 retired is narrow: a
form-view section
visibleWhendoes not bindcurrent_user. The true statement is that itdoes (objectui#6110 + objectui#6111), with two qualifications the repair kept — the binding is
client-side only, and the scope belongs to the host, so it is empty on the public
/f/:slugroute.⇒ The claim ⛔ cannot be "unbound near
visibleWhen", because two live sentences say exactly thatand are true: the
/f/:slugcaveat, and the object-level field rule (Field.*({ visibleWhen }),ADR-0036) which genuinely does not bind
current_userand says so two lines from avisibleWhen.The claim is pinned on the section surface instead.
Measured over the pre-repair tree (
b2dea862c^, the state #13532 corrected) and over today'scorpus, at six widths:
⇒ Live false claims: 0. Baseline entries: 0, at every width. Window 9 is the smallest that
reaches the binding-root table row — it sits nine lines below the nearest
visibleWhen(
layout-dsl.mdx:874vs:865), so at width 4 the clearest false statement on the page isinvisible — and 9…40 yield an identical ledger, so 9 sits at the bottom of a wide plateau at zero
cost. The number is a decision with evidence, exactly as row 1's 4 was.
Honest limit, stated rather than papered over
(
layout-dsl.mdx:882-884, "an authored section predicate is read by that second renderer alone,because the object-view chain drops the key before any evaluator sees it") spreads its falsity
across three wrapped lines, and claims are matched per line. The only per-line member that would
catch it is the literal
drops the key, which is a one-off phrase ban rather than a claim. Left outdeliberately.
Fixtures
Red, read verbatim out of git at
b2dea862c^at the real line spacing: theos:checkcomment("on a FormSection,
current_useris not"), the binding-root table row (asserted a site at window9 and not at window 8 — the boundary, on the row's own number), the "two limits" prose, and the
views.mdxfield-table row. Green: all four repaired texts, plus ⭐ the object-level field rule thatlegitimately does not bind
current_user, ⭐ the true "unbound" caveat about/f/:slug, and anordinary authored predicate of the shape the other 88 hits have.
The one-row cap moved to an EXACT ENUMERATION
VOCABULARY.length === 1 && VOCABULARY[0].id === 'exists-key-presence'becomeswith
SHIPPED_ROW_IDSnaming the four ids in order. ⛔ Never>= 1, ⛔ never "at most N": afloor lets a row be smuggled in with no survey, which is the one thing the assertion is for. The
assertion keeps its teaching text (why a word is a card, not an edit) and now names each shipped
row, its card and the survey it paid. A second leg proves the comparison discriminates — a
smuggled row fails it — so the assertion cannot pass on a predicate that approves everything.
Ablations — four legs, all red
Implementation committed first. Each leg mutated the committed file, proved on disk that the
anchor count moved and the marker appeared (never an exit code), ran, restored via
git checkout HEAD -- ABSOLUTE_PATHunder atrap … EXIT INT TERM, and re-proved byte identityagainst the HEAD blob. No build/
distis involved — the gate runs from source — so no rebuild legapplies.
VOCABULARYrow with no surveyEXIT 1, 7 named failures, the enumeration failure named firstEXIT 1, 11 named failures — every legitimate-usage leg fires, plus the new window-9 boundary leg ⇒ the phrase alone is a noise gateMath.abs(t - i) <= window→t === iEXIT 1, 10 named failures, including bothos:check-comment legs and all three new discrimination legsVOCABULARY.length >= 1, plus a smuggled rowEXIT 1, 6 named failures — ⭐ and the enumeration failure is absent from them. The smuggled row is caught only as collateral damage on six unrelated fixtures. That is precisely why the cap must be an enumeration: the floor form still reds, but it never tells the author "you added a row without a survey"Restore proven on every leg:
blob d453fef6b44b9364c54c373756739404ebb1f8e9 == HEAD blob,git diff HEADempty.Gates
Union derived in this worktree with
node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack— 16 families (14 bypath + 2 by change kind), harvested with
--commandsso neither spelling nor section can bedropped. Re-run in full at the final commit
4272212; exit codes captured by redirect beforeany pipe, never from one.
All 16 measured at
4272212: 15 RAN-PASS, 1 NOT MEASURED.pnpm check:corpus-claim-driftat4272212:exists-key-presence 4andLedger: 2are the pre-existing 2-file / 4-site figures, unchanged; thethree new rows report 0 each, which the gate publishes per row rather than hiding in a total.
Also green:
check:ratchet-remedy-authority("184 scripts swept … 12 mark the expanding remedy ⛔MAINTAINER-ONLY"),
check:watch-hint-literal("45 declaration(s) across 4 rostered name(s) … nounrostered spelling"),
scripts/pm/bare-root-worklist.mjs --self-test("57 live row(s) … nonestale, none missing, none contradicted"),
check:entry-guard,check:parse-guard,check:agent-test-spelling,check:bash32-floor,check:cli-command-ids,check:cross-package-test-inputs,check:pnpm-filter-targets,check-ci-filter-parity,check-cross-package-test-inputs,check-shard-attestation.NOT MEASURED (1, declared, ⛔ not a red):
node scripts/check-test-completeness.mjsexits 3— the script's own text says nothing was swept and that it is not a finding.
pnpm check:pm-dispatch-gates(the heavy convention-triggered family) was re-run to completion atthe final head after this PR was opened:
EXIT=0, "✓ dispatch-gates self-test: 1240 cases pass."Changeset: none —
scripts/**-only, nothing published.skip-changesetapplied.One thing this PR deliberately does NOT fix
.github/workflows/lint.yml, above thecheck:corpus-claim-driftstep, still reads "carrying the$existsfamily ONLY — each further word (the retired$regexspelling, #13532'svisibleWhenclaims) pays its own baseline on its own card." Every clause of that becomes false when this merges.
⛔
.github/**is off this card's file surface by dispatch (lint.ymlis a hot conflict file).Filed as #14601 with the correcting wording and a note that it must land after this PR, not
before.
🤖 Generated with Claude Code
https://claude.ai/code/session_01WLJQhde67SeTccsmnBVarV
Generated by Claude Code