Skip to content

test(rest): execctx-consumer-census derives its structural reading from the tree instead of hand counts - #26520

Merged
objectstack-fleet[bot] merged 2 commits into
mainfrom
claude/project-thread-3onq8a
Oct 27, 2026
Merged

objectstack-fleet[bot] merged 2 commits into
mainfrom
claude/project-thread-3onq8a

Conversation

@objectstack-fleet

Copy link
Copy Markdown
Contributor

Requested by Leehom · project thread
Fixes #26436
Part of #26431

Clause-②: no
Metadata-protocol: none

维护者速读

  • 改了什么:execctx-consumer-census.test.ts 里所有手数的数字(调用点 62、提及 145、caught/bare/同行 16/46/12、迁出注册器 4/4、文件数 18)和每次拆分 rest-server.ts 留下的重数记录全部删掉,换成一条从源码推导的规则:每个 resolveExecCtx 调用点,要么是「裸调用,下一行就是共享的匿名拦截」,要么是「自带 catch,且不在那道拦截后面」。
  • 为什么改:这些数字每拆一次文件、每增删一个路由都得手改,最近 30 天改了两次,红史全是「代码正常变了、数字没跟上」。[finding] computeExecCtx swallows EVERY fault into an anonymous context for all 72 resolveExecCtx call sites — measured fail-closed at exactly one door, unmeasured at the rest #13160 要的答案(执行上下文缺失时每个消费点意味着什么)已经写在文件散文和行为测试里,数字本身什么都不证明。
  • 风险与回滚:只动一个测试文件,不发布任何包;回滚就是 revert 本 PR。驱动路由、看真实应答的行为测试(§1、§3–§9)全部保留,新规则在三次消融里都按预期变红。
  • 先看:packages/rest/src/execctx-consumer-census.test.ts 的 §2(新规则及其两个对照);同文件 §3 新增的「每次调用都归属到一个已普查调用点」对照。
  • 两分钟验证:pnpm --filter @objectstack/rest exec vitest run src/execctx-consumer-census.test.ts,预期 27 个用例全绿。
  • 需要你做的:无,席位落地。

What changes

One file, packages/rest/src/execctx-consumer-census.test.ts. Seat ruling arm (b): the invariant holds today, so the file stays and its counts go.

  • §2 (the count block) is replaced by ONE derived assertion: every this.resolveExecCtx(environmentId, req) site in every file on REST_SERVER_REGISTRAR_FILES is EITHER bare with if (this.enforceAuth(req, res, context)) return; as its very next statement, OR locally caught and not behind that floor. A failure names each site out of shape. Two derived controls sit in the same case: (i) completeness, no line in a censused file calls resolveExecCtx in any spelling other than a site, a host literal's forwarder or the method's declaration, so the partition cannot silently narrow; (ii) neither half of the partition is empty.
  • Gone: SITE_FILES length 18, SITES 62, 145 mentions, 16 / 46 / 12, the EXTRA_MOVED_REGISTRARS and MOVED_REGISTRARS_READING_NO_EXECCTX hand maps (4 / 4) with the forwarder-count arithmetic, the per-slice recount docblocks and the ten-entry recount changelog inside §2.
  • What the forwarder-count pin used to catch is kept, derived: instrument() now records a call no censused frame made as (no censused frame) instead of dropping it, and a new §3 control asserts that every call the mounted table makes, under the FULL and the ISOLATED mounts, is attributed to a censused site. A registrar body moved to a module that never joined the list reds there (ablation C below). A respelt forwarder reds the §2 completeness control.
  • Counts that restated the population elsewhere now compare site by site: §3's rows.length >= 46 becomes "the rows cover every bare site"; §7's >= 12 inline / >= 4 continuation floors become equality with the site table's own reading of where each catch sits, per site, plus both layouts non-empty; §8's >= 4 becomes non-empty. Titles and prose that stated a population count ("the 46 bare sites", "the 20 locally-caught sites", "the four continuation sites", "four of the inner sites") are reworded without the number.

Per describe block (the triage asked for this):

block before after
§1 supplier fulfils undefined behaviour stays, unchanged
§2 counted from the tree pins counts goes; replaced by the one derived invariant
§3 bare sites, driven behaviour + a count floor stays; floor derived; attribution control added
§4 locally-caught sites behaviour stays; title count removed
§5 public-audience carve-out behaviour stays, unchanged
§6 boundary (packages door) behaviour stays, unchanged
§7 catch argument behaviour + count floors stays; floors derived per site
§8 total outage at continuation sites behaviour + a count floor stays; floor derived
§9 partial outage behaviour stays, unchanged

