From 49cb16b6cbb7f6fb1e22427edb568b119fd5326d Mon Sep 17 00:00:00 2001 From: bQUARKz Date: Sun, 5 Jul 2026 09:42:57 +0100 Subject: [PATCH] implements PLN-0166 --- discussion/index.ndjson | 2 +- ...hub-kill-contract-spec-and-lesson-hooks.md | 2 +- .../runtime/09-events-and-concurrency.md | 8 ++++ .../12-firmware-pos-and-prometeuhub.md | 40 +++++++++++++++++++ 4 files changed, 50 insertions(+), 2 deletions(-) diff --git a/discussion/index.ndjson b/discussion/index.ndjson index d1e7e8fd..daa693f8 100644 --- a/discussion/index.ndjson +++ b/discussion/index.ndjson @@ -1,5 +1,5 @@ {"type":"meta","next_id":{"DSC":45,"AGD":48,"DEC":41,"PLN":167,"LSN":53,"CLSN":1}} -{"type":"discussion","id":"DSC-0044","status":"in_progress","ticket":"hub-suspended-game-kill-affordance","title":"Hub Suspended Game Kill Affordance","created_at":"2026-07-05","updated_at":"2026-07-05","tags":["hub","lifecycle","game","ui"],"agendas":[{"id":"AGD-0047","file":"AGD-0047-hub-suspended-game-kill-affordance.md","status":"accepted","created_at":"2026-07-05","updated_at":"2026-07-05"}],"decisions":[{"id":"DEC-0040","file":"DEC-0040-hub-suspended-game-kill-affordance.md","status":"accepted","created_at":"2026-07-05","updated_at":"2026-07-05","ref_agenda":"AGD-0047"}],"plans":[{"id":"PLN-0163","file":"PLN-0163-render-hub-suspended-game-kill-control.md","status":"done","created_at":"2026-07-05","updated_at":"2026-07-05","ref_decisions":["DEC-0040"]},{"id":"PLN-0164","file":"PLN-0164-expose-resident-game-termination-contract.md","status":"done","created_at":"2026-07-05","updated_at":"2026-07-05","ref_decisions":["DEC-0040"]},{"id":"PLN-0165","file":"PLN-0165-validate-hub-kill-flow-end-to-end.md","status":"done","created_at":"2026-07-05","updated_at":"2026-07-05","ref_decisions":["DEC-0040"]},{"id":"PLN-0166","file":"PLN-0166-publish-hub-kill-contract-spec-and-lesson-hooks.md","status":"open","created_at":"2026-07-05","updated_at":"2026-07-05","ref_decisions":["DEC-0040"]}],"lessons":[]} +{"type":"discussion","id":"DSC-0044","status":"in_progress","ticket":"hub-suspended-game-kill-affordance","title":"Hub Suspended Game Kill Affordance","created_at":"2026-07-05","updated_at":"2026-07-05","tags":["hub","lifecycle","game","ui"],"agendas":[{"id":"AGD-0047","file":"AGD-0047-hub-suspended-game-kill-affordance.md","status":"accepted","created_at":"2026-07-05","updated_at":"2026-07-05"}],"decisions":[{"id":"DEC-0040","file":"DEC-0040-hub-suspended-game-kill-affordance.md","status":"accepted","created_at":"2026-07-05","updated_at":"2026-07-05","ref_agenda":"AGD-0047"}],"plans":[{"id":"PLN-0163","file":"PLN-0163-render-hub-suspended-game-kill-control.md","status":"done","created_at":"2026-07-05","updated_at":"2026-07-05","ref_decisions":["DEC-0040"]},{"id":"PLN-0164","file":"PLN-0164-expose-resident-game-termination-contract.md","status":"done","created_at":"2026-07-05","updated_at":"2026-07-05","ref_decisions":["DEC-0040"]},{"id":"PLN-0165","file":"PLN-0165-validate-hub-kill-flow-end-to-end.md","status":"done","created_at":"2026-07-05","updated_at":"2026-07-05","ref_decisions":["DEC-0040"]},{"id":"PLN-0166","file":"PLN-0166-publish-hub-kill-contract-spec-and-lesson-hooks.md","status":"done","created_at":"2026-07-05","updated_at":"2026-07-05","ref_decisions":["DEC-0040"]}],"lessons":[]} {"type":"discussion","id":"DSC-0043","status":"in_progress","ticket":"system-os-cartridge-switch-orchestrator","title":"SystemOS Cartridge Switch Orchestrator","created_at":"2026-07-03","updated_at":"2026-07-05","tags":["runtime","os","lifecycle","game","cartridge","architecture"],"agendas":[{"id":"AGD-0044","file":"AGD-0044-systemos-cartridge-switch-orchestrator.md","status":"accepted","created_at":"2026-07-03","updated_at":"2026-07-05"}],"decisions":[{"id":"DEC-0039","file":"DEC-0039-systemos-game-cartridge-switch-orchestrator.md","status":"accepted","created_at":"2026-07-05","updated_at":"2026-07-05","ref_agenda":"AGD-0044"}],"plans":[{"id":"PLN-0157","file":"PLN-0157-introduce-systemos-game-switch-target-contract.md","status":"done","created_at":"2026-07-05","updated_at":"2026-07-05","ref_decisions":["DEC-0039"]},{"id":"PLN-0158","file":"PLN-0158-terminate-resident-game-before-switching-cartridges.md","status":"done","created_at":"2026-07-05","updated_at":"2026-07-05","ref_decisions":["DEC-0039"]},{"id":"PLN-0159","file":"PLN-0159-recover-failed-game-switches-back-to-home.md","status":"done","created_at":"2026-07-05","updated_at":"2026-07-05","ref_decisions":["DEC-0039"]},{"id":"PLN-0160","file":"PLN-0160-add-dummy-boy-visual-switch-test-cartridge.md","status":"done","created_at":"2026-07-05","updated_at":"2026-07-05","ref_decisions":["DEC-0039"]},{"id":"PLN-0161","file":"PLN-0161-validate-stress-to-dummy-boy-game-switch-end-to-end.md","status":"done","created_at":"2026-07-05","updated_at":"2026-07-05","ref_decisions":["DEC-0039"]},{"id":"PLN-0162","file":"PLN-0162-specify-game-switch-contract-and-direct-boot-separation.md","status":"done","created_at":"2026-07-05","updated_at":"2026-07-05","ref_decisions":["DEC-0039"]}],"lessons":[]} {"type":"discussion","id":"DSC-0039","status":"abandoned","ticket":"render-pipeline-family-and-future-3d","title":"Render Pipeline Family and Future 3D","created_at":"2026-06-04","updated_at":"2026-06-04","tags":["gfx","renderer","runtime","architecture","pipeline"],"agendas":[{"id":"AGD-0039","file":"AGD-0039-render-pipeline-family-and-future-3d.md","status":"abandoned","created_at":"2026-06-04","updated_at":"2026-06-04","_override_reason":"User explicitly chose to close this agenda without a new decision because DSC-0038 already established enough architecture for future extension, and 3D is intentionally deferred."}],"decisions":[],"plans":[],"lessons":[],"_override_reason":"User explicitly chose to close this agenda without a new decision because DSC-0038 already established enough architecture for future extension, and 3D is intentionally deferred."} {"type":"discussion","id":"DSC-0040","status":"done","ticket":"vm-render-parallel-execution-boundary","title":"VM and Render Parallel Execution Boundary","created_at":"2026-06-04","updated_at":"2026-06-06","tags":["runtime","renderer","vm","concurrency","architecture","perf"],"agendas":[],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0048","file":"discussion/lessons/DSC-0040-vm-render-parallel-execution-boundary/LSN-0048-render-workers-need-a-closed-packet-contract.md","status":"done","created_at":"2026-06-06","updated_at":"2026-06-06"}]} diff --git a/discussion/workflow/plans/PLN-0166-publish-hub-kill-contract-spec-and-lesson-hooks.md b/discussion/workflow/plans/PLN-0166-publish-hub-kill-contract-spec-and-lesson-hooks.md index 1372728e..cff2b5f4 100644 --- a/discussion/workflow/plans/PLN-0166-publish-hub-kill-contract-spec-and-lesson-hooks.md +++ b/discussion/workflow/plans/PLN-0166-publish-hub-kill-contract-spec-and-lesson-hooks.md @@ -2,7 +2,7 @@ id: PLN-0166 ticket: hub-suspended-game-kill-affordance title: Publish Hub Kill Contract Spec And Lesson Hooks -status: open +status: done created: 2026-07-05 ref_decisions: [DEC-0040] tags: [hub, lifecycle, game, ui] diff --git a/docs/specs/runtime/09-events-and-concurrency.md b/docs/specs/runtime/09-events-and-concurrency.md index 055b7fdd..133b8839 100644 --- a/docs/specs/runtime/09-events-and-concurrency.md +++ b/docs/specs/runtime/09-events-and-concurrency.md @@ -174,6 +174,14 @@ foreground Game. The new Game MUST receive a fresh VM session. Failure while loading or initializing the replacement Game MUST return the machine to Hub/Home and MUST NOT restore the previous Game in v1. +Manual Hub termination of a suspended resident Game has the same session +removal authority as destructive Game replacement, except that no replacement +Game is started. SystemOS MUST remove the Game from execution eligibility and +resumable state, close its task, stop its process, remove its VM session, clear +task-scoped pending lifecycle delivery, and keep Hub/Home as the foreground +owner. After manual Hub termination, resume queries MUST report no resident +Game. A later launch of the same cartridge is a fresh Game session. + ## 9 Render Worker Concurrency The render worker is not a machine-visible event source and does not introduce diff --git a/docs/specs/runtime/12-firmware-pos-and-prometeuhub.md b/docs/specs/runtime/12-firmware-pos-and-prometeuhub.md index bda74dc3..c78311fa 100644 --- a/docs/specs/runtime/12-firmware-pos-and-prometeuhub.md +++ b/docs/specs/runtime/12-firmware-pos-and-prometeuhub.md @@ -55,6 +55,8 @@ The VM does not own the machine lifecycle. Firmware does. frame pacing. - **VM session**: the POS-owned mutable execution context for one VM-backed process. It contains the VM instance and per-session runtime state. +- **Hub resident Game kill control**: a Hub/Home affordance that terminates the + current resident Game instead of resuming it. ## 3 POS Responsibilities @@ -89,6 +91,8 @@ PrometeuHub is responsible for: - presenting the host-provided local games library when `--games-root ` is configured; - emitting system-owned launch actions for selected Home entries. +- presenting a resident Game kill control while Hub/Home owns foreground and a + Game is resident/suspended. The Hub does not execute bytecode directly. It always delegates execution setup to POS. @@ -219,6 +223,17 @@ It preserves Game VM state but is not execution-eligible except for the bounded pause handoff and later foreground resume. A VM-backed Shell has a separate VM session. A native Shell has no VM session. +When Hub/Home is foreground and a Game cartridge remains resident/suspended, +PrometeuHub MUST render a red control in the bottom-right of the Hub viewport. +The control MUST display only the resident Game title. It MUST NOT be rendered +for no resident Game, Shell tasks, System tasks, or native Shell tasks. + +Clicking the Hub resident Game kill control is a system-owned immediate +termination request. Firmware MUST keep the user in Hub/Home, MUST NOT ask for +confirmation in v1, and MUST NOT resume the killed Game on subsequent Home +actions. The control MUST disappear on the next Hub frame after the resident +Game is no longer present. + ## 8 Cartridge Load Flow Current high-level flow: @@ -257,6 +272,28 @@ before closing the old Game when such an event exists. Replacement MUST NOT block on that event in v1. VM-backed Shell loading creates a distinct Shell session and must not overwrite resident Game VM state. +Manual Hub resident Game kill and destructive different-Game replacement MUST +share the canonical resident-Game termination path. That path MUST: + +- close the resident Game task; +- mark its process stopped; +- remove its VM session; +- clear resident Game state and pending Game lifecycle delivery for that task; +- keep or return foreground ownership to Hub/Home; +- transition render ownership to Shell/Hub (`AppMode::Shell`, `app_id = 0`); +- clear the Game lifecycle audio pause state; +- unbind the Game2D frame composer scene; +- shut down cartridge-scoped asset manager state, including slot identity and + physical glyph/scene/sound banks. + +After this operation, the killed Game MUST NOT be resumable. Launching that +same Game again from Home is a fresh cartridge load and a fresh VM session. +Manual Hub kill MUST emit an INFO Hub log with the message shape: + +```text +Resident game killed from Hub: +``` + POS selects the cartridge and its execution context, but the cartridge's initial callable is not chosen by firmware metadata. Execution starts from the cartridge boot protocol defined in [`13-cartridge.md`](13-cartridge.md), currently `func_id = 0`. When Home launches a discovered Game entry, the request is a system-owned action @@ -341,6 +378,9 @@ Expected behavior: resident Game session; - returning to the same Game resumes it through the foreground lifecycle and waits for current-epoch Game rendering before visual Game presentation. +- clicking the red bottom-right resident Game kill control terminates the + resident Game, keeps Home foreground, clears runtime/cartridge residue, and + removes the resume path. ## 13 Relationship to Other Specs