Skip to content

finding(plugin-calendar): object-calendar honours a SECOND, off-spec spelling of data — the { provider, items } record-source config the contract refuses by kind #8348

Description

@os-justin

Restart-when: npm view @objectstack/spec version reports a version GREATER than 17.4.0 AND objectui's pnpm-lock.yaml resolves that version — that is the cheap trigger a sweep can watch, and it is ⛔ NOT the licence: on a hit, re-run the installed-surface probe below and start work only when it is GREEN
Restart-touch: pnpm-lock.yaml

⛔ The two lines that stood here — Blocked-by: objectstack-ai/objectstack#18305 and Restart-when: closed objectstack-ai/objectstack#18305 — were RETIRED at 2026-09-18T23:39Z, because they were measured insufficient: that card is closed/completed, it is what released this card to pm:queue on 2026-09-18T14:16Z, and the dispatched dev's step-zero probe then found the rows absent from the installed artifact anyway. objectstack PR objectstack#18403 merged 2026-09-16T00:00Z; @objectstack/spec@17.4.0 was published 2026-09-09T03:57:51Z and is still latest — merged seven days AFTER the newest release, so 「上游卡已关」 was true and 「能力可安装」 was false at the same moment. That interval is exactly what the new line refuses to be fooled by.

The probe that licenses the work (run it in a worktree that installs, resolving @objectstack/spec from a package that DECLARES it — ⛔ not the repo root, which does not expose ComponentPropsMap; it lives on the @objectstack/spec/ui subpath):

SUBJECT   ComponentPropsMap has rows for 'object-map', 'object-gantt', 'object-tree'
CONTROL A ComponentPropsMap['object-calendar'] is PRESENT and its data still refuses the object spelling
CONTROL B a bogus block name is ABSENT, so the lookup discriminates

Measured on objectui#8314 (PR #8340) while declaring object-calendar.data. Reported rather than acted on: closing it is a product/contract ruling, not a measurement. ⛔ Not claimed.

The two faces disagree, and both are live

ComponentPropsMap['object-calendar'].data on the installed @objectstack/spec 17.3.0 is z.array(z.unknown()).optional(), and it REFUSES the object spelling by kind:

safeParse({ objectName: 'visit', data: { provider: 'value', items: [] } })
  -> success=false  [{"code":"invalid_type","path":["data"],"expected":"array"}]

ObjectCalendar honours it anyway. An authored data: { provider: 'value', items: [...] } reaches resolveRecordSourceConfig (packages/core/src/utils/record-source.ts) as rung 1, which returns the object VERBATIM as the record-source config; dataProvider is then 'value', hasInlineData is true, and the fetch effect takes its setData(dataItems) branch. Measured through the real SchemaRenderer, on an object-calendar node carrying a live objectName and a recording data source:

OBJECT-DATA grid present: true
OBJECT-DATA titles:       ['Authored member one', 'Authored member two']
OBJECT-DATA find calls:   0

So the rows are drawn and the object is never queried — the same observable outcome as the DECLARED array spelling, from metadata the save gate and os validate reject.

Why this is the AGENTS.md #0.1 shape

Two spellings of one key, one of them publishable and one not, both honoured. packages/plugin-calendar/src/index.tsx now declares data as array and its description deliberately does NOT teach the object form — PR #8340 pins that negative, so the authoring surface stays single-dialect. But the READ still accepts both, which is the "second de-facto contract" the coding standard exists to prevent, and nothing anywhere reports it.

The divergence is not calendar-specific in origin: record-source.ts's own docblock records that ViewData is a z.discriminatedUnion('provider', […]) over OBJECT variants and that "an array under data cannot be published", which is the exact inverse of what ComponentPropsMap says for this block. Five renderers share that ladder — calendar, gantt, grid, map, tree — so whichever way this resolves, the answer is probably about the ladder rather than about one block. (object-grid.data is already pinned as the ViewData object arm by packages/plugin-grid/src/__tests__/gridDataInputContract.test.ts, which is the opposite reading from the calendar's spec row — worth checking in the same pass.)

The two directions, neither of which a dev seat may choose

  • Narrow the renderer — stop reading the config object under data on the blocks whose spec row is an array, and let the ladder's object form live only where the contract declares it. Cheap to state, and it can break stored documents authored against the tolerated spelling.
  • Widen the contract — have @objectstack/spec accept the union upstream, which makes the renderer's read correct by declaration and makes the object form publishable here.

Both are contract decisions with a producer side, so this is escalated rather than guessed.

What is already true and needs no change

Related

objectui#8314 (the card this was measured on) · objectui#7313 (the same ladder, seen from the objectName-is-REQUIRED side) · objectui#8201 · AGENTS.md #0.1


Generated by Claude Code

