docs: unclip the diagrams, and answer what compaction leaves behind
Two problems reported against docs/observational-memory.md, one cosmetic and one
substantive. Both turned out to be worth more than the fix.
Clipping. Several boxes lost their bottom line of text in the viewer, and neither
the source nor my own render showed it. Cause: Mermaid measures a node label with
its own font metrics, commits to a box size, then renders that label as real HTML
in a <foreignObject> — so any host stylesheet touching line-height or font-size
inflates the text past a box that is already fixed, and the overflow is clipped.
The error accumulates per line, which is why it always eats the last line of the
tallest labels.
Rejected the obvious fix after testing it rather than assuming it:
%%{init: {'flowchart': {'htmlLabels': false}}}%% *is* honoured (labels switch from
16 foreignObject to 7 tspan) and clips identically, because inflated font-size
inherits into SVG text too. The fix that works is a hard limit of two short lines
per node, with the detail moved into prose under each diagram — one- and two-line
boxes have the vertical slack to absorb inflation, three- and four-line boxes do
not. The nodes were carrying paragraph-sized text; the diagrams are better for
losing it.
Regression harness: render every block with line-height: 1.7 !important forced
onto the label HTML, screenshot, read it. That caught two survivors of the rewrite
that looked fine in the clean render — a long unbreakable /opt path wrapping to a
third line, and a cylinder shape whose curved bottom leaves less room than a
rectangle for the same two lines.
New §4, because the document explained that compaction folds the ledger and never
said what that leaves in the context. Asked directly: is the session back to
knowing nothing? No. A verbatim tail survives, sized by keepRecentTokens (20k) and
cut only at turn boundaries; the system prompt and AGENTS.md were never in the
compacted region because they are rebuilt from disk each request; nothing is
deleted from disk, since compaction appends a compaction entry rather than
rewriting lines; and recall keeps resolving ids whose sources left the context
because it reads the full branch via sessionManager.getBranch() and never consults
the context window. Repeated compaction renders from live records, not from the
previous summary's prose, so there is no generation-loss spiral.
Also corrects this repo's own "compaction calls no model" to the steady-state
claim it actually is: with an empty ledger the hook returns nothing and explicitly
declines ownership, and pi's native model-based summariser runs. Snippet quoted in
the doc.
And a bug shipped in the first version: §9 said the ledger entries are
custom_message and specifically not custom. Exactly backwards, so the one grep
that section existed to get right was the one it got wrong. Verified empirically
against the live session file — 11 om.observations.recorded and 6
om.reflections.recorded, all "type":"custom", next to "type":"custom_message"
entries whose customType is mempalace-mailbox and mempalace-wakeup. That is where
the confusion came from, and the distinction is load-bearing rather than
cosmetic: the mailbox uses the context-visible append API, om's ledger uses the
invisible one. Which makes it a feature the doc now advertises — the ledger costs
zero context until it is folded.
This commit is contained in:
@@ -190,6 +190,80 @@ browser and read back as an image. Recorded because it generalises:
|
||||
`mermaid.parse()` proves syntax and says nothing about layout, so a diagram is
|
||||
unverified until someone has looked at it.
|
||||
|
||||
### … and rendering it in *my* browser was still not enough
|
||||
|
||||
Reported from a real viewer: several boxes had their bottom line of text sliced
|
||||
off. Reproduced and root-caused rather than nudged — **Mermaid measures a node
|
||||
label with its own font metrics, computes the box, then renders the label as real
|
||||
HTML inside a `<foreignObject>`.** Any host stylesheet that touches the
|
||||
`line-height` or `font-size` of that HTML makes the text taller than the box
|
||||
already committed to, and the overflow is clipped at the box edge. Error
|
||||
accumulates per line, so the loss always lands on the last line of the tallest
|
||||
labels — which is exactly what was reported.
|
||||
|
||||
Two fixes were tried and only the second works:
|
||||
|
||||
- `%%{init: {'flowchart': {'htmlLabels': false}}}%%` — **rejected, and verified
|
||||
ineffective rather than assumed so.** The directive *is* honoured (label
|
||||
elements switch from 16 `foreignObject` to 7 `tspan`), and the clipping is
|
||||
identical, because the inflated font-size still inherits into SVG text.
|
||||
- **A hard limit of two short lines per node, with the detail moved into the prose
|
||||
under each diagram.** One- and two-line boxes have enough vertical slack to
|
||||
absorb the inflation; three- and four-line boxes do not. This is also better
|
||||
documentation — the old nodes were carrying paragraph-sized text.
|
||||
|
||||
The regression harness is now the interesting artefact: render every block with a
|
||||
deliberately inflated `line-height: 1.7 !important` on the label HTML, screenshot,
|
||||
and read it. Two survivors of the rewrite were caught only by that harness — a
|
||||
long unbreakable `/opt/pi-observational-memory` path silently wrapping to a third
|
||||
line, and a cylinder (`[( )]`) shape, whose curved bottom leaves less room than a
|
||||
rectangle for the same two lines.
|
||||
|
||||
### §4 answers the question the document left hanging: what compaction does to your context
|
||||
|
||||
Asked directly and worth writing down: *if the old conversation is folded away, is
|
||||
the session back to knowing nothing?* No — and the specifics are all checkable
|
||||
against pi 0.84.3's own `docs/compaction.md` and the extension's source:
|
||||
|
||||
- **A verbatim tail survives, sized by a token budget rather than a message
|
||||
count.** Pi walks back from the newest entry until `keepRecentTokens` [20000],
|
||||
and everything from that `firstKeptEntryId` onward is kept **unchanged**. Cut
|
||||
points land on turn boundaries, never mid-tool-call.
|
||||
- **The system prompt and `AGENTS.md` are not in the compacted region at all** —
|
||||
they are rebuilt from disk on every request, so compaction cannot lose them.
|
||||
- **Nothing is deleted from disk.** Compaction *appends* a `compaction` entry
|
||||
carrying the summary and the cut pointer; no session line is rewritten in place.
|
||||
- **`recall` therefore still resolves ids whose sources left the context**, because
|
||||
it reads the full branch via `sessionManager.getBranch()` and never consults the
|
||||
context window.
|
||||
- **Repeated compaction does not summarise the summary.** The text is always
|
||||
rendered from live observation/reflection records, so there is no
|
||||
generation-loss spiral; the projection is incremental against the last full-fold
|
||||
boundary and escalates to a true re-fold from the branch root at
|
||||
`observationsPoolMaxTokens` [20000].
|
||||
|
||||
And one correction to this repo's own earlier claim: **"compaction calls no model"
|
||||
is a steady-state property, not an absolute.** If the ledger is empty — compaction
|
||||
firing before the observer has ever run — the hook returns nothing and explicitly
|
||||
declines ownership (`// Decline ownership so Pi's native summarizer preserves the
|
||||
pre-cut context.`), and pi's own model-based summariser runs. The doc now says so,
|
||||
with the snippet.
|
||||
|
||||
### A shipped doc bug: the ledger entry type was stated exactly backwards
|
||||
|
||||
§9 told readers the entries are `custom_message` and specifically *not* `custom`.
|
||||
It is the other way round, so the one grep the section existed to get right was
|
||||
the one it got wrong. Corrected against the live session file — 11
|
||||
`om.observations.recorded` and 6 `om.reflections.recorded` entries, all
|
||||
`"type":"custom"`, alongside `"type":"custom_message"` entries whose `customType`
|
||||
is `mempalace-mailbox` and `mempalace-wakeup`, which is precisely where the
|
||||
confusion came from: **the mailbox uses the context-visible API, om's ledger uses
|
||||
the invisible one.**
|
||||
|
||||
That is not a typo but a load-bearing distinction, and the fix turns it into a
|
||||
feature the doc now advertises: `custom` entries *"do not participate in LLM
|
||||
context"* (pi `docs/session-format.md`), so **the ledger costs zero context until
|
||||
it is folded** — now a row in the cost table.
|
||||
### Not covered by any of this
|
||||
|
||||
The opencode bridge is a separate write path the feeder hook never sees, and the
|
||||
|
||||
Reference in New Issue
Block a user