From 601ccea39cac9c8c549c2bc9eb1216d5ece72768 Mon Sep 17 00:00:00 2001 From: Keysat Date: Thu, 18 Jun 2026 06:49:01 -0500 Subject: [PATCH] Adjudicate parked low-priority backlog items to verdicts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Ran the investigate→debate→judge pipeline over 4 parked ROADMAP items. DROP: - Design "structural" tier (palette consolidation): the rust-embedded admin SPA can't @import a shared file, so consolidation is a verbatim re-copy that doesn't remove the duplication it targets; the drift it guards is hypothetical. - Design "token gaps" tier: manual churn across untested public surfaces, and the audit was partly mis-specified (#d4b985/#a6b7cf are token values, not hardcoded literals). DO (low blast radius): - Reframe the manual "Zaprite sandbox pass" for multi-profile webhook routing into an automated regression test — routing is a deterministic provider-id PK lookup with an anti-forgery backstop, but the path-keyed route has zero automated coverage on the money path. ESCALATE: - Zaprite contact dedup cache → lean DROP: cosmetic, unverified harm (Zaprite dedup-on-email is undocumented); fix is HIGH blast radius on the money path. Gated on one cheap sandbox check. - Design "blocker" tier (3 gold-fill / pill-radius one-liners) → lean DO, pending an owner glance since they alter public/admin visuals. Replaces the "harden Zaprite failure-body shapes" item (already satisfied for non-2xx) with a bug the investigation surfaced: try_auto_charge_zaprite returns Ok(true) on any 2xx, so a 200 carrying a FAILED/DECLINED/EXPIRED status silently lapses the subscription. Elevated above the other parked payments items; safe fail-safe fix needs no prod data. --- ROADMAP.md | 44 +++++++++++++++----------------------------- 1 file changed, 15 insertions(+), 29 deletions(-) diff --git a/ROADMAP.md b/ROADMAP.md index 982151f..006bafc 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -6,8 +6,8 @@ Longer-term backlog. Near-term state lives in `AGENTS.md` → Current state. - Per-profile SMTP override (schema fields exist from the keysat-smtp-emails plan; needs the form + send path). - Rail-preference editing UI — only matters when two providers on one profile both serve the same rail; settable today via `PUT /v1/admin/merchant-profiles/:id/rail-preferences/:rail`. -- Keysat-side dedup cache for Zaprite contacts (same buyer purchasing recurring twice can create duplicate Zaprite contacts). -- Zaprite declined-card / expired-profile failure-body shapes are undocumented — harden `try_auto_charge_zaprite` once observed in production. +- **Auto-charge silently lapses a subscription on a 200-with-failure response (money-path bug; elevated above the other parked payments items).** `try_auto_charge_zaprite` returns `Ok(true)` on *any* HTTP 2xx (`subscriptions.rs:1403-1410`), reading the order `status` only for a log line. If Zaprite returns 200 carrying a `FAILED`/`DECLINED`/`EXPIRED` order status, the daemon fires `auto_charge_initiated` and then waits for an `order.paid` webhook that never arrives — the subscription silently lapses, no error surfaced, the customer churns. Safe fix (no production data needed): treat any non-`PAID` terminal order status as not-success and fall through to the manual-pay path — a conservative fail-safe, ~10 lines + a mock-provider test. (Found during the 2026-06-17 adjudication; it replaces the old "harden Zaprite failure-body shapes" item, which was already satisfied for non-2xx responses — those route correctly to WARN + `auto_charge_failed` audit + webhook + manual-pay fallback.) +- Keysat-side dedup cache for Zaprite contacts (same buyer purchasing recurring twice can create duplicate Zaprite contacts). **Adjudicated 2026-06-17 → lean DROP.** Harm is cosmetic (duplicate rows in the operator's Zaprite contact list) and unverified — Zaprite's own dedup-on-email behavior is undocumented; the fix (new `zaprite_contacts` table + threading a DB handle into `ZapriteProvider`) is HIGH blast radius on the money path and could introduce a stale-cache misrouting bug. **Cheap check before dropping for good: buy twice with the same email on a Zaprite sandbox — one contact → drop outright; two → defer until real recurring revenue makes it worth it.** ## Agent compatibility & scoped API keys @@ -45,36 +45,22 @@ Longer-term backlog. Near-term state lives in `AGENTS.md` → Current state. ## Validation - Re-test `KEYSAT_INTEGRATION.md` against a fresh downstream app to confirm a clean one-shot SDK integration. -- End-to-end Zaprite sandbox pass on the multi-merchant-profile webhook routing before relying on it in production. +- **Add an automated regression test for multi-profile webhook routing** (adjudicated 2026-06-17 → DO, low blast radius — replaces the parked "manual Zaprite sandbox pass"). The routing is a deterministic provider-id→profile primary-key lookup with an anti-forgery re-fetch backstop, so the manual sandbox ceremony isn't worth it — but the path-keyed route (`/v1/{provider}/webhook/:provider_id` → `handle_for_provider`) currently has zero automated coverage on the money path. Plan: in `tests/api.rs`, reuse the two-provider fixture (~:3958), POST a Settled webhook to `/v1/zaprite/webhook/{provider-A-id}`, assert only profile A settles (B untouched; an unknown path-id 404s). Existing mock seam, no external account, runs in `cargo test`. Effort S. ## Design (contract conformance) -The brand contract now lives in `design/DESIGN.md` + `design/tokens.tokens.json` (distilled -2026-06-16 from the prior Claude Design system, now archived in `design/_imports/`). A -`design-checker` audit (2026-06-16) found high fidelity overall, with these items where the -**code contradicts the contract's stated rules** or bypasses the token scale: +The brand contract lives in `design/DESIGN.md` + `design/tokens.tokens.json` (distilled +2026-06-16 from the prior Claude Design system, archived in `design/_imports/`). A +`design-checker` audit (2026-06-16) found high fidelity overall. **Adjudicated 2026-06-17:** +the structural palette-consolidation and the token-gap nitpicks were **dropped** — the +consolidation can't actually remove the duplication it targets (the rust-embedded admin SPA +can't `@import` a shared file, so "consolidation" is a verbatim re-copy), and the token-gap +list was partly mis-specified by the audit. Only the three contract-"never" blockers survive. -**Blockers (code violates a named "never" rule):** +**Blockers — approved to fix (adjudicated → lean DO; wants an owner glance since they change +public landing + admin visuals). Three reversible CSS one-liners:** - Gold used as an actionable *fill* (contract: gold is accent/border only, never a fill). - (a) admin SPA `.featured-pill-toggle.on` → `web/index.html:418`; (b) admin sidebar - upgrade CTA `#tier-banner-cta` → `web/index.html:537-542`. Fix to navy-fill or - gold-border/text. + (a) admin SPA `.featured-pill-toggle.on` → `web/index.html:417-419`; (b) admin sidebar + upgrade CTA `#tier-banner-cta` → `web/index.html:537`. Fix to navy-fill or gold-border/text. - Primary buy CTA uses pill radius `999px` (contract: buttons are `r-md` 8px; pill is - badges-only) — `keysat-xyz-landing/index.html:384-385`. Set to 8px. - -**Structural (headline):** -- All three surfaces inline their own copy of the CSS variables instead of importing the - canonical `design/brand/palette.css` (landing :33-56, docs.css :7-21, admin :9-25). Copies - are currently exact but one edit from drift. Consolidate onto `palette.css`. - -**Token gaps / drift (decide: tokenize the as-built value, or snap to an existing token):** -- `14px` card radius used throughout the marketing landing — not a token (between `r-lg` 12 - and `r-xl` 18). Snap to a token or add one. -- Wordmark letter-spacing is `0.30em` (landing) vs `0.28em` (docs/admin) and has no token — - pick one value, add a `letterSpacing.wordmark` token. -- Semantic badge *text* colors (`#205c47`/`#7a5814`/`#8a2828`) are darker one-offs with no - token — add `semantic.*-text` tokens or reference existing ones. -- Syntax-highlight colors hardcoded as hex (`#d4b985`=gold-400, `#a6b7cf`=navy-300) — switch - to `var()`. One admin hex `#f6f1e7` isn't a token (closest cream-50/100) — reconcile. -- Sticky-header backdrop on docs/admin (`blur(10px)`/`blur(8px)`) diverges from the contract's - `blur(12px)` — align if a single header treatment is wanted. + badges-only) — `keysat-xyz-landing/index.html:390`. Set to 8px.