You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
feat(sessions): Copy as Markdown — export a session, scrubbed
The M4 export slice (levelcode-sessions-experience.md §6): one action turns a
session into a clean Markdown transcript for pasting into a PR, and it is the
seed of a later share-a-run.
**It scrubs, and that is not incidental.** chat-sessions-design.md §10 already
decided this: transcripts at rest are the same trust class as your code, but
"anything that later *shares* a session must scrub — that is that feature's
burden." Export is the first surface that shares one, so redactSecrets — built
last week for project memory — is passed in at the call site rather than baked
into the renderer, so the scrub is visible where it happens instead of being a
property you have to know the module has.
**Roles are bold labels, never headings.** A turn routinely contains `## …` and
fenced code; a heading-based role label is visually outranked by the content it
is supposed to delimit, and `### LevelCode` above a reply opening with `#` reads
as though the model wrote the section title. Bold plus a rule survives every
renderer at every nesting depth.
The success message counts TURNS, not characters: "Copied 14 turns" tells you
whether you got the session you meant.
**The fifth button.** The action row is two fixed-height lines and
`flex-wrap: nowrap`, so buttons that do not fit do not wrap — they overflow.
Five labelled buttons need ~300px and a sidebar is routinely narrower, so the
card is now a container and the labels collapse below 360px, leaving icons at
~184px. Every button already carried title + aria-label, so nothing is lost to a
pointer or a screen reader — only to the eye, and only when there is no room.
Both webviews carry the card, and the pure block between the SESSIONS-PURE
markers must stay byte-identical across them — sessionsView.html is synced, which
is the existing test catching exactly what it was written for.
Tests: 5 new in sessionEvents.test.js (structure, heading safety, the scrub, the
opt-in, degenerate sessions), 2 in webviewCss.test.js pinning the overflow guard
in BOTH sheets, and the action-row test updated to five buttons. The CSS guard is
pinned because the failure is invisible in a wide window: whoever adds a sixth
button will not see it break — a user with a narrow sidebar will.
Verified non-vacuous: dropping the container query 13/15, the container-type
13/15, the aria-label 14/15, the export scrub 10/13. All 32 suites green.
Copy file name to clipboardExpand all lines: docs/levelcode-sessions-memory.md
+1-1Lines changed: 1 addition & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -173,7 +173,7 @@ The magic, delivered quietly (never a wall of text):
173
173
- ✅ **Poisoning red-team pass.**`test/memoryPoisoning.test.js` — 34 cases, an adversarial corpus in the style of `commandSafety.test.js`: ten hostile shapes that must never self-promote, benign project facts that must keep working, nine credential shapes that must never reach disk, and the near-misses (git SHAs, content hashes, asset names) that must survive untouched. It found the gap it was written to look for — see §7. Every case verified non-vacuous by bypassing each guard and confirming failure.
174
174
*Exit met: an adversarial repo cannot plant a load-bearing memory.* The original wording said "EXIT-TEST.md green", but that file is the **M0** fork/build checklist and was never the right home for this; an executable corpus is a better exit test than a checklist anyway, since it re-runs on every change.
175
175
- ⬜ **Decayed-entry recall** — surfacing an aged-out fact when a query matches it directly.
176
-
-⬜**Export** — "Copy as Markdown" for a session, and for the memory set. Cheap, since the storage is already plain text, and it seeds LevelLinks.
176
+
-✅**Export** — "Copy as Markdown" on the session card (`sessionEvents.toMarkdown`), clipboard with a *Save as file…* follow-up. **Scrubbed**, because this is the first surface that *shares* a session and `levelcode-chat-sessions-design.md` §10 says sharing carries that burden — `redactSecrets` is passed in explicitly at the call site rather than baked into the renderer, so the scrub is visible where it happens. Roles render as bold labels, never headings: a turn's own `#`/`##` would otherwise outrank the label meant to delimit it. Memory-set export is still open.
177
177
178
178
**Deliberately later:** cross-*project* memory ("how did I do idempotency in the *other* service?"); a vector cache over the plain files for large corpora; team-shared project memory (rides M9 sync).
0 commit comments