LifeLab · lens · correcting my own framing

No — and my last doc was one step from getting this wrong.

I said "one tree, three child-producers", which reads as though a lens becomes a node that has children. It shouldn't. A lens appears in the outline like a node so the verbs work, but it owns nothing — it has no children, only results. The distinction that keeps it ephemeral is ownership, not appearance: a container holds blocks; a lens points at blocks that are held elsewhere.

the invariantone rule, and everything else follows from it

Deleting a lens deletes nothing. Every block it showed still exists, unchanged, in the same place, with the same parent. If a gesture ever makes that false, that gesture has turned the lens into a container and must be redesigned.

container · what we're avoiding

The lens accumulates

  • Blocks are inside it; it's their address.
  • It has identity and state beyond its text — order, fold state, an id in the file.
  • Deleting it orphans or destroys content.
  • Drag into means "now it lives here".
  • It must be created, named, maintained — a folder in a costume.

lens · what it is

  • Blocks are elsewhere; the lens frames them.
  • It is its expression — the text ![[page]]{todo} is the entire object.
  • Deleting it removes a question, not an answer.
  • Drag onto it edits the block until it qualifies, or re-homes it. The lens never gains a child.
  • Results are recomputed every paint; nothing is stored under it.

Where the container smell was creeping in: drag-to-reparent. "Drag a block into a lens" sounds like putting it in — and if the lens is computed there's nowhere to put it. The honest reading, which you already have in the model: dropping on a computed lens makes the block match (tags it, sets its status), and dropping on a referenced lens re-homes it to that page. In both cases the change lands on the block, and the lens just re-runs. The lens is never a destination — the page or the predicate is.

so what is it, structurallya line of text that projects — not a node that holds

what's actually in the file

*Launch weeka real block
*Finalize release notesa real block
*![[project/LifeLab]]{todo}a line of text

Three lines. The third has no children in the file and never will — it's a sentence, editable as text, diffable, greppable, pasteable into another page where it means the same thing.

what you see, recomputed each paint

*Launch week
*Finalize release notes
*project/LifeLab{todo}2 · transient
*Record the walkthroughlives in project/LifeLab
*Wait on notarisationlives in person/Ada

The two results are borrowed for the duration of a render. Their rail says where they really live. Delete the lens line and they don't move, don't change, and don't notice.

Concretely: a lens is a node in the render tree and not in the document tree. That's what lets it keep the outliner's verbs — fold, zoom, keyboard nav all operate on the render tree — while owning nothing in the document. Fold state, scroll, and focus are view-local, not written back; if a lens ever needs to persist something, that something belongs in its expression, as text.

three grades of persistenceall ephemeral in structure — they differ only in how long the sentence lasts

flashdies on esc
project/LifeLab. keep
*Finalize release notes
*Sign the macOS build
made by
. on any reference — peek without moving.
written?
Never. Not in the file, not in session state.
feels
Like a thought, not a thing.
writtenlives as one line
project/LifeLab{todo}× removes
*Finalize release notes
made by
. again on a flash, or typing the sentence.
written?
One line of markup. That's the whole object.
feels
Like a saved question, not a folder.
framethe view itself
LifeLab{todo}
*Finalize release notes
*Sign the macOS build
made by
zoom on any lens, or the address bar.
written?
In the URL / history. Nothing touches the file.
feels
Like looking somewhere, not opening something.

The gradient is the feature. A question starts as a keystroke, and only becomes text if it earns it — and even then it's still just a sentence you can retype, not a structure you've committed to. Contrast with a folder or a saved search, both of which are objects you have to manage. Nothing here is ever managed; it's written or it's forgotten.

the testsrun these against any new lens gesture — if one fails, it's becoming a container

testmust be truewhat failure means
deleteRemoving the lens changes zero blocks.It owned something. Find out what and move it back to a page.
retypeTyping the same expression elsewhere gives an identical lens.It has hidden state — an id, an order, a stashed fold map. Put it in the sentence or drop it.
doubleThe same lens can appear twice on one page without conflict.It's an object with identity, not a projection.
dropDragging in changes the block (its home or its attributes), never the lens.You've built a bucket. The predicate should be the target, not the frame.
offlineDeleting every lens in the vault leaves the content complete.Structure has leaked into views — the vault is no longer plain pages of blocks.

The one I'd watch hardest is double. It's the cheapest way to catch container drift: the moment a lens needs to remember something per-instance, someone will add an id, and the day it has an id it's a thing you own rather than a question you asked.