Skip to content

feat: hierarchy outline rows a producer can shape: groups, nodes, labels - #102

Merged
endrix merged 5 commits into
mainfrom
feat/outline-rows
Oct 24, 2026
Merged

endrix merged 5 commits into
mainfrom
feat/outline-rows

Conversation

@endrix

@endrix endrix commented Oct 23, 2026

Copy link
Copy Markdown
Owner

Summary

The hierarchy outline (modelled on mlir-viewer's) lists views by instance name. That's the whole story for a workflow hierarchy, but too little for a product whose units have their own structure: a specification's chapters, its documents by title, and the clauses in each. This lets a producer shape its rows, with optional fields on HierarchyOutlineEntry:

  • role: 'group': a heading over other rows (a folder, a layer) that only opens and closes. It's transparent to paths (hierarchyPathChildren): hierarchyEntryAt and the trails look through it, so a document's path is still its id and a group is never a crumb. While rendered, rows are kept by row id, since a group has no path to look it up by.
  • role: 'node': a node inside the view above, named by the producer's nodeId and found through wf:graphNodeId. That key is now on every node: the same line feat: links, file targets and editable fields in the property panel #100 and feat: a status source, node states from a report drawn with the run overlay #101 add, so whichever merges second resolves a one-line overlap.
    • A click selects and centres the node, opening that view first when another is shown.
    • A double click runs the canvas's own double-click listeners on it, so it does what the canvas would.
  • label, detail, family, badges: what the row says and what follows it (the filter matches both), the node family's colour from the profile, and badges in the header's tones.
  • Current row: the current view's row opens along with its own group rows, so the units on screen are listed.
  • Layout: a labelled row drops the file chip; the detail gives way before the label; the panel takes up to 380 px, never more than half the editor.
  • clientBehavior.outlineTitle: the panel's title and its button's tooltip ("Hierarchy" by default). The filter just says "Filter…".

A hierarchy that sets none of these renders and behaves as before (the existing outline tests hold).

The ndf CLI (PTO-ISA/normative_language#8) now emits such an outline: folders, documents by title, and clauses under their refinement layers, with kind and modality. picorv32's is 357 rows.

Test plan

  • npm run typecheck, npm run check:neutrality, all four suites
  • hierarchy-outline.test.ts (+5): looking up through groups by a row's own path, a trail with no group crumb, opening down to the current view including its groups, label/detail and filtering by either, finding a node by producer id.
  • Headless on the integration branch, with the real client, the NDF profile and picorv32's 10-architecture/pipeline.md as the current view:
    • The panel lists chapters, documents and the current document's layers and clauses, with colour chips and badges.
    • Clicking a clause selects it on the canvas.
    • Double-clicking it opens its refinement trace in place, and only that (see the fix on feat: links, file targets and editable fields in the property panel #100).
    • Filtering FSM-LATCH leaves its path open.
    • Clicking that clause, which is in another document, requests that document's view, with the selection to follow.
  • Live in VS Code: the selection after an in-place open lands on the clause.

https://claude.ai/code/session_01E8WfqKknDNN6xpNVcJL5K8

The outline lists views by instance name, which is the whole story for a
workflow hierarchy and too little for a product whose units have a
structure of their own: a specification's chapters, its documents by title,
the clauses in each.

`HierarchyOutlineEntry` gains optional `role`, `label`, `detail`, `family`
and `badges`:

- `group` rows (a folder, a layer) only open and close. They are transparent
  to paths (`hierarchyPathChildren`): `hierarchyEntryAt` and the trails look
  through them, so a document's path is still its id and a group is never a
  crumb. Rows are kept by row id while rendered, since a group has no path
  to be looked up by.
- `node` rows stand for a node in the view above them, by the producer's
  `nodeId`, found through `wf:graphNodeId` (now on every node; the same line
  #100 and #101 add). A click selects and centres it, opening that view
  first when another is shown; a double click runs the canvas's own
  double-click listeners on it, so it does what the canvas would.
- Rows show the label and detail (the filter matches both), the family's
  colour from the profile's node families, and badges in the header's
  tones. The current view's row opens with what is in it
  (`hierarchyRowsTo`).

A hierarchy that sets none of these renders and behaves exactly as before.

Claude-Session: https://claude.ai/code/session_01E8WfqKknDNN6xpNVcJL5K8
A view's own groups (a document's refinement layers) only arrange what it
holds; left closed, the clauses of the document on screen were one more
click away in the outline.

Claude-Session: https://claude.ai/code/session_01E8WfqKknDNN6xpNVcJL5K8
A product's outline is not always a hierarchy of instances: a
specification's is its chapters, documents and clauses. The panel's title
and its button's tooltip come from clientBehavior.outlineTitle (still
"Hierarchy" by default), and the filter just says "Filter...". A row the
producer labels drops the file chip, its label shrinks before its count,
and the panel takes up to 380 px, half the editor at most.

Claude-Session: https://claude.ai/code/session_01E8WfqKknDNN6xpNVcJL5K8
Both shrank alike, so a clause's id was cut as short as its title. The
detail now takes what is left of the row and is the first to shrink.

Claude-Session: https://claude.ai/code/session_01E8WfqKknDNN6xpNVcJL5K8
Review of #102: `rowIdsTo` returned nothing when the shown view was not in
the outline (below a row the producer cut short), where the outline used
to open the ancestors down to the deepest row it knew. It now falls back
to the rows down to the deepest entry on the view's path that the outline
lists.

Claude-Session: https://claude.ai/code/session_01E8WfqKknDNN6xpNVcJL5K8
@endrix
endrix merged commit 2132328 into main Oct 24, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant