Skip to content

Commit 42ec951

Browse files
docs(permissions): generate the system-context site register; behaviour rows key their reads by symbol name (#26522)
<!-- claude-projects-attribution: {"github_login":"os-steve"} --> _Requested by **Steve** · [project thread](https://claude.ai/code/project/chan_01FdL1XeUyvVNxLreh3F4Qi9?thread=cmsg_01FdL1XeUyvVNxLreh3F4Qi9KWDJajrYvamoD37G6YZHjx)_ Fixes #26442 Part of #26431 Clause-②: no Metadata-protocol: none ## 维护者速读 - 改了什么:`system-context.mdx` 的行为表不再手写文件路径。每行在新的 `Symbol` 列里只写符号名(如 `registerAuthzMiddleware`)。页尾新增一个生成区「Site register」,每个有 isSystem 读点的符号一行,写完整的 `path#symbol`、该符号里的读点数和归属的行号。`check-system-context-census.mjs` 加了 `--write` 来重生这个区,检查时要求它和树上算出来的一字不差。 - 为什么改:页面 30 天里被改了 84 次,其中 12 次只是重构把函数挪到新文件后手改路径。现在挪文件只需跑 `--write`,登记表变一行,行文不动。本 PR 开发期间 main 正好又挪了一次(`resolveOneHopRelated` 挪进 `engine-master-detail-related.ts`),合并后跑 `--write`,登记表变了一行,没有手改任何一行。 - 风险与回滚:只动这个文档页和它的门禁脚本,不动任何 isSystem 读点和发布内容;回滚即 revert。检查只增不减:同一个符号里多加或删掉一个读点,原来门禁不红,现在登记表的读点数会变,不重生就红。 - 先看:`scripts/check-system-context-census.mjs` 里新加的 `resolveRowKeys` 和 `evaluateRegister`(F 段);再看页面 `## The table` 一节的 `Symbol` 列和页尾 `## Site register`。 - 两分钟验证:`pnpm check:system-context-census`,预期自测 all cases passed,门禁最后一句以 `the generated register (132 symbol(s)) matches the tree.` 结尾。 - 需要你做的:无,席位落地。另请 `domain:server` 确认符号清单(见下方 Server-lane confirmation)。 ## What changes **Generate, not retire.** The card offered two ways. This PR takes the generated one. The page is read: four docs pages link to it (`permissions/authorization.mdx`, `permissions/index.mdx`, `permissions/record-view-auditing.mdx`, `protocol/objectql/security.mdx`), two source comments quote it (`packages/objectql/src/engine.ts`, `security-plugin-authz-middleware.ts`), and #26466 is about to link its row 1b. Its value is the per-row behaviour prose, which no generator can write. So the census half is split off and generated, and the prose stays hand-written. This is the `tenant-audit-census.mdx` split. **The page** (`content/docs/permissions/system-context.mdx`) - In the six behaviour tables, the `Anchor` column (and section 6's `Site`) becomes `Symbol`. A cell names its symbols by name, for example `registerAuthzMiddleware`. Which file holds each one is no longer written by hand. - Four names are held by more than one file in the census: `isUserContextWrite` (3 files), and `onInsert`, `onUpdate` and `start` (2 each). For these the row keeps the full `path#symbol` anchor (rows 12, 23c, 23d, 25, 26, 26b, 62). The shared resolver still checks them, and they still move the old way. Three non-read citations stay as full anchors, as before (`READONLY_CLASS_REASONS`, `assertEngineOwnedWriteAllowed`, `registerCrudNodes`). - A new `## Site register` section holds a generated region, marked like the tenant-audit page's. It has one line per census symbol: `` `path#symbol` ``, its read count, and the rows whose `Symbol` cell names it. There are 132 lines and no total line, which keeps #22927's no-totals ruling. - The prose above the tables (the two callouts, "Maintaining this table", "What CI holds") now says what is generated and what is a human's call. The check table there grows from four rows to six. **The gate** (`scripts/check-system-context-census.mjs`) - New check **F, SITE REGISTER** (`evaluateRegister`). Every census read must be owned by a row whose `Symbol` cell names it (`[read-without-a-row]`). Every bare key must name exactly one file's symbol (`[row-key-no-read]`, `[row-key-ambiguous]`). Every row must key at least one read (`[row-without-a-read]`, `[row-without-a-key]`). The committed region must equal what `--write` renders (`[register-drift]`, which names the first differing line and the fix command). Missing or duplicated markers and a renamed key column are refusals (`[no-register]`, `[no-row-keys]`). - New `--write`. It splices only the region, so every byte outside the marker pair stays the same. It refuses, writing nothing, while any read has no row: the generator never assigns a read to a row. - `--fix` still refuses with exit 2, and now names `--write`. - Checks A to E are unchanged: RESOLUTION, POPULATION, CLASSIFICATION, the dated decomposition and ROW REFERENCES. The register's anchors satisfy POPULATION, so a stale register reds A and B as well as F. - Self-test: two new batteries, ⭐ THE SITE REGISTER (12 cases) and ⭐ THE REAL PAGE (5 cases). The `--fix` battery is rewritten to "only `--write` writes, and only the register" (5 cases). The precision battery gains a case showing the register now catches an added read (3 cases). The roster floor moves from 16 to 18. - Not changed: the root alias `check:system-context-census`, `lint.yml`, and any `isSystem` read. So this PR is not Tier H. ## Why The gate's `--fix` was retired (exit 2), so any change to an anchor was a hand edit. Measured on `origin/main` for the 30 days to `00a4593ad7`: **84** commits touched the page, and **12** of them changed nothing on it but the path inside an anchor. For example: `bdfad1fc7`, `366e4aa69`, `2e7127bc3` (objectql `engine.ts` cuts), and `df893f6d7`, `c15fd9a72`, `82f5a111b`, `dd124e946`, `77a77e42f`, `3e514912a` (plugin-security `security-plugin.ts` cuts). With this PR, a symbol move is `node scripts/check-system-context-census.mjs --write`, which changes one register line and no row. ## Server-lane confirmation (domain:server) The triage line asks `domain:server` to confirm the symbol list. This PR does not change any `isSystem` read. It only moves where each row writes its file. Please confirm two things: 1. Each row's `Symbol` cell names the reads that row describes. The conversion was mechanical: a full anchor whose `path#symbol` is a census read became its bare name when the name is unique, and nothing else changed. A row-by-row old/new listing is in the page diff, in the last cell of every table row. 2. The register's `Rows` column is right. Each register line says which rows own the symbol. Five symbols are owned by more than one row: `registerAuthzMiddleware` (rows 1, 2, 30), `insert` in `engine.ts` (21, 22), `update` in `engine.ts` (19, 20), `refusePackageRequest` (52, 54) and `handleMetadataRequest` (50, 52). ## Tests <details><summary>Red demonstration on a real tree: an <code>isSystem</code> read ADDED inside a keyed symbol, without regenerating (head 8b1b4d8 vs <code>origin/main</code> 00a4593)</summary> `scripts/ablation-replace.mjs` added `const probeSecondRead = execCtx?.isSystem;` inside `packages/objectql/src/engine-driver-options.ts#buildDriverOptions` (row 24's key). The file was restored, and `git diff HEAD` was empty afterwards. - On `origin/main` 00a4593 (a detached control worktree): `check-system-context-census` **exit 0**. This is the precision gap the page declared. - On this branch: **exit 1**, with exactly one finding: ``` ::error::[register-drift] the generated site register on the page is not what the tree produces -- a read was added, deleted or moved, or a row key changed, and the region was not regenerated. First difference at register line 10: committed : | `packages/objectql/src/engine-driver-options.ts#buildDriverOptions` | 1 | 24 | census : | `packages/objectql/src/engine-driver-options.ts#buildDriverOptions` | 2 | 24 | Fix: node scripts/check-system-context-census.mjs --write ``` </details> <details><summary>Red demonstration: a keyed symbol MOVED to another file, then regenerated with zero row edits (head 8b1b4d8)</summary> `isPerfDisclosurePrincipal` (row 13) was moved from `packages/observability/src/perf-timing.ts` into a new tracked file, `perf-timing-moved.ts`. The page was not touched. - Gate: **exit 1**, with `[register-drift]`, `[unresolved-symbol]`, `[file-without-a-row]` and `[anchor-is-not-a-read-site]`, one each. The drift line names `perf-timing-moved.ts#isPerfDisclosurePrincipal | 1 | 13`. - `--write`: exit 0. The page diff is exactly one register line (`-perf-timing.ts#…` / `+perf-timing-moved.ts#…`), and row 13 is unchanged. - Gate after `--write`: **exit 0**. The tree was restored afterwards, with `git diff HEAD` empty and the status clean. The same thing happened for real during this card. `origin/main` moved `resolveOneHopRelated` into `engine-master-detail-related.ts`. The merge conflicted only on the old anchor cell, which was resolved to the bare-key side. The gate then went red (`[register-drift]`, `[file-without-a-row]`, `[anchor-is-not-a-read-site]`), and `--write` changed one register line (commit 4d2bbfe). </details> <details><summary>Self-test and gate on HEAD</summary> ``` check-system-context-census --self-test: all cases passed check-system-context-census: OK — 153 elevation read sites in 22 packages across 83 files, living in 132 symbol(s); … 141 key(s) in 85 row(s) own every read, and the generated register (132 symbol(s)) matches the tree. ``` </details> ## Acceptance notes - **Card acceptance.** A symbol move needs no hand edit of the table: shown above, twice. `check-system-context-census` is a drift check over generated output plus the row-ownership rules. Its anchor checks are kept. - **The register's read count is a tripwire, not a row requirement.** `--write` clears a count change without touching the row, as the old site-total generator did. The page and the gate header both say so. Whether the row still describes the symbol is the reviewer's call. - **Pinned keys still move by hand.** Seven rows pin a name that two files share. A refactor that moves one of those files still means editing the anchor. A new collision is refused by name the day it appears (`[row-key-ambiguous]`). - **Prose citations still move by hand.** Anchors in prose outside the tables (for example the "What `isSystem` does not do" table, `enforceAuth`, `stampSystemInsertOwner`) are citations. The shared resolver still holds them. - **Not merge-driver routed.** Like `tenant-audit-census.mdx`, the page text-merges. A merge that leaves the region wrong is F's drift refusal on the PR and in the queue, as happened here. - **Stale comments outside this card's file surface (not edited here).** Three comments now say something false: - `.gitattributes` L97–108 says "nothing on it is generated". - `scripts/regen-artifacts.mjs`, `NOT_DRIVER_MANAGED` row `content/docs/permissions/**`, says it "is plain prose now". That row also prescribes routing any generated page here; `tenant-audit-census.mdx` is not routed either. - `scripts/git-merge-regen.mjs` `MIXED_COMPARATORS` describes `--fix` rewriting line anchors. That was already stale before this PR. These are left to the seat. ## Verification Readings on head `4d2bbfe38`, which includes the merge of `origin/main` at `3ebac9f5f`: - `node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack`: **64** derived commands, every exit captured before any pipe. All 64 exited 0. `check:pm-dispatch-gates` ran its fast tier (1935 cases, 394s). Two families first exited 1 and 3 because the merge left `packages/spec`'s build older than its sources (`check:docs`: json-schema older than src; `check:skill-examples`: exit 3, prerequisite). After `pnpm --filter @objectstack/spec build`, both exited 0. - `--ran`: `64 derived, 64 run, 0 NOT-MEASURED, 0 UNRUN` (a DERIVED zero: all 64 recorded an exit code and none is 3). - `pnpm exec eslint --no-inline-config scripts/check-system-context-census.mjs`: exit 0. - NOT MEASURED locally: CI's `Build Docs` and `Plan Test Core shards` steps, which the derivation names as path-scheduled with no local invocation. CI runs them on this PR. Changeset: `skip-changeset`. The diff is a docs page and a repo-internal gate script, and nothing publishes. ## Human Minimum - [x] 1. Schemas start as Zod; `packages/spec` holds no runtime logic. (not touched) - [x] 2. Every name I added uses the casing for its kind. - [x] 3. No formatter ran; `pnpm lint` passes. (eslint on the changed script: exit 0; the full run is CI's) - [x] 4. One issue, one branch off an up-to-date `main`, one pull request. - [x] 5. A change that publishes carries a changeset. (nothing publishes: `skip-changeset`) - [x] 6. `packages/spec` touched: n/a. - [x] 7. No hand edits to `content/docs/references/`, `packages/*/CHANGELOG.md` or `content/docs/releases/`. - [x] 8. Title, body and comments are in English, except the 维护者速读 block. - [x] The *Before Submitting* list in CONTRIBUTING.md is done. 🤖 Generated with [Claude Code](https://claude.com/claude-code) https://claude.ai/code/session_01ADHkmSHnQFa1PEAAXJ9hmc --- _Generated by [Claude Code](https://claude.ai/code/session_01ADHkmSHnQFa1PEAAXJ9hmc)_ --------- Co-authored-by: Claude <noreply@anthropic.com>
1 parent 48ee8b6 commit 42ec951

2 files changed

Lines changed: 1038 additions & 175 deletions

File tree

0 commit comments

Comments
 (0)