Skip to content

FE-747: Declarative output arcs β€” topology-level routing for branching transitions#154

Open
kostandinang wants to merge 4 commits into
graphite-base/154from
ka/fe-747-petri-declarative-routing
Open

FE-747: Declarative output arcs β€” topology-level routing for branching transitions#154
kostandinang wants to merge 4 commits into
graphite-base/154from
ka/fe-747-petri-declarative-routing

Conversation

@kostandinang
Copy link
Copy Markdown
Contributor

@kostandinang kostandinang commented May 25, 2026

TL;DR. Moves conditional output routing from wireHandlers fire closures into typed RouteGuard predicates on HandlerDescriptor. Topology-only consumers can now enumerate reachable output places per transition without instantiating actions, reports, or the test runner. FE-700-independent Phase-3 prep that also satisfies Phase 4 simulation's routing-side structural prerequisite.

What changed

Declarative routing on HandlerDescriptor

  • ActionDescriptor.routeField?: string β†’ guard: RouteGuard (required; {kind: 'always'} for unconditional).
  • RunTestsDescriptor adds passGuard: RouteGuard.
  • AssessSemanticDescriptor adds satisfiedGuard: RouteGuard.
  • Initial guard vocabulary: always, reportFieldTruthy. Extension shape documented in code.

Pure interpreter and topology consumer

  • evalRouteGuard(guard, report): boolean β€” pure helper consumed by wireHandlers.
  • enumerateCandidateOutputs(transition): Set<string> β€” returns the topology-derived output-place set per transition without runtime instantiation.

No inline if-ladders on report payloads in fire closures.

Invariant I125-K in memory/SPEC.md protects topology-side analyzability.

Why now

First Phase-3 prep step independent of FE-700 (intent-graph-semantics). Without declarative guards, formal analyses (reachability, deadlock detection, simulation) can only see input-side structure β€” which would make petri-simulation-oracle (Phase 4) impossible regardless of when Phase 3 graph compilation lands.

Verification

  • Engine contract suite (12+ scenarios, both engines) passes unchanged β€” runtime equivalence preserved.
  • New topology.test.ts β€” 12 tests covering evalRouteGuard purity, enumerateCandidateOutputs per descriptor kind, and 3 literal-fixture goldens that catch lockstep drift between emitter and enumerator.
  • npm run verify green β€” 122 test files, 1421+ tests pass.

Out of scope

Halt paths (run-tests retry exhaustion, assess-semantic rework exhaustion, verify-epic failure) still mutate ctx.halted from fire closures. Token transforms (reportId attach, retry/rework propagation, budget decrement) stay in closures. verify-epic still reads report.payload.passed inline. All flagged as follow-on slices in I125-K.

Traceability

Requirements 46, 47, 48; D155-K (refinement of FE-738 HandlerDescriptor design); invariant I125-K. Frontier petri-declarative-routing in memory/PLAN.md. Under umbrella H-6476.

kostandinang and others added 4 commits May 26, 2026 01:19
New TRACK F frontier between petri-epic-verification-merge (done) and
petri-graph-compilation (horizon, blocked on FE-700). Moves conditional
output routing from wireHandlers fire closures into typed Guard predicates
declared on HandlerDescriptor so a topology-only consumer can enumerate
reachable output places per transition without invoking actions, reports,
or the test runner β€” structural prerequisite for any static analysis
(simulation, reachability, deadlock detection) and FE-700-independent.

Retires the "Declarative output arcs" sub-bullet under petri-graph-compilation
since it's now its own frontier; keeps "Token state enrichment" there.

Co-Authored-By: Claude <noreply@anthropic.com>
Move conditional output routing from wireHandlers fire closures into typed
Guard predicates declared on HandlerDescriptor. ActionDescriptor gains a
required guard:Guard (replacing routeField); RunTestsDescriptor adds
passGuard; AssessSemanticDescriptor adds satisfiedGuard. wireHandlers
consumes them via a pure evalGuard(guard, report) helper.

