Skip to content

docs backend evidence fuel quality FQ08_READ_API

AlexandreZanata edited this page Oct 22, 2026 · 1 revision

FQ-08 — Official read API, timeline and coverage

Status: LOCAL_DONE / INTEGRATION_PENDING. Date: 2026-10-14. Base: codex/fuel-quality-plan atop origin/dev 08a54dc4. Depends: FQ-04/FQ-06/FQ-07. BUC-FQ-04/09. Anonymous public reads; no signed writes, scores, migrations, VPS or Android in this task.

Behavior before implementation

The ledger published but served nothing: no summary, pages, detail, lease envelope, staleness rule or route existed.

Delivered

  • db/queries/quality/reads.sql (new, sqlc vet/generate clean): lease-by-stream, station/fuel summary, keyset assay/action/sanction pages and sample/event detail, every row scoped to one caller-resolved published revision. Assay pages key on observed date plus row id; event pages key on native key plus row id for complete frozen-edition traversal. Event pages are stream-scoped: station attribution for events needs resolved links, recorded owed.
  • quality/application/reads.go (pure): closed-vocabulary fuel filter, UUID/text-filter validation, the frozen 180-day staleness rule (missing leases always stale, old leases served flagged, never dropped) and the deterministic denominator explanation builder.
  • quality/adapters/read: frozen-lease Reader; source CNPJs and internal notes never leave the package (machine-checked in tests).
  • quality/adapters/http: anonymous routes GET /v1/quality/summary, /assays, /samples/{ref}, /actions, /actions/{id}, /sanctions, /sanctions/{id}, every response carrying its lease (stream, edition, revision, denominators, periods, staleness, coverage note). Sealed filter-bound cursors fail closed across revisions; unknown stations/rows 404, unknown fuels/filters 400, storage failures 503 without internals. ANPFUEL_QUALITY_READS_ENABLED (default true) answers 404 without touching storage: the read recovery.
  • Additive OpenAPI schemas/paths (QualityLease, QualitySummary, QualityAssay(Page), QualitySample, QualityAction(Page), QualitySanction(Page)); apicontract suite green.
  • Wiring in cmd/api/main.go under the existing composition rule (station-exists closure, shared cursor secret); config flag validated at startup with the suite green.

Validation

RED→GREEN: unknown sanction id on an unpublished stream answered 503 instead of 404 — detail routes now map missing leases to not-found; rerun green.

  • go test -race -count=1 -tags=integration ./internal/modules/quality/...: all suites PASS (read 7/7 incl. frozen-revision concurrency and identifier-leak checks; http 6/6 incl. anonymous reads, codes, traversal, kill switch, cross-revision cursor refusal).
  • go build ./..., go vet -tags=integration, gofmt -l clean.
  • Real SQL EXPLAIN on a migrated scratch database (chain 000001–000095 applied clean, then dropped): summary and page plans use index scans on both join sides with no sequential scans — no denormalization.
  • git diff --check clean; new-file Markdown links resolve; scoped secret/PII scan clean (synthetic fixtures only).

Recovery

Turn quality reads off (ANPFUEL_QUALITY_READS_ENABLED=false); existing station/price/community reads keep working, routes untouched otherwise. Next: FQ-09 signed structured reports.

VPS deployment attempt (abastevo-temp only, 2026-10-14)

