Composition Mode - curated ordering + prose blocks inside a motif #128
Labels
No labels
bug
duplicate
enhancement
future
help wanted
invalid
question
wontfix
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
rbrooks/TeaLeaves#128
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Feature idea (Fable ideation, rank #5) · Effort: M · Value: High
Pitch
Let her arrange a motif's entries in narrative order and interleave short prose/heading blocks, so the published page and Markdown export read as an essay with evidence rather than a reverse-chron dump.
Why it matters
Publishing exists (public motif pages, embeds, all-motifs MD export) but every rendering orders entries
ORDER BY e.created_at DESC(verified inroutes/public.ts~45/315/430 androutes/export.ts). A researcher publishing an argument needs to control sequence: setup → evidence → counter-evidence → conclusion. Right now her newest stray note sits at the top of her published essay.How it fits
entry_motifs(005_motifs_connections.sql) has no position column - addposition INTEGERplus a smallmotif_blockstable (motif_id, position, content, format) reusingcontent_formatconventions from migration 031 and write-sanitization. Public renderer and MD exporter switch toORDER BY position NULLS LAST, created_at DESCso uncurated motifs behave exactly as today. Drag-to-reorder in the existing motif detail UI.Why it was likely missed
Motifs shipped as buckets in Phase 5; publishing (v5/v6) shipped as rendering the bucket. The document-ness of a published motif - that it's an authored artifact, not a query result - fell between those two phases.
Acceptance criteria
From the 2026-07-15 codebase audit - Fable feature-ideation pass. Companion report:
docs/.internal/report-2026-07-15.md(gitignored).Picking this up on
feat/v10-composition(targeting v9.4.0).Design:
entry_motifs.position INTEGER(nullable) +motif_blocks (id, motif_id, position, content, content_format)reusing the migration-031plain/markdownconvention.position. All renderers switch toORDER BY em.position NULLS LAST, e.created_at DESCand interleave blocks by position — so an uncurated motif renders exactly as today (all-NULL positions → created_at DESC, no blocks)./api/motifs/:id: extend detail withposition+ ablocksarray;PUT /composition(transactional reorder of the full mixed list),POST/PATCH/DELETE /blocks(sanitize on write). Writes gate onACCESSIBLE_PROJECTS_SQLlike the existing entry-add.routes/public.ts(3 sites) +routes/export.ts(MD) honor position + interleave blocks.Will report when the core lands.
Done — shipped in v9.4.0 (PR #143, merge
48c0048).Migration 056 (
entry_motifs.position+motif_blocks); motif detail returnsposition+blocks;PUT /composition(transactional reorder) +POST/PATCH/DELETE /blocks(sanitized). All renderers — public page JSON, motif Atom feed, Markdown export — useORDER BY position NULLS LAST, created_at DESCand the page/export interleave prose blocks. Frontend: "Compose" mode with native drag-reorder (▲/▼ touch fallback) + block editing; read + public views render the interleaved composition. 5 integration tests.Acceptance: ✅ entries manually orderable, order persists · ✅ prose/heading blocks interleaved between entries · ✅ public pages + MD export honor curated order, uncurated motifs unchanged (verified by a dedicated test).
Note: one bug caught in review before merge — the public-page entries query had
em.positioninGROUP BY/ORDER BYbut not theSELECT, so public entries lacked their position; fixed.