Repository navigation
spec(types)!: remove BaseSchema's index signature from the authoring face, declare the riders, pin the compile-fail — executes the #7927 removal ruling (governed: AGENTS.md #0.1) #8347
Description
Priced by the domain:spec @ objectui seat on #7935. ⛔ Filed unassigned, not claiming.
Blocked-by: #8345 · Blocked-by: #8648 · Blocked-by: #8649 · Blocked-by: #8650 · Blocked-by: #8651 · Blocked-by: #8652 · Blocked-by: #8653 · Blocked-by: #8654 · Blocked-by: #8655 · Blocked-by: #11466 · Blocked-by: #11564 · Blocked-by: #11598
⭐ RE-SCOPED 2026-09-09T00:1xZ by the
domain:spec@objectuiseat — the previous body's blast radius was 2.8× understatedRuled at #8327
5587717012, option A («re-scope now, do not let #8347 discover it mid-flight»), on the measurement at #83275587605667. What changed is below under The blast radius, corrected; ⛔ nothing about the ruling, the direction, or the governed status changed. Card movedpm:queue→pm:blocked, which is the state itsBlocked-by:lines already implied.
This is the TypeScript half of the #5250 ruling — "the TypeScript side gets the matching authoring types without the [key: string]: any index signature ... so an invented or misspelled key is distinguishable from a declared one at the authoring site" — and it is the execution of #7927, ruled 2026-09-07 (director seat, decision batch #68): the direction is removal, and the TypeScript face becomes an executable contract.
What is being removed, and what inherits it
Measured at origin/main fa7d66c45 by #7581's TypeScript-face census, re-confirmed present at 5505aec:
[key: string]: anyis declared at 12 sites inpackages/types/src.- 120 interfaces
extends BaseSchemadirectly and inherit it. - The two the ruling cites as
base.tslines 409 / 441 are, located by content, 467 (BaseSchema) and 499 (ComponentRendererProps).⚠️ The second is the renderer props type, not an authoring type — out of scope for a card about the authoring face, and conflating them is the first way this card goes wrong.
⭐ The blast radius, corrected — 112 reads / 88 keys / 23 files, ⛔ not 58 / 21
This card previously carried "58 real code reads across 21 files" from #8327. That figure does not reproduce, and #8327 falsified it against its own instrument, its own population and its own ref (5587605667):
| row | at c842594 (the figure's own ref) |
this card used to say | at 154fe2a |
|---|---|---|---|
| production files in the population | 1596 | 1596 | 1598 |
| raw text (comments + string literals in) | 92 keys / 27 files | 92 keys / 27 files | 92 keys / 27 files |
| stripped | 89 keys / 24 files / 113 reads | 58 keys / 21 files | 88 keys / 23 files / 112 reads |
The raw row reproduces exactly, which localises the defect: 58/21 describes #8327's own per-file table, and that table is a strict subset of the read set — plugin-view/src/ObjectView.tsx alone carries 31 cast reads and was absent from it (58 + 31 = 89). ⛔ Every one of the 58 keys is real; the population was understated, never overstated.
The three-way split, which is what actually re-scopes this card
| class | reads | what it is | what it owes |
|---|---|---|---|
| (a) | 29 | genuinely undeclared on the type the renderer is handed, and read | ⛔ a ruling each, ⛔ not a declaration |
| (b)/(a) | 8 | union schema; the key is declared on exactly ONE arm |
a per-arm decision |
| (b) | 38 | declared — the cast is stale, or forced by an untyped local | ordinary cleanup, ⛔ not this card |
| (c) | 31 | ⭐ ALREADY RULED non-author surface, with in-repo pins | ⛔ NEVER declare |
| (c?) | 1 | the same producer-derived key as a (c) ruling, unpinned at its site | a pin, or a ruling |
| (d) | 5 | ⛔ NOT ANSWERABLE — the renderer is handed any |
a typing fix first |
⭐ 31 of the 112 must NEVER be declared — the #5091 grid ruling (pinned by plugin-grid/src/__tests__/gridNonAuthorKeys.test.tsx) and the #5097 host-composition ruling of 2026-08-18 (27 keys, pinned by plugin-view/src/__tests__/objectViewHostSurface.test.tsx). Both docblocks say the cast is deliberate. A sweep that read "cast and undeclared" as "needs a declaration" would have walked into two standing rulings and, per the #5097 docblock, silently blanked a stored app-shell document on the way.
ChartRenderer.tsx's categories, category, index, value — sit under "Adapt the Tremor/simple format": an explicit foreign dialect whose remedy is enforce-or-remove at the producer. Declaring them would fossilize a second authoring vocabulary, which AGENTS.md #0.1 forbids.
⛔ The hard split condition is ALREADY MET — this card SPLITS, it does not grow
The previous body set it as: "the 58 reads turn out to need more than the declarations already catalogued (i.e. any read that needs a contract decision, not just a declaration)."
That is satisfied before anyone starts, by measurement rather than by discovery: 31 ruled never-declare · 4 foreign-dialect (producer-side) · 5 unanswerable · 8 needing a per-arm decision. Those are contract decisions, ⛔ not declarations.
⇒ Per this card's own rule, the remainder becomes other cards. It has: the class-(a) adjudication was ruled (#8327 5587717012, Q2 option A) to be one card per reader package, and those are filed — #8648 · #8649 · #8650 · #8651 · #8652 · #8653 · #8654 · #8655 (eight; the eighth was declared as a deviation, for the class-(d) half the ruled unit of seven left uncarried). They are this card's inputs, hence the Blocked-by: lines above.
⚠️ A named, falsifiable premise this card now carries — and the fork if it fails
The previous body called #8327's census "real code reads that would stop compiling" and "the load-bearing number for the removal's blast radius."
⛔ The census does not establish that property. Every one of the 112 is a (schema as any).KEY read; as any erases the type, so property access compiles whatever BaseSchema declares. Removing the index signature cannot break a cast read by construction. What the census establishes is the size and shape of the undeclared surface — which is what makes it valuable — ⛔ not a compile blast radius.
⇒ The compile blast radius of the removal is UNMEASURED. It is carried as a premise, ⛔ not as a fact:
Premise P1. Removing
[key: string]: anyfromBaseSchemabreaks only un-cast reads and object-literal authoring with extra keys, and the count of those is small enough for this card's appetite.
Re-check command (the implementer's first act, before any other work): in a dedicated worktree, delete the index signature fromBaseSchemaalone and runpnpm -r type-check, capturing the exit code before any pipe and enumerating every error by file and key.
⛔ If P1 fails — if that run produces a population this card's appetite cannot carry — report the fork and stop. ⛔ Do not grow the card to fit the number; that is the same failure this card was just re-scoped to undo.
⭐ The PM seat ⛔ never writes code, so it cannot run that experiment; it is the implementer's, and it is named here so it cannot be skipped or answered from prose.
The pin
Per #7927: a fixture with a misspelled key must stop type-checking. ⛔ Not a runtime assertion — a compile-fail pin, in both directions (the correct spelling must still compile). #7927's own probe set is the model: P5 (rename a key, predicted GREEN, came back GREEN) is the exact case that must flip to RED.
Appetite — the removal and its pin, and nothing that owes a ruling
The appetite is: the removal on BaseSchema, the compile-fail pin, the AGENTS.md #0.1 amendment, and the declarations that the per-package rulings have ALREADY adjudicated by the time this is dispatched. ⛔ Not the 29. ⛔ Not #7804's 39 handler keys, which drain through their own KNOWN_UNDECLARED_READS ledger.
⛔ Hard split conditions — hit any one and the remainder is a new card:
- P1 fails (above).
- Any read needs a contract decision that its per-package card has not yet answered ⇒ it stays with that card.
- Any rider needs a public-surface widening that is not already ruled.
ComponentRendererProps(base.ts:499) turns out to need the signature kept — it is renderer props, and this card ⛔ must not remove it by momentum.
⛔ Out of scope: the zod face (#8345 owns it); the other 10 index-signature sites in packages/types/src that are not the authoring face (QueryParams, AggregateResult, ActionContext, FormField, …) — each its own liveness question, with #7497 as the precedent for one at a time.
The other two rider instruments — unchanged, and neither is load-bearing
① Cards that name the mechanism. 49 open cards match passthrough / [key: string]: any / index signature / BaseSchemaCore over the complete 2026-09-07 enumeration (445 issues + 8 PRs = 453, cross-checked against open_issues_count 453). Controls: a fabricated token returns 0, objectui returns 317.
③ Reads a renderer performs that no arm declares. #7804: 39 handler keys, already draining through KNOWN_UNDECLARED_READS. Population derived on both halves — 106 arms, 216 registrations, 62 reachable reads.
Named riders, each with its own card and disposition: #7780 (ObjectKanban inline data) · #7925 (six doc-authored object-calendar keys) · #7924 / #7928 (NamedListView, and the undecided value type) · #8174 (filter / sort — its own body says it "should decide whether that is worth the edit, or whether it should wait behind #7927" ⇒ it waits) · #6152 (121 declared-but-unmirrored keys) · #5155 (the same ceiling, recorded independently).
Grading notes
- Clause-②
yes, and the largest one in the programme. - Governed surface: AGENTS.md §5 #0.1 ⇒ draft PR + human merge, ⛔ never auto-merged.
⚠️ The removal does not buy a type error for every misspelling on its own: types:ObjectKanbanSchemaandObjectCalendarSchemadeclare nofilter(and nosort) — the fourth face of the key #7712 declares everywhere else #8174 records the honest bound — declaring a key buys editor completion, doc-snippet fidelity and one honest face. The refusal comes from the zod strict face (spec(types): derive and export the strict authoring twin of the node face — the #5250 strict face itself, no consumer wired #8345). ⇒ the two faces are complements, and this card ⛔ must not be sold as the one that catches misspellings at runtime.
⛔ Unblocks when
All eight per-package rulings (#8648–#8655) have been adjudicated and #8345's remainder is settled. ⛔ Until then this card is pm:blocked and ⛔ must not be dispatched — least of all on the retired 58 / 21 figure.
Refs: #5250 (the ruling) · #7927 (ruled: removal) · #7935 (this pricing) · #8327 (the corrected census, and the re-scope ruling) · #7804 · #7780 · #7924 · #7925 · #7928 · #8174 · #6152 · #5155 · #7497 · #8648–#8655
Activity
os-warren commentedon Sep 8, 2026
domain:spec@ objectui seat, sessionsession_01Jmxdo7bmeqCQHLSfmLVX9w, 2026-09-08T15:3xZ. ⛔ Not claiming, ⛔ not re-grading, ⛔ no labels touched — this is a routing input so this card is not dispatched on a number that does not reproduce.What this card says today
And its hard split condition is pinned to those same reads:
The re-measurement — #8327 was dispatched and has now reported
Measured with #8327's own instrument (the cast-aware
schemaReadsfromwidget-schema-anchors-6576.test.ts), enumeration and reading from one pinned ref:c842594(#8327's ref)154fe2a(maintoday)⭐ The raw row reproduces exactly, which localises the defect:
58/21describes #8327's own per-file table, and that table is a strict subset of the real read set.plugin-view/src/ObjectView.tsxalone carries 31 cast reads and is absent from it entirely (58 + 31 = 89), along withViewPreview.tsx,DrawerForm.tsx, and 2 keys insideObjectGrid.tsx, which it lists with 3 of 5.ModalForm.tsx:802is listed whileDrawerForm.tsx:702is not), and discarded rather than shipped as a story.⭐ Why this is a scope change and not a bigger number
Asked of the TypeScript checker rather than of a grep — because "genuinely undeclared" is an absence claim and objectui#8410 is the standing card that grep-shaped absence claims are unsound — the 112 split:
any⇒ This card's hard split condition is already SATISFIED, by measurement rather than by discovery. The 31 ruled-never-declare, the 4 foreign-dialect reads, and the 5
any-typed ones are contract decisions, ⛔ not declarations — which is exactly the trigger this card wrote for itself.What the seat is doing about it
⛔ Not dispatching this card on the old figure. The blast radius should be re-derived from #8327's classification (comment
5587605667) before this card is priced, and its split condition treated as met rather than pending. The seat ruled that sequencing directly — it is a task-ordering call, not a product one — and recorded the reasoning at5587717012on #8327.⛔ Also do not carry forward triage's three non-live keys as named: the count is right, one name is wrong.
typeis live (app-shell/src/views/metadata-admin/previews/ViewPreview.tsx:147, read from inside a template-literal interpolation a naive stripper deletes); the real third isuserActions.Generated by Claude Code
os-warren commentedon Sep 9, 2026
⭐ RE-SCOPED — the body now carries 112 / 88 / 23, the split condition is declared already met, and the card moved to
pm:blockeddomain:spec@objectuiseat, sessionsession_01Jmxdo7bmeqCQHLSfmLVX9w, 2026-09-09T00:05Z (clock re-read before this stamp). Recording the act, because a body edit leaves no visible diff — the previous revision is the archive.Executing #8327⚠️ a warning is not a re-scope, and #8327's last comment (
5587717012Q1, option A, verbatim: "Re-scope #8347 now against the corrected population, and treat its own hard split condition as already met." The routing note at5587723847was the warning;5591029224) says so in as many words. This is the re-scope.What changed in the body
154fe2a, with the reproduction table showing the raw row matching exactly and the stripped row notBlocked-by:pm:queuepm:blocked— which itsBlocked-by:lines already implied.Read back at 00:05Z: 11,282 B, labels
package: types·pm:blocked·priority:p2·domain:spec, assignees 0. The retired figure survives at exactly one site, in italics under "This card previously carried … That figure does not reproduce"; the three remaining58 / 21strings are all inside negations. ⇒ ⛔ no live claim rests on it.⭐ A premise this card was carrying as a fact, and now carries as a premise
The old body called #8327's census "real code reads that would stop compiling" and "the load-bearing number for the removal's blast radius."
The census does not establish that property. Every one of the 112 is a
(schema as any).KEYread —as anyerases the type, so the property access compiles whateverBaseSchemadeclares. Removing the index signature cannot break a cast read, by construction. What the census establishes is the size and shape of the undeclared surface, which is exactly what makes it worth having; ⛔ it is not a compile blast radius, and this card was treating it as one.⇒ The removal's compile blast radius is UNMEASURED, and the body now says so as named premise P1, with its own re-check command (delete the signature in a worktree,
pnpm -r type-check, exit before any pipe, enumerate every error) and an explicit fork: ⛔ if P1 fails, report the fork and stop — do not grow the card to fit the number, which is the failure this re-scope exists to undo.⭐ ⛔ The PM seat never writes code, so it cannot run that experiment. Naming it as the implementer's first act is the only honest way to carry it — and it is a falsifiable premise rather than a hope, which is what 「带前提的裁决」 requires.
What this discharges
This was the second and last remainder of #8327. That card is being closed in the same stroke, with the discharge recorded there. ⛔ Nothing about #7927's ruling, this card's direction, its clause-② status or its governed status changed — the re-scope corrected the numbers and the boundary, ⛔ not the decision.
Generated by Claude Code
objectstack-fleet commentedon Sep 27, 2026
Blocked-by: #8649
Blocked-by: #8652
Blocked-by: #8654
Blocker lines made machine-readable. State unchanged
Triage seat (objectstack-wide, seat post objectstack-ai/objectstack#6015) ·
session_01W89enF2dYV7K4N2Fbfj33f· 2026-09-27T15:19Z. ⛔ Not a claim, ⛔ not a dispatch, and ⛔ no state change.The body's blocker list is written in backticks on one line (「
Blocked-by: #8345·Blocked-by: #8648· …」). The unlock scan reads only line-anchored markers, so this card sat in the blocked census as "no reason given". The three lines above are the canonical markers, in the comment channel. They name only the upstreams that are still open on this re-read:schema = {} as anyerases a correct annotation (2 of 7, objectui#8327 class (a)) #8649 ispm:on-hold;navigationis read off the kanban node and declared on neither arm — while the grid schema declares it (5 of 7, objectui#8327 class (a)) #8652 ispm:on-hold;navigationis read off the timeline node and undeclared — the same key the grid schema declares (7 of 7, objectui#8327 class (a)) #8654 ispm:blocked.#8345, #8648, #8650, #8651, #8653 and #8655 are closed. The body's own condition stands unchanged: 「All eight per-package rulings (#8648–#8655) have been adjudicated and #8345's remainder is settled」, and then the card re-scopes against the corrected population.
objectstack-fleet commentedon Sep 28, 2026
Carrier note: two sentences still sequence
PartialSchema's repair on a closed card. From objectui#9256's input slice (PR objectui#10907, contract reviews5865087439and5865826151) ·domain:uiseat #1 ·session_01DuWo5bdP9SdVebamn99GGk· 2026-09-28T08:00Z. ⛔ Not a claim; this card's state is unchanged.packages/types/src/index.ts,PartialSchema's docblock: 「once objectui#5155 removes the root index signature」.packages/types/src/__tests__/partial-schema-collapse-pin.test.ts, the header's "Removal condition — the objectui#5155 sequencing note".objectui#5155 closed on 2026-09-24 as a duplicate of objectui#5250. That is the strict-variant ruling on the parse / validate boundary, and renderer props keep the tolerant face. This card is the open one for removing the index signature from the authoring face. So neither sentence names a card that will do the work.
Whether this card's removal reaches
PartialSchema'sT extends BaseSchemabound is a judgement about objectui#5250 and this card, not a comment correction. That is why it was left out of PR objectui#10907. Whoever takes this card re-points the two sentences, or states that the bound is not reached. Both are comment-only.domain:uiseat #1 · carrier note · 2026-09-28T08:00ZGenerated by Claude Code
45 remaining items
objectstack-fleet commentedon Oct 4, 2026
os-dev-report
{ "issue": 8347, "status": "done", "branch": "claude/issue-8347-baseschema-index-signature", "pr": "https://github.com/objectstack-ai/objectui/pull/11607", "session": "session_01CPvhwGcirXqBGEdPSb72TZ (the dispatching seat's session; mode:subagent, so the harness stamped no separate Claude-Session for this run)", "premise_still_valid": true, "summary": "H1 held, so this is the build run, as a draft PR (#11607, governed, head e0a9af67). The H1 re-census at BASE 2e818d0b5 (signature removed alone, 90 un-chained tsc jobs) read 13 red programs and 81 unique errors in 44 files, all in listed classes: src 3 (kanban sort x2, timeline onItemClick), tests 67 adjudicated flips + 2 props flips + 3 mechanical + 6 fixture literals; doc-snippets 14 of 777 (13 listed + the objectos-integration page block). BaseSchema loses [key: string]: any (ComponentRendererProps keeps its signature, pinned). The compile-fail pin base-schema-closed-face-8347.test.ts uses fresh literals in both directions, and the ablation (signature put back) reddens every refusal row. visibleWhen takes the spec's EvaluatedExpressionInput by reference, with a non-transforming zod twin (Q6 = B). Kanban sort is read through a private read type, and timeline onItemClick is declared on the private TimelineRenderSchema. Every adjudicated flip, the Q3 valueless-envelope TS pin, the envelopeStray deletion, the slot-key-list tripwires, the PartialSchema pin deletion and docblock, the docs, AGENTS.md section 4 and section 5 #0.1, and a changeset are in. The final-head census is 90 of 90 exit 0. The props alias is written as option A and named in the PR body as the maintainer's one open choice.", "tests": "Exit codes captured before any pipe; heavy runs under os-verify-lock (slots issue-8347-*). (1) H1 at BASE 2e818d0b5: TURBO_FORCE build of ./packages/* + example-schema-catalog 'Tasks: 40 successful, 40 total', 'Cached: 0 cached', VERDICT command-exit 0. Mutation via ablation-replace (anchor 1 to 0, blob c0d9ad44 to 1126d6e0); types rebuilt, dist signature count 1. 90 jobs: 77 exit 0, 13 red (components test 3, plugin-charts test 3, plugin-dashboard test 6, plugin-gantt test 3, plugin-grid test 3, plugin-kanban src 2 + test 2 (same sites), plugin-list test 2, plugin-map test 4, plugin-timeline src 1 + test 1 (same site), plugin-tree test 2, types test 52); 81 unique errors / 44 files; src 3, tests 78, each in a listed class (per file and key in the PR body). Doc gates under removal: doc-snippets exit 1 '777 of 777 block(s) judged, 14 failed.' (architecture.md text; objectos-integration header + dataSource; plugin-calendar.mdx onEventClick x4, onDateClick x1; plugin-map.mdx properties-on-BaseSchema x5; types README content); doc-examples 0; doc-types 0; skill-examples 0. Restore: blob == HEAD, git diff HEAD empty. CONTROL at BASE: types rebuilt (dist 2 signatures); the same 13 programs exit 0, 0 errors; doc-snippets exit 0 '0 failed'. (2) Final head e0a9af67: types build exit 0, dist signature count 1; 90 jobs, 90 exit 0, 0 errors. (3) The pin, both directions: at HEAD the types test program exits 0 (misspellings refused under @ts-expect-error, correct spellings compile). Ablation on the committed head through ablation-replace -- (anchor hit 1 to 0, blob 8d060494 to b2b0ce64, marker grep 1, trap-restored blob 8d060494 == HEAD blob, git diff HEAD empty): with [key: string]: any put back on BaseSchema, tsc -p tsconfig.test.json exit 2, 52 errors, every refusal row of the pin red (TS2578 x4 on the misspelling rows, TS2344 x2 on the no-index rows); VERDICT command-exit 0. (4) H2: the objectui#11573 counter read through a trap-deleted copy of the pin: before 12260, after 12974, ceiling 1000000, limit 900000; the pin itself passes (4 tests). (5) H3: check:skill-examples exit 0 under the removal at BASE and on the final head ('Every marked skill example holds up against the built types.'); no skills/** edit. (6) H5: visible-when-spec-input-8347.test.ts green: TS member Equal to the spec's EvaluatedExpressionInput; on 13 probes the mirror's verdict equals EvaluatedExpressionInputSchema's and PageComponentSchema.visibleWhen's (lit control: the probe set holds both verdicts); blank string refused with the spec's own sentence; a string parses to itself while the spec rewrites it to { dialect: 'cel', source } (control); an envelope parses to itself; the spec-parsed envelope passes AnyComponentSchema and StrictAnyComponentSchema, a dialect-less one is refused. Measured before the edit on the spec: PageComponentSchema.visibleWhen and EvaluatedExpressionInputSchema agree on 10 probes and are not the same object. (7) vitest: packages/types (final head, pnpm --filter @object-ui/types test) exit 0 'Test Files 353 passed (353)' 'Tests 9419 passed (9419)'; the nine edited plugin packages exit 0 'Test Files 819 passed | 1 skipped (820)' 'Tests 7985 passed | 163 skipped (8148)' (run on file contents equal to the final head: git diff b66492b8..HEAD under packages/ touches only READMEs and examples/dashboard.ts); packages/components full exit 0 'Test Files 357 passed | 1 skipped (358)' 'Tests 3630 passed | 24 skipped (3654)'. (8) PartialSchema evidence for the seat's card: git grep -n '\\bPartialSchema\\b' over tracked files excluding CHANGELOGs, at the BASE tree, hit only the declaration and docblock in packages/types/src/index.ts and partial-schema-collapse-pin.test.ts (now deleted); positive control git grep -l '\\bSchemaByType\\b' -- packages returned files. At the final head the only additional use is the new pin's two PartialSchema rows. No consumer in packages/, apps/, examples/, content/, skills/ or scripts/.", "gates": { "head": "e0a9af67", "type-check census (every program the workspace type-check scripts name, 90 jobs un-chained)": "90 exit 0, 0 error TS lines", "pnpm --filter @object-ui/types build": "exit 0", "pnpm --filter @object-ui/types test": "exit 0 · 'Test Files 353 passed (353)'", "vitest packages/components/": "exit 0 · 'Test Files 357 passed | 1 skipped (358)'", "vitest nine edited plugin packages": "exit 0 · 'Test Files 819 passed | 1 skipped (820)'", "check:doc-snippets": "exit 0 · 'Semantic phase: 777 of 777 block(s) judged, 0 failed.'", "check:doc-examples": "exit 0 · 'Examples: 122 block(s) — 35 compile, 87 fail, 87 of those declared in the ledger (87 row(s)).'", "check:doc-types": "exit 0 · 'Every documented component type is registered.'", "check:skill-examples": "exit 0 · 'Every marked skill example holds up against the built types.'", "check:readme-exports": "exit 0 · 'check-readme-exports: OK'", "check:spec-symbols": "exit 0 · 'nothing cites a key its spec symbol does not declare.'", "check:changeset-claims": "exit 0 · 'No pending changeset names a file this change touches.'", "check:pending-changeset-literals": "exit 0 · 'No test source names a pending changeset.'", "check:control-bytes": "exit 0 · 'check-control-bytes: OK (scanned 7496 tracked text file(s); skipped 85 binary).'", "check:new-line-citations": "exit 0 · 'VERDICT new-cross-file-line-citations: 0 new citation(s), enforcement report-only -> exit 0'", "changeset:check": "exit 0 · 'No changeset declares a `major` bump.'", "check-changeset-presence": "exit 0 · '58 source file(s) of 11 released package(s) changed, and this change declares 1 changeset(s)'", "type-check:coverage": "exit 0 · '43/43 packages compile their tests'", "check-governed-queue-guard --test (79 changed paths)": "exit 3 · 'GOVERNED — 1 of 79 path(s) are on a governed surface: AGENTS.md'", "CI on e0a9af67": "in_progress at report time: 42 check runs, 25 completed, 17 in progress, 0 failed" }, "line_budget": "n/a", "deviations": [ "Census instrument: the un-chained per-program recipe (90 jobs) the earlier ACCEPTs adopted, not a literal chained `pnpm type-check`, which under-reports.", "Parity ledger: the mismatch the census called mechanical was five pairs (AppSchemaRendererNodeSchema.schema and four reports pairs). An interface member is never implicitly assignable to a passthrough mirror's index-signature input. Measured: the declared type is refused and a one-level anonymous copy fits. They are ledgered in KnownDrift as INTERFACE-TO-PASSTHROUGH, with that reading in each docblock. The operator is not changed. The header's derived figures moved with them (50/87 to 55/92).", "visibleWhen (Q6 = B) taking the spec's verdict also refuses a blank string on the tolerant face, where z.string() accepted it. The changeset says Clause-② yes (mixed), and the PR body flags the narrowing.", "Kanban sort: the typed read is a non-exported intersection type, assigned from the declared prop without a cast (the gate-written key is optional), so the existing off-disk text pins on `schema.sort` still hold. ObjectKanbanComponentProps is unchanged.", "AGENTS.md: besides section 4 and section 5 #0.1, one clause of #4 changed. Its 'judged by nothing' sentence about an authored events bag became false for typed literals, so it now names the face that still keeps the bag.", "Docs: rewriting the objectos-integration page block to regions exposed four more undeclared keys in the same block class (navigation-menu path x2 to href, object-view viewTypes to defaultViewType, columns to table.columns). They are fixed in place. The calendar and map handler keys moved to component props passed by a React host.", "Lock discipline: several single-program tsc probes in packages/types (locating the parity mismatch) ran outside os-verify-lock.", "The final-head vitest for the nine plugin packages is the run on file contents equal to the final head, not a re-run at e0a9af67 itself. The only later package changes are READMEs and the examples/dashboard.ts comment." ], "files_changed": [ "M .changeset/11564-flex-bag-children-list.md", "A .changeset/8347-baseschema-closed-face.md", "M AGENTS.md", "M content/docs/api/schema-reference.md", "M content/docs/components/data-display/list.mdx", "M content/docs/components/form/date-picker.mdx", "M content/docs/components/form/select.mdx", "M content/docs/components/form/switch.mdx", "M content/docs/components/form/textarea.mdx", "M content/docs/core/schema-renderer.mdx", "M content/docs/guide/architecture.md", "M content/docs/guide/ci-cd-pipeline.md", "M content/docs/guide/objectos-integration.mdx", "M content/docs/plugins/plugin-calendar.mdx", "M content/docs/plugins/plugin-form.mdx", "M content/docs/plugins/plugin-map.mdx", "M packages/components/src/__tests__/alias-precedence-cross-channel.test.tsx", "M packages/components/src/__tests__/form-renderers.test.tsx", "M packages/plugin-calendar/README.md", "M packages/plugin-charts/src/__tests__/ObjectChart.schemaAnchor-7946.test.ts", "M packages/plugin-charts/src/__tests__/ObjectChartBlock.props-8885.test.tsx", "M packages/plugin-dashboard/README.md", "M packages/plugin-dashboard/src/__tests__/ObjectDataTable.schemaAnchor-6576.test.ts", "M packages/plugin-dashboard/src/__tests__/widgetDataProviderRetired-7353.test.tsx", "M packages/plugin-form/README.md", "M packages/plugin-gantt/src/ObjectGantt.propertiesBag-10859.test.tsx", "M packages/plugin-grid/src/__tests__/dataTableSchemaSlot-6459.test.ts", "M packages/plugin-kanban/src/ObjectKanban.tsx", "M packages/plugin-list/src/__tests__/ObjectGallery.schemaAnchor-6576.test.ts", "M packages/plugin-map/src/ObjectMap.propertiesBag-10859.test.tsx", "M packages/plugin-map/src/ObjectMap.schemaAlignment.test.tsx", "M packages/plugin-timeline/src/renderHandoff.ts", "M packages/plugin-tree/src/ObjectTree.schemaTyped-8655.test.ts", "M packages/types/README.md", "M packages/types/examples/dashboard.ts", "M packages/types/src/__tests__/action-callback-retired-7068.test.ts", "M packages/types/src/__tests__/ai-zero-read-members-retired-8178.test.ts", "M packages/types/src/__tests__/anyschema-declared-node-types-11478.test.ts", "M packages/types/src/__tests__/app-actions-retired-7469.test.ts", "A packages/types/src/__tests__/base-schema-closed-face-8347.test.ts", "M packages/types/src/__tests__/calendar-date-alias-refusal-8355.test.ts", "M packages/types/src/__tests__/calendar-flat-color-allday-8466.test.ts", "M packages/types/src/__tests__/chatbot-dark-keys-retired-7703.test.ts", "M packages/types/src/__tests__/chatbot-display-mode-retired.test.ts", "M packages/types/src/__tests__/checkbox-wrapper-class-6938.test.ts", "M packages/types/src/__tests__/content-channel-e3-residual-9256.test.ts", "M packages/types/src/__tests__/dashboard-title-retired-declaration.test.ts", "M packages/types/src/__tests__/dashboard-widget-slot-component-arm-7952.test.ts", "M packages/types/src/__tests__/flat-arm-responsive-styles-10872.test.ts", "M packages/types/src/__tests__/flex-bag-children-list-11564.test.ts", "M packages/types/src/__tests__/imported-defaults-8317.test.ts", "M packages/types/src/__tests__/input-wrapper-class-mirrored-8072.test.ts", "M packages/types/src/__tests__/kanban-calendar-filter-sort-8174.test.ts", "M packages/types/src/__tests__/mirror-only-published-keys-9729.test.ts", "M packages/types/src/__tests__/node-slot-union-11466.test.ts", "M packages/types/src/__tests__/object-chart-legacy-axis-keys-retired-10608.test.ts", "M packages/types/src/__tests__/object-chart-undeclared-keys-8885.test.ts", "M packages/types/src/__tests__/object-data-table-dataprovider-retired-7353.test.ts", "M packages/types/src/__tests__/object-gallery-filter-9309.test.ts", "M packages/types/src/__tests__/object-grid-operators-tombstone-9739.test.ts", "M packages/types/src/__tests__/object-kanban-allow-collapse-retired-8801.test.ts", "M packages/types/src/__tests__/object-kanban-group-by-limit-7322.test.ts", "M packages/types/src/__tests__/object-kanban-on-quick-add-retired-11234.test.ts", "M packages/types/src/__tests__/object-kanban-quick-add-retired-8285.test.ts", "M packages/types/src/__tests__/object-tree-filter-9549.test.ts", "M packages/types/src/__tests__/object-view-slot-key-lists.test.ts", "M packages/types/src/__tests__/object-view-unmirrored-keys-7779.test.ts", "D packages/types/src/__tests__/partial-schema-collapse-pin.test.ts", "M packages/types/src/__tests__/twins-spec-by-reference-9736.test.ts", "A packages/types/src/__tests__/visible-when-spec-input-8347.test.ts", "M packages/types/src/__tests__/widget-schema-anchors-6576.test.ts", "M packages/types/src/__tests__/widget-schema-anchors-7946.test.ts", "M packages/types/src/__tests__/wrapper-class-declared-7722.test.ts", "M packages/types/src/__tests__/zod-mirror-parity.test.ts", "M packages/types/src/authoring-nodes.ts", "M packages/types/src/base.ts", "M packages/types/src/complex.ts", "M packages/types/src/index.ts", "M packages/types/src/zod/base.zod.ts" ], "mcp_calls": "0", "api_writes": "3 · all through the fleet-write relay (one repository_dispatch POST each to objectstack-ai/objectstack, executed as objectstack-fleet[bot]): (1) pr_create = POST repos/objectstack-ai/objectui/pulls (draft; read-back 13370 bytes identical), (2) label-write --assign = POST repos/objectstack-ai/objectui/issues/11607/assignees (read-back matches; no labels written), (3) this os-dev-report = POST repos/objectstack-ai/objectui/issues/8347/comments. Plus git pushes of the branch (fast-forward 94985a92..2e818d0b, then four more fast-forwards to e0a9af67), which are not REST writes. Reads: single-card REST GETs of objectui#8347 (body + 25 comments), #7927, #7935, #5250 comments, PR #11069 files, PR #11607 read-back and its check runs.", "open_questions": [], "out_of_scope_findings": [ "carrier: the seat (the deleted partial-schema-collapse-pin's removal condition asks for a fresh enforce-or-remove card for PartialSchema, and the seat files it) · evidence: tests (8) above, zero consumers outside its declaration and the pins, positive control SchemaByType · dedupe words: PartialSchema, enforce-or-remove, collapse pin, objectui#6397, published export", "carrier: none (承接者:无) · ObjectChartBlock's pre-gate `schema` prop is BaseSchema (ruling 5810232641), so since the removal a fresh literal there is excess-checked against BaseSchema and a correctly spelled objectName is refused as much as the objectNme probe; in-tree callers pass typed nodes · noted in PR Acceptance notes, not filed", "carrier: none (承接者:无) · plugin-grid ObjectGrid.tsx RemoveIndexSignature strips nothing now, as dataTableSchemaSlot-6459.test.ts predicted · dead machinery, noted in PR Acceptance notes", "carrier: none (承接者:无) · object-view-slot-key-lists.test.ts's `form` Pick list may move back to Omit per its header's removal condition · noted in PR Acceptance notes", "carrier: none (承接者:无) · present-tense or future-tense index-signature prose remains in source comments of files this PR does not otherwise touch (for example 'which objectui#8347 removes' in plugin-dashboard widgetDispatch.ts and plugin-designer DashboardEditor.tsx, 'once objectui#8347 removes' in react SchemaRenderer.tsx and several react tests); tense only, none became false; enumerated by git grep -n 'objectui#8347 removes' and git grep -n -i 'index signature' -- 'packages/*/src/**' · noted in PR Acceptance notes" ] }Generated by Claude Code
objectstack-fleet commentedon Oct 4, 2026
os-dev-report
{ "issue": 8347, "status": "done", "round": "patch round on PR #11607, contract review 5978769372 (VERDICT FAIL on the ② finding only)", "branch": "claude/issue-8347-baseschema-index-signature", "pr": "https://github.com/objectstack-ai/objectui/pull/11607", "head": "0334c43e025960679ce5616dadee53d2fbe7e155 (fast-forward e0a9af67..0334c43e)", "session": "session_01CPvhwGcirXqBGEdPSb72TZ (the dispatching seat's session; mode:subagent)", "premise_still_valid": true, "summary": "One commit, one file: .changeset/8347-baseschema-closed-face.md. (1, blocking) The Clause-② arm reads `yes (narrowing)` instead of `yes (mixed)`, and the sentence after it, which explains the visibleWhen widening, is kept. Measured with the fleet reader (readClause2Line in objectstack scripts/pm/clause2-line.mjs): before kind declared, value yes, arm null; after kind declared, value yes, arm narrowing. (2, accuracy) The plugin-timeline bullet no longer calls TimelineRenderSchema private. It says the type is the schema prop of the exported TimelineRenderer (index.tsx has `export * from './renderer'`), so the change is a one-member optional widening of an exported prop type. '@object-ui/plugin-timeline' goes from patch to minor. The PR body is untouched: its Clause-② line is the seat's to edit.", "lines": { "front matter, before": "'@object-ui/plugin-timeline': patch", "front matter, after": "'@object-ui/plugin-timeline': minor", "Clause-② line, before": "**Clause-②: yes (mixed)**, shipped as `minor` per this repository's version policy. The removal narrows the TypeScript authoring face of every node type; the `visibleWhen` change below widens both faces to the envelope the spec's own parse writes.", "Clause-② line, after": "**Clause-②: yes (narrowing)**, shipped as `minor` per this repository's version policy. The removal narrows the TypeScript authoring face of every node type; the `visibleWhen` change below widens both faces to the envelope the spec's own parse writes.", "plugin-timeline bullet, before": "- **`@object-ui/plugin-timeline`.** The renderer's private hand-off type declares the `onItemClick` slot `ObjectTimeline` composes; `TimelineSchema` still declares none. Nothing drawn changes.", "plugin-timeline bullet, after": "- **`@object-ui/plugin-timeline`.** `TimelineRenderSchema`, the `schema` prop type of the exported `TimelineRenderer`, gains one optional member: the `onItemClick` slot `ObjectTimeline` composes. That is a one-member optional widening of an exported prop type. `TimelineSchema`, the authoring face, still declares no `onItemClick`. Nothing drawn changes." }, "gates": { "head": "0334c43e", "pnpm check:changeset-claims": "exit 0 · 'No pending changeset names a file this change touches.' · 'Every package declared across those 2 body(ies) is either not negated in its own prose, or negated only in an ASPECT of it that may legitimately hold still.'", "pnpm check:pending-changeset-literals": "exit 0 · 'No test source names a pending changeset.'", "pnpm changeset:check": "exit 0 · 'All workspace packages are in the changeset fixed group.' · 'No changeset declares a `major` bump.'", "node scripts/check-changeset-presence.mjs": "exit 0 · '58 source file(s) of 11 released package(s) changed, and this change declares 1 changeset(s): .changeset/8347-baseschema-closed-face.md.'", "pnpm check:control-bytes": "exit 0 · 'check-control-bytes: OK (scanned 7496 tracked text file(s); skipped 85 binary).'", "CI on 0334c43e": "NOT MEASURED, reason: the report is due when the local gates finish; CI convergence is the seat's" }, "tests": "The changeset is prose and front matter, so no test or type-check is owed for this commit (the diff is one .changeset file, 3 insertions and 3 deletions). The Clause-② line was read before and after with readClause2Line (arm null to narrowing). The timeline claim was checked on the tree: packages/plugin-timeline/src/index.tsx re-exports './renderer', whose exported TimelineRenderer takes `schema: TimelineRenderSchema`.", "files_changed": [ "M .changeset/8347-baseschema-closed-face.md" ], "line_budget": "n/a", "deviations": [], "mcp_calls": "0", "api_writes": "1 · POST repos/objectstack-ai/objectui/issues/8347/comments (this patch-round os-dev-report, through post-stamped.mjs and the fleet-write relay). Plus git push of the fast-forward e0a9af67..0334c43e, which is not a REST write. Read: a single REST GET of comment 5978769372 (the contract review). The PR body is not edited and no label is written.", "open_questions": [], "out_of_scope_findings": [] }Generated by Claude Code
objectstack-fleet commentedon Oct 4, 2026
Seat ruling, patch round 2 on PR #11607 (2026-10-04T10:20Z). Session
session_01CPvhwGcirXqBGEdPSb72TZ,domain:specseat (objectui#10217).The contract review
5978958580reads PASS on head0334c43e. Before the maintainer is asked to approve, the seat answers the two items the record escalated to it:git grepoverpackages/*/srcfinds docblock sentences that still sayBaseSchemacarries, ends in or still carries[key: string]: any, plus the future-tense "which objectui#8347 removes" family. Each one becomes false when this PR merges, and TSDoc ships in the.d.ts. This is the same rule the seat applied on objectui#11598 (ruling B): a PR fixes the notes it makes false. So the original dev has one comment-only patch round, which also carries the record's ① item 9 precision: the §5 #0.1 sub-bullet gains the package-local hand-off-type route (objectui#6356) that the PR itself uses. A new head needs a new contract review record before the sign-off.PartialSchemaenforce-or-remove card is filed: objectui#11608 (bare,Blocked-by: #8347, for triage). It was filed after the inputs that record read were assembled.Not changed: the
propsalias stays option A in the PR, and it remains the maintainer's open choice on the Tier H approval. The PR stays a draft.Generated by Claude Code
objectstack-fleet commentedon Oct 4, 2026
os-dev-report
{ "issue": 8347, "status": "done", "round": "patch round 2 on PR #11607 (seat ruling 5978976059 on contract review 5978958580): rewrite every sentence the removal makes false, plus the AGENTS.md hand-off-type clause", "branch": "claude/issue-8347-baseschema-index-signature", "pr": "https://github.com/objectstack-ai/objectui/pull/11607", "head": "032b9a2d14e20ee729310aee18c69aa048a0f249 (one commit, fast-forward 0334c43e..032b9a2d; main NOT merged; GitHub reads mergeable=true, mergeable_state=behind, draft)", "session": "session_01CPvhwGcirXqBGEdPSb72TZ (the dispatching seat's session; mode:subagent)", "premise_still_valid": true, "summary": "One commit, comment and prose bytes only, 164 files: packages/types 110, components 12, react 8, examples/schema-catalog 7, plugin-dashboard 4, plugin-charts 4, plugin-calendar 3, plugin-view/tree/grid/gantt 2 each, plugin-timeline/map/list/kanban/form/designer 1 each, content/docs/plugins/plugin-chatbot.mdx, AGENTS.md. Every sentence that said BaseSchema (or a node type through it) carries, closes with, ends in or inherits `[key: string]: any`, every future-tense 'objectui#8347 removes' / 'once the index signature is gone' / '#5155 phase removes' removal condition, and every TS2578 note that promised a directive goes unused when its member is deleted, now states what is true at 032b9a2d. Tombstone reasoning is kept and split by face: the zod face still keeps an undeclared key (.passthrough()); the TS face carried the signature until objectui#8347, and a deletion there is now refused on a fresh literal but still rides a widened value, which is what the tombstone still refuses by name. TASK B: AGENTS.md section 5 #0.1 gains one clause in the same sub-bullet (a key only the host writes at runtime is typed on a package-local hand-off type where its producer and consumer live, never on the authoring face, objectui#6356); nothing else in AGENTS.md changed. No changeset entry was needed (the declaration and bump-policy checkers pass as is). The PR body was NOT patched: see deviations, and pr_body_bullet for the exact replacement text.", "files_touched": "git show --name-only --format= 032b9a2d (164 paths). The full before/after of every rewritten sentence is that commit's diff; 299 replacements were logged.", "rewrite_templates": [ "present tombstone reason -> past + face split. BEFORE: '{@link BaseSchema} carries `[key: string]: any`, so DELETING this member would let the retired spelling type-check green and go on doing nothing.' AFTER: '{@link BaseSchema} carried `[key: string]: any` until objectui#8347, and a deletion is still refused only on a fresh literal, so DELETING this member would let the retired spelling type-check green through a widened value and go on doing nothing.' (objectql.ts)", "zod reasoning kept, face named. BEFORE: '{@link BaseSchema} closes with `[key: string]: any` and its Zod twin ends `.passthrough()`. A dropped MEMBER key is therefore KEPT, not refused' AFTER: \"{@link BaseSchema}'s Zod twin ends `.passthrough()` (and the interface closed with `[key: string]: any` until objectui#8347). A dropped MEMBER key is therefore KEPT, not refused, on the Zod face\" (complex.ts; same shape in gantt/kanban/map index.tsx, views.ts, overlay.zod.ts, views.zod.ts and the retired-key test headers)", "future -> past. BEFORE: 'which objectui#8347 removes.' AFTER: 'which objectui#8347 removed.' (widgetDispatch.ts, DashboardEditor.tsx, list-title test, page-size test); 'once objectui#8347 removes ...' -> 'now that objectui#8347 has removed ...' (react tests); 'once `BaseSchema`'s index signature is gone (objectui#8347)' -> 'since objectui#8347 removed `BaseSchema`'s index signature' (components tests); objectql.ts removal conditions -> 'objectui#8347 removed `BaseSchema`'s root index signature (the #5155 phase this waited for), so `Omit` no longer collapses here'", "ceiling blocks. BEFORE: '`BaseSchema` ends in `[key: string]: any`, so an UNDECLARED key read off this type still compiles and still types `any`.' AFTER: '`BaseSchema` ended in `[key: string]: any` when this was written, so an UNDECLARED key read off this type still compiled and typed `any`. ... objectui#8347 removed the signature, so an undeclared read off this type no longer compiles.' (ObjectTree.tsx; same in ObjectChart.tsx, objectql.ts chart ceiling, layout.ts page bound, and the flipped-counter-probe test headers)", "TS2578 class. BEFORE: 'Each directive below fails the build (TS2578) the moment its key stops being declared, because the member then resolves to `any` through `BaseSchema`'s index signature' AFTER: 'Each directive below failed the build (TS2578) the moment its key stopped being declared, while the member resolved to `any` through `BaseSchema`'s index signature. Since objectui#8347 a removal makes the indexed access itself an error, which its directive swallows, so the deletion signal comes from the well-typed counter-probe below' (each file's real deletion guard named: counter-probe literal, Equal row, or derived invariant; where none exists the comment says the file no longer sees a deletion)", "AGENTS.md. BEFORE: '... declare it on the node type that reads it, by reference to the spec row, or fix the producer. ⛔ Never' AFTER: '... or fix the producer; a key only the host writes at runtime is typed on a package-local hand-off type where its producer and consumer live, never on the authoring face (objectui#6356). ⛔ Never'" ], "hits_left_and_why": [ "Other types whose own signature still stands, left as true: ComponentRendererProps; FormField (plugin-form README, form.ts, form-field-zod-coverage test); DashboardConfig's catch-all (designer.ts, dashboard-config test); NormalizedColumn; ActionDef/ActionContext (objectstack#4075 history); QueryParams history; the record-detail/reference-rail renderer schema types; the ObjectView views entry; KanbanCard; spec types (GanttConfig, ObjectFieldLike, FilterCondition, AppLike, AuthUser, DiscoveryInfo, RealtimeConfig); the forwardRef / PropsWithoutRef props-erasure notes; the ten out-of-scope index-signature declaration sites.", "zod-inferred signatures, left as true: ListViewInferred (objectql.ts), the passthrough mirror, z.input of passthrough arms, the calendar block (inferred from a .passthrough() schema; the plugin-calendar README now says so).", "Already true or past tense: every 'until objectui#8347 / since objectui#8347 / used to / Before this card' sentence, the PR's own new text, CHANGELOG.md files and released notes (append-only, not edited), content/docs/releases (not touched).", "Pre-existing and not made false by this PR: ObjectView.namedViewSortArity test header ('ObjectViewSchema.table collapses to a bare index signature (objectui#5102)'), false since the Pick lists, left as is.", "Test-name and assertion-message strings (code, reported not edited): action-callback-retired-7068 it-title 'and beats the inherited index signature'; timeline-dead-keys-retired-6170 it-title 'survives the index signature'; stack-schema-emitted-members it.each title 'not merely via the index signature'; schema-reference-named-list-view-keys-7923 assertion message \"`BaseSchema`'s index signature would swallow an annotation anyway (objectui#7927)\".", "skills/** (forbidden by this dispatch, not edited): the objectui architecture guide and protocol rule still say the published BaseSchema 'declares 21 members plus an index signature' and that props/events 'reach a node through BaseSchema's [key: string]: any index signature'. Both are false at this head; see out_of_scope_findings." ], "tests": "All at 032b9a2d unless noted. (1) Comment-only proof: every changed TS/TSX file printed through the TypeScript printer with removeComments, 0334c43e vs 032b9a2d: 161 files compared, 0 differences; controls on base.ts: a type edit IS detected, a comment edit is NOT. Non-TS: AGENTS.md (one clause), plugin-chatbot.mdx (prose), plugin-calendar README (comment lines inside a code fence only). (2) Forced build under os-verify-lock, TURBO_FORCE=true: turbo build 40 successful, 0 cached, VERDICT command-exit 0 (shared cache not read, written or deleted beyond turbo's own forced run). (3) type-check of all 17 touched workspace packages (types, react, components, plugin-calendar/charts/dashboard/designer/form/gantt/grid/kanban/list/map/timeline/tree/view, example-schema-catalog) via pnpm --workspace-concurrency=2 --filter ... run type-check, two locked batches: every package printed 'type-check: Done', VERDICT command-exit 0 both. (4) eslint on the 161 touched TS files (root eslint.config.js, not type-aware): 161 files reported, 0 errors, 787 warnings, all on unchanged code. (5) check:new-line-citations --base 2e818d0b5: 'VERDICT new-cross-file-line-citations: 0 new citation(s)', exit 0. (6) check:control-bytes OK, exit 0. (7) check:doc-snippets (plugin-chatbot.mdx and a README moved): 777 of 777 blocks judged, 0 failed, exit 0. (8) Changeset checkers: check-changeset-presence exit 0 ('171 source file(s) of 16 released package(s) changed, and this change declares 1 changeset(s)'), check-changeset-no-major 0, check:changeset-claims 0, check:pending-changeset-literals 0, changeset:check 0, so no package entry was added and no level changed. (9) Re-grep with positive control, one script over packages/apps/examples/content/docs/AGENTS.md, CHANGELOGs and releases excluded, patterns: 'objectui#8347 removes', '#5155 phase removes', BaseSchema still carries / closes with / ends in the signature, 'inherits BaseSchema's [key: string]: any', 'reads/resolves as any through the index signature', 'the member then resolves to': HEAD 032b9a2d 0 hits, previous head 0334c43e 88, BASE 2e818d0b5 106. A joined-line sweep (sentences split across lines, comment markers stripped): HEAD 2 hits, both past tense ('used to read', 'Before this card ... reached'), 0334c43e 112, BASE 137.", "mcp_calls": "0", "api_writes": "1 REST write: POST repos/objectstack-ai/objectui/issues/8347/comments (this os-dev-report, through the fleet-write relay, read back). Plus 1 git push (not REST). No PR body PATCH, no labels, no reviewers, no ready flip, no enqueue.", "pr_body_bullet": { "replace_bullet_beginning": "Source comments that still describe the signature in the present tense remain", "with": "- Source comments, test comments and docs that described the signature as live, or said objectui#8347 removes it, are repaired in this PR (comment and prose bytes only). The enumerating commands are `git grep -n -i \"index signature\"`, `git grep -n -F '[key: string]: any'` and `git grep -n 'objectui#8347 remove'` over `packages/`, `apps/`, `examples/` and `content/docs/`, CHANGELOGs and release notes excluded as append-only. What they still find is true at the head: other types' own signatures, the tolerant zod face's `.passthrough()`, and past-tense history. `skills/**` still describes the signature as live and is not edited here, because this dispatch forbids `skills/**`.", "note": "Everything else in the body, the Clause-② line included, stays as it is." }, "deviations": [ "The coordinator's PR BODY step asks the dev to rewrite the Acceptance-notes bullet. The standing dev contract says the dev writes the PR body once, at creation, and never PATCHes it; a later change is named in the report and the seat writes it. The contract wins on conflict, so the body was not touched: the exact replacement is in pr_body_bullet for the seat to apply through the relay." ], "open_questions": [], "out_of_scope_findings": [ "class: b · reach: named producer: the published skills/objectui architecture guide and protocol rule (agent-facing) still teach that BaseSchema declares 21 members 'plus an index signature' and that props/events reach a node 'through BaseSchema's [key: string]: any index signature'; this PR makes both false, and this dispatch forbids skills/** edits · evidence: git grep -n 'index signature' -- skills/objectui/guides/architecture.md skills/objectui/rules/protocol.md · dedupe words: skills BaseSchema index signature teaching copy, props events reach node, architecture.md protocol.md 21 members", "carrier: PR objectstack-ai/objectui#11607 (seat / maintainer) · noted, not filed · since the removal, a directive-only @ts-expect-error over a fresh literal or an indexed access no longer detects a DELETED member (the key is refused as undeclared, or the indexed access errors, and the directive swallows it). Files with no other TS deletion guard: object-kanban-card-title-9606 (cardTitle), object-grid-declared-keys-11068 (the two non-BaseSchema tombstones), object-grid-default-sort-tombstone-5861 (defaultSort), object-grid-show-filters-retired-11068 (showFilters); gantt-flat-config-declared-keys covers its GanttConfig keys through the derived invariant only. The comments now say so; adding an Equal row on the indexed access would restore the leg. Dedupe words: ts-expect-error deletion detection TS2578 tombstone Equal row", "carrier: 承接者:无 · noted, not filed · zod-mirror-parity's KnownDrift entry for complex.zod.ts#DashboardWidgetSchema recorded the slot's BaseSchema fallback as objectui#8347's to retire; objectui#8347 left the zod faces unchanged, so that reservation now has no owner (the comment now says the fallback still stands). Dedupe words: DashboardWidgetSchema BaseSchema fallback union KnownDrift component" ] }Generated by Claude Code
objectstack-fleet commentedon Oct 4, 2026
Claim amendment: patch round 3 on PR #11607 (2026-10-04T11:57Z). This continues claim
5977679107: assignee, branch and worktree name are unchanged. Sessionsession_01CPvhwGcirXqBGEdPSb72TZ,domain:spec#1.Trigger: dev report
5979644768(patch round 2, head032b9a2d). Itsout_of_scope_findingsname two more things this PR makes false or breaks. Under the seat's ruling5978976059(a PR fixes what it makes false, in the same PR), both belong here:skills/objectui/guides/architecture.mdandskills/objectui/rules/protocol.mdstill teach that the publishedBaseSchemadeclares its members "plus an index signature", and thatprops/events(andproperties) reach a node "throughBaseSchema's[key: string]: anyindex signature". Their teaching fences list those keys asBaseSchemamembers. On the TypeScript face this PR makes all of that false.object-kanban-card-title-9606,object-grid-declared-keys-11068,object-grid-default-sort-tombstone-5861andobject-grid-show-filters-retired-11068, an@ts-expect-errordirective used to catch a deleted member through TS2578. Now the undeclared-key error satisfies the directive, so a deletion goes unnoticed. These pins say they check something they no longer check.The round also carries the three test titles and one assertion message that round 2 reported but left unedited, because they now describe the signature as live.
File surface, amended: everything in claim
5977679107plusskills/objectui/**, limited to the sentences and teaching fences the removal makes false. This lifts claim5977679107's "⛔ Noskills/**edit" for those sentences only; that exclusion existed because askills/**path mandates the review tier for the build. Plus the deletion guards in the four named test files, and the four reported test strings.Container & model:
L,mode:subagent,model: CONTRACT_REVIEW_TIER(dispatch-gates --tier --repo objectstack-ai/objectuiover the two skill paths: MANDATORY, the 2026-09-10 published-skills ruling; the one-line downgrade is closed forskills/**). Rounds 1 and 2 were built at the default tier, on a surface with no path mandate.Unchanged: Tier H (
AGENTS.md, and nowskills/**too, under the same approvers); thepropsalias stays option A and remains the maintainer's open choice; the PR stays a draft; a new head needs a new contract review record.Generated by Claude Code
objectstack-fleet commentedon Oct 4, 2026
os-dev-report
{ "issue": 8347, "status": "done", "round": "patch round 3 on PR #11607 (claim 5977679107 amended by 5979679543): the published skill, the silenced deletion guards, the four strings, and the merge of main", "branch": "claude/issue-8347-baseschema-index-signature", "pr": "https://github.com/objectstack-ai/objectui/pull/11607", "head": "09165ac8d78fe269892c7bb6645c3806b7e5336a (pushed; GitHub ref read back equal). Merge commit 774e113bca7f89b6aa2dd9455913c68426a55847 = origin/main b508ac50 merged into 032b9a2d, no conflicts, no rebase, no amend, no force-push. Round commits after it: 50d31423 (skills), 2c8709b7 (guards + strings), de88092c (guard docblocks name the co-guards), 09165ac8 (two lint-disable comment lines). PR stays draft, Tier H.", "session": "session_01CPvhwGcirXqBGEdPSb72TZ (the dispatching seat's session; mode:subagent)", "premise_still_valid": true, "summary": "A. The two published-skill sections that taught a `BaseSchema` with an index signature now state the closed TypeScript face and the unchanged tolerant zod face, with the fresh-literal bound said as AGENTS.md §5 #0.1 says it; their teaching fences drop `props`, `events` (and `properties`), which the published type never declared, and end on the same no-index-signature line as AGENTS.md §4; `props` keeps one sentence stating option A. B. Five test files regain a real deletion guard: a type-level row on the member (an indexed access that is a compile error once the member is gone, with `Equal` pinning the declared or tombstone type), each shown red by a trap-restored deletion and green at HEAD; every existing assertion stays; the gantt file's derived invariant was shown by ablation to catch a deleted `GanttConfig` key, and its three query keys, which that invariant cannot see, got rows. C. Two it-titles, one it.each title and one assertion message are reworded, assertion logic untouched; no baseline, snapshot, allowlist or script references the old titles. D. `main` (b508ac50) is merged by a merge commit; the five packages main moved plus `types` type-check green afterwards; no new red site appeared. The PR body was not PATCHed (contract): the replacements are in pr_body.", "files_touched": "This round, 11 files: skills/objectui/guides/architecture.md, skills/objectui/rules/protocol.md, and packages/types/src/__tests__/{object-kanban-card-title-9606, object-grid-default-sort-tombstone-5861, object-grid-show-filters-retired-11068, object-grid-declared-keys-11068, gantt-flat-config-declared-keys, action-callback-retired-7068, timeline-dead-keys-retired-6170, stack-schema-emitted-members, schema-reference-named-list-view-keys-7923}.test.ts. The merge commit brings main's 49 files (app-shell, console, i18n, plugin-detail, plugin-form, two content/docs/guide pages, six changesets); none overlaps a file this branch edits (comm of the two name lists: empty).", "skill_rewrites": { "architecture.md_warning_paragraph": { "before": "⚠️ The fence below is a deliberately SIMPLIFIED teaching copy of the published `BaseSchema` (…), KEPT rather than replaced by an import: the published interface declares **21** members plus an index signature, and this section teaches the SHAPE, not the member list. Two consequences before you go looking in the `.d.ts`: nothing checks the copy against the real type, and `props` / `events` below are **not declared members** — they reach a node through `BaseSchema`'s `[key: string]: any` index signature, which is why you will not find them in the published member list.", "after": "⚠️ The fence below is a deliberately SIMPLIFIED teaching copy of the published `BaseSchema` (…), KEPT rather than replaced by an import: it teaches the SHAPE, not the member list, and nothing checks the copy against the real type. `BaseSchema` has **no index signature** (objectui#8347), so a key no member declares gets one verdict per face: on the TypeScript authoring face it is a compile error in a fresh typed literal (TypeScript excess-checks only a FRESH object literal, so a value that reached its annotation through a wider variable is not re-checked); on the tolerant zod / JSON face (`.passthrough()`) it is kept, and the named reader decides. That is why `props` and `events` are **absent** from the fence: `props` is the `element:*` config envelope the runtime reads and the TypeScript face does not declare; `events` is read by nothing on either face. The \"Keys Live on the Node\" and \"Actions Are Node Types\" rules in `rules/protocol.md` say who reads each.", "note": "The member count `21` is gone from prose (AGENTS.md #9); the sentence on `props` is the one a B/C flip rewrites." }, "architecture.md_fence": { "before": "members listed: type, id, props (`/** Config envelope — read only by element:* renderers; see rules/protocol.md */ props?: Record of string to any`), bind, className, hidden, disabled, events (`/** Event Handlers */ events?: Record of string to ActionSchema array`), children", "after": "members listed: type, id, bind, className, hidden, disabled, children; the `props` and `events` entries are removed and the fence ends on `// no index signature: a key no member declares is a compile error in a fresh typed literal` (the AGENTS.md §4 precedent). Still a SHAPE copy, not the member list; the fence carries no os:check marker before or after." }, "protocol.md_warning_paragraph": { "before": "⚠️ A deliberately SIMPLIFIED teaching copy of the published `BaseSchema` (…), KEPT rather than replaced by an import: the published interface declares **21** members plus an index signature, and this rule is about the SHAPE, not the full member list. Nothing checks the copy against the real type. `properties`, `props` and `events` are **not declared members** — they reach a node through `BaseSchema`'s `[key: string]: any` index signature, which is exactly why the two rules below have to state who reads each of them.", "after": "⚠️ A deliberately SIMPLIFIED teaching copy of the published `BaseSchema` (…), KEPT rather than replaced by an import: it teaches the SHAPE, not the full member list, and nothing checks the copy against the real type. `BaseSchema` has **no index signature** (objectui#8347): on the TypeScript authoring face a key no member declares is a compile error in a fresh typed literal (TypeScript excess-checks only a FRESH object literal, so a value that reached its annotation through a wider variable is not re-checked); on the tolerant zod / JSON face (`.passthrough()`) it is kept, and the named reader decides. So `properties`, `props` and `events` are **absent** from the fence: `properties` is declared per block on the authoring node types (`AuthoringNode`), not on `BaseSchema`; `props` is the `element:*` envelope the runtime reads and the TypeScript face does not declare; `events` is read by nothing. The two rules below state who reads each." }, "protocol.md_fence": { "before": "members listed: type, id, properties (two comment lines pointing at Keys Live on the Node), props (two comment lines), bind, className, hidden, disabled, events (`// Optional: event handlers`), children", "after": "members listed: type, id, bind, className, hidden, disabled, children; `properties`, `props` and `events` removed; the fence ends on `// no index signature: a key no member declares is a compile error in a fresh typed literal`. No os:check marker before or after." }, "protocol.md_events_paragraph": { "before": "**❌ DO NOT** author an `events` bag. `BaseSchema` declares no `events` member and no renderer reads `schema.events`; \"Rule: Component Schema Structure\" above lists it only because the node accepts any key — `.passthrough()` keeps such a node, judges it by nothing and runs it by nothing (objectui#6497).", "after": "**❌ DO NOT** author an `events` bag. `BaseSchema` declares no `events` member and no renderer reads `schema.events`: a typed literal refuses it (objectui#8347), and the tolerant zod face is `.passthrough()`, so one that arrives as data is kept, judged by nothing and run by nothing (objectui#6497).", "note": "Owed because the fence it pointed at no longer lists `events`; it now mirrors AGENTS.md #4's sentence." }, "line_readings": "architecture.md 104 → 105; protocol.md 372 → 373; skills/objectui/SKILL.md 142 → 142 (the only SKILL.md under skills/); every tracked file under skills/objectui summed 5414 → 5416. The deleted fence entries paid for the prose; no re-wrap was used as currency. The dispatch states no numeric budget; both readings are here for the PR body. Token counts: no sibling gate defines one in this repository, so none is reported.", "producer": "Both landing points are the files the dispatch named; no other producer writes these sections (the skill guides are authored markdown, `check:skills-paths` and `check:skill-eval-tokens` read them and stay green)." }, "guards": [ {"file": "object-kanban-card-title-9606", "member": "ObjectKanbanSchema.cardTitle", "row": "_CardTitleIsADeclaredString = Expect of Equal(TsObjectKanbanSchema['cardTitle'], string | undefined); plus _TitleFieldAliasIsStillDeclared as the third pin's type-level half", "ablation": "member line deleted (anchor hit 1 → 0, blob 56042f8c → a215a913): tsc -p tsconfig.test.json exit 2, 5 errors: the new row (TS2339 'cardTitle' does not exist on type 'ObjectKanbanSchema'), the two fresh literals CANONICAL_BOARD / BOTH_SPELLINGS_BOARD (TS2353), and the zod-mirror-parity mirrored-undeclared ledger (2 rows). The directive stayed used (no TS2578). Restored: blob == HEAD, git diff HEAD empty. At HEAD: exit 0. Note: the round-2 reading 'no other TS deletion guard' was partly wrong for this file — the fresh literals already refused the deletion; the file's docblock now says so, and its older claim that the parity ratchet is blind to this deletion is dated with the re-measurement beside it."}, {"file": "object-grid-default-sort-tombstone-5861", "member": "ObjectGridSchema.defaultSort (?: never)", "row": "_DefaultSortIsATombstone = Expect of Equal(ObjectGridSchemaType['defaultSort'], undefined)", "ablation": "deleted (1 → 0, blob → f10defea): exit 2, 5 errors: the new row (TS2339), the parity ledger (3 rows incl. ObjectViewSchema's), and `ObjectGridSlotKey` not satisfying `keyof ObjectGridSchema` in objectql.ts (TS2344). Directive stayed used. Restored: blob == HEAD. HEAD: exit 0."}, {"file": "object-grid-show-filters-retired-11068", "member": "ObjectGridSchema.showFilters (?: never)", "row": "_ShowFiltersIsATombstone = Expect of Equal(ObjectGridSchemaType['showFilters'], undefined); plus _ListViewShowFiltersIsLive / _ObjectViewShowFiltersIsLive (boolean | undefined) as the live controls", "ablation": "deleted via a three-line anchor unique to the grid member (1 → 0, blob → 4f87d17c): exit 2, 3 errors: the new row (TS2339) and the parity ledger (2). Directive stayed used. Restored: blob == HEAD. HEAD: exit 0. First attempt of this leg was refused by the tool (replacement text was a prefix of the anchor, count did not rise); re-run with a distinct marker line — the refusal is in the log, nothing was measured on it."}, {"file": "object-grid-declared-keys-11068", "member": "ObjectGridSchema.rowSpecActions and .bulkSpecActions (?: never) — the two tombstones BaseSchema does not declare", "row": "_RowSpecActionsIsATombstone / _BulkSpecActionsIsATombstone = Expect of Equal(…, undefined); `name` / `placeholder` keep their TS2578 guard (a deletion falls back to BaseSchema's string) and get no row", "ablation": "rowSpecActions deleted (blob → 5c55b337): exit 2, 3 errors: its row (TS2339) + parity ledger (2). bulkSpecActions deleted (blob → ba26ad43): exit 2, 3 errors: its row (TS2339) + parity ledger (2). Directives stayed used. Restored both: blob == HEAD. HEAD: exit 0."}, {"file": "gantt-flat-config-declared-keys", "member": "GanttConfig keys (derived invariant) and the three query keys staticData / filter / sort", "row": "existing `noGaps` row (FlatFaceGaps) for GanttConfig keys; new _StaticDataIsDeclared (any[] | undefined), _FilterIsDeclared (any[] | undefined), _SortIsDeclared (SortConfig[] | undefined)", "ablation": "colorField deleted (blob → da6e3a03): exit 2, 3 errors: `noGaps` (TS2322 Type 'true' is not assignable to type '\"colorField\"', naming the key) + parity ledger (2) — the derived invariant genuinely catches a deleted GanttConfig key. staticData deleted (blob → e340ba8b): exit 2, 4 errors: its row (TS2339), object-calendar-record-source-7313's read of the member, parity ledger (2). filter deleted (blob → 228a500f): exit 2, 3 errors: its row + ledger (2). sort deleted (blob → 6b4116f3): exit 2, 4 errors: its row, sort-string-arm-retired-8221's read, ledger (2). Directives stayed used in every leg. Restored each: blob == HEAD. HEAD: exit 0."} ], "ablation_protocol": "All legs on the committed head de88092c under os-verify-lock, through objectstack's scripts/ablation-replace.mjs in WRAP mode (trap-restored), cwd in the objectui worktree: per leg the tool printed 'anchor hits 1 time(s), as declared', the blob move, and 'ok restored: blob == HEAD (56042f8cfdaf) and `git diff HEAD` is empty'; this driver re-read blob == HEAD and git diff HEAD empty after every leg; final git status --short empty. Nine legs held the lock 268s (shared-box seconds). The final head 09165ac8 differs from de88092c by four comment lines in gantt-flat-config-declared-keys.test.ts (git diff --stat: 1 file, 4 insertions), and the types test program was re-run green there.", "four_strings": [ {"file": "action-callback-retired-7068", "before": "refuses both retired keys at compile time, in the form authors actually write — and beats the inherited index signature", "after": "refuses both retired keys at compile time, in the form authors actually write — by name, as `never` tombstones, not as undeclared keys"}, {"file": "timeline-dead-keys-retired-6170", "before": "refuses them in the form authors actually write — survives the index signature", "after": "refuses them in the form authors actually write — by name, as `never` tombstones on a fresh literal"}, {"file": "stack-schema-emitted-members (it.each)", "before": "declares `%s` in the emitted declaration, not merely via the index signature", "after": "declares `%s` as a named member of the emitted declaration, not a key a mapped type dropped"}, {"file": "schema-reference-named-list-view-keys-7923 (assertion message fragment)", "before": "`BaseSchema`'s index signature would swallow an annotation anyway (objectui#7927).", "after": "the typed-literal refusal objectui#7927 ruled (executed by objectui#8347) never sees a JSON fence."}, {"references_moved": "none: git grep over all tracked files for 'beats the inherited', 'survives the index', 'not merely via the', 'would swallow an annotation' outside the four files hit only an unrelated docblock sentence in data-display.ts ('`?: never` here beats the inherited `any`'), which is not a title reference; no baseline, snapshot, allowlist or script names these titles."} ], "post_merge_typecheck": "Merge base 2e818d0b5; main moved apps/console, packages/app-shell, packages/i18n, packages/plugin-detail, packages/plugin-form (plus content/docs and .changeset). After a forced turbo build of ./packages/* (TURBO_FORCE=true, scratch --cache-dir, 'Tasks: 39 successful, 39 total', 'Cached: 0 cached', VERDICT command-exit 0), pnpm --workspace-concurrency=2 --filter … run type-check under the lock: batch A app-shell + console both 'type-check: Done', VERDICT command-exit 0, 0 'error TS'; batch B i18n + plugin-detail + plugin-form + types all 'Done', VERDICT command-exit 0, 0 'error TS'. No new red site; nothing to adjudicate against the fork ACCEPT classes.", "pr_body": { "note": "Not PATCHed (contract). Each item is {replace_beginning, with}; the `Clause-②: yes (narrowing)` line is untouched. R3 is given against both possible current beginnings (the original bullet, and round 2's proposed text if the seat applied it). R4 and R5 are optional completeness items, not corrections.", "R1": {"replace_beginning": "Governed: this diff touches `AGENTS.md`, so the PR stays a draft", "with": "Governed: this diff touches `AGENTS.md` and two published-skill files (`skills/objectui/guides/architecture.md`, `skills/objectui/rules/protocol.md`), so the PR stays a draft until an authorized approval is on it (`node scripts/check-governed-queue-guard.mjs --test` over the three answers GOVERNED, 3 of 3: the `skills/**` catalog row twice, the `AGENTS.md` row once). Session: `https://claude.ai/code/session_01CPvhwGcirXqBGEdPSb72TZ` (PM loop round 5, claim `5977679107`, amended for patch round 3 by `5979679543`)."}, "R2": {"replace_beginning": "**H3, skill fences.** `check:skill-examples` exits 0 under the removal at BASE and on the final head. No `skills/**` path is edited.", "with": "**H3, skill fences.** `check:skill-examples` exits 0 under the removal at BASE and on every head since. Patch round 3 edits the two `skills/**` files whose prose the removal made false: the architecture guide's \"JSON Protocol\" section and the protocol rule's \"Component Schema Structure\" section said the published `BaseSchema` declares its members plus an index signature, and that `props` / `events` / `properties` reach a node through it. Both now state the two verdicts a key no member declares gets, one per face (a compile error in a fresh typed literal on the TypeScript face, with the fresh-literal bound said as AGENTS.md §5 #0.1 says it; kept and judged by the named reader on the tolerant zod face), and their teaching fences drop the three keys `BaseSchema` never declared and end on the same no-index-signature line as AGENTS.md §4. `props` keeps one sentence stating option A, so a flip to B or C is a one-sentence edit. Neither fence is a marked example; the gate, `check:skill-eval-tokens` and `check:skills-paths` stay green. Line readings: architecture.md 104 to 105, protocol.md 372 to 373, the bundle 5414 to 5416 — the deleted fence entries paid for the prose."}, "R3a": {"replace_beginning": "- Source comments that still describe the signature in the present tense remain", "with": "- Source comments, test comments, docs and the published skill that described the signature as live, or said objectui#8347 removes it, are repaired in this PR (patch rounds 2 and 3). The enumerating commands are `git grep -n -i \"index signature\"`, `git grep -n -F '[key: string]: any'` and `git grep -n 'objectui#8347 remove'` over `packages/`, `apps/`, `examples/`, `content/docs/` and `skills/`, CHANGELOGs and release notes excluded as append-only. What they still find is true at the head: other types' own signatures (`ComponentRendererProps`, `AuthUser`, `FormField`, a widget's own props type, the field-widget `data-` attribute signature, `QueryParams`' statements), the tolerant zod face's `.passthrough()`, and past-tense history.\n- The deletion guards the removal silenced are restored (patch round 3). While the signature stood, an `@ts-expect-error` over a tombstone or a typed member also failed (TS2578) when its member was deleted; since the removal the undeclared key satisfies the directive. `object-kanban-card-title-9606`, `object-grid-default-sort-tombstone-5861`, `object-grid-show-filters-retired-11068`, `object-grid-declared-keys-11068` and `gantt-flat-config-declared-keys` each gain a type-level row that is a compile error when its member is deleted and pins the declared or tombstone type; each was shown red by a trap-restored deletion of its member and green at HEAD (readings on the card). Four test titles and one assertion message that described the signature as live are reworded, assertion logic untouched."}, "R3b": {"replace_beginning": "- Source comments, test comments and docs that described the signature as live, or said objectui#8347 removes it, are repaired in this PR (comment and prose bytes only).", "with": "(the same two bullets as R3a)"}, "R4_optional": {"insert_after_item_beginning": "7. **The changeset.**", "with": "8. **Patch round 3, after the merge of `main` at `b508ac50`.** The two published-skill sections (H3 below); the five restored deletion guards and the four reworded strings (Acceptance notes); `main` merged by a merge commit, with the type-check of every package `main` moved since the merge base green afterwards."}, "R5_optional": {"append_to_paragraph_beginning": "**改了什么**:", "with": "已发布技能包(`skills/objectui`)里两处讲 `BaseSchema` 形状的教学文案同步改写——它们原先说该类型带索引签名、`props`/`events` 由签名承接,去掉签名后已不成立;因此本 PR 的受管面除 AGENTS.md 外还含 `skills/**`,同一份批准覆盖两者。"} }, "hits_left_and_why": [ "skills/objectui/guides/auth-permissions.md, two sentences on `AuthUser`'s own `[key: string]: unknown` (deliberate, better-auth projection) — AuthUser's own signature, true, not this PR's.", "skills/objectui/guides/data-integration.md, '`QueryParams` declares those nine keys and **no index signature**' — a QueryParams statement, true (the published interface declares no signature; measured, see out_of_scope_findings for the one sentence in the same guide that contradicts it).", "skills/objectui/guides/plugin-development.md, `MyWidgetProps`'s own `[key: string]: any` in a widget's props type, and the `data-` attribute signature of the field-widget DOM props — other types' own signatures, true.", "skills/objectui/guides/architecture.md and rules/protocol.md: the only remaining 'index signature' / 'objectui#8347' hits are this round's own sentences and the two fence comment lines.", "Re-grep with positive control: the four false-claim patterns ('plus an index signature', 'reach a node through', 'declares **21**', the `[key: string]: any` index-signature phrase) over skills/ at HEAD 09165ac8: 0 hits (git grep exit 1); at 032b9a2d: 6 hits." ], "tests": "Exit codes captured before any pipe; heavy runs under os-verify-lock (slots issue-8347-r3-*), TURBO_FORCE=true on the one turbo run. (1) Forced build, ./packages/*: 'Tasks: 39 successful, 39 total', 'Cached: 0 cached', VERDICT command-exit 0 (4m26s shared-box). (2) tsc -p packages/types/tsconfig.test.json at the final head 09165ac8: VERDICT command-exit 0, 0 'error TS'. (3) Post-merge type-check: see post_merge_typecheck (6 packages Done, 0 errors). (4) vitest at de88092c: pnpm exec vitest run packages/types/ → 'Test Files 353 passed (353)', 'Tests 9419 passed (9419)', VERDICT command-exit 0; the final head differs by 4 comment lines in one of those files. (5) Ablation: nine legs, see guards and ablation_protocol. (6) eslint (root config) on the nine touched test files: at de88092c 0 errors / 2 warnings (no-explicit-any on the two `any[]` rows that restate the members' declared type); at 09165ac8 the two rows carry a per-line disable with the reason, eslint exit 0, 0 problems. Skills are markdown, outside eslint. (7) check:skill-examples exit 0 'Every marked skill example holds up against the built types.' (8) check:skill-eval-tokens exit 0 'Every must_contain token is taught by its own skill bundle.'; check:skills-paths exit 0 (89/90 stated paths resolve, 1 baselined, unchanged). (9) check:control-bytes exit 0 at the final head; self-scan grep -naP over the touched files: no hits. (10) check:new-line-citations --base b508ac50 at the final head: 'VERDICT new-cross-file-line-citations: 0 new citation(s)', exit 0. (11) Changeset checkers at 2c8709b7 (tree since then: comment-only test edits): check-changeset-presence exit 0 ('171 source file(s) of 16 released package(s) changed, and this change declares 1 changeset(s): .changeset/8347-baseschema-closed-face.md'), check-changeset-no-major 0, check:changeset-claims 0 ('No pending changeset names a file this change touches'), check:pending-changeset-literals 0, changeset:check 0 → no entry added, no level changed, Clause-② line untouched; skills/** is not a workspace package. (12) NOT RUN, declared: check:doc-snippets — this round moves no content/docs page or README, and the gate's header says it does not judge skills/**; the two doc pages the merge brought are main's. (13) Governed guard: node scripts/check-governed-queue-guard.mjs --test over AGENTS.md and the two skill files → GOVERNED 3 of 3 (skills/** x2, AGENTS.md x1), exit 3.", "mcp_calls": "0", "api_writes": "1 REST write: POST repos/objectstack-ai/objectui/issues/8347/comments (this os-dev-report, through the fleet-write relay, read back). Plus 1 git push (not REST). No PR body PATCH, no labels, no assignees, no reviewers, no ready flip, no enqueue, no claim comment.", "deviations": [ "Worktree: the dispatch said to create `objectui-issue-8347` from the remote branch; a stale local branch of that name already existed at the remote head 032b9a2d with the right upstream (the previous dev removed only the worktree), so the worktree was attached to that branch instead of creating a duplicate, which git refuses. Verified by git worktree list before and after.", "check:doc-snippets not run, with the reason in tests (12). Every other verification the dispatch listed ran." ], "open_questions": [], "out_of_scope_findings": [ "carrier: 承接者:无 · noted, not filed · skills/objectui/guides/data-integration.md's 'Common data integration mistakes' bullet says that for `QueryParams` options spelled without the `$` prefix 'the index signature accepts them, nothing reads them', while the same guide's ⚠️ paragraph (and the published interface, which declares no signature) says an unprefixed `limit` is a compile error at the call site. Pre-existing, not made false by this PR, agent-facing prose only; one sentence to fix when that guide is next touched. Dedupe words: QueryParams index signature accepts them common mistakes data-integration.", "carrier: PR objectstack-ai/objectui#11607 · noted in this round's docblocks · the zod-mirror-parity mirrored-undeclared ledger reddens on every TS-side deletion of a zod-declared member (measured in all nine legs), so it is a second deletion guard for these members; object-kanban-card-title-9606's older claim that the ratchet was blind to this deletion is now dated in place with the re-measurement. No action beyond that." ] }Generated by Claude Code
objectstack-fleet commentedon Oct 4, 2026
Seat ruling, patch round 4 on PR #11607 (2026-10-04T12:55Z). Session
session_01CPvhwGcirXqBGEdPSb72TZ,domain:specseat. Claim5977679107continues, as amended by5979679543: same tier, same branch.Contract review
5980141759reads PASS on head09165ac8. Its ③ escalates four items to the seat. The answers:objectos-integration.mdxApp block: fixed in this PR (round 4). This PR wrote<SchemaRenderer dataSource={dataSource}>there, and a nearby comment offers that prop as one way to hand over the adapter.SchemaRendererreads its data source fromSchemaRendererContext, so an explicitdataSourceprop reaches only the root component.AGENTS.mdImplement visual designer for Object UI schemas #1 namesSchemaRendererProvideras the injection point. The old block was worse, but this PR authored the new sentence, and a published guide should not teach an injection point that never reaches the nestedobject-view. Same rule as5978976059.complex.zod.ts#DashboardWidgetSchemacomponentledger entry: the fallback stays, by objectui#8344's decision. The seat's Q3 = A (5977022487) put the zodcomponentslot'sBaseSchemaarm out of this card's scope: the zod face belonged to spec(types): derive and export the strict authoring twin of the node face — the #5250 strict face itself, no consumer wired #8345, and objectui#8344 chose that arm on purpose. Both cards are closedcompleted, and no open card retires the arm. Round 4 rewrites the ledger comment so its exit condition says exactly that, and stops reading as a reservation for objectui#8347. Comment bytes only.skills/objectui/guides/data-integration.md'sQueryParams"common mistakes" bullet: pre-existing, not made false by this PR. Not a rider here and not a card: no reader is in hand. Recorded as an acceptance note for whoever next edits that guide; a governed path, so it needs its own approval then.propsA / B / C: unchanged. The maintainer's call on the Tier H approval.Round 4 changes doc and comment bytes only, so a new head needs a new contract review record. The PR stays a draft.
Generated by Claude Code
objectstack-fleet commentedon Oct 4, 2026
os-dev-report
{ "issue": 8347, "status": "done", "round": "patch round 4 on PR #11607 (seat ruling 5980160589 on contract review 5980141759 ③): the integration guide's adapter injection point, and the widget-slot ledger entry's exit condition; doc and comment bytes only", "branch": "claude/issue-8347-baseschema-index-signature", "pr": "https://github.com/objectstack-ai/objectui/pull/11607", "head": "89c2138f253dc9daa101f058f417e23d800fd4c0 (ONE commit on top of 09165ac8, fast-forward, pushed; GitHub reads head 89c2138f, draft). No merge of main this round (GitHub reported no conflict; mergeable_state reads `blocked`, which is the missing approval, not a conflict). No rebase, no amend, no force-push.", "session": "session_01CPvhwGcirXqBGEdPSb72TZ (the dispatching seat's session; mode:subagent)", "premise_still_valid": true, "summary": "A. content/docs/guide/objectos-integration.mdx: the App block this PR rewrote handed the adapter as `dataSource={dataSource}` on `SchemaRenderer`; the renderer reads its data source from `SchemaRendererContext` (the `useContext(SchemaRendererContext)` read in SchemaRenderer.tsx) and forwards an explicit prop only to the root component, so the nested `object-view` never got it. The block now wraps the renderer in `SchemaRendererProvider dataSource={dataSource}` (imported as `import { SchemaRenderer, SchemaRendererProvider } from '@object-ui/react'`, the spelling building-crud-app.md, data-source.md, quick-start.md and data-objectstack.mdx use), with a four-line comment saying why; the \"System Objects Integration\" comment names only the provider. No other line this PR added hands an adapter to `SchemaRenderer` as a prop. B. zod-mirror-parity's `complex.zod.ts#DashboardWidgetSchema` `component` entry: the comment now says the mirror slot's `BaseSchema` fallback STAYS by objectui#8344's decision, that objectui#8347's Q3 = A (ACCEPT 5977022487) put the zod face out of that card's scope, that no open card retires the arm and narrowing it is a mirror change, and that this entry and the `widgets` one above are deleted when a card does retire it. The `widgets` entry and every other comment were checked: no sibling repeats the reservation. Comment bytes only, proven with the TypeScript printer. PR body: nothing becomes false; two optional completeness items in pr_body.", "files_touched": "2 files, 1 commit (89c2138f): content/docs/guide/objectos-integration.mdx (+40/−33), packages/types/src/__tests__/zod-mirror-parity.test.ts (+7/−6, comment bytes only).", "task_a": { "app_block": {"before": "a `div` (className min-h-screen bg-background) wrapping a `SchemaRenderer` element carrying `dataSource={dataSource}` and `schema={{ type: 'page', template: 'header-sidebar-main', regions: [...] }}`; import line `import { SchemaRenderer } from '@object-ui/react';`", "after": "a `SchemaRendererProvider` element carrying `dataSource={dataSource}`, wrapping the same div and a `SchemaRenderer` element carrying `schema={{ ... }}` and no `dataSource` prop; import line `import { SchemaRenderer, SchemaRendererProvider } from '@object-ui/react';`; a comment inside `App` says the adapter is installed once by the provider, every node including the nested `object-view` reads it from that context, and a `dataSource` prop on `SchemaRenderer` itself would only be forwarded to the root component. The schema literal is unchanged (regions, header-bar, navigation-menu, object-view)."}, "provider_props": "`SchemaRendererProvider` (packages/react/src/context/SchemaRendererContext.tsx, re-exported from the package root) takes `children`, `dataSource: DataSource | null | undefined`, and optional `debug`, `debugFlags`, `apiFetch`; the block passes `dataSource` only.", "comment": {"before": "// The adapter is handed to the renderer (`SchemaRenderer dataSource={objectStackAdapter}` as a JSX prop, spelled with angle brackets in the source) // or `SchemaRendererProvider`), never written on the node: a node's `dataSource` // is the spec's per-element binding, not an adapter.", "after": "// The adapter is installed above the renderer by `SchemaRendererProvider` // (`dataSource={objectStackAdapter}`, from `@object-ui/react`), never written on // the node: a node's `dataSource` is the spec's per-element binding, not an adapter."}, "added_lines_audit": "git diff b508ac50 89c2138f over content/docs, skills, examples, READMEs: the added lines carrying `dataSource=` were three — the App block (fixed), and the two plugin-calendar.mdx blocks (`EventClickCalendar`, `DateClickCalendar`), which pass `dataSource={dataSource}` to `ObjectCalendar`, the component itself, whose props declare `dataSource?: DataSource` (ObjectCalendar.tsx) — a component prop the component reads directly, not a `SchemaRenderer` prop, so they are correct and untouched. The one added comment line that named the prop is the rewritten one above.", "occurrences_on_main_not_edited": [ "content/docs/guide/objectos-integration.mdx, the \"Unit Tests\" block under Testing & Quality Assurance: a `SchemaRenderer` element carrying `schema={{ type: 'object-grid', properties: { objectName: 'contact' } }}` and `dataSource={mockDataSource}` — pre-existing (this PR's hunks in the file are the App block and the system-objects comment only), fragment-marked.", "content/docs/utilities/data-objectstack.mdx: the inline prose `SchemaRenderer schema={mySchema} dataSource={dataSource}` in the sentence about when to prefer the provider.", "packages/data-objectstack/README.md: the quick-start block passing `dataSource={dataSource}` to `SchemaRenderer`.", "examples/schema-catalog/test/catalog-gallery-render.test.tsx and plugin-dashboard-gallery-render.test.tsx: test harness renders passing `dataSource={galleryDataSource}` to `SchemaRenderer` (test code; whether the gallery relies on root-component forwarding is its own question, not read here)." ] }, "task_b": { "entry": "WiderThanDeclared, 'complex.zod.ts#DashboardWidgetSchema': 'component'", "before": "… so it accepts a `component` node the declaration now refuses. That fallback was left for objectui#8347 to retire with the index signature, ⛔ not this ledger's: narrowing it here is a mirror change. objectui#8347 removed the TS signature and left the zod faces unchanged, so the fallback still stands. When it goes, this entry and the `widgets` one above measure clean and are deleted (clause 4 above).", "after": "… so it accepts a `component` node the declaration refuses. That fallback STAYS, by objectui#8344's decision: the card that added the slot chose that arm on purpose, and objectui#8347's Q3 = A (the seat's ACCEPT `5977022487`) put the zod face out of that card's scope, so the TS index-signature removal left it untouched. ⛔ Not this ledger's to narrow: that is a mirror change, and no open card retires the arm. When a card does retire it, this entry and the `widgets` one above measure clean and are deleted (clause 4 above).", "siblings_checked": "The `widgets` entry above it (CONCRETE `widgets`, objectui#11466) says the slot is inherited through the element and points at the `component` entry; it carries no reservation and is unchanged. Every other `objectui#8347` mention in the file (the header's five-entry note, the INTERFACE-TO-PASSTHROUGH entries, the `until objectui#8347` history sentences, the `operators` note, the real-reference import comment) was read: none reserves the fallback for this card. The file's other `DashboardWidgetSchema` mentions (the header's entry-count history around objectui#8344 and the `6 entries` figure block naming the two CONCRETE arms) describe history, not an exit condition.", "comment_only_proof": "TypeScript printer with removeComments over HEAD's (09165ac8) and the committed (89c2138f) file: raw 453143 → 453276 bytes, printed 144552 → 144552 bytes, printed-equal true. Controls on the same instrument: a comment-word mutation is NOT detected (false, as expected); a one-token type mutation of the entry's key literal IS detected (true, as expected)." }, "pr_body": { "note": "Not PATCHed. Nothing in the body as read at this head becomes false: item 5 says the `objectos-integration.mdx` page block now authors `regions`, which still holds, and no body sentence describes the adapter as a `SchemaRenderer` prop or the ledger entry's exit condition. Two OPTIONAL completeness items for the seat:", "R1_optional": {"insert_after_item_beginning": "8. **Patch round 3, after the merge of `main` at `b508ac50`.**", "with": "9. **Patch round 4, doc and comment bytes only.** The integration guide's App block installs the adapter through `SchemaRendererProvider dataSource` (the renderer reads it from `SchemaRendererContext`; a `dataSource` prop on `SchemaRenderer` reaches only the root component), and its system-objects comment names only the provider. The parity ledger's `complex.zod.ts#DashboardWidgetSchema` `component` entry says the mirror slot's `BaseSchema` fallback stays by objectui#8344's decision, with no open card retiring it, instead of reserving it for this card."}, "R2_optional": {"replace_beginning": "5. **Docs.** The 13 listed doc blocks plus the `objectos-integration.mdx` page block (now `regions`)", "with": "5. **Docs.** The 13 listed doc blocks plus the `objectos-integration.mdx` page block (now `regions`, and since round 4 rendered under `SchemaRendererProvider`)"} }, "tests": "Exit codes captured before any pipe; heavy runs under os-verify-lock (slots issue-8347-r4-*; the box was contended: the build waited 405s and the verify batch 417s in the queue); TURBO_FORCE=true on the one turbo run with a scratch --cache-dir (the shared turbo cache not read, written or deleted). (1) Forced build, ./packages/*: 'Tasks: 39 successful, 39 total', 'Cached: 0 cached', VERDICT command-exit 0. (2) pnpm check:doc-snippets on the edited tree (bytes equal to 89c2138f): 'Semantic phase: 777 of 777 block(s) judged, 0 failed.', VERDICT command-exit 0 — the rewritten App block is in the compiled population (a `typescript` fence, no fragment marker). (3) tsc -p packages/types/tsconfig.test.json: tsc-exit=0, 0 'error TS'. (4) pnpm exec vitest run packages/types/src/__tests__/zod-mirror-parity.test.ts: 'Test Files 1 passed (1)', 'Tests 37 passed (37)', vitest-exit=0 (the lock wrapper's batch verdict covered the last part only, so both parts' own exit codes were written to their logs and read: 0 and 0). (5) Comment-only proof: see task_b.comment_only_proof. (6) pnpm check:new-line-citations --base b508ac50 at 89c2138f: 'VERDICT new-cross-file-line-citations: 0 new citation(s)', exit 0. (7) pnpm check:control-bytes at 89c2138f: OK, exit 0; self-scan grep -naP over the two files: no hits. (8) Changeset checkers not re-run: this round touches one doc page and comment bytes in one test file, the declaration (`.changeset/8347-baseschema-closed-face.md`) is unchanged, and `Changeset Declaration` reads the same source-file set it read at 09165ac8 plus one test file in `packages/types`, already a declared package. (9) Worktree removed after the push (git worktree remove without --force, exit 0); scratch turbo cache deleted.", "mcp_calls": "0", "api_writes": "1 REST write: POST repos/objectstack-ai/objectui/issues/8347/comments (this os-dev-report, through the fleet-write relay, read back). Plus 1 git push (not REST). No PR body PATCH, no labels, no assignees, no reviewers, no ready flip, no enqueue, no auto-merge, no claim comment.", "deviations": [], "open_questions": [], "out_of_scope_findings": [ "carrier: 承接者:无 · noted, not filed · four pre-existing `SchemaRenderer dataSource=` prop occurrences on main (the guide's Unit Tests fragment block, data-objectstack.mdx's inline sentence, data-objectstack's README quick-start block, two schema-catalog gallery test harnesses) teach or use the injection point the seat's item 1 says reaches only the root component; not this PR's lines, listed in task_a.occurrences_on_main_not_edited and not edited. Dedupe words: SchemaRenderer dataSource prop root component SchemaRendererProvider data-objectstack README." ] }Generated by Claude Code
objectstack-fleet commentedon Oct 4, 2026
ACCEPT: PR #11607 at head
89c2138f(2026-10-04T13:43Z)Seat
domain:spec @ objectui(objectui#10217), sessionsession_01CPvhwGcirXqBGEdPSb72TZ. Contract review of record:5980631123PASS on head89c2138f253dc9daa101f058f417e23d800fd4c0, atCONTRACT_REVIEW_TIER. Records on earlier heads:5978769372(FAIL, ② only),5978958580(PASS),5980141759(PASS).Rounds. The build round, then four patch rounds:
Clause-②arm.5978976059).main(claim amendment5979679543, at the review tier).5980160589).Round 1 answered the FAIL on the
Clause-②arm. Rounds 2 to 4 were each the seat's "fix what this PR makes false, in this PR", not a rework of the change.Checklist, read by the seat at this head:
main.Fixes #8347. That is the only closing keyword in the body: no closing verb sits next to any other card number.Clause-②: yes (narrowing), the same as the changeset's line.content/docs/releases/path.5953788689/5977022487adjudicated, or to a ruling above.AGENTS.md,skills/objectui/guides/architecture.md,skills/objectui/rules/protocol.md(Tier H).success, 3skippedby design, 0 failed.Changeset sentences checked against the diff (
.changeset/8347-baseschema-closed-face.md):.passthrough(), andComponentRendererPropskeeps its signature.PartialSchema<T>now works as written.visibleWhenis the spec'sEvaluatedExpressionInput, by reference, with a non-transforming zod twin.TimelineRenderSchemagains one optional member, so it ships asminor.props, the legacy alias ofproperties… the renderer still reads it" matchesSchemaRenderer's legacy-alias handling (the cross-channel alias-precedence test).Doc sentences checked against the diff:
api/schema-reference.md: thevisibleWhenrow, and "exhaustive for declared members; the two faces differ on accepted keys".wrapperClassnotes ("what was thenBaseSchema's index signature").core/schema-renderer.mdx: the abridgedBaseSchemaand "none of them carries an index signature". This holds at node level: the ten remaining signatures inpackages/types/srcsit on field entries, config types and nested members, not on a node type.guide/architecture.md:label.guide/ci-cd-pipeline.md: the out-of-scope sentence.guide/objectos-integration.mdx: theregionspage, theSchemaRendererProviderinjection,table.columns.plugins/plugin-calendar.mdx: click handlers asObjectCalendarprops.plugins/plugin-map.mdx:ObjectMapBlockNode, andonMarkerClickforwarded to the root map.plugins/plugin-chatbot.mdxandplugins/plugin-form.mdx.The maintainer's open choice: the
propsalias on the TS face. The PR writes A. If B or C is chosen instead, these move:AGENTS.md§4;Filed from this card: objectui#11608 (
PartialSchemaenforce-or-remove,Blocked-by: #8347, triaged p3).Acceptance notes (read, not filed; no named reader):
ObjectChartBlock's pre-gateschemaprop isBaseSchema, so a fresh literal there is excess-checked againstBaseSchemaitself. In-tree callers pass typed nodes. Retyping the prop is plugin-charts' own choice.RemoveIndexSignaturestrips nothing now, andobject-view-slot-key-lists'formPickmay return toOmit. Both are cleanup.complex.zod.ts#DashboardWidgetSchemacomponentfallback stays, by objectui#8344's decision. The ledger comment now says so.skills/objectui/guides/data-integration.md'sQueryParams"common mistakes" bullet contradicts the same guide. It predates this PR.SchemaRenderer dataSource=prop spellings onmain: the integration guide's Unit Tests fragment, adata-objectstack.mdxsentence, thedata-objectstackREADME quick-start, and two schema-catalog gallery harnesses. The prop reaches only the root component, so these are correct wherever the root is the data component. Not measured as broken, so not filed (the record5980631123escalated them as a candidate prose card; with no measured wrong result and no named reader, the filing gate keeps them a note).ObjectView.namedViewSortArity's header has been false since thePicklists landed. It is not this PR's.Landing: Tier H. The PR stays a draft, carries
needs-user-decision, and has review requested fromos-zhuangandhotlong. Once an APPROVED review by an account inGOVERNED_APPROVERSis on it, this seat lands it through the queue:pr_ready+automerge_enablethrough the relay, then the post-merge duties. No agent seat approves.Generated by Claude Code
feat(types)!: retire the `PartialSchema` export, which had no reader;…
feat(types)!: refuse both content channels on `input` (objectui#9256,…
feat(types)!: `BaseSchema` loses its index signature, so a typed node…
feat(types)!: retire the `PartialSchema` export, which had no reader;…