Readiness & Open Decisions — for Dave and Rob
Ref: suitability-engine-arch-3 · Capability: N/A — cross-cutting Status: draft Repo: suitability-engine
One page: what’s actually shipped, what’s mid-review, what’s blocked, and every decision that needs a human call before it’s technically ready. Snapshot as of 2026-08-17 — statuses below are live states, not aspirational.
1. What’s actually merged (real, in main, today)
Section titled “1. What’s actually merged (real, in main, today)”- HTTP service exposure (
format=jsonexport,/healthz) — suitability-engine#2 TENANT_CONFIG_STATIC_JSONbootstrap seed path — #5- Client-facing report UX spec + working reference implementation, adviser review design spec + wireframe, Origo integration architecture overview — #9
- Multi-tenant report templates —
format=docxnow works per-tenant — #8, closing #6. The review round found and fixed real security issues before merge: a tenant slug/ID collision that could leak one tenant’s data into another’s template, a symlink path-traversal escape from the template store, missing per-tenant subdirectory enforcement, filesystem paths leaking into error responses, and no size cap on partner-supplied templates. 130/130 tests passing. - Partner template fidelity smoke test — #15, a golden-record check + CLI a partner can run against their own template before deploying it. 149/149 tests passing.
- Self-hosted licence-gating — the
wtp-hostedbypass is closed — #7.DEPLOYMENT_MODEis now a compile-time constant baked intodist/by which Docker build target produced the image; no runtime input (env var, mounted file, CLI flag) can change it any more. Verified end-to-end (built both variants, confirmed each behaves correctly), 5 regression tests, 197 tests passing. - Template validation/lint — #18, closing #12. A pre-flight check + CLI for a candidate template’s
{{tag}}references against theSuitabilityDatacontract, with a decompression-size cap on the parsing path. - Self-serve template upload API — #25, landing #11 onto
mainfor real (hardened against a symlink write-target escape, atomic rename-based writes, an upload-time size ceiling). - This readiness hub + subdomain rename + REST/gRPC/GraphQL API definitions — #24.
- Branch protection enabled on
main— required status checks (typecheck + test,docker build smoke, governance/frontmatter), linear history, no force-push/deletion, conversation resolution required. This repo had none until 2026-08-17 (auto-flagged as a critical governance finding, issue #26).
2. Open PRs
Section titled “2. Open PRs”| PR | What | Status |
|---|---|---|
| suitability-engine#10 | Astro/Starlight docs-site | The licence-gating-disclosure issue that blocked this is fixed (via #24, merged into this branch) and the underlying gap itself is now closed (#7 merged) — ready for a fresh review and merge to main. |
| client-onboarding#2684 | FINIO shared-hub decommission | BLOCKED. The FINIO hub was destroyed cleanly in Azure, but CO’s Pulumi program (apps/client-onboarding/infra/__main__.py) has an unconditional StackReference.require_output() call to the now-gone stack that runs for every environment, not just Benchmark. pulumi preview fails in wtp-stg right now. |
3. Topology — what’s built and how it fits together
Section titled “3. Topology — what’s built and how it fits together”Green = merged and live. Amber = built, PR open, in review. Grey = designed or requested, not built.
4. Decisions that need Dave and/or Rob — nothing below is silently assumed
Section titled “4. Decisions that need Dave and/or Rob — nothing below is silently assumed”| # | Decision | Why it can’t be made in code | Recommendation if you want one |
|---|---|---|---|
| CO#2684 blocker | Fix the CO Pulumi program’s unconditional FINIO StackReference, or accept the breakage | Touches the live production CO stack — flagged by the reviewer as author-decision-required, not something to fix blind | Land a minimal guard (get_output with a None-check instead of require_output) as a fast follow-up PR, merge that first, then this one |
| #13 | PDF export approach | Real tradeoff between runtime weight (LibreOffice sidecar), a network dependency that contradicts the self-hosted design goal (cloud conversion API), or fidelity risk for a regulated document (pure-JS) | LibreOffice headless, accepting the heavier self-hosted container — most consistent with “no external network calls” being the whole point of Option D |
| #14 | Graded confidence scoring vs. surfacing the real categorical signal | Building real per-value confidence is a genuine feature investment; the honest alternative is presenting what already exists (sourceClass) without dressing it up | Surface sourceClass directly for now; revisit graded scoring only if an adviser reviewer workflow actually needs the finer signal |
| #16 | Where suitabilityReasons narrative content lives | Cross-repo (client-onboarding owns the real data today); may be a product/commercial call about what Origo is expected to author themselves | Document that Origo authors this themselves from derived recommendation data — cheapest, and consistent with “branding is not part of the contract” |
| #17 | Two-tier tenancy (partner → firm) | Confirm with Origo whether this is real near-term scope before redesigning TenantConfig | Don’t build ahead of confirmed need — single-tier is fine for a single-firm pilot |
| #19 / #3 | Per-tenant auth scoping for the shared bearer token (accepted gap, now live on main via #25 — the upload endpoint has no per-tenant scoping or audit trail) | A real fast-follow, not a blocker, but worth a target date now that it’s live rather than hypothetical | Scope before Origo pilots with more than one tenant sharing infrastructure |
| ADR-0001 | When CRM-bridge actually extracts | Depends on SPEC-153 reaching a stable bidirectional design — not a fixed date | Communicate explicitly to data-backbone’s team that this isn’t imminent, so they don’t wait indefinitely or build a duplicate |
| API interface strategy | Whether/when to actually implement gRPC or GraphQL servers | Both are unbuilt-by-design until a real consumer needs them | Wait for data-backbone (or another internal consumer) to have a concrete access pattern before implementing either |
5. Everything else — smaller, tracked, not blocking
Section titled “5. Everything else — smaller, tracked, not blocking”#3 (scope the shared server token per-tenant) and #4 (request/audit logging) are pre-existing, not new from this work, and not yet started — #3 is the same underlying gap as #19 above. #20 (synchronous/uncached render needs a concurrency bound) and #21 (no audit-record persistence for docx exports specifically) are tracked, not started.
6. The honest one-line summary
Section titled “6. The honest one-line summary”The Suitability Engine’s core pipeline, multi-tenant template mechanism,
licence-gating, self-serve template upload, and full UX design are all
built, hardened, and merged to main. Origo could pilot against the
JSON contract, generate branded documents, and run self-hosted with a
genuinely-enforced licence today. Every review this session surfaced real
issues before merge, not after — 5 security fixes in #8, the wtp-hosted
bypass fully closed and verified in #7, a symlink write-target escape
closed in #25 — and main now has branch protection for the first time,
closing a critical governance gap (#26) that predated all of this work.
What’s genuinely not built yet, and needs a scoping decision before it
is: PDF export (#13), graded confidence scoring (#14), multi-firm
tenancy (#17), and where suitabilityReasons narrative content lives
(#16). What’s outstanding and not a decision, just work: the docs-site
(#10) needs a final review pass now that its one blocker is fixed, and
CO#2684 (FINIO) needs its Pulumi guard fix landed.
