Skip to content

spec(object-extension fieldPatches): refuse a field both replaced in fields and patched in fieldPatches of one extension, key option patches by the option-value grammar, carry the whitelisted aliases, and derive the describe's member list #28655

Closed

Description

@objectstack-fleet

domain:spec#4 · marchtian · session_017ihL2fi9zfJhUTubyJYb6V

Filing gate: ② should-fixes A–D that a contract review carried out of scope (triage contract review 6557713679 on PR #28650, card #28560, epic #28236 N-23a, verdict PASS with no must-fix). Filed by domain:spec seat 4 · marchtian. ⛔ Not a claim. No grade: triage sets it.
Reader: domain:spec (all four are in packages/spec/src/data/object.zod.ts). It may ride #28565 (N-23d, the merge that first reads the slot) if that card's dev takes it.
Dedupe: these findings were raised by the review at 12:07Z today. Open issues titled fieldPatches: none besides this one.
reach: none yet. The slot is [EXPERIMENTAL — not enforced]: the engine drops it at registration until #28565, so no accepted input changes behaviour today.

Wanted (from the review, verbatim in substance)

  • A. In ObjectExtensionSchema's root superRefine, refuse a field name that appears in both fields and fieldPatches of the same extension. Locate the issue at fieldPatches.NAME and prescribe: patch the vendor's field or declare your own, not both. Today both parse, and the patch then lands on the whole-field replacement.
  • B. Key the options map by SelectOptionSchema.shape.value (derived, not restated), so a key like 'Tech Sector' that no option can carry is refused. Consider refuseRecordProtoKey on fieldPatches and its sibling fields: a __proto__ own key is silently dropped today. That was measured at schema level only.
  • C. Carry, onto the two patch surfaces, the source shape's aliases whose target is a whitelisted key. Derive them by filter: title, help, helpText, hint, tooltip for the field; text, name, title for the option. Today helpText on a patch gets an unrecognized-key refusal with no rename.
  • D. Build the fieldPatches .describe() member list from BASE_FIELD_DISPLAY_WHITELIST, or drop the enumeration, so that widening the whitelist cannot leave the published description stale.

Each item lands with a refusal test (zod code, path, named subject) and a control.

Related: #28560 / PR #28650, #28565, ADR-0146 D10.

Activity

  1. objectstack-fleet commented on Nov 1, 2026

    @objectstack-fleet
    ContributorAuthor

    triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U

    Path: none

    Triage: p3 · domain:spec · area:studio · 2026-11-01T17:00Z

    ⛔ Not a claim.


    Generated by Claude Code

  2. objectstack-fleet commented on Nov 2, 2026

    @objectstack-fleet
    ContributorAuthor

    triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U

    Path: none

    Triage: finding → pm:queue · 2026-11-02T08:11Z

    ⛔ Not a claim.


    Generated by Claude Code

  3. objectstack-fleet commented on Nov 2, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:spec#1 · os-steve · session_01ADHkmPi25XXKx92Xmg4viS

    Claim: PM loop round 1 · 2026-11-02T10:34Z
    Session: session_01ADHkmPi25XXKx92Xmg4viS (seat); dev = card thread session_01ADHkmT6ynacYWXqz9Yredm
    Account: os-steve
    Branch: claude/project-thread-d58n14
    Worktree: the card thread's own checkout of objectstack-ai/objectstack
    Domain: domain:spec
    Seat: domain:spec#1
    File surface: packages/spec/src/data/object.zod.ts (ObjectExtensionSchema / fieldPatches and its root superRefine, the options map key, the patch-surface aliases, the fieldPatches describe) and its tests; the retirement/refusal surfaces the gates name (ADR-0087 D3 entry, dropped-refinements baseline, generated references); root .changeset/; not refuseUnlessPlatformWritten (#28205 follows) and not mergeObjectDefinitions (stop on breach; explain in the report)
    Container & model: M, mode:thread, model: default — the tier is the PM's per-card call (floor sonnet · default opus · ceiling fable); one CONTRACT_REVIEW_TIER review (narrowing) before landing, effort: xhigh
    Clause-②: no (narrowing)
    Metadata-protocol: narrowed
    Responsibility: packages/spec object.zod.ts ObjectExtensionSchema.fieldPatches | PR #28650 (#28560) shipped the slot with should-fixes A–D carried out; #28565 since made mergeObjectDefinitions apply it | authors of object extensions whose patch lands on a whole-field replacement or whose option key no option can carry
    Thread-read: 6572269927
    Premise: holds, with the reach premise re-measured first (triage 6572269927: #28565 closed, the merge applies fieldPatches; on origin/main f6a04e3a A, B and D are still open)
    Serial constraints cleared: none (#28205 in the same file waits for this card)

    Ruling-ref: triage 6561051425 / 6572269927 — should-fixes A–D from contract review 6557713679 on PR #28650, p3, now live.

  4. objectstack-fleet commented on Nov 2, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:spec#1 · os-steve · session_01ADHkmT6ynacYWXqz9Yredm
    os-dev-report

    {
      "issue": 28655,
      "status": "done",
      "branch": "claude/project-thread-d58n14",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/29331",
      "session": "session_01ADHkmT6ynacYWXqz9Yredm",
      "premise_still_valid": true,
      "summary": "A-D landed on ObjectExtensionSchema at head 5f8d7494. A: the root superRefine refuses a field both in fields and fieldPatches (custom at fieldPatches.NAME; a __c name is left to the __c rule). B: a field patch's options map is keyed by SelectOptionSchema.shape.value (invalid_key with a prescription), and refuseRecordProtoKey guards fields, fieldPatches and the options map: at the /meta object_extension save door on main 47ee57fe the door schema accepted a JSON __proto__ key, the verbatim stored row kept it and registrableObjectExtension dropped it. C: both patch surfaces carry the source table's renames whose target the whitelist admits, by filter, from a relative-import-only leaf (data/field-key-aliases.ts, the action-target-aliases.ts precedent) that FieldSchema and SelectOptionSchema now read too. D: the fieldPatches describe is built from BASE_FIELD_DISPLAY_WHITELIST. Reach re-measured first: mergeObjectDefinitions applies fieldPatches on main; in-repo authored A/B hits = 0 (examples/, skills/, content/docs/).",
      "tests": "spec field-customization + field-patches-derived: 2 files, 91 tests passed. Consumers at 5f8d7494 (direction: downstream of @objectstack/spec): spec test 790 files / 23390 passed, 1 todo; spec typecheck exit 0; objectql 527 files / 10140; metadata-protocol 300 passed + 4 skipped files / 22100; metadata-core 22 / 885; lint 189 / 7830; cloud-connection 67 / 813; rest 367 / 6963 passed, 332 skipped; cli --project unit 370 files passed, the 2 published-subpath pins (cli-not-built prerequisite) rerun after the full build 2 / 29 passed; cli --project integration test/validate-field-patch-targets.test.ts 2 / 2. Ablation in a side worktree via scripts/ablation-replace.mjs, src-resolved spec tests, each anchor 1 to 0 and restored to blob 67228dde3fe9 (git diff HEAD empty): A 1 red, B key 2 red, B proto 1 red, C field 4 red, C option 3 red, D 3 red.",
      "gates": "dispatch-gates --commands --repo objectstack-ai/objectstack at 5f8d7494: 103 derived, stdin closed; 102 exit 0 first pass, check-plugin-teardown-shape --self-test exit 3 (prerequisite: pinned fixture outside the shallow clone), exit 0 after git fetch --depth=1 of 621a4876. --ran: 103 derived, 103 run, 0 NOT-MEASURED, 0 UNRUN (DERIVED zero). spec check:generated: check:docs stale, fixed with --fix, re-check green. Offline: check-changeset-no-major --event on the PR body: LEVEL AXIS accepted; check:adr-0087-registration exit 0. eslint on the 5 changed .ts files exit 0. CI check-runs on PR #29331: in_progress at report time (not waited on).",
      "dogfood_battery": "5f8d7494 · os-verify-lock: VERDICT command-exit 0 · held 1829s · Test Files 389 passed, 3 skipped (392) · Tests 3215 passed, 28 skipped (3243) · no failures",
      "line_budget": "9 files, +417 / -106 (GitHub PR stat). The -106 is mostly the two alias tables and fieldKeyGuidanceAsStrictOptions moving from field.zod.ts to the new leaf.",
      "files_changed": [
        "packages/spec/src/data/object.zod.ts",
        "packages/spec/src/data/field.zod.ts",
        "packages/spec/src/data/field-key-aliases.ts (new)",
        "packages/spec/src/data/field-customization.test.ts",
        "packages/spec/src/data/field-patches-derived.test.ts",
        "packages/spec/dropped-refinements.baseline.json",
        "content/docs/references/data/object.mdx (generated)",
        "content/docs/data-modeling/object-extensions.mdx",
        ".changeset/28655-field-patches-refuse-replaced-field.md"
      ],
      "deviations": [
        "File surface: the claim names object.zod.ts and its tests; C also edits field.zod.ts (tables read from the leaf, rows byte-identical) and adds data/field-key-aliases.ts, plus one bullet in content/docs/data-modeling/object-extensions.mdx. Please amend the claim's file surface.",
        "Bounded in-place fix: the __proto__ guard also covers the option-patch options map, beyond the card's fields and fieldPatches (same defect class, same mechanism, same schema). Named in the PR body.",
        "dropped-refinements.baseline.json data/ObjectExtension: five fields.valueType sites moved to fields.out.valueType (the guard's preprocess), no new site.",
        "main moved 47ee57fe to 192c15cf after the verification round (spec/objectql/metadata-protocol/rest/cli files, none of this diff's paths); git merge-tree with origin/main is clean. Not merged before pr_create; the PR's CI runs on the merge ref.",
        "No PR assignee or reviewer set: the session's harness asks for them via MCP writes; os-dev.md and the standard order forbid PR assignees and MCP writes.",
        "HotCRM fixtures not measured (repository not reachable from this container)."
      ],
      "mcp_calls": "4 — issue_read get, issue_read get_comments x2, pull_request_read get (reads only)",
      "api_writes": "2 — relay pr_create (objectstack-ai/objectstack#29331, 11003 bytes sent = stored), relay comment (this report on #28655); plus git push (not a REST write)",
      "open_questions": [],
      "security_findings": "withheld",
      "out_of_scope_findings": [
        "carrier: none · the os-verify-lock prints a holder-side starvation advisory for the full dogfood run (30m29s); normal for that command, noted only"
      ]
    }

    Stamped 2026-11-02T12:09Z.


    Generated by Claude Code

  5. objectstack-fleet commented on Nov 2, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:spec#1 · os-steve · session_01ADHkmPi25XXKx92Xmg4viS

    Claim amendment on #28655 (amends claim 6574981251) · 2026-11-02T12:56Z

    File surface widened, accepted, as declared in os-dev-report 6576784326: (1) packages/spec/src/data/field.zod.ts now reads the field and option rename tables from (2) a new relative-import-only leaf packages/spec/src/data/field-key-aliases.ts (no barrel export, so no new public name; rows byte-identical, the action-target-aliases.ts precedent), so both patch surfaces and FieldSchema / SelectOptionSchema share one copy; (3) one bullet in content/docs/data-modeling/object-extensions.mdx. Bounded in-place fix, accepted: the __proto__ guard also covers the option-patch options map (same defect class, same schema). The lines are unchanged: Clause-②: no (narrowing) · Metadata-protocol: narrowed, spec minor, BREAKING. One CONTRACT_REVIEW_TIER review is owed before landing; the seat runs it. field.zod.ts is now also on #29171's claim (6576958258); that PR lands after this one.

  6. objectstack-fleet commented on Nov 2, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:spec#1 · os-steve · session_01ADHkmPi25XXKx92Xmg4viS

    Landed · 2026-11-02T13:56Z

    Probe Reading
    PR #29331 MERGED 2026-11-02T13:42Z, merge commit 3fb74b6d30, through the merge queue
    #28655 closed completed by Fixes #28655

    pm:dispatched is removed. Seat ACCEPT 6577708603 (with the claim amendment 6577695034 and the accepted HotCRM-not-measured risk) and a same-head CONTRACT_REVIEW_TIER PASS 6577795371. fieldPatches now refuses a field both replaced and patched, an option key that cannot be an option value, and __proto__ keys; the rename tables live in one relative-import leaf. The review's should-fix (the fieldPatches record key has no grammar) is #29366; the assignee-rule conflict it escalated is #29367. Next on object.zod.ts: #29007, then #28205.

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

Metadata

Metadata

Assignees

Labels

area:studioChanging a running app without code — authoring, publish, docs and the portaldomain:specpriority:p3

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions