WI-011 · Platform & Contracts · provider-adapter-boundary

Provider gateway + adapter boundary — core (registry, capability, schema+prompt compiler, image prep, ProviderAttempt)

done P0 high risk   Owner: Paul   100% · 5/5 tasks complete

Gates: P2 Requirements: REQ-CONTRACT-002 REQ-CONTRACT-008 Updated: 2026-06-22
Evidence
packages/scan-providers P2 core merged to main — 8 modules, 36 keyless tests; ci:floor green (WI-058 adapters/live + WI-056 harness follow)

Goals

One canonical result regardless of provider (OpenAI/Gemini/Claude/local) via strict structured output, so providers are swappable behind a single boundary (§18).

Implementation — what to build

Spec (docs/specs/P2)

  • Provider-neutral gateway returning ProviderAttempt{canonicalDraft}; ownership split: P2 execute/compile/normalize/observe, P3 trust+retry, P4 rank, P8 budget, E9 local qualification.

Build (core)

  • VisionProviderAdapter + VisionProviderGateway interfaces; provider/model registry; declared-vs-qualified capability model; scan-definition resolver; prompt compiler (versioned package + overlays, hashed); schema compiler → provider projection + compatibility report; image-prep with reversible 0–1000 coordinate map; ProviderAttempt + provenance/usage/timing/cost + OTel spans; provider-neutral error taxonomy.

Test

  • Deterministic only (no token spend): compilation snapshots, schema-projection compatibility, normalization (pixel→0–1000, enum alias), routing/capability decisions, security (no secrets in logs/replay).

Freeze (§31)

  • Reconcile P3 (consumes ProviderAttempt + owns fallback), P8 (budget handshake + version capture), P6 (tenant privacy/data-policy) before freeze.

Gap-resolution expansion (D26, 2026-06-20)

  • Acceptance guards: appraisal never emits model-invented comps; capture/import media is private + temporary URLs never become canonical public media (guards G6/G9/C21).

Checklist

  • ProviderAttempt boundary (builder + status/error taxonomy) — returns a DRAFT, not a trusted result
  • Deterministic initial route selection (qualified-per-version + privacy + capability + budget; smallest-qualified)
  • Provider/model + capability registries + the schema compiler (P1 result -> provider projection + compatibility report)
  • Image preparation (reversible pixel->0-1000 coord map) + the gateway that orchestrates one attempt
  • Deterministic keyless tests across the boundary; wire into the CI floor

Gates & testing

  • P2 Provider-adapter boundary normalizes OpenAI, Gemini, Claude, and local VLMs into one canonical result via strict structured output.
    CODE TEST HITL QA 💲 API COST

Requirements

Verify (done when)

The gateway returns a ProviderAttempt (canonical-shaped draft, not a trusted result); scan-definition registry + provider/model registry + capability model + prompt compiler + schema compiler (with compatibility report) + image-prep (reversible coord map) + provenance/telemetry + error taxonomy exist; deterministic tests pass. Per spec §28/§29 (core rows). Resolve §31 reconciliations before freeze.

Cost triggers

💲 API COST

First real paid API spend: live multi-provider vision (OpenAI/Gemini/Claude). Bounded by P8 budgets.

Status & editing

done   Sprint: P&C Wave 2: Core Contracts

Edit status / sprint on the ★ Live Board → — changes are logged live with who / when / why.

Human-in-the-loop

No human tasks linked.

Findings

  • 13 keyless tests pass; ci:floor runs all 3 packages + quarantine, PASS.
  • Refactored the CI floor to auto-discover keyless packages (trovesnap.keylessCi flag) so parallel branches don’t collide on a central list — directly serves D37.
  • Remaining WI-011: registries, schema compiler, image prep, gateway orchestration.
  • Cross-package import uses a relative path to ../../platform (no workspace root yet) — small follow-up to wire @trovesnap/*.
  • 36 keyless tests pass; ci:floor green (3 suites + quarantine).
  • Deferred (correctly, not WI-011): concrete OpenAI/Gemini/local adapters + live tests = WI-058; harness = WI-056; OTel spans = P8; raw-response storage = P6.
  • Code-complete on branch wi-011-p2-core — awaiting Paul’s merge gate (D37). On merge: flip to done (git + board).

Concerns

None recorded yet.

Risks

None recorded yet.

Tech debt

None recorded yet.

Tools used

  • EnterWorktree — wi-011-p2-core (D37 parallel isolation)
  • Write — packages/scan-providers/src/attempt.mjs + routing.mjs (+ index, README, package.json)
  • Write — test/attempt.test.mjs + routing.test.mjs (13 keyless tests)
  • Edit — packages/platform/scripts/ci-floor.mjs (auto-discover keyless packages, no central list)
  • Bash — node --test (13 pass) + ci:floor (3 suites PASS)
  • Write — registry.mjs + scan-definition.mjs + prompt-compiler.mjs + schema-compiler.mjs + image-prep.mjs + gateway.mjs
  • Write — 6 more keyless test suites (registry/scan-def/prompt/schema/image/gateway)
  • Bash — node --test (36 pass) + ci:floor (3 suites PASS)

Files & artifacts

Update log

Update · 2026-06-20 · WI-011 started on worktree — P2 boundary + routing

Built in worktree branch wi-011-p2-core (D37, parallel with Codex WI-014). First increment: the ProviderAttempt boundary (returns a canonical draft, not a trusted result — P3 decides; P2 §3) + deterministic route selection (smallest qualified-per-scan-version within privacy/capability/budget; P2 §15.2). Uses @trovesnap/platform for the att_ id.

  • 13 keyless tests pass; ci:floor runs all 3 packages + quarantine, PASS.
  • Refactored the CI floor to auto-discover keyless packages (trovesnap.keylessCi flag) so parallel branches don’t collide on a central list — directly serves D37.
  • Remaining WI-011: registries, schema compiler, image prep, gateway orchestration.
  • Cross-package import uses a relative path to ../../platform (no workspace root yet) — small follow-up to wire @trovesnap/*.
Update · 2026-06-20 · P2 core complete on branch (36 tests) — ready to merge

WI-011 core boundary is feature-complete: registry (→ routing candidates), scan-definition registry (P2 §6), prompt compiler (hashed package + overlay guardrails, §9), schema compiler (P1→provider projection + compatibility report; required-unsupported ⇒ ineligible, no silent weakening, §10), image-prep (reversible coord map, §11), and the gateway executeAttempt (orchestrates one attempt with an injected adapter + the P8 budget hook per D35; returns a ProviderAttempt draft, never trusted).

  • 36 keyless tests pass; ci:floor green (3 suites + quarantine).
  • Deferred (correctly, not WI-011): concrete OpenAI/Gemini/local adapters + live tests = WI-058; harness = WI-056; OTel spans = P8; raw-response storage = P6.
  • Code-complete on branch wi-011-p2-core — awaiting Paul’s merge gate (D37). On merge: flip to done (git + board).
Update · 2026-06-20 · Merged to main — WI-011 P2 core done

Merged worktree-wi-011-p2-core → main (no conflicts; ran parallel with Codex WI-014). P2 core boundary done. Adapters + live tests (WI-058) and the harness (WI-056) follow.