Skip to content

fix(spec): the liveness ledger grades field.settledWhen live - #26918

Merged
objectstack-fleet[bot] merged 2 commits into
mainfrom
claude/project-thread-n1f3av
Oct 27, 2026
Merged

objectstack-fleet[bot] merged 2 commits into
mainfrom
claude/project-thread-n1f3av

Conversation

@os-support-ai

@os-support-ai os-support-ai commented Oct 27, 2026 •

Copy link
Copy Markdown
Collaborator

Requested by Yibo Wang · project thread

Fixes #26727

What changes

  • packages/spec/liveness/field.json › settledWhen: planned → live, verifiedAt 2026-10-27, evidenceScope cross-repo → in-repo (the renderer is ui/ since tooling(ui-merge): governance in-repo — liveness evidence and spec tests stop citing objectui by commit, one sdui-parser, AGENTS.md / pm scripts drop objectui#, ui/AGENTS.md nests, 18 governance workflows merged or retired (parent #25677, 4b/6) #25712). Evidence: ui/packages/core/src/evaluator/deadlineSettled.ts#isDeadlineSettled (the one host helper), ui/packages/fields/src/index.tsx#resolveDueLike (the date and datetime cells drop overdue wording and colour on a settled verdict), ui/packages/plugin-grid/src/objectGridGenerateColumns.tsx#useObjectGridGenerateColumns, ui/packages/app-shell/src/views/approval-decision/RecordSnapshotSummary.tsx#FieldFace. New producer: the grid's three column paths and plugin-detail ENRICHED_FIELD_METADATA_KEYS copy the key onto cell metadata; objectGridRowLoad.ts#useObjectGridRowLoad and ListView.tsx#ListView fetch the predicate's operands. The note names the other hosts that ask the same helper (DetailSection, HeaderHighlight, RelatedList, ObjectKanban, ObjectGallery, ListViewCompact, ObjectTree), each pinned by its own deadlineSettled-11815 test. The row had no authorWarn / authorHint, so none is dropped.
  • Same file › dueLike note: its "PARTIAL until objectui#11815 lands" clause was false (the grid copies the key on all three column paths, and DUE_LIKE_FIELD_NAME is gone). Note only; the status was already live.
  • packages/spec/liveness/state-counts/field.md: regenerated by gen:liveness-counts.
  • packages/spec/liveness/README.md: one sentence on the field row recording the flip and its counts.
  • packages/qa/dogfood/test/expression-conformance.ledger.ts › cel-field-deadline-settled: experimental / unevaluated ("NO EVALUATOR FOUND … objectui @55e90fd has no settledWhen read") → enforced / fail-soft-log, enforcement naming isDeadlineSettled → evalRowPredicate → evalFieldPredicate → celEngine. A faulting predicate is warned once per predicate text (warnPredicateFailure, via evalFieldPredicate, since isDeadlineSettled passes no warnOnError) and answers not settled, which is the cel-field-rule tier.
  • .changeset/26727-settled-when-ledger-live.md: @objectstack/spec patch (the liveness/ folder ships in the spec tarball).

object.tenancy is already right on main, and this PR leaves it alone. The QA's "no tenancy row" reading is not true at 2720874: object.json has a tenancy container with two children, both live and both checked at this head. enabled: isTenancyDisabled (object.zod.ts) is called by injected-system-columns.ts#resolveInjectedSystemColumns (withholds organization_id), sql-driver.ts#computeTenantField (no driver org scope) and security-plugin.ts#getObjectSecurityMeta (tenancyDisabled posture). tenantField: computeTenantField honours a declared column that exists on the object. Like the other container rows here (enable), the container itself carries no status.

Moved counts:

  • state-counts/field.md field row: live 99 → 100, planned 6 → 5 (106 classified, unchanged). It counts the field ledger rows by verdict, and one row moved verdict.
  • check:liveness producer census: live rows citing a producer reads 152 at this head. The settledWhen row is the only row that gained a producer, so main reads 151; that is inferred from the diff, not run on main. This count is not pinned; the gate only reports it.
  • No other pin moved. The expression-conformance ledger has no per-state count pin. Its unevaluated pin judges each unevaluated row's cell, and this row has left that set.

No .describe() change: the settledWhen / dueLike describe strings never said planned. The content/docs/data-modeling/fields.mdx deadline section already describes the live behaviour.

Why

The ledger tells authors and agents whether a key does anything. A planned grade on a key the console reads makes an agent treat it as inert. Re-measured on main 2720874, after the QA's 3fcafcd.

Verification

Clause-②: no
Metadata-protocol: none

Keep one value on each of the two lines above, each line starting with its key.
Human Minimum
item 5 says what they mean.

Tests and gates, run on head 1e5831a:

  • pnpm --filter @objectstack/spec check:liveness: exit 0 (after gen:liveness-counts; before it, the gate reported field.md stale with exactly the 99/6 → 100/5 move above). check:empty-state: exit 0.
  • spec vitest run scripts/liveness: 12 files, 358 tests passed. lint lint-liveness-properties.test.ts: 110 passed.
  • dogfood expression-conformance.test.ts: 8 passed (with @objectstack/verify built).
  • dispatch-gates --commands: 59 commands. 58 exit 0, including check:generated, check:doc-authoring, check-adr-0087-registration --base origin/main and check:published-files. check:dual-build-cjs-loads exits 3: it needs a full repo build, so nothing was measured. That is not a finding.

Human Minimum

Each item is one rule from
CONTRIBUTING.md › Human Minimum,
which links the AGENTS.md text that states it.

  • 1. Schemas start as Zod; packages/spec holds no runtime logic.
  • 2. Every name I added uses the casing for its kind.
  • 3. No formatter ran; pnpm lint passes. (No formatter ran. pnpm lint was not run locally: the diff is JSON, Markdown and one string-literal row, so CI's lint decides.)
  • 4. One issue, one branch off an up-to-date main, one pull request.
  • 5. A change that publishes carries a changeset, and both declaration lines are filled in here and in the changeset.
  • 6. packages/spec touched: its generated artifacts are regenerated and committed.
  • 7. No hand edits to content/docs/references/, packages/*/CHANGELOG.md or content/docs/releases/.
  • 8. Title, body and comments are in English.
  • The Before Submitting list in CONTRIBUTING.md is done.

Generated by Claude Code

The row said no reader existed, while ui/'s isDeadlineSettled has been
asked by every surface that draws a date cell since objectui#11815
landed. Flip the row to live with its readers and producers, refresh the
dueLike note's stale PARTIAL clause, regenerate the field state counts,
and re-state the expression-conformance row as enforced / fail-soft-log.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WGufzgGEj5Qdn1KEGPUrU8
@github-actions

github-actions Bot commented Oct 27, 2026 •

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

⚠️ 3 changed file(s) yielded no anchor (packages/spec/liveness/README.md, packages/spec/liveness/field.json, packages/spec/liveness/state-counts/field.md), so the pages documenting them are NOT COVERED by this run — this is not a clean bill of health for those files. Nothing else in this diff resolved to a documentable surface (no symbol, route or SDK anchor derived from 1 changed package(s)).

What this run could not see
  • 3 changed file(s) yielded no anchor (packages/spec/liveness/README.md, packages/spec/liveness/field.json, packages/spec/liveness/state-counts/field.md) — pages documenting those are invisible to this run
  • a page that states a rule by its inputs shares no identifier with the emitter that implements the rule, so an emitter-only diff cannot list it — not on this run and not on any run. Measured on fix(driver-sql): emit varchar(maxLength) for a text field a declared index keys on #11430: content/docs/protocol/objectql/types.mdx documents the text-family column mapping by the ObjectQL type names it maps FROM (text / textarea / html) while the diff changed createColumn; it went unlisted, and it was the page that diff falsified, in four places. No shared token exists to detect this on, so a rule your change carries has to be re-read by hand in the pages that restate it.
  • a key NAME is not a key, so the hand re-read the line above prescribes can land on the wrong schema. The same spelling is authorable on one governed type and a [REMOVED] tombstone on another for each of active, aria, joins, objects, template, tools and version (censused on [finding] tools is a key on BOTH AgentSchema (tombstoned, dead) and SkillSchema (live, cloud-attested), so a name-based search attributes skill examples to the agent key — it produced a false stop-the-line alarm on PR #19059 #19093 over the liveness ledger's governed types, top-level keys); nothing in a search result distinguishes the two, so a grep hit on a LIVE example reads as evidence about the DEAD key. Measured on fix(spec): the agent.tools liveness row says dead — it claimed live on a key the schema tombstoned #19059: content/docs/ai/agents.mdx was reported as contradicting the agent.tools tombstone over its tools: example at :161, which is inside the defineSkill({ block opened at :155 — the page was already correct. Settle ownership by PARSING the value against both schemas, never by the name: that literal PASSES SkillSchema, and as an AgentSchema it FAILS at tools with the tombstone prescription. ⛔ These names are not the whole class — a key retired through a .strict() guidance map leaves no tombstone in the walked shape and none of them here (tool.category, live as AIToolDefinition.category).

Coarse fallback — 147 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): node scripts/docs-audit/affected-docs.mjs --json 57820085fa1cfb522fefc1e24e12f252d8d4630e → packageMentionDocs.

@objectstack-fleet

Copy link
Copy Markdown
Contributor

Contract review

Served-tier: TIER_DEFAULT
Head-sha: 1e5831a53f68f7d58a7dd369b0d1bd9033b0ee26
Local-runs: none

Inputs read: card #26727 (body, the triage grade, the claim, the os-dev report), PR #26918 (body, its 5-file list), the net diff origin/main...1e5831a5 (merge-base 2720874a), the cited ui/ and server code at the head via git show, and the head's check-runs. record-recognisers --paths over the five changed paths decides no face, so the changeset's Clause-②: line decides it: declaration face, TIER_DEFAULT.

Check-runs on the head, read 2026-10-27T21:14Z: 38 total. 12 success, 6 skipped, 0 failed, 20 still in progress.

  • Success: Spec property liveness, Check Changeset, Dogfood Regression Gate (aggregate), Governed Surface Queue Guard, Lint · PM dispatch-gates, Lint · scoped · tooling self-tests, PR-body guards, Check PR Size, Flag docs affected by code changes, Plan Test Core shards, Auto Label, filter.
  • Skipped: the Dogfood Regression Gate (n/3) shards, Dogfood Verify CLI, Temporal Conformance, Build Docs, Packed-tarball smoke, 18.x upgrade harness. These are all full-battery or opt-in jobs that do not run on pull_request (ci.yml THE TWO SPEEDS), so they are skipped by design. The aggregate gate counts zero expected attestations and passes.
  • In progress: Test Core (1/8 to 8/8), Build Core, Build UI Deps, Type Check · workspace / debt ledger / consumer gates / source gates, Lint · ESLint, Lint · repo & tooling gates, Lint · docs & code guards, Lint · CI, release & engine gates, Lint · scoped · query-options erasure, Lint · scoped · slot lookup & corpus.
  • This verdict judges the contract. It does not answer those 20 gates. The merge still waits on them, and a red among them is the gate's verdict, not this record's.

① Derived judgments

The diff changes no Zod schema, no .describe() and no exported symbol. It changes the content of liveness/field.json, which ships in the @objectstack/spec tarball (files lists liveness), and three repo-internal files. Each implied change, judged:

  • field.settledWhen planned → live: right. At the head, ui/packages/core/src/evaluator/deadlineSettled.ts#isDeadlineSettled reads field.settledWhen. It returns false unless dueLike === true and the key is present, and otherwise evaluates through evalRowPredicate with fallback: false and the row bound as record. ui/packages/fields/src/index.tsx#resolveDueLike returns false on deadlineSettled === true, and both DateCellRenderer and DateTimeCellRenderer paint from it, so the claimed effect is real: no overdue wording and no overdue colour. The other two evidence anchors call the helper per row: objectGridGenerateColumns.tsx#useObjectGridGenerateColumns (settledFor, on every cell path) and RecordSnapshotSummary.tsx#FieldFace, which judges against the snapshot. Every reader the note names calls isDeadlineSettled at the head: DetailSection, HeaderHighlight, RelatedList, ObjectKanban, ObjectGallery, ListViewCompact and ObjectTree. Each is pinned by a deadlineSettled-11815 test. DetailSection and HeaderHighlight share recordPage.deadlineSettled-11815.test.tsx, and gallery and compact list share plugin-list/.../deadlineSettled-11815.test.tsx, so "its own" in the note is loose but true per surface. The in-repo scope is right because the renderer lives under ui/ (the refactor(spec-liveness): the renderer's ledger evidence is in-repo under ui/; objectui becomes a retired realm that fails #26150 realm move).
  • New producer anchors: right. The grid copies settledWhen onto fieldMeta on three column paths (lines 359, 603 and 790 at the head). The fourth, default-column path hands the object field itself to the cell (fieldForCell), so the key is already present there. plugin-detail/src/fieldEnrichment.ts#ENRICHED_FIELD_METADATA_KEYS lists settledWhen. objectGridRowLoad.ts#useObjectGridRowLoad and ListView.tsx#ListView add the operands of a shown deadline's predicate to their select. Field-ledger rows citing a producer go 1 → 2, which matches the PR's census of 151 → 152. That census is reported, not pinned.
  • State-count shard field row, live 99 → 100 and planned 6 → 5, 106 classified: right. Exactly one field.json row changes verdict (planned → live), and no row is added or removed. A raw status walk of the file at merge-base and head moves by the same +1 live / −1 planned. The absolute values come from gen:liveness-counts. Spec property liveness (check:liveness, which sums and compares the shards) is green on this head.
  • dueLike note correction: right, note only. At the head the grid copies dueLike on all three paths (lines 358, 602 and 789), and DUE_LIKE_FIELD_NAME appears nowhere under ui/packages outside changelogs. The row's status was already live.
  • Dogfood cel-field-deadline-settled, experimental / unevaluated → enforced / fail-soft-log: right in tier, with one wrong name in the cell (S1). A per-record evaluator exists. A bad predicate is caught, warned once per predicate text, and answers the safe default (not settled). That is the fail-soft-log behaviour of the sibling cel-field-rule row, and the unevaluated pin cannot hold on a row with a named evaluator, so enforced is the only consistent state. Unevaluated rows go 7 → 6, and no count of them is pinned. @objectstack/dogfood is private, so nothing in this file publishes.
  • liveness/README.md field cell: right. It is prose recording the flip and its counts.
  • Downstream effect on authors: none. packages/lint reports a planned row only when authorWarn is set (lint-liveness-properties.ts, shouldWarn before describe). This row never carried authorWarn, so no diagnostic an author sees appears or disappears. The accept set and the public surface are unchanged.

② Semver level

  • .changeset/26727-settled-when-ledger-live.md is in the root .changeset/. It reads '@objectstack/spec': patch. Right: it corrects data that ships in the spec tarball and changes no accepted input and no exported shape. The other two touched packages publish nothing that changed (@objectstack/dogfood is private, and liveness/README.md and the state counts are spec-internal), so no second package entry is owed. Check Changeset is green.
  • Clause-②: no is on its own line in both the PR body and the changeset. Right: nothing published accepts or exposes anything new or less. A grade moving planned → live on a row with no authorWarn changes no lint output.
  • Metadata-protocol: none is on its own line in both places. Right: nothing changes in what a metadata author can write.

③ Boundary flags

  • Card half 2, object.tenancy "has no ledger row": answered. The dev's report holds, so nothing is owed. object.json at the head has props.tenancy.children.enabled and props.tenancy.children.tenantField, both live, and this PR does not touch the file. The anchors hold at the head:

    • isTenancyDisabled is at object.zod.ts:740.
    • It is called by injected-system-columns.ts#resolveInjectedSystemColumns, which withholds organization_id, and by sql-driver.ts#computeTenantField, which returns null first.
    • security-plugin.ts carries tenancyDisabled on the object security meta.
    • computeTenantField returns a declared tenancy.tenantField only when that column exists on the object.

    The QA reading took the status-less container for a missing row; enable is shaped the same way. Fixes #26727 closes the card with this half answered as "already right". That is the claim's stated premise, and I accept it.

  • open_questions: []. Nothing to answer.

  • Out-of-scope finding (stale "five honest unevaluated rows" comment, expression-conformance.test.ts:662): confirmed and correctly left alone. The count was already stale on main (7) and reads 6 after this PR. It is comment prose with no pin and is not owed here.

  • Dev-reported check:dual-build-cjs-loads exit 3 (needs a full build): this is not a finding. CI's Build Core is the authority, and it is still in progress.

  • Human Minimum item 3 left unticked (pnpm lint not run locally): CI's Lint jobs decide it, and they are still in progress.

Should-fix

  • S1: the dogfood cel-field-deadline-settled enforcement cell, and the PR body, say a faulting predicate "is logged once (warnEvalError)". isDeadlineSettled calls evalRowPredicate without warnOnError. A fault therefore takes the fast route, evalFieldPredicate → warnPredicateFailure in ui/packages/core/src/evaluator/fieldRules.ts, not warnEvalError, which only the warnOnError route reaches. The behaviour stated (warned once per predicate, answers not settled) is true, so the tier stands. The cell should name warnPredicateFailure (or say "the evaluator's one-time warning"), and spell the chain isDeadlineSettled → evalRowPredicate → evalFieldPredicate → @objectstack/formula the way the cel-action-param-option-visible row spells its own. This is a one-line fix in a private test-ledger file and does not block.

Must-fix: none.

Implemented-by: claude/project-thread-n1f3av
Reviewed-by: session_01WGufzfhobWEgUUrjz4rrbh

VERDICT: PASS

isDeadlineSettled passes no warnOnError, so evalRowPredicate hands the
predicate to evalFieldPredicate, and a fault is warned by
warnPredicateFailure, not warnEvalError. Spell the chain through
evalFieldPredicate in the cel-field-deadline-settled enforcement cell.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WGufzgGEj5Qdn1KEGPUrU8
@objectstack-fleet

Copy link
Copy Markdown
Contributor

席位核对 · ACCEPT · domain:spec seat 1 (#6017) · session session_01WGufzfhobWEgUUrjz4rrbh · 2026-10-27T21:50Z

Head 39caaea39c7e9f52992ca1266f43ef0713b05fb9. Card #26727 (triage 6447056953), claim 6453112270, dev report 6453670060.

  • Contract review: owed on the declaration face at TIER_DEFAULT (Clause-②: no). The review (6453784731) at 1e5831a5 was a PASS with no must-fix. It found:
    • settledWhen planned → live is right. isDeadlineSettled reads it, resolveDueLike honours it, and every named surface calls the helper with a test. The producer anchors hold: the grid's column paths, ENRICHED_FIELD_METADATA_KEYS and the field fetches.
    • The field state-count arithmetic is right: one row moves, so live 99 → 100 and planned 6 → 5.
    • The dogfood row cel-field-deadline-settled moving to enforced / fail-soft-log matches the code.
    • The tenancy half of the card was already right: tenancy.enabled and tenancy.tenantField are live with real anchors. Nothing moves there.
  • Since then: 39caaea3 closes the one should-fix. The ledger cell now names the real fault route, isDeadlineSettled → evalRowPredicate → evalFieldPredicate → celEngine, warned once per predicate text by warnPredicateFailure because no warnOnError is passed. The seat mirrored that sentence into the body.
  • Shape: Fixes #26727, 5 files, +30/−17. One root changeset, @objectstack/spec patch. Clause-②: no and Metadata-protocol: none. check-governed-merges --pr 26918: NOT governed, 47 changed lines.
  • Gates: check-runs on this head are 40 success, 10 skipped and 0 red. mergeable_state is clean.
  • Landing: Tier S. pr_ready + automerge_enable in this act.

@objectstack-fleet
objectstack-fleet Bot marked this pull request as ready for review October 27, 2026 21:51
@objectstack-fleet
objectstack-fleet Bot enabled auto-merge October 27, 2026 21:51
@objectstack-fleet
objectstack-fleet Bot added this pull request to the merge queue Oct 27, 2026
Merged via the queue into main with commit 3fe9d25 Oct 27, 2026
51 checks passed
@objectstack-fleet
objectstack-fleet Bot deleted the claude/project-thread-n1f3av branch October 27, 2026 22:28
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation size/s tooling

Projects

None yet

Development

Successfully merging this pull request may close these issues.

spec liveness ledger drift: field.settledWhen is graded planned but is live (the console overdue colour reads it); object.tenancy has no ledger row

2 participants