feat: graph workspace and static analysis - #483
Merged
Conversation
Generalize PolicyWorkspace into Workspace: one store for policy and graph documents (DecisionContent union) with cross-document analysis. - Static type-flow analysis for decision graphs: topological walk with strict expression checking, switch branch narrowing, decision-node signature compatibility, output schema checks, coverage/nullability for decision tables, unreachable-node and parentheses lints - TypeScript function nodes: type stripping at compile time, types via consumer-provided resolver (sync callback or request/push), resolved types flow downstream instead of opaque walls - Dictionaries in graphs: imported through policy imports (forward-transitive), typed output columns, $dictionary input schema fields resolved to enums at eval, membership validation at runtime - Editor support for graphs: inspect/completions/NL via shared cursor, property and node rename with cross-document reference tracking, ReplaceNode edits - Trace enhancement for graph runs (per-node reads, DT row evaluations and inputPass bitmask, sub-decision recursion) - Workspace facade: generic paths()/remove_path() replace the policy/document-specific variants; nodejs binding exposes the full workspace API incl. ts-support helpers Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
ivanmiletic
approved these changes
Jul 16, 2026
Merged
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Graphs join the workspace
The workspace now stores decision graphs alongside policies and statically analyzes them. Types flow through the graph the way the runtime merges data: pass-through, loops, input and output field mappings, switch arms with branch narrowing, and nested decision nodes resolved against the callee's signature, whether that callee is a policy or another graph. Every expression is checked with the same strict checker policies use, with diagnostics anchored to the exact node, cell or expression. Nodes that cannot be typed (custom nodes, schema-less inputs) become opaque instead of guesses, and are listed so the editor can badge them.
TypeScript function nodes
Function nodes accept TypeScript, including enums. Sources are stripped to plain JS once at compile time instead of on every evaluation. Output types come from the host through a resolver callback or a request/push API, so a resolved function node types its downstream instead of ending the analysis.
Dictionaries in graphs
Graphs can import policies and use their dictionaries: decision-table output columns can be dictionary typed, and input schemas may declare
$dictionaryfields that resolve to string enums for both typing and validation. Membership is enforced at runtime as well as in diagnostics, dictionary labels appear in the natural-language projection, and resolution follows imports transitively, matching exactly what the runtime can load.Editor intelligence for graphs
Completions, hover, inspect and the natural-language projection work inside graph nodes through the same cursor API policies use. Properties and nodes can be renamed with references tracked across documents: renaming a policy output updates the graphs that call it, and graph property renames follow input/output mappings through nested decisions.
Explainable graph runs
Trace enhancement enriches a simulator run with per-expression reads and values, decision-table row evaluations with a per-cell input pass bitmask, and recursion into sub-decisions. A dependencies query returns the property dependency tree behind any output of a graph document.
Workspace API
paths()andremovePath()replace the separate policy and document variants and behave consistently for both kinds of documents. The nodejs binding exposes the full workspace surface, including the function-type resolver hook and ts-support helpers for typechecking function sources.Fixes
Traced and untraced decision-table evaluation now agree on first-hit selection, and a missing rule cell is treated as an empty cell in both, matching the analyzer. Dictionary diagnostics accept exactly what the runtime can resolve, no more and no less. Rename and reference spans are character offsets on every path, and renaming a field that exists only in a data model produces the correct edit again.
Business Value
Graph editing gets the same guardrails policies already have: type errors, unknown fields and uncovered tables surface while editing, anchored where they occur, instead of failing at runtime or silently producing nulls. Function nodes stop being walls in the analysis, so typed graphs stay typed end to end. Simulation explains itself, showing which rows matched and what each expression read. And what the editor reports is what the engine executes; the fixes close the remaining gaps where the two disagreed.