fix(workspace): tell the model which memory store is the team's, and flush mirrors before `run` exits
Issue for this PR
Closes #1332
Type of change
- Bug fix
What does this PR do?
Two stores answer "remember this for the team" in a linked project, and nothing told the model which one teammates read: the engine's always-on workflow text says to call add_memories, while altimate_memory_write's description never said its blocks are the workspace-mirrored, cross-checkout store. So a plain prompt went to the engine hub and the decision never reached repo B โ the issue's tapes show the mirror and overlay themselves work when the model is told to use the block store.
- Prompt. The
## Altimate Workspacesection (from #1330) gains a Team memory line for a bound project whose workspace has not said memory is off: save decisions and conventions withaltimate_memory_write(projectfor this project,globalfor everything); they sync to the workspace and every linked checkout; thedatamate_*memory tools are the engine's separate store and are not what teammates' sessions read; readaltimate_memory_readfirst and update an existing block rather than add a duplicate. The purerender()takes{ teamMemory }as an option (tests stay deterministic);systemSectionderives it frommemoryEnabledCached. The section cap is raised to 2,000 so the longest shape (pinned + stale + team memory) still fits a maximum-length name. - Tool description.
altimate_memory_writesays the same, for models that weight tool descriptions over prompt text. - Second defect from the issue โ lost uploads on exit.
MemoryStore.writemirrors fire-and-forget (void mirrorBlock(...)), which is right for the TUI and wrong for a one-shotrunthat exits when the turn ends.memory-syncnow tracks mirrors in flight and exposesflushPendingMirrors(timeoutMs);runawaits it beside the existingflushPendingSyncsbefore exiting. The store's write path is unchanged (a cloud failure still must not fail a local write).
Not in this PR (design decisions beyond a routing fix, from the issue's later comment): hiding or de-prioritising the engine hub when workspace memory is on, and training_save as a third write path with no dedup. The prompt line's "read before write" instruction is the cheap dedup; provenance in altimate_memory_read output is a separate change.
How did you verify your code works?
identity.test.ts: the line's content, present only withteamMemory: true, absent for unbound; every shape ร team-memory fits the cap with the name intact.identity-section.test.ts: throughsystemSection, a bound workspace with memory enabled in the memo gets the line and one with a remembered "off" does not (newnoteMemoryDisabledForTestsseam).memory-sync.test.ts:flushPendingMirrorsholds for a mirror parked on a slow server and returns when it lands; returns immediately with nothing in flight; gives up at its bound on a hung server. Deleting the tracking fails both.run-accounting.test.ts: the exit path flushes syncs and mirrors under the pilot flag (source-level, alongside the existing lifecycle contracts).test/altimate/workspace,test/memory,run-accounting, the v0.12.1 adversarial file: 1068 pass. Typecheck clean.
Not re-run live: the issue's two-repo tape needs two linked checkouts and the extractor; the mirror/overlay path is unchanged and was verified live before v0.12.0.
Screenshots / recordings
N/A โ system-prompt and tool-description text.
Checklist
- I have tested my changes locally
- I have not included unrelated changes in this PR
๐ค Generated with Claude Code
https://claude.ai/code/session_012Q51zFUmPg1WwtS5CrGJE6
Summary by cubic
Fixes workspace memory routing so a plain "save this for the team" reaches the store teammates read, and stops run from exiting before a last-turn memory upload lands (closes #1332).
- The identity section now tells a bound workspace with memory confirmed on to save with
altimate_memory_write, that it syncs to the workspace and linked checkouts, thatdatamate_*tools are a separate engine store, and to checkaltimate_memory_readfirst. The line renders only on confirmed enablement (not unknown or stale), and the section cap rises to 2,000. altimate_memory_write's description repeats the same guidance for models that read tool descriptions.runnow awaits the skill-sync and mirror flushes together before exiting so mirrors and block archives aren't abandoned. SIGINT/SIGTERM aborts the run first, then holds up to 2s for pending mirrors.- Mirror state is anchored on
globalThisso the flush reads the same set the writer filled despite two module specifiers.
Note: the first turn of a cold run can miss the line while the enablement request is in flight; the tool description covers that turn.
Summary by CodeRabbit
-
New Features
- Workspace identity information now shows team memory only when enabled for a linked workspace.
- Pending workspace memory mirrors and archives are completed before a run exits, with a timeout to prevent indefinite waiting.
- Workspace identity sections can now display up to 2,000 characters.
-
Bug Fixes
- Memory guidance is omitted when workspace memory is disabled, stale, or its status is unknown.
- Memory synchronization now requires both workspace synchronization and workspace memory to be enabled.
- Interrupt handling now allows pending memory updates to finish before exiting.