20 KiB
Housekeeping functional parity execution
Spec: docs/superpowers/specs/2026-08-30-housekeeping-stepwise-rebuild-design.md, with current conversation authorizing continuous execution and backend-first completion.
Global constraints
- Canonical checkout and existing
codex/housekeeping-rebuild-stepwise; no worktrees. - Preserve
/admin, preview isolation, unrelated local files and existing useful workflows. - Keep PR 53 draft, update English and Dutch after verified pushes. No deployment or merge.
- Backend completion requires operation-level evidence, not migration registration. UI and live acceptance remain separate gates.
- No new dependency or distributed-delivery guarantee without evidence and user discussion.
Task 1: Converge legacy room mutations on the Hotel service
Files: src/actions/rooms.ts, focused legacy-action regression tests; Hotel runtime/service helpers only where necessary to preserve the existing forms.
Replace direct room and furniture writes with the existing authenticated Hotel mutation service/production adapter, preserving exported action signatures and revalidation routes. Cover update, delete, bulk delete, room update/delete, and runtime actions. Preserve existing webhook notifications, but do not let notification failure reclassify a committed mutation as failed. Use correlation IDs and legacy context; do not manufacture an operator reason. Return actionable failure through the existing server-action convention. Check the caller hook before choosing the result adapter.
The effective contract must reject unknown fields, invalid IDs, invalid runtime actions and mutations targeting an item outside the supplied room. Bulk selection must be bounded, deduplicated and atomic: absent/wrong-room requested items must not silently count as deleted. Database changes and audit share the existing transaction. No success audit/revalidation on failed database work. Do not claim emulator reload after a database-only edit; correct misleading success copy in the affected edit dialog if necessary.
Use TDD against real action/service/runtime behavior with transport mocks, not an entirely mocked service: demonstrate the legacy bypass failing first, then test valid floor/wall edits, forbidden owner/type fields, wrong-room single/bulk targets, denied permission, audit failure rollback, and runtime false delivery. Run focused tests, typecheck, scoped Biome and full suite once before commit. Commit exact files, no push (controller reviews first). Report RED/GREEN commands and results.
Task 2: Scope and refresh radio settings consistently
Files: legacy radio setting actions, Hotel production adapter, site-settings service, focused tests.
Route legacy single/bulk radio setting updates through scoped validated Hotel operations. Only radio_/auto_dj_ keys, bounded batches and values; preserve forms and useful metadata. Reject invalid settings before writes. Invalidate siteSettings only after successful committed radio.settings.save-one, radio.settings.save-many and radio.points.save, never after rollback. Handle post-commit invalidation failure as partial completion, not a retryable failed write. TDD covers forged unrelated keys, invalid bulk entries, valid settings, transactional audit and commit/invalidation order. Preserve other radio CRUD for its own parity pass.
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.
Propagate normalized optional reason from command to invocation, intent and every audit event. Separate runner failure from final event persistence/readback failure: completed external work must return its known output with partial audit availability, never trigger a false failure event. Preserve genuine runner/cancellation failures and durable intent before side effects. False catalog/items refresh returns must produce warning/partial. Aggregate icon/Nitro repair child failures and setup error events. TDD each failure mode and passing case. Durable repository and full import orchestration are subsequent tasks, not solved by this task.
Task 4: Unify moderation target authority
Files: People moderation/user mutation services and tests; shared target-authority helper if needed.
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.
Task 5: Preserve People reasons and honest record existence
Propagate normalized reason across all People command/invocation/context paths into intent/success/failure/partial canonical audit entries, including delegated moderation/ticket executors. Do not synthesize a reason for legacy calls. Lock/read actual rows for IP/word-filter deletes; absent rows yield NOT_FOUND without reload or success audit. Test reason transport through real services and each outcome, plus absent and repeated deletes.
Task 6: Make System configuration and access mutations auditable and atomic
System settings, emulator configuration, alerts, maintenance and command-center execution must carry actor/reason/correlation and use intent/outcome audits appropriate to DB versus external work. DB changes and audit share a transaction; multi-key writes are all-or-nothing. Cache/RCON failures after commit are partial, not false failed writes. Validate required reason at sensitive command boundaries while preserving working legacy forms via adapters.
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.
Task 8: Repair Content CRUD state and complete editable projections
Tags, prefixes, help, writeables and email mutations must read/lock actual records, return NOT_FOUND for absent update/delete and capture real before/after audit snapshots. Prefix settings reject unknown keys and empty batches atomically. Expose typed editable query payloads for writeables, banners, prefixes/settings/blacklist, help and email; preserve untouched fields in round trips. Test nonexistent/concurrent stale targets, audit rollback, mixed-invalid settings and full field projection.
Task 9: Restore Theme Builder backend parity
Compare migration/content.ts Theme Builder responsibilities with active legacy source. Implement all retained scope/value create/update/delete, duplicate and reset operations plus typed scope/tree/value queries. Reuse existing Theme Builder persistence and validation; transactionally audit real snapshots. Test complete lifecycle, inheritance/duplicate/reset semantics, invalid scope/value, permission denial and rollback. This task does not declare the Theme Builder UI complete.
Include retained theme update/preset/custom application cache outcomes in this pass: mutation-runtime-external.ts currently calls siteSettings.reload() without awaiting or inspecting it. Consume Task2 invalidation status after committed writes and return truthful partial completion on failure. Preserve existing color contrast/readability behavior and custom store persistence; do not turn a cache failure into an invitation to replay committed theme edits.
Task 10: Complete Economy commerce and bulk outcomes
Restore editable voucher code with duplicate conflict handling and preserved locked use counters; correct migration responsibilities for voucher and rare category/value updates. Catalog bulk-create must validate nonempty bounded input and report per-row committed/failed outcomes honestly, with partial canonical audit whenever only part succeeds. Preserve successful IDs and actionable failure indexes; do not blind-retry successful rows. Fully failed input must not claim success. Test mixed/all failed/all passed batches, refresh failure, audit failure and voucher code conflicts.
Task 11: Restore soundtrack upload workflow
Add canonical soundtrack upload service/command using the reliable legacy MP3 validation, size limits and storage path rules. Share orchestration with the existing upload API; preserve authorization and response compatibility. Persist intent before filesystem work, compensate newly created file on DB failure, never delete a pre-existing file. Audit success/failure/partial truthfully. Test invalid content, oversize, successful upload, collision, DB failure cleanup and cleanup failure.
Task 12: Complete investigative and commerce read models
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.
Task 14: Complete Studio import orchestration
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.
The origin/main integration through 775d14f8 already supplies Git export, furniture inspection/review, advisory source preflight, streamed single-import errors, source-asset diagnostics, post-asset ID reservation/remapping, revision preservation and conversion recovery. Reuse these integrated foundations rather than recreating them. Task 14 remains responsible for the missing shared end-to-end Studio orchestration, selected-source/options forwarding and finalization truth; the integration alone does not satisfy it.
Repair the integration-test boundary while covering this workflow: src/test-repair-icons.test.ts currently runs based only on the presence of DATABASE_URL and logs a result without assertions. Routine test runs must not invoke live repair/import writes. Require explicit isolated-sandbox opt-in for genuine integration tests and assert meaningful outcomes; keep deterministic service/transport regression coverage in the default suite. Preserve the stronger sandbox boundary already used by import-live/catalog-repair-live tests.
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.
- Content/Economy and People/System audit reports: validate and append concrete tasks before implementation.
- Shared input, foreign-reference and operation-level audit policy review.
- Complete workflow-specific UI/read models and visual acceptance across six domains.
- Full branch review, builds, CI and service-backed acceptance; production cutover requires separate approval.