T-31MH-capability-graph-opens-folded
State: planning/draft · Impact: medium · Complexity: medium
The System page’s Capabilities source opens fully unfolded, which is too small to read at 127 capabilities. Open it folded to a default depth, and group the capabilities that have no parent so they read as a set and not as 51 stray top-level boxes. Nesting is a modelling aid, so an unnested capability is normal and must not look like a defect or imply a parent.
solutions/ontological/experiences/system-graph/app/pages/apps/system-graph/index.vuesets the fold after each load (about L599-602):setCollapsed(source.value === 'capabilities' ? new Set() : defaultCollapsed(t)). The comment above it says a capability corpus is “a few dozen nodes in a handful of trees, which reads better open than folded”. That is stale:docs/planning/capabilities/holds 127 files.- Of those, 54 have
parent_key: null. Three of the 54 arekind: systemroots (C-0050, C-8FKM, C-HRNS). The other 51 are unnested and are not systems. A fourthkind: systemcapability, C-0001, has a parent (C-0055). app/lib/collapse.tsalready hasbuildTree,collapseToDepth,depthOfCollapse,maxDepth,expandTo,collapseAll,expandAllanddefaultCollapsed.defaultCollapsedfolds every container that is not a root, which equalscollapseToDepth(tree, 1).components/SystemGraphControls.vuehas the Depth slider (id="sg-depth",update:depth), and reads the depth back withdepthOfCollapse.app/lib/capability-projection.ts(projectCapabilities) maps a capability to aSystemNodewithparentandkind. Every node with no parent is a root intree.roots, andapp/lib/diagram.ts(L347-350) lays the roots out as the top level throughlayoutLevel(null, roots, ...). Nothing tells a system root from an unnested one.tests/collapse.test.tscovers the fold helpers. The package’s test script isbun test tests(its tests importbun:test).
Proposed
Section titled “Proposed”- The Capabilities source opens folded to depth 1: each root is open and shows its direct children,
everything below is folded. This is the existing
defaultCollapsedresult, so the page can use it for every source. Depth 1 is picked because the system roots then show their subsystems, which is the level the planning views are read at, while the 100-odd deeper capabilities stay behind a fold. Decision: depth 1. The constant lives in one place (CAPABILITY_DEFAULT_DEPTH), so a later change to 2 is a one-line edit. - Roots are split into two groups by a pure function: system roots (
kind: system) and unnested capabilities (no parent, notkind: system). The diagram draws the unnested group inside a labelled “Unnested” band, drawn behind the boxes. The band is a drawing aid only. It is not a node, it has no id in the graph, and it adds no edge, so ids, edges, selection and URLs are unchanged. - The stale comment in
index.vueis replaced with one that states the real count and the chosen depth.
Approach
Section titled “Approach”- Add
app/lib/capability-groups.tswithpartitionRoots(tree: Tree): { systems: string[]; unnested: string[] }. A root whose nodekindissystemgoes insystems; any other root goes inunnested. Order is payload order. Also exportCAPABILITY_DEFAULT_DEPTH = 1anddefaultCapabilityFold(tree: Tree): Set<string>returningcollapseToDepth(tree, 1). - In
index.vue, calldefaultCapabilityFold(t)for the capabilities source, drop thenew Set()branch, and rewrite the comment. - In
app/lib/diagram.ts, compute the bands insidelayoutDiagramfrompartitionRoots, solayoutDiagram’s call sites (SystemGraphDiagram.vue,lib/derive.ts) keep their signature. Order the top-level roots systems first, then unnested. Add a fieldbands: DiagramBand[]toDiagramLayout, whereDiagramBand = { label: string; x: number; y: number; width: number; height: number }. For the capabilities source it holds one band, labelled “Unnested”, whose rectangle is the bounding box of the placed unnested roots grown byPADDING; it is empty when there are no unnested roots or for other sources.SystemGraphDiagram.vuereadslayout.bandsand draws each as a non-interactive element behind the nodes, with its label, using only--d-*tokens. - Add tests (
bun:test) intests/capability-groups.test.tsfor the partition and the fold. - Check by eye against
sdf-servethat the page opens folded and the band appears.
| Area | Note |
|---|---|
solutions/ontological/experiences/system-graph/app/lib/capability-groups.ts | New pure partition and default fold |
solutions/ontological/experiences/system-graph/app/pages/apps/system-graph/index.vue | Use the default fold; fix the stale comment |
solutions/ontological/experiences/system-graph/app/lib/diagram.ts | Top-level order and band geometry |
solutions/ontological/experiences/system-graph/app/components/SystemGraphDiagram.vue | Draw the labelled band |
solutions/ontological/experiences/system-graph/tests/ | Partition and fold tests |
Acceptance criteria
Section titled “Acceptance criteria”- AC-1:
partitionRootsputs everykind: systemroot insystemsand every other root inunnested, and a node with a parent is in neither. A test builds a tree with both and asserts the two lists. - AC-2:
defaultCapabilityFoldequalscollapseToDepth(tree, CAPABILITY_DEFAULT_DEPTH), and a test asserts that roots stay visible and their direct children are visible while deeper nodes are folded. - AC-3: Loading the Capabilities source opens at that fold with no
collapsedvalue written to the URL, and the Depth slider reads1. - AC-4: The graph payload is unchanged: node ids, parents and edges are identical with and
without the band, asserted in a test over
buildTree. - AC-5: The diagram shows a band labelled “Unnested” around the unnested roots and none around
system roots; the band is not selectable and has no node id. A test over
layoutDiagramassertslayout.bandshas one entry that contains every unnested root’s box and no system root’s box. - AC-6: The comment in
index.vueno longer says “a few dozen nodes”, and the new one states the depth and why. - AC-7: The band and its label use only
--d-*design tokens.
Verification
Section titled “Verification”- CI is the typecheck.
vue-tscandnuxi typecheckare never run locally. cd solutions/ontological/experiences/system-graph && bun test testscd solutions/ontological/desktop/src-nuxt && bun run testcd solutions/ontological/desktop/src-nuxt && bun run generate- Run against
sdf-serve, the headless server from open PR #2546, open the System page, choose the Capabilities source, and check the fold depth and the Unnested band. Every/api/*request over HTTP needs the platform token; a browser without it must be given one in Settings.
Out of scope
Section titled “Out of scope”- Giving unnested capabilities parents. That is the containment pass over the corpus in the milestone, and it is a modelling task, not a view task.
- The
sdlc capability graphtree output. - Grouping in the matrix, chord, table or outline views.
- Treating an unnested capability as a finding anywhere.
Dependencies
Section titled “Dependencies”- none