Uh oh!
There was an error while loading. Please reload this page.
skills(data): split security into rules/security.md under #14296 item 1 (package net −64 tokens) + DATA-B-06 - #14673
Merged
Conversation
DATA-I-04. The entry file carried a 239-line Security & Access Control block; six of its seven subsections move verbatim into a new `skills/objectstack-data/rules/security.md`. No sentence is added: the new file's only new bytes are its H1, and the entry keeps a one-line pointer plus one row in the routing table. `### Access depth (scope-depth)` stays in SKILL.md. It is a registered exhaustive section in `check:skill-identifier-liveness` Leg 2 (`access-scope-depth` -> `ObjectAccessScopeSchema`), keyed by file path plus heading, and a bound heading never leaves its file. Three declared deletions inside the moved text, each a duplicate that the split would otherwise carry across a file boundary: - `### Cross-skill notes` (3 bullets) — objectstack-api and objectstack-platform are routed by the entry's Skill Boundaries table, objectstack-formula by the frontmatter and by three other entry sites. - the `sharingModel` four-value re-enumeration in the RLS bullet — the exhaustive table lives in the entry's Required properties block. - Multi-tenancy's forward-pointer bullet to the visibility-posture recipe directly beneath it. Ceilings, per the ruling's condition (b): one row for the new file pinned at its landed count (2480), the entry row re-locked at its landed count (13892 -> 10009). No other row changes. Package (every file under skills/objectstack-data/, generated included): 38,219 -> 38,155 tokens, net -64. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LraLgQVGq8egUwfYZpbYt1
DATA-B-06 (MOVE-TO). The 9-row table telling an agent which `rules/` file answers its question sat at line 283 of 1,067, behind Core Concepts, the `searchableFields` section and Field Groups; an agent that stops reading early never learns `rules/` exists. It now sits directly after the Skill Boundaries table, which is the other routing construct in the file. Byte-neutral: the same 16 lines, moved. SKILL.md is 40,034 bytes before and after, so the ceiling re-locked in the previous commit still holds exactly. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LraLgQVGq8egUwfYZpbYt1
…ills-data-security-split
`check:role-word` went red as a ratchet-DOWN: the entry file's count improved 2 -> 1 because the deleted `### Cross-skill notes` bullet carried "role inheritance". The other occurrence is untouched, and the new `rules/security.md` carries none, so no entry is added. The remedy is the gate's own author-side one (`--update`), one shrinking line. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LraLgQVGq8egUwfYZpbYt1
…ills-data-security-split
os-zhuang
approved these changes
Sep 2, 2026
os-zhuang
marked this pull request as ready for review
September 2, 2026 22:51
os-zhuang
enabled auto-merge
September 2, 2026 22:51
Uh oh!
There was an error while loading. Please reload this page.
This was referenced Sep 3, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for freeto join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Part of #14297 — round 2 takes the deferred DATA-I-04 split plus DATA-B-06. The card stays open because DATA-F-07 (the
defineHook()prescription) is a maintainer call parked on decision batch 3, so this PR must not carry a closing keyword for that card.The two rulings
SKILL.mdinto entry +rules/are authorized within program Skills catalog optimization program (maintainer-directed): audit every skill on both roots, then optimize — program anchor #14292, under the three conditions as written: the same PR nets ≥10% off the whole package's token count; every new file's ceiling is pinned at its landed count; a split is never a channel for added prose."The three conditions, with numbers
(a) Token-neutral or negative on the package. Package = every file under
skills/objectstack-data/, generated included, measured withnode scripts/check-skills-token-ratchet.mjsbefore and after.references/_index.md(generated)ca48cf37b3b3cdabProgramme-level account for this package: 45,780 authored at the audit pin → 36,736 after round 1 (−9,044) → 36,672 after this PR (−64). Programme total −9,108, −19.9%.
(b) Ceiling rows — exactly two, no others.
skills/objectstack-data/rules/security.mdskills/objectstack-data/SKILL.mdThe entry row carried 1,339 of headroom at base, left un-re-locked by round 1; the re-lock takes all of it.
git diffonscripts/check-skills-token-ratchet.mjsis those two rows and their comments — no third row moves.(c) No added prose. Every sentence in
rules/security.mdis a sentence moved out ofSKILL.md. The new file's only new bytes are its H1 (# Security & Access Control, 28 bytes); six moved###headings are demoted to##(−6 bytes). The entry gains one pointer line and one routing-table row, inside the "at most one line per moved section" allowance for six moved sections. Three sentences were deleted rather than moved — each listed below.File map
### Object-level permissions (RBAC)rules/security.md## Object-level permissions (RBAC)### Assigning a permission set to a userrules/security.md## Assigning a permission set to a user### Row-Level Security (RLS)rules/security.md## Row-Level Security (RLS)### Sensitive fields — secret type + requiredPermissionsrules/security.md## Sensitive fields …### Multi-tenancyrules/security.md## Multi-tenancy### Platform-global / admin-only objects (visibility posture)rules/security.md## Platform-global / admin-only objects …### Access depth (scope-depth) — …SKILL.md— Leg-2 bound, see belowpermissions/hookskey)SKILL.md— it is a rule about whatObjectSchema.create()refuses, and that belongs where objects are authored### Cross-skill notesPer-move record
rules/)skills/objectstack-data/rules/security.md(new)SKILL.md12,553 tok; the Security & Access Control block is 239 lines / 2,867 tok of itSKILL.md10,009 tok (−2,544);rules/security.md2,480 tok; package −64skills/objectstack-data/SKILL.md, directly after the Skill Boundaries tablerules/routing table sat at line 283 of 1,067, behind Core Concepts, thesearchableFieldssection and Field GroupsSKILL.mdis 40,034 bytes immediately before and immediately after the moveThe Leg-2 constraint and its cost
check:skill-identifier-livenessLeg 2 registersaccess-scope-depth— fileskills/objectstack-data/SKILL.md, heading### Access depth (scope-depth) — the ERP "see my unit / my unit and below" axis, symbolObjectAccessScopeSchema— and the binding is keyed by file path plus heading, so a bound heading never leaves its file. That section and its exhaustive value list (own·own_and_reports·unit·unit_and_below·org) therefore stay in the entry while the rest of the security topic moves.The cost, stated rather than hidden: one topic now spans two files. A reader of
rules/security.mdgets RBAC bits, assignment, RLS,secret/requiredPermissions,tenancyand the platform-global posture; the declarative widening axis that composes with all of them is in the entry. The entry's pointer names the split so the reader is not left to discover it.scripts/check-skill-identifier-liveness.mjsis not edited by this PR.Declared deletions (three)
Each is a duplicate the split would otherwise have carried across a file boundary, and each is inside the moved text, which is what "minus deletions" in condition (c) permits.
### Cross-skill notes(3 bullets, 77 tok). objectstack-api and objectstack-platform are already routed by the entry's own Skill Boundaries table; objectstack-formula is routed by the frontmatter and by three other entry sites (Conditional Field Rules,Field Type Selection,Linting & Generation Quality).sharingModelfour-value re-enumeration in the RLS section's owner-scoping bullet. The exhaustive table for those four values is in the entry's Required-properties block (added by round 1's DATA-F-01); after the split the parenthetical would be a second, unratcheted copy in another file. The bullet keepssharingModeland its ADR-0056 D1 citation.tenancy: { enabled: false }… see the visibility-posture recipe below"), which points at the section immediately beneath it, where the same two keys are stated and explained at length.Premise notes
No finding was skipped as
premise_false. One recorded qualification: DATA-I-04's stated rationale included "sits exactly at its ceiling, so any true addition must be paid for inside it", which round 1 already retired — at this PR's baseSKILL.mdmeasured 12,553 against a 13,892 ceiling, 1,339 of headroom. The finding's primary ground (progressive disclosure: the entry did not shrink to match the eightrules/files it already has) is untouched, and #14568 = A ordered the split independently, so it is executed as written and the ceiling is re-locked to take the stale headroom back.DATA-B-06's premise holds as written, with re-measured numbers: an 8-row table at line 312 of 1,216 at the audit pin is a 9-row table at line 283 of 1,067 at this base.
Gates — head
b3b3cdabThe derived family is
node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack --commandsre-derived after the last move against the real 4-path change set (scripts/check-skills-token-ratchet.mjs,scripts/role-word-baseline.json,skills/objectstack-data/SKILL.md,skills/objectstack-data/rules/security.md): 25 commands. Seven more were run that the derivation does not name but this change owes: the card's fence gates and the self-tests. All 32 ran underscripts/pm/os-verify-lock.shwithOS_VERIFY_LOCK_SLOT=issue-14297-r2; every exit code was captured by redirecting first and reading$?before any pipe.31 exit 0, 1 exit 3 (NOT MEASURED). Each gate's own verdict line:
node scripts/check-skills-token-ratchet.mjs32 authored bundle file(s) within their ceilings; 11 generator-owned file(s) measured, not ratchetednode scripts/check-skills-token-ratchet.mjs --self-test64 cases passpnpm check:skill-identifier-livenessLeg 1: 465 citation(s) over 42 published file(s) … Leg 2: 8 registered exhaustive section(s), 0 ledgered gap(s)pnpm --filter @objectstack/spec run check:skill-examples256 prose examples type-check across 3 surface(s) — every marked block parsed, so tsc ran the SEMANTIC pass on all of thempnpm --filter @objectstack/spec run check:skill-docsSkill docs in syncpnpm --filter @objectstack/spec run check:skill-refs9 generated files in sync with packages/specpnpm check:skill-compatibility11 SKILL.md file(s) reconciled against 79 workspace packagespnpm check:role-wordOK, no new occurrences of the reserved wordpnpm check:published-readme-links176 outbound link(s) across 60 published markdown file(s): 0 root-relative, 0 non-canonical origin(s)pnpm check:nul-bytesscanned 8000 text file(s) … no raw ASCII control bytespnpm check:pm-skill-ratchetCLAUDE.md is 86 lines (ceiling 86; headroom 0)— untouched, as requiredpnpm check:pm-dispatch-gatesdispatch-gates self-test: 1240 cases passpnpm check:pm-governed-merges243 assertionspnpm check:skill-frame-sync4 copies of the decision frame are structurally isomorphic across 3 filespnpm check:ratchet-remedy-authority184 scripts swept … 12 mark the expanding remedy MAINTAINER-ONLYnode scripts/check-ci-filter-parity.mjsall 130 declared cross-package glob(s) (92 unique) are coverednode scripts/check-cross-package-test-inputs.mjs·pnpm check:cross-package-test-inputs25 package(s) read outside themselves, all declarednode scripts/check-shard-attestation.mjs2 aggregate gate(s) count 3 declared leg(s) across 3 attesting job(s)node scripts/pm/bare-root-worklist.mjs --self-test57 live row(s), 49 unreachable as spelled, 49 recorded verdict(s)pnpm --filter @objectstack/lint run check:doc-formula-expressions14 predicate(s) on a statically determinable field layer judged cleanpnpm check:agent-test-spelling0 violations — 426 file(s)pnpm check:bash32-floor26 tracked shell file(s) … name no bash 4+ constructpnpm check:cli-command-ids315 command-id literal(s) across 112 file(s) … all resolvepnpm check:corpus-claim-driftOK, no new claim sites beside a pinned spellingpnpm check:doc-authoring831 pinned site(s) across 231 file(s)pnpm check:entry-guard199 scripts/ file(s) — every entry guard goes through invoked-as.mjspnpm check:parse-guard198 scripts/ file(s) — every TypeScript parse goes through ts-parse.mjspnpm check:pnpm-filter-targets142/181 --filter occurrence(s) across 32 file(s) resolvepnpm check:watch-hint-literal45 declaration(s) across 4 rostered name(s)node scripts/check-skill-identifier-liveness.mjs --listaccess-scope-depthstill resolves inSKILL.mdnode scripts/check-test-completeness.mjsPREREQUISITE NOT MET — this gate grades a saved turbo run test log, and no log was namedcheck:skill-examplesfailed once, at exit 1, before it was measured:packages/spec/dist/**/*.d.ts is OLDER than packages/spec/srcafterorigin/mainwas merged in. That is the gate refusing to compute a verdict against a stale build, not a finding. It was re-run afterpnpm --workspace-concurrency=2 --filter '@objectstack/spec...' --filter '@objectstack/client-react...' --filter '@objectstack/client...' run buildand is the exit 0 recorded above.NOT MEASURED
node scripts/check-test-completeness.mjs— exit 3 by its own definition ("this gate exited before parsing a single summary line, so this result says NOTHING"). Not a red.pnpm lint— narrowed to the one changed file in ESLint's population, and the narrowing is measured rather than assumed: (i) the population is read fromeslint.config.mjsitself, whose one linting block isfiles: ['**/*.{ts,tsx,mts,cts,js,jsx,mjs,cjs}']— markdown and JSON are not members, so three of the four changed paths are outside it by the config's own declaration; (ii)pnpm exec eslint --no-inline-config --format json scripts/check-skills-token-ratchet.mjsreports 1 file linted, 0 errors, 0 warnings, exit 0; (iii) the config never enables type-aware linting (noparserOptions.project, no typed rules —eslint.config.mjsstates this at :327 and a grep of everyparserOptionsconfirms onlyecmaVersion/sourceType), so this diff cannot move the verdict on any file it does not touch.Follow-up for other packages (not edited here)
skills/objectstack-platform/SKILL.md:1212routes a reader to "Assigning a permission set to a user" in objectstack-data. That section still exists under that exact heading, now one file deeper inrules/security.md, so nothing is broken and no gate is red; a future platform flight may want to name the file. Not touched — another package.#anchorlink anywhere inskills/**,content/docs/**orpackages/**points into the moved sections, so no link was rewritten. Swept forobjectstack-data/SKILL.md#, and for each moved heading's slug.Landing
Governed surface (
skills/**) ⇒ this PR stays draft; review requests are the seat's step. Labels:skip-changeset(this PR releases nothing —scripts/check-empty-changeset.mjsenumerates ".github/, .claude/, skills/, docs/, content/, examples/, tests-only, and the like" as route 2, and its GREEN 3 self-test case pins askills/**-only PR with no changeset as green) andneeds:contract-review(published security-contract text —sharingModel, the permission scopes, the security lint ids, the tenant-wall posture — changes file).🤖 Generated with Claude Code
https://claude.ai/code/session_01LraLgQVGq8egUwfYZpbYt1
Generated by Claude Code