oficina / home Public

Home suite app catalog open

On branch feat/home-app-launcher

Bounded directory UI: show the suite catalog, link Docs to the existing authenticated chooser, and label other apps unavailable until their Home integration exists. No tenant routing, provisioning, credential policy, registry integration, or preview destination changes. User waived copy review for this round. Fable review and exact CI required before merge; root coordinates canary evidence and release.

Candidate 32b33d11f4ab6152e7f155a3a3fe03e440fb1f85 pushed from main60faf. Display catalog remains separate from runtime integration registry. Docs uses existing /apps/docs team chooser; Sheets, Slides, Calendar are explicitly not connected to Home yet; Meet is coming soon. No new app destinations, config, sessions, credentials, route policies, tenancy or provisioning. Focused authenticated/anonymous/no-false-link tests and full make test passed (native/ARM64 builds, regular tests, all race suites). Exact branch CI pending. Fable and canary review not performed; root owns review/release. Local gate receipt: /home/paulca/.cache/oficina-home-app-launcher/gate.log.

Exact candidate CI is now green at 32b33d11f4ab6152e7f155a3a3fe03e440fb1f85. Evidence bound in /home/paulca/.cache/oficina-home-app-launcher/evidence.json. Local gate and CI terminal success; no review, merge or deploy claim.

Bounded preview launcher design, authorized by Paul through root: optional HOMEDOCSPREVIEW_ORIGIN is trusted operator configuration for the directory role only. Empty preserves /apps/docs and Choose a team. A canonical HTTPS DNS origin, without credentials, path, query, fragment or port, yields one ordinary Docs link to origin+/signin labelled Open preview. Reject malformed origin and credential/directory self-targets; reject nonempty use outside directory role at boot. Reuse originHost strict parser. No browser-supplied destination, DB persistence, network discovery, credential material, identity assertions, registered consumers, CSP expansion, team routes or membership policy changes. The destination app performs its already configured Home handshake; this setting does not grant access or register a consumer. Authorized preview target already uses docs-overnight in Home. Full cross-app availability remains future work. Tests cover default, valid, malformed, wrong-role config and authenticated rendered navigation.

Final preview candidate 822a49b9e9f352284f3b4409eb78b64cfd20d166 pushed. Seven catalog apps; Mail/Files descriptive only until canonical outbound targets confirmed. Added §11 dated, user-approved preview navigation exception. No extra production-host constant restriction because deployment origins are configurable; the setting remains explicit operator opt-in, directory-only, strict canonical HTTPS and not either Home origin. Full final gate runs against immutable git archive; prior candidate gate terminated as superseded (not a test failure). Root coordinates Fable and browser review.

Verdict: APPROVE (source review only; merge remains gated on final CI and canary evidence).

  • Candidate: 822a49b9e9f352284f3b4409eb78b64cfd20d166 vs main 60faf058b00d695481124e54c5a005e90281a2a2
  • Reviewer model: Claude Fable 5.1 (claude-fable-5-1)
  • Blockers: none. Follow-ups: three, all low severity.

