Review: Tailscale funnel bug

review-443-2026-03-27 Review

review ready

Verdict: READY

Template Completeness

  • [x] Type — Bug
  • [x] Lineage — Standalone, discovered during westside-app deployment investigation
  • [x] Repo — forgejo_admin/pal-e-services
  • [x] What Broke — describes dead westsidekingsandqueens-funnel ingress with kubectl evidence
  • [x] Repro Steps — 3 steps with specific kubectl commands
  • [x] Expected Behavior — single working funnel ingress
  • [x] Environment — cluster, namespace, SHA, alert status noted
  • [x] Acceptance Criteria — 3 criteria
  • [x] Related — links to project-pal-e-platform and westside-app #100
All required sections for the bug template are present and complete.

Traceability

  • [x] story:superuser-deploy label — superuser deploy story
  • [x] arch:tailscale-funnel label — Tailscale funnel architecture component
  • [x] Forgejo issue — forgejo_admin/pal-e-services#35, open
All three traceability legs present.

File Targets

  • [x] terraform/services.tf lines 171-200 — verified: kubernetes_ingress_v1.service_funnel resource uses each.key as service name (line 189) and each.value.port (line 191)
  • [x] terraform/k3s.tfvars lines 129-136 — verified: westsidekingsandqueens service key exists with port = 80 and funnel = true
  • [x] Live cluster state verified — kubectl get ingress -n westsidekingsandqueens confirms westsidekingsandqueens-funnel has no ADDRESS, while westside-app-funnel has the correct address
  • [x] Live cluster state verified — kubectl get svc -n westsidekingsandqueens confirms no service named westsidekingsandqueens exists, only westside-app on port 3000
All file targets and live cluster assertions from the ticket are accurate.

Repo Placement

Correct. The Forgejo issue is filed on pal-e-services, which is where services.tf and k3s.tfvars live. The fix is to set funnel = false in the tfvars (letting kustomize own the ingress). Since kustomize already manages the working ingress (westside-app-funnel in pal-e-deployments/overlays/westsidekingsandqueens/prod/ingress.yaml), this is the minimal fix. Single repo change.

Dependencies

  • No blockers found. Board item #443 is in todo column with no dependencies.
  • Related closed issue: forgejo_admin/westside-app#100 (CI image repo mismatch) — already resolved, no dependency.
  • Board item #401 (Remove non-functional gRPC funnel, pal-e-platform#182) is a similar dead-ingress cleanup in backlog — related pattern but independent fix.

Acceptance Criteria

All 3 criteria are verifiable by an agent:
  • westsidekingsandqueens-funnel ingress removed — verify via kubectl get ingress -n westsidekingsandqueens
  • westside-app-funnel continues to serve traffic — verify ADDRESS is still assigned and curl returns 200
  • No regression in site availability — curl https://westsidekingsandqueens.tail5b443a.ts.net
All criteria are concrete and automatable.

Blast Radius

  • pal-e-app has the same dual-management pattern but is NOT broken: the terraform service key (pal-e-app) matches the kustomize service name (pal-e-app) and both use port 80, so the terraform-created and kustomize-created ingresses collide on the same name and config. No duplicate ingress.
  • All other services (platform-validation, basketball-api, pal-e-docs, gcal-scheduler, mcd-tracker, mcd-tracker-app) have matching service names and show only a single funnel ingress each.
  • westsidekingsandqueens is the only service where the terraform key diverges from the kustomize service name. The dead ingress is inert (no ADDRESS, no traffic routing) so removal carries zero risk.
  • Architectural note: The root cause is dual ownership of the funnel ingress (terraform + kustomize). For westsidekingsandqueens, the kustomize ingress was created because the service name was renamed from the generic base. A broader fix would be to decide on single ownership, but that is out of scope for this bug fix.

Decomposition

Single file change (k3s.tfvars line 133: funnel = true to funnel = false) + tofu apply. Well under the 5-minute rule. No decomposition needed.

Recommendation

No action needed — ticket is READY for execution. The fix is a one-line tfvars change + apply.