zettelkasten.spine_suggest¶
zettelkasten.spine_suggest ¶
Propose a NEW spine (comparison matrix) from a frame result — READ-ONLY.
Phase 1 of the "frame a question, then seed a spine" feature. This is the
structural sibling of :mod:zettelkasten.frame_answer: it layers an optional,
grounded PROPOSAL on top of an already-computed deterministic frame, for the
DASHBOARD only. The proposal is assembled from material the caller already
surfaced — the frame's facets/hubs and the suggest kind=structure clusters —
plus a tool-free LLM pass that drafts DIMENSION COLUMNS from the question.
Hard guarantees:
- Write-free. Only read functions are called: the pre-computed
framedict, the caller'sget_graphresolver plus :func:zettelkasten.server._structure_clusters(tag-cluster analysis only — no ghost graph is ever cached), and :func:zettelkasten.extraction_schemas.expand_spec(validation only). Nothing here saves, promotes, materializes, or otherwise mutates a graph or any state. - Never raises. The optional LLM stack degrades to a deterministic fallback
set of columns; schema validation failures are reported as
valid: Falserather than propagated. A missing/federated source graph is skipped, not fatal.
Phase 1 only PROPOSES. It does not reorganize existing notes (Phase 2) or run grounded extraction (a future opt-in). The default intent it records is "reorganize existing notes", which a later phase will act on.
Drafted columns are cached by :func:spine_signature — a hash over the
question/project/facet-coverage/gaps and the facets' evidence source graphs — so
re-proposing over an unchanged frame skips the LLM call while a frame change (or
a federated cross-repo source) yields a fresh draft.
spine_signature ¶
Content hash over the frame's shape — the column-draft cache key.
Covers the question, project, the (facet, coverage) pairs, the gap labels,
and each facet's evidence source_graph values. Column drafting depends
only on this surface (not on individual evidence rows), so a change to any of
them yields a fresh draft while a pure re-submit over an unchanged frame hits
the cache. Folding the source graphs mirrors
:func:frame_answer.frame_signature's guard: a federated frame (whose notes
carry namespaced repoid:graph source graphs) cannot collide in the
cross-repo cache with a same-shaped local frame. Deterministic.
Source code in zettelkasten/spine_suggest.py
suggest_spine ¶
suggest_spine(frame: dict, get_graph: Callable[[str], Any], *, project: str = '', search_sources=None, use_cache: bool = True) -> dict
Assemble a write-free spine PROPOSAL from a pre-computed frame result.
frame is the already-computed deterministic output of
:func:zettelkasten.framing.frame_question (never recomputed here). Rows are
derived from the frame's facets/hubs and from suggest kind=structure
clusters per source graph; columns are drafted from the question by a
tool-free LLM (with a deterministic fallback); thin facets become gaps. The
derived spec is validated write-free via
:func:extraction_schemas.expand_spec.
Returns {"proposal", "validated_spec", "valid"} — the exact response
contract the dashboard route re-exposes. Never raises and never writes.