coulomb-social/docs/architecture/authoring-modes-and-lazy-projections.md
tegwick e2aa4045f4 Design dual authoring modes and lazy projection fields
Document top-down and bottom-up writing, lazy title/abstractor/visual that
persist after generation, and per-field regenerate plus lock. Wire into
capability model and stage-1 notes.
2026-08-13 00:07:32 +02:00

9.6 KiB
Raw Blame History

Authoring modes and lazy projection fields

Field Value
Date 2026-08-13
Status design proposal (product + data model)
Related page-first model, Abstractor/Title/Visual, stage-1 cut, markitect structure

Intent

Coulomb should make both styles of knowledge work feel natural:

Mode Flow
Top-down Title → short description (abstractor) → outline → elaborate body → optional visual
Bottom-up Plunge into body text → title / abstractor / structure / visual emerge after or while writing

Neither mode may force the other. Empty or content-only entities must still display as first-class cards (title, description, illustration) without blocking the writer.

Principles

  1. Body is never blocked on metadata. A page with only prose is valid.
  2. Display needs projections — card/list UI needs title, abstractor, visual when showing an entity.
  3. Projections may start virtual — generated on first need (lazy), then persisted as normal field values.
  4. After persistence, fields behave like user-authored data — editable, exportable in frontmatter, same SoR as hand-written values.
  5. Regenerate is an explicit action, not ambient rewriting.
  6. Lock freezes a field against automatic (and optionally against bulk) regeneration.
  7. Structure stays page-first — outline is headings/sections in the markdown body (or a derived outline view), not a separate chunk ontology. See transclusion-and-chunks.md.

Field set (stage-1 aligned)

Field Role Display use
title Name of the entity Card headline, browser title, lists
abstractor Short description (Bubble: Abstractor) Card subtitle, previews, search snippet
visual Illustration / cover Card face, headers
body Main markdown content Full page view
outline Derived (usually) from body headings Top-down scaffold; navigation

outline is typically not a separate SoR blob: it is read from # / ## structure, or optionally written back as a stub section when the user accepts a generated outline in top-down mode.


Dual mode UX

Top-down path

New page
  → focus title (optional visual placeholder)
  → abstractor
  → "Generate outline" → body becomes heading skeleton
  → user elaborates under headings
  → visual optional (upload or generate)
  • Empty body with title/abstractor is fine.
  • Outline generation writes body (or a dedicated outline region) only when the user asks — not on every keystroke.

Bottom-up path

New page / open blank body
  → write freely
  → on first card/list display (or idle debounce): lazy-fill missing title/abstractor/visual
  → user may edit, regenerate, or lock any field
  → optional "Propose outline" restructures headings without deleting prose carelessly
  • Creating a page must not require a title dialog.
  • Autosave body continuously; projections fill lazily on display need or on explicit "Suggest metadata".

Mode switching

There is no mode toggle the user must set. The product infers intent:

  • If title/abstractor present and body empty → treat as top-down.
  • If body present and title empty → bottom-up; lazy projections allowed.
  • Both filled → normal edit; regenerate only on demand.

Lazy projections (virtual → real)

Lifecycle of a projection field

missing
  → (display needs field) generate candidate  [virtual / ephemeral]
  → persist to page frontmatter               [real]
  → user edit | regenerate | lock
State Meaning
absent No value in SoR; may generate
derived Value present; provenance: generated (or equivalent); unlocked
user Value present; last material edit was human (or import); unlocked
locked Value fixed; no auto/lazy regenerate; explicit unlock required

Rule: Once generated and saved, the value is kept as if the user had typed it — cards and export see real frontmatter, not a live prompt every time.

Lazy trigger examples:

  • First render of a card in a list/deck when title or abstractor or visual is absent
  • Opening page header chrome when fields missing
  • Explicit “Fill missing metadata”

Not triggers (by default):

  • Every keystroke in the body
  • Background jobs that rewrite locked or recently user-edited fields
  • Silent overwrites of user or locked values

Generation sources (implementation-agnostic)

Field Cheap deterministic options Richer options (optional)
title First H1, first non-empty line, filename/slug LLM short title from body
abstractor First paragraph, first section under H1 LLM 12 sentence summary
visual Palette placeholder from hash of id; first image in body/assets Image model / pick from assets
outline Existing headings; or insert H2 stubs from summary LLM outline from abstractor or body

Prefer deterministic first for offline/dev and predictable tests; LLM behind the same regenerate/lock contract.

Persist shape (illustrative frontmatter)

---
id: page-…
title: "Working title"
abstractor: "One-line sense of the page."
visual: "assets/visuals/page-….webp"   # or sha256:… asset ref
projections:
  title:
    state: derived          # absent | derived | user | locked
    locked: false
    generated_at: "2026-08-13T12:00:00Z"
    generator: "first-h1@v1"
    source_hash: "sha256:…" # body hash when generated — optional staleness hint
  abstractor:
    state: user
    locked: false
  visual:
    state: locked
    locked: true
    generated_at: "2026-08-13T11:00:00Z"
    generator: "placeholder-hash@v1"
---

Body markdown…

Notes:

  • Display values live in top-level title / abstractor / visual so export and non-coulomb tools still see normal fields.
  • projections.* holds lifecycle only (state, lock, generator, hashes) — not a second title.
  • If projections is missing (imported Bubble/markdown), treat present fields as user unlocked; absent fields as absent.

Actions on each field

Action Behavior
Edit Set value; set state → user; clear stale generator metadata or keep last generator for audit
Regenerate / Update Allowed if not locked; re-run generator; overwrite value; state → derived; refresh generated_at / source_hash
Lock locked: true, state → locked; blocks regenerate and lazy auto-fill
Unlock locked: false; state → user or derived (keep last provenance)

UI: per-field overflow (✎ edit · ↻ regenerate · 🔒 lock) on cards and page chrome — unobtrusive, always available.

Staleness (optional, unlocked derived only)

If source_hash ≠ current body hash, UI may show “metadata may be outdated” and offer regenerate — never auto-regenerate locked or user fields without consent. Policy for derived + stale can be: badge only (default) or auto-refresh if product later opts in.


Interaction with page-first / transclusion

  • Outline = structure of this pages body (headings), not a chunk table.
  • Top-down “generate outline” writes headings into body; elaboration is normal writing under those headings.
  • Bottom-up “propose outline” may reorganize into headings (explicit action; preview/diff recommended).
  • A card for a transcluded excerpt uses the source pages projections unless the excerpt is promoted to its own page.

Capability / feature mapping (rebuild)

Under cap.space-content (and any entity shown as a card):

Feature id (proposed) Description
feat.authoring-top-down Title/abstractor/outline-first create path
feat.authoring-bottom-up Body-first create; no required metadata gate
feat.projection-lazy-fill Lazy generate missing title/abstractor/visual on display
feat.projection-persist Persist generated values into frontmatter
feat.projection-regenerate Explicit per-field regenerate
feat.projection-lock Per-field lock against auto/regenerate

Stage-1: ship dual authoring + lazy title/abstractor at minimum; visual generation can start as placeholder art; LLM optional.


Anti-patterns

Avoid Why
Requiring title before first save Blocks bottom-up
Regenerating on every body keystroke Noisy, fights the writer
Virtual-only fields that never save Breaks export and “users data”
One global “AI mode” toggle for the whole page Prefer per-field lock/regenerate
Separate chunk entities only to hold outline Outline is page structure

Open product choices

  1. Default generator set — deterministic only vs LLM when configured.
  2. Stale derived fields — badge-only vs optional auto-refresh.
  3. Visual generation — placeholder vs asset pipeline vs external image model.
  4. Outline write-back — always mutate body vs ephemeral outline panel until “Apply”.
  5. Space-level projections — same contract for space cards (title/abstractor/visual).

One-liner

Top-down and bottom-up are both first-class; display fields can be born lazy, then live as ordinary locked-or-editable metadata so tooling never blocks the writing.

  • docs/architecture/transclusion-and-chunks.md
  • docs/architecture/ArchitectureBlueprint.md
  • docs/capability/stage-1-cutover.md
  • docs/capability/existing-bubble-capability-map.md (Title, Abstractor, Visual)