R2 candidate 868f189 addresses Fable REQUEST CHANGES on 9a780c6: documents strict cookie and immutable verification-time contracts; adds missing negative navigation regressions; hardens numeric-person reuse with a dedicated-DEK HMAC over namespace/origin/issuer/ID/canonical verified address checked at every proof stage and resolution. Additive migration 0002 leaves earlier unbound rows refused. Consumers must still use nonreusable IDs and delete account links transactionally; address or dedicated-key changes require an explicit migration/relink. Also shares validated Keymail OAuth continuation and optional safe local landing path for Meet. Shared package tests pass; full gate running. Root arranging Fable rereview; no deployment or merge.
Extract shared app Home authentication and explicit account linking open
On branch feat/shared-connect
Authorized rollout to the other suite apps. Framework-neutral nested module home/connect extracts the working Docs a8 explicit-link state machine and Home consumer bridge. Uses existing browser-bound handoff package, independent local freshness proof, fresh Home proof, explicit confirmation, one-to-one stable local identity mapping; no email auto-link, membership claims, local account/sample creation or Docs migration. Application callbacks provide current existing local identity/admission using transaction-scoped SQL Queryer, verified session read/write, rendering and framework-specific CSRF. Generic link migrations use new tables and exported FS so old/new framework migration types need not mix. Shared routes/navigation helper owned by homereviewfix in this same isolated branch; bridge/linkstore/config owned by home_launcher. Root review/deploy; full CI includes nested module. Source provenance: Docs keymail-oauth3ff tree equals deployeda8 bridge/linkstore. Copy-review waived by user. Docs cryptographic purpose strings retained with app-specific namespace, but new tables mean no existing Docs data migration implied.
Fable claude-fable-5-1 R2 APPROVE868f189. Exact local full make test terminal exit0 including handoff, roster and connect race. Nonblocking follow-ups recorded: validate configured FormPolicy issuer directive, optional explicit Keymail provider origin pin, domain-derived HMAC subkey, unlink/address-change/key-rotation API, standalone OAuth template execution regression. Synthetic Sheets app browser8/8 now exercises OAuth template and continuation with Chromium/WebKit JSon/off narrow/wide and no CSP or referrer leakage. Shared recovery b7bf63d adds only explicit /signin/local failed-page action, preserves stale-cookie403 and no session/cookie mutation in regression. Root owns final Estilo presentation extraction and R3 review/gate before merge.
Final shared package 5b8d8410775ffd6e4f62c64673347cef3b15d255. Root verified every frozen source file byte-for-byte against git archive. Full make test (including all module race checks) terminal exit 0; exact CI success. Inert library source only; consumer activation separately reviewed/gated. Actual Fable verdict follows:
Verdict: APPROVE for the shared connect library at candidate 5b8d8410 vs 868f189c, conditional on a terminal local gate plus green CI before merge. No activation from this tree. Reviewer: claude-fable-5-1, read-only, 2026-09-10. Reviewed as frozen source/ plus branch.diff (7 files). No git available, so I could not verify the tree equals commit 5b8d8410.
Requested checks
| Check | Result | Evidence | |---|---|---| | Failed page points to local sign-in | Confirmed | view.go:38-39 sets /signin/local with the existing local_action label. Same pair the unknown state already used. | | Stale cookie still 403, no cookie mutation | Confirmed | bridge.go:144-147 unchanged. New TestStaleSessionStillRefusesAndOffersExplicitLocalRecovery (routes_test.go:75) asserts 403, no Location, href="/signin/local" in body, zero Set-Cookie, empty session store. | | Templates and Data alias to Estilo dec3908 | Confirmed | view.go:8,10 and oauth.go:88 are pure forwarders and type aliases. Estilo homeconnect.PageData and OAuthData have identical field sets to the removed local structs, so consumers see no API change. | | Module cache API matches go.sum | Confirmed | connect/go.sum h1 LgE7WLm6… equals the cached .ziphash. The .info file resolves the pseudo-version to commit dec3908b237c…, the Estilo-approved revision. Cached homeconnect/view.go exports Templates(), PageData, OAuthData and embeds templates/*.html, so the ParseFS(…, "templates/*.html") pattern is unchanged. | | No duplicate template definitions | Confirmed | Both local template files deleted. No define "home-connect", home-oauth-head or home-oauth remains anywhere under source/ outside the Estilo module. Docs source does not yet import connect.Templates. | | URLs still validated by security code | Confirmed | OAuthPage is only reached via oauth.go:35, after keymailDestination passes (https, no userinfo, no fragment, exact /oauth/authorize, clientid, redirecturi, scope, S256). Every PageData.Action is a compile-time literal. href and action are URL contexts in html/template. The meta refresh content attribute is contentTypeUnsafe in Go 1.25 attr.go:40, meaning HTML-escaped but not scheme-filtered, exactly as before the move. Estilo's view_test.go now covers the render tests that R2 flagged as missing. | | GOPRIVATE export | Works, but redundant | See finding 1. |
Findings (all Low, none blocking)
- Low,
Makefile:1. The added line duplicates theprivate_commaform that already existed in the base atMakefile:2. With an empty ambientGOPRIVATEthe result is,amadan.net/oficina/estilo.git,amadan.net/oficina/estilo.git. Go'sMatchPrefixPatternsskips empty and repeated globs, so it is harmless, but it is a leftover. Delete line 1 in a follow-up. - Low,
view.go:54.menu_actionis now an unused key inEnglish. Remove it or keep it for translators, but decide. - Low, copy.
failed_bodystill says "Return to the app and start again" while the action now says "Sign in to your existing account". Acceptable per your explicit label reuse; noting the mismatch. - Informational. Root
go.modpins Estilo at 672a447 whileconnect/go.modpins dec3908. Separate modules, root imports onlytheme, and the Estilo diff was additive, so no conflict. Align on the next root bump. - Informational.
connect/README.mddoes not say the templates now live in Estilo. One sentence would help the next reader.
Gate evidence. gate-r3.log is not terminal. Vet, fmt (silent pass, since build ran), build including arm64, and go test across all four modules are green, including connect and connect/linkstore. The log ends at the root race command with no output yet. The handoff, roster and connect race steps are absent. Merge only after the log shows the connect race step completing and CI runs the identical .amadan/ci.d targets. CI's ability to fetch the private Estilo module is an infrastructure question I could not verify from this tree.
Before activation each consumer still needs its own review, and any app that still defines home-connect or home-oauth locally must drop those definitions in the same change, as the Estilo review noted.
No commands were run and no files were written.