OMLA Implementation Roadmap
Every gap we know about. Each item has a status, a priority, a design sketch, and a rough complexity estimate. Things already shipped are at the top for context; open work is below. The full behavioural spec this roadmap is closing against lives on the Technical Details page.
Priorities: P0 launch-blocking · P1 within 30 days · P2 within 90 days · P3 nice to have.
Shipped
Here for context. Details in the technical docs.
Shipped Registration flow (Ed25519 + Bech32m + lineage + splits + sign)
Six-step browser-side flow, real tweetnacl keypairs, real Bech32m addresses, writes through RLS. /register.html
Shipped Public registry with model detail
Searchable registry with lineage SVG, resolved splits table, compliance badge, invocation snippet, copy-to-clipboard everywhere. /registry.html
Shipped Creator dashboard
Models, wallets, earnings. Quarterly bar chart + payment ledger. /dashboard.html
Shipped Commercial-user flow
Company registration with API-key hashing, quarterly report submission with auto-royalty, report history. /commercial.html
Shipped Complaint intake + compliance explainer
Public complaint form, six-state compliance machine, stub blacklist. /complaint.html
Shipped Edge Function set (stubs)
submit-report, compliance-tick, quarterly-payout (DRY_RUN default), publish-blacklist — source + READMEs in omla-deploy/backend-services.
P0 — Launch-blocking
Items the site cannot responsibly go live without.
Planned G2 — Mutation signatures
Today, wallet / split / lineage updates are authorised only by RLS email match. A compromised email = full control. Each mutation should also carry an Ed25519 signature from the model's creator keypair and be server-verified.
update_signature BYTEA + update_nonce BIGINT columns to wallets, contribution_splits, lineage_edges. Server-side trigger uses pgsodium (or a small edge function proxy) to verify the signature against the row's owning models.ed25519_pubkey. Reject on failure. Client sends the signed payload via an Edge Function that pre-validates before the DB write.Planned G1 — Split update consent
Altering an existing split affects parties other than the creator. They must consent.
split_change_requests table holds a proposed contribution_splits diff + one row per affected recipient with a signed_at column. When every affected recipient has signed (via email-magic-link Ed25519 proof-of-key), an Edge Function applies the change atomically. Pending changes are visible on /dashboard-models.html so the creator can chase.Planned Stripe Connect integration (live)
Rails are stubbed. At least one rail must be live to pay creators.
backend-services/edge-functions/quarterly-payout to Stripe Connect via stripe-node. Use Transfer.create with idempotency key. Webhook endpoint stripe-webhook updates payments.status to completed/failed/reversed. Creator onboarding flow on /dashboard-wallets.html for rail='stripe' wallets — redirect to Stripe Express onboarding, capture acct_… on return.Planned G11 — Admin console
Board review is currently "open a SQL Editor tab". Too error-prone for a moderator that isn't a database engineer.
/admin.html password-gated via a board-member Supabase account with a service-role proxy Edge Function (never ship service-role key to browser). Flows: triage complaints, resolve/dismiss/blacklist, manually transition compliance state, redact audit log fields for GDPR, re-run quarterly payout for a specific report.P1 — Within 30 days
High-impact items that make the system usable at scale.
Planned Automated 24h complaint notification
The license promises 24-hour holder notification. Today it requires someone to read the complaints table daily.
notify-complaints runs hourly, finds complaints rows where notified_at IS NULL, sends email via Supabase's auth.admin.sendEmail() or a transactional provider (Postmark / Resend), stamps notified_at. Cron-scheduled; idempotent via the notified_at check.Planned G4 — Usage-report disputes
A creator who thinks their model earned more than was reported has no in-system recourse.
usage_disputes table keyed by report_id with reason, proposed_revenue_usd, proposed_cost_usd. Opening a dispute flips the report's status to 'disputed' and pauses that report's portion of the next payout. Board arbitrates; resolution writes the accepted numbers back and re-flips status.Planned G3 — Key rotation / recovery
Lost secret key = permanent loss of ability to update. Today: email-based manual recovery by the board.
models.pubkey_rotation_pending allows a 7-day challenge window; at end of window, rotation completes unless challenged. Lost-both recovery is an off-system legal process.Proposed G9 — Integration SDKs
Commercial users today paste JSON. SDKs drop the bar to ~10 lines.
omla-sdk-js: const omla = createClient({anonKey, url, apiKey}); await omla.report({quarter, entries}).
omla-sdk-python: same. Published to npm + PyPI. Repo lives alongside omla-deploy.Proposed G10 — Hugging Face / Civitai sidecar
A JSON sidecar that model hubs can host alongside weights. When someone views your model on HF, an OMLA badge shows the wallet + compliance state.
omla.json file format with model_id + pubkey + wallet + license_version. Client-side JS snippet that HF / Civitai UIs can include; pings /rpc/verify_by_hash and renders a badge.P2 — Within 90 days
Operational polish and compliance features.
Proposed G5 — Multi-currency payouts
All ledger fields are USD; actual payouts settle in local currency.
payments.settled_currency, payments.settled_amount, payments.fx_rate_used. New fx_rates table populated from the rail's settlement data. Reconciliation report flags drift > 2%.Proposed G6 — Withholding & tax forms
US creators > $600/yr need 1099-MISC; non-US need W-8BEN. Rails will eventually require this.
tax_forms(wallet_id, kind, filed_at, expires_at, document_ref). Payout pipeline skips wallets lacking a valid form when year-to-date total crosses the threshold; accumulates in dust_credits until filed. Annual 1099 generation via Stripe's 1099-K service or a paid Tax SaaS.Proposed G7 — Creator audit rights
Creators have no tool to challenge a commercial user's self-declared numbers.
audit_request(report_id, reason). Commercial user must reply with evidence_uploads (CSV export from Stripe, cost accounting, etc.) within 14 days, else report flips to 'disputed' and payout pauses. Board can compel or waive.Planned G14 — Registry pagination + filters
Current GET /models fetches everything. Fine for < 1k, painful above.
.range(offset, offset+49) with "load more" button. Facet filters: compliance state, domain, has-upstream-OMLA. Filters translate to PostgREST query params.Proposed G8 — Sybil / bot prevention
Anyone with a free email can register unlimited models and pollute the registry.
/register.html + per-IP rate limit (3 registrations / day) via Upstash Redis in an Edge Function. Legitimate creators stay well under the cap.Proposed G12 — Public transparency dashboard
Trust grows with transparency. Publish aggregate numbers.
/stats.html reads a materialized view refreshed hourly: total models (by compliance state), total commercial users, lifetime paid out, quarterly paid / denied / blacklisted counts, top 10 rails by volume. No PII.P3 — Nice to have
Proposed G13 — Internationalization
English only today. The audience is global.
i18n/{lang}.json. data-i18n="key" attributes on HTML elements; a loader swaps text at page load. License translations are advisory until board-approved.Proposed G15 — Asset kinds beyond models
Datasets, likenesses, art styles — same royalty/split/compliance machinery.
assets.asset_kind ENUM('model','dataset','likeness','artwork') defaulting to 'model'. Per-kind royalty_rate. Registry page grows a type filter. License text gets kind-specific §3 addenda.Proposed Community forum
Creator + commercial-user feedback loop.