Repository navigation
date cells: a due-like date on a completed record still renders red "Overdue Nd" (Done tasks flagged overdue) #11815
Description
Ruled: 6054882132 · letter D · 2026-10-08T07:27Z
Blocked-by: #12297
Filing gate ① — product defect with a named location and a reproduction. reach: showcase Tasks grid: Audit current IA (Status Done) shows Due Date Sep 19 in red; App wireframes (Done) shows Overdue 6d in red.
Who acts on it: objectui triage → the console / records owner. ⛔ Not a claim. Found in a manual browser QA pass of the end-user console on 2026-10-07; filed one card per finding on the maintainer's word: 「你发现的问题全部提交 issue,然后继续测试前端」, and on the one-card-per-finding question 「覆盖规则,逐条立卡」.
What happens
A due-like date is styled overdue whenever it is in the past, regardless of whether the record is finished, so completed work reads as late. Within a short window the text is relative ("Overdue 6d"), beyond it absolute ("Sep 19") — both red.
Where it comes from (read in source)
resolveDueLike in fields/src/index.tsx decides "due-like" from dueLike: true or the field-name pattern (due, deadline, expires, …); isOverdueInstant then compares only the date with today. Nothing consults the record's state.
Expected
No overdue styling once the record is closed (a terminal status option, a done/completed boolean, or an author-declared condition).
Suggested direction (triage to rule)
Let dueLike take a "settled when" condition (or infer from a status field's terminal option / a done boolean), and skip the overdue affordance when it holds.
Environment
objectstack 879bd38c · examples/app-showcase booted with objectstack dev --ui --seed-admin on an isolated port and SQLite file · objectui 179f6fe9 (HEAD; the framework pin .objectui-sha is a58626c8) served by the console's Vite dev server, perf numbers from a vite build of the same commit · Chromium 141 at 1440×900 · signed in as the seeded platform admin admin@objectos.ai unless stated.
Duplicate check
- Semantic issue search on objectstack-ai/objectui (open and closed), overdue red due date completed record done task dueLike: 1 hits (0 open, 1 closed).
- Semantic issue search on objectstack-ai/objectui (open and closed), date cell shows overdue badge for records whose status is closed or completed: 1 hits (0 open, 1 closed).
- Related, not the same defect:
- timeline: every past date is bucketed "Overdue", including creation dates and Done records #11676 (closed) — same 'Done records flagged overdue' defect on the timeline view; closed 2026-10-06 by PR feat(i18n,plugin-timeline): retire the unread
timeline.bucket.overduekey (objectui#11676) #11716 in plugin-timeline only (predates objectui 179f6fe), so the date-cell renderer was never covered: a different surface, not a regression
- timeline: every past date is bucketed "Overdue", including creation dates and Done records #11676 (closed) — same 'Done records flagged overdue' defect on the timeline view; closed 2026-10-06 by PR feat(i18n,plugin-timeline): retire the unread
- Positive control in the same run: related lists action id refusal notice shown to end users on objectstack-ai/objectui returned related lists: an action id the related object does not define draws a refusal notice above the list for whoever opens the record — an authoring fault shown to end users; scope it to authors/admins #11768: yes.
Dedupe words: overdue red completed record · dueLike done task overdue · due date styling closed status
Filed by Claude Code (session session_01D76mrPJrSSdaKRxR2rvrMG) from that QA pass.
Decision facets (added by domain:ui seat 1, session_01DrKzdPdyLLBW3qpZ4vtk7z, from its analysis 6051653391 on this card)
os-decision-facets
① 项目长远合理性:A 收窄特例——「完成」由声明决定,单元格只管渲染值,判断只有一个地方;B 增加按名字猜的特例(与 #11676 的先例相冲);C 中性。
② 实际业务拉动:今天有人撞上——三个示例应用都有截止日期,复现截图里 Done 的任务显示红色;但这是 P3,不会写错任何数据。
③ 防 AI 犯错:A 是闭合声明(strict schema,发布时校验),出错时会被明确拒绝;B 是静默容忍,拼写不同的应用悄悄失效,没人知道。
④ 创业阶段不扩散:A 增加一个 spec 键和一个可选 prop,都是永久义务;C 零增量;B 不加 spec 键,但加一个 prop,还要长期维护一份名字表。
Prior rulings read: overdue completed done terminal option → 2 hits(objectui#11815、#11676);objectstack select option terminal marker final state → 0;ADR none;thread: #11676 ruling 6011959066
推荐 A,回退 C。只看①选 A;②③④ 是否翻转:否(④只调分期:先落 spec 键,再做单元格通道)。
置信缺口:没测过 report、kanban 等宿主在信号字段不在列中时补查询的代价,也没测第三方应用里「完成」的其他拼写有多常见。完整分析见 6051653391。
Generated by Claude Code
Activity
objectstack-fleet commentedon Oct 7, 2026
Path: ② the capabilities an end user meets in the app — a record's dates | 缺项 | P3
Triage: first grade,
bug·priority:p3·domain:ui·area:records·pm:queue. Direction: no overdue styling on a finished recordTriage seat (objectstack-wide, seat post objectstack-ai/objectstack#6015) ·
session_01AavokzJ5DndAwitDXvKy4U· 2026-10-07T17:39Z. ⛔ Not a claim, ⛔ not a dispatch.Triage: lands in
packages/fields/src/index.tsx(resolveDueLikeat:1024,isOverdueInstantat:1046) ⇒domain:ui; rationale: a Studio or console surface in objectui. Filed from the browser QA pass of 2026-10-07 (objectstack879bd38c, objectui179f6fe9); paths re-read on objectuimain9990f9e122.done/completedboolean, or a terminal state where one is declared)Clause-②: no. Patch changeset in objectui.objectstack-fleet commentedon Oct 8, 2026
Claim: PM loop round 8
Session:
session_01DrKzdPdyLLBW3qpZ4vtk7zAccount:
huangyiireneBranch:
claude/issue-11815-overdue-finished-recordWorktree:
objectui-issue-11815Domain:
domain:uiSeat:
domain:ui#1File surface (line numbers on
cef0eee):packages/fields/src/index.tsx: the due-like decision (resolveDueLikeabout:1024,isOverdueInstantabout:1046) and the date cell that applies the overdue affordance. The cell skips it when the record is finished, judged from what the metadata already declares: adone/completedboolean, or a terminal state where one is declared..changeset/11815-*.md.⛔ Not on it:
6043405462names it a spec change in objectstack, not in this card.@object-ui/fields(packages/fields/src/index.tsxis the package entry). If the cell cannot see the record without a published prop or parameter, the dev stops and reportsneeds_decision. That would beClause-②: yes.packages/components/src/ui/**andpackages/i18n/**.Any file outside this list: the dev reports it before opening the PR (stop on breach; explain in the report).
Container & model:
M,mode:subagent,model: opus(dispatch-gates --tier --repo objectstack-ai/objectuiover these paths: no path-derived mandate; default tier)Clause-②: no
Responsibility:
objectui fields: a due-like date renders red "Overdue Nd" whenever it is past, whatever the record's state, because isOverdueInstant compares only the date with today | the platform path is right: the record's done boolean or terminal state is already declared metadata | every user reading a list or record of finished work, measured by the filer (Done tasks flagged Overdue)Thread-read: 6043405462
Serial constraints cleared:
noneblocking.area:recordsin flight: seat 3's objectui#11812 (CommandPalette.tsx), and this seat's objectui#11813 (plugin-grid/src/importParsers.ts). Both are disjoint frompackages/fields/src/index.tsx.packages/fields/src/index.tsx. Read 2026-10-08T03:24Z.batch3 working devs, on the maintainer's word in this session's chat (「改为并行派发,batch 3」, 「继续派发」).Why
Clause-②: no: the overdue affordance is suppressed from metadata the renderer already reads. No export, prop,@object-ui/typesmember, spec key or accepted input is added. The dev stops if that proves false.objectstack-fleet commentedon Oct 8, 2026
os-dev-report
{
"issue": 11815,
"status": "needs_decision",
"branch": "claude/issue-11815-overdue-finished-record",
"pr": null,
"session": "session_01DrKzdPdyLLBW3qpZ4vtk7z (the claim 6051524199 session; this subagent runs under it)",
"premise_still_valid": true,
"summary": "No PR and no code: the fence stop condition is met, and the fix is Clause-②: yes. Measured on origin/main cef0eee: the overdue affordance is decided inside DateCellRenderer and DateTimeCellRenderer (packages/fields/src/index.tsx, through resolveDueLike and isOverdueInstant), and their only inputs are the exported CellRendererProps (value, field, isEditing, onChange). Every host passes value and field only: 13 call sites in 11 files (ObjectGrid, RelatedList, DetailSection, HeaderHighlight, RecordMetaFooter, ObjectKanban, ObjectGallery, plugin-dashboard recordFields, ReportViewer, ObjectTree, console ApprovalsInboxPage). No per-row context exists, so the cell cannot see the record without a new published prop or context. The one existing record channel, useRecordContext() in @object-ui/react, is mounted only by the record page. record:related_list renders inside it and reads it for the PARENT record, so a date cell reading it would judge child rows by their parent. The declared-metadata premise also only half holds. The installed @objectstack/spec 17.7.0 declares no terminal marker on a select option: SelectOptionSchema is strict, with label, value, description, color, default and visibleWhen. It declares no final state on the state_machine rule either, which has transitions only. A dead-end list does not mean finished: showcase task done → in_progress and crm opportunity closed_lost → prospecting are both finished and both reopenable. So the only completion signal the codebase already names is the boolean set completed / is_completed / done / is_done (BooleanCellRenderer, isCompletionField). In the issue's own repro grid that boolean is not fetched: the grid's $select is id plus the view's columns (plus predicate and grouping fields), and the showcase All Tasks view does not show done.",
"mechanism_hypotheses": {
"H1": "Held. resolveDueLike and isOverdueInstant are module-private and are called by DateCellRenderer and DateTimeCellRenderer only. Both receive value and field and nothing else; there is no record, no object field map and no cell context.",
"H2": "Falsified. The row reaches the host (data-table calls col.cell(cellValue, row); ObjectGrid builds cellRenderer as (value, row)) but stops there: every host renders the cell with value and field only. No per-row React context exists in react, core, components, plugin-grid or plugin-detail. RecordContext covers the record page only, and it names the wrong record inside related lists.",
"H3": "Partly held. showcase_task declares a status select with a done option (no terminal marker; the spec has none), a done boolean, a state_machine rule that allows done → in_progress (so done is not a dead end), and an activityMilestones row (field status, value done, type completed). Its type is an open activity-row kind, not a record-state declaration. Both repro seed rows (Audit current IA, App wireframes) carry status done and done: true."
},
"tests": "No code changed, so no gate is owed: no diff, no package touched, so there is no dependency-closure build. One reproduction read ran through os-verify-lock (slot dev-11815) at cef0eee: pnpm exec vitest run packages/fields/src/tests/DateCellRenderer.test.tsx --maxWorkers=2 gave 'Test Files 1 passed (1) / Tests 8 passed (8)' and VERDICT command-exit 0. Its existing pin 'labels a past due_date as "Overdue Nd" and colors it red' renders DateCellRenderer with value daysAgo(6) and field type date, name due_date. That is the issue's App wireframes case, and it gets 'Overdue 6d' with text-red-600 from the only two inputs the cell has. Gates, deviations, files_changed and head are in the keys below.",
"gates": [
{
"cmd": "bash /home/user/objectstack/scripts/pm/os-verify-lock.sh -c 'pnpm exec vitest run packages/fields/src/tests/DateCellRenderer.test.tsx --maxWorkers=2'",
"exit": 0,
"verdict": "os-verify-lock: VERDICT command-exit 0 (Tests 8 passed (8))",
"head": "cef0eee"
}
],
"deviations": [
"No PR, no changeset and no merge of origin/main. This is the fence needs_decision stop, and the merge is owed only before a final gate union, which there is none of. The branch was pushed empty at cef0eee as the write probe and the claim landing mark. The worktree /home/user/objectui-issue-11815 is left in place, clean.",
"The ruling and H3 presumed the spec declares terminal select options and object state machines with final states. Measured, it declares neither (summary). Reported here; I did not pick a route around it."
],
"files_changed": [],
"head": "cef0eee (worktree clean; branch equals origin/main)",
"mcp_calls": "0. No MCP GitHub tool was called, read or write. Reads went through gh api REST GETs: issue 11815 and its comments, and the comments of issue 11676.",
"api_writes": "1 relay write as objectstack-fleet[bot]: this os-dev-report comment via post-stamped.mjs (POST /repos//issues/11815/comments, carried by POST /repos/objectstack-ai/objectstack/dispatches). No pr_create, no label write, no assignee write. Plus one git push of the empty branch, which is not REST.",
"open_questions": [
{
"question": "Q1 - how does a date cell learn that its row is finished? Every route that reaches the grid where the defect was measured adds a published input to @object-ui/fields (Clause-②: yes).",
"options": [
"A2 - add one optional boolean prop to the exported CellRendererProps (name to be ruled). Each host computes it once per row through ONE shared logic-only helper in @object-ui/core, from the row and the object schema it already holds. DateCellRenderer and DateTimeCellRenderer then skip only the red class and the Overdue wording; the date text stays. Business: the hosts already hold the row at the cell site. Long-term: cells stay pure value renderers, the judgement has one home, and the prop is additive. AI: nothing new for an app author to write. Startup: about 13 call sites in 11 files across 8 packages for a P3, plus a projection harvest wherever the signal field is not a shown column.",
"A - add an optional record (row values) prop to CellRendererProps and let the cell judge. Business: the same reach as A2. Long-term: weaker. Judging a declared option marker also needs the object field definitions, so a second schema prop follows, and every cell can then read every field of the row. AI: neutral. Startup: the same host cost as A2, with a wider published surface.",
"C - read the existing useRecordContext() in the two cells; Clause-② stays no. Refused on measurement. Only the record page mounts it, so the issue repro (the Tasks grid) is untouched. And record:related_list renders inside it reading the PARENT record, so a finished project would hide the overdue styling of its unfinished tasks; the showcase project Tasks related list shows due_date. Long-term and AI: it gives a wrong answer that looks right.",
"D - no change in objectui until Q2 has a declared signal. This follows the objectui#11676 timeline precedent: a due-date judgement is a new card that declares its signals in the spec first. Business: completed rows keep reading as late (P3; nothing is stored wrong). Startup: zero cost."
],
"recommendation": "A2, after Q2 is ruled. Business: it is the only route that reaches the grid where the defect was measured. Long-term: one home for the judgement, and the cells stay value renderers. AI: there is no new author-facing key. Startup: the plumbing is wasted if Q2 picks no signal, so D holds until Q2 is ruled."
},
{
"question": "Q2 - what declared metadata says a record is finished? The ruling assumed the spec declares terminal options or final states. Measured on @objectstack/spec 17.7.0, it declares neither.",
"options": [
"S2 - a spec-declared terminal marker on a select option, filed as an objectstack spec card (triage put the new key out of this card). The spec already declares the idea at component level: record:path stages[].terminal (won or lost). Business: three measured producers carry a due-like date. showcase task has status done and a done boolean. app-todo task has status completed only; its is_completed boolean was removed on purpose in objectstack#7226 because nothing maintained it, and the app teaches status as the completion signal. app-crm activity has status completed only. S2 reaches 3 of 3 once authored. Long-term: contract-first, declaration over inference. AI: SelectOptionSchema is strict, so the key is checked at publish, and the runtime honours what is declared. Startup: one new spec key with a measured consumer (this card), across two repos.",
"S1 - the completion booleans the codebase already names (completed, is_completed, done, is_done in BooleanCellRenderer isCompletionField), read as value === true. Business: it reaches 1 of 3 measured producers (showcase only). In the repro grid the boolean is not in the row, so hosts must also harvest it into the projection, gated on declared fields and FLS like the objectui#7179 grouping harvest. Long-term: name inference, the shape objectui#11676 refused for the timeline: 'a guess here reads like a declaration and is wrong for every object that spells either one differently'. AI: an app that spells is_closed, or carries status only, gets nothing and no signal. Startup: no spec change.",
"S3 - read a state_machine dead end (an empty transitions list) as terminal. Refused on measurement: a dead end means not reopenable, not finished. showcase task done → in_progress and crm opportunity closed_lost → prospecting are both finished and reopenable, so the repro Done tasks would stay red."
],
"recommendation": "S2. Business: it is the only signal that reaches all three measured producers. Long-term and AI: it is declared and checked at publish. S1 does not stand alone: it reaches 1 of 3 producers, needs a projection change and is name inference. It could ride in the same helper only because the codebase already names those booleans. If the maintainer prefers no spec growth at this stage (startup axis, P3), then D under Q1 is the honest answer."
}
],
"out_of_scope_findings": []
}
objectstack-fleet commentedon Oct 8, 2026
待裁:已完成的记录,日期还显示红色「逾期」——用什么声明判定「已完成」,单元格又如何得知
domain:ui执行席 1 ·session_01DrKzdPdyLLBW3qpZ4vtk7z· 2026-10-08T03:35Z。依据 dev 实测报告6051620515(在maincef0eee上测得)。Release:
session_01DrKzdPdyLLBW3qpZ4vtk7z(席位domain:ui#1,账号huangyiirene)释放认领6051524199。原因: 认领围栏的停止条件已触发,修复属于Clause-②: yes。去向: 本卡改挂needs-user-decision,清空 assignee,退出活动队列。一句话问题
一条已经完成的任务,截止日期仍显示红色的「逾期 N 天」。修好它需要两件平台目前都不具备的东西:一个声明「这条记录已完成」的信号,以及把这个信号送到日期单元格的通道。两者都会扩大公开契约。
背景(实测)
@object-ui/fields的DateCellRenderer/DateTimeCellRenderer内部判定(resolveDueLike+isOverdueInstant)。单元格唯一的输入是导出的CellRendererProps(value、field、isEditing、onChange)。value和field。行数据到了宿主,但没有传进单元格,也没有按行提供的 React context。useRecordContext()只在记录页挂载。而且在相关列表里它指向父记录:一个已完成的项目,会把它名下未完成任务的逾期样式也藏掉。所以不能用。@objectstack/spec17.7.0 的SelectOptionSchema是 strict 的(label/value/description/color/default/visibleWhen),没有终态标记。state_machine也只有transitions,没有终态。用「没有出边」来推断也不成立:showcase 的 taskdone → in_progress、crm 的 opportunityclosed_lost → prospecting,这两个状态都算完成,又都能重开。BooleanCellRenderer的isCompletionField认的布尔名(completed/is_completed/done/is_done)。status=done,也有done布尔;status=completed,它的is_completed已在 objectstack#7226 有意删除;status=completed。done布尔并没有被查询出来($select= id + 视图列)。Governing text
6043405462:「skip the overdue affordance when the record is finished, judged from what the metadata already declares」,并且「⛔ A new spec key ("settled when") is a spec change in objectstack and is not in this card」。6011959066):时间线在没有声明信号之前,不做「逾期」判断。理由是「a guess here reads like a declaration and is wrong for every object that spells either one differently」。前提(每条附 re-check 命令;复核时逐条跑)
re-check:
git -C /home/user/objectui grep -n "export interface CellRendererProps" origin/main -- packages/fields/src,然后读该接口的成员。阳性对照词:isEditing。re-check:
git -C /home/user/objectstack grep -n "SelectOptionSchema" origin/main -- packages/spec/src | head,然后读该 schema 的键表。阳性对照词:visibleWhen。re-check:读
ObjectGrid拼$select的那一处。阳性对照词:$select。选项(一次裁清 Q1「通道」与 Q2「信号」)
CellRendererProps加一个可选布尔 prop,由@object-ui/core里唯一的 helper 按行算出(从行数据和对象 schema 算),各宿主透传。单元格只是在这个 prop 为真时不加红色和「逾期」字样,日期本身照常显示。pm:on-hold,等 spec 声明了终态信号再做。业务含义直译:
IsClosed,Jira 的状态分为 To Do / In Progress / Done 三个类别,都是这样做的。已否决的路线(实测排除):
useRecordContext:在相关列表里会拿父记录的状态去判断子记录,给出看似正确的错误答案。四棱
Prior rulings read:
overdue completed done terminal option→ 2 hits(objectui#11815、#11676);objectstackselect option terminal marker final state→ 0;ADR none;thread: #11676 ruling6011959066推荐
A。两年后,「已完成」应当是状态选项上的一个声明(参照 Salesforce picklist 的
IsClosed、Jira 的状态类别),所有显示截止日期的地方都读这一个声明。pm:on-hold,写明Restart-when:为该 spec 卡关闭。裁后执行(维护者只需裁方向)
pm:blocked,并加Blocked-by:指向那张 spec 卡。@object-ui/core的 helper 加CellRendererProps的可选 prop 加宿主透传。若规模过大,按宿主拆成子卡。Clause-②: yes认领(新增可选 prop),信号只认已有的布尔名。pm:on-hold,写明Restart-when: closed <spec 卡>,不立 spec 卡。Generated by Claude Code
16 remaining items
objectstack-fleet commentedon Oct 17, 2026
Unlock:
pm:blocked→pm:queue· objectui#12297 landed · triage seat ·session_01AavokzJ5DndAwitDXvKy4U· 2026-10-17T05:55ZTriage seat (objectstack-wide, seat post objectstack-ai/objectstack#6015). ⛔ Not a claim, ⛔ not a dispatch.
completedwhen PR fix(types): type dueLike by reference and declare settledWhen on date and datetime field metadata (objectui#12297) #12861 merged.DateFieldMetadata/DateTimeFieldMetadatanow carrydueLikeandsettledWhenby reference to@objectstack/spec.6054882132): overdue is declared-only, the host evaluatessettledWhenand passes one optional boolean prop, and the field-name regex retires.Clause-②: yes. types(date, datetime): declaredueLikeandsettledWhenby reference to@objectstack/speconce objectui installs the release carrying objectstack-ai/objectstack#22503 #12297's report names both remaining gaps as this card's job.domain:ui,area:records. Thedca7aa8branch named on objectui#12726 is a reference only.Generated by Claude Code
objectstack-fleet commentedon Oct 17, 2026
Claim: PM loop round 3 (
priority:p2bug; maintainer ruling D,6054882132; unlocked by the triage seat,6230410097, when objectui#12297 landed as PR #12861 on this seat)Session:
session_01SJn1GEkrbbBQkhGC26wEDwAccount:
os-sales(the seat's linked user asGET /useranswers it; the card's assignee)Branch:
claude/issue-11815-declared-overdueWorktree:
objectui-issue-11815(in the cloud session's own container)Domain:
domain:uiSeat:
domain:ui#4File surface:
packages/fields/src/index.tsx: one optional boolean propdeadlineSettledonCellRendererProps;resolveDueLikereads the field's declareddueLikeonly, and the field-name regexDUE_LIKE_FIELD_NAMEretires; both date cells paint no overdue wording or colour whiledeadlineSettledis true.@object-ui/core: one helper besideevalRowPredicate(packages/core/src/evaluator/) that answers "is this declared deadline settled for this row", plus its export.packages/types/src/views.tsandpackages/types/src/zod/views.zod.ts: the authored view-levelDetailViewFieldSchema.dueLikemirror, per ruling 3 of the dispatch.packages/plugin-grid/src/ObjectGrid.tsx(andcellRendererResolution.tsif the builders need it): every column builder forwardsdueLikeandsettledWhen, and each row's cell getsdeadlineSettled;packages/plugin-detail/src/DetailSection.tsx,HeaderHighlight.tsxandfieldEnrichment.ts(settledWhenjoins the enriched keys);plugin-kanban/src/ObjectKanban.tsx,plugin-list/src/ObjectGallery.tsx,plugin-list/src/ListViewCompact.tsx,plugin-tree/src/ObjectTree.tsx,plugin-report/src/ReportViewer.tsx,plugin-detail/src/RelatedList.tsx..changeset/11815-*.mdper released package touched.packages/components/src/ui/**, every server-side file and every@object-ui/i18npack stay out.Stop on breach; explain in the report.
Container & model:
L,mode:cloud,model: opus(cloud on the maintainer's stance 「可以的话,ui 后续开发尽量用云 session,并且要求截图给我看」; lane scope on 「你也可以接ui车道的卡」; batch 3 on 「当前任务处理完,后续并发降到3」, this session's chat, 2026-10-16)Clause-②: yes
Clause-② reason:
@object-ui/fields' publishedCellRendererPropsgains a member.@object-ui/coreexports a helper.@object-ui/types'DetailViewFieldSchemamay lose itsdueLikemember.The seat's
TIER_DEFAULTreview comes before ready.Responsibility:
the overdue affordance of objectui's date and datetime cells, in every host that draws them | ruling D: the field's declaration is the only source, and the host evaluates settledWhen against the row | every member who reads a list or record with a deadlineThread-read: 6230410097
Serial constraints cleared:
8106db1).fields/src/index.tsx,ObjectGrid.tsx,DetailSection.tsx,HeaderHighlight.tsx,fieldEnrichment.ts,types/src/views.ts,date-display.tsor the host files above. Nopm:dispatchedobjectui claim names them in its file surface (read at dispatch).claude/issue-12726-overdue-reads-record-state(dca7aa8, no PR) is read, not merged.objectstack-fleet commentedon Oct 17, 2026
os-dev-report
{ "issue": 11815, "status": "done", "branch": "claude/issue-11815-declared-overdue", "pr": 12874, "head": "c6a46ce", "session": "session_01LzSF1MK7r46WEAYG2ooGiq (this cloud run; dispatched by PM seat domain:ui#4, session_01SJn1GEkrbbBQkhGC26wEDw, claim 6231347884)", "premise_still_valid": true, "summary": "Ruling D is implemented. A date or datetime reads overdue only when its field declares `dueLike: true`. The field-name regex `DUE_LIKE_FIELD_NAME` is gone, and `resolveDueLike` reads the declaration and nothing else. The cells now take one optional prop, `CellRendererProps.deadlineSettled`: while it is true, both date cells show the neutral wording and no red. The prop's value comes from one new helper, `isDeadlineSettled` in `@object-ui/core` (packages/core/src/evaluator/deadlineSettled.ts), which is built on `evalRowPredicate` with `fallback: false`. Every host calls this helper: all three ObjectGrid column builders that used to drop the keys now forward `dueLike` and `settledWhen`, and so do the cells and links on every column path. The other hosts are DetailSection, HeaderHighlight, RelatedList, the kanban card, the gallery card, the compact list and the tree. The view-level `DetailViewField.dueLike` and its zod row are removed: I found no producer of that key in objectui, objectstack/examples or hotcrm. Card stays open (`Part of`): ruling 6 is unmet for one host outside the claimed file surface. ListView builds the `$select` for the console's list views. A list view that hides the field a `settledWhen` reads therefore leaves its done rows overdue. That is the same as today, and the error points toward overdue, not away from it. The showcase's All Tasks view shows `status`, so the reported case is fixed live. Assumption check against current main: PM mechanism assumptions 1–6 all held. One correction: `DetailSection`'s read-only cell received no `dependentValues` (the reference note said so); the `dependentValues={data}` line at about :627 belongs to the inline-edit input. The host now evaluates `settledWhen` against `data` itself. Housekeeping: the shared checkout /home/user/objectui sat on a local branch with this branch's name and no commits of its own. I detached it at 473e5a0 to delete that branch, and it is still detached there.", "tests": "Pinned to c6a46ce. FULL SUITES of all 8 touched packages, run once in the foreground through os-verify-lock: `pnpm exec vitest run packages/fields/ packages/core/ packages/types/ packages/plugin-grid/ packages/plugin-detail/ packages/plugin-kanban/ packages/plugin-list/ packages/plugin-tree/ --maxWorkers=2` gave 'Test Files 1610 passed | 2 skipped (1612) / Tests 25618 passed | 52 skipped (25670)', VERDICT command-exit 0. NEW PINS: core deadlineSettled-11815.test.ts (8 tests: settled when the predicate holds, string and envelope forms; not settled when it does not hold, when settledWhen or dueLike is missing, on a fault or a null row; reads the host scope; exported from @object-ui/core). fields dateCells.deadlineSettled-11815.test.tsx (10 tests: on both date and datetime, a declared past deadline reads 'Overdue 6d' in red and the same field with deadlineSettled reads '6 days ago' with no red; deadlineSettled={false} changes nothing; the compact datetime face is not red when settled; CONTROL: an undeclared due_date or due_at is neutral and a declared future deadline is unchanged). plugin-grid ObjectGrid.deadlineSettled-11815.test.tsx (8 tests through the real ObjectGrid over in-memory data, on paths A (object columns, plus a link column), B (string columns, plus the deadline as the primary link column), C (inline `fields`) and D (default columns). In each, the open row reads 'Overdue 5d' in red, the done row reads '5 days ago' with no red, and an undeclared past date reads neutral. The projection asks for `status` when only title and the deadline are shown; CONTROL: an undeclared date pulls nothing in). plugin-detail recordPage.deadlineSettled-11815.test.tsx (DetailSection and HeaderHighlight, open vs done, plus an undeclared control) and RelatedList.deadlineSettled-11815.test.tsx (each child row is judged on its own row; `$select` includes status). Kanban, gallery, compact list and tree each have one open-vs-done pin. ABLATIONS: each run mutated the file on disk (anchor count dropped, injection counted), saw red, restored with `git checkout HEAD -- PATH`, checked the restore by hash against the HEAD blob, and confirmed `git diff HEAD` was empty. Sources are aliased in vitest.config.mts, so no rebuild was needed. Red counts: helper dueLike guard 1/8; cell deadlineSettled 3/10; name guess reinstated 4/30; grid settledFor 7/8; grid path-A forwarding 2/8; grid projection 1/8; DetailSection 1/5; HeaderHighlight 1/5; settledWhen removed from the enrichment keys 2/5; view-entry strip 1/3; RelatedList cell 1/2; RelatedList projection 1/2; kanban 1/1; gallery 1/2; gallery dueLike forward 1/2; compact 1/2; tree 1/1; zod row re-added 1/7. The first types-zod attempt was a no-op caught by my own guard (the replacement still contained the anchor). I discarded it and redid it with a disjoint replacement. Types reverse check: re-adding `dueLike?: boolean` to DetailViewField made `tsc -p tsconfig.test.json` exit 2 with TS2578 (unused @ts-expect-error) and TS2344 on the new pins; restored, diff empty. INVERTED PINS: DateCellRenderer.test.tsx 'labels a past due_date as Overdue Nd' is now 'CONTROL — an undeclared past due_date reads neutral' plus a declared twin. datetimeCell.dueLikeAffordance-8958 'the field-name heuristic answers the same on both cells' is now its CONTROL. DetailSection.dueLikeReachesTheCell-9729 now pins the field-level key and the view-entry key's absence. mirror-only-published-keys-9729 now pins the key's absence on both faces. Two pins used an undeclared due_date only as a way to get the overdue wording, and now declare `dueLike: true` with their subject unchanged: date-locale-channel 'resolves through the translate fn' (zh, en) and dateCell.unparsableValue-8581 'POPULATED — a past due_date is still Overdue Nd'. LIVE (e2e/live/ci/start-backend.sh, showcase at @objectstack/cli 18.0.0-next.2 = e5136ff1, which already declares task due_date with dueLike and settledWhen record.status == 'done'; port 4311; consoles on :5311 from a detached worktree at 473e5a0 and on :5312 from the branch; zh-CN, light). In a throwaway copy I added an undeclared `renewal_on` date (its name matches the old regex) and showed it in All Tasks; never pushed. I made 'Design system' (status in_review) due 2026-10-13. Today is 2026-10-17. On main: Audit current IA (done) '9月29日' red, App wireframes (done) '逾期 6 天' red, Design system (open) '逾期 4 天' red, renewal_on '逾期 5 天' red. On the branch: Audit current IA '9月29日' neutral, App wireframes '6天前' neutral, Design system '逾期 4 天' red, renewal_on '5天前' neutral. Record page of App wireframes, highlights strip 截止日期: '逾期 6 天' red on main, '6天前' neutral on the branch.", "gates": [ { "cmd": "bash os-verify-lock.sh -c 'pnpm exec vitest run packages/{fields,core,types,plugin-grid,plugin-detail,plugin-kanban,plugin-list,plugin-tree}/ --maxWorkers=2'", "exit": 0, "verdict": "VERDICT command-exit 0; 1610 files / 25618 tests passed", "head": "c6a46ce" }, { "cmd": "pnpm --workspace-concurrency=2 --filter (the 8 packages) build", "exit": 0, "note": "BUILD_EXIT=0 captured before any pipe; 8/8 'build: Done'", "head": "c6a46ce" }, { "cmd": "pnpm --workspace-concurrency=2 --filter (the 8 packages) type-check", "exit": 0, "note": "TC_EXIT=0; 8/8 type-check scripts echoed; 0 'error TS'. Run inside one lock call whose batch-last-exit covers only the last part, so each part's exit was captured separately", "head": "c6a46ce" }, { "cmd": "pnpm exec eslint --no-inline-config (the 38 touched .ts/.tsx files)", "exit": 1, "note": "4 errors / 330 problems on the four large host files, identical on main 473e5a0 (react-hooks 'Cannot create components during render' in RelatedList and ObjectGrid, at the same sites shifted by my insertions). The diff adds 0 errors and 0 warnings. Whole-repo lint belongs to CI" }, { "cmd": "pnpm check:i18n-keys", "exit": 0 }, { "cmd": "pnpm check:i18n-drift", "exit": 0 }, { "cmd": "pnpm check:new-line-citations", "exit": 0, "verdict": "VERDICT new-cross-file-line-citations: 0 new citation(s)" }, { "cmd": "node scripts/check-changeset-presence.mjs", "exit": 0, "verdict": "28 source file(s) of 8 released package(s) changed, and this change declares 8 changeset(s)" }, { "cmd": "node scripts/check-changeset-no-major.mjs", "exit": 0 }, { "cmd": "control-byte self-scan grep -naP over the 45 diffed files", "exit": 0, "note": "0 hits. scripts/check-nul-bytes.mjs exists only in objectstack (MODULE_NOT_FOUND here), so it is not a gate reading" }, { "cmd": "dispatch-gates.mjs --commands / --ran", "exit": null, "note": "NOT MEASURED: objectui has no scripts/pm/dispatch-gates.mjs; gates derived by hand from the order and package.json. check-platform-checklist.mjs is also absent here; no exported symbol was renamed or deleted (one export added: isDeadlineSettled)" }, { "cmd": "CI check-runs", "exit": null, "note": "in_progress / NOT MEASURED: no PR yet; the PM opens it" } ], "deviations": [ "The os-dev contract file says the dev opens the draft PR and posts the os-dev-report comment first. This order's degraded channel says not to: the fleet-write relay is refused with 403 in this container, and any MCP write tool voids the report. I followed the channel the container allows: no PR, no comment, no label write. The PR body and the report are below for the PM to post.", "Lock path: AGENTS.md names /home/user/objectstack/scripts/pm/os-verify-lock.sh. The read-only clone lives at /home/user/objectstack-ai/objectstack, so I used the same script from there with OS_VERIFY_LOCK_SLOT=dev-11815.", "plugin-report/src/ReportViewer.tsx is in the claimed surface but unchanged. It draws cells from a `ReportField` (a report column), which carries no `dueLike` and has no object field definition in scope. After the regex retires it paints no overdue at all, so it has nothing to settle.", "Two hosts outside the claimed surface were measured and not edited (stop on breach). (1) plugin-list/src/ListView.tsx builds the `$select` that feeds the console's list-view grid. Its harvest (columns, view bindings, grouping, rowColor, predicate operands through addSpeculative) has no arm for a shown deadline's settledWhen. See open_questions Q1. (2) apps/console/src/pages/system/ApprovalsInboxPage.tsx `RecordFieldFace` and app-shell/src/views/approval-decision/RecordSnapshotSummary.tsx `FieldFace` draw a declared deadline from the full field definition beside a snapshot of the record, with no deadlineSettled. See Q2.", "Live evidence used a throwaway copy of the pinned showcase: an added undeclared `renewal_on` date, that field shown in All Tasks and in the record's schedule section, and the app's stale dist removed so dev rebuilt it. Data was changed through the REST API. Nothing was pushed, and the scratch backend is deleted.", "The local merge of origin/main (app-shell only, no conflict) was amended before its first push to add the model-free trailer pair. No pushed history was rewritten." ], "files_changed": [ "packages/core/src/evaluator/deadlineSettled.ts (new)", "packages/core/src/evaluator/index.ts", "packages/core/src/evaluator/__tests__/deadlineSettled-11815.test.ts (new)", "packages/fields/src/index.tsx", "packages/fields/src/__tests__/dateCells.deadlineSettled-11815.test.tsx (new)", "packages/fields/src/__tests__/DateCellRenderer.test.tsx", "packages/fields/src/__tests__/datetimeCell.dueLikeAffordance-8958.test.tsx", "packages/fields/src/__tests__/date-locale-channel.test.tsx", "packages/fields/src/__tests__/dateCell.unparsableValue-8581.test.tsx", "packages/types/src/views.ts", "packages/types/src/zod/views.zod.ts", "packages/types/src/__tests__/mirror-only-published-keys-9729.test.ts", "packages/plugin-grid/src/ObjectGrid.tsx", "packages/plugin-grid/src/__tests__/ObjectGrid.deadlineSettled-11815.test.tsx (new)", "packages/plugin-detail/src/DetailSection.tsx", "packages/plugin-detail/src/HeaderHighlight.tsx", "packages/plugin-detail/src/RelatedList.tsx", "packages/plugin-detail/src/fieldEnrichment.ts", "packages/plugin-detail/src/__tests__/recordPage.deadlineSettled-11815.test.tsx (new)", "packages/plugin-detail/src/__tests__/RelatedList.deadlineSettled-11815.test.tsx (new)", "packages/plugin-detail/src/__tests__/DetailSection.dueLikeReachesTheCell-9729.test.tsx", "packages/plugin-kanban/src/ObjectKanban.tsx", "packages/plugin-kanban/src/__tests__/ObjectKanban.deadlineSettled-11815.test.tsx (new)", "packages/plugin-list/src/ObjectGallery.tsx", "packages/plugin-list/src/ListViewCompact.tsx", "packages/plugin-list/src/__tests__/deadlineSettled-11815.test.tsx (new)", "packages/plugin-tree/src/ObjectTree.tsx", "packages/plugin-tree/src/ObjectTree.deadlineSettled-11815.test.tsx (new)", "content/docs/api/schema-reference.md", "content/docs/fields/date.mdx", "content/docs/fields/datetime.mdx", ".changeset/11815-{fields-declared-overdue,core-deadline-settled,types-view-due-like-retired,grid-settled-deadline,detail-settled-deadline,kanban-settled-deadline,list-settled-deadline,tree-settled-deadline}.md (8, all minor)" ], "screenshots": [ "https://github.com/objectstack-ai/objectui/blob/2c26117564d3d9840d8391d167979e7c5f3952bf/docs/design/findings/11815/list-before-main.png?raw=true", "https://github.com/objectstack-ai/objectui/blob/2c26117564d3d9840d8391d167979e7c5f3952bf/docs/design/findings/11815/list-after-branch.png?raw=true", "https://github.com/objectstack-ai/objectui/blob/2c26117564d3d9840d8391d167979e7c5f3952bf/docs/design/findings/11815/record-done-after-branch.png?raw=true", "https://github.com/objectstack-ai/objectui/blob/2c26117564d3d9840d8391d167979e7c5f3952bf/docs/design/findings/11815/record-done-before-main.png?raw=true" ], "line_budget": "n/a", "mcp_calls": "2 — mcp__github__issue_read (get) and mcp__github__issue_read (get_comments) on objectui#11815; no write tool. Also two non-GitHub calls, mcp__claude-code-remote__add_repo (objectstack and hotcrm, read): both answered read_available and attached nothing.", "api_writes": "0 REST writes. git pushes only: claude/issue-11815-declared-overdue (empty-branch probe, then commits up to c6a46ce) and claude/issue-11815-evidence (2c26117, screenshots only, never merged into the feature branch). REST PATCHes went only to the local throwaway backend on localhost:4311.", "open_questions": [ { "question": "Q1 (ruling 6, needs_decision for the ListView host): in the console, a list view's grid rows come from ListView's own `$select`, which has no arm for a shown deadline's settledWhen operands. A list view that shows due_date but hides status leaves done rows overdue, the same as today. The fix is a one-place list edit in plugin-list/src/ListView.tsx, outside the claim's file surface.", "options": [ "A: a follow-up claim adds one loop beside the `addSpeculative(rowColorConfig?.field)` arm. For each shown column whose object field declares dueLike: true with a settledWhen, it would `addSpeculative` each field from `collectPredicateFieldRefs`. It goes through the same declared-field and FLS gate, with one pin. Business: the showcase's All Tasks shows status, but app-todo and app-crm views are unmeasured. Long-term: same shape as the grid's and RelatedList's harvests in this PR. AI: no new author-facing key. Startup: about 10 lines and one test.", "B: leave it. The docs in this PR already say to show the field the predicate reads as a column (date.mdx). Zero cost, but the docs then carry a caveat the code could remove." ], "recommendation": "A, because the same one-list edit already landed in the grid and the related list, and the gap fails toward a false overdue that an author cannot see. Carry it on this card (Part of) rather than a new one." }, { "question": "Q2: the approval surfaces (console ApprovalsInboxPage RecordFieldFace, app-shell RecordSnapshotSummary FieldFace) draw a declared deadline from the full field definition beside the record snapshot, with no deadlineSettled. A settled snapshot's past deadline still reads overdue there. Both are outside the claim's surface.", "options": [ "A: one call-site line each: `isDeadlineSettled(def, snapshot, ...)`. Pass it in, and add a pin.", "B: leave it. A snapshot is the record as submitted, and overdue there may be intended." ], "recommendation": "A, on the same card as Q1. It is the same mechanical line every other host got. But first get the product's word on B, because a snapshot's state is frozen." }, { "question": "Q3 (recorded choice, not blocking): the dashboard (`buildFieldMeta`) and the report viewer (`ReportField`) forward no dueLike. With the regex gone, a declared deadline never reads overdue there; before, only a matching name did.", "options": [ "A: leave it until a measured pull appears.", "B: forward dueLike and settledWhen and call the helper." ], "recommendation": "A, on the startup axis (no measured producer or reader of overdue on those surfaces). Contract-first is unaffected: nothing there claims to honour the key." }, { "question": "Recorded decisions (taken by ruling, no action needed): (1) View-level `DetailViewField.dueLike` is retired. Producer search: 0 hits in objectui apps/, examples/, packages/ (non-test) and content/docs; in objectstack examples/ only field-level `*.object.ts` (app-showcase task, app-todo task, app-crm activity); 0 in hotcrm. (2) Semver is minor for every package, on the precedent of f61dab1 (objectui#11070 round 4, `DetailViewField.reference_to` retired), which shipped under '### Minor Changes' in @object-ui/types 17.7.0; a major is also refused by the repo's no-major gate. (3) `enrichDetailField` deletes dueLike and settledWhen from the view entry, so the field's declaration is the one source even for untyped data.", "options": [ "as implemented" ], "recommendation": "as implemented" } ], "out_of_scope_findings": [ "class: none filed · reach: — · Q1–Q3 above are the measured remainder of this card's own scope, reported for the seat rather than filed. carrier: objectui#11815 (Part of). dedupe words: settledWhen projection list view · approval snapshot overdue · dashboard dueLike" ], "pr_title_draft": "fix(fields,core,grid,detail): overdue is declared-only, and a settled deadline paints nothing (objectui#11815)", "pr_body_draft": "(elided here: it is the body of objectstack-ai/objectui#12874, the dev's draft verbatim)" }Relayed by seat
domain:ui#4(session_01SJn1GEkrbbBQkhGC26wEDw) from the cloud session's final report (degraded channel: the session pushed and returnedpr: null). The seat opened #12874 fromclaude/issue-11815-declared-overdueatc6a46ceand setprabove; the title is the dev's draft, which already names the card. The body readsPart of #11815: ListView's own projection and the approval snapshot faces are outside the claimed surface. The seat's rulings on the three open questions are in the ACCEPT on the PR, followed by the seat'sTIER_DEFAULTcontract review (Clause-②: yes).Generated by Claude Code
objectstack-fleet commentedon Oct 17, 2026
Landed (partial) · PR #12874 merged as
f34e877onmain· read 2026-10-17T10:27Zorigin/mainf34e877DUE_LIKE_FIELD_NAMEinpackages/fields/src/index.tsxCellRendererProps.deadlineSettled?: booleanresolveDueLike(field, deadlineSettled)(:1101) readsdueLike === trueonlyisDeadlineSettledinpackages/core/src/evaluator/deadlineSettled.tsevalRowPredicatewithfallback: falseDetailViewField.dueLikeinpackages/types/src/views.ts.changeset/11815-*.mdclaude/issue-11815-evidenceState change: the PR read
Part of #11815, so this card stays open withpm:dispatched. This seat re-claims the remainder in the next comment, per ACCEPT rulings 1–2. The cloud sessionsession_01LzSF1MK7r46WEAYG2ooGiqis archived.Records of this card:
6232356784;6232369404;TIER_DEFAULTcontract review:6232373249(PASS);cf8beb1):6232451477;6232696839.Unblocked: objectui#12726 (closed as this card's duplicate) needs nothing more. The two remainder items are below.
Generated by Claude Code
objectstack-fleet commentedon Oct 17, 2026
Claim: PM loop round 3 (
priority:p2bug; the remainder of maintainer ruling D,6054882132, after PR #12874 landed in part asf34e877; the seat's ACCEPT rulings 1–2,6232369404)Session:
session_01SJn1GEkrbbBQkhGC26wEDwAccount:
os-sales(the seat's linked user asGET /useranswers it; the card's assignee)Branch:
claude/issue-11815-settled-remainderWorktree:
objectui-issue-11815b(in the cloud session's own container)Domain:
domain:uiSeat:
domain:ui#4File surface:
packages/plugin-list/src/ListView.tsx: the console list view's$selectharvest asks for a shown deadline'ssettledWhenoperands, beside theaddSpeculative(rowColorConfig?.field)arm, through the same declared-field and FLS gate;apps/console/src/pages/system/ApprovalsInboxPage.tsxRecordFieldFaceandpackages/app-shell/src/views/approval-decision/RecordSnapshotSummary.tsxFieldFace: each passesdeadlineSettledfromisDeadlineSettled(def, snapshot, …), judged against the same snapshot it draws;content/docs/fields/date.mdx: the "show that field as a column" caveat, only for the lines this removes;.changeset/11815-*.mdper released package touched.packages/components/src/ui/**stays out.Stop on breach; explain in the report.
Container & model:
S,mode:cloud,model: opus(cloud on the maintainer's stance 「可以的话,ui 后续开发尽量用云 session,并且要求截图给我看」; lane scope on 「你也可以接ui车道的卡」; batch 3 on 「当前任务处理完,后续并发降到3」, this session's chat, 2026-10-16)Clause-②: no
Clause-② reason: one projection list and two call sites read the published
isDeadlineSettledanddeadlineSettledthat #12874 added. No exported type, prop or@object-ui/i18nkey moves.Responsibility:
the two hosts objectstack-ai/objectui#12874 measured and left outside its surface | ruling D: a settled deadline paints nothing, in every host that draws one | every member reading a console list view that hides the predicate's field, or an approval that carries a deadlineThread-read: 6232815173
Serial constraints cleared:
f34e877, and this branch is cut after it.ListView.tsx,ApprovalsInboxPage.tsx,RecordSnapshotSummary.tsxorcontent/docs/fields/date.mdx, and nopm:dispatchedobjectui claim names them (read at dispatch).next.3bump) touches the lockfile and only the files its reds force. Whichever lands second mergesmain.objectstack-fleet commentedon Oct 17, 2026
os-dev-report
{ "issue": 11815, "status": "done", "branch": "claude/issue-11815-settled-remainder", "pr": 12879, "head": "6ae5c25", "session": "session_01DiTjG1AEXG49VTNoVQ5cpt (this cloud run; dispatched by PM seat domain:ui#4, session_01SJn1GEkrbbBQkhGC26wEDw, claim 6232823490)", "premise_still_valid": true, "summary": "Implemented ACCEPT rulings 1-2 and the docs caveat. (1) ListView's $select harvest gains one loop right after addSpeculative(rowColorConfig?.field). For each shown column that survived the FLS gate (cols) whose object field declares dueLike: true with a settledWhen, it runs addSpeculative on every operand collectPredicateFieldRefs finds. That is the same declared-field and FLS gate every binding there uses. (2) ApprovalsInboxPage RecordFieldFace and RecordSnapshotSummary FieldFace each pass deadlineSettled = isDeadlineSettled(def, snapshot, { scope: usePredicateScope(), fields }). (3) The date.mdx caveat now says what the code does. Claim check before the first edit: the newest Claim: comment, 6232823490, names this branch. Card assignee was not touched. All three PM mechanism assumptions measured true on f34e877. One live premise was falsified on the showcase, with a workaround: see deviations.", "snapshot_held_by_each_face": "ApprovalsInboxPage: the snapshot is the request row's raw `payload` (selected.payload). payloadSummary draws each value from it, and the lead amount reads selected.payload too. Both call sites pass that same object as `snapshot`, with fields = the indexed metadata defs (indexFieldDefs keeps the whole def, so dueLike and settledWhen survive). RecordSnapshotSummary: the snapshot is `shown` = withoutDeniedFields(row.payload, perms, target), the FLS-redacted record values FieldFace draws `value` from. A status the reader may not read is therefore absent: the predicate faults and the deadline stays unsettled. This is the same fail-toward-overdue direction ruling 1 accepts.", "tests": "Pinned to 6ae5c25. New pins: packages/plugin-list/src/__tests__/ListView.deadlineSettledSelect-11815.test.tsx (4), RecordSnapshotSummary.test.tsx +2, apps/console/src/pages/system/ApprovalsInboxPage.deadlineSettled-11815.test.tsx (3). ListView's 4 pins: (a) a view with columns title + deliver_by sends $select [deliver_by,id,status,title]; (b) against a backend that honours $select, the open row reads 'Overdue 5d' in red and the done row reads '5 days ago' neutral; (c) CONTROL: an undeclared date that carries a settledWhen pulls nothing in; (d) CONTROL: an operand the viewer may not read (secret_flag) is not requested. plugin-grid is not a plugin-list dependency (it would be a cycle), so the grid slot is stubbed as ListView.viewSwitchRefetch-7394 does. The stub draws each handed row through the real date cell and the real isDeadlineSettled. Approval faces: a done snapshot draws the past deadline '5 days ago' with no red; an open snapshot draws 'Overdue 5d' in red. The console file adds a CONTROL: an undeclared past date is never overdue. Ablation: each mutation was applied by anchored replace (count == 1 asserted), with trap restore via git checkout HEAD -- on an absolute path. Tests import source by relative path, so no dist is involved. Results: ListView arm 'addSpeculative(f)' -> 'void f': pins (a),(b) red, 2 failed / 2 passed. dueLike filter removed: CONTROL (c) red. Arm routed to required.add (FLS bypass): CONTROL (d) red. FieldFace 'deadlineSettled={deadlineSettled}' removed: the settled pin red, 1 failed / 18 passed. RecordFieldFace the same: the settled pin red, 1 failed / 2 passed. Every restore: git diff HEAD empty, blob hash = HEAD blob. Note: the first ablation's grep -cF line count was meaningless on a multi-line anchor; the python count==1 assert and the red run prove it landed. Full runs, foreground, under os-verify-lock: `pnpm exec vitest run --maxWorkers=2 packages/plugin-list/` 149 files / 1518 tests passed. `pnpm exec vitest run --maxWorkers=2 packages/app-shell/src/views/approval-decision/ apps/console/src/pages/system/ApprovalsInboxPage` 22 files / 138 passed. `pnpm exec vitest run --maxWorkers=2 scripts/__tests__/` 186 passed, 2 skipped files / 5620 passed, 2 skipped tests.", "gates": "Each exit captured before any pipe. Builds: `pnpm --filter plugin-list^... --filter app-shell^... --filter console^... build` VERDICT command-exit 0. `pnpm --filter @object-ui/plugin-list --filter @object-ui/app-shell --filter @object-ui/console build` exit 2 on the first run: console's build type-checks tests, and my test stub's inferred mock types were too narrow (TS2322 x2). Fixed in 6ae5c25; console build re-run VERDICT 0; plugin-list and app-shell builds passed in that same run. type-check (hyphenated, script name echoed): plugin-list 0, app-shell 0, console 0, all re-run after the tests existed. Lint: `eslint --no-inline-config` on the 3 host files is exit 1 on branch and on f34e877 alike. The per-rule diff (ruleId x severity, branch minus base and base minus branch) is empty for ListView.tsx, RecordSnapshotSummary.tsx and ApprovalsInboxPage.tsx. The 2 errors are the existing react-hooks/static-components line, whose eslint-disable --no-inline-config ignores. The 2 new test files: exit 0, 0 errors. check:i18n-keys 0. check:i18n-drift 0. check-changeset-presence 0 (3 released packages, 3 changesets). check-changeset-no-major 0. check:new-line-citations 0 (0 new). scripts/check-nul-bytes.mjs: MODULE_NOT_FOUND, because it exists only in objectstack, so this is not a gate reading. Self-scan of the diff with grep -naP for control bytes found none. CI check-runs: NOT MEASURED, no PR yet (the PM opens it). dispatch-gates.mjs is objectstack-only; objectui families were hand-derived per the dispatch.", "live": "Backend: e2e/live/ci/start-backend.sh (showcase at @objectstack/cli 18.0.0-next.2, e5136ff) on :4031, scratch dir in this session's scratchpad. Consoles: main f34e877 on :5291 (a detached worktree, since removed) and this branch on :5292. zh-CN, light, UTC. First reading: on the stock showcase, main already reads done rows neutral in a title + due_date view. The data request was select=id,title,due_date,status,priority,done on BOTH consoles: showcase_task's own row-action predicates already pull status into $select through the existing listViewPredicates harvest. So the stock showcase cannot tell main from the branch. Discriminating reading: in the scratch fixture only (never the repo), I added a 'Deadlines' list view (columns title, due_date) and pointed due_date's settledWhen at record.progress == 100 (done rows carry progress 100, and nothing else projects progress), then ran objectstack build and restarted. Result: main sends select=id,title,due_date,status,priority,done, and App wireframes reads '逾期 6 天' red, Audit current IA '9月29日' red. The branch sends select=id,title,due_date,status,priority,progress,done, and they read '6天前' and '9月29日' neutral. No open past-due row exists on today's seed (the open rows' dates are in the future), so no live overdue CONTROL row. Approval faces live: not measured. Only showcase_task declares dueLike, and no showcase approval process targets it (dynamic-approval targets showcase_announcement, approver-bindings showcase_field_zoo). The faces are covered by the unit pins above. Everything started was stopped by recorded PID; ports 4031/5291/5292 are free.", "screenshots": [ "https://github.com/objectstack-ai/objectui/blob/be335f3485f9f2080db03930000ab92d849d86ad/docs/design/findings/11815b/list-view-deadlines-main-f34e877.png?raw=true", "https://github.com/objectstack-ai/objectui/blob/be335f3485f9f2080db03930000ab92d849d86ad/docs/design/findings/11815b/list-view-deadlines-branch.png?raw=true" ], "files_changed": [ "packages/plugin-list/src/ListView.tsx", "packages/plugin-list/src/__tests__/ListView.deadlineSettledSelect-11815.test.tsx", "packages/app-shell/src/views/approval-decision/RecordSnapshotSummary.tsx", "packages/app-shell/src/views/approval-decision/RecordSnapshotSummary.test.tsx", "apps/console/src/pages/system/ApprovalsInboxPage.tsx", "apps/console/src/pages/system/ApprovalsInboxPage.deadlineSettled-11815.test.tsx", "content/docs/fields/date.mdx", ".changeset/11815-list-settled-select.md", ".changeset/11815-app-shell-approval-settled.md", ".changeset/11815-console-approval-settled.md" ], "deviations": [ "Live recipe: the stock showcase could not separate main from the branch, because showcase_task's row-action predicates already project status, so the dispatch's expected 'done rows read overdue on main' did not reproduce. I edited the scratch backend fixture only (an added Deadlines view, and settledWhen pointed at progress), never the repo, so the reading exercises the new arm. Both readings, stock and modified, are reported.", "Changesets are patch, not minor: this is a fix with no exported type, prop or i18n key moving, which matches the claim's Clause-② reason. One per released package touched (plugin-list, app-shell, console), user-facing prose only.", "ListView's arm reads `cols` (the authored columns after the FLS filter), not the raw columns: a deadline the viewer cannot read is not drawn, so nothing judges it. Field defs are looked up map-style (objectDef.fields[name]), as ObjectGallery and ListViewCompact do; an array-shaped fields container yields no harvest and fails toward overdue.", "Docs: only the caveat paragraph changed (4 lines to 5). It now also states that the approval summary judges against its snapshot.", "The feature worktree /home/user/objectui-issue-11815b is kept (clean, pushed) because the PR is not opened yet. The comparison and evidence worktrees were removed." ], "line_budget": "n/a", "mcp_calls": "2 GitHub MCP calls, both reads: mcp__github__issue_read (get_comments, #11815) and mcp__github__pull_request_read (get_comments, #12874). Plus 2 claude-code-remote add_repo calls (access: read; both answered read_available, nothing attached). No write tool.", "api_writes": "0 REST writes. git push only: claude/issue-11815-settled-remainder (empty branch first, then 3 commits) and claude/issue-11815b-evidence (1 commit, PNGs only, never merged into the feature branch).", "open_questions": [ { "question": "Where os-dev.md and the dispatch conflict: os-dev.md tells the dev to open the draft PR and post the os-dev-report comment on the card, while the dispatch forbids both (degraded channel: the fleet-write relay is refused with 403, and any MCP write tool voids the report). The file says it wins on conflict. Which applies?", "options": [ "A followed the dispatch: no PR and no card comment from this session; the PM opens the PR from pr_body_draft and relays this report", "B attempt the writes through MCP" ], "recommendation": "A, already taken. The relay is unavailable from this container, and B would void the report. Recorded here as the conflict os-dev.md asks dev reports to name." }, { "question": "The showcase's stock metadata cannot show this gap live, because row-action predicates already project status. Should the showcase gain a view that shows a deadline without its predicate field, so the live lane can pin it?", "options": [ "A no: the unit pin covers the mechanism, and adding showcase metadata is objectstack scope with no measured pull", "B file an objectstack card for such a view" ], "recommendation": "A, on the startup-focus axis: there is no named consumer, and the gap fails toward a visible false overdue, not a hidden one." } ], "out_of_scope_findings": [], "pr_title_draft": "fix(plugin-list,app-shell,console): settle a declared deadline in the list view's projection and the approval snapshots (objectui#11815)", "pr_body_draft": "(elided here: it is the body of objectstack-ai/objectui#12879, the dev's draft verbatim)" }Relayed by seat
domain:ui#4(session_01SJn1GEkrbbBQkhGC26wEDw) from the cloud session's final report. This is the degraded channel: the session pushed and returnedpr: null. The seat opened #12879 fromclaude/issue-11815-settled-remainderat6ae5c25and setprabove. The title is the dev's draft and already names the card.One change is back with the dev before the ACCEPT. In
RecordSnapshotSummary.tsxthe newconst deadlineSettledline sits betweeneslint-disable-next-line react-hooks/static-componentsandreturn <Cell …>. On a normal lint run that leaves an unused directive and an uncoveredstatic-componentshit (the repo setsreportUnusedDisableDirectives: 'error'). The report's lint diff ran with--no-inline-configon both sides, which cannot see it. The ACCEPT follows on the head that carries the fix.Generated by Claude Code
objectstack-fleet commentedon Oct 17, 2026
Landed · PR #12879 merged as
bf376c5onmain· read 2026-10-17T11:58Zorigin/mainbf376c5$selectarm for a shown declared deadline'ssettledWhenoperandsdeadlineDefs, :3087), throughaddSpeculativeisDeadlineSettledinRecordSnapshotSummary.tsxFieldFacestatic-componentsdirective sits on the<Cell>line (:102)isDeadlineSettledinApprovalsInboxPage.tsxRecordFieldFacepayloadcontent/docs/fields/date.mdxcaveatListView.deadlineSettledSelect-11815,ApprovalsInboxPage.deadlineSettled-11815,RecordSnapshotSummary.test+2patch:plugin-list,app-shell,consoleclaude/issue-11815b-evidenceState change: the card closed as completed through
Fixes #11815. With PR #12874 (f34e877), ruling D is fully implemented. This act removespm:dispatched. The cloud sessionsession_01DiTjG1AEXG49VTNoVQ5cptis archived.Records of the remainder:
6232823490;6233346343;6233414486;6233495450.Generated by Claude Code