chore(auth): close the password_set contract gap, fix the card's stale form - #3
Merged
Merged
Conversation
…e form The backend shipped, so the debt RUK-289 left behind came due. `me.json` is re-recorded against the live backend and `password_set` is on the wire, so the gap row and its absence assertion are gone. The detector worked as designed: the assertion said the key was ABSENT, so it was green while the gap was open and went red the moment the fixture was re-recorded. That is how this got closed rather than quietly forgotten. The registry row is kept and marked closed, per the file's convention — including a note that the row's first version named a detector that could not fire. Only `me` was re-captured. A full refresh needs a maintenance in the capture window and this database has none, but the recorder already skips context resolution for endpoints with a static path, so the narrow capture is the supported path rather than a workaround. The recorder masked `password_set` into the string `"<redacted-password_set>"` — `SENSITIVE_KEY_RE` matches its `password` prefix. It is a boolean saying whether an account HAS a password, not a credential, and masking changed its TYPE, which would fail any test asserting the shape. Added as a narrow allowlist rather than by loosening the pattern: the rule's asymmetry is right, and a false positive is fixed by naming it. Then the live run found a real defect no test could see. `asChange` was seeded with `useState(passwordSet === true)`, which runs only on mount, and this card is never remounted — so setting a password left `password_set` flipping to `true` on the wire while the form still offered "Set password", and the next submit would omit `current_password` and earn a 400 the user did nothing to deserve. It is now derived from the prop, with the one-time flip kept as an override. Every existing test mounted the component fresh, which is exactly why they all passed; the new ones re-render with a changed prop instead, and five tests fail against the old code. Verified end to end against the local stack: reset requested, code redeemed (204), session torn down, confirmation shown, sign-in with the new password works, `password_set` flips to true, and the profile card switches to the change form with no reload. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The backend shipped, so the debt RUK-289 left behind came due.
me.jsonisre-recorded against the live backend and
password_setis on the wire, so thegap row and its absence assertion are gone.
The detector worked as designed: the assertion said the key was ABSENT, so it
was green while the gap was open and went red the moment the fixture was
re-recorded. That is how this got closed rather than quietly forgotten. The
registry row is kept and marked closed, per the file's convention — including a
note that the row's first version named a detector that could not fire.
Only
mewas re-captured. A full refresh needs a maintenance in the capturewindow and this database has none, but the recorder already skips context
resolution for endpoints with a static path, so the narrow capture is the
supported path rather than a workaround.
The recorder masked
password_setinto the string"<redacted-password_set>"—SENSITIVE_KEY_REmatches itspasswordprefix. It is a boolean saying whetheran account HAS a password, not a credential, and masking changed its TYPE, which
would fail any test asserting the shape. Added as a narrow allowlist rather than
by loosening the pattern: the rule's asymmetry is right, and a false positive is
fixed by naming it.
Then the live run found a real defect no test could see.
asChangewas seededwith
useState(passwordSet === true), which runs only on mount, and this cardis never remounted — so setting a password left
password_setflipping totrueon the wire while the form still offered "Set password", and the nextsubmit would omit
current_passwordand earn a 400 the user did nothing todeserve. It is now derived from the prop, with the one-time flip kept as an
override. Every existing test mounted the component fresh, which is exactly why
they all passed; the new ones re-render with a changed prop instead, and five
tests fail against the old code.
Verified end to end against the local stack: reset requested, code redeemed
(204), session torn down, confirmation shown, sign-in with the new password
works,
password_setflips to true, and the profile card switches to the changeform with no reload.
Co-Authored-By: Claude Opus 5 noreply@anthropic.com