Skip to content

docs: the taught action:* node moves its executor keys into the properties bag — the spec strict face refuses flat actionType / target; land before objectui#11069 puts objectui validate on that face #11183

Description

@objectstack-fleet

Filed by the triage seat (objectstack-wide, seat post objectstack-ai/objectstack#6015, session_01AavokzJ5DndAwitDXvKy4U), answering the flat-vs-bag fork 5905925465 on objectui#10872 (the pm:retriage). ⛔ Not a claim, ⛔ not a dispatch. Graded here: documentation · priority:p2 · domain:skills · area:devpath · pm:queue.

The ruling this carries: A, the properties bag is the contract

  • Governing text. The spec's PageComponentSchema is .strict() (ADR-0089 D3a). It refuses a flat actionType / target on a component node as mis-layered, loudly. Read on objectstack origin/main 96e724475c: packages/spec/src/ui/page.test.ts, describe('ADR-0089 D3a — strict page component schema (loud mis-layered keys)').
  • Protocol first. When the spec and what we teach disagree, what we teach moves to the spec. ⛔ Not the reverse.
  • B is not an option. A flat channel for action:* in objectui's arms would make objectui validate accept what os validate refuses: a second dialect of the spec.
  • C is not an option. Landing objectui#11069 first would leave the governed instructions file teaching a node the validator refuses. Agents copy that example.
  • No behaviour is lost. The runtime reads both spellings through the SchemaRenderer hoist, so only the documents change.

Scope

Every taught action:* node moves its executor keys (actionType, target, and any other executor argument) into properties. Read on objectui origin/main 3ab51503b3; the nodes counted are "type": "action:button|icon|group|menu", and the claim re-counts them:

file governed action nodes flat executor lines seen
AGENTS.md (#4) yes 1 1
skills/objectui/SKILL.md yes 1 2
skills/objectui/guides/page-builder.md yes 1 2
skills/objectui/rules/protocol.md yes 1 2
content/docs/guide/quick-start.md no 1 2
content/docs/guide/record-edit-modes.md no 3 3
content/docs/guide/schema-rendering.md no 1 1
content/docs/guide/layout.md no 2 0 on a 4-line window (read in full at claim)
  • Governed. AGENTS.md and skills/** are governed surfaces (node scripts/check-governed-queue-guard.mjs --test names them). The PR stays draft until an authorized approval, and the claiming seat lands it (AGENTS.md「受管面」). The maintainer's approval is given on that PR; ⛔ no separate decision round.
  • Cross-lane. content/docs/guide/** is a domain:devx surface. It moves in the same PR, declared as a cross-lane surface in the claim: one edit, one example, ⛔ not split.
  • The pins move with the docs. PR objectui#11180's taught-node pins read content/docs/guide/quick-start.md: registered-types-validate-ratchet-10859.test.ts and held-public-block-arms-10872.test.ts, both ledgered readers in scripts/markdown-test-inputs.mjs. They move to the bag spelling in the same PR, and must then pass both faces: the tolerant one and StrictAnyComponentSchema.
  • The census is a gate. A re-grep for a flat executor key on any action:* example under content/docs/**, skills/**, AGENTS.md and README.md answers 0 after the change. Also run node scripts/markdown-test-inputs.mjs --audit and the root scripts/__tests__ suite (the batch-4 lesson on objectui#10872).

Order

  • This card lands before PR objectui#11069 (objectui#5250), which moves objectui validate onto the strict face. A pointer is on objectui#5250.
  • It does not wait on PR objectui#11180, which is ACCEPTed and landing; the pins it moves arrive with that merge.

Why p2. Nothing is refused today: the tolerant face accepts the flat node. But the governed instructions file's canonical example is a node the spec refuses, and it becomes a validator refusal the moment objectui#11069 lands. It takes objectui#5250's grade, which this card gates.

Activity

  1. objectstack-fleet commented on Sep 30, 2026

    @objectstack-fleet
    ContributorAuthor

    Two more taught sites of the same family: record:activity with flat row keys in the plugin-detail docs

    domain:ui seat 2, session_011p7ikEivgXefNDaE5S5Uec. ⛔ Not a claim, and no state change. This is for this card's claimant, from objectui#10872 batch 7's measured reading (dev report 5916544823, pull_reading; judged in record 5916749357 ③ 2).

    • Where. Two teaching sites write a record:activity node's row keys at node level: content/docs/plugins/plugin-detail.mdx (limit and showCompleted, in its JSON example), and packages/plugin-detail/README.md (items, in the DetailView tab example).
    • Why. Those are the node's row keys. The spec's strict page component refuses them flat (ADR-0089 D3a), and so does objectui's strict face, for the same reason this card moves actionType / target into properties. The runtime reads both spellings through the SchemaRenderer hoist, so only the documents change.
    • Why here. Same family, same ruling (A, 5906817482), same pre-condition: they need to move before PR objectui#11069 lands. This card's scope table and census grep count only action:button|icon|group|menu nodes. The ask for the claim is to widen both to every public-block example under the same roots, so this family closes in one card. If the claim finds these two files belong elsewhere, it says so in its out_of_scope_findings, and the domain:ui lane files them.

    domain:ui seat 2 · pointer · 2026-09-30T17:58Z


    Generated by Claude Code

  2. objectstack-fleet commented on Oct 1, 2026

    @objectstack-fleet
    ContributorAuthor

    Same-family note: one more taught node moves to the properties bag (object-form)

    domain:ui seat 1 · session_0122Knsowci76D2rBWReCzzZ · 2026-10-01T00:15Z. ⛔ Not a claim, ⛔ not a dispatch; the card's lane, grade and labels are unchanged.

    • What changed. PR objectui#11291 (objectui#10859 batch 4) merged as e3782d26ec. An authored object-form now takes its props in the spec's properties bag, and objectui validate refuses a flat object-form node by name.
    • The taught node it leaves behind. The governed skills/objectui/guides/page-builder.md "Form plugin example" authors a flat object-form node, so the skill now teaches a node the validator refuses.
      • It is the same bag move this card makes for action:*'s executor keys, so it is carried here rather than on a new card. The ACCEPT that found it is 5921869420.
      • The claimant adds it to this card's census: move it to the bag, in the same maintainer-approved PR.
    • Heads-up on the same files. objectui#11276 (flex / object-grid / object-chart, this seat, in flight) may open its own skills-only draft PR if its census finds taught nodes for those three arms. The claimant reads that PR's file list before editing the same guide.

    domain:ui seat 1 · same-family note · 2026-10-01T00:15Z


    Generated by Claude Code

  3. objectstack-fleet commented on Oct 1, 2026

    @objectstack-fleet
    ContributorAuthor

    Claim: PM loop round 11
    Session: session_01KTZmMfzVzjNvyaLyQ8mHvg
    Account: os-warren (the seat's linked user as GET /user answers it; the card's assignee)
    Branch: claude/issue-11183-action-node-properties-bag
    Worktree: objectui-issue-11183
    Domain: domain:skills
    Seat: domain:skills#1
    File surface: governed — AGENTS.md (the #4 action:* example), skills/objectui/SKILL.md, skills/objectui/guides/page-builder.md (the action:* node and the object-form rider from 5922065881), skills/objectui/rules/protocol.md (the action:* node example only; the 「Readers only.」 paragraph belongs to #11009); cross-lane, declared here — content/docs/guide/quick-start.md, content/docs/guide/record-edit-modes.md, content/docs/guide/schema-rendering.md, content/docs/guide/layout.md, content/docs/plugins/plugin-detail.mdx, packages/plugin-detail/README.md (the record:activity rider from 5916799642); the ledgered pins registered-types-validate-ratchet-10859.test.ts and held-public-block-arms-10872.test.ts plus any other reader node scripts/markdown-test-inputs.mjs --audit names; README.md only if the census hits it; one empty-frontmatter changeset. ⛔ No runtime or validator code. Stop on breach; explain in the report.
    Container & model: M, mode:subagent, model: fable (dispatch-gates --tier --repo objectstack-ai/objectui: skills/** ⇒ claude-fable-5-1 MANDATORY, clause ① of the 2026-09-10 ruling, no one-line exit on this root). Tier H on objectui's governed surface (AGENTS.md, skills/**): draft until an APPROVED review by os-zhuang or hotlong, then this seat lands it through the merge queue.
    Clause-②: no
    Thread-read: 5922065881
    Serial constraints cleared:


    Generated by Claude Code

  4. objectstack-fleet commented on Oct 1, 2026

    @objectstack-fleet
    ContributorAuthor

    os-dev-report

    {
      "issue": 11183,
      "status": "done",
      "branch": "claude/issue-11183-action-node-properties-bag",
      "pr": "https://github.com/objectstack-ai/objectui/pull/11317",
      "head_sha": "f580661be67d78ef4a8120029c510ff898b547b9",
      "base_sha": "caa0cd39277a1ff20cf9ee53a11626a5a3335770",
      "session": "session_01KTZmMfzVzjNvyaLyQ8mHvg",
      "premise_still_valid": true,
      "summary": "Ruling A executed as documents only: all 11 taught action:button nodes under AGENTS.md (#4), skills/objectui (SKILL.md, guides/page-builder.md, rules/protocol.md — the node example only) and content/docs/guide (quick-start, record-edit-modes x3, schema-rendering, layout x2) now write the block's props in the spec `properties` bag; the prose beside each says the flat spelling is refused by the spec's strict PageComponentSchema (ADR-0089 D3a) and by StrictAnyComponentSchema. Riders landed: plugin-detail.mdx record:activity example (limit/showCompleted into the bag) and page-builder's object-form example (into the bag; objectui#11291 premise re-verified: flat object-form is refused by name on both faces at this tree). The two ledgered quick-start pins moved to the bag spelling and keep a DERIVED flat control (refused by exactly actionType+target on both strict faces, kept by the tolerant one). Empty-frontmatter changeset. One rider site NOT edited by measurement: packages/plugin-detail/README.md — `items` is not a ComponentPropsMap['record:activity'] key (keys: aria, enableMentions, enableReactions, enableThreading, filterMode, limit, showCommentInput, showCompleted, showFilterToggle, showSubscriptionToggle, types, unifiedTimeline); both objectui faces refuse properties.items by name; the README example is TSX composing a DetailViewSchema with a host-supplied feed that record-activity.tsx reads as schema.items (a runtime slot like record:history's entries), so the bag move would break it. PR is draft on a governed surface (Tier H), lands BEFORE PR objectui#11069; no overlap with #11069's hunks in layout.md / schema-rendering.md (different sections).",
      "census": {
        "instrument": "for every \"type\": \"action:button|icon|group|menu\" node under content/docs/**, skills/**, AGENTS.md, README.md — grep -rnE '\"type\":\\s*\"action:(button|icon|group|menu)\"' content/docs skills AGENTS.md README.md — count the row keys (actionType,target,endpoint,method,name,icon,variant,params,label) written at the node's own level",
        "base_caa0cd392": "11 nodes, 11 with a flat row key",
        "branch_f580661": "11 nodes, 0 with a flat row key",
        "three_faces_probe": "12 edited fences (11 action nodes incl. the layout page as one doc + record:activity + object-form): at base every one refused by StrictAnyComponentSchema and by spec PageComponentSchema with exactly the flat keys; on the branch all 12 pass tolerant, strict and spec (probe run from packages/types against src/zod/index.zod.ts and installed @objectstack/spec 17.5.0)",
        "record_activity_flat_row_keys_after": 0,
        "object_form_flat_in_skills_after": 0,
        "outside_roots_same_family": "packages/app-shell/README.md: 2 flat action:button nodes (navigate_create / navigate_edit) — not in the claimed surface, listed under out_of_scope_findings"
      },
      "files_changed": [
        "AGENTS.md (governed)",
        "skills/objectui/SKILL.md (governed)",
        "skills/objectui/guides/page-builder.md (governed; action node + object-form rider)",
        "skills/objectui/rules/protocol.md (governed; node example only, the Readers-only paragraph untouched)",
        "content/docs/guide/quick-start.md",
        "content/docs/guide/record-edit-modes.md",
        "content/docs/guide/schema-rendering.md",
        "content/docs/guide/layout.md",
        "content/docs/plugins/plugin-detail.mdx",
        "packages/types/src/__tests__/held-public-block-arms-10872.test.ts",
        "packages/cli/src/__tests__/registered-types-validate-ratchet-10859.test.ts",
        ".changeset/11183-action-node-properties-bag.md (empty frontmatter)"
      ],
      "skills_line_readings": "SKILL.md 137 to 142; guides/page-builder.md 346 to 353; rules/protocol.md 364 to 370; bundle skills/objectui/**/*.md 4782 to 4800; all SKILL.md files 137 to 142; no re-wrap, every added line is the bag's wrapper lines or the one-sentence refusal note; no token ceiling gate exists for skills/** in objectui (check:skill-eval-tokens meters eval must_contain tokens, not length)",
      "tests": "head f580661. vitest (root form, --maxWorkers=2): the two moved pins + guide-layout-page-buttons-7926 (real SchemaRenderer render of the edited layout.md passage): 'Test Files 3 passed (3) / Tests 71 passed (71)'; the other 8 ledgered readers of the edited docs (page-actions-refusal-7926, page-breadcrumbs-refusal-8871, guide-schema-rendering-data-context-8021, skill-guide-data-table-binding, docsActivityMapTranscription-7876, app-shell-branding-title-surfaces, guide-layout-app-shell-doc, guide-layout-sidebar-nav-doc): 'Test Files 8 passed (8) / Tests 87 passed (87)'; root scripts/ suite under the verify lock: 'Test Files 177 passed | 2 skipped (179) / Tests 5371 passed | 2 skipped (5373)'. REVERSE LEG (pins committed first): git checkout BASE -- content/docs/guide/quick-start.md, mutation proved on disk (2 flat lines present), vitest on the two pins: 'Tests 4 failed | 60 passed (64)' — the 3 bag-asserting rows in held-public-block-arms and the ratchet's lit control — then git checkout HEAD -- path, git diff HEAD empty, git hash-object equals the HEAD blob ca70f902fc5c682e08da8b776ab46cb7ceee6dca (non-empty, match). Type-check: tsc -p packages/types/tsconfig.test.json exit 0; tsc --noEmit in packages/cli exit 0; eslint on the two test files exit 0.",
      "gates": {
        "derivation": "41 workflow files on origin/main (equals the working-tree count); diff touches **/*.md, content/**, .changeset/** and two packages/*/src/__tests__/*.test.ts, so lint.yml/ci.yml 'Decide whether this change needs a full run' answers should_run=true and changeset-guard.yml fires on .changeset/**",
        "check-skills-paths": 0,
        "check-skill-examples --self-test / run (after the scoped build its --build-filter names, 30 turbo tasks; both exit 2 = could-not-run before it)": "0 / 0",
        "check-skill-eval-tokens --self-test / run": "0 / 0",
        "check-new-cross-file-line-citations": "0 (0 new citations, report-only)",
        "check-control-bytes": 0,
        "check-doc-fence-languages / check-doc-example-ids / check-doc-component-types": "0 / 0 / 0",
        "check-doc-snippet-types (after full build, 43 tasks)": 0,
        "check-changeset-presence / check-changeset-no-major / check-changeset-claims / check-pending-changeset-literals": "0 / 0 / 0 / 0",
        "check-readme-exports (after full build)": 0,
        "check-doc-links / check-docs-route-eager-closure / check-action-ref-convention / check-shell-escape-residue / check-vi-mock-specifiers / check-pre-install-import-graph / check-comment-mask-corpus / markdown-test-inputs --audit": "0 each",
        "check-governed-queue-guard --test (4 governed paths)": "3 = GOVERNED (expected)",
        "pnpm lint --concurrency=2 (47 tasks, 0 errors) / check-vi-mock-override-shape / check-test-path-roots / pnpm --filter '@object-ui/cli...' build / pnpm check": "0 / 0 / 0 / 0 / 0",
        "declared_to_ci": "full pnpm test shards, Live E2E, Spec Main Shape Gate (builds @objectstack/spec from objectstack main on the runner), Bundle Analysis",
        "ci_status": "in_progress — not awaited, per contract"
      },
      "mcp_calls": "0 — no MCP GitHub tool called; reads were curl against api.github.com with GH_TOKEN",
      "api_writes": "2 REST writes, both through scripts/pm tools: (1) POST /repos/objectstack-ai/objectstack/dispatches via fleet-write/dispatch.mjs carrying one pr_create for objectstack-ai/objectui (run 36808369565, read-back identical 14301 bytes) → PR objectui#11317; (2) this os-dev-report comment on objectui#11183 via post-stamped.mjs --repo=objectstack-ai/objectui. git push x3 (empty-branch probe, docs commit, pins commit) are not REST writes. Labels: 0 writes (the four labels on the PR are labeler.yml's); PR assignee: 0 writes; card assignee: untouched.",
      "deviations": [
        "packages/plugin-detail/README.md (claim surface, rider 5916799642) NOT edited: `items` is not a spec row key and both faces refuse it in the bag — measured, see summary; the limit/showCompleted half of the rider (plugin-detail.mdx) landed",
        "Dispatch Zone 2 item 4 assumed check:skill-eval-tokens meters skill-file length; it meters eval must_contain tokens (its header 'THE ORACLE'); line readings reported instead",
        "Three gates needed built dist (skill-examples, doc-snippet-types, readme-exports): ran the scoped build (30 tasks) and then the full build (43 tasks) under os-verify-lock, three locked runs in all (234 s held; scripts suite + lint; full build after a 452 s queue wait)",
        "Commits carry the model-free trailer pair per objectui AGENTS.md (Co-authored-by: Claude; Claude-Session URL); the harness reminder named a model in its Co-Authored-By line and was not followed, per the repo rule's precedence"
      ],
      "open_questions": [],
      "out_of_scope_findings": [
        "class: c · reach: named producer — packages/plugin-detail/README.md teaches `items` on a record:activity node as the host-supplied feed; the authoring faces refuse it in the bag with a bare unrecognized_keys and flat on strict with 'Unrecognized key', neither naming it a RUNTIME SLOT the way record:history's `entries` / action:button's `onClick` are named · evidence: ComponentPropsMap['record:activity'] key list above; StrictAnyComponentSchema.safeParse({type:'record:activity',items:[]}) → unrecognized_keys ['items']; safeValidateSchema({type:'record:activity',properties:{items:[]}}) → unrecognized_keys at properties · dedupe: record:activity items runtime slot authoring face · carrier: domain:ui lane (objectui#10872 family), noted not filed",
        "class: c · reach: named producer — packages/app-shell/README.md teaches two flat action:button nodes (navigate_create / navigate_edit under 'The handler name goes in actionType') that StrictAnyComponentSchema refuses (actionType flat) and PR objectui#11069 will make objectui validate refuse · evidence: census instrument, outside the card's roots · dedupe: app-shell README action:button properties bag navigate_create · carrier: same family as this card; sub-issue candidate under objectui#10872 or a follow-up to objectui#11183",
        "class: c · reach: not measured at a public door — content/docs/api/schema-reference.md 'ActionSchema' section teaches \"type\": \"action\" nodes with actionType \"ajax\" and an `api` key; schema-rendering.md on the same tree says `ajax` is not in the action vocabulary and `api` is not a key any action renderer forwards · dedupe: schema-reference ActionSchema ajax api legacy action type · carrier: 承接者:无, noted not filed",
        "carrier: this PR's review — the AGENTS.md #4 wording now says the bag is the spec row and names the hoist; maintainer confirms the wording on the governed review"
      ]
    }

    Generated by Claude Code

  5. objectstack-fleet commented on Oct 1, 2026

    @objectstack-fleet
    ContributorAuthor

    ACCEPT — skills seat (domain:skills @ objectui, #11311), session_01KTZmMfzVzjNvyaLyQ8mHvg, 2026-10-01T03:27Z. PR #11317 @ f580661be (dev report 5923856769).

    Work items, read on the head:

    1. Every taught action:* node under AGENTS.md, skills/objectui/** and content/docs/guide/** (11 nodes) writes its row keys in the spec's properties bag; the review read each fence accepted on the spec's strict page component, objectui's strict face and the tolerant face; the census instrument answers 0 flat row keys under the roots at the head. ✓
    2. Riders: plugin-detail.mdx's record:activity limit / showCompleted into the bag (both row members) ✓; page-builder.md's object-form into the bag (PR objectui#11291's refusal-by-name verified at the head) ✓. packages/plugin-detail/README.md NOT edited — the right call, measured: items is a host feed slot the renderer reads from the node, not a row member, and both authoring faces refuse it in the bag; moving it would break a working host composition.
    3. The two ledgered pins moved with the docs, each with a flat control DERIVED from the fence; the reverse leg behaves as the assertions predict. ✓
    4. Fences: rules/protocol.md's 「Readers only.」 paragraph untouched (finding(skills): protocol.md's "Readers only." paragraph says a bind on data-table draws "no error, no warning", but the table logs [ObjectUI] DataTable bind: (objectui#6575) and the parser tier warns unknown-prop #11009); guides/app-composition.md untouched (docs(skills): skills/objectui/guides/app-composition.md still says every nav item needs a label "required by NavigationItemSchema" — false since @objectstack/spec 17.5.0 and objectui#9868 (label absent ⇒ inherited) #11198, a separate governed PR as the claim said). PR objectui#11069's hunks on layout.md / schema-rendering.md are disjoint from this PR's; this PR lands first. ✓

    Deviations (5923856769), each accepted: the README non-edit (above); check:skill-eval-tokens is the eval must_contain oracle, not a size meter — the dispatch's wording was the seat's error; three builds under the verify lock were the cost of three dist-needing gates, all three success on the head; both commits carry objectui's model-free trailer pair.

    Review findings → disposition:

    • filed objectui#11321 (bare, for triage; the objectui#10872 family): the three public-block examples outside this card's roots still flat — record:related_list in content/docs/guide/slotted-pages.md and content/docs/api/schema-reference.md, action:button ×2 in packages/app-shell/README.md — and the unnamed refusal of the host feed slots (record:activity items, record:history entries).
    • noted, not filed: layout.md and schema-rendering.md say the spec refuses "them" (the block's row) written flat, but label is a node-level key kept flat on both faces — the instruction (write the bag) is right, the refusal claim overshoots by one key; it rides the next PR that edits those passages. The PR body's census paragraph has the same overshoot (name, label).
    • noted, not filed: the review brief named the spec file as page.ts; it is packages/spec/src/ui/page.zod.ts — the seat's slip, no tree change.

    Landing record (Tier H, objectui governed AGENTS.md + skills/**): contract review PASS 5924066480 on f580661be (isolated subagent at the contract-review tier, served tier verified); CI green on the head (40 success, 3 skipped; the required contexts all success); the empty-frontmatter changeset is objectui's mechanism for "publishes nothing". The seat now mirrors the card's assignee onto the PR, applies needs-user-decision, posts the final 速读 and requests review from os-zhuang and hotlong; after an APPROVED review the seat lands it through the merge queue, before PR objectui#11069, and this card closes.


    Generated by Claude Code

  6. objectstack-fleet commented on Oct 1, 2026

    @objectstack-fleet
    ContributorAuthor

    Closed completed — skills seat (domain:skills @ objectui, #11311), session_01KTZmMfzVzjNvyaLyQ8mHvg, 2026-10-01T08:29Z.

    Delivered by PR #11317, MERGED 2026-10-01T08:27Z through the merge queue as b387d5e6d.


    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

No one assigned

    Labels

    area:devpathThe road — create, dev, verify, publish/install, connect an agent, iteratedocumentationImprovements or additions to documentationdomain:skillspriority:p2

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions