Repository navigation
spec: measure whether timeline / gantt / map / other switcher visualizations share the #13748 shape — whitelisted in appearance.allowedVisualizations with no binding block, renderer behavior unmeasured #14074
Description
Activity
Measurements for the question this card asks, taken from a real app while adding kanban / gantt / timeline / tree lenses over one object (
objectstack-ai/duly#12), on@objectstack/console17.2.0 and@objectstack/cli17.2.0.Every switcher visualization with a binding block has a literal-default fallback, and they are hard-coded strings in the ListView adapter (
plugins-views-*.js, theswitch (N)that builds the renderer props):type fallback when the block is absent calendarstartDateField || 'start_date',endDateField || 'end_date'ganttstartDateField || 'start_date',endDateField || 'end_date',progressField || 'progress',dependenciesField || 'dependencies'timelinestartDateField || 'created_at',titleField || 'name'maplocationField || 'location'treelabelField || titleField || 'name'gallerytitleField || 'name'kanbangroupBy = groupByField || groupField || <inferred from the object>— the one that does not use a literalSo on the switcher path the answer is yes: the shape is shared by
timeline,map,treeandgallery, not just the three the gate covers.Two behaviours worth separating, because they are not equally visible:
ganttfails closed. Its mapping returnsnullunless bothstartDateFieldandendDateFieldresolve —if (e.startDateField && e.endDateField) return { … }— and the task list is then[]. Blank chart.timelineandmapfail open-ish. They map every row and drop the ones whose date/coords do not parse, so the surface renders its chrome with nothing in it.treeis the odd one: it renders a complete, correct-looking flat table, because a missingparentFieldjust puts every record at depth 0.
Also worth noting for the whitelist half of this card specifically: the adapter computes the offered visualization list from which binding blocks are present —
let e = [`grid`]; (k.kanban?.groupByField || …) && e.push(`kanban`); (k.calendar?.startDateField || …) && e.push(`calendar`); ei(k).startDateField && e.push(`timeline`); (k.gantt?.startDateField || …) && e.push(`gantt`);
— and only then intersects that with
appearance.allowedVisualizations. So a type whitelisted with no block is filtered out of the switcher rather than offered unbound, which narrows this card's blast radius to authoredtype:(where it is real) plus whateverallowedVisualizationsentries survive that intersection.Filed the authored-
typehalf as a separate defect: theview/layout-without-bindinggate'sVIEW_BINDING_BLOCKStable nameskanban/calendar/ganttonly — #14106.
Generated by Claude Code
zhuangjianguo commented
on Sep 3, 2026 CollaboratorMore actionsClaim: PM loop,
domain:specseat (seat post #6017), R3 of this shift — group anchor (with #14073, per triage 5488535566 / 5488531595: one renderer measurement serves both cards, ⛔ not merged into one)
Session:session_0174WZTU6XcFcS7g2kykC53i(GitHubzhuangjianguo)
Branch:claude/issue-14074-switcher-visualization-binding(shared with #14073; a PR, if any, closes this card only)
Worktree:objectstack-issue-14074(+ a read-only or throwaway objectui worktree for the measurement — nothing is pushed to objectui)
Domain:domain:spec
File surface: MEASUREMENT FIRST, on objectuiorigin/mainf0f774b0(after objectui#7029 closed 2026-08-31) — the switcher path per visualization (kanban,gallery,timeline,gantt,chart,map,tree, andcalendaron the page door for #14073): whether a type whitelisted inappearance.allowedVisualizationswith no binding block is offered at all (packages/app-shell/src/views/InterfaceListPage.tsx:401intersection,ObjectView.tsx:2242-2256,ObjectDataPage.tsx:318), and if offered whether the renderer (a) hides, (b) refuses honestly or (c) invents a default (ObjectView.tsx:208,:290,:2366-2411literal fallbacks). CONDITIONAL code, only for this card and only if (c) is measured on the switcher path:packages/spec/src/ui/view.zod.ts(extend the #13817 cross-field refinement region near:1537-1545to the measured visualizations' required binding keys, no more than the renderer needs) ·packages/spec/src/ui/view.test.ts(flip the scope-pin "does NOT extend the requirement to 'timeline'" — the expected mechanical edit, not a regression — and add pins with issue code + path + first sentence) · generated artifactscheck:generated --fixproves stale ·.changeset/*.md@objectstack/spec(level per the changeset gates). ⛔packages/spec/src/ui/page.zod.tsuntouched (#14073 is measurement-only); ⛔ no objectui push. (a)/(b) measured working ⇒ no code, report only; the seat closes the card as archived. Stop on breach; explain in the report.
Container & model: M,mode:subagent,model: fable(CONTRACT_REVIEW_TIER).node scripts/pm/dispatch-gates.mjs --tier packages/spec/src/ui/view.zod.ts packages/spec/src/ui/page.zod.tsat0fb944b4(19:10Z): "no path-derived mandate" + "Clause ② SUSPECT surface" (both underpackages/spec/src/**); tier decided from content — the conditional outcome narrows a published accept set.
Clause-②: yes — conditional: extending the cross-field gate makes views that parse green today stop parsing. Provisional by design; ⛔ no pre-hang:needs:contract-reviewgoes on BOTH carriers (card + PR) in the same stroke only when a PR exists.
Serial constraints cleared: open-PR file scan at 19:08Z (24 open PRs, 207 changed-file rows) — none touchesui/view.zod.ts,ui/page.zod.ts,view.test.tsor the showcase pages; same-day churn: none (view.zod.ts96e25a8bandpage.zod.tsb7131f31both 2026-09-01); lane siblings in flight (#14048filter.zod.ts, #13916field.zod.ts, #14825 PR #15029 queued) file-disjoint; H17 on-hold trigger-file index (#9857 body, 13:47Z): #8346 declaresview.zod.tsas aRestart-touchtrigger — notification posted on #8346 in this stroke per the H17 precedent, no rider taken; no remote branch exists for this card (19:08Z).Decision re-read (2 comments): triage 5488535566 — deliverable is a measurement report, not code; only (c), or a provably failing (a)/(b), justifies extending the gate; a working (a) is a no-defect reading and the card closes as archived; the scope-pin flip is designed; group with #14073; H14 removal frozen (the card names objectui#7029). os-warren 5489373025 (measured on the console 17.2.0 bundle, not source): every visualization with a block has a literal-default fallback, gantt fails closed, timeline/map fail open-ish, tree renders a flat table; the adapter builds the offered list from PRESENT blocks and only then intersects with the whitelist, so a whitelisted type with no block is filtered out rather than offered — the authored-
typehalf was filed as #14106 and landed (closed 2026-09-02). That bundle reading is a mechanism hypothesis for the dev to confirm or refute on objectui SOURCE atf0f774b0, not a fact the dispatch inherits. Premise re-read onorigin/main0fb944b4(19:10Z):view.zod.ts:949allowedVisualizations: z.array(VisualizationTypeSchema).optional();:1170-1177and:1537-1545carry the #13817 calendar-only cross-field check;:849timelinestartDateFieldand:1227ganttstartDateFieldare required keys of optional blocks;view.test.tscarries the scope pin; #13817, #13748 and #14106 closed. Premise holds.
Generated by Claude Code
zhuangjianguo commented
on Sep 3, 2026 CollaboratorMore actionsDispatch (R3 of this shift, 2026-09-03T19:13Z) —
domain:specseat,session_0174WZTU6XcFcS7g2kykC53i, seat post #6017. Group anchor with #14073 (one measurement, two reports).mode:subagent,model: fable(CONTRACT_REVIEW_TIER), size M, Clause ② yes (conditional, provisional; ⛔ no pre-hang). The dev leaves its ownClaim:comment below; the assignee stays the PM's.Dispatch text handed to the dev, in brief (triage 5488535566's (a)/(b)/(c) criterion, "a working (a) is a no-defect reading", the designed scope-pin flip, and ⛔ measurement before any spec edit are quoted verbatim and marked non-renegotiable):
- M1 on objectui SOURCE at
origin/mainf0f774b0: for each switcher visualization whitelisted with no block — is it offered (the present-blocks-then-intersect logic inInterfaceListPage.tsx:401/ObjectView.tsx:2242-2256/ObjectDataPage.tsx:318, os-warren's bundle reading 5489373025 treated as a hypothesis), and if offered, (a)/(b)/(c) via the literal fallbacks atObjectView.tsx:208,:290,:2366-2411. A runtime probe in a throwaway objectui worktree is allowed; nothing is pushed to objectui. - (c) on the switcher path ⇒ extend the spec:
appearance.allowedVisualizationsmay includecalendarwith nocalendar:block — add the cross-field validation (calendar allowed ⇒calendar.startDateFieldrequired) #13817 cross-field check inview.zod.tsto those visualizations' required keys only, flip the scope pin inview.test.ts, pins with code + path + first sentence,check:generated --fix, changeset per the gates; hangneeds:contract-reviewon the PR AND this card in the same stroke. (a)/(b) working ⇒ no code; the report says so and the seat closes the card as archived. - Landing: draft PR
Fixes #14074only (⛔ no closing keyword near spec: interface pages acceptappearance.allowedVisualizations: ['calendar']but the page surface has NO calendar binding key at all — the #13748 shape on a different door #14073), two-limb Clause ② line in the body, ⛔ no ready flip;os-dev-reporton this card, and a secondos-dev-reporton spec: interface pages acceptappearance.allowedVisualizations: ['calendar']but the page surface has NO calendar binding key at all — the #13748 shape on a different door #14073 for its page-door reading.
Generated by Claude Code
- M1 on objectui SOURCE at
zhuangjianguo commented
on Sep 3, 2026 CollaboratorMore actionsos-dev-report
{ "issue": 14074, "status": "done", "branch": "claude/issue-14074-switcher-visualization-binding", "pr": null, "premise_still_valid": true, "summary": "Conclusion: no switcher-path defect; the authored-`type` half landed as #14106 (closed 2026-09-02). Measured on objectui source at `f0f774b0` (origin/main tip at measurement was `98d4108a`; the four named files, ListView.tsx and every renderer read are byte-identical between the two — the drift is 12 files under packages/types; control: the unrestricted diffstat is non-empty). H1 CONFIRMED on source and at runtime, on both doors: ListView `availableViews` (packages/plugin-list/src/ListView.tsx:2084-2153) builds `resolvable` from PRESENT bindings — kanban :2091, gallery :2096, calendar :2101, timeline :2108 via resolveTimelineDateBinding, gantt :2113, map :2129 via resolveListMapConfig, tree :2134 — then intersects with `appearance.allowedVisualizations` (:2141-2150, falling back to ['grid']); a whitelisted type with no block is filtered out, i.e. (a) the toggle is hidden. Probe: kanban/gallery/calendar/timeline/gantt/map/tree/chart not offered without a block (8/8), positive controls offered with the block (7/7; chart is the exception — see findings). The page door (InterfaceListPage.tsx:399-482) builds that same ListView schema, so it shares the intersection (H3 partly: it differs only in DERIVING each whitelisted binding from the source object's field types first — :409-418, helpers :153-200 and :253 — a real field name or undefined, never a literal); ObjectDataPage.tsx:318-327 builds its whitelist FROM the derived bindings, so the whitelist-without-block case cannot arise there. H2 CONFIRMED with one nuance: the ObjectView option bag invents no date, location or parent — calendarViewOptions :248-253 returns undefined, timelineViewOptions :200-211 and ganttViewOptions :285-291 restate only declared dates (probe: timelineViewOptions({}) and ganttViewOptions({}) both yield only titleField 'name'), map :2380 forwards viewDef.map?.locationField, tree :2405-2412 sends no parentField, kanban :2352-2364 derives the lane through detectStatusField (packages/types/src/record-semantics.ts:39-54), which only ever returns a field present on the object (probe: forced kanban hands groupBy 'status', a declared field). Surviving literals at :208, :290, :2366, :2381, :2395, :2411 are title floors ('name'), cosmetic. ONE binding-shaped literal survives: gallery `imageField || 'image'` (:2393) — it makes the gallery gate (:2096) answer yes for every object view, so a whitelisted gallery with no block IS offered from the view door (probe: ObjectView-bag offered = [\"Gallery\"], nothing else). Classified NOT (c): GalleryConfigSchema (packages/spec/src/ui/view.zod.ts:830-840) has no required key, and ObjectGallery (packages/plugin-list/src/ObjectGallery.tsx:233, :348-363) collapses the cover area when no record carries an image, so the offered gallery renders a truthful cover-less card list — there is no key a cross-field gate could require without requiring more than the renderer needs. The binding-key literals that DO survive (map 'location' ListView.tsx:2589; chart legacy axis 'name'/'value' :2633-2634; gantt 'progress'/'dependencies' :2558-2559) sit on the FORCED path only — reached when `viewType` names the type (authored `type:`, #14106's half, or the page door's allowed[0]) — and the switcher never reaches them (probe M1.2 vs M1.1). Therefore no (c) on the switcher path and no provably failing (a)/(b): no spec edit, no changeset, no PR; the #13817 scope pin stays as written. Pre-#7029 control (14884620, parent of 2a7ac324 = PR #7062 which closed objectui#7029): app-shell ObjectView.tsx:2220 fabricated calendar 'due_date' and :2259-2260 gantt 'start_date'/'end_date'; ListView.tsx:2240-2241 floored calendar, :2294 timeline 'created_at', :2310-2311 gantt — all gone at f0f774b0 (census by grep of `|| 'literal'` at both commits); objectui#7070 (2026-09-01, 5f4514f7) and #7500 (2026-09-03, 04a67b9d) removed the gantt and timeline floors. Housekeeping: assignee was empty at pickup (PM-side half state); the branch was pushed empty as the write-route probe (exit 0) and is left in place with no PR; objectstack origin/main moved 0fb944b4 to 82291fba before the worktree was cut — view.zod.ts, view.test.ts, page.zod.ts and the showcase page are unchanged between them (empty diffstat; control: the branch tip differs). Both worktrees removed without force.", "tests": "objectui throwaway worktree ../objectui-issue-14074 at f0f774b0 (local branch probe/issue-14074, never pushed, removed at the end): `pnpm install` under os-verify-lock (VERDICT command-exit 0, held 13s). `pnpm exec vitest run --maxWorkers=2` from the repo root (the canonical invocation) on 2 throwaway probe files plus 8 existing pins — run 1: `Test Files 2 failed | 8 passed (10)`, `Tests 2 failed | 103 passed (105)`, VERDICT command-exit 1: both reds were my own probe expectations, not defects (forced kanban hands groupBy 'status' derived from the object; defaultGanttFromObject on showcase_task derives endDateField 'due_date' by declaration order — both real fields); expectations corrected to the measured truth, run 2 (the 2 probe files): `Test Files 2 passed (2)`, `Tests 32 passed (32)`, VERDICT command-exit 0 (held 12s, waited 393s behind a sibling spec build). Probe readings printed to stdout: PROBE chart-with-block offered = false; ObjectView-bag offered = [\"Gallery\"]; forced calendar props = {}; forced timeline = {titleField:'name'}; forced gantt = {progressField:'progress', dependenciesField:'dependencies'}; forced map = {locationField:'location'}; forced tree = {labelField:'name'}; forced chart = {xAxisKey:'name', aggregate.field:'value'}; forced kanban = {groupBy:'status'}; forced gallery = {titleField:'name'}; timelineViewOptions({}) = {titleField:'name'}; ganttViewOptions({}) = {titleField:'name'}. Existing pins green at f0f774b0: plugin-list ListView.calendar-binding-7029 and ListView.gantt-binding-7070, plugin-calendar ObjectCalendar.unconfiguredRefusal-7029, plugin-gantt ObjectGantt.unconfiguredRefusal-7070, plugin-timeline ObjectTimeline.absentDateAxisRefusal-7459, app-shell InterfaceListPage.defaults, ObjectView.calendarBinding-7029, ObjectView.ganttBinding-7070. No objectstack code changed, so no objectstack gate is owed and none was run (dispatch-gates.mjs not invoked; the diff is empty). Zero-hit greps with positive controls: (1) `git diff --stat f0f774b0 98d4108a` restricted to the four named files is empty — control: unrestricted, 12 files; (2) `git show 2a7ac324 -- InterfaceListPage.tsx` is empty — control: the commit's --stat lists 9 files; (3) key-level `calendar` in page.zod.ts is zero — control: `appearance` at :438 in the same grep; (4) plugin-gallery/src yields nothing because that directory does not exist at f0f774b0 — control: the gallery renderer is plugin-list/src/ObjectGallery.tsx:233; (5) `VIEW_BINDING_BLOCKS` under packages/lint is zero — control: the rule id `view/layout-without-binding` resolves to packages/spec/src/kernel/functional-completeness.ts per validate-list-view-field-refs.ts:27.", "mcp_calls": "5 — search_issues x2 (dedupe on objectui for the two findings below), issue_write x1 (objectui#7544), add_issue_comment x2 (this report and #14073's); every card, comment, commit and file read went through git and the public issue-page payload at zero quota (objectui#7029's closer PR #7062 read from that payload).", "open_questions": [], "out_of_scope_findings": [ "filed as objectui#7544: ListView's capability gate never resolves `chart` — a grid view with a fully declared `chart:` block and `allowedVisualizations: ['grid','chart']` is never offered the Chart toggle (probe: chart-with-block offered = false; the other 7 types offered with their block); the map analogue was objectui#5042.", "NOT filed — objectui side, the objectui#7029 / #7070 / #7500 class, and H14 is frozen for this group (dedupe: a targeted objectui search returned no card): invented bindings surviving on the FORCED path (authored `type:` or page allowed[0]), unreachable through the switcher — map `locationField: mapConfig.locationField || 'location'` at plugin-list/src/ListView.tsx:2589 and plugin-view/src/ObjectView.tsx:1389; chart legacy axis `xAxisField || categoryField || 'name'` and value `'value'` at ListView.tsx:2633-2634 and plugin-view :1439-1440; gantt `progressField || 'progress'`, `dependenciesField || 'dependencies'` at ListView.tsx:2558-2559 and plugin-view :1377-1378 (optional keys, cosmetic class). PM to route.", "Observation, not filed: app-shell ObjectView.tsx:2393 `imageField || 'image'` makes the gallery capability gate a no-op from the view door (Gallery is offered to every object view that whitelists it); harmless today because the cover is optional and ObjectGallery hides the cover area, but it is the fabricated-name class.", "Observation, not filed: app-shell ObjectView.tsx:2254 and InterfaceListPage.tsx:482 compute `showViewSwitcher` from the whitelist LENGTH, not the filtered list — a view whitelisting ['grid','timeline'] with no timeline block shows switcher chrome with a single Grid entry (cosmetic).", "Observation for any future extension of #13817 to timeline: ListView resolveTimelineDateBinding (:411-437) accepts a `calendar:` block's startDateField as the timeline axis BY DESIGN, so a view with calendar bound and 'timeline' whitelisted with no `timeline:` block is offered and renders truthfully; a cross-field gate requiring `timeline.startDateField` would refuse that working shape — the pin's eventual flip, if ever, has to accept 'timeline OR calendar'." ] }Generated by Claude Code
Generated by Claude Code
zhuangjianguo commented
on Sep 3, 2026 CollaboratorMore actionsMeasurement review — ACCEPT · no switcher-path defect · card closes as archived (report 5531212329, no PR by design)
Reviewer of record: PM seat
domain:spec(session_0174WZTU6XcFcS7g2kykC53i). Provenance for the closure: triage 5488535566's own terminal condition — 「一个实测可用的 (a) 是「无缺陷」结论,那时本卡的正确结局是关卡存档,不是硬扩。」 The measurement is a good run: it confirmed the bundle-level hypothesis on SOURCE, on both doors, with runtime probes and positive controls, and it refuted nothing the card claimed — it answered the card's own question.Spot-checked by this seat on objectui
f0f774b0(19:49Z).packages/plugin-list/src/ListView.tsx:2085-2141:resolvableis built from PRESENT bindings (kanban:2092… tree:2135) and then intersected withappearance.allowedVisualizations(:2123), with the authoredviewTypeforce-pushed back in at:2139-2141— a whitelisted type with no block is not offered, i.e. (a) hidden, from either door. The page door (InterfaceListPage.tsx:412/414) derivescalendar/timelinefrom the object's fields throughdefaultCalendarFromObject(:170), a real field orundefined, never a literal. The surviving literals atListView.tsx:2558-2559/:2589andplugin-view/src/ObjectView.tsx:1377-1378/:1389sit on the forcedviewTypepath only — the authored-typehalf that #14106 (closed 2026-09-02) gates at authoring time.Derived judgments.
- No (c) on the switcher path for any of the seven visualizations; no provably failing (a)/(b). The spec:
appearance.allowedVisualizationsmay includecalendarwith nocalendar:block — add the cross-field validation (calendar allowed ⇒calendar.startDateFieldrequired) #13817 scope pin stays as written;view.zod.tsunchanged; no changeset, no PR. Correct. - The gallery nuance (
imageField || 'image'at app-shellObjectView.tsx:2393makes Gallery offerable from the view door without a block) is correctly classed NOT (c):GalleryConfigSchemahas no required key and the renderer collapses the cover area — a cross-field gate could only require more than the renderer needs, which the 视图声明 calendar 可视化但缺 calendar 配置块时,平台不报错——直接渲染成一屏错位画面(全部记录堆在今天) #13748 ruling forbids. - Pre-refactor(spec,cli):
--database-driver的可选值从共享驱动表推导,删掉 CLI 里的第二份词表 (#6969) #7029 control read at14884620is the honest "before": the fabricateddue_datelived on the VIEW door (app-shell ObjectView.tsx:2220), and objectui#7029 / finding: consumer half of #6523 — three plugin implementations still annotateSharingExecutionContext, so(context as any).postureis still needed to read a field the contract now declares #7070 / docs: plugin-distribution-framework-tasks.md marks F4 ✅, but PluginPermissionEnforcer has no production caller — the status row overstates #7500 removed the calendar, gantt and timeline floors. Consistent with the card's history. - Timeline-via-calendar axis (
resolveTimelineDateBindingacceptscalendar.startDateField) is recorded as a constraint on any future extension of spec:appearance.allowedVisualizationsmay includecalendarwith nocalendar:block — add the cross-field validation (calendar allowed ⇒calendar.startDateFieldrequired) #13817 — a gate requiringtimeline.startDateFieldwould refuse a working shape. Noted for the pin's eventual flip, if ever.
Out-of-scope group (sweep criterion: objectui renderer fallbacks outside the switcher path) — objectui#7544 (dev-filed:
chartis never resolved by the capability gate even with a full block); the forced-path invented bindings (map'location', chart axes'name'/'value', gantt'progress'/'dependencies') plus the gallery'image'literal and theshowViewSwitcher-reads-the-whitelist-length quirk — filed by this seat in objectui as one finding for that lane (number on the routing comment for #14073). The dev counted 5 MCP calls, all writes or controlled dedupe searches.State.
pm:dispatchedstripped, assignee released, card closed as completed with this measurement as the archive. The empty branchclaude/issue-14074-switcher-visualization-bindingstays on origin with no PR (the branch reaper is #12771's scope). Dev session: Agent task ad5c6cb868bd3b038 (subagent, finished; both worktrees removed without force).
Generated by Claude Code
- No (c) on the switcher path for any of the seven visualizations; no provably failing (a)/(b). The spec:
The #13748 ruling that produced #13817 (calendar cross-field gate) says in its scope clause: "Scope:
calendaronly — the measured defect. Iftimelineor another visualization has the same shape, that is a separate finding to measure first, not a rider here." This is that finding, filed for measurement — recording only.What is structurally true today (objectstack@6643ba1c, view.zod.ts)
kanban,gallery,timeline,gantt,chart,map,tree), andTimelineConfigSchema/GanttConfigSchemahave required binding keys (startDateField, and for ganttendDateFieldtoo) exactly like calendar'sstartDateField.appearance.allowedVisualizationsmay includecalendarwith nocalendar:block — add the cross-field validation (calendar allowed ⇒calendar.startDateFieldrequired) #13817,calendaris the ONLY entry ofappearance.allowedVisualizationstied cross-field to its block. A view whitelistingtimeline(organtt,map, ...) with no block still parses clean.checkViewCompletenesslayer WARNS (not refuses) for atype-level view missing its binding; the switcher path was the unguarded one for calendar.What needs measuring before any code (the ruling's precondition)
Per visualization, on the objectui renderer: when the switcher offers it with no block, does the renderer (a) hide the toggle (the client claims types "whose bindings don't resolve are hidden" — task.view.ts comment), (b) refuse honestly, or (c) invent a default the way calendar invented
startDateField: 'due_date'(ObjectView.tsx, removed by objectui#7029 — remains open)? Only shape (c), or a (a)/(b) path that provably fails, reproduces the measured #13748 defect and would justify extending the cross-field gate; a measured (a) that works is a no-defect reading.Note #13817's scope-pin test (
does NOT extend the requirement to 'timeline') intentionally pins today's accepting behavior — extending the gate flips that pin, which is the expected mechanical edit of the follow-up, not a conflict.Refs: #13748 (ruling and phenomenon record), #13817 (calendar half), objectui#7029 (calendar runtime half — remains open, not addressed here).
Generated by Claude Code