12 KiB
12 KiB
Nereus delivery roadmap
Updated: 2026-08-26
[x] means locally verified. [~] means implemented but awaiting a real
integration environment. [ ] means not implemented. [H] is human-owned and
must not be edited by agents.
Update this file in the same change that completes or materially changes a
task. Mark a task [x] only after its stated verification passes.
API service
- Create the Go 1.26 module and dependency lock file.
- Create the idempotent
buoystable migration. - Create the idempotent
readingstable migration. - Create
idx_readings_buoy_timeidempotently. - Parse
PORT,CHAOS_ERROR_RATE, andLOG_LEVEL. - Preserve the build-injected
APP_VERSIONvalue. - Require
DATABASE_URLwithout logging it. - Start HTTP without waiting for PostgreSQL.
- Retry migrations while PostgreSQL is unavailable.
- Keep
/healthzindependent of PostgreSQL. - Require a reachable, migrated database for
/readyz. - Implement
GET /api/v1/buoys. - Implement
POST /api/v1/buoys. - Implement
GET /api/v1/buoys/{id}. - Implement
DELETE /api/v1/buoys/{id}. - Implement filtered, paginated
GET /api/v1/readings. - Implement
POST /api/v1/readings. - Implement the real grouped aggregate query.
- Bound JSON request bodies and return JSON errors.
- Restrict chaos injection to
/api/v1/*. - Expose all five required Prometheus metrics.
- Use chi route templates for the HTTP
pathlabel. - Enable OTLP/gRPC tracing only when configured.
- Create HTTP spans and child database spans.
- Emit structured request logs containing
trace_id. - Add table-driven handler tests without a live database.
- Test chaos and unaffected health behavior.
- Add a
testing.Short()-guarded PostgreSQL integration test. - Pass
go test -short ./.... - Pass
go vet ./.... - Build with
CGO_ENABLED=0. - Run the integration test against PostgreSQL 17.
- Test database failure behavior on every data endpoint.
- Assert exact metric names and route-template labels in tests.
- Test malformed and oversized JSON request bodies.
- Run
golangci-lint runwith the CI-selected version.
Load generator
- Create the standalone Go 1.26 module.
- Require
TARGET_URLand defaultRPSto 5. - Reuse existing buoys or seed 42 validated offshore buoys.
- Generate the 60/25/15 request mix.
- Generate plausible synthetic reading values.
- Count HTTP statuses and network errors.
- Log a JSON status summary every ten seconds.
- Continue traffic while requests and seeding fail.
- Retry seeding without blocking read traffic.
- Handle SIGTERM and SIGINT.
- Keep the implementation below 200 lines.
- Pass
go vetand a static build. - Test request weighting deterministically.
- Test seeding against an empty
httptestAPI. - Test continued traffic through repeated HTTP 500 responses.
- Run against the real API for at least five minutes.
- Confirm Prometheus receives continuous request samples.
Container build and local Compose
- Create the API builder stage from
golang:1.26-alpine. - Cache dependencies before copying API source.
- Build with
CGO_ENABLED=0and-ldflags "-s -w". - Inject
APP_VERSIONwith-X. - Copy only the API binary into
gcr.io/distroless/static:nonroot. - Create the load-generator multi-stage image.
- Use
gcr.io/distroless/static:nonrootfor the load generator. - Add the required
.dockerignoreexclusions. - Confirm both images run non-root and read-only.
- Confirm the API image is below 25 MB (7,815,877 bytes locally).
- Add API, PostgreSQL 17, and OTEL Collector to local Compose.
- Add the PostgreSQL healthcheck.
- Make the API wait on healthy PostgreSQL in Compose.
- Verify
docker compose upreaches API readiness. - Keep Mini PC and local-development Compose files separate.
Static web dashboard
- Create the no-build static HTML entry point.
- Create the dark teal/navy glass visual system.
- Replace decorative background waves with an operational chart grid.
- Keep version, health, and error panels visible together.
- Show the build-injected API version from the existing health response header.
- Poll
/healthzevery two seconds. - Poll
/readyzevery two seconds. - Show each health indicator's last transition timestamp.
- Count non-2xx
/api/v1/*browser responses. - Calculate the rolling 60-second HTTP error rate.
- Distinguish network-offline events from HTTP errors.
- Preserve and grey the last known telemetry values offline.
- Recover automatically when the API returns.
- Add a fully local Natural Earth buoy map and pulsing markers.
- Add animated reading charts.
- Keep all API calls same-origin and relative.
- Remove all frontend runtime dependencies on external hosts.
- Verify all panels fit at 1280×720 without page scrolling.
- Create the unprivileged nginx image.
- Create the separate Mini PC Traefik Compose file.
- Test the finished offline/degraded rendering without API connectivity.
- Test the rendered dashboard while the API returns HTTP 500 responses.
Observability
- Receive OTLP/gRPC traces in the Collector.
- Export traces from the Collector to Tempo.
- [~] Ship structured Kubernetes pod logs to Loki with the cluster Collector.
- Start Loki locally and verify its Grafana data source readiness.
- Configure Prometheus to scrape
/metrics. - Add request-rate, error-rate, and latency panels.
- Add database-operation latency panels.
- Add readings-ingested and active-buoy panels.
- Add a deployed-version dashboard variable.
- [~] Correlate logs and traces using
trace_idafter cluster log ingestion exists. - Add API error-rate, latency, readiness, and scrape alerts.
- Load the dashboard and evaluate all six PromQL queries.
- Trigger chaos and distinguish the failing version in Grafana.
Fedora 44 host provisioning
- Separate node 1 and node 2 inventory groups.
- Pin the project k3s version.
- Reject managed hosts that are not Fedora 44.
- Install common host dependencies.
- Enable firewalld.
- Trust the configured pod and service CIDRs.
- Open VXLAN port 8472/UDP between nodes.
- Open kubelet port 10250/TCP between nodes.
- Open API server port 6443/TCP on node 1.
- Install node 1 as the k3s server.
- Install node 2 as a k3s agent.
- Keep the cluster token out of repository files and output.
- Enable both k3s systemd services.
- Wait for every Kubernetes node to become Ready.
- Add the equivalent manual configuration checklist.
- Document Terraform-to-Ansible inventory handoff.
- Keep libvirt addresses, bridge rules, and VM network profiles out of the reusable Ansible roles.
- Run the playbook twice on two clean Fedora 44 QEMU machines.
- Confirm the second run reports no unintended changes (
changed=0). - Restrict firewall sources to actual node/operator networks.
- Confirm SELinux remains enforcing on both QEMU machines.
- Reboot both QEMU machines and confirm automatic recovery.
- Disconnect and reconnect node 2, then confirm it rejoins.
- Record tested minimum CPU, memory, and disk requirements.
One-command QEMU lab
- Check QEMU, libvirt, cloud-utils, Ansible, SSH, ping, and KVM.
- Install missing dependencies on a Fedora workstation.
- Enable libvirt and its default network.
- Discover and cache the Fedora 44 x86_64 cloud image.
- Keep SSH and VM state outside the repository.
- Generate cloud-init media for both nodes.
- Create reusable copy-on-write disks.
- Create each VM with two vCPUs and 3 GiB RAM.
- Assign deterministic addresses to both local VMs.
- Wait for ICMP ping and SSH on both nodes.
- Generate the Ansible inventory automatically.
- Configure both nodes automatically.
- Check Ansible reachability, k3s files, and binaries.
- Check firewalld, k3s services, ports 6443 and 10250.
- Check Kubernetes node readiness.
- Add
check,stop, and explicitdestroyactions. - Execute
lab.sh upwith working/dev/kvmand pass the full verification. - Reboot both local VMs and pass the bounded post-reboot service and node checks.
- Execute
lab.sh checkafter a workstation reboot. - Test recovery from an interrupted image download and validate the resumed QCOW2.
- Test recovery after node 2 is deleted manually and rejoin it with a fresh identity.
- Test on a workstation with no dependencies installed.
- Decide whether an aarch64 image path is required; keep the lab x86_64-only.
- After final sign-off, destroy the QEMU lab and remove packages installed only for it with Pacman's dependency-aware cleanup.
Local k3d rollback mechanism
- Define one local server and two local agent nodes.
- Map Traefik to host ports 8080 and 8443.
- Add lean kube-prometheus-stack values.
- Add the synthetic Argo Rollouts analysis harness.
- Add an idempotent
up/check/destroycommand and verify fresh creation and reconciliation. - Install Argo Rollouts.
- Install kube-prometheus-stack with the local values.
- Apply the synthetic harness.
- Prove
vector(0.0)permits promotion. - Change the test value to
vector(1.0). - Prove failed analysis aborts promotion with
vector(0.9). - Tear down and recreate the test from scratch.
Human-owned deployment and infrastructure
- [H] Define infrastructure modules under
terraform/. - [H] Export provisioned addresses for Ansible inventory.
- [H] Create Kubernetes base resources and overlays. Agent-authored 2026-08-21 at the owner's request; builds and server dry-runs pass, not applied.
- [H] Create API and load-generator workloads. Agent-authored 2026-08-21; not applied.
- [H] Create active and preview Services. Agent-authored 2026-08-21; not applied.
- [H] Create the Prometheus ServiceMonitor. Agent-authored 2026-08-21; not applied, scrape not confirmed.
- [H] Create the real error-rate AnalysisTemplate. Agent-authored 2026-08-21; PromQL never evaluated against real series.
- [H] Configure blue-green promotion and automated rollback. Agent-authored 2026-08-21; promotion and abort paths untested with the real API.
- [H] Maintain Forgejo Actions and GitHub mirror workflows.
- [H] Create sealed secrets from off-repository plaintext inputs.
Forgejo CI/CD
- Run API and load-generator race tests, vet, and pinned lint in containers.
- Scan committed history and the working tree for secrets.
- Scan release configuration and images for high or critical findings.
- Build immutable commit-SHA API, load-generator, and web image tags.
- Keep active and preview traffic flowing during rollout analysis.
- Run the Forgejo workflow after a private
dockerrunner and encrypted secrets are configured. - Publish images and execute the first automated production rollout.
End-to-end acceptance
- Provision two clean Fedora hosts.
- Reboot both hosts before platform installation.
- Install the cluster platform components.
- Deploy PostgreSQL and wait for health.
- Verify API liveness before database readiness.
- Verify readiness after migrations complete.
- Deploy the load generator and observe continuous samples.
- Send one request to every API endpoint in the local Compose stack.
- Verify every required metric and exact label name locally.
- Verify an HTTP trace contains a child database span.
- Correlate one stdout request log and Tempo trace by
trace_id. - Promote a healthy preview through analysis.
- Deploy a preview with a nonzero chaos rate.
- Observe preview errors in Prometheus.
- Confirm analysis aborts the unhealthy promotion.
- Confirm the active Service remains on the healthy version.
- Confirm load generation continues throughout failure.
- Confirm the Mini PC page remains usable with the cluster off.
- Capture reproducible, non-secret evidence needed for the final project report.