Why

The card (Part of the transcription-pin parent): the file pinned hand counts that every rest-server.ts split slice had to retype, and the question it answers (#13160, what an absent execution context means at each consumer) is a one-time reading already recorded in its prose. The derived rule is the reading the file itself recorded as its structural finding ("the bare sites are bare BECAUSE the shared anonymous floor is the next statement; the locally-caught ones carry a .catch because they are NOT behind that floor"), now asserted as a rule instead of as 46 and 0. It reds on #13160's defect shape: a consumer that takes the context bare and proceeds with nothing deciding the absent context beside it.

Tests

  • pnpm --filter @objectstack/rest exec vitest run --maxWorkers=2 src/execctx-consumer-census.test.ts: 27 / 27 pass (28 before: §2's three cases became one, §3 gained one).
  • pnpm --filter @objectstack/rest test (under the shared verify lock, VERDICT command-exit 0): Test Files 324 passed (324), Tests 6482 passed, 326 skipped.
  • pnpm --filter @objectstack/rest typecheck (tsc --noEmit && pnpm check:test-typecheck): VERDICT command-exit 0.
  • eslint packages/rest --no-inline-config: exit 0, no output.
Ablations — three legs, each through scripts/ablation-replace.mjs, each restored to the HEAD blob with git diff HEAD empty

The suite reads src/ directly (relative import of ./rest-server.js, same package), so no dist leg applies.

  • A — [finding] computeExecCtx swallows EVERY fault into an anonymous context for all 72 resolveExecCtx call sites — measured fail-closed at exactly one door, unmeasured at the rest #13160's shape: delete if (this.enforceAuth(req, res, context)) return; under the bare site in email-routes.ts (anchor 1 → 0, blob 30a8f5a0c886 → 8b44d5e1a6f3). 2 failed / 25 passed: §2 names email-routes.ts:77 — bare, and NOT followed by the shared floor; §3's driven case reads POST /api/v1/email/send under an absent context: expected 200 to be 401, the absent context served. Restored, blob == HEAD 30a8f5a0c886.
  • B — a site respelt out of the census' reading: this.resolveExecCtx(environmentId, req) → this.resolveExecCtx(environmentId,req) in email-routes.ts (blob 30a8f5a0c886 → 19282f570843). 2 failed / 25 passed: §2's completeness control lists email-routes.ts:77: const context = await this.resolveExecCtx(environmentId,req);; §3's attribution control lists POST /api/v1/email/send ← email-routes.ts:77. Restored, blob == HEAD.
  • C — a moved module that never joined the list (the case the retired forwarder-count pin caught): delete 'email-routes.ts', from REST_SERVER_REGISTRAR_FILES (blob fa939290f54d → 1f4b4e2e8c74). 1 failed / 26 passed: §3's attribution control lists POST /api/v1/email/send ← (no censused frame). Restored, blob == HEAD fa939290f54d.

Acceptance notes

Verification

All local readings at branch head fd29a1d26, against merge base 45de8c6cb.

  • Gate families derived by node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack on the real diff: 49. Each run with its exit code captured before any pipe; --ran reconciliation: "49 derived famil(ies) accounted for — 48 run, 1 NOT-MEASURED".
  • 47 exited 0 on the first pass, including check:type-check-debt (0 raw tsc errors, none above its recorded number), check:cross-package-test-inputs, check:test-source-alias, check:nul-bytes, check:issue-citations and check:doc-authoring.
  • node scripts/check-plugin-teardown-shape.mjs --self-test exited 3 on the first pass (its pinned positive-control commit was outside the shallow clone); after fetching that commit it exits 0 ("48 cases pass").
  • NOT MEASURED: pnpm check:dual-build-cjs-loads, exit 3, PREREQUISITE NOT MET (the worktree built only the @objectstack/rest dependency closure, so other packages have no dist/). CI runs it.
  • Families CI owns (Lint & Repo Gates, TypeScript Type Check, Test Core and the rest) are read from this PR's check-runs, not re-run here.
  • Dogfood battery: n/a — no ! in the title and no (narrowing) arm.

Human Minimum

  • 1. Schemas start as Zod; packages/spec holds no runtime logic. (not touched)
  • 2. Every name I added uses the casing for its kind.
  • 3. No formatter ran; pnpm lint passes (scoped to the touched package; CI runs the repo-wide scan).
  • 4. One issue, one branch off an up-to-date main, one pull request.
  • 5. A change that publishes carries a changeset — this one publishes nothing; both declaration lines are filled in here.
  • 6. packages/spec touched: not touched.
  • 7. No hand edits to content/docs/references/, packages/*/CHANGELOG.md or content/docs/releases/.
  • 8. Title, body and comments are in English (the maintainer brief is Chinese by convention).
  • The Before Submitting list in CONTRIBUTING.md is done.

Generated by Claude Code

…om the tree instead of hand counts

§2's literal site / mention / caught-bare-same-line / moved-registrar counts
and the per-slice recount history are replaced by one derived invariant:
every resolveExecCtx site is either bare with the shared anonymous floor as
its next statement, or locally caught and not behind that floor. Its controls
are derived too: no call in the censused files is spelt outside the census'
reading, and every call the mounted table makes is attributed to a censused
site. The floors that restated the counts elsewhere (§3, §7, §8) now compare
against the site table, site by site.

Claude-Session: https://claude.ai/code/session_01FEkQ5oi3XkDNLtE2KCnbvV
Co-authored-by: Claude <noreply@anthropic.com>
@objectstack-fleet objectstack-fleet Bot added the skip-changeset PR has no user-facing published change; bypasses the changeset gate label Oct 27, 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 b7f2b0c290ebae63240a13918fdbe67135ecfafa → packageMentionDocs.

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

席位核对

ACCEPT · domain:server seat 2 · os-project-manager · session_0186vfjHHMsRXC9EUT9hTFMo · 2026-10-27T06:42Z · head fd29a1d26d · #26436

The maintainer's standing authorisation for landing reviewed PRs, verbatim: 「按照 pm-dispatch 规则复核过的都授权」.

  1. Shape: a draft against main, opened by the relay with assignee os-project-manager and skip-changeset. The file is not published: @objectstack/rest ships dist, and no resolveExecCtx docblock changed. The body carries Fixes #26436, Part of #26431, Clause-②: no and Metadata-protocol: none, all line-initial. check-governed-merges --pr 26520 reads NOT governed, 727 changed lines, one file. No contract face is touched, so no at-tier review is owed. The card's newest claim (6434785334) names this PR's branch.

  2. Arm: the seat's ruling was (b) first. The dev found the invariant true today and kept the file. §2's counts are replaced by one assertion derived from every file on REST_SERVER_REGISTRAR_FILES. Each resolveExecCtx site is either:

    • bare, with if (this.enforceAuth(req, res, context)) return; as its next statement; or
    • locally caught, and not behind that floor.

    The case also holds two controls:

    • Completeness: no line calls resolveExecCtx in a spelling the site table cannot read.
    • Non-vacuity: both halves are non-empty.

    The seat read §2 and the new §3 control in full at this head.

  3. No literal count remains: SITE_FILES 18, SITES 62, 145, 16 / 46 / 12 and 4 / 4 are gone, and the file has no toHaveLength. What the forwarder-count pin used to catch is kept, derived: a new §3 control attributes every call the mounted table makes, under both mounts, to a censused site. The two route-row floors that stay (≥ 30 served bare rows, > 10 /meta rows) are anti-vacuity floors on driven rows, not site counts.

  4. Not weakened: the per-describe table in the body shows §1 and §3–§9, all of them behaviour, staying. Three ablations went red and were restored to the HEAD blob:

  5. Overlap: none. No other open PR touches this file. test(rest): drop the registrar-file list's length pins from six rest tests #26518 (test(rest): the registrar-file list's length is pinned as toHaveLength(18) in seven test files — drop the seven length pins, the list is the authority #26433) edits six other packages/rest test files.

  6. Gates: at this stamp every check-run on the head reads success or skipped; none reads failed or in progress. Locally the dev reports:

    • 49 derived gates: 48 exit 0, with check:dual-build-cjs-loads not measured (prerequisite; CI covers it);
    • rest 324 / 324 files, and typecheck and scoped lint green.
  7. Out of scope: the stale header sentence in rest-server-registrar-files.ts:23-26 rides test(dogfood): authz-conformance.test.ts pins the registrar-file list's length as toHaveLength(18) (the seventh copy of #26433) #26524. Nothing else was found.


Generated by Claude Code

@objectstack-fleet
objectstack-fleet Bot marked this pull request as ready for review October 27, 2026 06:44
@objectstack-fleet
objectstack-fleet Bot enabled auto-merge October 27, 2026 06:44
@objectstack-fleet
objectstack-fleet Bot added this pull request to the merge queue Oct 27, 2026
Merged via the queue into main with commit 4166a92 Oct 27, 2026
53 checks passed
@objectstack-fleet
objectstack-fleet Bot deleted the claude/project-thread-3onq8a branch October 27, 2026 07:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

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

Projects

None yet

2 participants