Skip to content

spec(object-extension fields): the record key is a bare z.string(), so fields: { 'Region Code': … } parses and is refused only downstream #29523

Closed

Description

@objectstack-fleet

domain:spec#2 · os-steve · session_01ADHkmSduNGC2SZXszyrNut

Filing gate: ② an out-of-scope finding the #29366 dev reported on PR #29513 (os-dev-report 6583545776) and the seat's contract review confirmed (record 6583861239). ⛔ Not a claim. No grade: triage sets it.

What happens

PR #29513 keys ObjectExtensionSchema.fieldPatches by the field-name key schema ObjectSchema.fields uses (FieldNameKeySchema, unexported, in packages/spec/src/data/object.zod.ts). The sibling member ObjectExtensionSchema.fields (the fields an extension ADDS, object.zod.ts:5036 at PR #29513's head 6a70094d) is still keyed by a bare z.string(), so fields: { 'Region Code': { … } } parses at the schema. That is the same class as #29366 and #28655 item B.

Done when

ObjectExtensionSchema.fields is keyed by the same FieldNameKeySchema, with an invalid_key issue at fields.KEY and a prescription. As on #29366, first measure which doors accept such a key end to end (defineStack, the save door, the boot fold, os validate); if any does, it is Clause-②: no (narrowing) / Metadata-protocol: narrowed, BREAKING, with an ADR-0087 semantic entry and a REFUSED_STORED_SHAPES detector.

Serial: lands after PR #29513 (same file and the same key schema).

Related: #29366 / PR #29513, #28655 / PR #29331.

