Repository navigation
Commit 630b407
test(plugin-security): one stack per policy and two shared baseline trees in the last two slow security suites (test budget, slice 22) (#28425)
<!-- claude-projects-attribution: {"github_login":"os-tesla"} -->
_Requested by **Tesla** · [project
thread](https://claude.ai/code/project/chan_01AXsQkLFKRdQCqQ3RTr6Jao?thread=cmsg_01AXsQkLFKRdQCqQ3RTr6JaoBeGYBWERTvqddUhodNHgAv)_
Part of #23181 (slice 22, `@objectstack/plugin-security`). The card is a
series and stays open.
Clause-②: no
Metadata-protocol: none
Test-only diff: `skip-changeset`. Two test files under
`packages/plugins/plugin-security/src/`;
`@objectstack/plugin-security`'s `files[]` ships `dist`, `README.md` and
`CHANGELOG.md` only.
## 维护者速读
- 改了什么:plugin-security 包 2 个测试文件。`rls-check-stored-form`
里写同一条策略的用例按驱动共用一个已启动的栈(启动次数 90 → 50),每个用例只写、只读自己的
id;`default-row-scope-declarations` 的四个用例共用两棵只读的基线树(启动 7 →
2)。两个文件都在模块顶层先付首次加载,后者在第 2 行加 `// test-budget:` 声明。只动测试文件,不改断言。
- 为什么改:卡 #23181 要求单个测试文件不超过 10 s;最新一次定时全量运行(41199450735)里
plugin-security 整包超出套件上限 1.15 倍,上一片之后包内剩下的两个超 10 s 文件就是这两个:13.98 s、12.82
s。
- 风险与回滚:断言、超时、分层都没动;两个文件共 136 个用例名前后一致、全绿;三处消融(存储形态、JSON
列拒绝、对象默认行范围)改前与改后红的是同一组用例。回滚即 revert 本 PR。
- 先看:`rls-check-stored-form.test.ts` 的 `stackFor()`
注释(为什么写入的用例也能共用栈:各写各的 id,日志从自己的标记读起)。
- 两分钟验证:`pnpm --filter @objectstack/plugin-security exec vitest run
--maxWorkers=2 src/rls-check-stored-form.test.ts`,预期 104 个用例全绿,耗时约为 main
上的一半。
- 需要你做的:无,席位落地。
## What changes
**The reading.** The newest full-battery reading is the scheduled CI run
41199450735 (2026-10-31T12:04Z, `63a9bcb773`, before slice 21 landed);
its `Test Core` suite-ceiling report puts `@objectstack/plugin-security`
over its ceiling (547.25 s against 474.43 s, 1.15x). Of the five files
it names over 10 s, slice 21 (#28421) took three; this slice takes the
other two: `src/objects/default-row-scope-declarations.test.ts` 13.98 s
and `src/rls-check-stored-form.test.ts` 12.82 s (11.72 s and 15.50 s in
run 41183072927). The report names no other file over 10 s in the
packages it lists.
**`rls-check-stored-form`: one stack per policy.** Each of the 45 cells
per driver booted its own `ObjectQL` + driver + `SecurityPlugin` for the
one RLS policy it names, so about 90 boots ran for 25 distinct policies
per driver. Cells now share a stack per (driver, `using`, `check`):
`stackFor()`, 50 boots. These cells write, so the sharing rests on
isolation rather than on read-only-ness. Each cell's verdict is a
per-row predicate over the row it writes. Each cell writes, updates and
reads only under ids of its own (`ids()`). The one predicate update
matches `title: 'batch'`, which only that cell's own row carries. The
refusal cells read the plugin's server log from their own mark on
(`warnMark` / `refusalLines(logger, mark)`), so an earlier cell's
refusal line is never counted. The first boot, write and read on each
driver now run at module scope on a throwaway stack (AGENTS.md: clocked
windows measure behaviour, never loading).
**`default-row-scope-declarations`: two shared trees.** The four
baseline cases booted seven stacks, a declared and an undeclared tree
each time. None of them writes after the fixture is seeded (they find,
explain, or read the collection), so `baseline(declared)` boots each
tree once and the four cases share it. A throwaway tree answers one find
and one explain at module scope. What remains is the first case's own
work: every persona's read and explain of every declarer the sets carry,
on both trees (about 3 s locally). So the file declares a budget.
**Budget header (ruling record 6181973363, letter B).**
`default-row-scope-declarations` is about 3.1x its local clock on CI,
which puts it near the line after this change. It is a real plugin over
a real engine and SQL driver per tree, so it gets one line at line 2:
the slowest CI reading x 1.25, rounded up to the next 10 s.
`rls-check-stored-form` reads about 2.5x local on CI, about 6.4 s after
this change, so it takes no header.
| file | change | slowest CI reading (s) | budget |
|:--|:--|--:|--:|
| `src/rls-check-stored-form.test.ts` | one stack per policy, own ids,
own log mark, module-scope first boot | 15.50 | none (the 10 s line) |
| `src/objects/default-row-scope-declarations.test.ts` | two shared
read-only trees, module-scope first boot, header | 13.98 | 20 |
## Tests
Per file, vitest's own file clock (what the refresh lane reads), 3
interleaved A/B rounds, each file in its own run, `--maxWorkers=2`,
under the shared verify lock on a shared container. Before is the file
at `472351944`, after is this head.
| file | before r1/r2/r3 (s) | after r1/r2/r3 (s) |
|:--|:--|:--|
| rls-check-stored-form | 5.41 / 4.64 / 5.11 | 2.47 / 2.60 / 2.54 |
| default-row-scope-declarations | 4.53 / 4.84 / 4.33 | 3.86 / 3.20 /
3.53 |
Name census over the A/B JSON reports, before vs after: 104 / 32 test
names on both sides in every round, 0 lost, 0 new, 0 with a changed
status.
Whole package on this head: `Test Files 238 passed (238)`, `Tests 5125
passed | 45 skipped (5170)`.
<details><summary>Ablations: sharing the stacks keeps every cell's
red</summary>
Each mutation went through `scripts/ablation-replace.mjs` with the
marker counted on disk, and was restored with the blob equal to HEAD.
Each was run against the base file (`472351944`) and against this head:
| mutation | file | red, base | red, head | same set of names |
|:--|:--|--:|--:|:--|
| `storedFormImage` answers the image as written
(`src/rls-check-stored-form.ts`) | rls-check-stored-form | 27 / 104 | 27
/ 104 | yes |
| `findJsonColumnCheckRefusal` never refuses | rls-check-stored-form |
24 / 104 | 24 / 104 | yes |
| `objectDefaultRowScopePolicy` builds no default
(`src/object-default-row-scope.ts`) | default-row-scope-declarations | 3
/ 32 | 3 / 32 | yes |
The first two are the write-sharing check. If a wrongly admitted write
on a shared stack could leak into a later cell, head would go red on
more cells than base. It reds the same set.
</details>
<details><summary>Header parse</summary>
`readTestBudget` (`scripts/measure-test-shard-timings.mjs`) reads
`default-row-scope-declarations` as budget 20 at line 2, class `spawns
the real producer once per single-cause fixture`, and
`rls-check-stored-form` as declaring none.
</details>
## Acceptance notes
- The reading predates slice 21's merge, so it still shows that slice's
three files at their old times. They carry their own headers since
#28421.
- `rls-check-stored-form`'s remaining time is the 50 boots and each
cell's own write and reads. Sharing further (one stack per driver with
one object per policy) would change the fixture each policy is judged
in, so it is left out.
- Branch `claude/project-thread-avx4e9` is the card thread's
platform-assigned branch, restarted from `main` after #28421 merged;
claim 6544453637 names it.
## Verification
Local, on `405330d4e`: `node scripts/pm/dispatch-gates.mjs --commands
--repo objectstack-ai/objectstack` derived 52 families. Each was run
with `</dev/null`, and its exit was captured by redirect before any
pipe. All 52 exit 0. `--ran`: `52 derived famil(ies) accounted for — 52
run, 0 NOT-MEASURED`, exit 0. Scoped lint, the root `lint` script's own
command over `packages/plugins/plugin-security`: exit 0. `pnpm --filter
@objectstack/plugin-security typecheck`: exit 0 (`check:test-typecheck:
OK`, 0 errors held). Whole package: 238/238 files green.
---
_Generated by [Claude
Code](https://claude.ai/code/session_01L9qibxnQNCbvYbRCUqNNvt)_
---------
Co-authored-by: Claude <noreply@anthropic.com>1 parent 4bc077d commit 630b407
2 files changed
Lines changed: 126 additions & 48 deletions
File tree
- packages/plugins/plugin-security/src
- objects
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | 1 | | |
| 2 | + | |
2 | 3 | | |
3 | 4 | | |
4 | 5 | | |
| |||
473 | 474 | | |
474 | 475 | | |
475 | 476 | | |
| 477 | + | |
| 478 | + | |
| 479 | + | |
| 480 | + | |
| 481 | + | |
| 482 | + | |
| 483 | + | |
| 484 | + | |
| 485 | + | |
| 486 | + | |
| 487 | + | |
| 488 | + | |
| 489 | + | |
| 490 | + | |
| 491 | + | |
| 492 | + | |
| 493 | + | |
| 494 | + | |
| 495 | + | |
| 496 | + | |
| 497 | + | |
| 498 | + | |
| 499 | + | |
| 500 | + | |
| 501 | + | |
| 502 | + | |
476 | 503 | | |
477 | 504 | | |
478 | 505 | | |
479 | 506 | | |
480 | 507 | | |
481 | 508 | | |
482 | 509 | | |
483 | | - | |
484 | | - | |
| 510 | + | |
| 511 | + | |
485 | 512 | | |
486 | 513 | | |
487 | 514 | | |
| |||
508 | 535 | | |
509 | 536 | | |
510 | 537 | | |
511 | | - | |
512 | | - | |
| 538 | + | |
| 539 | + | |
513 | 540 | | |
514 | 541 | | |
515 | 542 | | |
| |||
518 | 545 | | |
519 | 546 | | |
520 | 547 | | |
521 | | - | |
522 | | - | |
| 548 | + | |
| 549 | + | |
523 | 550 | | |
524 | 551 | | |
525 | 552 | | |
| |||
549 | 576 | | |
550 | 577 | | |
551 | 578 | | |
552 | | - | |
| 579 | + | |
553 | 580 | | |
554 | 581 | | |
555 | 582 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
58 | 58 | | |
59 | 59 | | |
60 | 60 | | |
61 | | - | |
| 61 | + | |
62 | 62 | | |
63 | 63 | | |
64 | 64 | | |
| |||
137 | 137 | | |
138 | 138 | | |
139 | 139 | | |
| 140 | + | |
| 141 | + | |
| 142 | + | |
| 143 | + | |
| 144 | + | |
| 145 | + | |
140 | 146 | | |
141 | 147 | | |
142 | 148 | | |
143 | 149 | | |
144 | 150 | | |
145 | 151 | | |
146 | | - | |
| 152 | + | |
147 | 153 | | |
148 | 154 | | |
149 | 155 | | |
| |||
176 | 182 | | |
177 | 183 | | |
178 | 184 | | |
179 | | - | |
| 185 | + | |
180 | 186 | | |
181 | 187 | | |
182 | 188 | | |
| |||
212 | 218 | | |
213 | 219 | | |
214 | 220 | | |
| 221 | + | |
| 222 | + | |
| 223 | + | |
| 224 | + | |
| 225 | + | |
| 226 | + | |
| 227 | + | |
| 228 | + | |
| 229 | + | |
| 230 | + | |
| 231 | + | |
| 232 | + | |
| 233 | + | |
| 234 | + | |
| 235 | + | |
| 236 | + | |
| 237 | + | |
| 238 | + | |
| 239 | + | |
| 240 | + | |
| 241 | + | |
| 242 | + | |
| 243 | + | |
| 244 | + | |
| 245 | + | |
| 246 | + | |
| 247 | + | |
| 248 | + | |
| 249 | + | |
| 250 | + | |
| 251 | + | |
| 252 | + | |
| 253 | + | |
| 254 | + | |
| 255 | + | |
| 256 | + | |
215 | 257 | | |
216 | 258 | | |
217 | 259 | | |
| |||
271 | 313 | | |
272 | 314 | | |
273 | 315 | | |
274 | | - | |
275 | | - | |
| 316 | + | |
| 317 | + | |
| 318 | + | |
276 | 319 | | |
277 | 320 | | |
278 | | - | |
279 | | - | |
280 | | - | |
| 321 | + | |
| 322 | + | |
| 323 | + | |
281 | 324 | | |
282 | | - | |
| 325 | + | |
283 | 326 | | |
284 | 327 | | |
285 | 328 | | |
286 | 329 | | |
287 | 330 | | |
288 | | - | |
289 | | - | |
290 | | - | |
| 331 | + | |
| 332 | + | |
| 333 | + | |
| 334 | + | |
291 | 335 | | |
292 | | - | |
| 336 | + | |
293 | 337 | | |
294 | | - | |
| 338 | + | |
295 | 339 | | |
296 | 340 | | |
297 | 341 | | |
298 | | - | |
299 | | - | |
300 | | - | |
| 342 | + | |
| 343 | + | |
| 344 | + | |
| 345 | + | |
301 | 346 | | |
302 | | - | |
303 | | - | |
| 347 | + | |
| 348 | + | |
304 | 349 | | |
305 | | - | |
306 | | - | |
| 350 | + | |
| 351 | + | |
307 | 352 | | |
308 | 353 | | |
309 | 354 | | |
310 | | - | |
311 | | - | |
| 355 | + | |
| 356 | + | |
| 357 | + | |
312 | 358 | | |
313 | 359 | | |
314 | | - | |
| 360 | + | |
315 | 361 | | |
316 | 362 | | |
317 | | - | |
| 363 | + | |
318 | 364 | | |
319 | 365 | | |
320 | 366 | | |
| |||
358 | 404 | | |
359 | 405 | | |
360 | 406 | | |
361 | | - | |
362 | | - | |
363 | | - | |
| 407 | + | |
| 408 | + | |
| 409 | + | |
| 410 | + | |
| 411 | + | |
364 | 412 | | |
365 | 413 | | |
366 | 414 | | |
367 | 415 | | |
368 | 416 | | |
369 | 417 | | |
370 | | - | |
| 418 | + | |
| 419 | + | |
| 420 | + | |
371 | 421 | | |
372 | | - | |
| 422 | + | |
373 | 423 | | |
374 | | - | |
| 424 | + | |
375 | 425 | | |
376 | 426 | | |
377 | | - | |
378 | | - | |
379 | | - | |
| 427 | + | |
| 428 | + | |
| 429 | + | |
380 | 430 | | |
381 | 431 | | |
382 | 432 | | |
383 | 433 | | |
384 | 434 | | |
385 | 435 | | |
386 | 436 | | |
387 | | - | |
| 437 | + | |
388 | 438 | | |
389 | | - | |
| 439 | + | |
390 | 440 | | |
391 | 441 | | |
392 | 442 | | |
393 | 443 | | |
394 | 444 | | |
395 | | - | |
| 445 | + | |
396 | 446 | | |
397 | 447 | | |
398 | 448 | | |
| |||
403 | 453 | | |
404 | 454 | | |
405 | 455 | | |
406 | | - | |
407 | | - | |
408 | | - | |
| 456 | + | |
| 457 | + | |
| 458 | + | |
| 459 | + | |
409 | 460 | | |
410 | 461 | | |
411 | 462 | | |
412 | | - | |
| 463 | + | |
413 | 464 | | |
414 | 465 | | |
415 | 466 | | |
| |||
0 commit comments