Skip to content

FE-784: Petrinaut export: colour-fold per-slice subnet#160

Open
kostandinang wants to merge 7 commits into
mainfrom
ka/fe-784-petrinaut-colour-fold
Open

FE-784: Petrinaut export: colour-fold per-slice subnet#160
kostandinang wants to merge 7 commits into
mainfrom
ka/fe-784-petrinaut-colour-fold

Conversation

@kostandinang
Copy link
Copy Markdown
Contributor

@kostandinang kostandinang commented Jun 1, 2026

Summary

This PR makes the Petrinaut export readable at scale by color-folding repeated per-slice topology into one shared slice lifecycle. Slice identity moves from node IDs into token color metadata, so a two-slice plan drops from 42 to 23 places and from 37 to 21 transitions.

The fold is an export projection only. Runtime Petri-net execution stays concrete; net.json, net.sdcpn.json, and petrinaut-events.jsonl all map that concrete runtime into the same folded view.

What Changed

  • Adds a shared NetFolding projection used by both static export and live events.
  • Folds uniform slice places and transitions while preserving genuinely divergent dependency gates.
  • Adds token type metadata for slice color in net.json and bumps the export schema to 0.2.0.
  • Keeps SDCPN export count-folded until Petrinaut supports discrete string token dimensions.
  • Adds regression oracles for fold divergence, SDCPN naming, folded event mapping, and loader schema validity.
  • Aligns Brunch naming with Petrinaut's colorId wire vocabulary and updates the spec lexicon.

Scope

The folded net is a faithful projection of the compiled blueprint, not a separate runtime model. Runtime files such as petri-net.ts and net-compiler.ts are not changed for execution semantics.

Verification

npm run verify passed: format and lint checks, full test suite, and production build.

@cursor
Copy link
Copy Markdown

cursor Bot commented Jun 1, 2026

PR Summary

High Risk
Large orchestrator changes touch net topology, async firing, git worktree isolation, and export/event contracts; regressions could affect cook runs, halt semantics, or Petrinaut integration without strong contract test coverage on every path.

Overview
Petrinaut legibility (FE-784) introduces createNetFolding so net.json, SDCPN export, and petrinaut-events.jsonl share one concrete→folded projection: repeated per-slice places/transitions collapse to slice-independent ids while slice identity moves onto token color (tokenTypes / place typeId, export schema 0.2.0). Dependency-divergent nodes (e.g. dep-gated slice-ready) stay concrete. Runtime firing remains per-slice; only the visualization/export layer folds.

Brownfield cook replaces the reserved stub with resolveCookMode: .brunch/cook/plan.yaml triggers git-backed sandbox init (clean-tree gate, parent cook/<runId> worktree, per-slice cook-slice/<runId>/<sliceId> worktrees plus CoW copy of untracked deps). Cook artifacts and docs move from .cook/ to .brunch/cook/; integration smoke asserts source repo byte-identical isolation.

Petri-net / Petrinaut alignment (FE-761–763) refactors branching into sibling transitions with EnablingGuard, splits long-running steps into dispatch → running → complete with deferred async handlers, routes halts via :halted places and token haltReason (replacing ctx.halted), and emits net.json / event JSONL from the engine when runDir is set (failures surface as run warnings, not hard failures).

Planning/spec docs (orchestrator.md, PLAN.md, SPEC.md) and a new docs/praxis/orchestration-guide.md record codebase mode, Petrinaut integration track, and cook-on-brunch workflow.

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

Comment thread src/orchestrator/src/petrinaut-fold.ts
@augmentcode
Copy link
Copy Markdown

augmentcode Bot commented Jun 1, 2026

🤖 Augment PR Summary

Summary: Implements FE-784 “color fold” for Petrinaut exports by collapsing per-slice subnets into a single slice-independent projection while preserving slice identity on per-token color.

Changes:

  • Adds petrinaut-fold.ts with createNetFolding() (folded places/transitions/marking, transition id folding, and SliceColor token type)
  • Updates serializeBlueprint to export folded topology + initial marking, adds tokenTypes and optional place typeId, bumps schema to 0.2.0
  • Threads a single folding instance into the live Petrinaut event stream so exported net.json and emitted events fold identically
  • Adds focused fold-rule tests and “divergence oracle” tests to pin which transitions remain per-slice
  • Extends SDCPN export tests to validate naming/collision behavior on a real 2-slice folded net
  • Updates PLAN/SPEC lexicon entries and retires memory/CARDS.md

