Skip to content

zettelkasten.tables_spines

zettelkasten.tables_spines

Structural spine helpers for the synthesis-matrix engine.

Mechanically split out of tables.py: apex resolution, component-of depth / child indexing, the spine membership index, and the spine readback matrix.

spine_columns_at_level

spine_columns_at_level(get_graph: GetGraph, loc: 'Callable[[str], str]', graph_name: str, level: 'int | None') -> list[str]

The structure node ids at component-of depth level (apex = 0).

The pivot helper for the matrix flattening (§11.3): the nodes at the chosen level become the matrix COLUMNS, and each one's (rolled-up) membership is its cell. Per the documented pivot semantics the COLUMN axis is the spine's STRUCTURE (DIMENSION) nodes — never the row hubs (which are the ROW axis) and never an arbitrary non-dimension node that happens to sit at a depth:

  • level=None — every materialized dimension node regardless of depth (the flat depth-1 grid, today's behavior).
  • level == 0 — the apex only (the documented "level 0 = apex" pivot); the apex is the lone structure node above the dimension cut. Row hubs, which are also depth 0 (no component-of parent), are deliberately EXCLUDED so a hub whose label collides with a column can never leak onto the column axis.
  • level >= 1 — the DIMENSION nodes at exactly that component-of depth.

Ordered by title for a stable column order.

Source code in zettelkasten/tables_spines.py
def spine_columns_at_level(
    get_graph: GetGraph,
    loc: "Callable[[str], str]",
    graph_name: str,
    level: "int | None",
) -> list[str]:
    """The structure node ids at ``component-of`` depth ``level`` (apex = 0).

    The pivot helper for the matrix flattening (§11.3): the nodes at the chosen
    level become the matrix COLUMNS, and each one's (rolled-up) membership is its
    cell. Per the documented pivot semantics the COLUMN axis is the spine's
    STRUCTURE (``DIMENSION``) nodes — never the row hubs (which are the ROW axis)
    and never an arbitrary non-dimension node that happens to sit at a depth:

    * ``level=None`` — every materialized dimension node regardless of depth (the
      flat depth-1 grid, today's behavior).
    * ``level == 0`` — the apex only (the documented "level 0 = apex" pivot); the
      apex is the lone structure node above the dimension cut. Row hubs, which are
      also depth 0 (no ``component-of`` parent), are deliberately EXCLUDED so a
      hub whose label collides with a column can never leak onto the column axis.
    * ``level >= 1`` — the DIMENSION nodes at exactly that ``component-of`` depth.

    Ordered by title for a stable column order.
    """
    if not graph_name:
        return []
    try:
        zg = get_graph(loc(graph_name))
    except Exception:
        return []
    from zettelkasten.spine import APEX_TAGS, DIMENSION_TAG

    if level is None:
        nodes = [n for n in zg.notes.values() if DIMENSION_TAG in (n.tags or [])]
    elif level == 0:
        # Level 0 is the apex, and ONLY the apex — never a row hub (also depth 0)
        # nor any other node. The apex is the synthesis root above the column cut.
        apex = set(APEX_TAGS)
        nodes = [n for n in zg.notes.values() if apex <= set(n.tags or [])]
    else:
        # Depth >= 1: restrict to DIMENSION nodes at that depth, so row hubs and
        # any non-dimension node at the same depth are kept off the column axis.
        depths = _spine_node_depths(zg)
        nodes = [
            n
            for n in zg.notes.values()
            if depths.get(n.id, 0) == level and DIMENSION_TAG in (n.tags or [])
        ]
    nodes.sort(key=lambda n: (n.title or n.id).lower())
    return [n.id for n in nodes]

spine_readback_matrix

spine_readback_matrix(get_graph: GetGraph, localize: 'Callable[[str], str] | None' = None, *, graph_name: str, cols_level: 'int | None' = None, rollup: bool = True) -> dict[str, Any]

Read a spine's TREE back as a 2-axis matrix flattening (design §11.3).

The single readback entry point that turns the stored tree (structure nodes + component-of + spine-side spine-member edges) into a chosen 2-axis matrix view WITHOUT mutating storage:

  • cols_level picks the component-of depth whose structure nodes are the COLUMNS (apex = 0, top-level dimensions = 1, …); None = every dimension node (the flat depth-1 grid).
  • rollup (default) makes each column's cell AGGREGATE its descendants' members (the confirmed §11.3 rollup), so flattening a deep tree never drops a member attached to an interior or leaf node below the pivot.

Returns {"columns": [node_id, …], "membership": {node_id: {uid, …}}} where membership is keyed by EVERY structure node (so a caller can also read the rolled-up set for nodes off the column cut), and columns is the ordered column axis at the pivot.

Source code in zettelkasten/tables_spines.py
def spine_readback_matrix(
    get_graph: GetGraph,
    localize: "Callable[[str], str] | None" = None,
    *,
    graph_name: str,
    cols_level: "int | None" = None,
    rollup: bool = True,
) -> dict[str, Any]:
    """Read a spine's TREE back as a 2-axis matrix flattening (design §11.3).

    The single readback entry point that turns the stored tree (structure nodes +
    ``component-of`` + spine-side ``spine-member`` edges) into a chosen 2-axis
    matrix view WITHOUT mutating storage:

    * ``cols_level`` picks the ``component-of`` depth whose structure nodes are the
      COLUMNS (apex = 0, top-level dimensions = 1, …); ``None`` = every dimension
      node (the flat depth-1 grid).
    * ``rollup`` (default) makes each column's cell AGGREGATE its descendants'
      members (the confirmed §11.3 rollup), so flattening a deep tree never drops
      a member attached to an interior or leaf node below the pivot.

    Returns ``{"columns": [node_id, …], "membership": {node_id: {uid, …}}}`` where
    ``membership`` is keyed by EVERY structure node (so a caller can also read the
    rolled-up set for nodes off the column cut), and ``columns`` is the ordered
    column axis at the pivot.
    """
    loc = localize or (lambda s: s)
    # A column-axis pivot (``cols_level`` set) must expose the apex's rolled-up
    # membership: at ``cols_level == 0`` the apex IS the column, so excluding it
    # would silently drop the whole-corpus cell. ``cols_level=None`` keeps the
    # historical apex-excluded flat grid (byte-identical). Mirrors ``build_matrix``
    # (``exclude_apex = not pivoting``).
    exclude_apex = cols_level is None
    membership = _spine_membership_index(
        get_graph, loc, graph_name, rollup=rollup, exclude_apex=exclude_apex
    )
    columns = spine_columns_at_level(get_graph, loc, graph_name, cols_level)
    return {"columns": columns, "membership": membership}