oficina / home Public

Native app team chooser for public entry open

On branch feat/suite-team-entry

Implements the existing Docs chooser for the closed native registry: Docs, Sheets, Slides, Calendar, Meet, Memoria. Shared templates and admission/continuation checks. Explicit preview launcher overrides remain supported. Provisioning remains disabled pending audited platform maintenance dispatch. Candidate dbccdae; full gate running; Fable review pending. No public host changes yet.

Verdict: APPROVE (source and preview scope only). Reviewer model ID: claude-fable-5-1. Read-only; no commands, writes or deploys were made.

What the delta does. The compiled registry gains five entries with provisionable false and no foreign origin. The Docs chooser type is parameterised by slug and display name, mounted once per integrated app inside the existing host, duplicate-cookie, session and CSRF middleware. Templates take the app name and form action from the compiled registry, never from request input.

Checks passed against the frozen source:

  • Authority and scoping. Choices are filtered by the session person_ref and by the chooser's own app slug. The route validator binds app slug to origin with exact string equality, so a sheets row pointing at a docs or mail host refuses the whole result with 503. Test covers this per app.
  • Stale membership. Selection re-queries membership after CSRF and session checks. Removed membership returns 404 per app.
  • Duplicate cookies, host, CSRF. The path guard now covers all twelve routes before session middleware. Foreign Origin returns 403. Host refusal is middleware-wide and unchanged.
  • Scriptless continuation. The continuation template is unchanged: meta refresh plus a plain no-referrer link, no script. The title string comes from the registry.
  • Preview launcher. The operator preview map still wins over the chooser link. Catalog tests updated to six anchors and no invented destinations.
  • Provisioning not weakened. No Go code reads the provisionable flag. The operator provisioning constructor is wired only in tests in this binary. The wider app set does let the roster source serve sheets, slides, calendar, meet and memoria rows, but only the operator transaction can create those rows.
  • Integration claim is supportable. Sheets, slides, calendar and meet pin the handoff module; the memoria journey log exercises Home identity tests. Docs was already reviewed.
  • Gate. The log at home-team-entry-gate.log shows vet, build, test and race steps all ok with no FAIL lines, ending at the connect race step.

Test naming. The added tests are TestNativeAppChoicesKeepTeamAndAppBoundaries and TestProviderAndUnknownAppsDoNotBecomeTeamConsumers, not a TestNativeAppChoosers function.

Spec updates required before merge to main (project convention puts these in the implementation commit):

  • implementation/directory-runtime.md still says the registry has one supported entry and that other apps are not declared ready. Record six integrated entries, all provisionable false, and cite the consumer evidence per app.
  • implementation/docs-team-chooser.md describes a Docs-only chooser and templates. Note the shared parameterised chooser and that the catalog Meet status changed from Coming soon.
  • implementation/team-entry.md "Directory and Docs stages" should state that the same chooser now serves the five other native apps with no provisioning change.
  • Home spec §11 should record that six integrated entries exist and that the New button and grid remain unimplemented.

Minor, non-blocking: the constructor error string still says "Docs"; the docs field on the features struct duplicates the first chooser; the registry slice is allocated on every request in the path guard.

Rollout preconditions unchanged by this delta. Public app domains remain existing instances. The change adds no bare-host gateway and does not touch old content, deep links or private credentials. An operator deployment path and a restored-backup drill are still needed before any public Home cutover.

Finished checking both deltas against the frozen source. Writing up the verdicts now.

Reviewer: Claude Fable 5.1, model ID claude-fable-5-1. Read-only, no commands or writes. Bindings reviewed: Home eab0719de7d0fe727145f90a00f533aa7aeb9374, Calendar 10212c522c1876786383c2742fc0a089f6df6afb.

Verdicts

| App | Source | Preview | Public | |---|---|---|---| | Home | APPROVE | APPROVE | not approved, not requested | | Calendar | APPROVE | APPROVE | not approved, not requested |

Both approvals are conditional on exact green CI at the bound SHAs and on the live preview reporting those same SHAs before merge. Local gates were reported passing but CI at the final SHAs is still pending, so neither is merge-ready yet.

Home

The delta is documentation only, and it records what the frozen source already does. The registry in internal/home/directory_runtime.go has exactly six entries, all integrated true and provisionable false. The catalog loop turns Meet's default "Coming soon" into the team chooser link, and the preview origin map still wins. No grid, New button or public cutover appears in code or docs. The four documents named in the previous APPROVE are the four updated. The two evidence files the runtime doc cites exist on this filesystem. Discussion 53 and SHA dbccdae could not be checked without git or network.

Calendar

Sequence change is correct and increments exactly once. The single event update carries deletedat, updatedat and one sequence expression. The host-cancel helper in store_booking_cancel.go deliberately does not touch the event, and queues the cancellation mail at the current sequence plus one, which is the revision the delete then produces. Booked path behaviour is unchanged. The existing host test still expects sequence 2 after confirm plus delete, and the held-booking path still expires with no mail. The only behavioural change is that unbooked deletes now also bump, which matches spec section 5.5 as written.

Test pin is load-bearing. The override is created at master sequence plus one, so the assertion fails only if the delete bump is missing.

Flaky test fix is sound. It picks the last free slot whose host-local hour is 10 or later, using the same zone the slot windows are built in. A 9:30 slot is correctly excluded since it lies inside 9 to 10. Three days of a 9 to 5 page always yield such a slot, so the sentinel fatal cannot fire spuriously.

AGENTS.md line matches code. The sentinel key name and the legacy calendar-name check match key_check.go.

Carried advisories, non-blocking

  • Calendar: deleting a series master soft-deletes its overrides without a sequence or updated_at bump. Same class as the advisory just fixed, narrower exposure.
  • Calendar: concurrent first boot on a legacy database can fail with a duplicate-key error rather than re-verifying.
  • Calendar: N+1 reads in the feed export. Perf only.
  • Calendar: SplitSeries tail overrides keep the head UID. Pre-existing.
  • Calendar: a de-allowlisted Home person gets 404 per request but the Home session row is never revoked.
  • Calendar: the new AGENTS.md paragraph sits under the Authorship heading. Cosmetic.
  • Calendar public promotion: the reconciliation review's REQUEST CHANGES stands. The frozen source now has a DEK boot check, one-master feed export, and exhaustion-aware expansion, but I did not re-verify the DST gap and reminder reschedule fix in this bounded review.
  • Home: constructor error string still says Docs, the docs field duplicates the first chooser, and the registry slice is allocated per request in the path guard.
  • Home: operator deployment path and restore drill remain required before any public cutover.

Exact eab0719 CI passed including full race gate. 24 browser chooser cases passed on frozen eab0719 (Chromium/WebKit, JS on/off, all six apps) using real TLS/CONNECT transport and synthetic sessions/team data; this is chooser navigation evidence, not live customer provisioning. Both overnight-home and overnight-home-id now report eab0719de7d0fe727145f90a00f533aa7aeb9374 in body and edge header. All six directory routes303 preserve selected app return; all six credential-origin routes404. Evidence /home/paulca/.cache/oficina-rollout-20260911/home-live.json and chooser-browser/results.json. Existing preview links and secrets retained. Final Fable APPROVE above; merge follows. Public rollout remains blocked on platform worker/operator path and restore drill.