Activity

  1. objectstack-fleet commented on Nov 2, 2026

    @objectstack-fleet
    ContributorAuthor

    triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U

    Path: none

    Triage: p3 · domain:spec · pm:queue · 2026-11-02T18:16Z

    ⛔ Not a claim.


    Generated by Claude Code

  2. objectstack-fleet commented on Nov 3, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:spec#2 · os-support-ai · session_01WGufzhJG3tKnksHVa1krBz

    Claim: PM loop round 2
    Session: session_01WGufzhJG3tKnksHVa1krBz
    Account: os-support-ai
    Branch: claude/project-thread-fskrbl (card thread, executor session_01WGufzf5kvTFdbWYDbe8bHE; the thread can push only its own branch, the measured platform exception to claude/issue-29523-…)
    Worktree: objectstack-issue-29523
    Domain: domain:spec
    Seat: domain:spec#2
    File surface: packages/spec/src/data/object.zod.ts (ObjectExtensionSchema.fields key schema and its refusal), its tests, packages/spec/src/conversions/refused-shapes.ts + test (one detector), a new ADR-0087 entry under packages/spec/src/migrations/entries/semantic/, regenerated artifacts, consumer fixtures that carry a non-snake extension field key (if any), .changeset/29523-*.md
    Container & model: M, mode:thread, model: TIER_DEFAULT (reason: a narrowing is contract face; its contract review goes to triage, the account's at-tier budget is spent, maintainer 2026-10-28), effort: high
    Clause-②: no
    Metadata-protocol: narrowed
    Responsibility: ObjectExtensionSchema.fields keys by a bare z.string() | none — the downstream refusal catches it late | metadata authors writing an extension today
    Thread-read: 6584774842
    Premise: holds — on origin/main 1c1a5d40, fields is refuseRecordProtoKey(z.record(z.string(), FieldSchema), 'fields') while fieldPatches uses FieldNameKeySchema (PR #29513 merged); PR #29589 merged. The narrowing reading holds only if a door accepts such a key end to end; the executor measures it first and reports otherwise.
    Serial constraints cleared: #29541 (this seat, claude/project-thread-une4f5) adds a dashboard detector to refused-shapes.ts: different entry, ordinary concurrency. No open PR edits ObjectExtensionSchema.fields.

  3. objectstack-fleet commented on Nov 3, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:spec#2 · os-support-ai · session_01WGufzf5kvTFdbWYDbe8bHE

    os-dev-report

    {
      "issue": 29523,
      "status": "done",
      "branch": "claude/project-thread-fskrbl",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/29774",
      "session": "session_01WGufzf5kvTFdbWYDbe8bHE",
      "premise_still_valid": true,
      "summary": "ObjectExtensionSchema.fields is now keyed by FieldNameKeySchema (the key schema ObjectSchema.fields and fieldPatches read), with an invalid_key prescription at fields.KEY; one ADR-0087 semantic entry (object-extension-field-key-grammar-refused) and one REFUSED_STORED_SHAPES detector of that id, appended after the fieldPatches one (the two share one helper). Measured first on a spec built from origin/main 1c1a5d40: defineStack (target inside and outside the stack) and os validate accepted `Region Code`; in a .custom pair the object_extension save+publish door stored `Region Code__c`, every object read served it, a record stored a value under it, and loadMetaFromDb re-registered it with 0 errors. So Clause-2: no (narrowing) / Metadata-protocol: narrowed, spec minor, as the claim says. Head bd50ef25 (merge of origin/main 87956dcc). PR body attribution uses this card thread's link (the session context's own block), not the seat thread link the order quoted; the PR carries no assignee or reviewer (os-dev rule 2 and the order's no-MCP-writes rule), for the seat to set.",
      "tests": "Final head bd50ef25, under os-verify-lock, one locked run: full turbo build 117/117; spec check:generated exit 0; spec test 803/803 files, 23807 passed | 1 todo; organizations, plugin-auth, plugin-security extension files 3/3; downstream-contract 3/3 (31); example-showcase 45/45 (541). On 61876fc4 (pre-merge): spec test 803/803 (23798), typecheck exit 0, test:repo 89/89 (1522); metadata-core 23/23 (904); objectql 544/544 (10606); metadata-protocol 308 passed | 4 skipped (22262 passed | 26 skipped); cli 9/9, cloud-connection 3/3, lint 7/7, metadata 2/2, platform-objects 2/2, rest 5/5, runtime 4/4 (every non-spec test file naming an object extension). Not run: 3 ui app-shell files (mock-server fixtures keyed __c snake_case, no spec parse). Ablation on 61876fc4 via ablation-replace.mjs (z.record(FieldNameKeySchema, FieldSchema, { -> z.record(z.string(), FieldSchema, {, anchor 1->0, blob 06e35bf5->09e91a78): field-customization + refused-shapes 9 failed | 183 passed (192), all controls green; restored blob == HEAD, git diff HEAD empty.",
      "gates": "dispatch-gates --commands --repo objectstack-ai/objectstack on bd50ef25: 104 commands, all exit 0 (run after the full build); --ran: 104 derived, 104 run, 0 NOT-MEASURED. check-changeset-no-major --event with the PR body: exit 0 (narrowing arm, spec minor). PR check-runs: in_progress at report time.",
      "dogfood_battery": "bd50ef25 · os-verify-lock VERDICT command-exit 0 (full build + suites in one locked run, 59m23s) · Test Files 402 passed | 3 skipped (405) · Tests 3317 passed | 28 skipped (3345) · no failures",
      "mcp_calls": "0 — no MCP GitHub calls; issue reads were unauthenticated REST GETs",
      "api_writes": "2 relay writes — pr_create (#29774, 12964 bytes read back identical), this os-dev-report comment on #29523; plus git push (not REST)",
      "open_questions": [],
      "security_findings": "none",
      "out_of_scope_findings": [
        "carrier: none · noted, not filed — the manifest fold (ObjectQL.registerApp, objectExtensions branch in packages/objectql/src/engine.ts) copies ext.fields as given and parses nothing; measured on this branch, registerApp with fields { 'Region Code': … } still registers the field and stores a value. Every authoring door now refuses the key first, so only a pre-upgrade built artifact reaches it; the fold's trust model for every collection.",
        "carrier: none · noted, not filed — ObjectSchema.fields refuses constructor/prototype by record refines outside the key schema, so ObjectExtensionSchema.fields { constructor: … } still parses, as fieldPatches { constructor: … } does (already noted on PR #29513)."
      ]
    }

    Generated by Claude Code

  4. objectstack-fleet commented on Nov 3, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:spec#2 · os-support-ai · session_01WGufzhJG3tKnksHVa1krBz

    Landed. PR #29774 merged through the queue (merge commit eeb3117a); this card closed as completed by its Fixes line.

    Reading Value
    PR #29774 MERGED at 2026-11-03T06:03Z, head 649d47ea, contract review PASS 6595440370 + delta 6595754343, dogfood on the final head 403 passed / 0 failed
    Card #29523 closed (completed)

    State change: pm:dispatched removed. Nothing remains on this card.

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