think
16px
820px

Final-review fix wave — P1 exit gate

Status: DONE. All four items closed; live stack redeployed and verified.

Item 1 — fatal on ingester boot death

cmd/observatory/main.go: split run() into runFromEnv() (loads config
from OBSERVATORY_CONFIG) + run(cfg *config.Config) error (testable core).
Added a case err := <-ingestDone: arm to the startup select: since
ingestCtx is only canceled later (via cancelIngest(), after this select
returns), reaching this arm at all — error or nil — means the ingester died
or exited before any shutdown was requested. Both cases now return a fatal
error from run(), which main() turns into log.Fatal.

Test: cmd/observatory/main_test.goTestRunFailsFastWhenIngesterCannotStart
points RedisURL at 127.0.0.1:1 (connection refused, immediate) with the
real test DB, asserts run() returns non-nil within 10s. Skips cleanly if the
test DB isn't up (mirrors store.TestPool).

Item 2 — /series error mapping + bucket validation

internal/api/server.go handleSeries: bucket <= 0 now rejected at the API
layer (400/BAD_REQUEST) before ever reaching the store. store.QuerySeries
errors now map to 500/QUERY_FAILED (matching handleSummary/handleCalls)
instead of 400/BAD_REQUEST.

Test: extended TestSummaryAndSeriesReturnData in internal/api/server_test.go
with bucket=0s and bucket=-1m → both assert 400. The 500/QUERY_FAILED path
isn't independently exercised (forcing store.QuerySeries to fail would mean
breaking the shared test pool, taking out every other assertion in that test)
— verified by reading: the mapping is identical to the already-tested
handleSummary/handleCalls 500 paths.

Item 3 — doc caveats

  • deploy/observatory.example.yaml: retention_days now carries a comment —
    declared but NOT yet enforced, retention job is backlog, see README.
  • README.md: new "Known limitations" section — retention backlog + tripwire
    (body-heavy engine flip / ai_call_bodies > 5GB / disk < 25GB free);
    hash-chain envelope boundaries (full_body_sha256/ts outside row_hash,
    trigger-protected only; mid-chain verify trusts stored prev_hash, only a
    genesis run proves the full prefix; tamper-evident not tamper-proof, no
    external anchor); /api/verify-chain response shape
    ({"ok": bool, "bad_chain_pos": int64}). File is 73 lines (≤80 budget).

All three committed together.

Verification

go build ./cmd/observatory   -> OK
go vet ./...                 -> OK
go test ./internal/api/ ./internal/ingest/ ./cmd/... -count=1 -race  -> ok (all 3 packages)
go test ./... -count=1 -p 1  -> ok (all 5 packages)

Item 4 — live token rotation + redeploy (ai-ahu, 192.168.83.20)

  1. Confirmed the three tokens named in the leaked report matched the live
    ~/ahu-ai-observatory/deploy/observatory.yaml exactly (executive/operator/
    auditor).
  2. Generated three new openssl rand -hex 16 tokens on the host, edited
    observatory.yaml in place (same roles, new values) — the new values were
    never printed to, or transmitted through, this session; only pass/fail
    checks and HTTP status codes were echoed back.
  3. docker compose restart observatory; verified /healthz OK, an authed
    call with a new token → 200, the same call with an old token →
    401.
  4. Sanitized .superpowers/sdd/task-9-report.md: all four occurrences of the
    three old tokens (the credentials table + two example curl commands)
    replaced with REDACTED-ROTATED, plus a dated note pointing at this file.
    Re-uploaded (URL below) so the exposed version is replaced. Repo-wide
    grep confirms no other file contains the old token strings.
  5. Deployed the Item 1/2 code fix to the host: rsync -avz --exclude='.git' --exclude='.superpowers' --exclude='/observatory' ./ to
    ~/ahu-ai-observatory/ (host's deploy/observatory.yaml untouched — no
    local copy of that file to overwrite it with), then
    docker compose up -d --build. Post-redeploy: /healthz OK, authed call
    with the rotated operator token → 200.
  6. New tokens recorded only in ~/ahu-ai-observatory/deploy/observatory.yaml
    on ai-ahu — nowhere else, including not in this report.

Links

  • README (rendered): https://x056.think.val.id/README.md
  • Sanitized task-9 report (rendered): https://x056.think.val.id/task-9-report.md