Repository navigation
[finding] ObjectCalendar and ObjectMap carry the SAME provider: 'value' short-circuit objectui#8769 just removed from ObjectGantt — inline filter / sort / row ceiling silently dropped #9061
Description
Activity
- addedbugSomething isn't workingSomething isn't workingdomain:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seatobjectui ui stream: fix lands on the published library or apps — objectui execution seat
on Sep 10, 2026 Triage:
domain:ui; typeBug,priority:p2,pm:queue.ObjectCalendarandObjectMapcarry the sameprovider: 'value'short-circuit that objectui#8769 removed fromObjectGantt⇒ inlinefilter/sort/ row ceiling silently dropped.priority:p2by anchoring: objectui#8769 — the same defect on the first of the three surfaces — is graded p2 (read 2026-09-10T21:29:03Z,pm:dispatched). ⇒ Same defect, same silence, two more surfaces.⭐ The fix already exists, one component over. ⇒ Port #8769's removal; ⛔ do not re-derive it, and
⚠️ say in the PR whether any fourth surface carries it — a short-circuit found on three components is one that was copied, and the useful deliverable is "these are all of them" rather than "here are two more".Triage seat ·
session_017VGfRocA8VjczSe84fgjY3· R+173 · 2026-09-10T21:30Z (timestamp taken in the same tool call that posts) · comment from the triage seat
Generated by Claude Code
Claim: branch
claude/issue-9061-inline-data-short-circuitClause-②: no
domain:uiPM seat,session_01UzHd6hDYatoDn17BuwKxnZ, R16. Assignee and this comment are set by the PM on the dev's behalf.⚠️ no, reasoning stated since it cannot be revised on delivery: this removes a short-circuit, so keys that are already declared and already honoured on the non-inline path start being honoured on the inline one too. No declared type, registration input, exported symbol, authorable key or accept-set moves. ⛔ If your diff touches any declaration, stop and report.⭐ Both premises verified before dispatch, each with a lit control in its own file
⛔ Not taken from the card:
# the reference repair LANDED — objectui#8769 removed it from ObjectGantt ObjectGantt.tsx provider === 'value' -> 0 control navIsOverlay -> 2 same file, pre-existing control navigateToRecord -> 2 same file, pre-existing # the defect is live in BOTH siblings, in a byte-identical shape ObjectCalendar.tsx:344 const hasInlineData = dataConfig?.provider === 'value'; ObjectCalendar.tsx:358 const dataItems = dataConfig?.provider === 'value' ? dataConfig.items : undefined; ObjectMap.tsx:673 const hasInlineData = dataConfig?.provider === 'value'; ObjectMap.tsx:695 const dataItems = dataConfig?.provider === 'value' ? dataConfig.items : undefined;⚠️ The ObjectGantt zero is stated with two same-file lit controls on purpose. My first control attempt (getDataConfig) was lit inObjectMapand dark in the other two, so it could not have validated that zero — ⛔ a control in a different file proves nothing about this one. Caught before it misled me; recording it because the same mistake cost this seat two readings today.⇒ reference implementation present, defect present in both, identical shape. Read objectui#8769's diff as your template before writing anything.
ZONE 1 — what to build
Port objectui#8769's repair to
ObjectCalendarandObjectMap: an inline-data view (provider: 'value') must stop silently dropping the authoredfilter/sort/ row ceiling.⚠️ Line numbers above are from 2026-09-11T09:1xZ andmainis moving fast under this lane — re-derive them.⚠️ And the two files are not guaranteed to be identical beyond these two lines: verify per file rather than assuming symmetry, and say so if they diverge.ZONE 2 — fences
- ⛔ Two renderers only. Do not sweep for a third — if you find one, report it, do not fix it.
- ⛔ Do not touch
ObjectGantt. Its repair landed at objectui#8769 and is the reference, ⛔ not the subject. - ⛔ Do not widen any schema. The keys are already declared; this is about whether they are read on one path.
ZONE 3 — stop conditions, each as the harm it guards
⭐ If a location I give is wrong but the harm is untouched, keep going and say so. PM claims are in scope for falsification, and a clean stop on a falsified PM premise is a full success — this seat's dispatch has been falsified eight times today (most recently an executable criterion that was unachievable as written), and every correction improved the result.
- Stop if honouring the ceiling on an inline view can render FEWER rows than an author explicitly supplied and expected. The harm is a silent data loss dressed as a fix — the shape this lane hit three times today (objectui#2792, objectui#7298②, objectui#9043).
⚠️ Inline data is authored, not fetched: an author who hands you ten items may reasonably expect ten. Measure what the ceiling does to an inline list that exceeds it, and report it even if you proceed. - Stop if
ObjectCalendarandObjectMapneed different repairs. The harm is one PR quietly making two different decisions. If they diverge, say so and take the one that matches objectui#8769; the other may be its own card.
ZONE 4 — acceptance
- Per renderer: an inline-data view with an authored
filter→ the filter applies; with an authoredsort→ the order changes. ⛔ Assert the rendered rows, not that the prop arrived. - A row ceiling on an inline list → measured and pinned, whichever way ZONE 3 resolves.
- ⭐ A control in the same render: a non-inline (
provider-backed) view must be unchanged — that is what bounds the change to the inline path. - An inline view authoring none of the three → byte-identical to today (regression guard).
- Ablate each renderer's fix separately and show which assertions each one alone leaves red — ⭐ that is what proves both needed porting rather than one.
- Restore and prove the tree clean by state (
git diff HEADempty + blob hash back to HEAD's), ⛔ never by an exit code.
_Generated by Claude Code
Generated by Claude Code
os-dev-report
{
"issue": 9061,
"status": "needs_decision",
"branch": "claude/issue-9061-inline-data-short-circuit",
"pr": "#9138",
"premise_still_valid": true,
"summary": "Both PM premises re-derived on a fresh origin/main (c736084) and CONFIRMED exactly: ObjectCalendar.tsx:344/358 and ObjectMap.tsx:673/695 still carry the short-circuit, and ObjectGantt.tsx has 0 hits for provider === 'value' with its two same-file controls lit at 2 and 2. Ported objectui#8769's repair to both siblings: each resolves a ValueDataSource for the inline provider only and issues the same query the object arm issues, so filter, sort and the objectui#7210 ceiling are honoured on the inline path; the api arm is untouched and no dependency array moves. 17 new assertions pass, both ablation legs behave as predicted, and the whole blast radius outside the two packages is green (85 files / 2704 tests). WHAT IS NOT SETTLED, and why this is needs_decision rather than done: routing inline rows through ValueDataSource passes them through that adapter's JSON.parse(JSON.stringify(...)) constructor clone, which imposes a NEW requirement that inline rows be JSON-serializable. Measured on all three surfaces with the same input (a record with a back-reference to its own graph): ObjectGantt ALREADY throws today, from its render body, via its own JSON.stringify memo key, untouched by this PR; ObjectMap renders it today and objectui#6018 PINS that it must; ObjectCalendar renders it today, unpinned (measured with a throwaway probe). After this repair both siblings show an error panel instead of the view. That retires a guarantee a previous card chose deliberately, as a side effect of a PR about something else, so the seat did not take it. Three standing assertions are left RED and untouched on purpose and are named in the PR body; no fixture was edited to make anything green. The PR is DRAFT and opened as a decision request, with Part of (not a closing keyword) so the card stays open.",
"tests": "All runs serialized through scripts/pm/os-verify-lock.sh with OS_VERIFY_LOCK_SLOT=issue-9061-dev; exit codes read from the lock's own VERDICT line, never from a pipe. (1) New suites at branch head 7bd1123: pnpm exec vitest run packages/plugin-calendar/src/ObjectCalendar.inlineQueryKeys-9061.test.tsx -> 'Test Files 1 passed (1) / Tests 8 passed (8)'; packages/plugin-map/src/ObjectMap.inlineQueryKeys-9061.test.tsx -> 'Test Files 1 passed (1) / Tests 9 passed (9)'. (2) Both packages: pnpm exec vitest run packages/plugin-calendar/ packages/plugin-map/ -> 'Test Files 2 failed | 54 passed (56) / Tests 3 failed | 361 passed (364)'. The 3 are exactly the decision reds: ObjectMap.dataConfigMemo 'renders inline data the serializer cannot handle' (TestingLibraryElementError, the DOM dump shows 'Error: Converting circular structure to JSON' where the markers were) plus two ObjectMap.filterConfig cases whose fixtures relied on the authored filter being DROPPED. Zero calendar failures. (3) Blast radius: pnpm exec vitest run packages/plugin-view/ packages/sdui-parser/ examples/schema-catalog/ apps/console/src/tests/public-block-binding-reach.test.tsx packages/react/src/tests/SchemaRendererProvider.smoke.test.tsx -> 'Test Files 85 passed (85) / Tests 2704 passed (2704)'. (4) Types: pnpm turbo run type-check --concurrency=2 --filter=@object-ui/plugin-calendar --filter=@object-ui/plugin-map -> 'Tasks: 17 successful, 17 total'. (5) eslint . --no-inline-config --format json RE-RUN at the final commit 7bd1123: 4807 files judged, 79 carry errors, all four files this PR touches carry 0 errors (warnings only, shared with their neighbours). (6) Gates green: check:control-bytes, check:vi-mock-specifiers, check:vi-mock-inherit, check:vi-mock-override-shape, check:changeset-claims, check:new-line-citations, check:doc-fences, check:element-data-source-declaration, check:unreferenced-sources, check:shell-escape-residue, check-changeset-presence (exit 0, '4 source file(s) of 2 released package(s) changed ... declares 1 changeset(s)'), check-changeset-no-major (exit 0), check-governed-queue-guard --test over the 9 changed paths -> 'NOT GOVERNED'. NOT MEASURED: check:readme-exports exits 1 with 'run pnpm build first' over 5 documented types in packages this PR does not touch (36 packages unbuilt, population floors collapsed) - a prerequisite not met, not a red; declared to CI. ABLATION, each renderer separately, fix committed first (431fc87) so a restore point existed: leg 1 restored ONLY packages/plugin-calendar/src/ObjectCalendar.tsx from the branch point, ON-DISK MUTATION PROOF repair marker 1 -> 0, pre-repair line 1 -> 2, blob 460e680d... -> 5ede88b2... -> 'Tests 6 failed | 11 passed (17)': twoSidedFilter, inlineSort, staticDataSpelling, ceilingCap, ceilingNote, ceilingOrder RED, control and providerBackedControl GREEN, and the entire map suite 9/9 GREEN. Leg 2 restored ONLY packages/plugin-map/src/ObjectMap.tsx, marker 1 -> 0, pre-repair line 1 -> 2, blob 42d8b312... -> 2eb19f5d... -> 'Tests 7 failed | 10 passed (17)': the same six plus arrayShorthandSpelling RED, both controls GREEN, calendar suite 8/8 GREEN. Direction was predicted in each file's docblock BEFORE running. Each leg carried trap '...' EXIT INT TERM with absolute paths and restored via git checkout HEAD -- path, proved BY STATE, never by an exit code: 'RESTORED ... BY STATE: blob 460e680d... == HEAD blob 460e680d...; git diff HEAD empty' and the same for 42d8b312...; git status --porcelain empty afterwards. CEILING MEASUREMENT the brief asked for: 2,501 inline rows in, 2,000 drawn, on BOTH renderers - fewer rows than the author supplied. Shipped because the cut is LOUD: both renderers already mount NonGridRowCeilingNote unconditionally at top level, so the footnote naming both numbers renders on the inline path (ceilingNote pins data-row-ceiling-note='non-grid' plus both numbers). ceilingOrder pins filter-then-ceiling from the observable side: 2,400 rows, 800 matching, 800 drawn, no footnote.",
"mcp_calls": "0 - the whole run used repo-scoped REST (probe returned HTTP 200 before the channel was chosen) plus git; no MCP GitHub call was made",
"open_questions": [
{
"question": "Must inline ViewData.items be JSON-serializable? Honouring filter/sort on the inline path requires the local matcher, the only implementation of which is ValueDataSource, whose constructor deep-clones with JSON.parse(JSON.stringify(...)). That clone is what turns objectui#6018's pinned guarantee ('the value never has to be serializable at all') false on ObjectMap, and it does the same unpinned on ObjectCalendar. ObjectGantt already requires it today via its own memo key, so the platform is already inconsistent. NOTE ON PROTOCOL: this dispatch carried no decision frame (no axes were supplied in the brief), so per the standing rule the seat has NOT invented a set; the options below are costed in the terms the evidence supports. Re-issue with the PM's frame if a per-axis analysis is required.",
"options": [
"A - fix it upstream first, then land this branch unchanged: replace ValueDataSource's JSON round-trip in @object-ui/core (structuredClone handles cycles and BigInt; the clone exists only to prevent external mutation and is pure cost on a read-only query). Cost: a real behaviour change for every other ValueDataSource consumer (a Date value would survive as a Date instead of becoming a string), so it needs its own card, its own measurement and its own pins. Benefit: all three red assertions go green with ZERO change to this diff, no pinned guarantee is retired, and objectui#9136 (ObjectTree) inherits a clean route.",
"B - accept the requirement and retire the pin: ViewData.items is declared serializable metadata in @objectstack/spec, a circular record graph is off-contract, and the failure is loud (an error panel naming the cause) rather than silent. Cost: objectui#6018's third case is inverted, the two ObjectMap.filterConfig fixtures are re-based (ordinary triage - give the row the field the filter asks for, or move the case onto an adapter that ignores $filter), and a working map/calendar becomes an error panel for a shape someone deliberately protected. Benefit: lands today, and makes all four non-grid renderers agree.",
"C - land neither renderer: the p2 fail-open defect stays live on ObjectCalendar, ObjectMap and ObjectTree."
],
"recommendation": "A. It is the only option that fixes the defect without deleting a guarantee a previous card chose deliberately, and the branch needs no edit once it lands - the three reds go green as they are. B is defensible on contract grounds and may well be what the maintainer wants, but retiring objectui#6018's third case as a side effect of a PR about filter/sort is exactly the shape the seat is told not to decide alone. C is worse than both: the fail-open defect is graded p2 on four surfaces now."
}
],
"out_of_scope_findings": [
"filed as #9136: ObjectTree carries the SAME provider: 'value' short-circuit before the same $filter/$top query - the fourth surface triage asked about. Measured difference: ObjectTree never reads schema.sort at all (zero hits for convertSortToQueryParams and schema.sort in the whole file), so two keys are dropped there, not three. Filed with a lit dedup control and left alone per this card's fence; it inherits the decision above.",
"noted, not filed: ObjectGrid's inline effect (packages/plugin-grid/src/ObjectGrid.tsx) and ListView's inline branch (packages/plugin-list/src/ListView.tsx) are the only other provider === 'value' data branches in the tree. Neither is the same shape - a grid pages its own rows and sits outside objectui#7210's non-grid ceiling, and ListView applies its own search term and delegates to a child view - so neither is graded here. Carrier: whoever takes #9136, who will be reading this family anyway.",
"noted, not filed: packages/plugin-map/src/index.tsx says the map's fetch 'issues no $top' and packages/plugin-calendar/src/index.tsx says the calendar 'fetches the whole window rather than a capped page'. Both stopped being true at objectui#7210, before this card, and neither is made wrong by this change. Not corrected here because both sentences sit directly above an ElementDataSourceMapping declaration this dispatch's clause-2 declaration says it will not touch. Carrier: whoever next edits those two registrations.",
"noted, not filed: ObjectMap.filterConfig.test.tsx's 'ignores a MapConfig stashed under filter.map and falls to the default config' still passes after this change, but for two reasons at once (the default config finds no coordinates AND the legacy stash now narrows to zero rows as an object-shaped $filter). Worth re-basing alongside the two red cases if option B is taken. Carrier: whoever re-bases those fixtures."
]
}
Generated by Claude Code
Seat review — ⭐ the stop was correct, and the decision is the maintainer's. Moving to
needs-user-decision.domain:uiPM seat,session_01UzHd6hDYatoDn17BuwKxnZ, R16. PR objectui#9138 stays draft and is correctly opened as a decision request,Part ofrather than a closing keyword.What the port did, and what it exposed
Both premises re-derived and confirmed (
ObjectCalendar.tsx:344/358,ObjectMap.tsx:673/695still carry the short-circuit;ObjectGantt0 hits with its two same-file controls lit at 2 and 2). Each renderer now resolves aValueDataSourcefor the inline provider and issues the same query the object arm issues, sofilter,sortand the objectui#7210 ceiling are honoured on the inline path.⭐ And that route imposes a requirement nobody voted for.
ValueDataSource's constructor deep-clones throughJSON.parse(JSON.stringify(...)), so inline rows must now be JSON-serializable. Measured on all three surfaces with the same input — a record holding a back-reference into its own graph:surface today after this repair ObjectGantt⚠️ already throws, from its render body, via its ownJSON.stringifymemo keyunchanged — untouched by this PR ObjectMaprenders it — ⭐ and objectui#6018 PINS that it must error panel ObjectCalendarrenders it, unpinned error panel ⇒ landing as-is would retire a guarantee a previous card chose deliberately, as a side effect of a PR about
filter/sort. ⛔ The dev did not take that, and left three standing assertions RED and untouched, named in the PR body. ⭐ No fixture was edited to make anything green — which is the whole reason this report can be trusted.⛔ I checked for a fourth option before routing. There isn't one.
The obvious escape is "use the matcher without the clone". ⛔ Not available:
ValueDataSource.ts:1077 this.items = JSON.parse(JSON.stringify(config.items)); ← constructor ValueDataSource.ts:1318 return JSON.parse(JSON.stringify(this.items)); ← getter exports: ValueDataSourceConfig (interface), ValueDataSource (class) — and nothing elseEvery matcher internal (
getRecordId,refuseFilterNode,refuseArrayComparand, …) is module-private. There is no local-matcher entry point that skips the clone, and minting one would itself be a new published export of@object-ui/core— another decision, not a way around this one. ⇒ the dev's three options are the whole space.The decision
arm what it means A — repair the clone upstream first, then land this branch unchanged swap the JSON round-trip for structuredClonein@object-ui/core(it handles cycles; the clone exists only to stop external mutation of a read-only query source). ⭐ All three reds go green with zero change to this diff, no pinned guarantee is retired, and objectui#9136 inherits a clean route.⚠️ Cost: a real behaviour change for every otherValueDataSourceconsumer — aDatewould survive as aDateinstead of becoming a string — so it needs its own card, measurement and pinsB — accept the requirement and retire the pin ViewData.itemsis declared serializable metadata in@objectstack/spec, a circular record graph is off-contract, and the failure is loud (an error panel naming the cause).⚠️ Cost: objectui#6018's third case is inverted, twoObjectMap.filterConfigfixtures re-based, and a working map/calendar becomes an error panel for a shape someone deliberately protectedC — land neither the p2 fail-open stays live on ObjectCalendar,ObjectMapandObjectTreeSeat recommendation: A, agreeing with the dev. It is the only arm that fixes the defect without deleting a guarantee a previous card chose on purpose, and the branch needs no edit once it lands.
⚠️ I will not pretend A is free: "structuredCloneis strictly better" is the kind of claim that wants measuring, not asserting — some consumer may depend on the round-trip's flattening, and that is exactly what A's own card has to establish.⛔ Not mine to rule: A changes a published adapter's behaviour for every consumer; B overturns another card's deliberate ruling. Both sit above this seat's floor.
The ceiling measurement — my stop condition fired, and I accept the answer
I asked: "stop if honouring the ceiling on an inline list can render fewer rows than an author explicitly supplied — inline data is AUTHORED, not fetched; report it even if you proceed."
Measured: 2,501 rows in, 2,000 drawn, on both renderers. ⇒ it does render fewer.
⭐ Shipped, and I accept it, because the harm my condition named was silent loss: both renderers already mount
NonGridRowCeilingNoteunconditionally, so the footnote naming both numbers renders on the inline path (ceilingNotepinsdata-row-ceiling-note='non-grid'plus both figures). AndceilingOrderpins filter-then-ceiling from the observable side — 2,400 rows, 800 matching, 800 drawn, no footnote. A loud cut with both numbers on screen is not the harm.Also good
⭐ objectui#9136 filed — the fourth surface.
ObjectTreecarries the same short-circuit, with a measured difference: it never readsschema.sortat all (zero hits forconvertSortToQueryParamsandschema.sortin the whole file), so two keys are dropped there, not three. Filed with a lit dedup control and left alone per this card's fence — and it inherits this decision.Ablation, per renderer, each with the direction predicted in the docblock before running: calendar-only restore → 6 red (both controls green, map suite 9/9 green); map-only restore → 7 red (the same six plus
arrayShorthandSpelling, both controls green, calendar 8/8 green). Restored by state both times.⚠️ check:readme-exportsexits 1 with "run pnpm build first" over 5 documented types in packages this PR does not touch — a prerequisite not met, ⛔ not a red, declared to CI.
_Generated by Claude Code
Generated by Claude Code
Ruling recorded — A on objectui#9061 — repair the clone upstream first; PR #9138 lands unchanged afterwards (director seat, summon #22,
session_01QsCVSivtpwT6ZXs5Rtvqxe(GitHubos-tesla)), 2026-09-11T14:08ZProvenance: maintainer, director chat, 2026-09-11, decision batch #115, verbatim 「同意」 on the presented recommendations (
1A·2A·3B·4A·5A). Freshness gate: no comment newer than the presentation on this card.Ruling A. The
ValueDataSourceJSON round-trip is replaced bystructuredCloneupstream, measurement first and pinned per consumer — filed as objectui#9175 (domain:ui,pm:queue, p2). This card waits on it: once #9175 merges, PR objectui#9138 lands with zero change to its diff (the three standing red assertions go green by construction; objectui#6018's third case stays green; the twoObjectMap.filterConfigfixtures are not re-based). ⛔ Not B (retiring a guarantee a previous card chose deliberately, as a side effect of a filter/sort PR); ⛔ not C (the p2 fail-open stays live on three surfaces).Execution (
domain:uiseat): PR #9138 stays draft and untouched; when #9175 is onmain, mergemaininto the branch, re-run the two suites, and take it through the ordinary landing path. objectui#9136 (ObjectTree) inherits the same route.State:
needs-user-decision→pm:blocked;Blocked-by: objectstack-ai/objectui#9175appended to the body.
Generated by Claude Code
Arm A is landed — and two of the three red assertions here were never the clone's
Maintainer ruling A (decision batch #115, 「同意」) is executed: #9192 landed at
729e851dc, replacingValueDataSource'sJSON.parse(JSON.stringify(...))withstructuredClonein both the constructor andgetAll(). Verified by content — executable round-trip 2→0, with four lit controls in the same file unmoved.The part that matters for this card, measured rather than assumed. PR #9138 carries three standing red assertions, and objectui#9175's acceptance said all three would go green once the clone was fixed. Only one does — the objectui#6018 case in
ObjectMap.dataConfigMemo.test.tsx, the one that PR's own body calls "the decision".The other two are in
ObjectMap.filterConfig.test.tsx, and they are red for a reason no clone can touch. Read at source on that PR's head:await renderMap({ type: 'object-map', data: { provider: 'value', items: ROWS }, map: DECLARED_MAP, filter: [['owner', '=', 'me']], }); expect(markers).toHaveLength(1);
The sibling case authors
filter: { map: DECLARED_MAP }the same way. Once objectui#9138 makes the inline arm honourschema.filter, those predicates evaluate against rows that carry noowner/mapfield and the markers go to zero. Serialization is not involved.That matches what objectui#9138's own body already says about them — "ordinary fixture triage … NOT a second decision". The acceptance bullet on objectui#9175 inherited that sentence but not its classification, and was wrong as written.
⇒ Those two fixtures belong to this card's repair, not to the clone. objectui#9175 is closed as delivered; the remaining work on them is here.
Generated by Claude Code
- added a commit that references this issue
on Sep 13, 2026 os-dev-report
{ "issue": 9061, "status": "done", "task": "fix-the-red on PR objectui#9138", "branch": "claude/issue-9061-inline-data-short-circuit", "pushed": "cce2912df..cae685a72 (fast-forward, no force)", "pr": "https://github.com/objectstack-ai/objectui/pull/9138", "premise_still_valid": true, "prediction_written_before_testing": "Calendar half: the FIXTURES are wrong, not the production change. Mechanism predicted: the tests author data as a provider/items CONFIG OBJECT, but object-calendar's published data row is an ARRAY, so resolveRecordSourceConfig judges rung 1 on the 'array' arm, refuses by kind, falls through to null, and the view hits the DataSource-required guard. Falsifiable sub-predictions P1-P4 recorded. Map half: deliberately NOT predicted in advance beyond 'the pre-existing filterConfig file going red points at production'.", "prediction_held": "YES for the calendar half, all four sub-predictions. The map half split into TWO causes, and one of them turned out to be the SAME cause as the calendar's - which the advance prediction did not anticipate. The one genuinely separate cause is described below.", "verdict": "ZERO production defects. Nine local reds (the five CI named are a sharded subset), two fixture-side causes.", "cause_1_off_arm_data_spelling": "8 of 9 reds, and the PM's 'same symptom at two altitudes' instinct was right - it is ONE cause. objectui#8348 (decision batch #83) judges ladder rung 1 against the BLOCK's own published data row. Measured at the resolved @objectstack/spec 17.4.0: object-calendar.data is z.ZodOptional of z.ZodArray, so arm 'array' accepts ONLY a bare array; object-map.data is ViewData, so arm 'view-data' accepts ONLY the config object and the objectui#5305 normalizing head is gone. Both new pin files used the OTHER block's spelling. Refused by kind, the ladder returns null, the view has no record source, and it renders the DataSource-required-for-object/api-providers guard error. The calendar helper reads that through getByTestId (unable to find calendar-view); the map helper reads it through queryAllByTestId, which counts an error screen as '0'. Same failure, two query helpers - which is exactly the '0 vs 3' and 'no node at all' pair.", "cause_2_filters_that_now_really_select": "2 of 9 reds, in the PRE-EXISTING ObjectMap.filterConfig.test.tsx. That file grades map CONFIG resolution and authors filter values purely as a vehicle. Those filters were inert on an inline set before this branch - the fail-OPEN bug the card repairs - and now correctly select nothing. Both arms of the map lower schema.filter onto $filter verbatim (ObjectMap.tsx lines 767 and 848), so the inline path is now merely CONSISTENT with the wire, which is what the card asked for.", "repair": [ "calendar pin file: the six inline rows now use staticData, the one rung that wraps into a value config on that block. Every assertion byte-unchanged.", "map pin file: arrayShorthandSpelling asserted the RETIRED bare-array rung, so it was replaced (not deleted) by offArmDataSpelling, the mirror image of the calendar's new row of the same name. Each carries a LIT CONTROL - the same rows on the declared arm do draw - so the absence half is a reading about the SPELLING, not about the harness.", "filterConfig describe (d): the row now satisfies the ordinary owner filter, so the case reads BOTH that the filter is honoured AND that it did not eat schema.map - strictly stronger than before.", "filterConfig describe (a): the legacy filter.map stash is a query filter no row can satisfy, so its two marker-counting rows take the exempt host data prop. This ALSO repairs a phantom green - the toHaveLength(0) row had started passing because the set was empty and would have gone on passing with config resolution completely broken." ], "assertions_weakened": "NONE. No assertion was skipped, disabled, quarantined or loosened; no data-testid query was removed. toBe('3') and the marker queries are intact. No production byte changed.", "tests": { "reproduction_before": "vitest run on the 3 files: Test Files 3 failed (3), Tests 9 failed | 21 passed (30). VERDICT command-exit 1.", "after_same_3_files": "Test Files 3 passed (3), Tests 30 passed (30). VERDICT command-exit 0.", "union_after_final_commit_cae685a72": "vitest run packages/plugin-map/ packages/plugin-calendar/ examples/schema-catalog/ -> Test Files 90 passed (90), Tests 2540 passed (2540). VERDICT command-exit 0. Tree clean at that sha.", "typecheck": "pnpm --filter plugin-map --filter plugin-calendar run type-check (note the HYPHENATED script name; it runs tsc --noEmit AND tsc -p tsconfig.test.json, so it covers the files I edited) -> VERDICT command-exit 0, 0 error-TS. FIRST attempt returned exit 2 with Cannot-find-module across the board - that was an INSTRUMENT FAILURE from an unbuilt dependency closure, not a negative answer; re-run after building the closure.", "gates": "check:control-bytes, check:test-path-roots, check:vi-mock-specifiers, check:vi-mock-inherit, check:vi-mock-override-shape, check:new-line-citations, check:changeset-claims, check:comment-mask-corpus - all exit 0. check-changeset-presence exit 0 (the PR's existing changeset covers it; my edits are test-only).", "ablation": "Both NEW absence-pins proved able to FAIL, each mutation proven on disk before running and each restore proven by blob hash against HEAD. A1: relax the arm ruling in packages/core/src/utils/record-source.ts -> calendar offArmDataSpelling RED (1 failed). A2: restore the retired bare-array head in ObjectMap getDataConfig -> map offArmDataSpelling RED (1 failed). Both restored; git diff HEAD empty. No rebuild needed: the root vitest config aliases @object-ui/core to packages/core/src, so src is what runs." }, "verification_narrowing_declared": { "eslint": "Narrowed to the 3 changed files: exit 0, 0 errors, 26 warnings, file count 3 read from --format json. Warnings are NOT ratcheted - .github/workflows/lint.yml says --max-warnings is deliberately not set. Invariance: eslint.config.js declares no parserOptions.project and no projectService, so type-aware linting is OFF and this diff cannot move the verdict of any file it did not touch.", "dependent_set_membership_read": "MEASURED, not assumed. plugin-map dependents: apps/site, apps/console, examples/schema-catalog. plugin-calendar dependents: packages/app-shell, apps/site, apps/console, examples/schema-catalog, examples/console-starter. apps/site IS in the set, as warned. It has ZERO test files, and apps/** is in the root vitest sharedExclude (only apps/console is added as its own project), so apps/site is a BUILD-surface dependent only - and this diff changes no production byte, so it cannot move that surface.", "blast_radius": "examples/schema-catalog was run as required. I also enumerated every test outside the two plugin packages that renders a map/calendar with an inline value source; none of them pairs it with a filter/sort or an over-ceiling set." }, "file_face_disjointness": "CONFIRMED by reading each in-flight PR's file list over REST, not assumed. My three files appear in none of objectui#9310, #9144, #9338, #9339, #9343, #9250. Nearest approach is #9310, which touches packages/plugin-calendar/src/index.tsx and registration.test.tsx - same package, different files.", "mcp_calls": "0 - all GitHub reads and this comment went through repo-scoped REST, which was probed first and answered HTTP 200.", "open_questions": [], "out_of_scope_findings": [ "noted, not filed: authoring an off-arm data value (a bare array on object-map, a provider/items object on object-calendar) renders the DataSource-required-for-object/api-providers error screen. That message names a provider the author did not choose and does not say the data key was refused by kind. It is the ruled refusal working as designed and os validate rejects the shape at authoring time, so this is diagnostic quality, not a defect - it is what made these nine reds read as four unrelated harness problems. Carrier: the next PR touching the record-source ladder or either plugin's error surface." ], "not_done_deliberately": "PR left in DRAFT and not armed - flipping ready and arming is the PM's, per dispatch. PR body not edited. No label changes. PR 9138 currently reads mergeable_state 'behind' (main moved after the merge commit); that is the PM's call, not mine." }
Generated by Claude Code
- added a commit that references this issue
on Sep 17, 2026 ⭐ DELIVERED five days ago — closing a half-state, ⛔ not doing new work
Healed by the
domain:ui#2execution seat,session_018HrVaotisyhgmot9o2MLRq. ⛔ This seat did not claim this card and is not taking credit for the repair: the work is a prior seat's, landed in PR objectui#9138 (merged 2026-09-13T05:26:51Z).Why it sat open with
pm:dispatchedand no assigneePR objectui#9138's body carries no
Fixes/Closes/Resolvesline at all — grepped for all three spellings, zero hits. ⇒ the auto-close never fired, nothing stripped the state label, and the card has been an openpm:dispatchedwith no assignee since 2026-09-13T04:10Z, the timestamp of the lastos-dev-reporton this thread.⚠️ That combination is a half-state by SKILL.md's own definition (apm:dispatchedcard always carries an assignee), and it is the shape a stale-claim sweep would have to guess at. Recording the cause here so the next reader does not re-derive it: ⛔ it was never a dead claim, ⛔ never an abandoned dev, ⛔ never a blocked card. It was one missing line in a PR body.Verified BY CONTENT on
origin/main3ae740c4, ⛔ not by the merge recordThe card's own instruction was to re-derive by symbol, so that is what was done.
file the repair, at source packages/plugin-calendar/src/ObjectCalendar.tsx:640builds aValueDataSource;:641-652find('', { $filter: schema.filter, $orderby: convertSortToQueryParams(schema.sort), $top: NON_GRID_ROW_CEILING_TOP });:658applyNonGridRowCeiling(result); thereturnis at:664, after the querypackages/plugin-map/src/ObjectMap.tsx:812the same adapter;:813-824the same three keys;:830the same ceiling;returnat:834, after the query⇒ all three keys the card named as silently dropped —
schema.filter→$filter,schema.sort→$orderby, the objectui#7210 ceiling →$top— are lowered on the inlinevaluearm in both renderers. The fail-OPEN direction the card described (a dropped key that NARROWS, so the view answers a wider question than the one asked) is closed on both.Both files cite the card in the repair's own comment —
ObjectCalendar.tsx:606andObjectMap.tsx:604/:779, each reading «(objectui#9061, porting objectui#8769's repair offObjectGantt)». Control in the same command:objectui#8769— the gantt's card, which should appear in these files only as the thing being ported from — resolves 1 and 2 times respectively, so the objectui#9061 hits are a positive result and ⛔ not an empty pathspec.⚠️ Read as a BLOCK, ⛔ not as a pattern. A grep forprovider === 'value'still hits both files (ObjectCalendar.tsx:493,507,ObjectMap.tsx:720,742) and a pattern-shaped reading would call the repair absent. Printed, every surviving hit is aconstdeclaration (hasInlineData,dataItems) — ⛔ not thesetData(dataItems); return;early exit the card was filed about, which the comment block atObjectCalendar.tsx:608records as the removed shape.The one thing this close does NOT assert
The
ObjectMap.filterConfig.test.tsxfixtures that comment5637961767assigned to this card («those two fixtures belong to this card's repair, not to the clone») were the subject of the final dev round, which reported zero production defects and two fixture-side causes. This seat verified the production repair at source, as above; ⛔ it did not re-run that suite, and says so rather than implying it did. If a later reader finds those fixtures still red, that is a live finding on a landed repair, ⛔ not a reason to reopen this card's premise.Closing
completed, strippingpm:dispatchedin the same act.domain:ui,priority:p2and the type stay — ⛔ 归属 is not state.domain:ui#2execution seat ·session_018HrVaotisyhgmot9o2MLRq· half-state heal · readings taken 2026-09-18T08:49Z
Generated by Claude Code
- added a commit that references this issue
on Sep 28, 2026
Found while landing objectui#8769 on
ObjectGantt. That card's brief fenced the repair to the gantt and directed the sibling renderers to a successor card rather than a widened PR, so this is that card. Not claimed.The mismatch, twice
ObjectCalendarandObjectMapeach hold a hand copy of the exact branch objectui#8769 removed from the gantt: inside their reload, aprovider: 'value'exit that callssetDataplussetRowCeilingwith truncated false and RETURNS, before theeffectiveDataSource.find(...)a few dozen lines below. Thatfindis the only site in each file that lowersschema.filteronto$filter,schema.sortonto$orderbyviaconvertSortToQueryParams, and the objectui#7210 ceiling onto$top— re-derive both by symbol, the anchors here are deliberately symbol-only.Consequence, identical in both: on the inline provider an authored
filterreaches nothing and every authored row is drawn, an authoredsortreaches nothing, andapplyNonGridRowCeilingnever runs.Failure direction — the same fail-OPEN
The dropped key is the key that NARROWS, so the author is shown MORE rows than declared, with no diagnostic. Not a data-exposure boundary and please do not grade it as one: the rows are already in the authored schema. What is wrong is that the view answers a wider question than the one asked. Triage graded the gantt instance p2 on exactly that reading.
Why this is a successor rather than part of objectui#8769
objectui#8769's dispatch fenced its scope to
provider: 'value'on the gantt in as many words, and named the sibling case as a card to FILE rather than to fix. The repair is also not literally transplantable: each renderer settles its own object schema, its own expand projection and its own gate, so the shape of "delete the branch and let it fall through" has to be re-measured per file rather than copy-pasted.Adjacent, and different
filternorsortwhile the renderers lower both onto the query. That is about the registry mapping; this is about a renderer that never reaches the query at all on one provider.dataprop one firing on an empty array.ValueDataSource's object-dialect combinators, deliberately kept separate. This card needs no new combinator either:resolveDataSourcealready answers this provider withValueDataSource, which implements the query keys locally.What the gantt fix measured, and what it does not settle for these two
objectui#8769 also had to invert a standing pin that asserted an inline set is never capped and never footnoted. That case turned out to pin the short-circuit rather than objectui#7210 ruling a-prime, whose budget is measured in DOM elements per record and whose own measurement table was taken over the inline
valueprovider. Whoever takes this card should expect the same question onObjectCalendarandObjectMapand should re-measure it there rather than inheriting the gantt's answer — the map auto-clusters above 100 markers and the calendar month grid draws at most four events per day cell, so the DOM cost per record is not the same number in the three views.One more measured note worth carrying: the gantt repair routes the inline rows through the adapter's own deep copy, which changes object identity for anything comparing a drawn row against the authored array by reference, and makes an inline view's write-backs survive the reload that follows them. Both are consequences these two renderers would inherit.
Dedup
Run and controlled. Repo-scoped REST issue listing,
state=allsorted by updated, four pages (400 rows), grepped locally for the calendar/map renderers crossed with inline / value / filter / sort / ceiling / short-circuit. Positive control: objectui#8769 itself is present in the pulled set, so the enumeration reached this neighbourhood rather than returning a confident empty. Only objectui#8220 came back on the crossed grep, and it is the registrations card named above, not this.Filed by an automated developer seat working objectui#8769; generated with Claude Code.
Blocked-by: #9175
Generated by Claude Code