Working roadmap for hipo (HK IPO Verify): current status and next steps with their verification gates. Stack, infra, and model-gateway setup live in README.md; full product vision in initial-plan.md; the assignment brief in goal.md.
App decommissioned. The infra/*.tf resources and the three deploy
workflows are commented out (not deleted — this repo stays a readable archive).
Merging that PR to master makes HCP Terraform plan a full destroy; approve it
in the HCP workspace UI. Manual teardown steps are below — a few resources are
not Terraform-managed and one (the R2 bucket) must be emptied before the destroy
applies.
Do these around the destroy, in order:
- Before the destroy applies — empty R2. Cloudflare refuses to delete a
non-empty bucket. Empty
hipo-filings(dashboard → R2 → hipo-filings → delete all objects, orwrangler r2 object deletein a loop). If the destroy run fails on the bucket, empty it and re-apply. - Delete the catalog Worker (wrangler-owned, not in Terraform).
hipo-catalogscript + its cron trigger:wrangler delete --name hipo-catalog(or dashboard → Workers → hipo-catalog → Delete). Terraform only owned its KV + R2 stores. - Approve the HCP destroy run, which tears down: 3 Lambdas + streaming
Function URL, ECR repo (images go with
force_delete), HTTP API + authorizer- routes, 4 log groups, the IAM exec role, the KV namespace, the (now-empty)
R2 bucket, the Pages project + its deployments, the
hipo.vsh852.comPages domain + CNAME. Thevsh852.comzone is a data source — untouched.
- routes, 4 log groups, the IAM exec role, the KV namespace, the (now-empty)
R2 bucket, the Pages project + its deployments, the
- After the destroy — revoke/remove what Terraform never held:
- GitHub repo secrets (Settings → Secrets → Actions):
CLOUDFLARE_API_TOKEN,CLOUDFLARE_ACCOUNT_ID,CATALOG_KV_NAMESPACE_ID,AWS_ACCESS_KEY_ID,AWS_SECRET_ACCESS_KEY,AWS_REGION,ECR_REPOSITORY_URL, the three*_LAMBDA_FUNCTION_NAME,VITE_CATALOG_BASE_URL,VITE_API_BASE_URL. - The deploy IAM user (the ECR-push + Lambda-update access key) in AWS IAM.
- Rotate/revoke the app's live keys: the Cloudflare API token, the LLM gateway
keys (
ANTHROPIC_API_KEY,OPENAI_API_KEY,GEMINI_API_KEY), and the sharedapi_key. - HCP workspace
hipo: after the destroy leaves state empty, delete the workspace (and its sensitive variables) if you're done with it.
- GitHub repo secrets (Settings → Secrets → Actions):
Everything below is the pre-sunset record, kept for the archive.
Brief A shipped. The demoable MVP is live in two pieces — the agent backend on Lambda (a bounded analysis loop turning a PHIP into a validated, cited factsheet) and the analyst-workstation SPA on Cloudflare Pages (hipo.vsh852.com). Design spec: Brief A MVP design. Deferred next: multi-model agreement (B), CI eval gate (C), trust alarm (D).
The Brief-A MVP is live end to end at hipo.vsh852.com. Stack, infra, and the deploy/ops detail live in README.md and operations.md.
- Tooling + CI gate.
mise run check(ruff, ty, pytest, Biome/Vitest, tf fmt/validate), pinned toolchain, pre-commit, a hook blocking localterraform apply/destroy, and GitHub Actions running the same gates. - Infra applied via HCP. CloudWatch, least-privilege roles, KV
(
hipo-catalog), R2 (hipo-filings), ECR, three Lambdas (hipo-api,hipo-api-authorizer,hipo-api-stream), HTTP API v2 + authorizer, and the streaming Function URL. Both providers authenticate (AWS OIDC, Cloudflare token). - LLM gateway client (
llm_gateway/client.py): vendor-neutral routing, per-vendor auth, fallback-chain escalation, streamingcomplete_stream. Opt-in live smoke (mise run models:smoke). - Catalog Worker — live.
HkexTitleSearchSource+HkexApplicantArchiveSourcebehind oneCatalogSource;CatalogIndex(KV) +FilingStore(R2, sha256); SSRF allowlist. ServesGET /catalogfrom live KV; filings cache to live R2 on first view; cron refresh on schedule. - Analysis tools + schema.
packages/contracts(Field,Factsheet,Rejection,AgentTrace/TraceStep;schema_version=202401),parse.py(pdfminer + redaction detection),chunk.py,select.py,validate.py(schema + citation gate → Full/Partial/Rejected). Fixtures: a PHIP (app-108691-1) and an AP. - Streaming analysis agent — live. Bounded, code-driven loop in
apps/api/hipo_api/agent/(parse → chunk → select → extract → normalize → validate → interrupt; step cap 8; model only insideextract; always ends at the interrupt).POST /analyze/{id}drivesrun_agenton a worker thread and yields each event off a queue as it fires —event: stepfor trace steps,event: thinkingfor the model's own output tokens, then a terminalevent: result/rejected. Served by the separate uvicorn streaming Lambda behind aRESPONSE_STREAMFunction URL; the buffered Mangum path is untouched. - Analyst-workstation SPA — live (#13, #16).
apps/web/React 19 + Vite + TS on Pages: filing list, four factsheet panels, right-rail trace streaming live over SSE (steps + a live model-output panel), page-level citation popovers that deep-link to the source PDF, three degradation states, persistent boundary banner, dark-mode toggle, key gate, hippo branding + repo link. Brief-A trust components: elapsed timer with a slow-run cue, retry-on-failure, an evidence-coverage card (disclosed-% / cited-% dials via a purefactsheetStatswalker), and a JSON export carrying the never-act disclaimer + provenance. Vitest + RTL + axe green.
- Brief B — multi-model extract + agreement/disagreement panel + arbiter on disputes. Schema and trace are built to accept it without rework.
- Brief C — gold dataset + CI eval gate that goes red on a bad change; one-command Lambda-alias + Pages rollback.
- Brief D — end-to-end correlation IDs (partly done), no raw text in logs (done), one alarm on trust degradation (citation/schema rejection rate).
- Model access depends on the external LLM gateway (swappable provider); smoke scripts are opt-in / network-dependent, not in CI.
- Rollback is only half-wired: the API deploy publishes a Lambda version +
livealias, but the HTTP API integration still invokes$LATEST, so an alias move is not yet an instant rollback (see operations.md). - Recent HKEX window skews toward ETF/fund prospectuses; PHIP is the MVP focus.
apps/api/DockerfileusesCOPY --from=ghcr.io/astral-sh/uv:latest; pin to a digest in a later hardening step.
- Historical catalog backfill (~2013 onward), GEM board, applicant-JSON submission-revision lifecycle — current catalog is recent + Main Board.
- D1 instead of KV if the catalog ever needs real queries.