Spec slice: V1/features.md lines 4942–5204. Date: 2026-06-11. Method: static
source reading only (no builds/tests/servers); every claim below was traced to
current code, following delegation chains end-to-end.
Context honored: B3/C8/C12/C13/D3 closures from the 2026-06-10 audit were
re-verified as landed (tenant onboarding store is real; tenant-admin
members/sso/audit read the live BFF; admin-mobile action sheet is mounted and
posts to POST /v1/admin/review/items/:reviewId/decision which exists at
apps/oshun/bff/src/routes/admin.ts:6399; banners/help/status authored→consumed
loop is real in apps/oshun/bff/src/routes/customer-communications.ts; OIDC SSO
login runtime is real and fail-closed in
apps/oshun/bff/src/auth/sso-login-routes.ts). SAML deferral is recorded and
not re-raised. The three systemic "management without enforcement" items from
the 06-10 audit's pattern 5 had no dedicated backlog task and are confirmed
still open — they are findings 1–3 below, characterized precisely.
1. API keys are stored, rotated, revoked — and still never validated on any request#
Severity: P0-STRUCT
Evidence:
apps/oshun/bff/src/admin/admin-integrations-registry-store.ts:261-277—authenticateApiKeyForexists (sha256 hash match → tenant-consoleauthenticateApiKeywith expiry/revocation/IP-allowlist checks) and is exported at line 543.- Call-site grep across
apps/oshun/bff/src,apps/oshun/web/src,apps/oshun/admin/src: the ONLY references are the store itself and the durable wrapper's mutator list (apps/oshun/bff/src/admin/durable-backed-integrations-registry-store.ts:59). Zero routes, zero middleware, zero preHandlers call it. apps/oshun/bff/src/middleware/authz.ts:99-122— the only request authentication is bearer dev/tenant./HS256-JWT tokens. Nox-api-keyorAuthorization: oshun_…path exists anywhere inapp.ts/server.ts.
Spec promise: features.md:5131-5132 ("API keys with scopes, rotation, expiration, rate limits, IP allowlists, last-used metadata, and revocation"), :5144 ("Tests for key rotation, scope enforcement …").
What the code actually does: full CRUD + rotation-with-grace + revocation +
hashing are real, and the route surface
(apps/oshun/bff/src/routes/admin-integrations-registry.ts, proxied by
apps/oshun/admin/src/app/api/admin/integrations/*) works. But no inbound
request anywhere can present an API key, so scopes, rate limits, IP allowlists
and expiration are stored-config-never-enforced. Corollary:
lastUsedAtUnixSeconds is only ever set by the seed or by authenticateApiKey
— so the "Last used" the admin panel renders can never change for any
operator-created key (dead UI signal).
Fix sketch: add a createApiKeyAuthPreHandler(store) that accepts
Authorization: Bearer oshun_…, calls store.authenticateApiKey, maps key
scopes → request.authContext, and mount it on at least one partner-facing
route group (the natural first consumer: a public ingest/metrics route matching
the seeded ingest:write/metrics:read scopes). Enforce rateLimitPerMinute
in the same preHandler via the existing abuse-protection window store.
2. Outbound webhooks: the real delivery executor was built — and orphaned; no real event ever dispatches#
Severity: P0-STRUCT
Evidence:
libs/oshun/tenant-console/src/integrations/webhook-delivery-execution.ts:1-21— module docstring says it "closes the gap" found by the audit, builds the canonical signed request and sends via an injectedWebhookHttpTransport, noting "the app boundary wires a realfetch-based transport".- Repo-wide consumer grep for
executeWebhookDelivery/WebhookHttpTransport/buildWebhookRequest/classifyDeliveryResponse: only the module itself andlibs/oshun/tenant-console/src/integrations/index.ts. No app boundary ever wired it. No fetch-based transport exists in the BFF. - No event source: nothing in
apps/oshun/bff/srcconstructs aWebhookEventor callssubscriptionsForEventoutside the simulator. The only delivery ever recorded isfireWebhookSimulator(admin-integrations-registry-store.ts:325-422), which is correctly labeledstub:legitimateas the §20.6 simulator feature and is restricted to sandbox tenants. - A blocking sub-gap even if someone wires it: raw signing secrets live only in
the in-memory
webhookSigningSecretsmap (admin-integrations-registry-store.ts:158-159) and are excluded fromIntegrationsRegistryPersistedState(lines 72-79, 482-490) — after a BFF restart no secret can be resolved for any pre-restart subscription (SIGNING_SECRET_UNAVAILABLE, honest fail-loud, but delivery-dead). - The two other "webhook" stores are classifiers, not transports:
apps/oshun/bff/src/studio/webhook-delivery-store.ts(pure backoff/status classifier over caller-supplied response codes) andapps/oshun/bff/src/aja/webhook-management-store.ts(config validator + status state machine). Neither performs HTTP.@oshun/event-busshipsoutbound-delivery.tsbut its only non-test consumers are the tenant-console lib comment and a yemaya capture lib.
Spec promise: features.md:5133-5135 ("Outbound webhook management with topic subscriptions, signing keys, retry/backoff policy, dead-letter inspection, replay tooling, and per-event audit"), :5144-5145 ("webhook delivery semantics, signature verification, replay safety").
What the code actually does: subscriptions are authored, stored durably, and listed; deliveries shown in the admin panel can only ever be simulator rows. A partner who registers a webhook will never receive a single real event.
Fix sketch: (1) wire a fetch transport + createWebhookDeliveryExecutor in the
BFF composition root; (2) persist signing secrets (encrypted column or env-KMS
seam) or store-and-return-once with a durable encrypted copy; (3) publish
WebhookEvents from at least the admin audit-events firehose
(adminAuditEventsStore.record is the natural single choke point) and run the
retry loop on the existing reminder-worker-style interval timer.
3. Role templates and the entire roles engine never feed the live authz check#
Severity: P0-STRUCT
Evidence:
libs/oshun/tenant-console/src/roles/roles.ts— real engines exist:diffTemplateAgainstCanonical(:60),validateTemplateWithinApprovedBounds(:127),effectiveCapabilities(:189, inheritance-ordered),transitionAssignment(:276, approval/expiry/recertification lifecycle),runDryRun(:326, the spec's role test harness).- Consumer grep across all apps: the ONLY non-test consumer is the tenant-admin
demo page
apps/oshun/tenant-admin/src/app/roles/page.tsx(explicitly labeled demo, line 83). - The live authorization check is raw scope-string matching on the token:
apps/oshun/bff/src/middleware/authz.ts:144-145(scopes.includes('domain:*') || scopes.includes('domain:${id}')) and per-routeadmin:*/admin:studio/tenant:admin:{id}includes-checks (e.g.routes/tenant-console-reads.ts:24-26,routes/admin-tenant-console.ts:41-44). Nothing ever expands a role template into scopes, and no store or route for tenant role templates exists in the BFF at all (theadmin-yemaya-rbac/admin-studio-rbac-policyroutes are different domains' own RBAC surfaces). - Consequently the spec's role-assignment workflow (approval, expiration,
recertification) has no backend:
RoleAssignmentrecords exist only as values constructed inside the demo page.
Spec promise: features.md:5079-5090 (operator-editable templates, per-tenant customization within bounds, permission diffs with signoff, assignment workflows with approval/expiration/recertification, dry-run harness, tests for isolation/expiry/scope-restriction).
What the code actually does: a complete, well-tested pure-function role engine sits in the library; the running system authorizes purely on literal scope strings minted into tokens by dev tooling; the two never meet.
Fix sketch: add a BFF role-template store (durable, like the other
durable-backed-* stores) + /v1/admin/role-templates CRUD; at token issuance
(or as an authz-preHandler expansion step keyed on tid + role ids in the
token) resolve effectiveCapabilities → scope set, so templates actually gate
requests; expose runDryRun on a route so the harness the spec promises is
reachable.
4. Bulk-operation "staged commit" commits nothing — committed is a timestamp, not an action#
Severity: P0-HONESTY
Evidence: apps/oshun/bff/src/admin/admin-bulk-operations-store.ts:217-219 —
the entire effect of the committed transition is committedAt = stamp;.
transition() (139-241) validates rationale + state machine, validated
computes real per-row issues, dry_run_complete builds a real per-row plan
(buildDryRunPlan → classifyAdminBulkOperationRowAction), and then commit
writes... nothing. Grep for consumers of committed operations across the BFF:
none. No row is ever applied to tenantInviteStore (users), the OneRoster apply
store (rosters), entitlements, taxonomy, or persona assignment stores — all of
which exist in the same codebase.
Spec promise: features.md:4977-4979 ("Bulk-operation console for users, rosters, content, taxonomy, persona assignments, and entitlements with dry-run, validation, and staged commit"), :5111-5115 (same for import: "conflict report, and staged commit"), :5124 ("Tests for … bulk-action rollback").
What the code actually does: the operator walks draft → validate → dry-run → stage → commit, the UI reports the operation as committed, and zero records change anywhere. This crosses the result-faking line: the system claims an outcome ("committed") it did not produce.
Fix sketch: on the committing step, dispatch rows by kind to the real stores
already in-repo (users → tenantInviteStore.addMember/invite; rosters → the
OneRoster apply store; entitlements → customerAuthStateStore.updatePlan),
record per-row outcomes on the operation, and fail-loud (failed status +
failureReason) for kinds with no executor instead of stamping success.
5. "Bulk export of tenant-owned data" exports whatever JSON the operator pastes — it never reads tenant data#
Severity: P1
Evidence:
apps/oshun/bff/src/routes/admin-bulk-exports.ts:60-68—records: parsed.data.recordscomes from the request body.apps/oshun/admin/src/components/AdminBulkExportsPanel.tsx:264-267— the records are abulk-export-records-inputtextarea the operator pastes JSON into (parsed at :100-120).- The engine itself is real:
executeBulkExportformats (JSON/CSV/OneRoster/xAPI/Caliper), residency gating, integrity manifest, and a workingverifyendpoint (apps/oshun/bff/src/admin/admin-bulk-exports-store.ts:88-148).
Spec promise: features.md:5116-5118 ("Bulk export of tenant-owned content, tenant-owned data, audit bundles, rights/provenance bundles, and Metis academic records…").
What the code actually does: a packaging/manifest service. It is honest (it exports exactly what you give it) but the spec's feature — exporting the tenant's actual records — has no data source: nothing pulls members, audit events, content, or Metis records into an export.
Fix sketch: add server-side record sources per resourceKind (members →
tenantInviteStore.listMembers; audit → the tenant-filtered
listAcrossOperators scan already written for /v1/tenant-console/audit) and
make the pasted-records path an explicit "custom records" mode.
6. Integrations registry boots with unlabeled fixture keys/webhooks/connectors reporting fabricated "healthy" probes#
Severity: P0-HONESTY
Evidence:
apps/oshun/bff/src/admin/admin-integrations-registry-store.ts:698-806—seed()fabricateskey-prod-1("Production ingest", last used 1h ago),hook-1(→https://example.partner/api/oshun-webhook),conn-lms-1("Acme School LMS"),conn-payment-1, plus one connector of every kind fort-pioneer, each withlastHealthVerdict: 'healthy'andlastHealthCheckUnixSecondssynthesized relative to boot time ("2 minutes ago", "30 seconds ago").- No health probe exists anywhere: the only mutation of connector health is the
manual
recordConnectorErrorroute. The "last health check" ages from boot, is never refreshed, and never corresponds to any probe of any endpoint. apps/oshun/admin/src/components/AdminIntegrationsRegistryPanel.tsxrenderssnapshot()rows with no fixture labeling. The honest-labeling primitive exists —apps/oshun/admin/src/components/PlaceholderDataBanner.tsx— but a repo-wide grep shows it is mounted on zero routes (dead component).
Spec promise: features.md:5140-5141 ("Connector health, error budgets, circuit breakers, version pinning, and upgrade pathways"); features.md:4980-4982 (integrations registry as an operator surface).
What the code actually does: an operator opening the registry sees a production-named API key, a partner webhook, and ~10 connectors asserting recent healthy probes — none of which exist. Unlike the tenant-admin demo pages (finding 12), nothing tells the operator this is seed data.
Fix sketch: either drop the seed in favor of honest empty states (the panel
already handles creation flows), or mount PlaceholderDataBanner over the
seeded rows; replace fabricated lastHealthCheck* with null + "never probed"
until a real probe loop exists.
7. SCIM 2.0 has a full engine and no HTTP surface — an IdP cannot provision anyone#
Severity: P1
Evidence: libs/oshun/tenant-console/src/identity/scim.ts implements
applyScimSync (create/update/deactivate/suspend, group sync,
conflict-resolution policies) with tests. Grep across apps/oshun/bff/src for
scim: only a OneRoster route comment (tenant-console/oneroster-route.ts:2)
and domain-stub manifests. There is no /scim/v2/Users, /scim/v2/Groups, or
any SCIM-shaped endpoint; the only runtime consumer of the engine is the labeled
tenant-admin identity demo page.
Spec promise: features.md:5064-5066 ("SCIM 2.0 user and group provisioning with create, update, deactivate, suspend, group membership sync, and conflict-resolution policies"); features.md:5072-5074 (SCIM lifecycle tests).
What the code actually does: orphaned engine. Identity providers have no URL to call; tenant member lifecycle is only mutable via the operator invite routes.
Fix sketch: add a scim-route.ts exposing SCIM 2.0 Users/Groups CRUD that
translates resources through applyScimSync onto tenantInviteStore members,
authenticated per-tenant (natural first consumer of finding 1's API-key
preHandler — SCIM clients authenticate with bearer tokens).
8. Per-tenant authentication policy (MFA / step-up / IP allowlist) is never evaluated on the real login path#
Severity: P1
Evidence: evaluateAuthChallenge (libs/oshun/tenant-console/src/identity/*)
is consumed only by the labeled identity demo page
(apps/oshun/tenant-admin/src/app/identity/page.tsx:115). The live OIDC
callback (apps/oshun/bff/src/auth/sso-login-routes.ts:156-259) mints a session
after id_token verification + JIT gate with no MFA requirement, no step-up
trigger, no IP allowlist, no device posture, and no session-refresh policy;
there is also no per-tenant auth-policy store anywhere in the BFF to hold such a
policy.
Spec promise: features.md:5070-5072 ("Per-tenant authentication policy: MFA requirement, step-up triggers, IP allowlists, device posture signals, and session refresh rules"), :5074 ("step-up enforcement" tests).
What the code actually does: the policy engine exists, the login runtime exists,
and the login runtime never consults the engine (no policy data exists to
consult). Note admin-mobile has its own step-up screen/flow (app/step-up.tsx,
src/auth/adminMobileStepUp.ts) — step-up exists as a client concept but not as
a tenant-policy-driven server gate.
Fix sketch: add tenantAuthPolicyStore (per-tenant policy CRUD on the operator
SSO surface), call evaluateAuthChallenge in the SSO callback and in
createAuthPreHandler for step-up-trigger routes, and 403 with a
step_up_required reason the clients already know how to render.
9. The tenant cockpit has no production login path#
Severity: P1
Evidence:
apps/oshun/bff/src/middleware/authz.ts:216-233—tenant.session tokens are parsed as unsigned dev-format tokens and share the dev-token environment gate;areDevTokensAllowed(:498-503) returns false wheneverNODE_ENV/OSHUN_ENV/RUNTIME_ENV === 'production'. The code comment defers to "§28 signed tenant sessions".- The real OIDC login (finding 8's route) mints a customer session via
customerAuthStateStore.provisionFederatedUser(:245-249); nothing ever issues a token carryingtenant:admin:{tenantId}scopes outside dev tooling. apps/oshun/tenant-admin/src/app/handoff/page.tsxtells the user "your identity provider will issue one" — no IdP integration does; and no surface inapps/oshun/adminorapps/oshun/weblinks to the tenant cockpit or its handoff page at all (repo grep).
Spec promise: features.md:5041-5043 ("Tenant admin shell distinct from Oshun operator admin, scoped strictly to the tenant's data…") — implies tenant admins can actually reach it in production.
What the code actually does: in production builds, every tenant-admin page
redirects to /unauthorized forever, because the only accepted credential
format is environment-disabled. This is acknowledged in code comments (a known
seam, not a hidden fake), but it has no recorded backlog item in the 06-10 audit
— flagging so it does not fall between "C12 done" and "§28 someday".
Fix sketch: extend createBffAuthToken to mint signed HS256 tenant sessions
(tid + tenant:admin:{tid} scopes — the verifier already handles tid),
issue them from the SSO callback when the connection's tenant has the member,
and set the tenant-admin cookie on a /handoff completion route.
10. Audit tamper-evidence and redaction engines are orphaned; a comment claims a firehose feed that does not exist#
Severity: P2
Evidence:
libs/oshun/tenant-console/src/audit-explorer/audit-explorer.ts:132(verifyAuditChain), :165 (applyRedactions), :146 (buildCorrelationThread), :92 (SavedInvestigation) — consumed by no app code (repo grep; theverifyAuditChaininapps/oshun/bff/src/studio/audit-chain-store.ts:64is a separate studio-domain implementation serving its own route).apps/oshun/bff/src/admin/admin-audit-events-store.ts:13-15— comment: "Cross-user investigations route through the §20.4 tenant-console audit-explorer … which receives a separate firehose feed." No such feed exists; the live explorer (/v1/admin/audit-log/*,apps/oshun/bff/src/routes/admin-audit-log.ts+apps/oshun/web/src/app/operator/audit/page.tsx) servesadminAuditEventsStorerecords directly, with filters, saved investigations, and Markdown export.- What is real: investigation/export bundles carry a
contentHash(apps/oshun/bff/src/admin/admin-investigation-bundle-store.ts:187), and the tenant-scoped audit read honestly filters by tenant reference (routes/tenant-console-reads.ts:109-142).
Spec promise: features.md:5102-5105 ("Tamper-evident storage with verification tooling, integrity attestation, and policy-controlled redaction for privacy-sensitive fields").
What the code actually does: export-level hashing exists; per-event hash-chain integrity and redaction policy do not run anywhere on the live audit path, and the store's comment overstates the wiring.
Fix sketch: thread recordHash/previousRecordHash through
adminAuditEventsStore.record using the lib's chain scheme, expose a /verify
endpooint calling verifyAuditChain, and apply applyRedactions in the
tenant-scoped read; fix the firehose comment either way.
11. Webhook signing secrets and the simulator do not survive restart#
Severity: P2
Evidence: apps/oshun/bff/src/admin/admin-integrations-registry-store.ts —
webhookSigningSecrets (line 159) is deliberately not part of
IntegrationsRegistryPersistedState (:72-79); after durable-store hydration
(importState, :493-507 clears the map), fireWebhookSimulator throws
SIGNING_SECRET_UNAVAILABLE (:351-358) for every pre-restart subscription.
Fail-loud and honest — but it means the spec's simulator/replay tooling silently
degrades to "recreate your subscription" after any deploy.
Spec promise: features.md:5133-5135 (signing keys, replay tooling), :5144-5145 (signature verification, replay safety).
Fix sketch: persist secrets encrypted-at-rest in the durable state (or an env-keyed AES-GCM wrap), since the verification flow needs the raw secret to re-sign; alternatively store-and-display-once and let replay re-issue a new secret with explicit operator action.
12. The nine labeled demo pages: labeling is honest and consistent; four have backends wireable today#
Severity: P2 (wiring opportunity register; the labeling itself passes)
Verified label text — "The figures on this page exercise the real engines on
labeled sample inputs (demo data); this surface is not yet wired to live tenant
records." — present, verbatim and visible in the page subtitle, on all nine:
agents/page.tsx:74, content/page.tsx:75, roles/page.tsx:83,
status/page.tsx:164, integrations/page.tsx:107, data/page.tsx:117,
notifications/page.tsx:124, help/page.tsx:118, policy/page.tsx:95. Each
page genuinely exercises the real tenant-console engines (e.g. resolvePolicy
tighten-only inheritance, dryRunImport/planStagedCommit,
buildStatusPageView, evaluateSlo) on inline inputs — no fake engines. The
hybrid pages are honest too: identity renders the REAL
/v1/tenant-console/sso table first with explicit unavailable/empty states and
labels its engine section "Policy engine checks (sample inputs)"
(identity/page.tsx:203); members and audit are fully live reads with honest
unreachable/empty states.
Cheap-wire ranking (real backend already exists, read-only projection suffices):
- status —
GET /v1/statusis already a public BFF route serving the authored components/incidents/maintenance (customer-communications.ts). The page's fabricated "Tenant API degraded / major incident" view (status/page.tsx:26-60) could be replaced by that read today; only the per-tenant SLO/escalation sections lack data. - help —
GET /v1/communications/helpserves published operator-authored articles with locale fallback; the page's targeting demo could ride on it. - integrations —
adminIntegrationsRegistryStorerecords are keyed bytenantId; a/v1/tenant-console/integrationsread filteringsnapshot()to the session tenant is a ~40-line addition in the same style as tenant-console-reads.ts. - policy (partial) —
tenantOnboardingStoreholds the real tenant record (kind, parent, residency, seats: tenant-onboarding-store.ts:26-38); the page currently fabricates a district→school chain (policy/page.tsx:14-48). Identity card is wireable now; policy overlays have no store anywhere. - agents (partial) —
routes/agentic-runs-lifecycle.tsalready resolves tenant-scoped runs (tenantId: authContext.tenantId, :45-53); run inventory is wireable; budgets/approval-gate config per tenant has no store. - data (partial) — bulk operations carry
targetTenantId(admin-bulk-operations-store.ts:118); a tenant-filtered read is possible, though per-operator bucketing makes the scan awkward, and finding 4 means there is nothing real to show post-commit anyway.
No tenant-scoped backend exists at all for: roles (finding 3), content
scopes (only the living-scenes governance slice has a store/route),
notifications (templates store is operator-bucketed; channel-preference data
lives in customer reminders, not per-tenant; the lib's A/B
testing/digest/message-center engines in
libs/oshun/tenant-console/src/notifications/ are consumed by this demo page
only — note the spec's A/B testing (features.md:5159) and digest modes (:5162)
therefore have no live path; the real customer message center is the separate
libs/oshun/customer-message-center + BFF store, a benign but duplicate second
engine).
13. Secret generator's Math.random() fallback is mislabeled "non-secret"#
Severity: P2
Evidence:
apps/oshun/bff/src/admin/admin-integrations-registry-store.ts:151-156 —
generateRawToken produces API-key bearer tokens and webhook signing
secrets (used at :185, :289). Its fallback branch uses
Math.random().toString(36) with the carve-out comment "legitimate non-secret
id/token suffix… carved out true secrets" — wrong for this call site; these are
exactly the true secrets the V1-P2-08xx audit carved out. Mitigating: the
primary branch is randomUUID() (CSPRNG) and typeof randomUUID === 'function'
is always true on Node ≥14.17, so the fallback is effectively dead code — but it
is a loaded footgun with an incorrect audit annotation.
Fix sketch: replace the fallback with randomBytes(24).toString('base64url')
(already imported pattern in sso-login-routes.ts) or simply throw; fix the
comment.
14. UX / product cohesion across the three admin surfaces#
Severity: UX
- Two operator front-ends, one BFF.
apps/oshun/admin(shell with inbox/review/trust-safety/privacy/policy/tenant-console/... + Next API proxies) andapps/oshun/web/operator/*+/studio/*lane consoles both serve operator workflows against the same/v1/admin/*routes — e.g. the audit explorer exists asapps/oshun/web/src/app/operator/audit/page.tsx(OperatorAuditExplorer) whileapps/oshun/adminproxies the same/v1/admin/audit-log/*endpoints for its own surfaces, and tenant member invite/add verbs live inapps/oshun/web/src/components/lilith/TenantMemberActions.tsx, not in the admin app. Operators must know which app owns which verb; nothing cross-links them. - No journey into the tenant cockpit. Nothing in either operator surface
links to
apps/oshun/tenant-adminor its/handoffpage (repo grep, finding 9); the cockpit is an island reachable only by typing its URL with a hand-minted cookie. - Tenant admins can look but not touch. The members page is read-only; all
member mutations (invite, add) are operator-web components hitting
/v1/admin/tenant-console/members/*. The spec (features.md:5048-5050) gives the tenant admin role assignment, group membership, license allocation and seat management — none of which the tenant shell can perform. The sidebar's honest "Locked" treatment partially mitigates. - Error-state conflation.
tenantBffGetreturnsnullfor any non-ok response (tenant-bff.ts:44-46), so a 403 scope mismatch renders as "the backend is unreachable — check that the Oshun BFF is running", sending a mis-scoped admin down the wrong debugging path. - Positive: admin-mobile is genuinely cohesive — login → step-up → operator
tabs → workspace queues, all clients hit real
/v1/admin/*routes (adminMobileReviewQueueClient→/v1/admin/workspaces/review,urgentQueueClient→/v1/admin/workspaces/inbox, decision client →/v1/admin/review/items/...), with offline cache, honest degraded states, and the C13 action sheet mounted in the queue panel (AdminMobileReviewQueuePanel.tsx:135). The tenant cockpit's shell (scope-gated sidebar, per-page testids, consistent unavailable/empty/demo states) is internally consistent and the most honest surface in the slice.
Severity counts#
| Severity | Count | Findings |
|---|---|---|
| P0-SEC | 0 | — |
| P0-HONESTY | 2 | #4 bulk-commit commits nothing; #6 unlabeled fixture registry w/ fabricated health |
| P0-STRUCT | 3 | #1 API keys never validated; #2 webhook dispatch orphaned; #3 role templates never feed authz |
| P1 | 4 | #5 bulk export has no data source; #7 SCIM no HTTP surface; #8 tenant auth policy unenforced; #9 no prod tenant-cockpit login |
| P2 | 4 | #10 audit chain/redaction orphaned + false firehose comment; #11 signing secrets lost on restart; #12 demo-page wiring register (labeling passes); #13 mislabeled Math.random secret fallback |
| UX | 1 | #14 cohesion: split operator surfaces, island tenant cockpit, read-only tenant verbs, conflated errors |
| DEPLOY | 0 | — |