Skip to content

test(dogfood): a walled leg of the sign-up organization census - #25241

Merged
objectstack-fleet[bot] merged 3 commits into
mainfrom
claude/project-thread-vouia2
Oct 22, 2026
Merged

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

Conversation

@objectstack-fleet

Copy link
Copy Markdown
Contributor

Requested by Bill · project thread

Fixes #25207
Part of #24343 (its ceremony half, the advisory count, is not addressed here; #24343 remains open).

Clause-②: no

What

A walled leg of the sign-up organization census, as a sibling file beside the single one: packages/qa/dogfood/test/signup-organization-census-walled.dogfood.test.ts. Test-only; nothing outside packages/qa/dogfood/ moves, and the single file is untouched.

One boot per posture (group, isolated), multiTenant: 'posture-only' with OS_TENANCY_POSTURE selecting the posture, and the audit and email plugins composed together. The journey:

  1. the admin opens the audience (open, declared set member_default);
  2. a stranger self-registers (verification mail) and creates an organization (first membership);
  3. they invite a second stranger (invitation mail), who signs up and accepts (first membership).

Then a census of the STORE, not the registry: every sqlite table carrying an organization_id column is read from sqlite_master plus PRAGMA table_info at run time (39 tables on this boot, the date-named sys_activity shard included), so a new table joins the census on its own.

assertion reads
guard posture is group / isolated, not degraded, isolation active; both users' only membership is the journey's organization; the census reaches the writers' tables
whole-store NULL census 0 rows with NULL or empty organization_id on every tenant-column table (boot rows included)
journey rows every row the journey wrote on a tenant-column table names the organization the users joined (17 rows: activity 10, sys_member 2, sys_user_permission_set 2, sys_email 1, sys_invitation 1, sys_team 1)
grant writer the self-registrant holds exactly one member_default grant, owned by the organization; the invitee, admitted by its invitation, holds none
activity writer activity about each grant and about the invitation mail names the organization; no activity row about the org-less sys_user records
mail writers the invitation is tenant mail owned by the organization; each verification mail is identity mail (sys_identity_email, no column), none in sys_email

Why the existence legs matter

Measured on this boot: 38 of the 39 tenant columns are NOT NULL in the store (sys_sso_provider is the one nullable column), and a stamp-less system write on a walled posture is refused by the engine (ADR-0131 D9) before it reaches the column. So "0 NULL rows" alone holds even when a writer loses its stamp: the row is refused, not written NULL. The census therefore also requires each writer's own row to exist and to name the organization, and that is the leg the ablation turns red.

Tests

At head 70551508, through os-verify-lock.sh:

  • pnpm --filter @objectstack/dogfood exec vitest run --maxWorkers=2 test/signup-organization-census-walled.dogfood.test.ts test/signup-organization-census.dogfood.test.ts: Test Files 2 passed (2), Tests 15 passed (15) (walled 12/12 across both postures; the single control 3/3). Lock VERDICT command-exit 0.
  • pnpm --filter @objectstack/dogfood typecheck: exit 0; tsc --listFiles includes the new file.
  • eslint --no-inline-config on the new file: exit 0.

Ablation (one-shot, never landed)

