Repository navigation
Commit df22adc
test(plugin-auth): keep the absolute-limit switch fixture off the one-hour boundary (#31213)
<!-- claude-projects-attribution: {"github_login":"os-project-manager"}
-->
_Requested by **Leehom** · [project
thread](https://claude.ai/code/project/chan_01TenzsRopZj4jMbvjX8uz1X?thread=cmsg_01TenzsRopZj4jMbvjX8uz1X5P75jPsrvBic2pzcJ3eDvb)_
Fixes #31175
Clause-②: no
Metadata-protocol: none
## 维护者速读
- **改了什么**:只改一个测试文件:plugin-auth 里「切换组织时按绝对时长上限判定」那条用例的会话夹具,从「正好 60
分钟前创建」改为「59 分钟前创建」,并补一句注释说明为什么不能贴着上限。
- **为什么改**:上限是 1 小时,判定时会重新读时钟;夹具正好 60 分钟,只要过去 1
毫秒会话就超限被结束,「还没到上限」的断言就红。本地实测:旧夹具在 main 上每次都红,不是偶发。产品判定本身是对的,不动产品代码。
- **风险与回滚**:极低。不改任何发布内容(测试文件不进包),「超限」那条 61 分钟断言原样保留;回滚即还原这一行。
-
**先看**:`packages/plugins/plugin-auth/src/organization-access-policy.test.ts`(L398
夹具与 L421 注释)。
- **两分钟验证**:`pnpm --filter @objectstack/plugin-auth exec vitest run
src/organization-access-policy.test.ts`,预期 19/19 通过。
- **需要你做的**:无,席位落地。
## What changes
- `packages/plugins/plugin-auth/src/organization-access-policy.test.ts`,
in the `deployment()` fixture of the "a switch of the active
organization is judged against the target's limits" block: the `s1`
session row is created 59 minutes ago instead of exactly 60. The "not
over yet" comment now says why the fixture must sit clearly inside the
limit. The "over" leg (`created_at` 61 minutes ago, expect `ended` with
`revoke_reason: absolute_max`) is unchanged, so the test still proves
the absolute limit is judged at the switch, on both sides of it.
- The same fixture feeds the idle-timeout case in that block. It judges
`last_activity_at` (30 minutes ago, against a 10-minute idle limit) and
sets no absolute limit, so 59 vs 60 does not change what it reads.
No product file is touched; `organization-access-policy.ts` and
`auth-manager.ts` are as on `main`.
## Why
`AuthManager.judgeSessionSwitch` (`auth-manager.ts` L6352–6355) takes
its own `Date.now()` after the fixture is written and ends the session
when `now - created_at > absoluteHours * 3_600_000`. A row made
`Date.now() - 60 * MIN` against a one-hour limit is over as soon as one
millisecond passes between the fixture and the judgment. The product
comparison is right; the fixture sat on the boundary. Main went red on
it in `Test Core (7/8)` (run 42384924042); locally the base fixture is
red on every run (the memory engine's insert and read take well over a
millisecond).
## Tests
<details><summary>Acceptance: a 5-second fake-clock advance between
fixture and judgment; base fixture red, new fixture green</summary>
Each leg runs `pnpm --filter @objectstack/plugin-auth exec vitest run
--maxWorkers=2 src/organization-access-policy.test.ts -t 'the absolute
limit is judged too'` under `os-verify-lock`, with the mutation written
by `scripts/ablation-replace.mjs` (anchor must hit, blob verified,
restored to the HEAD blob). The test imports `./auth-manager` from
`src/`, so there is no `dist/` hop and no rebuild per leg. The delay is
`vi.useFakeTimers({ toFake: ['Date'] }); vi.setSystemTime(Date.now() +
5_000);` inserted on the line of the "not over yet" assertion; it was
removed afterwards and is not in the diff.
| leg | fixture | delay | on-disk check | result |
|---|---|---|---|---|
| 0 | 59 min (head) | none | fixture59=1 fixture60=0 delay=0 | `Tests 1
passed`, exit 0 |
| 0b | 60 min (base) | none | fixture59=0 fixture60=1 delay=0 |
`AssertionError: expected 'ended' to be 'admitted'`, exit 1 |
| 1 | 59 min (head) | +5 s | fixture59=1 fixture60=0 delay=1 | `Tests 1
passed`, exit 0 |
| 2 | 60 min (base) | +5 s | fixture59=0 fixture60=1 delay=1 |
`AssertionError: expected 'ended' to be 'admitted'`, exit 1 |
Restore proof after the last leg: `git diff HEAD` empty, blob on disk
`086c2c08` = HEAD blob `086c2c08`.
A first attempt at legs 1 and 2 was a no-op: the delay replacement still
contained the anchor line, so `ablation-replace` refused it ("anchor
count moved 1 -> 1") before running anything. It was redone with a
replacement that rewrites the anchor line itself; the table above is the
second run.
</details>
<details><summary>plugin-auth suite and typecheck at head
228d061</summary>
- `pnpm --filter @objectstack/plugin-auth test`: `Test Files 234 passed
(234)`, `Tests 4168 passed | 10 skipped (4178)`, `VERDICT command-exit
0`.
- `pnpm --filter @objectstack/plugin-auth typecheck` (tsc, examples,
`check:test-typecheck`): `check:test-typecheck: OK`, `VERDICT
command-exit 0`. The first run answered exit 2 on
`examples/basic-usage.ts` because plugin-auth's own `dist/` was not
built yet in the fresh worktree; after `pnpm --filter
@objectstack/plugin-auth build` it is green.
- `eslint --no-inline-config packages/plugins/plugin-auth`: exit 0
(plugin-auth has no `lint` script, so a filtered `pnpm lint` would match
nothing).
</details>
## Acceptance notes
- Same-file boundary sweep (the card's L336–346 `minutesAgo` helper):
the four concurrent-cap cases use ages 50/40/1, 5/30, 5/30 and 30/20/1
minutes. They only order sessions by age against count caps
(`max_concurrent_sessions_per_user`, `maxConcurrentSessions`); no time
limit is judged, so nothing sits on a boundary. The other same-file
clock fixture, L291 `hourAgo` (60 minutes) against Alpha's 5-minute idle
limit, is far over. No other same-file fix.
- Rest of `plugin-auth/src/**/*.test.ts`, every `Date.now() - N` fixture
read against the limit it meets: none equals its limit. Closest reads:
`auth-manager.test.ts` L4997 (created 60 minutes ago, but the case
judges a 15-minute idle limit with no absolute limit),
`session-of-record.test.ts` L313/L332 (12 h and 2 h against an 8 h cap),
`auth-manager.mcp-oauth.test.ts` L359/L546 (consent timestamps, no limit
judged). Nothing out of scope to file.
## Verification
- Derived gate families (`node scripts/pm/dispatch-gates.mjs --commands
--repo objectstack-ai/objectstack`, 52 commands) run at head, reconciled
with `--ran`: 51 exit 0, 1 NOT MEASURED (`pnpm
check:dual-build-cjs-loads`, exit 3 PREREQUISITE NOT MET: it needs every
package's `dist/` and the worktree built only plugin-auth's closure).
`node scripts/check-plugin-teardown-shape.mjs --self-test` first
answered exit 3 on the shallow clone and is exit 0 after `git fetch
--depth=1 origin 621a487`. `--ran`: "52 derived famil(ies) accounted
for — 51 run, 1 NOT-MEASURED", exit 0. The 16 `--self-test` families are
checker health only, not a verdict on this diff.
- `skip-changeset`: plugin-auth `files[]` is `dist`, `README.md`,
`CHANGELOG.md`. After a build, the new comment text and the test file
name have 0 hits there; positive control `judgeSessionSwitch` has 4 hits
in `dist`.
---
_Generated by [Claude
Code](https://claude.ai/code/session_01FEkQ5mS6HNaJTYsygvmxuM)_
Co-authored-by: Claude <noreply@anthropic.com>1 parent 714dda8 commit df22adc
1 file changed
Lines changed: 4 additions & 2 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
395 | 395 | | |
396 | 396 | | |
397 | 397 | | |
398 | | - | |
| 398 | + | |
399 | 399 | | |
400 | 400 | | |
401 | 401 | | |
| |||
418 | 418 | | |
419 | 419 | | |
420 | 420 | | |
421 | | - | |
| 421 | + | |
| 422 | + | |
| 423 | + | |
422 | 424 | | |
423 | 425 | | |
424 | 426 | | |
| |||
0 commit comments