feat: finalize mindspace service extraction phase a
This commit is contained in:
@@ -0,0 +1,324 @@
|
||||
# MindSpace Seamless Migration Runbook
|
||||
|
||||
## Scope
|
||||
|
||||
This runbook defines the no-loss migration path for extracting MindSpace from the Memind monolith.
|
||||
|
||||
Current execution scope:
|
||||
|
||||
- Phase A only
|
||||
- local standalone service on the same machine
|
||||
- no 103 usage
|
||||
- no 105 rollout yet
|
||||
|
||||
## Invariants
|
||||
|
||||
- Existing Memind local behavior remains the baseline.
|
||||
- `local` and `remote` adapter modes must stay switchable through env only.
|
||||
- User-facing functionality must not regress when `remote` points to the local standalone service.
|
||||
- Production release rules stay unchanged: merge to `main`, pass `bash scripts/check-release-ready.sh`, release from verified `main`.
|
||||
|
||||
## Phase A Goal
|
||||
|
||||
Run MindSpace as a standalone local service while Memind uses `MINDSPACE_SERVER_ADAPTER=remote`, with no intentional feature loss versus the current local adapter path.
|
||||
|
||||
Phase A is complete when:
|
||||
|
||||
- standalone MindSpace service uses `/Users/john/Project/MindSpace/runtime` by default
|
||||
- Memind can use `MINDSPACE_SERVER_ADAPTER=remote` against the standalone service
|
||||
- `npm run verify:phase-a-local` passes for a real user with existing data
|
||||
- Memind remote-mode HTTP page list, page create, and page delete pass through the standalone service
|
||||
- temporary verification data and login sessions are cleaned up
|
||||
- remaining Memind-local responsibilities are documented instead of hidden
|
||||
|
||||
## Current data-root policy
|
||||
|
||||
- New default standalone data root: `/Users/john/Project/MindSpace/runtime`
|
||||
- Old Memind directories are treated as migration source and rollback source
|
||||
- Data-root migration is executed by script, not by ad hoc manual copying
|
||||
|
||||
## Phase A Components
|
||||
|
||||
### Memind
|
||||
|
||||
- Shared adapter contract
|
||||
- Local and remote adapter selection
|
||||
- Remote transport with auth token, timeout, and configurable operation path
|
||||
- Remote mode skips Memind-side generated-page workspace sync; background jobs stay on the standalone MindSpace runtime
|
||||
|
||||
### Standalone MindSpace service
|
||||
|
||||
Path:
|
||||
- `/Users/john/Project/MindSpace`
|
||||
|
||||
Responsibilities:
|
||||
- bootstrap DB-backed local MindSpace services
|
||||
- expose `POST /mindspace/v1/adapter/:binding/:method`
|
||||
- expose `/health` and `/mindspace/v1/contract`
|
||||
- manage publication cleanup
|
||||
- manage optional workspace maintenance
|
||||
- manage optional agent worker
|
||||
- read existing session snapshots for conversation-package public-html hydration
|
||||
|
||||
### Standalone data-root overrides
|
||||
|
||||
Use these when you intentionally want a runtime root other than the default `/Users/john/Project/MindSpace/runtime`:
|
||||
|
||||
- `MINDSPACE_SERVICE_H5_ROOT`
|
||||
- `MINDSPACE_STORAGE_ROOT`
|
||||
- `H5_USERS_ROOT`
|
||||
|
||||
## Start Order
|
||||
|
||||
### 1. Start standalone MindSpace service
|
||||
|
||||
```bash
|
||||
cd /Users/john/Project/MindSpace
|
||||
npm run migrate:data-root -- --yes
|
||||
MINDSPACE_MEMIND_ROOT=../Memind \
|
||||
MINDSPACE_REMOTE_AUTH_TOKEN=local-dev-token \
|
||||
MINDSPACE_SERVICE_PORT=19081 \
|
||||
MINDSPACE_SERVICE_AGENT_WORKER_ENABLED=true \
|
||||
node server.mjs
|
||||
```
|
||||
|
||||
### 1b. Start standalone service against a new data root
|
||||
|
||||
```bash
|
||||
cd /Users/john/Project/MindSpace
|
||||
MINDSPACE_MEMIND_ROOT=../Memind \
|
||||
MINDSPACE_SERVICE_H5_ROOT=/Users/john/Project/MindSpace/runtime \
|
||||
MINDSPACE_STORAGE_ROOT=/Users/john/Project/MindSpace/runtime/data/mindspace \
|
||||
H5_USERS_ROOT=/Users/john/Project/MindSpace/runtime/users \
|
||||
MINDSPACE_REMOTE_AUTH_TOKEN=local-dev-token \
|
||||
MINDSPACE_SERVICE_PORT=19081 \
|
||||
MINDSPACE_SERVICE_AGENT_WORKER_ENABLED=true \
|
||||
node server.mjs
|
||||
```
|
||||
|
||||
### 2. Point Memind at the standalone service
|
||||
|
||||
```bash
|
||||
export MINDSPACE_SERVER_ADAPTER=remote
|
||||
export MINDSPACE_REMOTE_BASE_URL=http://127.0.0.1:19081
|
||||
export MINDSPACE_REMOTE_AUTH_TOKEN=local-dev-token
|
||||
```
|
||||
|
||||
### 3. Start Memind normally
|
||||
|
||||
Use the standard local startup flow already used in this repo.
|
||||
|
||||
## Validation
|
||||
|
||||
### Phase A local gate
|
||||
|
||||
```bash
|
||||
cd /Users/john/Project/MindSpace
|
||||
MINDSPACE_LOOPBACK_USER_ID=<user-id> \
|
||||
MINDSPACE_REMOTE_BASE_URL=http://127.0.0.1:19081 \
|
||||
MINDSPACE_REMOTE_AUTH_TOKEN=local-dev-token \
|
||||
npm run verify:phase-a-local
|
||||
```
|
||||
|
||||
Expected result:
|
||||
|
||||
- standalone service is healthy, either reused if already running or started by the verifier
|
||||
- RPC unit tests pass
|
||||
- infra smoke, read parity, page write parity, asset upload parity, and conversation package parity all pass
|
||||
- Memind remote-mode HTTP page list, page create, and page delete pass
|
||||
- final read parity still reports no drift after write-path validation
|
||||
- any service started by the verifier is stopped before exit
|
||||
|
||||
Current verified local user:
|
||||
- `1c99b83b-0454-474f-a5d2-129d34506a32`
|
||||
|
||||
Latest verified totals from the Phase A gate:
|
||||
- pages: `302 / 302`
|
||||
- assets: `100 / 100`
|
||||
- jobs: `0 / 0`
|
||||
- drift counters: `onlyLocal = 0`, `onlyRemote = 0`, `changed = 0`
|
||||
|
||||
### Memind remote-mode HTTP gate
|
||||
|
||||
```bash
|
||||
cd /Users/john/Project/MindSpace
|
||||
MINDSPACE_LOOPBACK_USER_ID=<user-id> \
|
||||
MINDSPACE_REMOTE_BASE_URL=http://127.0.0.1:19081 \
|
||||
MEMIND_REMOTE_MODE_BASE_URL=http://127.0.0.1:18082 \
|
||||
MINDSPACE_REMOTE_AUTH_TOKEN=local-dev-token \
|
||||
npm run verify:memind-remote-mode
|
||||
```
|
||||
|
||||
Expected result:
|
||||
|
||||
- standalone MindSpace service is healthy
|
||||
- Memind starts with `MINDSPACE_SERVER_ADAPTER=remote`
|
||||
- a short-lived local login session can access Memind `/auth/status`
|
||||
- Memind HTTP page list, page create, and page delete succeed through the remote adapter
|
||||
- temporary login session is revoked and temporary page is deleted before exit
|
||||
|
||||
### Infra smoke
|
||||
|
||||
```bash
|
||||
cd /Users/john/Project/MindSpace
|
||||
node scripts/loopback-smoke.mjs
|
||||
```
|
||||
|
||||
### User-scoped smoke
|
||||
|
||||
```bash
|
||||
cd /Users/john/Project/MindSpace
|
||||
MINDSPACE_LOOPBACK_USER_ID=<user-id> \
|
||||
MINDSPACE_REMOTE_AUTH_TOKEN=local-dev-token \
|
||||
node scripts/loopback-smoke.mjs
|
||||
```
|
||||
|
||||
Expected result:
|
||||
|
||||
- `asset count`, `page count`, `job count` return real values for a user with existing MindSpace data
|
||||
- empty collections are acceptable only when the chosen user truly has no stored data
|
||||
|
||||
### Local vs remote comparison
|
||||
|
||||
```bash
|
||||
cd /Users/john/Project/MindSpace
|
||||
MINDSPACE_LOOPBACK_USER_ID=<user-id> \
|
||||
MINDSPACE_REMOTE_BASE_URL=http://127.0.0.1:19081 \
|
||||
node scripts/compare-local-remote.mjs
|
||||
```
|
||||
|
||||
Expected result:
|
||||
|
||||
- page totals match
|
||||
- asset totals match
|
||||
- job totals match
|
||||
- `onlyLocal`, `onlyRemote`, `changed` all stay `0` for stable read surfaces
|
||||
|
||||
### Write-path parity
|
||||
|
||||
```bash
|
||||
cd /Users/john/Project/MindSpace
|
||||
MINDSPACE_LOOPBACK_USER_ID=<user-id> \
|
||||
MINDSPACE_REMOTE_BASE_URL=http://127.0.0.1:19081 \
|
||||
node scripts/compare-write-local-remote.mjs
|
||||
```
|
||||
|
||||
Expected result:
|
||||
|
||||
- temporary local and remote pages are both created successfully
|
||||
- `create -> publish -> offline -> delete` produces no semantic diff between local and remote comparisons
|
||||
- temporary validation data is cleaned up before the script exits
|
||||
|
||||
### Asset upload parity
|
||||
|
||||
```bash
|
||||
cd /Users/john/Project/MindSpace
|
||||
MINDSPACE_LOOPBACK_USER_ID=<user-id> \
|
||||
MINDSPACE_REMOTE_BASE_URL=http://127.0.0.1:19081 \
|
||||
node scripts/compare-asset-local-remote.mjs
|
||||
```
|
||||
|
||||
Expected result:
|
||||
|
||||
- temporary local and remote text uploads both complete successfully
|
||||
- `createUpload -> writeUploadContent -> completeUpload -> readAsset -> deleteAsset` produces no semantic diff
|
||||
- temporary validation assets are deleted before the script exits
|
||||
|
||||
### Conversation package parity
|
||||
|
||||
```bash
|
||||
cd /Users/john/Project/MindSpace
|
||||
MINDSPACE_LOOPBACK_USER_ID=<user-id> \
|
||||
MINDSPACE_REMOTE_BASE_URL=http://127.0.0.1:19081 \
|
||||
node scripts/compare-conversation-package-local-remote.mjs
|
||||
```
|
||||
|
||||
Expected result:
|
||||
|
||||
- temporary local and remote packages are both created successfully
|
||||
- object write, artifact registration, manifest write, manifest file contents, and prepare-read outputs produce no semantic diff
|
||||
- temporary validation package rows and storage objects are removed before the script exits
|
||||
|
||||
### Manual UX validation
|
||||
|
||||
- asset list and upload
|
||||
- page list and page render
|
||||
- page publish and public page access
|
||||
- agent job create, run, and completion
|
||||
- conversation package read for sessions that already have snapshots
|
||||
|
||||
## Phase A Boundary Audit
|
||||
|
||||
The following MindSpace surfaces are now covered by the standalone service adapter and Phase A gate:
|
||||
|
||||
- page list/read/create/publish/offline/delete
|
||||
- asset list/upload/write/complete/read/delete
|
||||
- conversation package object write, artifact registration, manifest write, and prepare-read
|
||||
- remote RPC transport including JSON-serialized `Buffer` arguments
|
||||
- Memind HTTP page list/create/delete while `MINDSPACE_SERVER_ADAPTER=remote`
|
||||
|
||||
The following responsibilities intentionally remain Memind-local in Phase A:
|
||||
|
||||
- user auth, wallet/quota/category APIs, audit writes, and subscription integration still run in Memind
|
||||
- public route HTTP serving is still mounted by Memind, although publication resolution and page rendering use MindSpace service APIs
|
||||
- chat Finish public HTML materialization still writes to the Memind workspace path to preserve the verified `edit_file` regression guard
|
||||
- chat-save preview/thumbnail flows still read workspace HTML from the Memind workspace path
|
||||
- Goose/session workspace capability is still issued from Memind user auth and exposes the local workspace path plus `workspaceRef`
|
||||
|
||||
Remote-mode guardrails added during Phase A:
|
||||
|
||||
- Memind remote mode no longer runs local generated-page workspace sync before page listing
|
||||
- remote adapter background jobs stay on the standalone MindSpace runtime
|
||||
- Phase A verification uses short-lived login sessions and revokes them before exit
|
||||
|
||||
Known Phase A residual risks:
|
||||
|
||||
- real browser UI coverage is still manual; the automated HTTP gate covers Memind API behavior, not a full browser session
|
||||
- full agent job execution and Goose workspace writes are not yet a standalone-service-only contract
|
||||
- complete production separation still needs process supervision, TLS/domain routing, monitoring, and deployment rollback work in later phases
|
||||
|
||||
## Rollback
|
||||
|
||||
If any remote-path issue appears locally:
|
||||
|
||||
```bash
|
||||
unset MINDSPACE_SERVER_ADAPTER
|
||||
unset MINDSPACE_REMOTE_BASE_URL
|
||||
unset MINDSPACE_REMOTE_AUTH_TOKEN
|
||||
```
|
||||
|
||||
Memind will fall back to the local adapter path.
|
||||
|
||||
## Remaining Phase A hardening
|
||||
|
||||
- add browser-level remote-mode smoke once UI automation credentials are available
|
||||
- add a full agent job execution smoke that verifies workspace writes against the intended service runtime
|
||||
- decide when chat Finish public HTML materialization moves from Memind to the standalone service
|
||||
|
||||
## Data migration outline
|
||||
|
||||
When you decide to move local data into the standalone root, use this order:
|
||||
|
||||
1. Stop local writes or switch Memind back to `local`
|
||||
2. Run `npm run migrate:data-root -- --yes`
|
||||
3. Start standalone service
|
||||
4. Run
|
||||
- `npm run smoke:loopback`
|
||||
- `MINDSPACE_LOOPBACK_USER_ID=<user-id> npm run compare:local-remote`
|
||||
- `MINDSPACE_LOOPBACK_USER_ID=<user-id> npm run compare:write-local-remote`
|
||||
- `MINDSPACE_LOOPBACK_USER_ID=<user-id> npm run compare:asset-local-remote`
|
||||
- `MINDSPACE_LOOPBACK_USER_ID=<user-id> npm run compare:conversation-package-local-remote`
|
||||
- `MINDSPACE_LOOPBACK_USER_ID=<user-id> npm run verify:memind-remote-mode`
|
||||
5. Only keep the new root if parity remains clean
|
||||
|
||||
Rollback:
|
||||
|
||||
- stop standalone service
|
||||
- point Memind back to `local` or stop the standalone service
|
||||
- if needed, start standalone with `MINDSPACE_SERVICE_H5_ROOT=/Users/john/Project/Memind`
|
||||
- old Memind data root becomes active again immediately
|
||||
|
||||
## Deferred
|
||||
|
||||
- Phase C `105` integration
|
||||
- Phase D production cutover
|
||||
Reference in New Issue
Block a user