docs(07): record the phase goal verification

The six plans are in, and three of the four success criteria hold. AUTH-01 stays blocked because the 15 user API routes are still pending against the recorded PHP bodies.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Jakub Zych
2026-09-22 19:27:27 +02:00
parent 9446981ffd
commit d4e9c17816
2 changed files with 152 additions and 0 deletions

View File

@@ -0,0 +1,42 @@
---
phase: 07-user-plugin-and-authentication
reviewed: 2026-09-22T17:26:00Z
depth: standard
files_reviewed: 4
files_reviewed_list:
- ../fonoteka.go/plugins/golem15/user/controllers/api_controller.go
- ../fonoteka.go/parity/schema_diff_test.go
- ../fonoteka.go/parity/manifest.yaml
- bouncer/phase07_coverage_test.go
findings:
critical: 0
warning: 2
info: 0
total: 2
status: issues_found
---
# Phase 7: Code Review Report
**Reviewed:** 2026-09-22T17:26:00Z
**Depth:** standard
**Files Reviewed:** 4
**Status:** issues_found
## Summary
The session, token, and lock tests match the handlers they name. Two response differences against the recorded PHP corpus are still in the Go handlers. Neither is a new crash or a secret leak. Both keep the user API routes pending.
## Warnings
### 1. Wrong activation code returns 200
`Activate` ignores the error from `VerifyActivationCode` and always writes the user payload at status 200. The isolated PHP app throws and returns the HTML error page at status 500 for `POST /_user/api/v1/activate` with `{"code":"wrong"}` and for `POST /_user/api/v1/activate-by-code` with `1!nope`. The fixtures record the HTML. The Go handler was left as-is in 07-05.
### 2. Logout blacklists a token PHP still accepts
Go logout adds the presented jti to `jwt_blacklist`, so the next fetch is 401. PHP logout returns `{"message":"Logged out"}` and a following fetch with that bearer is still 200. `TestSessionSequence` locks in the Go behavior. The recorded fixtures lock in the PHP behavior. The routes stay `pending`.
## Info
None.

View File

@@ -0,0 +1,110 @@
---
phase: 07-user-plugin-and-authentication
verified: 2026-09-22T17:26:00Z
status: gaps_found
score: 3/4 must-haves verified
overrides_applied: 0
---
# Phase 7: User plugin and authentication Verification Report
**Phase Goal:** The user plugin is ported with registration, login, JWT issue/refresh, organizations, personal API tokens and the must-change-password lock.
**Verified:** 2026-09-22T17:26:00Z
**Status:** gaps_found
## Goal Achievement
### Observable Truths
| # | Truth | Status | Evidence |
|---|-------|--------|----------|
| 1 | A user can register, log in, log out, reset a password, verify email, and receive a JWT the Nuxt app can use unchanged | ✗ FAILED | Handlers and mail tests exist. The 15 `/_user/api/v1` routes are recorded and `pending`. `TestParityCorpus` is 7 ported, 162 pending, 0 failing. Wrong-code activate is HTML 500 in PHP and 200 in Go. Fetch after logout is 200 in PHP and 401 in Go. |
| 2 | Organization fields arrive through a fire-and-collect event, and the user module does not import fonoteka | ✓ VERIFIED | `TestGetApiArray` and `TestRegisterImportDirection` passed under `-race`. |
| 3 | Personal tokens mint, list, and revoke inside the read/write/ai ceiling, and a read token is rejected on a write route | ✓ VERIFIED | `TestTokenApi` and `TestInvScope` passed under `-race`. The ported token and locale routes replay green. |
| 4 | The password lock returns 423 except locale and change-password, and locale still resolves while locked | ✓ VERIFIED | `TestMustChangePasswordLock` and `TestLocaleFromPrincipal` passed under `-race`. |
**Score:** 3/4 truths verified
### Required Artifacts
| Artifact | Expected | Status | Details |
|----------|----------|--------|---------|
| `bouncer` JWT mint/refresh/blacklist | Session tokens | ✓ EXISTS + SUBSTANTIVE | Round-trip and concurrent blacklist tests passed |
| `plugins/golem15/user` session and account handlers | Register through reset and activation | ✓ EXISTS + SUBSTANTIVE | Covered by session, mail, and sequence tests. Two responses differ from PHP |
| `plugins/golem15/fonoteka` tokens and locale | AUTH-03 and the lock exemption | ✓ EXISTS + SUBSTANTIVE | Ported routes replay green |
| `parity` user-api fixtures | Byte-identical replay | ✗ RECORDED, NOT REPLAYED | 15 routes stay `pending` |
**Artifacts:** 3/4 verified
### Key Link Verification
| From | To | Via | Status | Details |
|------|----|----|--------|---------|
| fonoteka `getApiArray` listener | user payload | fire-and-collect | ✓ WIRED | `TestGetApiArray` |
| `InvScope` | token routes | Phase 6 middleware | ✓ WIRED | `TestInvScope` returns 403 for a missing write scope |
| user API handlers | Nuxt contract | parity replay | ✗ NOT WIRED | Pending routes are not sent to the Go handler |
**Wiring:** 2/3 connections verified
## Requirements Coverage
| Requirement | Status | Blocking Issue |
|-------------|--------|----------------|
| AUTH-01 | ✗ BLOCKED | User API responses are not the PHP contract the Nuxt app calls |
| AUTH-02 | ✓ SATISFIED | Event payload and import direction are tested. Checkbox stays open until this phase passes |
| AUTH-03 | ✓ SATISFIED | Mint, list, revoke, and scope ceiling are tested |
| AUTH-04 | ✓ SATISFIED | 423 exemption and lock clear are tested |
| I18N-02 | ✓ SATISFIED | `LocaleFromPrincipal` is tested, including the locked path |
**Coverage:** 4/5 requirements satisfied. AUTH-01 blocks phase sign-off. None of the five checkboxes were marked in `REQUIREMENTS.md`.
## Anti-Patterns Found
| File | Line | Pattern | Severity | Impact |
|------|------|---------|----------|--------|
| `plugins/golem15/user/controllers/api_controller.go` | 322 | `VerifyActivationCode` error discarded | ⚠️ Warning | Wrong code still returns 200 |
| `jwt_blacklist` on logout | — | Stricter than PHP | ⚠️ Warning | Logged-out bearer is 401 in Go and 200 in PHP |
**Anti-patterns:** 2 found (0 blockers, 2 warnings)
## Human Verification Required
None — the failing comparison is already in the recorded fixtures.
## Gaps Summary
### Critical Gaps (Block Progress)
1. **User API is not the PHP contract**
- Missing: a green replay of the 15 `/_user/api/v1` routes
- Impact: the Nuxt app would notice activate and fetch-after-logout, and the other pending bodies were not accepted as matches
- Fix: change the Go handlers to the recorded PHP status and body, then flip those routes from `pending` to `ported` only when replay is green
### Non-Critical Gaps (Can Defer)
None. The schema allow-list for `user_throttle` and `jwt_blacklist` is an intentional snapshot gap, not a missing migration.
## Recommended Fix Plans
### 07-07-PLAN.md: Close the user API parity gaps
**Objective:** Make the 15 recorded `/_user/api/v1` routes replay against Go.
**Tasks:**
1. Match authenticated activate and activate-by-code failure to the recorded HTML 500.
2. Match fetch-after-logout to the recorded 200, or record an explicit decision that Go's blacklist is the contract and update the fixtures.
3. Diff the remaining pending bodies and close each one, then flip the route to `ported` only after replay is green.
**Estimated scope:** Medium
## Verification Metadata
**Verification approach:** Goal-backward from the ROADMAP success criteria
**Must-haves source:** ROADMAP.md Phase 7 success criteria
**Automated checks:** `go test ./... -race` passed in both modules after the schema-gate fix. Schema drift check returned `drift_detected: false`.
**Human checks required:** 0
**Regression gate:** prior-phase suites are in the same `go test ./... -race` run and passed
---
*Verified: 2026-09-22T17:26:00Z*
*Verifier: inline goal check after 07-06*