Skip to content

feat(graph): graph engine core — node kinds, registries, host effects - #983

Merged
drewstone merged 1 commit into
mainfrom
feat/graph-engine-core
Aug 22, 2026
Merged

feat(graph): graph engine core — node kinds, registries, host effects#983
drewstone merged 1 commit into
mainfrom
feat/graph-engine-core

Conversation

@drewstone

Copy link
Copy Markdown
Contributor

Map: #966 · ticket: #979 (engine build 1/4) · spec: #969 (contract), #970 (kinds), #978 (registry).

What lands

@tangle-network/agent-runtime/graph (new subpath), offline and kernel-hosted:

  • NodeKind — declarative record: id/version, validateConfig by name (no zod), typed inputs/outputs ports, declared effects, onCrash, budget, run(...) returning the Agent that Scope.spawn hosts. validateNodeKind refuses implicit out/trace ports, duplicate ports, unknown policies. narrowEffects hands a kind exactly what it declared, frozen, and refuses before the node runs when the host lacks one, listing what the host has.
  • Registry<T> — enumerable, per-instance, require refuses by name and lists what is registered; handle prints <id>/v<n>.
  • Four core kindsagent (→ workerFromBackend), supervisor (→ supervisorAgent), script (pure ⇒ exempt + content-addressed; metered-without-report ⇒ UNKNOWN), subgraph (validates and registers; run waits for the scheduler, Engine build 2/4: scheduler over typed ports — three edge kinds, guards, joins, visit caps, terminals #980). createGraphEngine({ coreKinds, kinds, effects }) + missingEffects().

Two kernel changes the engine needed, each useful on its own:

  1. Verbatim-executor intake.scope.spawn required every AgentSpec.profile to select a harness and model, including a spec carrying a verbatim executor — which sees only (task, signal), so nothing could fill it from ambient config. A script runs no model; claiming one would lie in the journal identity. A verbatim executor now needs a parsed profile, not an executable one; factories, harnesses and the router keep the full requirement. The script kind stamps execution.correlation.nodeKind so identity never collides across kinds.
  2. Spend contract at settle. An executor whose artifact carried no Spend crashed the child with a raw TypeError and leaked its reservation (reconcile ran on undefined). scope.spawn now refuses it by name before it can replace the live spend; the child goes down, the reservation reconciles on what was proven, and the pool is sealed unknown as on any crash.

Acceptance (#979 "done when") → proof

ItemWhere
Registry: enumeration, refuse-by-name listing known, per-instance, <id>/v<n>tests/graph/registry.test.ts
Each core kind constructs; undeclared effect unreachable; metered-without-Spend is an engine errortests/graph/kind.test.ts, tests/graph/kinds.test.ts (real Scope)
Generality: ADC integration.invoke + notify as NodeKinds against a fake host; engine source names neithertests/graph/fixtures/adc-kinds.ts, tests/graph/adc-kinds.test.ts, tests/graph/generality.test.ts
oracle: true refused as delegates/data target at compilemoved to #980 — build 1 has no graph definition or edges; the refusal is written with the compiler that owns them
typecheck, lint, check:version-bump (minor), docs regeneratedall green; api-surface.json, fixtures, docs/api regenerated

Verification

  • pnpm run typecheck 0 errors · pnpm run lint clean · pnpm run docs:api + docs:freshness green · check:version-bump → minor.
  • Local full suite diffed against an unmodified origin/main checkout on the same host: identical failing-file set (macOS baseline: /var symlinks, 127.0.0.53, Linux-only paths), 0 regressions. tests/untracked-clone.test.ts flaked once under load and passes alone.
  • Targeted: tests/graph 37/37, tests/kernel + src/runtime/supervise green except the 127.0.0.53 bind (baseline).

Version 0.162.0; CHANGELOG entry included. Follow-ups: #980 scheduler, #981 fold + replay, #982graphFromRunGraph.

Add `@tangle-network/agent-runtime/graph`: the `NodeKind` contract, `Registry<T>`,
the four core kinds (agent, supervisor, script, subgraph) and `createGraphEngine`.
A host extends the engine by registering kinds and effects; the engine source names
no host kind (a test greps for it), and ADC's `integration.invoke` and `notify` are
written as fixtures against a fake host to prove it.
Two kernel changes:
- `scope.spawn` admits a verbatim `executor` on a parsed profile; the executable
identity rule stays for factories, harnesses and the router.
- An artifact with no `Spend` is refused by name before it replaces the live spend,
so the child goes down and its reservation no longer leaks.
Map #966, ticket #979. Version 0.162.0.

@tangletoolstangletools left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Auto-approved drewstone PR — 5ec25b8e

This PR was opened by the trusted drewstone account.

This approval is provisional and was applied by the local stand-in because the pr-reviewer webhook host is unreachable (2026-08-21). CI on this head is fully green. The full PR reviewer audit re-runs via the resweep when the service returns and will publish findings if it detects issues.

@drewstone
drewstone merged commit c345b13 into mainAug 22, 2026
4 checks passed
@drewstone
drewstone deleted the feat/graph-engine-core branch August 22, 2026 07:32
Sign up for freeto 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.

2 participants

@drewstone@tangletools