What I verified

  • review/branch.diff and ../final.diff are identical, and the frozen review/source files match the diff (directory_catalog.go, directory.html, runtime.go, directory.go).
  • Loading and constructor guards. The setting is validated in all three entry points: LoadRuntime before the role switch (runtime.go:47-50), NewRuntime (runtime.go:159), and the direct newDirectory constructor (directory.go:20). Legacy and credential roles refuse any non-empty value. Empty value is a no-op, so existing deployments are unaffected.
  • Canonical origin restriction. Reuses the existing originHost (origins.go:39): https only, no userinfo, exact https://host string match (rejects path, port, query, fragment, trailing dot, whitespace), lowercase, no IP literal, label rules. Self-origin refusals compare against the configured credential and directory origins, not constants. The test corpus covers 24 negative shapes plus both self origins and both wrong roles.
  • Security policy. SecurityPolicy() untouched; the new element is a plain <a href> navigation, which none of the served CSP directives govern. Tests assert exactly one <a> on the page, no <script>, Cache-Control: no-store, anonymous 303 to /auth/start, and that ?return_to= on / is not reflected.
  • Template escaping. html/template in href-attribute context; Href is either the constant /apps/docs or validated origin plus the fixed /signin. Names and statuses are compile-time constants. Attribute spelling (rst-list, rst-row, rst-row-sub) follows AGENTS.md ruling 20 and exists in vendored tokens.css.
  • Scope. directoryApps, directoryRouteAllowed, docs_chooser.go, routes, consumers, migrations, and schema are unchanged. /apps/docs chooser behaviour is re-asserted under the preview setting.
  • Spec exception. The §11 paragraph states exactly what the code enforces (directory-only, canonical origin, self-origin refusal, fixed /signin, no consumer registration) and explicitly records the staged catalog as not the full grid. Dated and attributed. Consistent.
  • Live premise. live-before/results.json shows the deployed Docs preview at /signin already handing off to the same credential issuer as consumer docs-overnight, across Chromium and WebKit with JS on and off, which supports the "destination has its own Home handshake" assumption.

Follow-ups (non-blocking)

  1. directory_catalog.go:33 does not reject a preview origin that is a subdomain of the credential host, whereas Origins.validate does for the directory origin. Navigation-only, so low, but cheap to align.
  2. A rejected preview origin surfaces as the generic "invalid assertion configuration" error. Misleading for operators debugging this one setting.
  3. HOME_DOCS_PREVIEW_ORIGIN appears only in the spec, not in implementation/directory-runtime.md operator notes.

Evidence status

| Artifact | State | |---|---| | ci-final.json for 822a49b9 | running, not passed | | gate-final.log | vet/build/go-test ok, race stage incomplete | | evidence.json / ci.json | stale, for 32b33d1 | | docs-link-tests.log | ok |

Limitations. Read-only review; I ran no tests. The snapshot is not a git checkout, so I could not cryptographically bind review/source to the candidate hash beyond diff equivalence. rastrillo's security-header middleware and the Estilo theme are outside the tree and were not inspected. Copy review waived per user. Authenticated browser fixtures and live canary verification remain outstanding and are required before closing the stage.

Root observed CLI terminal exit 0. Candidate extracted by git archive from exact822a49b; source binding and final CI/live canary evidence will be recorded before merge.

Final candidate822a49b9e9f352284f3b4409eb78b64cfd20d166 full local make test PASSED from immutable archive, including ARM64 commands and every race suite; exact candidate CI SUCCESS. Evidence receipt /home/paulca/.cache/oficina-home-app-launcher/evidence-final.json binds gate-final.log and ci-final.json. No authored changes after this candidate. Root owns Fable/browser review and release. Worktree clean; local gate terminal0.

Candidate822a49b9e9f352284f3b4409eb78b64cfd20d166 meets Fable source-approval conditions: full immutable-source make test exit0 and exact candidate CI success (ci-predeploy.json), all203 source files byte-match git objects (review/binding.json), 8 authenticated synthetic UI browser cases pass (ui-822a49), and8 live unsigned canary browser cases pass (live-canary/results.json). Both actual Home /api/version bodies and edge headers match822a49b (canary-verified.json). The first deploy watch timed out while directory still executed eabd7e1; scoped restarts/config convergence eventually yielded822, with original logs retained. Only named overnight-directory config gained HOMEDOCSPREVIEW_ORIGIN=https://overnight-docs.bds.oncarlos.com. Other app config, credentials, team routing, roster and checker activation unchanged. No human sign-in/email/account-link action performed. Home53 tracks low follow-ups. Ready to merge exact candidate.

Merged as cd476a280200fddfe02eae43c289c5426132d937; tree exactly equals reviewed, tested and live822a49b. Kept the verified candidate release live rather than cycling identical code under a new version string. Production Home and Docs versions unchanged. Task52 Done; Home53 low follow-ups. User must complete their own one-time explicit Docs/Home account connection; no authentication or identity shortcut performed.