Repository navigation
Commit 3f7cb1b
test(dogfood): re-pin the forced-reset gate code and the password-set ledger decisions to ruling C′ (#23512)
Fixes #23493
Clause-②: no
## What changed
Two dogfood pins still stated the contract from before ruling C′
(director record `6159450584`, the maintainer's 「同意」; letter A
`6165848580` sets the revocation ON by default). PR #23440
(`0f059078ec`) landed that ruling, and the hourly full run went red on
**Dogfood Regression Gate (3/3)**: 2 files, 4 tests, at both
`0d3ea295d1` (run `38568381233`) and `394f65e891` (run `38576826654`).
This PR re-pins both files to the ruled answer. Every assertion keeps
its exact `toBe` / closed-set form, and nothing is skipped, deleted or
widened. Test files only. No product source changes.
**1.
`packages/qa/dogfood/test/bearer-lane-password-change.dogfood.test.ts`,
all three lanes.**
- The gate refusal for an admin-provisioned user now expects `403` +
`error.code === 'PASSWORD_RESET_REQUIRED'`. It expected
`PASSWORD_EXPIRED`. The test title and the file header now name the new
code.
- **Deciding clause:** ruling C′ item 2: 「The admin-forced change
(`must_change_password`) stops reusing `PASSWORD_EXPIRED`: it gets its
own code (`PASSWORD_RESET_REQUIRED`, scope `credential`)」.
- **Premise check (falsifiable, verified).** The scenario is the
administrator-forced change, not expiry:
- The user comes from `POST /auth/admin/create-user`, whose answer
asserts `mustChangePassword === true`.
- The file arms only `passwordHistoryCount` (through
`applyConfigPatch`), so `passwordExpiryDays` stays off.
- In `AuthManager.resolveUserAuthGates`
(`plugin-auth/src/auth-manager.ts`), `PASSWORD_RESET_REQUIRED` is pushed
only for `must_change_password`, and `PASSWORD_EXPIRED` only when
`expiryDays` is above 0 and `password_changed_at` is older than that.
- So the product's `PASSWORD_RESET_REQUIRED` is the ruled answer here,
not a defect.
- **Downstream steps:** none needed a re-pin. The ruled revocation rides
`runAdminSetUserPassword` (`/auth/admin/set-user-password`). This file
never calls it: it only creates the user, then signs in, changes the
password, reads and attempts reuse with the user's own credentials.
Measured three ways:
- both hourly logs show only the first step red in each lane;
- the 12 tests of this file pass locally;
- the ablation below turns exactly the three gate-refusal steps red and
nothing else.
**2.
`packages/qa/dogfood/test/admin-ledger-decision-metadata.dogfood.test.ts`,
the closed decision set of `user.admin_password_set`.**
- Before: `required: ['event', 'passwordGenerated']`, `optional: []`.
- After: `required: ['event', 'passwordGenerated',
'revokeSessionsAndKeys']`, `optional: ['revokedSessions',
'revokedApiKeys', 'revocationComplete']`.
- **Deciding clauses:**
- ruling C′ item 2: the forced reset 「carries a "revoke the user's
sessions and API keys" switch」;
- letter A: ON by default for every forced reset;
- PR #23440's producer records the decision and what landed on the
ledger row.
- **Required or optional: measured from the producer, per key.**
`runAdminSetUserPassword` (`plugin-auth/src/admin-user-endpoints.ts`)
writes the metadata as follows:
- `revokeSessionsAndKeys` is the boolean switch. It is written on
**every** admin password set, so it is `required`.
- `revokedSessions`, `revokedApiKeys` and `revocationComplete` are
spread in only when the revocation ran (`...(revocation ? {…} : {})`),
so they are `optional`.
- That matches the producer's own `AdminAuditDecisions` type, which
declares the switch as required and the three counts with `?`. The
table's existing `organizationId` follows the same convention.
- The unit pin beside the producer (`admin-user-endpoints.test.ts`,
`PASSWORD_SET_DECISIONS`) holds the six-key set on the default-on path.
- **Deviation from the triage's reading (`6170015227`):** the triage
named `revokeSessionsAndKeys` as the one missing key. The CI assertion
stops at its first undeclared key, which hid three more. This fixture's
reset leaves the switch at its default (on), so its row also carries the
three counts. A one-key re-pin leaves this file red. The ablation's leg
2 below measures that.
## Verification
All local runs were on head `8b7306a355` (base `ad5a7d7c39`), under the
shared verify lock, with the dogfood dependency closure built first:
`pnpm turbo run build --filter=@objectstack/dogfood --concurrency=2`,
`VERDICT command-exit 0`, 65/65 tasks.
- **Green:** `pnpm --filter @objectstack/dogfood exec vitest run
--maxWorkers=2 test/bearer-lane-password-change.dogfood.test.ts
test/admin-ledger-decision-metadata.dogfood.test.ts` gave `Test Files 2
passed (2)`, `Tests 20 passed (20)` (12 bearer-lane tests, 8 ledger
tests), exit 0. It ran twice: before the ablation, and again after the
restore.
- **Typecheck:** `pnpm --filter @objectstack/dogfood typecheck` (`tsc
--noEmit`) exited 0. `tsc --listFilesOnly` lists both edited files in
that program (2 of 2).
### Ablation: each re-pinned expectation reverted to its old value
Each leg used `scripts/ablation-replace.mjs` in WRAP mode. Every anchor
hit 1 → 0, and every mutation was proved on disk by blob change and
`grep -c`. Every restore was proved: the blob equals HEAD and `git diff
HEAD` is empty.
| Leg | Mutation | Result |
|---|---|---|
| 1 | bearer `toBe('PASSWORD_RESET_REQUIRED')` →
`toBe('PASSWORD_EXPIRED')`, and the ledger set back to `required:
['event', 'passwordGenerated'], optional: []` (blobs `c2170a9eaf66` →
`1cd8a3348170`, `0826915c7b04` → `b8a4c082c149`) | `4 failed / 16
passed`: the 3 lanes, with `expected 'PASSWORD_RESET_REQUIRED' to be
'PASSWORD_EXPIRED'`, and the ledger control, with `expected [ 'event',
'passwordGenerated' ] to include 'revokeSessionsAndKeys'`. These are the
same 4 tests and the same assertion text as both hourly runs. |
| 2 | ledger: `revokeSessionsAndKeys` kept, the three counts dropped
(`optional: []`; blob `0826915c7b04` → `24315e7155c7`) | `1 failed / 7
passed`: the ledger control, with `expected [ 'event',
'passwordGenerated', …(1) ] to include 'revokedSessions'` |
After the restore, both blobs equal HEAD (`c2170a9eaf66`,
`0826915c7b04`), `git diff HEAD` is empty, and the green run above was
repeated at 20/20.
### Gates
`node scripts/pm/dispatch-gates.mjs --commands --repo
objectstack-ai/objectstack` derived 53 commands on `8b7306a355`. Each
one ran with its exit code captured before any pipe. `--ran` reconciles:
`53 derived, 51 run, 2 NOT-MEASURED, 0 UNRUN`.
- 51 exited 0, including `check:nul-bytes`,
`check:cross-package-test-inputs`, `check:test-source-alias` and
`check:issue-citations`. `check:dts-closure` and
`check:lean-entry-closure` exited 0 on a re-run after the closure build;
their first run had no `dist/`.
- 2 are NOT MEASURED (exit 3, PREREQUISITE NOT MET):
- `check:dual-build-cjs-loads` needs the whole workspace built, beyond
the dogfood closure.
- `check:type-check-debt`'s own closure build timed out in the shared
lock queue.
- Both are whole-tree families, which `Lint & Repo Gates` runs on this
PR.
- `node scripts/check-empty-changeset.mjs`: exit 0, no changeset added.
### What this PR's CI cannot show
The `Dogfood Regression Gate` jobs run only on `push` / `schedule` /
`workflow_dispatch` (`ci.yml`, `github.event_name != 'pull_request' &&
github.event_name != 'merge_group'`). This PR's checks therefore do not
run either file. The local runs above are the pre-landing evidence. The
first hourly full run after this lands is the authority, and it
refreshes #23493.
## Acceptance notes
- **Changeset: none, and `skip-changeset` applies.** The diff is two
test files in `@objectstack/dogfood`, a `private: true` package, so it
publishes nothing. On this repo an empty-frontmatter changeset is
refused (`check-empty-changeset`).
- **`origin/main` was not merged in before opening.** It moved four
commits past the base (`111b5821ce`, `5547ad451a`, `3a2adc8835`,
`f9b421716d`). A diffstat of that range over `packages/qa/dogfood`,
`plugin-auth`, `plugin-audit`, `core`, `rest` and `runtime` touches only
`runtime/src/domains/automation.ts` and a test beside it (the automation
flow doors). Neither is on the auth gate or the ledger path these pins
read. Merging would rebuild the whole closure on a shared box for no
overlap. This PR's CI runs on the merge ref.
- **The producer's doc comment is behind its type.** The header above
`AdminAuditDecisions` in `plugin-auth/src/admin-user-endpoints.ts` lists
the closed members (`event`, `passwordGenerated`, `placeholderEmail`,
`membershipCreated`, `organizationId`) and says each is "a decision that
no field of the user stores, or a reference to another record". It names
none of the four keys PR #23440 added, and the three counts are neither
a decision nor a reference: they are counts of what the revocation
landed. The type itself declares them, and no user-field value reaches
the row. Noted, not filed (`carrier:` none); this PR does not touch
product source.
---
_Generated by [Claude
Code](https://claude.ai/code/session_0121ooBYRmS8ziFXm9ai5YHm)_
Co-authored-by: Claude <noreply@anthropic.com>1 parent daafae6 commit 3f7cb1b
2 files changed
Lines changed: 26 additions & 7 deletions
File tree
- packages/qa/dogfood/test
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
87 | 87 | | |
88 | 88 | | |
89 | 89 | | |
90 | | - | |
| 90 | + | |
| 91 | + | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
| 95 | + | |
| 96 | + | |
| 97 | + | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
91 | 101 | | |
92 | 102 | | |
93 | 103 | | |
94 | 104 | | |
95 | | - | |
| 105 | + | |
| 106 | + | |
| 107 | + | |
| 108 | + | |
96 | 109 | | |
97 | 110 | | |
98 | 111 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
6 | 6 | | |
7 | 7 | | |
8 | 8 | | |
9 | | - | |
10 | | - | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
11 | 14 | | |
12 | 15 | | |
13 | 16 | | |
| |||
225 | 228 | | |
226 | 229 | | |
227 | 230 | | |
228 | | - | |
| 231 | + | |
229 | 232 | | |
230 | 233 | | |
231 | 234 | | |
| |||
241 | 244 | | |
242 | 245 | | |
243 | 246 | | |
244 | | - | |
| 247 | + | |
| 248 | + | |
| 249 | + | |
| 250 | + | |
245 | 251 | | |
246 | | - | |
| 252 | + | |
247 | 253 | | |
248 | 254 | | |
249 | 255 | | |
| |||
0 commit comments