FS.GG.Coord.Cli
0.78.0
Prefix Reserved
See the version list below for details.
dotnet tool install --global FS.GG.Coord.Cli --version 0.78.0
dotnet new tool-manifest
dotnet tool install --local FS.GG.Coord.Cli --version 0.78.0
#tool dotnet:?package=FS.GG.Coord.Cli&version=0.78.0
nuke :add-package FS.GG.Coord.Cli --version 0.78.0
FS.GG.Coord.Cli — the typed coordination engine
The schedulability model behind fsgg-coord, as one total function.
This is not a user-facing tool. scripts/fsgg-coord is the client you run; this is the engine it
shells out to. You will normally never invoke it by hand.
What it is for
scripts/fsgg-coord was 4,000 lines of bash modelling a concurrent, transactional, budget-constrained
domain in a substrate with no types, no Result, no atomicity, and whose default failure mode was to
fail open — an error, an empty result, and a legitimate "no" were the same value. The defect record
follows from the substrate: "is this item startable?" was computed in five places and agreed in none
(#485), and the fail-open family
(#266) has 51 children.
ADR-0034 moves
that domain to a typed F# core. There is no bool in a verdict:
type Verdict<'a> = Green of 'a | Red of string list | NoVerdict of reason: string
type Schedulability =
| Startable
| WrongStatus of BoardStatus // NoStatus is its own case, not a Backlog
| IssueClosed // the issue outranks the board column
| NoTouchSet // an OMISSION
| DeliberatelyNoTouchSet // `Paths: none` — a DECISION. Not the same fact.
| UnusableTouchSet of tokens: string list
| BlockedBy of Blocker list // resolved = CLOSED *or MERGED*
| HeldBy of WorkerId
| HeldByLiveWork of WorkerId * pr: int // the lease lapsed; the WORK did not
| OverlapsInFlight of (string * string) list
| Undetermined of reason: string // "I could not decide." NEVER green, never a silent skip.
It reads nothing
The engine performs no IO. No board, no issues, no network, no token. The client has already paid for the board scan and the claim markers by the time it decides, so it hands that state over on stdin and the engine decides from it:
fsgg-coord-engine decide < snapshot.json # → a typed verdict per candidate, as JSON
fsgg-coord-engine decide --text < snapshot.json
That is what makes the engine pure and reproducible: the verdict is a total function of the snapshot, so the same board state always decides the same way, and a test can state the answer rather than stand a live fixture up — no second scan of the 5,000 pt/hr budget the whole fleet shares (#418).
It is the client now
scripts/fsgg-coord is the ADR-0034
§4.4 shim (ADR-0040 Phase D):
it resolves this compiled engine and execs it, passing argv through unchanged. The ~7,000-line bash
implementation, and the shadow that once ran both engines side by side and returned bash's answer, are
gone — this engine is the one and only coordination client.
Exit codes
These are the engine's, not the client's — the client translates them.
| Code | Meaning |
|---|---|
0 |
green — a batch was computed |
1 |
bad arguments, or a malformed snapshot |
2 |
the engine itself broke (a defect, never the caller's fault) |
3 |
red — the batch is refused. A reservation whose touch-set is unmatchable reserves nothing, so scheduling against it would hand a second worker files somebody is standing in. |
4 |
no-verdict — could not reach an answer. Never zero, and never silently a "no". |
An unreachable answer is not a negative one. That rule is the whole point.
License
MIT
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
This package has no dependencies.
| Version | Downloads | Last Updated |
|---|---|---|
| 0.109.0 | 0 | 10/19/2026 |
| 0.108.0 | 0 | 10/19/2026 |
| 0.107.0 | 82 | 10/18/2026 |
| 0.106.0 | 91 | 10/18/2026 |
| 0.105.0 | 79 | 10/18/2026 |
| 0.104.0 | 126 | 10/17/2026 |
| 0.102.0 | 145 | 10/11/2026 |
| 0.101.0 | 132 | 10/10/2026 |
| 0.100.0 | 165 | 10/8/2026 |
| 0.99.0 | 209 | 10/7/2026 |
| 0.98.0 | 200 | 10/6/2026 |
| 0.97.1 | 189 | 10/5/2026 |
| 0.97.0 | 181 | 10/4/2026 |
| 0.96.0 | 223 | 10/3/2026 |
| 0.95.0 | 192 | 10/2/2026 |
| 0.94.0 | 245 | 9/28/2026 |
| 0.93.0 | 234 | 9/28/2026 |
| 0.92.0 | 183 | 9/28/2026 |
| 0.91.5 | 1,227 | 9/27/2026 |
| 0.78.0 | 109 | 8/31/2026 |
0.78.0 — canonical intake vocabulary and partial-transaction recovery.
WHAT MOVED, AND WHY IT IS A MINOR. FS.GG.Coord.Cli intake now derives Class from the same closed
vocabulary used by issue bodies and Projects v2. A partial create can resume after an explicitly
declared legacy correction: the receipt and exact generated predecessor body authorize the rewrite,
the canonical body is re-read after PATCH, and only then is the receipt advanced and projection
resumed. Arbitrary changed drafts and operator-edited bodies still fail closed. FS.GG.Kit and
FS.GG.Drivers remove the unprojectable `capability` value from their filing examples.
All three packages advance together because they share one coherent version. Existing command names,
flags, result schemas, exit codes, and public members remain compatible.
STANDING ADVISORIES — these are NOT this release's notes, and they do not age out.
Two published FS.GG.Coord.Cli versions must never be adopted. Their own listings are immutable and
cannot be corrected, so the NEWEST listing is the only channel that can say so — and an unpinned
`dotnet tool install` resolves the newest version, which makes this the entry a consumer reads.
They live in their own MSBuild property (`FsggStandingAdvisories`) rather than inside the release
narrative below, so that trimming the narrative and deleting a warning are different edits
(.github#2579). `scripts/check-engine-release-notes.py` refuses a listing that stops referencing
this property or empties it; 4fccc76d deleted these warnings once while that gate was green.
DO NOT ADOPT 0.50.1. It is a permanent two-of-three set. The 0.50.1 cut published `FS.GG.Kit` and
`FS.GG.Drivers` to both feeds and was then REFUSED for this package by `check-engine-release-notes`
(`.github#1762`), which correctly flagged that the release notes still began with `0.50.0`. Both
sibling packages were already immutable at 0.50.1 and `.github#1772`'s sibling-tag precondition
requires all three tags to name the SAME commit, so 0.50.1 could not be completed from a corrected
tree. `FS.GG.Kit 0.50.1` and `FS.GG.Drivers 0.50.1` should not be adopted on their own; adopt
0.50.2, which is the whole set cut from one commit.
DO NOT ADOPT 0.50.5. It is a permanent two-of-three set, the same shape and the same cause as
0.50.1. `FS.GG.Kit 0.50.5` and `FS.GG.Drivers 0.50.5` published to both feeds; this package's
publish was then REFUSED by `check-engine-release-notes` because the notes still began with
`0.50.4` while `Version` had moved to `0.50.5`. Correcting that needs a new commit, and the
sibling-tag precondition requires all three tags at the SAME commit, so 0.50.5 could not be
finished from a corrected tree — re-cutting it is the re-pack divergence `.github#2240` documents.
Adopt 0.50.6.
DO NOT ADOPT 0.52.0. It is a different permanent partial set: `FS.GG.Kit` and `FS.GG.Drivers`
published to both feeds, and `FS.GG.Coord.Cli` published to the org feed before nuget.org rejected
its 37,279-character `PackageReleaseNotes`. NuGet versions are immutable and re-packing corrected
bytes under 0.52.0 would make the same version identify different artifacts. Adopt 0.53.0, the next
coherent set cut from corrected source. All three partial sets are recorded in
`registry/dependencies.yml`.
FULL PER-VERSION HISTORY IS SERVED BY THE REGISTRY, NOT REPEATED HERE (`.github#2579`). Every
published version's own notes remain readable, permanently, on that version's own listing at
FS.GG.Coord.Cli — and each cut's evidence is recorded in
`registry/dependencies.yml` and `registry/CHANGELOG.md` at https://github.com/FS-GG/.github.
The release notes remain bounded: previous-version history stays on the registry listings and only
the standing safety advisories carry forward.