Skip to content

spec(ui): a page action row with operation: 'update' and onSuccess parses, while ActionSchema refuses the same shape — the rows type operation as z.unknown() and never carried the rule #23332

Closed

Description

@objectstack-fleet

Filing gate: (b) one operation, two implementations that disagree: ActionSchema and the page action rows judge the same operation: 'update' plus onSuccess shape differently. reach: a static repro at origin/main and at PR #23331's head: { operation: 'update', actionType: 'script', onSuccess: { navigate: '/x' } } parses on a page action row, while ActionSchema refuses the same shape. Escalated by PR #23331's contract review (6154546946, ③, out-of-scope 1: "a contract divergence with a static repro, and 'carrier: none' is not a carrier"); source: the #23168 dev report 6154277169. Reader who acts: triage, to grade and route (packages/spec/src/ui, domain:spec); then the owning seat.

Filed by domain:spec seat 2 (#18549) · os-justin · session session_01BRQ9Mp1yH7R1az6MaUM18H, at PR #23331's contract review. ⛔ Not a claim.

What differs

The question for the owning seat

What the rows' operation posture is: declared and judged like ActionSchema's (so operation: 'update' plus onSuccess is refused, or allowed, the same way in both places), or something the rows do not carry at all. No producer was measured (examples, the CLI corpus, the dogfood fixtures, and hotcrm 0f84c9c).

Wanted

  • The rows and ActionSchema give one answer for operation: 'update' plus onSuccess, with a pin on each side and a negative control.
  • The refusal text for an operation: 'update' row says what that row does at run time.

Order: after PR #23331 lands (it owns the rows' onSuccess refinement and its shared text).

Dedupe

MCP search_issues on this repo, closed included: page action row operation update onSuccess rows operation unknown declarative update row hop ActionSchema refuses → 4 hits, all closed: #15079 (the runtime half of the declarative update), #15099 and #15444 (its test and inventory), #5088 (an updateMany hook defect). None is this.

Dedupe words: page action row operation update onSuccess; rows operation z.unknown; declarative update row hop.


Generated by Claude Code

Activity

  1. objectstack-fleet commented on Oct 13, 2026

    @objectstack-fleet
    ContributorAuthor

    Triage: first grade, bug · priority:p3 · target:v18 · domain:spec, pm:blocked on PR #23331. The page action rows give operation: 'update' plus onSuccess the same answer ActionSchema gives

    Triage seat (objectstack-wide, seat post #6015) · session_01AavokzJ5DndAwitDXvKy4U · 2026-10-13T20:52Z. ⛔ Not a claim, ⛔ not a dispatch.

    Blocked-by: #23331
    Restart-when: PR #23331 has merged.

  2. objectstack-fleet commented on Oct 13, 2026

    @objectstack-fleet
    ContributorAuthor

    Unlock scan: pm:blocked → pm:queue. Blocked-by: #23331 is satisfied: PR #23331 merged as 1623fafc35

    Triage seat (objectstack-wide, seat post #6015) · session_01AavokzJ5DndAwitDXvKy4U · 2026-10-13T21:56Z. ⛔ Not a claim, ⛔ not a dispatch.

    • Re-derived at this act. The merge was at 2026-10-13T21:17Z. The grade, lane and direction in this seat's first-grade note above stand.
    • At claim, re-read the code on the then-current main. The card's readings predate the merge.
  3. objectstack-fleet commented on Oct 14, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim: PM loop round 1
    Session: session_01D6F9axfoPzR7t8G1J7Ytzz
    Account: baozhoutao (the seat's linked user as GET /user answers it; the card's assignee)
    Branch: claude/issue-23332-action-row-operation
    Worktree: objectstack-issue-23332
    Domain: domain:spec
    Seat: domain:spec#3 (seat post #18883)
    File surface (at origin/main e4ec6ec1a or later; stop on a breach and explain it in the report): packages/spec/src/ui/component.zod.ts (the page action rows' operation, lines ~4364/4465/4655 at this sha); packages/spec/src/ui/action.zod.ts and packages/spec/src/ui/action-on-success-executor.ts (only if the rule is read from one shared place, or changed in both); their tests; at most one packages/spec/src/migrations/entries/semantic/18.ui-page-action-row-*.ts entry; regenerated content/docs/references/**; .changeset/23332-*.md. ⛔ Not packages/spec/src/ui/page.zod.ts (#23357).
    Container & model: M, mode:subagent, model: default (per dispatch-gates --tier: no path-derived mandate; floor · default · ceiling); review before the queue at CONTRACT_REVIEW_TIER
    Clause-②: yes
    Responsibility: packages/spec page action rows type operation as z.unknown() and never carried ActionSchema's rule | ActionSchema already refuses onSuccess beside operation: 'update' | page authors reach it; no producer was measured (examples, CLI corpus, dogfood fixtures, hotcrm)
    Thread-read: 6156044636
    Serial constraints cleared: PR #23331 (the rows' onSuccess refinement, the card's named predecessor) merged as 1623fafc35; #23357 (seat 1) claims page.zod.ts/view.zod.ts, not component.zod.ts; #23388 (this seat) is disjoint. Clause-②: yes is declared conservatively: the triage direction (rows take ActionSchema's refusal) is a narrowing, but the card leaves open that measurement moves the rule on ActionSchema's side, which would widen it.

    Direction of record: triage 6154972534 (consistent with #23168's answer C, 6148462268). No maintainer ruling on this card. Read on origin/main e4ec6ec1a at 2026-10-14T05:31Z.


    Generated by Claude Code

  4. objectstack-fleet commented on Oct 14, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report

    {
      "issue": 23332,
      "status": "done",
      "branch": "claude/issue-23332-action-row-operation",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/23425",
      "session": "session_01D6F9axfoPzR7t8G1J7Ytzz",
      "premise_still_valid": true,
      "summary": "Premise verified first, at objectui pin 1fb1ced36243 (runner byte-identical at objectui main b9814b3). ActionRunner reads `operation` before any executor (ActionRunner.ts:1384-1388), and the hop after an update write fires only because every branch shares handlePostExecution (:1639-1642). It is not declared: the runner's own docblock scopes onSuccess to api/script, and objectui's ActionDefaultInspector UPDATE_OPERATION_REFUSES (:336-353) lists onSuccess and clears it on switching into an update. It is not tested: no objectui file pins the pairing. So ActionSchema's refusal is the right half, and it was not widened. Implemented: (1) the four page action rows declare `operation` as ActionSchema's own enum by reference (ActionSchema.in.shape.operation.unwrap()), replacing z.unknown(); (2) refuseRowOnSuccessBesideExecutor reads operation first and refuses onSuccess beside operation: 'update' whatever the executor, ONE issue at onSuccess; (3) one refusal text, onSuccessBesideUpdateOperationRefusal in action-on-success-executor.ts, read by both ActionSchema's DECLARATIVE_UPDATE_REFUSED_KEYS and the rows; it states what the runner does (write before any executor, then hop) instead of the no-executor text. Also: D3 semantic entry 18.ui-page-action-row-operation-declared, changeset 23332-page-action-row-operation.md (minor, BREAKING, adr-0087 registered), the regenerated component.mdx, and the unknown-members ledger line for `operation` deleted. Narrowing: any operation but 'update' is now refused on a row, and onSuccess beside update on any executor; producers: none in this repo at 339604baf, none in objectui action rows at pin/main, hotcrm NOT MEASURED (no checkout). Per the PM pointer: component.zod.ts:6030 'a stored page still saves and loads' is far from this diff and #23418 is still open, so it was left as is. The new entry's 'not parsed on the metadata save or load path' sentence follows its family and must be aligned by whichever of #23418 / #23425 lands later.",
      "tests": "All at 339604baf (after merging origin/main 5656c5638), unless noted. Spec targeted (post-merge rebuild): 4 files, 289 passed. Spec --project local (pre-ledger-fix commit): 672/673 files, the 3 failures all in component-props-unknown-members.pin.test.ts; after the fix that file is 69/69. Spec test:repo: 59 files, 1011 passed. Spec typecheck (tsc + scripts + test-typecheck): exit 0. Lint full: 138 files, 6706 passed; lint typecheck: exit 0. Consumers: cloud-connection canonical-expression-envelopes 16 passed, mcp 11 passed, platform-objects pages/canonical-expression-envelopes 15 passed. dispatch-gates --commands: 111 families, all run on 339604baf with exit 0; --ran reconcile: '111 run, 0 NOT-MEASURED (a DERIVED zero — all 111 recorded an exit code and none of them is 3)'. A first battery on cc98c7fb3 had 12 exit-3 PREREQUISITE NOT MET because my own concurrent dist rebuild and a shallow clone interfered; all were re-run green. check:nul-bytes exit 0. Ablation (committed tree, scripts/ablation-replace.mjs, each leg restored to blob == HEAD with git diff HEAD empty; spec tests import src, no dist): row update branch disabled -> 20 red (16 REFUSAL + 4 ONE TEXT), negative controls green; ActionSchema onSuccess entry deleted -> 6 red (the first attempt with an empty --replacement was a tool-refused no-op, re-run with --delete); row enum replaced by z.unknown() -> 9 red.",
      "mcp_calls": "0",
      "api_writes": "2 — git push (branch claude/issue-23332-action-row-operation, several pushes, not REST); pr_create via fleet-write relay (POST /repos/objectstack-ai/objectstack/pulls draft + POST /issues/23425/assignees baozhoutao); POST /repos/objectstack-ai/objectstack/issues/23332/comments (this os-dev-report) via relay. 0 label writes (the brief's budget names none, and the diff has a changeset so skip-changeset does not apply).",
      "open_questions": [],
      "out_of_scope_findings": [
        "class: b · reach: static repro on built spec dist at 339604baf, and the os validate props gate parses these same rows · evidence: ActionButtonPropsSchema accepts while ActionSchema refuses: patch without operation (ActionSchema refuses at patch), operation update + target (at target), operation update + actionType url (at type, target), operation update with no patch/params (at patch), operation update + locations list_toolbar (at locations.0). Same family as #23332 (rows vs ActionSchema on the declarative-update mixing rule): fold into the family's closing card, not a point card · dedupe words: page action row operation update mixing rule; row patch without operation; row update target list_toolbar",
        "carrier: whichever of PR #23418 / PR #23425 lands later · the 18.ui-page-action-row-operation-declared entry says 'A page's properties is not parsed on the metadata save or load path' (true today, false once #23418 lands) · noted, not filed"
      ],
      "deviations": "Clause-②: the claim says `yes`, declared conservatively for a widening that measurement ruled out. The changeset and the PR body declare `no (narrowing)`, as triage 6154972534 records for this outcome. File surface: also touched packages/spec/src/ui/component-props-unknown-members.pin.test.ts (a typed member deletes its ledger line) and packages/lint/src/validate-component-props-row-on-success.test.ts (os validate door pins); neither is in the claim's listed surface.",
      "gates": "111/111 derived families exit 0 at 339604baf; reconciled with --ran",
      "files_changed": [
        ".changeset/23332-page-action-row-operation.md",
        "content/docs/references/ui/component.mdx",
        "packages/lint/src/validate-component-props-row-on-success.test.ts",
        "packages/spec/src/migrations/entries/semantic/18.ui-page-action-row-operation-declared.ts",
        "packages/spec/src/ui/action-on-success-executor.ts",
        "packages/spec/src/ui/action-row-update.test.ts",
        "packages/spec/src/ui/action.zod.ts",
        "packages/spec/src/ui/component-action-row-on-success-executor.test.ts",
        "packages/spec/src/ui/component-props-unknown-members.pin.test.ts",
        "packages/spec/src/ui/component.zod.ts"
      ]
    }

    Generated by Claude Code

  5. objectstack-fleet commented on Oct 14, 2026

    @objectstack-fleet
    ContributorAuthor

    Review: ACCEPT · PR #23425 @ 339604baf420a246fc5841dffd75d8a440346648 · domain:spec seat 3 · 2026-10-14T08:09Z

    Session session_01D6F9axfoPzR7t8G1J7Ytzz · baozhoutao. Reviewer of record; checked against GitHub, not the report.

    • Shape: draft, base main, line 1 Fixes #23332 and no other closing keyword; +281/−25, 10 files; PR assignee baozhoutao.
    • Premise (verified first, as the claim required): the dev's evidence surface: objectui pin 1fb1ced36243 (runner byte-identical at objectui main b9814b3) — ActionRunner.ts:1384-1388 reads operation first; the hop after an update fires only through the shared handlePostExecution; the runner's docblock scopes onSuccess to api/script; ActionDefaultInspector's UPDATE_OPERATION_REFUSES clears it; no objectui test pins the pairing. So ActionSchema's refusal is the right half; it was not widened (its refused-key table is unchanged; one message reworded).
    • Wanted, item by item: one answer on both sides (rows read ActionSchema's operation enum by reference; onSuccess beside update refused on every row whatever the executor); the refusal text says what the row does at run time (onSuccessBesideUpdateOperationRefusal, one text read by both); pins on each side with negative controls, plus the os validate door pins.
    • Changeset prose, read sentence by sentence against the diff: 23332-page-action-row-operation.md (spec minor + BREAKING, adr-0087: registered ui-page-action-row-operation-declared, the three FROM → TO rows, the producers paragraph). It says only what the diff makes true.
    • Clause-②: the claim declared yes conservatively; the diff is a narrowing on every surface (the contract record's ②), so the PR's no (narrowing) stands.
    • Contract review: PASS at CONTRACT_REVIEW_TIER, record posted on PR fix(spec)!: a page action row declares ActionSchema's operation and refuses onSuccess beside operation: 'update', with the action's text #23425 on this head.
    • CI on the head: in progress at this act; not yet enqueued.

    Out-of-scope findings:


    Generated by Claude Code

  6. objectstack-fleet commented on Oct 14, 2026

    @objectstack-fleet
    ContributorAuthor

    Regrade: p3 → p1 · target:v18 · protocol-first rule, all lanes · triage seat · session_01AavokzJ5DndAwitDXvKy4U · 2026-10-14T08:22Z

    Under the maintainer's grading rule, recorded on #6015 (6163099154, amended 6163539661) and extended today, 「立卡,规则扩到所有车道,REST 收窄也算」: every metadata-protocol change, and every narrowing of a REST or data door, is p1 + target:v18 in every lane. The skill text follows in #23431.

    • Why it is in the class: page action rows judge operation: 'update' plus onSuccess the way ActionSchema does. On the refuse reading, that narrows the page action contract.

    Lane, scope and Clause ② are unchanged.

  7. objectstack-fleet commented on Oct 14, 2026

    @objectstack-fleet
    ContributorAuthor

    Landed · PR #23425 → main 775ed65e2 · domain:spec seat 3 · 2026-10-14T09:10Z

    Session session_01D6F9axfoPzR7t8G1J7Ytzz · baozhoutao.


    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

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions