Lean A3b — pairing, eerste start, account; fix A3a login-rem #83
No reviewers
Labels
No labels
No milestone
No project
No assignees
2 participants
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
janpeter/Media-Organizer!83
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "feat/lean-a3b-pairing-account"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Samenvatting
Tweede helft van Lean A3 (auth), bovenop de gemergede en uitgerolde A3a.
POST /api/pair/start, krijgt een code +verifyUrl(uitAPP_BASE_URL); de eigenaar keurt goed op/pair(ingelogdeprotectedPage); de poll levert eenmalig een token, alleen als hash opgeslagen. Overgangen metSELECT … FOR UPDATEop id + bewaakteUPDATE … AND expires_at > clock_timestamp()(E6). Een apparaat-token kan niets goedkeuren of wijzigen (browserOnly)./setupis 404 zodra er een account is — pagina én action, race-vast via advisory lock./accountbeheert sessies en apparaten (intrekken per rij + alle andere) en het wachtwoord (huidig wachtwoord vereist, min. 12 tekens, via dezelfde rem/semafoor, trekt alle andere sessies en apparaten in)./users*worden redirects naar/account;create-adminen registratie verdwijnen; herstel vianpm run reset-password -- '<pw>'in de container.APP_BASE_URLin de compose-file; runbook met de Caddy-regelheader_up X-Real-IP {remote_host}(zonder die regel is de per-IP-rem adviserend).Bevat een fix van een gat in de UITGEROLDE A3a-login-rem: één begrensde FIFO op door de aanvaller gekozen namen was uit te zetten met ~1000 verzonnen namen. Opgelost met toelating in plaats van verdringing:
accountCounters(alleen een gevonden account maakt een sleutel, nooit te verdringen) ensharedCounters(verzonnen namen). Deze fix zit in de pairing-commit (throttle.ts) en gaat met A3b mee naar productie.Herkomst
docs/superpowers/specs/2026-09-20-lean-a3-auth-design.md(rev 3, errata E1–E9).docs/superpowers/plans/2026-09-20-lean-a3b-pairing-account.md(revisie 5, dubbele GO in reviewronde 5 doormac:codexenscrum4me-server:claude; Review record onderaan, vijf rondes). De drie patches naast het plan zijn toegepast; de codeboom na taak 2 is identiek aan de referentie-implementatie.Verificatie (lokaal, macOS)
typecheck,lint(0 errors, 3 bestaande warnings),buildgroen.deploy/media-organizer.env.sopsonaangeroerd.Open gates — niet door een agent
DELETE FROM "Session"is verplicht,device_pairing-rijen wissen is optioneel; het terugrol-artefact (§0 van het A3a-runbook) moet door JP opnieuw worden klaargezet als de sops-file sindsdien wijzigde.Aanvaard restrisico (§7.1)
Een hoofdlettervariant verraadt in ~7 pogingen of een gebruikersnaam bestaat. Bewust niet gerepareerd (de gebruikersnaam is geen geheim op een alleen-LAN-systeem); vastgelegd in een test.
🤖 Generated with Claude Code
Verdict: REQUEST_CHANGES
geen gekoppeld plan gevonden — beoordeeld op codekwaliteit + product-standaarden.
Findings
src/actions/account.ts:18—setupActionwordt geëxporteerd alsexport async function, terwijl de auth/productregel in deze PR zelf blijft voorschrijven dat server actions insrc/actions/*.tsaltijd alsexport const ...worden geëxporteerd. De uitzondering voorsetupActionhoort alleen te gaan over het ontbreken vanprotectedActionomdat er nog geen account bestaat, niet over het openbreken van de gesloten export-grammatica. Maak dit bijvoorbeeldexport const setupAction = async (...) => ...en laat de guard-test die vorm expliciet bewaken, zodat toekomstige action-exports niet ongemerkt buiten de afgesproken vorm vallen.Review-notitie
De pairing/setup/account-richting past verder bij de productdocs: één account,
/setupals publieke eerste-startpagina, publieke maar begrensdepair/startenpair/poll, en accountbeheer via/account. Door bovenstaande grammatica/patroonbreuk keur ik de PR niet goed.Dank voor de review. We houden
setupActionbewust alsexport async function; hieronder waarom dit geen breuk van de gesloten grammatica is.setupActionstaat inACTION_EXCEPTIONSinsrc/test/page-action-guard.test.tsmet reden (er is per definitie nog geen account, dusprotectedActionkan niet). De gesloten checker (src/test/guard-ast.ts) weigert elke niet-uitgezonderde export die niet exactexport const x = protectedAction(...)is.page-action-guard.test.ts:186eist voor élke uitzonderingexport async function <naam>in de bron. Een uitzondering kan dus niet ongemerkt een andere vorm aannemen, en een toekomstige action-export kan niet buiten de afgesproken vorm vallen zonder dat de test omvalt — precies de zorg die je noemt, is al afgedekt.setupActionwordt afgewezen:export async function stiekem()erbij → de boom-brede vormtest wordt rood. De uitzondering dekt exact één binding.loginAction,logoutAction,heartbeatAction) hebben dezelfdeexport async function-vorm en draaien al in productie (A3a). AlleensetupActionomzetten maakt de vier onderling inconsistent; alle vier omzetten raakt uitgerolde code zonder security- of correctheidswinst.De andere declaratievorm is hier bewust een zichtbaar signaal ('dit is een uitzondering, kijk hier') dat de test bovendien afdwingt — een extra grendel, geen losse. Op die gronden houden we de huidige vorm aan. Beslissing van de eigenaar (JP).