Skip to content

test(plugin-security): pin that the registered security service serves reopenAudienceBindingSuggestion - #27546

Merged
objectstack-fleet[bot] merged 2 commits into
mainfrom
claude/issue-27362-reopen-served-pin
Oct 29, 2026
Merged

objectstack-fleet[bot] merged 2 commits into
mainfrom
claude/issue-27362-reopen-served-pin

Conversation

@objectstack-fleet

Copy link
Copy Markdown
Contributor

Requested by Sales · project thread

Fixes #27362

Clause-②: no
Metadata-protocol: none
Skills-docs: none — test-only diff; no published skill, doc or authorable surface moves.

维护者速读

  • 改了什么:新增一个测试文件,钉住 plugin-security 注册的 security 服务确实提供可选方法 reopenAudienceBindingSuggestion,并且它调用的是真正的模块函数而不是桩。
  • 为什么改:这个方法是可选的,若接线被重构删掉,所有测试仍然全绿,而两个“重新打开建议绑定”的接口会悄悄变成 501。
  • 风险与回滚:只加测试,不改任何源码、不发布任何内容(skip-changeset);回滚即删除该测试文件。
  • 先看:packages/plugins/plugin-security/src/registered-security-service-reopen.pin.test.ts(唯一改动文件,看文件头说明的理由与断言)。
  • 两分钟验证:pnpm --filter @objectstack/plugin-security exec vitest run src/registered-security-service-reopen.pin.test.ts,预期 1 个测试通过。
  • 需要你做的:无,席位落地。

What changes

One new test file beside the members pin: packages/plugins/plugin-security/src/registered-security-service-reopen.pin.test.ts.

It boots the real SecurityPlugin the same way registered-security-service-members.pin.test.ts does and takes the object it registers as security. Then it asserts two things:

  1. reopenAudienceBindingSuggestion is a function on the registered object.
  2. Calling it reaches this package's reopenAudienceBindingSuggestion module function, with the suggestion deps (which carry ql), the caller context and the id. The test returns that function's answer unchanged. The module function is replaced with a spy through a partial vi.mock, so the test proves the call is delegated and not answered by a stub.

Per triage 6486679343, the test sits beside the members pin with its own reason and is not in MUST_SERVE_OPTIONAL. That list holds optional members whose absence consumers read as a fallback that admits. Reopen's absence refuses (501, every dismissal stands), so it does not belong there. The file header gives the reason.

No source change. The member's wiring in security-plugin-security-service.ts is untouched.

Tests

  • New pin plus members pin, on merged head a34ad920b1: Test Files 2 passed (2), Tests 5 passed (5).
  • pnpm --filter @objectstack/plugin-security test: Test Files 237 passed (237), Tests 5112 passed | 45 skipped (5157).
  • pnpm --filter @objectstack/plugin-security typecheck: exit 0. This includes check:test-typecheck over tsconfig.test.json, which compiles the new file: 0 file(s) / 0 error(s).
Negative-pin ablation (through scripts/ablation-replace.mjs; restored, blob equal to HEAD)

The test imports ./security-plugin.js relatively, so it runs against src/ and no dist/ rebuild applies.

A: delete the two wiring lines (reopenAudienceBindingSuggestion: (callerContext: any, id: string) => and the delegation line under it)

ablation-replace: ok mutation landed: anchor 1 -> 0, blob 49d0052dfcc1 -> f7bf8b8f1b32
     × serves the member, delegating to the module function with the caller context and id
AssertionError: reopenAudienceBindingSuggestion is not served: both reopen routes answer 501: expected 'undefined' to be 'function'
 Test Files  1 failed (1)
ablation-replace:   blob after restore  49d0052dfcc19efcadaa7dd47386e9459f570413
ablation-replace:   blob at HEAD        49d0052dfcc19efcadaa7dd47386e9459f570413
ablation-replace:   git diff HEAD       empty

B: keep the member and replace the delegation with a stub (Promise.resolve({ suggestion: { id, status: 'pending' } }))

ablation-replace: ok mutation landed: anchor 1 -> 0, blob 49d0052dfcc1 -> 0af78b7d0772
     × serves the member, delegating to the module function with the caller context and id
AssertionError: expected { suggestion: { id: 'sugg_1', …(1) } } to be { suggestion: { id: 'sugg_1', …(1) } } // Object.is equality
 Test Files  1 failed (1)
ablation-replace:   blob after restore  49d0052dfcc19efcadaa7dd47386e9459f570413

After restore the pin is green again: Tests 1 passed (1).

Acceptance notes

  • skip-changeset: the diff publishes nothing. files[] is dist, README.md and CHANGELOG.md, and the tsup entry is src/index.ts. Measured after pnpm build: the new test's names occur in 0 dist/ files, and the positive control reopenAudienceBindingSuggestion occurs in 4.
  • The boot helper (about 25 lines) is copied from the members pin, not imported. The pin file exports nothing, and importing one test file from another would also run its suites.

Verification

Local subset on head a34ad920b1 (merge of origin/main f57eddcf0c). Exit codes were captured before any pipe.

  • node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack derived 52 commands. 50 exited 0.
  • Two answered exit 3 (PREREQUISITE NOT MET, they need the whole workspace built): pnpm check:dual-build-cjs-loads and pnpm check:i18n. Both are NOT MEASURED locally and are left to CI's Lint & Repo Gates. A single test file under src/ is outside what either one reads.
  • --ran reconcile: 52 derived famil(ies) accounted for — 50 run, 2 NOT-MEASURED (2 DERIVED from a recorded exit 3), exit 0.
  • The derivation printed a stale-tree warning: origin/main moved after the merge, and the changed files are scripts/pm/* and scripts/gen-sdui-reference.mjs families. They are not this diff's.
  • npx eslint --no-inline-config on the new file: exit 0.
  • pnpm --filter @objectstack/plugin-security typecheck: exit 0.
  • pnpm --filter @objectstack/plugin-security test: exit 0, 237/237 files.
  • Every family CI runs is read from this PR's check-runs. None of them was re-run locally.

Generated by Claude Code

🤖 Generated with Claude Code

https://claude.ai/code/session_01L6bhgXcN9HaZYSEUdJWEjw

…s reopenAudienceBindingSuggestion

The optional member is wired on the registered object, but nothing pinned it:
dropping the wiring left every suite green while both reopen routes answered
501. The new pin boots the plugin like the members pin, asserts the member is
served, and asserts it delegates to the module function with the caller
context and id. It sits beside the members pin with its own reason, not in
MUST_SERVE_OPTIONAL: reopen's absence refuses rather than admits.

Co-authored-by: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01L6bhgXcN9HaZYSEUdJWEjw
@objectstack-fleet objectstack-fleet Bot added the skip-changeset PR has no user-facing published change; bypasses the changeset gate label Oct 29, 2026
@github-actions

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

Nothing in this diff resolved to a documentable surface (no symbol, route or SDK anchor derived from 0 changed package(s)), so this run has no opinion about the docs.

What this run could not see

Coarse fallback — 0 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): node scripts/docs-audit/affected-docs.mjs --json d4ff1a025fa4568505bfbc66a0f8cbeb3bab06ff → packageMentionDocs.

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

domain:server#1 · os-sales · session_01L6bhgXcN9HaZYSEUdJWEjw

维护者速读(席位终稿)

  • 改了什么:给 plugin-security 新增一个只读测试(钉子),钉住它注册的 security 服务确实提供可选成员 reopenAudienceBindingSuggestion,而且调用会真正落到本包的实现上。没有改任何源码。
  • 为什么改:plugin-security: no test pins that the registered security service serves the optional reopenAudienceBindingSuggestion, so dropping its wiring would turn both reopen routes into 501 with every suite green #27362:这个成员是可选的,缺了它,两个「重新打开建议绑定」接口会变成 501,而现有所有测试照样全绿,没人能发现。
  • 风险与回滚:极低,只加一个测试文件,skip-changeset。回滚就是还原这一个 PR。
  • 先看:packages/plugins/plugin-security/src/registered-security-service-reopen.pin.test.ts 开头的说明,讲了它为什么不放进 MUST_SERVE_OPTIONAL。
  • 两分钟验证:pnpm --filter @objectstack/plugin-security exec vitest run src/registered-security-service-reopen.pin.test.ts,预期通过。
  • 需要你做的:无。Tier S,席位落地。

席位意见:接受。消融两条腿(删接线、换成桩)都转红,还原后与 HEAD 一致。

席位核对 — ACCEPT · domain:server#1 · head a34ad92 · 2026-10-29T12:44Z

  • Shape: one new test file beside the members pin, per triage 6486679343 (own reason, not in MUST_SERVE_OPTIONAL); boots the real SecurityPlugin; asserts the registered security object serves reopenAudienceBindingSuggestion and that a call reaches the module function with deps, caller context and id, answer returned unchanged. No source change.
  • Premise: the claim 6488787575 holds; Fixes #27362.
  • Gates: 53 check-runs on this head: 34 success, 19 skipped, 0 failed, 0 pending. check-expected-skips --pr 27546 (fresh origin/main): VERDICT … OK — 19 skipped check-run(s), every one in main's roster (exit 0). mergeable_state: clean. Ablation: (A) wiring deleted → RED with the 501 message; (B) stub delegation → RED on identity; both restored blob == HEAD. Locally NOT-MEASURED check:dual-build-cjs-loads and check:i18n (exit 3, prerequisite) are answered green by CI's Lint & Repo Gates on this head.
  • Contract review: not owed. check-governed-merges --pr 27546: NOT governed; test-only, no export, no accept-set change.
  • Accepted deviations: a ~25-line boot helper copied from the members pin (that pin exports nothing; importing a test file would run its suites). The merge commit carries git's default message (trailer check passed).
  • Declaration: Clause-②: no, Metadata-protocol: none, skip-changeset (the new test's identifiers occur in 0 dist files).
  • Out of scope: none. Skills-docs: none.
  • Landing: Tier S, 80 changed lines → pr_ready + automerge_enable via the relay now.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/s skip-changeset PR has no user-facing published change; bypasses the changeset gate tests

Projects

None yet

1 participant