Repository navigation
feat(spec)!: retire PositionGrantVia 'name' and the Setup by-name grant readers - #26398
Conversation
…ders in Setup Narrows PositionGrantVia to 'definition', registers the ADR-0087 D3 entry position-grant-via-name-retired, drops the Setup position list's by-name badge and its two i18n keys, and retires the client-side name fold in the managed-environment Users marker with its pins. Claude-Session: https://claude.ai/code/session_01WGufzgKsGKQ8LMfpA72sns Co-authored-by: Claude <noreply@anthropic.com>
📓 Docs Drift CheckThis PR changes 2 package(s): 3 hand-written doc(s) NAME something this change touched and may need an implementation-accuracy re-verification:
⛔ 5 release-owned page(s) also name something this change touched. These are read-only:
What this run could not see
Coarse fallback — 149 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): Which tree this was computed onThis run read A worktree cut from an older # while this PR is open — GitHub drops the merge commit once it closes
git fetch origin aa8e1604305496aad21739b7e143d84b7d227844 && git checkout aa8e1604305496aad21739b7e143d84b7d227844
# afterwards, rebuild it from the two parents, which stay fetchable
git fetch origin e677770ae03bd7a5b20d4cd44e1f66137add1910 570809677a686ea38406d3445f309f2522614f3e && git checkout -B drift-repro e677770ae03bd7a5b20d4cd44e1f66137add1910 && git merge --no-ff 570809677a686ea38406d3445f309f2522614f3e
node scripts/docs-audit/affected-docs.mjs --json e677770ae03bd7a5b20d4cd44e1f66137add1910
|
|
Claim: contract review of PR #26398 at head The dispatching seat's own at-tier review: the diff touches |
Contract reviewServed-tier: Inputs: card #26022 (body and all seven comments, through the dev report 6431841169), PR #26398 (body, 12-file list, both comments, no review comments, no reviews), the net diff against ① Derived judgments
② Semver level
③ Boundary flags
Implemented-by: Rendered by an isolated CONTRACT_REVIEW_TIER subagent of seat session_01WGufzfhobWEgUUrjz4rrbh ( VERDICT: PASS |
…aged Users marker A holder of a position that only shares its name with a permission set is now marked Not authorized; the registry double no longer serves the permission catalogue or getTypeStatus, which the read no longer asks for. Claude-Session: https://claude.ai/code/session_01WGufzgKsGKQ8LMfpA72sns Co-authored-by: Claude <noreply@anthropic.com>
Contract reviewServed-tier: Addendum to record 6431990382 (head 1a70ed5): one commit, 4b0074c, touches one file (+9/-8); the first record's ①–② stand, its ③ missed a sibling pin and a stale guide sentence, and the guide sentence is what fails this head. ① Derived judgments
② Semver levelUnchanged from record 6431990382: the delta is one test file, no source, no type, no changeset. ③ Boundary flags
Implemented-by: Rendered by an isolated CONTRACT_REVIEW_TIER subagent of seat session_01WGufzfhobWEgUUrjz4rrbh ( VERDICT: FAIL |
…he name fold Claude-Session: https://claude.ai/code/session_01WGufzgKsGKQ8LMfpA72sns Co-authored-by: Claude <noreply@anthropic.com>
Contract reviewServed-tier: Addendum to records 6431990382 and 6432502078: one commit, 5708096, touches two files (+3/-3), both prose; the FAIL item of record 6432502078 (the stale guide sentence) is rewritten and true at the head, the flagged docblock is rewritten and true at the head, and nothing else moves. ① Derived judgments
② Semver levelUnchanged from records 6431990382 and 6432502078. The delta is two prose hunks: one TSDoc comment in ③ Boundary flags
Implemented-by: Rendered by an isolated CONTRACT_REVIEW_TIER subagent of seat session_01WGufzfhobWEgUUrjz4rrbh ( VERDICT: PASS |
席位核对 · ACCEPT ·
|
Requested by Yibo Wang · project thread
Fixes #26022
Clause-②: no (narrowing)
Metadata-protocol: none
维护者速读
PositionGrantVia收窄为只剩'definition';Setup 岗位列表去掉「(同名)」徽标及其两个 i18n 键;托管环境 Users 页的「未授权」标记不再按岗位同名推算权限集。via: 'name';spec 和界面却还在描述这种已不存在的授权(Permission-set resolution binds by POSITION NAME while sys_position_permission_set sits near-empty — confirm name-based resolution is the intended mechanism, not an accident the empty junction hides #13419 裁决 B,18.x 直接退役)。'definition');TS 消费方若比较via === 'name'会编译报错,删掉该分支即可。回滚 = revert 本 PR。ui/packages/app-shell/src/views/managedEnvironmentUsers.tsx(判定逻辑变化:同名岗位的持有人现在会被标「未授权」);packages/spec/src/contracts/security-service.ts(公开类型收窄);packages/spec/src/migrations/entries/semantic/18.position-grant-via-name-retired.ts(ADR-0087 登记)。cd ui && pnpm exec vitest run packages/app-shell/src/views/__tests__/managedEnvironmentUsers-13330.test.tsx,预期 16 个用例全绿,其中「a position grants nothing by sharing its name with a permission set」为新判定。CONTRACT_REVIEW_TIER契约复核)。What changes
@objectstack/spec:PositionGrantVia(packages/spec/src/contracts/security-service.ts) is now'definition'. The docblock no longer describes the position-name fold. The security plugin already serves onlyvia: 'definition'(security-plugin.tsdescribePositionGrants), so the wire answer does not change.position-grant-via-name-retiredregisters the retirement. The type describes a served answer, not a stack collection or a metadata type, so there is no D2 conversion source. The changeset carries theregistereddisposition.PositionGrantCells.tsx): the granted-sets cell shows each set's name alone. The "(by name)" / 「(同名)」 badge, its hint, and the i18n keysengine.position.grants.byNameandengine.position.grants.byNameHint(en and zh) are removed. The served-entry filter accepts onlyvia: 'definition'.managedEnvironmentUsers.tsx): the client-side name fold is retired. A held position now counts only by the sets its definition lists. The permission-set catalogue read,catalogueRead, andPositionRegistrySource.getTypeStatusexisted only for the fold. Measured: no other reader in the file or in its one caller,objectViewIdentity.tsx. All three are removed, including the caller'sgetTypeStatusline. The observable change: a holder of a position whose name matches a permission set the definition does not list is now marked Not authorized, unless something else grants them a set beyond the baseline. That matches what the server enforces.packages/rest/src/meta-item-read-gate.ts(describeMetaPositionList) now saysvia: 'definition'.packages/runtime/src/domains/meta-list-projection-parity.test.tsandui/packages/data-objectstack/src/metadata-client.listInclude-25333.test.tsstill servedvia: 'name'from their doubles. Both now serve{ name: 'forecasting', via: 'definition' }.Tests
managedEnvironmentUsers-13330.test.tsx: the name-fold pin is inverted. A holder ofcloser(a position that shares its name with a set but lists only a baseline set) readsbaseline-only. The control holder ofsales_repreadsbeyond-baseline. The registry is asked only forposition. The "catalogue cannot be read" case is deleted because the read it covered is gone.ResourceListPage.positionGrants-25333.test.tsx: the fixture serves only declared sets. Each badge's text is exactly the set name and carries notitle.beyondBaseline(position) ||in the position branch, turns three cases red, the new one among them. The file was restored, and its blob equals HEAD (044d3b83d42f).Local readings (head 1efc50f, then merged head 1a70ed5)
pnpm --filter @objectstack/spec build: exit 0.check:generated: exit 0, all 14 artifacts up to date. The api-surface is unchanged because the export name stays.pnpm --filter @objectstack/spec test: 726/726 files, 21984 tests passed.cd ui && vitest runon the three touched test files: 3/3 files, 25/25 tests. Ablation run: 3 failed / 13 passed, as intended, then restored.cd ui && vitest runonapp-shell/src/views/__tests__/,metadata-admin/ResourceListPage*,zh-base-term, all ofdata-objectstack, andi18nobjectView-config-keys-retired-4730: 182/182 files, 1871/1871 tests, on both heads.packages/runtimemeta-list-projection-parity.test.ts: 1/1 file, 878/878 tests.@object-ui/app-shell type-check(both heads),@object-ui/data-objectstack type-check,@objectstack/spec typecheck,@objectstack/rest typecheckand@objectstack/runtime typecheck: exit 0. Runtime first reported TS2307 for@objectstack/driver-turso, an unbuilt dist. It was green after building that package.dispatch-gates --commandson the final head 1a70ed5: 94 commands, all exit 0.--ranreconciliation: 94 derived, 94 run, 0 NOT-MEASURED, a derived zero.Full dogfood battery (final head 1a70ed5)
pnpm --filter @objectstack/dogfood testunder the verify lock: 302 files (2 failed, 297 passed, 3 skipped), 2549 tests (10 failed, 2521 passed, 18 skipped). VERDICT command-exit 1.All 10 failures are in
test/authz-probe-blind-spot.test.ts(4) andtest/authz-conformance.test.ts#17111 (6). They count text inpackages/rest/src/rest-server.tsandpackages/rest/src/rest-route-ledger.ts, for example the controlthis.routeManager.register(is expected at 62 and found at 63. This PR does not touch either file orpackages/qa/dogfood.git diff origin/mainon all three is empty, so the same counts fail onorigin/main(e931621). They are main's, not this change's.10 reds in authz-conformance.test.ts and authz-probe-blind-spot.test.ts are main's at origin/main abb9046 (same 10, measured on a detached worktree), anchored on #26400; not this PR's.
Acceptance notes
packages/plugins/plugin-security/src/security-plugin.ts(docblock ofdescribePositionGrants, around line 3535) still says "the contract's'name'member is no longer served". The member is now gone, so the sentence goes stale. It is left alone because PR feat!: ownership queues and assignment rules (ADR-0142 phase 2) #26337 holds that file. Carrier: the seat..changeset/24757-retire-position-name-fold.md(pending, from Setup: a position's same-named permission set is in force but invisible — the set's Assigned Users panel is empty and the position reads as granting nothing #24757) says the'name'member is "retired separately in spec: retire PositionGrantVia 'name' (the position-name fold's grant mark) once #24757's runtime retirement lands #26022; until then the value is published but never served". It stays accurate as a record of that change and is not edited here.origin/main(see the dogfood block). They are reported to the seat as a main-red finding, not fixed here.Verification
CONTRACT_REVIEW_TIERcontract review before the queue, as the claim records.Generated by Claude Code