--- id: PLN-0037 ticket: studio-project-local-studio-state-under-dot-studio title: Project-local Studio state store and restoration status: done created: 2026-04-04 completed: 2026-04-04 tags: [studio, project-session, project-state, persistence, dot-studio, shell, layout, setup] --- ## Objective Implement the first accepted wave of project-local Studio state persistence under `.studio/`, using a single-file project-session-owned store that restores setup, shell organization, and editor tabs for a project. ## Background DEC-0016 normatively locks the following: - project-local Studio state must live under `.studio/` in the project root; - the main store must be owned by `StudioProjectSession`; - the main store must start as a single file; - wave 1 must include project-local setup, shell layout, open shell/workspace state, and editor restoration; - project-local activity must remain outside the main store; - the policy is read on project-session open, restore on shell mount, and save on shell/project close; - missing or invalid persisted state must fall back to safe defaults without blocking project open. The current codebase already has a `StudioProjectSession` boundary plus a `MainView` shell and an `EditorWorkspace` with in-memory tab/session state, but it has no project-local persistence contract for those concerns. ## Scope ### Included - Propagate DEC-0016 into Studio specifications. - Introduce a project-session-owned single-file state store under `.studio/`. - Load project-local setup when a project session opens. - Restore shell layout and open shell/workspace state when the project shell mounts. - Restore editor open tabs and active tab from project-local persisted state. - Save the main project-session store when the shell or project session closes. - Fall back to default values when persisted state is absent, unknown, or invalid. - Add tests for store parsing, fallback behavior, session ownership, shell restoration, and editor tab restoration. ### Excluded - Project-local activity persistence changes. - General autosave or global incremental persistence for the main store. - Multi-file store layout under `.studio/`. - New settings UI for project-local setup editing. - Persistence of ephemeral hover state, derived cache, heavy logs, or recomputable operational output. ## Execution Steps ### Step 1 - Propagate DEC-0016 into Studio specs **What:** Add normative spec coverage for the project-local Studio state store and its wave-1 boundaries. **How:** Update the existing shell and editor specs, and add a dedicated Studio persistence spec if needed, so the repository explicitly states: - `.studio/` is the project-local root for the main Studio state store; - `StudioProjectSession` owns load/save lifecycle for the store; - the store begins as a single file; - wave-1 categories are `projectLocalSetup`, `shellLayout`, `openShellState`, and `editorRestoration`; - `project-local activity` is excluded from the main store; - read/restore/save policy and default fallback behavior are normative. The preferred propagation shape is: - update [`docs/specs/studio/1. Studio Shell and Workspace Layout Specification.md`](/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/studio/docs/specs/studio/1.%20Studio%20Shell%20and%20Workspace%20Layout%20Specification.md) for shell/session ownership and restore/save timing; - update [`docs/specs/studio/5. Code Editor Workspace Specification.md`](/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/studio/docs/specs/studio/5.%20Code%20Editor%20Workspace%20Specification.md) to replace the current “no cross-session tab restoration” rule with the accepted wave-1 restoration contract; - add a new dedicated spec such as [`docs/specs/studio/8. Project-Local Studio State Specification.md`](/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/studio/docs/specs/studio/8.%20Project-Local%20Studio%20State%20Specification.md) to hold the store schema boundary and exclusions. **File(s):** - `/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/studio/docs/specs/studio/1. Studio Shell and Workspace Layout Specification.md` - `/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/studio/docs/specs/studio/5. Code Editor Workspace Specification.md` - `/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/studio/docs/specs/studio/8. Project-Local Studio State Specification.md` - `/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/studio/docs/specs/studio/README.md` if the new spec must be indexed ### Step 2 - Define the project-session state store contract and single-file codec **What:** Create the main persisted-state model and the single-file read/write boundary used by `StudioProjectSession`. **How:** Introduce a small persistence module or package in `prometeu-studio` that defines: - a versioned root DTO for the main state file; - wave-1 category DTOs for `projectLocalSetup`, `shellLayout`, `openShellState`, and `editorRestoration`; - a file path convention under `.studio/`; - loader/writer logic that returns safe defaults when the file is absent, unreadable, schema-incompatible, or invalid. The implementation must keep `project-local activity` out of this file and must not broaden the schema to cache-like or transient UI data. **File(s):** - `/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/studio/prometeu-studio/src/main/java/p/studio/projectsessions/` - a new package for state persistence such as `/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/studio/prometeu-studio/src/main/java/p/studio/projectstate/` - corresponding test files under `/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/studio/prometeu-studio/src/test/java/p/studio/` ### Step 3 - Extend StudioProjectSession to load setup and expose restorable state **What:** Move the main store lifecycle into the project-session boundary. **How:** Update `StudioProjectSession` and `StudioProjectSessionFactory` so opening a project session: - loads the main store from `.studio/`; - exposes the loaded state to shell/workspace consumers through explicit accessors or a dedicated session-owned state service; - makes project-local setup available before workspace-specific UI mounts. The session boundary must remain the owner of the persistence lifecycle; `MainView` and workspaces may consume the state but must not redefine load semantics. **File(s):** - `/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/studio/prometeu-studio/src/main/java/p/studio/projectsessions/StudioProjectSession.java` - `/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/studio/prometeu-studio/src/main/java/p/studio/projectsessions/StudioProjectSessionFactory.java` - any new project-session-owned state service under `/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/studio/prometeu-studio/src/main/java/p/studio/projectsessions/` or `/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/studio/prometeu-studio/src/main/java/p/studio/projectstate/` ### Step 4 - Restore shell layout and open shell/workspace state from the session store **What:** Apply persisted shell organization when the project shell mounts and capture it again when the shell closes. **How:** Update `MainView` and any shell controls it owns so they can: - restore the selected/open workspace state from the session store instead of hardcoding the default assets workspace when persisted state exists; - restore accepted shell layout properties such as splitter positions or equivalent shell-level geometry once the relevant shell surfaces are mounted; - collect the latest shell state before the shell or project session closes so `save on close` persists the canonical snapshot. If a specific shell surface does not yet expose restorable layout state, introduce the minimal shell-owned API needed to read/write that state without making the shell controls own persistence themselves. **File(s):** - `/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/studio/prometeu-studio/src/main/java/p/studio/window/MainView.java` - shell controls under `/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/studio/prometeu-studio/src/main/java/p/studio/controls/shell/` - application/window close wiring where the current Studio shell lifecycle is finalized ### Step 5 - Restore editor open tabs and active tab through an editor-owned snapshot contract **What:** Persist and restore the editor workspace’s accepted wave-1 restoration state. **How:** Refactor the editor workspace so it can: - export a pure restoration snapshot containing open tab paths and active tab path; - accept a restoration snapshot when the workspace mounts under a project session; - reopen supported files through `prometeu-vfs` using those persisted paths; - fall back safely when a previously open file no longer exists or is no longer supported; - preserve the active-tab choice when restoration succeeds. This step must not broaden into persistence of editor-local transient data beyond what DEC-0016 accepts. **File(s):** - `/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/studio/prometeu-studio/src/main/java/p/studio/workspaces/editor/EditorWorkspace.java` - `/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/studio/prometeu-studio/src/main/java/p/studio/workspaces/editor/EditorOpenFileSession.java` - `/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/studio/prometeu-studio/src/main/java/p/studio/workspaces/editor/EditorTabStrip.java` if small UI adjustments are needed for restore-first behavior ### Step 6 - Wire save-on-close and category-scoped checkpoints if any are required **What:** Make the accepted save policy real in the application lifecycle. **How:** Ensure the main store is serialized: - when the project shell closes; - and when the project session closes through its normal lifecycle. Do not introduce general autosave for the main store. Only add checkpoint saves if a specific accepted category proves it cannot safely rely on close-time persistence alone, and keep that logic isolated to that category. **File(s):** - `/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/studio/prometeu-studio/src/main/java/p/studio/window/MainView.java` - `/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/studio/prometeu-studio/src/main/java/p/studio/projectsessions/StudioProjectSession.java` - any shell/window lifecycle integration surface that currently owns project-window close behavior ### Step 7 - Add tests for defaults, restoration, and persistence boundaries **What:** Lock the decision through automated tests. **How:** Add tests that verify: - missing `.studio/` falls back to defaults; - invalid or schema-incompatible persisted content falls back to defaults; - project-local setup is loaded at project-session open; - shell/workspace state is restored from persisted state when present; - editor open tabs and active tab restore correctly; - `project-local activity` is not part of the main store contract; - saving the main store happens on the accepted close boundary. **File(s):** - `/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/studio/prometeu-studio/src/test/java/p/studio/projectsessions/` - `/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/studio/prometeu-studio/src/test/java/p/studio/window/` - `/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/studio/prometeu-studio/src/test/java/p/studio/workspaces/editor/` - tests for the new persistence package under `/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/studio/prometeu-studio/src/test/java/p/studio/projectstate/` ## Test Requirements ### Unit Tests - Persisted-state codec tests for versioned single-file read/write behavior. - Fallback tests for absent, invalid, and schema-incompatible state files. - Session-service tests proving default values are exposed when persisted state is unusable. - Editor snapshot tests proving only open-tab paths and active-tab identity are persisted. ### Integration Tests - `StudioProjectSessionFactory` tests that verify setup is loaded during session open. - Shell or window tests that verify persisted workspace selection and shell state are applied on mount. - Editor workspace tests that reopen tabs from persisted paths and preserve the active tab when possible. - Close-lifecycle tests that verify the main store is written when the shell or session closes. ### Manual Verification - Open a project with no `.studio/` state and confirm the Studio boots with defaults. - Configure project-local setup such as a Prometeu runtime path, close the shell, reopen the project, and confirm the setup is restored. - Open multiple editor tabs, switch the active tab, close the project, reopen it, and confirm the same tabs and active tab are restored. - Change shell/workspace organization that is in scope for wave 1, close the project, reopen it, and confirm that layout/workspace state is restored. - Corrupt or remove the persisted state file and confirm the project still opens with defaults instead of failing. ## Acceptance Criteria - [ ] Studio specs normatively describe the `.studio/` single-file project-session store and its exclusions. - [ ] `StudioProjectSession` owns loading of project-local setup and access to the main state store. - [ ] The main store is persisted as a single file under `.studio/`. - [ ] Wave-1 categories are implemented without admitting excluded categories such as activity history or derived cache. - [ ] Shell/workspace state restores on shell mount and saves on shell/project close. - [ ] Editor open tabs and active tab restore from persisted project-local state. - [ ] Missing or invalid persisted state falls back to safe defaults without blocking project open. ## Dependencies - Accepted decision [`DEC-0016-project-local-studio-state-under-dot-studio.md`](/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/studio/discussion/workflow/decisions/DEC-0016-project-local-studio-state-under-dot-studio.md) - Existing project-session boundary in `/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/studio/prometeu-studio/src/main/java/p/studio/projectsessions/` - Existing editor tab/session behavior in `/Users/niltonconstantino/personal/workspace.personal/intrepid/prometeu/studio/prometeu-studio/src/main/java/p/studio/workspaces/editor/` ## Risks - The current shell controls may not yet expose enough structured state to restore all accepted wave-1 layout fields cleanly. - Editor restoration may need a small refactor to separate pure restore snapshots from current UI-driven open-file behavior. - A new persistence spec may overlap with current shell/editor specs unless propagation boundaries are written carefully. - Save-on-close behavior may depend on application/window lifecycle code not yet centralized in one obvious surface.