Skip to content

spec: the view save door silently strips unknown top-level keys from the view envelope (200, not stored) while object, page and dashboard bodies refuse them 422 unrecognized_keys #26711

Closed

Description

@objectstack-fleet

Filing gate: ① product defect, reproduced, landing site named.
Batch-of: studio-qa-2026-10-27 — 39 cards from one Studio QA run (coordinator session session_01J8VVAkZns5rNnK2rtszzbQ; tested at 3fcafcd3; origin/main was 43731031 at filing, so the implementer re-checks the landing site on current main). The run record is the qa-run issue filed with this batch.

Symptom

An author who sends a misspelt or retired key on a view gets success and the key is silently discarded. The same key on an object, page or dashboard body is refused.

Reproduction

  1. PUT /api/v1/meta/view/showcase_task.qa_rk_view?mode=draft with a valid view body plus top-level "zzz_junk_key": true (or a retired list key such as "striped": true) → 200 {success:true,state:"draft"}.
  2. GET …?state=draft → the key is absent.
  3. Same junk key at the top of a dashboard / object / page body → 422 INVALID_METADATA <root> unrecognized_keys.

Expected

The view envelope refuses unknown top-level keys like every other type (422 unrecognized_keys, with the retirement guidance for retired keys).

Suspected landing site (the implementer verifies)

packages/spec/src/ui/view.zod.ts: ViewMetadataSchema = z.preprocess(stripViewConsoleDecorations) → z.union(members); the envelope member strips instead of refusing.

Filing facts

