diff --git a/AGENTS.md b/AGENTS.md index 8fa8b23..4aabd37 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -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→profile **write path** is missing. **This is the gating piece for multi-profile** — see the scoped slice below. -- **Next, in priority order**: - (1) **Product→merchant-profile picker** (gating piece above). Slice: - add `merchant_profile_id: Option` to the `Product` model + its SELECT - column mapping in `repo.rs`; add a `set_product_merchant_profile` follow-up - writer mirroring `set_product_entitlements_catalog`; add the field to - `CreateProductReq`/`UpdateProductReq` (`api/admin.rs`) applied as a post-create/ - update follow-up; add a profile `` 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 - 43 pass / 3 known-fail (test-debt), other suites green. No CI; fmt/prettier not - enforced or clean. FK enforcement **confirmed** — the sqlx pool sets - `foreign_keys(true)` per connection (`db/mod.rs`); the old "latent/unchecked" - caveat is resolved. + 43 pass / 3 known-fail (now tracked in the work queue above), other suites + green. FK enforcement **confirmed** — sqlx pool sets `foreign_keys(true)` per + connection (`db/mod.rs`). CI/fmt status is in Known debt.