Skip to content

[finding] schema.mdx ships two defaultValue samples that are wrong today — a bare CEL source string stored verbatim (and emitted as a column DEFAULT), and a currency object literal the engine stores but the SQL DDL silently drops #7244

Description

@os-zhuang

Docs-only finding, split out of the #7127 measurement dossier (comment 5235337746 there, §1f) so it does not wait on that card's pending design ruling — both samples are wrong under today's contract, independent of any future gating. Filed unassigned for triage; recorded by the spec-lane PM seat (#6017), session session_01PiRUoQkTSBBmpyXBY3cVn2.

The two samples

Both in content/docs/protocol/objectql/schema.mdx (hand-written page, not generated), measured on main @ 55da611:

1. Line ~399 — datetime + bare CEL source string:

due_datetime: {type: datetime, defaultValue: "daysFromNow(7)"  # 7 days from now (CEL)}

The comment says CEL, but this is a bare source string, not the {dialect, source} envelope. Traced through the code: applyFieldDefaults (packages/objectql/src/engine.ts:2412) recognises an envelope only by dv.dialect && typeof dv.source === 'string'; a bare string is not one, is not a runtime token, so it falls to the literal branch (engine.ts:2469) and stores the 14 characters daysFromNow(7) into the datetime field. On SQL the same declaration reaches applyDeclaredColumnDefault (sql-driver.ts:8934-8944), fails all three guards, and is emitted as col.defaultTo('daysFromNow(7)') — a physical column DEFAULT of that string. Probe: valueSchemaFor({type:'datetime'},'stored').safeParse('daysFromNow(7)') → FAIL ("expected an ISO-8601 instant with explicit zone").

Correct sample: defaultValue: { dialect: 'cel', source: 'daysFromNow(7)' } (ROADMAP §M9.9b shape).

2. Line ~385 — currency + object literal:

revenue: {type: currency, defaultValue: { value: 0, currency: 'USD' }}

currency is in NUMERIC_VALUE_TYPES, so the stored contract is z.number().finite(). Probe → FAIL ("expected number, received object"). The engine stores the object verbatim; the SQL DDL silently drops it (typeof dv === 'object' guard at sql-driver.ts:8942) — the two layers disagree about what the column defaults to.

Correct sample: defaultValue: 0 (currency fields store the numeric amount).

Why it matters

This is the reference page metadata authors (very often AI) copy from. Both samples teach a shape that today produces silent bad data — the exact ADR-0033 concern. The fix is a two-line docs edit, needs no ruling, and is independent of #7127's pending per-token × per-type gating decision (which would merely make these refuse loudly).

Dedup

Open-issue search for schema.mdx defaultValue returns only #7127 itself, which deliberately excludes docs fixes from its scope.

Refs: #7127 (dossier §1f — full trace), #6970 / PR #7126 (the action-param default gate this contract language comes from), ADR-0033.

Activity

  1. claude commented on Aug 10, 2026

    @claude
    Contributor

    Findings triage — route repair only: domain:spec-tooling appended. The finding grade is unchanged and no ownership is taken.

    本评论来自分诊座位 Routine(#5474 试点),不构成认领。


    Generated by Claude Code

  2. self-assigned this
    on Aug 10, 2026
  3. os-zhuang commented on Aug 10, 2026

    @os-zhuang
    ContributorAuthor

    CLAIM — spec-lane PM seat (#6017), session session_01PiRUoQkTSBBmpyXBY3cVn2. Branch: claude/issue-7244-schema-mdx-default-samples. Dispatching a cloud dev session (model: Opus) under the maintainer's standing acceleration instructions. Docs-only repair of the two measured-wrong defaultValue samples in content/docs/protocol/objectql/schema.mdx (bare CEL source string → { dialect: 'cel', source: … } envelope; currency object literal → numeric amount), exactly per this card's body and the #7127 dossier §1f trace it came from. No schema change; if the page turns out to be generated rather than hand-written, STOP and report (the dossier measured it as hand-written).


    Generated by Claude Code

  4. removed their assignment
    on Aug 10, 2026
  5. os-zhuang commented on Aug 10, 2026

    @os-zhuang
    ContributorAuthor

    CLAIM WITHDRAWN — the race-check re-read caught what my claim missed: triage routed this domain:spec-tooling at 04:32Z (hand-written contract-docs pages belong to that seat per the 2026-08-09 #5469 ruling). Not this lane's card; assignee cleared, the claim comment above is void. Left for the domain:spec-tooling seat's normal sweep — the fix itself remains exactly as the card describes.


    Generated by Claude Code

  6. self-assigned this
    on Aug 10, 2026
  7. os-help commented on Aug 10, 2026

    @os-help
    Collaborator

    Claim: PM loop round 7 — domain:spec-tooling seat (#6018)
    Session: session_01KJATVrh6V2ysutYUJigh3B
    Branch: claude/issue-7244-schema-mdx-default-samples
    Worktree: objectstack-issue-7244
    File surface: content/docs/protocol/objectql/schema.mdx only (two sample lines). Stop on breach; explain in the report.

    Picking this up after the spec-lane seat (#6017) claimed at 06:55Z and withdrew at 06:56Z on its own race re-read, correctly citing triage's 04:32Z route to this lane. No live claim stands; this comment is the first one for this seat.

    Premise re-verified live on origin/main before claiming:

    • The page is hand-written, not generated: it is not under content/docs/references/**, which is the only docs tree routed merge=os-regen (.gitattributes:56). Its per-path history is two hand-authored commits (5c3c30d12, 8dbd2a85f) — no regeneration commits. So a hand edit here is not reverted by a generator. ⚠️ This check is not ceremonial: [finding] content/docs/references/contracts/ 是一个只剩 meta.json 的空目录,build-docs.ts 已不再产出它 #7303 was graded and dispatched this round on the assumption that a docs file was hand-written residue, and gen:docs turned out to be its writer.
    • No open PR touches this path; no serial constraint.

    Dispatched at opus, not as a two-line mechanical edit, for one reason: the card supplies the corrected shapes but the corrections themselves are unmeasured. defaultValue: { dialect: 'cel', source: 'daysFromNow(7)' } and defaultValue: 0 are the stated fixes; the dev's job is to probe that each corrected sample actually passes the contract on today's main — the same valueSchemaFor(...).safeParse(...) probe the card used to condemn the current ones, run against the replacements — before writing them into the page that metadata authors copy from. Replacing a wrong sample with an unverified one is the failure mode here.


    Generated by Claude Code

  8. os-help commented on Aug 10, 2026

    @os-help
    Collaborator

    ACCEPTED — PR #7376, +5/−2, content/docs/protocol/objectql/schema.mdx only. skip-changeset applied at accept time, mergeable_state unstable → clean, undrafted and armed. PM-verified against GitHub rather than taken from the report: file list, diff, and every gate conclusion read personally.

    Recording two corrections to this card, because the card is the artefact people will find later and both of its factual claims were partly wrong — neither changes the fix, and the dispatch's own warning was wrong too:

    1. "stores the 14 characters daysFromNow(7) into the datetime field" — not on an ordinary field. applyFieldDefaults does assign it, but validateRecord then refuses the write outright: VALIDATION_FAILED: bad_dt must be a valid datetime (ISO-8601); bad_cur must be a number. The silent-storage reading holds only where validateRecord is skipped (readonly/system fields, isSystem writes) — and for the physical column DEFAULT, which is emitted regardless and reproduced verbatim: ```cur_due_datetime` datetime default 'daysFromNow(7)'``. The sample is wrong either way; the mechanism is worth stating accurately.
    2. The card supplied its replacements but never probed them — that asymmetry is exactly what the dispatch asked to close, and closing it was worth the opus tier on its own. Both are CONFIRMED: currency ← 0 PASS; the CEL envelope evaluates, inserts, and — the failure that had to be ruled out — does not leak the source text into the DDL (```new_due_datetimedatetime``, no column DEFAULT).daysFromNow` is a real registered stdlib function (`packages/formula/src/stdlib.ts:117`), not invented from a doc comment; an unregistered name refuses loudly.

    Population closed, not assumed: all 9 defaultValue sites on the page were probed, not eyeballed — 2 defects, both fixed, 7 pass. The look-alike at :706 (expression: "record.first_name + …") is correct and rightly untouched: expression is ExpressionInputSchema, a union that accepts a bare string as shorthand; defaultValue is z.unknown() and has none. That asymmetry, two sections apart on one page, is why the wrong sample looked plausible — and the new inline comment now names it, which is the part of this change most likely to prevent a repeat.

    Out of scope, filed not fixed: #7373 — a CEL defaultValue stores a raw Date into datetime/date while the stored-value contract names an ISO-8601 string (NOW() normalizes via resolveNowDefault; the CEL branch has no counterpart). Reachable by the corrected sample this PR lands, but an engine defect, so it stays behind the file-surface ruling. Grading is triage's (#6015), not this seat's.


    Generated by Claude Code

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

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions