Triage full-eval findings into Current state: work queue / known debt / deferred
This commit is contained in:
@@ -117,28 +117,59 @@ Operator-specific memories at `~/.claude/projects/-Users-macpro-Projects-licensi
|
|||||||
product's sales to them. The data model + resolver fully support it; only the
|
product's sales to them. The data model + resolver fully support it; only the
|
||||||
product→profile **write path** is missing. **This is the gating piece for
|
product→profile **write path** is missing. **This is the gating piece for
|
||||||
multi-profile** — see the scoped slice below.
|
multi-profile** — see the scoped slice below.
|
||||||
- **Next, in priority order**:
|
- **Triage from `EVALUATION.md` (full-eval, 2026-06-13)** — P0/P1 = work queue,
|
||||||
(1) **Product→merchant-profile picker** (gating piece above). Slice:
|
P2 = known debt, P3+ = deferred. The report at repo root has file:line evidence.
|
||||||
add `merchant_profile_id: Option<String>` to the `Product` model + its SELECT
|
|
||||||
column mapping in `repo.rs`; add a `set_product_merchant_profile` follow-up
|
- **Work queue (P0/P1 — do first, in this order)**:
|
||||||
writer mirroring `set_product_entitlements_catalog`; add the field to
|
1. **[P1] Provider-injection test seam — BEFORE #2's fix.** The prod purchase/
|
||||||
`CreateProductReq`/`UpdateProductReq` (`api/admin.rs`) applied as a post-create/
|
settle path has no mock seam (the mock injects into the dead `state.payment`
|
||||||
update follow-up; add a profile `<select>` (populated from
|
singleton, not `resolve_provider_for_profile_rail` — this is how the `:52`
|
||||||
`GET /v1/admin/merchant-profiles`) to the create + edit product forms in
|
500 shipped). Add an always-compiled `Option<Arc<dyn PaymentProvider>>`
|
||||||
`web/index.html`, rendered only when >1 profile exists. No migration (column
|
override on `AppState`, checked first in `resolve_provider_for_profile_rail`.
|
||||||
exists since 0020). Default/None → stays on default profile.
|
Greens the two `paid_purchase_*` red tests and gives #2 a regression harness.
|
||||||
(2) resolve the 3 red tests — **delete** the dead
|
**Delete** the dead `payment_provider_preference_round_trip` in the same pass.
|
||||||
`payment_provider_preference_round_trip`; for the two `paid_purchase_*`, add a
|
2. **[P0] Zaprite webhook forgery.** The settle-webhook is unauthenticated — a
|
||||||
provider-injection seam (recommended: an always-compiled
|
forged `order.change`/`status=PAID` with a buyer-visible order id mints a
|
||||||
`Option<Arc<dyn PaymentProvider>>` override on `AppState`, checked first in
|
signed license (the `externalUniqId` "trust anchor" in the comments is never
|
||||||
`resolve_provider_for_profile_rail`; alt: gate a mock behind a `test-mocks`
|
read in the webhook path). Fix: on settle, re-fetch `get_invoice_status` from
|
||||||
cargo feature). See `docs/guides/testing.md`.
|
the provider and require local `pending` state + matching amount/currency
|
||||||
(3) build the other 3 deferred UIs (rail picker, per-profile SMTP, rail-pref
|
before issuing (mirror the reconciler's safe re-fetch). Closes the P1 below
|
||||||
editor) + add `unlimited_merchant_profiles` to master Pro/Patron policies;
|
too. `payment/zaprite/provider.rs:234-362`, `api/webhook.rs:62-196,121-194`.
|
||||||
(4) re-register the master Zaprite webhook; (5) optional: run formatters as a
|
3. **[P1] Scoped API keys (`ks_…`) are non-functional** — issuable but 403 on
|
||||||
standalone commit.
|
every admin endpoint; the `require_admin`→`require_scope` migration was never
|
||||||
|
done. Finish it, or stop advertising/issuing them. `api/api_keys.rs:14`.
|
||||||
|
- **Then resume feature work**: the **product→merchant-profile picker** (the GAP
|
||||||
|
above — slice: add `merchant_profile_id` to the `Product` model + `repo.rs`
|
||||||
|
SELECT mapping; a `set_product_merchant_profile` follow-up writer mirroring
|
||||||
|
`set_product_entitlements_catalog`; the field on `CreateProductReq`/
|
||||||
|
`UpdateProductReq` applied post-write; a profile `<select>` from
|
||||||
|
`GET /v1/admin/merchant-profiles` in the create+edit product forms, shown only
|
||||||
|
when >1 profile; no migration), the 3 other deferred UIs (rail picker,
|
||||||
|
per-profile SMTP, rail-pref editor), and `unlimited_merchant_profiles` on
|
||||||
|
master Pro/Patron policies.
|
||||||
|
|
||||||
|
- **Known debt (P2 — schedule, not urgent)**: no rate-limit on `/v1/purchase` +
|
||||||
|
`/v1/redeem`; rate-limit bucket keys on spoofable `X-Forwarded-For` (bypass
|
||||||
|
conditional on whether the StartOS proxy rewrites XFF — unverified); `422`/`415`
|
||||||
|
errors return plain-text not JSON (breaks SDK `JSON.parse`); product `slug` has
|
||||||
|
no validation (empty/300-char/meta chars stored); `GET /v1/admin/products`
|
||||||
|
returns 405 though OpenAPI documents it; dep advisories (`sqlx`→≥0.8.1
|
||||||
|
RUSTSEC-2024-0363, `rustls-webpki`→≥0.103.12); **4 StartOS submission blockers** —
|
||||||
|
missing `instructions.md`, dead `packageRepo` (`…/keysat-startos`→`…/keysat`) +
|
||||||
|
`docsUrls` (`/docs/`→`/licensing-service/docs/`) manifest links, aarch64
|
||||||
|
declared-but-not-shipped; no CI + fmt/clippy/prettier unenforced.
|
||||||
|
|
||||||
|
- **Deferred (P3+ — bulk or later decision)**: `/v1/purchase` 400 vs
|
||||||
|
`/v1/btcpay/webhook` 503 for the same no-provider cause; undocumented required
|
||||||
|
`kind` on discount-codes; field-naming drift (`license_id`/`id`, machines `key`
|
||||||
|
vs `license_key`, `redeem`/`purchase` `product` vs `validate` `product_slug`);
|
||||||
|
migration self-heal `_sqlx_migrations` allowlist foot-gun; 2 KB unauth Zaprite
|
||||||
|
payload WARN-log; outbound-webhook SSRF (operator-only); stale
|
||||||
|
`versions/v0.2.0.ts:3-4` "NOT YET WIRED" comment; re-register the master Zaprite
|
||||||
|
webhook at the path-keyed URL; registry icon non-render (known platform limit);
|
||||||
|
optional fmt/prettier standalone commit.
|
||||||
|
|
||||||
- **Tests/build**: `cargo check` clean (1 intentional deprecation warning); api
|
- **Tests/build**: `cargo check` clean (1 intentional deprecation warning); api
|
||||||
43 pass / 3 known-fail (test-debt), other suites green. No CI; fmt/prettier not
|
43 pass / 3 known-fail (now tracked in the work queue above), other suites
|
||||||
enforced or clean. FK enforcement **confirmed** — the sqlx pool sets
|
green. FK enforcement **confirmed** — sqlx pool sets `foreign_keys(true)` per
|
||||||
`foreign_keys(true)` per connection (`db/mod.rs`); the old "latent/unchecked"
|
connection (`db/mod.rs`). CI/fmt status is in Known debt.
|
||||||
caveat is resolved.
|
|
||||||
|
|||||||
Reference in New Issue
Block a user