Scope respected: only namespace abastevo-temp mutated (images, migration job, one deployment's rollout); primary checkout, test-agent branch and all other namespaces untouched (pods diff clean except one external healthy restart of guia-cidade gc-api, unrelated).

  • Built abastevo-api:temp + abastevo-migrate:temp + abastevo-worker:temp from 91ff1f93, imported to k3s, migration job applied exactly [000093 000094 000095], rollout restarted only deployment/abastevo-temp-api.
  • RESULT: BLOCKED — pods run the new image (config-digest verified) but /health/ready stays 503 on the schema check while db passes.
  • Ruled out with evidence: ledger chain (95/95 byte-identical checksums), all 11 tables present, embedded chain in the image (95 files, quality SQL present), credentials and DSN (migration job succeeds with them), DNS/service endpoints (single ready endpoint), locks (none), disk (42%), secret stability (unchanged since Oct 08). The same image reports READY against a freshly migrated scratch database, and migrate.Apply re-run reports "already current".
  • Not yet determined: the exact Check error text inside the pod (distroless image has no shell; ephemeral debug containers share neither network namespace nor target-container access on this runtime).
  • State left: deployment on :temp images, DB migrated (append-only, irreversible by policy), service degraded until the check passes. Rollback to an older image cannot pass either (chain older than DB).
  • Resume: instrumented rebuild with the check error surfaced (prepared /debugz/schema-check draft, kept out of the branch), or compare a fresh pod's first-probe timing against pool setup; audit any concurrent writer to the image store (tag flapping observed on throwaway tags).

Readiness recovery (2026-10-14, selected FQ-08 source)

Status: STAGING_READY for the existing FQ-08 binary; not FQ-17 acceptance.

Root cause: the Kubernetes command overrides were /opt/abastevo-tools/api and /opt/abastevo-tools/worker, backed by a read-only hostPath containing community source 8bc9e5ba (migration chain 92). Updating the image to FQ-08 (chain 95) did not replace those executed binaries. The image itself was correct; the mounted executables were incompatible with the migrated database. The worker also exited with database schema is not compatible.

Only abastevo-temp/deployment/abastevo-temp-api was patched, guarded by its resourceVersion and expected container/image/command set. A private deployment backup is retained at /opt/abastevo-temp/fq08-recovery-20261014/ outside Git. API/worker commands now select /api and /worker; image references are fixed to the already imported FQ-08 manifests:

  • API: sha256:df0c44c915642ef860e1fa9a30d1f6535c4ee379d61d34ae8de6e0ae05564094.
  • Worker: sha256:5815c86e62aaade3d517248bd6e212ab55012f97fd102f222f8145f271bd125d.

The first rollout attempt could not resolve digest-only references because k3s had imported only :temp aliases. Registered the digest aliases for these two existing Abastevo images; no rebuild/pull or unrelated image changes. Private storage, all environment values, volumes, quotas and other namespaces remained unchanged. Provenance annotations now name actual source 91ff1f93 and schema95.

Observed after recovery: pod abastevo-temp-api-59fdd7477-cm8tb 3/3 Running, zero restarts; GET /health/ready 200 ready; GET /v1/stations?limit=1 200; GET quality summary for a nonexistent synthetic station 404 quality.not-found (proves the current FQ-08 route executes). Worker starts and performs its existing privacy/evidence sweeps successfully. No schema check was relaxed or bypassed.

Deployment regression rule: inspect effective commands, entrypoints and mounted executable provenance together. Image labels/digests alone never establish the running source. Register local digest references before selecting imported k3s images. A rollback binary must still support the applied append-only chain; restore the previous specification only with a compatible executable, never blindly return to the stale mounted binaries.

Read contract hardening (2026-10-14, after FQ-09)

Status: LOCAL_DONE Validation: PASS Integration: INTEGRATION_PENDING on maintained dev.

Actual HTTP→PostGIS→OpenAPI tests exposed empty event pages encoded as null and unknown lease timestamps/IDs encoded as invalid empty strings. Empty collections now encode as arrays; missing identifiers/dates use explicit JSON null under the OpenAPI 3.1 unions. Optional action/sanction dates and unmatched station links follow the same rule. Prior published nonempty values retain their wire types.

A deterministic concurrent-publication regression reproduced a mixed response: the handler validated its cursor against the old lease, then the reader resolved a new revision for rows. AssaysAtLease, EnforcementAtLease and SanctionsAtLease now consume the handler's one resolved lease. Old revisions remain immutable during that request; a subsequent request refuses its obsolete cursor. No second resolution can mix payload, envelope and sealed cursor.

ETags now include the complete lease for assay/action/sanction pages and sample detail, so a staleness transition cannot receive 304 and conceal changed metadata. Native event keys containing | decode at the final separator before UUID; existing opaque cursor serialization remains compatible.

Validation: the prior source 371983ca reproduced both the mixed-revision failure and stale-data 304 in a Go overlay without modifying the checkout. The corrected source passes real-PostGIS race read/HTTP suites, actual response schema validation (published/empty/missing-source states), deterministic publication-between-cursor-and-query, obsolete-cursor refusal and cache age regressions. Affected vet/staticcheck, OpenAPI lint/contracts, formatting, whitespace and scoped secret review PASS. This proves one frozen edition's reads; full historical-edition coverage and native-source import acceptance remain required by FQ-17 and are not inferred from this repair.

Fuel prices wiki

Source: AlexandreZanata/brazil-fuel-prices @ bbd96568180563ced975b96f8f89f7a3c242522e

Clone this wiki locally