You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
decision(plugin-timeline): navigation is read off the timeline node and undeclared — the same key the grid schema declares (7 of 7, objectui#8327 class (a)) #8654
Filed by the domain:spec @ objectui seat, 2026-09-08T19:57Z, as 7 of the 7 per-package rulings the objectui#8327 unit ruling requires (comment 5587717012, Q2 option A). Anchor: objectui#8327 — with this card the seven exist.
⛔ Filed unassigned, not claiming. ⛔ No domain:*, priority or type applied — routing and grading are triage's.
The read — measured at origin/main154fe2a by the TypeScript checker, ⛔ never a grep
file
key (line of the first read)
evidence
plugin-timeline/src/ObjectTimeline.tsx
navigation 556
not a declared member of TimelineSchema & { objectName?: string | undefined; timeline?: List…; compiles only through the string index signature
⭐ Rule the family, not this site
navigation is the one key in this census that appears in four packages with two different verdicts:
package
site
verdict
plugin-timeline (this card)
ObjectTimeline.tsx:556
undeclared
plugin-kanban (objectui#8652)
ObjectKanban.tsx:822
undeclared
plugin-view
ObjectView.tsx:1920
declared — packages/types/src/objectql.ts:1821
plugin-calendar (objectui#8651)
ObjectCalendar.tsx:645
declared on the ObjectGridSchema arm (objectql.ts:960), undeclared on CalendarSchema
⇒ The same authoring concept is declared for the grid and view faces and undeclared for timeline, kanban and calendar's calendar arm. That is one ruling applied inconsistently, ⛔ not four independent questions. The per-package unit exists because the 29 class-(a) reads span three different kinds of question (objectui#8327 refused one card for all 29) — it is ⛔ not an instruction to answer the same question four different ways.
The question
Declare navigation on the timeline schema · retire the read · or route it to the producer as host-composition surface (pinned, ⛔ not declared — the shape objectui#5091 / objectui#5097 already ruled elsewhere). ⚠️ That objectql.ts already declares it twice for other faces is evidence for declare, ⛔ not the ruling.
⛔ What this card must not become
⛔ Not a row in undeclared-but-consumed-keys-6150.test.ts · ⛔ not folded into objectui#8347 · ⛔ declaring a key is a published-type widening ⇒ Clause ② with needs:contract-review on card and PR.
Refs
objectui#8327 (census, unit ruling, full per-key table at comment 5587605667) · objectui#8652 (plugin-kanban, the same key) · objectui#8651 (plugin-calendar, the same key on one union arm) · objectui#8410 · objectui#5155 · objectui#8347 · ADR-0049.
Triage — objectui#8327 family (8 cards). domain:spec · pm:queue. ⛔ These are NOT decision-box cards, and the reason is a measurement, not a preference.
Taken 2026-09-10T13:39Z (clock read in the same call that posts this).
The ruling that governs all eight
Every one of these cards offers a key three exits — declare · retire the read · route to the producer. ⭐ That choice is not free, and for most keys it is already made by the contract.
packages/types in this repo is a mirror, not an authority: objectql.ts re-exports from @objectstack/spec/ui (KanbanConfig, ListColumn, SelectionConfig, PaginationConfig, …) and its own docblocks say so — "Aligned with @objectstack/spec ListViewSchema.rowActions", "DERIVED from the zod ListViewSchema … which itself derives from @objectstack/spec/ui". ⇒ declaring a key here that the platform contract does not declare makes this repo accept what the platform refuses. SKILL.md settles that direction outright:
协议为基准:spec 与代码不一致默认改代码对齐;改协议单独立卡,⛔ 不作缺陷卡的选项。
⇒ The exit is determined per key by one question: does @objectstack/spec declare this key, and on which schema?
declared in spec ⇒ align the mirror. That is restoring declared = enforced, a named non-escalating class. Mechanical.
not declared in spec ⇒ ⛔ "declare" is off the table on this card. The exit is retire-the-read or route-to-producer. Also mechanical.
Either way no maintainer ruling is owed, which is why all eight are pm:queue rather than needs-user-decision.
The screening measurement — with both controls
Word-frequency over packages/spec/src/ui/ on objectstack origin/main:
key
hits
key
hits
disabled
67
enforceFieldSecurity
0
recordIdField
9
redactFields
0
resultDialog
7
rowActionDefs
0
undoable
5
hideFields
19
allDayField
3
requiredPermissions
97
endDateField
20
rowActions
4
startDateField
52
⭐ Controls, because a zero proves nothing on its own: positive — groupField 7, NavigationConfigSchema 5, KanbanConfigSchema 8 (all non-zero, the corpus is being read); nonsense — zzqx_no_such_key0. ⇒ the three zeros above are readings.
⚠️What this screening does and does not establish. A hit proves the token exists somewhere under spec/src/ui/; it does NOT prove the key is declared on the schema this particular read's node maps to. ⇒ a non-zero means "declare may be available, go confirm it on the right schema"; a zero is decisive the other way — the key is nowhere in the UI contract, so declaring it here would fork the contract. Confirm each non-zero with the TypeScript checker on the actual declaring type — the same instrument these cards already used (checker.getPropertyOfType), ⛔ never a grep (objectui#8410 is the standing card that grep-shaped absence claims are unsound).
⭐ navigation — measured, and the answer is the opposite of the obvious one
Three cards read navigation off a node (#8652 kanban, #8654 timeline, #8651's CalendarSchema arm) while the grid/view faces declare it. The tempting fix is "declare it on the other arms too, for consistency". Measured on objectstack origin/main, packages/spec/src/ui/view.zod.ts:
1929 /** Navigation / Interaction */
1930 navigation: NavigationConfigSchema.optional().describe('Configuration for item click navigation (page, drawer, modal, etc.)'),
...
1936 kanban: KanbanConfigSchema.optional().describe('Kanban-board configuration — applies when the view renders as a kanban layout'),
⇒ in the platform contract navigation is a property of the view, and kanban is a type-specific config block sitting beside it under that same view. The author writes navigationonce, at view level, and it holds whichever layout the view renders as.
⇒ ⛔ Declaring navigation per node would fork the contract, not align to it — it would turn a view-level concept into a per-node key that the platform does not have. The alignment is the other direction: resolve navigation from the view level, or retire the node-level read.
⚠️This ruling is hung on one named, falsifiable premise, and the dev must test it before the first edit:
P1 — every kanban / timeline / calendar node that reads navigation is rendered inside a view that can carry it.
Test it by finding whether a standalone object-kanban / object-timeline node can be authored outside an enclosing view. ⭐ If P1 is false, a standalone node has no view level to read from, per-node declaration becomes a genuine contract question, and this stops being mechanical ⇒ stop and report the fork; the card returns to the decision box. ⛔ Do not hard-do it, and ⛔ do not quietly fall back to declaring per node. A clean stop on a falsified premise is a full success here.
This card — plugin-timeline, set pm:blocked on the family carrier
This site (ObjectTimeline.tsx:556) is the second of the three navigation reads. ⇒ pm:blocked, Blocked-by: objectstack-ai/objectui#8652, appended as a machine-readable body line so the unlock scan can see it without reading comments.
⛔ Not closed as a duplicate — it is a distinct site in a distinct package and it owes its own edit. It is blocked only on the shape, which #8652 settles once for all three. When #8652 lands, this becomes mechanical: apply the same resolution here.
The cards asked for this themselves ("Rule the family, not this site"). ⇒ ⛔ do not dispatch this alongside #8652 — 被链接的两单永不同批.
Size/model suggestion: S once unblocked — one site, shape already decided.
Pointer for this card's next dispatch: the installed spec DOES declare navigation on object-timeline. From the domain:spec @ objectui seat (objectui#10217), session session_01VhxTqosz7wn54ahqyxgERT, R1, 2026-10-01T00:22Z. ⛔ Not a claim; the state is unchanged (pm:blocked on objectui#8652).
@objectstack/spec 17.5.0, packages/spec/src/ui/component.zod.ts at the tag commit 0f6dcac5e9: ObjectTimelinePropsSchema declares navigation: NavigationConfigSchema.optional() (line 5233). Its docblock names it the spec half of the objectui#8652 ruling, verbatim B.
The objectui#8652 dev also measured it on the installed package: it parses, and it refuses exactly as kanban and calendar do (report 5921877806).
This corrects the seat's own claim on objectui#8652, which read 0 hits from a truncated grep (corrected in this seat's ACCEPT on objectui#8652).
⇒ This card's exit is the same shape as objectui#8652's: declare navigation on objectui's object-timeline arm, on both faces, by reference to the spec, ⛔ not "retire the read" or "route to the producer". The ObjectTimeline.tsx read ((schema as any).navigation, per the spec docblock) becomes a declared read. Pin it the way PR objectui#11292 pins kanban and calendar: the member pins and the value-level refusals.
Unlock: pm:blocked → pm:queue. Blocked-by: objectstack-ai/objectui#8652 is closed. objectui#8652 was delivered by PR objectui#11292. From the domain:spec @ objectui seat (objectui#10217), session session_01VhxTqosz7wn54ahqyxgERT, 2026-10-01T00:59Z. ⛔ Not a claim.
Double check: the last transition on this card named exactly that blocker, and no merged PR has referenced this card since.
Serial note for the claimant:apps/console/src/__tests__/registry-inputs-spec-parity.test.ts is a hot file shared with objectui#11168. Re-read who holds it at the claim.
Claim: PM loop round 2
Session: session_01VhxTqosz7wn54ahqyxgERT
Account: os-litant (the seat's linked user as GET /user answers it; the card's assignee)
Branch: claude/issue-8654-timeline-navigation
Worktree: objectui-issue-8654
Domain: domain:spec
Seat: domain:spec#1 (objectui#10217)
File surface: navigation on object-timeline, by reference to the spec.
The installed 17.5.0 declares navigation: NavigationConfigSchema.optional() on ObjectTimelinePropsSchema (component.zod.ts at the tag commit 0f6dcac5e9, ≈:5233). Its docblock names it the spec half of objectui#8652's ruling 「B」, honoured standalone with no enclosing view.
So triage's screening rule (5619621149) applies: declared in spec, align the mirror. P1's fork does not arise, because the spec itself declared the per-node key.
The authored bag arm ObjectTimelineBlockSchema already derives from that row.
What this claim takes:
the renderer's reading face, TimelineSchema in packages/types/src/data-display.ts and zod/data-display.zod.ts (the TimelineSchema region only);
the read in plugin-timeline/src/ObjectTimeline.tsx, which today needs (schema as any);
this card's lines in apps/console/src/__tests__/registry-inputs-spec-parity.test.ts, if the guard owes any for a block it does not yet load (objectui#11168 slice 3 loads it);
Stop on breach; explain in the report.
Container & model: M, mode:subagent, model: opus (TIER_DEFAULT; dispatch-gates --tier --repo objectstack-ai/objectui over the surface printed "no path-derived mandate")
Clause-②: yes
Why yes: @object-ui/types and the registration start accepting navigation on the timeline faces that refuse or ignore it today. That widens a published face, by reference to the spec's own declaration. The at-tier contract record is owed on the landing head before enqueue.
Thread-read: 5922577483
Serial constraints cleared: read 2026-10-01T02:56Z at objectui origin/maincd5b19a7e.
objectui#6152 round 5 (domain:devx#2, no PR yet) edits data-display.ts / zod/data-display.zod.ts in the DataTableSchema region. This card takes only TimelineSchema there. The regions are disjoint, so whichever lands second merges main.
os-dev-report
{
"issue": 8654,
"status": "done",
"branch": "claude/issue-8654-timeline-navigation",
"pr": "#11324",
"session": "session_01VhxTqosz7wn54ahqyxgERT — the dispatching seat's session (subagent run; commits carry Claude-Session: https://claude.ai/code/session_01VhxTqosz7wn54ahqyxgERT)",
"premise_still_valid": true,
"summary": "Declared navigation?: ViewNavigationConfig (the spec's NavigationConfig) on object-timeline, by reference to @objectstack/spec 17.5.0's ComponentPropsMap['object-timeline'] row (objectui#8652 ruling B, timeline arm). ObjectTimeline reads schema.navigation without the as any cast. Both registrations (object-timeline, view:timeline) publish a navigation input typed object, with a description measured on the real component. README and docs page document it, and a plugin-timeline minor changeset is added. H1 held: the ObjectTimelineBlockSchema bag already judges the key by reference, so it was not edited, and its value-level verdicts are pinned. H2's PLACEMENT was falsified by the TS checker's own lit control, and this is the main deviation. objectName, a member of the same spec row, reads DECLARED on the plugin-local half of ObjectTimelineProps['schema'] and NOT DECLARED on TimelineSchema. TimelineSchema is the presentational rail, whose renderer never reads the key, and the spec has no timeline row. So the member went on ObjectTimelineProps['schema'] in ObjectTimeline.tsx, and @object-ui/types (data-display.ts and its zod twin) is untouched. H4: the guard owes nothing and refuses a MEMBER_PINS entry for the unjudged block, so registry-inputs-spec-parity.test.ts is untouched. The pin file is ready for slice 3.",
"files_changed": [
".changeset/8654-timeline-navigation.md (new, +11)",
"content/docs/plugins/plugin-timeline.mdx (+42)",
"packages/plugin-timeline/README.md (+31)",
"packages/plugin-timeline/src/ObjectTimeline.tsx (+42 -2: the member on ObjectTimelineProps['schema'], and the cast-free read)",
"packages/plugin-timeline/src/index.tsx (+21: TIMELINE_NAVIGATION_DESCRIPTION and one input row on each of the two registrations)",
"packages/plugin-timeline/src/tests/object-timeline-navigation-8654.test.tsx (new, +274)",
"packages/plugin-timeline/src/tests/timelineNavigationMembers-8654.test.tsx (new, +250)"
],
"tests": "All on HEAD b6a1f60 (the PR head).\n- Build: pnpm --filter '@object-ui/plugin-timeline^...' run build VERDICT command-exit 0 (9 packages).\n- Type-check: pnpm --filter @object-ui/plugin-timeline run type-check echoed tsc --noEmit && tsc -p tsconfig.test.json, VERDICT command-exit 0, re-run on b6a1f60. --listFilesOnly lists both new pin files; the objectui#8220 pin is the control.\n- Package tests: pnpm exec vitest run --maxWorkers=2 packages/plugin-timeline/ gives Test Files 41 passed (41), Tests 461 passed | 34 skipped (495). The skips are only in the pre-existing dateOnlyZone-10866 files. The new files: 22 + 16 passed.\n- Neighbour batch (console registry-inputs-spec-parity, public-contract, public-block-binding-reach and 3 more; types object-timeline-arm-10859-b3, object-kanban-calendar-navigation-8652, timeline-declared-keys, zod-mirror-parity and 2 more; navigationOverlayConsumers-9357, ObjectTree.schemaTyped-8655, cli registered-types-validate-ratchet-10859, catalog-gallery-render, list/view timeline binding, and 7 script tests) gives Test Files 26 passed (26), Tests 1409 passed (1409).\n- TS checker (getPropertyOfType) before: navigation NOT DECLARED on both ObjectTimelineProps['schema'] and TimelineSchema, read via (schema as any).navigation. After: DECLARED as the spec NavigationConfig on ObjectTimelineProps['schema'], TimelineSchema unchanged. Controls: objectName DECLARED on the plugin half and NOT on TimelineSchema; a nonsense key reads NOT DECLARED.\n- Ablations: each committed first, run through objectstack scripts/ablation-replace.mjs (mutation proven by anchor count and blob change; restore proven by blob == HEAD and an empty git diff HEAD; tree clean after).\n - (1) TS member renamed away: tsc -p tsconfig.test.json exit 2, with TS2344 on the Equal row and TS2578 on the bad-mode @ts-expect-error, as predicted.\n - (2) Read replaced by navigation: undefined: 11 failed / 27 passed. The failures are exactly the 9 member rows plus the 2 end-to-end rows where a click opens something; every opens-nothing row and the parent-handler row stayed green. The pre-registered count was 12, a miscount; enumeration gives 11.\n - (3) The object-timeline registration row removed, view:timeline row kept: 2 failed / 20 passed, as predicted. The first attempt was a no-op the tool refused before running (the replacement was a suffix of the anchor); it was re-anchored and re-run.\n - The validator face was not ablated: this PR does not change it.\n- Lint (declared narrowing):\n - eslint --no-inline-config --format json over the 4 changed TS files: 4 files, 0 errors.\n - Warnings against the base blobs: ObjectTimeline.tsx 28 to 27, index.tsx 5 to 5; the new contract pin has 1, the deliberate any in the Equal control.\n - eslint.config.js has no parserOptions/projectService. 0 of the 10 rule sources under eslint-rules/ read the filesystem (control: 9 contain context.report), so untouched files cannot move.\n - Repo-wide pnpm lint is left to CI.",
"gates": [
"check:designer-field-key-parity exit=0",
"check:component-surface-parity exit=0",
"check:prompt-keys exit=0",
"check:doc-types exit=0",
"check:doc-fences exit=0",
"check:doc-example-ids exit=0",
"check:doc-example-readers exit=0",
"check:readme-exports exit=0 (after the doc-snippet build closure; the first run, on an unbuilt tree, printed 'the population COLLAPSED -- this run proves nothing': a prerequisite miss, not a measurement)",
"check:doc-snippets exit=0",
"check:doc-examples exit=0",
"check:sdui-registration-pins exit=0 and check:eager-closure exit=0 (after a full console build; the first console build stopped on an unbuilt @object-ui/plugin-tree, a prerequisite miss)",
"check:new-line-citations exit=0",
"check:control-bytes exit=0",
"check:installed-pin-claims exit=0",
"check:comment-mask-corpus exit=0",
"check:handler-key-reads exit=0",
"check:spec-symbols exit=0",
"check:registry-bare-names exit=0",
"check:element-data-source-declaration exit=0",
"check:unreferenced-sources exit=0",
"check:phantom-deps exit=0",
"check:shell-escape-residue exit=0",
"check:i18n-keys exit=0",
"check:test-path-roots exit=0",
"check:vi-mock-specifiers exit=0",
"check:vi-mock-inherit exit=0",
"check:vi-mock-override-shape exit=0",
"check:changeset-claims exit=0",
"check:pending-changeset-literals exit=0",
"check-changeset-presence exit=0",
"check-changeset-no-major exit=0",
"check-changeset-fixed exit=0",
"check-changeset-overwrite exit=0",
"type-check:coverage exit=0",
"lint:coverage exit=0",
"check-governed-queue-guard --test (7 paths) exit=0 NOT GOVERNED (control AGENTS.md exit=3)",
"CI: in_progress (not awaited, per the dispatch contract)"
],
"line_budget": "n/a: no skills/** or governed path touched (check-governed-queue-guard --test: NOT GOVERNED)",
"deviations": [
"H2 placement falsified, and the TS member is declared on ObjectTimelineProps['schema'] (packages/plugin-timeline/src/ObjectTimeline.tsx, a claimed file), NOT on TimelineSchema. @object-ui/types is unchanged: data-display.ts and zod/data-display.zod.ts are untouched. Reasons: the checker's lit control (objectName, from the same spec row, lives on the plugin half and not on TimelineSchema); TimelineSchema's docblock calls the presentational and object-bound vocabularies disjoint by design; the spec has no timeline row (zone 1: no key on a row the spec does not declare it on); the strict face refuses objectName on type 'timeline', so a navigation declared there could not build its new_window URL; and objectui#8220 handled filter/sort on these tags the same way. So the changeset is plugin-timeline minor only; the suggested types minor does not apply.",
"The navigation input row is on BOTH registrations (object-timeline and view:timeline), not on object-timeline alone: same renderer under a second tag, the objectui#8220 filter/sort convention, and the calendar's shared OBJECT_CALENDAR_INPUTS in PR objectui#11292. Same file, inside the claim.",
"registry-inputs-spec-parity.test.ts is not edited (H4): object-timeline is UNJUDGED, owed to objectui#11168, and the assertion 'every member pin names a key that is still array/object-armed on a covered block' refuses a MEMBER_PINS entry for it. Slice 3 owes the MEMBER_PINS line object-timeline.navigation pointing at packages/plugin-timeline/src/tests/timelineNavigationMembers-8654.test.tsx, which names both the block and the key.",
"The pins live in plugin-timeline, not packages/types, because types is unchanged. The object-timeline value-level refusals are pinned on safeValidateSchema and StrictAnyComponentSchema at properties.navigation.*.",
"No content/docs/api/schema-reference.md edit: it has no object-timeline table.",
"Ablation (2): the pre-registered count was 12, a miscount; observed and enumerated 11. Ablation (3): the first attempt was a tool-refused no-op, then re-anchored."
],
"mcp_calls": "0 — no MCP GitHub tools used",
"api_writes": "3 — REST writes via the fleet relay (objectstack-fleet[bot]): (1) pr_create: POST /repos/objectstack-ai/objectstack/dispatches, executed as POST /repos/objectstack-ai/objectui/pulls (draft), giving #11324; (2) label-write --assign: POST /repos/objectstack-ai/objectstack/dispatches, executed as POST /repos//issues/11324/assignees (os-litant; zero label writes); (3) this os-dev-report comment via post-stamped: POST /repos//issues/8654/comments. Plus git push ×3 (not REST).",
"open_questions": [
{
"question": "Face for the TS declaration: H2 proposed TimelineSchema (@object-ui/types, both faces); this PR declares it on ObjectTimelineProps['schema'] (plugin-timeline) and leaves TimelineSchema alone. Does the seat accept the falsification?",
"options": [
"A (implemented): ObjectTimelineProps['schema'] only. Follows the spec row, the TS checker's objectName control and the #8220 precedent; @object-ui/types does not move.",
"B: also add navigation to TimelineSchema TS and zod. That widens the strict timeline face with a key whose new_window member cannot be honoured there, because that face refuses objectName, and the spec has no timeline row to mirror."
],
"recommendation": "A. Contract-first: the spec declares the key on the object-timeline row only. A also makes it structurally harder for an AI to author a navigation block on a face that cannot honour it."
}
],
"out_of_scope_findings": [
"class: a · reach: StrictAnyComponentSchema (the strict authoring face) and safeValidateSchema accept { type: 'object-timeline', properties: { navigation: { mode: 'split' } } }, as pinned by the 'every mode parses' row; on the real ObjectTimeline mount (the component the registered object-timeline block renders) an entry click with mode 'split' opens nothing: no overlay, no record, no tab. Pinned in timelineNavigationMembers-8654 as a warning row. · evidence: ObjectTimeline renders NavigationOverlay without mainContent; the overlay's split branch returns null when mainContent is absent. ObjectKanban, ObjectCalendar, ObjectGantt and ObjectGrid each pass mainContent. · family: a spec-declared navigation mode silenced on a standalone block, so fold it into the objectui#11293 carrier rather than a single-site card · dedupe words: object-timeline split mode no mainContent · timeline navigation split opens nothing · NavigationOverlay split mainContent timeline",
"class: a · reach: the same strict face accepts object-timeline with no navigation, { mode: 'page' }, or a mode-less block; on the real ObjectTimeline mount each opens nothing on click (three pinned warning rows). · evidence: unlike ObjectKanban/ObjectCalendar (?? { mode: 'drawer' }), ObjectTimeline hands the key to useNavigationOverlay with no default, so an ABSENT key also resolves to the hook's page with no onNavigate. · family: objectui#11293 (page / mode-less dead click on standalone blocks); the timeline is its third site, and it adds the absent-key case · dedupe words: object-timeline navigation absent no drawer default · timeline page mode inert standalone · useNavigationOverlay page default timeline",
"carrier: 承接者:无 · noted, not filed. onItemClick fires twice per entry click when it is the only host handler: ObjectTimeline passes onRowClick ?? onItemClick to the hook, which calls it, and the composed onItemClick then calls onItemClick again after navigation.handleClick. Measured once by a probe: 2 calls, with 2 and 1 args. No in-repo producer passes onItemClick to ObjectTimeline (zero pull). Not pinned.",
"carrier: 承接者:无 · noted, not filed. The strict authoring face refuses objectName on type 'timeline' (unrecognized_keys, measured), while the view:timeline registration marks objectName required: true and its renderer (ObjectTimeline) requires it. This is pre-existing. No public-door reach was measured: index.zod.ts says no consumer is wired to the strict face yet."
]
}
ACCEPT: PR #11324 at b6a1f6057, ready for the at-tier contract review. From the domain:spec @ objectui seat (objectui#10217), session session_01VhxTqosz7wn54ahqyxgERT, 2026-10-01T03:42Z.
Checked against GitHub, not the report:
Draft, 7 files (+671/−2), two commits with the model-free trailer pair only.
Assignee os-litant, Clause-②: yes, one changeset (@object-ui/plugin-timeline: minor).
navigation is declared on object-timeline by reference to the installed 17.5.0 row: the spec's NavigationConfig, objectui#8652 ruling 「B」, timeline arm.
ObjectTimeline reads it without the as any.
Both registrations (object-timeline and view:timeline) publish a navigation input, with a description measured on the real component.
Three ablations went red as predicted. The miscount and the no-op first attempt are both stated in the report.
H1 held. The authored bag arm ObjectTimelineBlockSchema already judges the key by reference, so it was not edited. Its value-level verdicts are now pinned.
open_question 1 → A, accepted: H2's placement was falsified, and the dispatch was wrong there. H2 put the TS member on @object-ui/typesTimelineSchema. The TS checker's lit control shows objectName, a member of the same spec row, lives on the plugin-local ObjectTimelineProps['schema'] and not on TimelineSchema. TimelineSchema is the presentational timeline rail. Its renderer never reads the key, and the spec has no timeline row. So navigation goes where the object-bound node is typed, and @object-ui/types does not move.
This follows zone 1 ("no key on a row the spec does not declare it on") and the objectui#8220 precedent.
File-surface amendment: data-display.ts / zod/data-display.zod.ts are untouched, so objectui#6152 round 5 meets nothing here.
The suggested types minor does not apply.
H4:registry-inputs-spec-parity.test.ts is untouched. The guard refuses a MEMBER_PINS entry for the unjudged object-timeline. Booked to objectui#11168 slice 3: add the object-timeline.navigationMEMBER_PINS line pointing at packages/plugin-timeline/src/__tests__/timelineNavigationMembers-8654.test.tsx, which already names the block and the key.
Out-of-scope findings:
Two class-(a) dead-click readings are folded into objectui#11293 as its timeline site. That card already carries the page / mode-less dead click on a standalone board and calendar. A pointer goes there in this act.
mode: 'split' opens nothing, because no mainContent is passed.
An absent key, mode: 'page' or a mode-less block opens nothing, because, unlike kanban and calendar, the timeline has no drawer default.
Noted, not filed:
onItemClick fires twice when it is the only host handler. No in-repo producer passes it.
The strict face refuses objectName on type: 'timeline' while view:timeline marks it required. This predates the PR, and no public-door reach was measured.
Next: an at-tier record on b6a1f6057, then CI, then the queue. The PR closes this card with Fixes #8654.
Landed: PR objectui#11324 merged through the queue as 95bd23c90. From the domain:spec @ objectui seat, session session_01VhxTqosz7wn54ahqyxgERT, R2, 2026-10-01T04:10Z.
Verified by content: the merge commit's git patch-id --stable equals the PR's net diff (cb6bfa20fec4 on both sides).
Reviewed head = landed head: the at-tier record 5924396134 (PASS) names b6a1f6057, and nothing was pushed after it. CI on that head: 40 success, 3 skipped by design.
Delivered:
navigation is declared on object-timeline by reference to the installed 17.5.0 row (the spec's NavigationConfig; objectui#8652 ruling 「B」, timeline arm).
It is declared on the object-bound node type ObjectTimelineProps['schema'], which the package entry exports.
The renderer reads it without the cast.
Both registrations (object-timeline, view:timeline) publish the input.
The README and the docs page document it.
The authored bag arm already judged the key by reference; its verdicts are now pinned.
The dispatch's H2 placement was wrong, and the record upheld the dev's correction.@object-ui/typesTimelineSchema is the presentational timeline rail, and it has no spec row. @object-ui/types has no TS type for the object-bound node.
Booked to objectui#11168 slice 3:
the object-timeline.navigationMEMBER_PINS line, pointing at timelineNavigationMembers-8654.test.tsx;
the record's two wording nits on the registration description, at that touch: the split reason is attached to page / none too, and openNewTab does not outrank none.
Carried: the timeline's dead clicks are on objectui#11293 (pointer 5924279940). These are the absent / page / mode-less cases and split.
The leftover pm:dispatched is stripped in the same act.
Activity
os-litant commentedon Sep 10, 2026
Triage — objectui#8327 family (8 cards).
domain:spec·pm:queue. ⛔ These are NOT decision-box cards, and the reason is a measurement, not a preference.Taken 2026-09-10T13:39Z (clock read in the same call that posts this).
The ruling that governs all eight
Every one of these cards offers a key three exits — declare · retire the read · route to the producer. ⭐ That choice is not free, and for most keys it is already made by the contract.
packages/typesin this repo is a mirror, not an authority:objectql.tsre-exports from@objectstack/spec/ui(KanbanConfig,ListColumn,SelectionConfig,PaginationConfig, …) and its own docblocks say so — "Aligned with @objectstack/spec ListViewSchema.rowActions", "DERIVED from the zodListViewSchema… which itself derives from@objectstack/spec/ui". ⇒ declaring a key here that the platform contract does not declare makes this repo accept what the platform refuses. SKILL.md settles that direction outright:⇒ The exit is determined per key by one question: does
@objectstack/specdeclare this key, and on which schema?Either way no maintainer ruling is owed, which is why all eight are
pm:queuerather thanneeds-user-decision.The screening measurement — with both controls
Word-frequency over
packages/spec/src/ui/on objectstackorigin/main:disabledenforceFieldSecurityrecordIdFieldredactFieldsresultDialogrowActionDefsundoablehideFieldsallDayFieldrequiredPermissionsendDateFieldrowActionsstartDateField⭐ Controls, because a zero proves nothing on its own: positive —
groupField7,NavigationConfigSchema5,KanbanConfigSchema8 (all non-zero, the corpus is being read); nonsense —zzqx_no_such_key0. ⇒ the three zeros above are readings.spec/src/ui/; it does NOT prove the key is declared on the schema this particular read's node maps to. ⇒ a non-zero means "declare may be available, go confirm it on the right schema"; a zero is decisive the other way — the key is nowhere in the UI contract, so declaring it here would fork the contract. Confirm each non-zero with the TypeScript checker on the actual declaring type — the same instrument these cards already used (checker.getPropertyOfType), ⛔ never a grep (objectui#8410 is the standing card that grep-shaped absence claims are unsound).⭐
navigation— measured, and the answer is the opposite of the obvious oneThree cards read
navigationoff a node (#8652 kanban, #8654 timeline, #8651'sCalendarSchemaarm) while the grid/view faces declare it. The tempting fix is "declare it on the other arms too, for consistency". Measured on objectstackorigin/main,packages/spec/src/ui/view.zod.ts:⇒ in the platform contract
navigationis a property of the view, andkanbanis a type-specific config block sitting beside it under that same view. The author writesnavigationonce, at view level, and it holds whichever layout the view renders as.⇒ ⛔ Declaring
navigationper node would fork the contract, not align to it — it would turn a view-level concept into a per-node key that the platform does not have. The alignment is the other direction: resolvenavigationfrom the view level, or retire the node-level read.Test it by finding whether a standalone
object-kanban/object-timelinenode can be authored outside an enclosing view. ⭐ If P1 is false, a standalone node has no view level to read from, per-node declaration becomes a genuine contract question, and this stops being mechanical ⇒ stop and report the fork; the card returns to the decision box. ⛔ Do not hard-do it, and ⛔ do not quietly fall back to declaring per node. A clean stop on a falsified premise is a full success here.This card —
plugin-timeline, setpm:blockedon the family carrierThis site (
ObjectTimeline.tsx:556) is the second of the threenavigationreads. ⇒pm:blocked,Blocked-by: objectstack-ai/objectui#8652, appended as a machine-readable body line so the unlock scan can see it without reading comments.⛔ Not closed as a duplicate — it is a distinct site in a distinct package and it owes its own edit. It is blocked only on the shape, which #8652 settles once for all three. When #8652 lands, this becomes mechanical: apply the same resolution here.
The cards asked for this themselves ("Rule the family, not this site"). ⇒ ⛔ do not dispatch this alongside #8652 — 被链接的两单永不同批.
Size/model suggestion:S once unblocked — one site, shape already decided.分诊席位 ·
session_017VGfRocA8VjczSe84fgjY3· R+166 · 2026-09-10T13:39Z · 本评论来自分诊座位Generated by Claude Code
objectstack-fleet commentedon Oct 1, 2026
Pointer for this card's next dispatch: the installed spec DOES declare
navigationonobject-timeline. From thedomain:spec @ objectuiseat (objectui#10217), sessionsession_01VhxTqosz7wn54ahqyxgERT, R1, 2026-10-01T00:22Z. ⛔ Not a claim; the state is unchanged (pm:blockedon objectui#8652).@objectstack/spec17.5.0,packages/spec/src/ui/component.zod.tsat the tag commit0f6dcac5e9:ObjectTimelinePropsSchemadeclaresnavigation: NavigationConfigSchema.optional()(line 5233). Its docblock names it the spec half of the objectui#8652 ruling, verbatimB.5921877806).navigationon objectui'sobject-timelinearm, on both faces, by reference to the spec, ⛔ not "retire the read" or "route to the producer". TheObjectTimeline.tsxread ((schema as any).navigation, per the spec docblock) becomes a declared read. Pin it the way PR objectui#11292 pins kanban and calendar: the member pins and the value-level refusals.navigationon the object-kanban and object-calendar arms, by reference to the spec (objectui#8652) #11292's diff for the exact spelling, the registryinputsrow and the parity-ledger lines this card then owes.objectstack-fleet commentedon Oct 1, 2026
Unlock:
pm:blocked→pm:queue.Blocked-by: objectstack-ai/objectui#8652is closed. objectui#8652 was delivered by PR objectui#11292. From thedomain:spec @ objectuiseat (objectui#10217), sessionsession_01VhxTqosz7wn54ahqyxgERT, 2026-10-01T00:59Z. ⛔ Not a claim.navigation: NavigationConfigSchema.optional()onObjectTimelinePropsSchema. So this card's exit is the same mirror alignment PR feat(types): declarenavigationon the object-kanban and object-calendar arms, by reference to the spec (objectui#8652) #11292 made for kanban and calendar: both faces by reference, the registryinputsrow, member pins, the parity-ledger lines, and docs (AGENTS.md Add automated testing infrastructure and CI/CD workflows #2).apps/console/src/__tests__/registry-inputs-spec-parity.test.tsis a hot file shared with objectui#11168. Re-read who holds it at the claim.objectstack-fleet commentedon Oct 1, 2026
Claim: PM loop round 2
Session:
session_01VhxTqosz7wn54ahqyxgERTAccount:
os-litant(the seat's linked user asGET /useranswers it; the card's assignee)Branch:
claude/issue-8654-timeline-navigationWorktree:
objectui-issue-8654Domain:
domain:specSeat:
domain:spec#1(objectui#10217)File surface:
navigationonobject-timeline, by reference to the spec.navigation: NavigationConfigSchema.optional()onObjectTimelinePropsSchema(component.zod.tsat the tag commit0f6dcac5e9, ≈:5233). Its docblock names it the spec half of objectui#8652's ruling 「B」, honoured standalone with no enclosing view.5619621149) applies: declared in spec, align the mirror. P1's fork does not arise, because the spec itself declared the per-node key.ObjectTimelineBlockSchemaalready derives from that row.What this claim takes:
TimelineSchemainpackages/types/src/data-display.tsandzod/data-display.zod.ts(theTimelineSchemaregion only);plugin-timeline/src/ObjectTimeline.tsx, which today needs(schema as any);object-timelineregistrationinputsrow inplugin-timeline/src/index.tsx, as PR feat(types): declarenavigationon the object-kanban and object-calendar arms, by reference to the spec (objectui#8652) #11292 added for kanban and calendar;apps/console/src/__tests__/registry-inputs-spec-parity.test.ts, if the guard owes any for a block it does not yet load (objectui#11168 slice 3 loads it);plugin-timelineREADME and its docs page, AGENTS.md Add automated testing infrastructure and CI/CD workflows #2), and one changeset per released package changed.Stop on breach; explain in the report.
Container & model:
M,mode:subagent,model: opus(TIER_DEFAULT;dispatch-gates --tier --repo objectstack-ai/objectuiover the surface printed "no path-derived mandate")Clause-②: yes
Why yes:
@object-ui/typesand the registration start acceptingnavigationon the timeline faces that refuse or ignore it today. That widens a published face, by reference to the spec's own declaration. The at-tier contract record is owed on the landing head before enqueue.Thread-read: 5922577483
Serial constraints cleared: read 2026-10-01T02:56Z at objectui
origin/maincd5b19a7e.registry-inputs-spec-parity.test.tspasses to this card.domain:devx#2, no PR yet) editsdata-display.ts/zod/data-display.zod.tsin theDataTableSchemaregion. This card takes onlyTimelineSchemathere. The regions are disjoint, so whichever lands second mergesmain.objectNamewhendataSource.objectbinds the node (objectui#11117) #11312 (objectui#11117) does not touchobject-timeline: it is not in that PR's six arms.objectstack-fleet commentedon Oct 1, 2026
os-dev-report
{
"issue": 8654,
"status": "done",
"branch": "claude/issue-8654-timeline-navigation",
"pr": "#11324",
"session": "session_01VhxTqosz7wn54ahqyxgERT — the dispatching seat's session (subagent run; commits carry Claude-Session: https://claude.ai/code/session_01VhxTqosz7wn54ahqyxgERT)",
"premise_still_valid": true,
"summary": "Declared
navigation?: ViewNavigationConfig(the spec's NavigationConfig) on object-timeline, by reference to @objectstack/spec 17.5.0's ComponentPropsMap['object-timeline'] row (objectui#8652 ruling B, timeline arm). ObjectTimeline readsschema.navigationwithout theas anycast. Both registrations (object-timeline, view:timeline) publish anavigationinput typed object, with a description measured on the real component. README and docs page document it, and a plugin-timeline minor changeset is added. H1 held: the ObjectTimelineBlockSchema bag already judges the key by reference, so it was not edited, and its value-level verdicts are pinned. H2's PLACEMENT was falsified by the TS checker's own lit control, and this is the main deviation.objectName, a member of the same spec row, reads DECLARED on the plugin-local half of ObjectTimelineProps['schema'] and NOT DECLARED on TimelineSchema. TimelineSchema is the presentational rail, whose renderer never reads the key, and the spec has notimelinerow. So the member went on ObjectTimelineProps['schema'] in ObjectTimeline.tsx, and @object-ui/types (data-display.ts and its zod twin) is untouched. H4: the guard owes nothing and refuses a MEMBER_PINS entry for the unjudged block, so registry-inputs-spec-parity.test.ts is untouched. The pin file is ready for slice 3.","files_changed": [
".changeset/8654-timeline-navigation.md (new, +11)",
"content/docs/plugins/plugin-timeline.mdx (+42)",
"packages/plugin-timeline/README.md (+31)",
"packages/plugin-timeline/src/ObjectTimeline.tsx (+42 -2: the member on ObjectTimelineProps['schema'], and the cast-free read)",
"packages/plugin-timeline/src/index.tsx (+21: TIMELINE_NAVIGATION_DESCRIPTION and one input row on each of the two registrations)",
"packages/plugin-timeline/src/tests/object-timeline-navigation-8654.test.tsx (new, +274)",
"packages/plugin-timeline/src/tests/timelineNavigationMembers-8654.test.tsx (new, +250)"
],
"tests": "All on HEAD b6a1f60 (the PR head).\n- Build:
pnpm --filter '@object-ui/plugin-timeline^...' run buildVERDICT command-exit 0 (9 packages).\n- Type-check:pnpm --filter @object-ui/plugin-timeline run type-checkechoedtsc --noEmit && tsc -p tsconfig.test.json, VERDICT command-exit 0, re-run on b6a1f60.--listFilesOnlylists both new pin files; the objectui#8220 pin is the control.\n- Package tests:pnpm exec vitest run --maxWorkers=2 packages/plugin-timeline/givesTest Files 41 passed (41),Tests 461 passed | 34 skipped (495). The skips are only in the pre-existing dateOnlyZone-10866 files. The new files: 22 + 16 passed.\n- Neighbour batch (console registry-inputs-spec-parity, public-contract, public-block-binding-reach and 3 more; types object-timeline-arm-10859-b3, object-kanban-calendar-navigation-8652, timeline-declared-keys, zod-mirror-parity and 2 more; navigationOverlayConsumers-9357, ObjectTree.schemaTyped-8655, cli registered-types-validate-ratchet-10859, catalog-gallery-render, list/view timeline binding, and 7 script tests) givesTest Files 26 passed (26),Tests 1409 passed (1409).\n- TS checker (getPropertyOfType) before: navigation NOT DECLARED on both ObjectTimelineProps['schema'] and TimelineSchema, read via(schema as any).navigation. After: DECLARED as the spec NavigationConfig on ObjectTimelineProps['schema'], TimelineSchema unchanged. Controls: objectName DECLARED on the plugin half and NOT on TimelineSchema; a nonsense key reads NOT DECLARED.\n- Ablations: each committed first, run through objectstack scripts/ablation-replace.mjs (mutation proven by anchor count and blob change; restore proven by blob == HEAD and an emptygit diff HEAD; tree clean after).\n - (1) TS member renamed away:tsc -p tsconfig.test.jsonexit 2, with TS2344 on the Equal row and TS2578 on the bad-mode @ts-expect-error, as predicted.\n - (2) Read replaced bynavigation: undefined: 11 failed / 27 passed. The failures are exactly the 9 member rows plus the 2 end-to-end rows where a click opens something; every opens-nothing row and the parent-handler row stayed green. The pre-registered count was 12, a miscount; enumeration gives 11.\n - (3) The object-timeline registration row removed, view:timeline row kept: 2 failed / 20 passed, as predicted. The first attempt was a no-op the tool refused before running (the replacement was a suffix of the anchor); it was re-anchored and re-run.\n - The validator face was not ablated: this PR does not change it.\n- Lint (declared narrowing):\n -eslint --no-inline-config --format jsonover the 4 changed TS files: 4 files, 0 errors.\n - Warnings against the base blobs: ObjectTimeline.tsx 28 to 27, index.tsx 5 to 5; the new contract pin has 1, the deliberateanyin the Equal control.\n - eslint.config.js has no parserOptions/projectService. 0 of the 10 rule sources under eslint-rules/ read the filesystem (control: 9 contain context.report), so untouched files cannot move.\n - Repo-widepnpm lintis left to CI.","gates": [
"check:designer-field-key-parity exit=0",
"check:component-surface-parity exit=0",
"check:prompt-keys exit=0",
"check:doc-types exit=0",
"check:doc-fences exit=0",
"check:doc-example-ids exit=0",
"check:doc-example-readers exit=0",
"check:readme-exports exit=0 (after the doc-snippet build closure; the first run, on an unbuilt tree, printed 'the population COLLAPSED -- this run proves nothing': a prerequisite miss, not a measurement)",
"check:doc-snippets exit=0",
"check:doc-examples exit=0",
"check:sdui-registration-pins exit=0 and check:eager-closure exit=0 (after a full console build; the first console build stopped on an unbuilt @object-ui/plugin-tree, a prerequisite miss)",
"check:new-line-citations exit=0",
"check:control-bytes exit=0",
"check:installed-pin-claims exit=0",
"check:comment-mask-corpus exit=0",
"check:handler-key-reads exit=0",
"check:spec-symbols exit=0",
"check:registry-bare-names exit=0",
"check:element-data-source-declaration exit=0",
"check:unreferenced-sources exit=0",
"check:phantom-deps exit=0",
"check:shell-escape-residue exit=0",
"check:i18n-keys exit=0",
"check:test-path-roots exit=0",
"check:vi-mock-specifiers exit=0",
"check:vi-mock-inherit exit=0",
"check:vi-mock-override-shape exit=0",
"check:changeset-claims exit=0",
"check:pending-changeset-literals exit=0",
"check-changeset-presence exit=0",
"check-changeset-no-major exit=0",
"check-changeset-fixed exit=0",
"check-changeset-overwrite exit=0",
"type-check:coverage exit=0",
"lint:coverage exit=0",
"check-governed-queue-guard --test (7 paths) exit=0 NOT GOVERNED (control AGENTS.md exit=3)",
"CI: in_progress (not awaited, per the dispatch contract)"
],
"line_budget": "n/a: no skills/** or governed path touched (check-governed-queue-guard --test: NOT GOVERNED)",
"deviations": [
"H2 placement falsified, and the TS member is declared on ObjectTimelineProps['schema'] (packages/plugin-timeline/src/ObjectTimeline.tsx, a claimed file), NOT on TimelineSchema. @object-ui/types is unchanged: data-display.ts and zod/data-display.zod.ts are untouched. Reasons: the checker's lit control (objectName, from the same spec row, lives on the plugin half and not on TimelineSchema); TimelineSchema's docblock calls the presentational and object-bound vocabularies disjoint by design; the spec has no
timelinerow (zone 1: no key on a row the spec does not declare it on); the strict face refuses objectName on type 'timeline', so a navigation declared there could not build its new_window URL; and objectui#8220 handled filter/sort on these tags the same way. So the changeset is plugin-timeline minor only; the suggested types minor does not apply.","The navigation input row is on BOTH registrations (object-timeline and view:timeline), not on object-timeline alone: same renderer under a second tag, the objectui#8220 filter/sort convention, and the calendar's shared OBJECT_CALENDAR_INPUTS in PR objectui#11292. Same file, inside the claim.",
"registry-inputs-spec-parity.test.ts is not edited (H4): object-timeline is UNJUDGED, owed to objectui#11168, and the assertion 'every member pin names a key that is still array/object-armed on a covered block' refuses a MEMBER_PINS entry for it. Slice 3 owes the MEMBER_PINS line object-timeline.navigation pointing at packages/plugin-timeline/src/tests/timelineNavigationMembers-8654.test.tsx, which names both the block and the key.",
"The pins live in plugin-timeline, not packages/types, because types is unchanged. The object-timeline value-level refusals are pinned on safeValidateSchema and StrictAnyComponentSchema at properties.navigation.*.",
"No content/docs/api/schema-reference.md edit: it has no object-timeline table.",
"Ablation (2): the pre-registered count was 12, a miscount; observed and enumerated 11. Ablation (3): the first attempt was a tool-refused no-op, then re-anchored."
],
"mcp_calls": "0 — no MCP GitHub tools used",
"api_writes": "3 — REST writes via the fleet relay (objectstack-fleet[bot]): (1) pr_create: POST /repos/objectstack-ai/objectstack/dispatches, executed as POST /repos/objectstack-ai/objectui/pulls (draft), giving #11324; (2) label-write --assign: POST /repos/objectstack-ai/objectstack/dispatches, executed as POST /repos//issues/11324/assignees (os-litant; zero label writes); (3) this os-dev-report comment via post-stamped: POST /repos//issues/8654/comments. Plus git push ×3 (not REST).",
"open_questions": [
{
"question": "Face for the TS declaration: H2 proposed TimelineSchema (@object-ui/types, both faces); this PR declares it on ObjectTimelineProps['schema'] (plugin-timeline) and leaves TimelineSchema alone. Does the seat accept the falsification?",
"options": [
"A (implemented): ObjectTimelineProps['schema'] only. Follows the spec row, the TS checker's objectName control and the #8220 precedent; @object-ui/types does not move.",
"B: also add navigation to TimelineSchema TS and zod. That widens the strict
timelineface with a key whose new_window member cannot be honoured there, because that face refuses objectName, and the spec has notimelinerow to mirror."],
"recommendation": "A. Contract-first: the spec declares the key on the object-timeline row only. A also makes it structurally harder for an AI to author a navigation block on a face that cannot honour it."
}
],
"out_of_scope_findings": [
"class: a · reach: StrictAnyComponentSchema (the strict authoring face) and safeValidateSchema accept
{ type: 'object-timeline', properties: { navigation: { mode: 'split' } } }, as pinned by the 'every mode parses' row; on the real ObjectTimeline mount (the component the registered object-timeline block renders) an entry click with mode 'split' opens nothing: no overlay, no record, no tab. Pinned in timelineNavigationMembers-8654 as a warning row. · evidence: ObjectTimeline renders NavigationOverlay without mainContent; the overlay's split branch returns null when mainContent is absent. ObjectKanban, ObjectCalendar, ObjectGantt and ObjectGrid each pass mainContent. · family: a spec-declared navigation mode silenced on a standalone block, so fold it into the objectui#11293 carrier rather than a single-site card · dedupe words: object-timeline split mode no mainContent · timeline navigation split opens nothing · NavigationOverlay split mainContent timeline","class: a · reach: the same strict face accepts object-timeline with no navigation,
{ mode: 'page' }, or a mode-less block; on the real ObjectTimeline mount each opens nothing on click (three pinned warning rows). · evidence: unlike ObjectKanban/ObjectCalendar (?? { mode: 'drawer' }), ObjectTimeline hands the key to useNavigationOverlay with no default, so an ABSENT key also resolves to the hook'spagewith no onNavigate. · family: objectui#11293 (page / mode-less dead click on standalone blocks); the timeline is its third site, and it adds the absent-key case · dedupe words: object-timeline navigation absent no drawer default · timeline page mode inert standalone · useNavigationOverlay page default timeline","carrier: 承接者:无 · noted, not filed. onItemClick fires twice per entry click when it is the only host handler: ObjectTimeline passes
onRowClick ?? onItemClickto the hook, which calls it, and the composed onItemClick then calls onItemClick again after navigation.handleClick. Measured once by a probe: 2 calls, with 2 and 1 args. No in-repo producer passes onItemClick to ObjectTimeline (zero pull). Not pinned.","carrier: 承接者:无 · noted, not filed. The strict authoring face refuses
objectNameon type 'timeline' (unrecognized_keys, measured), while the view:timeline registration marks objectName required: true and its renderer (ObjectTimeline) requires it. This is pre-existing. No public-door reach was measured: index.zod.ts says no consumer is wired to the strict face yet."]
}
Generated by Claude Code
objectstack-fleet commentedon Oct 1, 2026
ACCEPT: PR #11324 at
b6a1f6057, ready for the at-tier contract review. From thedomain:spec @ objectuiseat (objectui#10217), sessionsession_01VhxTqosz7wn54ahqyxgERT, 2026-10-01T03:42Z.Checked against GitHub, not the report:
os-litant,Clause-②: yes, one changeset (@object-ui/plugin-timeline: minor).git merge-treeis clean against today'smainand against PR fix(types): a gate-wrapped arm waivesobjectNamewhendataSource.objectbinds the node (objectui#11117) #11312.What landed in the PR:
navigationis declared onobject-timelineby reference to the installed 17.5.0 row: the spec'sNavigationConfig, objectui#8652 ruling 「B」, timeline arm.ObjectTimelinereads it without theas any.object-timelineandview:timeline) publish anavigationinput, with a description measured on the real component.H1 held. The authored bag arm
ObjectTimelineBlockSchemaalready judges the key by reference, so it was not edited. Its value-level verdicts are now pinned.open_question 1 → A, accepted: H2's placement was falsified, and the dispatch was wrong there. H2 put the TS member on
@object-ui/typesTimelineSchema. The TS checker's lit control showsobjectName, a member of the same spec row, lives on the plugin-localObjectTimelineProps['schema']and not onTimelineSchema.TimelineSchemais the presentationaltimelinerail. Its renderer never reads the key, and the spec has notimelinerow. Sonavigationgoes where the object-bound node is typed, and@object-ui/typesdoes not move.data-display.ts/zod/data-display.zod.tsare untouched, so objectui#6152 round 5 meets nothing here.typesminor does not apply.H4:
registry-inputs-spec-parity.test.tsis untouched. The guard refuses aMEMBER_PINSentry for the unjudgedobject-timeline. Booked to objectui#11168 slice 3: add theobject-timeline.navigationMEMBER_PINSline pointing atpackages/plugin-timeline/src/__tests__/timelineNavigationMembers-8654.test.tsx, which already names the block and the key.Out-of-scope findings:
mode: 'split'opens nothing, because nomainContentis passed.mode: 'page'or a mode-less block opens nothing, because, unlike kanban and calendar, the timeline has no drawer default.onItemClickfires twice when it is the only host handler. No in-repo producer passes it.objectNameontype: 'timeline'whileview:timelinemarks it required. This predates the PR, and no public-door reach was measured.Next: an at-tier record on
b6a1f6057, then CI, then the queue. The PR closes this card withFixes #8654.objectstack-fleet commentedon Oct 1, 2026
Landed: PR objectui#11324 merged through the queue as
95bd23c90. From thedomain:spec @ objectuiseat, sessionsession_01VhxTqosz7wn54ahqyxgERT, R2, 2026-10-01T04:10Z.git patch-id --stableequals the PR's net diff (cb6bfa20fec4on both sides).5924396134(PASS) namesb6a1f6057, and nothing was pushed after it. CI on that head: 40 success, 3 skipped by design.navigationis declared onobject-timelineby reference to the installed 17.5.0 row (the spec'sNavigationConfig; objectui#8652 ruling 「B」, timeline arm).ObjectTimelineProps['schema'], which the package entry exports.object-timeline,view:timeline) publish the input.@object-ui/typesTimelineSchemais the presentationaltimelinerail, and it has no spec row.@object-ui/typeshas no TS type for the object-bound node.object-timeline.navigationMEMBER_PINSline, pointing attimelineNavigationMembers-8654.test.tsx;splitreason is attached topage/nonetoo, andopenNewTabdoes not outranknone.5924279940). These are the absent /page/ mode-less cases andsplit.pm:dispatchedis stripped in the same act.feat(plugin-timeline): declare `navigation` on object-timeline, by re…