diff --git a/docs/superpowers/evidence/2026-09-05-housekeeping-parity-gaps.md b/docs/superpowers/evidence/2026-09-05-housekeeping-parity-gaps.md index b1978e6e..366fea0c 100644 --- a/docs/superpowers/evidence/2026-09-05-housekeeping-parity-gaps.md +++ b/docs/superpowers/evidence/2026-09-05-housekeeping-parity-gaps.md @@ -2,6 +2,12 @@ Baseline: 8e54cdbc. CI aggregate success verified remotely. This is an open-work inventory, not a completion report. +## Delivery checkpoints + +- Task 1 room/room-furniture legacy convergence: implemented in 184052fb and d0190bc1, independently reviewed, pushed; CI passed. Post-commit refresh warnings are truthful response metadata, but shared UI display remains open. +- Task 4 moderation authority and guarded legacy entrypoints: implemented in 8a894617; pool-starvation review finding fixed in 54f0345a with 112 focused tests passing. Independent scoped re-review clean. No live DB/RCON contention or emulator acknowledgment evidence. +- All other findings below remain open until their implementation, tests and review are recorded. A baseline finding is retained here for traceability even after its corresponding checkpoint is delivered. + ## Hotel / Studio / Operations | Priority | Confirmed gap | Evidence | Execution | @@ -19,6 +25,8 @@ Baseline: 8e54cdbc. CI aggregate success verified remotely. This is an open-work Also requiring explicit parity review: one-time radio API-key delivery; catalog audit/repair bridge versus a history-only screen; radio CRUD legacy convergence. +Radio follow-up confirmed: admin-radio-api-keys.ts, admin-radio-autodj.ts and admin-radio-moderation.ts still write directly and can audit absent targets or swallow failures. Canonical radio runtime checks existence but does not lock those rows before mutations. radio.api-key.create returns metadata without the generated key; the legacy API-key page only renders a masked prefix. Functional parity Task16 covers guarded convergence and a creation-only secret result separated from audit/list output. + Controller confirmed shared site-settings freshness defect: an expired memory cache is returned before attempting a database refresh whenever Redis has no value. Cache invalidation also resets inFlight without protecting against stale in-flight work repopulating the cache. Include regression coverage in the settings task. Operations replacing legacy dashboard metrics is intentional in migration/operations.ts, not itself missing parity. @@ -38,8 +46,10 @@ Audit coverage: Hotel mutations, Studio service/runner/repository, Hotel query/s | System | Privileged configuration/external operations lack canonical audit | Task 6 | | System | Multi-key settings/maintenance writes are non-atomic | Task 6 | | System | Unknown permission slugs silently revoke grants; audit outside transaction | Task 6 | +| System | Canonical ACL changes omit the permissions cache invalidation used by legacy actions | Task 6 | | System | Rank update accepts missing target and empty/unknown fields | Task 6 | | System | Logs fixed to flattened latest 50, no investigation filters/details | Task 12 | +| System | Command-center query omits declared recent emulator-error/staff-activity feeds | Task 12 | | Content | Theme Builder operations absent despite verified migration row | Task 9 | | Content | CRUD synthetic snapshots/false success for absent records | Task 8 | | Content | Prefix settings silently skip invalid keys | Task 8 | @@ -55,3 +65,7 @@ Audit coverage: Hotel mutations, Studio service/runner/repository, Hotel query/s Read-only audit coverage included all declared commands and production query routing for Content/Economy, and People/System commands, services, query models and affected legacy entrypoints. Findings are mapped to implementation work; each needs focused regression evidence. Proposed badge slot uniqueness is NOT accepted without model verification: slot semantics may allow multiple unequipped badges. No domain is declared complete by this document. UI-only omissions remain separately open even when their backend operation already exists. + +Support follow-up confirmed in people/services/support-mutations.ts: ticket, Help Center, template and CFH reads lack FOR UPDATE; ticket-template delete audits success for a missing row; ticket.assign writes a supplied assignee without a user/eligibility lookup. Legacy CFH assign/state/close still write directly in actions/moderation.ts. Functional parity Task17 covers state integrity and active staff-action convergence, preserving separately scoped public ticket flows. + +Acceptance infrastructure check: current e2e/smoke.spec.ts only checks health and homepage rendering; it does not exercise authenticated administration workflows. The supplied docker-compose.yml assumes existing host MariaDB/Redis/emulator services rather than provisioning an isolated test stack. No Docker/MySQL/MariaDB executable was found on the current PATH. These are live-acceptance limitations, not reasons to defer locally testable implementation or to use production data as fixtures. diff --git a/docs/superpowers/plans/2026-09-05-housekeeping-backend-integrity.md b/docs/superpowers/plans/2026-09-05-housekeeping-backend-integrity.md index 4202108e..c42ab7fc 100644 --- a/docs/superpowers/plans/2026-09-05-housekeeping-backend-integrity.md +++ b/docs/superpowers/plans/2026-09-05-housekeeping-backend-integrity.md @@ -4,6 +4,8 @@ **Goal:** Complete the approved backend review, starting with reproducible audit and external-completion defects. +**Delivery status:** Tasks 1 and 2 were implemented and verified in `555bc75f`. Commerce locking followed in `4b88c695`, voucher reservation in `8e54cdbc`, and legacy room convergence in `184052fb` / `d0190bc1`. The remaining complete-product work is tracked in `2026-09-05-housekeeping-functional-parity.md`; these checkpoints do not mean backend or UI completion. + **Architecture:** Retain the six domain services and production adapters. Follow every operation from its public entrypoint through authorization, validation, storage, external effects and audit. Route coverage is not functional completion. **Tech Stack:** TypeScript, Drizzle/MySQL, Vitest, Next.js, pnpm. diff --git a/docs/superpowers/plans/2026-09-05-housekeeping-functional-parity.md b/docs/superpowers/plans/2026-09-05-housekeeping-functional-parity.md index 444ca716..2fb7951c 100644 --- a/docs/superpowers/plans/2026-09-05-housekeeping-functional-parity.md +++ b/docs/superpowers/plans/2026-09-05-housekeeping-functional-parity.md @@ -28,6 +28,8 @@ Route legacy single/bulk radio setting updates through scoped validated Hotel op Repair shared cache freshness: expired memory must attempt database refresh when Redis misses; retain stale data only on actual dependency failure. An in-flight read started before reload must not repopulate the current cache or overwrite Redis with stale settings. Preserve single-flight behavior and build-time stable reads. Test expiration without Redis, database failure fallback, reload during an in-flight read and Redis invalidation failures. Do not install a cache dependency. +Compatibility checks: the existing radio settings form currently contains 102 curated keys, so the present 100-entry runtime limit cannot serve it. Support bounded batches up to 500 entries, reject duplicates/invalid entries atomically, and test the complete curated form size. Include legacy savePoints delegation; never redirect with saved=1 after a failed write. These are direct server forms returning Promise, so preserve their submission contract and show sanitized error/partial/success notices through the existing page/redirect pattern. Keep reload compatible with existing fire-and-forget callers: expose invalidation status without introducing unhandled rejections in unrelated actions. + ## Task 3: Preserve Studio reasons and truthful completion Files: Hotel Studio commands, repository contracts and focused tests. @@ -40,6 +42,8 @@ Files: People moderation/user mutation services and tests; shared target-authori Apply the existing peer/higher-rank protection and superadmin exception consistently to ban.create, user.alert, user.trade-lock, user-targeted moderation actions and CFH sanctions. A missing target returns NOT_FOUND before mutation or RCON. CFH loads/locks the ticket, binds the sanction to its reported user (reject caller mismatch), validates actionable state and applies the same target guard. Database target checks belong in the transaction; external actions must be guarded immediately before dispatch. Respect existing rank lock ordering and do not invent a new bypass permission. +Keep the user-row lock through bounded external dispatch so a promotion cannot slip between the guard and the effect. If the read-only guard transaction fails after dispatch is known completed, preserve that completed outcome instead of inviting a retry. Cover lock/dispatch ordering and post-dispatch transaction failure in focused tests. + Ban IP/machine/super types must use the actual target identifiers rather than empty strings; validate required identifiers using existing canonical ban semantics. Preserve account bans and existing result/legacy signatures. Test lower/peer/higher/superadmin, absent target, forged CFH user, closed ticket, missing ban identifiers, denied calls with no write/transport, and successful audited calls. Existing rank coordinator is already delivered and must not regress. Include active quick user-targeted actions in src/actions/moderation.ts and legacy user alert/trade-lock entrypoints: converge them on the guarded service so they cannot bypass the fix. Preserve action response and permission contracts. Enforce the CFH sanction action allowlist in the service itself, not only the command schema; CFH cannot smuggle broadcast/room-kick input through a direct invocation. Existing ticket assign/state/close operations are a separate transactional parity follow-up. @@ -54,6 +58,8 @@ System settings, emulator configuration, alerts, maintenance and command-center Permission-set updates must resolve every normalized/deduplicated slug before replacement; unknown slugs reject atomically, empty list remains explicit revoke-all only under its existing confirmation contract. Rank updates accept only known editable fields, reject empty/unknown input and missing ranks, lock real rows, preserve rank coordinator behavior, and audit changes transactionally. TDD invalid slug/no writes, nth-write rollback, missing rank, empty/unknown fields, real before/after, audit failures and external partial outcomes. +Converge corresponding legacy configuration/permission/maintenance actions instead of leaving parallel bypasses. In particular src/actions/permissions.ts setCmsPermissions has the same unknown-slug defect. Invalidate the existing permissions cache tag after successful ACL commits (the canonical path currently omits it); classify invalidation failures as committed partial outcomes. Preserve the established repair-grants policy while making its writes/audit atomic, rather than silently redefining grant policy. + ## Task 7: Restore missing People account and badge operations Add canonical typed create-user, individual badge grant and removal operations required by migration/people.ts. Reuse reliable legacy user creation/password validation/defaults and badge services; avoid parallel implementations. Create user/settings/currency rows transactionally with audit, honor authority and unique identity constraints. Serialize badge grants on a stable user row and preserve emulator slot semantics (do not assume all badge slots must be unique). Restore compatible badge-code bounds after checking database/emulator contract; reject overlength instead of truncating. Test missing/duplicate users, authorization, rollback, duplicate badge, grant/remove external failures, code boundaries and legacy delegation. @@ -78,6 +84,8 @@ Add canonical soundtrack upload service/command using the reliable legacy MP3 va Extend People user detail with bounded/batched legacy relations and capability-based sensitive-field redaction. Extend System logs with route-specific pagination/filter/search, stable ordering/totals and relevant investigation fields. Extend Economy marketplace/transactions with state/status, username joins/search and sorting; exclude expired active subscriptions; add full calendar campaign/reward and grouped rare category/value fields. Fix Hotel UNION filtering by applying filters to a derived table of the complete selection while preserving ordering aliases and fallback behavior. Tests must exercise real SQL/projections, parameter binding, totals and field round trips, not only manifest entries. +Restore the System command-center recent emulator-error and staff-activity feeds declared in migration/system.ts but absent from system/queries/operations.ts. Keep those feeds bounded and permission-scoped. Hotel radio setting prefix filters must match literal radio_/auto_dj_ prefixes, not SQL wildcard underscores; retain private-value redaction. + ## Task 13: Make Studio history durable Replace production process-memory-only reads with a bounded shared database-backed operation state/history repository. Retain existing repository contract and test-only in-memory adapter. Reuse current persistence if it can provide atomic identity/state validation; otherwise add a backward-compatible table/migration using repository conventions. Validate terminal transitions and monotonic progress atomically across instances. Keep secrets out of persisted output; do not pretend interrupted jobs are safely resumable. Test fresh-instance reads, list search/pagination, duplicate intent, competing/terminal events, and repository unavailability. @@ -86,6 +94,24 @@ Replace production process-memory-only reads with a bounded shared database-back Extract shared furniture import orchestration from the active legacy API and use it from Studio. Preserve selected source, translation options, final reconciliation, asset ownership, gamedata sync and catalog/items refresh. Preserve API streaming and cancellation contracts. Return explicit per-stage partial outcomes without replaying completed stages. Compare every Studio operation with its legacy responsibility, including catalog audit/repair. Test source/options forwarding and finalization failures using service transport adapters; no real external writes. +## Task 15: Close shared validation and reference-integrity gaps + +Review direct service/runtime parsers across all domains after the preceding concrete repairs. Reject booleans/arrays/objects masquerading as numeric identifiers, unsafe integers and values beyond actual database column bounds. Preserve legitimate form numeric strings and explicit checkbox handling. Required text must not silently truncate or coerce arbitrary objects into stored values; overlength returns field validation while optional/default semantics remain compatible with callers. + +For catalog moves/creates and editable foreign references, verify destination/reference existence in the same transaction and preserve documented special sentinel IDs from legacy behavior. Unknown fields and empty patches must fail before writes. Bulk limits, deduplication and all-or-partial outcomes must match actual forms and commands. Test boundary and malformed-input cases against real runtime functions; do not claim completeness from parser-only mocks. Review persisted audit payload size/serialization and secret redaction for these maximum accepted inputs. + +## Task 16: Complete radio CRUD and credential delivery + +Converge legacy radio API-key, AutoDJ, shout moderation, banner and radio-rank actions on the canonical Hotel operations, preserving direct-form contracts and existing permissions. Read/lock actual rows before toggles, updates and deletes so audits reflect real state; absent targets must not produce success. Preserve desired-state toggles, metadata and rollback on audit failure; provide sanitized notices for validation, dependency failure and committed refresh failure. + +API-key creation currently generates and stores a secret but returns only metadata, while the legacy list only displays a mask. Return a typed creation-only credential separately from audit snapshots, never in URLs, logs, persisted operation history or subsequent list/detail responses. Wire an authorized creation result to a deliberate copy/reveal UI, with no secret echoed after reload. Preserve existing authentication storage compatibility; do not replace the emulator key scheme or invent a key rotation policy. Test authorized one-time result, denied access, failed insert/audit, later read redaction, exact desired-state updates and stale targets. Shared validation Task15 establishes field boundaries; this task must retain them. + +## Task 17: Complete support state and legacy action convergence + +Support ticket, Help Center, template and CFH state mutations must lock the real record before deriving updates/audits. Preserve established reopen/reply/assign semantics and permission contracts; keep closed timestamps consistent with the resulting status. Validate ticket assignees against the existing staff eligibility policy and real user before assignment. Missing template deletes must return NOT_FOUND; updates must reject empty or unknown patches. Preserve BIGINT Help Center IDs and transactional ban-removal semantics. + +Converge active staff entrypoints in actions/tickets.ts, admin-help-tickets.ts, ticket-templates.ts and the CFH assign/state/close handlers in actions/moderation.ts on canonical services. Keep public ticket submission/customer replies separate and preserve notifications and redirect/result contracts. Test locked state transitions, concurrent stale reads, absent targets, unauthorized assignment, audit rollback and post-commit notification/cache failures. Reuse Task5 reason propagation and Task4 CFH sanction authority; do not acquire locks in reverse order or log via a second pooled connection while holding a transaction. + ## Remaining inventory (not completion claims) - Hotel union query filtering; durable Studio history; furniture import orchestration parity; radio API-key delivery and full radio CRUD review.