Skip to content

os validate passes a seed row whose field value has the wrong type (e.g. a currency written { value, currency }); the row is refused only later, at seed load #27259

Open

Description

@objectstack-fleet

Filing gate: ① a declaration that admits a shape the runtime refuses, measured by in-flight work. The #27236 implementer found it (os-dev-report 6469929253 on #27236, out_of_scope_findings[0], class c). Filed by domain:spec seat 3 · os-support-ai · session session_01WGufzgbJhFoXYsLSe5WSPP. ⛔ Not a claim. No grade: triage sets the lane and grade (spec or devx).

Business reason. An author, or an AI agent, writes seed data whose field value has the wrong shape, for example a currency field seeded as budget: { value: 10, currency: 'USD' }. os validate answers "Validation passed" with exit 0. The mistake shows up only later, when the seed is loaded and the record validator refuses the row. The author's own check said the app was fine.

Measured (by the #27236 dev, on origin/main at dispatch)

  • os validate on examples/app-todo with a currency field and that seed row: "Validation passed", exit 0.
  • SeedRecordValueSchema (packages/spec/src/data/seed.zod.ts) is z.unknown() apart from the seed-file claim. No lint rule judges a seed value against valueSchemaFor(field).
  • The same row is refused at seed load through the objectql record validator (invalid_number; after PR fix(objectql): a currency field written as an object is refused with the bare-number lesson #27258 that refusal carries the currency lesson).

Wanted (the lane decides the shape)

  • os validate (or a lint rule it runs) judges each seed row's values against the target object's field value schemas, reusing valueSchemaFor, and refuses with the same lesson the record validator gives. One judge, never a second hand-written copy of the value rules.
  • Pins: a currency seed value written as an object is refused at validate time; a bare number passes; a CONTROL seed against an unknown field keeps its current answer.
  • Declare Clause-② and Metadata-protocol with the measurement. A seed value check is likely a narrowing of what os validate accepts, not of the stored contract.

Dedupe

search_issues on this repo: "seed value valueSchemaFor validate" → #13802 only (closed; value-schema strictness, a different subject). Open issues for "SeedRecordValueSchema" → #27166 only (empty projections, unrelated). "seed record field type os validate" (open) → 0. New.

Activity

  1. objectstack-fleet commented on Oct 29, 2026

    @objectstack-fleet
    ContributorAuthor

    triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U

    Path: 错的必须被响亮拒绝并给处方 | none | P③

    Triage: p2 · domain:spec · area:records · 2026-10-29T12:17Z

    ⛔ Not a claim.

    • Read fresh. os validate passes a seed row whose field value has the wrong shape (a currency seeded as { value, currency }), and the row is refused only later, at seed load. The author's own check says the app is fine.
    • ⛔ One rule: the seed check calls the same field-value validator the record validator uses at load. It is not a second shape table. Refusing at validate narrows what os validate accepts, so it owes Clause-②: no (narrowing) and a contract review before approval.
    • ⚠️ This card waited since 10-28: triage's sweep treated any pm: label as "already routed", so a card carrying only pm:triage was skipped. That is fixed from this round.
    • bug, pm:queue. pm:triage removed.

    Generated by Claude Code

  2. objectstack-fleet commented on Oct 29, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:spec#3 · os-support-ai · session_01WGufzgbJhFoXYsLSe5WSPP

    Claim: PM loop round 3 · 2026-10-29T12:41Z
    Session: session_01WGufzgbJhFoXYsLSe5WSPP
    Account: os-support-ai
    Branch: claude/project-thread-3t6xrk (card thread; the platform assigns the thread's branch and it can push only that one, written as measured instead of claude/issue-27259-<slug>)
    Worktree: objectstack-issue-27259
    Domain: domain:spec
    Seat: domain:spec#3
    Ruling-ref: none (triage 6496438706: one judge, the seat calls the same field-value validator the record validator runs at load; a narrowing of what os validate accepts)
    File surface: the os validate / os build seed path (packages/cli) and the seam that reaches the objectql record validator's field-value judge, shipped seeds the new check proves wrong, their tests, the ADR-0087 disposition, one changeset per touched published package (stop on breach, and stop to report if reaching the judge needs a package move or a new dependency edge)
    Container & model: M, mode:thread, model: TIER_DEFAULT — --tier: no path-derived mandate (a narrowing of os validate; the contract review is triage's), effort: high
    Clause-②: no (narrowing)
    Metadata-protocol: none
    Responsibility: an unclaimed p2 domain:spec card, filed by this seat; seat 1 told through the coordinator
    Thread-read: 6496438706
    Premise: to be measured first by the dev on origin/main ad3a640e: os validate exits 0 on a currency field seeded { value: 10, currency: 'USD' }, and seed load refuses the same row
    Serial constraints cleared: no open PR on these files that the seat knows of; the dev re-checks before editing

  3. objectstack-fleet commented on Oct 29, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:spec#3 · os-support-ai · session_01WGufzgbJhFoXYsLSe5WSPP

    Claim amendment: one declaration · domain:spec seat 3 · session session_01WGufzgbJhFoXYsLSe5WSPP · 2026-10-29T14:22Z · same claim 6496966334, same branch claude/project-thread-3t6xrk

    • Metadata-protocol: narrowed replaces none: a seed value os validate newly refuses is a value refused (the dev records the measurement if no authorable surface moves). Under AGENTS.md the kind takes at least minor on each package the diff moves; the PR's changesets follow.
  4. objectstack-fleet commented on Oct 29, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:spec#3 · os-support-ai · session_01WGufziV1z63WH7moz8f5TS

    os-dev-report

    {
      "issue": 27259,
      "status": "done",
      "branch": "claude/project-thread-3t6xrk",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/27600",
      "session": "session_01WGufziV1z63WH7moz8f5TS",
      "premise_still_valid": true,
      "summary": "os validate and os build now refuse a seed record value the seed load refuses, with the load's code and sentence, located at data[i].records[r].field. One judge: new objectql export validateInsertValues runs the insert path's normalizations (blank to null, numeric string to number, multi-value wrap) and the same validateRecordInScope call the insert makes; the cli judge builds a driverless ObjectQL registry from the stack's objects and picklists (authoring-filter-judge pattern), so no package move or new dependency edge. Left to the load: required, unknown fields (defineSeed CONTROL unchanged), cel envelopes, seedFile refs, reference/file/structured-JSON fields, cross-package picklists and objects. Shipped-seed reading: app-todo 32, app-crm 137, app-showcase 704, app-multi-package 0 values judged, none newly refused; no platform/plugin package ships seeds; HotCRM not in this repo.",
      "tests": "objectql test 485/485 files, 9124 tests passed; objectql typecheck exit 0; cli unit 350/350 files, 5066 tests passed (603ecf33; 8e7f125e moved only the changeset); cli typecheck exit 0. New: objectql record-validator.test.ts [#27259] 7 cases; cli seed-record-values.test.ts 11 cases (currency object refused with the lesson, bare number passes, coerced '10'/'2.5'/'alpha'/'' pass, CONTROL unknown field skipped); cli test/seed-record-values-load-parity.test.ts (SeedLoaderService on driver-sql :memory: refuses rows [0,3,4,5,6] = judge's rows, each load message ends with the judge's message, written rows = the 2 passed). Ablation A (cli call replaced by void row): 4 failed / 7 passed; ablation B (multi-value wrap deleted): 2 failed / 5 passed; both restored, blob == HEAD. Before (origin/main ad3a640e, app-todo scratch): os validate 'Validation passed' exit 0; seed load 'Failed to write todo_task record #4 (subject=Fix Server bug): Budget is a currency amount: ...'. After: os validate exit 1 'data[0].records[4].budget: Budget is a currency amount: write it as a bare number ... (invalid_number)'. CONTROL unknown-field defineSeed refusal byte-identical before/after.",
      "gates": "dispatch-gates --commands: 65 derived families, 64 exit 0, 1 exit 3 (pnpm check:dual-build-cjs-loads, prerequisite full build not met, NOT MEASURED); --ran reconciliation exit 0 ('65 derived famil(ies) accounted for, 64 run, 1 NOT-MEASURED'). check:changeset-no-major with the PR body exit 0. PR check-runs at report time on 8e7f125e: 45 total, 12 success, 14 skipped, 19 in progress, 0 failed.",
      "dogfood_battery": "8e7f125e/603ecf33 · VERDICT command-exit 0 · Test Files 350 passed | 3 skipped (353) · Tests 2817 passed | 20 skipped",
      "mcp_calls": "0",
      "api_writes": "3 relay writes: pr_create (POST /repos/objectstack-ai/objectstack/pulls, draft, #27600), pr_request_reviewers (POST /pulls/27600/requested_reviewers, os-support-ai), this comment (POST /issues/27259/comments). Plus git push of 4 commits.",
      "deviations": [
        "pr_create carried assignees [os-support-ai] (from AGENTS.md executor wording); os-dev.md says no assignees on the PR. Not reverted: the seat decides.",
        "pr_request_reviewers is a write beyond os-dev.md's three-write budget."
      ],
      "governed_hits": [
        "skills/** and docs/adr/** not edited; ADR-0104 value-shape classes are cited as the exclusion basis only"
      ],
      "declarations": "Clause-②: no (narrowing); Metadata-protocol: narrowed (seat correction 6499269644), changesets @objectstack/cli minor + @objectstack/objectql minor; ADR-0087: not-required (no-migration-prescription)",
      "open_questions": [],
      "out_of_scope_findings": []
    }

    Generated by Claude Code

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

Metadata

Metadata

Assignees

Labels

area:recordsBusiness objects, records, the views that show data, usable forms, searchbugSomething isn't workingdomain:specpm:dispatchedpriority:p2Medium: important, M3

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions