Record the chooser's app-root destination in the implementation notes
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2 files changed,
+2
−2
implementation/directory-runtime.md+1 −1implementation/docs-team-chooser.md+1 −1
CI failed — run details
CI log
amadan: .amadan/timeout: this job's budget is 15m0s (this runner allows up to 30m0s) === vet === CGO_ENABLED=0 go vet ./... go: downloading amadan.net/carlos/platform.git/launchctx v0.0.0-20260911135504-fb577f96f7d1 go: downloading amadan.net/oficina/estilo.git v0.0.0-20260911182719-0bcb9287988d internal/home/credits.go:8:2: amadan.net/oficina/estilo.git@v0.0.0-20260911182719-0bcb9287988d: invalid version: git fetch -f --end-of-options origin refs/heads/*:refs/heads/* refs/tags/*:refs/tags/* in /home/paulca/.local/state/amadan/runner/repos/oficina__home/cache/go-mod/cache/vcs/bf4984e7a537af013cffcd0a654026b503a4e1566cddf740e3c37d2f6ae937e4: exit status 128: fatal: unable to access 'https://amadan.net/oficina/estilo/': The requested URL returned error: 429 internal/home/app.go:25:2: amadan.net/oficina/estilo.git@v0.0.0-20260911182719-0bcb9287988d: invalid version: git fetch -f --end-of-options origin refs/heads/*:refs/heads/* refs/tags/*:refs/tags/* in /home/paulca/.local/state/amadan/runner/repos/oficina__home/cache/go-mod/cache/vcs/bf4984e7a537af013cffcd0a654026b503a4e1566cddf740e3c37d2f6ae937e4: exit status 128: fatal: unable to access 'https://amadan.net/oficina/estilo/': The requested URL returned error: 429 internal/operator/command_linux.go:10:2: amadan.net/carlos/platform.git/launchctx@v0.0.0-20260911135504-fb577f96f7d1: invalid version: git fetch -f --end-of-options origin refs/heads/*:refs/heads/* refs/tags/*:refs/tags/* in /home/paulca/.local/state/amadan/runner/repos/oficina__home/cache/go-mod/cache/vcs/55cd75de7b117f7c5cd43edfd800f8d47521af42d6b939d46f385b6d34c14c9a: exit status 128: fatal: unable to access 'https://amadan.net/carlos/platform/': The requested URL returned error: 429 internal/operator/command_linux.go:11:2: amadan.net/carlos/platform.git/launchctx@v0.0.0-20260911135504-fb577f96f7d1: invalid version: git fetch -f --end-of-options origin refs/heads/*:refs/heads/* refs/tags/*:refs/tags/* in /home/paulca/.local/state/amadan/runner/repos/oficina__home/cache/go-mod/cache/vcs/55cd75de7b117f7c5cd43edfd800f8d47521af42d6b939d46f385b6d34c14c9a: exit status 128: fatal: unable to access 'https://amadan.net/carlos/platform/': The requested URL returned error: 429 make: *** [Makefile:69: test-vet] Error 1 amadan: step vet failed: exit status 2 amadan: job failed at step vet — its output is above, not at the tail of this log
diff --git a/implementation/directory-runtime.md b/implementation/directory-runtime.md| index f97acd8..b8638cc 100644 |
| --- a/implementation/directory-runtime.md |
| +++ b/implementation/directory-runtime.md |
| @@ -26,7 +26,7 @@ Mount GET /apps/docs and POST /apps/docs/team under the directory's existing exa |
| Before chooser handlers consult the session, reject duplicate actual session cookies for these two chooser routes. Do not change the existing assertion callback or global session flow in this slice. Constructor tests exercise the actual App.Handler and role routing so credential and legacy hosts cannot reach the chooser. Every chooser response, including errors and unknown-host refusal at the app boundary, remains no-store; use the narrow route boundary as needed without weakening shared host checks. |
| -Zero choices renders the reviewed empty page; one choice uses the existing303 GET redirect to the registered app's /auth/start with local return /. Multiple choices render the reviewed form. The successful POST response depends on separately reviewed continuation amendment95dcd682ac106ab725d9a85f141285709ab3659c: return200, immediate meta-refresh plus a plain fallback link to the revalidated stored destination. Preserve CSRF and the post-selection membership re-query. This avoids an unbounded outgoing CSP list; no wildcard or global form-action change. Do not implement or deploy the successful POST integration before that amendment is approved and its browser/fallback tests pass. |
| +Zero choices renders the reviewed empty page; one choice uses the existing303 GET redirect to the registered app's root / (amended 2026-09-23 from /auth/start with local return /; the successful POST continuation targets the same root). Multiple choices render the reviewed form. The successful POST response depends on separately reviewed continuation amendment95dcd682ac106ab725d9a85f141285709ab3659c: return200, immediate meta-refresh plus a plain fallback link to the revalidated stored destination. Preserve CSRF and the post-selection membership re-query. This avoids an unbounded outgoing CSP list; no wildcard or global form-action change. Do not implement or deploy the successful POST integration before that amendment is approved and its browser/fallback tests pass. |
| A source-backed browser check exposed a second redirect-chain case: an expired directory session on an otherwise same-origin chooser POST currently returns303 to /auth/start and then to the credential origin, where form-action self blocks it. Handle this inside the chooser subject helper after Select has applied its existing method/path checks and CSRF protection. When that helper finds no current session on POST, render the same200 continuation template to the fixed validated directory origin plus /auth/start?return_to=%2Fapps%2Fdocs. An anonymous GET still uses the existing303. Refactor only the common final rendering/header step; the successful-choice caller validates its stored Docs origin, while the reauthentication caller constructs its destination entirely from validated runtime origin and fixed constants. No submitted team, arbitrary URL, query parameter or resource path enters that destination. Both set no-store and no-referrer and keep a real plain fallback link. This starts authentication only; it does not retain the stale submitted selection or create a membership/session/proof. After sign-in the chooser re-queries current membership and the person selects again if several teams remain. Test real expired-session POST in Chromium/WebKit with scripts on/off, fallback navigation, fixed Home return and unchanged CSRF/unknown-host refusal; do not treat the old blocked behavior as accepted integration. |
diff --git a/implementation/docs-team-chooser.md b/implementation/docs-team-chooser.md| index 3d370f3..cd69ccd 100644 |
| --- a/implementation/docs-team-chooser.md |
| +++ b/implementation/docs-team-chooser.md |
| @@ -6,7 +6,7 @@ A directory App constructs the chooser with `newDocsChooser(store)`. Credential |
| Entry accepts no query parameters. It reads identity exclusively from sessions.Current and requires Home's opaque person-ref shape. Signed-out navigation redirects to the shared consumer with fixed return_to=/apps/docs; a test follows the actual credential issuer, callback, inbox and finish back to that route. No email, team selection, arbitrary return URL or document path is accepted as identity/navigation state. |
| -Zero live choices renders an honest empty state. One redirects to that validated stored origin's /auth/start with local return /. Several render ordinary POST buttons carrying only team sqid. Selection re-queries current memberships and compares the requested sqid; foreign, removed and unknown teams receive the same 404. Redirecting changes no session/cookie and grants no item access. Apps must still validate roster standing and individual grants after their own authentication. Two simultaneous tabs carry independent explicit POST selections. |
| +Zero live choices renders an honest empty state. One redirects to that validated stored origin's root, / (amended 2026-09-23, shared-chrome spec §6.2(a): it was /auth/start with local return /, which re-ran the exchange even with a live app session; the app's own guard now decides). A configured preview origin for the app takes precedence over team choices here too, redirecting to the preview's root without a directory session (§6.2(b)). Several render ordinary POST buttons carrying only team sqid. Selection re-queries current memberships and compares the requested sqid; foreign, removed and unknown teams receive the same 404. Redirecting changes no session/cookie and grants no item access. Apps must still validate roster standing and individual grants after their own authentication. Two simultaneous tabs carry independent explicit POST selections. |
| The existing Home renderer, layout, Estilo theme assets and Rastrillo attribute components are reused. Team names stay template-escaped; no script is added. Every controller response including redirects, method/query errors, CSRF rejection and storage failure is no-store. A failed read renders fixed text without stored names or origins. Runtime routing remains unchanged. |