Repository navigation
Commit 5d46f43
feat(spec): ExplainAccessRequest declares recordIds, the batch selector the explain wire schema already carries (#29470)
<!-- claude-projects-attribution: {"github_login":"os-steve"} -->
_Requested by **Steve** · [project
thread](https://claude.ai/code/project/chan_01FdL1XeUyvVNxLreh3F4Qi9?thread=cmsg_01FdL1XeUyvVNxLreh3F4Qi99U9EnFooYs4VpVTYdtMEsX)_
Fixes #29297
Clause-②: yes (widening)
Metadata-protocol: none
Skills-docs: none — no page under `skills/` or `content/docs/` spells
the members of the `ExplainAccessRequest` contract type;
`content/docs/permissions/explain.mdx` shows the kernel call with
`object`/`operation`/`userId` only, and the batch form is already a
wire-schema fact of `ExplainRequestSchema` (grep `explain` and
`recordIds` in both trees, on 29000bb).
## 维护者速读
- 改了什么:`security` 服务契约的 explain 请求类型 `ExplainAccessRequest` 补上可选的
`recordIds`(批量记录 id),类型直接取自线上 schema `ExplainRequestSchema` 的同名成员。
- 为什么改:线上 schema、REST 解释路由和参考安全服务早已支持批量形态,唯独它们之间的 TypeScript
契约没声明,调用方只能强转才能传批量请求。
- 风险与回滚:仅类型放宽,无运行时改动;此前能编译的调用照常编译。回滚即撤销本 PR。
-
先看:`packages/spec/src/contracts/security-service.ts`(新成员与文档注释)、`packages/spec/src/contracts/security-service.test.ts`(类型钉)。
- 两分钟验证:`pnpm --filter @objectstack/spec check:test-typecheck`,预期
OK;把新成员改成 `readonly string[]` 再跑,预期该测试文件报 3 个类型错误。
- 需要你做的:无,席位落地。
## What changes
- `ExplainAccessRequest`
(`packages/spec/src/contracts/security-service.ts`) gains `recordIds?:
ExplainRequest['recordIds']`, with a doc comment: mutually exclusive
with `recordId`; at least one and at most `EXPLAIN_BATCH_MAX_RECORD_IDS`
ids (linked, not spelled); answered by `ExplainDecision.records` in the
same order; an implementation may ignore it and answer only the
object-level decision, and the caller then asks each id singularly, as
the REST explain route does.
- The member's type is the wire schema's own (`ExplainRequest` =
`z.input<typeof ExplainRequestSchema>`), not a hand-written `string[]`.
Only this member is derived: tying the whole interface to the schema
would change `operation` (the contract's `ExplainOperation | string`
against the schema's closed enum) and replace the contract's member
docs.
- The last doc sentence is measured against both readers on 29000bb:
the REST door hands the service the batch and falls back per id when the
answer carries no `records` of the right length
(`packages/rest/src/security-routes.ts` L256–299, the call at L279, the
check at L280, the per-id loop at L289–296); the reference service reads
the member and refuses it beside `recordId`
(`packages/plugins/plugin-security/src/security-plugin-explain-access.ts`
L128, L142–145, L526–527).
- No runtime change. `check:api-surface` agrees with no regeneration (it
records export names; no export was added or removed).
- Changeset: `.changeset/29297-explain-access-request-record-ids.md`,
`@objectstack/spec` patch.
## Tests
- New in `packages/spec/src/contracts/security-service.test.ts` (no
existing test was edited):
- `ExplainRecordIdsIsOptional`: a type alias that reds if the member
becomes required.
- `ExplainRecordIdsMatchesWire`: a type alias holding
`ExplainAccessRequest['recordIds']` equal to `z.input<typeof
ExplainRequestSchema>['recordIds']`.
- `explain accepts a batch request…`: the same equality through
`expectTypeOf`, a batch literal reaching the service, and a
`@ts-expect-error` that a bare string is not a batch.
- The file is compiled by `check:test-typecheck` (`tsconfig.test.json`)
and is not in `test-typecheck-debt.json` (0 hits), so the aliases are
live checks.
<details><summary>Ablation (type pin)</summary>
`node scripts/ablation-replace.mjs --file
packages/spec/src/contracts/security-service.ts --anchor "recordIds?:
ExplainRequest['recordIds'];" --replacement 'recordIds?: readonly
string[];' -- pnpm --filter @objectstack/spec check:test-typecheck`
- mutation landed: anchor 1 → 0, blob `ea8eb5b53fb0` → `f7a8cee931f6`
- `src/contracts/security-service.test.ts: 3 type error(s) in a file the
ledger does not cover` · command exited 1
- restored: blob == HEAD (`ea8eb5b53fb0`), `git diff HEAD` empty
</details>
<details><summary>Package suites on 29000bb (os-verify-lock)</summary>
- closure build `--filter '@objectstack/plugin-security^...' --filter
'@objectstack/rest^...'`: VERDICT command-exit 0
- `@objectstack/spec` test: Test Files 791 passed (791) · Tests 23470
passed, 1 todo · exit 0
- `@objectstack/spec` typecheck (tsc + scripts + test layer): exit 0 ·
`check:test-typecheck: OK — 52 file(s) / 240 error(s) / 131 pinned
signature(s) held`
- `@objectstack/plugin-security` test: Test Files 240 passed (240) ·
Tests 5175 passed, 45 skipped · exit 0
- `@objectstack/plugin-security` typecheck: exit 0
- `@objectstack/rest` test: Test Files 371 passed (371) · Tests 7032
passed, 332 skipped · exit 0
- `@objectstack/rest` typecheck: exit 0
- eslint `--no-inline-config` on both changed files: exit 0
</details>
## Acceptance notes
- `@objectstack/plugin-sharing`, `@objectstack/service-storage` and
`@objectstack/plugin-audit` also import `ExplainAccessRequest`; the
change only adds an optional member, so their code and test doubles stay
assignable. Not run locally; CI's Test Core and TypeScript Type Check
cover them.
## Verification
- Gates on 29000bb: `dispatch-gates.mjs --commands` derived 79; `--ran`
reconciles 79 derived, 78 run, 1 NOT-MEASURED, 0 UNRUN. 78 exit 0.
- `check-plugin-teardown-shape.mjs --self-test` first exited 3 on this
shallow clone (its positive-control fixture is pinned to a commit the
clone lacked); after fetching that one commit it exits 0 (`48 cases
pass`).
- `pnpm check:dual-build-cjs-loads` exits 3, `PREREQUISITE NOT MET` (48
packages have no `dist/`; it needs a whole-repo build). NOT MEASURED
locally; this diff changes one declared type member and no emitted
JavaScript. CI's Lint & Repo Gates runs it.
- `check-changeset-no-major.mjs --base origin/main --event` against this
body, offline: exit 0, `LEVEL AXIS … clause-② yes (widening) and
metadata-protocol none … a non-protocol change at patch`.
---
_Generated by [Claude
Code](https://claude.ai/code/session_01ADHkmQS1wrCba8FkVowBLy)_
---------
Co-authored-by: Claude <noreply@anthropic.com>1 parent 128681f commit 5d46f43
3 files changed
Lines changed: 89 additions & 2 deletions
File tree
- .changeset
- packages/spec/src/contracts
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | 1 | | |
2 | 2 | | |
3 | | - | |
| 3 | + | |
| 4 | + | |
4 | 5 | | |
5 | 6 | | |
6 | 7 | | |
| |||
9 | 10 | | |
10 | 11 | | |
11 | 12 | | |
| 13 | + | |
12 | 14 | | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
13 | 43 | | |
14 | 44 | | |
15 | 45 | | |
| |||
563 | 593 | | |
564 | 594 | | |
565 | 595 | | |
| 596 | + | |
| 597 | + | |
| 598 | + | |
| 599 | + | |
| 600 | + | |
| 601 | + | |
| 602 | + | |
| 603 | + | |
| 604 | + | |
| 605 | + | |
| 606 | + | |
| 607 | + | |
| 608 | + | |
| 609 | + | |
| 610 | + | |
| 611 | + | |
| 612 | + | |
| 613 | + | |
| 614 | + | |
| 615 | + | |
| 616 | + | |
| 617 | + | |
| 618 | + | |
566 | 619 | | |
567 | 620 | | |
568 | 621 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
64 | 64 | | |
65 | 65 | | |
66 | 66 | | |
67 | | - | |
| 67 | + | |
68 | 68 | | |
69 | 69 | | |
70 | 70 | | |
| |||
166 | 166 | | |
167 | 167 | | |
168 | 168 | | |
| 169 | + | |
| 170 | + | |
| 171 | + | |
| 172 | + | |
| 173 | + | |
| 174 | + | |
| 175 | + | |
| 176 | + | |
| 177 | + | |
| 178 | + | |
| 179 | + | |
| 180 | + | |
| 181 | + | |
| 182 | + | |
| 183 | + | |
| 184 | + | |
| 185 | + | |
| 186 | + | |
| 187 | + | |
169 | 188 | | |
170 | 189 | | |
171 | 190 | | |
| |||
0 commit comments