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
skills: evaluate whether the published security/platform guidance must teach the app-capability vs system-permission distinction and the isDefault → everyone binding rule (after #17189) #17359
Filed by the director seat (summon #21, session_01QVMnxyWBx8cAQMsV6akDV9) on the maintainer's instruction, verbatim and untranslated: 「17189 同意,但是同时评估是否需要改进skills」 (director chat, 2026-09-10T08:4xZ, replying to decision batch #110 item 1). Routed domain:skills under the maintainer direct-dispatch channel (the instruction names the work explicitly); pm:queue.
The question
After #17189 lands (ruling (i): an app-declared capability token is not a system permission for the everyone-anchor high-privilege check; ADR-0090 D5 amended), does any published skill under skills/** need to change so that an AI author writing a metadata app does not reproduce the shape hotclm hit?
Measured on origin/main47863f4 (2026-09-10T08:3xZ)
skills/objectstack-data/rules/security.md teaches definePermissionSet, the permissions: stack key, requiredPermissions as an ADR-0066 D3 AND-gate, and the platform-exclusive capabilities (manage_metadata, manage_platform_settings, …).
skills/objectstack-platform/SKILL.md teaches the capabilities stack key as a demand for a platform provider (the 28 PLATFORM_CAPABILITY_TOKENS) and requires:.
Zero hits for: isDefault: true on a permission set (the ADR-0090 D5 everyone auto-binding), the high-privilege refusal and what trips it, an app-declared capability token (ADR-0066 D1, scope: 'org') as distinct from a platform token, or the pattern "one default set that every employee holds, carrying the app's own navigation tokens". The only isDefault in the corpus is a list-view example.
⇒ Today the published guidance can teach an author to declare app capabilities (D1) and to gate navigation on them, and separately to write permission sets, but it says nothing about the one combination that failed in the field: the default set that carries app tokens. Whether that is a gap worth text, and where it lands (security.md vs platform SKILL.md), is this card's assessment.
Deliverable
An assessment on this card: which skill file(s), which sentences, and whether a negative example (hotclm#11's shape: seven per-position bindings as a workaround) belongs in the text. If the answer is "no change needed", say why with the grep above as the control.
Open domain:skills cards read by title on 2026-09-10T08:3xZ (17): none about capability tokens, the everyone anchor, or permission-set defaults. Refs: #17189 (the fix and its ruling), hotclm#11, ADR-0090 D5/D9, ADR-0066 D1.
Claim: PM loop round 1
Session: session_01YKEjmbYNvYWJvWGSWx26zK (GitHub os-litant, skills seat), claimed at 2026-09-10T09:03Z
Branch: claude/issue-17359-skills-capability-guidance
Worktree: objectstack-issue-17359
Domain: domain:skills
File surface: skills/objectstack-data/rules/security.md, skills/objectstack-platform/SKILL.md — READ-ONLY in this dispatch: deliverable 1 (the assessment on this card); ⛔ no edit to skills/** until #17189's fix merges (the card's own condition) (stop on breach; explain in the report)
Container & model: M (a judgment card — the deliverable decides what a published skills/** surface will say; not mechanical), mode:subagent, model: claude-fable-5-1 — node scripts/pm/dispatch-gates.mjs --tier skills/objectstack-data/rules/security.md skills/objectstack-platform/SKILL.md at 706ad0f prints 「Model tier — MANDATORY: claude-fable-5-1 … 'skills/**' — clause ① (2026-09-10 ruling, verbatim 「必须 fable的还包括对外发布的skills」) … no one-line exemption applies under this root」; passed explicitly as the dispatch's model parameter.
Clause-②: no — an assessment; no accept set or public surface moves (any later text is guidance on an already-ruled contract, #17189 (i)).
Thread-read: none (0 comments on the card at claim time; body read in full; #17189's four comments incl. the ruling 5615806616 read).
Serial constraints cleared: no open PR touches the two files and no other claim on this lane names them (git ls-remote at claim: the lane's only branch was the merged #17302's, deleted); action face git log -8 origin/main -- <the two files> newest b110578 (same day — the dev works from current origin/maine669e5e); #17189 has no PR (closed_by_pull_requests 0; spec seat vacant) ⇒ the text half stays blocked on it; H17 hold index names neither file; verify-lock free (--status: lock is free, queue empty).
Dispatched — R1, 2026-09-10T09:09Z, mode:subagent, build tier claude-fable-5-1 passed explicitly (clause ①: published skills/** is the surface under assessment). Claim 5616017852 is the dev's identity; branch claude/issue-17359-skills-capability-guidance. Scope of this dispatch = deliverable 1 only (the assessment comment; pr: null); ⛔ no edit to skills/** until #17189's fix merges. Disjoint from #17164 (objectos CLAUDE.md) and #17346 (check-clause2-carriers.mjs C4 + contract-review.md :35–:37). Patrol timer trig_012AMK9J7RnbBAeY1WNEtrLA fires 09:49Z.
One 3-line construct in skills/objectstack-data/rules/security.md; skills/objectstack-platform/SKILL.md unchanged. The text lands only after #17189's fix merges, because it teaches ruling (i)'s semantics, not the pre-fix refusal.
Tip read: origin/main = e669e5e (e669e5eee296410731c8a00cba366369f005bc96), read 2026-09-10T09:1xZ. The two candidate files last moved at b110578 (same day); both read at tip, in full for security.md (210 lines) and by section for the platform file.
capabilities in skills/objectstack-platform/SKILL.md: the top-level key list at :76 (name only) and the requires: section :435-482, which teaches the 28 PLATFORM_CAPABILITY_TOKENS (kernel/platform-capabilities.ts) — a different registry from the capabilities: stack key (security/capabilities.ts, ADR-0066 D1).
Positive control git grep -c definePermissionSet origin/main -- 'skills/**' → skills/objectstack-api/SKILL.md:1, skills/objectstack-data/rules/security.md:4 — identical to the PM's reading at e669e5e.
Zone-2 assumptions: A holds (as above). B holds and is wider than the card's one combination: the published skills teach neither the DEFINE key (capabilities: / defineCapability) nor the GRANT key (systemPermissions); security.md:145's own requiredPermissions: ['view_pii'] names an app token that no skill shows declared or granted anywhere (view_pii is not among the 9 curated PLATFORM_CAPABILITIES). C is falsified in one half — see Reader.
Reader
The reader is an AI author writing a metadata app's permissions (and capabilities) into the post-(i) world. Under (i) a systemPermissions name is an app token only when it carries package provenance, i.e. when the stack declares it under capabilities: (boot side: the sys_capability row is managed_by:'package'; lint side: the stack's declaration list). The back-compat implicit derivation that ADR-0066 D1 keeps alive seeds an undeclared name as managed_by:'platform' with no package provenance (packages/plugins/plugin-security/src/bootstrap-declared-capabilities.ts :9-11, :230). So after the fix:
a declared app token on the isDefault: true set binds to everyone with no warning — hotclm's intended shape works;
an undeclared app token on that set still reads as 'system permissions': security-anchor-high-privilege (error) and the boot refusal are unchanged, and the lint's fix-it hint (packages/lint/src/validate-security-posture.ts :781-783, "Split the powerful bits into a separate set granted through ordinary positions") walks the author into exactly hotclm#11's seven-per-position workaround instead of the declaration;
a platform capability (manage_users, setup.access, … — the 9 curated names) or VAMA / delete / transfer / export on that set is refused, loudly, with the bit named.
Value gate:
① Which decision the text changes: whether to declare the token under capabilities: before granting it via systemPermissions on the isDefault: true set. Shape produced today without the text: the skills name none of the three keys, so an author reaches systemPermissions from the schema alone (its .describe() is "System level capabilities") and writes the undeclared grant — the shape the skill's own view_pii example models. That shape still fails after the fix, and its diagnostic steers into the workaround. The plain "app tokens may ride on the default set" sentence (Zone 2 C) changes no decision post-fix — that shape simply works — so it is not what is written.
② Deletion or rewrite instead of addition: no. No existing sentence in either file names isDefault, systemPermissions or capabilities:, so there is nothing to rewrite; the only candidate neighbour (security.md:135-139, requiredPermissions, the REQUIRE side) is correct as written, and folding DEFINE/GRANT into it would be re-wrap paying for new content, which is not a currency.
③ Construct over prose: yes — one bullet in the permission-set key list naming the three keys, the anchor, and the two things refused there.
Real-usage reading (axis ①, measured at e669e5e): examples/app-showcase declares two capabilities (showcase.export_data, showcase.restricted_ops, src/security/capabilities.ts :52, :77) and grants one on OpsPermissionSet (permission-sets.ts :220); its isDefault set showcase_member_default (:295-346) deliberately carries no systemPermissions. The DEFINE → GRANT → REQUIRE chain is taught only in that example's code comments (capabilities.ts :15-20), in no published skill. No other example carries the combination; the named consumer that does is hotclm (external, read through #17189's quotation — hotclm#11 itself answered 403 on both the API and the page from this seat).
Four axes: business need — a named consumer hit the combination, and the post-fix failure mode is the undeclared variant an author reaches first from the schema; long-run — the rule is the permanent post-(i) contract ("declaration is what makes a token an app token"), not the pre-fix refusal, so it is not transitional; AI error — the construct closes the one silent-until-lint path; the contract-tightening alternative (retire the implicit derivation so an undeclared name is refused at defineStack) is a spec-lane decision outside this card and would not remove the need to name the three keys; startup focus — +3 lines, one file, no new section.
Proposal
skills/objectstack-data/rules/security.md — insert one bullet after line 33, inside the existing key list of "## Object-level permissions (RBAC)". Neighbours, verbatim at e669e5e:
Proposed bullet (becomes lines 34-36; widths 81 / 82 / 90 — the file's longest existing lines are 93):
- **`isDefault: true` = the `everyone` baseline (ADR-0090 D5).** It may carry app
capabilities declared under `capabilities:` (`defineCapability`) and granted via
`systemPermissions`; a platform capability or undeclared name there fails lint and boot.
Net: +3 lines in security.md. It names the anchor key, the anchor, the DEFINE and GRANT keys, and the two things that may not ride: a platform capability and an undeclared name. VAMA / delete / transfer / export are not restated — they are the "super-user" bits named two lines above, and the lint names them precisely when they occur.
skills/objectstack-platform/SKILL.md — no change (0 lines). Its "capability" vocabulary is the requires: service-plugin tokens; teaching app-declared capabilities there would put two registries under one word in one file. capabilities stays a listed key at :76 whose semantics live beside the GRANT key in security.md.
Total net across both files: +3 — within budget.
Negative example (hotclm#11's seven per-position bindings): not included. It is a pre-fix workaround, so text describing it is transitional (不渐进); an author following the construct never reaches it; it costs lines the budget does not have; and the one thing that steers a post-fix author toward it is the lint hint for the undeclared-name case, which lives in #17189's declared file surface (packages/lint/src/validate-security-posture*), not in a skill.
Wording dependency on #17189's landing: the bullet is correct under ruling (i) as recorded. If the fix PR also retires the implicit derivation (undeclared names refused at authoring), the words "or undeclared name" become redundant with the contract and should be dropped at landing; the other two lines stand either way. Two pre-fix sentences outside skills/** that the fix PR should move in the same diff are listed in the dev report below (content/docs/permissions/permission-sets.mdx :223-225, examples/app-showcase/src/security/permission-sets.ts :290-291).
{
"issue": 17359,
"status": "done",
"branch": "claude/issue-17359-skills-capability-guidance",
"pr": null,
"premise_still_valid": true,
"summary": "Assessment delivered as comment 5616225081 on #17359 (deliverable 1 only): verdict CHANGE NEEDED — one 3-line bullet in skills/objectstack-data/rules/security.md after line 33, skills/objectstack-platform/SKILL.md unchanged, negative example not included, Blocked-by: #17189. Zone-2 A and B hold (B is wider: the skills teach neither `capabilities:`/`defineCapability` nor `systemPermissions`); C is falsified in one half — under ruling (i) an UNDECLARED app token on the `isDefault` set still counts as a system permission (derived placeholders are managed_by 'platform', no package provenance), so the residual post-fix trap is two-directional and the construct names the declaration route. No file under skills/** edited; identity branch pushed empty; no PR by design.",
"tests": "No code change; no test or build run. Control grep re-run at origin/main e669e5e: 83 hits / 19 files; isDefault only at skills/objectstack-ui/rules/list-views.md:122; everyone only at objectstack-data/SKILL.md:78-79 and objectstack-formula/SKILL.md:409; systemPermissions | defineCapability | scope: 'org' zero hits (exit 1). Positive control definePermissionSet: objectstack-api/SKILL.md:1, objectstack-data/rules/security.md:4. Decision-frame md5 22f2339f0acb64cdb50c7adc9db681c3 verified at e669e5e. Candidate bullet measured: 3 lines, widths 81/82/90 vs file max 93. dispatch-gates.mjs --commands on the branch: exit 2, 'this branch changes nothing against origin/main (merge base e669e5eee) — nothing to derive'.",
"gates": [],
"gates_reason": "empty diff — dispatch-gates.mjs derived nothing (exit 2, quoted in tests); verify lock not taken",
"line_budget": { "skills/objectstack-data/rules/security.md": "+3 (proposed, not applied)", "skills/objectstack-platform/SKILL.md": "no edit", "total": "+3 of +3" },
"files_changed": [],
"deviations": [
"no pnpm install in the worktree: assessment only — zero edits, zero gates to run",
"hotclm#11 not read directly (REST 403 and page 403 from this seat); read through #17189's body quotation; add_repo read-attach answered git-only and was not used",
"channel: every GitHub read and both writes went through repo-scoped REST (probe 200), GitHub MCP unused",
"assessment comment read back: all section markers 1x, byte count equal (10027/10027); the only difference from the sent body is the footer block, which the platform re-laid (one rule line, one footer)"
],
"mcp_calls": "0 — GitHub MCP unused; one Claude_Code_Remote add_repo call (not GitHub MCP)",
"open_questions": [],
"out_of_scope_findings": [
"noted, not filed: published skills teach neither the DEFINE key (`capabilities:`/`defineCapability`) nor the GRANT key (`systemPermissions`); security.md:145 `view_pii` is an app token no skill shows declared or granted — 承接者: skills seat (the wider gap the card's combination sits inside)",
"noted, not filed: packages/lint/src/validate-security-posture.ts:781-783 fix-it hint steers an undeclared-app-token author into the per-position workaround post-fix — a warning pointing at metadata the runtime honours but makes worse (boundary, not class c) — 承接者: #17189's implementing PR (file in its declared surface)",
"noted, not filed: content/docs/permissions/permission-sets.mdx:223-225 lists 'system permissions' among anchor-forbidden bits and says 'nothing auto-binds', while PermissionSetSchema.isDefault .describe() says app-level sets are auto-bound at boot — pre-fix wording in a hand-written docs tree — 承接者: #17189's implementing PR",
"noted, not filed: examples/app-showcase/src/security/permission-sets.ts:290-291 comment 'the D7 lint hard-blocks ... system permissions' — pre-fix wording — 承接者: #17189's implementing PR",
"noted, not filed: the word 'capability' names two registries in skills/objectstack-platform/SKILL.md (`requires:` tokens vs the `capabilities:` key); a string array under `capabilities:` is refused loudly by the strict CapabilityDeclarationSchema, no failing probe — 承接者: skills seat"
]
}
Checklist: no PR by design (pr: null, status: done, files_changed empty, gates: [] with the reason quoted from dispatch-gates.mjs — exit 2 on an empty diff); the identity branch sits at e669e5e with no commits; worktree removed; report shape correct; open_questions empty; report read back on the card (5616244069).
Spot-checked on origin/main (143c715 at 09:2xZ; the two skill files unchanged since b110578): security.md :31–:34 neighbours verbatim as quoted, 210 lines, widest line 93; packages/spec/src/security/capabilities.ts :86–:102 (a declaration carries managed_by:'package' + package_id; the implicit derivation still runs for back-compat); packages/plugins/plugin-security/src/bootstrap-declared-capabilities.ts :9–:11 and :230 (an undeclared name falls back to the derived placeholder with no package provenance); packages/lint/src/validate-security-posture.ts :778–:784 (the fix-it hint steers to the per-position split); security.md :145 requiredPermissions: ['view_pii']. The control grep at e669e5e matches this seat's own reading at 706ad0f.
Verdict accepted: CHANGE NEEDED — one +3-line bullet in skills/objectstack-data/rules/security.md after :33, skills/objectstack-platform/SKILL.md unchanged, no negative example; within the +3 budget. The value-gate reading carries the decision: under ruling (i) a DECLARED app token on the isDefault: true set binds to everyone, an UNDECLARED one still reads as a system permission, and no published skill names any of the three keys — so the text changes the author's decision to declare before granting. Zone-2 C half-falsified by the dev; accepted.
Out-of-scope items (five noted, not filed; three-class test applied): none is class (a)/(b)/(c) — an undeclared-token grant still resolves (back-compat), so nothing is refused or dropped; the lint-hint item is the recorded boundary (a warning steering to worse metadata). Items 2–4 (the lint hint :778–:784; content/docs/permissions/permission-sets.mdx :223–:225; examples/app-showcase/src/security/permission-sets.ts :290–:291) are relayed to An app-declared capability with scope: 'org' counts as a high-privilege bit, so a set carrying only app capability tokens cannot bind to the everyone anchor #17189 for its implementing dev (the record stays 5616225081). Items 1 and 5 (DEFINE/GRANT keys untaught anywhere; the two "capability" registries in the platform skill) are this seat's — folded into the text dispatch's reading, ⛔ not into its budget.
Re-dispatch shape (pre-written for the unlock): one dev at the contract-review tier (published skills/**), budget +3 lines in security.md only, the bullet from 5616225081 with the boot-wording correction above and the "undeclared" clause re-checked against the merged fix; governed ⇒ draft PR + 速读草稿, skills-seat review at tier, human merge.
Double-check on the last transition (5616301504, 2026-09-10T09:25Z: 「back to pm:queue by the unlock scan when #17189 closes」): ① #17189 is closed completed (2026-09-15T15:05Z, director exit 5682637828) — its fix PR #17811 merged 2026-09-14T04:19Z (d5c91dd6, files: packages/spec/src/security/high-privilege.ts + test + api-surface + changeset) after the ADR PR #17814 (2026-09-13T15:12Z, docs/adr/0090-…); ② no PR references this card (closed_by_pull_requests 0) ⇒ nothing newer to refuse on. Re-verified on origin/main2496415: skills/objectstack-data/rules/security.md is untouched since the assessment (last touch 6a3bcd8, 211 lines; the :31–:34 neighbours read as quoted in 5616225081); bootstrap-declared-capabilities.ts's docblock still describes the implicit systemPermissions placeholder derivation (managed_by:'platform', claimed by an explicit declaration) ⇒ the 「or undeclared name」 clause of the proposed bullet is still live post-fix, subject to the dispatch's re-read of the merged predicate in high-privilege.ts. Blocked-by: #17189 removed from the body in the same act; the pre-written re-dispatch shape (5616301504) is executed next: one dev at the contract-review tier, +3 lines in security.md only, boot wording 「refused by lint and at boot」.
Ruling recorded — the security.md token ceiling is raised to 2543. Skills seat, session_01Gqi43smmqjJ5sUrhfoPeKu, 2026-09-17T07:15Z. Maintainer, verbatim, in this seat's chat: 「security.md 允许增加到 2543」 — answering the 需裁 item put in the round report (park record 5704584550 on this card, park note 5704585750 on PR #18531: skills/objectstack-data/rules/security.md reads 2543 tokens on head 4ea43892, ceiling 2480, over by 63; recommendation A = raise).
What this discharges: release condition ② of the park. The raise lands in PR #18531 itself: the ratchet row ['skills/objectstack-data/rules/security.md', 2480] in scripts/check-skills-token-ratchet.mjs becomes 2543 with this ruling quoted beside it, and the PR body quotes it — the ratchet's own rule (「the other direction lands only in a PR whose body quotes a maintainer ruling authorizing it」).
What it does not discharge: release condition ① — #18535 (the declared app capability token is still refused at the everyone anchor because describeHighPrivilegeBits's consumers pass no declaredCapabilities), which the three lines describe as already true. #18535 is ownerless (bare finding, no lane, no assignee, 0 comments since filing); per SKILL.md 「阻塞项无主 ⇒ 被挡席认领做掉」 this seat claims and dispatches it next; PR #18531's single patch round (merge origin/main, the ceiling raise quoting this ruling, skills/** gates re-run) follows #18535's landing, then the four-piece.
Unparked — release condition ① discharged; the single patch round is dispatched. Skills seat, session_01Gqi43smmqjJ5sUrhfoPeKu, 2026-09-17T09:01Z. #18535 landed on origin/main as 21b7c12b4 at 2026-09-17T09:00:08Z (landing record 5711759365): the four consumers of the anchor predicate now pass the stack's declared capabilities, so the three lines PR #18531 adds to skills/objectstack-data/rules/security.md describe landed behaviour (「文档应该以实际实现为准」). Condition ② was ruled at 5710537499 (「security.md 允许增加到 2543」). Same act: pm:blocked → pm:dispatched (assignee unchanged), the Blocked-by: / Unlock-action: lines dropped from the body.
Claim continues — patch round (the seat's re-dispatch on the same branch; round 2 of the original claim)
Session: session_01Gqi43smmqjJ5sUrhfoPeKu
Branch: claude/issue-17359-skills-capability-guidance (PR #18531, head 4ea43892 before the round)
Worktree: objectstack-issue-17359
Domain: domain:skills
Seat: domain:skills#1
File surface: skills/objectstack-data/rules/security.md (the three accepted lines, unchanged unless the merge of origin/main requires re-anchoring; re-count) · scripts/check-skills-token-ratchet.mjs (row :424 on 21b7c12b4, ['skills/objectstack-data/rules/security.md', 2480] → 2543 with the ruling quoted verbatim beside it, in the file's own raise-ritual form) · the PR body quotes the ruling (the ratchet's rule for a raise) (stop on breach; explain in the report). ⛔ No other skill file, ⛔ no other ceiling.
Container & model: S(合 main + 抬上限引裁定), mode:subagent, model: claude-fable-5-1 — node scripts/pm/dispatch-gates.mjs --tier --repo objectstack-ai/objectstack skills/objectstack-data/rules/security.md scripts/check-skills-token-ratchet.mjs at 2026-09-17T09:01Z on the fast-forwarded tree: 「Model tier — MANDATORY: claude-fable-5-1」 (published skills/**); no downgrade exit taken
Clause-②: no
Thread-read: 5710537499
Serial constraints cleared: security.md hot-file — no other open PR touches it (this seat's own PR #18531 is the carrier); the branch merges origin/main cleanly (git merge-tree at 2026-09-17T08:43Z: no conflict, 35 commits behind); os-verify-lock.sh --status at 2026-09-17T09:01Z: free; shared checkout fast-forwarded to origin/main21b7c12b4.
Ruling-ref: 5710537499
{
"issue": 17359,
"status": "done",
"branch": "claude/issue-17359-skills-capability-guidance",
"pr": "https://github.com/objectstack-ai/objectstack/pull/18531",
"head": "dfe355143c2e8debd21e886aa30c594d26e3be6e",
"merge_commit": "68e1b07e18742a169ed93208d8d5c38c5b815628 — git merge --no-ff origin/main (21b7c12b4) into the branch; no rebase, no force-push, no new PR; clean (merge-tree exit 0, 37 commits behind); no os-regen-pending",
"files": [
"scripts/check-skills-token-ratchet.mjs (+10/−1: CEILINGS row 2480 → 2543 with the ruling quoted verbatim beside it, in the file's own raise-ritual form)",
"skills/objectstack-data/rules/security.md (+3/−0 vs origin/main; byte-identical to 4ea43892 — no clause corrected)"
],
"session": "session_01Gqi43smmqjJ5sUrhfoPeKu",
"premise_still_valid": true,
"summary": "Patch round on PR #18531 (draft, still draft). Merged origin/main 21b7c12b4 as merge commit 68e1b07e1 (#18535 landed, so the three security.md lines now describe landed boot and lint behaviour; re-read against declared-capability-context.ts, the boot bind in security-plugin.ts and the lint rule in validate-security-posture.ts — every clause true, none corrected). Re-counted security.md after the merge: 2543 tokens, not above the ruling, so the ratchet row was raised 2480 → 2543 (commit dfe355143) with the maintainer ruling 「security.md 允许增加到 2543」 (2026-09-17, record 5710537499) quoted verbatim beside the row and in the PR body's appended 'Patch round' section; the 速读 draft's 改了什么/风险/你要做的 carry a dated update; a status line marks the body's original Blocked-by paragraph as discharged. 40 derived gates all exit 0 (the previously expected-red ratchet now green); GOVERNED — landing stays the maintainer's. Assignee untouched (os-justin, set by the dispatch).",
"measurements": {
"tokens_security_md": "convention ceil(utf8 bytes / 4): origin/main 21b7c12b4 = 9913 bytes → 2479 (main did not touch the file); branch head before the round 4ea43892 = 10170 bytes → 2543; after the merge (68e1b07e1 and head dfe355143) = 10170 bytes → 2543 — not more than 2543, so the raise equals the ruling",
"ratchet_row": "before: ['skills/objectstack-data/rules/security.md', 2480] (line 424 on 21b7c12b4); after: ['skills/objectstack-data/rules/security.md', 2543] (line 433 on dfe355143); comment beside it ends: Maintainer ruling 2026-09-17 (recorded on #17359 as comment 5710537499), verbatim and untranslated: 「security.md 允许增加到 2543」; +63 tokens, zero headroom, ceiling +63; no other row moved",
"three_lines_reread": "clause 1 (isDefault: true = the everyone baseline, ADR-0090 D5): still true — packages/spec/src/security/permission.zod.ts:682 describe('[ADR-0090 D5] App baseline for the everyone position …'), ADR-0090 D5 at docs/adr/0090-…:46. clause 2 (may carry app capabilities declared under capabilities: (defineCapability) and granted via systemPermissions): now true at boot and in lint, protocol-only before #18535 — packages/plugins/plugin-security/src/declared-capability-context.ts readDeclaredCapabilityContext reads the stack's capabilities: declarations; security-plugin.ts:3592–3595 describeHighPrivilegeBits(boot, anchorContext); engine write gate :5503–5508; suggested-audience-bindings.ts:968–972; packages/lint/src/validate-security-posture.ts:439–443 builds anchorContext from stack.capabilities, :795 passes it. clause 3 (lint and boot refuse a platform capability or undeclared name there): still true — high-privilege.ts:70–74 platform floor (PLATFORM_CAPABILITY_NAMES never excused), :134 「Omission refuses」 (a token absent from declaredCapabilities stays offending); lint emits security-anchor-high-privilege at severity error (:795–808); boot logs '[security] refusing to bind fallback set to everyone — high-privilege bits' and skips the binding (:3595–3600). No clause corrected.",
"line_readings": "security.md 211 → 214 lines (+3), widest line 93; package (10 SKILL.md + objectstack-data rules/references, 20 files) 8959 → 8962",
"governed": "node scripts/pm/check-governed-merges.mjs --test security.md check-skills-token-ratchet.mjs → exit 3 「GOVERNED — a human merge is the review record for this PR」 (1 of 2 paths; skills/** rules layer)",
"labels": "read back after the round: documentation, size/s, skip-changeset — no label written this round; skip-changeset still holds (repo-root gate script in the private root package; skills/** ships in no files[])",
"pr_body": "PATCH /pulls/18531 → 200; read back: 'Patch round' section, the verbatim ruling, the status line, the 速读 update and the 40-line gate list all present; stored 20496 bytes = sent 20438 + 58 (the platform appended one bare footer beside the kept session-URL footer — the recorded REST-PATCH reading); draft unchanged true; 0 less-than characters; closing keyword only Fixes #17359"
},
"tests": "Gates on dfe355143 in worktree objectstack-issue-17359: node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack derived 40 (change set 2 paths vs merge base 21b7c12b4); all 40 run with redirect-then-$? capture; --ran reconcile 「40 derived, 40 run, 0 NOT-MEASURED, 0 UNRUN」 exit 0; all 40 exit 0. Named: node scripts/check-skills-token-ratchet.mjs → 「✓ check-skills-token-ratchet: skills/objectstack-data/rules/security.md is 2543 tokens (ceiling 2543; headroom 0).」 and 「34 authored bundle file(s) within their ceilings; 10 generator-owned file(s) measured, not ratcheted.」; --self-test 「65 cases pass」; pnpm check:ratchet-remedy-authority OK (255 scripts swept; 15 mark the expanding remedy ⛔ MAINTAINER-ONLY — unchanged); pnpm check:skill-frame-sync ✓ (14 self-test cases; frame coherent); check:skill-compatibility, check:skill-identifier-liveness, check:role-word, check:doc-authoring, check:corpus-claim-drift, check:nul-bytes, check:pm-governed-merges, check:pm-dispatch-gates (626 s, completed in the background after the foreground cap, exit 0 from the runner's own redirect), check:cross-package-test-inputs, check:entry-guard, check:parse-guard, check:watch-hint-literal and the rest → exit 0; pnpm --filter @objectstack/lint run check:doc-formula-expressions → exit 0 after building '@objectstack/lint...' under scripts/pm/os-verify-lock.sh (「VERDICT command-exit 0 · held the lock 136s · waited 0s」). Ablation from the committed head (trap-restored, absolute paths, no dist involved — the gate reads its own source): row reverted to 2480 on disk (grep counts 2480-row 1 / 2543-row 0) → gate exit 1 「✗ … is 2543 tokens; the ratchet ceiling is 2480 (over by 63) … ⛔ MAINTAINER-ONLY」; restored with git checkout HEAD -- path: git hash-object = HEAD blob 5b984866, git diff HEAD empty, git status --porcelain empty, gate exit 0 again. Control characters: grep -naP over both touched files → no match (exit 1). No ① dependency-closure build and no ② package test owed (no package touched); the artifact-roster / wide-population / pending-changeset families are CI's own. Pre-push hook: 「check:commit-card-trailers: … no card relation and no model identifier in the trailer pair」 on both pushes. Cleanup: node_modules deleted, git worktree remove exit 0 (no --force).",
"mcp_calls": "0 — no MCP GitHub tool called; every GitHub read and write went through REST curl with GITHUB_TOKEN",
"api_writes": "2 — PATCH /repos/objectstack-ai/objectstack/pulls/18531 (body), POST /repos/objectstack-ai/objectstack/issues/17359/comments (this report); plus 2 git pushes to the branch (68e1b07e1, dfe355143); no label write, no POST /pulls, no POST /issues, no assignee write",
"open_questions": [],
"out_of_scope_findings": [
"noted, not filed (承接者: 无): pnpm check:pm-dispatch-gates took 626 s on this shared box and overran the ~10-minute foreground cap (completed in the background, exit 0); platform-readings line 427 already records 430–450 s single-machine and prescribes detaching with tail --pid — the reading is low under contention, not wrong",
"noted, not filed (承接者: the skills seat at the four-piece): the PR body's original top paragraph (Blocked-by #17189 step-②) is historical; a dated status line was inserted above it instead of rewriting it, so the original reasoning stays readable"
]
}
ACCEPT (patch round) — in-seat contract-tier review of PR #18531 at head dfe355143 (report 5712105389) by the skills seat, 2026-09-17T09:31Z. Verified against GitHub and a scratch worktree at the head, ⛔ not against the report:
The construct is unchanged: skills/objectstack-data/rules/security.md on the head is byte-identical to the ACCEPTED head 4ea43892 (git diff empty) — the three lines after the RBAC Source: line (ACCEPT of the construct 5616301504, assessment 5616225081); +3 lines vs origin/main, 211 → 214. The seat re-read the three clauses against the landed A declared app capability token is still refused at the everyone anchor: describeHighPrivilegeBits's consumers pass no declaredCapabilities (PR #17811 landed the spec predicate only) #18535 code (declared-capability-context.ts; security-plugin.ts boot bind and write gate; suggested-audience-bindings.ts; validate-security-posture.ts :439–:443 / :795) and high-privilege.ts (platform floor :70–:74, 「omission refuses」 :134): all three true on origin/main21b7c12b4; none needed correction.
Merge: 68e1b07e1 merges origin/main21b7c12b4 (no rebase, no force-push); merge base = origin/main; only the two intended files differ from main.
The ceiling raise is the ruling, in the ratchet's own form: scripts/check-skills-token-ratchet.mjs row ['skills/objectstack-data/rules/security.md', 2480] → 2543 with the raise comment quoting the maintainer verbatim and untranslated — 「security.md 允许增加到 2543」 (2026-09-17, record 5710537499) — and the PR body quoting it in its 「Patch round」 section; no other row moved. Measured on the head: 10170 bytes → 2543 tokens (ceil(utf8 bytes / 4)); check-skills-token-ratchet 「is 2543 tokens (ceiling 2543; headroom 0)」, --self-test 65 cases; check:skill-frame-sync 0; --pair 18531 → 0 (Clause-②: no). check-governed-merges --test → GOVERNED (skills/**, rules layer). The report's 40 derived gates all exit 0, re-derived here for the ratchet, the frame sync and the pair.
Dev's open questions: none. Out-of-scope notes (a 626 s check:pm-dispatch-gates under contention; the body's historical Blocked-by paragraph kept under a dated status line) — nothing to file.
Rules layer (published skills/**) ⇒ the four-piece is hung on PR #18531 in the same act: 维护者速读(终稿), needs-user-decision, review requested from os-zhuang and hotlong. An authorized APPROVED lands it by ruling C (the CI head was still finishing one job at review time; the landing pre-check re-reads it); a human merge is equally the record.
Authorized approval received — ruling C: the seat lands it. Skills seat, session_01Gqi43smmqjJ5sUrhfoPeKu, 2026-09-17T09:37Z. Read on GitHub: PR #18531 (head dfe355143) carries review 5233769130 APPROVED by os-zhuang (in GOVERNED_APPROVERS) at 2026-09-17T09:37:20Z on the current head, and the same account flipped it ready at 2026-09-17T09:37:24Z. Landing pre-checks on this head: CI final 27 success / 15 rostered skips (check-expected-skips OK at 2026-09-17T09:34Z), --pair 18531 0, harness CURRENT (re-taken now), mergeable clean. Same act: needs-user-decision removed from the PR (the label leaves with the approval); the seat arms auto-merge SQUASH through the CCR route next unless the approver already enqueued it; the landing record follows merged_at.
Landing record — skills seat, session_01Gqi43smmqjJ5sUrhfoPeKu, 2026-09-17T09:54Z. PR #18531 (head dfe355143) MERGED through the merge queue at 2026-09-17T09:53:14Z (merged_at) as 7299b945a2fcdc649de1a59ac71a006c6f38ff9b — single parent d5e64d8d9 per git rev-list --parents (a squash); merged_by os-zhuang, the authorized approver who approved (5233769130), flipped ready and enqueued it by hand — ruling C completed by the approver's own act; the seat's part was the construct review (5616301504), the park and its discharge (5704584550 → 5711767613), the patch-round review (5712132917), the label strip (5712211637) and this record. Verified on origin/main by git at 2026-09-17T09:53:36Z: the squash is an ancestor; git log --oneline origin/main | grep -F '(#18531)' hits; skills/objectstack-data/rules/security.md carries the three lines (214 lines, 2543 tokens by ceil(utf8 bytes / 4)); the ratchet row reads ['skills/objectstack-data/rules/security.md', 2543] with the ruling 「security.md 允许增加到 2543」 quoted beside it; the queue ref is gone. Same act: pm:dispatched removed and the assignee cleared on this auto-closed card (Fixes #17359, completed); domain:skills stays. Downstream: #17189's rider is discharged (the published guidance now teaches the DECLARE/GRANT pair and the runtime + lint honour it since #18535); hotclm#11's workaround waits on the release that ships @objectstack/plugin-security / @objectstack/lint at minor.
Activity
os-litant commentedon Sep 10, 2026
Claim: PM loop round 1
Session:
session_01YKEjmbYNvYWJvWGSWx26zK(GitHubos-litant, skills seat), claimed at 2026-09-10T09:03ZBranch:
claude/issue-17359-skills-capability-guidanceWorktree:
objectstack-issue-17359Domain:
domain:skillsFile surface:
skills/objectstack-data/rules/security.md,skills/objectstack-platform/SKILL.md— READ-ONLY in this dispatch: deliverable 1 (the assessment on this card); ⛔ no edit toskills/**until #17189's fix merges (the card's own condition) (stop on breach; explain in the report)Container & model:
M(a judgment card — the deliverable decides what a publishedskills/**surface will say; not mechanical),mode:subagent,model: claude-fable-5-1—node scripts/pm/dispatch-gates.mjs --tier skills/objectstack-data/rules/security.md skills/objectstack-platform/SKILL.mdat706ad0fprints 「Model tier — MANDATORY: claude-fable-5-1 … 'skills/**' — clause ① (2026-09-10 ruling, verbatim 「必须 fable的还包括对外发布的skills」) … no one-line exemption applies under this root」; passed explicitly as the dispatch's model parameter.Clause-②: no — an assessment; no accept set or public surface moves (any later text is guidance on an already-ruled contract, #17189 (i)).
Thread-read: none (0 comments on the card at claim time; body read in full; #17189's four comments incl. the ruling 5615806616 read).
Serial constraints cleared: no open PR touches the two files and no other claim on this lane names them (
git ls-remoteat claim: the lane's only branch was the merged #17302's, deleted); action facegit log -8 origin/main -- <the two files>newestb110578(same day — the dev works from currentorigin/maine669e5e); #17189 has no PR (closed_by_pull_requests0; spec seat vacant) ⇒ the text half stays blocked on it; H17 hold index names neither file; verify-lock free (--status: lock is free, queue empty).Generated by Claude Code
os-litant commentedon Sep 10, 2026
Dispatched — R1, 2026-09-10T09:09Z,
mode:subagent, build tierclaude-fable-5-1passed explicitly (clause ①: publishedskills/**is the surface under assessment). Claim 5616017852 is the dev's identity; branchclaude/issue-17359-skills-capability-guidance. Scope of this dispatch = deliverable 1 only (the assessment comment;pr: null); ⛔ no edit toskills/**until #17189's fix merges. Disjoint from #17164 (objectosCLAUDE.md) and #17346 (check-clause2-carriers.mjsC4 +contract-review.md:35–:37). Patrol timertrig_012AMK9J7RnbBAeY1WNEtrLAfires 09:49Z.Generated by Claude Code
os-litant commentedon Sep 10, 2026
Assessment
CHANGE NEEDED
One 3-line construct in
skills/objectstack-data/rules/security.md;skills/objectstack-platform/SKILL.mdunchanged. The text lands only after #17189's fix merges, because it teaches ruling (i)'s semantics, not the pre-fix refusal.Ruling assessed against (#17189 comment 5615806616, verbatim): 「
describeHighPrivilegeBits多收一个输入——本 stack 声明过的应用能力名单——名单内的名字不计为系统权限;启动侧拒绝与 lint 规则同笔跟随;ADR-0090 D5 的 offending 清单相应收窄为「平台系统权限;带 package provenance 的应用声明 capability 令牌不计」,ADR 修订走独立受管 PR」. Maintainer's instruction for this card, verbatim: 「17189 同意,但是同时评估是否需要改进skills」.Control
Tip read:
origin/main=e669e5e(e669e5eee296410731c8a00cba366369f005bc96), read 2026-09-10T09:1xZ. The two candidate files last moved atb110578(same day); both read at tip, in full forsecurity.md(210 lines) and by section for the platform file.git grep -n -iE 'isDefault|systemPermissions|capabilit|everyone|permission set' origin/main -- 'skills/**'→ 83 hits in 19 files:objectstack-data/references/data-hooks.md23 ·objectstack-platform/SKILL.md14 ·objectstack-data/SKILL.md10 ·objectstack-data/rules/security.md9 ·objectstack-ai/SKILL.md4 ·objectstack-upgrade/SKILL.md3 ·objectstack-ui/rules/pages.md3 ·objectstack-data/references/_index.md3 ·objectstack-ui/rules/navigation.md2 ·objectstack-platform/references/_index.md2 ·objectstack-automation/SKILL.md2 · one each inobjectstack-ui/rules/list-views.md,objectstack-ui/rules/actions.md,objectstack-ui/references/_index.md,objectstack-ui/SKILL.md,objectstack-formula/SKILL.md,objectstack-data/rules/indexing.md,objectstack-data/evals/README.md,skills/README.md.isDefault: exactly one hit,skills/objectstack-ui/rules/list-views.md:122(a list-view example).everyone:skills/objectstack-data/SKILL.md:78-79(sharing-model table) andskills/objectstack-formula/SKILL.md:409only.systemPermissions/system_permissions: zero.defineCapability/scope: 'org': zero (second grep, exit 1).capabilitiesinskills/objectstack-platform/SKILL.md: the top-level key list at :76 (name only) and therequires:section :435-482, which teaches the 28PLATFORM_CAPABILITY_TOKENS(kernel/platform-capabilities.ts) — a different registry from thecapabilities:stack key (security/capabilities.ts, ADR-0066 D1).Positive control
git grep -c definePermissionSet origin/main -- 'skills/**'→skills/objectstack-api/SKILL.md:1,skills/objectstack-data/rules/security.md:4— identical to the PM's reading ate669e5e.Zone-2 assumptions: A holds (as above). B holds and is wider than the card's one combination: the published skills teach neither the DEFINE key (
capabilities:/defineCapability) nor the GRANT key (systemPermissions);security.md:145's ownrequiredPermissions: ['view_pii']names an app token that no skill shows declared or granted anywhere (view_piiis not among the 9 curatedPLATFORM_CAPABILITIES). C is falsified in one half — see Reader.Reader
The reader is an AI author writing a metadata app's
permissions(andcapabilities) into the post-(i) world. Under (i) asystemPermissionsname is an app token only when it carries package provenance, i.e. when the stack declares it undercapabilities:(boot side: thesys_capabilityrow ismanaged_by:'package'; lint side: the stack's declaration list). The back-compat implicit derivation that ADR-0066 D1 keeps alive seeds an undeclared name asmanaged_by:'platform'with no package provenance (packages/plugins/plugin-security/src/bootstrap-declared-capabilities.ts:9-11, :230). So after the fix:isDefault: trueset binds toeveryonewith no warning — hotclm's intended shape works;'system permissions':security-anchor-high-privilege(error) and the boot refusal are unchanged, and the lint's fix-it hint (packages/lint/src/validate-security-posture.ts:781-783, "Split the powerful bits into a separate set granted through ordinary positions") walks the author into exactly hotclm#11's seven-per-position workaround instead of the declaration;manage_users,setup.access, … — the 9 curated names) or VAMA / delete / transfer / export on that set is refused, loudly, with the bit named.Value gate:
① Which decision the text changes: whether to declare the token under
capabilities:before granting it viasystemPermissionson theisDefault: trueset. Shape produced today without the text: the skills name none of the three keys, so an author reachessystemPermissionsfrom the schema alone (its.describe()is "System level capabilities") and writes the undeclared grant — the shape the skill's ownview_piiexample models. That shape still fails after the fix, and its diagnostic steers into the workaround. The plain "app tokens may ride on the default set" sentence (Zone 2 C) changes no decision post-fix — that shape simply works — so it is not what is written.② Deletion or rewrite instead of addition: no. No existing sentence in either file names
isDefault,systemPermissionsorcapabilities:, so there is nothing to rewrite; the only candidate neighbour (security.md:135-139,requiredPermissions, the REQUIRE side) is correct as written, and folding DEFINE/GRANT into it would be re-wrap paying for new content, which is not a currency.③ Construct over prose: yes — one bullet in the permission-set key list naming the three keys, the anchor, and the two things refused there.
Real-usage reading (axis ①, measured at
e669e5e):examples/app-showcasedeclares two capabilities (showcase.export_data,showcase.restricted_ops,src/security/capabilities.ts:52, :77) and grants one onOpsPermissionSet(permission-sets.ts:220); itsisDefaultsetshowcase_member_default(:295-346) deliberately carries nosystemPermissions. The DEFINE → GRANT → REQUIRE chain is taught only in that example's code comments (capabilities.ts:15-20), in no published skill. No other example carries the combination; the named consumer that does is hotclm (external, read through #17189's quotation — hotclm#11 itself answered 403 on both the API and the page from this seat).Four axes: business need — a named consumer hit the combination, and the post-fix failure mode is the undeclared variant an author reaches first from the schema; long-run — the rule is the permanent post-(i) contract ("declaration is what makes a token an app token"), not the pre-fix refusal, so it is not transitional; AI error — the construct closes the one silent-until-lint path; the contract-tightening alternative (retire the implicit derivation so an undeclared name is refused at
defineStack) is a spec-lane decision outside this card and would not remove the need to name the three keys; startup focus — +3 lines, one file, no new section.Proposal
skills/objectstack-data/rules/security.md— insert one bullet after line 33, inside the existing key list of "## Object-level permissions (RBAC)". Neighbours, verbatim ate669e5e:Proposed bullet (becomes lines 34-36; widths 81 / 82 / 90 — the file's longest existing lines are 93):
Net: +3 lines in
security.md. It names the anchor key, the anchor, the DEFINE and GRANT keys, and the two things that may not ride: a platform capability and an undeclared name. VAMA / delete / transfer / export are not restated — they are the "super-user" bits named two lines above, and the lint names them precisely when they occur.skills/objectstack-platform/SKILL.md— no change (0 lines). Its "capability" vocabulary is therequires:service-plugin tokens; teaching app-declared capabilities there would put two registries under one word in one file.capabilitiesstays a listed key at :76 whose semantics live beside the GRANT key insecurity.md.Total net across both files: +3 — within budget.
Negative example (hotclm#11's seven per-position bindings): not included. It is a pre-fix workaround, so text describing it is transitional (不渐进); an author following the construct never reaches it; it costs lines the budget does not have; and the one thing that steers a post-fix author toward it is the lint hint for the undeclared-name case, which lives in #17189's declared file surface (
packages/lint/src/validate-security-posture*), not in a skill.Wording dependency on #17189's landing: the bullet is correct under ruling (i) as recorded. If the fix PR also retires the implicit derivation (undeclared names refused at authoring), the words "or undeclared name" become redundant with the contract and should be dropped at landing; the other two lines stand either way. Two pre-fix sentences outside
skills/**that the fix PR should move in the same diff are listed in the dev report below (content/docs/permissions/permission-sets.mdx:223-225,examples/app-showcase/src/security/permission-sets.ts:290-291).Blocked-by
Blocked-by: #17189
Generated by Claude Code
os-litant commentedon Sep 10, 2026
os-dev-report
{ "issue": 17359, "status": "done", "branch": "claude/issue-17359-skills-capability-guidance", "pr": null, "premise_still_valid": true, "summary": "Assessment delivered as comment 5616225081 on #17359 (deliverable 1 only): verdict CHANGE NEEDED — one 3-line bullet in skills/objectstack-data/rules/security.md after line 33, skills/objectstack-platform/SKILL.md unchanged, negative example not included, Blocked-by: #17189. Zone-2 A and B hold (B is wider: the skills teach neither `capabilities:`/`defineCapability` nor `systemPermissions`); C is falsified in one half — under ruling (i) an UNDECLARED app token on the `isDefault` set still counts as a system permission (derived placeholders are managed_by 'platform', no package provenance), so the residual post-fix trap is two-directional and the construct names the declaration route. No file under skills/** edited; identity branch pushed empty; no PR by design.", "tests": "No code change; no test or build run. Control grep re-run at origin/main e669e5e: 83 hits / 19 files; isDefault only at skills/objectstack-ui/rules/list-views.md:122; everyone only at objectstack-data/SKILL.md:78-79 and objectstack-formula/SKILL.md:409; systemPermissions | defineCapability | scope: 'org' zero hits (exit 1). Positive control definePermissionSet: objectstack-api/SKILL.md:1, objectstack-data/rules/security.md:4. Decision-frame md5 22f2339f0acb64cdb50c7adc9db681c3 verified at e669e5e. Candidate bullet measured: 3 lines, widths 81/82/90 vs file max 93. dispatch-gates.mjs --commands on the branch: exit 2, 'this branch changes nothing against origin/main (merge base e669e5eee) — nothing to derive'.", "gates": [], "gates_reason": "empty diff — dispatch-gates.mjs derived nothing (exit 2, quoted in tests); verify lock not taken", "line_budget": { "skills/objectstack-data/rules/security.md": "+3 (proposed, not applied)", "skills/objectstack-platform/SKILL.md": "no edit", "total": "+3 of +3" }, "files_changed": [], "deviations": [ "no pnpm install in the worktree: assessment only — zero edits, zero gates to run", "hotclm#11 not read directly (REST 403 and page 403 from this seat); read through #17189's body quotation; add_repo read-attach answered git-only and was not used", "channel: every GitHub read and both writes went through repo-scoped REST (probe 200), GitHub MCP unused", "assessment comment read back: all section markers 1x, byte count equal (10027/10027); the only difference from the sent body is the footer block, which the platform re-laid (one rule line, one footer)" ], "mcp_calls": "0 — GitHub MCP unused; one Claude_Code_Remote add_repo call (not GitHub MCP)", "open_questions": [], "out_of_scope_findings": [ "noted, not filed: published skills teach neither the DEFINE key (`capabilities:`/`defineCapability`) nor the GRANT key (`systemPermissions`); security.md:145 `view_pii` is an app token no skill shows declared or granted — 承接者: skills seat (the wider gap the card's combination sits inside)", "noted, not filed: packages/lint/src/validate-security-posture.ts:781-783 fix-it hint steers an undeclared-app-token author into the per-position workaround post-fix — a warning pointing at metadata the runtime honours but makes worse (boundary, not class c) — 承接者: #17189's implementing PR (file in its declared surface)", "noted, not filed: content/docs/permissions/permission-sets.mdx:223-225 lists 'system permissions' among anchor-forbidden bits and says 'nothing auto-binds', while PermissionSetSchema.isDefault .describe() says app-level sets are auto-bound at boot — pre-fix wording in a hand-written docs tree — 承接者: #17189's implementing PR", "noted, not filed: examples/app-showcase/src/security/permission-sets.ts:290-291 comment 'the D7 lint hard-blocks ... system permissions' — pre-fix wording — 承接者: #17189's implementing PR", "noted, not filed: the word 'capability' names two registries in skills/objectstack-platform/SKILL.md (`requires:` tokens vs the `capabilities:` key); a string array under `capabilities:` is refused loudly by the strict CapabilityDeclarationSchema, no failing probe — 承接者: skills seat" ] }Generated by Claude Code
os-litant commentedon Sep 10, 2026
ACCEPT (deliverable 1 — the assessment, comment 5616225081) — reviewed in-seat at the contract-review tier (skills seat, session
session_01YKEjmbYNvYWJvWGSWx26zK, 2026-09-10T09:25Z).claude/issue-17359-skills-capability-guidance(claim 5616017852; build tier claude-fable-5-1 passed explicitly;mode:subagent). Reviewed-by:session_01YKEjmbYNvYWJvWGSWx26zK(the skills seat) — independence pair holds.pr: null,status: done,files_changedempty,gates: []with the reason quoted fromdispatch-gates.mjs— exit 2 on an empty diff); the identity branch sits ate669e5ewith no commits; worktree removed; report shape correct;open_questionsempty; report read back on the card (5616244069).origin/main(143c715at 09:2xZ; the two skill files unchanged sinceb110578):security.md:31–:34 neighbours verbatim as quoted, 210 lines, widest line 93;packages/spec/src/security/capabilities.ts:86–:102 (a declaration carriesmanaged_by:'package'+package_id; the implicit derivation still runs for back-compat);packages/plugins/plugin-security/src/bootstrap-declared-capabilities.ts:9–:11 and :230 (an undeclared name falls back to the derived placeholder with no package provenance);packages/lint/src/validate-security-posture.ts:778–:784 (the fix-it hint steers to the per-position split);security.md:145requiredPermissions: ['view_pii']. The control grep ate669e5ematches this seat's own reading at706ad0f.skills/objectstack-data/rules/security.mdafter :33,skills/objectstack-platform/SKILL.mdunchanged, no negative example; within the +3 budget. The value-gate reading carries the decision: under ruling (i) a DECLARED app token on theisDefault: trueset binds toeveryone, an UNDECLARED one still reads as a system permission, and no published skill names any of the three keys — so the text changes the author's decision to declare before granting. Zone-2 C half-falsified by the dev; accepted.bindBaselineToEveryone), it does not fail; the landed sentence must say "is refused by lint and at boot" or equivalent. The dependency the dev names stands: if An app-declaredcapabilitywithscope: 'org'counts as a high-privilege bit, so a set carrying only app capability tokens cannot bind to theeveryoneanchor #17189's PR also retires the implicit derivation, drop "or undeclared name" at landing.noted, not filed; three-class test applied): none is class (a)/(b)/(c) — an undeclared-token grant still resolves (back-compat), so nothing is refused or dropped; the lint-hint item is the recorded boundary (a warning steering to worse metadata). Items 2–4 (the lint hint :778–:784;content/docs/permissions/permission-sets.mdx:223–:225;examples/app-showcase/src/security/permission-sets.ts:290–:291) are relayed to An app-declaredcapabilitywithscope: 'org'counts as a high-privilege bit, so a set carrying only app capability tokens cannot bind to theeveryoneanchor #17189 for its implementing dev (the record stays 5616225081). Items 1 and 5 (DEFINE/GRANT keys untaught anywhere; the two "capability" registries in the platform skill) are this seat's — folded into the text dispatch's reading, ⛔ not into its budget.pm:dispatched→pm:blocked;Blocked-by: #17189appended to the body (the fix has no PR yet; the spec seat is vacant). Release: sessionsession_01YKEjmbYNvYWJvWGSWx26zK; reason = deliverable 1 done, deliverable 2 waits on An app-declaredcapabilitywithscope: 'org'counts as a high-privilege bit, so a set carrying only app capability tokens cannot bind to theeveryoneanchor #17189's fix merging; destination =pm:blocked, back topm:queueby the unlock scan when An app-declaredcapabilitywithscope: 'org'counts as a high-privilege bit, so a set carrying only app capability tokens cannot bind to theeveryoneanchor #17189 closes. Assignee cleared in the same act.skills/**), budget +3 lines insecurity.mdonly, the bullet from 5616225081 with the boot-wording correction above and the "undeclared" clause re-checked against the merged fix; governed ⇒ draft PR + 速读草稿, skills-seat review at tier, human merge.Generated by Claude Code
os-justin commentedon Sep 16, 2026
pm:blocked→pm:queue— unlock scan, skills seat,session_01Gqi43smmqjJ5sUrhfoPeKu, 2026-09-16T20:44Z.Double-check on the last transition (5616301504, 2026-09-10T09:25Z: 「back to
pm:queueby the unlock scan when #17189 closes」): ① #17189 is closedcompleted(2026-09-15T15:05Z, director exit 5682637828) — its fix PR #17811 merged 2026-09-14T04:19Z (d5c91dd6, files:packages/spec/src/security/high-privilege.ts+ test + api-surface + changeset) after the ADR PR #17814 (2026-09-13T15:12Z,docs/adr/0090-…); ② no PR references this card (closed_by_pull_requests0) ⇒ nothing newer to refuse on. Re-verified onorigin/main2496415:skills/objectstack-data/rules/security.mdis untouched since the assessment (last touch6a3bcd8, 211 lines; the :31–:34 neighbours read as quoted in 5616225081);bootstrap-declared-capabilities.ts's docblock still describes the implicitsystemPermissionsplaceholder derivation (managed_by:'platform', claimed by an explicit declaration) ⇒ the 「or undeclared name」 clause of the proposed bullet is still live post-fix, subject to the dispatch's re-read of the merged predicate inhigh-privilege.ts.Blocked-by: #17189removed from the body in the same act; the pre-written re-dispatch shape (5616301504) is executed next: one dev at the contract-review tier, +3 lines insecurity.mdonly, boot wording 「refused by lint and at boot」.Generated by Claude Code
8 remaining items
os-justin commentedon Sep 17, 2026
Ruling recorded — the
security.mdtoken ceiling is raised to 2543. Skills seat,session_01Gqi43smmqjJ5sUrhfoPeKu, 2026-09-17T07:15Z. Maintainer, verbatim, in this seat's chat: 「security.md 允许增加到 2543」 — answering the 需裁 item put in the round report (park record 5704584550 on this card, park note 5704585750 on PR #18531:skills/objectstack-data/rules/security.mdreads 2543 tokens on head4ea43892, ceiling 2480, over by 63; recommendation A = raise).What this discharges: release condition ② of the park. The raise lands in PR #18531 itself: the ratchet row
['skills/objectstack-data/rules/security.md', 2480]inscripts/check-skills-token-ratchet.mjsbecomes 2543 with this ruling quoted beside it, and the PR body quotes it — the ratchet's own rule (「the other direction lands only in a PR whose body quotes a maintainer ruling authorizing it」).What it does not discharge: release condition ① — #18535 (the declared app capability token is still refused at the
everyoneanchor becausedescribeHighPrivilegeBits's consumers pass nodeclaredCapabilities), which the three lines describe as already true. #18535 is ownerless (barefinding, no lane, no assignee, 0 comments since filing); per SKILL.md 「阻塞项无主 ⇒ 被挡席认领做掉」 this seat claims and dispatches it next; PR #18531's single patch round (mergeorigin/main, the ceiling raise quoting this ruling,skills/**gates re-run) follows #18535's landing, then the four-piece.Generated by Claude Code
os-justin commentedon Sep 17, 2026
Unparked — release condition ① discharged; the single patch round is dispatched. Skills seat,
session_01Gqi43smmqjJ5sUrhfoPeKu, 2026-09-17T09:01Z. #18535 landed onorigin/mainas21b7c12b4at 2026-09-17T09:00:08Z (landing record 5711759365): the four consumers of the anchor predicate now pass the stack's declared capabilities, so the three lines PR #18531 adds toskills/objectstack-data/rules/security.mddescribe landed behaviour (「文档应该以实际实现为准」). Condition ② was ruled at 5710537499 (「security.md 允许增加到 2543」). Same act:pm:blocked→pm:dispatched(assignee unchanged), theBlocked-by:/Unlock-action:lines dropped from the body.Claim continues — patch round (the seat's re-dispatch on the same branch; round 2 of the original claim)
Session:
session_01Gqi43smmqjJ5sUrhfoPeKuBranch:
claude/issue-17359-skills-capability-guidance(PR #18531, head4ea43892before the round)Worktree:
objectstack-issue-17359Domain:
domain:skillsSeat:
domain:skills#1File surface:
skills/objectstack-data/rules/security.md(the three accepted lines, unchanged unless the merge oforigin/mainrequires re-anchoring; re-count) ·scripts/check-skills-token-ratchet.mjs(row :424 on21b7c12b4,['skills/objectstack-data/rules/security.md', 2480]→ 2543 with the ruling quoted verbatim beside it, in the file's own raise-ritual form) · the PR body quotes the ruling (the ratchet's rule for a raise) (stop on breach; explain in the report). ⛔ No other skill file, ⛔ no other ceiling.Container & model:
S(合 main + 抬上限引裁定),mode:subagent,model: claude-fable-5-1—node scripts/pm/dispatch-gates.mjs --tier --repo objectstack-ai/objectstack skills/objectstack-data/rules/security.md scripts/check-skills-token-ratchet.mjsat 2026-09-17T09:01Z on the fast-forwarded tree: 「Model tier — MANDATORY: claude-fable-5-1」 (publishedskills/**); no downgrade exit takenClause-②: no
Thread-read: 5710537499
Serial constraints cleared:
security.mdhot-file — no other open PR touches it (this seat's own PR #18531 is the carrier); the branch mergesorigin/maincleanly (git merge-treeat 2026-09-17T08:43Z: no conflict, 35 commits behind);os-verify-lock.sh --statusat 2026-09-17T09:01Z: free; shared checkout fast-forwarded toorigin/main21b7c12b4.Ruling-ref: 5710537499
Generated by Claude Code
chore(scripts): raise the security.md skills token ceiling to 2543 un…
os-justin commentedon Sep 17, 2026
os-dev-report
{ "issue": 17359, "status": "done", "branch": "claude/issue-17359-skills-capability-guidance", "pr": "https://github.com/objectstack-ai/objectstack/pull/18531", "head": "dfe355143c2e8debd21e886aa30c594d26e3be6e", "merge_commit": "68e1b07e18742a169ed93208d8d5c38c5b815628 — git merge --no-ff origin/main (21b7c12b4) into the branch; no rebase, no force-push, no new PR; clean (merge-tree exit 0, 37 commits behind); no os-regen-pending", "files": [ "scripts/check-skills-token-ratchet.mjs (+10/−1: CEILINGS row 2480 → 2543 with the ruling quoted verbatim beside it, in the file's own raise-ritual form)", "skills/objectstack-data/rules/security.md (+3/−0 vs origin/main; byte-identical to 4ea43892 — no clause corrected)" ], "session": "session_01Gqi43smmqjJ5sUrhfoPeKu", "premise_still_valid": true, "summary": "Patch round on PR #18531 (draft, still draft). Merged origin/main 21b7c12b4 as merge commit 68e1b07e1 (#18535 landed, so the three security.md lines now describe landed boot and lint behaviour; re-read against declared-capability-context.ts, the boot bind in security-plugin.ts and the lint rule in validate-security-posture.ts — every clause true, none corrected). Re-counted security.md after the merge: 2543 tokens, not above the ruling, so the ratchet row was raised 2480 → 2543 (commit dfe355143) with the maintainer ruling 「security.md 允许增加到 2543」 (2026-09-17, record 5710537499) quoted verbatim beside the row and in the PR body's appended 'Patch round' section; the 速读 draft's 改了什么/风险/你要做的 carry a dated update; a status line marks the body's original Blocked-by paragraph as discharged. 40 derived gates all exit 0 (the previously expected-red ratchet now green); GOVERNED — landing stays the maintainer's. Assignee untouched (os-justin, set by the dispatch).", "measurements": { "tokens_security_md": "convention ceil(utf8 bytes / 4): origin/main 21b7c12b4 = 9913 bytes → 2479 (main did not touch the file); branch head before the round 4ea43892 = 10170 bytes → 2543; after the merge (68e1b07e1 and head dfe355143) = 10170 bytes → 2543 — not more than 2543, so the raise equals the ruling", "ratchet_row": "before: ['skills/objectstack-data/rules/security.md', 2480] (line 424 on 21b7c12b4); after: ['skills/objectstack-data/rules/security.md', 2543] (line 433 on dfe355143); comment beside it ends: Maintainer ruling 2026-09-17 (recorded on #17359 as comment 5710537499), verbatim and untranslated: 「security.md 允许增加到 2543」; +63 tokens, zero headroom, ceiling +63; no other row moved", "three_lines_reread": "clause 1 (isDefault: true = the everyone baseline, ADR-0090 D5): still true — packages/spec/src/security/permission.zod.ts:682 describe('[ADR-0090 D5] App baseline for the everyone position …'), ADR-0090 D5 at docs/adr/0090-…:46. clause 2 (may carry app capabilities declared under capabilities: (defineCapability) and granted via systemPermissions): now true at boot and in lint, protocol-only before #18535 — packages/plugins/plugin-security/src/declared-capability-context.ts readDeclaredCapabilityContext reads the stack's capabilities: declarations; security-plugin.ts:3592–3595 describeHighPrivilegeBits(boot, anchorContext); engine write gate :5503–5508; suggested-audience-bindings.ts:968–972; packages/lint/src/validate-security-posture.ts:439–443 builds anchorContext from stack.capabilities, :795 passes it. clause 3 (lint and boot refuse a platform capability or undeclared name there): still true — high-privilege.ts:70–74 platform floor (PLATFORM_CAPABILITY_NAMES never excused), :134 「Omission refuses」 (a token absent from declaredCapabilities stays offending); lint emits security-anchor-high-privilege at severity error (:795–808); boot logs '[security] refusing to bind fallback set to everyone — high-privilege bits' and skips the binding (:3595–3600). No clause corrected.", "line_readings": "security.md 211 → 214 lines (+3), widest line 93; package (10 SKILL.md + objectstack-data rules/references, 20 files) 8959 → 8962", "governed": "node scripts/pm/check-governed-merges.mjs --test security.md check-skills-token-ratchet.mjs → exit 3 「GOVERNED — a human merge is the review record for this PR」 (1 of 2 paths; skills/** rules layer)", "labels": "read back after the round: documentation, size/s, skip-changeset — no label written this round; skip-changeset still holds (repo-root gate script in the private root package; skills/** ships in no files[])", "pr_body": "PATCH /pulls/18531 → 200; read back: 'Patch round' section, the verbatim ruling, the status line, the 速读 update and the 40-line gate list all present; stored 20496 bytes = sent 20438 + 58 (the platform appended one bare footer beside the kept session-URL footer — the recorded REST-PATCH reading); draft unchanged true; 0 less-than characters; closing keyword only Fixes #17359" }, "tests": "Gates on dfe355143 in worktree objectstack-issue-17359: node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack derived 40 (change set 2 paths vs merge base 21b7c12b4); all 40 run with redirect-then-$? capture; --ran reconcile 「40 derived, 40 run, 0 NOT-MEASURED, 0 UNRUN」 exit 0; all 40 exit 0. Named: node scripts/check-skills-token-ratchet.mjs → 「✓ check-skills-token-ratchet: skills/objectstack-data/rules/security.md is 2543 tokens (ceiling 2543; headroom 0).」 and 「34 authored bundle file(s) within their ceilings; 10 generator-owned file(s) measured, not ratcheted.」; --self-test 「65 cases pass」; pnpm check:ratchet-remedy-authority OK (255 scripts swept; 15 mark the expanding remedy ⛔ MAINTAINER-ONLY — unchanged); pnpm check:skill-frame-sync ✓ (14 self-test cases; frame coherent); check:skill-compatibility, check:skill-identifier-liveness, check:role-word, check:doc-authoring, check:corpus-claim-drift, check:nul-bytes, check:pm-governed-merges, check:pm-dispatch-gates (626 s, completed in the background after the foreground cap, exit 0 from the runner's own redirect), check:cross-package-test-inputs, check:entry-guard, check:parse-guard, check:watch-hint-literal and the rest → exit 0; pnpm --filter @objectstack/lint run check:doc-formula-expressions → exit 0 after building '@objectstack/lint...' under scripts/pm/os-verify-lock.sh (「VERDICT command-exit 0 · held the lock 136s · waited 0s」). Ablation from the committed head (trap-restored, absolute paths, no dist involved — the gate reads its own source): row reverted to 2480 on disk (grep counts 2480-row 1 / 2543-row 0) → gate exit 1 「✗ … is 2543 tokens; the ratchet ceiling is 2480 (over by 63) … ⛔ MAINTAINER-ONLY」; restored with git checkout HEAD -- path: git hash-object = HEAD blob 5b984866, git diff HEAD empty, git status --porcelain empty, gate exit 0 again. Control characters: grep -naP over both touched files → no match (exit 1). No ① dependency-closure build and no ② package test owed (no package touched); the artifact-roster / wide-population / pending-changeset families are CI's own. Pre-push hook: 「check:commit-card-trailers: … no card relation and no model identifier in the trailer pair」 on both pushes. Cleanup: node_modules deleted, git worktree remove exit 0 (no --force).", "mcp_calls": "0 — no MCP GitHub tool called; every GitHub read and write went through REST curl with GITHUB_TOKEN", "api_writes": "2 — PATCH /repos/objectstack-ai/objectstack/pulls/18531 (body), POST /repos/objectstack-ai/objectstack/issues/17359/comments (this report); plus 2 git pushes to the branch (68e1b07e1, dfe355143); no label write, no POST /pulls, no POST /issues, no assignee write", "open_questions": [], "out_of_scope_findings": [ "noted, not filed (承接者: 无): pnpm check:pm-dispatch-gates took 626 s on this shared box and overran the ~10-minute foreground cap (completed in the background, exit 0); platform-readings line 427 already records 430–450 s single-machine and prescribes detaching with tail --pid — the reading is low under contention, not wrong", "noted, not filed (承接者: the skills seat at the four-piece): the PR body's original top paragraph (Blocked-by #17189 step-②) is historical; a dated status line was inserted above it instead of rewriting it, so the original reasoning stays readable" ] }Generated by Claude Code
os-justin commentedon Sep 17, 2026
ACCEPT (patch round) — in-seat contract-tier review of PR #18531 at head
dfe355143(report 5712105389) by the skills seat, 2026-09-17T09:31Z. Verified against GitHub and a scratch worktree at the head, ⛔ not against the report:skills/objectstack-data/rules/security.mdon the head is byte-identical to the ACCEPTED head4ea43892(git diffempty) — the three lines after the RBACSource:line (ACCEPT of the construct 5616301504, assessment 5616225081); +3 lines vsorigin/main, 211 → 214. The seat re-read the three clauses against the landed A declared app capability token is still refused at theeveryoneanchor:describeHighPrivilegeBits's consumers pass nodeclaredCapabilities(PR #17811 landed the spec predicate only) #18535 code (declared-capability-context.ts;security-plugin.tsboot bind and write gate;suggested-audience-bindings.ts;validate-security-posture.ts:439–:443 / :795) andhigh-privilege.ts(platform floor :70–:74, 「omission refuses」 :134): all three true onorigin/main21b7c12b4; none needed correction.68e1b07e1mergesorigin/main21b7c12b4(no rebase, no force-push); merge base =origin/main; only the two intended files differ from main.scripts/check-skills-token-ratchet.mjsrow['skills/objectstack-data/rules/security.md', 2480]→2543with the raise comment quoting the maintainer verbatim and untranslated — 「security.md 允许增加到 2543」 (2026-09-17, record 5710537499) — and the PR body quoting it in its 「Patch round」 section; no other row moved. Measured on the head: 10170 bytes → 2543 tokens (ceil(utf8 bytes / 4));check-skills-token-ratchet「is 2543 tokens (ceiling 2543; headroom 0)」,--self-test65 cases;check:skill-frame-sync0;--pair 18531→ 0 (Clause-②: no).check-governed-merges --test→ GOVERNED (skills/**, rules layer). The report's 40 derived gates all exit 0, re-derived here for the ratchet, the frame sync and the pair.check:pm-dispatch-gatesunder contention; the body's historicalBlocked-byparagraph kept under a dated status line) — nothing to file.Rules layer (published
skills/**) ⇒ the four-piece is hung on PR #18531 in the same act: 维护者速读(终稿),needs-user-decision, review requested fromos-zhuangandhotlong. An authorized APPROVED lands it by ruling C (the CI head was still finishing one job at review time; the landing pre-check re-reads it); a human merge is equally the record.Generated by Claude Code
os-justin commentedon Sep 17, 2026
Authorized approval received — ruling C: the seat lands it. Skills seat,
session_01Gqi43smmqjJ5sUrhfoPeKu, 2026-09-17T09:37Z. Read on GitHub: PR #18531 (headdfe355143) carries review 5233769130 APPROVED byos-zhuang(inGOVERNED_APPROVERS) at 2026-09-17T09:37:20Z on the current head, and the same account flipped it ready at 2026-09-17T09:37:24Z. Landing pre-checks on this head: CI final 27 success / 15 rostered skips (check-expected-skipsOK at 2026-09-17T09:34Z),--pair 185310, harness CURRENT (re-taken now), mergeable clean. Same act:needs-user-decisionremoved from the PR (the label leaves with the approval); the seat arms auto-merge SQUASH through the CCR route next unless the approver already enqueued it; the landing record followsmerged_at.Generated by Claude Code
os-justin commentedon Sep 17, 2026
Landing record — skills seat,
session_01Gqi43smmqjJ5sUrhfoPeKu, 2026-09-17T09:54Z. PR #18531 (headdfe355143) MERGED through the merge queue at 2026-09-17T09:53:14Z (merged_at) as7299b945a2fcdc649de1a59ac71a006c6f38ff9b— single parentd5e64d8d9pergit rev-list --parents(a squash);merged_byos-zhuang, the authorized approver who approved (5233769130), flipped ready and enqueued it by hand — ruling C completed by the approver's own act; the seat's part was the construct review (5616301504), the park and its discharge (5704584550 → 5711767613), the patch-round review (5712132917), the label strip (5712211637) and this record. Verified onorigin/mainby git at 2026-09-17T09:53:36Z: the squash is an ancestor;git log --oneline origin/main | grep -F '(#18531)'hits;skills/objectstack-data/rules/security.mdcarries the three lines (214 lines, 2543 tokens byceil(utf8 bytes / 4)); the ratchet row reads['skills/objectstack-data/rules/security.md', 2543]with the ruling 「security.md 允许增加到 2543」 quoted beside it; the queue ref is gone. Same act:pm:dispatchedremoved and the assignee cleared on this auto-closed card (Fixes #17359,completed);domain:skillsstays. Downstream: #17189's rider is discharged (the published guidance now teaches the DECLARE/GRANT pair and the runtime + lint honour it since #18535); hotclm#11's workaround waits on the release that ships@objectstack/plugin-security/@objectstack/lintatminor.Generated by Claude Code
docs(skills): teach the isDefault everyone baseline and its app-capab…