Download Latest Version flow-next v3.15.1 source code.zip (16.8 MB)
Email in envelope

Get an email when there's a new version of Flow-Next

Home / flow-next-v3.13.2
Name Modified Size InfoDownloads / Week
Parent folder
flow-next v3.13.2 source code.tar.gz 2026-08-02 13.7 MB
flow-next v3.13.2 source code.zip 2026-08-02 16.3 MB
README.md 2026-08-02 7.2 kB
Totals: 3 Items   29.9 MB 0

Three chart defects that all failed the same way - silently. A reopened chart could not get back to capture, a supersession could wire a replacement to the premise it had just superseded, and an ambiguous initial map resolved edges to the wrong decision. None of them raised, none logged; each persisted a chart that looked correct and answered every later question from the wrong state. Plus a CI change that is invisible to anyone running flow-next: the repo's own test runner now uses the whole build machine.

Reopening a chart no longer costs you the way back to capture. chart reopen does not re-open the decisions, so a finished chart is ready to brief again the moment it reopens - and asking for that briefing, same proposal over an unchanged ledger, used to hand back the briefing the reopen had just staled and call it a no-op. You were left with a chart reporting itself ready to brief, no capture-ready package, no path to one, and nothing on screen saying why. A reopen now counts as a new epoch, so the same proposal mints the next briefing package and names what it supersedes.

Fixed

  • Running the suite from a Cursor agent session keeps its local headroom. Cursor sets CI=1 in its agent shell, so CI detection alone would have handed the whole machine to the test runner on a developer box - starving the editor and the agent that the two-core reservation exists to protect. A non-empty CURSOR_AGENT now forces the local branch; hosted runners never set it, so real CI is unaffected.
  • A superseded premise no longer strands the decision that depends on it. When one supersession cascaded through several resolved dependents, the cascade processed them in local D-number order, not premise-first. A dependent numbered ahead of its own premise was replaced first, so its replacement was wired to the premise the same cascade was about to supersede rather than to that premise's replacement. Nothing raised, nothing logged: the chart persisted a graph that looked correct and answered every later supersession, briefing, and capture question from the stale edge. Cascades now walk the dependency graph premise-first (Kahn's algorithm with a min-heap on the local D-number), so equal-eligibility decisions still emerge in ascending D-number and identical ordered inputs reproduce byte-identical affected, cascade_open, cascade_resolved, and replacements arrays. --keep-dependents is untouched - it keeps emitting dependents in local-number order from its own call site, so its public --json arrays are byte-identical to before.
  • An ambiguous initial map is refused instead of silently mis-wired. chart create --initial-map-file resolves edges through one flat alias namespace - the ordinal <n>, the d<n> form, the full decision id, and an optional explicit id - and every one of those was a plain assignment where the last writer won. A decision supplying id: "d7" while D7 did not exist yet had its alias silently taken over when decision [#7] registered its own generated d7, and every edge naming that alias then pointed at the wrong decision. Graph validation could not catch it: it runs on the already-resolved graph, where the mis-wiring looks perfectly valid. One alias claimed by two different decisions is now refused up front with a validation / alias_collision error naming the alias and both claimants (first is the incumbent, second the rejected one), documented in docs/flowctl.md. Legal input is unchanged: the same alias registered twice for the same decision is still idempotent - an explicit id equal to that decision's own generated alias keeps working - and an id that normalizes to the empty string is still ignored. A rejection makes no durable reservation and writes no file, so the next valid create still receives the same fn-N.
  • A reopened chart can always be briefed again. chart reopen stales the existing briefing, which is right - it was written before the reopen. But briefing identity was computed from the chart revision, the proposal, and the rendered decision evidence, and from none of what a reopen changes, so re-running the same proposal over an unchanged ledger matched the staled package and echoed it back with noop: true. (Change a decision or its evidence first and the hash moved, so that route always minted normally; the stranded case is the one where nothing else changed - and a reopen alone is enough to make a finished chart briefable again.) Nothing hinted that a changed proposal was the only way out, and downstream surfaces that correctly gate capture on a final briefing rendered a door that could not open. The chart's reopen timestamp is now part of briefing identity, so a post-reopen re-brief takes the ordinary emission path: it mints B(n+1), recomputes draft-versus-final from the live chart (a stale draft can never silently become final), rewrites the convenience copies in step with the sidecar, runs in the existing transaction and lock, and projects to the tracker like any other briefing. Charts that were never reopened keep byte-identical fingerprints - the key is omitted rather than hashed as null - so a B-ID minted by an earlier version still matches an identical retry after the upgrade, proven against a checked-in pre-fix sidecar fixture. A briefing whose status is stale is never returned as an idempotent answer even when its stored hash matches, so a sidecar written by an older binary or edited by hand cannot bring the echo back.

Added

  • The briefing tells you what it just did. A fresh emission that supersedes staled predecessors now reports them: supersedes_stale (array of B-IDs, in sidecar order) in the --json result, and (supersedes stale B1) on the human line, in place of the misleading status=stale (noop) the defect produced. Presence is the discriminator, so the key is absent from first emissions, idempotent retries, and error envelopes: every non-superseding response is byte-unchanged, and the only result whose shape changes is one that genuinely supersedes staled briefings. It reports the invocation only: per-briefing status in the chart sidecar's briefings[] stays the single source of truth for capture-readiness.

Changed

  • The repo's own parallel test runner stops leaving CI cores idle. scripts/run_tests_parallel.py reserved two cores unconditionally. That reservation exists for machines with a human on them - an editor, a language server, an agent - and a build machine has none of that. The default is now the full core count when CI is set (1/true/yes, case-insensitive) and unchanged (cpu_count - 2) everywhere else; absent, empty, false, 0 and anything unrecognized all mean local, and TTY state is deliberately not part of the signal. --jobs and --serial still override, in that order, and the file set is unchanged - no test selection, no path filters, nothing skipped. The runner also gains its first tests. Maintainer-only CI tooling: nothing changes for anyone installing or running flow-next.
Source: README.md, updated 2026-08-02