Review: Add prediction-assistant to services terraform
Verdict: READY
Pass 3 — 2026-07-04. Prior passes had conflicting findings about whether the entry already exists. Verified directly: it does NOT exist in k3s.tfvars. Issue body corrected to say "add new entry".
Template Completeness
- [x] Type (Feature)
- [x] Lineage
- [x] Repo
- [x] User Story
- [x] Context
- [x] File Targets
- [x] Feature Flag (none)
- [x] Acceptance Criteria
- [x] Test Expectations
- [x] Constraints
- [x] Checklist
- [x] Related
Traceability
- [x] story:platform-setup label — verified in project-prediction-assistant user-stories table
- [x] story note verified — "Platform Setup" entry exists on project-prediction-assistant user-stories section (key: platform-setup, role: Developer (Lucas))
- [x] arch:iac label — present on board item
- [ ] arch note MISSING — arch-iac note does not exist in pal-e-docs. Known platform-wide documentation gap; not blocking per review policy
- [x] Forgejo issue — ldraney/pal-e-services#170, open
File Targets
- [x]
terraform/k3s.tfvars— verified: file exists (symlinked from ~/secrets/pal-e-services/k3s.tfvars). Confirmed prediction-assistant entry does NOT exist (grep returns empty). Services map starts at line 218. Existing pattern clear (landscaping-assistant at line 228 is the closest Rails analog: port 3000, funnel true). - [x]
terraform/services.tf— verified: for_each loop at line 156.coalesce(each.value.source_repo, each.value.forgejo_repo)at line 181 correctly handles null source_repo by falling back to forgejo_repo. Agent correctly told NOT to touch. - [x]
terraform/variables.tf— verified: service type definition at lines 234-247. All required fields present (forgejo_repo, image_repo, port, funnel, source_repo optional, source_path optional). Agent correctly told NOT to touch. - [x]
k8s/overlays/prod/— verified: directory exists in prediction-assistant repo with kustomization.yaml, ingress.yaml, cluster-issuer.yaml, redirect-middleware.yaml. source_path value "k8s/overlays/prod" is accurate.
Repo Placement
Correct. Issue filed on pal-e-services (#170), which is where the services terraform and k3s.tfvars live. Single-repo change — no cross-repo coordination needed.
Dependencies
- #1769 "Add prediction-assistant database to CNPG" (backlog, sprint:9) — sibling, not a blocker. Services entry is independent of database provisioning.
- #1768 "Add Keycloak realm + OIDC client" (backlog, sprint:9) — sibling, not a blocker. Keycloak and services are separate terraform resources.
- #1772 "tofu apply — provision prediction-assistant infra" (backlog, sprint:10) — downstream dependency. Correctly sequenced one sprint later. Depends on this ticket completing first.
- #1770 "Update .woodpecker.yaml to match platform CI pattern" (backlog, sprint:9) — sibling, independent.
No undocumented blockers. Sprint sequencing (sprint:9 before sprint:10) implicitly handles the dependency chain.
Acceptance Criteria
All 4 criteria are concrete and agent-verifiable:
- [x] AC1: "prediction-assistant entry exists in services map without source_repo" — verifiable via grep. Omitting source_repo is a supported pattern: coalesce() falls back to forgejo_repo (line 181 of services.tf). Precedent: platform-validation entry in k3s.tfvars.example also omits source_repo.
- [x] AC2: "source_path is k8s/overlays/prod" — verifiable via grep. Path confirmed to exist in the prediction-assistant repo with kustomization.yaml.
- [x] AC3: "tofu plan shows new namespace, Harbor project, robot accounts, ArgoCD application, Tailscale funnel" — verifiable via tofu plan output.
- [x] AC4: "No errors on plan" — verifiable via exit code.
Test command
cd terraform && tofu plan is real and appropriate.Blast Radius
Low. Adding a new entry to the services map is additive — it cannot break existing services. The for_each loop processes each service independently. The image-updater annotation conditional (lines 171-173 of services.tf) correctly omits the kustomization write-back-target when source_repo is null, which is appropriate for a service whose k8s manifests live in the app repo. No similar bug pattern to propagate — this is a new entry, not a fix.
Decomposition Assessment
- 1 file target across 1 repo — below threshold
- 4 acceptance criteria — below threshold
- Estimated agent work: under 2 minutes (add ~8 lines to a tfvars map, run tofu plan)
No decomposition needed.
Recommendation
[SCOPE]Create architecture notearch-iacfor the IaC component — platform-wide gap, not blocking this ticket. Track as a separate documentation item.
No other action needed. Scope is solid.