Skip to content

feat(aqs): land focused AQS ingest recovery for BUY-12919 - #168

Open
BuyWhere wants to merge 1 commit into
mainfrom
buy-12919-aqs-recover
Open

feat(aqs): land focused AQS ingest recovery for BUY-12919#168
BuyWhere wants to merge 1 commit into
mainfrom
buy-12919-aqs-recover

Conversation

@BuyWhere

Copy link
Copy Markdown
Owner

Summary

Re-lands the AQS ingest pipeline from BUY-12919 as a focused single-commit recovery on top of current main.

This strips out the unrelated commits that accumulated on PR #128 and keeps only the AQS surface:

  • .github/workflows/aqs-ingest.yml
  • api/src/aqs/repository.ts
  • api/src/routes/aqs.ts
  • api/src/migrate.ts
  • api/src/server.ts
  • app/services/aqs_storage.py
  • scripts/aqs_calculator.py
  • docs/AQS_INGEST.md
  • .github/workflows/deploy-api-production.yml

Verification

  • Cherry-picked cleanly onto current origin/main as ae2397ae
  • Verified Railway Postgres already has public.aqs_cycles with the expected columns and indexes
  • Verified public.aqs_cycles currently contains 1 backfill row (cycle_id=2026-06-07T15:00:00Z, aqs=86.73, grade=Good, source=backfill)

Remaining runtime requirement

GitHub Actions still needs the runtime secrets/envs used by aqs-ingest.yml (notably the test-cycle source URL and DB connection path) to produce new scheduled rows after merge.

…riter (BUY-33907)

The 2026-05-12 AQS feature branch commit (e0aff70) shipped only
app/services/aqs_calculator.py + scripts/aqs_calculator.py. The rest
of the BUY-12919 scope — scheduled workflow, /v1/aqs/* routes,
aqs_cycles Postgres table, AQS_TEST_CYCLE_URL contract, and
Railway-aware deploy — was never merged to main. This commit
re-delivers the missing surface so BUY-16518 has a real
(workflow → writer → table → API verify) path to dispatch against.

Additions
- .github/workflows/aqs-ingest.yml
  Every 15 min (off the :00/:15/:30/:45 marks, see comment).
  Fetches the test-cycle JSON from $AQS_TEST_CYCLE_URL, falls back
  to /tmp/aqs-cycles/ on first-run, runs scripts/aqs_calculator.py
  --store, then verifies via GET /v1/aqs/health.
- api/src/aqs/repository.ts
  Read-side helper: listRecentCycles, getCycleById, getLatestCycle,
  getHealth. Idempotent; all queries are parameterised.
- api/src/routes/aqs.ts
  GET /v1/aqs/{health,latest,cycles,cycles/:cycle_id}. Public,
  no auth — AQS is a public-facing quality signal.
- api/src/migrate.ts → AQS_MIGRATION
  Adds aqs_cycles (BIGSERIAL PK, UNIQUE cycle_id, JSONB columns for
  dimensions / sub_metrics / escalations / raw_payload, three
  indexes on computed_at / grade / aqs). Non-fatal: missing table
  falls back to file-based JSONL history.
- app/services/aqs_storage.py
  Python writer. Uses psycopg (v3) with psycopg2 fallback. Upsert
  on cycle_id so retries don't duplicate. Non-blocking on failure
  (file history is the source of truth for offline replay).
- scripts/aqs_calculator.py --store / --source / --database-url
  Extends the existing 15-min runner with a Postgres persist step.
- docs/AQS_INGEST.md
  Operating manual: pipeline diagram, secret table, AQS_TEST_CYCLE_URL
  data contract (BUY-12885 §4.1), local-usage examples, and
  acceptance checklist tying BUY-33907 to BUY-16518.

Changes
- api/src/server.ts: mount /v1/aqs
- .github/workflows/deploy-api-production.yml: rewrite for the
  Railway target (BUY-15318). Same service id (945e8a6d-...) and
  env id (ebcb2ca2-...) as deploy-railway.yml. Keeps the regression
  + smoke gates; drops the GCP/SSH path.

Acceptance
- aqs-ingest.yml is on main (Path A) — once this PR is merged.
- A real path exists for BUY-16518 to dispatch + verify a write.

Refs BUY-12919, BUY-16518, BUY-15318, BUY-33837, BUY-12885, BUY-12892.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
(cherry picked from commit 5c82d4d)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant