coulomb-social/docs/architecture/transclusion-and-chunks.md
tegwick 64d4dcda7c Note page-first content with markitect transclusion as chunk model
Document markitect include/selector/region/explode primitives and map Bubble
chunks to addressable extractions rather than a priori chunk storage.
2026-08-12 23:48:25 +02:00

189 lines
7.3 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Transclusion vs a priori chunks — coulomb + markitect
| Field | Value |
|-------|--------|
| Date | 2026-08-12 |
| Status | design note (aligns with ArchitectureBlueprint + existing Bubble map) |
| Layer | markitect-tool (syntax) · coulomb product model |
## Thesis
**Pages of markdown are the fluent unit of knowledge work.**
A “chunk” should usually mean **an addressable region or extracted view of a page** (or of another page), not a separate first-class storage object that documents are assembled from *a priori*.
Bubbles `custom.chunk` graph (stages, subchunks, backlog) is powerful but **tool-shaped**: it forces structure before fluency. Rebuild should invert that:
```text
Write fluently in a page
→ address regions when reuse is needed
→ transclude / extract / promote
→ only then materialize a derived page or asset if it earns independence
```
Tooling adapts; it does not demand an ontology of chunks up front.
---
## What markitect-tool already provides
### 1. Include / transclusion (FR-022)
Documented in `markitect-tool/docs/transform-compose-include.md`.
**Markers:**
```markdown
<!-- mkt:include path="sections/intro.md" -->
<!-- mkt:include path="other.md" selector="sections[heading=Summary]" heading_delta="1" -->
{{include:sections/intro.md}}
```
| Attribute | Role |
|-----------|------|
| `path` | Target markdown file (relative; sandboxed under base dir) |
| `selector` | Optional query — **only matching content** is included |
| `heading_delta` | Shift heading levels on include |
| `include_frontmatter` | Optionally keep target frontmatter |
**API:** `resolve_includes(...)`
**Safety:** cycle detection, max depth, no path escape, markers inside fences left literal
**Provenance:** include events record marker line, target path, selector, heading shift
This is **transclusion without a database**: the including page remains editable markdown; resolution is a deterministic operation for render/export/agents.
### 2. Selectors (query / extract)
`docs/query-extraction.md` — extract sections/blocks without inventing chunk rows:
```text
sections[heading=Context]
sections[heading~=risk]
sections[contains~=PROBLEM]
blocks[type=paragraph]
headings[level=2]
```
`mkt transform --extract SELECTOR` can replace a document with extracted content — **promote a region to a standalone body** when needed.
### 3. Content references (addressable units)
`docs/content-references.md` — name units without a priori chunk types:
```text
path/to/file.md
path/to/file.md#section:introduction
path/to/file.md::sections[heading=Decision]
std:clauses/payment.md#region:boilerplate
```
**Named regions** (in-document, optional):
```markdown
<!-- mkt:region id="boilerplate" tags="legal reuse" -->
Reusable text.
<!-- /mkt:region -->
```
Units carry `unit_id`, kind (`document` | `section` | `heading` | …), source span, content hash — enough for cache, ACLs later, and include targets.
### 4. Explode / implode (optional materialization)
`docs/explode-implode.md` — temporarily split a large page into section files + manifest, edit, reassemble.
**Not** “documents are made of chunk types”; it is a **reversible workflow** when humans want filesystem granularity.
### 5. Compose
`compose_files` — concatenate whole files (different from selective transclusion).
---
## Mapping to coulomb / Bubble concepts
| Bubble (live) | Page-first + transclusion model |
|---------------|----------------------------------|
| `custom.page` | **SoR page** — frontmatter + body + backmatter |
| `custom.chunk` as storage atoms | **Avoid a priori** — use sections/regions/selectors inside the page |
| Chunk list / SelectedChunk | **Derived view**: query `sections[...]` or region index on the page |
| Subchunks | Nested headings / nested regions, not separate types |
| Copy page | Duplicate page file (or deep-copy with rewritten includes) |
| Transfer page | Move/re-home page file; includes keep relative or get rewritten |
| Card UI | Projection of page (title, abstractor, visual) — may also project a **transcluded excerpt** as card body |
| Article + chunks_list | Page that **includes** other pages or regions, or a view over query results |
| Stage1…Stage5 on chunks | Optional **workflow metadata** on regions/frontmatter later — not required for S1 |
### “Extract a chunk out of a page”
Three elegant operations, increasing commitment:
| Op | Meaning | Storage impact |
|----|---------|----------------|
| **Address** | Point at `page.md#section:foo` or `::sections[heading=Foo]` | None — still one page |
| **Transclude** | Another page includes that region via `mkt:include` + selector | Still one SoR for the region; host page has a marker |
| **Promote / extract** | Write region to `pages/foo-excerpt.md` (transform extract or explode entry) | New page; optional leave include behind in origin |
Fluency prefers **address → transclude → promote**, not **create chunk type first**.
---
## Product rules (proposed)
1. **SoR is the page file** (markdown). No required `Chunk` table for stage 1.
2. **Cards** show page projections; optional card body = first section or selected region.
3. **Reuse** uses markitect include/reference, resolved at render/export/agent time (and optionally cached).
4. **Independent editing of a reused piece** = promote to its own page, then transclude from both places.
5. **DB/cache** may index section titles and region ids for search/cards — **disposable**, rebuilt from markdown.
6. Bubble chunk migration: prefer **serialize chunk trees into page sections/regions** or separate pages with includes, not recreate `custom.chunk` as a permanent model.
---
## Where this sits in the architecture
```text
coulomb UI (cards, edit, copy, transfer)
PageOps (get/put page markdown)
├─ markitect-tool: parse, query, resolve_includes, extract, references
└─ content plane: store page files (+ assets)
```
Transclusion is a **syntax-layer** concern (markitect-tool), not a reason to pick kontextual vs shard-wiki. Any content plane that stores markdown files can host includes.
---
## Gaps / future (markitect-tool)
From markitect docs themselves (not blockers for S1):
- Variable / conditional transclusion not yet
- Includes currently path-first; content-reference-as-include path is designed for later
- Dependency graph invalidation for caches is planned (WP-0007 hooks)
Coulomb can start with **path + selector includes** and **section/region addressing**.
---
## Relation to stage-1 cut
| Stage-1 need | Transclusion stance |
|--------------|---------------------|
| Title / Abstractor / Visual | Page frontmatter |
| Page CRUD | Whole page files |
| Page copy | File duplicate; resolve or rewrite includes |
| Page transfer | Move file between spaces; rewrite relative includes |
| Chunk UX (if users need “pieces”) | Address/transclude first; promote only if sticky |
---
## One-liner
**Dont model knowledge as Lego chunks that assemble into pages.
Model pages as living markdown, and treat chunks as addressable, transcludable extractions that tooling materializes only when reuse demands it.**
## Related
- markitect-tool: `docs/transform-compose-include.md`, `docs/content-references.md`, `docs/query-extraction.md`, `docs/explode-implode.md`
- coulomb: `docs/architecture/ArchitectureBlueprint.md`, `docs/capability/existing-bubble-capability-map.md`