review: fix 26 findings from a 4-agent audit
ci / lint (push) Successful in 34s
ci / unit (push) Successful in 1m41s
ci / types (push) Successful in 1m41s
ci / dockerfile (push) Successful in 18s
ci / security (push) Successful in 1m27s
ci / chart (push) Failing after 1m11s
ci / integration (push) Successful in 1m10s
ci / image (api) (push) Has been skipped
ci / image (reconciler) (push) Has been skipped
ci / image (worker) (push) Has been skipped
ci / bump (push) Has been skipped

CORRECTNESS
- lost-lease race: complete()/fail() did not check ownership, so a worker whose
  lease expired could mark a task done while another worker was running it, or
  requeue a task someone else owned. Reproduced, fixed with a CAS on
  (state, locked_by), pinned by two regression tests.
- worker died on report failure: _run_one's docstring claimed no exception
  escapes the TaskGroup; fail()/complete() were outside the guarded block, so a
  DB blip cancelled every sibling provision on the pod.
- claim query used an INNER join, which could strand a just-claimed task and
  report 'queue empty'. LEFT join.
- InstanceRepo.set_error bypassed the state machine and had no callers. Deleted.
- handle_deprovision ignored its CAS result, so a wrong-state instance kept a
  dangling endpoint and got re-provisioned by the drift check 60s later.
- handle_verify re-notified on every retry: five pages for one halt.

DEPLOY-BREAKING
- the migration Job could never succeed: no Dockerfile copied migrations/, and
  migrate.py resolved the path relative to the source tree, which only works for
  an editable install. Added COPY + SVCFORGE_MIGRATIONS_DIR.
- ServiceMonitor selector did not match the Service: API metrics never scraped.
- SvcforgeReconcilerStale fired permanently from every pod, because the gauge is
  module-level and every service exports it as 0. Scoped to the reconciler job.
- SvcforgeTaskFailed latched forever on a monotonic counter. Now increase()[15m].
- the digest guard accepted the all-zeros placeholder.
- worker terminationGracePeriodSeconds was 60s against a 600s helm timeout.

DEAD CODE THAT SHOULD NOT HAVE BEEN
- adapters/k8s.py was never called, so tenant namespaces were never created and
  the first provision for a new team would fail. Wired into handle_provision.
- adapters/redis.py was never imported by any service. Rate limiting is now wired
  into the API, failing open.
- Settings.check_production() had no callers. Given an explicit environment and
  called from every entrypoint.

OBSERVABILITY
- the API never called obs.setup(): no JSON logs, no trace correlation, log_json
  silently inert.
- LogNotifier's structured fields were discarded by the stdlib->structlog bridge.
- bind_task_context cleared the 'service' binding for the life of every task.
- split tasks_failed into task_attempts_failed and tasks_dead_lettered.

SECURITY
- trivy correctly blocked the worker/reconciler images: helm 3.16.2 and kubectl
  1.31.2 carry CRITICAL Go stdlib CVEs. Bumped to helm 3.21.3 and kubectl 1.35.3,
  which also closes a four-minor skew against the v1.35.3 cluster.

TESTS THAT COULD NOT FAIL
- the concurrency cap test passed on a fully serial worker.
- the alert/metric cross-check asserted a hardcoded list instead of reading the
  chart, so it could not catch a rename on the chart side.
- fixed OTel tracer-provider pollution between test files.

DOCS
- ARCHITECTURE.md: mermaid diagrams, user stories, and the helm-vs-ArgoCD
  guarantee (verified with --dry-run=server).