Adds enumerateCandidateOutputs(transition) so static consumers can derive
the reachable output-place set per transition from topology alone, without
instantiating actions, reports, or the test runner. Halt paths (budget
exhaustion, verify-epic failure) and token transforms stay in fire closures
and remain follow-on slices.

New invariant I125-K. Engine contract suite unchanged (84 orchestrator
tests pass); npm run verify green.

Co-Authored-By: Claude <noreply@anthropic.com>
Disambiguates the typed routing predicate from TransitionContract.guard,
the pre-existing human-readable note string on the same record.
Pure rename across net-blueprint.ts (type + interpreter), net-compiler.ts
(consumer), and topology.test.ts. Descriptor field names (passGuard,
satisfiedGuard, ActionDescriptor.guard) keep their domain identifiers.
No behavior change; 84 orchestrator tests pass.

Co-Authored-By: Claude <noreply@anthropic.com>
The existing per-kind tests computed expected output sets from the same
descriptor fields the enumerator consumes, so they'd pass silently if both
the topology emitter and the enumerator dropped a branch in lockstep. Add
three goldens that pin literal expected place names for slice-1:evaluate,
slice-1:run-tests, and slice-1:assess-semantic against the simplePlan
fixture. Lockstep drift now surfaces immediately.

Retires memory/REFACTOR.md (FE-747 refactor pass complete).

Co-Authored-By: Claude <noreply@anthropic.com>
Copy link
Copy Markdown
Contributor Author

@kostandinang kostandinang changed the title FE-747: Add petri-declarative-routing frontier to plan. FE-747: Declarative output arcs β€” topology-level routing for branching transitions May 25, 2026
@kostandinang kostandinang marked this pull request as ready for review May 26, 2026 07:52
@cursor
Copy link
Copy Markdown

cursor Bot commented May 26, 2026

PR Summary

Low Risk
Refactor preserves dual-engine contract behavior; risk is limited to orchestrator routing equivalence, covered by existing contract tests plus new topology tests.

Overview
FE-747 moves Petri branching from inline report checks in wireHandlers into declarative RouteGuard data on HandlerDescriptor (always, reportFieldTruthy), with evalRouteGuard at fire time and enumerateCandidateOutputs for topology-only output-place sets. compileTopology now emits guards on evaluate, write-tests/code, run-tests, and assess-semantic; net-compiler routes actions and test/semantic branches through evalRouteGuard instead of ad hoc payload reads.

I125-K in memory/SPEC.md and petri-declarative-routing (done) in memory/PLAN.md record the change; Track F notes declarative routing unblocks simulation’s routing side while graph compilation (FE-700) is still required for graph-derived gates. Halt paths, budget exhaustion, token transforms, and verify-epic pass/fail in closures are unchanged (out of scope).

Reviewed by Cursor Bugbot for commit f9de408. Bugbot is set up for automated code reviews on this repo. Configure here.

Copy link
Copy Markdown

@augmentcode augmentcode Bot left a comment

Choose a reason for hiding this comment

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

Review completed. 1 suggestion posted.

Fix All in Augment

Comment augment review to trigger a new review at any time.


export type RouteGuard = { kind: 'always' } | { kind: 'reportFieldTruthy'; field: string };

export function evalRouteGuard(guard: RouteGuard, report: ReportLine | undefined): boolean {
Copy link
Copy Markdown

@augmentcode augmentcode Bot May 26, 2026

Choose a reason for hiding this comment

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

evalRouteGuard currently has no explicit fallthrough handling, so an unknown/malformed guard.kind at runtime would return undefined (treated as false) and could silently misroute. Since guards are pure data (and may eventually be serialized/deserialized), consider making unsupported kinds fail fast to protect routing correctness.

Severity: medium

Fix This in Augment

πŸ€– Was this useful? React with πŸ‘ or πŸ‘Ž, or πŸš€ if it prevented an incident/outage.

@kostandinang kostandinang changed the base branch from ka/fe-745-petri-epic-verification-merge to graphite-base/154 May 26, 2026 08:21
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