Review: Hostname swap step 1 — additive api.pal-e-docs funnel (round 2)
Verdict: APPROVED
Round 2 review of board item #972 (Forgejo
forgejo_admin/pal-e-platform#278). Round 1 verdict was NEEDS_REFINEMENT (review-972-2026-04-11). All round 1 findings are resolved or explicitly accepted. Scope is now single-repo, two-new-files, additive-only, and fits the 5-minute rule.Round 1 Findings — Resolution Check
| # | Round 1 finding | Round 2 status | Verified by |
|---|---|---|---|
| 1 | [FALSE POSITIVE] claim that <code>arch-domain-pal-e-docs</code> does not exist | <strong>Refuted — confirmed live</strong> | <code>get_note(slug="arch-domain-pal-e-docs")</code> → id=1410, note_type=architecture, project=pal-e-docs, created 2026-04-10, status=active. Round 1 search missed it. |
| 2 | [REAL] wrong file targets (<code>terraform/k3s-funnels.tf</code> does not exist) | <strong>Resolved</strong> | Round 2 pivoted to Option B. Verified precedent <code>~/pal-e-deployments/overlays/pal-e-production/prod/ingress.yaml</code> exists (7-line Ingress using <code>ingressClassName: tailscale</code> + <code>tailscale.com/funnel: "true"</code>). Target files in the new overlay are plausible and do not collide with any existing file. |
| 3 | [REAL] decomposition needed (5-minute rule) | <strong>Resolved</strong> | Scope shrunk to Step 1 only. Single repo (<code>pal-e-deployments</code>), 2 new files, 8 ACs (all curl/kubectl verifiable), no SDK/MCP/frontend changes. Steps 2-7 filed as <code>forgejo_admin/pal-e-platform#280</code> (verified open). |
| 4 | [REAL] <code>arch:k8s-deploy</code> has no backing arch note | <strong>Accepted as known debt</strong> | Ticket explicitly acknowledges the gap, cites sibling tickets #234/#613/#973 also using the label, and defers a proper <code>arch-deployment-pal-e-docs</code> note as out-of-scope. Consistent with the traceability triangle convention's allowance for foundational-work gaps. |
| 5 | [REAL] deferred decisions in ticket body | <strong>Resolved</strong> | All redirect/decommission/swap choices moved to follow-up #280. This ticket has no scoping deferrals — every acceptance criterion is concrete. |
| 6 | [REAL] same-namespace ingress backend constraint | <strong>Trivially satisfied</strong> | New Ingress and existing <code>pal-e-docs</code> Service both live in the <code>pal-e-docs</code> namespace. Verified via <code>~/pal-e-deployments/overlays/pal-e-docs/prod/kustomization.yaml</code> which renames the base Service to <code>pal-e-docs</code>. |
Template Completeness
- [x] Type — Feature
- [x] Lineage — covers both discovery context and round 1 refutation
- [x] Repo —
forgejo_admin/pal-e-deployments - [x] User Story — reader-browse, correctly traced to
project-pal-e-docs - [x] Architecture —
arch:notes+arch:k8s-deploy(latter flagged as debt) - [x] Context — current-state table + target-state table, clear before/after
- [x] Rationale — preserved verbatim from round 1 for decision audit trail
- [x] File Targets — two new files with precedent path for templating
- [x] Acceptance Criteria — 8 concrete, verifiable
- [x] Test Expectations — 4 smoke tests including regression on existing hostname
- [x] Constraints — reversibility explicit, "do not touch" list complete
- [x] Checklist — standard
- [x] Related — dependency, follow-up, arch note, convention, precedent path, round 1 review
Traceability
- [x]
story:reader-browselabel — "I can browse public notes, plans, and project pages in a web UI without authentication." Verified inproject-pal-e-docsuser-stories table (row 5). - [x] story note verified — foundation is live at
project-pal-e-docs#user-stories - [x]
arch:noteslabel — maps to thenotescomponent row inarch-domain-pal-e-docs(id 1410). The new funnel exposes the FastAPI surface that serves note-shaped resources, so the label is load-bearing. - [x] arch note verified —
arch-domain-pal-e-docsid=1410 exists (refutes round 1 false positive) - [!]
arch:k8s-deploylabel — no backing note. Accepted as known debt per ticket body and per sibling-ticket precedent (#234, #613, #973). Tracked for futurearch-deployment-pal-e-docs. Not a blocker for this ticket. - [x] Forgejo issue — pal-e-platform#278, state=open
File Targets
- [x]
overlays/pal-e-docs-api/prod/kustomization.yaml— NEW. Parent dir does not exist yet (verified:~/pal-e-deployments/overlays/lists 14 overlays, nopal-e-docs-api). Creating a new overlay directory is the correct pattern and matches howpal-e-production,pal-e-streamlit,westside-email, etc. are structured. - [x]
overlays/pal-e-docs-api/prod/ingress.yaml— NEW. The template reference (overlays/pal-e-production/prod/ingress.yaml) exists and is 16 lines — literally justIngresswithingressClassName: tailscale,tailscale.com/funnel: "true", and adefaultBackend.serviceref. Copy-edit-commit is a <5-minute task. - [x] Unmanaged
pal-e-docs-funnel— correctly flagged as "do not touch". Verified:~/pal-e-deployments/overlays/pal-e-docs/prod/containskustomization.yaml,deployment-patch.yaml,embedding-worker.yaml,harbor-creds.enc.yaml— noingress.yaml, confirming the existing funnel is not managed by this overlay. Adding a new overlay next to it is safe and non-overlapping. - [x] Backend service ref
pal-e-docsin namespacepal-e-docs— verified viaoverlays/pal-e-docs/prod/kustomization.yamlwhich renames the base Service topal-e-docs. Port resolves at dev time viakubectl get svc -n pal-e-docs pal-e-docs(baseservice.yamluses 8000). Not a scoping gap — one-command lookup.
Repo Placement
Correct. Issue is filed on
forgejo_admin/pal-e-platform (the bootstrap repo, matching where the #278/#280/#234/#613 tickets live) but explicitly names forgejo_admin/pal-e-deployments as the implementation repo. The PR will open against pal-e-deployments. This is the standard split in this org: platform holds the meta-tickets, deployments holds the kustomize code.Dependencies
- Soft dep on pal-e-api#256 (CORS middleware) — ticket correctly notes that Step 1 does not require CORS (no browser-side fetches change) but flags it as a prerequisite for later steps. Not a blocker for #278.
- Unblocks follow-up #280 — verified open. Steps 2-7 depend on the additive funnel being live.
- Board item #972 is not blocked by any other in-flight item in
in_progressbased on the board listing.
Acceptance Criteria
All 8 ACs are concrete and verifiable by a dev agent without judgment calls. The ArgoCD sync check and the dual-ingress check give clean go/no-go signals. The cert smoke test acknowledges Tailscale cert provisioning latency implicitly (the AC is phrased as "after Tailscale provisions the cert"). The MCP smoke test being explicitly marked as "smoke test only, not a permanent migration" is exactly right — prevents scope creep into Step 3.
Blast Radius
Minimal and well-contained.
- Additive only: creates one new Ingress object in one namespace, zero modifications to existing resources.
- Reversible:
kubectl delete ingress pal-e-docs-api-funnel -n pal-e-docs(explicitly called out in ticket Constraints). - No SDK/MCP/frontend/CORS changes in this PR — all deferred to follow-up.
- The existing
pal-e-docs-funnelremains unmanaged and untouched, so there is zero risk to current MCP, SDK, and CLAUDE.md consumers. - Sibling overlay pattern (
pal-e-production-funnel) has been in production for 7 days with no issues — precedent is battle-tested.
Decomposition Assessment
No decomposition needed. Against the 5-minute rule:
- Files: 2 new files in 1 repo (limit: >3 files across >2 repos). Well under.
- Acceptance criteria: 8 ACs (limit: >5). Slightly over the nominal threshold, BUT all 8 are mechanical verifications of the same single change (kustomize create → ArgoCD sync → kubectl get → curl). They are not independent work units — they are verification facets of one atomic change. Splitting would be artificial.
- Estimated agent work: Copy precedent ingress.yaml (7 lines), change hostname, change service name, create kustomization.yaml referencing ingress.yaml, commit, PR. Realistic estimate: 3-5 minutes for the agent, plus ArgoCD sync + Tailscale cert provisioning wall-clock (not agent wall-clock).
- Repos: 1 (
pal-e-deployments). Limit: >2. Well under.
Round 2 decomposition is exactly the right grain. Further splitting would be muda.
Round 1 Findings Not Yet Addressed
None. Every round 1 finding is either resolved (#2, #3, #5, #6), refuted with evidence (#1), or explicitly accepted as known debt with a forwarding path (#4).
Minor Observations (non-blocking)
- [LABEL] Board item #972 title on board-pal-e-docs still reads "Swap hostname routing — pal-e-docs serves frontend, api.pal-e-docs serves API" (the round 1 framing). The Forgejo issue title has been updated to "Hostname swap step 1 — add additive api.pal-e-docs funnel via pal-e-deployments kustomize". Consider updating the board item display title to match — but this is metadata hygiene, not a scope issue, and should not block advancement.
- Round 1 review note
review-972-2026-04-11is referenced in the ticket body but a search of pal-e-docs returns no note with that slug. Not blocking — the round 1 findings are preserved verbatim in the ticket Lineage section, which is the load-bearing artifact.
Recommendation
APPROVED. Ticket is ready to advance backlog → todo. No blockers.
[LABEL](optional, non-blocking) Update board item #972 display title on board-pal-e-docs to match the current Forgejo issue title.
All other round 1 findings are resolved. Dispatch to dev when Ava is ready.