Repository navigation
fix(fields,core,grid,detail): overdue is declared-only, and a settled deadline paints nothing (objectui#11815) - #12874
Conversation
…ints nothing (objectui#11815)
- `@object-ui/core` gains `isDeadlineSettled(field, row, { scope, fields })`,
built on `evalRowPredicate`: settled only when the field declares
`dueLike: true` and a `settledWhen` that holds for the row; a faulting
predicate is not settled.
- `CellRendererProps` gains the optional `deadlineSettled` prop. While it is
true, the date and datetime cells paint no overdue wording and no red.
- The field-name regex behind `resolveDueLike` retires: only a declared
`dueLike: true` makes a date a deadline. Pins that asserted the name guess
are inverted to controls; two pins that used an undeclared `due_date` as a
vehicle for the overdue wording now declare it.
Claude-Session: https://claude.ai/code/session_01LzSF1MK7r46WEAYG2ooGiq
Co-authored-by: Claude <noreply@anthropic.com>
The deadline is the object field's declaration (`DateFieldMetadata.dueLike` and `settledWhen`, by reference to `@objectstack/spec`). `DetailViewField` and `DetailViewFieldSchema` drop their `dueLike` member, with no alias; the pins that asserted the key now assert its absence on both faces. Claude-Session: https://claude.ai/code/session_01LzSF1MK7r46WEAYG2ooGiq Co-authored-by: Claude <noreply@anthropic.com>
…ledWhen (objectui#11815) `DetailSection`'s read-only cell, `HeaderHighlight` and `RelatedList` hand each date cell `deadlineSettled` from `isDeadlineSettled`, judged against the record (or, in a related list, each child row). Enrichment forwards the field's `settledWhen` beside its `dueLike`, and never takes either from the view entry. `RelatedList` asks for a drawn deadline's `settledWhen` operands through its existing projection gates. Claude-Session: https://claude.ai/code/session_01LzSF1MK7r46WEAYG2ooGiq Co-authored-by: Claude <noreply@anthropic.com>
… row (objectui#11815) The object-column, name-column and inline-row builders forward the field's `dueLike` and `settledWhen` (only the object-field-list builder used to carry the field whole), and every cell, links included, gets `deadlineSettled` from `isDeadlineSettled` for its row. The grid's own projection asks for a shown declared deadline's `settledWhen` operands through the existing gates. Claude-Session: https://claude.ai/code/session_01LzSF1MK7r46WEAYG2ooGiq Co-authored-by: Claude <noreply@anthropic.com>
…clared deadline (objectui#11815) The kanban card, the gallery card, the compact list and the tree hand each date cell `deadlineSettled` from `isDeadlineSettled` for the record they draw. The gallery's field enrichment now carries the field's `dueLike`. Claude-Session: https://claude.ai/code/session_01LzSF1MK7r46WEAYG2ooGiq Co-authored-by: Claude <noreply@anthropic.com>
… (objectui#11815) The date / datetime pages and the schema reference drop the retired field-name convention and the authored view-level `dueLike`, and say how `settledWhen` reaches each view. One changeset per released package touched. Claude-Session: https://claude.ai/code/session_01LzSF1MK7r46WEAYG2ooGiq Co-authored-by: Claude <noreply@anthropic.com>
…clared-overdue Claude-Session: https://claude.ai/code/session_01LzSF1MK7r46WEAYG2ooGiq Co-authored-by: Claude <noreply@anthropic.com>
席位核对 — ACCEPT · objectui#11815 · head
|
| row | main 473e5a0 |
this branch |
|---|---|---|
| Audit current IA (done) | 9月29日, red | 9月29日, neutral |
| App wireframes (done) | 逾期 6 天, red | 6天前, neutral |
| Design system (in review) | 逾期 4 天, red | 逾期 4 天, red (CONTROL) |
renewal_on (undeclared, matched the old regex) |
逾期 5 天, red | 5天前, neutral |
Screenshots, read by the seat (zh-CN, light; never-merged claude/issue-11815-evidence at 2c26117, PNGs only):
- the All Tasks grid, before and after, matching the table above row by row;
- App wireframes' record page, whose highlights strip reads 截止日期 6天前, neutral, beside the 已完成 stage.
Sent to the maintainer at 2026-10-17T09:36Z.
Tests:
- New pins: the helper (8), both cells (10),
ObjectGridon every column path (8), the record page,RelatedList, and the kanban, gallery, compact and tree hosts. - Inverted to CONTROLs, each named in the PR:
DateCellRenderer's undeclareddue_date, the finding(fields):dueLikeis declared for "date/datetime" fields butDateTimeCellRenderernever reads it — the overdue affordance is silently dropped on adatetimecolumn #8958 name-heuristic case, the finding(types): two published zod mirrors validate a key their TypeScript twin never declares (dueLike,operators) — and the third the ledger groups with them is a tombstone that REFUSES, not a mirror that admits #9729 view-entry case and the published-face mirror. - Two pins that used the name only to reach the wording now declare
dueLike: true. - Each new pin was ablated once and turned red. The view-level key's type pin was reverse-checked: re-declaring it gives TS2578 / TS2344.
- Full suites of the eight touched packages: 25618 tests passed.
buildandtype-checkpass for all eight. check:i18n-keys,check:i18n-drift,check:new-line-citations, changeset presence and no-major all exit 0.- Lint adds nothing: the 4 errors on the touched host files are identical on
main.
Changesets: eight, one per released package, all minor; user-facing prose.
CI: running at this record. Landing waits for green and for the contract review below.
Rulings
- Q1, ListView's own projection: A, on this card after this PR lands. It is the same one-list edit the grid and
RelatedListreceived here: anaddSpeculativeloop over a shown deadline'ssettledWhenoperands, plus one pin. The gap fails toward a false overdue that an author cannot see. The seat re-claims the remainder on this card, a small follow-up inplugin-list/src/ListView.tsx. Docs that tell authors to show the predicate's field as a column are revisited in that follow-up. - Q2, the approval snapshot faces: A, in the same follow-up. The face draws the snapshot's date, and the snapshot carries the status as submitted. Judging
settledWhenagainst that same snapshot is the consistent reading, since the date and the status are frozen together. One call-site line each, inApprovalsInboxPage'sRecordFieldFaceandRecordSnapshotSummary'sFieldFace, with a pin. - Q3, the dashboard and the report viewer: A, left alone. Neither forwards
dueLike, so neither claims to honour it, and nothing measured pulls for overdue there. - The recorded decisions are accepted:
- the view-level key retires with no alias;
minorfollows f61dab1 (objectui#11070'sreference_to, a Minor Change in@object-ui/types17.7.0), and the no-major gate would refuse a major anyway;- enrichment strips both keys from the view entry.
- The PM assumption correction is noted:
DetailSection's read-only cell had nodependentValues, and the host now evaluates againstdataitself, as the reference note said.
Implemented-by: cloud session session_01LzSF1MK7r46WEAYG2ooGiq, branch claude/issue-11815-declared-overdue
Generated by Claude Code
Contract reviewServed-tier: Face: the
The PR's file list carries no Inputs read:
Nothing was built or run locally. ① Derived judgments
② Semver levelEight minor changesets, in
Retiring an optional published member as minor follows the repo's own precedent: f61dab1, objectui#11070's ③ Boundary flags
Implemented-by: VERDICT: PASS Generated by Claude Code |
✅ Console Performance Budget
The eager closure is every chunk the entry reaches through static imports — what the browser fetches and parses before the app renders. The entry chunk on its own is a small fraction of it. 📦 Bundle Size Report
Size Limits
|
CI red ·
|
…ctui#11815) `dateCell.overdueZone-10183` runs only in forked children under non-UTC zones (`date-only-zone-pins-10183` drives it), and it relied on the retired field-name guess to make `due_date` a deadline. Its subject is the zone-correct day of the overdue colour, so the field now declares `dueLike: true`. Claude-Session: https://claude.ai/code/session_01LzSF1MK7r46WEAYG2ooGiq Co-authored-by: Claude <noreply@anthropic.com>
✅ Console Performance Budget
The eager closure is every chunk the entry reaches through static imports — what the browser fetches and parses before the app renders. The entry chunk on its own is a small fraction of it. 📦 Bundle Size Report
Size Limits
|
Landing · head
|
Part of #11815 — two hosts outside the claimed file surface stay open, named under Deviations: ListView's own projection (ruling 6), and the approval snapshot faces.
Clause-②: yes
What changed
Ruling D (6054882132): overdue is declared-only.
date/datetimereads overdue only when its field declaresdueLike: true, and never while that field'ssettledWhenholds for the record. The field-name regexDUE_LIKE_FIELD_NAMEretires (ADR-0049: nothing undeclared paints). An undeclareddue_datein the past now reads as any past date does.CellRendererProps.deadlineSettled?: booleanin@object-ui/fields. While it is true,DateCellRendererandDateTimeCellRendererpaint no overdue wording and notext-red-600; the wording falls back to the neutral relative phrase. Absent or false changes nothing. Settled is never carried asdueLike: false.isDeadlineSettled(field, row, { scope, fields })in@object-ui/core(evaluator/deadlineSettled.ts), built onevalRowPredicate(settledWhen, row, { fallback: false, scope, fields }). It isfalsefor a field withoutdueLike: trueor withoutsettledWhen, andfalsewhen the predicate fails to evaluate. Every host calls it; none has its own copy.ObjectGrid: object columns, name columns and inline-row fields now forwarddueLikeandsettledWhen; three of the four builders used to dropdueLike. Every cell and link cell on all four paths getsdeadlineSettledfor its row. The grid's own$selectadds a shown deadline'ssettledWhenoperands through the existing declared-field and FLS gates.DetailSection's read-only cell, judged againstdata, andHeaderHighlight, judged against the staged record.fieldEnrichmentforwardssettledWhenbesidedueLikeand takes neither from the view entry.RelatedList: each child row is judged on its own row, never the parent's. The row'sdueLikeis forwarded, and its projection asks for the predicate's operands.dueLike), compact list and tree: one call-site line each.ReportViewerand the dashboard'sbuildFieldMetaforward nodueLike, so they paint no overdue at all.RecordMetaFooterdraws only user lookups.DetailView's summary chips do not reach the date cells.DetailViewField.dueLikeand itsDetailViewFieldSchemarow are retired, with no alias. Producer search for the authored view-level key found 0 in objectui (apps/,packages/,examples/,content/docs), 0 in hotcrm, and in objectstackexamples/only field-level declarations (app-showcase task, app-todo task, app-crm activity). Semver isminoron the precedent of f61dab1 (objectui#11070 round 4,DetailViewField.reference_toretired as a Minor Change in@object-ui/types17.7.0).content/docs/fields/date.mdx,datetime.mdxandapi/schema-reference.mddrop the name convention and the view-level key, and say howsettledWhenreaches each view.Inverted pins (each a CONTROL now)
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.test.tsx— 'the field-name heuristic answers the same on both cells' is now 'CONTROL — with no key authored, a deadline-shaped name paints nothing on either cell'.DetailSection.dueLikeReachesTheCell-9729.test.tsx— the view-entry key no longer reaches the cell; the object field's does.mirror-only-published-keys-9729.test.ts— the key is absent from both published faces.date-locale-channel'resolves through the translate fn' (zh, en) anddateCell.unparsableValue-8581'POPULATED — a past due_date is still Overdue Nd' now declaredueLike: true.Live, before and after
Setup: showcase at
@objectstack/cli18.0.0-next.2 throughe2e/live/ci/start-backend.sh; taskdue_datedeclaresdueLike: trueandsettledWhen: record.status == 'done'. A throwaway copy adds an undeclaredrenewal_on. zh-CN, light, today 2026-10-17.On the record page of the done task, the highlights strip reads 逾期 6 天 in red on main and 6天前 neutral on the branch.
Screenshots (evidence branch
claude/issue-11815-evidence, not merged):Test evidence (head c6a46ce)
buildandtype-checkpass for all eight packages.check:i18n-keys,check:i18n-drift,check:new-line-citations, changeset presence and no-major all exit 0.Deviations
plugin-list/src/ListView.tsx, outside the claimed surface) builds the$selectfor console list views and has no arm forsettledWhenoperands. A list view that hidesstatusleaves done rows overdue, as today. The fix is oneaddSpeculativeloop; this needs the seat's call.ApprovalsInboxPageRecordFieldFace, app-shellRecordSnapshotSummaryFieldFace) draw a declared deadline beside the record snapshot with nodeadlineSettled. The fix is one call-site line each; this needs the seat's call.ReportVieweris in the claimed surface but unchanged: report columns carry nodueLike.Session:
https://claude.ai/code/session_01LzSF1MK7r46WEAYG2ooGiqGenerated by Claude Code