Repository navigation
feat(spec): declare element-level navigation on object-kanban / object-calendar and give object-timeline its ComponentPropsMap row (#17987) - #19219
Conversation
…ine` its props-map row `ComponentPropsMap` refused `navigation` by name on `object-kanban` and `object-calendar` while objectui's renderers read and honour it on a standalone node, and `object-timeline` had no row at all, so the authoring gate skipped it in both directions. Both faces now carry `NavigationConfigSchema` — the same def `ListViewSchema.navigation` declares, by reference — and the timeline row declares the key set measured from the renderer's read points at the `.objectui-sha` pin. The view-level carrier is untouched. Claude-Session: https://claude.ai/code/session_01AmH9bKvGoLjiY86Q4Z3og2 Co-authored-by: Claude <noreply@anthropic.com>
…ion moves `gen:schema` / `gen:docs` and the four dist-read snapshots follow the new keys: the authorable surface gains `ObjectKanbanProps:navigation`, `ObjectCalendarProps:navigation` and the fourteen `ObjectTimelineProps` keys, the dropped-refinement ledger gains the timeline row the projection cannot carry (`filter.element`, `timeline.groupByField`) with its header totals, and the strictness ledger counts one more closed object site in `ui/`. Claude-Session: https://claude.ai/code/session_01AmH9bKvGoLjiY86Q4Z3og2 Co-authored-by: Claude <noreply@anthropic.com>
📓 Docs Drift CheckThis PR changes 1 package(s): 7 hand-written doc(s) NAME something this change touched and may need an implementation-accuracy re-verification:
⛔ 5 release-owned page(s) also name something this change touched. These are read-only:
What this run could not see
Coarse fallback — 136 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): Which tree this was computed onThis run read A worktree cut from an older # while this PR is open — GitHub drops the merge commit once it closes
git fetch origin ade56b521cb00acdf79c4d9e65ced8b7030d01c7 && git checkout ade56b521cb00acdf79c4d9e65ced8b7030d01c7
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin 0046a41b43da8e7d2db9d7f926cc0518a357c379 ee50b4cd13e07a2d3327e78d5f98aefd30ed85ab && git checkout -B drift-repro 0046a41b43da8e7d2db9d7f926cc0518a357c379 && git merge --no-ff ee50b4cd13e07a2d3327e78d5f98aefd30ed85ab
node scripts/docs-audit/affected-docs.mjs --json 0046a41b43da8e7d2db9d7f926cc0518a357c379
|
Contract reviewReviewed at 2026-09-20T00:25Z · contract-tier review of record for PR #19219 (card #17987), Served-tier: Measured on a detached checkout of the head (merge-base with ① Derived judgments1. Accept-set movement is widening only — PASS. Instrument: a script that loads 2. The carrier is the shared def, and the identity pin is real — PASS. 3. The view-level carrier is untouched — PASS. 4. ⭐ The
Nested, for completeness: 5. Reverse verification — PASS. Re-run in an isolated worktree through 6. The files outside the declared surface — PASS. From a fresh 7. The changeset — PASS on level, prose must move with the row. Also measured: BLOCKING — the new
|
… honours it The first cut of this row measured `schema.*` read points only, so it declared fourteen keys and refused `data` by name — on the one face that, before the row existed, refused nothing at all. `ObjectTimeline.tsx` reads the key off REACT PROPS (`:171` seeds loading, `:247` skips the object query, `:256` is the row source itself, ahead of the data-scope binding and the fetch), and an authored `properties.data` reaches that channel through `SchemaRenderer`'s hoist and prop spread. The door takes the shape its two sibling object-bound faces already declare, so the third face is not a second vocabulary, and the door's docblock keeps the reason a `schema.*`-only sweep missed it. Claude-Session: https://claude.ai/code/session_01AmH9bKvGoLjiY86Q4Z3og2 Co-authored-by: Claude <noreply@anthropic.com>
Contract reviewReviewed at 2026-09-20T01:23Z · contract-tier review of record, round 2, for PR #19219 (card #17987), Served-tier: Measured on a detached worktree of the head (merge-base with ① The five things round 2 had to settle1. ⭐ The BLOCKING finding is closed — on the siblings' shape, with a describe held to the timeline — PASS.
2. The new test leg is a real pin — PASS, re-run here. Baseline at head, before any mutation: 3. ⭐ The regression question — the whole row re-derived under BOTH channels — PASS: Instrument and radius. A sweep over the code lines (comments excluded) of the three non-test sources that answer Every top-level key read, its channel, and the row's disposition (
The gate's other reads ( 4. Nothing else moved — PASS. The delta is exactly the six files the remedy named: 5. The PR body and the changeset tell the truth — PASS, one stale figure noted. Changeset: the noted (not blocking)
② Semver level
③ Boundary flags
Implemented-by: VERDICT: PASS Served-tier: Generated by Claude Code |
Sync with origin/main through scripts/pm/os-regen-merge.sh, whose step 2 restored main's side of the four os-regen artifacts both branches moved (api-surface/ui.json, api-surface-declarations/ui.txt, authorable-surface/ui.json, export-origins/ui.json) — the driver had merged them exit 0 while silently keeping one side. Regenerated from the merged tree after a real build, so both sides' entries are present: #19219's element-level `navigation` rows and its ObjectTimelineProps block, and this branch's three `limit` rows plus DEFAULT_VIEW_ROW_LIMIT and KanbanConfigParsed. gen:docs adds the timeline row to the component reference page. Claude-Session: https://claude.ai/code/session_01JbZnqu8bt6YqfJsr9vaFb3 Co-authored-by: Claude <noreply@anthropic.com>
ActionEngineFacade.find takes the engine query envelope, not a bare filter
#19223
…ed tree Baseline drift, not a code change. `origin/main`'s #19219 moved `ComponentPropsMap` and `ObjectTimelinePropsSchema` after this branch forked, and `api-surface-declarations/**` is a `merge=os-regen` path — so the merge produced a `ui.txt` that was current for neither side, which is what turned `Check @objectstack/spec declaration text` red. Regenerated from a real build of the merged tree (34/34 declaration files emitted; ⛔ no `OS_SKIP_DTS`), via `scripts/pm/os-regen-merge.sh`. BOTH SIDES asserted present afterwards, by quoted-exact name against the INDEX blob rather than the worktree, with a dark control reading 0 files: this branch's `find(object: string, query: EngineQueryOptions)` and `ACTION_ENGINE_FIND_ENVELOPE_PRESCRIPTION`; #19219's `ObjectTimelineProps`, `ObjectTimelinePropsSchema` and `ComponentPropsMap`. Note the two `navigation` keys that branch also added live in `authorable-surface/ui.json` and in NO declaration file — a grep scoped to `api-surface-declarations/` reads 0 for them out of range, not out of loss, so the assertion ran over the whole tree and printed paths. Claude-Session: https://claude.ai/code/session_01JbZnqu8bt6YqfJsr9vaFb3 Co-authored-by: Claude <noreply@anthropic.com>
…ged tree Baseline drift, not a code change — the fourth sync lap on this branch. Main's #19226 and #19235 moved `packages/spec/api-surface-declarations/{data,root, system,ui}.txt`, and that directory is a `merge=os-regen` path, so the merge produced four files current for neither side. Regenerated from a real build of the merged tree (34/34 declaration files emitted; ⛔ no `OS_SKIP_DTS`), via `scripts/pm/os-regen-merge.sh`, with `MERGE_HEAD` confirmed absent first — the build opens with `gen:schema`, and running that in MERGE state is the anchor-rollback trap.⚠️ The `MM` grade was live here and was read on purpose. After regenerating, the index held main's side (803/535) while the worktree held the regeneration (323/4); a bare `git commit` would have landed the index. `git add -A` first, then `git diff --cached` re-read as the 323/4 it should be, and every one of the four index blobs hash-matches its worktree file. BOTH SIDES asserted by quoted-exact name over the WHOLE TREE with paths printed, then again against the index blobs, with a dark control reading 0 files: this branch's facade signature and prescription constant; #19226's `DEFAULT_VIEW_ROW_LIMIT`, `KanbanConfigParsed` and the three `ui/{Gallery,Kanban,Timeline}Config:limit` keys; #19235's `RecordRelatedListProps.columns[number]` and `z.array(ListColumnSchema)`; and #19219's `ObjectTimelinePropsSchema` carried forward. Note the three `limit` keys live ONLY in `authorable-surface/ui.json` and `authorable-defaults/ui.json` and the related-list row ONLY in `content/docs/references/ui/component.mdx` — a grep scoped to the declaration files reads 0 for them out of range, not loss. Claude-Session: https://claude.ai/code/session_01JbZnqu8bt6YqfJsr9vaFb3 Co-authored-by: Claude <noreply@anthropic.com>
…hipped prescriptions were denying a door that exists (objectstack-ai#19234) Fixes objectstack-ai#17487 Clause-②: no ## The defect, and its direction Three shipped, customer-facing prescriptions in `@objectstack/spec` stated in the present tense that the runtime confirmation door had not shipped. It has: `actionConfirmationRefusal` is called pre-dispatch by `invokeBusinessAction` in `@objectstack/runtime`, and the MCP `run_action` tool grew the `confirm` member in the same change (the card behind it, objectstack-ai#15942, is done — `state_reason=completed`; its changeset `action-confirmation-gate-enforced` is still pending, so the door is on `main` and not yet released). So the published text denied a door that exists, and it failed in the dangerous direction: an author who reads it concludes the safety flag stops nothing, and either arranges a human in the loop some other way or stops setting the flag — losing the gate at the moment it starts working. That is the ADR-0049 false-compliance class with the sign flipped. ## Re-derivation — all three sites read on today's `origin/main` Triage's unblock comment verified site 1 only and said the other two were unmeasured. All three were re-read at merge base `805811e0d`. | # | Path | Current text | Verdict | |---|---|---|---| | 1 | `packages/spec/src/ai/tool.zod.ts` — `TOOL_RETIRED_KEY_GUIDANCE.requiresConfirmation` | "the declaration is the contract, not yet the behaviour — the runtime door that performs the refusal ships separately, and until it does, setting the flag does NOT stop an unconfirmed call. Do not try to verify the gate by invoking the operation without the member: until that door lands, such a call simply RUNS." | **FALSE today** | | 2 | `packages/spec/src/migrations/entries/semantic/17.tool-requires-confirmation-retired.ts` — `replacement` | "The refusal is DECLARED, not yet performed — the runtime door lands in objectstack-ai#15942, so until then the flag stops nothing on its own and the human in the loop is still yours to arrange" | **FALSE today** | | 3 | the same file — `acceptanceCriteria` | "Do NOT try to 'prove the gate' by invoking the operation without the confirmation member: the runtime door that refuses lands in objectstack-ai#15942, so before that ships the call is not refused, it RUNS the destructive operation." | **FALSE today** | **Correction to the card's count of the carriers.** The card names the `spec-changes` entry, the upgrade guide and the `os migrate meta` projection as if they were separate sites. They are not: all three are projections of the **one** ADR-0087 D3 entry file above. The measurement is therefore **three false prescriptions living in two source files**, plus three generated artefacts that carry them (`src/migrations/registry.ts`, `spec-changes.json`, `docs/protocol-upgrade-guide.md`), all regenerated here by `check:generated --fix`. Sweep radius for "is that all of them": eleven denial phrasings grepped repo-wide (`not yet the behaviour`, `ships separately`, `not yet performed`, `stops nothing`, `simply RUNS`, `until it does`, `until that door`, `door lands`, `yours to arrange`, `nothing server-side`, `no pause`), with `requiresConfirmation` lighting 10 files under `packages/spec/src` as the positive control. Two adjacent texts were read and left alone as **NOT A DEFECT**: `packages/spec/src/contracts/ai-service.ts` already states the gate in normative present tense, and `content/docs/ai/tools.mdx` says the retired **tool**-level key "returns only together with its enforcement", which is still true — the tool key has not returned. Two further readings are recorded under *Acceptance notes*. ## What the prose says now, and what holds it there Each prescription now states the refusal in the present tense **with the door's bounds**, because an unbounded "the platform refuses unconfirmed calls" is this same defect in the other direction. Read off the door's own docblock and its shipped changeset, never inferred: - the refusal is `ACTION_CONFIRMATION_REQUIRED`, 428, naming the action and the member `confirm: true`; - a GATE, not a queue — nothing is parked, and a refused call did not run: the gate sits before `loadActionSubjectRecord`, so no record is read and none written; - the enforced set is the doors that enforce the author's `ai.exposed` opt-in — today the action door reached from MCP `run_action`. REST `/actions` is **not** `ai.exposed`-gated and sits outside the gate, so an API-key agent on that route still needs its own human; - only the author's declared `ai.requiresConfirmation: true` refuses, and only the boolean `true` confirms; the wider `list_actions` heuristic advises and never refuses; - `confirm: true` is an unverifiable caller claim: the gate makes forgetting loud, it does not prove a human. `packages/spec/src/ai/tool-confirmation-prescription-tense.pin.test.ts` is the tie that was missing the first time — the prose was never bound to the function it describes, which is how it rotted. It reads the three shipped strings **and** the runtime door, and fails in both directions. **No pin was moved.** `ui/action-requires-confirmation-docblock.pin.test.ts` was read: it anchors on the `ai.requiresConfirmation` JSDoc in `ui/action.zod.ts` and on `actionLooksDestructive`, neither of which this diff touches, so it covers none of the three sites and stays as it is. ## Clause-②: no — the accept set did not move `check:authorable-surface` and `check:api-surface` are green with **zero** diff under `packages/spec/authorable-surface/` and `packages/spec/api-surface/`. The pin's last case feeds the same authored metadata in before and after: `tool.requiresConfirmation` still refused, a minimal tool still accepted, `action.ai.requiresConfirmation` still accepted for both `true` and `false`. What moved is string content inside `dist` and `spec-changes.json`, which is why a `patch` changeset is owed and present. ## Tests, and the reverse verification `pnpm --filter @objectstack/spec test` — 499 files / 14614 tests passed. `test:repo` — 34 files / 580 tests passed. `typecheck` — clean. New pin: 8/8. Three ablation legs, each mutated on disk through `scripts/ablation-replace.mjs` (anchor hit declared, blob hash proven to move), direction predicted before the run, restored and proven by blob hash against `HEAD` with `git diff HEAD` empty: | leg | mutation | predicted | observed | |---|---|---|---| | 1 | re-insert `The refusal is DECLARED, not yet performed` into the D3 entry's `replacement` | RED on "no shipped prescription denies the refusal" | RED, naming the replacement carrier | | 2 | rename the gate call inside `invokeBusinessAction` | RED on "the AI-facing door still calls the gate pre-dispatch" | RED | | 3 | make the REST `/actions` door name the gate | RED on the over-claim guard | RED | Leg 3's **first attempt was a no-op** and is reported as such: the replacement text still contained the anchor, so `ablation-replace` refused (anchor drop 0, not the declared 1) and nothing ran. It was re-anchored and re-run; the reading above is the re-run. ## Gates All 85 commands derived by `node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --commands` for this diff were run locally and exit 0, exit codes captured before any pipe. Eight first returned a stale-`dist` or `PREREQUISITE NOT MET` result (exit 1 / exit 3 — not measured, not findings); they were re-run green after `pnpm --filter @objectstack/spec build` and a full `turbo run build` closure. `pnpm lint` (`eslint . --no-inline-config`, whole repo, no narrowing) exits 0 at `HEAD`. CI still owns its own farm: the five path-scheduled CI jobs, the 11 wide-population families and the artifact rosters are outside that 85 and are NOT MEASURED here. ## Acceptance notes Two readings taken while re-deriving, both **out of scope for this card** and neither edited here: 1. `packages/spec/docs/MCP_GUIDE.md` (around the "Side Effects" section) tells an author to gate side effects with "`ai.requiresConfirmation` on the underlying **action** (+ the HITL approval queue)" and then warns, in the adjacent block, that "nothing server-side pauses on it". The warning is correctly scoped to the MCP capability descriptor in that page's examples and is true of it; but the approval-queue requirement now overstates what the action-level flag needs, and the two paragraphs read together in the card's own dangerous direction. Not in the declared file surface. Reported for filing with dedupe words: `MCP_GUIDE`, `requiresConfirmation`, `HITL approval queue`, `nothing server-side pauses`, `confirmation gate`. 2. `content/docs/ai/actions-as-tools.mdx` — the "Human-in-the-loop approval" section still says that on the open MCP path "the approval step lives at the protocol boundary" (client-side prompting), and the numbered open-MCP action-gate list enumerates five gates without the confirmation gate that now sits between the param contract and the subject-record load. An omission against a contract that `@objectstack/spec/contracts` declares. Reported for filing with dedupe words: `actions-as-tools`, `human-in-the-loop`, `protocol boundary`, `run_action`, `confirmation gate`. Noted, not filed: `packages/spec/src/api/error-code-ledger.zod.ts` says of the `ACTION_CONFIRMATION_REQUIRED` row that "the door will assert this exact string by value" — a forward tense about something that is now true. It misleads nobody about the gate and it is provenance prose about the row's split registration, not a prescription. Successor: the next change that touches that ledger row. ## Occupancy Re-scanned at 2026-09-20T01:52Z over all 21 open PRs, with PR objectstack-ai#17076 (639 files) fully paged so no path is under-read. `packages/spec/src/ai/tool.zod.ts`, the D3 entry, `spec-changes.json`, `docs/protocol-upgrade-guide.md`, `vitest.repo-tests.json` and `src/ai/tool.test.ts` all read FREE. Firing controls in the same scan: `packages/spec/src/ui/component.zod.ts` HELD by objectstack-ai#19219, `packages/spec/src/ui/view.test.ts` HELD by objectstack-ai#19226; dark control (a nonexistent path) reads FREE. One reading to flag: `packages/spec/src/migrations/registry.ts` reads HELD by objectstack-ai#19223, objectstack-ai#19090 and objectstack-ai#18319 — it is a generated, `merge=os-regen` artefact and none of those three touches the D3 entry this diff edits, so the contention is the one the regen driver exists for rather than two hands on the same prose. --- _Generated by [Claude Code](https://claude.ai/code/session_01AmH9bKvGoLjiY86Q4Z3og2)_ --------- Co-authored-by: Claude <noreply@anthropic.com>
Fixes #17987
Clause-②: yes (widening) — one new optional key on two published element faces plus one new
ComponentPropsMaprow. Nothing previously admitted is refused, nothing is renamed or retired.Executes the objectui#8652 maintainer ruling, reply verbatim 「B」 — declare
navigationon the platform element schemas. Options A / C / D were not taken and are not reopened here.What landed
object-kanbanandobject-calendardeclarenavigation, carryingNavigationConfigSchema— the defListViewSchema.navigationalready declares, taken BY REFERENCE so the vocabulary cannot fork. The retirednavigation.viewtombstone rides along onto both element faces.object-timelinegets itsComponentPropsMaprow. It was a registered objectui renderer reachable only through the component type union's open string arm with no row here, so the props gate skipped it: unjudged in both directions. The row declares the key set measured from the renderer's own read points at the.objectui-shapin53ded82b—objectName,timeline,filter,sort,limit,data,items,variant,dateFormat,rowLabel,minDate,maxDate,descriptionField,mapping,navigation— with the per-key citations, and what it deliberately does NOT declare, in the schema's own header.navigationonListViewSchemais untouched. The element key is an ADDITIONAL carrier for the standalone placement, not a replacement; a test pins that half so a later sweep cannot fold the two into one question.Premise re-derived on today's
origin/mainbefore any editBase
24d622b94b8afe93d00deda39062bf292e0d5d2f. The card's own numbers had moved, so every leg was re-measured rather than inherited:ComponentPropsMapentriesobject-kanban+navigationunrecognized_keys: ['navigation']object-calendar+navigationobject-timelinerownavigationControls, in the same run, so the zeros are readings:
object-kanban+cardFieldsandobject-calendar+defaultViewbothsuccess: trueat base, i.e. these faces were not refusing everything.zzzDefinitelyNotAKeyrefused through the sameunrecognized_keyschannel on both faces, before and after: the refusal ofnavigationwas the generic unknown-key rule, and it still is for an undeclared key.object-kanban/object-calendar/object-grid/object-treeall resolved in the same call, so "no entry" was a reading rather than a dead probe.The card's acceptance criterion, run
ComponentPropsMap['object-kanban'].safeParse({ objectName: 'task', navigation: { mode: 'drawer' } })returnssuccess: true,ComponentPropsMap['object-timeline']is defined, and the bogus-key control still returnssuccess: falsethroughunrecognized_keys. All three legs, plus the control, are pinned inpackages/spec/src/ui/component-element-navigation-17987.test.ts(12 tests at the current head; the sentence above is the card's criterion, and the leg added in round 2 sits beside it). The parsed state is the view face's:{ mode: 'drawer', preventNavigation: false, openNewTab: false, size: 'auto' }.The "cannot fork" clause has teeth rather than prose: the element door is asserted to resolve to the very object
ListViewSchema.navigationcarries, and the two faces' accept/refuse verdicts are asserted EQUAL over a five-document battery that contains both verdicts (so the equality cannot hold vacuously).Reverse verification — the fix committed first, then mutated on disk
02d81323c9. Its numbers and blobs are that head's and are left exactly as measured — ⛔ not restated as if they were the current head's. The round-2 leg follows it.Both legs went through
scripts/ablation-replace.mjs, so the write is proven by anchor counts and blob hashes rather than by an exit code, and each restore is proven byblob == HEADwithgit diff HEADempty.navigationdoor on all three faces (anchor x3 → x0, blob9b38bfa56e57→4f12296e0afc)object-timelinerow key (anchor x1 → x0, blob9b38bfa56e57→e2b329749e22)TimelineConfigSchemaprescription leg, neither of which depends on the rowRestored to
9b38bfa56e57b72e630540950d55f8fd09b6bee2both times; the suite is green on the restored tree.Round 2, head
ee50b4cd13— thedatadoor mutated through the same tool (anchor x1 → x0, blobd663b3c630d6): predicted red on exactly the two legs that authordataand nothing else; observed 2 failed / 10 passed, with the bogus-key control on that same face staying green and its refusal naming the bogus key and notdata. Restore proven byblob == HEADwithgit diff HEADempty. ⭐ The round-2 contract reviewer re-ran this leg independently with a different replacement string and read the same 2 failed / 10 passed.Gates
node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstackderives 107 families for this diff. All 107 were run and reconciled with--ran: 107 run, 0 NOT-MEASURED, 0 UNRUN.pnpm --filter @objectstack/spec buildthencheck:generated— green; six artifacts were regenerated by--fix(api-surface, api-surface-declarations, export-origins, declaration-map, the reference pages, the strictness ledger) plusgen:schema's authorable-surface and json-schema manifest.pnpm --filter @objectstack/spec test— 500 files / 14611 tests passed at the ROUND-1 head02d81323c9;typecheckgreen.ee50b4cd13: 500 files / 14612 tests passed — read twice independently, by the implementer and by the round-2 contract reviewer, andtypecheckgreen in both.pnpm lint— repo-wide, exit 0. Not a narrowed run: the wholeeslint . --no-inline-configuniverse.check:react-declaration-parityin CI's own spelling (MANIFEST="$PWD/sdui.manifest.json" … --baseline react-declaration-parity.baseline.json --strict) exits 0:object-timelinereads2 declared by both, 13 spec-only, 0 registry-only, so the new row needs no baseline entry and the ratchet reports no new divergence.MANIFESTthe gate reports "did not run" rather than skipping — and that non-zero inran.listis that refusal, not a divergence.scripts/pm/os-verify-lock.sh; the six path-scheduled CI jobs, the artifact-roster families and the wide-population families are CI's farm and are NOT measured here.Two files outside the card's declared surface, named rather than widened silently
The card's surface is
packages/spec/src/ui/plus the changeset and the generated pages that follow. Two more tracked files had to move, both mechanically and both printed by the gate that refused without them:packages/spec/dropped-refinements.baseline.json— the build REFUSES untilui/ObjectTimelinePropsdeclares the two sites its projection cannot carry (filter.element,timeline.groupByField), and prints the entry verbatim. It is the same rowui/ObjectGanttPropsalready carries. Its header totals moved with it (204 schemas / 560 sites), whichscripts/dropped-refinements.test.tsasserts.docs/audits/2026-07-unknown-key-strictness-ledger.counts.md— regenerated bygen:strictness-ledger: one more closed object site inui/.Acceptance notes — observed in passing, not filed, not fixed here
object-grid,object-ganttandobject-treedeclarenavigationasz.unknown(). Three element faces therefore acceptnavigation: { mode: 'drawr' }andnavigation: 'drawer'while the three this card touches now judge the value. Narrowing a published accept face is a different act from widening one, it is outside this card's closed scope, and it deserves its own ruling. Reported to the seat with dedupe words rather than filed from here.ListViewTimelineConfigdeclares a nestedtimeline.dateFieldalias thatTimelineConfigSchemarefuses by name, and the renderer reads it. That is the same defect shape as this card on a different key, on the VIEW face, so it is neither in scope nor fixable as a rider. Reported likewise. This PR's guidance prescription is careful about it: it namestimeline.startDateField, the key the alias resolves to and oneTimelineConfigSchemaaccepts — the trap spec: ComponentPropsMap['object-calendar'] prescribescalendar: { ..., allDayField }— a shape its own CalendarConfigSchema refuses by name #17054 already paid for once, pinned in the new test.object-treereads "NO component in the manifest" in the parity gate. Pre-existing, untouched, and outside the baseline's ratchet.Downstream
objectui#8652, objectui#8654 and objectui#8651's⚠️ Their unlock criterion is consumer-installable — a released
CalendarSchemaarm wait on this.@objectstack/speccarrying the declaration, installable there, with the pin moved — ⛔ not this merging.Body edited by the dispatching seat
domain:spec#4(session_01AmH9bKvGoLjiY86Q4Z3og2) after the rework landed atee50b4cd13e07a2d3327e78d5f98aefd30ed85ab: theobject-timelinekey list gaineddata, and the parity figure moved from 12 to 13 spec-only. The implementer named both edits in its report and correctly declined to patch this body itself — a dev writes a PR body once, at the POST that opens it.Generated by Claude Code