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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 46 additions & 0 deletions docs/idb-workspace-state.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# IndexedDB Workspace State Ownership

This document is the source of truth for what `@knighted/develop` stores in IndexedDB.

## Storage Location

- Database: `knighted-develop-workspaces`
- Object store: `prWorkspaces`

## Canonical State In IDB

IndexedDB is the canonical source for workspace and pull request context.

Each workspace record may include:

- Workspace identity and timing:
- `id`
- `createdAt`
- `lastModified`
- Repository and PR context:
- `repo`
- `base`
- `head`
- `prTitle`
- `prNumber`
- `prContextState` (`inactive` | `active` | `disconnected` | `closed`)
- Runtime/editor state:
- `renderMode`
- `activeTabId`
- `tabs[]` including content, dirty state, sync metadata, and file paths

## Why IDB Is Canonical

Workspace restore and PR workflow continuity require structured, durable records.

IDB supports that by storing:

- Full workspace snapshots
- Repo-scoped context records
- Historical transitions such as disconnected or closed PR context

## Design Rule

If a value is required to accurately restore PR/workspace behavior after reload, it must live in IDB records.

`localStorage` should only mirror user preferences and lightweight bootstrap values.
33 changes: 33 additions & 0 deletions docs/localstorage-state.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# localStorage State Ownership

This document is the source of truth for what `@knighted/develop` stores in `localStorage`.

## Allowed Keys

`localStorage` is intentionally limited to lightweight user preference/session keys:

1. `knighted:develop:github-pat`
- GitHub personal access token used for API calls.
2. `knighted:develop:github-repository`
- Last selected repository full name (for example: `owner/repo`).
3. `knighted-develop:render-mode`
- Last selected render mode (`dom` or `react`).
4. Theme/UI preference keys managed by layout theme modules.

## Not Allowed In localStorage

Do not store pull request context in `localStorage`.

Examples that must stay out of `localStorage`:

- PR context state (`active`, `disconnected`, `closed`, `inactive`)
- PR number and URL
- PR base/head/title/body
- PR drawer repository-scoped workflow state
- Workspace tab snapshots and synced file metadata

## Design Rule

`localStorage` is for lightweight bootstrap preferences only.

If data is needed to restore workspace or pull request workflow state, it belongs in IndexedDB workspace records.
59 changes: 21 additions & 38 deletions docs/pr-context-storage-matrix.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,16 @@

How `@knighted/develop` stores pull request context across browser storage.

This guide focuses on two storage surfaces:
This guide focuses on PR-context ownership only.

PR context is stored in one place:

1. **IndexedDB (IDB)**: workspace snapshots used by the Workspaces drawer.
2. **localStorage**: repository-scoped PR drawer context metadata.

See the full storage ownership docs for non-PR keys:

- [localstorage-state.md](localstorage-state.md)
- [idb-workspace-state.md](idb-workspace-state.md)

## Storage Surfaces

Expand All @@ -21,61 +27,38 @@ This guide focuses on two storage surfaces:

### localStorage

- Key pattern: `knighted:develop:github-pr-config:<owner>/<repo>`
- Relevant fields in each config:
- `isActivePr`: `boolean`
- `prContextState`: `inactive` | `active` | `disconnected` | `closed`
- `pullRequestNumber`: `number | null`
- `pullRequestUrl`: `string`
- `prTitle`, `baseBranch`, `headBranch`
- Not used for PR context state.

## Status Matrix

Use this matrix as the source of truth when debugging UI/storage mismatch.

| Scenario | IDB `prContextState` | IDB `prNumber` | localStorage `isActivePr` | localStorage `prContextState` | Notes |
| --------------------------------------------- | -------------------- | --------------------------------- | ------------------------- | ----------------------------- | ----------------------------------------------------------- |
| A. Local workspace only, no PR context | `inactive` | `null` | `false` (or no key) | `inactive` (or no key) | No connected PR context. |
| B. Workspace is for an active, open PR | `active` | PR number | `true` | `active` | Push mode in PR controls. |
| C. Workspace is for a disconnected PR context | `disconnected` | last known PR number if available | `false` | `disconnected` | PR may still be open on GitHub; reconnect can verify later. |
| D. Workspace is for a PR closed on GitHub | `closed` | closed PR number | `false` | `closed` | Historical context retained for debugging/reference. |

## Why Both IDB And localStorage Exist
| Scenario | IDB `prContextState` | IDB `prNumber` | localStorage PR fields | Notes |
| --------------------------------------------- | -------------------- | --------------------------------- | ---------------------- | ----------------------------------------------------------- |
| A. Local workspace only, no PR context | `inactive` | `null` | none | No connected PR context. |
| B. Workspace is for an active, open PR | `active` | PR number | none | Push mode in PR controls. |
| C. Workspace is for a disconnected PR context | `disconnected` | last known PR number if available | none | PR may still be open on GitHub; reconnect can verify later. |
| D. Workspace is for a PR closed on GitHub | `closed` | closed PR number | none | Historical context retained for debugging/reference. |

The two stores have different responsibilities:
## Why PR Context Lives In IDB Only

1. **IDB (workspace scope)**
- Persists full editor/workspace snapshots.
- Drives Workspaces drawer restore and switching.
2. **localStorage (repository PR scope)**
- Persists PR drawer config and active context metadata for the selected repository.
- Drives Open PR vs Push mode and active-context checks.
PR workflow state is part of workspace state.

They intentionally overlap on PR metadata so the app can restore workspace context and PR drawer behavior across reloads.
Storing it only in IDB avoids drift between storage systems and keeps a single source of truth for restore behavior.

## Debugging Checklist

When the UI does not match expected PR state:

1. Check localStorage key for the selected repository and inspect:
- `isActivePr`
- `prContextState`
- `pullRequestNumber`
2. Check IDB workspace record currently selected/opened and inspect:
1. Check the IDB workspace record currently selected/opened and inspect:
- `prContextState`
- `prNumber`
- `repo`, `head`, `prTitle`
3. Compare against the matrix above.
4. If scenario C is expected, remember GitHub-open verification is deferred until reconnect flow is invoked.
2. Compare against the matrix above.
3. If scenario C is expected, remember GitHub-open verification is deferred until reconnect flow is invoked.

## Console Snippets

LocalStorage (selected repo key):

```js
JSON.parse(localStorage.getItem('knighted:develop:github-pr-config:OWNER/REPO') || '{}')
```

IndexedDB (all workspace records):

```js
Expand Down
Loading
Loading