Technical notes: Folding keeps certain dependency-gated transitions concrete (e.g. slice-ready, return-done) while folding uniform lifecycle transitions and moving slice identity to token color dimensions.

🤖 Was this summary useful? React with 👍 or 👎

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.

Comment thread src/orchestrator/src/petrinaut-fold.ts
@kostandinang kostandinang force-pushed the ka/fe-763-petri-event-stream branch from a26f784 to ea6bae2 Compare June 2, 2026 07:31
@kostandinang kostandinang force-pushed the ka/fe-784-petrinaut-colour-fold branch from 01f5f73 to 5303ecc Compare June 2, 2026 07:31
Copy link
Copy Markdown

@cursor cursor Bot left a comment

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 5303ecc. Configure here.

Comment thread src/orchestrator/src/petrinaut-fold.ts
@kostandinang kostandinang force-pushed the ka/fe-763-petri-event-stream branch from ea6bae2 to 4fad33b Compare June 2, 2026 08:11
@kostandinang kostandinang force-pushed the ka/fe-784-petrinaut-colour-fold branch 2 times, most recently from 1ff3253 to aa37122 Compare June 2, 2026 09:03
@kostandinang kostandinang force-pushed the ka/fe-763-petri-event-stream branch from 3242403 to fc96a0b Compare June 2, 2026 09:56
@kostandinang kostandinang force-pushed the ka/fe-784-petrinaut-colour-fold branch from aa37122 to b7e96aa Compare June 2, 2026 09:56
@kostandinang kostandinang changed the base branch from ka/fe-763-petri-event-stream to graphite-base/160 June 2, 2026 11:40
@kostandinang kostandinang force-pushed the ka/fe-784-petrinaut-colour-fold branch from b7e96aa to b56f559 Compare June 2, 2026 11:40
@kostandinang kostandinang changed the base branch from graphite-base/160 to ka/fe-763-petri-event-stream June 2, 2026 11:40
@kostandinang kostandinang changed the base branch from ka/fe-763-petri-event-stream to graphite-base/160 June 2, 2026 12:40
@kostandinang kostandinang force-pushed the ka/fe-784-petrinaut-colour-fold branch from b56f559 to 5ced434 Compare June 2, 2026 12:40
@kostandinang kostandinang changed the base branch from graphite-base/160 to ka/fe-763-petri-event-stream June 2, 2026 12:40
@kostandinang kostandinang changed the base branch from ka/fe-763-petri-event-stream to graphite-base/160 June 2, 2026 13:06
@kostandinang kostandinang force-pushed the ka/fe-784-petrinaut-colour-fold branch from 5ced434 to 1c21816 Compare June 2, 2026 13:07
@kostandinang kostandinang changed the base branch from graphite-base/160 to ka/fe-763-petri-event-stream June 2, 2026 13:07
@graphite-app graphite-app Bot changed the base branch from ka/fe-763-petri-event-stream to graphite-base/160 June 2, 2026 16:41
@kostandinang kostandinang self-assigned this Jun 2, 2026
kostandinang and others added 7 commits June 2, 2026 20:52
Fold the per-slice concrete subnet (slice:<sid>:*) N→1 in the Petrinaut
export projection, carrying slice identity on the token colour instead of
in the node id. Petrinaut's canvas is flat (no hierarchy/grouping), so
collapsing the N structurally-identical slice subnets into one is the only
way the imported net stays legible at scale — and it dissolves most of the
per-slice naming problem.

Projection only — runtime (petri-net.ts / net-compiler.ts) is untouched;
the live event adapter maps concrete firings onto the same folded net.

- petrinaut-fold.ts (new): pure fold rules. foldPlaceId strips slice:<sid>:
  (per-edge dep-signal:<dependent> places stay unique); foldTransitionId
  removes the owning slice-id segment; buildTransitionFoldMap collapses
  groups with identical folded shape but keeps divergent ones (dep-gated
  slice-ready, dep-signalling return-done) at concrete ids. Defines the
  SliceColour token type.
- petrinaut-export.ts: serializeBlueprint folds places/transitions/arcs and
  the initial marking; adds tokenTypes + place typeId; schema 0.1.0 → 0.2.0.
