Skip to content

test(dogfood): re-pin the forced-reset gate code and the password-set ledger decisions to ruling C′ - #23512

Merged
objectstack-fleet[bot] merged 1 commit into
mainfrom
claude/issue-23493-dogfood-repin-ruling-c-prime
Oct 14, 2026
Merged

objectstack-fleet[bot] merged 1 commit into
mainfrom
claude/issue-23493-dogfood-repin-ruling-c-prime

Conversation

@objectstack-fleet

Copy link
Copy Markdown
Contributor

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:
  • 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 feat(spec,core,plugin-auth)!: an API key answers as its owner's session does when the ADR-0069 policy holds the account (#23287) #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

… ledger decisions to ruling C'

The administrator-forced change (must_change_password) now answers
403 PASSWORD_RESET_REQUIRED on every lane, and the admin password-set
ledger row records the revokeSessionsAndKeys switch (on every reset) and
the revocation's counts (when it ran). Both pins keep their exact answer;
only the answer moves to the ruled contract.

Claude-Session: https://claude.ai/code/session_0121ooBYRmS8ziFXm9ai5YHm
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 14, 2026
@github-actions github-actions Bot added the tests label Oct 14, 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 1418de4c7e07bf15469ee8a91ebab19fc843d0b1 → packageMentionDocs.

@objectstack-fleet

Copy link
Copy Markdown
Contributor Author

席位核对

domain:spec seat 4 (#18917) · sunhaolin · session session_0121ooBYRmS8ziFXm9ai5YHm · claim 6170989014 on #23493 · reviewed head 8b7306a3553075a16ed7cbd3eccf2f6da389585e · 2026-10-14T15:37Z

Verdict: ACCEPT. Not governed (check-governed-merges --pr 23512), 2 files, +26 / −7, test-only. It lands after the landing clauses in item 6.

  1. Shape. Draft, first line Fixes #23493, Clause-②: no at line start, skip-changeset (test-only; check-empty-changeset exit 0, no changeset added or changed). Only the two files the claim named. No product source.
  2. Premises against the dispatch.
    • The bearer-lane user is an administrator-forced change, not expiry: it is provisioned through /auth/admin/create-user (mustChangePassword), and the file arms no passwordExpiryDays. So ruling C′ item 2's PASSWORD_RESET_REQUIRED is the one ruled answer. The pin keeps 403 plus the exact code on all three lanes.
    • The ledger's closed set stays closed and is re-pinned to the producer, runAdminSetUserPassword and its AdminAuditDecisions type. revokeSessionsAndKeys is required, written on every admin password set. revokedSessions, revokedApiKeys and revocationComplete are optional, written only when the revocation ran.
    • The triage named one key; the producer writes four. Ablation leg 2 shows a one-key re-pin stays red.
    • No assertion was loosened, skipped or deleted.
  3. Gates and evidence.
    • Head check-runs read at this record: 30 success, 10 skipped, 4 in progress, 0 failures.
    • Dogfood Regression Gate reads success on the PR only because its three shard jobs skip on pull_request and merge_group by design (ci.yml :1648). It measured nothing here.
    • The pre-landing evidence for the two files is the dev's lock-held local run: 20/20 green.
    • Ablation leg 1 (both re-pins reverted) went 4 failed, the same four tests and assertion text as hourly runs 38568381233 and 38576826654.
    • Ablation leg 2 (one-key ledger) went 1 failed. The restore was proven: blobs equal HEAD, tree clean.
    • The authority after landing is the next hourly full run, which re-reads hourly full run: red on main (CI) #23493.
  4. Accepted deviations.
    • Four ledger keys instead of one, measured on the producer.
    • origin/main was not merged before opening: the 4 commits since the base touch none of these paths, and CI runs on the merge ref.
    • check:dual-build-cjs-loads and check:type-check-debt were NOT MEASURED locally (whole-tree). CI's lint and type-check lanes on this head are the reading.
  5. Out-of-scope dispositions. The doc comment above AdminAuditDecisions (plugin-auth/src/admin-user-endpoints.ts) still lists the pre-ruling members. That is comment drift with no reachable defect: Acceptance notes, carrier: none, dropped from filing.
  6. Landing clauses.
    • (a) Every check green, or skipped by design, on the landing head.
    • (b) mergeable_state clean at enqueue.
    • No contract review is owed: a re-pin of two tests to a landed, ruled contract changes no accept set or public surface.

@objectstack-fleet
objectstack-fleet Bot marked this pull request as ready for review October 14, 2026 15:49
@objectstack-fleet
objectstack-fleet Bot enabled auto-merge October 14, 2026 15:49
@objectstack-fleet
objectstack-fleet Bot added this pull request to the merge queue Oct 14, 2026
Merged via the queue into main with commit 3f7cb1b Oct 14, 2026
46 checks passed
@objectstack-fleet
objectstack-fleet Bot deleted the claude/issue-23493-dogfood-repin-ruling-c-prime branch October 14, 2026 16:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

hourly full run: red on main (CI)

2 participants