--- phase: 06-http-routing-auth-groups-and-rate-limiting plan: 10 subsystem: auth tags: [inv-scope, wire-json, php-parity, regression-tests] requires: - phase: 06-http-routing-auth-groups-and-rate-limiting provides: bouncer user/credential context, InvScope middleware, and shared wire.WriteJSON response conventions provides: - Byte-exact no-newline InvScope 401 and 403 denial responses - Raw-byte regression assertions for missing-user, missing-scope, and wrong-credential denial paths affects: [phase-06-verification, personal-token-routes, php-parity] tech-stack: added: [] patterns: - Security denial middleware delegates JSON serialization to the shared PHP-compatible wire writer - Wire-contract tests compare recorder bytes before decoding response shape key-files: created: [] modified: - fonoteka.go/plugins/golem15/fonoteka/middleware/token_scope.go - fonoteka.go/plugins/golem15/fonoteka/middleware/token_scope_test.go key-decisions: - "Use wire.WriteJSON for both InvScope denial branches so authentication and scope errors share the established PHP-compatible no-newline serialization path" - "Assert exact response bytes before secondary JSON shape checks; denial tests must never normalize whitespace" patterns-established: - "TokenScope parity: status, Content-Type, and raw body bytes are one indivisible HTTP contract" requirements-completed: [HTTP-05, HTTP-06] duration: 3h 15m completed: 2026-09-20 --- # Phase 6 Plan 10: Exact InvScope Denial Bodies Summary **Personal-token scope denials now use `wire.WriteJSON`, producing PHP-byte-identical 401/403 bodies with raw-byte tests that fail on any newline or carriage return** ## Performance - **Duration:** 3h 15m elapsed (including sandbox approval wait) - **Started:** 2026-09-20T19:10:39Z - **Completed:** 2026-09-20T22:26:07Z - **Tasks:** 1 TDD task - **Files modified:** 2 ## Accomplishments - Replaced InvScope's local `json.Encoder` response helper with the framework's PHP-compatible `wire.WriteJSON` for both denial branches. - Added exact raw-body assertions for the 401 missing-user and 403 missing-scope cases, including explicit final-`}` and no-CR/LF checks. - Kept JSON decoding as a secondary envelope check and preserved the valid-scope next-handler and wrong-credential fail-closed behavior. ## Task Commits Each TDD stage was committed atomically in the `fonoteka.go` repository: 1. **RED: Assert exact InvScope denial bytes** - `bf3f8a0` (test) 2. **GREEN: Emit exact InvScope denial bodies** - `d43cc76` (fix) **Plan metadata:** (this commit) _No refactor commit was needed; the production change is the minimal shared-writer delegation._ ## Files Created/Modified - `fonoteka.go/plugins/golem15/fonoteka/middleware/token_scope.go` - delegates 401/403 serialization to `wire.WriteJSON` and removes the local encoder helper. - `fonoteka.go/plugins/golem15/fonoteka/middleware/token_scope_test.go` - compares exact recorder bodies, asserts JSON content type, forbids CR/LF bytes, and retains decoded shape checks. ## Decisions Made - Both denial branches use the existing framework writer rather than duplicating newline trimming in app middleware. - Exact bytes are asserted before JSON decoding so semantically valid but wire-incompatible whitespace cannot pass. ## Deviations from Plan None - plan executed exactly as written. ## Issues Encountered - The first sandboxed Go verification could not write to the shared Go build cache; rerunning the same bounded command with approved cache access passed. This was an execution-environment constraint, not a code defect. ## User Setup Required None - no external service configuration required. ## TDD Gate Compliance - RED: `bf3f8a0` demonstrated all three denial bodies carried the unwanted trailing newline. - GREEN: `d43cc76` switched both branches to `wire.WriteJSON`; the exact tests passed under `-race`. - REFACTOR: omitted because the minimal implementation already removed the redundant helper. ## Verification - `go test ./plugins/golem15/fonoteka/middleware -run 'TestInvScope' -count=1 -race -short` - pass - `go vet ./plugins/golem15/fonoteka/middleware` - pass - `go test ./plugins/golem15/fonoteka/... -count=1 -short` - pass - Acceptance greps - two `wire.WriteJSON` calls present; no `json.NewEncoder`, local `writeJSON`, `TrimSpace`, or normalized denial-body comparison. ## Known Stubs None. ## Threat Flags None. The change narrows an existing authentication response serialization path and introduces no new endpoint, trust boundary, file access, or schema surface. ## Next Phase Readiness - The fourth authoritative Phase 6 verification gap is closed; Plan 06-11 can perform final coverage and phase closeout. - No blockers. ## Self-Check: PASSED - FOUND: both modified middleware files. - FOUND: `bf3f8a0` and `d43cc76` in the `fonoteka.go` history. - PASS: exact InvScope tests, middleware vet, and full Fonoteka plugin suite. - PASS: no generated or untracked files in `fonoteka.go`; the pre-existing main-repo `go.work.sum` remains untouched. --- *Phase: 06-http-routing-auth-groups-and-rate-limiting* *Completed: 2026-09-20*