Active focus
What the project is pointed at right now — read this first.
15-hour proof-of-concept route — shooter is maintenance-only unless demo-breaking; the active MVP is the freedom-tech loop (gateway/NAP-to-NAP preview → Plebeian/Nostr product panel → leaderboard preview → torii.quest update-check). Polish comes after PoC validation.
Handoff / release control panel
HANDOFF READY · MVP BLOCKER PENDING (USER PLAYTEST + OK) GENERATED HANDOFF / RELEASE CONTROL PANEL · LOCAL · READ-ONLY · ONE-GLANCE PICKUPRead this FIRST. One read-only surface to pick up the project safely: current version + live URLs, the latest app-entry and oversight-dashboard cloud smokes, the one manual blocker (user runs the live-browser MVP playtest + explicitly approves), the next safe no-blocker task, the actions NOT to take without user input, and the project's practical operating principles. GREEN here means the handoff surface is complete — NOT that the MVP is approved.
Versionv0.2.244-alpha
Live gamehttps://torii-quest.pplx.app
Live dashboardhttps://torii-quest.pplx.app/continuum.html
Entry smokePASS @ v0.2.230-alpha (3/3 checks; implies approval: no)
Dashboard smokePASS @ v0.2.231-alpha (4/4 checks; implies approval: no)
Manual blocker
- PENDING — LOCAL GATES GREEN
- MANUAL PLAYTEST + APPROVAL PENDING
MVP approvalPENDING (explicit user OK required)
Next safe taskContinue the read-only oversight loop — next safe infra/dashboard slice
Do NOT (without user OK)
- Do NOT deploy, publish, or push — the maintainer performs the manual deploy.
- Do NOT create a git tag, GitHub release, or announcement.
- Do NOT perform any live Nostr write (no signing, no relay publish) beyond the existing read-only NIP-07 reads.
- Do NOT make a payment or move real value — alpha sats are fake.
- Do NOT mark the MVP approved — only the user can, after running the live-browser playtest.
- Do NOT enable godMode or any debug capability in shipped runtime — godMode stays false.
- Do NOT add network calls, auto-update, or external redirects to the oversight surfaces.
Workflow invariants
- Do NOT cancel a useful in-progress job halfway through — finish it first, THEN process the user's next request. Cancelling useful work wastes compute time and money.
- Exception — explicit cancel: the user explicitly asks to cancel or abandon the job.
- Exception — immediate conflict: the running job conflicts with an immediate user request (e.g. it would clash with edits the new request needs now).
- Exception — safely resumable: the work can be safely resumed later from where it left off, so stopping loses nothing.
- Exception — stale/hung & already shipped: the job is stale or hung AND its output has already been committed, shipped, pushed, synced, and smoke-tested — stopping it only avoids further waste.
Operating principles
- Self-sovereignty: the user owns their identity (their npub) and their data; the project never holds the keys to a user.
- Consent first: nothing signs, publishes, pays, or navigates on the user's behalf without an explicit, informed action.
- Privacy by default: collect nothing by default; no surveillance, no tracking, no telemetry phoned home.
- Open protocols: build on Nostr, Bitcoin, and ecash so the user can leave and take their identity and value with them.
- Free and open source: the code is FOSS so anyone can read, fork, verify, and self-host it — no black boxes.
- No vendor lock-in: interoperable by design; data and identity stay portable across clients and relays.
- Local circular economics: favour voluntary, peer-to-peer value exchange over extractive, ad-funded, or rent-seeking models.
- No dark patterns: no manipulation, no coercive monetization, no engagement traps — the user stays in control.
- Reversible, user-controlled actions: prefer actions the user can undo and explicitly trigger over irreversible automatic ones.
- Community agency: tools should grow the community's capability to act for itself, not centralise control.
- Truthful status reporting: dashboards and handoffs report the real posture — a pass is never claimed without the evidence behind it.
EthicsThese are practical operating principles, not dogma: Torii Quest exists to give people self-sovereign, consent-driven freedom tech on open protocols (Nostr, Bitcoin, ecash) with no surveillance, no dark patterns, and no lock-in. When a decision is ambiguous, choose the option that keeps the user in control of their identity, data, and value, and that reports status truthfully.
Handoff / release control panel — the single read-only surface a fresh agent or human reads first to pick up the project safely: current version + live URLs, the latest app-entry and oversight-dashboard cloud smokes, the one manual blocker (the human must run the live-browser MVP playtest and explicitly approve), the next safe no-blocker task, the exact actions NOT to take without user input, the standing workflow invariants (e.g. finish a useful in-progress job rather than cancelling it), and the project's practical non-religious operating principles. GREEN means this surface is COMPLETE + trustworthy, NOT that the MVP is approved: a smoke pass is not approval, a dashboard pass is not a completed human playtest, and no live Nostr write is ever implied. It approves/releases/deploys/publishes NOTHING.
Ship readiness
READY GENERATED SHIP READINESS · LAST GATE · READ-ONLYThe last local release-readiness verdict (npm run release:status) and the next safe task to pick up — read-only; the gate stays the authority.
Next safe task ▸ Continue the read-only oversight loop — next safe infra/dashboard slice
Keep shipping no-runtime-risk tooling/docs that make AI handoff faster and the gate harder to get wrong (e.g. package the release:status verdict as a build artifact, or add a docs-freshness signal). SEC-gated live-relay / world-hop work stays parked behind SEC-1/2/3 and a manual deploy — not a safe pick yet.
| Signal | State | Detail |
|---|---|---|
| Version sync | ok | config v0.2.244-alpha / pkg 0.2.244-alpha |
| Test profiles | ok | fast 5 · foundation 25 file(s) |
| Regression gate | ok | 15 / 15 checks |
| Bundle baseline | advisory | advisory — over limit: rapier-DE6a0vmv.js |
| /zone/* fallback | ok | docs + dist ok |
| Docs consistency | ok | continuity docs carry current version |
The last local release-readiness verdict (run: npm run release:status) plus the recommended next SAFE task. Read-only oversight — it mirrors the gate, never runs a deploy/publish. GENERATED at packaging time from the live signals; LAST-KNOWN (last green gate) when not regenerated this build. The regression gate stays the authority. Verdict for v0.2.244-alpha @ 680dedd. Full gate: npm run test:release.
RC / release manifest
LOCAL GATES GREEN · MANUAL VALIDATION + APPROVAL PENDING GENERATED RC / RELEASE MANIFEST · LOCAL · READ-ONLYRelease-candidate artifact posture — manifest + RC-doc coverage, test count, and the manual validation still outstanding. Read-only; release/tag/publish stay manual + user-approved.
Source versionv0.2.244-alpha
Release manifest
- COMPLETE
- 6/6 required present
- 6/6 optional present
RC package docs7/7 present
Tests1686 passing / 102 files
Test profiles
- fast ~5
- foundation ~25
- full
Manual validation remaining7 live-browser checks pending
Last release gateREADY
Release-candidate artifact posture — the release-artifact MANIFEST (required/optional present) and RC package-doc coverage, the curated test count, the manual validation still outstanding, and the last local release-gate verdict, folded into one read-only band. GENERATED at packaging time from on-disk artifact presence; LAST-KNOWN when not regenerated this build. It releases/tags/publishes/deploys NOTHING — manual live-browser validation and explicit user approval stay required (run: npm run rc:snapshot / npm run release:manifest).
MVP approval
MVP APPROVAL PENDING · USER PLAYTEST + EXPLICIT OK REQUIRED GENERATED MVP APPROVAL · LOCAL · READ-ONLY · PENDING UNTIL EXPLICIT USER OKThe single auditable approval gate (MVP_APPROVAL_STATE.json). Local gates are green, but the MVP is NOT approved until a human runs the live-browser playtest and explicitly says "MVP approved". Read-only.
Approval statusPENDING
Versionv0.2.244-alpha
Approved byno approver yet
Approved at—
Next stepUser: run the live-browser MVP playtest, then explicitly say "MVP approved"
MVP approval state — the single auditable record (MVP_APPROVAL_STATE.json) of whether a human has EXPLICITLY approved the live-browser MVP. Local automated gates are green, but approval is a manual step: the user must run the playtest and say "MVP approved" (which also records approved_by + approved_at). Status stays PENDING until then and can never silently flip — there is no --approve path in the read-only CLI (npm run approval:state). GENERATED at packaging time from the on-disk record; LAST-KNOWN when not regenerated this build. It approves/releases/tags/publishes/deploys NOTHING.
MVP approval gate
CONFIDENCE GREEN · AWAITING EXPLICIT USER PLAYTEST + OK GENERATED MVP APPROVAL GATE · LOCAL · READ-ONLY · GREEN CHECKS ≠ HUMAN APPROVALThe rubric for sign-off. Automated tests, the release gate, and the cloud smokes are CONFIDENCE signals — green means the code and deployed surfaces look healthy, NOT that the MVP is approved. Approval is a separate explicit step: a human runs the live-browser playtest and says "MVP approved". Read-only.
Gate verdictawaiting-approval
Release gategreen (confidence only, not approval)
Entry smokegreen (confidence only, not approval)
Dashboard smokegreen (confidence only, not approval)
Test suitegreen — 1686 passing / 102 files
Explicit approvalPENDING — a human must run the live playtest and explicitly say "MVP approved"
How approval works
- Automated tests and cloud smokes are CONFIDENCE signals: green means the code and the deployed surfaces look healthy — it is NOT approval.
- MVP approval still requires an EXPLICIT human OK: a person (Chiefmonkey / the user) runs the live-browser playtest and says "MVP approved".
- A smoke pass is not MVP approval and a dashboard pass is not a completed human playtest — the gate stays PENDING until the explicit sign-off is recorded.
Manual playtest focus
- Entry flow: title screen loads, ENTER ARENA and LOGIN WITH NOSTR give visible feedback, pointer-lock engages.
- Shooter feel: the core shoot → hit → respawn loop feels responsive and fair.
- Hit registration / headshots: connecting shots register, and headshots vs body shots resolve as expected.
- Bot behaviour: bots move, react, take damage, die, and respawn without freezing or stalling.
- Movement / footsteps: WASD + jump are smooth, walls hold, and footstep feedback tracks motion.
- Reload feel: reload triggers, feels snappy, and refills ammo to the magazine size.
- Mirror / reflection: the mirror is coherent (no garble / recursion meltdown) and not a framerate sink.
- Crates: crates are solid under movement and fire and do not jitter, launch, or sink through the floor.
- NAP monkey: crossing the torii gate into the Non-Aggression zone disables the weapon and bots do not follow.
- Dashboard clarity: continuum.html renders the version, test status, and active slice clearly and matches the build.
- Subjective fun / feel: any game-feel blocker that makes the proof unconvincing, even if every automated check is green.
MVP approval gate — the rubric that keeps automated green from being mistaken for human game-feel approval. The automated tests, the release gate, and the two cloud smokes are CONFIDENCE signals: green means the code and the deployed surfaces look healthy, NOT that the MVP is approved. Approval is a separate, explicit step: a human (Chiefmonkey / the user) runs the live-browser playtest — judging entry flow, shooter feel, hit registration / headshots, bot behaviour, movement, reload, mirror, crates, the NAP monkey, dashboard clarity, and overall fun / feel — and then says "MVP approved", which records the approver and timestamp in MVP_APPROVAL_STATE.json. A smoke pass is not approval and a dashboard pass is not a completed playtest. This card approves/releases/deploys/publishes NOTHING.
Playtest results
PLAYTEST NOT RUN · NO RESULTS RECORDED YET GENERATED MVP PLAYTEST RESULTS · LOCAL · READ-ONLY · NOT RUN UNTIL TESTER RECORDS · NOT AN APPROVALWhether the actual manual playtest results have been recorded (MVP_PLAYTEST_RESULTS.md), and what they said. Ships blank → NOT RUN. A recorded result never implies approval — that stays a separate explicit user gate. Read-only.
Results statusNOT-RUN
Recordedno — results file still blank
Items
- 0 pass
- 0 fail
- 0 n/a
- 17 blank / 17
Implies approvalno — approval is a separate explicit user gate
Next stepUser: run the live-browser playtest, then record results in MVP_PLAYTEST_RESULTS.md
MVP playtest results state — read from the source-controlled MVP_PLAYTEST_RESULTS.md, the one place a tester records the actual manual live-browser playtest outcomes. It ships BLANK, so a fresh build reads NOT RUN. A recorded result is NECESSARY but NOT SUFFICIENT for MVP approval: even an all-PASS playtest still needs the explicit user "MVP approved" (the separate MVP-approval gate above). This card can never imply approval — approvalImplied is pinned false. GENERATED at packaging time from the on-disk file; LAST-KNOWN when not regenerated this build. It approves/releases/tags/publishes/deploys NOTHING.
Playtest verdict
NO VERDICT RECORDED YET LAST-KNOWN MVP PLAYTEST VERDICT · LOCAL · READ-ONLY · TESTER VERDICT ≠ MVP APPROVALThe one-line live-browser verdict: Chiefmonkey reports "MVP OK" or "blockers: …" in MVP_PLAYTEST_VERDICT.md. Every reported blocker stays visible here. A tester verdict is a confidence signal — it NEVER approves the MVP; approval is the separate explicit user step. Read-only.
Verdictpending (not reported)
Blockersnone reported
Reported by(not recorded)
How to report
- Report MVP OK (no blockers found): write a line `Verdict: MVP OK`.
- Report blockers: write a line `Verdict: blockers: <comma- or semicolon-separated list>`.
- Reporting a verdict NEVER approves the MVP — approval is the separate explicit step recorded in MVP_APPROVAL_STATE.json.
Focus to judge
- Entry flow: title screen loads, ENTER ARENA and LOGIN WITH NOSTR give visible feedback, pointer-lock engages.
- Shooter feel: the core shoot → hit → respawn loop feels responsive and fair.
- Hit registration / headshots: connecting shots register, and headshots vs body shots resolve as expected.
- Bot behaviour: bots move, react, take damage, die, and respawn without freezing or stalling.
- Movement / footsteps: WASD + jump are smooth, walls hold, and footstep feedback tracks motion.
- Reload feel: reload triggers, feels snappy, and refills ammo to the magazine size.
- Mirror / reflection: the mirror is coherent (no garble / recursion meltdown) and not a framerate sink.
- Crates: crates are solid under movement and fire and do not jitter, launch, or sink through the floor.
- NAP monkey: crossing the torii gate into the Non-Aggression zone disables the weapon and bots do not follow.
- Dashboard clarity: continuum.html renders the version, test status, and active slice clearly and matches the build.
- Subjective fun / feel: any game-feel blocker that makes the proof unconvincing, even if every automated check is green.
Implies approvalNO — a tester verdict is a confidence signal; approval is the separate explicit user OK in MVP_APPROVAL_STATE.json
MVP playtest verdict — the one-line capture for the live-browser playtest. Chiefmonkey (or the user) edits MVP_PLAYTEST_VERDICT.md to report ONE of "Verdict: MVP OK" or "Verdict: blockers: <list>". Every reported blocker stays visible here and in NEXT_ACTION_STATE.json so it can be fed back into todo/progress. A verdict of MVP OK means the tester found no blockers — it is NOT MVP approval: approval is the separate explicit user step (approved + approver + timestamp in MVP_APPROVAL_STATE.json). This card approves/releases/deploys/publishes NOTHING.
Manual validation
LOCAL GATES GREEN · MANUAL PLAYTEST + APPROVAL PENDING GENERATED MANUAL VALIDATION · MVP PLAYTEST · READ-ONLYLocal automated gates are green, but the MVP playtest is a human, live-browser task. This separates what is no-blocker (local gates) from what still needs manual input (the playtest + explicit approval). Read-only.
Local automated gates
- READY
- 15/15 local checks green
Manual playtest
- PENDING
- live-browser run + explicit user approval required
Playtest checklist
- 13 sections
- 17 items
Severity coverage
- 4 blocker
- 5 major
- 8 minor
Playtest docs
- checklist present
- results template present
Manual validation areas
- Launch / title screen
- Shooter loop
- Movement / footsteps
- Aim / hit feedback / headshots / body shots
- Reload feel
- Gun / reflection / mirror sanity
- Continuum dashboard + release/update prompt + Nostr read + gateway shell
Manual-validation / MVP-playtest readiness — the one thing the local automated gates can NOT prove. Local checks are green, but a human must still run the live-browser playtest (see the highest-level areas above) and explicitly approve before any release. GENERATED at packaging time from the playtest-checklist section/item/severity counts + on-disk doc presence; LAST-KNOWN when not regenerated this build. It releases/tags/publishes/deploys NOTHING (run: npm run playtest:checklist / npm run playtest:results to refresh the docs).
No-blocker queue
NO-BLOCKER WORK AVAILABLE · MANUAL PLAYTEST AWAITS USER GENERATED NO-BLOCKER QUEUE · SAFE NEXT WORK · READ-ONLYWhat an AI agent can pick up next WITHOUT user input — the next safe no-runtime-risk slice plus the active/next/archive queue, separated from the one item parked on the human (the MVP playtest + approval). Read-only.
Next safe taskContinue the read-only oversight loop — next safe infra/dashboard slice
Why safe
- infra
- no runtime risk
- no deploy
- no gate to unlock
Awaiting userMVP playtest + explicit approval (manual, live-browser) — the ONLY user-gated item
Active now50 in progress
Next up
- 12 queued
- next-12
Archive / done
- 11 landed clusters
- 27 done (24h)
- 12 struck markers
No-blocker queue — what an AI agent can pick up NEXT without any user input. The next safe task is a no-runtime-risk infra/docs/tooling slice (no deploy, no gate to unlock); the active/next/archive counts are DERIVED from the same parsed todo.md/progress.md the rest of the dashboard uses (no second source of truth). The ONLY thing waiting on a human is the MVP playtest + explicit approval (see the Manual validation card). GENERATED at packaging time; LAST-KNOWN when not regenerated this build. It queues/runs/deploys NOTHING.
Milestones
4The one true ACTIVE milestone vs. clearly-labelled SEED/future roadmap.
Total milestones: 4 — 1 active, 3 seed/future SEED · not yet tracked
15-hour proof-of-concept routeACTIVE
The one true ACTIVE milestone — the freedom-tech loop: gateway/NAP-to-NAP travel → Plebeian/Nostr product panel → leaderboard → torii.quest update-check.
- 5 tasks total
- 0 done
- 4 active
- 1 pending
Live relay I/O + event signingSEED · future
Gated by SEC-1/2/3 — explicit consent, handoff verification, and URL validation must clear before any wire write or live navigation.
Open-world NAP-to-NAP federationSEED · future
Real in-world portals plus a formalised NAP zone registry, beyond the inert travel preview.
Component / Plebeian market economySEED · future
A CMP component marketplace and real Plebeian.Market listings over the read-only product-panel shells.
One real ACTIVE milestone (its tasks are the 15-hour MVP slices, DERIVED from the route states); the rest are SEED/future milestones — labelled as such, not pretending to carry real task counts yet. Future hook: derive seed milestones from strategy.md.
At a glance
7Build truth: source version, test/gate status, and the headline progress rings.
Source versionv0.2.244-alpha (build truth; live trails — manual deploy)
Tests1686 passing / 102 files (profiles: test:fast ~5, test:foundation ~25)
Regression check15 / 15 GREEN
Bundle (advisory)~2.9 MB raw / ~1022 KB gzip (rapier chunk >700 KB, expected)
Gates
- SEC-1 / SEC-2 / SEC-3 intact
- godMode false
- continuum CSP enforced
Smoke (entry + dashboard)Both cloud smokes consolidated into the Handoff / release control panel at the top of this page — app-entry v0.2.230-alpha PASS 3/3, oversight-dashboard v0.2.231-alpha PASS 4/4. A smoke pass does not imply MVP approval or a completed human playtest.
Active slicev0.2.244 HOST-SAFE CANONICAL ZONE ROUTE (game slice) — fixes the v0.2.243 follow-up: the live rendered screenshot of /zone/plebeian-market-bazaar/ STILL showed the JSON 404 ("No static asset at /zone/plebeian-market-bazaar"). ROOT CAUSE: the published exact-path static host (torii-quest.pplx.app) has NO SPA rewrite and NO directory index and normalises BOTH /zone/<slug> AND /zone/<slug>/ to an exact static-asset lookup → 404, so EVERY /zone/* PATH strategy fails (v0.2.242 extensionless → octet-stream download; v0.2.243 directory-index shell → 404). Only the root / reliably serves index.html as text/html. FIX (no backend): the canonical zone route is now the URL FRAGMENT /#/zone/<slug> — the fragment is never sent to the server, so the request path is always / and the root shell ALWAYS renders on hard refresh; the client parser reads the fragment. zoneRouteFor + handoffRouteFor build /#/zone/<slug>; the portal allowlists are /#/zone/; main._applyZoneRoute reads the URL hash fragment (+ a hashchange listener) and falls back to the path for a LEGACY /zone/<slug> link, which the parser still resolves client-side (NON-CANONICAL: a cold /zone/* deep-link 404s before the bundle loads, so it is never generated/shared). No per-slug static shell is generated any more (the build step + tools/zoneShells.mjs + tools/generate-zone-shells.mjs were removed); the dist ships NO /zone/* file. Preserves the v0.2.240 service-worker fail-soft precache (HTML is network-first; the root / is always the cache key), the v0.2.238 fail-closed loop, and the v0.2.236 NIP-07 login decoupling; root entry flow + ENTER ARENA + ESC pause unchanged. Prior — v0.2.243 zone renderable trailing-slash shell (404d live, superseded); v0.2.242 zone exact-path extensionless shell (downloaded as octet-stream, superseded); v0.2.241 zone hard-refresh shell; v0.2.240 travel-gateway entry repair. HARD CONSTRAINTS held: godMode false; no new timers (loop uses rAF only); no new hot-path Vector3/Matrix4; nostrich comments; Chiefmonkey exact; debug tools ship unconditionally; non-religious ethics guard + useful-job invariant intact; no Nostr writes/signing beyond the existing login/read; no deploy/publish/push (parent handles those).
Contributors SEED · not live1 human · 3 clankers
Docs-derived DERIVED · build-time
- 12 completed task markers (todo.md)
- 12 next-12
- 11 archive clusters
12tasks ahead
50active
27done (24h)
11archive clusters
6tracks
0 / 5milestones
Engineering health
8The efficiency loop in numbers — each card chipped GENERATED or LAST-KNOWN.
Build version GENERATEDv0.2.244-alpha
Test files / profiles GENERATED
- fast 5
- foundation 25
- full 102
Total tests LAST-KNOWN1686 passing / 102 files
Profile timings LAST-KNOWN
- fast ~1s
- foundation ~6s
- full suite ~44s
Bundle baseline LAST-KNOWN2.9 MB raw / ~1022 KB gzip (rapier chunk >700 KB, expected)
Parser gaps GENERATED
- 0
- dashboard lists fully derived
Release gate LAST-KNOWN
- 15 / 15 regression checks GREEN
- last green v0.2.244-alpha
Source-of-truth docs GENERATED
- progress.md
- todo.md
- strategy.md carry this version
Engineering health — the efficiency/oversight loop: measure · profile · standardise · automate · modularise · document. GENERATED at build time where deterministic (profile sizes, parser gaps, version, doc-sync); LAST-KNOWN where captured from the most recent green release-gate run (total tests, timings, bundle).
Deployment readiness
READY DEPLOY READINESS · STATIC HOST · READ-ONLYStatic-host posture for the gateway /zone/* travel feature — repo-side prerequisites are checked locally; configuring the host + deploying stay manual.
| Check | State | Note |
|---|---|---|
| SPA /zone/* fallback documented | no-blocker | VPS_INSTALL.md + HANDOFF.md describe serving index.html for /zone/* deep-links |
| Built dist route shape | no-blocker | dist/index.html present; no static file under /zone/* shadows the fallback |
| Host SPA fallback configured | manual | serve index.html for unmatched paths on torii.quest — manual maintainer step, outside this repo |
| Auto-update | manual | none — the update-check is read-only and actionable:false; deploys stay a manual maintainer action |
Static-host deployment readiness for the gateway /zone/* travel feature. The repo-side prerequisites (docs describe the index.html SPA fallback; a built dist/ has index.html with no /zone/* file shadowing it) are verified LOCALLY by npm run zones:check / regression-check [15]. Configuring the real host fallback and deploying stay MANUAL maintainer steps — this surface only INFORMS.
Nostr read-path health
READ-ONLY OK NOSTR READ-PATH · READ-ONLYStatic, local proof that every Nostr path is read-only at the MVP stage and the live-write tier stays consent-gated — derived from the pure read helpers, no relay call.
| Signal | State | Detail |
|---|---|---|
| relay read model present | ok | read-only adapter exposes read() only; no publish/sign/send/connect/close |
| no EVENT publish verb in relay read path | ok | read verbs are [REQ, CLOSE] — no EVENT publish frame |
| profile read path present | ok | kind:0 READ→sanitise proven (1 profile); signed:false published:false |
| leaderboard read path present | ok | kind-30000 READ→rank proven (1 row); signed:false published:false |
| write paths disabled / consent gated | ok | 3 read action(s) allowed; 5 write action(s) blocked without explicit consent |
| SEC-1 / SEC-2 / SEC-3 still future-gated | ok | SEC-1 signer/publish write path deferred; 3 signed write action(s) gated |
Read-only invariants: signed:false · published:false · readOnly:true — 6/6 signals ok.
Nostr surface is read-only at the MVP stage; the live-write path (NIP-07 signer + relay publish, SEC-1) stays consent-gated and deferred.
Track overview
6Directional per-track completion — momentum, not archaeology.
Foundation / ARS71% · 5 / 7
ARS-4 (FSM fold) + ARS-6 (CODE_INDEX upkeep) open
Combat / Game-feel100% · 30 / 30
1 open edge (travel-time lead on moving targets)
Rapier / Physics100% · 5 / ~5 seams
ARS-3 raycast migration complete
SDK / API86% · 18 / ~21
player boundary lift + BotAgent runtime remain
Nostr / Open-world15% · 0 / 5+
read-paths + consent gate + travel chain + read-path health model proven; relays/signing deferred
Deployment / VPSn/a · —
source clean; live behind (manual deploy)
15-hour proof-of-concept route
5The active milestone's slices (LEAN-1..5) and what each still needs to ACT.
| # | Slice | Status |
|---|---|---|
| LEAN-1 | Torii.quest live (publish green source) | pending (manual smoke first) |
| LEAN-2 | Gateway / NAP-to-NAP travel | in-world PORTAL TRIGGER (181) + pure SPA /zone/<slug> ROUTE PARSER (182): proximity arms the injected boundary + prompt (inert), an explicit KeyF interact performs the confirmed same-origin hop, and the resulting /zone/ URL has a safe client-side read (home/zone/invalid → inert HUD notice). The static-host SPA fallback for hard-refresh deep links is now docs-explicit + locally checkable (v0.2.185 zones:check / regression [15]) and pinned end-to-end by the v0.2.197 host-route smoke (unknown /zone/<slug> → index.html, no built file shadows the fallback, slug kept safe); still needs a dedicated portal MESH and the host fallback configured on torii.quest itself |
| LEAN-3 | Plebeian/Nostr product panel | shells + visible preview; needs in-world mesh + real listing |
| LEAN-4 | Leaderboard (Nostr signed events) | unsigned helpers + publisher adapter + view + relay-read proof; needs real signer (SEC-1) + relay read |
| LEAN-5 | torii.quest GitHub update-check | helper + view-model + release source/status + static release-metadata template/spec (v0.2.192, npm run release:meta) + local install dry-run checklist (v0.2.193, npm run vps:dry-run) + update-flow smoke harness pinning the read-only/no-auto-update/confirmation-gated contracts (v0.2.196, ToriiDebug.shells.updateFlowSmoke); needs read-only releases fetch + prompt mesh |
Now · Next · Later
Active work, the archive of landed clusters, and what shipped in the last day.
NOW · Active 50
- v0.2.223 — MVP playtest results surfaced on the Continuum dashboard (buildPlaytestResultsCardModel/PLAYTESTRESULTS_LASTKNOWN/PLAYTESTRESULTS_BADGE + _playtestResultsSection in src/engine/dashboard/continuumData.js; live gather in tools/build-continuum.mjs; tests/continuum-dashboard.test.js): the Torii Continuum oversight dashboard now carries a compact Playtest results section placed BETWEEN the MVP-approval card and the Manual-validation card, so the page shows whether the actual MVP playtest has been RECORDED — not only that approval is pending. The new PURE, browser-safe buildPlaytestResultsCardModel(input?) renders the standard card shape (badge/kind/band/statusLabel/pill/metrics/note) over the v0.2.222 playtest-results state: status not-run / incomplete / attention / complete / unknown, recorded yes/no, item counts, any failing item ids, and a clear next step; it takes plain data (status/ran/total/pass/fail/na/blank/other/fails) and degrades to an honest PLAYTESTRESULTS_LASTKNOWN not-run fallback (kind:'last-known') with no input (never throws). tools/build-continuum.mjs reads MVP_PLAYTEST_RESULTS.md (read-only stat+read), re-shapes it through the pure summarizePlaytestForState model, and folds it via buildContinuumModel({playtestResults}); on any failure it degrades to the curated not-run card with a console note (no continuumData→tools import). approvalImplied is HARD-pinned false in EVERY branch — including a fully complete playtest — and the card carries an "Implies approval: no — approval is a separate explicit user gate" metric, so a recorded playtest can never, by itself, imply approval. It reuses the existing .metric/.pill markup (pill vocabulary manual/open-edge/no-blocker) so the continuum CSP + inline refresh-script hash are untouched, and every value is HTML-escaped. +8 tests (tests/continuum-dashboard.test.js; 1463→1471, files unchanged at 89): last-known not-run model, live not-run card with the clear next step, attention card with failing ids, complete NOT-AN-APPROVAL card with approvalImplied:false, pill vocabulary, continuumDataJSON carries playtestResults, renderContinuumPage shows the section/badge/pill, hostile tag-injection escaped + exactly one inline script + hash intact. DASHBOARD/DOCS/TOOLING-ONLY — status STAYS not-run/pending — no results fabricated, no MVP approval granted in this slice; no runtime/gameplay/physics/shooter/Rapier change; no Nostr signing/publishing/live network write; no network/deploy/publish/tag/release/self-update; godMode stays false; no new setTimeout/Vector3/Matrix4.
- v0.2.222 — MVP playtest results intake (tools/playtestResultsState.mjs pure module + CLI tools/playtest-results-status.mjs, npm run playtest:status + committed MVP_PLAYTEST_RESULTS.md; wired into tools/nextActionState.mjs/tools/next-action-state.mjs; tests/playtest-results-state.test.js + tests/next-action-state.test.js): a clean, source-controlled home for MANUAL MVP playtest outcomes instead of scattered notes. The committed MVP_PLAYTEST_RESULTS.md recording file ships with all 17 items across 13 sections blank (Result cells empty → reads not-run) and version/commit left blank so the tester records the build they actually tested — distinct from the build-regenerated, ephemeral MVP_PLAYTEST_RESULTS_TEMPLATE.md. The new PURE, node-safe tools/playtestResultsState.mjs exports summarizePlaytestForState/formatPlaytestResultsState + frozen PLAYTEST_RESULTS_STATE_SCHEMA(torii.playtest-results-state)/_SCHEMA_VERSION(1)/_BADGE/_FILE(MVP_PLAYTEST_RESULTS.md)/_STATUSES; it WRAPS the existing summarizePlaytestResults parser, accepts either raw results markdown OR a summary, and maps to statuses unknown (no items) / not-run (every item blank — the shipped default) / incomplete (some recorded, some blank) / attention (any FAIL) / complete (all PASS/N-A, no FAIL). approvalImplied is HARD-pinned false in EVERY branch — including a fully complete playtest — so the state can never, by itself, imply approval; a recorded playtest is necessary but NOT sufficient. The thin CLI tools/playtest-results-status.mjs reads/summarises the file read-only (text / --json), and under an explicit --write seeds a BLANK canonical record ONLY IF the file is absent (NO-CLOBBER — never destroys a tester's recorded results), the path confined in-repo via the shared resolveHandoffWritePath. The machine-readable next-action state now folds the file via summarizePlaytestForState (playtestResults added to NEXT_ACTION_STATE_REQUIRED_KEYS; the CLI gathers it from MVP_PLAYTEST_RESULTS.md through parsePlaytestResults+summarizePlaytestResults), and the text/markdown formatters print an MVP playtest: <status> (pending …; implies approval: no) line, so a next agent can see whether the human playtest was RECORDED without it ever implying approval. +1 new test file tests/playtest-results-state.test.js (11: constants, status mapping not-run/attention/incomplete/complete/unknown + accepts-text-or-summary, the never-implies-approval hard invariant, formatter null-safety, committed-artifact reads not-run) + 3 added tests/next-action-state.test.js cases (null→unknown + blank-summary→not-run with approvalImplied false; complete→still approvalImplied false; formatter prints the playtest line) → suite 1450→1463, files 88→89. DOCS/TOOLING-ONLY — read-only except the explicit no-clobber --write; status STAYS not-run/pending — no results fabricated, no MVP approval granted in this slice; no runtime/gameplay/physics/shooter/Rapier change; no Nostr signing/publishing/live network write; no network/deploy/publish/tag/release/self-update; godMode stays false; no new setTimeout/Vector3/Matrix4.
- v0.2.221 — MVP approval surfaced on the Continuum dashboard (buildMvpApprovalModel/MVPAPPROVAL_LASTKNOWN/MVPAPPROVAL_BADGE + _mvpApprovalSection in src/engine/dashboard/continuumData.js; live gather in tools/build-continuum.mjs; tests/continuum-dashboard.test.js): the Torii Continuum oversight dashboard now carries a compact, impossible-to-miss MVP approval section placed ABOVE the Manual validation card, derived from the v0.2.220 MVP_APPROVAL_STATE.json record — because the user previously MISSED the manual-validation card before going to test. The card shows status PENDING, the version, no approver ("no approver yet" / "—"), and the clear next step: the user must run the live-browser MVP playtest and explicitly say "MVP approved". The new PURE, browser-safe buildMvpApprovalModel(input?) renders the standard card shape (badge/kind/band/statusLabel/pill/metrics/note), takes plain data (status/approved/version/approvedBy/approvedAt), and degrades to an honest MVPAPPROVAL_LASTKNOWN pending fallback (kind:'last-known') with no input (never throws); tools/build-continuum.mjs reads the on-disk record and re-shapes it through buildApprovalState+summarizeApprovalForState (the strict isApproved() floor) before folding it via buildContinuumModel({mvpApproval}). Rendering approved is STRICT: only an exact approved status WITH the approved:true flag AND approved_by+approved_at renders as approved (band:'approved', pill:'no-blocker'); anything else stays PENDING (band:'pending', pill:'manual'), so a partial/garbled record can never look approved. It reuses the existing .metric/.pill markup so the continuum CSP + inline refresh-script hash are untouched, and every value is HTML-escaped. +7 tests (tests/continuum-dashboard.test.js; 1443→1450, files unchanged at 88): last-known pending model, live generated pending card with the clear next step, strict approved-only-with-provenance (partial + flag-only stay pending), pill vocabulary, continuumDataJSON carries mvpApproval, renderContinuumPage shows the section, hostile-input escape + script-hash intact. DASHBOARD/DOCS/TOOLING-ONLY — status STAYS pending — no MVP approval granted in this slice; no runtime/gameplay/physics/shooter/Rapier change; no Nostr signing/publishing/live network write; no network/deploy/publish/tag/release/self-update; godMode stays false; no new setTimeout/Vector3/Matrix4.
- v0.2.220 — MVP manual-approval state placeholder (tools/mvpApproval.mjs pure module + CLI tools/mvp-approval-state.mjs, npm run approval:state + MVP_APPROVAL_STATE.json; wired into tools/nextActionState.mjs/tools/next-action-state.mjs; tests/mvp-approval-state.test.js + tests/next-action-state.test.js): a clean, auditable single source to record MVP approval when the user explicitly approves — instead of hand-editing many docs or guessing. The PURE, node-safe tools/mvpApproval.mjs models a {kind:'torii.mvp-approval-state'/v1, status, version, commit, approved_by, approved_at, notes, safety{deploy/publish/push/tag/networkWrite/nostrWrite/godMode all false}} record and EXPORTS buildApprovalState/validateApprovalState/isApproved/formatApprovalState/summarizeApprovalForState + frozen MVP_APPROVAL_SCHEMA(torii.mvp-approval-state)/_SCHEMA_VERSION(1)/_BADGE/_FILE(MVP_APPROVAL_STATE.json)/_STATUSES/APPROVAL_REQUIRED_FIELDS(approved_by,approved_at). It is designed so it CANNOT silently approve: buildApprovalState coerces any status other than 'approved' to 'pending' and carries provenance verbatim (trimmed→null); validateApprovalState returns {ok,errors,warnings} and ERRORS on a wrong kind/schemaVersion/status, a bad version marker, a non-null/non-string commit, an APPROVED record missing any required provenance field or a version marker, OR a PENDING record that carries approver fields; isApproved is strict (status 'approved' AND validation ok). The committed MVP_APPROVAL_STATE.json defaults to pending (approved_by/approved_at/commit null, pending note, safety all-false, valid). The thin CLI tools/mvp-approval-state.mjs reads the record re-shaped through buildApprovalState (else a default pending for the current config version), renders text / --json, and under an explicit --write emits ONLY a PENDING record for the current version — there is deliberately NO --approve path in this slice. The machine-readable next-action state now folds the record via summarizeApprovalForState (mvpApproval:{status,approved,approvedBy,approvedAt,version} — mvpApproval added to NEXT_ACTION_STATE_REQUIRED_KEYS; the CLI gathers it from MVP_APPROVAL_STATE.json), and the text/markdown formatters print an MVP approval: line, so a FUTURE approval flips ONE state file rather than scattered docs. +1 new test file tests/mvp-approval-state.test.js (build coercion/defaults, validate safety floor, isApproved strictness, formatters, committed-artifact pending+valid+tracks VERSION) + 3 added tests/next-action-state.test.js cases (pending fold → approved:false; approved valid vs partial; unknown when no record) → suite 1417→1443, files 87→88. DOCS/TOOLING/DASHBOARD-ONLY — read-only except the explicit --write pending output; status STAYS pending — no MVP approval granted in this slice; no runtime/gameplay/physics/shooter/Rapier change; no Nostr signing/publishing/live network write; no network/deploy/publish/tag/release/self-update; godMode stays false; no new setTimeout/Vector3/Matrix4.
- v0.2.219 — Service-worker cache-version hygiene + guard (public/sw.js CACHE_VERSION; tools/regression-check.mjs [5] block): changed public/sw.js CACHE_VERSION from the static tq-v1 to a version-tracking tq-v0.2.219-alpha so every shipped version bump now mints a fresh service-worker cache name (torii-quest-tq-v0.2.219-alpha) and the existing activate handler purges the prior version's caches — no stale assets after an asset-changing deploy. HARDENED the regression-check [5] version-marker block with a guard that reads the CACHE_VERSION literal via regex and FAILS if it does not EMBED the current EXPECTED_VERSION (so it can never silently rot back to a static value like tq-v1; emits a public/sw.js CACHE_VERSION tracks v0.2.219-alpha pass line). Resolves the v0.2.217/v0.2.218 security-review advisory (non-blocking: public/sw.js CACHE_VERSION remained tq-v1). public/sw.js is copied VERBATIM by Vite (it lives in public/, no module system), so it cannot import config.js — CACHE_VERSION stays a hardcoded string literal kept in lockstep with the other version markers via the new guard, the same enforcement pattern as the package.json version. All install/activate/fetch/skipWaiting/clients.claim/old-cache-purge SW safety behavior is UNCHANGED, and the cache-first-for-assets / network-first-for-JS-CSS-HTML strategy is untouched. No test file added — the existing 15-check gate carries the guard, so the Vitest suite stays at 1417/87 (no CURRENT_TEST_STATUS/DEFAULT_TEST_STATUS numeric change). SERVICE-WORKER/TOOLING-ONLY — no runtime/gameplay/physics/shooter/Rapier change; no Nostr signing/publishing/live network write; no network/deploy/publish/tag/release/self-update; godMode stays false; no new setTimeout/Vector3/Matrix4.
- v0.2.218 — package.json privacy hygiene + guard (package.json "private": true; tools/regression-check.mjs [5] block): added "private": true to package.json so this static web-app/game can never be accidentally npm publish-ed, and HARDENED the regression-check [5] version-marker block with a guard that FAILS if package privacy is ever dropped (pkg.private !== true → fail; else a package.json is private pass line). Resolves the v0.2.217 security-review advisory (low risk: package.json lacked "private": true). The [5] block was refactored to read the whole pkg object once so both the version match and the privacy flag are checked from a single parse. No test file added — the existing 15-check gate carries the guard, so the Vitest suite stays at 1417/87 (no CURRENT_TEST_STATUS/DEFAULT_TEST_STATUS numeric change). PACKAGE-HYGIENE/TOOLING-ONLY — no runtime/gameplay/physics/shooter/Rapier change; no Nostr signing/publishing/live network write; no network/deploy/publish/tag/release/self-update; godMode stays false; no new setTimeout/Vector3/Matrix4.
- v0.2.217 — Machine-readable next-action state (buildNextActionState/formatNextActionState/formatNextActionStateMarkdown + frozen NEXT_ACTION_STATE_SCHEMA/_SCHEMA_VERSION/_BADGE/_WRITE_FILENAME/_REQUIRED_KEYS in tools/nextActionState.mjs; thin CLI tools/next-action-state.mjs, npm run handoff:next; tests/next-action-state.test.js): a compact machine-readable next-action/handoff state so an agent (GPT/Claude/DeepSeek/other) can pick up the safe MVP pipeline WITHOUT reading the whole repo. The PURE, node-safe buildNextActionState({agentHandoff,manualValidation,testStatus,docs,generatedAt}) FLATTENS the EXISTING buildAgentHandoff() export (itself a compose of buildHandoffSummary() + runMvpReadiness()) into one stable object — version/packageVersion/gitCommit/liveUrl, release{ready,gateStatus,gateCommand,blockers,regression{count,expected}}, readiness{pct,status}, tests{passing,files}, manualBlocker{pending,statusLabel,pill}, nextSafeTask{title,why,kind}, constraints[], docs[], reports[], and an all-false safety{deploy,publish,push,tag,networkWrite,nostrWrite,godMode} posture — NOT a second task list. The manual-blocker flag is DERIVED from the same buildManualValidationModel(...) pill (pill !== 'no-blocker') build-continuum.mjs already uses, so it can't drift; no manual card → pending:null (unknown). Null/garbled inputs degrade to honest nulls / gateStatus:'UNKNOWN' and never throw. The thin CLI does the fs/git I/O behind a realpathSync run-guard, modes text / --json / --markdown, and writes NEXT_ACTION_STATE.json ONLY under an explicit --write[=path] (confined in-repo via the SHARED resolveHandoffWritePath — absolute / .. rejected → exit 2); always exits 0 otherwise. +13 tests (tests/next-action-state.test.js; 1404→1417, files 86→87): constants frozen, assembly folds handoff+manual+test count, required keys ALWAYS present, no stale version vs config VERSION + CURRENT_TEST_STATUS, manual-blocker derivation pending/clear/unknown, all-false safety posture, degraded/garbled inputs, text/markdown/null-safe formatters. DASHBOARD/DOCS/TOOLING-ONLY — read-only except the explicit --write output; no runtime/gameplay/physics/shooter/Rapier change; no Nostr signing/publishing/live network write; no network/deploy/publish/tag/release/self-update; godMode stays false; no new setTimeout/Vector3/Matrix4.
- v0.2.216 — Continuum no-blocker queue card (buildNoBlockerQueueModel/NOBLOCKERQUEUE_LASTKNOWN/NOBLOCKERQUEUE_BADGE + _noBlockerQueueSection in src/engine/dashboard/continuumData.js; live gather in tools/build-continuum.mjs; tests/continuum-dashboard.test.js): the Torii Continuum oversight dashboard now surfaces a read-only No-blocker queue section just below the manual-validation card that answers, at a glance, WHAT AN AI AGENT CAN PICK UP NEXT WITHOUT USER INPUT — the next safe no-runtime-risk slice (SHIP_NEXT_SAFE_TASK: title/why/kind) plus the active/next/archive queue COUNTS — kept SEPARATE from the one item parked on the human (the live-browser MVP playtest + explicit approval). The new PURE, browser-safe buildNoBlockerQueueModel(input?) DERIVES the counts from the SAME taskTotals already parsed off todo.md/progress.md by tools/continuumParse.mjs (activeNow/next12/archiveClusters/completed24h/todoCompletedMarkers) — no second source of truth — folded in via buildContinuumModel({noBlockerQueue}) with a manualPending flag read off manualValidation.pill !== 'no-blocker'; with no input it degrades to an honest NOBLOCKERQUEUE_LASTKNOWN fallback (kind:'last-known') and never throws, mirroring the rc-status/manual-validation/ship/health builders. Band logic: manualPending → NO-BLOCKER WORK AVAILABLE · MANUAL PLAYTEST AWAITS USER (band:'safe-available', pill:'no-blocker'); else NO-BLOCKER WORK AVAILABLE (band:'safe-available-clear'). Six metrics: next safe task, why safe, awaiting user, active now, next up, archive/done. It reuses the existing .metric/.pill markup so the continuum CSP + inline refresh-script hash are untouched, and every value is HTML-escaped. +8 tests (tests/continuum-dashboard.test.js; 1396→1404, files unchanged at 86): last-known model shape (6 metrics, band/pill/statusLabel), live generated band separating safe vs user-gated, manual-clear variant (manualPending:false→safe-available-clear), invalid/omitted counts fall back to last-known, pill vocabulary, continuumDataJSON carries noBlockerQueue, renderContinuumPage shows the section, hostile-input escape + script-hash intact. DASHBOARD/DOCS/TOOLING-ONLY — no generator output-shape break; no runtime/gameplay/physics/shooter/Rapier change; no Nostr signing/publishing/live network write; no network/deploy/publish/tag/release/self-update; godMode stays false; no new setTimeout/Vector3/Matrix4.
- v0.2.215 — Continuum manual-validation / MVP-playtest readiness card (buildManualValidationModel/MANUALVALIDATION_LASTKNOWN/MANUALVALIDATION_BADGE + _manualValidationSection in src/engine/dashboard/continuumData.js; live gather in tools/build-continuum.mjs; tests/continuum-dashboard.test.js): the Torii Continuum oversight dashboard now surfaces a read-only Manual validation section just below the RC / release-manifest card that CLEARLY SEPARATES what is no-blocker (the LOCAL automated gates, green: READY · 15/15 local checks green) from what still needs manual input (the live-browser MVP playtest + explicit user approval, PENDING). It folds the playtest-checklist section/item counts (13 sections · 17 items), the blocker/major/minor severity tallies (4/5/8), the on-disk presence of the checklist + results-template docs, and the highest-level manual validation areas into one band. The new PURE, browser-safe buildManualValidationModel(input?) DERIVES this from existing helpers/constants (PLAYTEST_CHECKLIST_SECTIONS/playtestItemCount()/PLAYTEST_SEVERITIES from tools/playtestChecklist.mjs + the two playtest docs stat-ed on disk by build-continuum.mjs — cheap file-presence only, no crypto/git/network — and folded in via buildContinuumModel({manualValidation})) rather than duplicating gate logic; with no input it degrades to an honest MANUALVALIDATION_LASTKNOWN fallback (kind:'last-known') and never throws, mirroring the rc-status/ship/health builders. Band logic: checklist or results-template doc missing → PLAYTEST DOCS INCOMPLETE (gated); docs present + gate READY → LOCAL GATES GREEN · MANUAL PLAYTEST + APPROVAL PENDING (manual); else MANUAL VALIDATION OUTSTANDING (manual). It reuses the existing .metric/.pill markup so the continuum CSP + inline refresh-script hash are untouched, and every value is HTML-escaped. +8 tests (tests/continuum-dashboard.test.js; 1388→1396, files unchanged at 86): last-known model shape, live generated band separating automated vs manual, PLAYTEST DOCS INCOMPLETE on a missing doc, MANUAL VALIDATION OUTSTANDING on a non-green gate, pill vocabulary, continuumDataJSON carries manualValidation, renderContinuumPage shows the section, hostile-input escape + script-hash intact. DASHBOARD/DOCS/TOOLING-ONLY — no generator output-shape break; no runtime/gameplay/physics/shooter/Rapier change; no Nostr signing/publishing/live network write; no network/deploy/publish/tag/release/self-update; godMode stays false; no new setTimeout/Vector3/Matrix4.
- v0.2.214 — Continuum RC / release-manifest status card (buildRcStatusModel/RCSTATUS_LASTKNOWN/RCSTATUS_BADGE + _rcStatusSection in src/engine/dashboard/continuumData.js; live gather in tools/build-continuum.mjs; tests/continuum-dashboard.test.js): the Torii Continuum oversight dashboard now surfaces a read-only RC / release manifest section just below Ship readiness, folding the local release-candidate artifact posture into one band — current version, the release-artifact MANIFEST verdict (required/optional present), RC package-doc coverage, the curated test count + profile summary, how many MANUAL live-browser validation checks remain, and the last local release-gate verdict. The new PURE, browser-safe buildRcStatusModel(input?) DERIVES this from existing helpers/constants (release-manifest RELEASE_MANIFEST_REQUIRED/RELEASE_MANIFEST_OPTIONAL refs + RC_SNAPSHOT_DOC_REFS/RC_SNAPSHOT_MANUAL_VALIDATION, stat-ed on disk by build-continuum.mjs — cheap file-presence only, no crypto/git/network — and folded in via buildContinuumModel({rcStatus})) rather than duplicating gate logic; with no input it degrades to an honest RCSTATUS_LASTKNOWN fallback (kind:'last-known') and never throws, mirroring the ship/health builders. Band logic: any required artifact/RC doc missing → ARTIFACTS INCOMPLETE (gated); complete + gate READY → LOCAL GATES GREEN · MANUAL VALIDATION + APPROVAL PENDING (manual); else NEAR · LOCAL GATES (manual). It reuses the existing .metric/.pill markup so the continuum CSP + inline refresh-script hash are untouched, and every value is HTML-escaped. +7 tests (tests/continuum-dashboard.test.js; 1381→1388, files unchanged at 86): last-known model shape, live generated band, ARTIFACTS INCOMPLETE on a missing required artifact/RC doc, pill vocabulary, continuumDataJSON carries rcStatus, renderContinuumPage shows the section, hostile-input escape + script-hash intact. DASHBOARD/DOCS/TOOLING-ONLY — no generator output-shape break; no runtime/gameplay/physics/shooter/Rapier change; no Nostr signing/publishing/live network write; no network/deploy/publish/tag/release/self-update; godMode stays false; no new setTimeout/Vector3/Matrix4.
- v0.2.213 — Shell-less release tooling report discovery (tools/rc-snapshot.mjs + tools/release-package.mjs CLIs reuse selectRecentReports from tools/releaseManifest.mjs; tests/rc-snapshot.test.js + tests/release-package.test.js): the rc-snapshot and release-package CLIs' recent-report discovery no longer shells out to execSync('ls torii-v*-report.md 2>/dev/null'). The v0.2.212 release-manifest cleanup left these two tools still carrying the same hardcoded shell glob (a v0.2.212 security-review note — no injection vector, but cleaner/more portable as plain JS). Both recentReports() now call the SHARED pure selectRecentReports(readdirSync(ROOT)) — no child_process for discovery, deterministically sorted/capped, identical output; the helper is reused (not duplicated) so there is one source of truth across all three release tools. execSync stays imported in both only for read-only git (rc-snapshot: commit/status --porcelain/@{u}; release-package: commit stamp). +4 tests (tests/rc-snapshot.test.js, tests/release-package.test.js; 1377→1381, files unchanged at 86): each CLI's source no longer matches the execSync('ls …') glob and DOES import/use the shared helper. DOCS/TOOLING-ONLY — build-time CLI discovery + tests; no generator output-shape change; no runtime/gameplay/physics/shooter/Rapier change; no Nostr signing/publishing/live network write; no network/deploy/publish/tag/release/self-update; godMode stays false; no new setTimeout/Vector3/Matrix4.
- v0.2.212 — Release-manifest shell-less report discovery (selectRecentReports + RELEASE_MANIFEST_REPORT_RE/_CAP in tools/releaseManifest.mjs; tools/release-manifest.mjs CLI; tests/release-manifest.test.js): the release-manifest CLI's recent-report discovery no longer shells out to execSync('ls torii-v*-report.md 2>/dev/null'). A v0.2.211 security review SHIPPED but noted the hardcoded shell glob has no injection vector yet is cleaner/more portable as plain JS. The new PURE selectRecentReports(names, cap=RELEASE_MANIFEST_REPORT_CAP) filters names matching the exported RELEASE_MANIFEST_REPORT_RE (/^torii-v.*-report\.md$/), sorts them lexicographically for a deterministic order (matching the old ls default), and .slice(-cap) to the most recent (cap 6; a non-positive/garbled cap falls back to the default); it is null-safe and never throws. recentReports() in the CLI now calls selectRecentReports(readdirSync(ROOT)) — no child_process, identical output, fully unit-testable. execSync stays imported only for the read-only git rev-parse commit stamp. +5 tests (tests/release-manifest.test.js; 1372→1377, files unchanged at 86): report-shape filtering drops non-reports, deterministic sort regardless of input order, cap to the most recent, custom/garbled cap handling, and RELEASE_MANIFEST_REPORT_RE/_CAP exposure + null-safety (undefined/non-array/garbled entries → [], never throws). DOCS/TOOLING-ONLY — build-time CLI discovery + pure helper + tests; no generator output-shape change; no runtime/gameplay/physics/shooter/Rapier change; no Nostr signing/publishing/live network write; no network/deploy/publish/tag/release/self-update; godMode stays false; no new setTimeout/Vector3/Matrix4.
- v0.2.211 — Release artifact integrity manifest (tools/releaseManifest.mjs + CLI tools/release-manifest.mjs, npm run release:manifest + tests/release-manifest.test.js): a pure, node-safe, read-only manifest that records the RC package artifacts a future GitHub release / VPS self-update flow must verify, with present/missing status + stable sha256 checksums. The frozen RELEASE_MANIFEST_REQUIRED (RELEASE_NOTES_DRAFT.md, MVP_RELEASE_PACKAGE.md, GITHUB_RELEASE_DRY_RUN.md, public/release-metadata.json, package.json, index.html) + RELEASE_MANIFEST_OPTIONAL (RC snapshot, playtest checklist/results, handoff, VPS install, continuum-data) each carry {key,file,label,category}; the CLI reads each in-repo text doc / served build-metadata file, computes a sha256 + byte size via node:crypto, and injects a {present,sha256,bytes} map into buildReleaseManifestModel(inputs) → {schema:'torii.release-manifest'/v1, badge, title, manifest:true, status, complete, version, packageVersion, gitCommit, liveUrl, required[], optional[], missingRequired[], counts:{required,requiredPresent,requiredMissing,optional,optionalPresent,hashed}, notes[], latestReports[], safety (released/tagged/published/selfUpdated/served/wrote/network/hashedSecrets all false), rendered:false, actionable:false}. It bands COMPLETE iff every REQUIRED artifact is present (an unknown present flag is never treated as missing) else INCOMPLETE; an injected non-64-hex sha256 is rejected; checksums cover in-repo text docs + small served build-metadata JSON only — no secrets, no large binaries. Null/garbled inputs degrade to honest UNKNOWNs and never throw. formatReleaseManifest()/formatReleaseManifestMarkdown() render stable text/markdown (null-safe; 'release-manifest: (no manifest)' / '_(no manifest)_'). The thin CLI does the fs/git I/O (read-only git rev-parse), modes text / --json (schema torii.release-manifest v1) / --markdown; READ-ONLY except an opt-in bounded in-repo --write[=path] (default RELEASE_ARTIFACT_MANIFEST.md, confined via the SHARED resolveHandoffWritePath — absolute / .. rejected); always exits 0 (rejected --write path → exit 2) — VISIBILITY, not a gate (the authority stays npm run test:release). MANIFEST ONLY — creates no GitHub release, no git tag, no push, no deploy/publish/self-update, and reaches no network/server. DOCS/TOOLING-ONLY; read-only except the explicit --write output; no gameplay/physics/shooter/Rapier change; no Nostr signing/publishing/live network write; godMode stays false; no new setTimeout/Vector3/Matrix4. +14 tests (tests/release-manifest.test.js; 1358→1372, files 85→86; asserts every REQUIRED artifact exists on disk so a missing RC artifact is caught locally).
- v0.2.210 — MVP RC snapshot / freeze-candidate summary (tools/rcSnapshot.mjs + CLI tools/rc-snapshot.mjs, npm run rc:snapshot + tests/rc-snapshot.test.js): a pure, node-safe, read-only RC snapshot that COMPOSES the already-pure local verdicts — buildMvpRcGate() + runMvpReadiness() + buildGithubReleaseDryRunModel() + gatherReleaseReadiness() + the curated test counts + a present/missing map of every RC package doc — into ONE freeze-candidate document (MVP_RC_SNAPSHOT.md), re-deriving no check. buildRcSnapshotModel(inputs) → {schema:'torii.rc-snapshot'/v1, badge, title, snapshot:true, status, freezeCandidate, version, packageVersion, gitCommit, liveUrl, versionConsistency, rcGate, mvpReadiness, releaseDryRun, tests, regression, docs, advisories, manualValidation, releaseSteps, latestReports, safety (released/tagged/published/announced/served/navigated/wrote/network all false), rendered:false, actionable:false}; it bands FREEZE-CANDIDATE (RC gate is a candidate AND the dry-run is not blocked) / NEAR / BLOCKED, surfaces what STILL needs manual user validation and what cutting a real GitHub release/tag would require, and flags version drift across the folded sources via rcSnapshotVersionConsistency(). Null/garbled inputs degrade to honest UNKNOWNs and never throw. formatRcSnapshot()/formatRcSnapshotMarkdown() render stable text/markdown (null-safe; 'rc-snapshot: (no snapshot)' / '_(no snapshot)_'). The thin CLI does the fs/git I/O (read-only git rev-parse/status --porcelain/rev-parse @{u} — NO fetch), stat-s each RC doc for present/missing, lists recent torii-v*-report.md; modes text / --json (schema torii.rc-snapshot v1) / --markdown; it is READ-ONLY except an opt-in bounded in-repo --write[=path] (default MVP_RC_SNAPSHOT.md, confined via the SHARED resolveHandoffWritePath — absolute / .. rejected); always exits 0 (rejected --write path → exit 2) — VISIBILITY, not a gate (the authority stays npm run test:release). SNAPSHOT ONLY — creates no GitHub release, no git tag, no push, no deploy/publish/announce, and reaches no network/server. DOCS/TOOLING-ONLY; read-only except the explicit --write output; no gameplay/physics/shooter/Rapier change; no Nostr signing/publishing/live network write; godMode stays false; no new setTimeout/Vector3/Matrix4. +19 tests (tests/rc-snapshot.test.js; 1339→1358, files 84→85; asserts every referenced RC doc exists on disk so the doc list cannot silently rot).
- v0.2.209 — Generated commit-stamp clarity (tools/commitStamp.mjs + tools/agentHandoff.mjs/releasePackage.mjs/playtestChecklist.mjs/releaseNotes.mjs/githubReleaseDryRun.mjs/handoffSummary.mjs + tests/agent-handoff.test.js): the tracked generated artifacts (HANDOFF.generated.md, MVP_RELEASE_PACKAGE.md, MVP_PLAYTEST_CHECKLIST.md, RELEASE_NOTES_DRAFT.md, GITHUB_RELEASE_DRY_RUN.md) are written BEFORE the commit that will contain them, so the short commit they stamped was repo HEAD AT GENERATION — the PARENT of each file's own commit. Security reviews kept flagging a bare "commit"/"Git commit" label as cosmetic-but-stale/misleading. Added one shared pure helper (sourceCommitLabel → <hash> (source commit at generation — precedes this file's own commit)/(unavailable); sourceCommitInline → @ <hash> (source)/''; SOURCE_COMMIT_NOTE) and wired all five generator libs plus the handoff-summary brief to render the stamp with explicit non-misleading wording — inline @ <hash> (source) on the version line, and a dedicated Source commit: field (was Git commit:) in the handoff exports. tools/playtestResults.mjs deliberately UNTOUCHED (its Commit row is a human-filled intake prefill asserted verbatim in its test). +5 tests (1334→1339, files unchanged at 84): hash + "source commit" present, null/empty/garbled → (unavailable)/'', markdown uses Source commit: never Git commit:. No generator schema/output-shape change; affected artifacts regenerated so committed copies carry the honest wording. DOCS/TOOLING-ONLY; no runtime/gameplay/physics/shooter/Rapier change; no Nostr signing/publishing/live network write; no network/deploy/publish; godMode stays false; no new setTimeout/Vector3/Matrix4.
- v0.2.208 — Progress parser gap cleanup (tools/continuumParse.mjs deriveContinuumData() + tests/continuum-parse.test.js): closed the Continuum build-parser gaps the build logs flagged (activeNow: no usable items parsed from progress.md and completed24h: no usable items parsed from progress.md, which forced the dashboard to keep curated defaults). Root cause was the per-section tryList(key, items, {min,max}) bounds, not the parsing logic: progress.md's ## Active now / ## Completed last 24h are running logs (each shipped slice prepends an entry) that had grown past the original v0.2.174 guard ceilings — activeNow had 34 top-level bullets vs max:16, completed24h had 26 struck bullets vs max:24 — so both sections were dropped as gaps. The running-log format is intended, so per the work-order's "add parser tolerance with tests" option the bounds were RAISED (activeNow/completed24h max:60, archive max:40, next12 max:24) while KEEPING the protective guard — a >60-item garbled section still degrades to the curated default. After the fix npm run build:continuum derives all four lists from progress.md (next12 (12), activeNow (34), completed24h (26), archive (11); gaps: none). +2 tests (15→17): a long-but-bounded 34/26 parse with no gap, and an absurd 61-item list that still falls back. Pure build-time parser change only — no parser CALL site, schema, or dashboard render path changed. DOCS/TOOLING-ONLY; no gameplay/physics/shooter/Rapier change; no Nostr signing/publishing/live network write; godMode stays false; no new setTimeout/Vector3/Matrix4.
- v0.2.207 — GitHub MVP release dry-run checklist (buildGithubReleaseDryRunModel/formatGithubReleaseDryRun/formatGithubReleaseDryRunMarkdown in tools/githubReleaseDryRun.mjs + CLI tools/github-release-dry-run.mjs, npm run release:dry-run): a pure, node-safe LOCAL dry-run that validates the prerequisites for a FUTURE GitHub MVP proof release WITHOUT creating it. It folds a frozen 9-item prerequisite set (GITHUB_RELEASE_DRY_RUN_PREREQUISITES — version marker [gating], version↔package sync [gating], clean working tree [soft], pushed commit [soft], release-notes draft present [gating], release package present [gating], RC gate ready [gating], public live URL [gating], no autoUpdate/actionable release metadata [gating]) plus 3 known advisories (rapier bundle / SDK_DEBUG / alpha). The model carries {schema:'torii.github-release-dry-run'/v1, badge, title, dryRun:true, version, packageVersion, gitCommit, status('ready'/'near'/'blocked'), statusLabel, ready, prerequisites[] (each {key,label,gating,state∈ok/blocked/pending/unknown,detail}), missing[], advisories[], approvalGate, approvalRequired:true, futureCommands[] (git tag / git push / gh release — each note demands approval), safety (tagged/released/pushed/published/deployed/announced/served/navigated/wrote/network all false), rendered:false, actionable:false}; null/garbled inputs degrade to honest unknowns and never throw. Verdict: a gating prerequisite in blocked → BLOCKED; a gating unknown or a soft-pending (expected dirty tree / unpushed HEAD before the parent pushes) → NEAR; else READY — and even READY reads "READY (pending manual approval)" because the manual-approval gate is a standing always-shown requirement, never a scored item. The thin CLI stamps version (configVersion()) + package version + best-effort short commit + read-only git (git status --porcelain for clean-tree, git rev-parse HEAD vs @{u} for pushed — NO fetch) + the SHARED live URL + the release-metadata autoUpdate/actionable read; it builds with gateReady:null (the RC gate is deliberately NOT run by the tool, holding gate-ready at unknown→NEAR rather than over-claiming); modes text / --json (schema torii.github-release-dry-run v1) / --markdown; it is READ-ONLY except an opt-in bounded in-repo --write[=path] (default GITHUB_RELEASE_DRY_RUN.md, confined via the SHARED resolveHandoffWritePath — absolute / .. rejected); always exits 0 (rejected --write path → exit 2). DRY-RUN ONLY — it runs NO git tag, NO git push, NO gh release, NO deploy/publish/announce, and reaches NO network/server; the suggested future commands are TEXT ONLY and each carries an explicit "do not run without user approval". DOCS/TOOLING-ONLY; read-only except the explicit --write output; no gameplay/physics/shooter/Rapier change; no Nostr signing/publishing/live network write; godMode stays false; no new setTimeout/Vector3/Matrix4. +16 tests (tests/github-release-dry-run.test.js).
- v0.2.206 — MVP release package index (buildReleasePackageModel/formatReleasePackage/formatReleasePackageMarkdown in tools/releasePackage.mjs + CLI tools/release-package.mjs, npm run release:package): a pure, node-safe release-package INDEX generator producing a single discoverability artifact (MVP_RELEASE_PACKAGE.md) so humans and future agents can find every relevant MVP-proof file fast. The frozen RELEASE_PACKAGE_ENTRIES index (10 entries grouped by category) points at RELEASE_NOTES_DRAFT.md, MVP_PLAYTEST_CHECKLIST.md, MVP_PLAYTEST_RESULTS_TEMPLATE.md, HANDOFF.generated.md, HANDOFF.md, progress.md, todo.md, UPDATE_CHECK.md, VPS_INSTALL.md, ZONE_FALLBACK_READINESS.md, and folds in version/commit, the curated test-count, the live URL, the known non-blocking advisories, and the recommended next safe action. The model carries {schema:'torii.release-package'/v1, badge, title, index:true, version, gitCommit, liveUrl, tests, regression, entries[] (each {key,file,label,category,present}), advisories[], latestReports[], nextAction, safety (all false), rendered:false, actionable:false}; the present map is INJECTED by the CLI so the helper stays fs-free, and null/garbled inputs degrade to honest unknowns and never throw. formatReleasePackage()/formatReleasePackageMarkdown() render text/markdown grouped by category with a present/missing/unknown mark per file (null-safe). The thin CLI stamps version (configVersion()) + best-effort short commit + the SHARED live URL + the curated CURRENT_TEST_STATUS, stat-s each indexed file for present/missing, and lists recent torii-v*-report.md; modes text / --json (schema torii.release-package v1) / --markdown; it is READ-ONLY except an opt-in bounded in-repo --write[=path] (default MVP_RELEASE_PACKAGE.md, confined via the SHARED resolveHandoffWritePath — absolute / .. rejected); always exits 0 (rejected --write path → exit 2). INDEX ONLY — creates no GitHub release, no git tag, no public announcement, no deploy/publish, and reaches no network/server; NOT a gameplay change and not a live browser test. DOCS/TOOLING-ONLY; read-only except the explicit --write output; no gameplay/physics/shooter/Rapier change; no Nostr signing/publishing/live network write; godMode stays false; no new setTimeout/Vector3/Matrix4. +12 tests (tests/release-package.test.js).
- v0.2.205 — Playtest checklist doc warning cleanup (tools/playtestChecklist.mjs): cleared the non-blocking WARN from the v0.2.204 security review where two illustrative v0.2.203-alpha example strings (plus a dated (v0.2.203) authorship stamp in the file header) lingered in the checklist tooling's comments/examples and were re-flagged each review as "stale". Made them version-neutral so future security reviews stop tripping on them: the LAUNCH-1 expected version-label example now reads "matching the build (the current vX.Y.Z-alpha marker)", the buildPlaytestChecklistModel version input doc-comment now reads "config.js VERSION (a 'vX.Y.Z-alpha' marker)", and the file-header authorship stamp drops the bare (v0.2.203). Docs/comment cleanup ONLY — no behavior change, no CLI/schema/output change, and no new test file, so the suite count is unchanged at 1304/82 (the existing tests/playtest-checklist.test.js only asserts expected is a non-empty string, so the example wording is free to change). NON-GOALS held: no gameplay/physics/shooter/Rapier change; no Nostr signing/publishing/live network write; godMode stays false; no new setTimeout/Vector3/Matrix4.
- v0.2.204 — MVP manual playtest results intake template (buildPlaytestResultsTemplate/formatPlaytestResultsTemplate/formatPlaytestResultsTemplateMarkdown + parsePlaytestResults/summarizePlaytestResults/formatPlaytestResultsSummary in tools/playtestResults.mjs + CLI tools/playtest-results.mjs, npm run playtest:results): a pure, node-safe results-intake generator that gives a structured way to RECORD manual playtest results from the v0.2.203 MVP_PLAYTEST_CHECKLIST.md and feed failures back into todo/progress/handoff without ambiguity. The blank results template DERIVES its 17 items across 13 sections from PLAYTEST_CHECKLIST_SECTIONS (imported from tools/playtestChecklist.mjs), so it stays in lock-step with the checklist as the single source of truth — carrying build/version, commit, live URL, tester, date, environment + overall meta fields and per-item result (PASS/FAIL/N/A), severity, repro notes, screenshot/video refs and a recommended next action. The model carries {schema:'torii.playtest-results'/v1, badge, title, manual:true, version, gitCommit, liveUrl, resultValues:['PASS','FAIL','N/A'], severities[], howTo[], metaFields[], itemFields[], sections[] (each item id/title/severity/expected), itemCount, safety, rendered:false, actionable:false}; null/garbled inputs degrade safely and never throw. A tolerant pure parser/summary reads a COMPLETED results markdown back: parsePlaytestResults(text) → {items:[{id,result,raw}], total} (heading-anchored, reads the Result row's value cell, strips emphasis + parenthetical hints, never throws); summarizePlaytestResults() → {counts:{total,pass,fail,na,blank,other}, fails:[ids], verdict} with verdict EMPTY / INCOMPLETE / ATTENTION / COMPLETE (tolerates blanks). The thin CLI stamps version (configVersion()) + best-effort short commit + the SHARED live URL; modes text / --json (schema torii.playtest-results v1) / --markdown; it is READ-ONLY except an opt-in bounded in-repo --write[=path] (default MVP_PLAYTEST_RESULTS_TEMPLATE.md, confined via the SHARED resolveHandoffWritePath — absolute / .. rejected) plus a read-only --summarize[=path] (in-repo read only); always exits 0 (rejected --write/--summarize path → exit 2). RESULTS INTAKE ONLY — runs no browser, automates nothing, navigates/serves/deploys/publishes/writes (beyond the explicit --write) NOTHING; NOT a gameplay change and not a live browser test. DOCS/TOOLING-ONLY; read-only except the explicit --write output; no gameplay/physics/shooter/Rapier change; no Nostr signing/publishing/live network write; godMode stays false; no new setTimeout/Vector3/Matrix4. +16 tests (tests/playtest-results.test.js).
- v0.2.203 — MVP manual playtest acceptance checklist (buildPlaytestChecklistModel/formatPlaytestChecklist/formatPlaytestChecklistMarkdown in tools/playtestChecklist.mjs + CLI tools/playtest-checklist.mjs, npm run playtest:checklist): a pure, node-safe generator that emits a clear MANUAL playtest / MVP acceptance checklist for the user to run against the live build. It folds a frozen, hand-curated 13-area / 17-item checklist — launch/title; shooter loop; movement/footsteps; aim/hit-feedback/headshots/body-shots; reload feel; gun/reflection sanity; mirror sanity; crates/physics-nudge sanity; NAP monkey sanity; Continuum dashboard; release-metadata/update prompt; Nostr read surfaces; gateway portal/travel-confirm shell — where every item carries {id, steps[], expected, severity (blocker/major/minor), ifFailed} plus Result (PASS/FAIL/N/A) + Notes fields, a how-to preamble, and four known deferred/non-blocking advisories; purpose-built for future AI handoffs. The model carries {schema:'torii.playtest-checklist'/v1, badge, title, manual:true, version, gitCommit, liveUrl, severities[], howTo[], sections[] (deep-copied), itemCount, advisories[], safety:{automated/served/navigated/deployed/published/wrote/network all false}, rendered:false, actionable:false}; null/garbled inputs degrade safely and never throw. The thin CLI builds the model from configVersion()/gitCommit()/the SHARED live URL; modes text / --json (schema torii.playtest-checklist v1) / --markdown; it is READ-ONLY except an opt-in bounded in-repo --write[=path] (default MVP_PLAYTEST_CHECKLIST.md, confined via the SHARED resolveHandoffWritePath — absolute / .. rejected); always exits 0. MANUAL CHECKLIST ONLY — runs no browser, automates nothing, navigates/serves/deploys/publishes/writes (beyond the explicit --write) NOTHING; NOT a gameplay change and not a live browser test. DOCS/TOOLING-ONLY; read-only except the explicit --write output; no gameplay/physics/shooter/Rapier change; no Nostr signing/publishing/live network write; godMode stays false; no new setTimeout/Vector3/Matrix4. +15 tests (tests/playtest-checklist.test.js).
- v0.2.202 — MVP proof release-notes draft (buildReleaseNotesModel/formatReleaseNotes/formatReleaseNotesMarkdown in tools/releaseNotes.mjs + CLI tools/release-notes.mjs, npm run release:notes): a pure, node-safe DRAFT generator for the first MVP proof-of-concept candidate, based only on current local status/reports/docs. It FOLDS a frozen, hand-curated "what's built" narrative — shooter proof loop; Nostr read/profile/leaderboard proof surfaces; gateway travel shell; update/VPS readiness; Continuum dashboard; SDK/debug handoff surfaces; tests/guardrails; known non-blocking advisories — with the already-computed local verdicts: the runMvpReadiness() rollup (MVP pct/status), the buildMvpRcGate() candidate verdict (READY/NEAR/BLOCKED + pct + reasons), and the buildHandoffSummary() brief (version + latest reports). The model carries {schema:'torii.release-notes'/v1, badge, title, draft:true, version, gitCommit, liveUrl, candidate, readiness, sections[], advisories[], latestReports[], safety, rendered:false, actionable:false}; null/garbled inputs degrade to honest UNKNOWNs and never throw. The thin CLI composes gatherReleaseReadiness + runMvpReadiness + buildMvpRcGate + buildHandoffSummary; modes text / --json (schema torii.release-notes v1) / --markdown; it is READ-ONLY except an opt-in bounded in-repo --write[=path] (default RELEASE_NOTES_DRAFT.md, confined via the SHARED resolveHandoffWritePath — absolute / .. rejected); always exits 0. DRAFT ONLY — it creates no GitHub release, no git tag, no public announcement, no deploy/publish, and reaches no network/server. DOCS/TOOLING-ONLY; read-only except the explicit --write output; no gameplay/physics/shooter/Rapier change; no Nostr signing/publishing/live network write; godMode stays false; no new setTimeout/Vector3/Matrix4. +13 tests (tests/release-notes.test.js).
- v0.2.201 — MVP release-candidate gate (buildMvpRcGate/formatMvpRcGate/formatMvpRcGateMarkdown in tools/mvpRcGate.mjs + CLI tools/mvp-rc-gate.mjs, npm run rc:gate): a pure, node-safe read-only gate that answers ONE question — is this build ready to call an MVP proof-of-concept *release candidate*? It COMPOSES the existing readiness signals only (no re-derivation): the runMvpReadiness() rollup (Nostr read health / gateway-travel / update-flow / host-route smoke + version/meta/test/VPS/docs floor) and the gatherReleaseReadiness()→buildReleaseReadiness() fold (versionSync / tests / regression / zoneFallback / docs required signals, bundle advisory), with buildHandoffSummary() as the next-safe-task fallback. Verdict: READY iff release is ready AND the MVP rollup is green AND there are no release unknowns; BLOCKED if inputs are missing, a release blocker exists, or ≥2 MVP signals fail; else NEAR. pct blends passing MVP signals + the five required release signals; reasons lists release:<key> / mvp:<key>: <detail> / release:<key> (not checked this pass); nextTasks leads with Clear top blocker: … then the safe task, deduped + capped at 2. Every report pins served/deployed/published/navigated/released/tagged/wrote/network=false; null/garbled inputs degrade to an honest BLOCKED at 0% and never throw. The thin CLI runs gatherReleaseReadiness + runMvpReadiness + buildHandoffSummary, supports text / --json (schema torii.mvp-rc-gate v1) / --markdown; it is READ-ONLY/local/no-network, NEVER writes, creates no release, cuts no git tag, and always exits 0. INFRA/TOOLING-ONLY; no real release creation / git tag / GitHub release / deploy / network / server; read-only; no gameplay/physics/shooter/Rapier change; no Nostr signing/publishing/live network write; godMode stays false; no new setTimeout/Vector3/Matrix4. +14 tests (tests/mvp-rc-gate.test.js).
- v0.2.200 — Dashboard metric freshness cleanup (CURRENT_TEST_STATUS + testCountLabel() in src/engine/dashboard/continuumData.js): resolves the recurring stale LAST-KNOWN test-count issue noted in security reviews — HEALTH_LASTKNOWN.totalTests was a SECOND hand-maintained copy stuck at '1180 passing' while the suite was 1246/78, so the engineering-health "Total tests" metric and the metrics "Tests" row had drifted apart. Now a SINGLE curated source of truth CURRENT_TEST_STATUS {passing:1246, files:78, fastProfile:5, foundationProfile:25} + a testCountLabel(status?) helper (canonical "<passing> passing / <files> files", null/partial-safe) feed BOTH surfaces: HEALTH_LASTKNOWN.totalTests now DERIVES from testCountLabel() and the metrics "Tests" row renders testCountLabel() + the profile counts, so the two cannot diverge again. To catch FUTURE drift, a new tests/continuum-dashboard.test.js block ("test-count freshness — single source of truth", +5 cases) asserts the source is frozen + well-shaped; the curated files equals the REAL on-disk *.test.js count via readdirSync(tests/) (forces a bump when files are added/removed); testCountLabel() is correct + degrades safely on null/partial; BOTH displayed surfaces derive from the single source and totalTests no longer matches /1180/; and mvpReadiness.DEFAULT_TEST_STATUS (the separate readiness-rollup capture, bumped to 1246/78) agrees with CURRENT_TEST_STATUS — enforced by a cross-capture test WITHOUT cross-importing (keeps the dashboard↔status concerns split). INFRA/DASHBOARD/STATUS-DATA-ONLY; no gameplay/physics/shooter/Rapier change; no Nostr signing/publishing/live network write; godMode stays false; no new setTimeout/Vector3/Matrix4.
- v0.2.199 — Agent handoff readiness export (buildAgentHandoff/formatAgentHandoff/formatAgentHandoffMarkdown in tools/agentHandoff.mjs + CLI tools/agent-handoff.mjs, npm run handoff:agent): a pure, node-safe export that folds the EXISTING local status signals a NEXT agent — including non-Perplexity tools (DeepSeek/Perplexica/Routstr-style handoffs) — needs to continue the safe MVP pipeline WITHOUT reading the whole repo: version, live URL, gate verdict, regression + test-profile counts, latest reports, the standing hard constraints, the next SAFE task, the pure smoke-harness inventory, and the v0.2.198 MVP-readiness rollup (pct + status). It COMPOSES the existing buildHandoffSummary() brief + runMvpReadiness() rollup rather than re-deriving either, adding ONLY the frozen SMOKE_HARNESSES inventory (readHealth/gatewayTravelSmoke/updateFlowSmoke/hostRouteSmoke/mvpReadiness → SDK namespace + debug shell + live status pulled from the rollup signals) and the readiness pct/status the base summary lacked; null/garbled inputs degrade to honest UNKNOWNs and never throw. The thin CLI supports text / --json (stable schema torii.agent-handoff v1) / --markdown; it is READ-ONLY/local/no-network and never writes unless an explicit --write[=path] flag is given — that emits HANDOFF.generated.md (default), confined inside the repo via the SHARED resolveHandoffWritePath (absolute path / .. escape rejected) and NEVER touching the curated HANDOFF.md. INFRA/DOCS/TOOLING-ONLY; read-only except the explicit --write output; no gameplay/physics/shooter/Rapier change; no Nostr signing/publishing/live network write; godMode stays false; no new setTimeout/Vector3/Matrix4. +13 tests (tests/agent-handoff.test.js).
- v0.2.198 — MVP release-readiness rollup (runMvpReadiness/formatMvpReadiness in src/engine/status/mvpReadiness.js): a pure, node-safe read-only rollup that folds the already-pure local readiness signals into ONE verdict with an MVP percentage/status + next safe task, so the user can see how close the read-only MVP proof is WITHOUT manually digging through every harness, doc, and gate. NINE signals — version marker valid (VERSION is a valid vX.Y.Z[-tag]); Nostr read-path health (runReadHealth().ok); gateway travel smoke (runGatewayTravelSmoke().ok); update-flow smoke (runUpdateFlowSmoke().ok); host-route smoke (runHostRouteSmoke().ok); release-metadata safety floor (validateReleaseMeta(buildReleaseMeta()) valid AND a tampered autoUpdate:true REJECTED); the injected last-known test-suite verdict (DEFAULT_TEST_STATUS 1246/78, override via opts.tests); the injected VPS manual-deploy dry-run verdict (DEFAULT_VPS_DRY_RUN, override via opts.vpsDryRun); the injected docs/handoff freshness verdict (DEFAULT_DOCS_STATUS, override via opts.docs) — fold into {version,badge,ok,mvpPct,status,currentVersion,signals,summary,safety,reasons,nextSafeTask,rendered:false,actionable:false}. The four live smoke verdicts are computed from the already-pure harnesses; the fs-backed signals (test counts, VPS dry-run, docs freshness) are INJECTED via opts with curated last-known defaults — exactly like the dashboard ship/health models — so the module stays PURE + node-safe (no THREE/Rapier/DOM/window/location/fs/child_process/network/socket). mvpPct = share of passing signals (0..100); status = READY (all green) / NEAR (one short) / ATTENTION (≥2). Every report pins served/deployed/published/navigated/performed/fetched/wrote/network=false; every check is wrapped, so a broken injected fixture degrades to a fail with concrete reasons and the rollup never throws. Surfaced via the SDK (mvpReadiness, EXPERIMENTAL), the debug shell (ToriiDebug.shells.mvpReadiness / mvpReadinessReport() folded into buildShellReport). INFRA/DASHBOARD/TOOLING-ONLY; read-only — serves/deploys/fetches/writes NOTHING; no gameplay/physics/shooter/Rapier change; no Nostr signing/publishing/live network write; godMode stays false; no new setTimeout/Vector3/Matrix4. +14 tests (tests/mvp-readiness-rollup.test.js).
- v0.2.197 — Host-route + asset smoke harness (runHostRouteSmoke/formatHostRouteSmoke in src/engine/host/hostRouteSmoke.js): a pure, node-safe read-only smoke harness that folds the torii.quest static-host route + asset readiness contracts into ONE fail-fast report so future VPS/static-host work can be regression-checked locally without a server, shell, or network. TEN signals — root index.html present in the dist path set; the DIST_SPEC.expectedArtifacts (index.html+assets) present; the /continuum.html dashboard asset present; the release-metadata.json update asset present; the REQUIRED_FILES floor documented; the /zone/* SPA fallback documented in VPS_INSTALL.md/HANDOFF.md (reuses checkFallbackDocs); NO built file shadows the /zone/<slug> fallback (zonePathsInDist empty); an unknown /zone/<slug> is served index.html by host config while NOT a built file; the app route parser keeps the slug SAFE (parseZoneRoute→ZONE, isValidZoneSlug true) and rejects the whole HOSTILE_ZONE_PATHS fixture (absolute scheme / protocol-relative / dot-dot / sub-path / uppercase+underscore / empty slug / percent-encoding / javascript:); and no host-side action (every exercised report pins served/deployed/navigated/performed/external/network/wrote/fetched=false and exposes NO serve/deploy/publish/upload/fetch/write/navigate/exec/spawn/run/ssh/connect CALLABLE) — fold into {version,badge,ok,signals,summary,safety,reasons,rendered:false,actionable:false}. It composes only the already-pure readiness helpers (zoneFallbackReadiness, zoneRoute, releaseMeta) over deterministic LOCAL fixtures (SAMPLE_DIST_PATHS/SAMPLE_FALLBACK_DOCS/HOSTILE_ZONE_PATHS) — it serves/deploys/touches NOTHING and never reaches a server or the wire; every check is wrapped, so malformed injected input degrades to a fail and the harness never throws. Surfaced via the SDK (hostRouteSmoke, EXPERIMENTAL), the debug shell (ToriiDebug.shells.hostRouteSmoke / hostRouteSmokeReport() folded into buildShellReport). INFRA/TESTING/TOOLING-ONLY; NOT a VPS deployment — touches no real server/DNS/SSH/remote command/network; no gameplay/physics/shooter/Rapier change; no Nostr signing/publishing/live network write; godMode stays false; no new setTimeout/Vector3/Matrix4. +17 tests (tests/host-route-smoke.test.js).
- v0.2.196 — Update-flow smoke harness (runUpdateFlowSmoke/formatUpdateFlowSmoke in src/engine/update/updateFlowSmoke.js): a pure, node-safe read-only smoke harness that folds the shipped torii.quest / VPS self-update contracts into ONE fail-fast report so future self-update work can be regression-checked locally without a browser, shell, package manager, or network. TEN signals — current version read (VERSION is a valid marker); release metadata shape parses (selectLatestRelease → usable release); a strictly-newer release → update-available; a same/older release → up-to-date; every MALFORMED_PAYLOADS entry (null / number / string / {} / draft / empty list) degrades to UNKNOWN without throwing; the in-game status panel/view are manual-only (readOnly:true, actionable:false, MANUAL badge); the release-metadata safety floor REJECTS a tampered autoUpdate:true (reuses validateReleaseMeta); none of the read-only outputs (panel/view/meta/evaluation) expose a fetch/install/update/apply/exec/spawn/run/download/write/navigate/sign/publish/deploy CALLABLE; apply-update is confirmation-gated (evaluateConsent('update:apply', …) — no grant → blocked/CONSENT_REQUIRED, a grant → allowed/CONSENT_GRANTED but STILL performed:false); no auto action (every exercised report pins performed/actionable/autoUpdate/installed/executed/fetched/network/signed/published/navigated=false, read path synchronous) — fold into {version,badge,ok,signals,summary,safety,reasons,rendered:false,actionable:false}. It composes only the already-pure helpers over deterministic LOCAL fixtures (SAMPLE_NEWER_FEED/SAMPLE_CURRENT_RELEASE/MALFORMED_PAYLOADS) — it fetches/installs/applies NOTHING and never reaches the wire; every check is wrapped, so malformed injected input degrades to a fail and the harness never throws. Surfaced via the SDK (updateFlowSmoke, EXPERIMENTAL), the debug shell (ToriiDebug.shells.updateFlowSmoke / updateFlowSmokeReport() folded into buildShellReport). INFRA/TESTING/TOOLING-ONLY; NOT an updater — performs no real update; no gameplay/physics/shooter/Rapier change; no Nostr signing/publishing/live network write; godMode stays false; no new setTimeout/Vector3/Matrix4. +17 tests (tests/update-flow-smoke.test.js).
- v0.2.195 — Gateway travel smoke harness (runGatewayTravelSmoke/formatGatewayTravelSmoke in src/engine/gateway/travelSmoke.js): a pure, node-safe read-only smoke harness that folds the shipped gateway travel-flow contracts into ONE fail-fast report so future portal/travel feature work can be regression-checked locally without a browser. TEN signals — trigger arms on proximity; proximity ALONE never navigates; explicit confirm required to act; hop targets a same-origin /zone/<slug> route only; the route allowlist is scoped (never '/'); a valid /zone/<slug> resolves; the HOSTILE_ROUTES fixture (traversal / percent-traversal / protocol-relative / absolute scheme / javascript: / uppercase-slug / sub-path) is all rejected as INVALID; no external gateway website is carried into the hop; consent gates travel (no grant → blocked, a grant → allowed but still never performed); no auto travel/write (every exercised report pins navigated/performed/external/signed/published/network=false) — fold into {version,badge,ok,signals,summary,safety,reasons,rendered:false,actionable:false}. It drives the boundary with dryRun:true and NO injected transport, so even a fully-confirmed confirm() is a dry-run no-op that navigates NOTHING; every check is wrapped, so malformed injected input degrades to a fail and the harness never throws. Surfaced via the SDK (travelSmoke, EXPERIMENTAL), the debug shell (ToriiDebug.shells.travelSmoke / travelSmokeReport() folded into buildShellReport). INFRA/TESTING/TOOLING-ONLY; no gameplay/physics/shooter/Rapier change; no Nostr signing/publishing/live network write; godMode stays false; no new setTimeout/Vector3/Matrix4. +12 tests (tests/gateway-travel-smoke.test.js).
- v0.2.194 — Nostr read-path health model + dashboard panel (runReadHealth/formatReadHealth in src/engine/nostr/readHealth.js + buildReadHealthModel in src/engine/dashboard/continuumData.js): a pure, node-safe read-only health model that folds the shipped read-path proofs into ONE report confirming the Nostr surface is still READ-ONLY at the MVP stage and every live-write path stays consent-gated. SIX signals — relay read model present (read-only {read} adapter, no publish/sign/send/connect/close); no EVENT publish verb in the relay read path (RELAY_READ_VERBS=['REQ','CLOSE']); kind:0 profile read path; kind-30000 leaderboard read path; write paths consent-gated (reads allowed / writes blocked without a grant); SEC-1/SEC-2/SEC-3 still future-gated — fold into {ok,badge,signals,summary,readOnly:true,signed:false,published:false,errors}. It EXERCISES only the already-pure read helpers over deterministic LOCAL sample events + reads the consent registry — NO relay I/O, NO WebSocket, NO signing, NO publishing, NO NIP-07, NO key handling, NO network; every signal pins signed:false/published:false/readOnly:true and degrades safely on null/empty input. Surfaced via the SDK (nostrReadHealth, EXPERIMENTAL), the debug shell (ToriiDebug.shells.readHealth / readHealthReport()), and a new Nostr read-path health Torii Continuum panel (buildReadHealthModel maps each signal onto the existing pill vocabulary → continuum CSP/script-hash untouched). TOOLING/DASHBOARD-ONLY; no live Nostr writes/signing/EVENT publishing/relay network/user-key handling; no gameplay/portal/physics/controls change. +16 tests (tests/nostr-read-health.test.js) + 7 dashboard-panel tests.
- v0.2.193 — VPS install dry-run checklist (runVpsDryRun/formatVpsDryRun in tools/vpsDryRun.mjs + npm run vps:dry-run / tools/vps-dry-run.mjs): a local, read-only readiness checklist an operator runs BEFORE deploying torii.quest to a VPS/static host, with NO SSH, network, DNS, or server change. The pure helper REUSES the shipped pure guards — validateReleaseMeta() for the manual-only/non-actionable floor and fallbackEvidence() for the /zone/* SPA fallback — and folds 11 checks: required deploy docs present; dist/ (if built) carries index.html (+ the copied release-metadata.json); public/release-metadata.json present + manual-only/non-actionable; metadata + UPDATE_CHECK.md point at the real repo ChiefmonkeyArt/torii-gate; the /zone/* SPA fallback documented; VPS_INSTALL.md build/manual-update/rollback/security sections; the npm run build/npm run check commands documented; rollback + manual/no-auto-update wording; the service-worker stance documented; live URL references clear. The thin CLI (text default; --json) reads local files only and prints a clear pass/fail/warn/skip checklist; it exits non-zero ONLY on a blocking FAIL (warnings + the skipped dist/ row never fail) and is deliberately NOT wired into npm run check (standalone operator tool). Documented in VPS_INSTALL.md §13 (+ the §9 service-worker caveat). TOOLING/DOCS-ONLY; no deploy, no SSH/DNS/server change, no gameplay/portal/physics/controls/Nostr change. +43 tests (tests/vps-dry-run.test.js).
- v0.2.192 — GitHub release/update metadata (buildReleaseMeta/validateReleaseMeta in tools/releaseMeta.mjs + npm run release:meta / tools/release-meta.mjs): prepares the static metadata a FUTURE torii.quest / VPS update-checker reads to surface an inert "update available" notice, with NO live update and NO runtime network. The pure helper shapes {kind, schemaVersion, channel (derived from the version tag), version, commit, documentation-only GitHub source URLs, dist artifact expectations, requiredFiles/requiredChecks, manual/no-auto-update consent + notice wording}. validateReleaseMeta() is the SAFETY FLOOR — update.autoUpdate and update.actionable MUST be false or it ERRORs, so the no-auto-update contract is machine-enforced. The thin CLI (text default; --json; --write emits the DETERMINISTIC public/release-metadata.json so re-runs never churn the tree; --stamp bakes live commit/time for a deploy step) is local/read-only/network-free, ALWAYS exits 0, and writes only the in-repo safe path under an explicit --write. Spec mirrored into UPDATE_CHECK.md §5 + VPS_INSTALL.md §12. TOOLING/DOCS-ONLY; no live update execution, no gameplay/portal/physics/controls/Nostr change. +23 tests (tests/release-meta.test.js).
- v0.2.191 — stale-doc detector (detectStaleDocs in tools/staleDocs.mjs + npm run docs:stale / tools/stale-docs.mjs): a new ADVISORY detector that catches docs/status/version drift earlier and more clearly than the gated docConsistency guard. The pure helper reuses the docConsistency primitives (CONTINUITY_DOCS/findVersionMarkers/versionInText) and flags precise version-HEADER drift in each continuity doc, a continuity doc that never mentions the current version, a newest report no continuity doc links to, a newest report that lags the current version, and disagreeing test counts across the continuity docs. Low false positives by design: a HEADER assertion requires ONLY separator/markup chars between "version" and the marker, and backtick/double-quote spans are stripped first, so changelog prose ("version drift fixed (v0.2.137)") and quoted examples are ignored. The thin CLI (text default; --json) is local/read-only/network-free and ALWAYS exits 0 — ADVISORY, deliberately NOT wired into npm run check (the hard gate stays docConsistency [14], so the finer/higher-recall signals are surfaced, not enforced — keeping false positives from blocking safe dev). TOOLING/DOCS-ONLY; no gameplay/portal/physics/controls/Nostr change. +25 tests (tests/stale-docs.test.js).
- v0.2.190 — handoff auto-summary (buildHandoffSummary in tools/handoffSummary.mjs + npm run handoff:summary / tools/handoff-summary.mjs): a pure helper folds the existing local status/readiness inputs into ONE concise brief for the next agent/model — version, git commit, live URL, the current gate verdict (consumed from the releaseReadiness summary via gatherReleaseReadiness(); no check re-implemented), regression + test-profile counts, latest reports, the recommended next SAFE task, the standing key constraints, and the exact release-verify commands. The thin CLI prints text by default, with --json (stable schema torii.handoff-summary v1), --markdown, and an opt-in --write[=path] (the ONLY writer — read-only/local/network-free otherwise). Deterministic generatedAt (optional + isolated, omit → null for tests); garbled/missing release input → honest unknown gate; never throws. TOOLING/DOCS-ONLY; no gameplay/portal/physics/controls/Nostr change. +13 tests (tests/handoff-summary.test.js).
- v0.2.189 — release-readiness JSON export (buildReleaseStatusJson in tools/releaseReadiness.mjs + a --json flag / npm run release:status:json in tools/release-readiness.mjs): the local readiness verdict can now be consumed by the dashboard/handoff/updater/agents WITHOUT parsing the human terminal block. The pure buildReleaseStatusJson(summary,{generatedAt}) wraps a buildReleaseReadiness() summary in a stable envelope (RELEASE_STATUS_SCHEMA='torii.release-status' / RELEASE_STATUS_SCHEMA_VERSION=1) carrying status/statusLabel/ready/blockers/unknowns/version/packageVersion/gitCommit/signals/latestReports. Deterministic by design — generatedAt is the ONLY non-deterministic field, OPTIONAL + isolated (omit → null, fully reproducible for tests; the CLI passes a real ISO stamp at print time). A missing/garbled summary (incl. arrays) degrades to an honest status:'unknown'/error:'no-summary' envelope; never throws, never mutates the source arrays/signals. The CLI --json path prints JSON.stringify(...) to stdout and exits 0 — pure parseable JSON (node tools/release-readiness.mjs --json is pure JSON; plain npm run prepends a lifecycle banner to stdout, so scripted consumers use npm run --silent release:status:json) — while the default human block + the realpathSync run-guard are unchanged. TOOLING/DOCS-ONLY + read-only/local-only/no network; no gameplay/portal/physics/controls/Nostr change. +7 tests (tests/release-readiness.test.js).
- v0.2.188 — dashboard SHIP-READINESS + NEXT-SAFE-TASK (buildShipModel + _shipSection in engine/dashboard/continuumData.js; live verdict fed by tools/build-continuum.mjs via the new reusable gatherReleaseReadiness in tools/release-readiness.mjs): the Torii Continuum now surfaces the LAST local release-readiness verdict (npm run release:status) AND the recommended NEXT SAFE task as a first-class Ship readiness section. The pure, browser-safe buildShipModel({readiness,nextTask}) folds the EXISTING releaseReadiness summary (version sync, test profiles, the 15-check regression gate, advisory bundle, /zone/* fallback, docs consistency) into a render-ready {badge,statusCommand,gateCommand,kind,status,statusLabel,ready,version,gitCommit,signals[],blockers[],unknowns[],nextTask,note} model: an overall status pill, a six-row per-signal table (reusing the existing pill vocabulary — no-blocker/gated/manual/deferred — so _shipSection adds NO new CSS), and a highlighted next-safe-task block (a no-runtime-risk infra/docs slice, DISTINCT from the SEC-gated next12[0]). kind is GENERATED (live verdict folded this build) or LAST-KNOWN (curated SHIP_LASTKNOWN fallback) via the engineering-health provenance chip; never throws. tools/release-readiness.mjs was refactored to export gatherReleaseReadiness(root) so build-continuum.mjs folds the SAME live signals without duplicating fs/git I/O (CLI behaviour unchanged via a realpathSync run-guard). continuumDataJSON now carries ship. DASHBOARD/TOOLING-ONLY + INERT: server-rendered escaped text, NO new <script> and no new data-k key → CSP/XSS guard + the v0.2.172 refresh-script sha256 intact; no network, no deploy/publish, no gameplay/portal/physics/controls/Nostr change. SDK continuum auto-exports buildShipModel/SHIP_BADGE/SHIP_LASTKNOWN/SHIP_NEXT_SAFE_TASK via export *. +10 tests.
- v0.2.186 — deployment-readiness VISIBILITY (buildReadinessModel + _readinessSection in engine/dashboard/continuumData.js; real verdict fed by tools/build-continuum.mjs): the v0.2.185 /zone/* static-host fallback verdict is now a first-class Deployment-readiness section in the Torii Continuum (data model + visible page), so project oversight shows the VPS/static-host posture at a glance. The pure, node-safe buildReadinessModel({zoneFallback}) folds the read-only checkZoneFallbackReadiness({docs,dist}) result into a render-ready {badge,status,statusLabel,checks,errors,warnings,note} model with honest states — READY (docs ok + dist checked) / DOCS READY · BUILD CHECK PENDING (docs ok, no build yet) / NOT READY (a required doc/dist shape fails) / NOT CHECKED (no input) — and a four-row per-check table (SPA fallback documented, built dist route shape, host fallback configured = MANUAL, auto-update = MANUAL). It NEVER throws (no input → honest NOT-CHECKED) and each check state reuses the existing pill vocabulary (no-blocker/gated/manual/deferred) so the renderer adds NO new CSS. tools/build-continuum.mjs reads the required docs + walks dist/ at packaging time (absent → dist check SKIPPED — honest, since build:continuum runs before vite build; regression-check [15] is the authoritative dist check) and passes the real verdict in; with no override the curated NOT-CHECKED model ships. continuumDataJSON now carries readiness. DASHBOARD/TOOLING-ONLY + INERT: server-rendered escaped text, NO new <script> and no new data-k key, so the v0.2.172 refresh-script sha256 still matches — CSP/XSS guard intact; no server access/SSH/credentials, no deploy/publish/upload, no auto-update, no navigation/runtime/gameplay change. SDK continuum auto-exports buildReadinessModel/READINESS_BADGE via export *. +8 tests.
- v0.2.184 — LEAN-2 portal/zone state CLARITY (engine/gateway/zoneLabel.js pure label helpers, wired at the main.js composition root): the surgical polish that tells a player WHERE the portal goes and WHAT they entered, without touching the navigation-safety model. portalPromptLabel({slug|route|title, key}) builds a target-aware proximity prompt ("Press F to travel to Plebeian Market Bazaar"), falling back to the generic "Press F to travel" when no target is known; enteredZoneLabel(input, {prefix}) builds the concise post-hop notice ("Entered: Plebeian Market Bazaar"), returning '' for an unknown/empty target. Both DERIVE their human text from the safe slug via the v0.2.182 humanizeZoneSlug (alnum by construction); any free-form/hostile string is run through an internal allowlist sanitiser ([A-Za-z0-9 -], length-capped) so no markup/dangerous token can survive even though the HUD sink is textContent. In main.js the trigger's promptText is the target-aware label, and the KeyF handler shows the entered-notice ONLY when the v0.2.180 confirm() report comes back navigated:true with a string zoneId (pushState does not fire popstate, so the existing route-applier never refreshed it). DISPLAY-ONLY + INERT: no network/relay/sign/publish/external nav/payments/auto-update/confirmation bypass — proximity still ARMS, KeyF still CONFIRMS, route stays same-origin /zone/ only. SDK zoneLabel (experimental) + read-only ToriiDebug.shells.zoneLabel(opts?) (label preview + a safe flag proving hostile input is stripped). +15 tests. Remaining (documented): the static-host SPA rewrite for /zone/* hard-refresh and the signed/relay-mediated SEC-2 tier stay outstanding/gated.
- v0.2.183 — LEAN-2 in-world GATEWAY PORTAL marker (engine/gateway/portalMeshPlan.js pure plan + engine/gateway/portalMesh.js browser adapter, built at the main.js composition root): the visible landmark that finally lets a player SEE the travel point the v0.2.181 trigger arms. buildPortalMeshPlan({position, range, title}) is PURE/node-safe — it turns the trigger geometry into a plain-data description of four inert marker parts (an outer ring whose radius EQUALS the proximity range, an inner accent ring, a faint translucent beam, and a slow-spinning core), every part + the plan pinning navigated/performed/external/signed/published false and readOnly:true/actionable:false. The browser-only adapter consumes an ok plan and a scene to build a small set of emissive MeshStandardMaterial meshes exactly once behind a _built guard; tickPortalMesh(dt) advances the idle animation by mutating only scalars (rotation.y, emissiveIntensity) so the no-allocation hot-path rule holds (no Vector3/Matrix4/geometry/material per frame); disposePortalMesh() frees the GPU resources for a clean teardown. DISPLAY-ONLY + INERT: no collider, no raycast/click/input, no navigation/relay/sign/publish — the safety model is unchanged (proximity ARMS, KeyF CONFIRMS, same-origin /zone/ only). SDK portalMeshPlan (experimental) + read-only ToriiDebug.shells.portalMeshPlan() (plan report) and ToriiDebug.shells.portalMesh() (render state). +18 tests. Remaining (documented): the static-host SPA rewrite for /zone/* hard-refresh and the signed/relay-mediated SEC-2 tier stay outstanding/gated.
- v0.2.182 — LEAN-2 pure SPA /zone/<slug> ROUTE PARSER (engine/gateway/zoneRoute.js, read at the main.js composition root): the safe client-side read of the same-origin URL state the v0.2.181 portal hop pushes, so a refresh/deep-link on /zone/* is no longer brittle. parseZoneRoute(path) runs the route through the v0.2.179-hardened safeRoutePath first (rejects dot-dot/percent/protocol-relative/js-scheme/data-scheme/markup/control/whitespace/over-length → INVALID), strips a trailing ?query/#hash, then classifies HOME (root / or any non-/zone/ same-origin path), ZONE (a strict slug — lowercase alnum words joined by single hyphens, ≤64 chars), or INVALID (sub-path /zone/a/b, malformed slug, hostile, non-string). A valid zone maps to an INERT display state (title/zoneId/route/notice); navigated/performed/external/signed/published/network are all pinned false — it interprets a URL, never acts. The module is pure/node-safe with no module-scope browser global; main.js reads the browser location pathname once on startup and on popstate, showing an inert HUD #zone-notice for a zone/invalid route and hiding it on home (showZoneNotice/hideZoneNotice, lazy opacity-crossfade, no setTimeout). Hard-refresh deep-link still needs a static-host SPA fallback (serve index.html for /zone/*) — DOCUMENTED in HANDOFF.md/GATEWAY_PROTOCOL.md, NOT faked in app code. SDK zoneRoute (experimental) + read-only ToriiDebug.shells.zoneRoute(). +28 tests. Remaining (documented): a dedicated portal MESH + the static-host SPA rewrite rule are the next steps; the signed/relay-mediated SEC-2 tier stays gated and not live.
- v0.2.181 — LEAN-2 in-world gateway PORTAL TRIGGER (engine/gateway/portalTrigger.js, wired at the main.js composition root): the surgical bridge that finally makes the v0.2.180 portal boundary ACT from gameplay, without a broad rewrite. A pure, node-safe createPortalTrigger({boundary, component, context, portalPos, range, onPrompt}) returns a per-frame tick(playerPos) that uses withinPortalRange (scalar squared-distance, no Vector3) to ARM the injected v0.2.180 boundary and raise a HUD prompt when the player nears the torii gate — both inert (no navigation; onPrompt fires only on range transitions). Leaving range cancel()s the staged portal; reset() clears a stale prompt on pause/leave. The ONLY navigating step is an explicit interact(grant) (host-bound to KeyF), which delegates to boundary.confirm() → the v0.2.178 confirmed:true → consent → scoped-allowlist gates → a same-origin /zone/<slug> hop. In main.js the real browser window is injected once into createGatewayPortalBoundary (composition root, never module scope); the allowlist is hard-scoped ['/zone/']; external website URLs are never navigated. A bottom-centre HUD prompt (showPortalPrompt/hidePortalPrompt, lazy opacity-crossfade like the NAP pill, no setTimeout). SDK portalTrigger (experimental) + read-only ToriiDebug.shells.portalTrigger() over an in-memory recording host (proves far→no-arm, near→arm-inert, interact→confirmed hop). +18 tests. Remaining (documented): a dedicated portal MESH + an SPA route handler (so the /zone/<slug> URL resolves on refresh) are the next step; the signed/relay-mediated SEC-2 tier stays gated and not live.
- v0.2.180 — LEAN-2 in-world gateway portal activation seam (engine/gateway/gatewayPortalActivation.js): the surgical bridge from a gateway component to the v0.2.178 confirmed same-origin hop, built as pure helpers + an injected-transport controller (no broad rewrite). portalActivationInput(component, context) maps the gateway's internal target → a /zone/<slug> activation input and deliberately drops any external website (the hop is same-origin route only — an external profile URL is never built into the input and never navigated). sanitizePortalAllowlist(list) folds a trivially-permissive ['/'] (or any all-garbage list) to the scoped default ['/zone/'], so the boundary can never be permit-everything. createGatewayPortalBoundary(opts) is an injectable arm → confirm controller: the browser window/transport/host is captured once at construction (never module scope), arming is inert (no navigation), and only confirm(grant) resolves the transport and delegates to activateGatewayHandoff with confirmed:true. activatePortalHandoff(...) is the one-shot form, and withinPortalRange(a,b,r) is a scalar squared-distance proximity helper (no Vector3/Matrix4). No NIP-07/signing/keys/payments/relay writes/auto-update/external nav/popup-windows/dynamic-code-eval; SEC-2 signed/relay-mediated tier untouched and not live. SDK gatewayPortalActivation (experimental) + read-only ToriiDebug.shells.gatewayPortalActivation() over an in-memory recording host. +28 tests. Remaining blocked step (documented): there is no in-world portal MESH/proximity trigger yet, so main.js is intentionally NOT auto-wired to navigate — the seam is ready for a host to inject the real window and call arm/confirm from a future mesh pass.
- v0.2.179 — LEAN-2 gateway route hardening (safeRoutePath in engine/gateway/handoffPlan.js + _routeAllowed in engine/gateway/gatewayActivation.js): a focused security-review follow-up before any live gateway wiring. safeRoutePath now additionally rejects any .. dot-dot traversal segment AND any % percent-encoding — closing /zone/../admin + /zone/%2e%2e/admin climb-out attempts (the current surface is closed because targetRoute is built internally by handoffRouteFor/_zoneSlug, which only emit [a-z0-9-], so /zone/foo still passes; this is defense in depth before portal wiring). The activation routeAllowlist now ignores trivially-permissive prefixes shorter than 2 chars, so a ['/'] allowlist fails closed (matches nothing) rather than silently allowing every same-origin route; meaningful prefixes like ['/zone/'] are unaffected. Pure/node-safe, never navigates; godMode stays false. +5 tests.
- v0.2.178 — LEAN-2 gateway handoff activation (engine/gateway/gatewayActivation.js): the confirmed same-origin host transport is now live-wired into the v0.2.168 executor. resolveHostTransport(source) turns an injected transport / a window (history.pushState) / a recording host into a usable transport without navigating, and activateGatewayHandoff(input,grant,opts) only resolves + drives it after three ordered gates — a literal confirmed:true, the consent-gated dry-run plan being ok, and an optional same-origin route allowlist — so any preview/render/unconfirmed path can never navigate. A failed navigate rolls back to the rollback route (back-home); external/worldReloaded/signed/published/network stay false. Reachable read-only via ToriiDebug.shells.gatewayActivation() over an in-memory recording host. +25 tests.
- v0.2.177 — dashboard layout/readability pass (DASHBOARD-LAYOUT-1; renderContinuumPage in continuumData.js): a visual-hierarchy + scannability pass on /continuum.html — the ACTIVE-milestone headline is promoted above At-a-glance; every section gains a one-line lead caption + a _h2(title,count) heading row with an item-count chip; the Now/Archive/Done columns reflow on a responsive auto-fit grid (no hard 3→1 jump) and show live counts; spacing/typography tightened (wider main, more section separation, subtle card hover). DERIVED/GENERATED/LAST-KNOWN/SEED chips stay visible. No new <script>/asset; CSP/refresh-script hash unchanged. A larger visual redesign remains a future follow-up.
- v0.2.176 — milestone + layout pass (buildMilestoneModel + SEED_MILESTONES in continuumData.js): a build-time, static, read-only Milestones section on /continuum.html surfaces the 15-hour MVP route as the one true ACTIVE milestone — the leanRoute slices ARE its tasks, folded into DERIVED counts (5 total / 0 done / 4 active / 1 pending) + a directional 46% complete progress bar — alongside clearly-labelled SEED future milestones (honest total: 1 active + 3 seed, never pretending the seeds carry real task counts). Grouped card values (health, docs-derived) now render as bullet lists via _cardValueHtml, not dense ·-separated prose. No new <script>; CSP/refresh-script hash unchanged. Follow-up: DASHBOARD-LAYOUT-1 (design dashboard layout/formatting better).
- v0.2.175 — engineering health metrics (buildHealthModel in continuumData.js + tools/build-continuum.mjs): a build-time, static, read-only Engineering health section on /continuum.html surfaces the efficiency loop (measure · profile · standardise · automate · modularise · document) — profile/test-file counts, parser-gap count, version + doc-sync GENERATED at build; total tests, profile timings, bundle baseline, last-green gate LABELLED last-known. CSP/refresh-script hash unchanged; page stays fully static/read-only.
- v0.2.174 — dashboard data automation (tools/continuumParse.mjs + tools/build-continuum.mjs): the continuum page now DERIVES its next-12 / active-now / completed-24h / archive lists + a docs-derived task-count metric from progress.md + todo.md at build time, falling back to the curated continuumData.js defaults (with parser-gap reporting) on any miss. CSP unchanged; page stays fully static/read-only.
- ARS-4 — finish folding reload/pointer-lock into the guarded FSM.
- ARS-6 / PROGRESS-1 — ongoing CODE_INDEX + living-docs upkeep.
LATER · Archive 11
- v0.2.169 — progress-dashboard rewrite (this file). Compact bars/percentages/badges/totals, 24h struck-through completions, concise archive. Docs/tooling only.
- v0.2.159–168 — gateway-travel chain + Nostr read foundation. Read-only NIP-01 relay-read foundation → leaderboard/profile/gateway-destination read proofs → consent-gate foundation → leaderboard submit + gateway travel-confirm intents → consent UX view-model → dry-run handoff plan → first same-origin travel executor (injected transport). All PURE & INERT; never navigates/signs/publishes/writes network.
- v0.2.153–158 — infra/handoff tooling + update-check source. Bundle-size baseline [13], doc-consistency guard [14], AI-handoff status snapshot (npm run handoff:status); GitHub release-check source + in-game update-status panel (host-only injected fetcher, no auto-update).
- v0.2.147–152 — proof-surface pipeline. Pure spec layer → spec↔registry cross-check → anchor→transform contract → first display-only in-world mesh pass → parent binding → promotion/regression GATE (regression check [12]). All inert; no click/raycast/navigation.
- v0.2.144–146 — docs + review symmetry. VPS_INSTALL.md self-hosting guide; SDK_DEBUG_INDEX.md + shells.summary(); shells.diff() preview→live promotion checklist.
- v0.2.138–143 — MVP loop made visible. Pivot to the 15-hour PoC route; four inert title-screen preview cards (gateway/product/leaderboard/update) + MVP-loop header; LEAN-5 update-check architecture. Rendered via textContent only.
- v0.2.134–137 — lean-MVP foundation. Gateway Protocol draft + travelIntent; CMP-13 product display; LB-1 leaderboard helpers; CMP-7 registry; gateway/portal/panel view shells; HARD-1..4 hardening + shellReport.
- v0.2.131–133 — SDK + components. src/sdk/index.js entrypoint + stability tiers; component contract + manifest spec; first reference component (toriiGateway); ARS-3 raycast migration; real GAMEOVER edge.
- v0.2.120–130 — foundation & test harness. Vitest added; event bus + FSM slices; ToriiDebug snapshot/report; pure physics/raycast/combat seams; HANDOFF.md.
- v0.2.114–119 — decoupling. Player/combat math extracted; foliage/mirror/bot-hit globals moved onto the event bus / module registries.
- v0.2.100–113 — reconciliation & game-feel (2026-06-23). Source reconciled by concern; physics SDK seams; regression batch (hit-reg, head-zone, reload, barrel→crosshair aim); CSP + avatar-URL hardening.
DONE · Last 24h 27
- v0.2.207 — GitHub MVP release dry-run checklist (buildGithubReleaseDryRunModel/formatGithubReleaseDryRun/formatGithubReleaseDryRunMarkdown in tools/githubReleaseDryRun.mjs + CLI tools/github-release-dry-run.mjs, npm run release:dry-run): a pure, node-safe LOCAL dry-run that validates the prerequisites for a FUTURE GitHub MVP proof release WITHOUT creating one. Folds a frozen 9-item prerequisite set (version marker/version↔package sync/clean tree/pushed/release-notes draft/release package/RC gate/live URL/no-autoUpdate metadata) + 3 known advisories into {schema:'torii.github-release-dry-run'/v1, dryRun:true, status(ready/near/blocked), prerequisites[], missing[], approvalRequired:true, futureCommands[] (INERT TEXT), safety (all false), rendered:false, actionable:false}; the CLI reads version/package/short-commit + READ-ONLY git (status --porcelain, rev-parse @{u} — no fetch) + the release-metadata autoUpdate read, modes text/--json/--markdown, READ-ONLY except an opt-in bounded --write[=path] (default GITHUB_RELEASE_DRY_RUN.md). DRY-RUN ONLY — no git tag, no push, no gh release, no deploy/publish/announce, no network; suggested commands are text-only each carrying "do not run without user approval". DOCS/TOOLING-ONLY; godMode false; no new setTimeout/Vector3/Matrix4. +16 tests.
- v0.2.206 — MVP release package index (buildReleasePackageModel/formatReleasePackage/formatReleasePackageMarkdown in tools/releasePackage.mjs + CLI tools/release-package.mjs, npm run release:package): a pure, node-safe release-package INDEX generator emitting a single discoverability artifact (MVP_RELEASE_PACKAGE.md) so humans and future agents can find every MVP-proof file fast. A frozen 10-entry index (grouped by category) points at the release-notes draft, playtest checklist/results template, handoff docs, progress/todo, update/VPS docs, and zone-fallback readiness, folding in version/commit, the curated test-count, the live URL, the known non-blocking advisories, and the next safe action. The present map is INJECTED by the CLI (helper stays fs-free); modes text / --json (schema torii.release-package v1) / --markdown; READ-ONLY except an opt-in bounded in-repo --write[=path]. INDEX ONLY — no GitHub release / git tag / announce / deploy / publish / network. DOCS/TOOLING-ONLY; godMode false; no new setTimeout/Vector3/Matrix4. +12 tests.
- v0.2.205 — Playtest checklist doc warning cleanup (tools/playtestChecklist.mjs): cleared the non-blocking WARN from the v0.2.204 security review where two illustrative v0.2.203-alpha example strings (plus a dated (v0.2.203) authorship stamp) lingered in the checklist tooling's comments/examples and were re-flagged each review as "stale". Made them version-neutral (the LAUNCH-1 expected example + the buildPlaytestChecklistModel version doc-comment now read "a vX.Y.Z-alpha marker"; the header stamp drops the bare (v0.2.203)) so future reviews stop tripping on them. Docs/comment cleanup ONLY — no behavior/CLI/schema/output change and no new test file. NON-GOALS held: no gameplay/physics/shooter/Rapier change; no Nostr signing/publishing/live network write; godMode stays false; no new setTimeout/Vector3/Matrix4.
- v0.2.193 — VPS install dry-run checklist (runVpsDryRun/formatVpsDryRun in tools/vpsDryRun.mjs + npm run vps:dry-run): a pure helper + thin CLI give an operator a local, read-only readiness checklist to run BEFORE deploying torii.quest to a VPS/static host — NO SSH, network, DNS, or server change. REUSES the shipped pure guards (validateReleaseMeta() for the manual-only floor, fallbackEvidence() for the /zone/* fallback) and folds 11 checks: required deploy docs; dist/ (if built) carries index.html (+ copied release-metadata.json); public/release-metadata.json present + manual-only; metadata + UPDATE_CHECK.md point at the real repo ChiefmonkeyArt/torii-gate; /zone/* fallback documented; VPS_INSTALL.md build/manual-update/rollback/security sections; build/verify commands documented; rollback + manual/no-auto-update wording; service-worker stance documented; live URL refs clear. Text default; --json; local/read-only/network-free; exits non-zero ONLY on a blocking FAIL (warn/skip never fail); NOT in npm run check (standalone operator tool). Documented in VPS_INSTALL.md §13 + §9. TOOLING/DOCS-ONLY; no deploy/SSH/DNS/server/gameplay/portal/physics/controls/Nostr change. +43 tests.
- v0.2.192 — GitHub release/update metadata (buildReleaseMeta/validateReleaseMeta in tools/releaseMeta.mjs + npm run release:meta): a pure helper + thin CLI prepare the static metadata a FUTURE torii.quest / VPS update-checker reads to show an inert "update available" notice, with NO live update and NO runtime network. Shapes channel (from the version tag)/version/commit/doc-only GitHub source URLs/dist artifact expectations/requiredFiles+Checks/manual+no-auto-update consent wording; validateReleaseMeta enforces the safety floor (update.autoUpdate + actionable MUST be false → ERROR otherwise). Text default; --json; --write the DETERMINISTIC public/release-metadata.json; --stamp for live provenance. Local/read-only/network-free; ALWAYS exits 0; writes only the in-repo safe path under --write. TOOLING/DOCS-ONLY; no live update execution. +23 tests.
- v0.2.191 — stale-doc detector (detectStaleDocs in tools/staleDocs.mjs + npm run docs:stale): a new ADVISORY detector + thin CLI catch docs/status/version drift earlier/clearer than the gated docConsistency guard — version-HEADER drift per continuity doc, a doc that never mentions the current version, a newest report nobody links, a newest report lagging the current version, and disagreeing test counts across continuity docs. Low false positives: HEADER-only matching (separator/markup gap) + quoted-span stripping so changelog prose is ignored. Text default; --json; local/read-only/network-free; ALWAYS exits 0 — advisory, NOT in npm run check (hard gate stays docConsistency [14]). TOOLING/DOCS-ONLY. +25 tests.
- v0.2.190 — handoff auto-summary (buildHandoffSummary in tools/handoffSummary.mjs + npm run handoff:summary): a pure helper + thin CLI fold the existing local status/readiness inputs into ONE concise brief for the next agent/model (version, git commit, live URL, gate verdict via gatherReleaseReadiness(), regression + test-profile counts, latest reports, next SAFE task, key constraints, exact release-verify commands). Text default; --json (schema torii.handoff-summary v1); --markdown; opt-in --write[=path] is the only writer. Deterministic generatedAt; garbled/missing release → honest unknown gate; never throws. TOOLING/DOCS-ONLY; read-only/local/no-network. +13 tests.
- v0.2.189 — release-readiness JSON export (buildReleaseStatusJson in tools/releaseReadiness.mjs + a --json flag / npm run release:status:json): the local readiness verdict is now machine-readable for the dashboard/handoff/updater/agents — a stable envelope (RELEASE_STATUS_SCHEMA='torii.release-status' / SCHEMA_VERSION=1) over buildReleaseReadiness(). Deterministic by design (generatedAt is the only non-deterministic field — optional + isolated, omit → null for tests; CLI passes a real ISO stamp); garbled summary → honest status:'unknown'/error:'no-summary'; never throws/mutates. CLI --json prints pure JSON to stdout + exits 0 (node tools/release-readiness.mjs --json is pure JSON; plain npm run prepends a lifecycle banner to stdout, so scripted consumers use npm run --silent release:status:json); default human block + run-guard unchanged. TOOLING/DOCS-ONLY + read-only/local/no-network; no gameplay/portal/physics/controls/Nostr change. +7 tests.
- v0.2.188 — dashboard SHIP-READINESS + NEXT-SAFE-TASK (buildShipModel + _shipSection in engine/dashboard/continuumData.js; live verdict fed by tools/build-continuum.mjs via the new reusable gatherReleaseReadiness): the Torii Continuum now surfaces the LAST release-readiness verdict (npm run release:status) and the recommended NEXT SAFE task as a first-class Ship readiness section — a status pill, a six-signal table (reusing the existing pill CSS), and a next-safe-task highlight. kind GENERATED (live) or LAST-KNOWN (curated fallback). release-readiness.mjs refactored to export gatherReleaseReadiness(root) (CLI unchanged via a run-guard); continuumDataJSON carries ship. DASHBOARD/TOOLING-ONLY + INERT: NO new <script>/data-k → CSP/XSS guard + refresh-script sha256 intact; no network/deploy/publish/gameplay/portal/physics/controls/Nostr change. SDK continuum auto-exports buildShipModel/SHIP_BADGE/SHIP_LASTKNOWN/SHIP_NEXT_SAFE_TASK. +10 tests.
- v0.2.187 — release-readiness VISIBILITY (tooling/docs only, no runtime change): a new read-only, local, network-free command (npm run release:status) aggregates the local ship signals into ONE concise verdict for AI handoff — version sync, test-profile counts, the 15-check regression gate (read-only presence/count), the advisory bundle baseline, the /zone/* SPA-fallback verdict, docs/status consistency, and latest reports. Pure aggregator (tools/releaseReadiness.mjs) + thin CLI (tools/release-readiness.mjs) folding the existing pure checks; bundle stays ADVISORY (never blocks); honest READY / NOT READY / INCOMPLETE verdict. +15 unit tests; foundation profile +1. NON-GOALS: no fs writes, no network, no deploy/publish, no gameplay/portal/physics/controls/Nostr change.
- v0.2.186 — deployment-readiness VISIBILITY (buildReadinessModel + _readinessSection in engine/dashboard/continuumData.js; real verdict fed by tools/build-continuum.mjs): the v0.2.185 /zone/* static-host fallback verdict is now a first-class Deployment-readiness section in the Torii Continuum (data + visible page). Pure buildReadinessModel({zoneFallback}) folds the read-only checkZoneFallbackReadiness({docs,dist}) result into honest states — READY / DOCS READY · BUILD CHECK PENDING / NOT READY / NOT CHECKED — with a four-row per-check table (SPA fallback documented, dist route shape, host fallback MANUAL, auto-update MANUAL); never throws (no input → NOT CHECKED); each state reuses the existing pill vocabulary so NO new CSS. build-continuum.mjs reads the required docs + walks dist/ at packaging time (absent → dist check SKIPPED; regression-check [15] is authoritative). continuumDataJSON carries readiness. DASHBOARD/TOOLING-ONLY + INERT: server-rendered escaped text, NO new <script>/data-k → CSP/XSS guard + refresh-script sha256 intact; no server access/SSH/credentials, no deploy/publish/upload, no auto-update, no navigation/runtime/gameplay change. +8 tests.
- v0.2.185 — deployment-readiness FOUNDATION (docs + local check, no runtime change): the outstanding torii.quest/VPS static-host requirement — serve index.html for /zone/* on a cold hard-refresh/deep-link — is now operationally explicit and LOCALLY checkable. Pure tools/zoneFallbackReadiness.mjs + read-only network-free CLI (npm run zones:check) + regression-check [15] verify VPS_INSTALL.md/HANDOFF.md describe the SPA fallback and a built dist/ has index.html with no /zone/* file shadowing it. New ZONE_FALLBACK_READINESS.md + VPS_INSTALL.md §11 + UPDATE_CHECK.md pointer. NON-GOALS: no server access/SSH/credentials, no deploy/publish/upload, no auto-update, no navigation/runtime change. +20 tests.
- v0.2.184 — LEAN-2 portal/zone state CLARITY (engine/gateway/zoneLabel.js, wired at the main.js boundary): pure label helpers that tell the player WHERE the portal goes and WHAT they entered. portalPromptLabel() builds a target-aware proximity prompt ("Press F to travel to Plebeian Market Bazaar") with a generic fallback; enteredZoneLabel() builds the post-hop notice ("Entered: …"), '' for unknown. Both DERIVE text from the safe slug via humanizeZoneSlug; free-form/hostile input is stripped to an [A-Za-z0-9 -] allowlist (length-capped), so no markup survives even though the HUD sink is textContent. The KeyF handler shows the notice ONLY on a navigated:true confirm report. DISPLAY-ONLY + INERT: no nav/relay/sign/publish/network — safety model unchanged (proximity arms, KeyF confirms, same-origin /zone/ only). SDK (experimental) + debug-shell exposure. +15 tests. Remaining: static-host SPA rewrite + SEC-2 tier.
- v0.2.183 — LEAN-2 in-world GATEWAY PORTAL marker (engine/gateway/portalMeshPlan.js pure plan + engine/gateway/portalMesh.js browser THREE adapter, built at the main.js boundary): the visible landmark that lets a player SEE the v0.2.181 travel point. buildPortalMeshPlan({position, range, title}) is PURE/node-safe — four inert marker parts (an outer ring whose radius EQUALS the proximity range, an inner accent ring, a faint translucent beam, a slow-spinning core), navigated/performed/external/signed/published pinned false + readOnly:true. The browser adapter builds emissive meshes ONCE behind a _built guard; tickPortalMesh(dt) mutates ONLY scalars (rotation.y, emissiveIntensity) so the no-allocation hot-path rule holds; disposePortalMesh() frees GPU resources. DISPLAY-ONLY + INERT: no collider/raycast/input/nav/relay/sign/publish — safety model unchanged. SDK (experimental) + debug-shell (plan + render state) exposure. +18 tests. Remaining: static-host SPA rewrite + SEC-2 tier.
- v0.2.182 — LEAN-2 pure SPA /zone/<slug> ROUTE PARSER (engine/gateway/zoneRoute.js, read at the main.js boundary): the safe client-side READ of the same-origin URL the v0.2.181 portal hop pushes, so a refresh/deep-link on /zone/* is not brittle. parseZoneRoute() runs the route through safeRoutePath (rejects dot-dot/percent/protocol-relative/js-scheme/data-scheme/markup/control/over-length), strips ?query/#hash, then classifies HOME (root or non-/zone/) vs ZONE (strict slug: lowercase alnum + single hyphens, ≤64) vs INVALID (sub-path/malformed/hostile/non-string); a valid zone maps to an INERT display state (title + HUD notice). navigated/performed/external/signed/published/network all stay false. The browser location-path read + a popstate listener wired ONLY at the main.js composition root; module is pure/node-safe with no module-scope browser global. Hard-refresh deep-link still needs a static-host SPA fallback (serve index.html for /zone/*) — DOCUMENTED, not faked. SDK (experimental) + debug-shell exposure. +28 tests. Remaining: dedicated portal MESH + the static-host SPA rewrite rule.
- v0.2.181 — LEAN-2 in-world gateway PORTAL TRIGGER (engine/gateway/portalTrigger.js, wired at the main.js boundary): a pure per-frame tick(playerPos) uses withinPortalRange (scalar, no Vector3) to ARM the v0.2.180 portal boundary + raise a HUD prompt near the torii gate — both inert (proximity never navigates). An explicit KeyF interact() is the ONLY navigating step → confirmed same-origin /zone hop over the real window injected once at the composition root (no module-scope window). Allowlist scoped ['/zone/'] (never ['/']); external website URLs never navigate; external/world/network/sign/publish stay false; SEC-2 untouched. SDK (experimental) + debug-shell (recording host) exposure. +18 tests. Remaining: dedicated portal MESH + SPA route handler.
- v0.2.180 — LEAN-2 in-world gateway PORTAL ACTIVATION seam (engine/gateway/gatewayPortalActivation.js): the pure bridge from a gateway component to the v0.2.178 confirmed same-origin hop. portalActivationInput() maps the internal target → a /zone/<slug> input and drops the external website (same-origin route only); sanitizePortalAllowlist() folds ['/'] → ['/zone/'] (never permit-all); createGatewayPortalBoundary() is an injected-transport arm → confirm controller (arming inert; only confirm() acts); withinPortalRange() is a scalar (no Vector3) proximity helper. No module-scope window; no external nav/world-reload/network/sign/publish; SEC-2 untouched. SDK (experimental) + debug-shell (recording host) exposure. +28 tests. Stopped at the safe seam — no in-world mesh trigger yet, so main.js is intentionally not auto-wired.
- v0.2.179 — LEAN-2 gateway ROUTE HARDENING (security-review follow-up): safeRoutePath now also rejects any .. dot-dot traversal segment and any % percent-encoding (closing /zone/../admin + /zone/%2e%2e/admin climb-outs — internal /zone/<slug> routes never need either); the activation routeAllowlist ignores prefixes shorter than 2 chars so a ['/'] allowlist fails CLOSED (matches nothing) rather than allowing every same-origin route, while ['/zone/'] still allows /zone/foo. Pure/node-safe, never navigates; godMode false. +5 tests.
- v0.2.178 — LEAN-2 gateway handoff ACTIVATION (engine/gateway/gatewayActivation.js): live-wired the confirmed same-origin host transport into the v0.2.168 executor. resolveHostTransport() picks an injected / browser-window (History pushState) / recording-host transport WITHOUT navigating; activateGatewayHandoff() double-gates on a literal confirmed:true AND the consent-gated dry-run plan AND an optional same-origin route allowlist before resolving any transport — so preview/render/unconfirmed paths can never navigate. Rollback/back-home reachable; external/worldReloaded/signed/published/network all stay false. SDK (experimental) + debug-shell (in-memory recording host) exposure. +25 tests.
- v0.2.177 — dashboard layout/readability pass (DASHBOARD-LAYOUT-1): visual-hierarchy + scannability pass on /continuum.html — the ACTIVE-milestone headline promoted above At-a-glance, one-line lead captions + live item counts per section, the Now/Archive/Done columns reflow on a responsive auto-fit grid, spacing/typography tightened. DERIVED/GENERATED/LAST-KNOWN/SEED chips stay visible. No new <script>/asset; CSP/refresh-script hash unchanged. +tests.
- v0.2.176 — milestone + layout pass: an explicit Milestones section surfaces the 15-hour MVP route as the one ACTIVE milestone (pure buildMilestoneModel() folds the leanRoute slices into DERIVED counts + a directional % bar) alongside clearly-labelled SEED future milestones; grouped card values render as bullet lists. CSP/refresh-script unchanged. +tests.
- v0.2.175 — engineering health metrics: a new build-time, static, read-only Engineering health section on /continuum.html (provenance-chipped cards + SVG rings) surfaces the efficiency loop (measure · profile · standardise · automate · modularise · document). Pure buildHealthModel() + a HEALTH_LASTKNOWN baseline in continuumData.js run at module load (curated fallback) AND in build-continuum.mjs with freshly GENERATED inputs (profile/test-file counts, parser gaps, version, doc-sync); total tests / timings / bundle baseline / last-green gate are LABELLED last-known via a chip so a stale number is obvious. continuumDataJSON carries health. CSP/refresh-script hash unchanged; page stays fully static/read-only. +9 tests.
- v0.2.174 — dashboard data automation: a pure tools/continuumParse.mjs parses progress.md + todo.md at build time so the continuum page DERIVES its next-12 / active-now / completed-24h / archive lists + a docs-derived task-count metric; buildContinuumModel(overrides) merges them over the curated fallback with parser-gap reporting; CSP unchanged, page stays fully static/read-only. +15 tests.
- v0.2.173 — test-profile system for faster agent loops (tools/testProfiles.mjs PURE registry + tools/test-profile.mjs CLI): npm run test:fast (5 core files — state/events/classifier/aim/snapshot) + test:foundation (16 pure/guard files) for inner loops, test:release = FULL suite + check/build/bundle/handoff (release gate unchanged). Explicit curated lists (no git-diff heuristics) validated against disk (fast ⊆ foundation, no stale entries) + a timing footer so savings are visible. Agents iterate on fast/foundation; every deploy/publish/push still runs test:release. +11 tests.
- v0.2.172 — Continuum dashboard CSP hardening: strict Content-Security-Policy <meta> on the generated public/continuum.html — script-src 'self' + the sha256 of the one packaged refresh script (NO 'unsafe-inline' script), style-src 'self' 'unsafe-inline' (data-driven track bars), connect-src 'self' (same-origin JSON refresh), default-src 'self' with object-src/base-uri/form-action/frame-ancestors locked to 'none'. Script body + hash kept in sync by a node:crypto test (cannot drift). Resolves the prior inline-script WARN; page stays fully static/read-only. +7 tests.
- v0.2.171 — Torii Continuum project-oversight dashboard: a thin static page (public/continuum.html) generated from a curated, node-safe progress.md data model (engine/dashboard/continuumData.js) — CSS bars + SVG donut rings + totals strip, Now/Next/Later, next-12, struck completed-24h, archive, seed contributors/clankers metric, source-of-truth footer. Regenerated from packaged data each build (build:continuum); a same-origin-only refresh script re-reads continuum-data.json (no external URL/eval/timers). Safe relative link added to the title screen. Docs/tooling only, no gameplay change. +22 tests.
- v0.2.170 — same-origin host transport adapter (engine/gateway/hostTransport.js): the injectable seam the v0.2.168 executor drives — createHostTransport/createRecordingHost (default-safe in-memory) + createBrowserHostTransport runtime seam (pushState/replaceState only, not yet wired); safeRoutePath re-validated, back-home rollback, browser APIs behind DI; null host → executor no-op. +21 tests.
Next 12 tasks
12The ordered queue — top of the list is the next thing to pick up.
- 1Drive gatewayActivation (v0.2.178) from a real host router — inject the app/browser window or host transport at the gateway boundary + a same-origin route allowlist wired to CSP, so a confirmed in-world hop performs the live same-origin navigation.
- 2Gateway portal mesh — actually move the player in-world on a confirmed hop (the front-end trigger for the live-wired activation seam).
- 3SEC-2 handoff verification gate — cryptographic checks before acting on live relay travel intents.
- 4Real leaderboard signer/publisher + relay read (SEC-1 explicit NIP-07 consent first).
- 5In-world product panel mesh over productPanelShell + a real Plebeian.Market listing.
- 6SEC-3 product URL validation — URL-object parsing (scheme+host), not regex-only.
- 7Read-only GitHub releases fetch (CSP-scoped) + in-world update-prompt mesh.
- 8LEAN-1 / TQ-MANUAL-113 — manual smoke on real hardware, then publish source-built artifact.
- 9ARS-4 FSM fold close-out.
- 10Player boundary full extraction (movement tick, combat, lifecycle, body-state behind the seam).
- 11BotAgent runtime migration — wire decideActions, migrate stateful tick/shoot/blowback.
- 12Formalise NAP zone registry for the gateway/NAP-to-NAP travel preview.
Risk / blocked / no-blocker
6What can move freely vs. what is gated, manual, or a tracked open edge.
| Item | State | Note |
|---|---|---|
| Foundation / docs / tooling slices | no-blocker | Pure node-safe, no deploy needed — the current cadence. |
| Gateway-travel chain (read→execute) | no-blocker | All PURE & INERT; never navigates/signs/publishes/writes network. |
| Live relay I/O · signing · world hop | gated | SEC-1/2/3 must clear before any wire write or live navigation. |
| Live deployment | manual | Trails source; needs maintainer smoke + publish (LEAN-1). |
| Travel-time lead on fast targets | open-edge | Hitscan-aimed but projectile-flown; long shots on strafing bots can trail. |
| ESBUILD-1 dev-server advisory | deferred | npm audit fix pulls a risky rolldown/vite chain; tracked WARN. |