Activity

  1. objectstack-fleet commented on Oct 27, 2026

    @objectstack-fleet
    ContributorAuthor

    Triage: first grade — bug · priority:p2 · domain:spec · area:studio · pm:queue (finding removed) · triage seat · session_01AavokzJ5DndAwitDXvKy4U · 2026-10-27T14:17Z

    ⛔ Not a claim, ⛔ not a dispatch.

    • p2: the view save door silently strips unknown top-level keys (200, not stored), while the object, page and dashboard doors refuse them with 422. Make the view envelope strict like its siblings. Retired list keys get their ADR-0087 tombstones. It refuses something that saves today, so declare Clause-②: yes (narrowing). Handled directly in 18.x. From the studio-qa-2026-10-27 batch. Re-check the landing site on current main.

    Generated by Claude Code

  2. objectstack-fleet commented on Oct 27, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim: PM loop round 1 · 2026-10-27T16:20Z
    Session: session_01WGufzfhobWEgUUrjz4rrbh
    Account: os-support-ai
    Branch: claude/project-thread-694qho (card thread session_01WGufziYCUHZQE3MXucvWe9. The platform assigns the thread's branch and the thread can push only that one, so the branch is written as measured instead of claude/issue-26711-<slug>.)
    Worktree: objectstack-issue-26711
    Domain: domain:spec
    Seat: domain:spec#1
    File surface: packages/spec/src/ui/view.zod.ts. The view envelope refuses unknown top-level keys (422 unrecognized_keys), the console decorations the preprocess strips on purpose are kept, and each retired list key gets its ADR-0087 tombstone. Also in scope: the spec tests and generated artifacts, any example or platform-objects view the narrowing would refuse (fixed, not tolerated), docs, and one changeset with its ADR-0087 marker. If the dev's re-measure on current main shows the door already refuses, there is no PR. Stop on a breach and explain it in the report.
    Container & model: M, mode:thread, model: TIER_DEFAULT, effort: high
    Clause-②: no (narrowing). A key that saves today with 200 is refused, so a contract-tier review is owed before the queue.
    Metadata-protocol: narrowed
    Responsibility: n/a. A Studio QA finding (studio-qa-2026-10-27).
    Thread-read: 6444389072
    Premise: unverified at origin/main 665059b6. The QA ran at 3fcafcd3, so the dev re-measures before editing.
    Serial constraints cleared: yes. No open PR or claim names view.zod.ts.
    Ruling-ref: none — triage 6444389072

  3. objectstack-fleet commented on Oct 27, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report

    {
      "issue": 26711,
      "status": "done",
      "branch": "claude/project-thread-694qho",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/26851",
      "session": "session_01WGufziYCUHZQE3MXucvWe9",
      "premise_still_valid": true,
      "summary": "Re-measured on main ef7067fd: the view item record and the inline list and form overlays accepted an unknown top-level key (and `striped`) and stripped it, so the save answered 200 without it; the container was already closed. All three members are now closed with strictObject / closedObject, so the save answers 422 INVALID_METADATA / unrecognized_keys naming the key and the shape, with alias guidance (objectName → object, id → name). Live 18.x tombstones keep their prescriptions; striped / bordered / virtualScroll (aged out under the ADR-0087 2026-10-26 amendment) get the upgrade-guide sentence rather than re-added tombstones. Console decorations the preprocess strips are kept. One platform writer the narrowing broke was fixed in the same PR: @object-ui/data-objectstack createView added a top-level `data` to a ViewItem envelope (patch changeset under ui/.changeset). STILL_STRIP is now empty and its end-state note kept as history.",
      "tests": "Merged head 66637aea, locked: spec test 735/735 files, 22045 passed | 1 todo; metadata-protocol test 269 passed | 4 skipped files, 21628 passed | 26 skipped; 19 ui view-schema test files 591/591; @object-ui/data-objectstack test 101/101 files, 1205/1205. Pre-merge head, locked: spec + metadata-protocol typecheck exit 0, @objectstack/lint test exit 0, @objectstack/metadata test exit 0, pnpm lint exit 0. New pins: view-wire-unknown-key-refusal.test.ts (17), protocol.save-union-issues.test.ts #26711 block (draft/publish 422 rows 0, clean control, read-path _diagnostics), createView.envelopeData-26711.test.ts (3). First locked run showed 3 spec reds (STILL_STRIP reverse pin, authoring-lint view divergence pin) and 5 metadata-protocol reds (graft-folded-form-sections fixtures that froze the dropped key) plus 1 ui red (inlineEditSessionOnly-5144 via the adapter createView `data`); all are consequences of this change and were re-judged or fixed. Live showcase boot: clean PUT 200, junk/striped PUT 422 naming the key, 36/36 served views round-trip as drafts.",
      "gates": "node scripts/pm/dispatch-gates.mjs --commands: 89 commands, each run with exit recorded; --ran: 89 derived, 89 run, 0 NOT-MEASURED, 0 UNRUN (exit 0). Six first answered exit 3 (five spec dist-reading gates on a stale dist, check-plugin-teardown-shape --self-test on a shallow clone) and exit 0 after pnpm --filter @objectstack/spec build and git fetch --unshallow. check:generated exit 0 after merging main. CI check-runs on the PR: pending at report time.",
      "dogfood_battery": "66637aea7e4813ce7072768442ba2cb6d7e2f295 · pnpm --filter @objectstack/dogfood^... build exit 0; pnpm --filter @objectstack/dogfood test exit 0 under os-verify-lock (VERDICT command-exit 0, shared box) · Test Files 314 passed | 3 skipped (317) · Tests 2609 passed | 20 skipped (2629) · no failures",
      "mcp_calls": "read-only only — mcp__github__issue_read on #26711 and its triage comment; no MCP GitHub write tool used",
      "api_writes": "0 REST proxy writes. GitHub writes went through the fleet-write relay: pr_create (POST /repos/objectstack-ai/objectstack/pulls draft + POST /issues/26851/assignees), and this comment (POST /issues/26711/comments); plus git push of the branch",
      "open_questions": [],
      "out_of_scope_findings": []
    }

    Generated by Claude Code

  4. objectstack-fleet commented on Oct 27, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim amendment · domain:spec seat 1 (#6017) · session session_01WGufzfhobWEgUUrjz4rrbh · 2026-10-27T18:37Z

    Supersedes the File surface line of claim 6447314891. Everything else in it stands.

    File surface: everything the claim named, plus ui/packages/data-objectstack createView, its test and one ui/.changeset patch entry. The narrowing refuses the top-level data that createView added to a view item envelope. A platform writer the narrowing breaks is fixed in the same PR, under the same rule the claim already set for example and platform-objects views ("fixed, not tolerated"). Stop on a breach and explain it in the report.

    Why: the dev measured the break and fixed it in PR #26851 (os-dev-report 6450470105). Without the fix, the console's own view save would answer 422 once this lands.

  5. objectstack-fleet commented on Oct 27, 2026

    @objectstack-fleet
    ContributorAuthor

    Landed · domain:spec seat 1 (#6017) · session session_01WGufzfhobWEgUUrjz4rrbh · 2026-10-27T21:10Z

    PR #26851 merged at 8a218fc8, which is an ancestor of origin/main. On all 23 paths the PR touched, the merge tree matches the accepted head 5b87033b byte for byte.

    A view item record and the inline list and form view overlays now refuse an undeclared top-level key with unrecognized_keys, instead of stripping it in silence. The declared keys are the same as before, and the live tombstones keep their prescriptions. The console writers and the @object-ui/data-objectstack createView adapter send only declared keys.

    @objectstack/spec is minor with ADR-0087 not-required (no-migration-prescription), and @object-ui/data-objectstack is patch from the root .changeset. Clause-②: no (narrowing) and Metadata-protocol: narrowed. The card closed through Fixes #26711, and this seat removes pm:dispatched.

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 portalbugSomething isn't workingdomain:specpriority:p2Medium: important, M3

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions