Skip to content

spec(system): retire EmailAndPasswordConfig.revokeSessionsOnPasswordReset — a completed password reset always ends the account's sessions #29909

Closed

Description

@objectstack-fleet

security#1 · os-justin · session_01QSeKYn5CmmdShCJifm6WYj

Blocked-by: #29827

Maintainer ruling. In session session_01QSeKYn5CmmdShCJifm6WYj on 2026-11-03, the maintainer first ruled, verbatim: 「一律吊销,不加开关」. A completed self-service password reset always ends the account's sessions, and there is no setting. Later, accepting the seat's analysis (reviewed at CONTRACT_REVIEW_TIER first), they said, verbatim: 「第三批 同意」. Item 2 of that analysis: retire the key.

What

PR #29827 makes plugin-auth always pass revokeSessionsOnPasswordReset: true. It also refuses an explicit false at the AuthManager constructor and in applyConfigPatch. After it lands, the spec key EmailAndPasswordConfig.revokeSessionsOnPasswordReset (packages/spec/src/system/auth-config.zod.ts:318, z.boolean().optional(), on the authorable-surface baseline) can hold only one value. Under ADR-0049 enforce-or-remove, it is retired.

Change (spec lane; follow the spec-property-retirement skill)

Acceptance

  • The key is gone from the authorable surface, and its tombstone prescribes the deletion.
  • No producer anywhere writes the key.
  • The D3 entry is registered.
  • check:authorable-surface, check:generated and the liveness ledger are green.

Re-check: git grep -n revokeSessionsOnPasswordReset -- packages docs skills content

Activity

  1. objectstack-fleet commented on Nov 3, 2026

    @objectstack-fleet
    ContributorAuthor

    triage#1 · os-zhuang · session_01AavokzJ5DndAwitDXvKy4U

    Path: none

    Triage: first-touch audit · p2 · domain:spec kept · pm:queue kept · 2026-11-03T11:03Z

    ⛔ Not a claim.

    • Read fresh. Retire EmailAndPasswordConfig.revokeSessionsOnPasswordReset, per the maintainer's 「一律吊销,不加开关」. Blocked-by: #29827 is satisfied: that PR merged at 10:39Z, so a reset always ends sessions and an explicit false is refused. A retirement, so p2 (「其余 p2」).
    • Follow the spec-property-retirement skill. The paired removal of plugin-auth's assertPasswordResetEndsSessions rides in the same change.

    Generated by Claude Code

  2. objectstack-fleet commented on Nov 3, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:spec#2 · os-support-ai · session_01WGufzhJG3tKnksHVa1krBz

    Claim: PM loop round 5
    Session: session_01WGufzhJG3tKnksHVa1krBz
    Account: os-support-ai
    Branch: claude/project-thread-dpz9e7 (card thread, executor session_01WGufzgjTaf6BB6T3vxdisU; the thread can push only its own branch, the measured platform exception to claude/issue-29909-…)
    Worktree: objectstack-issue-29909
    Domain: domain:spec
    Seat: domain:spec#2
    File surface: packages/spec/src/system/auth-config.zod.ts + test (the tombstone, the externalVocabulary example comment), plugin-auth's reset path and tests (assertPasswordResetEndsSessions and any forward of the key), docs/HARDENING.md, the ADR-0087 D3 entry, regenerated baselines and docs, .changeset/29909-*.md
    Container & model: S, mode:thread, model: TIER_DEFAULT, effort: high (p2); contract review at CONTRACT_REVIEW_TIER in seat before landing; dogfood pinned to the final head (narrowing)
    Clause-②: no (narrowing)
    Metadata-protocol: narrowed
    Responsibility: a password reset always ends the account's sessions | the spec still declares a setting that can hold only one value | plugin-auth (PR #29827 made the behaviour unconditional)
    Thread-read: 6602106272
    Premise: holds at main 21510bba: PR #29827 merged (the Blocked-by is cleared); EmailAndPasswordConfig.revokeSessionsOnPasswordReset is still z.boolean().optional() on the authorable surface. The executor re-greps every producer on its base.
    Serial constraints cleared: no open PR from this seat edits EmailAndPasswordConfig; the executor re-checks open PRs at PR time.

  3. objectstack-fleet commented on Nov 3, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:spec#3 · os-support-ai · session_01WGufzfgvGexKn9vLHsy89K

    Claim: PM loop round 8
    Session: session_01WGufzfgvGexKn9vLHsy89K
    Account: os-support-ai
    Branch: the card thread's own claude/project-thread-* branch, named in the dev's hand-back and restated in a later claim (a measured platform exception to claude/issue-29909-…)
    Worktree: objectstack-issue-29909
    Domain: domain:spec
    Seat: domain:spec#3
    File surface: packages/spec/src/system/auth-config.zod.ts (tombstone + comment) and its tests, the D3 migration entry, regenerated baselines/docs/ledger; packages/plugins/plugin-auth/src/{password-reset-ends-sessions.ts,auth-manager.ts} and their tests; docs/HARDENING.md, content/docs/permissions/authentication.mdx; .changeset/29909-*.md.
    Container & model: M, mode:thread, model: TIER_DEFAULT, effort: high
    Clause-②: no (narrowing)
    Metadata-protocol: narrowed
    Responsibility: n/a — not a defect card (ruled key retirement)
    Thread-read: 6602106272
    Premise: holds. #29827 merged (2026-11-03T10:39Z); on origin/main auth-config.zod.ts still declares revokeSessionsOnPasswordReset, and plugin-auth's assertPasswordResetEndsSessions refuses false.
    Serial constraints cleared: #29827 (merged). Dispatch resumed on the user's word 「车队可以继续派发了,只派发 p1 p2 ,总并发不超过 20」 (2026-11-03T15:40Z); this card is p2.

  4. objectstack-fleet commented on Nov 3, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:spec#3 · os-support-ai · session_01WGufzfgvGexKn9vLHsy89K

    Claim release: spec seat 3 withdraws its claim 6608275168 on #29909. Spec seat 2 (domain:spec#2) asked for this card first, and its card thread is already running, so seat 2's claim stands. The assignee and pm:dispatched stay as they are, under seat 2.

  5. objectstack-fleet commented on Nov 3, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:spec#2 · os-support-ai · session_01WGufzgjTaf6BB6T3vxdisU
    os-dev-report
    Stamp: 2026-11-03T18:15Z

    {
      "issue": 29909,
      "status": "done",
      "branch": "claude/project-thread-dpz9e7",
      "pr": "https://github.com/objectstack-ai/objectstack/pull/29964",
      "session": "session_01WGufzgjTaf6BB6T3vxdisU",
      "premise_still_valid": true,
      "summary": "EmailAndPasswordConfig.revokeSessionsOnPasswordReset is a retiredKey() tombstone with the exported prescription REVOKE_SESSIONS_ON_PASSWORD_RESET_RETIRED; RETIRED_KEYS_BY_MAJOR[18] row, D3 semantic entry email-and-password-revoke-sessions-on-reset-retired and a STEP18_RATIONALE fragment; no D2 (host plugin config, not a stack member or stored row). The externalVocabulary example comment now lists only live forwarded siblings. Falsified premise: plugin-auth's assertPasswordResetEndsSessions is NOT unreachable (AuthManager never parses its config through AuthConfigSchema), so on seat 2's word it was kept and re-aimed to refuse the retired key at ANY value with the spec prescription; auth-manager-auth-instance.ts has no forward of the spec key, only better-auth's own option, which stays. Tests writing true moved to the refusal; HARDENING.md (2 references, not 3) and content/docs/permissions/authentication.mdx (a producer the card did not list) updated. Step 0: the newest Claim at first was spec#3's (6608275168); stopped, seat 2 had it released (6608312848) and the live Claim 6608265385 names this branch.",
      "tests": "spec: new repo-project pin auth-revoke-sessions-on-password-reset-retirement.test.ts 15/15 (at 2d3b20f5); spec test:repo Test Files 90 passed (90), Tests 1539 passed (at 6c320a30); spec local targeted 6 files 255 passed; spec typecheck exit 0. plugin-auth: typecheck exit 0, test Test Files 219 passed (219), Tests 3772 passed, 10 skipped. Ablation at 6c320a30 via ablation-replace.mjs (retiredKey(...)  to  z.boolean().optional() /* ablated-29909 */, anchor 1 to 0, blob 6336afb7 to 3666d8f9, src-read so no build leg): pin 9 failed | 6 passed (15); restored, blob == HEAD 6336afb7, git diff HEAD empty.",
      "gates": "dispatch-gates --commands: 108 families (same list at 6c320a30 and d217dd5f). First serial run: 103 exit 0; check:comment-mask-adoption exit 1 (real: private comment stripper in the new pin; fixed in 2d3b20f5 via scripts/js-comment-mask.mjs, rerun exit 0); check-plugin-teardown-shape --self-test exit 3 (shallow clone; fetched pinned fixture, rerun 0); check:exported-any 3, check:skill-examples 3, check:generated 1 (stale spec dist during a concurrent test:repo; after rebuild all 0). dispatch-gates --ran: 108 derived, 108 run, 0 NOT-MEASURED, 0 UNRUN. check-changeset-no-major --event with the PR title+body exit 0 at d217dd5f (LEVEL AXIS no (narrowing) / narrowed, no package graded patch); check-adr-0087-registration and check-empty-changeset exit 0 at d217dd5f; check:cross-package-test-inputs, check:authorable-surface exit 0; check-platform-checklist --changed-from origin/main OK (23 anchors, 0 lost). After merging origin/main (os-regen-merge, clean) at d217dd5f: spec build + check:generated: all 14 generated artifacts up to date. CI check-runs: in_progress at report time.",
      "dogfood_battery": "d217dd5f · os-verify-lock: VERDICT command-exit 0 (turbo build 120/120 then pnpm --filter @objectstack/dogfood test, 47m35s shared box) · Test Files 414 passed | 3 skipped (417) · Tests 3427 passed | 28 skipped (3455) · no failures",
      "mcp_calls": "4 — mcp__github__issue_read x4 (get 1, get_comments 3); no write tools",
      "api_writes": "2 — relay pr_create (POST pulls, #29964) and this os-dev-report comment via post-stamped.mjs; git push is not a REST write",
      "open_questions": [],
      "security_findings": "none",
      "out_of_scope_findings": [
        "carrier: none · noted, not filed: overlap check searched open PR text only (0 hits for the key, EmailAndPasswordConfig, assertPasswordResetEndsSessions, password reset); open PRs' file lists were NOT MEASURED"
      ]
    }
  6. objectstack-fleet commented on Nov 4, 2026

    @objectstack-fleet
    ContributorAuthor

    domain:spec#2 · os-support-ai · session_01WGufzhJG3tKnksHVa1krBz

    Landed. PR #29964 merged through the queue (merge commit 4be8a2e9); this card closed as completed by its Fixes line.

    Reading Value
    PR #29964 MERGED at 2026-11-04T02:26Z, head bfdab107, contract review PASS 6612114259 + deltas 6613896572, 6616230346, 6620458295, ACCEPT 6620524481
    Card #29909 closed (completed)

    State change: pm:dispatched removed. What shipped: EmailAndPasswordConfig.revokeSessionsOnPasswordReset is retired (tombstone, RETIRED_KEYS_BY_MAJOR[18] row, ADR-0087 D3 entry email-and-password-revoke-sessions-on-reset-retired); plugin-auth refuses the key at any value, and a completed password reset always ends every session of the account. Left elsewhere: the dogfood census red at the final head was main's (#29975) and is already fixed on main by #29992; nothing carried. One low should-fix (the D3 entry's surface spelling) is not carried.

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

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions