repl: asm tier auto-pause uses replay mode — env reconstructs on resume
Asm tier has no in-eval poll site (the WAT interpreter doesn't read
the SAB atomic), so SAB-pause + portal-snapshot don't apply. Until
the asm interpreter grows its own poll, fall back to the same
replay pattern the manual asm portal-save already uses: stash every
successful prior input from the transcript on tab.autoPause.replayInputs.
autoResumeTab now always reboots the tier first, then:
* replayInputs set — re-eval each in order so env rebuilds,
log a "; resumed asm tier — replayed N prior inputs" entry, then
sendInput re-fires the active input.
* blob set (c / python) — round-trip through portal-load! as before.
* neither (no SAB, lost) — bare sendInput, env starts cold.
Now switching away from a tab mid-asm-eval and switching back
re-establishes every (define …) the user had before, then re-fires
the loop. Same UX shape as the C/Python path.
This commit is contained in:
parent
1f2ef730a2
commit
6bcc20cb27
3 changed files with 69 additions and 9 deletions
|
|
@ -264,7 +264,14 @@ async function autoPauseTab(tab) {
|
|||
}
|
||||
|
||||
if (activeInput) {
|
||||
tab.autoPause = { tier, blob, inputSrc: activeInput, savedAt: Date.now() };
|
||||
// Asm tier has no SAB poll site, so we can't snapshot env mid-eval.
|
||||
// Fall back to replay mode: every successful prior input gets
|
||||
// re-eval'd on resume to rebuild the env, then the active input
|
||||
// is sent fresh. Same pattern the manual asm portal-save uses.
|
||||
const replayInputs = (tier === "asm")
|
||||
? tab.transcript.filter((e) => e.kind !== "error" && e.input !== activeInput).map((e) => e.input)
|
||||
: null;
|
||||
tab.autoPause = { tier, blob, replayInputs, inputSrc: activeInput, savedAt: Date.now() };
|
||||
}
|
||||
|
||||
// Terminate the worker(s) so the heap is reclaimed while the tab
|
||||
|
|
@ -284,8 +291,21 @@ async function autoResumeTab(tab) {
|
|||
tab.tier = ap.tier;
|
||||
tierSelectEl.value = ap.tier;
|
||||
|
||||
if (ap.blob) {
|
||||
rebootTier(tab.id, ap.tier);
|
||||
rebootTier(tab.id, ap.tier);
|
||||
|
||||
if (ap.replayInputs && ap.replayInputs.length) {
|
||||
// Asm tier replay path — re-eval every successful prior input
|
||||
// in order so the env is reconstructed before sendInput fires
|
||||
// the active one. Errors mid-replay are swallowed; restoring
|
||||
// from a transcript that defined-on-error is the user's call.
|
||||
for (const src of ap.replayInputs) {
|
||||
try { await evalInTier(tab.id, ap.tier, src); } catch (e) { /* keep going */ }
|
||||
}
|
||||
tab.transcript.push({
|
||||
input: `; resumed asm tier — replayed ${ap.replayInputs.length} prior inputs`,
|
||||
results: [{ tier: ap.tier, output: "#t" }], kind: "ok",
|
||||
});
|
||||
} else if (ap.blob) {
|
||||
// Round-trip through the tier so portal-load! has the blob
|
||||
// to read. The bare 'init eval forces the tier to bootstrap
|
||||
// before we push the blob into MEMFS.
|
||||
|
|
|
|||
|
|
@ -264,7 +264,14 @@ async function autoPauseTab(tab) {
|
|||
}
|
||||
|
||||
if (activeInput) {
|
||||
tab.autoPause = { tier, blob, inputSrc: activeInput, savedAt: Date.now() };
|
||||
// Asm tier has no SAB poll site, so we can't snapshot env mid-eval.
|
||||
// Fall back to replay mode: every successful prior input gets
|
||||
// re-eval'd on resume to rebuild the env, then the active input
|
||||
// is sent fresh. Same pattern the manual asm portal-save uses.
|
||||
const replayInputs = (tier === "asm")
|
||||
? tab.transcript.filter((e) => e.kind !== "error" && e.input !== activeInput).map((e) => e.input)
|
||||
: null;
|
||||
tab.autoPause = { tier, blob, replayInputs, inputSrc: activeInput, savedAt: Date.now() };
|
||||
}
|
||||
|
||||
// Terminate the worker(s) so the heap is reclaimed while the tab
|
||||
|
|
@ -284,8 +291,21 @@ async function autoResumeTab(tab) {
|
|||
tab.tier = ap.tier;
|
||||
tierSelectEl.value = ap.tier;
|
||||
|
||||
if (ap.blob) {
|
||||
rebootTier(tab.id, ap.tier);
|
||||
rebootTier(tab.id, ap.tier);
|
||||
|
||||
if (ap.replayInputs && ap.replayInputs.length) {
|
||||
// Asm tier replay path — re-eval every successful prior input
|
||||
// in order so the env is reconstructed before sendInput fires
|
||||
// the active one. Errors mid-replay are swallowed; restoring
|
||||
// from a transcript that defined-on-error is the user's call.
|
||||
for (const src of ap.replayInputs) {
|
||||
try { await evalInTier(tab.id, ap.tier, src); } catch (e) { /* keep going */ }
|
||||
}
|
||||
tab.transcript.push({
|
||||
input: `; resumed asm tier — replayed ${ap.replayInputs.length} prior inputs`,
|
||||
results: [{ tier: ap.tier, output: "#t" }], kind: "ok",
|
||||
});
|
||||
} else if (ap.blob) {
|
||||
// Round-trip through the tier so portal-load! has the blob
|
||||
// to read. The bare 'init eval forces the tier to bootstrap
|
||||
// before we push the blob into MEMFS.
|
||||
|
|
|
|||
|
|
@ -264,7 +264,14 @@ async function autoPauseTab(tab) {
|
|||
}
|
||||
|
||||
if (activeInput) {
|
||||
tab.autoPause = { tier, blob, inputSrc: activeInput, savedAt: Date.now() };
|
||||
// Asm tier has no SAB poll site, so we can't snapshot env mid-eval.
|
||||
// Fall back to replay mode: every successful prior input gets
|
||||
// re-eval'd on resume to rebuild the env, then the active input
|
||||
// is sent fresh. Same pattern the manual asm portal-save uses.
|
||||
const replayInputs = (tier === "asm")
|
||||
? tab.transcript.filter((e) => e.kind !== "error" && e.input !== activeInput).map((e) => e.input)
|
||||
: null;
|
||||
tab.autoPause = { tier, blob, replayInputs, inputSrc: activeInput, savedAt: Date.now() };
|
||||
}
|
||||
|
||||
// Terminate the worker(s) so the heap is reclaimed while the tab
|
||||
|
|
@ -284,8 +291,21 @@ async function autoResumeTab(tab) {
|
|||
tab.tier = ap.tier;
|
||||
tierSelectEl.value = ap.tier;
|
||||
|
||||
if (ap.blob) {
|
||||
rebootTier(tab.id, ap.tier);
|
||||
rebootTier(tab.id, ap.tier);
|
||||
|
||||
if (ap.replayInputs && ap.replayInputs.length) {
|
||||
// Asm tier replay path — re-eval every successful prior input
|
||||
// in order so the env is reconstructed before sendInput fires
|
||||
// the active one. Errors mid-replay are swallowed; restoring
|
||||
// from a transcript that defined-on-error is the user's call.
|
||||
for (const src of ap.replayInputs) {
|
||||
try { await evalInTier(tab.id, ap.tier, src); } catch (e) { /* keep going */ }
|
||||
}
|
||||
tab.transcript.push({
|
||||
input: `; resumed asm tier — replayed ${ap.replayInputs.length} prior inputs`,
|
||||
results: [{ tier: ap.tier, output: "#t" }], kind: "ok",
|
||||
});
|
||||
} else if (ap.blob) {
|
||||
// Round-trip through the tier so portal-load! has the blob
|
||||
// to read. The bare 'init eval forces the tier to bootstrap
|
||||
// before we push the blob into MEMFS.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue