v0.34.0
An open-task stack was only ever visible as prose: every task_begin/task_end
result names the depth, and the lifecycle hints name the task they nag about —
but nothing showed the STACK itself. Meanwhile a real session was carrying six
permanent folding… rows for tasks that had ended long before: the reducer
closed a queued archive only when a committed fold shadowed its BEGIN anchor,
and a fold region deliberately STARTS AFTER the Task begun result so that
anchor always survives — the witness could never fire, and a restart replayed to
the same verdict. Both halves are fixed here, and the dock is what made the
second one visible at all.
- The open-task stack is now a live dock above the composer.
taskMarks
gains awireview (mirroring thetodosprojection) so the browser can read
it, andplugins/task-stack-ui.mjsrenders it: outermost task first, the
innermost highlighted, one row per closing task, pendingtask_begin/
task_endcalls as counts, and NOTHING at all when the stack is empty. Every
number comes from the session's own projection — the dock appends no events
and costs the model no context. Layout is the host's composer-card recipe
(aligned width, hairline border, 13px rows) with the stylesheet injected by
the bundle, and the panel collapses to its one-line summary on click. stateVersion9 → 10: archives close on the close RESULT, not only the
begin anchor. A committed fold shadows a range that ENDS AT the close result
and starts after theTask begunresult, so the close result is the witness
every successful fold leaves behind. Either witness present now drops the row
(rows persisted beforefoldResultSeqexisted keep the anchor-only rule), and
the version bump forces the full replay that converges sessions already
carrying ghost rows — observed live: sixfolding…rows before,[]after,
with the one genuinely open task untouched.- The drain settles in the pass that removed the row — and only then. A fold
whose region had to shrink BELOW the close result leaves the row queued AND
unsettled on purpose: unconditional settling would have eaten the "shrink at
an END boundary needs a re-plan" semantics and stopped the walk early. - The lifecycle hint now carries the whole stack on one line:
Task lifecycle: task stack — 3 open, outermost first: "a" > "b" > "c"; 2 folding, 1 end pending.(orempty). Shape only — names in stack order
plus the counts, no round ages and no seqs — because the hint channel compares
published text verbatim: a number that drifted per round would re-inject
context every round. It is appended to a live hint and never emitted as a
standing state line, so it re-publishes exactly when the stack moves. - The browser bundle stays a COMMITTED artifact with a freshness gate.
plugins/task-stack-ui.mjsis the single source of truth;
scripts/build-client.mjsstrips its ESM keywords and splices it into
scripts/taskfold-client.template.mjs, emittingplugins/taskfold-client.mjs
as a loader-factory classic script — no bundler, no build step in the repo.
test/client-bundle.test.mjsbyte-compares the committed file against a fresh
render, and the release flow refuses to draft or publish a stale one. - Fix — the release freshness guard never actually ran. It called
clientBundlePath()/renderBundle()with no arguments while only
buildClientcarried the repo-root default, so it threw a TypeError instead
of comparing anything. Both sides now default to this repo through
repoBundleText(root), and two tests cover the exact default-root call the
release makes plus a stale artifact in a temp tree, which must fail with
"is stale" rather than crash. - Manifest:
exports["./client"]+dsh.client.platform = "web"make the
bundle discoverable, while"."and"./plugins/*"keep the existing
path-mounted rows and legacy subpath imports working. - Docs: two store screenshots —
assets/screenshot-tasks.pngand
assets/screenshot-tasks-collapsed.png, both 1280×720 — rendered from the
shipped component with the host's real theme tokens, listed in
screenshots.jsonand embedded in both READMEs. - Live verification on the running host (dsh 0.1.5-rc.1): the persisted
projection cache showstaskMarksatver: 10withpendingArchives: [];
the lifecycle event renders the new stack line (byte-stable across two
consecutive injections); the served client bundle is byte-identical to the
committed artifact.verify-cache --since-restartjudges the folds committed
after the session's restart: 2/2 pass, prefix-cache hit 96.5% and 96.2%
(uncached 2,309 / 1,918 tokens against spans of 20,254 / 3,390). Offline
suite: 156 tests, 12 suites, 0 fail.
Prebuilt plugin bundle attached: dsh-taskfold-0.34.0.tgz (npm pack of this tag).