Skip to content

docs(spec): scope the text-operator door's formula prose to the judgement it states - #17711

Merged
os-bill merged 1 commit into
mainfrom
claude/issue-17400-filter-text-operator-declared-type-claim
Sep 12, 2026
Merged

docs(spec): scope the text-operator door's formula prose to the judgement it states#17711
os-bill merged 1 commit into
mainfrom
claude/issue-17400-filter-text-operator-declared-type-claim

Conversation

@os-bill

@os-bill os-bill commented Sep 11, 2026

Copy link
Copy Markdown
Collaborator

Part of #17400

Prose only. The verdict function, its sets, the class table, the probe object and every case are byte-identical; no logic, no accept set, no behaviour moves.

  • Clause-②: no

The fork this card set, and which branch the measurement supports

The card offered two: (a) the prose is wrong, or (b) the implementation drifted. Measured here: (a).

textOperatorDoorVerdict does exactly what the prose says about it — the spec-table-says column below is the function's own answer for all five formula shapes, and it matches the ruling. What is false-as-written is the prose's claim about where that judgement takes effect: the module frames itself throughout as the door "at the engine's field-aware seam", and at that seam a formula filter never arrives.

My own contradicting measurement

A probe driving the real engine (ObjectQL + a recording driver + this module's own probe object), $contains over each field:

key type returnType spec table says engine seam does code status
f_formula_number formula number door-refusal refused INVALID_FIELD 400
f_formula_text formula text passes refused INVALID_FIELD 400
f_formula_boolean formula boolean door-refusal refused INVALID_FIELD 400
f_formula_date formula date door-refusal refused INVALID_FIELD 400
f_formula_untyped formula deferred refused INVALID_FIELD 400
f_number number door-refusal refused INVALID_FILTER 400
f_boolean boolean door-refusal refused INVALID_FILTER 400
f_date date door-refusal refused INVALID_FILTER 400
f_text text passes reached driver
f_select select passes reached driver

The five formula rows carry three different declared verdicts and the seam answers all five identically, with a different code from this door's own — so returnType is never the deciding fact, and none of the three verdicts is observable.

Lit control (the bottom five rows). The same probe reproduces the table exactly where the assertion does hold: number / boolean / date refused with this door's INVALID_FILTER 400, text / select through to the driver. A probe that called everything a contradiction would prove nothing; this one discriminates.

The probe was temporary and is not in the diff.

Why not (b)

Nothing shows the code drifted. The earlier refusal is deliberate and recorded: assertFilterIsMaterializable refuses every formula filter because no driver materialises a column for one, packages/spec/src/migrations/registry.ts carries it as the engine-find-formula-filter-refused entry with a migration remedy, and filter-dotted-head.ts says the same of formula heads. Reordering the ladder would answer one condition with two wire codes chosen by returnType — the card's option 3, explicitly a maintainer's decision. Nothing here touches it.

Census — the card reported 1 site, there are 7

# site file
1 the Deferred bullet in the module header filter-text-operator-declared-type.ts
2 the sentence the card quotes same
3 the "How the engine suite consumes" prescription, incl. "a refusal can only be this door's" same
4 TextOperatorDoorVerdict's deferred doc same
5 the class table's formula row note same
6 the deferred formula case note same
7 the barrel comment packages/spec/src/data/index.ts

Site 3 uses neither the word "formula" nor "seam" — a word-level grep misses it. It prescribes that every case is either a refusal by this door or a driver read; for the formula rows neither holds, which is why the engine suite already partitions them out.

Lit controls for the census. A fabricated phrase scored 0 while a known-present symbol scored 35. Text that mentions formula and the doors and is correct was not flagged: packages/objectql/src/text-operator-declared-type-door.ts (documents this divergence deliberately), migrations/registry.ts, filter-dotted-head.ts, field-value.zod.ts, filter-text-conformance.ts.

Deliberately not rewritten: the maintainer's verbatim ruling quote in the header blockquote. Rewriting a quoted ruling rewrites the ruling. 0 blockquote lines appear in the diff.

Verification

  • pnpm --filter @objectstack/spec test — 473 files, 13432 tests, all pass
  • pnpm --filter @objectstack/spec typecheck — clean
  • the named consumer, engine-text-operator-declared-type-door.test.ts — 22 tests pass
  • 71 derived gate commands run; 69 exit 0. The two non-zero are check:dual-build-cjs-loads and check:lean-entry-closure, both exit 3 PREREQUISITE NOT MET, which those scripts define as NOT MEASURED — they need a full-repo build.
  • eslint . --no-inline-config over the whole repo: 6635 files, 0 errors
  • check:nul-bytes exit 0

Changeset

Required, and measured rather than assumed. The rule is that a changeset may be skipped only when nothing published moves, where published means what the package's files[] actually ships. @objectstack/spec is not private and its files[] includes dist. After a rebuild, the new note text appears 8 times under dist/ and the new doc prose 2 times (in the .d.ts consumers read), against a positive control of 4 and a fabricated control of 0. Published bytes move, so: patch.

🤖 Generated with Claude Code

https://claude.ai/code/session_01MkQhmuuJAVDjmeWNixwDDH


Generated by Claude Code

…ment it states

The module asserted that a `formula` with a readable `returnType` is judged as
the field type its return type names. Measured at the door's only consumer, the
engine's field-aware seam, no formula filter ever arrives: the earlier
materializability door refuses every one of them with `INVALID_FIELD` 400,
whatever the `returnType`, so none of the three formula verdicts is observable
there. The non-formula rows are observed with this door's own `INVALID_FILTER`
400, which is what makes the formula rows the exception.

Prose only. The verdict function, its sets, the class table, the probe object
and every case are byte-identical; seven sites across two files now say the
formula rows are a contract answer no consumer currently reaches, and why they
are kept rather than retired. The maintainer's verbatim ruling quote is
untouched.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MkQhmuuJAVDjmeWNixwDDH
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

1 anchor(s) derived from 1 changed package(s); no hand-written page names any of them. ⚠️ 1 changed file(s) yielded no anchor (packages/spec/src/data/index.ts), so the pages documenting them are NOT COVERED by this run — this is not a clean bill of health for those files.

What this run could not see
  • 1 changed file(s) yielded no anchor (packages/spec/src/data/index.ts) — pages documenting those are invisible to this run
  • 1 name(s) were too generic to anchor anything (single lowercase words)
  • the SDK route bridge reached 60 of 215 client-bound route-ledger rows — the other 155 have no registrar path: tail to select them, so pages documenting THEIR client methods cannot appear above, on this or any run. Of those 155: 0 are remediable by widening that discovery convention (an in-repo file declares the path; the convention did not scan it); 55 are structural — on a ledger where NOT ONE row is declared in-repo, so no discovery change reaches them at any price; 100 are undecided (no in-repo declaration, on a ledger that has other in-repo registrars — absence and an unreadable spelling are not distinguishable here). The rows themselves: node scripts/docs-audit/affected-docs.mjs --bridge-coverage
  • a page that states a rule by its inputs shares no identifier with the emitter that implements the rule, so an emitter-only diff cannot list it — not on this run and not on any run. Measured on fix(driver-sql): emit varchar(maxLength) for a text field a declared index keys on #11430: content/docs/protocol/objectql/types.mdx documents the text-family column mapping by the ObjectQL type names it maps FROM (text / textarea / html) while the diff changed createColumn; it went unlisted, and it was the page that diff falsified, in four places. No shared token exists to detect this on, so a rule your change carries has to be re-read by hand in the pages that restate it.

Coarse fallback — 135 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 7173d7d142896fe549de8a1779414954e9f83f63packageMentionDocs.

Which tree this was computed on

This run read content/docs from b7ec52f2a2fdf235eafc598749330d08b2f9217e — the merge of head 243b2f9fea3c1c39d58f1ddef45672931739b3fe into base 7173d7d142896fe549de8a1779414954e9f83f63, which is what actions/checkout gives a pull_request run. Not the PR head.

A worktree cut from an older main holds a different content/docs, so re-deriving there can legitimately return a different list — that is a different tree, not a wrong row. To answer on the same tree:

# while this PR is open — GitHub drops the merge commit once it closes
git fetch origin b7ec52f2a2fdf235eafc598749330d08b2f9217e && git checkout b7ec52f2a2fdf235eafc598749330d08b2f9217e
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin 7173d7d142896fe549de8a1779414954e9f83f63 243b2f9fea3c1c39d58f1ddef45672931739b3fe && git checkout -B drift-repro 7173d7d142896fe549de8a1779414954e9f83f63 && git merge --no-ff 243b2f9fea3c1c39d58f1ddef45672931739b3fe

node scripts/docs-audit/affected-docs.mjs --json 7173d7d142896fe549de8a1779414954e9f83f63

⚠️ That checkout carried uncommitted changes, so the commit above does not fully identify what was read.

os-bill commented Sep 12, 2026

Copy link
Copy Markdown
Collaborator Author

Landing is blocked on the ready flip only — all four pre-checks pass on this head

Read at 2026-09-12T00:36Z by the domain:spec execution seat, on head 243b2f9f. ⛔ Nothing about this PR is red; the blocker is the transport for one action.

The four pre-checks, measured on THIS head (not recalled)

# check reading
at-tier verdict not owed — clause ② does not fire (Clause-②: no)
check-clause2-carriers --pair 17711 exit 0 — declaration readable in the fixed spelling, both carriers agree, no widening tell
check-governed-merges --test over the FINAL 3-path diff 0 of 3 hit the register ⇒ ordinary queue landing. Lit control: the same script on AGENTS.md returns 1 of 1, exit 3 ⇒ the instrument could have come back the other way
checks on 243b2f9f, newest-run-per-check-NAME 34 names, 31 success, 3 skipped (Build Docs, Console Pin Gate, Packed-tarball smoke (opt-in)) — conditional jobs that did not apply. 0 failures, 0 pending. mergeable_state: clean

What is actually blocking

The draft→ready flip has two carriers and both answer, separately, that they cannot serve it right now:

  • POST /repos/objectstack-ai/objectstack/pulls/17711/ccr/ready_for_reviewHTTP 503, body {"message":"GitHub is temporarily unavailable. Retry shortly."} — four attempts, 2026-09-12T00:1xZ through 00:35Z. Read back after each: draft is still true, so ⛔ nothing partially landed.
  • the MCP update_pull_request path (draft: false) ⇒ rate limit already exceeded for user ID 324100929. ⚠️ That is a quota answer, not a capability refusal — a different instrument failing for a different reason, which is why it is recorded rather than read as confirmation of the first.

The guard held. Each step of the landing script is gated on its own result: the flip must return 200 and read back draft=false before anything else runs. Because step ① never returned 200, ⛔ no ④ re-read, ⛔ no auto_merge arm, ⛔ no enqueue was attempted. Earlier today this seat armed auto-merge while a gate was still pending because a poll loop broke on a count instead of a judgement; that is the defect this shape exists to prevent.

What happens next

⛔ Not standing down, and ⛔ not re-running anything that already passed as a way of looking busy. This PR stays watched with a check-in armed; the flip is retried on each wake until it returns 200, at which point ④ is re-read (the ready flip re-triggers Check Changeset, so a reading taken before the flip is stale) and only then is auto-merge armed.

domain:spec execution seat · session_01MkQhmuuJAVDjmeWNixwDDH · readings taken 2026-09-12T00:36Z


Generated by Claude Code

@os-bill
os-bill marked this pull request as ready for review September 12, 2026 01:24
@os-bill
os-bill added this pull request to the merge queue Sep 12, 2026
Merged via the queue into main with commit d414e2b Sep 12, 2026
36 checks passed
@os-bill
os-bill deleted the claude/issue-17400-filter-text-operator-declared-type-claim branch September 12, 2026 01:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation protocol:data size/s tooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants