Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 4 additions & 5 deletions docs/roadmap.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,11 @@ Ordered next work. State, decisions and deadlines live in [status.md](status.md)

The backup, profile-role hardening/audit, two-script Worker URL restrictions and credential containment are recorded as complete in [status](status.md#latest-live-readbacks). Status action numbers are stable references; this is the execution order. Preserve durable facts (Supabase data, migrations, backups), not obsolete runtime topology: fix forward, delete classified legacy surfaces, and make the next production release the architecture we keep. Each production step retains its operator authority and stop points.

Action 5 discovery is complete. Action 8 retains a deletion-time zone DNS/Worker-route check because the scoped Cloudflare token cannot read those surfaces; that gap does not block GitHub governance.
Action 5 discovery and action 10 GitHub governance are complete. Action 8 retains a deletion-time zone DNS/Worker-route check because the scoped Cloudflare token cannot read those surfaces; that gap does not block the first release.

1. Establish the `main` ruleset, Production deployment protections and Dependabot controls (action 10) before the release. Require the exact check `Full repository validation`; inspect bypass behavior and the existing Wrangler/Miniflare ignore policy — authenticated control readbacks.
2. First release (action 3) from a clean checkout of the exact successful CI commit, at a quiet time, with operator commands rather than a CI dispatch: read back the completed `games` count, `player_stats` rows and summed `games_played` (the one-time rebuild resets stats that no completed game backs), apply `20260914000001` and `20260914000002` alone, deploy `dicee-web`, detach `dicee.games` from Pages and attach it to `dicee-web` (short outage), then deploy `dicee` (its protocol gate closes the old Pages client's sockets), run the smoke checks including one completed game, delete the deployed `aggregate-game-stats` Edge Function and rebuild all `player_stats` once, then delete the Pages project and the classified scripts (action 8) — sign-in, room/lobby, a persisted game with stats, headers, transcription, non-admin refusal and deletion readbacks.
3. Implement the profile visibility opt-in control, initially off for private profiles, writing `profiles.is_public`; explain that visibility is voluntary and cover it with tests. Merge through the new ruleset — successful full validation on the PR.
4. Deploy the opt-in code, verify the control and a test bug report, then take a fresh complete encrypted backup. Recheck the production link and history (`000001` remote, `000002` local-only), apply only `000002`, and verify the schema and two-account privacy behavior (action 4). Invite opt-ins only after verification; the migration clears earlier opt-ins. Fix forward — fresh backup evidence, migration readback and privacy tests.
1. First release (action 3) from a clean checkout of the exact successful CI commit, at a quiet time, with operator commands rather than a CI dispatch: read back the completed `games` count, `player_stats` rows and summed `games_played` (the one-time rebuild resets stats that no completed game backs), apply `20260914000001` and `20260914000002` alone, deploy `dicee-web`, detach `dicee.games` from Pages and attach it to `dicee-web` (short outage), then deploy `dicee` (its protocol gate closes the old Pages client's sockets), run the smoke checks including one completed game, delete the deployed `aggregate-game-stats` Edge Function and rebuild all `player_stats` once, then delete the Pages project and the classified scripts (action 8) — sign-in, room/lobby, a persisted game with stats, headers, transcription, non-admin refusal and deletion readbacks.
2. Implement the profile visibility opt-in control, initially off for private profiles, writing `profiles.is_public`; explain that visibility is voluntary and cover it with tests. Merge through the new ruleset — successful full validation on the PR.
3. Deploy the opt-in code, verify the control and a test bug report, then take a fresh complete encrypted backup. Recheck the production link and history (`000001` remote, `000002` local-only), apply only `000002`, and verify the schema and two-account privacy behavior (action 4). Invite opt-ins only after verification; the migration clears earlier opt-ins. Fix forward — fresh backup evidence, migration readback and privacy tests.

Do not reapply or reverse `000001`, run a broad database push, or treat a successful dry run as namespace proof. Hosted multiplayer testing waits for an isolated backend (section 8).

Expand Down
10 changes: 5 additions & 5 deletions docs/status.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
# Dicee status

**As of:** 2026-09-14T18:58:21Z
**As of:** 2026-09-14T19:16:31Z

**Current phase:** 2026-09 operator safety rollout; GitHub transfer complete, action 10 governance next, then the first release that ships stats correctness and the dicee-web cutover (no deployment yet)
**Current phase:** 2026-09 operator safety rollout; GitHub governance complete, first production release next (no deployment yet)

Next work: [roadmap.md](roadmap.md). Cloudflare: [cloudflare.md](cloudflare.md).
## Current state
Expand All @@ -12,7 +12,7 @@ Next work: [roadmap.md](roadmap.md). Cloudflare: [cloudflare.md](cloudflare.md).
- The profile-role audit (action 2) is complete: 7 profiles comprise 5 users and 2 super admins, with no moderators or admins. The operator confirmed both elevated assignments as intentional after private record review; no role changes were needed. Audit-log absence cannot establish that the old privilege was never exploited.
- The database backup is encrypted and verified on off-machine storage; Storage contained 0 objects. The plaintext exports were removed after verification.
- `workers.dev` and Preview URLs are disabled on `dicee` and `dicee-production`; `gamelobby-production` still exposes both. Namespace and binding discovery is complete; zone-level DNS and Worker-route reads remain unavailable to the scoped Cloudflare token and must be rechecked before deletion.
- The GitHub repository is now `jefahnierocks/dicee` and the checkout is `~/Organizations/jefahnierocks/dicee`; the existing shared Cloudflare account and steward remain unchanged. Infrastructure adoption and any provider-account relocation remain separate future work.
- The GitHub repository is `jefahnierocks/dicee`; `main` is protected by an active ruleset requiring `Full repository validation`, Production is reviewer-gated and main-only, and Dependabot alerts/security updates are enabled. The existing shared Cloudflare account and steward remain unchanged; provider/infrastructure ownership is separate future work.
- Credential containment (action 9) is complete: both exposed tokens (Cloudflare and Supabase) return HTTP 401 and their replacements authenticate (see readbacks). The Supabase CLI credential is a project-scoped token with only Database read-write access that expires 7 days after its 2026-09-14 creation; renew it before later operator steps need it.
- No application deployment has run during this operator rollout. CI deploys only on a manual `workflow_dispatch` from `main` with `deploy=true`.
- Legacy client layers are retired and the docs are consolidated into this file, the roadmap, `docs/cloudflare.md`, `docs/architecture/` and `docs/development/`. Git history is the archive.
Expand Down Expand Up @@ -43,7 +43,7 @@ These are stable action identifiers, not execution order. [Roadmap section 1](ro
7. [ ] **Stats aggregation.** Fixed in source: `20260914000001` makes `player_stats` a rebuildable projection and stores AI seats, and the Worker now sends JSON arrays (its old array literals were rejected, so the deployed Worker has likely never persisted a game). Complete with action 3: delete the deployed `aggregate-game-stats` Edge Function, then rebuild all stats once.
8. [ ] **Delete obsolete surfaces.** `dicee-production`, `gamelobby` and `gamelobby-production` are legacy cleanup candidates; no deployed Worker service binding consumes them. `gamelobby-production` still exposes `workers.dev` and Preview URLs, and zone-level Worker routes/DNS remain unverified because the scoped token receives HTTP 403. Recheck those surfaces immediately before deletion. Delete Pages `dicee` only after the `dicee-web` cutover; live Durable Object state on legacy scripts is not preserved.
9. [x] **Credential containment.** Both exposed tokens are replaced, revoked and verified dead by direct HTTP 401 readbacks. Cloudflare: the replacement is canonical in 1Password and GitHub Production, and the repository duplicate is removed. Supabase: a project-scoped token with only Database read-write access is the sole CLI credential; temporary copies, the environment override, the fallback token file and plaintext copies are absent.
10. [ ] **GitHub governance.** A `main` ruleset requiring the check **Full repository validation** (the job display name, not `validate`); a `Production` environment with required reviewers and a main-only deployment branch policy; Dependabot alerts and security updates.
10. [x] **GitHub governance.** Active `main` ruleset with no bypass entries requires the exact check **Full repository validation** with strict status checks and blocks deletion/non-fast-forward updates. `Production` requires one reviewer, permits self-review, and accepts deployments only from `main`. Dependabot alerts and security updates are enabled.
11. [ ] **Supabase default grants change on 2026-10-30** for newly created tables; existing tables keep their grants. Apply the explicit-grants migration from the roadmap first ([change notice](https://supabase.com/changelog/45329-breaking-change-tables-not-exposed-to-data-and-graphql-api-automatically)).
12. [ ] Migrate off the legacy `anon` and `service_role` API keys before the announced end-of-2026 deprecation. Verify the final schedule before cutover ([migration guide](https://supabase.com/docs/guides/getting-started/migrating-to-new-api-keys)).
13. [ ] Revoke unused Infisical machine identities and any leftover Vercel or PartyKit credentials.
Expand Down Expand Up @@ -74,7 +74,7 @@ Recorded results; do not rerun the database checks. The operator confirmed that
|---|---|---|---|
| Worker inventory | 2026-09-14T18:58:21Z | API: scripts, Durable Object namespaces, Worker metadata and Pages bindings | 11 scripts; Pages production binds `GAME_WORKER` to `dicee`; `dicee`, `dicee-production` and `gamelobby-production` hold SQLite `GameRoom`/`GlobalLobby` namespace pairs at v2; source `dicee` matches v1/v2, so no lifecycle deploy or cutover is required |
| Worker subdomain URLs | 2026-09-14T18:58:21Z | API: subdomains, custom domains, cron and service-binding consumers | `dicee`, `dicee-production` and `gamelobby` have direct Worker URLs disabled; `gamelobby-production` has workers.dev and Preview URLs enabled; no custom domains, cron or Worker service-binding consumers were found; zone DNS/routes remain unresolved under the scoped token |
| GitHub governance | 2026-09-14T18:58:21Z | Transfer plus REST readback after move | Repository is `jefahnierocks/dicee`; local origin/home updated; Actions secrets and Production environment survived; 0 repository/organization/effective-main rules, Production still unprotected; action 10 remains next |
| GitHub governance | 2026-09-14T19:16:31Z | REST: repository/effective rules, Production environment and Dependabot controls | Active `main` ruleset: no bypass entries; deletion and non-fast-forward blocked; strict `Full repository validation` required. Production: 1 required reviewer, self-review permitted, custom deployment branch policy `main` only. Dependabot alerts and security updates enabled |
| Credential containment | 2026-09-14T06:25:02Z | Cloudflare (04:41:28Z): private token verification, wrapper auth, GitHub secret-name readback. Supabase: dashboard last-used match, Management API call with the preserved old token, CLI `SELECT 1` with the replacement, local-copy inventory | Cloudflare: replacement canonical in 1Password; Production `CLOUDFLARE_API_TOKEN` present; repository duplicate absent; old token HTTP 401. Supabase: old token HTTP 401, other account tokens unchanged; project-scoped Database read-write replacement authenticates; environment override, fallback file, temporary Keychain copies and plaintext copies absent. No deployment or database mutation |
| Cloudflare Pages and build triggers | 2026-09-13T04:35Z | API: Pages project `dicee`, Workers Builds triggers | Pages has no Git source, production branch `main`; trigger reads returned 403, so triggers are unverified |
| GitHub Apps | 2026-09-13T04:49Z | Repository installed GitHub Apps page | No Cloudflare Workers and Pages app; with no Pages Git source, the native Git build integration is not in use |
4 changes: 2 additions & 2 deletions project.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ role: canonical
peers: []
status:
posture: deployed-system
local_phase: "2026-09 operator safety rollout; GitHub transfer complete, action 10 governance next, then the first release that ships stats correctness and the dicee-web cutover (no deployment yet)"
as_of: "2026-09-14T18:58:21Z"
local_phase: "2026-09 operator safety rollout; GitHub governance complete, first production release next (no deployment yet)"
as_of: "2026-09-14T19:16:31Z"
authority:
status_of_record: docs/status.md
presentation:
Expand Down