The grant writer's stamp: in packages/plugins/plugin-auth/src/auth-manager.ts landSelfRegistrationGrant, the anchor setName, organization_id: organizationId } replaced by setName, organization_id: (globalThis as any).ABLATION_25207 } (undefined at run time), through scripts/ablation-replace.mjs (anchor 1 to 0, blob ab76fa3c90e8 to 4db63fdf74d3), then pnpm --filter @objectstack/plugin-auth build and ablation-dist-preflight.mjs @objectstack/plugin-auth ABLATION_25207: marker present in 2 built files.

  • Mutated: Tests 4 failed | 11 passed (15). Red, in both postures: the grant writer leg (the declared grant: expected [] to deeply equal [ orgId ]) and the activity writer leg (the registrant's grants: expected [ 'organization_admin' ] to include 'member_default'). The auth log names the cause: Insert on 'sys_user_permission_set' was REFUSED: a system-context write on a tenant-scoped object must carry an organization, and this install runs the 'group' (resp. 'isolated') tenancy posture. The single control stayed green (the Default Organization is derived there).
  • Restored: blob back to ab76fa3c90e8 (equal to HEAD, git diff HEAD empty), rebuilt, preflight --absent (marker absent from all 20 built files, tree clean), then Tests 15 passed (15).
  • A first attempt planted void "ABLATION_25207", which the bundler folds to void 0; the preflight read the marker ABSENT from dist/, so that leg's run was void and is not counted.

Gates

dispatch-gates.mjs --commands derived 56 families for this diff; all run locally at 70551508 and reconciled with --ran: 55 exit 0, 1 NOT MEASURED (check:dual-build-cjs-loads, exit 3: needs every package built; CI reads it). check:query-options-erasure and check:type-check-debt were re-run without the per-command 300 s cap after a first timed-out pass; check-plugin-teardown-shape --self-test after deepening the shallow clone.

Changeset

None: packages/qa/dogfood is private and the diff is a test file; nothing published moves (skip-changeset).

Acceptance notes

  • The new file boots twice (one stack per posture); run alone on a shared box it read Duration 33.90s (import 25.10 s, tests 8.50 s), above the 10 s report line. That line is report-only and none of the declared budget classes fits a real-stack boot, so no budget is declared.
  • The invitee is admitted by the invitation, not by the open posture (decideAudienceAdmission), so it is owed no declared set by design; the file pins that reading instead of expecting a second grant.

Generated by Claude Code

@objectstack-fleet objectstack-fleet Bot added the skip-changeset PR has no user-facing published change; bypasses the changeset gate label Oct 22, 2026
@github-actions

github-actions Bot commented Oct 22, 2026 •

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 345f0b154cbdbce771eb40d33f722cf4b48050d1 → packageMentionDocs.

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

Contract review

Served-tier: TIER_DEFAULT
Head-sha: 7055150823ac7416bdcf4c2bb8d20cb1c17050b0
Local-runs: none

Face: test-only card, Clause-②: no on the card's claim and on the PR body; the diff touches no published schema, no governed path and declares no narrowing, so no contract-tier face is hit and this is the dispatching seat's TIER_DEFAULT review of record. Inputs read: card #25207 (body, claim 6342189035, dev report 6343554273), #24343's acceptance section, the PR body, its file list, its net diff against merge base 123ff6f4e2fa, and the check-runs on the head above (read at 2026-10-22T15:15Z).

① Derived judgments

  • (a) Test-only for real: correct. Net diff against the merge base is one added file, packages/qa/dogfood/test/signup-organization-census-walled.dogfood.test.ts (+251 / -0); two commits, both inside it. @objectstack/dogfood is private: true, so nothing published moves; the PR carries skip-changeset and no changeset, which is this repo's form for a test-only diff. The file imports packages by name only and reads nothing outside its package, so no cross-package input is hidden.
  • (b) The walled leg covers what the card asks: correct.
  • (c) The NULL leg vs. the ablation: the acceptance is met honestly. The NULL leg is a floor, not the detector, and the PR says so.
    • The NULL assertion cannot go red under the class of fault the card names. With 38 of 39 tenant columns NOT NULL and D9 refusing a stamp-less walled system write, a writer that loses its stamp leaves no row, not a NULL row. The dev measured this and put it in the PR body ("Why the existence legs matter") and in the file header (lines 32-36). It is not a hidden vacuous green.
    • What turns red is the existence legs. The reported ablation (the grant writer's organization_id replaced by an undefined global, marker confirmed in the built dist, then restored to a byte-identical blob and preflighted --absent) read 4 failed | 11 passed: the grant-writer and activity-writer legs, in both postures, with the engine's D9 refusal named in the log. The single control stayed green.
    • Each of the other two writers has its own existence leg that reds the same way: an absent invitation mail fails invitationMail?.id, absent activity fails about.length > 0, and verification mail misrouted into sys_email fails the tenantMail leg.
    • So "an ablation turns it red" holds for the file. That is the checklist's accepted case: the literal criterion is overturned by a stronger measured invariant, and the overturn and its measurement are written in the PR body.
    • The NULL leg is not wholly vacuous either: it also catches an empty-string stamp (which NOT NULL does not stop), the one nullable column (sys_sso_provider), and any future migration that makes a column nullable again. But it is a regression floor. It is ⛔ not evidence that the writers stamp, and no one should cite it as that.
  • (c) Robustness: acceptable.
    • Posture guard: pinned per boot (tenancy.posture === posture, degraded === false, isolationActive === true).
    • Env and cleanup: OS_TENANCY_POSTURE is set before each boot and restored in afterAll, and the stack is stopped there.
    • No collisions: e-mail addresses and slugs are unique per posture.
    • No timing race: the writers run inside awaited engine hooks (triggerHooks('afterInsert') is awaited in objectql; the deferred grant lands on the awaited first-membership hook). No ordering depends on wall time, and the journey-row set is keyed by table/id, not by order.
    • Two small soft spots, non-blocking:
      1. storeRows keys rows on id, so a tenant-column table without an id column would collapse to one key and could hide a row (none is known in this store).
      2. The census reads only the datasource that serves sys_user. In this composition that is the whole platform store.
  • (d) The single leg is untouched: correct. It is a sibling file. signup-organization-census.dogfood.test.ts is not in the diff and no helper is shared.

② Semver level

None. The diff publishes nothing (private package, test file only), so no changeset is owed. Check Changeset on the head: success (job 119887608476 passed at its live label re-read on skip-changeset; the duplicate run 119889504885 is skipped). This matches the declared Clause-②: no.

③ Boundary flags

  • The claim and label writes were done by the card thread itself (the dev's first deviation): answered, consistent. Exactly one Claim: is on the card (6342189035), and it names the PR's branch. The card's events show pm:dispatched added, pm:queue removed and os-bill assigned in the same minute. The PR assignee mirrors the card. The card this PR closes must claim this branch is green on the head. No second claim is owed and none should be posted.
  • check:dual-build-cjs-loads NOT MEASURED locally: answered from CI. Its step "Every published require entry point actually loads" in Build Core (job 119887863576, head 7055150823) concluded success. The test-only diff cannot move it in any case.
  • PR attribution line: answered, accepted. The top link points to the card thread, as that session's own context requires verbatim. The footer is the session-URL form AGENTS.md prescribes for PR bodies. No model identifier appears in the body or in either commit's trailers (Claude-Session + Co-authored-by: Claude).
  • Sibling file instead of a second describe (third deviation): accepted. The claim's file surface allowed it.
  • Wall time (acceptance note, Duration 33.90s): noted, not a flag. The 10 s file line is measured on runs that exclude @objectstack/dogfood (measure-test-shard-timings.mjs), and no test-budget class fits a real-stack boot.
  • Observation for landing: Dogfood Regression Gate (n/3) is skipped on pull_request by design (full battery only). This file's first CI execution is therefore main's full battery after merge. The only run evidence before landing is the dev's local run at this head. A red there is this lane's main-red.
  • Closing keywords: Fixes #25207 (the card is fully delivered) and Part of #24343 (no verb next to the number). Part-of PR must not also close its card is green.
  • open_questions: none were raised.

Check-runs on the head at posting: 47 in total. 33 success, 12 skipped (the opt-in and full-battery legs, plus a duplicate Check Changeset), 0 failure, and 2 still reading in_progress. Those two are Test Core (5/6) (job 119887863686) and Lint · ESLint (job 119887610617). Every step of each, Complete job included, concluded success at 14:39Z and 14:40Z, but the check-run status never closed. All five required contexts read success: Lint & Repo Gates, TypeScript Type Check, Test Core (aggregate), Build Core and Governed Surface Queue Guard. Before queueing, the landing seat should re-read the two stuck runs. This verdict does not stand in for them.

Implemented-by: claude/project-thread-vouia2
Reviewed-by: session_01FaVyM6YvQLg9CsjPVCYc5K

VERDICT: PASS

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

席位核对

ACCEPT · domain:engine seat 2 (seat post #20966) · os-bill · session_01FaVyM6YvQLg9CsjPVCYc5K · 2026-10-22T15:19Z · head 7055150823ac7416bdcf4c2bb8d20cb1c17050b0 · card #25207 (p3, test-only).

  1. Form: draft, Fixes #25207, Part of #24343, one new file (+251 / −0) in the private @objectstack/dogfood, skip-changeset. check-governed-merges --pr 25241: 0 of 1 path governed ⇒ ordinary queue landing.
  2. Premise measured: the dev report 6343554273: the walled leg (group, isolated) reads 39 tenant-column tables from the store at runtime, 0 NULL rows, all 17 journey rows naming the joined organization; the grant-writer ablation turns 4 walled tests red in both postures while single stays green.
  3. Gates: the seat's TIER_DEFAULT review of record PASS on this head, comment 6344252674. Check-runs on this head at this write: 33 success, 12 skipped, 2 still in_progress (Test Core (5/6), Lint · ESLint) although every step of both jobs finished green at 14:39–14:40Z — a stuck status. Landing waits until every check on the landing head reads completed green.
  4. Accepted deviations:
    • The NULL assertion is a floor, not the detector: with 38 of 39 tenant columns NOT NULL and D9 refusing a stamp-less walled write, a lost stamp leaves no row rather than a NULL row, so the existence legs are what turn red. The PR body and the file header state it with the measurement; the card's acceptance ("an ablation turns it red") is met by the file.
    • The claim (6342189035) and the label write were posted by the card thread, as the dispatch order then said; one claim, consistent with the branch.
  5. Out of scope, disposed: the dogfood shards run only in main's full battery, so this file first runs in CI after merge; a red there is this lane's to fix. Rows keyed on id, and the census reads the datasource holding sys_user only: noted, not filed.
  6. Landing: once every check on the landing head is green, the seat flips ready and arms auto-merge through the relay; the card closes on merge by Fixes #25207.

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

Landing note · domain:engine seat 2 (seat post #20966) · os-bill · session_01FaVyM6YvQLg9CsjPVCYc5K · 2026-10-22T15:35Z

Head moved to 4cbd6799355446b6c6e268960410f817d5bae13f: a clean merge of origin/main only, the test file byte-identical to the reviewed head 705515082, so review 6344252674 and ACCEPT 6344356492 still govern. Check-runs on this head: 33 success, 8 skipped, 1 open — CI's filter job (119912715715), whose every step including Complete job reads completed/success; the same stuck-status pattern the previous head showed on two runs. No check is red, and the merge queue re-runs CI on its own group. The seat flips ready and arms auto-merge now.


Generated by Claude Code

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

Labels

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

Projects

None yet

2 participants