- AGENTS.md + CLAUDE.md.
- prose sweep for back-and-forth phrasing across 19 files.
This commit is contained in:
Nguyen Minh Phuc
2026-07-18 12:13:49 +00:00
parent 77d560ddae
commit c76154aeaa
45 changed files with 1520 additions and 216 deletions
+31 -16
View File
@@ -13,11 +13,13 @@ import json
import logging
import re
from collections.abc import Iterator
from pathlib import Path
from typing import Any
from uuid import uuid4
import pytest
import structlog
import yaml
from opentelemetry import trace
from opentelemetry.sdk.trace import TracerProvider
from prometheus_client import REGISTRY
@@ -89,8 +91,8 @@ def test_provision_histogram_has_a_bucket_for_a_thirty_minute_provision() -> Non
With the library defaults the top finite bucket is 10s, every provision lands in +Inf,
and histogram_quantile interpolates across a bucket spanning 10s to infinity. The p95
it returns is not slow or fast, it is meaningless and it is meaningless silently,
which is why this is asserted rather than eyeballed on a dashboard.
it returns is meaningless, and it is meaningless silently, which is why this is
asserted rather than eyeballed on a dashboard.
"""
bounds = obs.PROVISION_TIME._upper_bounds
assert 1800.0 in bounds
@@ -105,21 +107,34 @@ def test_provision_histogram_exports_the_1800_bucket() -> None:
assert bucket is not None
def test_metric_names_are_the_ones_the_alerts_query() -> None:
"""The four alerts are PromQL strings in values.yaml; nothing type-checks them.
def test_every_metric_the_alerts_query_actually_exists() -> None:
"""Parse the alerts out of values.yaml and check each metric is really registered.
A rename here is a silent alert that never fires again. This test is the link between
the chart's rules and the code.
Reading the chart is the whole point. An earlier version of this test asserted against
a hardcoded list, which meant it could only catch a rename on the *code* side — rename
a metric in values.yaml and it stayed green while the alert silently never fired again.
A test that duplicates the thing it is meant to cross-check is not a cross-check.
"""
for name in (
"svcforge_tasks_claimed_total",
"svcforge_tasks_failed_total",
"svcforge_provision_duration_seconds",
"svcforge_queue_depth",
"svcforge_instances",
"svcforge_reconciler_last_tick_timestamp_seconds",
):
assert REGISTRY._names_to_collectors.get(name) is not None, f"{name} is queried by an alert"
values = yaml.safe_load(
(Path(__file__).resolve().parents[2] / "deploy" / "chart" / "values.yaml").read_text()
)
rules = (values.get("prometheusRule") or {}).get("rules") or []
assert rules, "no alert rules found under prometheusRule.rules — this test would silently pass"
# Prometheus appends _bucket/_sum/_count to a histogram's series; the collector is
# registered under the base name.
suffixes = ("_bucket", "_sum", "_count")
registered = set(REGISTRY._names_to_collectors)
checked = 0
for rule in rules:
for token in re.findall(r"\bsvcforge_[a-z0-9_]+\b", str(rule.get("expr", ""))):
base = next((token[: -len(s)] for s in suffixes if token.endswith(s)), token)
assert base in registered, (
f"alert {rule.get('alert')!r} queries {token!r}, but no such metric is registered"
)
checked += 1
assert checked >= len(rules), "expected at least one metric reference per alert"
# --- Trace context across the queue -------------------------------------------------------
@@ -232,7 +247,7 @@ def test_json_renderer_is_last_and_output_is_one_object_per_line(logs: io.String
def test_setup_is_idempotent(logs: io.StringIO) -> None:
"""Called twice, one handler, one line. Not a nicety: two handlers is two of every line.
"""Called twice, one handler, one line. Two handlers would be two of every line.
Each service calls setup() from its entrypoint, and an entrypoint that imports another
entrypoint (the CLI shelling into the reconciler) calls it twice.
+2 -2
View File
@@ -79,8 +79,8 @@ def take_cache(c: InstanceCacheProto) -> None: ...
def test_redis_implementations_conform() -> None:
"""A client at a closed port is still a Redis. Nothing here connects — no commands billed.
That is not a trick to keep the test fast; it is the module's thesis restated as a
fixture. Every one of these classes has to be constructible and callable with Redis
That is the module's thesis restated as a fixture, rather than a trick to keep the
test fast. Every one of these classes has to be constructible and callable with Redis
unreachable, because that is the state they are designed for.
"""
from datetime import UTC, datetime