All releases
Release
v1.2.15
What shipped, in numbers
- 26
- PRs merged
- 3,279,215
- Lines added
- 896,868
- Code lines
- Code
- 896,868
- Tests
- 985,929
- Docs
- 1,396,418
- Sum · code + tests + docs
- 3,279,215
of 26 merged
- bug 9 34%
- feature 14 54%
- polish 0 0%
- docs 2 8%
- groundwork 0 0%
- unclassified 1 4%
since v1.2.14 · tagged
What shipped
The release that carries a real customer onto FlowForge as their ticket system — and, getting there, finds that several things we believed were working had never been reachable, and that two "obvious" root causes were both wrong.
Your tickets arrive whole
- Open issues can be imported at all.
flowforge tickets pullwalks a repository's open and closed issues in one pass, filters pull requests out at the wire, and then reads the rows back and compares them by title and body, exiting non-zero on any gap. The verb it replaces imported closed history only — a count-only check would have scored a project "complete" while every row's content belonged elsewhere (#5204, #5207). - An interrupted import no longer poisons every retry. A row committed without its identity binding is an orphan: it holds an issue's number while resolving to nothing, so the next run tries to insert that number again and collides — at the same row, every time. The import now adopts orphans instead of failing on them (#5224, #5226).
- A ticket carries its buckets. The console can filter by bucket the way it already filters by project (#5205, #5206).
The board tells you the truth
- A GOLDEN pull request no longer reads as blocked. When a reviewer is non-deterministic and posts a second, contradicting verdict on bytes that never changed, the convergence ledger already recorded it as non-binding — but the merge queue rendered the variance as the status. Shippable work sat still while the board said it could not move (#5241, #5243).
- A worker row names which of four review states it is in — reviewer running, verdict bound, parked idle, or crew died. Before this, a worker whose reviewer had finished three hours earlier still displayed "reviewer running", so nobody knew to rescue it (#5241, #5243).
- The epic's indent was clamped, not missing. An epic nested inside a sprint rendered flush with its parent, so the two read as siblings. The ladder's nesting budget now fits the ladder it actually has (#5233, #5237).
- Creating an initiative refreshes the board. The create wrote to one projection and the ladder built its rows from another, so the new row appeared only after leaving the screen and coming back (#5234, #5238).
- The Fleet footer says what shipped — and what nobody labelled. The window's merged pull requests now break down as
▲ bug · ● feature · ▪ unclassifiedwith percentages, on a third pinned line that renders in every state: populated, empty, and still loading. The counts come from the provider-neutral classification map rather than by asking GitHub, so a project whose tickets live in FlowForge or Jira reads the same line as one whose tickets live in GitHub issues. Getting there turned up a footer that had been quietly losing its last row at 80 columns for as long as the ledger has been too wide to fit — the table reserved space by counting line breaks, which cannot see a line that wraps (#4274, #5252).
Buckets, comments, and the surfaces that were missing
- A bucket can be created without a terminal.
uopens the Buckets screen; a bucket is a lens over tickets that moves no work and changes no repository (#5227, #5229). - The desktop app can see and change its workspace.
⌘Kremains the project palette it has always been;Ctrl+Kis the workspace switcher — the same chord the cockpit uses, so the two surfaces stop disagreeing (#5228, #5232). - The Wave Screen has a reference, in English and Brazilian Portuguese — every shortcut verified against its key handler rather than a help string, and two long-standing questions answered at source: an epic opens neither a board nor a timeline, and pressing
ton one silently widens to its whole sprint (#5211, #5222).
Telemetry, and two wrong answers on the way to the right one
- The ingest endpoint accepts batches again. It had returned an opaque 500 for eighteen days. The first diagnosis — a missing
EXECUTEgrant — was wrong: the grant is absent by design, asserted as a pass condition by the migration that created the function, and granting it would have let any signed-in user write telemetry attributed to any organisation. The real fault was the caller identity, fixed with no migration at all (#5208, #5210). - The second diagnosis was also wrong. Once the endpoint could speak, it named a statement timeout, not a permission error: the saldo rebuild ran on the ingest write path. It comes off that path now (#5208, #5223).
- Adoption is readable.
public.v_team_adoptionreports active members, sessions started, active days and last activity per organisation — with the action set decided at source, so a lease release is never counted as a session start (#5209, #5215).
Your team can talk on a ticket
- A FlowForge ticket can be commented on. Volan runs FlowForge as their ticket system — FlowForge does not sync, it is the source of truth — so every conversation that used to live in a GitHub issue thread had nowhere to go. Ships the data seam, an unforgeable author taken from the session rather than the payload, tenancy proven under impersonation, keyset pagination, and a 16 KiB body bound enforced at both doors (#5230, #5235).
- And the cockpit surface to use it — read a thread and write to it, in English and Brazilian Portuguese, verified by render at 80×24 in both (#5248, #5250). Editing and deleting a comment is filed and not yet reachable (#5242).
- 🔴 Volan's historical GitHub comment threads are NOT in FlowForge. The importer never carried them: zero rows against 855 imported issues, and no comment was ever mapped. Importing them is its own decision with its own cost (#5236).
The board you can actually configure
- Create an epic from the War Room — the tier that groups tickets inside a sprint had no creation path at all; initiatives and sprints did (#5231, #5240).
public.v_projectandpublic.v_bucket— the console's project and bucket filters shipped weeks ago and had been refusing honestly ever since, because the two catalogue views they read did not exist. They exist now, and the filter went live with zero console changes (#5244, #5245).- Choose Ace's output style from Settings — a data-driven list, so a style added later needs no code change to the picker. It governs Ace's replies only: workers and reviewers emit machine-parsed markers a style layer could corrupt, and the screen says so (#5246, #5247).
- Fleet's classification counts now come from the agnostic map rather than a GitHub-shaped path, closing the Fleet Filters v2 umbrella (#4274, #5252).
Linux, and a guard that was right all along
- The Linux desktop AppImage. It had never shipped: the packaging step produced 14 KB stubs where real WebKitGTK helpers belong, and the blank-window guard correctly refused to package a desktop that would open an empty window. Earlier releases that did ship had the same defect and no guard — which is why they showed a white screen. The guard was never the problem (#5202, #5251).
Windows, answered
- WSL2 is the supported Windows path, and the native port is explicitly declined for now — ~1–2 engineer-weeks against 3–9 engineer-months for a port that would fork the process model the entire worker lifecycle depends on. The study measures it: of 358 non-test files mentioning tmux, 24 actually invoke it and 203 are prose. Two premises were corrected on the way — libghostty already supports Windows and is shipped as WASM anyway, so it was never the blocker; the desktop blocker is
creack/pty(#5253, #5254).
Known gaps
- Nothing schedules the telemetry export. Ingest works; a human still runs
flowforge supabase-export(#4461). - Importing is fast enough for a pilot, not for an estate — roughly 3.6 s per ticket against ~16 round-trips (#5225).
- Editing and deleting a comment is not yet reachable from the cockpit; writing and reading are (#5242).