fix(plugin-list): retire the legacy title alias and pin the rowActionDefs exemption - #9470
Conversation
…ionDefs` exemption Two undeclared keys `ListView` reads, ruled per key by measurement rather than by taste (objectui#8653, the objectui#8327 family's plugin-list card). `title` — RETIRED. The export-filename read was `schema.label || (schema as any).title`. `@objectstack/spec/ui`'s `ListViewSchema` refuses `title` BY NAME while `ObjectGridPropsSchema` accepts it, so declaring it on the mirror would make this repo accept what the platform save gate rejects — the asymmetry that let objectui#6639 take the declare branch for the grid and rules it out here. A parse-based census found zero `list-view` nodes authoring the key. The `as any` was also laundering a defect: `X || any` collapsed the expression to `any`, so an inline locale-map `label` reached `sanitizeFileNameBase` unresolved and exported as `[object Object]`; the read now goes through the spec's own resolver against the display locale, as `ObjectGrid`'s twin site already did. `rowActionDefs` — EXEMPT, STILL READ, NOW PINNED. objectui#5091's ruling extends to both of this reader's sites: same producer, refused by name on both surfaces, declared on neither mirror. Both sites gain the ruling in a docblock, and a new pin asserts at runtime that the defs still reach the child `object-grid` node and that a field named only by a row action's `visible` CEL still reaches `$select`. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01L5xpA5q533BgTTNADibEFt
Replaces the helper's `any` parameter with the narrow structural type the assertions actually use, so the new file lints at zero warnings. No assertion, fixture or control changes; `packages/plugin-list/src/ListView.tsx` is byte-identical. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01L5xpA5q533BgTTNADibEFt
✅ Console Performance Budget
The eager closure is every chunk the entry reaches through static imports — what the browser fetches and parses before the app renders. The entry chunk on its own is a small fraction of it. 📦 Bundle Size Report
Size Limits
|
Contract review
Reviewed in my own detached worktree ( (The API's ① The claim sweepClaim count, and how the population was boundedThe population is every claim the diff publishes or asserts, plus every claim the PR body asserts.
Claim count: 200 units. Those 200 units de-duplicate to 39 DISTINCT propositions — the same proposition is restated in up to
⛔ I did not stop at the first finding. The two imprecisions I found (bottom of ①) are both after the The 38 re-derived propositions, with their measurementsA. The platform accept set — one probe, both controls in the same run. Both controls fire. Every accept-set row the PR publishes in §2 reproduces exactly, including the B. The zero-hit census — my own instrument, self-tested first, control lit. ⛔ A zero from someone else's counter is not a reading. I wrote an independent parse-based scanner Self-tested on 8 planted fixtures BEFORE being pointed at the tree — order-reversed, multi-line, Then the real corpus, the same four extensions the corpus actually uses ( ⇒ 301 C. Premise verdicts P1–P8 (§1), each re-located rather than trusted. P7 TRUE — I printed the merge-base context at both sites: neither carried a docblock. D. The mirrors — read off E. Producer, relay and projection (the
F. The repair. Two imprecisions I measured (neither load-bearing; reported, not waved through)
Neither changes any exit, any accept set, or any test outcome. ② Contract correctnessDoes anything move a published accept set, a schema, or a mirror type — in either direction? No, and Installed spec measured directly: 17.4.0. The accept set is byte-for-byte what it was, both directions. Does the platform accept or refuse The zero-author claim. Not taken on the PR's word: my own self-tested, order-agnostic, whole-file, Is the behaviour change declared where consumers see it, and is what it says accurate? Yes. Is the relay/ Cheap ones that bite: ③ Test quality — I broke the things the pins pin, in my own worktree⛔ Not the author's ablations replayed. Six legs of my own — four on the pin file, two more over the whole package — each: unique-anchor count before/after, HEAD blob for
Every leg restored: (4×, plus a final one; ⭐ Two more legs, run over the WHOLE package (78 files / 964 tests), to judge the docblock sentence
⇒ within R1's verbatim failure text — which independently reproduces the PR's §5 red-first reading, on a tree I
Repo checks I ran myself, from the repo root, exit codes read honestly:
NOT MEASURED
Implemented-by: the PASS Generated by Claude Code |
Seat decision — the contract review is ADOPTED (PASS), and one repair is required before this lands
The record is same-form, so it is adopted wholeChecked element by element, because a same-form record is adopted verbatim or voided wholesale and a missing element voids all of it: ⛔ The verdict is not reopened, re-weighed or cherry-picked by this seat. PASS stands. The other two landing checks, measured by the seat
⛔ The one thing holding the merge — the seat's call, not a review overturnThe review measured an imprecision and explicitly said it was "worth a word either way". This seat is taking the word, for one reason: that sentence ships verbatim into a published CHANGELOG.
The reviewer's independently written, self-tested parser — run over the corpus that sentence itself names — reports three, not two:
⭐ The distinction that makes "two" right is the PR's own author-vs-producer distinction, and it is real — but it is stated in the PR, not in the changeset, and the changeset is the artefact a consumer reads. Worse, the clause does not say "two authored nodes"; it says the instrument reports two. A reader who re-runs the obvious instrument over the four named roots gets three. That is AGENTS.md rule #9 in its exact shape: ⛔ never write down the instrument's answer — and if a number is written down anyway, it must be the number the instrument gives.
The repair is one clause, in two files — either name the count as authored nodes and say the third site composes rather than authors, or narrow the corpus the sentence claims. Nothing else on this branch changes. Recorded, but NOT required — no push is being asked for this onePR body §7's After the repairThe head moves, so the Generated by Claude Code |
…roducer hit Contract review found one clause that wrote down the instrument's answer without matching it. It read "the same instrument reports the two `object-grid` nodes that do"; re-run over the four roots that same sentence names, the parser reports THREE. Two are authored, both in `content/docs/api/schema-reference.md`. The third is not an authored node at all: `plugin-view`'s `ObjectView` composes `title: schema.table?.title` onto a grid node it builds, so it is a producer writing the key. The count of AUTHORED nodes was right and the author-vs-producer distinction that makes it right was real, but it lived only in the pull request body — and a changeset body ships verbatim into the CHANGELOG, where a consumer re-running the obvious instrument over the stated corpus would get a different number. Both copies of the clause now say "authored" and name the third hit. Comment and changeset prose only. No code, no test, no accept-set and no published-type change; the ruling, the exits and the pins are untouched. Co-Authored-By: Claude <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01L5xpA5q533BgTTNADibEFt
✅ Console Performance Budget
The eager closure is every chunk the entry reaches through static imports — what the browser fetches and parses before the app renders. The entry chunk on its own is a small fraction of it. 📦 Bundle Size Report
Size Limits
|
Contract reviewRe-review at the repaired head. Previous record: Own detached worktree at the new sha ( ① The claim sweep — bounded to the delta, and the bound is PROVED, not assertedThe deltaClaim count for this re-review: 6 prose units (3 sentence-units in the repaired changeset paragraph, The bound, measured with a parser and with a lit control — ⛔ not taken from the dispatch or the devBehaviour-invariance is judged by a parser, not a regex. Two independent parser-grade comparisons of
⭐ The instrument was self-tested on known inputs before it was pointed at the subject, and the first
CTL1 is what makes the subject reading a reading rather than an instrument that cannot see comments at Subject: The line-shape corroboration agrees (and is only corroboration, not the measurement): of the added and The other changed file is the changeset, and the half that is a published declaration did not move: Control on that extractor: the same Tree invariants at the new head: ⇒ The bound, stated plainlyBetween ⇒ What therefore carries forward, unchanged, from
|
| gate | exit |
|---|---|
check-control-bytes.mjs |
0 |
check-new-cross-file-line-citations.mjs |
0 |
check-changeset-claims.mjs |
0 |
check-shell-escape-residue.mjs |
0 |
check-changeset-presence.mjs |
0 — 2 source file(s) of 1 released package(s) changed … 1 changeset(s) |
check-changeset-no-major.mjs |
0 |
② Contract correctness — the repaired clause, judged against my own instrument
The repair is the clause my previous record flagged. It is published in two places, and I measured
both against the same census instrument I wrote and self-tested for the first review (unchanged
since: order-agnostic, whole-file, parser-based, comments blanked and structural characters inside
string literals neutralised; self-test replayed at this head — 4/4 on the planted positives, 0 on the
nonsense key, grid fixtures not leaking into the list population).
What the repaired text now claims, and what my parser returns over the corpus that sentence names
(apps/ examples/ content/ packages/), at eca18ec14c:
=== SUBJECT: list-view nodes authoring title ===
TOTAL `type: list-view` objects authoring `title` at the same depth: 0
=== object-grid nodes carrying title, same corpus, same instrument ===
content/docs/api/schema-reference.md:730 keys=[… 'title', 'type']
content/docs/api/schema-reference.md:1297 keys=['columns','objectName','showSearch','title','type']
packages/plugin-view/src/ObjectView.tsx:1714 keys=[… 'title', 'type']
TOTAL `type: object-grid` objects authoring `title` at the same depth: 3
=== NEGATIVE CONTROL: list-view nodes authoring a nonsense key ===
TOTAL: 0
=== POPULATION BOUND: every object with a depth-1 `type: 'list-view'` in that corpus ===
TOTAL: 301
Sub-claim by sub-claim:
| # | the repaired text claims | my measurement | verdict |
|---|---|---|---|
| 1 | zero list-view nodes author title |
0 of 301 | ✅ |
| 2 | over the corpus apps/ examples/ content/ packages/ |
that is the corpus I ran | ✅ |
| 3 | the instrument reports three object-grid nodes carrying the key |
3 | ✅ |
| 4 | two of them are authored | both sit inside ```json fenced example blocks (nearest fence above line 730 is 729: ```json; above 1297 is 1262: ```json) |
✅ |
| 5 | both authored ones are in content/docs/api/schema-reference.md |
lines 730 and 1297 | ✅ |
| 6 | the third is packages/plugin-view/src/ObjectView.tsx composing title: schema.table?.title onto a grid node it builds |
that exact string occurs once in the file, at line 1714, inside return { type: 'object-grid', objectName: …, title: schema.table?.title, … } |
✅ |
| 7 | the third is a producer writing the key, not an author declaring it | it is renderer source in the return of a node-building function — the node is composed at runtime, not authored in a document |
✅ |
And the prescriptive sentence the docblock adds — "Say "authored" or the two numbers disagree." — is
not prose to wave through: I executed the procedure it prescribes over the whole population, both ways.
Stated as authored, the count is 2; stated as carrying the key over that corpus, it is 3.
The two numbers do disagree, exactly as the sentence says, and that disagreement is the defect this
commit repairs. The prescription is validated by the measurement that produced it.
Is the author-vs-producer distinction now where a CHANGELOG reader meets it? Yes. It is in the
changeset body, which publishes verbatim into the CHANGELOG — not only in the PR body:
Over that same corpus the instrument reports three
object-gridnodes carrying the key: two
authored ones, both incontent/docs/api/schema-reference.md, plus one that is not authored at all —
packages/plugin-view/src/ObjectView.tsxcomposestitle: schema.table?.titleonto a grid node it
builds, so it is a producer writing the key rather than an author declaring it.
That was the entire point of raising it: the old sentence stated an instrument's answer the instrument
does not give, in the one carrier that ships to users. It now states the answer the instrument gives, and
it names the distinction that makes 2 and 3 both true.
Accept set, both directions, at the new head: unmoved — packages/types tree hash identical to the
merge base, no manifest or lockfile touched, @objectstack/spec still ^17.0.0 and still 17.4.0
installed. The closing keyword is unchanged and still the only one: Fixes objectui#8653, which remains
right — both card items are discharged.
Still open from the previous record, and not repaired here: PR body §7 still says
check-changeset-presence.mjs … 1 published source file, where the gate's own output at this head says
2 of them published source of a package the release covers / ✅ 2 source file(s) of 1 released package(s) changed. It was non-load-bearing then and it is non-load-bearing now — the PR body does not
ship to users, the exit is reported correctly, and it is not a reason to fail. Recorded so it is not
mistaken for something I stopped checking.
③ Test quality
Carried forward under the proved bound. The pin file is byte-identical (6bf8d8bb0c… at both heads) and
not one code token of the reader it pins moved, so the six ablations of the previous record — four on the
pin file (including one leg the PR did not run: adding a title relay, to prove the absence-assertion
discriminates) and two over the whole 78-file package — measure this head exactly as they measured the
last one. ⛔ Re-running them would have been theatre, not measurement; the bound is what makes that
statement defensible, and the bound is measured above with a controlled instrument.
CI at eca18ec14c, read from the API rather than assumed: 36 check runs — 33 success, 3 skipped
(Test (coverage), Test (coverage shard …), dependabot), 0 failures, 0 still running at the time
this record was written. Type Check is among the successes.
NOT MEASURED
- Everything the previous record listed as NOT MEASURED remains NOT MEASURED, unchanged and for the
same reasons:check:sdui-registration-pins(exit 2,No console build to weigh at apps/console/dist/assets— a precondition failure, ⛔ never rounded to green); §6 leg D's execution
half (the app-shellrelayRungCensus-7559census was confirmed structurally — it names the read only
in aWRITE_EXCEPTIONSreason string — but not re-executed under the mutation); the docblock's "no
test failure anywhere else in the tree", which is proved overpackages/plugin-listonly; and the
provenance of the installed@objectstack/specartefact. - The 38 propositions and the six ablations were not re-executed at this head. They are carried
forward on the proved bound, not re-measured. If the bound were wrong, this record would be wrong with
it — which is why the bound, and not the propositions, is where the measurement went. - The full test suite was not re-run locally at this head. CI's four
Test (shard n/4)runs are read
from the API, not reproduced on this box. - Rendered CHANGELOG output — I read the changeset body, not a
changeset versionrender of it.
Implemented-by: the os-dev developer subagent that authored eca18ec14c on branch claude/issue-8653-listview-title-undeclared
Reviewed-by: the same independently spawned domain:spec contract-review agent that produced the 701218c682 record, working from a fresh detached worktree at eca18ec14c, re-deriving the bound and the repaired clause from primary sources and carrying nothing forward that the bound does not cover
PASS
Generated by Claude Code
Landed — all three pre-landing checks satisfied at
|
| check | reading |
|---|---|
| ① same-form contract review, PASS at this head | the narrow re-review above. ⛔ Adopted verbatim, form verified element by element: heading · the new head in a code span · ①②③ with commands and real output · explicit claim count (6 prose units → 7 sub-claims + 1 prescriptive sentence) with the bound stated · Implemented-by:/Reviewed-by: pair · NOT MEASURED with a reason each · unhedged **PASS** alone on its line |
② PM_SWEEP_REPO=objectstack-ai/objectui node scripts/pm/check-clause2-carriers.mjs --pair 9470 |
exit 0 at 08:23Z — re-run after the review comment landed, because this check reads the comment set and a stale reading is not a reading |
| ③ every check green | total_count 36, returned 36 — counts agree, so the enumeration is complete and not a page of a longer list. 33 success / 3 skipped / 0 not-green / 0 still running; legacy combined status success; mergeable_state: clean |
| governed surface | docs/adr/** · .claude/** · skills/** · AGENTS.md · CLAUDE.md · content/docs/releases/ — no hit across the 3 changed files, so the ordinary landing path applies |
⭐ Why the narrow re-review was accepted as ① rather than a full one
Because the reviewer proved the bound instead of asserting it, which is the only thing that makes a carry-forward honest. It compared the two ListView.tsx blobs with a parser, not a regex — an AST token walk plus a removeComments: true emit comparison — and lit three controls on the instrument: a comment-only edit that must read IDENTICAL, one changed code token that must read DIFFER, one deleted code line that must read DIFFER.
⭐ Its first instrument failed its own self-test and was discarded: a naive ts.createScanner loop desynchronises on ${…} template continuations and swallowed docblock text into a template token, which would have reported a difference that does not exist. That is the discipline working — an instrument that is not self-tested is not an instrument.
Subject reading: token streams identical (18356 = 18356) and emitted JS byte-identical (99307 = 99307). Not one code token moved. The changeset's YAML frontmatter hashed identically across both heads (e2dc954ee1…), with a control confirming the extractor would have caught a minor → patch flip. packages/types tree hash identical to the merge base; the pin file identical across heads.
⇒ the 38 propositions and six ablations of the 701218c682 record carry forward on a measured bound. The reviewer re-ran only the gates whose input actually changed — the text gates — all exit 0.
Enqueued
Marked ready for review, then auto-merge armed with squash (PUT /pulls/9470/ccr/auto_merge → 200 {"enabled":true,"merge_method":"squash"}).
Evidence of enqueue is the queue ref, not the API field — auto_merge now reads null because the two are mutually exclusive, and reading that field alone would say the arming failed when it in fact succeeded:
$ git ls-remote origin 'refs/heads/gh-readonly-queue/*'
3a9ab021c8ff38aa3dfd8161b8a58541f6501661 refs/heads/gh-readonly-queue/main/pr-9470-c5cd9c019ff6a5f9e0432dadff62f76c834a66a9
Governed Surface Queue Guard fired on the enqueue at 08:23:49Z and is success — an independent confirmation of the governed-surface row above, taken by the repo's own gate rather than by this seat's path matching.
⛔ The merge is the queue's to perform. This seat does not merge directly and does not bypass the queue.
Carried, not dropped
needs:contract-reviewcleared from both carriers in the same pass — PR and card objectui#8653 — each with a read-union-write-readback, both readbacks MATCH, nothing stripped by another actor in between.- The PR carries
Fixes objectui#8653, so the card closes on merge. ⛔pm:dispatchedand the assignee are not stripped automatically by a mergedFixes— measured six times this session — so post-merge bookkeeping on that card is owed and will be done rather than assumed. - Reviewer imprecision Implement visual designer for Object UI schemas #1 remains unrepaired and is recorded rather than fixed: PR body §7 says
check-changeset-presence.mjs … 1 published source filewhere the gate's own output at this head says2 of them published source/✅ 2 source file(s) of 1 released package(s) changed. The PR body does not ship to users and the exit is reported correctly, so it is not a reason to hold a green PR — and ⛔ noPATCHwas made for it, because that channel appends a second bare attribution footer on every write.
Generated by Claude Code
Fixes objectui#8653.
That closer is deliberate and it is the only one in this body: both of the card's items are answered and pinned here — item 1's exit is chosen by measurement, item 2's exemption is confirmed and given the pin the card asked for. Question 2 at the bottom is where to say so if the seat reads item 1 as still open.
needs:contract-reviewis on the card and this PR is written to be judged: every accept-set change and every public-surface change is enumerated below, one by one, and every published claim here was executed before it was written down.1. Premise verdicts — the card measured at
origin/main154fe2a, and that surface has movedBranch base:
e3cb47624e.ListView.tsxhas taken several merges since154fe2a(the dispatch names six), so every line number, count and "is read undeclared" claim on the card was re-derived here before anything was edited. Declaredness was measured with the TypeScript checker (checker.getPropertyOfTypeover emitted declarations — thepartial-schema-collapse-pin.test.tsinstrument), never a grep (objectui#8410).main, so the file is freegit log --oneline --grep='#9362' origin/mainnamesc10bc4c89e; control--grep='#9366'names the branch basee3cb47624e.titleis read atListView.tsx:3122viewLabeltakingschema.labelOR-ed with(schema as any).title.titleis not a declared member ofListViewSchematitleresolves to no property symbol onListViewSchema. The probe is a one-shot reading, so it carries its controls with it:label,objectName,columns,rowActions,bulkActionDefsall resolve;zzqx_no_such_keydoes not; an index-signature-free control type resolvestitle.as anyCAST, at154fe2atoo (git show 154fe2a:...prints the identical line), so the index signature never carried it. The checker also reads that signature asunknown, notany— a bareschema.titlewould not have compiled into astringslot. ⭐ This matters: the cast was laundering a real defect (§3).rowActionDefsis read atListView.tsx:1970, ONE sitelistViewPredicates(...)harvest and the relay into the childobject-gridnode. Both re-located by symbol.rowActionDefsis not declared onListViewSchemaObjectGridSchema, which is why both renderers cast.rowActionDefsread site carries NO docblockrowActionDefsread site carries NO pinapp-shell'sObjectView.relayRungCensus-7559.test.tsWRITE_EXCEPTIONS. That census re-derives what the PRODUCER writes, not that the READER reads. Ablation leg D below deletes bothListViewreads and the census still passes 24/24, exit 0.2. The exit each key takes, and why the contract chose it
The objectui#8327 family triage ruled that
packages/typesis a mirror: declaring a key here that the platform does not declare makes this repo accept what the platform refuses. So the exit is decided per key by the contract. Measured against@objectstack/spec17.4.0, as KEY verdicts over otherwise-legal fixtures:ListViewSchemaObjectGridPropsSchematitleunrecognized_keys: ['title'])rowActionDefslabel(positive control)bulkActionDefs(positive control)zzqx_no_such_key(nonsense control)Both controls fire in the same run, so the refusals are readings. All five rows are re-derived every test run in §1 of the new pin — ⛔ nothing above is a number this PR asks you to trust.
title⇒ retire the read (the objectui#7129 route, as at objectui#7623)titleon the list surface while accepting it on the grid surface. That asymmetry is exactly why objectui#6639 could take the declare branch forObjectGridSchema.titlein 2026-08-29 and this site cannot: declaring it here would publish a key the save gate rejects.labelfor this job on the list surface, and the reader already read it first. Asking the platform to add a deprecated alias to a closed schema would widen the platform's accept set for zero authors.object-grid.titlenodes existed. Here they do not: a parse-based, order-agnostic sweep ofapps/ examples/ content/andpackages/found zerolist-viewnodes authoringtitle. The same instrument, in the same runs, reproduced objectui#6639's own reading on the grid population (its twocontent/docs/api/schema-reference.mdhits) and returned zero for a nonsense key.ObjectGrid's own twotitlereads are untouched. They remain declared, ruled and read.rowActionDefs⇒ the objectui#5091 exemption extends; pin it here the way the grid's is pinnedThe card's question, answered on five legs — the grid's three plus two this site adds:
app-shell'sObjectViewderives it fromobjectDef.actionsfiltered bylocations.includes('list_item')and writes it onto afullSchema: ListViewSchema;plugin-view'sObjectViewcomposes the same key onto alist-viewnode.@object-ui/typesdeclares it on neither mirror ⇒ that is why both renderers cast.object-gridnode, where the data-table surface does declare it.basePropsis an explicit picklist, so that one line is the only way a host's composed row actions reach the row menu.visible/disabledCELs andrecordIdField; deleting the read returns rows whose predicate operand was never selected — objectui#3501's fail-closed CEL fault arriving with a success receipt.3. The defect the cast was laundering — repaired in the same expression
viewLabelisstring.ListViewSchema.labelisstring | I18nLabel(the spec's inline locale map, published since objectui#4580's revised Q1).X || anycollapses the whole expression toany, so an inline locale-maplabelreachedsanitizeFileNameBaseunresolved:That string is the verbatim red-first reading below, taken on the unmodified tree. The read now goes through the spec's own
resolveI18nLabelagainst the display locale — the same resolver, same argument order,ObjectGridalready used at its twin site.4. Accept-set and public-surface changes, enumerated
packages/typesis not touched at all: no interface member, no zod shape, no.d.ts. What a document may contain is byte-for-byte what it was.pnpm --filter @object-ui/plugin-list type-checkcovers bothtsc --noEmitandtsc -p tsconfig.test.json; exit 0, zeroerror TSlines.list-viewnode authoring onlytitle(nolabel) no longer contributes a view segment to the export filename; it exports as OBJECTLABEL dash TIMESTAMP dot EXT. Migration: writelabel, the declared slot on both faces. Nothing in the measured corpora has to change.labelnow resolves instead of stringifying (§3).rowActionDefssites, one at the retired site, and one new test file.The claim
Clause-②was filed conservatively because declare was one of three available exits at claim time. The measured exits are retire and pin, and neither widens the accept set — which is the review's question, answered with the table in §2.5. Red-first — the pin was written and run BEFORE the repair
Run on the unmodified tree at
e3cb47624e(the pin file added,ListView.tsxuntouched): 2 failed | 10 passed, verbatim:After the repair: 12 passed (12). Both runs from the repo ROOT with
--reporter=verbose(objectui#3378);apps/consoleoccurs 0 times in each log.6. Ablation — four legs, each proved on disk and restored by hash equality
Every leg: mutate, count the anchor occurrences before and after, compare the on-disk
git hash-objectagainst the HEAD blob, run, restore withgit checkout HEAD -- PATH, and verify the restore by hash equality plus an emptygit diff HEAD— ⛔ never by an exit code. All undertrap ... EXIT INT TERMwith absolute paths. HEAD blob forListView.tsx:17ff6add4af9dd38743f6ec7acd12621cd067dc6; every leg restored to exactly that.listViewPredicatesread4eecde37a52b7149eec4(schema as any).titlearm04f7e2d16ctitleassertions RED — 2 failed / 10 passedrowActionDefsreads5dc6180788⭐ Leg D is the one that measures the card's "NO pin" claim. On the same mutated tree, in the same run:
app-shell'sObjectView.relayRungCensus-7559.test.ts— baseline 24 passed, exit 0; mutated 24 passed, exit 0. The only thing in the tree that names this read does not notice it is gone.Leg B also reddens §3's "
titleis inert" case, and that is the control doing its job rather than a leak: that case usesrowActionDefsreaching the stub as its in-fixture proof that the stub received a real composition, so removing the relay removes the control. The test says so at the assertion.7. Verification
Run from the repo root. Heavy runs went through
scripts/pm/os-verify-lock.shin argv form; exits read from the wrapper's ownVERDICT command-exitline.pnpm exec vitest run packages/plugin-list/(whole package)apps/console0 occurrencespnpm --filter @object-ui/plugin-list type-checkpnpm --filter '@object-ui/plugin-list^...' build(exit 0).TS2307 Cannot find module '@object-ui/types'before its dependency closure was built: that is NOT MEASURED, neither a pass nor a red, and it was re-run.eslint --no-inline-configon the two changed source filesListView.tsx185 pre-existing ones (no-explicit-any/react-refresh, none introduced). Counts read from--format json. The universe is narrowed deliberately: the config declares noprojectServiceand noparserOptions.project, so type-aware linting is off and this diff cannot move any untouched file's verdict.check:control-bytesgrep -naPover the three changed files (no hit; a planted control byte in a scratch file makes the same instrument fire)check:new-line-citationscheck:changeset-claimscheck:test-path-rootscheck:vi-mock-specifiers/vi-mock-override-shape/vi-mock-inheritcheck:handler-key-readscheck:metadata-write-doorscheck:shell-escape-residuecheck:unreferenced-sourcescheck-changeset-presence.mjscheck-changeset-no-major.mjscheck-governed-queue-guard.mjs --teston all three pathsNOT GOVERNED, 3 paths against 5 governed surfaces, none matchedcheck:sdui-registration-pinsNo console build to weigh at apps/console/dist/assets, which that script itself prints as "not a pass". It is owned byperformance-budget.yml, which builds the console; this diff touches no registration array.Acceptance notes
Observed while measuring, ⛔ not filed and ⛔ not repaired here:
packages/types/src/objectql.tsandzod/objectql.zod.tsboth describeObjectGridSchema.titleas read atviewLabel: schema.label || schema.title. The liveObjectGrid.tsxspelling has had the i18n resolver wrapped aroundschema.labelfor some time, so the quoted expression is prose drift, not a defect: the two sites, their count and theirlabel-first semantics are all still accurate. Noted, not filed — a doc nit with a named successor: the next card that touchesObjectGridSchema.titleor that ledger entry.ListView's export-filenamelabelargument (the OBJECT label, distinct from the view label this PR touched) is still handed through without the inline-locale resolver. It is a different argument on a different key with a different producer, andresolveObjectLabelalready handles the translated case ahead of it. Noted, not filed; carrier: any card that revisitsbuildExportFileName's callers.Open questions for the in-seat contract review
retirethe right exit fortitle, or does the seat want route-to-producer? The measurement says the platform refuses the key on this surface and no author writes it, and §2 argues route-to-producer would widen the platform for zero authors. If the seat disagrees, the objectstack-side card would have to ask@objectstack/spec'sListViewSchemato declare a deprecatedtitlealias — and this PR'sListView.tsxhunk would revert to the cast plus a pin, exactly the objectui#8652 / objectstack#17987 shape.Fixesright, or should this bePart of? Both card items are answered and pinned, which is whyFixesis used. If the seat treats item 1's exit as still open pending (1), say so and it becomesPart of.Session:
session_01L5xpA5q533BgTTNADibEFtGenerated by Claude Code