fix(editor): reconcile active file-group pointers; stop persisting compiledProgram

deleteFileGroup left editorStore.activeGroupId dangling at the removed
group: Monaco (and agent writes) kept editing a group compile never reads,
so a stale same-named sketch.ino shipped instead of the code on screen
(the 'leftover template Blink built for 35 minutes' failure). The pointer
now re-targets a surviving group, and compile re-points the editor when
the two pointers diverge (with a visible warning log).

compiledProgram is no longer serialised into boards_json: the firmware
blob was 99.99% of a typical ESP32 save (a bare board already ~1.04 MB),
pushing every real project against the request-size ceiling, and a
restored binary is stale the moment the code differs. Loaders still
accept it from old rows.
This commit is contained in:
David Montero 2026-08-15 08:29:39 +02:00
parent b58ecd1c37
commit 941df93cb3
3 changed files with 34 additions and 1 deletions

View File

@ -529,6 +529,26 @@ export const EditorToolbar = ({
blog('info', `Starting compilation for ${boardLabel} (${fqbn})...`);
try {
// Reconcile the two "active group" pointers before reading sources.
// If the editor drifted to another BOARD's group (dangling pointer
// after a board delete/add, a restore race), Monaco edits — and the
// agent's write_file calls — land in a group this compile silently
// ignores, shipping a stale same-named sketch.ino instead of the code
// on screen. Re-point the editor at the group being compiled. Chip
// program groups are legitimate cross-edits and stay untouched.
const edGroup = useEditorStore.getState().activeGroupId;
if (
activeBoard?.activeFileGroupId &&
edGroup !== activeBoard.activeFileGroupId &&
!edGroup.startsWith('group-chip-')
) {
blog(
'warning',
`Editor file group (${edGroup}) diverged from the compiled board group ` +
`(${activeBoard.activeFileGroupId}) — switching the editor to the compiled group.`,
);
useEditorStore.getState().setActiveGroup(activeBoard.activeFileGroupId);
}
const groupFiles = activeBoard?.activeFileGroupId
? useEditorStore.getState().getGroupFiles(activeBoard.activeFileGroupId)
: files;

View File

@ -517,11 +517,19 @@ export const useEditorStore = create<EditorState>((set, get) => ({
const { [groupId]: _a, ...restActive } = s.activeGroupFileId;
const { [groupId]: _o, ...restOpen } = s.openGroupFileIds;
const { [groupId]: _f, ...restFolders } = s.folderGroups;
// Never leave activeGroupId dangling at the deleted group: Monaco (and
// every agent write_file) keeps targeting it, while compile reads the
// board's group — two same-named sketch.ino files silently diverge and
// the build ships the WRONG one (the "leftover template Blink compiled
// instead of my code" class). Re-point at any surviving group.
const nextActive =
s.activeGroupId === groupId ? Object.keys(rest)[0] ?? '' : s.activeGroupId;
return {
fileGroups: rest,
activeGroupFileId: restActive,
openGroupFileIds: restOpen,
folderGroups: restFolders,
activeGroupId: nextActive,
};
});
},

View File

@ -38,7 +38,12 @@ function serialisableBoard(b: BoardInstance) {
activeFileGroupId: b.activeFileGroupId,
languageMode: b.languageMode,
serialBaudRate: b.serialBaudRate,
compiledProgram: b.compiledProgram,
// compiledProgram is deliberately NOT persisted. The firmware blob was
// 99.99% of a typical ESP32 save payload (~1.04 MB base64 for a bare
// board), pushing every real project against the request-size ceiling,
// and a restored binary is stale the moment the code differs from what
// was compiled. Sources are saved; the binary is recompiled on demand.
// (Loaders still accept compiledProgram from old rows.)
// ESP32 board options + uploaded SPIFFS files. Optional, only present
// after the user has opened Board Options... at least once. Both ride
// inside boards_json so there's no DB migration.