- petrinaut-events.ts: transition_fired / initial_marking fold concrete →
  folded ids (blueprint-derived map, with per-event fallback), keeping slice
  colour on the token.
- SDCPN export stays count-fold (colorId: null) until Petrinaut supports
  discrete string token dimensions (H-6518/H-6519).

net.json envelope is additive; folded counts pinned (depPlan 42→23 places,
37→21 transitions). Full gate green (check/test/build).

Co-Authored-By: Claude <noreply@anthropic.com>
…stream

The colour-fold was split across petrinaut-fold.ts (primitives),
serializeBlueprint, and the event adapter, with the event stream capturing
fold context as a side effect of emitInitialMarking (silently degrading if a
firing arrived before it). Extract a single NetFolding object that owns the
whole concrete→folded projection.

- petrinaut-fold.ts: add createNetFolding(blueprint) → NetFolding with
  foldedPlaces / foldedTransitions / foldedMarking<T> / foldTransition /
  tokenTypes. The id maps stay private; foldPlaceId, foldTransitionId,
  collectSliceIds, buildTransitionFoldMap, foldedShapeSignature are no longer
  exported (no parallel API to drift from the folded net).
- serializeBlueprint: consumes the folding; keeps schemaVersion, UUID mint,
  shortPlaceLabel, seedToToken.
- createPetrinautEventStream: takes `folding` at construction; deletes the
  let sliceIds/transitionFoldMap capture and the per-event collectSliceIds
  fallback. foldedMarking<T> replaces the duplicated groupTokens + byPlace
  grouping in both consumers.
- engine.ts threads one createNetFolding(blueprint) into the stream.

Seam invariant: static net.json and the live stream fold identically because
both derive from one NetFolding (engine-contract e2e covers it). Behaviour-
preserving: export/events/engine-contract assertions unchanged; fold-rule
tests re-expressed against the public surface. Full gate green.

Co-Authored-By: Claude <noreply@anthropic.com>
The fold keeps divergent transitions concrete and folds uniform ones, but
nothing asserted *which* transitions diverge — a future compiler change that
made a uniform lifecycle transition split per slice would silently re-expand
the graph while reading as "fold worked".

Add an oracle over createNetFolding(compileTopology(depPlan)): the set of
foldedTransitions whose id still carries a slice-id segment must equal exactly
{slice-ready:slice-a, slice-ready:slice-b, slice-a:return-done,
slice-b:return-done}. Exact-set equality, so any extra divergence fails it.

Pure test addition. Full gate green (1504 tests).

Co-Authored-By: Claude <noreply@anthropic.com>
The fold's original motivation was clean SDCPN names — unfolded, every slice's
`slice:slice-N:spec-ready` PascalCased to the same base and the name allocator
appended collision counters (SliceSliceSpecReady2). Nothing tested that the
fold dissolved this.

Add oracles over toSdcpnFile(realNet(depPlan)): no place name carries an
allocator digit suffix (pascalCaseLetters strips source digits, so any digit
is a collision counter) and names are unique; the shared lifecycle place
appears once and the 2-slice place count stays well under 2× the single-slice
net; the file still satisfies the Petrinaut loader schema.

Pure test addition. Gate green (orchestrator 161, check 0 errors, build ✓).

Co-Authored-By: Claude <noreply@anthropic.com>
Brunch-owned fold identifiers were British (SLICE_COLOUR_TYPE, 'slice-colour',
SliceColour) while the Petrinaut wire field is American (colorId). Rename to a
single spelling matching the wire contract: SLICE_COLOR_TYPE /
SLICE_COLOR_TYPE_ID / 'slice-color' / SliceColor, plus colour→color across the
fold's comments. Petrinaut's own colorId field is unchanged.

Add SPEC §Lexicon entries for the durable concepts: `color fold`,
`token color`, `folded net`.

Retire memory/CARDS.md — the FE-784 follow-up queue (#3, #4, #6) is exhausted.

Pure rename + docs. Gate green (check 0 errors, orchestrator 161, build ✓).

Co-Authored-By: Claude <noreply@anthropic.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
@kostandinang kostandinang force-pushed the ka/fe-784-petrinaut-colour-fold branch from 1c21816 to bfb687f Compare June 2, 2026 18:55
@kostandinang kostandinang changed the base branch from graphite-base/160 to main June 2, 2026 18:56
@kostandinang kostandinang requested a review from lunelson June 3, 2026 06:56
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