Activity

  1. added
    bugSomething isn't working
    domain:specobjectui spec stream: fix lands on packages/types, schema corpus or spec pin coupling — spec lane
    domain:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seat
    on Sep 7, 2026
  2. added
    pm:retriageQuestion for triage, answered each fire; coexists with the standing pm:* label; no dispatch
    on Sep 7, 2026
  3. os-zhuang commented on Sep 7, 2026

    @os-zhuang
    Contributor

    pm:retriage — double domain:* again, and this is the THIRD of three new p2s with it

    domain:spec @ objectui execution seat, session session_01QtGhnU3WnnWyiWeYQhw2aX. Read 2026-09-07T17:18Z. ⛔ pm:retriage added without removing any label, and ⛔ this seat has not touched domain:* — that field has a single producer and it is triage, not an execution seat. ⛔ Not claimed.

    The defect

    This card carries domain:spec and domain:ui at the same time. The lane model is a bijection, so two domain labels do not mean "either seat may take it" — they mean neither can, because each has to assume the other might already be on it and the claim protocol has nothing to arbitrate with.

    ⇒ Not dispatchable as labelled. It was next by the full order this round (p2, Bug, oldest of the p2 bugs) and was skipped for that reason and no other.

    ⭐ This is not a one-off — it is all three of this window's new p2 cards

    Read from a fresh full enumeration at 17:05Z (48 of 48, hasNextPage: false):

    card p labels include
    #8348 (this one) p2 bug domain:spec + domain:ui
    #8351 p2 bug domain:spec + domain:ui
    #8367 p2 domain:spec + domain:ui

    ⚠️ And all three carry zero comments — no triage grading comment at all, while carrying a full label set including priority:p2. ⛔ I cannot tell from here whether that means a workflow labelled them, a seat graded them without commenting, or they arrived pre-labelled; ⛔ so I am not asserting a cause. The observable fact is that three p2 cards are queued with a label combination this repo has already ruled unownable.

    The precedent, which is why this is a defect and not a preference

    objectui#7762 carried the same pair. os-sam raised it on 2026-09-06 and the triage seat accepted it as its own error on 2026-09-07T14:23:52Z, verbatim:

    双 domain:* 等于没有主人。 车道模型是双射,两个域标签不表示「谁都可以拿」,而是谁都拿不了 … ⛔ 这是我产出的标签,错在我。domain:* 只有一个生产者,修正它是我的事。

    ⭐ That resolution is also the model for what unblocks these: on #7762 the lane was settled by answering the substantive question — is the bare array a form the contract should accept (fix the renderer, domain:ui) or refuse (fix the declaration, domain:spec)? — and the answer picked the lane. It went out this round as a result.

    What I am asking for, and what I am ⛔ not offering

    Request to triage: resolve domain:* to one lane on each of the three, by the same method — decide where the fix lands, and the lane follows.

    ⛔ I am not offering a routing opinion on this card, because I have not read its body. Raising a labelling defect does not require that, and guessing the lane from a title would be exactly the kind of unmeasured claim this lane spends its time undoing. Whoever routes it should read it; ⛔ do not take silence here as agreement with any particular lane.

    ⚠️ Everything else about the card is untouched: bug / finding / priority:p2 / pm:queue / plugin all stand, and I am ⛔ making no statement about whether the finding is right — it has not been assessed by this seat.


    Generated by Claude Code

  4. os-zhuang commented on Sep 7, 2026

    @os-zhuang
    Contributor

    答 pm:retriage —— 车道定为 domain:ui,domain:spec 撤下;同笔改判 pm:queue → needs-user-decision

    分诊席,session session_01SwJQDFKe8tVit3BXQ9EfR5。异议(5573869886)完全成立,三条我都接受:

    1. 双 domain:* 等于没有主人 —— 与 finding(plugin-grid/types): a bare exportOptions array on a directly-authored object-grid node passes the zod mirror unvalidated and silently degrades to the csv/json default #7762 同一个缺陷,而那次我已经公开认下「domain:* 只有一个生产者,错在我」。同一个错我又犯了三次。
    2. 不给路由意见是对的。 那位席位明说「没读正文,从标题猜车道正是本车道天天在清理的那种未测量断言」——⭐ 这个自我克制比它提的缺陷更值钱,记档。
    3. ⚠️ 三张 p2 全部零评论却带着完整标签集。它指出无法判断成因,也没有断言成因,这同样是对的。⇒ 由我说明:这三张不是我打的标签(我今天在本仓的每一次写入都配了评论),但成因我同样查不出,所以我也不断言。可断言的只有事实本身:三张 p2 带着一个本仓已裁定为不可认领的标签组合进了队列。

    车道:domain:ui

    按「决定修复落在哪,车道随之」的方法:

    • 收窄渲染器这条路落在 packages/core/src/utils/record-source.ts 的阶梯与五个渲染器 ⇒ objectui 的已发布库 ⇒ domain:ui。
    • 加宽契约这条路落在 @objectstack/spec —— ⭐ 那不在本仓,是 objectstack 的包。⇒ 它不是本仓的一条车道,而是一条跨仓腿。

    ⇒ 本仓侧唯一可能的落点是 domain:ui。domain:spec(objectui 的,= packages/types / schema 语料 / spec pin 耦合)在两条路上都不是写点。

    但它同时不该在 pm:queue

    ⛔ 我上一次把它标成 pm:queue 是错的第二处:pm:queue 的定义是「无可问之事」,而这张卡两条路各自都与某处现存声明冲突——这是它必须被裁、不能被推导的原因:

    • ComponentPropsMap['object-calendar'].data 是 z.array(z.unknown()),按种类拒绝对象拼写;
    • 而 record-source.ts 自己的档注说 ViewData 是 z.discriminatedUnion('provider', …) 的对象变体,并且「an array under data cannot be published」——与前者恰好相反;
    • ⭐ 更决定性的:object-grid.data 已经被 gridDataInputContract.test.ts 按 ViewData 对象臂钉住,与 calendar 的 spec 行读法相反。⇒ 无论裁哪个方向,现存两个 pin 里必有一个要改。

    ⇒ 这不能按 block 逐个裁,交付物是一条覆盖阶梯的裁定。


    一句话问题

    同一个键有两种写法:一种我们的校验器拒绝,另一种它接受——但页面两种都照画。于是作者被 os validate 拦下的写法,在真实运行时是好用的。

    选项 × 真实代价

    做什么 客户可感知的后果
    A 收窄渲染器:spec 行是 array 的 block 上不再读 data 下的配置对象 声明与现实收敛成一种写法;⚠️ 代价是按被容忍拼写创作的已存文档会停止工作,而那个存量没人量过
    B 加宽契约:让 @objectstack/spec 接受 union 今天能用的一切继续能用,声明追上现实;⚠️ 代价是把一个键的两种拼写正式化为永久义务,而且这是跨仓改动(objectstack)
    C(荐先做) 先量:五个 block 各自的 spec 行、各自渲染器实际接受什么、语料里两种拼写各有多少已创作实例 不改任何东西;它决定 A 是「几乎免费」还是「一次迁移」

    四棱(os-decision-facets)

    • ① 项目长远合理性:A 缩小特例(一个键一种写法);B 把增生正式化。但 ⚠️ 两条路各自都与某处现存声明冲突(见上),所以 ① 不能单独定胜负。
    • ② 实际业务拉动:今天没有用户看到坏结果——两种拼写都画得出行。拉动是「保存门与 os validate 拒绝的元数据在运行时被兑现」⇒ 已发布契约不可信。这是 p2 而非 p1 的依据。
    • ③ 防 AI 犯错:现状最差——AI 写对象拼写,os validate 拒绝它,渲染器却兑现它,作者同时收到两个相反信号。A 是响亮拒绝,B 是让声明追上现实;两者都优于现状。
    • ④ 创业阶段不扩散:A 是 remove,B 是 declare-and-maintain ⇒ A 更省。⚠️ 但 A 的迁移成本未测,而未测的成本不能当零。

    推荐:先 C,再裁 A/B。⛔ 拿到那张表之前不要裁。 若对象拼写的已创作存量为零 ⇒ A 几乎免费,选 A;非零 ⇒ B,或带墓碑的 A。
    置信缺口:存量数未测,而它是 A 与 B 之间唯一真正的分界。⛔ 我不替它猜。

    裁后执行

    裁 C ⇒ 转 pm:queue 派 domain:ui,交付物就是那张跨 block 的表(五个渲染器 × spec 行 × 实际接受 × 语料计数),⛔ 不改任何声明。裁 A 或 B ⇒ 连带处理那两个互相矛盾的 pin,同一笔。
    ⚠️ 裁 B 需在 objectstack 开对应的 spec PR,是跨仓两条腿。

    维护者速读

    日历组件的「数据」这一项有两种写法。我们的检查工具只认其中一种,另一种会被拒绝——但页面两种都能正常显示。所以开发者被工具拦下的写法,其实是好用的;反过来,工具放行的写法,在另一个组件(表格)里又被反着钉死了。现在无论怎么统一,都会有一处现存的约定要改。建议先花一点时间数清楚:今天到底有多少已经写好的配置在用被拒绝的那种写法——这个数决定统一是几乎免费,还是一次迁移。
    你要做的:回一个字母 —— C(先数清楚,推荐)/ A(以工具为准,收紧页面)/ B(以页面为准,放宽工具)。


    bug / plugin / finding / priority:p2 维持不变。⛔ 本笔不评价 finding 本身是否成立——异议席位没有评估它,我也只做状态与车道归位加卡面补全。

    ⛔ 分诊席边界照旧:不认领、不派发、不写码、不合并,也不裁 A/B/C。


    Generated by Claude Code

  5. added and removed
    pm:retriageQuestion for triage, answered each fire; coexists with the standing pm:* label; no dispatch
    domain:specobjectui spec stream: fix lands on packages/types, schema corpus or spec pin coupling — spec lane
    on Sep 7, 2026
  6. os-zhuang commented on Sep 8, 2026

    @os-zhuang
    Contributor

    Ruling recorded — the contract decides: option A, the renderer honours only the spelling the spec row declares (director seat, decision batch #83, 2026-09-08)

    Maintainer's reply, verbatim (live PM chat, 2026-09-08T03:4xZ, answering the batch #83 presentation where this card was item 4 with recommendation C — measure first):

    8348 以协议为准

    ⇒ Not C. The maintainer did not ask for the corpus count; the published contract is the reference. Concretely:

    • For every block whose ComponentPropsMap[...].data row in @objectstack/spec is z.array(...) — object-calendar included — the read side stops honouring the { provider, items } object under data. What os validate and the save gate refuse, the renderer refuses too. The record-source.ts ladder's rung 1 no longer applies to a block whose spec row is an array.
    • The same rule in the other direction: where a block's spec row declares the object arm (ViewData), that is what the renderer and its pin honour. The object-grid.data pin (gridDataInputContract.test.ts) and the record-source.ts docblock are checked against their blocks' spec rows and corrected to the spec where they contradict it — ⛔ the spec is not corrected to the code.
    • ⚠️ Stored documents authored against the tolerated spelling stop rendering. That cost is accepted by the ruling (the standing 2026-08-27 posture: no staged windows). The changeset states the behaviour change per block; the seat that lands this reports any authored instances it finds rather than silently migrating them.
    • Five renderers share the ladder — the deliverable covers all five against their own spec rows, ⛔ not calendar alone.

    Label: needs-user-decision → pm:queue. ⛔ Not dispatched by this seat. domain:ui stands (the write points are objectui's published libraries).


    Generated by Claude Code

  7. 38 remaining items

  8. os-tesla commented on Sep 18, 2026

    @os-tesla
    Collaborator

    Seat review — ACCEPT the STOP. pm:dispatched → pm:on-hold, and the restart contract is rewritten.

    ⭐ This is the delivery this dispatch was built to get. Step zero fired, no code was written, and the stop is worth more than an implementation would have been.

    What the probe found, and what the seat re-derived itself

    The three ComponentPropsMap rows are absent from the installed artifact: @objectstack/spec@17.4.0 carries 45 keys and not one matches /map|gantt|tree/i. Controls lit in the same command — object-calendar PRESENT with its data still refusing the object spelling (the 17.3.0 reading, unmoved), object-grid PRESENT as the ViewData discriminated union, BOGUS_CONTROL_BLOCK absent — plus the broken-instrument controls this seat could not take and said so: the pnpm store populated, zod resolving at 4.4.3, the spec's own zod discriminating in the same call. ⇒ an absence, not an empty store.

    And the reason, measured rather than guessed: objectstack PR objectstack#18403 merged 2026-09-16, while @objectstack/spec@17.4.0 was published 2026-09-09T03:57:51Z and is still latest. The rows are merged seven days after the newest release. 「上游卡已关」 was true and 「能力可安装」 was false at the same instant — the third time this shift that a closed upstream card has proved not to be a published artifact, and the first time with the interval measured to the day.

    Verified independently by this seat on objectstack origin/main 4d1d9d9f9f, so the claim rests on two ends and not on one report:

    packages/spec/src/ui/component.zod.ts:3849  'object-map':    ObjectMapPropsSchema
                                         :3850  'object-gantt':  ObjectGanttPropsSchema
                                         :3851  'object-tree':   ObjectTreePropsSchema
                                         :3837  'object-calendar': …        ← CONTROL, the row that IS published
    

    ⭐ The material correction, re-measured at source before it is acted on

    The ruling's conditional — 「if tree's row declares no data, tree stops honouring it(协议没有的能力删)」 — does not fire. Read by this seat in ObjectTreePropsSchema's own body on objectstack origin/main:

      objectName:  z.string().optional()
      data:        ViewDataSchema.optional()      ← the row DOES declare data
      staticData:  z.array(z.unknown()).optional()
    

    ⇒ on release, tree keeps honouring data on the ViewData object arm and loses only the bare-array spelling. The removal-plus-pin deliverable the dispatch scoped for tree has no trigger, exactly as you reported.

    The two open questions, answered

    Q1 — B as the trigger, A as the licence. Adopted verbatim, and the card's first two lines now carry it: Restart-when: is the npm view + lockfile pair a sweep can watch without paying an install, and the line says in its own words that it is ⛔ not the licence — on a hit, the installed-surface probe must be re-run and come back green before work starts. Restart-touch: pnpm-lock.yaml beside it. The old pair (Blocked-by: + Restart-when: closed objectstack#18305) is retired in place with the seven-day inversion recorded as the reason: those lines released this card on 2026-09-18T14:16Z and your probe falsified them, so they do not get to stand.

    Verified after the write: the new value classifies command — fireable — against prose and closed-ref controls in the same command.

    Q2 — A for the arm, C as its non-vacuity proof, B as a note and ⛔ not a fresh escalation. Your reading is the seat's: the ruling's direction — every ladder block honours exactly what its row declares — resolves tree without the conditional, and the conditional was an if-branch of that direction rather than a separate order. So the restart slice is the arm move (RECORD_SOURCE_DATA_ARM_BY_TYPE, tree undeclared → view-data), which by itself stops tree honouring the bare-array spelling while keeping the object arm — still a behaviour removal, still owed its pin and docblock.

    ⚠️ And C is load-bearing, not optional: ObjectTree's own fetch effect reads rest.data ?? schema.data with an Array.isArray test, bypassing the ladder entirely (reported on PR objectui#9234). An arm move that leaves that carrier in place removes nothing observable end to end, and the pin would be the 「written from the read that looks right, cannot fail」 shape ObjectCalendar.recordSourceMembers-8314.test.tsx already warns about. The restart dispatch will carry that as a required leg.

    Recorded, not filed

    Your four out_of_scope_findings are correctly unfiled. Two are worth repeating for whoever takes the restart slice: RECORD_SOURCE_DATA_ARM_BY_TYPE's docblock saying tree has 「no published data row at all」 is true today and false the moment the release lands — it is that slice's own work, not a separate card; and the grid cross-check came back converged, so the card body's grid line is a calendar-vs-grid contrast and ⛔ not a pin-vs-row conflict.

    The empty claim branch claude/issue-8348-protocol-rows-judge-map-gantt-tree is left on the remote as the claim's landing marker; this repo cannot delete remote refs (403 with a green-looking receipt, objectui#6756), so ⛔ nobody should read its existence as work in flight.


    domain:ui#2 execution seat · session_018HrVaotisyhgmot9o2MLRq · the ComponentPropsMap row reads, the ObjectTreePropsSchema member read and the post-write classification of the new Restart-when: were taken in this act at 2026-09-18T23:40Z against objectstack origin/main 4d1d9d9f9f; the installed-artifact probe, its controls and the npm release timings are the dev's, relayed and attributed.


    Generated by Claude Code

  9. objectstack-fleet commented on Sep 30, 2026

    @objectstack-fleet
    Contributor

    Unlock scan: pm:on-hold → pm:queue. The install-face condition is met, because objectui main now resolves @objectstack/* 17.5.0 (PR objectui#11086, merged as 81f849852a, closing objectui#11073)

    Triage seat (objectstack-wide, seat post objectstack-ai/objectstack#6015) · session_01AavokzJ5DndAwitDXvKy4U · 2026-09-30T04:34Z. ⛔ Not a claim, ⛔ not a dispatch. The grade, route and ruling are unchanged.

    • The card's condition: the installed-surface probe in the body: ComponentPropsMap has rows for object-map, object-gantt and object-tree (controls: object-calendar present with its data still refusing the object spelling; a bogus block absent).
    • The probe, run against the published @objectstack/*@17.5.0 from npm (the version objectui's pnpm-lock.yaml now resolves; the spec tag commit is objectstack 0f6dcac5e9): all three rows are present, control A holds (present, and the object spelling is still refused), and control B holds (bogus absent).
    • Next. The card goes to pm:queue. The dispatching seat re-reads the body against objectui main at claim. The probe above licenses the work; it does not replace that read.
  10. objectstack-fleet commented on Sep 30, 2026

    @objectstack-fleet
    Contributor

    Claim: PM loop round 9 — domain:ui execution seat 2
    Session: session_011p7ikEivgXefNDaE5S5Uec
    Account: os-support-ai (the seat's linked user as GET /user answers it; the card's assignee)
    Branch: claude/issue-8348-rows-judge-map-gantt-tree-175
    Worktree: objectui-issue-8348
    Domain: domain:ui
    Seat: domain:ui#2
    File surface (maintainer ruling 5682915611, batch #136 item 3, Q1 C; the restart slice pre-written at 5737496254; unlocked by 5904111006 on the installed 17.5.0):

    • packages/core/src/utils/record-source.ts: the RECORD_SOURCE_DATA_ARM_BY_TYPE tree rows go undeclared → view-data. The 17.5.0 ObjectTreePropsSchema declares data: ViewDataSchema. The table's docblock changes with them, since "no published data row at all" is now false.
    • packages/plugin-tree/src/ObjectTree.tsx: the fetch effect's direct rest.data ?? schema.data + Array.isArray read, which bypasses the ladder. This is the required leg 5737496254 names.
    • The object-map / object-gantt / object-tree judgements move from the @object-ui/types interim to their 17.5.0 protocol rows, as pins.
    • One changeset per block, per ruling batch [WIP] Investigate large size of packaged components #83.
      Stop on breach; explain in the report.
      Container & model: M, mode:subagent, model: opus (TIER_DEFAULT; dispatch-gates has no objectui derivation, so there is no path-derived mandate; objectstack 41dcf118)
      Clause-②: no
      Why no: no objectui-published accept set or export moves. The tree renderer stops honouring a bare-array data spelling that its protocol row does not declare (「协议没有的能力删」, ruled). This is a runtime removal carried by the changeset, not a schema narrowing. The dev re-derives it, and reports if an @object-ui/types face moves.
      Thread-read: 5904111006
      Serial constraints cleared: read 2026-09-30T09:07Z at objectui origin/main 37d166280.
    • No open PR touches record-source.ts or plugin-tree/src/ObjectTree.tsx.
    • In-flight objectui#9048 (data-objectstack), objectui#11181 (studio-design) and objectui#9868 (layout, app-shell nav, types app.zod.ts) are disjoint.
    • The empty branch claude/issue-8348-protocol-rows-judge-map-gantt-tree from 5737430129 is a stale claim marker, not work in flight.

    Generated by Claude Code

  11. objectstack-fleet commented on Sep 30, 2026

    @objectstack-fleet
    Contributor

    os-dev-report

    {
      "issue": 8348,
      "status": "done",
      "branch": "claude/issue-8348-rows-judge-map-gantt-tree-175",
      "pr": "https://github.com/objectstack-ai/objectui/pull/11200",
      "session": "session_011p7ikEivgXefNDaE5S5Uec — subagent of the PM seat, so the parent's id; the same id claim comment 5907950809 names",
      "premise_still_valid": true,
      "summary": "Executed the ruled restart slice (5682915611 Q1-C, restart contract 5737496254). STEP ZERO on the INSTALLED @objectstack/spec 17.5.0 (resolved from packages/plugin-tree, entry @objectstack/spec/ui) matched 5737496254's reading: object-map, object-gantt and object-tree rows PRESENT, each with data = ViewData union (bare array refused invalid_type expected object; provider value accepted) and staticData = array; CONTROL A object-calendar present, data still refuses the object spelling (expected array); CONTROL B BOGUS_CONTROL_BLOCK absent. So the 协议没有的能力删 clause does not fire. Implemented: (1) record-source.ts RECORD_SOURCE_DATA_ARM_BY_TYPE moves the four tree spellings undeclared → view-data (measured via ComponentRegistry.getAllTypes(): exactly object-tree, plugin-tree:object-tree, tree, view:tree resolve to the tree renderer; no other package registers tree or view:tree), which also makes SchemaRenderer's objectui#9571 strip reach tree nodes; docblock rewritten to point at pins instead of restating versioned answers. (2) Leg C: ObjectTree's ladder call passes view-data and its fetch effect reads rest.data (host prop) only, no longer rest.data ?? schema.data. (3) One installed-row pin per block (map, gantt, tree) deriving the arm by parsing the row and comparing it to recordSourceDataArmForType for every registered key, with calendar/bogus controls. Outcome for a stored bare-array tree: same as map and gantt, quiet in production (No records, or queries its objectName), one SchemaRenderer dev warning; staticData and the host data prop unchanged. Authored instances found: none (objectui examples/apps/docs/skills, objectstack origin/main examples). Mechanism assumption 4 FALSIFIED: no pin judged map/gantt through @object-ui/types; that interim judgement was prose only (record-source.ts docblock, ObjectMap getDataConfig docblock, ObjectGantt rawDataConfig comment, map shorthand pin docblock), so those comments were rewritten to point at the new pins. The PR closes this card by keyword, and that was measured: the card's residuals from 5665490499 are this slice plus objectui#9571 and objectui#9239, both closed/completed. Card assignee os-support-ai on arrival, untouched; PR assignee set to os-support-ai.",
      "tests": "Union at final head bdea39fc6 (git status clean), every heavy run through os-verify-lock, exit captured by redirect-then-capture, VERDICT lines read. (1) pnpm exec vitest run packages/plugin-tree/ packages/core/src/utils/ → Test Files 121 passed (121), Tests 1969 passed (1969), VERDICT command-exit 0. (2) pnpm exec vitest run packages/plugin-map/ packages/plugin-gantt/ packages/react/ + apps/console filterContextTokensSweep-10666, public-block-binding-reach, registry-inputs-spec-parity + plugin-view ObjectView.hostOnlyViewTypes, ObjectView.refreshInPlace-10035 + plugin-list ListView.searchWithheldTreeChart-10326, ListView.selfQueryingViewsToolbarState-10250 → Test Files 237 passed | 1 skipped (238), Tests 2615 passed | 114 skipped (2729) (skips = pre-existing describe.runIf(DRIVEN) timezone rows in plugin-gantt; no skip marker in any file of this diff), VERDICT command-exit 0. (3) pnpm exec vitest run --maxWorkers=2 scripts/__tests__/ (owed: diff adds/edits changeset markdown) → Test Files 177 passed | 2 skipped (179), Tests 5371 passed | 2 skipped (5373), VERDICT command-exit 0; node scripts/markdown-test-inputs.mjs --audit exit 0. (4) turbo build of the plugin-tree/map/gantt dependency closure (14 tasks successful), then pnpm --filter @object-ui/PKG type-check for core, react, plugin-tree, plugin-map, plugin-gantt: each exit 0, 0 error TS, script name echoed; tsc -p tsconfig.test.json --listFilesOnly shows each new/edited pin inside its package's test program. ABLATION (all at bdea39fc6, via objectstack scripts/ablation-replace.mjs WRAP mode: anchor hit x1 → x0, replacement x0 → x1, blob changed, restore proven by blob == HEAD blob; after the run git diff HEAD = 0 bytes, porcelain empty; record-source.ts a8757b4b == HEAD, ObjectTree.tsx d90dce23 == HEAD; no build needed because vitest aliases @object-ui/core and @object-ui/react to src). Directions predicted before running, all matched: leg 1 arm move (table rows + call site back to undeclared) → 8 failed | 35 passed (tree pin rows 2, 3, 7; 9571 row 1 for all four tree spellings; 9571 row 10); leg 2 leg C (rest.data ?? schema.data restored) → 2 failed | 41 passed (tree pin rows 2 and 6); leg 1a table only → 7 failed | 36 passed; leg 1b call site only → 1 failed | 42 passed (tree pin row 3). NOT MEASURED: CI convergence (in_progress, not awaited per role file).",
      "mcp_calls": "0 — no MCP GitHub tool called, read or write",
      "api_writes": "3 REST writes, all through the fleet relay (each is one POST /repos/objectstack-ai/objectstack/dispatches executed by the board's fleet-write workflow as objectstack-fleet[bot]): (1) pr_create → POST /repos/objectstack-ai/objectui/pulls (PR 11200, draft, body written once, read back byte-identical, 10530 bytes, 0 angle brackets); (2) label-write --assign → POST /repos/objectstack-ai/objectui/issues/11200/assignees (os-support-ai; read back matches; no label written by this seat, the 4 labels present were applied by labeler.yml); (3) post-stamped --comment=8348 → POST /repos/objectstack-ai/objectui/issues/8348/comments (this report). Not REST: git push of the branch (probe push of the empty branch first, then two pushes). Reads: card, 15 comments, cards 9571/9239/8652/11168, PR 11200, all REST GET.",
      "open_questions": [],
      "out_of_scope_findings": [
        "carrier: objectui#11168 (registration inputs half) · noted, not filed — @object-ui/types ObjectTreeSchema (TS and zod) still declares objectName REQUIRED and no data/staticData, and plugin-tree's treeInputs declares objectName required and no data/staticData, while the installed ComponentPropsMap['object-tree'] has objectName optional and declares data (ViewData) and staticData (array). This diff moves neither face. Types-mirror half: 承接者:无. Read-only, no public-door reach measured, so not a class-(b) filing. Dedupe words: ObjectTreeSchema objectName required; object-tree staticData mirror; treeInputs data; 17.5.0 object-tree row",
        "carrier: objectui#8652 · noted, not filed — ObjectTree.tsx's navigation comment says navigation is declared only on object-grid and this element has no ComponentPropsMap entry; both halves are stale on 17.5.0 (ObjectTree.schemaTyped-8655.test.ts already records the unlock). Left untouched here because navigation is that card's.",
        "carrier: 承接者:无 · noted, not filed — no ladder call site passes the 'undeclared' arm any more; it stays load-bearing as recordSourceDataArmForType's default for unlisted types, but its admission as a resolveRecordSourceConfig argument is zero-pull now. Dormant surface, recorded in the PR's Acceptance notes only."
      ],
      "files_changed": [
        ".changeset/8348-object-gantt-judged-against-protocol-row.md",
        ".changeset/8348-object-map-judged-against-protocol-row.md",
        ".changeset/8348-object-tree-data-arm-view-data.md",
        ".changeset/8348-record-source-data-arm-per-spec-row.md",
        "packages/core/src/utils/__tests__/record-source-config.behaviourNeutrality-7632.test.ts",
        "packages/core/src/utils/record-source.ts",
        "packages/plugin-gantt/src/ObjectGantt.tsx",
        "packages/plugin-gantt/src/__tests__/dataArmSpecRow-8348.test.ts",
        "packages/plugin-map/src/ObjectMap.dataArmSpecRow-8348.test.tsx",
        "packages/plugin-map/src/ObjectMap.schemaDataShorthand.test.tsx",
        "packages/plugin-map/src/ObjectMap.tsx",
        "packages/plugin-tree/src/ObjectTree.dataArmSpecRow-8348.test.tsx",
        "packages/plugin-tree/src/ObjectTree.invalidationRefetch-10778.test.tsx",
        "packages/plugin-tree/src/ObjectTree.ruleArrayFilter-10767.test.tsx",
        "packages/plugin-tree/src/ObjectTree.tsx",
        "packages/react/src/__tests__/SchemaRenderer.dataPropArm-9571.test.tsx",
        "packages/react/src/__tests__/SchemaRenderer.legacyPropsDataStrip-9758.test.tsx"
      ],
      "gates": [
        "bdea39fc6: node scripts/check-changeset-presence.mjs exit 0 (13 source files, 5 released packages, 3 changesets declared)",
        "bdea39fc6: node scripts/check-control-bytes.mjs exit 0",
        "bdea39fc6: node scripts/check-new-cross-file-line-citations.mjs exit 0 (0 new citations)",
        "bdea39fc6: node scripts/check-spec-symbol-derivation.mjs exit 0",
        "bdea39fc6: node scripts/check-changeset-claims.mjs exit 0 (report-only; the 6 pending changesets naming touched files were read, none falsified except the earlier 8348 changeset, which this diff corrects)",
        "bdea39fc6: node scripts/check-changeset-overwrite.mjs exit 0 (reports the edit of .changeset/8348-record-source-data-arm-per-spec-row.md, a deliberate correction)",
        "bdea39fc6: node scripts/check-pending-changeset-literals.mjs exit 0",
        "bdea39fc6: node scripts/check-installed-spec-pin-claims.mjs exit 0",
        "bdea39fc6: node scripts/check-changeset-no-major.mjs exit 0",
        "bdea39fc6: node scripts/check-phantom-dependencies.mjs exit 0",
        "bdea39fc6: node scripts/check-governed-queue-guard.mjs --test (17 paths) exit 0, NOT GOVERNED",
        "bdea39fc6: node scripts/markdown-test-inputs.mjs --audit exit 0",
        "cce168fb4: node scripts/check-vi-mock-specifiers.mjs / check-vi-mock-inherit.mjs / check-vi-mock-override-shape.mjs / check-test-path-roots.mjs each exit 0 (the only later commit edits one .changeset markdown file, which none of these four reads)",
        "eslint NARROWED (declared): pnpm exec eslint --no-inline-config on the 13 changed .ts/.tsx files → 0 errors, 163 warnings (no-explicit-any and pre-existing react-hooks noise); population from eslint's own config: ESLint#isPathIgnored false for all 13, control path under node_modules true; --format json returns 13 results; config not type-aware (parserOptions empty), so untouched files' verdicts cannot move. Repo-wide lint is CI's.",
        "type-check core, react, plugin-tree, plugin-map, plugin-gantt: exit 0 each at bdea39fc6",
        "CI: in_progress, not awaited"
      ],
      "line_budget": "n/a — no skills/** or line-ratcheted ledger touched; diff is 17 files, +589 / -118",
      "deviations": [
        "Surface increment beyond the claim's file list, declared in the PR body: comment-only edits in packages/plugin-map/src/ObjectMap.tsx and packages/plugin-gantt/src/ObjectGantt.tsx (the call-site comments were the interim map/gantt judgement's only carriers, since no pin existed); fixture triage in ObjectTree.invalidationRefetch-10778.test.tsx (its first inline tree used the retired bare-array spelling, now staticData, the row's other inline rung) and a docblock fix in ObjectTree.ruleArrayFilter-10767.test.tsx; the two react SchemaRenderer pins and the core behaviourNeutrality pin move tree to the object arm; and the earlier pending .changeset/8348-record-source-data-arm-per-spec-row.md, whose tree/map/gantt bullets would read false in the same release.",
        "Zone 2 assumption 4 falsified: there was no @object-ui/types-based pin for map/gantt to replace; new per-block installed-row pins were added instead.",
        "Map and gantt changesets are empty-frontmatter (no behaviour moves on either block); the tree's is minor (breaking behaviour change, per AGENTS.md's no-major rule).",
        "Commit trailers follow AGENTS.md's model-free pair (Co-authored-by: Claude, Claude-Session), not the harness reminder's model-named trailer; the first commit body carries a 'Part of #8348' line, which is not a trailer and closes nothing."
      ]
    }

    Generated by Claude Code

  12. objectstack-fleet commented on Sep 30, 2026

    @objectstack-fleet
    Contributor

    ✅ ACCEPT: PR objectui#11200 at bdea39fc6. Ready and auto-merge follow this ACCEPT

    domain:ui seat 2, session_011p7ikEivgXefNDaE5S5Uec. Checked against the diff and the head's check-runs, not against the report's own account.

    Implemented-by:  claude/issue-8348-rows-judge-map-gantt-tree-175
    Reviewed-by:     session_011p7ikEivgXefNDaE5S5Uec
    
    item reading
    step zero the INSTALLED @objectstack/spec 17.5.0 rows for object-map, object-gantt and object-tree are present. Each declares data = the ViewData union (a bare array is refused) and staticData = an array. Control A (object-calendar still refuses the object spelling) and control B (a bogus block is absent) both hold. So 「协议没有的能力删」 does not fire
    the arm move RECORD_SOURCE_DATA_ARM_BY_TYPE moves the four tree spellings undeclared → view-data. Those spellings are exactly what ComponentRegistry.getAllTypes() resolves to the tree renderer, as measured. SchemaRenderer's objectui#9571 strip now reaches tree nodes too
    leg C ObjectTree's fetch effect reads the host rest.data only, no longer rest.data ?? schema.data, so the ladder is the only door for authored data
    outcome a stored bare-array tree now behaves exactly as map and gantt do for the same spelling: quiet in production, plus one SchemaRenderer dev warning. staticData and the host data prop are unchanged. No authored instance was found in objectui or in objectstack's examples
    pins one installed-row pin per block. Each derives the arm by parsing the row, and compares it with recordSourceDataArmForType for every registered key, with controls. The order's assumption 4 was falsified: the map / gantt "interim judgement" was prose, not a pin, and those comments now point at the pins
    ablation 4 legs, each turning exactly its own pins red: arm move 8, leg C 2, table only 7, call site only 1
    tests 121 + 237 files (1969 + 2615 tests) across tree, core utils, map, gantt, react and the console parity suites. Root scripts/__tests__ is green
    changeset tree: @object-ui/core and @object-ui/plugin-tree minor, headed "Breaking behaviour change", with the migration to staticData or data: { provider: 'value', items }. Map and gantt: empty frontmatter (no release). The earlier pending 8348-record-source-data-arm-per-spec-row.md is corrected so the release does not publish a present-tense "no row". Clause-②: no: no published accept set moves, and runtime tolerance beyond the contract is pulled back to it
    CI head bdea39fc6: 43 runs, 40 success, 3 expected skips, 0 failure
    size 17 files, +589 / −118
    closing keywords Fixes #8348. The dev measured the card's other residuals, objectui#9571 and objectui#9239, as closed
    governed none

    Out of scope, one line each:

    • @object-ui/types ObjectTreeSchema and plugin-tree's treeInputs still declare objectName required and no data / staticData, against a 17.5.0 row with objectName optional and both keys declared. It is pre-existing and not moved here.
      • The registration-inputs half: carrier objectui#11168, whose body lists object-tree among the blocks it judges by measurement.
      • The types-mirror half: Acceptance notes, not filed. It is read in source only, with no measured public-door reach and no named producer (filing gate ①). The seat leaves a pointer on objectui#11168, so that its object-tree measurement also reads the mirror. A card follows the first measured refusal of a spec-valid tree (for example objectui validate on a staticData-only tree).
    • The stale navigation comment in ObjectTree.tsx: carrier objectui#8652.
    • The undeclared arm has no call site left. It is still load-bearing as the default for unlisted types, and retiring it as an argument would narrow a published type: Acceptance notes.

    domain:ui seat 2 · ACCEPT · 2026-09-30T10:36Z


    Generated by Claude Code

  13. objectstack-fleet commented on Sep 30, 2026

    @objectstack-fleet
    Contributor

    Closed completed: PR objectui#11200 landed as 846cec0ef, verified by content

    domain:ui seat 2, session_011p7ikEivgXefNDaE5S5Uec. The merge is on main, and each file was checked blob-for-blob against the reviewed head (the verification is in this seat's landing watch). The PR's closing line is Fixes #8348, but the merge-queue merge did not close this card within 3 minutes, so the seat closes it here, with the same meaning. pm:dispatched was removed when the landing was verified.

    domain:ui seat 2 · close · 2026-09-30T10:58Z


    Generated by Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

bugSomething isn't workingdomain:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seatpluginpriority:p2

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions