You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
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
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/main96e724475c: 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/main3ab51503b3; the nodes counted are "type": "action:button|icon|group|menu", and the claim re-counts them:
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.
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.
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.
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 #4action:* 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:
Last touches on objectui origin/main: page-builder.md45dbf1c (09-28), AGENTS.mda097316 (09-28), quick-start.md2acd8e1 (09-19), record-edit-modes.mdf61dab1 (09-30), schema-rendering.md5c94589 (09-28), layout.md3cc4fe5 (09-30), plugin-detail.mdx1263e40 (09-30), plugin-detail/README.md741864f (09-30). PR objectui#11291 (object-form in the bag) is MERGED as e3782d26ec, so the rider's premise holds.
{
"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"
]
}
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. ✓
Riders: plugin-detail.mdx's record:activitylimit / 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.
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. ✓
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:activityitems, record:historyentries).
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.
Delivered by PR #11317, MERGED 2026-10-01T08:27Z through the merge queue as b387d5e6d.
Content on main: every taught action:* node under AGENTS.md, skills/objectui/** and content/docs/guide/** (11 nodes) writes its executor keys in the spec's properties bag, with the prose beside each naming who refuses the flat spelling (the spec's strict page component, objectui's strict authoring face); the two same-family riders landed (plugin-detail.mdx's record:activity row keys, page-builder.md's object-form example); the two ledgered pins moved to the bag spelling with a derived flat control. packages/plugin-detail/README.md was left as measured (items is a host feed slot, not a row key). Landed before PR objectui#11069, as the card ordered.
Landing record: Tier H (AGENTS.md + skills/**). Contract review PASS 5924066480 on f580661be (contract-review tier); ACCEPT 5924123994; 速读 5924129531; APPROVED review by os-zhuang (05:34Z), who flipped it ready and armed auto-merge. The queue removed it once (05:46Z) on Spec Main Shape Gate; the seat's reading 5927274924: the branch's base lacked objectui main's own fix 47e3ce00 (PR fix(types,runner): the retired-key pins and the runner sidebar compile against both the pinned spec and objectstack main (objectui#11330) #11343) for exactly the five files the gate named, so the seat merged main in through the update-branch route (head 31d85dc96, no diff change); green, re-queued 08:12Z, merged 08:27Z.
Noted, not filed: layout.md / schema-rendering.md say the spec refuses "them" (the block's row) written flat, but a flat label is kept on both faces — rides the next PR that edits those passages.
Activity
objectstack-fleet commentedon Sep 30, 2026
Two more taught sites of the same family:
record:activitywith flat row keys in the plugin-detail docsdomain:uiseat 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 report5916544823,pull_reading; judged in record5916749357③ 2).record:activitynode's row keys at node level:content/docs/plugins/plugin-detail.mdx(limitandshowCompleted, in its JSON example), andpackages/plugin-detail/README.md(items, in theDetailViewtab example).actionType/targetintoproperties. The runtime reads both spellings through theSchemaRendererhoist, so only the documents change.5906817482), same pre-condition: they need to move before PR objectui#11069 lands. This card's scope table and census grep count onlyaction:button|icon|group|menunodes. 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 itsout_of_scope_findings, and thedomain:uilane files them.domain:uiseat 2 · pointer · 2026-09-30T17:58ZGenerated by Claude Code
objectstack-fleet commentedon Oct 1, 2026
Same-family note: one more taught node moves to the
propertiesbag (object-form)domain:uiseat 1 ·session_0122Knsowci76D2rBWReCzzZ· 2026-10-01T00:15Z. ⛔ Not a claim, ⛔ not a dispatch; the card's lane, grade and labels are unchanged.e3782d26ec. An authoredobject-formnow takes its props in the spec'spropertiesbag, andobjectui validaterefuses a flatobject-formnode by name.skills/objectui/guides/page-builder.md"Form plugin example" authors a flatobject-formnode, so the skill now teaches a node the validator refuses.action:*'s executor keys, so it is carried here rather than on a new card. The ACCEPT that found it is5921869420.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:uiseat 1 · same-family note · 2026-10-01T00:15ZGenerated by Claude Code
objectstack-fleet commentedon Oct 1, 2026
Claim: PM loop round 11
Session:
session_01KTZmMfzVzjNvyaLyQ8mHvgAccount:
os-warren(the seat's linked user asGET /useranswers it; the card's assignee)Branch:
claude/issue-11183-action-node-properties-bagWorktree:
objectui-issue-11183Domain:
domain:skillsSeat:
domain:skills#1File surface: governed —
AGENTS.md(the #4action:*example),skills/objectui/SKILL.md,skills/objectui/guides/page-builder.md(theaction:*node and theobject-formrider from 5922065881),skills/objectui/rules/protocol.md(theaction:*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(therecord:activityrider from 5916799642); the ledgered pinsregistered-types-validate-ratchet-10859.test.tsandheld-public-block-arms-10872.test.tsplus any other readernode scripts/markdown-test-inputs.mjs --auditnames;README.mdonly 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 byos-zhuangorhotlong, then this seat lands it through the merge queue.Clause-②: no
Thread-read: 5922065881
Serial constraints cleared:
pm:blockinglevel, computed live: objectui#5250 carriesBlocked-by: #11183(5906832343), and PR objectui#11069 (objectui validateonto the strict face) waits on it. feat(cli):objectui validateandobjectui checkjudge through the strict authoring face (objectui#5250, slice A) #11069 touchescontent/docs/guide/layout.mdandschema-rendering.md; this card lands first by the card's own order, feat(cli):objectui validateandobjectui checkjudge through the strict authoring face (objectui#5250, slice A) #11069 mergesmainafter.objectui validateandobjectui checkjudge through the strict authoring face (objectui#5250, slice A) #11069 touches this surface (the two files above); feat(types)!: an authored object-map takes its props in the spec's properties bag; the flat spelling is refused by name (objectui#10859, batch 5) #11309, docs(types,plugin-calendar): teach object-calendar's field-name keys inside thecalendarblock; the flat spelling is the runtime handoff (objectui#8831) #11308, feat(types,components,fields,plugin-form,plugin-dashboard)!: the text family reads the spec's minLength / maxLength alone; auto_compute, auto_update and FieldMeta.display_field retire (objectui#11070, round 5) #11307, feat(types)!:showFiltersis retired onobject-grid, refused by name with the list view'suserActions.filternamed (objectui#11068) #11306, feat(components): element:text takes the published ninevariantvalues (objectui#7450) #11304 touch none of it.skills/objectui/rules/protocol.mdis shared with finding(skills):protocol.md's "Readers only." paragraph says abindondata-tabledraws "no error, no warning", but the table logs[ObjectUI] DataTable bind:(objectui#6575) and the parser tier warnsunknown-prop#11009 (pm:queuesince its unlock 5923309483, the 「Readers only.」 paragraph): serial, this card first; finding(skills):protocol.md's "Readers only." paragraph says abindondata-tabledraws "no error, no warning", but the table logs[ObjectUI] DataTable bind:(objectui#6575) and the parser tier warnsunknown-prop#11009 claims after this PR merges.skills/objectui/guides/app-composition.mdstill says every nav item needs a label "required by NavigationItemSchema" — false since @objectstack/spec 17.5.0 and objectui#9868 (label absent ⇒ inherited) #11198 (p3,guides/app-composition.mdnav label) does NOT ride this PR: a different defect form (fold gate ①), so it is a separate governed PR after this one. Said here in writing, as triage 5909803018 asked.origin/main:page-builder.md45dbf1c (09-28),AGENTS.mda097316 (09-28),quick-start.md2acd8e1 (09-19),record-edit-modes.mdf61dab1 (09-30),schema-rendering.md5c94589 (09-28),layout.md3cc4fe5 (09-30),plugin-detail.mdx1263e40 (09-30),plugin-detail/README.md741864f (09-30). PR objectui#11291 (object-formin the bag) is MERGED ase3782d26ec, so the rider's premise holds.Generated by Claude Code
objectstack-fleet commentedon Oct 1, 2026
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
objectstack-fleet commentedon Oct 1, 2026
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:
action:*node underAGENTS.md,skills/objectui/**andcontent/docs/guide/**(11 nodes) writes its row keys in the spec'spropertiesbag; 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. ✓plugin-detail.mdx'srecord:activitylimit/showCompletedinto the bag (both row members) ✓;page-builder.md'sobject-forminto the bag (PR objectui#11291's refusal-by-name verified at the head) ✓.packages/plugin-detail/README.mdNOT edited — the right call, measured:itemsis 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.rules/protocol.md's 「Readers only.」 paragraph untouched (finding(skills):protocol.md's "Readers only." paragraph says abindondata-tabledraws "no error, no warning", but the table logs[ObjectUI] DataTable bind:(objectui#6575) and the parser tier warnsunknown-prop#11009);guides/app-composition.mduntouched (docs(skills):skills/objectui/guides/app-composition.mdstill 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 onlayout.md/schema-rendering.mdare disjoint from this PR's; this PR lands first. ✓Deviations (5923856769), each accepted: the README non-edit (above);
check:skill-eval-tokensis 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 threesuccesson 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_listincontent/docs/guide/slotted-pages.mdandcontent/docs/api/schema-reference.md,action:button×2 inpackages/app-shell/README.md— and the unnamed refusal of the host feed slots (record:activityitems,record:historyentries).noted, not filed:layout.mdandschema-rendering.mdsay the spec refuses "them" (the block's row) written flat, butlabelis 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 aspage.ts; it ispackages/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 onf580661be(isolated subagent at the contract-review tier, served tier verified); CI green on the head (40success, 3skipped; the required contexts allsuccess); the empty-frontmatter changeset is objectui's mechanism for "publishes nothing". The seat now mirrors the card's assignee onto the PR, appliesneeds-user-decision, posts the final 速读 and requests review fromos-zhuangandhotlong; after an APPROVED review the seat lands it through the merge queue, before PR objectui#11069, and this card closes.Generated by Claude Code
objectstack-fleet commentedon Oct 1, 2026
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.main: every taughtaction:*node underAGENTS.md,skills/objectui/**andcontent/docs/guide/**(11 nodes) writes its executor keys in the spec'spropertiesbag, with the prose beside each naming who refuses the flat spelling (the spec's strict page component, objectui's strict authoring face); the two same-family riders landed (plugin-detail.mdx'srecord:activityrow keys,page-builder.md'sobject-formexample); the two ledgered pins moved to the bag spelling with a derived flat control.packages/plugin-detail/README.mdwas left as measured (itemsis a host feed slot, not a row key). Landed before PR objectui#11069, as the card ordered.AGENTS.md+skills/**). Contract review PASS 5924066480 onf580661be(contract-review tier); ACCEPT 5924123994; 速读 5924129531; APPROVED review byos-zhuang(05:34Z), who flipped it ready and armed auto-merge. The queue removed it once (05:46Z) onSpec Main Shape Gate; the seat's reading 5927274924: the branch's base lacked objectuimain's own fix47e3ce00(PR fix(types,runner): the retired-key pins and the runner sidebar compile against both the pinned spec and objectstack main (objectui#11330) #11343) for exactly the five files the gate named, so the seat mergedmainin through the update-branch route (head31d85dc96, no diff change); green, re-queued 08:12Z, merged 08:27Z.record:related_list×2, app-shell READMEaction:button×2), and the host feed slotsitems/entriesare refused without being named #11321 (barefinding) — three public-block examples outside this card's roots still flat, and the unnamed host feed slots.layout.md/schema-rendering.mdsay the spec refuses "them" (the block's row) written flat, but a flatlabelis kept on both faces — rides the next PR that edits those passages.Fixes #11183closed this card at merge. The seat stripspm:dispatchedand the assignee here.skills/objectui/rules/protocol.mdis now free for finding(skills):protocol.md's "Readers only." paragraph says abindondata-tabledraws "no error, no warning", but the table logs[ObjectUI] DataTable bind:(objectui#6575) and the parser tier warnsunknown-prop#11009 (queued).Generated by Claude Code
docs: taught action:* nodes move their executor keys into the spec `p…