diff --git a/.agents/skills/check-board/references/deep-detail.md b/.agents/skills/check-board/references/deep-detail.md index 1d84a4bf7..948ac9224 100644 --- a/.agents/skills/check-board/references/deep-detail.md +++ b/.agents/skills/check-board/references/deep-detail.md @@ -229,6 +229,8 @@ Each finding has a code, a ground truth, and a fix — or an explicit refusal to | `CLAIM-STATUS-LAG` | held claim, and board `status` is one of `Ready`/`Backlog`/*(no status)* — the columns a claim SHOULD have overwritten. A held `Blocked`/`In review` is the holder's own decision and is **deferred, not reconciled** (#331) | `set-field --batch "Status=In progress"` | | `CLAIM-REVIEW-LAG` | held claim, a freshly observed item PR is open, and board `status != In review` | `set-field --batch "Status=In review"` | | `LIFECYCLE-PROJECTION-LAG` | a fresh complete lifecycle observation disagrees with Project Status and no legacy Chore owns that Status write | `set-field --batch Status=Ready/Backlog/In progress/Blocked/In review/Done` | +| `PREMATURE-COMPLETION` | the issue closed without authoritative completion evidence; reconciliation persists a correction receipt and restores a safe nonterminal projection | reopen issue, then `set-field --batch Status=Blocked/In review` | +| `COMPLETION-PROJECTION-LAG` | a verified typed completion receipt exists but issue closure or Project Status is incomplete | close issue as completed, then `set-field --batch Status=Done` | | `AUTO-DONE-LIVE-CLAIM` | held claim and board `status == Done` — merge/issue-close automation may have projected completion while the holder still owes release, publication, dispatch, or deployment verification | **report and message the holder; never count terminal** — the holder reopens the issue and freshly restores `In review`, or produces the exact green `FSGG-DONE` evidence and drops the claim | | `UNDECLARED-PATHS` | open, unclaimed, not `Done`, and the issue body declares no `Paths:` | **ask** (§5) — the fix is an *issue* edit, so it takes an answer | | `ON-BOARD-NO-STATUS` | open, **unclaimed**, on the board, with an empty `Status` column (`""` — `NoStatus`) | **report only** — a human must choose `Ready` vs `Backlog`; the reconciler cannot invent the missing fact (§5's *never guess*), so it names the drift and writes **nothing** | diff --git a/.agents/skills/cross-repo-coordination/references/deep-detail.md b/.agents/skills/cross-repo-coordination/references/deep-detail.md index 1df3d3829..cbcfa336d 100644 --- a/.agents/skills/cross-repo-coordination/references/deep-detail.md +++ b/.agents/skills/cross-repo-coordination/references/deep-detail.md @@ -329,7 +329,7 @@ by printing a success line; **earn** it — have the tool confirm both facts fir ```sh scripts/fsgg-coord done # verify BOTH; green FSGG-DONE stamp (exit 0) or # red FSGG-NOT-DONE stamp naming the failing check (exit 1) -scripts/fsgg-coord done --flip # once the PR is merged, also set Status=Done, then stamp +scripts/fsgg-coord delivery --pr --flip --apply # verify the merge, receipt it, then project Done scripts/fsgg-coord done --pr # name the closing PR explicitly (else the first merged closer) ``` @@ -403,7 +403,7 @@ wrong and the registry advertises a version the feed can't serve. The universal (e.g. `FS.GG.Templates` → `providers/.providers.yml` `source: ::`); its own CI (e.g. `composition`) must pass. 4. **Land + record.** Merge both PRs, confirm the producer issue closed, then close out each board - item with `scripts/fsgg-coord done --flip` (see *Signal an item is finished*) — it flips + item with `scripts/fsgg-coord delivery --pr --flip --apply` (see *Signal an item is finished*) — it flips `Status: Done` only after re-confirming the merge, the green stamp is your proof, and the parent epic rolls up to `Done` on its own once the last child stamps green. diff --git a/.agents/skills/intra-repo-parallel-work/references/deep-detail.md b/.agents/skills/intra-repo-parallel-work/references/deep-detail.md index fc7eb489d..d06fac95e 100644 --- a/.agents/skills/intra-repo-parallel-work/references/deep-detail.md +++ b/.agents/skills/intra-repo-parallel-work/references/deep-detail.md @@ -65,7 +65,7 @@ Whatever named you, the claim marker records `harness= session=` as pr | A repo owner is a **person you can ask** | Workers cannot see or talk to each other | **`who`** (what is running) + **`say`/`inbox`** (a channel) | Everything else is inherited: the board is still the source of *order*, the registry of -*contracts*, ADRs of *decisions*; `fsgg-coord done --flip` still earns the done-stamp +*contracts*, ADRs of *decisions*; `fsgg-coord delivery --pr --flip --apply` earns typed completion authority and rolls epics up. ## When to use this skill @@ -107,7 +107,7 @@ jq -e '.markerObserved and .converged' <<<"$receipt" >/dev/null git fetch origin # NOTHING else does — the base is otherwise the PAST (#622) git worktree add ../- -b item/- origin/main # name the base (#319) # ...implement, commit with the printed FSGG-Worker trailer, PR into main... -scripts/fsgg-coord done --flip # earn the stamp +scripts/fsgg-coord delivery --pr --flip --apply # verify and project completion ``` `take` is the entry point. It asks `batch` what is schedulable *right now* (disjoint from @@ -387,7 +387,7 @@ dead queue ([#601](https://github.com/FS-GG/.github/issues/601)). ## 5. Finish — the earned done-stamp (unchanged) ```sh -scripts/fsgg-coord done --flip # green FSGG-DONE only after PR merged AND Status=Done +scripts/fsgg-coord delivery --pr --flip --apply # receipt only after exact PR merge verification ``` Same stamp and epic roll-up as cross-repo. Check your PR stayed inside its declaration: diff --git a/.agents/skills/pnext-item/SKILL.md b/.agents/skills/pnext-item/SKILL.md index 25b9b1798..f0a77fb0e 100644 --- a/.agents/skills/pnext-item/SKILL.md +++ b/.agents/skills/pnext-item/SKILL.md @@ -389,9 +389,11 @@ load [deep detail](references/deep-detail.md). ## 7. Stamp and stop ```bash -scripts/fsgg-coord done --flip --pr +scripts/fsgg-coord delivery --pr --flip --apply --json ``` -The exact green done stamp, closed issue, `Done` column, released claim, zero pending board writes, and -fresh board confirmation are completion. If any is missing, repair it before reporting. Clean the -worktree and branch only after verification. Report the exact stamp and stop; one invocation owns one item. +This completion call re-inspects the exact merge and declared obligations, appends the typed completion +receipt first, and only then projects the closed issue, `Done` column, released claim, and cleanup state. +The exact green done stamp, zero pending board writes, and fresh board confirmation are completion. If any +is missing, repair it and repeat this same idempotent delivery call before reporting. Clean the worktree +and branch only after verification. Report the exact receipt/stamp and stop; one invocation owns one item. diff --git a/.agents/skills/pnext-item/references/command-contracts.md b/.agents/skills/pnext-item/references/command-contracts.md index fd0a6cda8..e9c47902d 100644 --- a/.agents/skills/pnext-item/references/command-contracts.md +++ b/.agents/skills/pnext-item/references/command-contracts.md @@ -95,7 +95,7 @@ no PR of its ever carries the marker and doing so would wedge it forever. | **0** | GREEN — the PR is finished work: it merges cleanly, and every workflow run and check-run scored on its head SHA passed. The ONLY code that means merge it. | Merge it. This is the only code that says so. | | **7** | PENDING — the verdict has not SETTLED: checks are still running, none have registered yet, the run set is still growing, GitHub has not finished computing the PR's mergeability (it does so in a BACKGROUND job, and `null` is the normal first answer for a PR you just opened — #950), GITHUB ITSELF SAYS IT WILL REFUSE THIS MERGE — its `mergeable_state` for the gated head is `blocked` (the base branch policy is not satisfied: a required context that failed, or that has NO CHECK RUN AT ALL because the workflow producing it is not on this branch, or a required review, or an unresolved conversation), `behind` (a strict base moved) or `draft` (#1575) — or an assertion you added (`--require`, `--sha`) is not yet met. The ONE retryable verdict, which is why it has a code of its own rather than sharing one with a way to stop. | Keep waiting — this is the only code that says wait. Prefer `--wait`, which polls until the verdict settles rather than believing an early green. A `pending` that NEVER resolves is a finding, and the remedies are OPPOSITE, so read which one you were handed. GitHub refused the merge (`blocked`/`behind`/`draft`, and the line names the state and the base branch): REBASE onto the current base so the required workflow exists on this head and can fire; mark a DRAFT ready for review; or stop requiring a context nothing on this branch can produce. WAITING CANNOT CREATE A CHECK RUN FOR A WORKFLOW THAT DOES NOT EXIST ON THIS BRANCH — no amount of polling makes an absent producer report, which is why this arm names the context rather than telling you to wait harder. Otherwise: the job was RENAMED, its workflow's `paths:` filter no longer matches, `--sha` named the wrong commit, or GitHub never finished computing mergeability (rare, and not something waiting longer fixes — read the PR yourself). | | **3** | RED or CONFLICTED — two words, one code, because both mean STOP and neither improves by waiting. Red: a run or check-run failed. Conflicted: the PR does not merge cleanly, so GitHub cannot build `refs/pull/N/merge` and gives it NO CI at all — which is why it is returned immediately rather than polled. | Stop. Do NOT wait — 3 is the code the recipe used to call `pending`, and a loop that waits on it never terminates. A red check is a finding; a conflicted PR needs a rebase, which is AUTHORING, not landing. | -| **10** | MERGED, or CLOSED without merging — the PR is NOT OPEN, so there is nothing left to gate (#1680). The word on stdout tells the two apart: `merged` means the work LANDED, `closed` means it was abandoned or rejected and nothing landed. Terminal, and deliberately NOT 7: GitHub reports `mergeable: null` for a merged PR, which used to read as "still computing" and return PENDING — the ONE code the contract defines as worth retrying — for the most terminal state there is. `landable --wait` therefore spent its entire 600s budget (30 tries x 20s) on a settled fact, every time, and the caller that meets this most is the RECOVERY path (`pnext-item` §5, `adopt`), which re-gates a PR whose worker died between merge and stamp. It was told to wait forever on work that was already landed. It is also not 3: `merged` is a success, and folding it into the red/conflicted code would tell that same successor to stop rather than to stamp. | Stop polling — no amount of waiting reopens a PR, and `--wait` does not poll this at all. READ THE WORD, because the next act is opposite. `merged`: the work is LANDED. Do not merge it again and do not treat it as a failure — if you are recovering an item whose worker died mid-flight, go STAMP it (`done --flip --pr `). `closed`: nothing landed, so do NOT stamp it done; the branch was abandoned or the PR rejected, and the item needs re-work or release, not a merge. | +| **10** | MERGED, or CLOSED without merging — the PR is NOT OPEN, so there is nothing left to gate (#1680). The word on stdout tells the two apart: `merged` means the work LANDED, `closed` means it was abandoned or rejected and nothing landed. Terminal, and deliberately NOT 7: GitHub reports `mergeable: null` for a merged PR, which used to read as "still computing" and return PENDING — the ONE code the contract defines as worth retrying — for the most terminal state there is. `landable --wait` therefore spent its entire 600s budget (30 tries x 20s) on a settled fact, every time, and the caller that meets this most is the RECOVERY path (`pnext-item` §5, `adopt`), which re-gates a PR whose worker died between merge and stamp. It was told to wait forever on work that was already landed. It is also not 3: `merged` is a success, and folding it into the red/conflicted code would tell that same successor to stop rather than to stamp. | Stop polling — no amount of waiting reopens a PR, and `--wait` does not poll this at all. READ THE WORD, because the next act is opposite. `merged`: the work is LANDED. Do not merge it again and do not treat it as a failure — if you are recovering an item whose worker died mid-flight, complete delivery (`delivery --pr --flip --apply`). `closed`: nothing landed, so do NOT project it done; the branch was abandoned or rejected and the item needs re-work or release, not a merge. | | **4** | UNKNOWN — no verdict, and this is the FAIL-CLOSED one (#266). The read could not be made or its answer was not conclusive: a rate limit, a 404, a PR whose `mergeable` field is ABSENT entirely. Note what it is NOT. An UNREADABLE BRANCH POLICY is NOT one of these causes (#1575): when GitHub says it will refuse the merge, the refusal stands on GitHub's OWN word (`mergeable_state`, already in the PR body) and the policy read is DIAGNOSIS ONLY — a 403 or a rate limit on it costs you the SENTENCE naming which context is unmet, never the verdict, which stays PENDING (7). A gate that failed closed on a read the fleet's token cannot make would not fail closed; it would fail ALWAYS (#463). A `mergeable` GitHub has not computed YET is PENDING (7), not this — it is guaranteed to change, and calling it unknown made `--wait` settle at once and abandon a seconds-old PR (#950). And there is no EX_RATE (75) here, unlike `take`: an exhausted budget arrives as this code, because `landable` has no error channel to carry a budget on. | Do not merge, and do not treat it as a red. An unreachable answer is not a negative one. Look at why the read failed — check `budget` if you suspect a rate limit — and ask again. | | **1** | REFUSED — the engine rejected your INPUT before it ever looked at the PR: no `--repo` (so which repo the PR is in is undefined), a ref that is not a PR number, or the wrong number of arguments. It is not a verdict about the PR, and no word is printed. | Read the message and fix the call. Not retryable — it will refuse identically. | | **2** | The ENGINE broke — an unhandled defect, with a stack trace. Its own code, so a broken engine cannot hide behind a stream of what look like bad inputs. | Report it. Do not retry, and do not merge a PR you have no verdict on. | diff --git a/.agents/skills/pnext-item/references/deep-detail.md b/.agents/skills/pnext-item/references/deep-detail.md index 862ad77ee..f7c22b5e5 100644 --- a/.agents/skills/pnext-item/references/deep-detail.md +++ b/.agents/skills/pnext-item/references/deep-detail.md @@ -1161,7 +1161,7 @@ scripts/fsgg-coord set-field Status "In review" scripts/fsgg-coord ready --repo --all --json \ | jq -e '.[] | select(.number == and .status == "In review")' >/dev/null # Run and verify every named release/publication/dispatch/deployment obligation here. -# Once all are verified, close the issue again; only then can `done --flip` earn FSGG-DONE below. +# Once all are verified, let `delivery --apply` append the typed completion receipt and reconcile closure below. gh api -X PATCH repos/FS-GG//issues/ -f state=closed ``` @@ -1384,7 +1384,7 @@ A red check is a finding, not an obstacle. Then earn the stamp: ```sh -scripts/fsgg-coord done --flip # green FSGG-DONE only if PR merged AND Status=Done +scripts/fsgg-coord delivery --pr --flip --apply --json # receipt first; then closure and Done ``` Capture and report the exact `FSGG-DONE` line. The board's `Done` column is only a projection and may diff --git a/.claude/skills/check-board/references/deep-detail.md b/.claude/skills/check-board/references/deep-detail.md index 1d84a4bf7..948ac9224 100644 --- a/.claude/skills/check-board/references/deep-detail.md +++ b/.claude/skills/check-board/references/deep-detail.md @@ -229,6 +229,8 @@ Each finding has a code, a ground truth, and a fix — or an explicit refusal to | `CLAIM-STATUS-LAG` | held claim, and board `status` is one of `Ready`/`Backlog`/*(no status)* — the columns a claim SHOULD have overwritten. A held `Blocked`/`In review` is the holder's own decision and is **deferred, not reconciled** (#331) | `set-field --batch "Status=In progress"` | | `CLAIM-REVIEW-LAG` | held claim, a freshly observed item PR is open, and board `status != In review` | `set-field --batch "Status=In review"` | | `LIFECYCLE-PROJECTION-LAG` | a fresh complete lifecycle observation disagrees with Project Status and no legacy Chore owns that Status write | `set-field --batch Status=Ready/Backlog/In progress/Blocked/In review/Done` | +| `PREMATURE-COMPLETION` | the issue closed without authoritative completion evidence; reconciliation persists a correction receipt and restores a safe nonterminal projection | reopen issue, then `set-field --batch Status=Blocked/In review` | +| `COMPLETION-PROJECTION-LAG` | a verified typed completion receipt exists but issue closure or Project Status is incomplete | close issue as completed, then `set-field --batch Status=Done` | | `AUTO-DONE-LIVE-CLAIM` | held claim and board `status == Done` — merge/issue-close automation may have projected completion while the holder still owes release, publication, dispatch, or deployment verification | **report and message the holder; never count terminal** — the holder reopens the issue and freshly restores `In review`, or produces the exact green `FSGG-DONE` evidence and drops the claim | | `UNDECLARED-PATHS` | open, unclaimed, not `Done`, and the issue body declares no `Paths:` | **ask** (§5) — the fix is an *issue* edit, so it takes an answer | | `ON-BOARD-NO-STATUS` | open, **unclaimed**, on the board, with an empty `Status` column (`""` — `NoStatus`) | **report only** — a human must choose `Ready` vs `Backlog`; the reconciler cannot invent the missing fact (§5's *never guess*), so it names the drift and writes **nothing** | diff --git a/.claude/skills/cross-repo-coordination/references/deep-detail.md b/.claude/skills/cross-repo-coordination/references/deep-detail.md index 1df3d3829..cbcfa336d 100644 --- a/.claude/skills/cross-repo-coordination/references/deep-detail.md +++ b/.claude/skills/cross-repo-coordination/references/deep-detail.md @@ -329,7 +329,7 @@ by printing a success line; **earn** it — have the tool confirm both facts fir ```sh scripts/fsgg-coord done # verify BOTH; green FSGG-DONE stamp (exit 0) or # red FSGG-NOT-DONE stamp naming the failing check (exit 1) -scripts/fsgg-coord done --flip # once the PR is merged, also set Status=Done, then stamp +scripts/fsgg-coord delivery --pr --flip --apply # verify the merge, receipt it, then project Done scripts/fsgg-coord done --pr # name the closing PR explicitly (else the first merged closer) ``` @@ -403,7 +403,7 @@ wrong and the registry advertises a version the feed can't serve. The universal (e.g. `FS.GG.Templates` → `providers/.providers.yml` `source: ::`); its own CI (e.g. `composition`) must pass. 4. **Land + record.** Merge both PRs, confirm the producer issue closed, then close out each board - item with `scripts/fsgg-coord done --flip` (see *Signal an item is finished*) — it flips + item with `scripts/fsgg-coord delivery --pr --flip --apply` (see *Signal an item is finished*) — it flips `Status: Done` only after re-confirming the merge, the green stamp is your proof, and the parent epic rolls up to `Done` on its own once the last child stamps green. diff --git a/.claude/skills/intra-repo-parallel-work/references/deep-detail.md b/.claude/skills/intra-repo-parallel-work/references/deep-detail.md index fc7eb489d..d06fac95e 100644 --- a/.claude/skills/intra-repo-parallel-work/references/deep-detail.md +++ b/.claude/skills/intra-repo-parallel-work/references/deep-detail.md @@ -65,7 +65,7 @@ Whatever named you, the claim marker records `harness= session=` as pr | A repo owner is a **person you can ask** | Workers cannot see or talk to each other | **`who`** (what is running) + **`say`/`inbox`** (a channel) | Everything else is inherited: the board is still the source of *order*, the registry of -*contracts*, ADRs of *decisions*; `fsgg-coord done --flip` still earns the done-stamp +*contracts*, ADRs of *decisions*; `fsgg-coord delivery --pr --flip --apply` earns typed completion authority and rolls epics up. ## When to use this skill @@ -107,7 +107,7 @@ jq -e '.markerObserved and .converged' <<<"$receipt" >/dev/null git fetch origin # NOTHING else does — the base is otherwise the PAST (#622) git worktree add ../- -b item/- origin/main # name the base (#319) # ...implement, commit with the printed FSGG-Worker trailer, PR into main... -scripts/fsgg-coord done --flip # earn the stamp +scripts/fsgg-coord delivery --pr --flip --apply # verify and project completion ``` `take` is the entry point. It asks `batch` what is schedulable *right now* (disjoint from @@ -387,7 +387,7 @@ dead queue ([#601](https://github.com/FS-GG/.github/issues/601)). ## 5. Finish — the earned done-stamp (unchanged) ```sh -scripts/fsgg-coord done --flip # green FSGG-DONE only after PR merged AND Status=Done +scripts/fsgg-coord delivery --pr --flip --apply # receipt only after exact PR merge verification ``` Same stamp and epic roll-up as cross-repo. Check your PR stayed inside its declaration: diff --git a/.claude/skills/pnext-item/SKILL.md b/.claude/skills/pnext-item/SKILL.md index 25b9b1798..f0a77fb0e 100644 --- a/.claude/skills/pnext-item/SKILL.md +++ b/.claude/skills/pnext-item/SKILL.md @@ -389,9 +389,11 @@ load [deep detail](references/deep-detail.md). ## 7. Stamp and stop ```bash -scripts/fsgg-coord done --flip --pr +scripts/fsgg-coord delivery --pr --flip --apply --json ``` -The exact green done stamp, closed issue, `Done` column, released claim, zero pending board writes, and -fresh board confirmation are completion. If any is missing, repair it before reporting. Clean the -worktree and branch only after verification. Report the exact stamp and stop; one invocation owns one item. +This completion call re-inspects the exact merge and declared obligations, appends the typed completion +receipt first, and only then projects the closed issue, `Done` column, released claim, and cleanup state. +The exact green done stamp, zero pending board writes, and fresh board confirmation are completion. If any +is missing, repair it and repeat this same idempotent delivery call before reporting. Clean the worktree +and branch only after verification. Report the exact receipt/stamp and stop; one invocation owns one item. diff --git a/.claude/skills/pnext-item/references/command-contracts.md b/.claude/skills/pnext-item/references/command-contracts.md index fd0a6cda8..e9c47902d 100644 --- a/.claude/skills/pnext-item/references/command-contracts.md +++ b/.claude/skills/pnext-item/references/command-contracts.md @@ -95,7 +95,7 @@ no PR of its ever carries the marker and doing so would wedge it forever. | **0** | GREEN — the PR is finished work: it merges cleanly, and every workflow run and check-run scored on its head SHA passed. The ONLY code that means merge it. | Merge it. This is the only code that says so. | | **7** | PENDING — the verdict has not SETTLED: checks are still running, none have registered yet, the run set is still growing, GitHub has not finished computing the PR's mergeability (it does so in a BACKGROUND job, and `null` is the normal first answer for a PR you just opened — #950), GITHUB ITSELF SAYS IT WILL REFUSE THIS MERGE — its `mergeable_state` for the gated head is `blocked` (the base branch policy is not satisfied: a required context that failed, or that has NO CHECK RUN AT ALL because the workflow producing it is not on this branch, or a required review, or an unresolved conversation), `behind` (a strict base moved) or `draft` (#1575) — or an assertion you added (`--require`, `--sha`) is not yet met. The ONE retryable verdict, which is why it has a code of its own rather than sharing one with a way to stop. | Keep waiting — this is the only code that says wait. Prefer `--wait`, which polls until the verdict settles rather than believing an early green. A `pending` that NEVER resolves is a finding, and the remedies are OPPOSITE, so read which one you were handed. GitHub refused the merge (`blocked`/`behind`/`draft`, and the line names the state and the base branch): REBASE onto the current base so the required workflow exists on this head and can fire; mark a DRAFT ready for review; or stop requiring a context nothing on this branch can produce. WAITING CANNOT CREATE A CHECK RUN FOR A WORKFLOW THAT DOES NOT EXIST ON THIS BRANCH — no amount of polling makes an absent producer report, which is why this arm names the context rather than telling you to wait harder. Otherwise: the job was RENAMED, its workflow's `paths:` filter no longer matches, `--sha` named the wrong commit, or GitHub never finished computing mergeability (rare, and not something waiting longer fixes — read the PR yourself). | | **3** | RED or CONFLICTED — two words, one code, because both mean STOP and neither improves by waiting. Red: a run or check-run failed. Conflicted: the PR does not merge cleanly, so GitHub cannot build `refs/pull/N/merge` and gives it NO CI at all — which is why it is returned immediately rather than polled. | Stop. Do NOT wait — 3 is the code the recipe used to call `pending`, and a loop that waits on it never terminates. A red check is a finding; a conflicted PR needs a rebase, which is AUTHORING, not landing. | -| **10** | MERGED, or CLOSED without merging — the PR is NOT OPEN, so there is nothing left to gate (#1680). The word on stdout tells the two apart: `merged` means the work LANDED, `closed` means it was abandoned or rejected and nothing landed. Terminal, and deliberately NOT 7: GitHub reports `mergeable: null` for a merged PR, which used to read as "still computing" and return PENDING — the ONE code the contract defines as worth retrying — for the most terminal state there is. `landable --wait` therefore spent its entire 600s budget (30 tries x 20s) on a settled fact, every time, and the caller that meets this most is the RECOVERY path (`pnext-item` §5, `adopt`), which re-gates a PR whose worker died between merge and stamp. It was told to wait forever on work that was already landed. It is also not 3: `merged` is a success, and folding it into the red/conflicted code would tell that same successor to stop rather than to stamp. | Stop polling — no amount of waiting reopens a PR, and `--wait` does not poll this at all. READ THE WORD, because the next act is opposite. `merged`: the work is LANDED. Do not merge it again and do not treat it as a failure — if you are recovering an item whose worker died mid-flight, go STAMP it (`done --flip --pr `). `closed`: nothing landed, so do NOT stamp it done; the branch was abandoned or the PR rejected, and the item needs re-work or release, not a merge. | +| **10** | MERGED, or CLOSED without merging — the PR is NOT OPEN, so there is nothing left to gate (#1680). The word on stdout tells the two apart: `merged` means the work LANDED, `closed` means it was abandoned or rejected and nothing landed. Terminal, and deliberately NOT 7: GitHub reports `mergeable: null` for a merged PR, which used to read as "still computing" and return PENDING — the ONE code the contract defines as worth retrying — for the most terminal state there is. `landable --wait` therefore spent its entire 600s budget (30 tries x 20s) on a settled fact, every time, and the caller that meets this most is the RECOVERY path (`pnext-item` §5, `adopt`), which re-gates a PR whose worker died between merge and stamp. It was told to wait forever on work that was already landed. It is also not 3: `merged` is a success, and folding it into the red/conflicted code would tell that same successor to stop rather than to stamp. | Stop polling — no amount of waiting reopens a PR, and `--wait` does not poll this at all. READ THE WORD, because the next act is opposite. `merged`: the work is LANDED. Do not merge it again and do not treat it as a failure — if you are recovering an item whose worker died mid-flight, complete delivery (`delivery --pr --flip --apply`). `closed`: nothing landed, so do NOT project it done; the branch was abandoned or rejected and the item needs re-work or release, not a merge. | | **4** | UNKNOWN — no verdict, and this is the FAIL-CLOSED one (#266). The read could not be made or its answer was not conclusive: a rate limit, a 404, a PR whose `mergeable` field is ABSENT entirely. Note what it is NOT. An UNREADABLE BRANCH POLICY is NOT one of these causes (#1575): when GitHub says it will refuse the merge, the refusal stands on GitHub's OWN word (`mergeable_state`, already in the PR body) and the policy read is DIAGNOSIS ONLY — a 403 or a rate limit on it costs you the SENTENCE naming which context is unmet, never the verdict, which stays PENDING (7). A gate that failed closed on a read the fleet's token cannot make would not fail closed; it would fail ALWAYS (#463). A `mergeable` GitHub has not computed YET is PENDING (7), not this — it is guaranteed to change, and calling it unknown made `--wait` settle at once and abandon a seconds-old PR (#950). And there is no EX_RATE (75) here, unlike `take`: an exhausted budget arrives as this code, because `landable` has no error channel to carry a budget on. | Do not merge, and do not treat it as a red. An unreachable answer is not a negative one. Look at why the read failed — check `budget` if you suspect a rate limit — and ask again. | | **1** | REFUSED — the engine rejected your INPUT before it ever looked at the PR: no `--repo` (so which repo the PR is in is undefined), a ref that is not a PR number, or the wrong number of arguments. It is not a verdict about the PR, and no word is printed. | Read the message and fix the call. Not retryable — it will refuse identically. | | **2** | The ENGINE broke — an unhandled defect, with a stack trace. Its own code, so a broken engine cannot hide behind a stream of what look like bad inputs. | Report it. Do not retry, and do not merge a PR you have no verdict on. | diff --git a/.claude/skills/pnext-item/references/deep-detail.md b/.claude/skills/pnext-item/references/deep-detail.md index 862ad77ee..f7c22b5e5 100644 --- a/.claude/skills/pnext-item/references/deep-detail.md +++ b/.claude/skills/pnext-item/references/deep-detail.md @@ -1161,7 +1161,7 @@ scripts/fsgg-coord set-field Status "In review" scripts/fsgg-coord ready --repo --all --json \ | jq -e '.[] | select(.number == and .status == "In review")' >/dev/null # Run and verify every named release/publication/dispatch/deployment obligation here. -# Once all are verified, close the issue again; only then can `done --flip` earn FSGG-DONE below. +# Once all are verified, let `delivery --apply` append the typed completion receipt and reconcile closure below. gh api -X PATCH repos/FS-GG//issues/ -f state=closed ``` @@ -1384,7 +1384,7 @@ A red check is a finding, not an obstacle. Then earn the stamp: ```sh -scripts/fsgg-coord done --flip # green FSGG-DONE only if PR merged AND Status=Done +scripts/fsgg-coord delivery --pr --flip --apply --json # receipt first; then closure and Done ``` Capture and report the exact `FSGG-DONE` line. The board's `Done` column is only a projection and may diff --git a/.github/workflows/coord-board-reconcile.yml b/.github/workflows/coord-board-reconcile.yml index 05c369a52..966e5b79a 100644 --- a/.github/workflows/coord-board-reconcile.yml +++ b/.github/workflows/coord-board-reconcile.yml @@ -152,6 +152,11 @@ jobs: # the `on:` block fix alone got a job scheduled, and this is what the job then hit. Mirrors # `touch-set-drift.yml`'s established build-then-run wiring, the one other workflow that # executes the client on a runner rather than only referencing it in a comment or path filter. + # The shim discovers this canonical checkout build through tier 2. Do not set + # `FSGG_COORD_ENGINE_BIN` here: that tier-1 override means an operator-selected candidate, and + # write-capable candidate use correctly requires a self-host bootstrap receipt. This workflow + # is executing the revision GitHub checked out for the workflow itself, not selecting an ad hoc + # binary outside the resolver's canonical source-build route. - uses: actions/setup-dotnet@v6 with: global-json-file: global.json @@ -337,7 +342,6 @@ jobs: if: steps.budget.outputs.defer != 'true' env: GITHUB_TOKEN: ${{ steps.app-token.outputs.token }} - FSGG_COORD_ENGINE_BIN: ${{ github.workspace }}/src/FS.GG.Coord.Cli/bin/Release/net10.0/fsgg-coord-engine FSGG_LIFECYCLE_EVENT: ${{ github.event_name }} FSGG_LIFECYCLE_EVENT_AT: ${{ github.event.repository.updated_at || github.run_started_at }} FSGG_COORD_HEALTH_REPORT: artifacts/coordination-health/health-observation.json diff --git a/.github/workflows/coord-engine.yml b/.github/workflows/coord-engine.yml index 7a9418ca0..6025b1f2f 100644 --- a/.github/workflows/coord-engine.yml +++ b/.github/workflows/coord-engine.yml @@ -14,64 +14,16 @@ # discovers nothing exits 0, so the non-vacuity step asserts a floor of tests actually ran. A green gate # over an untested fail-open surface is the exact bug this engine exists to end. # -# The build config is in the trigger list, and BOTH halves of it are (#609): the root -# Directory.Build.props IMPORTS dist/dotnet/Directory.Build.props, which is what sets RestoreLockedMode -# and the ADR-0032 lock-hash fix behind this job's locked restore. An edit to the org-shared file -# changes this build, so it must be able to re-run this gate. +# The PR trigger is deliberately unfiltered so the required change-completeness context always reports. +# Its impact classifier retains the old path-sensitive boundary for the expensive engine job, including +# both build-config halves: root Directory.Build.props and its dist/dotnet import. name: coord-engine on: + # No PR path filter: `change-completeness` is a required predecessor and must report on every head. + # The expensive engine job retains path-sensitive execution through the gate's typed impact output. + # paths-coherence: allow-divergence — the required PR context is intentionally universal; push remains path-sensitive and the classifier gates the expensive successor. pull_request: - paths: - - "src/FS.GG.Coord.Cli/**" - # .github#2725 — `FS.GG.Coord.Cli` now ProjectReferences the CLI kernel, so a change under - # `src/FS.GG.Coord.Cli.Kernel/**` changes what this workflow builds. Without this entry the - # workflow would not start on such a change and would be green by absence (#266) — which is - # exactly what `scripts/check-paths-coherence.py` rule (b) refuses. - - "src/FS.GG.Coord.Cli.Kernel/**" - - "src/FS.GG.Coord.Cli.BoardOps/**" - - "src/FS.GG.Coord.Core/**" - - "src/FS.GG.Coord.GitHub/**" - - "tests/FS.GG.Coord.Cli.Tests/**" - # .github#2725 — the kernel suite. It is a SEPARATE assembly with its own 179 tests, and - # `dotnet test` on the CLI suite does not run one of them, so a workflow that started only on - # the CLI suite would report green over a kernel change it never executed. - - "tests/FS.GG.Coord.Cli.Kernel.Tests/**" - - "tests/FS.GG.Coord.Cli.BoardOps.Tests/**" - - "tests/FS.GG.Coord.Core.Tests/**" - - "tests/m6-decision-cutover/**" - # THE SHARED CROSS-LANGUAGE CORPUS (.github#2563), and this entry is part of the gate - # rather than bookkeeping. `tests/delivery-leading-line/corpus.json` is the one statement of - # the delivery-marker leading-line boundary; `DeliveryApplicationTests` grades the ENGINE - # against it and `tests/kit-published-coherence/run.sh` grades the PYTHON gate against the - # same verdicts. Without this path a PR that moved the Python limit and edited the corpus to - # match would never start this workflow, so the F# half would stay silent on precisely the - # coordinated one-sided edit the corpus exists to catch — a gate keyed on `paths:` is - # selectively silent, and quietest on the additive variants (.github#2551). - - "tests/delivery-leading-line/**" - - "tests/coord-engine-e2e/**" - - "tests/coord-engine-parity/**" - - "tests/coord-engine-mutation/**" - - "tests/coord-engine-replay/**" - - "tests/review-critic-succession-wire/**" - - "scripts/fsgg-coord" - # THE GUARD MODULE, AND ITS ABSENCE HERE WAS A HOLE (.github#2581). `.github#1586` moved the verb - # partition and both guards out of `scripts/fsgg-coord` into `scripts/fsgg-coord-guards.sh` — - # and this filter did not follow them. `tests/coord-engine-parity/shim.sh` §3b lifts the three - # verb sets out of THAT file and grades their bijection against the engine's own - # `command-contract`, and §3c drives every one of them against a stale fixture; so the suites - # whose entire subject is that file were started by no path when it changed, on either trigger. - # A gate keyed on `paths:` is selectively silent, and quietest on exactly the edits it is for - # (.github#2551). Measured: `grep -rn "fsgg-coord-guards" .github/workflows/` returned nothing. - - "scripts/fsgg-coord-guards.sh" - - "scripts/record-board-fixture.py" - - "scripts/read-trx-count.py" - - "tests/ci-runtime-optimization/**" - - "Directory.Build.props" - - "dist/dotnet/Directory.Build.props" - - "Directory.Packages.props" - - "global.json" - - ".github/workflows/coord-engine.yml" push: branches: [main] paths: @@ -114,6 +66,9 @@ on: - "scripts/record-board-fixture.py" - "scripts/read-trx-count.py" - "tests/ci-runtime-optimization/**" + - "tests/change-completeness/**" + - "tests/change-risk-compatibility/**" + - "scripts/change-completeness" - "Directory.Build.props" - "dist/dotnet/Directory.Build.props" - "Directory.Packages.props" @@ -129,7 +84,46 @@ concurrency: cancel-in-progress: true jobs: + change-completeness: + runs-on: ubuntu-latest + timeout-minutes: 5 + outputs: + engine_changed: ${{ steps.gate.outputs.engine_changed }} + steps: + - uses: actions/checkout@v7 + with: + fetch-depth: 0 + - uses: actions/setup-dotnet@v6 + with: + global-json-file: global.json + cache: true + cache-dependency-path: "**/packages.lock.json" + - name: Run bounded structural and focused production-route checks + id: gate + env: + EVENT_NAME: ${{ github.event_name }} + EVENT_BASE: ${{ github.event.pull_request.base.sha || github.event.before }} + EVENT_HEAD: ${{ github.event.pull_request.head.sha || github.sha }} + PR_BODY: ${{ github.event.pull_request.body }} + run: | + set -euo pipefail + base="$EVENT_BASE" + if [ -z "$base" ] || [[ "$base" =~ ^0+$ ]]; then base="$(git rev-parse HEAD^)"; fi + body_arg=() + if [ "$EVENT_NAME" = pull_request ]; then + printf '%s' "$PR_BODY" > "$RUNNER_TEMP/pr-body.md" + body_arg=(--pr-body "$RUNNER_TEMP/pr-body.md") + fi + scripts/change-completeness --base "$base" --head "$EVENT_HEAD" \ + --github-output "$GITHUB_OUTPUT" "${body_arg[@]}" + - name: Prove the gate wiring and named structural families + run: bash tests/change-completeness/run.sh + - name: Prove every authority slice retains parity and an effective inversion + run: bash tests/change-risk-compatibility/run.sh + engine: + needs: change-completeness + if: github.event_name != 'pull_request' || needs.change-completeness.outputs.engine_changed == 'true' runs-on: ubuntu-latest timeout-minutes: 20 steps: diff --git a/.github/workflows/release-coord-engine.yml b/.github/workflows/release-coord-engine.yml index 9b2a32a72..a3c356163 100644 --- a/.github/workflows/release-coord-engine.yml +++ b/.github/workflows/release-coord-engine.yml @@ -326,7 +326,9 @@ jobs: VERSION: ${{ steps.v.outputs.version }} run: | set +eu - python3 scripts/dashboard-tick.py --package FS.GG.Coord.Cli --version "$VERSION" + python3 scripts/dashboard-tick.py --package FS.GG.Coord.Cli --version "$VERSION" \ + --journal artifacts/packages/journal-FS.GG.Coord.Cli.json \ + --receipt-dir artifacts/receiver-receipts rc=$? set -eu # By EXIT CODE, never by prose (#335). Every non-zero is red; the arms differ so the @@ -338,6 +340,14 @@ jobs: 3) echo "::error title=release-coord-engine: delivery never ran::scripts/dashboard-tick.py exited 3 — a permanent no-verdict (the roster would not read, or the credential was empty). NOTHING was attempted, so no receiver was told. The engine IS published." ; exit 1 ;; *) echo "::error title=release-coord-engine: the release told nobody, or a write was refused::scripts/dashboard-tick.py exited $rc. The engine IS published — this is a DELIVERY failure, not a publish failure." ; exit 1 ;; esac + + - name: Persist append-only receiver receipts outside immutable release assets + uses: actions/upload-artifact@v6 + with: + name: receiver-receipts-FS.GG.Coord.Cli-${{ steps.v.outputs.version }} + path: artifacts/receiver-receipts/*.json + if-no-files-found: error + retention-days: 90 # ───────────────────────────────────────────────────────────────────────────────────────── # `always()`: a DELIVERY failure above must not suppress the record that the package reached diff --git a/.github/workflows/release-kit.yml b/.github/workflows/release-kit.yml index 9798afefe..018903285 100644 --- a/.github/workflows/release-kit.yml +++ b/.github/workflows/release-kit.yml @@ -408,7 +408,9 @@ jobs: VERSION: ${{ steps.v.outputs.version }} run: | set +eu - python3 scripts/dashboard-tick.py --package FS.GG.Kit --version "$VERSION" + python3 scripts/dashboard-tick.py --package FS.GG.Kit --version "$VERSION" \ + --journal artifacts/packages/journal-FS.GG.Kit.json \ + --receipt-dir artifacts/receiver-receipts rc=$? set -eu # Classify by EXIT CODE, never by prose (#335). Every non-zero is red; they are separate @@ -425,6 +427,14 @@ jobs: 3) echo "::error title=release-kit: delivery never ran::scripts/dashboard-tick.py exited 3 — a permanent no-verdict (the roster would not read, or the credential was empty). NOTHING was attempted, so no receiver was told. The kit IS published." ; exit 1 ;; *) echo "::error title=release-kit: the release told nobody, or a write was refused::scripts/dashboard-tick.py exited $rc. The kit IS published — this is a DELIVERY failure, not a publish failure." ; exit 1 ;; esac + + - name: Persist append-only receiver receipts outside immutable release assets + uses: actions/upload-artifact@v6 + with: + name: receiver-receipts-FS.GG.Kit-${{ steps.v.outputs.version }} + path: artifacts/receiver-receipts/*.json + if-no-files-found: error + retention-days: 90 # ───────────────────────────────────────────────────────────────────────────────────────── # `always()`: the publish is the thing this summary reports, and a DELIVERY failure above must diff --git a/.github/workflows/release-saga-promote.yml b/.github/workflows/release-saga-promote.yml index a3ed9b0be..b153ec4ac 100644 --- a/.github/workflows/release-saga-promote.yml +++ b/.github/workflows/release-saga-promote.yml @@ -11,6 +11,7 @@ on: types: [completed] permissions: + actions: read contents: write packages: read @@ -62,6 +63,39 @@ jobs: done [ "$journal_count" -eq 3 ] || { echo "::error::expected exactly 3 package journals, found $journal_count"; exit 1; } python3 scripts/release-saga.py merge-journals --manifest artifacts/packages/release-manifest.json "${journals[@]}" + + # Receiver evidence is intentionally NOT a release asset: promotion makes that asset set + # immutable. Each package run publishes an append-only Actions artifact, and this observer + # binds every receipt back to the exact journal/package/source identity before promotion. + mkdir -p artifacts/receiver-receipts + receipt_args=(); expected_args=() + for package_workflow in "FS.GG.Coord.Cli=release-coord-engine.yml" "FS.GG.Kit=release-kit.yml"; do + package="${package_workflow%%=*}" + workflow="${package_workflow#*=}" + target="artifacts/receiver-receipts/$package" + mkdir -p "$target" + downloaded=false + while IFS= read -r run_id; do + if gh run download "$run_id" --repo "$GITHUB_REPOSITORY" \ + --name "receiver-receipts-$package-$version" --dir "$target" 2>/dev/null; then + downloaded=true + break + fi + done < <(gh run list --repo "$GITHUB_REPOSITORY" --workflow "$workflow" \ + --status success --limit 100 --json databaseId,createdAt \ + --jq 'sort_by(.createdAt) | reverse | .[].databaseId') + [ "$downloaded" = true ] || { echo "::error::no successful $workflow run published receiver receipts for $package $version"; exit 1; } + for receipt in "$target"/*.json; do + [ -f "$receipt" ] && receipt_args+=(--receipt "$receipt") + done + while IFS= read -r receiver; do + [ -n "$receiver" ] && expected_args+=(--expected "$package=$receiver") + done < <(bash scripts/repos.sh list --receives coordination-kit --kit-delivery package) + done + [ "${#receipt_args[@]}" -gt 0 ] || { echo "::error::no receiver receipts were downloaded"; exit 1; } + python3 scripts/release-saga.py verify-receivers \ + --manifest artifacts/packages/release-manifest.json \ + "${expected_args[@]}" "${receipt_args[@]}" - name: Observe both registries env: GH_TOKEN: ${{ github.token }} diff --git a/Directory.Build.props b/Directory.Build.props index c2c00af68..39371d1e3 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -435,8 +435,13 @@ file-backed create and explicit-id amend comment mutation, authoritative UTF-8 length/SHA-256 readback, and per-operation recovery capabilities. Packed skills adopt this verified route in place of raw comment mutation. Additive behavior; no command or package identity is removed. --> + - 0.72.0 + 0.73.0 diff --git a/docs/coordination/parallel-work.md b/docs/coordination/parallel-work.md index e78f2b172..aca5cee74 100644 --- a/docs/coordination/parallel-work.md +++ b/docs/coordination/parallel-work.md @@ -656,13 +656,13 @@ told its claim was collected, and a worker whose touch-set was invaded is told b ### 5. Finish — the earned done-stamp ```sh -scripts/fsgg-coord done --flip # green FSGG-DONE only after PR merged AND Status=Done +scripts/fsgg-coord delivery --pr --flip --apply --json # typed completion receipt before Done scripts/fsgg-coord child # link a filed issue as a sub-issue of its epic ``` Same stamp and epic roll-up as cross-repo. -**The claim's lifetime is the WORK's lifetime.** `done --flip` drops the marker +**The claim's lifetime is the WORK's lifetime.** receipt-gated `delivery --apply --flip` drops the marker ([#533](https://github.com/FS-GG/.github/issues/533)); an expired lease whose `item/-*` PR is still open does **not** release the item ([#581](https://github.com/FS-GG/.github/issues/581)); and a worker holds **at most one item** ([#516](https://github.com/FS-GG/.github/issues/516)). @@ -874,7 +874,7 @@ scripts/fsgg-coord take --repo # pick + claim the next SCHEDULABL git fetch origin # NOTHING else does — the base is otherwise the PAST (§2) git worktree add ../- -b item/- origin/main # name the base: HEAD is not `main` (§2) # ...implement; `heartbeat` if it runs long; `say`/`inbox` if work touches... -scripts/fsgg-coord done --flip # earn the stamp +scripts/fsgg-coord delivery --pr --flip --apply --json # earn the typed receipt and stamp scripts/fsgg-coord release # ...or hand it back ``` @@ -882,8 +882,9 @@ scripts/fsgg-coord release # ...or hand it back - **Sequencing** — the Coordination board's `Blocked by` and sub-issues (ADR-0001). Overlap detection just decides *which* items get a dependency edge. -- **Finishing** — `fsgg-coord done --flip`: the green `FSGG-DONE` stamp earned only after the - PR is merged **and** the board is `Done`, with automatic epic roll-up — which refuses to fire over +- **Finishing** — `fsgg-coord delivery --pr --flip --apply --json`: the typed completion + receipt and green `FSGG-DONE` stamp earned only after the exact PR merge and declared obligations are + verified, followed by the board's `Done` projection and automatic epic roll-up — which refuses to fire over an epic whose body declares a child the sub-issue graph lacks. `fsgg-coord child ` is what puts a child *in* that graph; nothing else does. - **The GraphQL budget discipline.** Everything in this protocol is **REST** (a separate 5,000 diff --git a/docs/coordination/self-host-bootstrap.md b/docs/coordination/self-host-bootstrap.md new file mode 100644 index 000000000..868527278 --- /dev/null +++ b/docs/coordination/self-host-bootstrap.md @@ -0,0 +1,54 @@ +# Candidate-engine self-host bootstrap + +Use this route only when the shared coordination engine refuses because it cannot understand a new schema +case or because the authoritative decision boundary moved. Business-rule disagreement is not a bootstrap +reason and cannot be represented by the receipt type. + +The direct implementation and enforcement live in `.github`. Framework and product workspaces are affected +when they invoke an explicitly selected coordination engine: reads remain available, but an authored or +opaque candidate cannot perform a write without this authority. + +## Receipt sequence + +1. Run the shared engine and preserve its exact refusal. +2. Build the candidate and produce the immutable snapshot plus its proposed decision and action keys. +3. Prepare a proposal JSON containing `baseSha`, `candidateHeadSha`, `sharedRefusal`, one allowed `reason`, + the five evidence references, `candidateDecisionKey`, `candidateActionKey`, and accountable + `hostAcceptance` (`actor` and `acceptedAt`). +4. Have a stable engine measure and bind the candidate and snapshot: + + ```text + fsgg-coord-engine self-host mint proposal.json candidate-engine snapshot.json receipt.txt + fsgg-coord-engine self-host verify receipt.txt candidate-engine /candidate/checkout + fsgg-coord-engine self-host record FS-GG/.github#1234 receipt.txt + ``` + +5. Only after verification, expose the candidate to the shim for the one authorized write session: + + ```text + export FSGG_COORD_ENGINE_BIN=/candidate/checkout/src/FS.GG.Coord.Cli/bin/Release/net10.0/fsgg-coord-engine + export FSGG_COORD_STABLE_ENGINE_BIN=/shared/stable/fsgg-coord-engine + export FSGG_SELF_HOST_RECEIPT=/absolute/path/receipt.txt + scripts/fsgg-coord heartbeat FS-GG/.github#1234 --worker worker-1 + ``` + +The shim asks the distinct stable engine to verify the receipt immediately before forwarding a write. It +checks the receipt digest, candidate SHA-256, reported version, exact candidate `HEAD`, and merge-base. +Missing, malformed, stale, contradictory, anonymous, or self-verified authority is a refusal with no remote +mutation. Read-only candidate inspection does not require a receipt. + +## Post-merge replay + +After merge, rebuild the shared engine, run it against the preserved snapshot, and pass its resulting keys +through the replay verifier: + +```text +fsgg-coord-engine self-host replay receipt.txt snapshot.json +fsgg-coord-engine self-host replay-record FS-GG/.github#1234 receipt.txt snapshot.json +``` + +The first command is a read-only preview. The second appends the digest-bound replay receipt to the same +accountable item. Completion remains blocked after a bootstrap receipt until exactly one matching replay +receipt is durable. A different snapshot digest, decision key, action key, malformed receipt, orphan +replay, or duplicate receipt is refused. Retain the snapshot and provenance material with the two durable +receipts as the delivery evidence set. diff --git a/readiness/2819-pass-red-exhaustion-writer/work-model.json b/readiness/2819-pass-red-exhaustion-writer/work-model.json index d6ac97781..9eb332b37 100644 --- a/readiness/2819-pass-red-exhaustion-writer/work-model.json +++ b/readiness/2819-pass-red-exhaustion-writer/work-model.json @@ -772,7 +772,7 @@ "FR-001" ], "artifactRefs": [ - "work/2819-pass-red-exhaustion-writer/artifacts/verification.trx" + "work/2819-pass-red-exhaustion-writer/artifacts/verification.test-report.xml" ], "result": "pass", "synthetic": false, @@ -798,7 +798,7 @@ "FR-002" ], "artifactRefs": [ - "work/2819-pass-red-exhaustion-writer/artifacts/verification.trx" + "work/2819-pass-red-exhaustion-writer/artifacts/verification.test-report.xml" ], "result": "pass", "synthetic": false, @@ -824,7 +824,7 @@ "FR-003" ], "artifactRefs": [ - "work/2819-pass-red-exhaustion-writer/artifacts/verification.trx" + "work/2819-pass-red-exhaustion-writer/artifacts/verification.test-report.xml" ], "result": "pass", "synthetic": false, @@ -850,7 +850,7 @@ "FR-004" ], "artifactRefs": [ - "work/2819-pass-red-exhaustion-writer/artifacts/verification.trx" + "work/2819-pass-red-exhaustion-writer/artifacts/verification.test-report.xml" ], "result": "pass", "synthetic": false, @@ -876,7 +876,7 @@ "FR-005" ], "artifactRefs": [ - "work/2819-pass-red-exhaustion-writer/artifacts/verification.trx" + "work/2819-pass-red-exhaustion-writer/artifacts/verification.test-report.xml" ], "result": "pass", "synthetic": false, @@ -902,7 +902,7 @@ "FR-006" ], "artifactRefs": [ - "work/2819-pass-red-exhaustion-writer/artifacts/verification.trx" + "work/2819-pass-red-exhaustion-writer/artifacts/verification.test-report.xml" ], "result": "pass", "synthetic": false, @@ -926,7 +926,7 @@ ], "requirementRefs": [], "artifactRefs": [ - "work/2819-pass-red-exhaustion-writer/artifacts/verification.trx" + "work/2819-pass-red-exhaustion-writer/artifacts/verification.test-report.xml" ], "result": "pass", "synthetic": false, @@ -950,7 +950,7 @@ ], "requirementRefs": [], "artifactRefs": [ - "work/2819-pass-red-exhaustion-writer/artifacts/verification.trx" + "work/2819-pass-red-exhaustion-writer/artifacts/verification.test-report.xml" ], "result": "pass", "synthetic": false, @@ -974,7 +974,7 @@ ], "requirementRefs": [], "artifactRefs": [ - "work/2819-pass-red-exhaustion-writer/artifacts/verification.trx" + "work/2819-pass-red-exhaustion-writer/artifacts/verification.test-report.xml" ], "result": "pass", "synthetic": false, @@ -998,7 +998,7 @@ ], "requirementRefs": [], "artifactRefs": [ - "work/2819-pass-red-exhaustion-writer/artifacts/verification.trx" + "work/2819-pass-red-exhaustion-writer/artifacts/verification.test-report.xml" ], "result": "pass", "synthetic": false, @@ -1022,7 +1022,7 @@ ], "requirementRefs": [], "artifactRefs": [ - "work/2819-pass-red-exhaustion-writer/artifacts/verification.trx" + "work/2819-pass-red-exhaustion-writer/artifacts/verification.test-report.xml" ], "result": "pass", "synthetic": false, @@ -1046,7 +1046,7 @@ ], "requirementRefs": [], "artifactRefs": [ - "work/2819-pass-red-exhaustion-writer/artifacts/verification.trx" + "work/2819-pass-red-exhaustion-writer/artifacts/verification.test-report.xml" ], "result": "pass", "synthetic": false, @@ -1070,7 +1070,7 @@ ], "requirementRefs": [], "artifactRefs": [ - "work/2819-pass-red-exhaustion-writer/artifacts/verification.trx" + "work/2819-pass-red-exhaustion-writer/artifacts/verification.test-report.xml" ], "result": "pass", "synthetic": false, @@ -1094,7 +1094,7 @@ ], "requirementRefs": [], "artifactRefs": [ - "work/2819-pass-red-exhaustion-writer/artifacts/verification.trx" + "work/2819-pass-red-exhaustion-writer/artifacts/verification.test-report.xml" ], "result": "pass", "synthetic": false, @@ -1118,7 +1118,7 @@ ], "requirementRefs": [], "artifactRefs": [ - "work/2819-pass-red-exhaustion-writer/artifacts/verification.trx" + "work/2819-pass-red-exhaustion-writer/artifacts/verification.test-report.xml" ], "result": "pass", "synthetic": false, @@ -1142,7 +1142,7 @@ ], "requirementRefs": [], "artifactRefs": [ - "work/2819-pass-red-exhaustion-writer/artifacts/verification.trx" + "work/2819-pass-red-exhaustion-writer/artifacts/verification.test-report.xml" ], "result": "pass", "synthetic": false, @@ -1166,7 +1166,7 @@ ], "requirementRefs": [], "artifactRefs": [ - "work/2819-pass-red-exhaustion-writer/artifacts/verification.trx" + "work/2819-pass-red-exhaustion-writer/artifacts/verification.test-report.xml" ], "result": "pass", "synthetic": false, diff --git a/readiness/coordination-change-risk-mitigation/agent-commands/claude/commands.md b/readiness/coordination-change-risk-mitigation/agent-commands/claude/commands.md new file mode 100644 index 000000000..b823d346b --- /dev/null +++ b/readiness/coordination-change-risk-mitigation/agent-commands/claude/commands.md @@ -0,0 +1,199 @@ +# Agent commands for claude (generated) + +Generated from `readiness/coordination-change-risk-mitigation/work-model.json`. This is a generated projection of the +normalized work model, not an authored source of truth. See `guidance.json`. + +## T001 — Implement requirement FR-001 +- Stage: specify +- Purpose: Carry out lifecycle task T001 (done) covering AC-001, FR-001, PD-002. +- Related: AC-001, FR-001, PD-002 + +## T002 — Implement requirement FR-002 +- Stage: specify +- Purpose: Carry out lifecycle task T002 (pending) covering AC-002, FR-002, PD-003. +- Related: AC-002, FR-002, PD-003 + +## T003 — Implement requirement FR-003 +- Stage: specify +- Purpose: Carry out lifecycle task T003 (pending) covering AC-003, FR-003, PD-004. +- Related: AC-003, FR-003, PD-004 + +## T004 — Implement requirement FR-004 +- Stage: specify +- Purpose: Carry out lifecycle task T004 (pending) covering AC-004, FR-004, PD-005. +- Related: AC-004, FR-004, PD-005 + +## T005 — Implement requirement FR-005 +- Stage: specify +- Purpose: Carry out lifecycle task T005 (pending) covering AC-005, FR-005, PD-006. +- Related: AC-005, FR-005, PD-006 + +## T006 — Implement requirement FR-006 +- Stage: specify +- Purpose: Carry out lifecycle task T006 (pending) covering AC-006, FR-006, PD-007. +- Related: AC-006, FR-006, PD-007 + +## T007 — Implement requirement FR-007 +- Stage: specify +- Purpose: Carry out lifecycle task T007 (pending) covering AC-007, FR-007, PD-008. +- Related: AC-007, FR-007, PD-008 + +## T008 — Implement requirement FR-008 +- Stage: specify +- Purpose: Carry out lifecycle task T008 (pending) covering AC-008, FR-008, PD-009. +- Related: AC-008, FR-008, PD-009 + +## T009 — Implement requirement FR-009 +- Stage: specify +- Purpose: Carry out lifecycle task T009 (done) covering AC-009, FR-009, PD-001. +- Related: AC-009, FR-009, PD-001 + +## T010 — Implement clarification decision DEC-001 +- Stage: specify +- Purpose: Carry out lifecycle task T010 (done) covering DEC-001. +- Related: DEC-001 + +## T011 — Implement clarification decision DEC-002 +- Stage: specify +- Purpose: Carry out lifecycle task T011 (pending) covering DEC-002. +- Related: DEC-002 + +## T012 — Implement clarification decision DEC-003 +- Stage: specify +- Purpose: Carry out lifecycle task T012 (pending) covering DEC-003. +- Related: DEC-003 + +## T013 — Implement clarification decision DEC-004 +- Stage: specify +- Purpose: Carry out lifecycle task T013 (pending) covering DEC-004. +- Related: DEC-004 + +## T014 — Implement clarification decision DEC-005 +- Stage: specify +- Purpose: Carry out lifecycle task T014 (pending) covering DEC-005. +- Related: DEC-005 + +## T015 — Update contract surface PC-001 +- Stage: specify +- Purpose: Carry out lifecycle task T015 (done) covering PC-001, PD-002. +- Related: PC-001, PD-002 + +## T016 — Update contract surface PC-002 +- Stage: specify +- Purpose: Carry out lifecycle task T016 (pending) covering PC-002, PD-003. +- Related: PC-002, PD-003 + +## T017 — Update contract surface PC-003 +- Stage: specify +- Purpose: Carry out lifecycle task T017 (pending) covering PC-003, PD-004. +- Related: PC-003, PD-004 + +## T018 — Update contract surface PC-004 +- Stage: specify +- Purpose: Carry out lifecycle task T018 (pending) covering PC-004, PD-005. +- Related: PC-004, PD-005 + +## T019 — Update contract surface PC-005 +- Stage: specify +- Purpose: Carry out lifecycle task T019 (pending) covering PC-005, PD-006. +- Related: PC-005, PD-006 + +## T020 — Update contract surface PC-006 +- Stage: specify +- Purpose: Carry out lifecycle task T020 (pending) covering PC-006, PD-007. +- Related: PC-006, PD-007 + +## T021 — Update contract surface PC-007 +- Stage: specify +- Purpose: Carry out lifecycle task T021 (pending) covering PC-007, PD-008. +- Related: PC-007, PD-008 + +## T022 — Record verification evidence VO-001 +- Stage: specify +- Purpose: Carry out lifecycle task T022 (pending) covering PD-001, VO-001. +- Related: PD-001, VO-001 + +## T023 — Record verification evidence VO-002 +- Stage: specify +- Purpose: Carry out lifecycle task T023 (done) covering PC-001, PD-002, VO-002. +- Related: PC-001, PD-002, VO-002 + +## T024 — Record verification evidence VO-003 +- Stage: specify +- Purpose: Carry out lifecycle task T024 (pending) covering PC-001, PD-002, VO-003. +- Related: PC-001, PD-002, VO-003 + +## T025 — Record verification evidence VO-004 +- Stage: specify +- Purpose: Carry out lifecycle task T025 (pending) covering PC-002, PD-003, PD-007, VO-004. +- Related: PC-002, PD-003, PD-007, VO-004 + +## T026 — Record verification evidence VO-005 +- Stage: specify +- Purpose: Carry out lifecycle task T026 (pending) covering PC-003, PD-004, VO-005. +- Related: PC-003, PD-004, VO-005 + +## T027 — Record verification evidence VO-006 +- Stage: specify +- Purpose: Carry out lifecycle task T027 (pending) covering PC-004, PD-005, VO-006. +- Related: PC-004, PD-005, VO-006 + +## T028 — Record verification evidence VO-007 +- Stage: specify +- Purpose: Carry out lifecycle task T028 (pending) covering PC-005, PD-006, VO-007. +- Related: PC-005, PD-006, VO-007 + +## T029 — Record verification evidence VO-008 +- Stage: specify +- Purpose: Carry out lifecycle task T029 (pending) covering PC-006, PD-007, VO-008. +- Related: PC-006, PD-007, VO-008 + +## T030 — Record verification evidence VO-009 +- Stage: specify +- Purpose: Carry out lifecycle task T030 (pending) covering PC-007, PD-008, VO-009. +- Related: PC-007, PD-008, VO-009 + +## T031 — Record verification evidence VO-010 +- Stage: specify +- Purpose: Carry out lifecycle task T031 (pending) covering PD-009, VO-010. +- Related: PD-009, VO-010 + +## T032 — Handle migration posture PM-001 +- Stage: specify +- Purpose: Carry out lifecycle task T032 (done) covering PC-001, PM-001. +- Related: PC-001, PM-001 + +## T033 — Handle migration posture PM-002 +- Stage: specify +- Purpose: Carry out lifecycle task T033 (pending) covering PC-002, PM-002. +- Related: PC-002, PM-002 + +## T034 — Handle migration posture PM-003 +- Stage: specify +- Purpose: Carry out lifecycle task T034 (pending) covering PC-003, PM-003. +- Related: PC-003, PM-003 + +## T035 — Handle migration posture PM-004 +- Stage: specify +- Purpose: Carry out lifecycle task T035 (pending) covering PC-005, PM-004. +- Related: PC-005, PM-004 + +## T036 — Handle migration posture PM-005 +- Stage: specify +- Purpose: Carry out lifecycle task T036 (pending) covering PC-007, PM-005. +- Related: PC-007, PM-005 + +## T037 — Refresh generated view impact GV-001 +- Stage: specify +- Purpose: Carry out lifecycle task T037 (pending) covering GV-001, PD-001. +- Related: GV-001, PD-001 + +## T038 — Refresh generated view impact GV-002 +- Stage: specify +- Purpose: Carry out lifecycle task T038 (done) covering GV-002, PD-002. +- Related: GV-002, PD-002 + +## T039 — Refresh generated view impact GV-003 +- Stage: specify +- Purpose: Carry out lifecycle task T039 (pending) covering GV-003, PD-004. +- Related: GV-003, PD-004 diff --git a/readiness/coordination-change-risk-mitigation/agent-commands/claude/guidance.json b/readiness/coordination-change-risk-mitigation/agent-commands/claude/guidance.json new file mode 100644 index 000000000..c247dbbcf --- /dev/null +++ b/readiness/coordination-change-risk-mitigation/agent-commands/claude/guidance.json @@ -0,0 +1,547 @@ +{ + "schemaVersion": 1, + "viewVersion": "1.0", + "workId": "coordination-change-risk-mitigation", + "targetId": "claude", + "generator": "FS.GG.SDD.Artifacts/1.1.0", + "generated": true, + "sources": [ + { + "path": "readiness/coordination-change-risk-mitigation/work-model.json", + "kind": "workModel", + "digest": { + "algorithm": "sha256", + "value": "00fea72e349956b5653f3555fbeb74b53fb767197e241fe38a50b9336dcbb038" + }, + "schemaVersion": 1, + "schemaStatus": "current" + } + ], + "behaviorModelDigest": { + "algorithm": "sha256", + "value": "5f4b86aaf52d429b7e2360ee2c7c929d09e037a07b5324a2afc217b573286883" + }, + "commands": [ + { + "id": "T001", + "title": "Implement requirement FR-001", + "stage": "specify", + "purpose": "Carry out lifecycle task T001 (done) covering AC-001, FR-001, PD-002.", + "relatedIds": [ + "AC-001", + "FR-001", + "PD-002" + ] + }, + { + "id": "T002", + "title": "Implement requirement FR-002", + "stage": "specify", + "purpose": "Carry out lifecycle task T002 (pending) covering AC-002, FR-002, PD-003.", + "relatedIds": [ + "AC-002", + "FR-002", + "PD-003" + ] + }, + { + "id": "T003", + "title": "Implement requirement FR-003", + "stage": "specify", + "purpose": "Carry out lifecycle task T003 (pending) covering AC-003, FR-003, PD-004.", + "relatedIds": [ + "AC-003", + "FR-003", + "PD-004" + ] + }, + { + "id": "T004", + "title": "Implement requirement FR-004", + "stage": "specify", + "purpose": "Carry out lifecycle task T004 (pending) covering AC-004, FR-004, PD-005.", + "relatedIds": [ + "AC-004", + "FR-004", + "PD-005" + ] + }, + { + "id": "T005", + "title": "Implement requirement FR-005", + "stage": "specify", + "purpose": "Carry out lifecycle task T005 (pending) covering AC-005, FR-005, PD-006.", + "relatedIds": [ + "AC-005", + "FR-005", + "PD-006" + ] + }, + { + "id": "T006", + "title": "Implement requirement FR-006", + "stage": "specify", + "purpose": "Carry out lifecycle task T006 (pending) covering AC-006, FR-006, PD-007.", + "relatedIds": [ + "AC-006", + "FR-006", + "PD-007" + ] + }, + { + "id": "T007", + "title": "Implement requirement FR-007", + "stage": "specify", + "purpose": "Carry out lifecycle task T007 (pending) covering AC-007, FR-007, PD-008.", + "relatedIds": [ + "AC-007", + "FR-007", + "PD-008" + ] + }, + { + "id": "T008", + "title": "Implement requirement FR-008", + "stage": "specify", + "purpose": "Carry out lifecycle task T008 (pending) covering AC-008, FR-008, PD-009.", + "relatedIds": [ + "AC-008", + "FR-008", + "PD-009" + ] + }, + { + "id": "T009", + "title": "Implement requirement FR-009", + "stage": "specify", + "purpose": "Carry out lifecycle task T009 (done) covering AC-009, FR-009, PD-001.", + "relatedIds": [ + "AC-009", + "FR-009", + "PD-001" + ] + }, + { + "id": "T010", + "title": "Implement clarification decision DEC-001", + "stage": "specify", + "purpose": "Carry out lifecycle task T010 (done) covering DEC-001.", + "relatedIds": [ + "DEC-001" + ] + }, + { + "id": "T011", + "title": "Implement clarification decision DEC-002", + "stage": "specify", + "purpose": "Carry out lifecycle task T011 (pending) covering DEC-002.", + "relatedIds": [ + "DEC-002" + ] + }, + { + "id": "T012", + "title": "Implement clarification decision DEC-003", + "stage": "specify", + "purpose": "Carry out lifecycle task T012 (pending) covering DEC-003.", + "relatedIds": [ + "DEC-003" + ] + }, + { + "id": "T013", + "title": "Implement clarification decision DEC-004", + "stage": "specify", + "purpose": "Carry out lifecycle task T013 (pending) covering DEC-004.", + "relatedIds": [ + "DEC-004" + ] + }, + { + "id": "T014", + "title": "Implement clarification decision DEC-005", + "stage": "specify", + "purpose": "Carry out lifecycle task T014 (pending) covering DEC-005.", + "relatedIds": [ + "DEC-005" + ] + }, + { + "id": "T015", + "title": "Update contract surface PC-001", + "stage": "specify", + "purpose": "Carry out lifecycle task T015 (done) covering PC-001, PD-002.", + "relatedIds": [ + "PC-001", + "PD-002" + ] + }, + { + "id": "T016", + "title": "Update contract surface PC-002", + "stage": "specify", + "purpose": "Carry out lifecycle task T016 (pending) covering PC-002, PD-003.", + "relatedIds": [ + "PC-002", + "PD-003" + ] + }, + { + "id": "T017", + "title": "Update contract surface PC-003", + "stage": "specify", + "purpose": "Carry out lifecycle task T017 (pending) covering PC-003, PD-004.", + "relatedIds": [ + "PC-003", + "PD-004" + ] + }, + { + "id": "T018", + "title": "Update contract surface PC-004", + "stage": "specify", + "purpose": "Carry out lifecycle task T018 (pending) covering PC-004, PD-005.", + "relatedIds": [ + "PC-004", + "PD-005" + ] + }, + { + "id": "T019", + "title": "Update contract surface PC-005", + "stage": "specify", + "purpose": "Carry out lifecycle task T019 (pending) covering PC-005, PD-006.", + "relatedIds": [ + "PC-005", + "PD-006" + ] + }, + { + "id": "T020", + "title": "Update contract surface PC-006", + "stage": "specify", + "purpose": "Carry out lifecycle task T020 (pending) covering PC-006, PD-007.", + "relatedIds": [ + "PC-006", + "PD-007" + ] + }, + { + "id": "T021", + "title": "Update contract surface PC-007", + "stage": "specify", + "purpose": "Carry out lifecycle task T021 (pending) covering PC-007, PD-008.", + "relatedIds": [ + "PC-007", + "PD-008" + ] + }, + { + "id": "T022", + "title": "Record verification evidence VO-001", + "stage": "specify", + "purpose": "Carry out lifecycle task T022 (pending) covering PD-001, VO-001.", + "relatedIds": [ + "PD-001", + "VO-001" + ] + }, + { + "id": "T023", + "title": "Record verification evidence VO-002", + "stage": "specify", + "purpose": "Carry out lifecycle task T023 (done) covering PC-001, PD-002, VO-002.", + "relatedIds": [ + "PC-001", + "PD-002", + "VO-002" + ] + }, + { + "id": "T024", + "title": "Record verification evidence VO-003", + "stage": "specify", + "purpose": "Carry out lifecycle task T024 (pending) covering PC-001, PD-002, VO-003.", + "relatedIds": [ + "PC-001", + "PD-002", + "VO-003" + ] + }, + { + "id": "T025", + "title": "Record verification evidence VO-004", + "stage": "specify", + "purpose": "Carry out lifecycle task T025 (pending) covering PC-002, PD-003, PD-007, VO-004.", + "relatedIds": [ + "PC-002", + "PD-003", + "PD-007", + "VO-004" + ] + }, + { + "id": "T026", + "title": "Record verification evidence VO-005", + "stage": "specify", + "purpose": "Carry out lifecycle task T026 (pending) covering PC-003, PD-004, VO-005.", + "relatedIds": [ + "PC-003", + "PD-004", + "VO-005" + ] + }, + { + "id": "T027", + "title": "Record verification evidence VO-006", + "stage": "specify", + "purpose": "Carry out lifecycle task T027 (pending) covering PC-004, PD-005, VO-006.", + "relatedIds": [ + "PC-004", + "PD-005", + "VO-006" + ] + }, + { + "id": "T028", + "title": "Record verification evidence VO-007", + "stage": "specify", + "purpose": "Carry out lifecycle task T028 (pending) covering PC-005, PD-006, VO-007.", + "relatedIds": [ + "PC-005", + "PD-006", + "VO-007" + ] + }, + { + "id": "T029", + "title": "Record verification evidence VO-008", + "stage": "specify", + "purpose": "Carry out lifecycle task T029 (pending) covering PC-006, PD-007, VO-008.", + "relatedIds": [ + "PC-006", + "PD-007", + "VO-008" + ] + }, + { + "id": "T030", + "title": "Record verification evidence VO-009", + "stage": "specify", + "purpose": "Carry out lifecycle task T030 (pending) covering PC-007, PD-008, VO-009.", + "relatedIds": [ + "PC-007", + "PD-008", + "VO-009" + ] + }, + { + "id": "T031", + "title": "Record verification evidence VO-010", + "stage": "specify", + "purpose": "Carry out lifecycle task T031 (pending) covering PD-009, VO-010.", + "relatedIds": [ + "PD-009", + "VO-010" + ] + }, + { + "id": "T032", + "title": "Handle migration posture PM-001", + "stage": "specify", + "purpose": "Carry out lifecycle task T032 (done) covering PC-001, PM-001.", + "relatedIds": [ + "PC-001", + "PM-001" + ] + }, + { + "id": "T033", + "title": "Handle migration posture PM-002", + "stage": "specify", + "purpose": "Carry out lifecycle task T033 (pending) covering PC-002, PM-002.", + "relatedIds": [ + "PC-002", + "PM-002" + ] + }, + { + "id": "T034", + "title": "Handle migration posture PM-003", + "stage": "specify", + "purpose": "Carry out lifecycle task T034 (pending) covering PC-003, PM-003.", + "relatedIds": [ + "PC-003", + "PM-003" + ] + }, + { + "id": "T035", + "title": "Handle migration posture PM-004", + "stage": "specify", + "purpose": "Carry out lifecycle task T035 (pending) covering PC-005, PM-004.", + "relatedIds": [ + "PC-005", + "PM-004" + ] + }, + { + "id": "T036", + "title": "Handle migration posture PM-005", + "stage": "specify", + "purpose": "Carry out lifecycle task T036 (pending) covering PC-007, PM-005.", + "relatedIds": [ + "PC-007", + "PM-005" + ] + }, + { + "id": "T037", + "title": "Refresh generated view impact GV-001", + "stage": "specify", + "purpose": "Carry out lifecycle task T037 (pending) covering GV-001, PD-001.", + "relatedIds": [ + "GV-001", + "PD-001" + ] + }, + { + "id": "T038", + "title": "Refresh generated view impact GV-002", + "stage": "specify", + "purpose": "Carry out lifecycle task T038 (done) covering GV-002, PD-002.", + "relatedIds": [ + "GV-002", + "PD-002" + ] + }, + { + "id": "T039", + "title": "Refresh generated view impact GV-003", + "stage": "specify", + "purpose": "Carry out lifecycle task T039 (pending) covering GV-003, PD-004.", + "relatedIds": [ + "GV-003", + "PD-004" + ] + } + ], + "skills": [ + { + "id": "automated-tests", + "title": "automated-tests", + "capability": "Required by tasks: T022, T023, T024, T025, T026, T027, T028, T029, T030, T031.", + "relatedIds": [ + "T022", + "T023", + "T024", + "T025", + "T026", + "T027", + "T028", + "T029", + "T030", + "T031" + ] + }, + { + "id": "deterministic-json", + "title": "deterministic-json", + "capability": "Required by tasks: T037, T038, T039.", + "relatedIds": [ + "T037", + "T038", + "T039" + ] + }, + { + "id": "fsharp", + "title": "fsharp", + "capability": "Required by tasks: T001, T002, T003, T004, T005, T006, T007, T008, T009, T010, T011, T012, T013, T014, T015, T016, T017, T018, T019, T020, T021.", + "relatedIds": [ + "T001", + "T002", + "T003", + "T004", + "T005", + "T006", + "T007", + "T008", + "T009", + "T010", + "T011", + "T012", + "T013", + "T014", + "T015", + "T016", + "T017", + "T018", + "T019", + "T020", + "T021" + ] + }, + { + "id": "implementation", + "title": "implementation", + "capability": "Required by tasks: T001, T002, T003, T004, T005, T006, T007, T008, T009, T010, T011, T012, T013, T014.", + "relatedIds": [ + "T001", + "T002", + "T003", + "T004", + "T005", + "T006", + "T007", + "T008", + "T009", + "T010", + "T011", + "T012", + "T013", + "T014" + ] + }, + { + "id": "readiness-evidence", + "title": "readiness-evidence", + "capability": "Required by tasks: T022, T023, T024, T025, T026, T027, T028, T029, T030, T031.", + "relatedIds": [ + "T022", + "T023", + "T024", + "T025", + "T026", + "T027", + "T028", + "T029", + "T030", + "T031" + ] + }, + { + "id": "schema-versioning", + "title": "schema-versioning", + "capability": "Required by tasks: T032, T033, T034, T035, T036.", + "relatedIds": [ + "T032", + "T033", + "T034", + "T035", + "T036" + ] + } + ], + "renderedFiles": [ + { + "path": "readiness/coordination-change-risk-mitigation/agent-commands/claude/commands.md", + "kind": "commands" + }, + { + "path": "readiness/coordination-change-risk-mitigation/agent-commands/claude/skills.md", + "kind": "skills" + } + ], + "diagnostics": [] +} \ No newline at end of file diff --git a/readiness/coordination-change-risk-mitigation/agent-commands/claude/skills.md b/readiness/coordination-change-risk-mitigation/agent-commands/claude/skills.md new file mode 100644 index 000000000..789102782 --- /dev/null +++ b/readiness/coordination-change-risk-mitigation/agent-commands/claude/skills.md @@ -0,0 +1,30 @@ +# Agent skills for claude (generated) + +Generated from `readiness/coordination-change-risk-mitigation/work-model.json`. This is a generated projection of the +normalized work model, not an authored source of truth. See `guidance.json`. + +For public-impact F# work, author or update the compiled `.fsi` signature before implementation hardens the surface. Prefer simple modules, functions, records, and discriminated unions; keep effects at explicit boundaries. + +## automated-tests — automated-tests +- Capability: Required by tasks: T022, T023, T024, T025, T026, T027, T028, T029, T030, T031. +- Related: T022, T023, T024, T025, T026, T027, T028, T029, T030, T031 + +## deterministic-json — deterministic-json +- Capability: Required by tasks: T037, T038, T039. +- Related: T037, T038, T039 + +## fsharp — fsharp +- Capability: Required by tasks: T001, T002, T003, T004, T005, T006, T007, T008, T009, T010, T011, T012, T013, T014, T015, T016, T017, T018, T019, T020, T021. +- Related: T001, T002, T003, T004, T005, T006, T007, T008, T009, T010, T011, T012, T013, T014, T015, T016, T017, T018, T019, T020, T021 + +## implementation — implementation +- Capability: Required by tasks: T001, T002, T003, T004, T005, T006, T007, T008, T009, T010, T011, T012, T013, T014. +- Related: T001, T002, T003, T004, T005, T006, T007, T008, T009, T010, T011, T012, T013, T014 + +## readiness-evidence — readiness-evidence +- Capability: Required by tasks: T022, T023, T024, T025, T026, T027, T028, T029, T030, T031. +- Related: T022, T023, T024, T025, T026, T027, T028, T029, T030, T031 + +## schema-versioning — schema-versioning +- Capability: Required by tasks: T032, T033, T034, T035, T036. +- Related: T032, T033, T034, T035, T036 diff --git a/readiness/coordination-change-risk-mitigation/agent-commands/codex/commands.md b/readiness/coordination-change-risk-mitigation/agent-commands/codex/commands.md new file mode 100644 index 000000000..471a549c1 --- /dev/null +++ b/readiness/coordination-change-risk-mitigation/agent-commands/codex/commands.md @@ -0,0 +1,199 @@ +# Agent commands for codex (generated) + +Generated from `readiness/coordination-change-risk-mitigation/work-model.json`. This is a generated projection of the +normalized work model, not an authored source of truth. See `guidance.json`. + +## T001 — Implement requirement FR-001 +- Stage: specify +- Purpose: Carry out lifecycle task T001 (done) covering AC-001, FR-001, PD-002. +- Related: AC-001, FR-001, PD-002 + +## T002 — Implement requirement FR-002 +- Stage: specify +- Purpose: Carry out lifecycle task T002 (pending) covering AC-002, FR-002, PD-003. +- Related: AC-002, FR-002, PD-003 + +## T003 — Implement requirement FR-003 +- Stage: specify +- Purpose: Carry out lifecycle task T003 (pending) covering AC-003, FR-003, PD-004. +- Related: AC-003, FR-003, PD-004 + +## T004 — Implement requirement FR-004 +- Stage: specify +- Purpose: Carry out lifecycle task T004 (pending) covering AC-004, FR-004, PD-005. +- Related: AC-004, FR-004, PD-005 + +## T005 — Implement requirement FR-005 +- Stage: specify +- Purpose: Carry out lifecycle task T005 (pending) covering AC-005, FR-005, PD-006. +- Related: AC-005, FR-005, PD-006 + +## T006 — Implement requirement FR-006 +- Stage: specify +- Purpose: Carry out lifecycle task T006 (pending) covering AC-006, FR-006, PD-007. +- Related: AC-006, FR-006, PD-007 + +## T007 — Implement requirement FR-007 +- Stage: specify +- Purpose: Carry out lifecycle task T007 (pending) covering AC-007, FR-007, PD-008. +- Related: AC-007, FR-007, PD-008 + +## T008 — Implement requirement FR-008 +- Stage: specify +- Purpose: Carry out lifecycle task T008 (pending) covering AC-008, FR-008, PD-009. +- Related: AC-008, FR-008, PD-009 + +## T009 — Implement requirement FR-009 +- Stage: specify +- Purpose: Carry out lifecycle task T009 (done) covering AC-009, FR-009, PD-001. +- Related: AC-009, FR-009, PD-001 + +## T010 — Implement clarification decision DEC-001 +- Stage: specify +- Purpose: Carry out lifecycle task T010 (done) covering DEC-001. +- Related: DEC-001 + +## T011 — Implement clarification decision DEC-002 +- Stage: specify +- Purpose: Carry out lifecycle task T011 (pending) covering DEC-002. +- Related: DEC-002 + +## T012 — Implement clarification decision DEC-003 +- Stage: specify +- Purpose: Carry out lifecycle task T012 (pending) covering DEC-003. +- Related: DEC-003 + +## T013 — Implement clarification decision DEC-004 +- Stage: specify +- Purpose: Carry out lifecycle task T013 (pending) covering DEC-004. +- Related: DEC-004 + +## T014 — Implement clarification decision DEC-005 +- Stage: specify +- Purpose: Carry out lifecycle task T014 (pending) covering DEC-005. +- Related: DEC-005 + +## T015 — Update contract surface PC-001 +- Stage: specify +- Purpose: Carry out lifecycle task T015 (done) covering PC-001, PD-002. +- Related: PC-001, PD-002 + +## T016 — Update contract surface PC-002 +- Stage: specify +- Purpose: Carry out lifecycle task T016 (pending) covering PC-002, PD-003. +- Related: PC-002, PD-003 + +## T017 — Update contract surface PC-003 +- Stage: specify +- Purpose: Carry out lifecycle task T017 (pending) covering PC-003, PD-004. +- Related: PC-003, PD-004 + +## T018 — Update contract surface PC-004 +- Stage: specify +- Purpose: Carry out lifecycle task T018 (pending) covering PC-004, PD-005. +- Related: PC-004, PD-005 + +## T019 — Update contract surface PC-005 +- Stage: specify +- Purpose: Carry out lifecycle task T019 (pending) covering PC-005, PD-006. +- Related: PC-005, PD-006 + +## T020 — Update contract surface PC-006 +- Stage: specify +- Purpose: Carry out lifecycle task T020 (pending) covering PC-006, PD-007. +- Related: PC-006, PD-007 + +## T021 — Update contract surface PC-007 +- Stage: specify +- Purpose: Carry out lifecycle task T021 (pending) covering PC-007, PD-008. +- Related: PC-007, PD-008 + +## T022 — Record verification evidence VO-001 +- Stage: specify +- Purpose: Carry out lifecycle task T022 (pending) covering PD-001, VO-001. +- Related: PD-001, VO-001 + +## T023 — Record verification evidence VO-002 +- Stage: specify +- Purpose: Carry out lifecycle task T023 (done) covering PC-001, PD-002, VO-002. +- Related: PC-001, PD-002, VO-002 + +## T024 — Record verification evidence VO-003 +- Stage: specify +- Purpose: Carry out lifecycle task T024 (pending) covering PC-001, PD-002, VO-003. +- Related: PC-001, PD-002, VO-003 + +## T025 — Record verification evidence VO-004 +- Stage: specify +- Purpose: Carry out lifecycle task T025 (pending) covering PC-002, PD-003, PD-007, VO-004. +- Related: PC-002, PD-003, PD-007, VO-004 + +## T026 — Record verification evidence VO-005 +- Stage: specify +- Purpose: Carry out lifecycle task T026 (pending) covering PC-003, PD-004, VO-005. +- Related: PC-003, PD-004, VO-005 + +## T027 — Record verification evidence VO-006 +- Stage: specify +- Purpose: Carry out lifecycle task T027 (pending) covering PC-004, PD-005, VO-006. +- Related: PC-004, PD-005, VO-006 + +## T028 — Record verification evidence VO-007 +- Stage: specify +- Purpose: Carry out lifecycle task T028 (pending) covering PC-005, PD-006, VO-007. +- Related: PC-005, PD-006, VO-007 + +## T029 — Record verification evidence VO-008 +- Stage: specify +- Purpose: Carry out lifecycle task T029 (pending) covering PC-006, PD-007, VO-008. +- Related: PC-006, PD-007, VO-008 + +## T030 — Record verification evidence VO-009 +- Stage: specify +- Purpose: Carry out lifecycle task T030 (pending) covering PC-007, PD-008, VO-009. +- Related: PC-007, PD-008, VO-009 + +## T031 — Record verification evidence VO-010 +- Stage: specify +- Purpose: Carry out lifecycle task T031 (pending) covering PD-009, VO-010. +- Related: PD-009, VO-010 + +## T032 — Handle migration posture PM-001 +- Stage: specify +- Purpose: Carry out lifecycle task T032 (done) covering PC-001, PM-001. +- Related: PC-001, PM-001 + +## T033 — Handle migration posture PM-002 +- Stage: specify +- Purpose: Carry out lifecycle task T033 (pending) covering PC-002, PM-002. +- Related: PC-002, PM-002 + +## T034 — Handle migration posture PM-003 +- Stage: specify +- Purpose: Carry out lifecycle task T034 (pending) covering PC-003, PM-003. +- Related: PC-003, PM-003 + +## T035 — Handle migration posture PM-004 +- Stage: specify +- Purpose: Carry out lifecycle task T035 (pending) covering PC-005, PM-004. +- Related: PC-005, PM-004 + +## T036 — Handle migration posture PM-005 +- Stage: specify +- Purpose: Carry out lifecycle task T036 (pending) covering PC-007, PM-005. +- Related: PC-007, PM-005 + +## T037 — Refresh generated view impact GV-001 +- Stage: specify +- Purpose: Carry out lifecycle task T037 (pending) covering GV-001, PD-001. +- Related: GV-001, PD-001 + +## T038 — Refresh generated view impact GV-002 +- Stage: specify +- Purpose: Carry out lifecycle task T038 (done) covering GV-002, PD-002. +- Related: GV-002, PD-002 + +## T039 — Refresh generated view impact GV-003 +- Stage: specify +- Purpose: Carry out lifecycle task T039 (pending) covering GV-003, PD-004. +- Related: GV-003, PD-004 diff --git a/readiness/coordination-change-risk-mitigation/agent-commands/codex/guidance.json b/readiness/coordination-change-risk-mitigation/agent-commands/codex/guidance.json new file mode 100644 index 000000000..da38f5b1e --- /dev/null +++ b/readiness/coordination-change-risk-mitigation/agent-commands/codex/guidance.json @@ -0,0 +1,547 @@ +{ + "schemaVersion": 1, + "viewVersion": "1.0", + "workId": "coordination-change-risk-mitigation", + "targetId": "codex", + "generator": "FS.GG.SDD.Artifacts/1.1.0", + "generated": true, + "sources": [ + { + "path": "readiness/coordination-change-risk-mitigation/work-model.json", + "kind": "workModel", + "digest": { + "algorithm": "sha256", + "value": "00fea72e349956b5653f3555fbeb74b53fb767197e241fe38a50b9336dcbb038" + }, + "schemaVersion": 1, + "schemaStatus": "current" + } + ], + "behaviorModelDigest": { + "algorithm": "sha256", + "value": "5f4b86aaf52d429b7e2360ee2c7c929d09e037a07b5324a2afc217b573286883" + }, + "commands": [ + { + "id": "T001", + "title": "Implement requirement FR-001", + "stage": "specify", + "purpose": "Carry out lifecycle task T001 (done) covering AC-001, FR-001, PD-002.", + "relatedIds": [ + "AC-001", + "FR-001", + "PD-002" + ] + }, + { + "id": "T002", + "title": "Implement requirement FR-002", + "stage": "specify", + "purpose": "Carry out lifecycle task T002 (pending) covering AC-002, FR-002, PD-003.", + "relatedIds": [ + "AC-002", + "FR-002", + "PD-003" + ] + }, + { + "id": "T003", + "title": "Implement requirement FR-003", + "stage": "specify", + "purpose": "Carry out lifecycle task T003 (pending) covering AC-003, FR-003, PD-004.", + "relatedIds": [ + "AC-003", + "FR-003", + "PD-004" + ] + }, + { + "id": "T004", + "title": "Implement requirement FR-004", + "stage": "specify", + "purpose": "Carry out lifecycle task T004 (pending) covering AC-004, FR-004, PD-005.", + "relatedIds": [ + "AC-004", + "FR-004", + "PD-005" + ] + }, + { + "id": "T005", + "title": "Implement requirement FR-005", + "stage": "specify", + "purpose": "Carry out lifecycle task T005 (pending) covering AC-005, FR-005, PD-006.", + "relatedIds": [ + "AC-005", + "FR-005", + "PD-006" + ] + }, + { + "id": "T006", + "title": "Implement requirement FR-006", + "stage": "specify", + "purpose": "Carry out lifecycle task T006 (pending) covering AC-006, FR-006, PD-007.", + "relatedIds": [ + "AC-006", + "FR-006", + "PD-007" + ] + }, + { + "id": "T007", + "title": "Implement requirement FR-007", + "stage": "specify", + "purpose": "Carry out lifecycle task T007 (pending) covering AC-007, FR-007, PD-008.", + "relatedIds": [ + "AC-007", + "FR-007", + "PD-008" + ] + }, + { + "id": "T008", + "title": "Implement requirement FR-008", + "stage": "specify", + "purpose": "Carry out lifecycle task T008 (pending) covering AC-008, FR-008, PD-009.", + "relatedIds": [ + "AC-008", + "FR-008", + "PD-009" + ] + }, + { + "id": "T009", + "title": "Implement requirement FR-009", + "stage": "specify", + "purpose": "Carry out lifecycle task T009 (done) covering AC-009, FR-009, PD-001.", + "relatedIds": [ + "AC-009", + "FR-009", + "PD-001" + ] + }, + { + "id": "T010", + "title": "Implement clarification decision DEC-001", + "stage": "specify", + "purpose": "Carry out lifecycle task T010 (done) covering DEC-001.", + "relatedIds": [ + "DEC-001" + ] + }, + { + "id": "T011", + "title": "Implement clarification decision DEC-002", + "stage": "specify", + "purpose": "Carry out lifecycle task T011 (pending) covering DEC-002.", + "relatedIds": [ + "DEC-002" + ] + }, + { + "id": "T012", + "title": "Implement clarification decision DEC-003", + "stage": "specify", + "purpose": "Carry out lifecycle task T012 (pending) covering DEC-003.", + "relatedIds": [ + "DEC-003" + ] + }, + { + "id": "T013", + "title": "Implement clarification decision DEC-004", + "stage": "specify", + "purpose": "Carry out lifecycle task T013 (pending) covering DEC-004.", + "relatedIds": [ + "DEC-004" + ] + }, + { + "id": "T014", + "title": "Implement clarification decision DEC-005", + "stage": "specify", + "purpose": "Carry out lifecycle task T014 (pending) covering DEC-005.", + "relatedIds": [ + "DEC-005" + ] + }, + { + "id": "T015", + "title": "Update contract surface PC-001", + "stage": "specify", + "purpose": "Carry out lifecycle task T015 (done) covering PC-001, PD-002.", + "relatedIds": [ + "PC-001", + "PD-002" + ] + }, + { + "id": "T016", + "title": "Update contract surface PC-002", + "stage": "specify", + "purpose": "Carry out lifecycle task T016 (pending) covering PC-002, PD-003.", + "relatedIds": [ + "PC-002", + "PD-003" + ] + }, + { + "id": "T017", + "title": "Update contract surface PC-003", + "stage": "specify", + "purpose": "Carry out lifecycle task T017 (pending) covering PC-003, PD-004.", + "relatedIds": [ + "PC-003", + "PD-004" + ] + }, + { + "id": "T018", + "title": "Update contract surface PC-004", + "stage": "specify", + "purpose": "Carry out lifecycle task T018 (pending) covering PC-004, PD-005.", + "relatedIds": [ + "PC-004", + "PD-005" + ] + }, + { + "id": "T019", + "title": "Update contract surface PC-005", + "stage": "specify", + "purpose": "Carry out lifecycle task T019 (pending) covering PC-005, PD-006.", + "relatedIds": [ + "PC-005", + "PD-006" + ] + }, + { + "id": "T020", + "title": "Update contract surface PC-006", + "stage": "specify", + "purpose": "Carry out lifecycle task T020 (pending) covering PC-006, PD-007.", + "relatedIds": [ + "PC-006", + "PD-007" + ] + }, + { + "id": "T021", + "title": "Update contract surface PC-007", + "stage": "specify", + "purpose": "Carry out lifecycle task T021 (pending) covering PC-007, PD-008.", + "relatedIds": [ + "PC-007", + "PD-008" + ] + }, + { + "id": "T022", + "title": "Record verification evidence VO-001", + "stage": "specify", + "purpose": "Carry out lifecycle task T022 (pending) covering PD-001, VO-001.", + "relatedIds": [ + "PD-001", + "VO-001" + ] + }, + { + "id": "T023", + "title": "Record verification evidence VO-002", + "stage": "specify", + "purpose": "Carry out lifecycle task T023 (done) covering PC-001, PD-002, VO-002.", + "relatedIds": [ + "PC-001", + "PD-002", + "VO-002" + ] + }, + { + "id": "T024", + "title": "Record verification evidence VO-003", + "stage": "specify", + "purpose": "Carry out lifecycle task T024 (pending) covering PC-001, PD-002, VO-003.", + "relatedIds": [ + "PC-001", + "PD-002", + "VO-003" + ] + }, + { + "id": "T025", + "title": "Record verification evidence VO-004", + "stage": "specify", + "purpose": "Carry out lifecycle task T025 (pending) covering PC-002, PD-003, PD-007, VO-004.", + "relatedIds": [ + "PC-002", + "PD-003", + "PD-007", + "VO-004" + ] + }, + { + "id": "T026", + "title": "Record verification evidence VO-005", + "stage": "specify", + "purpose": "Carry out lifecycle task T026 (pending) covering PC-003, PD-004, VO-005.", + "relatedIds": [ + "PC-003", + "PD-004", + "VO-005" + ] + }, + { + "id": "T027", + "title": "Record verification evidence VO-006", + "stage": "specify", + "purpose": "Carry out lifecycle task T027 (pending) covering PC-004, PD-005, VO-006.", + "relatedIds": [ + "PC-004", + "PD-005", + "VO-006" + ] + }, + { + "id": "T028", + "title": "Record verification evidence VO-007", + "stage": "specify", + "purpose": "Carry out lifecycle task T028 (pending) covering PC-005, PD-006, VO-007.", + "relatedIds": [ + "PC-005", + "PD-006", + "VO-007" + ] + }, + { + "id": "T029", + "title": "Record verification evidence VO-008", + "stage": "specify", + "purpose": "Carry out lifecycle task T029 (pending) covering PC-006, PD-007, VO-008.", + "relatedIds": [ + "PC-006", + "PD-007", + "VO-008" + ] + }, + { + "id": "T030", + "title": "Record verification evidence VO-009", + "stage": "specify", + "purpose": "Carry out lifecycle task T030 (pending) covering PC-007, PD-008, VO-009.", + "relatedIds": [ + "PC-007", + "PD-008", + "VO-009" + ] + }, + { + "id": "T031", + "title": "Record verification evidence VO-010", + "stage": "specify", + "purpose": "Carry out lifecycle task T031 (pending) covering PD-009, VO-010.", + "relatedIds": [ + "PD-009", + "VO-010" + ] + }, + { + "id": "T032", + "title": "Handle migration posture PM-001", + "stage": "specify", + "purpose": "Carry out lifecycle task T032 (done) covering PC-001, PM-001.", + "relatedIds": [ + "PC-001", + "PM-001" + ] + }, + { + "id": "T033", + "title": "Handle migration posture PM-002", + "stage": "specify", + "purpose": "Carry out lifecycle task T033 (pending) covering PC-002, PM-002.", + "relatedIds": [ + "PC-002", + "PM-002" + ] + }, + { + "id": "T034", + "title": "Handle migration posture PM-003", + "stage": "specify", + "purpose": "Carry out lifecycle task T034 (pending) covering PC-003, PM-003.", + "relatedIds": [ + "PC-003", + "PM-003" + ] + }, + { + "id": "T035", + "title": "Handle migration posture PM-004", + "stage": "specify", + "purpose": "Carry out lifecycle task T035 (pending) covering PC-005, PM-004.", + "relatedIds": [ + "PC-005", + "PM-004" + ] + }, + { + "id": "T036", + "title": "Handle migration posture PM-005", + "stage": "specify", + "purpose": "Carry out lifecycle task T036 (pending) covering PC-007, PM-005.", + "relatedIds": [ + "PC-007", + "PM-005" + ] + }, + { + "id": "T037", + "title": "Refresh generated view impact GV-001", + "stage": "specify", + "purpose": "Carry out lifecycle task T037 (pending) covering GV-001, PD-001.", + "relatedIds": [ + "GV-001", + "PD-001" + ] + }, + { + "id": "T038", + "title": "Refresh generated view impact GV-002", + "stage": "specify", + "purpose": "Carry out lifecycle task T038 (done) covering GV-002, PD-002.", + "relatedIds": [ + "GV-002", + "PD-002" + ] + }, + { + "id": "T039", + "title": "Refresh generated view impact GV-003", + "stage": "specify", + "purpose": "Carry out lifecycle task T039 (pending) covering GV-003, PD-004.", + "relatedIds": [ + "GV-003", + "PD-004" + ] + } + ], + "skills": [ + { + "id": "automated-tests", + "title": "automated-tests", + "capability": "Required by tasks: T022, T023, T024, T025, T026, T027, T028, T029, T030, T031.", + "relatedIds": [ + "T022", + "T023", + "T024", + "T025", + "T026", + "T027", + "T028", + "T029", + "T030", + "T031" + ] + }, + { + "id": "deterministic-json", + "title": "deterministic-json", + "capability": "Required by tasks: T037, T038, T039.", + "relatedIds": [ + "T037", + "T038", + "T039" + ] + }, + { + "id": "fsharp", + "title": "fsharp", + "capability": "Required by tasks: T001, T002, T003, T004, T005, T006, T007, T008, T009, T010, T011, T012, T013, T014, T015, T016, T017, T018, T019, T020, T021.", + "relatedIds": [ + "T001", + "T002", + "T003", + "T004", + "T005", + "T006", + "T007", + "T008", + "T009", + "T010", + "T011", + "T012", + "T013", + "T014", + "T015", + "T016", + "T017", + "T018", + "T019", + "T020", + "T021" + ] + }, + { + "id": "implementation", + "title": "implementation", + "capability": "Required by tasks: T001, T002, T003, T004, T005, T006, T007, T008, T009, T010, T011, T012, T013, T014.", + "relatedIds": [ + "T001", + "T002", + "T003", + "T004", + "T005", + "T006", + "T007", + "T008", + "T009", + "T010", + "T011", + "T012", + "T013", + "T014" + ] + }, + { + "id": "readiness-evidence", + "title": "readiness-evidence", + "capability": "Required by tasks: T022, T023, T024, T025, T026, T027, T028, T029, T030, T031.", + "relatedIds": [ + "T022", + "T023", + "T024", + "T025", + "T026", + "T027", + "T028", + "T029", + "T030", + "T031" + ] + }, + { + "id": "schema-versioning", + "title": "schema-versioning", + "capability": "Required by tasks: T032, T033, T034, T035, T036.", + "relatedIds": [ + "T032", + "T033", + "T034", + "T035", + "T036" + ] + } + ], + "renderedFiles": [ + { + "path": "readiness/coordination-change-risk-mitigation/agent-commands/codex/commands.md", + "kind": "commands" + }, + { + "path": "readiness/coordination-change-risk-mitigation/agent-commands/codex/skills.md", + "kind": "skills" + } + ], + "diagnostics": [] +} \ No newline at end of file diff --git a/readiness/coordination-change-risk-mitigation/agent-commands/codex/skills.md b/readiness/coordination-change-risk-mitigation/agent-commands/codex/skills.md new file mode 100644 index 000000000..900169b20 --- /dev/null +++ b/readiness/coordination-change-risk-mitigation/agent-commands/codex/skills.md @@ -0,0 +1,30 @@ +# Agent skills for codex (generated) + +Generated from `readiness/coordination-change-risk-mitigation/work-model.json`. This is a generated projection of the +normalized work model, not an authored source of truth. See `guidance.json`. + +For public-impact F# work, author or update the compiled `.fsi` signature before implementation hardens the surface. Prefer simple modules, functions, records, and discriminated unions; keep effects at explicit boundaries. + +## automated-tests — automated-tests +- Capability: Required by tasks: T022, T023, T024, T025, T026, T027, T028, T029, T030, T031. +- Related: T022, T023, T024, T025, T026, T027, T028, T029, T030, T031 + +## deterministic-json — deterministic-json +- Capability: Required by tasks: T037, T038, T039. +- Related: T037, T038, T039 + +## fsharp — fsharp +- Capability: Required by tasks: T001, T002, T003, T004, T005, T006, T007, T008, T009, T010, T011, T012, T013, T014, T015, T016, T017, T018, T019, T020, T021. +- Related: T001, T002, T003, T004, T005, T006, T007, T008, T009, T010, T011, T012, T013, T014, T015, T016, T017, T018, T019, T020, T021 + +## implementation — implementation +- Capability: Required by tasks: T001, T002, T003, T004, T005, T006, T007, T008, T009, T010, T011, T012, T013, T014. +- Related: T001, T002, T003, T004, T005, T006, T007, T008, T009, T010, T011, T012, T013, T014 + +## readiness-evidence — readiness-evidence +- Capability: Required by tasks: T022, T023, T024, T025, T026, T027, T028, T029, T030, T031. +- Related: T022, T023, T024, T025, T026, T027, T028, T029, T030, T031 + +## schema-versioning — schema-versioning +- Capability: Required by tasks: T032, T033, T034, T035, T036. +- Related: T032, T033, T034, T035, T036 diff --git a/readiness/coordination-change-risk-mitigation/analysis.json b/readiness/coordination-change-risk-mitigation/analysis.json new file mode 100644 index 000000000..c3c98e97f --- /dev/null +++ b/readiness/coordination-change-risk-mitigation/analysis.json @@ -0,0 +1,1332 @@ +{ + "schemaVersion": 1, + "viewVersion": "1.0", + "workId": "coordination-change-risk-mitigation", + "stage": "analyze", + "status": "implementationReady", + "generator": "FS.GG.SDD.Artifacts/1.1.0", + "sources": [ + { + "path": ".fsgg/agents.yml", + "kind": "agentsConfig", + "digest": { + "algorithm": "sha256", + "value": "c67035b1cf31b6fa802c10f761eeb1e5bf5d198c38d159b54fac299957b5aac3" + }, + "schemaVersion": 1, + "schemaStatus": "current" + }, + { + "path": ".fsgg/project.yml", + "kind": "projectConfig", + "digest": { + "algorithm": "sha256", + "value": "ef78f002b33ce22f738bac2c0dbf716db729a7d3ae3e4a68a4ce4b93810ced66" + }, + "schemaVersion": 1, + "schemaStatus": "current" + }, + { + "path": ".fsgg/sdd.yml", + "kind": "sddConfig", + "digest": { + "algorithm": "sha256", + "value": "fe5a7c270a975153e80ab0d08a610c9b302585dcb0b5f7c654841ceced9272cb" + }, + "schemaVersion": 1, + "schemaStatus": "current" + }, + { + "path": "readiness/coordination-change-risk-mitigation/work-model.json", + "kind": "workModel", + "digest": { + "algorithm": "sha256", + "value": "20ba3fe174bf186c655ac4ab3a45c54f9368d88dee5fba2de415878cc408cfd3" + }, + "schemaVersion": 1, + "schemaStatus": "current" + }, + { + "path": "work/coordination-change-risk-mitigation/checklist.md", + "kind": "checklist", + "digest": { + "algorithm": "sha256", + "value": "ac1c0ac8b8feafbedd9582ac17b8196e57b46867459a31c380cbb83e0a342548" + }, + "schemaVersion": 1, + "schemaStatus": "current" + }, + { + "path": "work/coordination-change-risk-mitigation/clarifications.md", + "kind": "clarification", + "digest": { + "algorithm": "sha256", + "value": "02eedf550b282d9788487b3efbd6f0034d35e5982b70dcf8abf01bd6fa61b18c" + }, + "schemaVersion": 1, + "schemaStatus": "current" + }, + { + "path": "work/coordination-change-risk-mitigation/plan.md", + "kind": "plan", + "digest": { + "algorithm": "sha256", + "value": "6ac822bae2e476fadcadf67890e437775bafd311f11baf6574cc70c48e1dcab6" + }, + "schemaVersion": 1, + "schemaStatus": "current" + }, + { + "path": "work/coordination-change-risk-mitigation/spec.md", + "kind": "specification", + "digest": { + "algorithm": "sha256", + "value": "596003775028144db71fd9a411385e205ed07488ee164d79471c153bb0ec084e" + }, + "schemaVersion": 1, + "schemaStatus": "current" + }, + { + "path": "work/coordination-change-risk-mitigation/tasks.yml", + "kind": "tasks", + "digest": { + "algorithm": "sha256", + "value": "62ab55764176264149db6b706e9dcf9b17d2c9d489bbda1e08599304e2a8ce46" + }, + "schemaVersion": 1, + "schemaStatus": "current" + } + ], + "sourceRelationships": [ + { + "id": "AR001", + "sourcePath": "work/coordination-change-risk-mitigation/checklist.md", + "targetPath": "work/coordination-change-risk-mitigation/plan.md", + "sourceId": null, + "targetId": null, + "relationship": "planSourceChecklist", + "state": "current", + "diagnosticIds": [] + }, + { + "id": "AR002", + "sourcePath": "work/coordination-change-risk-mitigation/checklist.md", + "targetPath": "work/coordination-change-risk-mitigation/tasks.yml", + "sourceId": null, + "targetId": null, + "relationship": "taskSourceChecklist", + "state": "current", + "diagnosticIds": [] + }, + { + "id": "AR003", + "sourcePath": "work/coordination-change-risk-mitigation/clarifications.md", + "targetPath": "work/coordination-change-risk-mitigation/checklist.md", + "sourceId": null, + "targetId": null, + "relationship": "checklistSourceClarifications", + "state": "current", + "diagnosticIds": [] + }, + { + "id": "AR004", + "sourcePath": "work/coordination-change-risk-mitigation/clarifications.md", + "targetPath": "work/coordination-change-risk-mitigation/tasks.yml", + "sourceId": "DEC-001", + "targetId": null, + "relationship": "clarificationDisposition", + "state": "current", + "diagnosticIds": [] + }, + { + "id": "AR005", + "sourcePath": "work/coordination-change-risk-mitigation/clarifications.md", + "targetPath": "work/coordination-change-risk-mitigation/tasks.yml", + "sourceId": "DEC-002", + "targetId": null, + "relationship": "clarificationDisposition", + "state": "current", + "diagnosticIds": [] + }, + { + "id": "AR006", + "sourcePath": "work/coordination-change-risk-mitigation/clarifications.md", + "targetPath": "work/coordination-change-risk-mitigation/tasks.yml", + "sourceId": "DEC-003", + "targetId": null, + "relationship": "clarificationDisposition", + "state": "current", + "diagnosticIds": [] + }, + { + "id": "AR007", + "sourcePath": "work/coordination-change-risk-mitigation/clarifications.md", + "targetPath": "work/coordination-change-risk-mitigation/tasks.yml", + "sourceId": "DEC-004", + "targetId": null, + "relationship": "clarificationDisposition", + "state": "current", + "diagnosticIds": [] + }, + { + "id": "AR008", + "sourcePath": "work/coordination-change-risk-mitigation/clarifications.md", + "targetPath": "work/coordination-change-risk-mitigation/tasks.yml", + "sourceId": "DEC-005", + "targetId": null, + "relationship": "clarificationDisposition", + "state": "current", + "diagnosticIds": [] + }, + { + "id": "AR009", + "sourcePath": "work/coordination-change-risk-mitigation/clarifications.md", + "targetPath": "work/coordination-change-risk-mitigation/plan.md", + "sourceId": null, + "targetId": null, + "relationship": "planSourceClarifications", + "state": "current", + "diagnosticIds": [] + }, + { + "id": "AR010", + "sourcePath": "work/coordination-change-risk-mitigation/clarifications.md", + "targetPath": "work/coordination-change-risk-mitigation/tasks.yml", + "sourceId": null, + "targetId": null, + "relationship": "taskSourceClarifications", + "state": "current", + "diagnosticIds": [] + }, + { + "id": "AR011", + "sourcePath": "work/coordination-change-risk-mitigation/plan.md", + "targetPath": "work/coordination-change-risk-mitigation/tasks.yml", + "sourceId": "PC-001", + "targetId": null, + "relationship": "contractDisposition", + "state": "current", + "diagnosticIds": [] + }, + { + "id": "AR012", + "sourcePath": "work/coordination-change-risk-mitigation/plan.md", + "targetPath": "work/coordination-change-risk-mitigation/tasks.yml", + "sourceId": "PC-002", + "targetId": null, + "relationship": "contractDisposition", + "state": "current", + "diagnosticIds": [] + }, + { + "id": "AR013", + "sourcePath": "work/coordination-change-risk-mitigation/plan.md", + "targetPath": "work/coordination-change-risk-mitigation/tasks.yml", + "sourceId": "PC-003", + "targetId": null, + "relationship": "contractDisposition", + "state": "current", + "diagnosticIds": [] + }, + { + "id": "AR014", + "sourcePath": "work/coordination-change-risk-mitigation/plan.md", + "targetPath": "work/coordination-change-risk-mitigation/tasks.yml", + "sourceId": "PC-004", + "targetId": null, + "relationship": "contractDisposition", + "state": "current", + "diagnosticIds": [] + }, + { + "id": "AR015", + "sourcePath": "work/coordination-change-risk-mitigation/plan.md", + "targetPath": "work/coordination-change-risk-mitigation/tasks.yml", + "sourceId": "PC-005", + "targetId": null, + "relationship": "contractDisposition", + "state": "current", + "diagnosticIds": [] + }, + { + "id": "AR016", + "sourcePath": "work/coordination-change-risk-mitigation/plan.md", + "targetPath": "work/coordination-change-risk-mitigation/tasks.yml", + "sourceId": "PC-006", + "targetId": null, + "relationship": "contractDisposition", + "state": "current", + "diagnosticIds": [] + }, + { + "id": "AR017", + "sourcePath": "work/coordination-change-risk-mitigation/plan.md", + "targetPath": "work/coordination-change-risk-mitigation/tasks.yml", + "sourceId": "PC-007", + "targetId": null, + "relationship": "contractDisposition", + "state": "current", + "diagnosticIds": [] + }, + { + "id": "AR018", + "sourcePath": "work/coordination-change-risk-mitigation/plan.md", + "targetPath": "work/coordination-change-risk-mitigation/tasks.yml", + "sourceId": "GV-001", + "targetId": null, + "relationship": "generatedViewDisposition", + "state": "current", + "diagnosticIds": [] + }, + { + "id": "AR019", + "sourcePath": "work/coordination-change-risk-mitigation/plan.md", + "targetPath": "work/coordination-change-risk-mitigation/tasks.yml", + "sourceId": "GV-002", + "targetId": null, + "relationship": "generatedViewDisposition", + "state": "current", + "diagnosticIds": [] + }, + { + "id": "AR020", + "sourcePath": "work/coordination-change-risk-mitigation/plan.md", + "targetPath": "work/coordination-change-risk-mitigation/tasks.yml", + "sourceId": "GV-003", + "targetId": null, + "relationship": "generatedViewDisposition", + "state": "current", + "diagnosticIds": [] + }, + { + "id": "AR021", + "sourcePath": "work/coordination-change-risk-mitigation/plan.md", + "targetPath": "work/coordination-change-risk-mitigation/tasks.yml", + "sourceId": "PM-001", + "targetId": null, + "relationship": "migrationDisposition", + "state": "current", + "diagnosticIds": [] + }, + { + "id": "AR022", + "sourcePath": "work/coordination-change-risk-mitigation/plan.md", + "targetPath": "work/coordination-change-risk-mitigation/tasks.yml", + "sourceId": "PM-002", + "targetId": null, + "relationship": "migrationDisposition", + "state": "current", + "diagnosticIds": [] + }, + { + "id": "AR023", + "sourcePath": "work/coordination-change-risk-mitigation/plan.md", + "targetPath": "work/coordination-change-risk-mitigation/tasks.yml", + "sourceId": "PM-003", + "targetId": null, + "relationship": "migrationDisposition", + "state": "current", + "diagnosticIds": [] + }, + { + "id": "AR024", + "sourcePath": "work/coordination-change-risk-mitigation/plan.md", + "targetPath": "work/coordination-change-risk-mitigation/tasks.yml", + "sourceId": "PM-004", + "targetId": null, + "relationship": "migrationDisposition", + "state": "current", + "diagnosticIds": [] + }, + { + "id": "AR025", + "sourcePath": "work/coordination-change-risk-mitigation/plan.md", + "targetPath": "work/coordination-change-risk-mitigation/tasks.yml", + "sourceId": "PM-005", + "targetId": null, + "relationship": "migrationDisposition", + "state": "current", + "diagnosticIds": [] + }, + { + "id": "AR026", + "sourcePath": "work/coordination-change-risk-mitigation/plan.md", + "targetPath": "work/coordination-change-risk-mitigation/tasks.yml", + "sourceId": "PD-001", + "targetId": null, + "relationship": "planDecisionDisposition", + "state": "current", + "diagnosticIds": [] + }, + { + "id": "AR027", + "sourcePath": "work/coordination-change-risk-mitigation/plan.md", + "targetPath": "work/coordination-change-risk-mitigation/tasks.yml", + "sourceId": "PD-002", + "targetId": null, + "relationship": "planDecisionDisposition", + "state": "current", + "diagnosticIds": [] + }, + { + "id": "AR028", + "sourcePath": "work/coordination-change-risk-mitigation/plan.md", + "targetPath": "work/coordination-change-risk-mitigation/tasks.yml", + "sourceId": "PD-003", + "targetId": null, + "relationship": "planDecisionDisposition", + "state": "current", + "diagnosticIds": [] + }, + { + "id": "AR029", + "sourcePath": "work/coordination-change-risk-mitigation/plan.md", + "targetPath": "work/coordination-change-risk-mitigation/tasks.yml", + "sourceId": "PD-004", + "targetId": null, + "relationship": "planDecisionDisposition", + "state": "current", + "diagnosticIds": [] + }, + { + "id": "AR030", + "sourcePath": "work/coordination-change-risk-mitigation/plan.md", + "targetPath": "work/coordination-change-risk-mitigation/tasks.yml", + "sourceId": "PD-005", + "targetId": null, + "relationship": "planDecisionDisposition", + "state": "current", + "diagnosticIds": [] + }, + { + "id": "AR031", + "sourcePath": "work/coordination-change-risk-mitigation/plan.md", + "targetPath": "work/coordination-change-risk-mitigation/tasks.yml", + "sourceId": "PD-006", + "targetId": null, + "relationship": "planDecisionDisposition", + "state": "current", + "diagnosticIds": [] + }, + { + "id": "AR032", + "sourcePath": "work/coordination-change-risk-mitigation/plan.md", + "targetPath": "work/coordination-change-risk-mitigation/tasks.yml", + "sourceId": "PD-007", + "targetId": null, + "relationship": "planDecisionDisposition", + "state": "current", + "diagnosticIds": [] + }, + { + "id": "AR033", + "sourcePath": "work/coordination-change-risk-mitigation/plan.md", + "targetPath": "work/coordination-change-risk-mitigation/tasks.yml", + "sourceId": "PD-008", + "targetId": null, + "relationship": "planDecisionDisposition", + "state": "current", + "diagnosticIds": [] + }, + { + "id": "AR034", + "sourcePath": "work/coordination-change-risk-mitigation/plan.md", + "targetPath": "work/coordination-change-risk-mitigation/tasks.yml", + "sourceId": "PD-009", + "targetId": null, + "relationship": "planDecisionDisposition", + "state": "current", + "diagnosticIds": [] + }, + { + "id": "AR035", + "sourcePath": "work/coordination-change-risk-mitigation/plan.md", + "targetPath": "work/coordination-change-risk-mitigation/tasks.yml", + "sourceId": null, + "targetId": null, + "relationship": "taskSourcePlan", + "state": "current", + "diagnosticIds": [] + }, + { + "id": "AR036", + "sourcePath": "work/coordination-change-risk-mitigation/plan.md", + "targetPath": "work/coordination-change-risk-mitigation/tasks.yml", + "sourceId": "VO-001", + "targetId": null, + "relationship": "verificationDisposition", + "state": "current", + "diagnosticIds": [] + }, + { + "id": "AR037", + "sourcePath": "work/coordination-change-risk-mitigation/plan.md", + "targetPath": "work/coordination-change-risk-mitigation/tasks.yml", + "sourceId": "VO-002", + "targetId": null, + "relationship": "verificationDisposition", + "state": "current", + "diagnosticIds": [] + }, + { + "id": "AR038", + "sourcePath": "work/coordination-change-risk-mitigation/plan.md", + "targetPath": "work/coordination-change-risk-mitigation/tasks.yml", + "sourceId": "VO-003", + "targetId": null, + "relationship": "verificationDisposition", + "state": "current", + "diagnosticIds": [] + }, + { + "id": "AR039", + "sourcePath": "work/coordination-change-risk-mitigation/plan.md", + "targetPath": "work/coordination-change-risk-mitigation/tasks.yml", + "sourceId": "VO-004", + "targetId": null, + "relationship": "verificationDisposition", + "state": "current", + "diagnosticIds": [] + }, + { + "id": "AR040", + "sourcePath": "work/coordination-change-risk-mitigation/plan.md", + "targetPath": "work/coordination-change-risk-mitigation/tasks.yml", + "sourceId": "VO-005", + "targetId": null, + "relationship": "verificationDisposition", + "state": "current", + "diagnosticIds": [] + }, + { + "id": "AR041", + "sourcePath": "work/coordination-change-risk-mitigation/plan.md", + "targetPath": "work/coordination-change-risk-mitigation/tasks.yml", + "sourceId": "VO-006", + "targetId": null, + "relationship": "verificationDisposition", + "state": "current", + "diagnosticIds": [] + }, + { + "id": "AR042", + "sourcePath": "work/coordination-change-risk-mitigation/plan.md", + "targetPath": "work/coordination-change-risk-mitigation/tasks.yml", + "sourceId": "VO-007", + "targetId": null, + "relationship": "verificationDisposition", + "state": "current", + "diagnosticIds": [] + }, + { + "id": "AR043", + "sourcePath": "work/coordination-change-risk-mitigation/plan.md", + "targetPath": "work/coordination-change-risk-mitigation/tasks.yml", + "sourceId": "VO-008", + "targetId": null, + "relationship": "verificationDisposition", + "state": "current", + "diagnosticIds": [] + }, + { + "id": "AR044", + "sourcePath": "work/coordination-change-risk-mitigation/plan.md", + "targetPath": "work/coordination-change-risk-mitigation/tasks.yml", + "sourceId": "VO-009", + "targetId": null, + "relationship": "verificationDisposition", + "state": "current", + "diagnosticIds": [] + }, + { + "id": "AR045", + "sourcePath": "work/coordination-change-risk-mitigation/plan.md", + "targetPath": "work/coordination-change-risk-mitigation/tasks.yml", + "sourceId": "VO-010", + "targetId": null, + "relationship": "verificationDisposition", + "state": "current", + "diagnosticIds": [] + }, + { + "id": "AR046", + "sourcePath": "work/coordination-change-risk-mitigation/spec.md", + "targetPath": "work/coordination-change-risk-mitigation/tasks.yml", + "sourceId": "AC-001", + "targetId": null, + "relationship": "acceptanceDisposition", + "state": "current", + "diagnosticIds": [] + }, + { + "id": "AR047", + "sourcePath": "work/coordination-change-risk-mitigation/spec.md", + "targetPath": "work/coordination-change-risk-mitigation/tasks.yml", + "sourceId": "AC-002", + "targetId": null, + "relationship": "acceptanceDisposition", + "state": "current", + "diagnosticIds": [] + }, + { + "id": "AR048", + "sourcePath": "work/coordination-change-risk-mitigation/spec.md", + "targetPath": "work/coordination-change-risk-mitigation/tasks.yml", + "sourceId": "AC-003", + "targetId": null, + "relationship": "acceptanceDisposition", + "state": "current", + "diagnosticIds": [] + }, + { + "id": "AR049", + "sourcePath": "work/coordination-change-risk-mitigation/spec.md", + "targetPath": "work/coordination-change-risk-mitigation/tasks.yml", + "sourceId": "AC-004", + "targetId": null, + "relationship": "acceptanceDisposition", + "state": "current", + "diagnosticIds": [] + }, + { + "id": "AR050", + "sourcePath": "work/coordination-change-risk-mitigation/spec.md", + "targetPath": "work/coordination-change-risk-mitigation/tasks.yml", + "sourceId": "AC-005", + "targetId": null, + "relationship": "acceptanceDisposition", + "state": "current", + "diagnosticIds": [] + }, + { + "id": "AR051", + "sourcePath": "work/coordination-change-risk-mitigation/spec.md", + "targetPath": "work/coordination-change-risk-mitigation/tasks.yml", + "sourceId": "AC-006", + "targetId": null, + "relationship": "acceptanceDisposition", + "state": "current", + "diagnosticIds": [] + }, + { + "id": "AR052", + "sourcePath": "work/coordination-change-risk-mitigation/spec.md", + "targetPath": "work/coordination-change-risk-mitigation/tasks.yml", + "sourceId": "AC-007", + "targetId": null, + "relationship": "acceptanceDisposition", + "state": "current", + "diagnosticIds": [] + }, + { + "id": "AR053", + "sourcePath": "work/coordination-change-risk-mitigation/spec.md", + "targetPath": "work/coordination-change-risk-mitigation/tasks.yml", + "sourceId": "AC-008", + "targetId": null, + "relationship": "acceptanceDisposition", + "state": "current", + "diagnosticIds": [] + }, + { + "id": "AR054", + "sourcePath": "work/coordination-change-risk-mitigation/spec.md", + "targetPath": "work/coordination-change-risk-mitigation/tasks.yml", + "sourceId": "AC-009", + "targetId": null, + "relationship": "acceptanceDisposition", + "state": "current", + "diagnosticIds": [] + }, + { + "id": "AR055", + "sourcePath": "work/coordination-change-risk-mitigation/spec.md", + "targetPath": "work/coordination-change-risk-mitigation/checklist.md", + "sourceId": null, + "targetId": null, + "relationship": "checklistSourceSpec", + "state": "current", + "diagnosticIds": [] + }, + { + "id": "AR056", + "sourcePath": "work/coordination-change-risk-mitigation/spec.md", + "targetPath": "work/coordination-change-risk-mitigation/plan.md", + "sourceId": null, + "targetId": null, + "relationship": "planSourceSpec", + "state": "current", + "diagnosticIds": [] + }, + { + "id": "AR057", + "sourcePath": "work/coordination-change-risk-mitigation/spec.md", + "targetPath": "work/coordination-change-risk-mitigation/tasks.yml", + "sourceId": "FR-001", + "targetId": null, + "relationship": "requirementDisposition", + "state": "current", + "diagnosticIds": [] + }, + { + "id": "AR058", + "sourcePath": "work/coordination-change-risk-mitigation/spec.md", + "targetPath": "work/coordination-change-risk-mitigation/tasks.yml", + "sourceId": "FR-002", + "targetId": null, + "relationship": "requirementDisposition", + "state": "current", + "diagnosticIds": [] + }, + { + "id": "AR059", + "sourcePath": "work/coordination-change-risk-mitigation/spec.md", + "targetPath": "work/coordination-change-risk-mitigation/tasks.yml", + "sourceId": "FR-003", + "targetId": null, + "relationship": "requirementDisposition", + "state": "current", + "diagnosticIds": [] + }, + { + "id": "AR060", + "sourcePath": "work/coordination-change-risk-mitigation/spec.md", + "targetPath": "work/coordination-change-risk-mitigation/tasks.yml", + "sourceId": "FR-004", + "targetId": null, + "relationship": "requirementDisposition", + "state": "current", + "diagnosticIds": [] + }, + { + "id": "AR061", + "sourcePath": "work/coordination-change-risk-mitigation/spec.md", + "targetPath": "work/coordination-change-risk-mitigation/tasks.yml", + "sourceId": "FR-005", + "targetId": null, + "relationship": "requirementDisposition", + "state": "current", + "diagnosticIds": [] + }, + { + "id": "AR062", + "sourcePath": "work/coordination-change-risk-mitigation/spec.md", + "targetPath": "work/coordination-change-risk-mitigation/tasks.yml", + "sourceId": "FR-006", + "targetId": null, + "relationship": "requirementDisposition", + "state": "current", + "diagnosticIds": [] + }, + { + "id": "AR063", + "sourcePath": "work/coordination-change-risk-mitigation/spec.md", + "targetPath": "work/coordination-change-risk-mitigation/tasks.yml", + "sourceId": "FR-007", + "targetId": null, + "relationship": "requirementDisposition", + "state": "current", + "diagnosticIds": [] + }, + { + "id": "AR064", + "sourcePath": "work/coordination-change-risk-mitigation/spec.md", + "targetPath": "work/coordination-change-risk-mitigation/tasks.yml", + "sourceId": "FR-008", + "targetId": null, + "relationship": "requirementDisposition", + "state": "current", + "diagnosticIds": [] + }, + { + "id": "AR065", + "sourcePath": "work/coordination-change-risk-mitigation/spec.md", + "targetPath": "work/coordination-change-risk-mitigation/tasks.yml", + "sourceId": "FR-009", + "targetId": null, + "relationship": "requirementDisposition", + "state": "current", + "diagnosticIds": [] + }, + { + "id": "AR066", + "sourcePath": "work/coordination-change-risk-mitigation/spec.md", + "targetPath": "work/coordination-change-risk-mitigation/clarifications.md", + "sourceId": null, + "targetId": null, + "relationship": "sourceSpec", + "state": "current", + "diagnosticIds": [] + }, + { + "id": "AR067", + "sourcePath": "work/coordination-change-risk-mitigation/spec.md", + "targetPath": "work/coordination-change-risk-mitigation/tasks.yml", + "sourceId": null, + "targetId": null, + "relationship": "taskSourceSpec", + "state": "current", + "diagnosticIds": [] + }, + { + "id": "AR068", + "sourcePath": "work/coordination-change-risk-mitigation/tasks.yml", + "targetPath": "work/coordination-change-risk-mitigation/tasks.yml", + "sourceId": "T001", + "targetId": "T009", + "relationship": "taskDependency", + "state": "current", + "diagnosticIds": [] + }, + { + "id": "AR069", + "sourcePath": "work/coordination-change-risk-mitigation/tasks.yml", + "targetPath": "work/coordination-change-risk-mitigation/tasks.yml", + "sourceId": "T002", + "targetId": "T001", + "relationship": "taskDependency", + "state": "current", + "diagnosticIds": [] + }, + { + "id": "AR070", + "sourcePath": "work/coordination-change-risk-mitigation/tasks.yml", + "targetPath": "work/coordination-change-risk-mitigation/tasks.yml", + "sourceId": "T003", + "targetId": "T002", + "relationship": "taskDependency", + "state": "current", + "diagnosticIds": [] + }, + { + "id": "AR071", + "sourcePath": "work/coordination-change-risk-mitigation/tasks.yml", + "targetPath": "work/coordination-change-risk-mitigation/tasks.yml", + "sourceId": "T003", + "targetId": "T006", + "relationship": "taskDependency", + "state": "current", + "diagnosticIds": [] + }, + { + "id": "AR072", + "sourcePath": "work/coordination-change-risk-mitigation/tasks.yml", + "targetPath": "work/coordination-change-risk-mitigation/tasks.yml", + "sourceId": "T004", + "targetId": "T003", + "relationship": "taskDependency", + "state": "current", + "diagnosticIds": [] + }, + { + "id": "AR073", + "sourcePath": "work/coordination-change-risk-mitigation/tasks.yml", + "targetPath": "work/coordination-change-risk-mitigation/tasks.yml", + "sourceId": "T005", + "targetId": "T003", + "relationship": "taskDependency", + "state": "current", + "diagnosticIds": [] + }, + { + "id": "AR074", + "sourcePath": "work/coordination-change-risk-mitigation/tasks.yml", + "targetPath": "work/coordination-change-risk-mitigation/tasks.yml", + "sourceId": "T006", + "targetId": "T002", + "relationship": "taskDependency", + "state": "current", + "diagnosticIds": [] + }, + { + "id": "AR075", + "sourcePath": "work/coordination-change-risk-mitigation/tasks.yml", + "targetPath": "work/coordination-change-risk-mitigation/tasks.yml", + "sourceId": "T007", + "targetId": "T004", + "relationship": "taskDependency", + "state": "current", + "diagnosticIds": [] + }, + { + "id": "AR076", + "sourcePath": "work/coordination-change-risk-mitigation/tasks.yml", + "targetPath": "work/coordination-change-risk-mitigation/tasks.yml", + "sourceId": "T007", + "targetId": "T005", + "relationship": "taskDependency", + "state": "current", + "diagnosticIds": [] + }, + { + "id": "AR077", + "sourcePath": "work/coordination-change-risk-mitigation/tasks.yml", + "targetPath": "work/coordination-change-risk-mitigation/tasks.yml", + "sourceId": "T007", + "targetId": "T006", + "relationship": "taskDependency", + "state": "current", + "diagnosticIds": [] + }, + { + "id": "AR078", + "sourcePath": "work/coordination-change-risk-mitigation/tasks.yml", + "targetPath": "work/coordination-change-risk-mitigation/tasks.yml", + "sourceId": "T008", + "targetId": "T007", + "relationship": "taskDependency", + "state": "current", + "diagnosticIds": [] + }, + { + "id": "AR079", + "sourcePath": "work/coordination-change-risk-mitigation/tasks.yml", + "targetPath": "work/coordination-change-risk-mitigation/tasks.yml", + "sourceId": "T010", + "targetId": "T001", + "relationship": "taskDependency", + "state": "current", + "diagnosticIds": [] + }, + { + "id": "AR080", + "sourcePath": "work/coordination-change-risk-mitigation/tasks.yml", + "targetPath": "work/coordination-change-risk-mitigation/tasks.yml", + "sourceId": "T011", + "targetId": "T002", + "relationship": "taskDependency", + "state": "current", + "diagnosticIds": [] + }, + { + "id": "AR081", + "sourcePath": "work/coordination-change-risk-mitigation/tasks.yml", + "targetPath": "work/coordination-change-risk-mitigation/tasks.yml", + "sourceId": "T012", + "targetId": "T005", + "relationship": "taskDependency", + "state": "current", + "diagnosticIds": [] + }, + { + "id": "AR082", + "sourcePath": "work/coordination-change-risk-mitigation/tasks.yml", + "targetPath": "work/coordination-change-risk-mitigation/tasks.yml", + "sourceId": "T013", + "targetId": "T007", + "relationship": "taskDependency", + "state": "current", + "diagnosticIds": [] + }, + { + "id": "AR083", + "sourcePath": "work/coordination-change-risk-mitigation/tasks.yml", + "targetPath": "work/coordination-change-risk-mitigation/tasks.yml", + "sourceId": "T014", + "targetId": "T008", + "relationship": "taskDependency", + "state": "current", + "diagnosticIds": [] + }, + { + "id": "AR084", + "sourcePath": "work/coordination-change-risk-mitigation/tasks.yml", + "targetPath": "work/coordination-change-risk-mitigation/tasks.yml", + "sourceId": "T015", + "targetId": "T001", + "relationship": "taskDependency", + "state": "current", + "diagnosticIds": [] + }, + { + "id": "AR085", + "sourcePath": "work/coordination-change-risk-mitigation/tasks.yml", + "targetPath": "work/coordination-change-risk-mitigation/tasks.yml", + "sourceId": "T016", + "targetId": "T002", + "relationship": "taskDependency", + "state": "current", + "diagnosticIds": [] + }, + { + "id": "AR086", + "sourcePath": "work/coordination-change-risk-mitigation/tasks.yml", + "targetPath": "work/coordination-change-risk-mitigation/tasks.yml", + "sourceId": "T017", + "targetId": "T003", + "relationship": "taskDependency", + "state": "current", + "diagnosticIds": [] + }, + { + "id": "AR087", + "sourcePath": "work/coordination-change-risk-mitigation/tasks.yml", + "targetPath": "work/coordination-change-risk-mitigation/tasks.yml", + "sourceId": "T018", + "targetId": "T004", + "relationship": "taskDependency", + "state": "current", + "diagnosticIds": [] + }, + { + "id": "AR088", + "sourcePath": "work/coordination-change-risk-mitigation/tasks.yml", + "targetPath": "work/coordination-change-risk-mitigation/tasks.yml", + "sourceId": "T019", + "targetId": "T005", + "relationship": "taskDependency", + "state": "current", + "diagnosticIds": [] + }, + { + "id": "AR089", + "sourcePath": "work/coordination-change-risk-mitigation/tasks.yml", + "targetPath": "work/coordination-change-risk-mitigation/tasks.yml", + "sourceId": "T020", + "targetId": "T006", + "relationship": "taskDependency", + "state": "current", + "diagnosticIds": [] + }, + { + "id": "AR090", + "sourcePath": "work/coordination-change-risk-mitigation/tasks.yml", + "targetPath": "work/coordination-change-risk-mitigation/tasks.yml", + "sourceId": "T021", + "targetId": "T007", + "relationship": "taskDependency", + "state": "current", + "diagnosticIds": [] + }, + { + "id": "AR091", + "sourcePath": "work/coordination-change-risk-mitigation/tasks.yml", + "targetPath": "work/coordination-change-risk-mitigation/tasks.yml", + "sourceId": "T022", + "targetId": "T009", + "relationship": "taskDependency", + "state": "current", + "diagnosticIds": [] + }, + { + "id": "AR092", + "sourcePath": "work/coordination-change-risk-mitigation/tasks.yml", + "targetPath": "work/coordination-change-risk-mitigation/tasks.yml", + "sourceId": "T023", + "targetId": "T015", + "relationship": "taskDependency", + "state": "current", + "diagnosticIds": [] + }, + { + "id": "AR093", + "sourcePath": "work/coordination-change-risk-mitigation/tasks.yml", + "targetPath": "work/coordination-change-risk-mitigation/tasks.yml", + "sourceId": "T024", + "targetId": "T015", + "relationship": "taskDependency", + "state": "current", + "diagnosticIds": [] + }, + { + "id": "AR094", + "sourcePath": "work/coordination-change-risk-mitigation/tasks.yml", + "targetPath": "work/coordination-change-risk-mitigation/tasks.yml", + "sourceId": "T025", + "targetId": "T016", + "relationship": "taskDependency", + "state": "current", + "diagnosticIds": [] + }, + { + "id": "AR095", + "sourcePath": "work/coordination-change-risk-mitigation/tasks.yml", + "targetPath": "work/coordination-change-risk-mitigation/tasks.yml", + "sourceId": "T025", + "targetId": "T020", + "relationship": "taskDependency", + "state": "current", + "diagnosticIds": [] + }, + { + "id": "AR096", + "sourcePath": "work/coordination-change-risk-mitigation/tasks.yml", + "targetPath": "work/coordination-change-risk-mitigation/tasks.yml", + "sourceId": "T026", + "targetId": "T017", + "relationship": "taskDependency", + "state": "current", + "diagnosticIds": [] + }, + { + "id": "AR097", + "sourcePath": "work/coordination-change-risk-mitigation/tasks.yml", + "targetPath": "work/coordination-change-risk-mitigation/tasks.yml", + "sourceId": "T027", + "targetId": "T018", + "relationship": "taskDependency", + "state": "current", + "diagnosticIds": [] + }, + { + "id": "AR098", + "sourcePath": "work/coordination-change-risk-mitigation/tasks.yml", + "targetPath": "work/coordination-change-risk-mitigation/tasks.yml", + "sourceId": "T028", + "targetId": "T019", + "relationship": "taskDependency", + "state": "current", + "diagnosticIds": [] + }, + { + "id": "AR099", + "sourcePath": "work/coordination-change-risk-mitigation/tasks.yml", + "targetPath": "work/coordination-change-risk-mitigation/tasks.yml", + "sourceId": "T029", + "targetId": "T020", + "relationship": "taskDependency", + "state": "current", + "diagnosticIds": [] + }, + { + "id": "AR100", + "sourcePath": "work/coordination-change-risk-mitigation/tasks.yml", + "targetPath": "work/coordination-change-risk-mitigation/tasks.yml", + "sourceId": "T030", + "targetId": "T021", + "relationship": "taskDependency", + "state": "current", + "diagnosticIds": [] + }, + { + "id": "AR101", + "sourcePath": "work/coordination-change-risk-mitigation/tasks.yml", + "targetPath": "work/coordination-change-risk-mitigation/tasks.yml", + "sourceId": "T031", + "targetId": "T008", + "relationship": "taskDependency", + "state": "current", + "diagnosticIds": [] + }, + { + "id": "AR102", + "sourcePath": "work/coordination-change-risk-mitigation/tasks.yml", + "targetPath": "work/coordination-change-risk-mitigation/tasks.yml", + "sourceId": "T031", + "targetId": "T022", + "relationship": "taskDependency", + "state": "current", + "diagnosticIds": [] + }, + { + "id": "AR103", + "sourcePath": "work/coordination-change-risk-mitigation/tasks.yml", + "targetPath": "work/coordination-change-risk-mitigation/tasks.yml", + "sourceId": "T031", + "targetId": "T023", + "relationship": "taskDependency", + "state": "current", + "diagnosticIds": [] + }, + { + "id": "AR104", + "sourcePath": "work/coordination-change-risk-mitigation/tasks.yml", + "targetPath": "work/coordination-change-risk-mitigation/tasks.yml", + "sourceId": "T031", + "targetId": "T024", + "relationship": "taskDependency", + "state": "current", + "diagnosticIds": [] + }, + { + "id": "AR105", + "sourcePath": "work/coordination-change-risk-mitigation/tasks.yml", + "targetPath": "work/coordination-change-risk-mitigation/tasks.yml", + "sourceId": "T031", + "targetId": "T025", + "relationship": "taskDependency", + "state": "current", + "diagnosticIds": [] + }, + { + "id": "AR106", + "sourcePath": "work/coordination-change-risk-mitigation/tasks.yml", + "targetPath": "work/coordination-change-risk-mitigation/tasks.yml", + "sourceId": "T031", + "targetId": "T026", + "relationship": "taskDependency", + "state": "current", + "diagnosticIds": [] + }, + { + "id": "AR107", + "sourcePath": "work/coordination-change-risk-mitigation/tasks.yml", + "targetPath": "work/coordination-change-risk-mitigation/tasks.yml", + "sourceId": "T031", + "targetId": "T027", + "relationship": "taskDependency", + "state": "current", + "diagnosticIds": [] + }, + { + "id": "AR108", + "sourcePath": "work/coordination-change-risk-mitigation/tasks.yml", + "targetPath": "work/coordination-change-risk-mitigation/tasks.yml", + "sourceId": "T031", + "targetId": "T028", + "relationship": "taskDependency", + "state": "current", + "diagnosticIds": [] + }, + { + "id": "AR109", + "sourcePath": "work/coordination-change-risk-mitigation/tasks.yml", + "targetPath": "work/coordination-change-risk-mitigation/tasks.yml", + "sourceId": "T031", + "targetId": "T029", + "relationship": "taskDependency", + "state": "current", + "diagnosticIds": [] + }, + { + "id": "AR110", + "sourcePath": "work/coordination-change-risk-mitigation/tasks.yml", + "targetPath": "work/coordination-change-risk-mitigation/tasks.yml", + "sourceId": "T031", + "targetId": "T030", + "relationship": "taskDependency", + "state": "current", + "diagnosticIds": [] + }, + { + "id": "AR111", + "sourcePath": "work/coordination-change-risk-mitigation/tasks.yml", + "targetPath": "work/coordination-change-risk-mitigation/tasks.yml", + "sourceId": "T032", + "targetId": "T015", + "relationship": "taskDependency", + "state": "current", + "diagnosticIds": [] + }, + { + "id": "AR112", + "sourcePath": "work/coordination-change-risk-mitigation/tasks.yml", + "targetPath": "work/coordination-change-risk-mitigation/tasks.yml", + "sourceId": "T033", + "targetId": "T016", + "relationship": "taskDependency", + "state": "current", + "diagnosticIds": [] + }, + { + "id": "AR113", + "sourcePath": "work/coordination-change-risk-mitigation/tasks.yml", + "targetPath": "work/coordination-change-risk-mitigation/tasks.yml", + "sourceId": "T034", + "targetId": "T017", + "relationship": "taskDependency", + "state": "current", + "diagnosticIds": [] + }, + { + "id": "AR114", + "sourcePath": "work/coordination-change-risk-mitigation/tasks.yml", + "targetPath": "work/coordination-change-risk-mitigation/tasks.yml", + "sourceId": "T035", + "targetId": "T019", + "relationship": "taskDependency", + "state": "current", + "diagnosticIds": [] + }, + { + "id": "AR115", + "sourcePath": "work/coordination-change-risk-mitigation/tasks.yml", + "targetPath": "work/coordination-change-risk-mitigation/tasks.yml", + "sourceId": "T036", + "targetId": "T021", + "relationship": "taskDependency", + "state": "current", + "diagnosticIds": [] + }, + { + "id": "AR116", + "sourcePath": "work/coordination-change-risk-mitigation/tasks.yml", + "targetPath": "work/coordination-change-risk-mitigation/tasks.yml", + "sourceId": "T037", + "targetId": "T031", + "relationship": "taskDependency", + "state": "current", + "diagnosticIds": [] + }, + { + "id": "AR117", + "sourcePath": "work/coordination-change-risk-mitigation/tasks.yml", + "targetPath": "work/coordination-change-risk-mitigation/tasks.yml", + "sourceId": "T038", + "targetId": "T015", + "relationship": "taskDependency", + "state": "current", + "diagnosticIds": [] + }, + { + "id": "AR118", + "sourcePath": "work/coordination-change-risk-mitigation/tasks.yml", + "targetPath": "work/coordination-change-risk-mitigation/tasks.yml", + "sourceId": "T039", + "targetId": "T017", + "relationship": "taskDependency", + "state": "current", + "diagnosticIds": [] + } + ], + "readiness": { + "status": "implementationReady", + "readyCount": 118, + "advisoryCount": 0, + "warningCount": 0, + "blockingCount": 0, + "staleSourceCount": 0, + "missingDispositionCount": 0, + "malformedSourceCount": 0, + "generatedViewFindingCount": 0, + "acceptedDeferralCount": 0 + }, + "findings": [], + "generatedViews": [ + { + "path": "readiness/coordination-change-risk-mitigation/work-model.json", + "kind": "workModel", + "currency": "current", + "diagnosticIds": [] + } + ], + "optionalBoundaryFacts": [ + { + "path": ".fsgg/policy.yml", + "relationship": "optionalGovernancePolicy", + "requiredBySdd": false, + "state": "notEvaluated", + "diagnosticIds": [] + }, + { + "path": ".fsgg/capabilities.yml", + "relationship": "optionalGovernanceCapabilities", + "requiredBySdd": false, + "state": "notEvaluated", + "diagnosticIds": [] + }, + { + "path": ".fsgg/tooling.yml", + "relationship": "optionalGovernanceTooling", + "requiredBySdd": false, + "state": "notEvaluated", + "diagnosticIds": [] + } + ], + "diagnostics": [], + "nextAction": { + "actionId": "analysis.next.implement", + "command": null, + "reason": "Lifecycle sources are current and ready for implementation." + } +} \ No newline at end of file diff --git a/readiness/coordination-change-risk-mitigation/governance-handoff.json b/readiness/coordination-change-risk-mitigation/governance-handoff.json new file mode 100644 index 000000000..82eb83eda --- /dev/null +++ b/readiness/coordination-change-risk-mitigation/governance-handoff.json @@ -0,0 +1,969 @@ +{ + "schemaVersion": 1, + "contractVersion": "2.0.0", + "generatorVersion": "FS.GG.SDD.Artifacts/1.1.0", + "workId": "coordination-change-risk-mitigation", + "sources": [ + { + "path": "readiness/coordination-change-risk-mitigation/ship.json", + "digest": "sha256:ef57bc17656734d353105dc68a57f6fc497a91ece8064f9937b1697b0c23ac63", + "schemaVersion": 1 + }, + { + "path": "readiness/coordination-change-risk-mitigation/verify.json", + "digest": "sha256:9ca2c9c9c99cac74059830225637843350237ad87a8b4d30e8c5806287f282bb", + "schemaVersion": 1 + }, + { + "path": "readiness/coordination-change-risk-mitigation/work-model.json", + "digest": "sha256:2b4fcd016b7de64a639bccfacefd4fdafc4c185879c1c04421c72466c187aba8", + "schemaVersion": 1 + } + ], + "evidence": { + "nodes": [ + { + "id": "evidence:EV001", + "state": "real", + "rationale": null + }, + { + "id": "evidence:EV002", + "state": "real", + "rationale": null + }, + { + "id": "evidence:EV003", + "state": "real", + "rationale": null + }, + { + "id": "evidence:EV004", + "state": "real", + "rationale": null + }, + { + "id": "evidence:EV005", + "state": "real", + "rationale": null + }, + { + "id": "evidence:EV006", + "state": "real", + "rationale": null + }, + { + "id": "evidence:EV007", + "state": "real", + "rationale": null + }, + { + "id": "evidence:EV008", + "state": "real", + "rationale": null + }, + { + "id": "evidence:EV009", + "state": "real", + "rationale": null + }, + { + "id": "evidence:EV010", + "state": "real", + "rationale": null + }, + { + "id": "evidence:EV011", + "state": "real", + "rationale": null + }, + { + "id": "evidence:EV012", + "state": "real", + "rationale": null + }, + { + "id": "evidence:EV013", + "state": "real", + "rationale": null + }, + { + "id": "evidence:EV014", + "state": "real", + "rationale": null + }, + { + "id": "evidence:EV015", + "state": "real", + "rationale": null + }, + { + "id": "evidence:EV016", + "state": "real", + "rationale": null + }, + { + "id": "evidence:EV017", + "state": "real", + "rationale": null + }, + { + "id": "evidence:EV018", + "state": "real", + "rationale": null + }, + { + "id": "evidence:EV019", + "state": "real", + "rationale": null + }, + { + "id": "evidence:EV020", + "state": "real", + "rationale": null + }, + { + "id": "evidence:EV021", + "state": "real", + "rationale": null + }, + { + "id": "evidence:EV022", + "state": "real", + "rationale": null + }, + { + "id": "evidence:EV023", + "state": "real", + "rationale": null + }, + { + "id": "evidence:EV024", + "state": "real", + "rationale": null + }, + { + "id": "evidence:EV025", + "state": "real", + "rationale": null + }, + { + "id": "evidence:EV026", + "state": "real", + "rationale": null + }, + { + "id": "evidence:EV027", + "state": "real", + "rationale": null + }, + { + "id": "evidence:EV028", + "state": "real", + "rationale": null + }, + { + "id": "evidence:EV029", + "state": "real", + "rationale": null + }, + { + "id": "evidence:EV030", + "state": "real", + "rationale": null + }, + { + "id": "evidence:EV031", + "state": "real", + "rationale": null + }, + { + "id": "evidence:EV032", + "state": "real", + "rationale": null + }, + { + "id": "evidence:EV033", + "state": "real", + "rationale": null + }, + { + "id": "evidence:EV034", + "state": "real", + "rationale": null + }, + { + "id": "evidence:EV035", + "state": "real", + "rationale": null + }, + { + "id": "evidence:EV036", + "state": "real", + "rationale": null + }, + { + "id": "evidence:EV037", + "state": "real", + "rationale": null + }, + { + "id": "evidence:EV038", + "state": "real", + "rationale": null + }, + { + "id": "evidence:EV039", + "state": "real", + "rationale": null + }, + { + "id": "task:T001", + "state": "real", + "rationale": null + }, + { + "id": "task:T002", + "state": "real", + "rationale": null + }, + { + "id": "task:T003", + "state": "real", + "rationale": null + }, + { + "id": "task:T004", + "state": "real", + "rationale": null + }, + { + "id": "task:T005", + "state": "real", + "rationale": null + }, + { + "id": "task:T006", + "state": "real", + "rationale": null + }, + { + "id": "task:T007", + "state": "real", + "rationale": null + }, + { + "id": "task:T008", + "state": "real", + "rationale": null + }, + { + "id": "task:T009", + "state": "real", + "rationale": null + }, + { + "id": "task:T010", + "state": "real", + "rationale": null + }, + { + "id": "task:T011", + "state": "real", + "rationale": null + }, + { + "id": "task:T012", + "state": "real", + "rationale": null + }, + { + "id": "task:T013", + "state": "real", + "rationale": null + }, + { + "id": "task:T014", + "state": "real", + "rationale": null + }, + { + "id": "task:T015", + "state": "real", + "rationale": null + }, + { + "id": "task:T016", + "state": "real", + "rationale": null + }, + { + "id": "task:T017", + "state": "real", + "rationale": null + }, + { + "id": "task:T018", + "state": "real", + "rationale": null + }, + { + "id": "task:T019", + "state": "real", + "rationale": null + }, + { + "id": "task:T020", + "state": "real", + "rationale": null + }, + { + "id": "task:T021", + "state": "real", + "rationale": null + }, + { + "id": "task:T022", + "state": "real", + "rationale": null + }, + { + "id": "task:T023", + "state": "real", + "rationale": null + }, + { + "id": "task:T024", + "state": "real", + "rationale": null + }, + { + "id": "task:T025", + "state": "real", + "rationale": null + }, + { + "id": "task:T026", + "state": "real", + "rationale": null + }, + { + "id": "task:T027", + "state": "real", + "rationale": null + }, + { + "id": "task:T028", + "state": "real", + "rationale": null + }, + { + "id": "task:T029", + "state": "real", + "rationale": null + }, + { + "id": "task:T030", + "state": "real", + "rationale": null + }, + { + "id": "task:T031", + "state": "real", + "rationale": null + }, + { + "id": "task:T032", + "state": "real", + "rationale": null + }, + { + "id": "task:T033", + "state": "real", + "rationale": null + }, + { + "id": "task:T034", + "state": "real", + "rationale": null + }, + { + "id": "task:T035", + "state": "real", + "rationale": null + }, + { + "id": "task:T036", + "state": "real", + "rationale": null + }, + { + "id": "task:T037", + "state": "real", + "rationale": null + }, + { + "id": "task:T038", + "state": "real", + "rationale": null + }, + { + "id": "task:T039", + "state": "real", + "rationale": null + } + ], + "dependencies": [ + { + "dependent": "evidence:EV001", + "dependency": "task:T001" + }, + { + "dependent": "evidence:EV002", + "dependency": "task:T002" + }, + { + "dependent": "evidence:EV003", + "dependency": "task:T003" + }, + { + "dependent": "evidence:EV004", + "dependency": "task:T004" + }, + { + "dependent": "evidence:EV005", + "dependency": "task:T005" + }, + { + "dependent": "evidence:EV006", + "dependency": "task:T006" + }, + { + "dependent": "evidence:EV007", + "dependency": "task:T007" + }, + { + "dependent": "evidence:EV008", + "dependency": "task:T008" + }, + { + "dependent": "evidence:EV009", + "dependency": "task:T009" + }, + { + "dependent": "evidence:EV010", + "dependency": "task:T010" + }, + { + "dependent": "evidence:EV011", + "dependency": "task:T011" + }, + { + "dependent": "evidence:EV012", + "dependency": "task:T012" + }, + { + "dependent": "evidence:EV013", + "dependency": "task:T013" + }, + { + "dependent": "evidence:EV014", + "dependency": "task:T014" + }, + { + "dependent": "evidence:EV015", + "dependency": "task:T015" + }, + { + "dependent": "evidence:EV016", + "dependency": "task:T016" + }, + { + "dependent": "evidence:EV017", + "dependency": "task:T017" + }, + { + "dependent": "evidence:EV018", + "dependency": "task:T018" + }, + { + "dependent": "evidence:EV019", + "dependency": "task:T019" + }, + { + "dependent": "evidence:EV020", + "dependency": "task:T020" + }, + { + "dependent": "evidence:EV021", + "dependency": "task:T021" + }, + { + "dependent": "evidence:EV022", + "dependency": "task:T022" + }, + { + "dependent": "evidence:EV023", + "dependency": "task:T023" + }, + { + "dependent": "evidence:EV024", + "dependency": "task:T024" + }, + { + "dependent": "evidence:EV025", + "dependency": "task:T025" + }, + { + "dependent": "evidence:EV026", + "dependency": "task:T026" + }, + { + "dependent": "evidence:EV027", + "dependency": "task:T027" + }, + { + "dependent": "evidence:EV028", + "dependency": "task:T028" + }, + { + "dependent": "evidence:EV029", + "dependency": "task:T029" + }, + { + "dependent": "evidence:EV030", + "dependency": "task:T030" + }, + { + "dependent": "evidence:EV031", + "dependency": "task:T031" + }, + { + "dependent": "evidence:EV032", + "dependency": "task:T032" + }, + { + "dependent": "evidence:EV033", + "dependency": "task:T033" + }, + { + "dependent": "evidence:EV034", + "dependency": "task:T034" + }, + { + "dependent": "evidence:EV035", + "dependency": "task:T035" + }, + { + "dependent": "evidence:EV036", + "dependency": "task:T036" + }, + { + "dependent": "evidence:EV037", + "dependency": "task:T037" + }, + { + "dependent": "evidence:EV038", + "dependency": "task:T038" + }, + { + "dependent": "evidence:EV039", + "dependency": "task:T039" + }, + { + "dependent": "task:T001", + "dependency": "evidence:EV001" + }, + { + "dependent": "task:T001", + "dependency": "task:T009" + }, + { + "dependent": "task:T002", + "dependency": "evidence:EV002" + }, + { + "dependent": "task:T002", + "dependency": "task:T001" + }, + { + "dependent": "task:T003", + "dependency": "evidence:EV003" + }, + { + "dependent": "task:T003", + "dependency": "task:T002" + }, + { + "dependent": "task:T003", + "dependency": "task:T006" + }, + { + "dependent": "task:T004", + "dependency": "evidence:EV004" + }, + { + "dependent": "task:T004", + "dependency": "task:T003" + }, + { + "dependent": "task:T005", + "dependency": "evidence:EV005" + }, + { + "dependent": "task:T005", + "dependency": "task:T003" + }, + { + "dependent": "task:T006", + "dependency": "evidence:EV006" + }, + { + "dependent": "task:T006", + "dependency": "task:T002" + }, + { + "dependent": "task:T007", + "dependency": "evidence:EV007" + }, + { + "dependent": "task:T007", + "dependency": "task:T004" + }, + { + "dependent": "task:T007", + "dependency": "task:T005" + }, + { + "dependent": "task:T007", + "dependency": "task:T006" + }, + { + "dependent": "task:T008", + "dependency": "evidence:EV008" + }, + { + "dependent": "task:T008", + "dependency": "task:T007" + }, + { + "dependent": "task:T009", + "dependency": "evidence:EV009" + }, + { + "dependent": "task:T010", + "dependency": "evidence:EV010" + }, + { + "dependent": "task:T010", + "dependency": "task:T001" + }, + { + "dependent": "task:T011", + "dependency": "evidence:EV011" + }, + { + "dependent": "task:T011", + "dependency": "task:T002" + }, + { + "dependent": "task:T012", + "dependency": "evidence:EV012" + }, + { + "dependent": "task:T012", + "dependency": "task:T005" + }, + { + "dependent": "task:T013", + "dependency": "evidence:EV013" + }, + { + "dependent": "task:T013", + "dependency": "task:T007" + }, + { + "dependent": "task:T014", + "dependency": "evidence:EV014" + }, + { + "dependent": "task:T014", + "dependency": "task:T008" + }, + { + "dependent": "task:T015", + "dependency": "evidence:EV015" + }, + { + "dependent": "task:T015", + "dependency": "task:T001" + }, + { + "dependent": "task:T016", + "dependency": "evidence:EV016" + }, + { + "dependent": "task:T016", + "dependency": "task:T002" + }, + { + "dependent": "task:T017", + "dependency": "evidence:EV017" + }, + { + "dependent": "task:T017", + "dependency": "task:T003" + }, + { + "dependent": "task:T018", + "dependency": "evidence:EV018" + }, + { + "dependent": "task:T018", + "dependency": "task:T004" + }, + { + "dependent": "task:T019", + "dependency": "evidence:EV019" + }, + { + "dependent": "task:T019", + "dependency": "task:T005" + }, + { + "dependent": "task:T020", + "dependency": "evidence:EV020" + }, + { + "dependent": "task:T020", + "dependency": "task:T006" + }, + { + "dependent": "task:T021", + "dependency": "evidence:EV021" + }, + { + "dependent": "task:T021", + "dependency": "task:T007" + }, + { + "dependent": "task:T022", + "dependency": "evidence:EV022" + }, + { + "dependent": "task:T022", + "dependency": "task:T009" + }, + { + "dependent": "task:T023", + "dependency": "evidence:EV023" + }, + { + "dependent": "task:T023", + "dependency": "task:T015" + }, + { + "dependent": "task:T024", + "dependency": "evidence:EV024" + }, + { + "dependent": "task:T024", + "dependency": "task:T015" + }, + { + "dependent": "task:T025", + "dependency": "evidence:EV025" + }, + { + "dependent": "task:T025", + "dependency": "task:T016" + }, + { + "dependent": "task:T025", + "dependency": "task:T020" + }, + { + "dependent": "task:T026", + "dependency": "evidence:EV026" + }, + { + "dependent": "task:T026", + "dependency": "task:T017" + }, + { + "dependent": "task:T027", + "dependency": "evidence:EV027" + }, + { + "dependent": "task:T027", + "dependency": "task:T018" + }, + { + "dependent": "task:T028", + "dependency": "evidence:EV028" + }, + { + "dependent": "task:T028", + "dependency": "task:T019" + }, + { + "dependent": "task:T029", + "dependency": "evidence:EV029" + }, + { + "dependent": "task:T029", + "dependency": "task:T020" + }, + { + "dependent": "task:T030", + "dependency": "evidence:EV030" + }, + { + "dependent": "task:T030", + "dependency": "task:T021" + }, + { + "dependent": "task:T031", + "dependency": "evidence:EV031" + }, + { + "dependent": "task:T031", + "dependency": "task:T008" + }, + { + "dependent": "task:T031", + "dependency": "task:T022" + }, + { + "dependent": "task:T031", + "dependency": "task:T023" + }, + { + "dependent": "task:T031", + "dependency": "task:T024" + }, + { + "dependent": "task:T031", + "dependency": "task:T025" + }, + { + "dependent": "task:T031", + "dependency": "task:T026" + }, + { + "dependent": "task:T031", + "dependency": "task:T027" + }, + { + "dependent": "task:T031", + "dependency": "task:T028" + }, + { + "dependent": "task:T031", + "dependency": "task:T029" + }, + { + "dependent": "task:T031", + "dependency": "task:T030" + }, + { + "dependent": "task:T032", + "dependency": "evidence:EV032" + }, + { + "dependent": "task:T032", + "dependency": "task:T015" + }, + { + "dependent": "task:T033", + "dependency": "evidence:EV033" + }, + { + "dependent": "task:T033", + "dependency": "task:T016" + }, + { + "dependent": "task:T034", + "dependency": "evidence:EV034" + }, + { + "dependent": "task:T034", + "dependency": "task:T017" + }, + { + "dependent": "task:T035", + "dependency": "evidence:EV035" + }, + { + "dependent": "task:T035", + "dependency": "task:T019" + }, + { + "dependent": "task:T036", + "dependency": "evidence:EV036" + }, + { + "dependent": "task:T036", + "dependency": "task:T021" + }, + { + "dependent": "task:T037", + "dependency": "evidence:EV037" + }, + { + "dependent": "task:T037", + "dependency": "task:T031" + }, + { + "dependent": "task:T038", + "dependency": "evidence:EV038" + }, + { + "dependent": "task:T038", + "dependency": "task:T015" + }, + { + "dependent": "task:T039", + "dependency": "evidence:EV039" + }, + { + "dependent": "task:T039", + "dependency": "task:T017" + } + ] + }, + "performanceEvidence": [], + "governedReferences": [], + "governanceConfig": { + "policyPresent": false, + "capabilitiesPresent": false, + "toolingPresent": false + }, + "readiness": { + "shipDisposition": "shipReady", + "verificationReadiness": "verificationReady", + "counts": { + "advisory": 0, + "warning": 0, + "blocking": 0, + "classifiedObligationsUnmet": 0, + "journeyObligationsUnmet": 0 + }, + "blockingDiagnosticIds": [], + "perViewState": [ + { + "view": "ship.json", + "state": "current" + }, + { + "view": "verify.json", + "state": "current" + }, + { + "view": "work-model.json", + "state": "current" + } + ] + }, + "diagnostics": [] +} \ No newline at end of file diff --git a/readiness/coordination-change-risk-mitigation/ship-verdict.json b/readiness/coordination-change-risk-mitigation/ship-verdict.json new file mode 100644 index 000000000..1ec2c2411 --- /dev/null +++ b/readiness/coordination-change-risk-mitigation/ship-verdict.json @@ -0,0 +1,19 @@ +{ + "schemaVersion": 1, + "viewVersion": "1.0", + "workId": "coordination-change-risk-mitigation", + "stage": "ship", + "status": "shipReady", + "generator": "FS.GG.SDD.Artifacts/1.1.0", + "verificationReadiness": { + "status": "verificationReady", + "evidenceSupportedCount": 39, + "evidenceSelfAttestedCount": 0, + "evidenceObservedCount": 39 + }, + "disposition": { + "state": "shipReady", + "blockingFindingIds": [] + }, + "readiness": "shipReady" +} \ No newline at end of file diff --git a/readiness/coordination-change-risk-mitigation/ship.json b/readiness/coordination-change-risk-mitigation/ship.json new file mode 100644 index 000000000..bc85e231b --- /dev/null +++ b/readiness/coordination-change-risk-mitigation/ship.json @@ -0,0 +1,554 @@ +{ + "schemaVersion": 1, + "viewVersion": "1.0", + "workId": "coordination-change-risk-mitigation", + "stage": "ship", + "status": "shipReady", + "generator": "FS.GG.SDD.Artifacts/1.1.0", + "sources": [ + { + "path": ".fsgg/agents.yml", + "kind": "agentsConfig", + "digest": { + "algorithm": "sha256", + "value": "c67035b1cf31b6fa802c10f761eeb1e5bf5d198c38d159b54fac299957b5aac3" + }, + "schemaVersion": 1, + "schemaStatus": "current" + }, + { + "path": ".fsgg/project.yml", + "kind": "projectConfig", + "digest": { + "algorithm": "sha256", + "value": "ef78f002b33ce22f738bac2c0dbf716db729a7d3ae3e4a68a4ce4b93810ced66" + }, + "schemaVersion": 1, + "schemaStatus": "current" + }, + { + "path": ".fsgg/sdd.yml", + "kind": "sddConfig", + "digest": { + "algorithm": "sha256", + "value": "fe5a7c270a975153e80ab0d08a610c9b302585dcb0b5f7c654841ceced9272cb" + }, + "schemaVersion": 1, + "schemaStatus": "current" + }, + { + "path": "readiness/coordination-change-risk-mitigation/analysis.json", + "kind": "analysis", + "digest": { + "algorithm": "sha256", + "value": "37c0545383a55866f5f83b5da4f0f5301fcbe4e046b0591811ad5a9651443dfa" + }, + "schemaVersion": 1, + "schemaStatus": "current" + }, + { + "path": "readiness/coordination-change-risk-mitigation/verify.json", + "kind": "source", + "digest": { + "algorithm": "sha256", + "value": "9ca2c9c9c99cac74059830225637843350237ad87a8b4d30e8c5806287f282bb" + }, + "schemaVersion": 1, + "schemaStatus": "current" + }, + { + "path": "readiness/coordination-change-risk-mitigation/work-model.json", + "kind": "workModel", + "digest": { + "algorithm": "sha256", + "value": "2b4fcd016b7de64a639bccfacefd4fdafc4c185879c1c04421c72466c187aba8" + }, + "schemaVersion": 1, + "schemaStatus": "current" + }, + { + "path": "work/coordination-change-risk-mitigation/checklist.md", + "kind": "checklist", + "digest": { + "algorithm": "sha256", + "value": "ac1c0ac8b8feafbedd9582ac17b8196e57b46867459a31c380cbb83e0a342548" + }, + "schemaVersion": 1, + "schemaStatus": "current" + }, + { + "path": "work/coordination-change-risk-mitigation/clarifications.md", + "kind": "clarification", + "digest": { + "algorithm": "sha256", + "value": "02eedf550b282d9788487b3efbd6f0034d35e5982b70dcf8abf01bd6fa61b18c" + }, + "schemaVersion": 1, + "schemaStatus": "current" + }, + { + "path": "work/coordination-change-risk-mitigation/evidence.yml", + "kind": "evidence", + "digest": { + "algorithm": "sha256", + "value": "50a00b29f2bc0ae0fd5d1940799b702d3c9e63dc5e05b0ad26b2a8de83c9c928" + }, + "schemaVersion": 1, + "schemaStatus": "current" + }, + { + "path": "work/coordination-change-risk-mitigation/plan.md", + "kind": "plan", + "digest": { + "algorithm": "sha256", + "value": "6ac822bae2e476fadcadf67890e437775bafd311f11baf6574cc70c48e1dcab6" + }, + "schemaVersion": 1, + "schemaStatus": "current" + }, + { + "path": "work/coordination-change-risk-mitigation/spec.md", + "kind": "specification", + "digest": { + "algorithm": "sha256", + "value": "596003775028144db71fd9a411385e205ed07488ee164d79471c153bb0ec084e" + }, + "schemaVersion": 1, + "schemaStatus": "current" + }, + { + "path": "work/coordination-change-risk-mitigation/tasks.yml", + "kind": "tasks", + "digest": { + "algorithm": "sha256", + "value": "d18dc3eacc78599e0cdcf030e8a8d74c324bb10d35788702e44e3781c5b6083c" + }, + "schemaVersion": 1, + "schemaStatus": "current" + } + ], + "lifecycleReadiness": { + "status": "shipReady", + "stages": [ + { + "stage": "analyze", + "status": "ready" + }, + { + "stage": "checklist", + "status": "ready" + }, + { + "stage": "clarify", + "status": "ready" + }, + { + "stage": "evidence", + "status": "ready" + }, + { + "stage": "plan", + "status": "ready" + }, + { + "stage": "specify", + "status": "ready" + }, + { + "stage": "tasks", + "status": "ready" + }, + { + "stage": "verify", + "status": "ready" + } + ] + }, + "verificationReadiness": { + "status": "verificationReady", + "blockingFindingIds": [], + "evidenceSupportedCount": 39, + "evidenceSelfAttestedCount": 0, + "evidenceObservedCount": 39, + "evidenceDeferredCount": 0, + "evidenceMissingCount": 0, + "evidenceStaleCount": 0, + "evidenceSyntheticCount": 0, + "evidenceInvalidCount": 0 + }, + "evidenceDispositions": [ + { + "id": "ED-EV001", + "obligationId": "EV001", + "state": "supported", + "observed": true, + "severity": "ready", + "diagnosticIds": [] + }, + { + "id": "ED-EV002", + "obligationId": "EV002", + "state": "supported", + "observed": true, + "severity": "ready", + "diagnosticIds": [] + }, + { + "id": "ED-EV003", + "obligationId": "EV003", + "state": "supported", + "observed": true, + "severity": "ready", + "diagnosticIds": [] + }, + { + "id": "ED-EV004", + "obligationId": "EV004", + "state": "supported", + "observed": true, + "severity": "ready", + "diagnosticIds": [] + }, + { + "id": "ED-EV005", + "obligationId": "EV005", + "state": "supported", + "observed": true, + "severity": "ready", + "diagnosticIds": [] + }, + { + "id": "ED-EV006", + "obligationId": "EV006", + "state": "supported", + "observed": true, + "severity": "ready", + "diagnosticIds": [] + }, + { + "id": "ED-EV007", + "obligationId": "EV007", + "state": "supported", + "observed": true, + "severity": "ready", + "diagnosticIds": [] + }, + { + "id": "ED-EV008", + "obligationId": "EV008", + "state": "supported", + "observed": true, + "severity": "ready", + "diagnosticIds": [] + }, + { + "id": "ED-EV009", + "obligationId": "EV009", + "state": "supported", + "observed": true, + "severity": "ready", + "diagnosticIds": [] + }, + { + "id": "ED-EV010", + "obligationId": "EV010", + "state": "supported", + "observed": true, + "severity": "ready", + "diagnosticIds": [] + }, + { + "id": "ED-EV011", + "obligationId": "EV011", + "state": "supported", + "observed": true, + "severity": "ready", + "diagnosticIds": [] + }, + { + "id": "ED-EV012", + "obligationId": "EV012", + "state": "supported", + "observed": true, + "severity": "ready", + "diagnosticIds": [] + }, + { + "id": "ED-EV013", + "obligationId": "EV013", + "state": "supported", + "observed": true, + "severity": "ready", + "diagnosticIds": [] + }, + { + "id": "ED-EV014", + "obligationId": "EV014", + "state": "supported", + "observed": true, + "severity": "ready", + "diagnosticIds": [] + }, + { + "id": "ED-EV015", + "obligationId": "EV015", + "state": "supported", + "observed": true, + "severity": "ready", + "diagnosticIds": [] + }, + { + "id": "ED-EV016", + "obligationId": "EV016", + "state": "supported", + "observed": true, + "severity": "ready", + "diagnosticIds": [] + }, + { + "id": "ED-EV017", + "obligationId": "EV017", + "state": "supported", + "observed": true, + "severity": "ready", + "diagnosticIds": [] + }, + { + "id": "ED-EV018", + "obligationId": "EV018", + "state": "supported", + "observed": true, + "severity": "ready", + "diagnosticIds": [] + }, + { + "id": "ED-EV019", + "obligationId": "EV019", + "state": "supported", + "observed": true, + "severity": "ready", + "diagnosticIds": [] + }, + { + "id": "ED-EV020", + "obligationId": "EV020", + "state": "supported", + "observed": true, + "severity": "ready", + "diagnosticIds": [] + }, + { + "id": "ED-EV021", + "obligationId": "EV021", + "state": "supported", + "observed": true, + "severity": "ready", + "diagnosticIds": [] + }, + { + "id": "ED-EV022", + "obligationId": "EV022", + "state": "supported", + "observed": true, + "severity": "ready", + "diagnosticIds": [] + }, + { + "id": "ED-EV023", + "obligationId": "EV023", + "state": "supported", + "observed": true, + "severity": "ready", + "diagnosticIds": [] + }, + { + "id": "ED-EV024", + "obligationId": "EV024", + "state": "supported", + "observed": true, + "severity": "ready", + "diagnosticIds": [] + }, + { + "id": "ED-EV025", + "obligationId": "EV025", + "state": "supported", + "observed": true, + "severity": "ready", + "diagnosticIds": [] + }, + { + "id": "ED-EV026", + "obligationId": "EV026", + "state": "supported", + "observed": true, + "severity": "ready", + "diagnosticIds": [] + }, + { + "id": "ED-EV027", + "obligationId": "EV027", + "state": "supported", + "observed": true, + "severity": "ready", + "diagnosticIds": [] + }, + { + "id": "ED-EV028", + "obligationId": "EV028", + "state": "supported", + "observed": true, + "severity": "ready", + "diagnosticIds": [] + }, + { + "id": "ED-EV029", + "obligationId": "EV029", + "state": "supported", + "observed": true, + "severity": "ready", + "diagnosticIds": [] + }, + { + "id": "ED-EV030", + "obligationId": "EV030", + "state": "supported", + "observed": true, + "severity": "ready", + "diagnosticIds": [] + }, + { + "id": "ED-EV031", + "obligationId": "EV031", + "state": "supported", + "observed": true, + "severity": "ready", + "diagnosticIds": [] + }, + { + "id": "ED-EV032", + "obligationId": "EV032", + "state": "supported", + "observed": true, + "severity": "ready", + "diagnosticIds": [] + }, + { + "id": "ED-EV033", + "obligationId": "EV033", + "state": "supported", + "observed": true, + "severity": "ready", + "diagnosticIds": [] + }, + { + "id": "ED-EV034", + "obligationId": "EV034", + "state": "supported", + "observed": true, + "severity": "ready", + "diagnosticIds": [] + }, + { + "id": "ED-EV035", + "obligationId": "EV035", + "state": "supported", + "observed": true, + "severity": "ready", + "diagnosticIds": [] + }, + { + "id": "ED-EV036", + "obligationId": "EV036", + "state": "supported", + "observed": true, + "severity": "ready", + "diagnosticIds": [] + }, + { + "id": "ED-EV037", + "obligationId": "EV037", + "state": "supported", + "observed": true, + "severity": "ready", + "diagnosticIds": [] + }, + { + "id": "ED-EV038", + "obligationId": "EV038", + "state": "supported", + "observed": true, + "severity": "ready", + "diagnosticIds": [] + }, + { + "id": "ED-EV039", + "obligationId": "EV039", + "state": "supported", + "observed": true, + "severity": "ready", + "diagnosticIds": [] + } + ], + "generatedViews": [ + { + "path": "readiness/coordination-change-risk-mitigation/analysis.json", + "kind": "analysis", + "currency": "current", + "diagnosticIds": [] + }, + { + "path": "readiness/coordination-change-risk-mitigation/verify.json", + "kind": "verification", + "currency": "current", + "diagnosticIds": [] + }, + { + "path": "readiness/coordination-change-risk-mitigation/work-model.json", + "kind": "workModel", + "currency": "current", + "diagnosticIds": [] + } + ], + "disposition": { + "state": "shipReady", + "blockingFindingIds": [], + "warningFindingIds": [], + "advisoryFindingIds": [], + "contributingStages": [], + "classifiedObligationsUnmetCount": 0, + "journeyObligationsUnmetCount": 0, + "correction": "" + }, + "findings": [], + "governanceCompatibility": [ + { + "path": ".fsgg/policy.yml", + "relationship": "optionalGovernancePolicy", + "requiredBySdd": false, + "state": "notEvaluated", + "diagnosticIds": [] + }, + { + "path": ".fsgg/capabilities.yml", + "relationship": "optionalGovernanceCapabilities", + "requiredBySdd": false, + "state": "notEvaluated", + "diagnosticIds": [] + }, + { + "path": ".fsgg/tooling.yml", + "relationship": "optionalGovernanceTooling", + "requiredBySdd": false, + "state": "notEvaluated", + "diagnosticIds": [] + } + ], + "diagnostics": [], + "readiness": "shipReady", + "nextAction": { + "actionId": "ship.next.protectedBoundary", + "command": null, + "reason": "Ship readiness is current and ready for the protected-boundary handoff." + } +} \ No newline at end of file diff --git a/readiness/coordination-change-risk-mitigation/summary.md b/readiness/coordination-change-risk-mitigation/summary.md new file mode 100644 index 000000000..77ab8b973 --- /dev/null +++ b/readiness/coordination-change-risk-mitigation/summary.md @@ -0,0 +1,32 @@ + + +# Readiness Summary — coordination-change-risk-mitigation + +**Lifecycle stage**: refresh **Outcome**: succeededWithWarnings **Disposition**: awaiting-lifecycle + +## Generated-view currency +| View | State | +|---|---| +| work-model | current | +| analysis | current | +| verify | missing | +| ship | missing | +| ship-verdict | missing | +| governance-handoff | missing | +| agent-commands | current | +| summary | current | + +## Diagnostics +- refresh.notYetGenerated (info) readiness/coordination-change-risk-mitigation/ship-verdict.json: Generated view 'readiness/coordination-change-risk-mitigation/ship-verdict.json' has not been produced at the current lifecycle state. — Run `fsgg-sdd ship` for this work item; refresh reports downstream lifecycle views but does not generate them out of order. +- refresh.notYetGenerated (info) readiness/coordination-change-risk-mitigation/ship.json: Generated view 'readiness/coordination-change-risk-mitigation/ship.json' has not been produced at the current lifecycle state. — Run `fsgg-sdd ship` for this work item; refresh reports downstream lifecycle views but does not generate them out of order. +- refresh.notYetGenerated (info) readiness/coordination-change-risk-mitigation/verify.json: Generated view 'readiness/coordination-change-risk-mitigation/verify.json' has not been produced at the current lifecycle state. — Run `fsgg-sdd verify` for this work item; refresh reports downstream lifecycle views but does not generate them out of order. + +## Next action +Run the next lifecycle command named by the not-yet-generated view; refresh does not generate lifecycle views out of order. diff --git a/readiness/coordination-change-risk-mitigation/verify.json b/readiness/coordination-change-risk-mitigation/verify.json new file mode 100644 index 000000000..436eafe94 --- /dev/null +++ b/readiness/coordination-change-risk-mitigation/verify.json @@ -0,0 +1,1762 @@ +{ + "schemaVersion": 1, + "viewVersion": "1.0", + "workId": "coordination-change-risk-mitigation", + "stage": "verify", + "status": "verificationReady", + "generator": "FS.GG.SDD.Artifacts/1.1.0", + "sources": [ + { + "path": ".fsgg/agents.yml", + "kind": "agentsConfig", + "digest": { + "algorithm": "sha256", + "value": "c67035b1cf31b6fa802c10f761eeb1e5bf5d198c38d159b54fac299957b5aac3" + }, + "schemaVersion": 1, + "schemaStatus": "current" + }, + { + "path": ".fsgg/project.yml", + "kind": "projectConfig", + "digest": { + "algorithm": "sha256", + "value": "ef78f002b33ce22f738bac2c0dbf716db729a7d3ae3e4a68a4ce4b93810ced66" + }, + "schemaVersion": 1, + "schemaStatus": "current" + }, + { + "path": ".fsgg/sdd.yml", + "kind": "sddConfig", + "digest": { + "algorithm": "sha256", + "value": "fe5a7c270a975153e80ab0d08a610c9b302585dcb0b5f7c654841ceced9272cb" + }, + "schemaVersion": 1, + "schemaStatus": "current" + }, + { + "path": "readiness/coordination-change-risk-mitigation/analysis.json", + "kind": "analysis", + "digest": { + "algorithm": "sha256", + "value": "37c0545383a55866f5f83b5da4f0f5301fcbe4e046b0591811ad5a9651443dfa" + }, + "schemaVersion": 1, + "schemaStatus": "current" + }, + { + "path": "readiness/coordination-change-risk-mitigation/work-model.json", + "kind": "workModel", + "digest": { + "algorithm": "sha256", + "value": "2b4fcd016b7de64a639bccfacefd4fdafc4c185879c1c04421c72466c187aba8" + }, + "schemaVersion": 1, + "schemaStatus": "current" + }, + { + "path": "work/coordination-change-risk-mitigation/checklist.md", + "kind": "checklist", + "digest": { + "algorithm": "sha256", + "value": "ac1c0ac8b8feafbedd9582ac17b8196e57b46867459a31c380cbb83e0a342548" + }, + "schemaVersion": 1, + "schemaStatus": "current" + }, + { + "path": "work/coordination-change-risk-mitigation/clarifications.md", + "kind": "clarification", + "digest": { + "algorithm": "sha256", + "value": "02eedf550b282d9788487b3efbd6f0034d35e5982b70dcf8abf01bd6fa61b18c" + }, + "schemaVersion": 1, + "schemaStatus": "current" + }, + { + "path": "work/coordination-change-risk-mitigation/evidence.yml", + "kind": "evidence", + "digest": { + "algorithm": "sha256", + "value": "50a00b29f2bc0ae0fd5d1940799b702d3c9e63dc5e05b0ad26b2a8de83c9c928" + }, + "schemaVersion": 1, + "schemaStatus": "current" + }, + { + "path": "work/coordination-change-risk-mitigation/plan.md", + "kind": "plan", + "digest": { + "algorithm": "sha256", + "value": "6ac822bae2e476fadcadf67890e437775bafd311f11baf6574cc70c48e1dcab6" + }, + "schemaVersion": 1, + "schemaStatus": "current" + }, + { + "path": "work/coordination-change-risk-mitigation/spec.md", + "kind": "specification", + "digest": { + "algorithm": "sha256", + "value": "596003775028144db71fd9a411385e205ed07488ee164d79471c153bb0ec084e" + }, + "schemaVersion": 1, + "schemaStatus": "current" + }, + { + "path": "work/coordination-change-risk-mitigation/tasks.yml", + "kind": "tasks", + "digest": { + "algorithm": "sha256", + "value": "d18dc3eacc78599e0cdcf030e8a8d74c324bb10d35788702e44e3781c5b6083c" + }, + "schemaVersion": 1, + "schemaStatus": "current" + } + ], + "lifecycleReadiness": { + "status": "implementationReady", + "stages": [ + { + "stage": "analyze", + "status": "implementationReady" + }, + { + "stage": "checklist", + "status": "current" + }, + { + "stage": "clarify", + "status": "current" + }, + { + "stage": "evidence", + "status": "evidenceReady" + }, + { + "stage": "plan", + "status": "current" + }, + { + "stage": "specify", + "status": "current" + }, + { + "stage": "tasks", + "status": "current" + } + ] + }, + "taskGraph": { + "taskCount": 39, + "dependencyCount": 51, + "dependenciesValid": true, + "statusesValid": true, + "findingIds": [] + }, + "evidenceDispositions": [ + { + "id": "ED-EV001", + "obligationId": "EV001", + "state": "supported", + "observed": true, + "classifiedRequirement": false, + "journeyRequirement": false, + "recordRequirement": false, + "evidenceIds": [ + "EV001" + ], + "affectedTaskIds": [ + "T001" + ], + "affectedSourceIds": [ + "AC-001", + "FR-001", + "PD-002" + ], + "severity": "ready", + "diagnosticIds": [], + "correction": "" + }, + { + "id": "ED-EV002", + "obligationId": "EV002", + "state": "supported", + "observed": true, + "classifiedRequirement": false, + "journeyRequirement": false, + "recordRequirement": false, + "evidenceIds": [ + "EV002" + ], + "affectedTaskIds": [ + "T002" + ], + "affectedSourceIds": [ + "AC-002", + "FR-002", + "PD-003" + ], + "severity": "ready", + "diagnosticIds": [], + "correction": "" + }, + { + "id": "ED-EV003", + "obligationId": "EV003", + "state": "supported", + "observed": true, + "classifiedRequirement": false, + "journeyRequirement": false, + "recordRequirement": false, + "evidenceIds": [ + "EV003" + ], + "affectedTaskIds": [ + "T003" + ], + "affectedSourceIds": [ + "AC-003", + "FR-003", + "PD-004" + ], + "severity": "ready", + "diagnosticIds": [], + "correction": "" + }, + { + "id": "ED-EV004", + "obligationId": "EV004", + "state": "supported", + "observed": true, + "classifiedRequirement": false, + "journeyRequirement": false, + "recordRequirement": false, + "evidenceIds": [ + "EV004" + ], + "affectedTaskIds": [ + "T004" + ], + "affectedSourceIds": [ + "AC-004", + "FR-004", + "PD-005" + ], + "severity": "ready", + "diagnosticIds": [], + "correction": "" + }, + { + "id": "ED-EV005", + "obligationId": "EV005", + "state": "supported", + "observed": true, + "classifiedRequirement": false, + "journeyRequirement": false, + "recordRequirement": false, + "evidenceIds": [ + "EV005" + ], + "affectedTaskIds": [ + "T005" + ], + "affectedSourceIds": [ + "AC-005", + "FR-005", + "PD-006" + ], + "severity": "ready", + "diagnosticIds": [], + "correction": "" + }, + { + "id": "ED-EV006", + "obligationId": "EV006", + "state": "supported", + "observed": true, + "classifiedRequirement": false, + "journeyRequirement": false, + "recordRequirement": false, + "evidenceIds": [ + "EV006" + ], + "affectedTaskIds": [ + "T006" + ], + "affectedSourceIds": [ + "AC-006", + "FR-006", + "PD-007" + ], + "severity": "ready", + "diagnosticIds": [], + "correction": "" + }, + { + "id": "ED-EV007", + "obligationId": "EV007", + "state": "supported", + "observed": true, + "classifiedRequirement": false, + "journeyRequirement": false, + "recordRequirement": false, + "evidenceIds": [ + "EV007" + ], + "affectedTaskIds": [ + "T007" + ], + "affectedSourceIds": [ + "AC-007", + "FR-007", + "PD-008" + ], + "severity": "ready", + "diagnosticIds": [], + "correction": "" + }, + { + "id": "ED-EV008", + "obligationId": "EV008", + "state": "supported", + "observed": true, + "classifiedRequirement": false, + "journeyRequirement": false, + "recordRequirement": false, + "evidenceIds": [ + "EV008" + ], + "affectedTaskIds": [ + "T008" + ], + "affectedSourceIds": [ + "AC-008", + "FR-008", + "PD-009" + ], + "severity": "ready", + "diagnosticIds": [], + "correction": "" + }, + { + "id": "ED-EV009", + "obligationId": "EV009", + "state": "supported", + "observed": true, + "classifiedRequirement": false, + "journeyRequirement": false, + "recordRequirement": false, + "evidenceIds": [ + "EV009" + ], + "affectedTaskIds": [ + "T009" + ], + "affectedSourceIds": [ + "AC-009", + "FR-009", + "PD-001" + ], + "severity": "ready", + "diagnosticIds": [], + "correction": "" + }, + { + "id": "ED-EV010", + "obligationId": "EV010", + "state": "supported", + "observed": true, + "classifiedRequirement": false, + "journeyRequirement": false, + "recordRequirement": false, + "evidenceIds": [ + "EV010" + ], + "affectedTaskIds": [ + "T010" + ], + "affectedSourceIds": [ + "DEC-001" + ], + "severity": "ready", + "diagnosticIds": [], + "correction": "" + }, + { + "id": "ED-EV011", + "obligationId": "EV011", + "state": "supported", + "observed": true, + "classifiedRequirement": false, + "journeyRequirement": false, + "recordRequirement": false, + "evidenceIds": [ + "EV011" + ], + "affectedTaskIds": [ + "T011" + ], + "affectedSourceIds": [ + "DEC-002" + ], + "severity": "ready", + "diagnosticIds": [], + "correction": "" + }, + { + "id": "ED-EV012", + "obligationId": "EV012", + "state": "supported", + "observed": true, + "classifiedRequirement": false, + "journeyRequirement": false, + "recordRequirement": false, + "evidenceIds": [ + "EV012" + ], + "affectedTaskIds": [ + "T012" + ], + "affectedSourceIds": [ + "DEC-003" + ], + "severity": "ready", + "diagnosticIds": [], + "correction": "" + }, + { + "id": "ED-EV013", + "obligationId": "EV013", + "state": "supported", + "observed": true, + "classifiedRequirement": false, + "journeyRequirement": false, + "recordRequirement": false, + "evidenceIds": [ + "EV013" + ], + "affectedTaskIds": [ + "T013" + ], + "affectedSourceIds": [ + "DEC-004" + ], + "severity": "ready", + "diagnosticIds": [], + "correction": "" + }, + { + "id": "ED-EV014", + "obligationId": "EV014", + "state": "supported", + "observed": true, + "classifiedRequirement": false, + "journeyRequirement": false, + "recordRequirement": false, + "evidenceIds": [ + "EV014" + ], + "affectedTaskIds": [ + "T014" + ], + "affectedSourceIds": [ + "DEC-005" + ], + "severity": "ready", + "diagnosticIds": [], + "correction": "" + }, + { + "id": "ED-EV015", + "obligationId": "EV015", + "state": "supported", + "observed": true, + "classifiedRequirement": false, + "journeyRequirement": false, + "recordRequirement": false, + "evidenceIds": [ + "EV015" + ], + "affectedTaskIds": [ + "T015" + ], + "affectedSourceIds": [ + "PC-001", + "PD-002" + ], + "severity": "ready", + "diagnosticIds": [], + "correction": "" + }, + { + "id": "ED-EV016", + "obligationId": "EV016", + "state": "supported", + "observed": true, + "classifiedRequirement": false, + "journeyRequirement": false, + "recordRequirement": false, + "evidenceIds": [ + "EV016" + ], + "affectedTaskIds": [ + "T016" + ], + "affectedSourceIds": [ + "PC-002", + "PD-003" + ], + "severity": "ready", + "diagnosticIds": [], + "correction": "" + }, + { + "id": "ED-EV017", + "obligationId": "EV017", + "state": "supported", + "observed": true, + "classifiedRequirement": false, + "journeyRequirement": false, + "recordRequirement": false, + "evidenceIds": [ + "EV017" + ], + "affectedTaskIds": [ + "T017" + ], + "affectedSourceIds": [ + "PC-003", + "PD-004" + ], + "severity": "ready", + "diagnosticIds": [], + "correction": "" + }, + { + "id": "ED-EV018", + "obligationId": "EV018", + "state": "supported", + "observed": true, + "classifiedRequirement": false, + "journeyRequirement": false, + "recordRequirement": false, + "evidenceIds": [ + "EV018" + ], + "affectedTaskIds": [ + "T018" + ], + "affectedSourceIds": [ + "PC-004", + "PD-005" + ], + "severity": "ready", + "diagnosticIds": [], + "correction": "" + }, + { + "id": "ED-EV019", + "obligationId": "EV019", + "state": "supported", + "observed": true, + "classifiedRequirement": false, + "journeyRequirement": false, + "recordRequirement": false, + "evidenceIds": [ + "EV019" + ], + "affectedTaskIds": [ + "T019" + ], + "affectedSourceIds": [ + "PC-005", + "PD-006" + ], + "severity": "ready", + "diagnosticIds": [], + "correction": "" + }, + { + "id": "ED-EV020", + "obligationId": "EV020", + "state": "supported", + "observed": true, + "classifiedRequirement": false, + "journeyRequirement": false, + "recordRequirement": false, + "evidenceIds": [ + "EV020" + ], + "affectedTaskIds": [ + "T020" + ], + "affectedSourceIds": [ + "PC-006", + "PD-007" + ], + "severity": "ready", + "diagnosticIds": [], + "correction": "" + }, + { + "id": "ED-EV021", + "obligationId": "EV021", + "state": "supported", + "observed": true, + "classifiedRequirement": false, + "journeyRequirement": false, + "recordRequirement": false, + "evidenceIds": [ + "EV021" + ], + "affectedTaskIds": [ + "T021" + ], + "affectedSourceIds": [ + "PC-007", + "PD-008" + ], + "severity": "ready", + "diagnosticIds": [], + "correction": "" + }, + { + "id": "ED-EV022", + "obligationId": "EV022", + "state": "supported", + "observed": true, + "classifiedRequirement": false, + "journeyRequirement": false, + "recordRequirement": false, + "evidenceIds": [ + "EV022" + ], + "affectedTaskIds": [ + "T022" + ], + "affectedSourceIds": [ + "PD-001", + "VO-001" + ], + "severity": "ready", + "diagnosticIds": [], + "correction": "" + }, + { + "id": "ED-EV023", + "obligationId": "EV023", + "state": "supported", + "observed": true, + "classifiedRequirement": false, + "journeyRequirement": false, + "recordRequirement": false, + "evidenceIds": [ + "EV023" + ], + "affectedTaskIds": [ + "T023" + ], + "affectedSourceIds": [ + "PC-001", + "PD-002", + "VO-002" + ], + "severity": "ready", + "diagnosticIds": [], + "correction": "" + }, + { + "id": "ED-EV024", + "obligationId": "EV024", + "state": "supported", + "observed": true, + "classifiedRequirement": false, + "journeyRequirement": false, + "recordRequirement": false, + "evidenceIds": [ + "EV024" + ], + "affectedTaskIds": [ + "T024" + ], + "affectedSourceIds": [ + "PC-001", + "PD-002", + "VO-003" + ], + "severity": "ready", + "diagnosticIds": [], + "correction": "" + }, + { + "id": "ED-EV025", + "obligationId": "EV025", + "state": "supported", + "observed": true, + "classifiedRequirement": false, + "journeyRequirement": false, + "recordRequirement": false, + "evidenceIds": [ + "EV025" + ], + "affectedTaskIds": [ + "T025" + ], + "affectedSourceIds": [ + "PC-002", + "PD-003", + "PD-007", + "VO-004" + ], + "severity": "ready", + "diagnosticIds": [], + "correction": "" + }, + { + "id": "ED-EV026", + "obligationId": "EV026", + "state": "supported", + "observed": true, + "classifiedRequirement": false, + "journeyRequirement": false, + "recordRequirement": false, + "evidenceIds": [ + "EV026" + ], + "affectedTaskIds": [ + "T026" + ], + "affectedSourceIds": [ + "PC-003", + "PD-004", + "VO-005" + ], + "severity": "ready", + "diagnosticIds": [], + "correction": "" + }, + { + "id": "ED-EV027", + "obligationId": "EV027", + "state": "supported", + "observed": true, + "classifiedRequirement": false, + "journeyRequirement": false, + "recordRequirement": false, + "evidenceIds": [ + "EV027" + ], + "affectedTaskIds": [ + "T027" + ], + "affectedSourceIds": [ + "PC-004", + "PD-005", + "VO-006" + ], + "severity": "ready", + "diagnosticIds": [], + "correction": "" + }, + { + "id": "ED-EV028", + "obligationId": "EV028", + "state": "supported", + "observed": true, + "classifiedRequirement": false, + "journeyRequirement": false, + "recordRequirement": false, + "evidenceIds": [ + "EV028" + ], + "affectedTaskIds": [ + "T028" + ], + "affectedSourceIds": [ + "PC-005", + "PD-006", + "VO-007" + ], + "severity": "ready", + "diagnosticIds": [], + "correction": "" + }, + { + "id": "ED-EV029", + "obligationId": "EV029", + "state": "supported", + "observed": true, + "classifiedRequirement": false, + "journeyRequirement": false, + "recordRequirement": false, + "evidenceIds": [ + "EV029" + ], + "affectedTaskIds": [ + "T029" + ], + "affectedSourceIds": [ + "PC-006", + "PD-007", + "VO-008" + ], + "severity": "ready", + "diagnosticIds": [], + "correction": "" + }, + { + "id": "ED-EV030", + "obligationId": "EV030", + "state": "supported", + "observed": true, + "classifiedRequirement": false, + "journeyRequirement": false, + "recordRequirement": false, + "evidenceIds": [ + "EV030" + ], + "affectedTaskIds": [ + "T030" + ], + "affectedSourceIds": [ + "PC-007", + "PD-008", + "VO-009" + ], + "severity": "ready", + "diagnosticIds": [], + "correction": "" + }, + { + "id": "ED-EV031", + "obligationId": "EV031", + "state": "supported", + "observed": true, + "classifiedRequirement": false, + "journeyRequirement": false, + "recordRequirement": false, + "evidenceIds": [ + "EV031" + ], + "affectedTaskIds": [ + "T031" + ], + "affectedSourceIds": [ + "PD-009", + "VO-010" + ], + "severity": "ready", + "diagnosticIds": [], + "correction": "" + }, + { + "id": "ED-EV032", + "obligationId": "EV032", + "state": "supported", + "observed": true, + "classifiedRequirement": false, + "journeyRequirement": false, + "recordRequirement": false, + "evidenceIds": [ + "EV032" + ], + "affectedTaskIds": [ + "T032" + ], + "affectedSourceIds": [ + "PC-001", + "PM-001" + ], + "severity": "ready", + "diagnosticIds": [], + "correction": "" + }, + { + "id": "ED-EV033", + "obligationId": "EV033", + "state": "supported", + "observed": true, + "classifiedRequirement": false, + "journeyRequirement": false, + "recordRequirement": false, + "evidenceIds": [ + "EV033" + ], + "affectedTaskIds": [ + "T033" + ], + "affectedSourceIds": [ + "PC-002", + "PM-002" + ], + "severity": "ready", + "diagnosticIds": [], + "correction": "" + }, + { + "id": "ED-EV034", + "obligationId": "EV034", + "state": "supported", + "observed": true, + "classifiedRequirement": false, + "journeyRequirement": false, + "recordRequirement": false, + "evidenceIds": [ + "EV034" + ], + "affectedTaskIds": [ + "T034" + ], + "affectedSourceIds": [ + "PC-003", + "PM-003" + ], + "severity": "ready", + "diagnosticIds": [], + "correction": "" + }, + { + "id": "ED-EV035", + "obligationId": "EV035", + "state": "supported", + "observed": true, + "classifiedRequirement": false, + "journeyRequirement": false, + "recordRequirement": false, + "evidenceIds": [ + "EV035" + ], + "affectedTaskIds": [ + "T035" + ], + "affectedSourceIds": [ + "PC-005", + "PM-004" + ], + "severity": "ready", + "diagnosticIds": [], + "correction": "" + }, + { + "id": "ED-EV036", + "obligationId": "EV036", + "state": "supported", + "observed": true, + "classifiedRequirement": false, + "journeyRequirement": false, + "recordRequirement": false, + "evidenceIds": [ + "EV036" + ], + "affectedTaskIds": [ + "T036" + ], + "affectedSourceIds": [ + "PC-007", + "PM-005" + ], + "severity": "ready", + "diagnosticIds": [], + "correction": "" + }, + { + "id": "ED-EV037", + "obligationId": "EV037", + "state": "supported", + "observed": true, + "classifiedRequirement": false, + "journeyRequirement": false, + "recordRequirement": false, + "evidenceIds": [ + "EV037" + ], + "affectedTaskIds": [ + "T037" + ], + "affectedSourceIds": [ + "GV-001", + "PD-001" + ], + "severity": "ready", + "diagnosticIds": [], + "correction": "" + }, + { + "id": "ED-EV038", + "obligationId": "EV038", + "state": "supported", + "observed": true, + "classifiedRequirement": false, + "journeyRequirement": false, + "recordRequirement": false, + "evidenceIds": [ + "EV038" + ], + "affectedTaskIds": [ + "T038" + ], + "affectedSourceIds": [ + "GV-002", + "PD-002" + ], + "severity": "ready", + "diagnosticIds": [], + "correction": "" + }, + { + "id": "ED-EV039", + "obligationId": "EV039", + "state": "supported", + "observed": true, + "classifiedRequirement": false, + "journeyRequirement": false, + "recordRequirement": false, + "evidenceIds": [ + "EV039" + ], + "affectedTaskIds": [ + "T039" + ], + "affectedSourceIds": [ + "GV-003", + "PD-004" + ], + "severity": "ready", + "diagnosticIds": [], + "correction": "" + } + ], + "testDispositions": [ + { + "id": "TD-EV001", + "obligationId": "EV001", + "state": "satisfied", + "observed": true, + "recordRequirement": false, + "evidenceIds": [ + "EV001" + ], + "affectedTaskIds": [ + "T001" + ], + "affectedRequirementIds": [ + "FR-001" + ], + "severity": "ready", + "diagnosticIds": [], + "correction": "" + }, + { + "id": "TD-EV002", + "obligationId": "EV002", + "state": "satisfied", + "observed": true, + "recordRequirement": false, + "evidenceIds": [ + "EV002" + ], + "affectedTaskIds": [ + "T002" + ], + "affectedRequirementIds": [ + "FR-002" + ], + "severity": "ready", + "diagnosticIds": [], + "correction": "" + }, + { + "id": "TD-EV003", + "obligationId": "EV003", + "state": "satisfied", + "observed": true, + "recordRequirement": false, + "evidenceIds": [ + "EV003" + ], + "affectedTaskIds": [ + "T003" + ], + "affectedRequirementIds": [ + "FR-003" + ], + "severity": "ready", + "diagnosticIds": [], + "correction": "" + }, + { + "id": "TD-EV004", + "obligationId": "EV004", + "state": "satisfied", + "observed": true, + "recordRequirement": false, + "evidenceIds": [ + "EV004" + ], + "affectedTaskIds": [ + "T004" + ], + "affectedRequirementIds": [ + "FR-004" + ], + "severity": "ready", + "diagnosticIds": [], + "correction": "" + }, + { + "id": "TD-EV005", + "obligationId": "EV005", + "state": "satisfied", + "observed": true, + "recordRequirement": false, + "evidenceIds": [ + "EV005" + ], + "affectedTaskIds": [ + "T005" + ], + "affectedRequirementIds": [ + "FR-005" + ], + "severity": "ready", + "diagnosticIds": [], + "correction": "" + }, + { + "id": "TD-EV006", + "obligationId": "EV006", + "state": "satisfied", + "observed": true, + "recordRequirement": false, + "evidenceIds": [ + "EV006" + ], + "affectedTaskIds": [ + "T006" + ], + "affectedRequirementIds": [ + "FR-006" + ], + "severity": "ready", + "diagnosticIds": [], + "correction": "" + }, + { + "id": "TD-EV007", + "obligationId": "EV007", + "state": "satisfied", + "observed": true, + "recordRequirement": false, + "evidenceIds": [ + "EV007" + ], + "affectedTaskIds": [ + "T007" + ], + "affectedRequirementIds": [ + "FR-007" + ], + "severity": "ready", + "diagnosticIds": [], + "correction": "" + }, + { + "id": "TD-EV008", + "obligationId": "EV008", + "state": "satisfied", + "observed": true, + "recordRequirement": false, + "evidenceIds": [ + "EV008" + ], + "affectedTaskIds": [ + "T008" + ], + "affectedRequirementIds": [ + "FR-008" + ], + "severity": "ready", + "diagnosticIds": [], + "correction": "" + }, + { + "id": "TD-EV009", + "obligationId": "EV009", + "state": "satisfied", + "observed": true, + "recordRequirement": false, + "evidenceIds": [ + "EV009" + ], + "affectedTaskIds": [ + "T009" + ], + "affectedRequirementIds": [ + "FR-009" + ], + "severity": "ready", + "diagnosticIds": [], + "correction": "" + }, + { + "id": "TD-EV010", + "obligationId": "EV010", + "state": "satisfied", + "observed": true, + "recordRequirement": false, + "evidenceIds": [ + "EV010" + ], + "affectedTaskIds": [ + "T010" + ], + "affectedRequirementIds": [], + "severity": "ready", + "diagnosticIds": [], + "correction": "" + }, + { + "id": "TD-EV011", + "obligationId": "EV011", + "state": "satisfied", + "observed": true, + "recordRequirement": false, + "evidenceIds": [ + "EV011" + ], + "affectedTaskIds": [ + "T011" + ], + "affectedRequirementIds": [], + "severity": "ready", + "diagnosticIds": [], + "correction": "" + }, + { + "id": "TD-EV012", + "obligationId": "EV012", + "state": "satisfied", + "observed": true, + "recordRequirement": false, + "evidenceIds": [ + "EV012" + ], + "affectedTaskIds": [ + "T012" + ], + "affectedRequirementIds": [], + "severity": "ready", + "diagnosticIds": [], + "correction": "" + }, + { + "id": "TD-EV013", + "obligationId": "EV013", + "state": "satisfied", + "observed": true, + "recordRequirement": false, + "evidenceIds": [ + "EV013" + ], + "affectedTaskIds": [ + "T013" + ], + "affectedRequirementIds": [], + "severity": "ready", + "diagnosticIds": [], + "correction": "" + }, + { + "id": "TD-EV014", + "obligationId": "EV014", + "state": "satisfied", + "observed": true, + "recordRequirement": false, + "evidenceIds": [ + "EV014" + ], + "affectedTaskIds": [ + "T014" + ], + "affectedRequirementIds": [], + "severity": "ready", + "diagnosticIds": [], + "correction": "" + }, + { + "id": "TD-EV015", + "obligationId": "EV015", + "state": "satisfied", + "observed": true, + "recordRequirement": false, + "evidenceIds": [ + "EV015" + ], + "affectedTaskIds": [ + "T015" + ], + "affectedRequirementIds": [], + "severity": "ready", + "diagnosticIds": [], + "correction": "" + }, + { + "id": "TD-EV016", + "obligationId": "EV016", + "state": "satisfied", + "observed": true, + "recordRequirement": false, + "evidenceIds": [ + "EV016" + ], + "affectedTaskIds": [ + "T016" + ], + "affectedRequirementIds": [], + "severity": "ready", + "diagnosticIds": [], + "correction": "" + }, + { + "id": "TD-EV017", + "obligationId": "EV017", + "state": "satisfied", + "observed": true, + "recordRequirement": false, + "evidenceIds": [ + "EV017" + ], + "affectedTaskIds": [ + "T017" + ], + "affectedRequirementIds": [], + "severity": "ready", + "diagnosticIds": [], + "correction": "" + }, + { + "id": "TD-EV018", + "obligationId": "EV018", + "state": "satisfied", + "observed": true, + "recordRequirement": false, + "evidenceIds": [ + "EV018" + ], + "affectedTaskIds": [ + "T018" + ], + "affectedRequirementIds": [], + "severity": "ready", + "diagnosticIds": [], + "correction": "" + }, + { + "id": "TD-EV019", + "obligationId": "EV019", + "state": "satisfied", + "observed": true, + "recordRequirement": false, + "evidenceIds": [ + "EV019" + ], + "affectedTaskIds": [ + "T019" + ], + "affectedRequirementIds": [], + "severity": "ready", + "diagnosticIds": [], + "correction": "" + }, + { + "id": "TD-EV020", + "obligationId": "EV020", + "state": "satisfied", + "observed": true, + "recordRequirement": false, + "evidenceIds": [ + "EV020" + ], + "affectedTaskIds": [ + "T020" + ], + "affectedRequirementIds": [], + "severity": "ready", + "diagnosticIds": [], + "correction": "" + }, + { + "id": "TD-EV021", + "obligationId": "EV021", + "state": "satisfied", + "observed": true, + "recordRequirement": false, + "evidenceIds": [ + "EV021" + ], + "affectedTaskIds": [ + "T021" + ], + "affectedRequirementIds": [], + "severity": "ready", + "diagnosticIds": [], + "correction": "" + }, + { + "id": "TD-EV022", + "obligationId": "EV022", + "state": "satisfied", + "observed": true, + "recordRequirement": false, + "evidenceIds": [ + "EV022" + ], + "affectedTaskIds": [ + "T022" + ], + "affectedRequirementIds": [], + "severity": "ready", + "diagnosticIds": [], + "correction": "" + }, + { + "id": "TD-EV023", + "obligationId": "EV023", + "state": "satisfied", + "observed": true, + "recordRequirement": false, + "evidenceIds": [ + "EV023" + ], + "affectedTaskIds": [ + "T023" + ], + "affectedRequirementIds": [], + "severity": "ready", + "diagnosticIds": [], + "correction": "" + }, + { + "id": "TD-EV024", + "obligationId": "EV024", + "state": "satisfied", + "observed": true, + "recordRequirement": false, + "evidenceIds": [ + "EV024" + ], + "affectedTaskIds": [ + "T024" + ], + "affectedRequirementIds": [], + "severity": "ready", + "diagnosticIds": [], + "correction": "" + }, + { + "id": "TD-EV025", + "obligationId": "EV025", + "state": "satisfied", + "observed": true, + "recordRequirement": false, + "evidenceIds": [ + "EV025" + ], + "affectedTaskIds": [ + "T025" + ], + "affectedRequirementIds": [], + "severity": "ready", + "diagnosticIds": [], + "correction": "" + }, + { + "id": "TD-EV026", + "obligationId": "EV026", + "state": "satisfied", + "observed": true, + "recordRequirement": false, + "evidenceIds": [ + "EV026" + ], + "affectedTaskIds": [ + "T026" + ], + "affectedRequirementIds": [], + "severity": "ready", + "diagnosticIds": [], + "correction": "" + }, + { + "id": "TD-EV027", + "obligationId": "EV027", + "state": "satisfied", + "observed": true, + "recordRequirement": false, + "evidenceIds": [ + "EV027" + ], + "affectedTaskIds": [ + "T027" + ], + "affectedRequirementIds": [], + "severity": "ready", + "diagnosticIds": [], + "correction": "" + }, + { + "id": "TD-EV028", + "obligationId": "EV028", + "state": "satisfied", + "observed": true, + "recordRequirement": false, + "evidenceIds": [ + "EV028" + ], + "affectedTaskIds": [ + "T028" + ], + "affectedRequirementIds": [], + "severity": "ready", + "diagnosticIds": [], + "correction": "" + }, + { + "id": "TD-EV029", + "obligationId": "EV029", + "state": "satisfied", + "observed": true, + "recordRequirement": false, + "evidenceIds": [ + "EV029" + ], + "affectedTaskIds": [ + "T029" + ], + "affectedRequirementIds": [], + "severity": "ready", + "diagnosticIds": [], + "correction": "" + }, + { + "id": "TD-EV030", + "obligationId": "EV030", + "state": "satisfied", + "observed": true, + "recordRequirement": false, + "evidenceIds": [ + "EV030" + ], + "affectedTaskIds": [ + "T030" + ], + "affectedRequirementIds": [], + "severity": "ready", + "diagnosticIds": [], + "correction": "" + }, + { + "id": "TD-EV031", + "obligationId": "EV031", + "state": "satisfied", + "observed": true, + "recordRequirement": false, + "evidenceIds": [ + "EV031" + ], + "affectedTaskIds": [ + "T031" + ], + "affectedRequirementIds": [], + "severity": "ready", + "diagnosticIds": [], + "correction": "" + }, + { + "id": "TD-EV032", + "obligationId": "EV032", + "state": "satisfied", + "observed": true, + "recordRequirement": false, + "evidenceIds": [ + "EV032" + ], + "affectedTaskIds": [ + "T032" + ], + "affectedRequirementIds": [], + "severity": "ready", + "diagnosticIds": [], + "correction": "" + }, + { + "id": "TD-EV033", + "obligationId": "EV033", + "state": "satisfied", + "observed": true, + "recordRequirement": false, + "evidenceIds": [ + "EV033" + ], + "affectedTaskIds": [ + "T033" + ], + "affectedRequirementIds": [], + "severity": "ready", + "diagnosticIds": [], + "correction": "" + }, + { + "id": "TD-EV034", + "obligationId": "EV034", + "state": "satisfied", + "observed": true, + "recordRequirement": false, + "evidenceIds": [ + "EV034" + ], + "affectedTaskIds": [ + "T034" + ], + "affectedRequirementIds": [], + "severity": "ready", + "diagnosticIds": [], + "correction": "" + }, + { + "id": "TD-EV035", + "obligationId": "EV035", + "state": "satisfied", + "observed": true, + "recordRequirement": false, + "evidenceIds": [ + "EV035" + ], + "affectedTaskIds": [ + "T035" + ], + "affectedRequirementIds": [], + "severity": "ready", + "diagnosticIds": [], + "correction": "" + }, + { + "id": "TD-EV036", + "obligationId": "EV036", + "state": "satisfied", + "observed": true, + "recordRequirement": false, + "evidenceIds": [ + "EV036" + ], + "affectedTaskIds": [ + "T036" + ], + "affectedRequirementIds": [], + "severity": "ready", + "diagnosticIds": [], + "correction": "" + }, + { + "id": "TD-EV037", + "obligationId": "EV037", + "state": "satisfied", + "observed": true, + "recordRequirement": false, + "evidenceIds": [ + "EV037" + ], + "affectedTaskIds": [ + "T037" + ], + "affectedRequirementIds": [], + "severity": "ready", + "diagnosticIds": [], + "correction": "" + }, + { + "id": "TD-EV038", + "obligationId": "EV038", + "state": "satisfied", + "observed": true, + "recordRequirement": false, + "evidenceIds": [ + "EV038" + ], + "affectedTaskIds": [ + "T038" + ], + "affectedRequirementIds": [], + "severity": "ready", + "diagnosticIds": [], + "correction": "" + }, + { + "id": "TD-EV039", + "obligationId": "EV039", + "state": "satisfied", + "observed": true, + "recordRequirement": false, + "evidenceIds": [ + "EV039" + ], + "affectedTaskIds": [ + "T039" + ], + "affectedRequirementIds": [], + "severity": "ready", + "diagnosticIds": [], + "correction": "" + } + ], + "skillVisibility": [], + "generatedViews": [ + { + "path": "readiness/coordination-change-risk-mitigation/analysis.json", + "kind": "verification", + "currency": "current", + "diagnosticIds": [] + }, + { + "path": "readiness/coordination-change-risk-mitigation/work-model.json", + "kind": "workModel", + "currency": "current", + "diagnosticIds": [] + } + ], + "findings": [], + "governanceCompatibility": [ + { + "path": ".fsgg/policy.yml", + "relationship": "optionalGovernancePolicy", + "requiredBySdd": false, + "state": "notEvaluated", + "diagnosticIds": [] + }, + { + "path": ".fsgg/capabilities.yml", + "relationship": "optionalGovernanceCapabilities", + "requiredBySdd": false, + "state": "notEvaluated", + "diagnosticIds": [] + }, + { + "path": ".fsgg/tooling.yml", + "relationship": "optionalGovernanceTooling", + "requiredBySdd": false, + "state": "notEvaluated", + "diagnosticIds": [] + } + ], + "diagnostics": [], + "readiness": "verificationReady", + "nextAction": { + "actionId": "verify.next.ship", + "command": null, + "reason": "Verification readiness is current and ready for ship." + } +} \ No newline at end of file diff --git a/readiness/coordination-change-risk-mitigation/work-model.json b/readiness/coordination-change-risk-mitigation/work-model.json new file mode 100644 index 000000000..064bd704a --- /dev/null +++ b/readiness/coordination-change-risk-mitigation/work-model.json @@ -0,0 +1,2452 @@ +{ + "schemaVersion": 1, + "modelVersion": "1.2.0", + "workId": "coordination-change-risk-mitigation", + "project": { + "id": ".github-2127", + "defaultWorkRoot": "work", + "profile": null + }, + "sources": [ + { + "path": ".fsgg/agents.yml", + "kind": "agentsConfig", + "owner": "sdd", + "schemaVersion": 1, + "rawSchemaVersion": "1", + "schemaStatus": "current", + "sourceDigest": { + "algorithm": "sha256", + "value": "c67035b1cf31b6fa802c10f761eeb1e5bf5d198c38d159b54fac299957b5aac3" + } + }, + { + "path": ".fsgg/project.yml", + "kind": "projectConfig", + "owner": "sdd", + "schemaVersion": 1, + "rawSchemaVersion": "1", + "schemaStatus": "current", + "sourceDigest": { + "algorithm": "sha256", + "value": "ef78f002b33ce22f738bac2c0dbf716db729a7d3ae3e4a68a4ce4b93810ced66" + } + }, + { + "path": ".fsgg/sdd.yml", + "kind": "sddConfig", + "owner": "sdd", + "schemaVersion": 1, + "rawSchemaVersion": "1", + "schemaStatus": "current", + "sourceDigest": { + "algorithm": "sha256", + "value": "fe5a7c270a975153e80ab0d08a610c9b302585dcb0b5f7c654841ceced9272cb" + } + }, + { + "path": "work/coordination-change-risk-mitigation/checklist.md", + "kind": "checklist", + "owner": "sdd", + "schemaVersion": 1, + "rawSchemaVersion": "1", + "schemaStatus": "current", + "sourceDigest": { + "algorithm": "sha256", + "value": "ac1c0ac8b8feafbedd9582ac17b8196e57b46867459a31c380cbb83e0a342548" + } + }, + { + "path": "work/coordination-change-risk-mitigation/clarifications.md", + "kind": "clarifications", + "owner": "sdd", + "schemaVersion": 1, + "rawSchemaVersion": "1", + "schemaStatus": "current", + "sourceDigest": { + "algorithm": "sha256", + "value": "02eedf550b282d9788487b3efbd6f0034d35e5982b70dcf8abf01bd6fa61b18c" + } + }, + { + "path": "work/coordination-change-risk-mitigation/evidence.yml", + "kind": "evidence", + "owner": "sdd", + "schemaVersion": 1, + "rawSchemaVersion": "1", + "schemaStatus": "current", + "sourceDigest": { + "algorithm": "sha256", + "value": "4f56b80be2007d2e7048e262eb370fdda44619d11da81e75d319e8ac948b45f3" + } + }, + { + "path": "work/coordination-change-risk-mitigation/plan.md", + "kind": "plan", + "owner": "sdd", + "schemaVersion": 1, + "rawSchemaVersion": "1", + "schemaStatus": "current", + "sourceDigest": { + "algorithm": "sha256", + "value": "6ac822bae2e476fadcadf67890e437775bafd311f11baf6574cc70c48e1dcab6" + } + }, + { + "path": "work/coordination-change-risk-mitigation/spec.md", + "kind": "spec", + "owner": "sdd", + "schemaVersion": 1, + "rawSchemaVersion": "1", + "schemaStatus": "current", + "sourceDigest": { + "algorithm": "sha256", + "value": "596003775028144db71fd9a411385e205ed07488ee164d79471c153bb0ec084e" + } + }, + { + "path": "work/coordination-change-risk-mitigation/tasks.yml", + "kind": "tasks", + "owner": "sdd", + "schemaVersion": 1, + "rawSchemaVersion": "1", + "schemaStatus": "current", + "sourceDigest": { + "algorithm": "sha256", + "value": "d18dc3eacc78599e0cdcf030e8a8d74c324bb10d35788702e44e3781c5b6083c" + } + } + ], + "workItem": { + "id": "coordination-change-risk-mitigation", + "title": "Coordination Change Risk Mitigation", + "stage": "specify", + "changeTier": "tier1", + "status": "specified" + }, + "performanceIntent": null, + "requirements": [ + { + "id": "FR-001", + "title": "The engine MUST own one exhaustive command catalogue and one BoardOps handler binding list, deriving declarative command metadata and conformance cases while keeping heterogeneous parser arms explicit. (Stories: US-001; Acceptance: AC-001)", + "text": "The engine MUST own one exhaustive command catalogue and one BoardOps handler binding list, deriving declarative command metadata and conformance cases while keeping heterogeneous parser arms explicit. (Stories: US-001; Acceptance: AC-001)", + "acceptanceCriteria": [ + "AC-001" + ], + "priority": null, + "classification": [], + "source": "work/coordination-change-risk-mitigation/spec.md", + "sourceLocation": { + "line": 79, + "column": 1 + }, + "linkedTaskIds": [ + "T001" + ], + "linkedEvidenceIds": [ + "EV001" + ] + }, + { + "id": "FR-002", + "title": "Every disputed lifecycle transition MUST expose one complete typed fact input and decision output consumed unchanged by projection and writer admission; writers may add only freshness, idempotency, and effect mechanics. (Stories: US-002; Acceptance: AC-002)", + "text": "Every disputed lifecycle transition MUST expose one complete typed fact input and decision output consumed unchanged by projection and writer admission; writers may add only freshness, idempotency, and effect mechanics. (Stories: US-002; Acceptance: AC-002)", + "acceptanceCriteria": [ + "AC-002" + ], + "priority": null, + "classification": [], + "source": "work/coordination-change-risk-mitigation/spec.md", + "sourceLocation": { + "line": 80, + "column": 1 + }, + "linkedTaskIds": [ + "T002" + ], + "linkedEvidenceIds": [ + "EV002" + ] + }, + { + "id": "FR-003", + "title": "Completion MUST require an exact-merge \u0060DeliveryCompletionReceipt\u0060 proving reachability, verified declared obligations, no contradictions, and zero pending board writes before projecting issue closure or \u0060Status=Done\u0060. (Stories: US-003; Acceptance: AC-003)", + "text": "Completion MUST require an exact-merge \u0060DeliveryCompletionReceipt\u0060 proving reachability, verified declared obligations, no contradictions, and zero pending board writes before projecting issue closure or \u0060Status=Done\u0060. (Stories: US-003; Acceptance: AC-003)", + "acceptanceCriteria": [ + "AC-003" + ], + "priority": null, + "classification": [], + "source": "work/coordination-change-risk-mitigation/spec.md", + "sourceLocation": { + "line": 81, + "column": 1 + }, + "linkedTaskIds": [ + "T003" + ], + "linkedEvidenceIds": [ + "EV003" + ] + }, + { + "id": "FR-004", + "title": "Candidate-engine writes MUST require an enumerated bootstrap reason, a digest-bound \u0060SelfHostBootstrapReceipt\u0060, stable-verifier validation, accountable host acceptance, and post-merge shared-engine replay. (Stories: US-004; Acceptance: AC-004)", + "text": "Candidate-engine writes MUST require an enumerated bootstrap reason, a digest-bound \u0060SelfHostBootstrapReceipt\u0060, stable-verifier validation, accountable host acceptance, and post-merge shared-engine replay. (Stories: US-004; Acceptance: AC-004)", + "acceptanceCriteria": [ + "AC-004" + ], + "priority": null, + "classification": [], + "source": "work/coordination-change-risk-mitigation/spec.md", + "sourceLocation": { + "line": 82, + "column": 1 + }, + "linkedTaskIds": [ + "T004" + ], + "linkedEvidenceIds": [ + "EV004" + ] + }, + { + "id": "FR-005", + "title": "A required \u0060change-completeness\u0060 context MUST run structural closure, parity, path, message, provenance, and focused route checks before independent review and expensive mutation work, with a five-minute ordinary-change target. (Stories: US-005; Acceptance: AC-005)", + "text": "A required \u0060change-completeness\u0060 context MUST run structural closure, parity, path, message, provenance, and focused route checks before independent review and expensive mutation work, with a five-minute ordinary-change target. (Stories: US-005; Acceptance: AC-005)", + "acceptanceCriteria": [ + "AC-005" + ], + "priority": null, + "classification": [], + "source": "work/coordination-change-risk-mitigation/spec.md", + "sourceLocation": { + "line": 83, + "column": 1 + }, + "linkedTaskIds": [ + "T005" + ], + "linkedEvidenceIds": [ + "EV005" + ] + }, + { + "id": "FR-006", + "title": "Bounded Review and Delivery models MUST prove projection decision, writer admission, and reducer transition parity, and MUST include effective mutations that make every consumer red on divergence. (Stories: US-002; Acceptance: AC-006)", + "text": "Bounded Review and Delivery models MUST prove projection decision, writer admission, and reducer transition parity, and MUST include effective mutations that make every consumer red on divergence. (Stories: US-002; Acceptance: AC-006)", + "acceptanceCriteria": [ + "AC-006" + ], + "priority": null, + "classification": [], + "source": "work/coordination-change-risk-mitigation/spec.md", + "sourceLocation": { + "line": 84, + "column": 1 + }, + "linkedTaskIds": [ + "T006" + ], + "linkedEvidenceIds": [ + "EV006" + ] + }, + { + "id": "FR-007", + "title": "Immutable release recovery MUST verify existing journal and artifact identity, perform zero asset mutation, resume downstream delivery, and append verified receiver receipts outside the immutable asset set. (Stories: US-006; Acceptance: AC-007)", + "text": "Immutable release recovery MUST verify existing journal and artifact identity, perform zero asset mutation, resume downstream delivery, and append verified receiver receipts outside the immutable asset set. (Stories: US-006; Acceptance: AC-007)", + "acceptanceCriteria": [ + "AC-007" + ], + "priority": null, + "classification": [], + "source": "work/coordination-change-risk-mitigation/spec.md", + "sourceLocation": { + "line": 85, + "column": 1 + }, + "linkedTaskIds": [ + "T007" + ], + "linkedEvidenceIds": [ + "EV007" + ] + }, + { + "id": "FR-008", + "title": "Rollout MUST use independently mergeable, reversible compatibility slices and MUST retain predecessor paths until behavior parity and an effective inversion pass. (Stories: US-001, US-005; Acceptance: AC-008)", + "text": "Rollout MUST use independently mergeable, reversible compatibility slices and MUST retain predecessor paths until behavior parity and an effective inversion pass. (Stories: US-001, US-005; Acceptance: AC-008)", + "acceptanceCriteria": [ + "AC-008" + ], + "priority": null, + "classification": [], + "source": "work/coordination-change-risk-mitigation/spec.md", + "sourceLocation": { + "line": 86, + "column": 1 + }, + "linkedTaskIds": [ + "T008" + ], + "linkedEvidenceIds": [ + "EV008" + ] + }, + { + "id": "FR-009", + "title": "The implementation MUST establish phase-0 baselines and monthly success metrics, with zero divergence, premature \u0060Done\u0060, and unreceipted self-host writes as invariant targets. (Stories: US-003, US-006; Acceptance: AC-009)", + "text": "The implementation MUST establish phase-0 baselines and monthly success metrics, with zero divergence, premature \u0060Done\u0060, and unreceipted self-host writes as invariant targets. (Stories: US-003, US-006; Acceptance: AC-009)", + "acceptanceCriteria": [ + "AC-009" + ], + "priority": null, + "classification": [], + "source": "work/coordination-change-risk-mitigation/spec.md", + "sourceLocation": { + "line": 87, + "column": 1 + }, + "linkedTaskIds": [ + "T009" + ], + "linkedEvidenceIds": [ + "EV009" + ] + } + ], + "decisions": [ + { + "id": "DEC-001", + "title": "Use expand-and-contract migration for the command catalogue; coexistence precedes deletion.", + "decision": "Use expand-and-contract migration for the command catalogue; coexistence precedes deletion.", + "requirementRefs": [], + "storyRefs": [], + "acceptanceRefs": [], + "source": "work/coordination-change-risk-mitigation/clarifications.md", + "sourceLocation": { + "line": 34, + "column": 1 + }, + "linkedTaskIds": [ + "T010" + ] + }, + { + "id": "DEC-002", + "title": "Preserve current external JSON schemas by adapter translation unless a phase proves a versioned", + "decision": "Preserve current external JSON schemas by adapter translation unless a phase proves a versioned", + "requirementRefs": [], + "storyRefs": [], + "acceptanceRefs": [], + "source": "work/coordination-change-risk-mitigation/clarifications.md", + "sourceLocation": { + "line": 35, + "column": 1 + }, + "linkedTaskIds": [ + "T011" + ] + }, + { + "id": "DEC-003", + "title": "Stage \u0060change-completeness\u0060 advisory first, then required only after its boundedness and signal are", + "decision": "Stage \u0060change-completeness\u0060 advisory first, then required only after its boundedness and signal are", + "requirementRefs": [], + "storyRefs": [], + "acceptanceRefs": [], + "source": "work/coordination-change-risk-mitigation/clarifications.md", + "sourceLocation": { + "line": 37, + "column": 1 + }, + "linkedTaskIds": [ + "T012" + ] + }, + { + "id": "DEC-004", + "title": "Store receiver receipts as append-only evidence outside immutable assets and include them in the", + "decision": "Store receiver receipts as append-only evidence outside immutable assets and include them in the", + "requirementRefs": [], + "storyRefs": [], + "acceptanceRefs": [], + "source": "work/coordination-change-risk-mitigation/clarifications.md", + "sourceLocation": { + "line": 39, + "column": 1 + }, + "linkedTaskIds": [ + "T013" + ] + }, + { + "id": "DEC-005", + "title": "Treat the source design as one umbrella work package whose tasks map to phases 0 through 5; each phase may", + "decision": "Treat the source design as one umbrella work package whose tasks map to phases 0 through 5; each phase may", + "requirementRefs": [], + "storyRefs": [], + "acceptanceRefs": [], + "source": "work/coordination-change-risk-mitigation/clarifications.md", + "sourceLocation": { + "line": 41, + "column": 1 + }, + "linkedTaskIds": [ + "T014" + ] + } + ], + "tasks": [ + { + "id": "T001", + "title": "Implement requirement FR-001", + "status": "done", + "owner": "sdd", + "dependencies": [ + "T009" + ], + "requirements": [ + "FR-001" + ], + "decisions": [], + "sourceIds": [ + "AC-001", + "FR-001", + "PD-002" + ], + "requiredSkills": [], + "requiredEvidence": [ + "EV001" + ], + "source": "work/coordination-change-risk-mitigation/tasks.yml", + "sourceLocation": { + "line": 1, + "column": 1 + } + }, + { + "id": "T002", + "title": "Implement requirement FR-002", + "status": "done", + "owner": "sdd", + "dependencies": [ + "T001" + ], + "requirements": [ + "FR-002" + ], + "decisions": [], + "sourceIds": [ + "AC-002", + "FR-002", + "PD-003" + ], + "requiredSkills": [], + "requiredEvidence": [ + "EV002" + ], + "source": "work/coordination-change-risk-mitigation/tasks.yml", + "sourceLocation": { + "line": 2, + "column": 1 + } + }, + { + "id": "T003", + "title": "Implement requirement FR-003", + "status": "done", + "owner": "sdd", + "dependencies": [ + "T002", + "T006" + ], + "requirements": [ + "FR-003" + ], + "decisions": [], + "sourceIds": [ + "AC-003", + "FR-003", + "PD-004" + ], + "requiredSkills": [], + "requiredEvidence": [ + "EV003" + ], + "source": "work/coordination-change-risk-mitigation/tasks.yml", + "sourceLocation": { + "line": 3, + "column": 1 + } + }, + { + "id": "T004", + "title": "Implement requirement FR-004", + "status": "done", + "owner": "sdd", + "dependencies": [ + "T003" + ], + "requirements": [ + "FR-004" + ], + "decisions": [], + "sourceIds": [ + "AC-004", + "FR-004", + "PD-005" + ], + "requiredSkills": [], + "requiredEvidence": [ + "EV004" + ], + "source": "work/coordination-change-risk-mitigation/tasks.yml", + "sourceLocation": { + "line": 4, + "column": 1 + } + }, + { + "id": "T005", + "title": "Implement requirement FR-005", + "status": "done", + "owner": "sdd", + "dependencies": [ + "T003" + ], + "requirements": [ + "FR-005" + ], + "decisions": [], + "sourceIds": [ + "AC-005", + "FR-005", + "PD-006" + ], + "requiredSkills": [], + "requiredEvidence": [ + "EV005" + ], + "source": "work/coordination-change-risk-mitigation/tasks.yml", + "sourceLocation": { + "line": 5, + "column": 1 + } + }, + { + "id": "T006", + "title": "Implement requirement FR-006", + "status": "done", + "owner": "sdd", + "dependencies": [ + "T002" + ], + "requirements": [ + "FR-006" + ], + "decisions": [], + "sourceIds": [ + "AC-006", + "FR-006", + "PD-007" + ], + "requiredSkills": [], + "requiredEvidence": [ + "EV006" + ], + "source": "work/coordination-change-risk-mitigation/tasks.yml", + "sourceLocation": { + "line": 6, + "column": 1 + } + }, + { + "id": "T007", + "title": "Implement requirement FR-007", + "status": "done", + "owner": "sdd", + "dependencies": [ + "T004", + "T005", + "T006" + ], + "requirements": [ + "FR-007" + ], + "decisions": [], + "sourceIds": [ + "AC-007", + "FR-007", + "PD-008" + ], + "requiredSkills": [], + "requiredEvidence": [ + "EV007" + ], + "source": "work/coordination-change-risk-mitigation/tasks.yml", + "sourceLocation": { + "line": 7, + "column": 1 + } + }, + { + "id": "T008", + "title": "Implement requirement FR-008", + "status": "done", + "owner": "sdd", + "dependencies": [ + "T007" + ], + "requirements": [ + "FR-008" + ], + "decisions": [], + "sourceIds": [ + "AC-008", + "FR-008", + "PD-009" + ], + "requiredSkills": [], + "requiredEvidence": [ + "EV008" + ], + "source": "work/coordination-change-risk-mitigation/tasks.yml", + "sourceLocation": { + "line": 8, + "column": 1 + } + }, + { + "id": "T009", + "title": "Implement requirement FR-009", + "status": "done", + "owner": "sdd", + "dependencies": [], + "requirements": [ + "FR-009" + ], + "decisions": [], + "sourceIds": [ + "AC-009", + "FR-009", + "PD-001" + ], + "requiredSkills": [], + "requiredEvidence": [ + "EV009" + ], + "source": "work/coordination-change-risk-mitigation/tasks.yml", + "sourceLocation": { + "line": 9, + "column": 1 + } + }, + { + "id": "T010", + "title": "Implement clarification decision DEC-001", + "status": "done", + "owner": "sdd", + "dependencies": [ + "T001" + ], + "requirements": [], + "decisions": [ + "DEC-001" + ], + "sourceIds": [ + "DEC-001" + ], + "requiredSkills": [], + "requiredEvidence": [ + "EV010" + ], + "source": "work/coordination-change-risk-mitigation/tasks.yml", + "sourceLocation": { + "line": 10, + "column": 1 + } + }, + { + "id": "T011", + "title": "Implement clarification decision DEC-002", + "status": "done", + "owner": "sdd", + "dependencies": [ + "T002" + ], + "requirements": [], + "decisions": [ + "DEC-002" + ], + "sourceIds": [ + "DEC-002" + ], + "requiredSkills": [], + "requiredEvidence": [ + "EV011" + ], + "source": "work/coordination-change-risk-mitigation/tasks.yml", + "sourceLocation": { + "line": 11, + "column": 1 + } + }, + { + "id": "T012", + "title": "Implement clarification decision DEC-003", + "status": "done", + "owner": "sdd", + "dependencies": [ + "T005" + ], + "requirements": [], + "decisions": [ + "DEC-003" + ], + "sourceIds": [ + "DEC-003" + ], + "requiredSkills": [], + "requiredEvidence": [ + "EV012" + ], + "source": "work/coordination-change-risk-mitigation/tasks.yml", + "sourceLocation": { + "line": 12, + "column": 1 + } + }, + { + "id": "T013", + "title": "Implement clarification decision DEC-004", + "status": "done", + "owner": "sdd", + "dependencies": [ + "T007" + ], + "requirements": [], + "decisions": [ + "DEC-004" + ], + "sourceIds": [ + "DEC-004" + ], + "requiredSkills": [], + "requiredEvidence": [ + "EV013" + ], + "source": "work/coordination-change-risk-mitigation/tasks.yml", + "sourceLocation": { + "line": 13, + "column": 1 + } + }, + { + "id": "T014", + "title": "Implement clarification decision DEC-005", + "status": "done", + "owner": "sdd", + "dependencies": [ + "T008" + ], + "requirements": [], + "decisions": [ + "DEC-005" + ], + "sourceIds": [ + "DEC-005" + ], + "requiredSkills": [], + "requiredEvidence": [ + "EV014" + ], + "source": "work/coordination-change-risk-mitigation/tasks.yml", + "sourceLocation": { + "line": 14, + "column": 1 + } + }, + { + "id": "T015", + "title": "Update contract surface PC-001", + "status": "done", + "owner": "sdd", + "dependencies": [ + "T001" + ], + "requirements": [], + "decisions": [], + "sourceIds": [ + "PC-001", + "PD-002" + ], + "requiredSkills": [], + "requiredEvidence": [ + "EV015" + ], + "source": "work/coordination-change-risk-mitigation/tasks.yml", + "sourceLocation": { + "line": 15, + "column": 1 + } + }, + { + "id": "T016", + "title": "Update contract surface PC-002", + "status": "done", + "owner": "sdd", + "dependencies": [ + "T002" + ], + "requirements": [], + "decisions": [], + "sourceIds": [ + "PC-002", + "PD-003" + ], + "requiredSkills": [], + "requiredEvidence": [ + "EV016" + ], + "source": "work/coordination-change-risk-mitigation/tasks.yml", + "sourceLocation": { + "line": 16, + "column": 1 + } + }, + { + "id": "T017", + "title": "Update contract surface PC-003", + "status": "done", + "owner": "sdd", + "dependencies": [ + "T003" + ], + "requirements": [], + "decisions": [], + "sourceIds": [ + "PC-003", + "PD-004" + ], + "requiredSkills": [], + "requiredEvidence": [ + "EV017" + ], + "source": "work/coordination-change-risk-mitigation/tasks.yml", + "sourceLocation": { + "line": 17, + "column": 1 + } + }, + { + "id": "T018", + "title": "Update contract surface PC-004", + "status": "done", + "owner": "sdd", + "dependencies": [ + "T004" + ], + "requirements": [], + "decisions": [], + "sourceIds": [ + "PC-004", + "PD-005" + ], + "requiredSkills": [], + "requiredEvidence": [ + "EV018" + ], + "source": "work/coordination-change-risk-mitigation/tasks.yml", + "sourceLocation": { + "line": 18, + "column": 1 + } + }, + { + "id": "T019", + "title": "Update contract surface PC-005", + "status": "done", + "owner": "sdd", + "dependencies": [ + "T005" + ], + "requirements": [], + "decisions": [], + "sourceIds": [ + "PC-005", + "PD-006" + ], + "requiredSkills": [], + "requiredEvidence": [ + "EV019" + ], + "source": "work/coordination-change-risk-mitigation/tasks.yml", + "sourceLocation": { + "line": 19, + "column": 1 + } + }, + { + "id": "T020", + "title": "Update contract surface PC-006", + "status": "done", + "owner": "sdd", + "dependencies": [ + "T006" + ], + "requirements": [], + "decisions": [], + "sourceIds": [ + "PC-006", + "PD-007" + ], + "requiredSkills": [], + "requiredEvidence": [ + "EV020" + ], + "source": "work/coordination-change-risk-mitigation/tasks.yml", + "sourceLocation": { + "line": 20, + "column": 1 + } + }, + { + "id": "T021", + "title": "Update contract surface PC-007", + "status": "done", + "owner": "sdd", + "dependencies": [ + "T007" + ], + "requirements": [], + "decisions": [], + "sourceIds": [ + "PC-007", + "PD-008" + ], + "requiredSkills": [], + "requiredEvidence": [ + "EV021" + ], + "source": "work/coordination-change-risk-mitigation/tasks.yml", + "sourceLocation": { + "line": 21, + "column": 1 + } + }, + { + "id": "T022", + "title": "Record verification evidence VO-001", + "status": "done", + "owner": "sdd", + "dependencies": [ + "T009" + ], + "requirements": [], + "decisions": [], + "sourceIds": [ + "PD-001", + "VO-001" + ], + "requiredSkills": [], + "requiredEvidence": [ + "EV022" + ], + "source": "work/coordination-change-risk-mitigation/tasks.yml", + "sourceLocation": { + "line": 22, + "column": 1 + } + }, + { + "id": "T023", + "title": "Record verification evidence VO-002", + "status": "done", + "owner": "sdd", + "dependencies": [ + "T015" + ], + "requirements": [], + "decisions": [], + "sourceIds": [ + "PC-001", + "PD-002", + "VO-002" + ], + "requiredSkills": [], + "requiredEvidence": [ + "EV023" + ], + "source": "work/coordination-change-risk-mitigation/tasks.yml", + "sourceLocation": { + "line": 23, + "column": 1 + } + }, + { + "id": "T024", + "title": "Record verification evidence VO-003", + "status": "done", + "owner": "sdd", + "dependencies": [ + "T015" + ], + "requirements": [], + "decisions": [], + "sourceIds": [ + "PC-001", + "PD-002", + "VO-003" + ], + "requiredSkills": [], + "requiredEvidence": [ + "EV024" + ], + "source": "work/coordination-change-risk-mitigation/tasks.yml", + "sourceLocation": { + "line": 24, + "column": 1 + } + }, + { + "id": "T025", + "title": "Record verification evidence VO-004", + "status": "done", + "owner": "sdd", + "dependencies": [ + "T016", + "T020" + ], + "requirements": [], + "decisions": [], + "sourceIds": [ + "PC-002", + "PD-003", + "PD-007", + "VO-004" + ], + "requiredSkills": [], + "requiredEvidence": [ + "EV025" + ], + "source": "work/coordination-change-risk-mitigation/tasks.yml", + "sourceLocation": { + "line": 25, + "column": 1 + } + }, + { + "id": "T026", + "title": "Record verification evidence VO-005", + "status": "done", + "owner": "sdd", + "dependencies": [ + "T017" + ], + "requirements": [], + "decisions": [], + "sourceIds": [ + "PC-003", + "PD-004", + "VO-005" + ], + "requiredSkills": [], + "requiredEvidence": [ + "EV026" + ], + "source": "work/coordination-change-risk-mitigation/tasks.yml", + "sourceLocation": { + "line": 26, + "column": 1 + } + }, + { + "id": "T027", + "title": "Record verification evidence VO-006", + "status": "done", + "owner": "sdd", + "dependencies": [ + "T018" + ], + "requirements": [], + "decisions": [], + "sourceIds": [ + "PC-004", + "PD-005", + "VO-006" + ], + "requiredSkills": [], + "requiredEvidence": [ + "EV027" + ], + "source": "work/coordination-change-risk-mitigation/tasks.yml", + "sourceLocation": { + "line": 27, + "column": 1 + } + }, + { + "id": "T028", + "title": "Record verification evidence VO-007", + "status": "done", + "owner": "sdd", + "dependencies": [ + "T019" + ], + "requirements": [], + "decisions": [], + "sourceIds": [ + "PC-005", + "PD-006", + "VO-007" + ], + "requiredSkills": [], + "requiredEvidence": [ + "EV028" + ], + "source": "work/coordination-change-risk-mitigation/tasks.yml", + "sourceLocation": { + "line": 28, + "column": 1 + } + }, + { + "id": "T029", + "title": "Record verification evidence VO-008", + "status": "done", + "owner": "sdd", + "dependencies": [ + "T020" + ], + "requirements": [], + "decisions": [], + "sourceIds": [ + "PC-006", + "PD-007", + "VO-008" + ], + "requiredSkills": [], + "requiredEvidence": [ + "EV029" + ], + "source": "work/coordination-change-risk-mitigation/tasks.yml", + "sourceLocation": { + "line": 29, + "column": 1 + } + }, + { + "id": "T030", + "title": "Record verification evidence VO-009", + "status": "done", + "owner": "sdd", + "dependencies": [ + "T021" + ], + "requirements": [], + "decisions": [], + "sourceIds": [ + "PC-007", + "PD-008", + "VO-009" + ], + "requiredSkills": [], + "requiredEvidence": [ + "EV030" + ], + "source": "work/coordination-change-risk-mitigation/tasks.yml", + "sourceLocation": { + "line": 30, + "column": 1 + } + }, + { + "id": "T031", + "title": "Record verification evidence VO-010", + "status": "done", + "owner": "sdd", + "dependencies": [ + "T008", + "T022", + "T023", + "T024", + "T025", + "T026", + "T027", + "T028", + "T029", + "T030" + ], + "requirements": [], + "decisions": [], + "sourceIds": [ + "PD-009", + "VO-010" + ], + "requiredSkills": [], + "requiredEvidence": [ + "EV031" + ], + "source": "work/coordination-change-risk-mitigation/tasks.yml", + "sourceLocation": { + "line": 31, + "column": 1 + } + }, + { + "id": "T032", + "title": "Handle migration posture PM-001", + "status": "done", + "owner": "sdd", + "dependencies": [ + "T015" + ], + "requirements": [], + "decisions": [], + "sourceIds": [ + "PC-001", + "PM-001" + ], + "requiredSkills": [], + "requiredEvidence": [ + "EV032" + ], + "source": "work/coordination-change-risk-mitigation/tasks.yml", + "sourceLocation": { + "line": 32, + "column": 1 + } + }, + { + "id": "T033", + "title": "Handle migration posture PM-002", + "status": "done", + "owner": "sdd", + "dependencies": [ + "T016" + ], + "requirements": [], + "decisions": [], + "sourceIds": [ + "PC-002", + "PM-002" + ], + "requiredSkills": [], + "requiredEvidence": [ + "EV033" + ], + "source": "work/coordination-change-risk-mitigation/tasks.yml", + "sourceLocation": { + "line": 33, + "column": 1 + } + }, + { + "id": "T034", + "title": "Handle migration posture PM-003", + "status": "done", + "owner": "sdd", + "dependencies": [ + "T017" + ], + "requirements": [], + "decisions": [], + "sourceIds": [ + "PC-003", + "PM-003" + ], + "requiredSkills": [], + "requiredEvidence": [ + "EV034" + ], + "source": "work/coordination-change-risk-mitigation/tasks.yml", + "sourceLocation": { + "line": 34, + "column": 1 + } + }, + { + "id": "T035", + "title": "Handle migration posture PM-004", + "status": "done", + "owner": "sdd", + "dependencies": [ + "T019" + ], + "requirements": [], + "decisions": [], + "sourceIds": [ + "PC-005", + "PM-004" + ], + "requiredSkills": [], + "requiredEvidence": [ + "EV035" + ], + "source": "work/coordination-change-risk-mitigation/tasks.yml", + "sourceLocation": { + "line": 35, + "column": 1 + } + }, + { + "id": "T036", + "title": "Handle migration posture PM-005", + "status": "done", + "owner": "sdd", + "dependencies": [ + "T021" + ], + "requirements": [], + "decisions": [], + "sourceIds": [ + "PC-007", + "PM-005" + ], + "requiredSkills": [], + "requiredEvidence": [ + "EV036" + ], + "source": "work/coordination-change-risk-mitigation/tasks.yml", + "sourceLocation": { + "line": 36, + "column": 1 + } + }, + { + "id": "T037", + "title": "Refresh generated view impact GV-001", + "status": "done", + "owner": "sdd", + "dependencies": [ + "T031" + ], + "requirements": [], + "decisions": [], + "sourceIds": [ + "GV-001", + "PD-001" + ], + "requiredSkills": [], + "requiredEvidence": [ + "EV037" + ], + "source": "work/coordination-change-risk-mitigation/tasks.yml", + "sourceLocation": { + "line": 37, + "column": 1 + } + }, + { + "id": "T038", + "title": "Refresh generated view impact GV-002", + "status": "done", + "owner": "sdd", + "dependencies": [ + "T015" + ], + "requirements": [], + "decisions": [], + "sourceIds": [ + "GV-002", + "PD-002" + ], + "requiredSkills": [], + "requiredEvidence": [ + "EV038" + ], + "source": "work/coordination-change-risk-mitigation/tasks.yml", + "sourceLocation": { + "line": 38, + "column": 1 + } + }, + { + "id": "T039", + "title": "Refresh generated view impact GV-003", + "status": "done", + "owner": "sdd", + "dependencies": [ + "T017" + ], + "requirements": [], + "decisions": [], + "sourceIds": [ + "GV-003", + "PD-004" + ], + "requiredSkills": [], + "requiredEvidence": [ + "EV039" + ], + "source": "work/coordination-change-risk-mitigation/tasks.yml", + "sourceLocation": { + "line": 39, + "column": 1 + } + } + ], + "evidence": [ + { + "id": "EV001", + "kind": "verification", + "subjectType": "task", + "subjectId": "T001", + "taskRefs": [ + "T001" + ], + "requirementRefs": [ + "FR-001" + ], + "artifactRefs": [ + "work/coordination-change-risk-mitigation/artifacts/command-catalogue-boardops.test-report.xml", + "work/coordination-change-risk-mitigation/artifacts/command-catalogue-kernel.test-report.xml" + ], + "result": "pass", + "synthetic": false, + "performanceBudget": null, + "performanceEvidenceArtifact": null, + "performanceMeasurements": [], + "rationale": null, + "source": "work/coordination-change-risk-mitigation/evidence.yml", + "sourceLocation": { + "line": 1, + "column": 1 + } + }, + { + "id": "EV002", + "kind": "verification", + "subjectType": "task", + "subjectId": "T002", + "taskRefs": [ + "T002" + ], + "requirementRefs": [ + "FR-002" + ], + "artifactRefs": [ + "work/coordination-change-risk-mitigation/artifacts/lifecycle-decisions-cli.test-report.xml", + "work/coordination-change-risk-mitigation/artifacts/lifecycle-decisions-core.test-report.xml" + ], + "result": "pass", + "synthetic": false, + "performanceBudget": null, + "performanceEvidenceArtifact": null, + "performanceMeasurements": [], + "rationale": null, + "source": "work/coordination-change-risk-mitigation/evidence.yml", + "sourceLocation": { + "line": 2, + "column": 1 + } + }, + { + "id": "EV003", + "kind": "verification", + "subjectType": "task", + "subjectId": "T003", + "taskRefs": [ + "T003" + ], + "requirementRefs": [ + "FR-003" + ], + "artifactRefs": [ + "work/coordination-change-risk-mitigation/artifacts/completion-receipts-boardops.test-report.xml", + "work/coordination-change-risk-mitigation/artifacts/completion-receipts-cli.test-report.xml", + "work/coordination-change-risk-mitigation/artifacts/completion-receipts-core.test-report.xml", + "work/coordination-change-risk-mitigation/artifacts/completion-receipts-github.test-report.xml", + "work/coordination-change-risk-mitigation/artifacts/completion-receipts-kernel.test-report.xml" + ], + "result": "pass", + "synthetic": false, + "performanceBudget": null, + "performanceEvidenceArtifact": null, + "performanceMeasurements": [], + "rationale": null, + "source": "work/coordination-change-risk-mitigation/evidence.yml", + "sourceLocation": { + "line": 3, + "column": 1 + } + }, + { + "id": "EV004", + "kind": "verification", + "subjectType": "task", + "subjectId": "T004", + "taskRefs": [ + "T004" + ], + "requirementRefs": [ + "FR-004" + ], + "artifactRefs": [ + "work/coordination-change-risk-mitigation/artifacts/self-host-boardops.test-report.xml", + "work/coordination-change-risk-mitigation/artifacts/self-host-cli.test-report.xml", + "work/coordination-change-risk-mitigation/artifacts/self-host-core.test-report.xml", + "work/coordination-change-risk-mitigation/artifacts/self-host-github.test-report.xml", + "work/coordination-change-risk-mitigation/artifacts/self-host-kernel.test-report.xml" + ], + "result": "pass", + "synthetic": false, + "performanceBudget": null, + "performanceEvidenceArtifact": null, + "performanceMeasurements": [], + "rationale": null, + "source": "work/coordination-change-risk-mitigation/evidence.yml", + "sourceLocation": { + "line": 4, + "column": 1 + } + }, + { + "id": "EV005", + "kind": "verification", + "subjectType": "task", + "subjectId": "T005", + "taskRefs": [ + "T005" + ], + "requirementRefs": [ + "FR-005" + ], + "artifactRefs": [ + "work/coordination-change-risk-mitigation/artifacts/change-completeness-boardops.test-report.xml", + "work/coordination-change-risk-mitigation/artifacts/change-completeness-cli.test-report.xml", + "work/coordination-change-risk-mitigation/artifacts/change-completeness-kernel.test-report.xml" + ], + "result": "pass", + "synthetic": false, + "performanceBudget": null, + "performanceEvidenceArtifact": null, + "performanceMeasurements": [], + "rationale": null, + "source": "work/coordination-change-risk-mitigation/evidence.yml", + "sourceLocation": { + "line": 5, + "column": 1 + } + }, + { + "id": "EV006", + "kind": "verification", + "subjectType": "task", + "subjectId": "T006", + "taskRefs": [ + "T006" + ], + "requirementRefs": [ + "FR-006" + ], + "artifactRefs": [ + "work/coordination-change-risk-mitigation/artifacts/lifecycle-model-core.test-report.xml" + ], + "result": "pass", + "synthetic": false, + "performanceBudget": null, + "performanceEvidenceArtifact": null, + "performanceMeasurements": [], + "rationale": null, + "source": "work/coordination-change-risk-mitigation/evidence.yml", + "sourceLocation": { + "line": 6, + "column": 1 + } + }, + { + "id": "EV007", + "kind": "verification", + "subjectType": "task", + "subjectId": "T007", + "taskRefs": [ + "T007" + ], + "requirementRefs": [ + "FR-007" + ], + "artifactRefs": [ + "work/coordination-change-risk-mitigation/artifacts/release-recovery.junit.xml" + ], + "result": "pass", + "synthetic": false, + "performanceBudget": null, + "performanceEvidenceArtifact": null, + "performanceMeasurements": [], + "rationale": null, + "source": "work/coordination-change-risk-mitigation/evidence.yml", + "sourceLocation": { + "line": 7, + "column": 1 + } + }, + { + "id": "EV008", + "kind": "verification", + "subjectType": "task", + "subjectId": "T008", + "taskRefs": [ + "T008" + ], + "requirementRefs": [ + "FR-008" + ], + "artifactRefs": [ + "work/coordination-change-risk-mitigation/artifacts/compatibility-slices.junit.xml" + ], + "result": "pass", + "synthetic": false, + "performanceBudget": null, + "performanceEvidenceArtifact": null, + "performanceMeasurements": [], + "rationale": null, + "source": "work/coordination-change-risk-mitigation/evidence.yml", + "sourceLocation": { + "line": 8, + "column": 1 + } + }, + { + "id": "EV009", + "kind": "verification", + "subjectType": "task", + "subjectId": "T009", + "taskRefs": [ + "T009" + ], + "requirementRefs": [ + "FR-009" + ], + "artifactRefs": [ + "work/coordination-change-risk-mitigation/phase-0-baseline.json", + "work/coordination-change-risk-mitigation/phase-0-baseline.md" + ], + "result": "pass", + "synthetic": false, + "performanceBudget": null, + "performanceEvidenceArtifact": null, + "performanceMeasurements": [], + "rationale": null, + "source": "work/coordination-change-risk-mitigation/evidence.yml", + "sourceLocation": { + "line": 9, + "column": 1 + } + }, + { + "id": "EV010", + "kind": "verification", + "subjectType": "task", + "subjectId": "T010", + "taskRefs": [ + "T010" + ], + "requirementRefs": [], + "artifactRefs": [ + "work/coordination-change-risk-mitigation/artifacts/command-catalogue-boardops.test-report.xml" + ], + "result": "pass", + "synthetic": false, + "performanceBudget": null, + "performanceEvidenceArtifact": null, + "performanceMeasurements": [], + "rationale": null, + "source": "work/coordination-change-risk-mitigation/evidence.yml", + "sourceLocation": { + "line": 10, + "column": 1 + } + }, + { + "id": "EV011", + "kind": "verification", + "subjectType": "task", + "subjectId": "T011", + "taskRefs": [ + "T011" + ], + "requirementRefs": [], + "artifactRefs": [ + "work/coordination-change-risk-mitigation/artifacts/compatibility-slices.junit.xml" + ], + "result": "pass", + "synthetic": false, + "performanceBudget": null, + "performanceEvidenceArtifact": null, + "performanceMeasurements": [], + "rationale": null, + "source": "work/coordination-change-risk-mitigation/evidence.yml", + "sourceLocation": { + "line": 11, + "column": 1 + } + }, + { + "id": "EV012", + "kind": "verification", + "subjectType": "task", + "subjectId": "T012", + "taskRefs": [ + "T012" + ], + "requirementRefs": [], + "artifactRefs": [ + "work/coordination-change-risk-mitigation/artifacts/compatibility-slices.junit.xml" + ], + "result": "pass", + "synthetic": false, + "performanceBudget": null, + "performanceEvidenceArtifact": null, + "performanceMeasurements": [], + "rationale": null, + "source": "work/coordination-change-risk-mitigation/evidence.yml", + "sourceLocation": { + "line": 12, + "column": 1 + } + }, + { + "id": "EV013", + "kind": "verification", + "subjectType": "task", + "subjectId": "T013", + "taskRefs": [ + "T013" + ], + "requirementRefs": [], + "artifactRefs": [ + "work/coordination-change-risk-mitigation/artifacts/compatibility-slices.junit.xml" + ], + "result": "pass", + "synthetic": false, + "performanceBudget": null, + "performanceEvidenceArtifact": null, + "performanceMeasurements": [], + "rationale": null, + "source": "work/coordination-change-risk-mitigation/evidence.yml", + "sourceLocation": { + "line": 13, + "column": 1 + } + }, + { + "id": "EV014", + "kind": "verification", + "subjectType": "task", + "subjectId": "T014", + "taskRefs": [ + "T014" + ], + "requirementRefs": [], + "artifactRefs": [ + "work/coordination-change-risk-mitigation/artifacts/compatibility-slices.junit.xml" + ], + "result": "pass", + "synthetic": false, + "performanceBudget": null, + "performanceEvidenceArtifact": null, + "performanceMeasurements": [], + "rationale": null, + "source": "work/coordination-change-risk-mitigation/evidence.yml", + "sourceLocation": { + "line": 14, + "column": 1 + } + }, + { + "id": "EV015", + "kind": "verification", + "subjectType": "task", + "subjectId": "T015", + "taskRefs": [ + "T015" + ], + "requirementRefs": [], + "artifactRefs": [ + "work/coordination-change-risk-mitigation/artifacts/command-catalogue-boardops.test-report.xml" + ], + "result": "pass", + "synthetic": false, + "performanceBudget": null, + "performanceEvidenceArtifact": null, + "performanceMeasurements": [], + "rationale": null, + "source": "work/coordination-change-risk-mitigation/evidence.yml", + "sourceLocation": { + "line": 15, + "column": 1 + } + }, + { + "id": "EV016", + "kind": "verification", + "subjectType": "task", + "subjectId": "T016", + "taskRefs": [ + "T016" + ], + "requirementRefs": [], + "artifactRefs": [ + "work/coordination-change-risk-mitigation/artifacts/compatibility-slices.junit.xml" + ], + "result": "pass", + "synthetic": false, + "performanceBudget": null, + "performanceEvidenceArtifact": null, + "performanceMeasurements": [], + "rationale": null, + "source": "work/coordination-change-risk-mitigation/evidence.yml", + "sourceLocation": { + "line": 16, + "column": 1 + } + }, + { + "id": "EV017", + "kind": "verification", + "subjectType": "task", + "subjectId": "T017", + "taskRefs": [ + "T017" + ], + "requirementRefs": [], + "artifactRefs": [ + "work/coordination-change-risk-mitigation/artifacts/compatibility-slices.junit.xml" + ], + "result": "pass", + "synthetic": false, + "performanceBudget": null, + "performanceEvidenceArtifact": null, + "performanceMeasurements": [], + "rationale": null, + "source": "work/coordination-change-risk-mitigation/evidence.yml", + "sourceLocation": { + "line": 17, + "column": 1 + } + }, + { + "id": "EV018", + "kind": "verification", + "subjectType": "task", + "subjectId": "T018", + "taskRefs": [ + "T018" + ], + "requirementRefs": [], + "artifactRefs": [ + "work/coordination-change-risk-mitigation/artifacts/compatibility-slices.junit.xml" + ], + "result": "pass", + "synthetic": false, + "performanceBudget": null, + "performanceEvidenceArtifact": null, + "performanceMeasurements": [], + "rationale": null, + "source": "work/coordination-change-risk-mitigation/evidence.yml", + "sourceLocation": { + "line": 18, + "column": 1 + } + }, + { + "id": "EV019", + "kind": "verification", + "subjectType": "task", + "subjectId": "T019", + "taskRefs": [ + "T019" + ], + "requirementRefs": [], + "artifactRefs": [ + "work/coordination-change-risk-mitigation/artifacts/compatibility-slices.junit.xml" + ], + "result": "pass", + "synthetic": false, + "performanceBudget": null, + "performanceEvidenceArtifact": null, + "performanceMeasurements": [], + "rationale": null, + "source": "work/coordination-change-risk-mitigation/evidence.yml", + "sourceLocation": { + "line": 19, + "column": 1 + } + }, + { + "id": "EV020", + "kind": "verification", + "subjectType": "task", + "subjectId": "T020", + "taskRefs": [ + "T020" + ], + "requirementRefs": [], + "artifactRefs": [ + "work/coordination-change-risk-mitigation/artifacts/compatibility-slices.junit.xml" + ], + "result": "pass", + "synthetic": false, + "performanceBudget": null, + "performanceEvidenceArtifact": null, + "performanceMeasurements": [], + "rationale": null, + "source": "work/coordination-change-risk-mitigation/evidence.yml", + "sourceLocation": { + "line": 20, + "column": 1 + } + }, + { + "id": "EV021", + "kind": "verification", + "subjectType": "task", + "subjectId": "T021", + "taskRefs": [ + "T021" + ], + "requirementRefs": [], + "artifactRefs": [ + "work/coordination-change-risk-mitigation/artifacts/compatibility-slices.junit.xml" + ], + "result": "pass", + "synthetic": false, + "performanceBudget": null, + "performanceEvidenceArtifact": null, + "performanceMeasurements": [], + "rationale": null, + "source": "work/coordination-change-risk-mitigation/evidence.yml", + "sourceLocation": { + "line": 21, + "column": 1 + } + }, + { + "id": "EV022", + "kind": "verification", + "subjectType": "task", + "subjectId": "T022", + "taskRefs": [ + "T022" + ], + "requirementRefs": [], + "artifactRefs": [ + "work/coordination-change-risk-mitigation/artifacts/compatibility-slices.junit.xml" + ], + "result": "pass", + "synthetic": false, + "performanceBudget": null, + "performanceEvidenceArtifact": null, + "performanceMeasurements": [], + "rationale": null, + "source": "work/coordination-change-risk-mitigation/evidence.yml", + "sourceLocation": { + "line": 22, + "column": 1 + } + }, + { + "id": "EV023", + "kind": "verification", + "subjectType": "task", + "subjectId": "T023", + "taskRefs": [ + "T023" + ], + "requirementRefs": [], + "artifactRefs": [ + "work/coordination-change-risk-mitigation/artifacts/command-catalogue-kernel.test-report.xml" + ], + "result": "pass", + "synthetic": false, + "performanceBudget": null, + "performanceEvidenceArtifact": null, + "performanceMeasurements": [], + "rationale": null, + "source": "work/coordination-change-risk-mitigation/evidence.yml", + "sourceLocation": { + "line": 23, + "column": 1 + } + }, + { + "id": "EV024", + "kind": "verification", + "subjectType": "task", + "subjectId": "T024", + "taskRefs": [ + "T024" + ], + "requirementRefs": [], + "artifactRefs": [ + "work/coordination-change-risk-mitigation/artifacts/compatibility-slices.junit.xml" + ], + "result": "pass", + "synthetic": false, + "performanceBudget": null, + "performanceEvidenceArtifact": null, + "performanceMeasurements": [], + "rationale": null, + "source": "work/coordination-change-risk-mitigation/evidence.yml", + "sourceLocation": { + "line": 24, + "column": 1 + } + }, + { + "id": "EV025", + "kind": "verification", + "subjectType": "task", + "subjectId": "T025", + "taskRefs": [ + "T025" + ], + "requirementRefs": [], + "artifactRefs": [ + "work/coordination-change-risk-mitigation/artifacts/compatibility-slices.junit.xml" + ], + "result": "pass", + "synthetic": false, + "performanceBudget": null, + "performanceEvidenceArtifact": null, + "performanceMeasurements": [], + "rationale": null, + "source": "work/coordination-change-risk-mitigation/evidence.yml", + "sourceLocation": { + "line": 25, + "column": 1 + } + }, + { + "id": "EV026", + "kind": "verification", + "subjectType": "task", + "subjectId": "T026", + "taskRefs": [ + "T026" + ], + "requirementRefs": [], + "artifactRefs": [ + "work/coordination-change-risk-mitigation/artifacts/compatibility-slices.junit.xml" + ], + "result": "pass", + "synthetic": false, + "performanceBudget": null, + "performanceEvidenceArtifact": null, + "performanceMeasurements": [], + "rationale": null, + "source": "work/coordination-change-risk-mitigation/evidence.yml", + "sourceLocation": { + "line": 26, + "column": 1 + } + }, + { + "id": "EV027", + "kind": "verification", + "subjectType": "task", + "subjectId": "T027", + "taskRefs": [ + "T027" + ], + "requirementRefs": [], + "artifactRefs": [ + "work/coordination-change-risk-mitigation/artifacts/compatibility-slices.junit.xml" + ], + "result": "pass", + "synthetic": false, + "performanceBudget": null, + "performanceEvidenceArtifact": null, + "performanceMeasurements": [], + "rationale": null, + "source": "work/coordination-change-risk-mitigation/evidence.yml", + "sourceLocation": { + "line": 27, + "column": 1 + } + }, + { + "id": "EV028", + "kind": "verification", + "subjectType": "task", + "subjectId": "T028", + "taskRefs": [ + "T028" + ], + "requirementRefs": [], + "artifactRefs": [ + "work/coordination-change-risk-mitigation/artifacts/compatibility-slices.junit.xml" + ], + "result": "pass", + "synthetic": false, + "performanceBudget": null, + "performanceEvidenceArtifact": null, + "performanceMeasurements": [], + "rationale": null, + "source": "work/coordination-change-risk-mitigation/evidence.yml", + "sourceLocation": { + "line": 28, + "column": 1 + } + }, + { + "id": "EV029", + "kind": "verification", + "subjectType": "task", + "subjectId": "T029", + "taskRefs": [ + "T029" + ], + "requirementRefs": [], + "artifactRefs": [ + "work/coordination-change-risk-mitigation/artifacts/compatibility-slices.junit.xml" + ], + "result": "pass", + "synthetic": false, + "performanceBudget": null, + "performanceEvidenceArtifact": null, + "performanceMeasurements": [], + "rationale": null, + "source": "work/coordination-change-risk-mitigation/evidence.yml", + "sourceLocation": { + "line": 29, + "column": 1 + } + }, + { + "id": "EV030", + "kind": "verification", + "subjectType": "task", + "subjectId": "T030", + "taskRefs": [ + "T030" + ], + "requirementRefs": [], + "artifactRefs": [ + "work/coordination-change-risk-mitigation/artifacts/compatibility-slices.junit.xml" + ], + "result": "pass", + "synthetic": false, + "performanceBudget": null, + "performanceEvidenceArtifact": null, + "performanceMeasurements": [], + "rationale": null, + "source": "work/coordination-change-risk-mitigation/evidence.yml", + "sourceLocation": { + "line": 30, + "column": 1 + } + }, + { + "id": "EV031", + "kind": "verification", + "subjectType": "task", + "subjectId": "T031", + "taskRefs": [ + "T031" + ], + "requirementRefs": [], + "artifactRefs": [ + "work/coordination-change-risk-mitigation/artifacts/compatibility-slices.junit.xml" + ], + "result": "pass", + "synthetic": false, + "performanceBudget": null, + "performanceEvidenceArtifact": null, + "performanceMeasurements": [], + "rationale": null, + "source": "work/coordination-change-risk-mitigation/evidence.yml", + "sourceLocation": { + "line": 31, + "column": 1 + } + }, + { + "id": "EV032", + "kind": "verification", + "subjectType": "task", + "subjectId": "T032", + "taskRefs": [ + "T032" + ], + "requirementRefs": [], + "artifactRefs": [ + "work/coordination-change-risk-mitigation/artifacts/command-catalogue-boardops.test-report.xml" + ], + "result": "pass", + "synthetic": false, + "performanceBudget": null, + "performanceEvidenceArtifact": null, + "performanceMeasurements": [], + "rationale": null, + "source": "work/coordination-change-risk-mitigation/evidence.yml", + "sourceLocation": { + "line": 32, + "column": 1 + } + }, + { + "id": "EV033", + "kind": "verification", + "subjectType": "task", + "subjectId": "T033", + "taskRefs": [ + "T033" + ], + "requirementRefs": [], + "artifactRefs": [ + "work/coordination-change-risk-mitigation/artifacts/compatibility-slices.junit.xml" + ], + "result": "pass", + "synthetic": false, + "performanceBudget": null, + "performanceEvidenceArtifact": null, + "performanceMeasurements": [], + "rationale": null, + "source": "work/coordination-change-risk-mitigation/evidence.yml", + "sourceLocation": { + "line": 33, + "column": 1 + } + }, + { + "id": "EV034", + "kind": "verification", + "subjectType": "task", + "subjectId": "T034", + "taskRefs": [ + "T034" + ], + "requirementRefs": [], + "artifactRefs": [ + "work/coordination-change-risk-mitigation/artifacts/compatibility-slices.junit.xml" + ], + "result": "pass", + "synthetic": false, + "performanceBudget": null, + "performanceEvidenceArtifact": null, + "performanceMeasurements": [], + "rationale": null, + "source": "work/coordination-change-risk-mitigation/evidence.yml", + "sourceLocation": { + "line": 34, + "column": 1 + } + }, + { + "id": "EV035", + "kind": "verification", + "subjectType": "task", + "subjectId": "T035", + "taskRefs": [ + "T035" + ], + "requirementRefs": [], + "artifactRefs": [ + "work/coordination-change-risk-mitigation/artifacts/compatibility-slices.junit.xml" + ], + "result": "pass", + "synthetic": false, + "performanceBudget": null, + "performanceEvidenceArtifact": null, + "performanceMeasurements": [], + "rationale": null, + "source": "work/coordination-change-risk-mitigation/evidence.yml", + "sourceLocation": { + "line": 35, + "column": 1 + } + }, + { + "id": "EV036", + "kind": "verification", + "subjectType": "task", + "subjectId": "T036", + "taskRefs": [ + "T036" + ], + "requirementRefs": [], + "artifactRefs": [ + "work/coordination-change-risk-mitigation/artifacts/compatibility-slices.junit.xml" + ], + "result": "pass", + "synthetic": false, + "performanceBudget": null, + "performanceEvidenceArtifact": null, + "performanceMeasurements": [], + "rationale": null, + "source": "work/coordination-change-risk-mitigation/evidence.yml", + "sourceLocation": { + "line": 36, + "column": 1 + } + }, + { + "id": "EV037", + "kind": "verification", + "subjectType": "task", + "subjectId": "T037", + "taskRefs": [ + "T037" + ], + "requirementRefs": [], + "artifactRefs": [ + "work/coordination-change-risk-mitigation/artifacts/compatibility-slices.junit.xml" + ], + "result": "pass", + "synthetic": false, + "performanceBudget": null, + "performanceEvidenceArtifact": null, + "performanceMeasurements": [], + "rationale": null, + "source": "work/coordination-change-risk-mitigation/evidence.yml", + "sourceLocation": { + "line": 37, + "column": 1 + } + }, + { + "id": "EV038", + "kind": "verification", + "subjectType": "task", + "subjectId": "T038", + "taskRefs": [ + "T038" + ], + "requirementRefs": [], + "artifactRefs": [ + "work/coordination-change-risk-mitigation/artifacts/command-catalogue-kernel.test-report.xml" + ], + "result": "pass", + "synthetic": false, + "performanceBudget": null, + "performanceEvidenceArtifact": null, + "performanceMeasurements": [], + "rationale": null, + "source": "work/coordination-change-risk-mitigation/evidence.yml", + "sourceLocation": { + "line": 38, + "column": 1 + } + }, + { + "id": "EV039", + "kind": "verification", + "subjectType": "task", + "subjectId": "T039", + "taskRefs": [ + "T039" + ], + "requirementRefs": [], + "artifactRefs": [ + "work/coordination-change-risk-mitigation/artifacts/compatibility-slices.junit.xml" + ], + "result": "pass", + "synthetic": false, + "performanceBudget": null, + "performanceEvidenceArtifact": null, + "performanceMeasurements": [], + "rationale": null, + "source": "work/coordination-change-risk-mitigation/evidence.yml", + "sourceLocation": { + "line": 39, + "column": 1 + } + } + ], + "generatedViews": [ + { + "path": "readiness/coordination-change-risk-mitigation/work-model.json", + "kind": "workModel", + "schemaVersion": 1, + "generator": { + "id": "FS.GG.SDD.Artifacts", + "version": "1.1.0" + }, + "sources": [ + { + "path": ".fsgg/agents.yml", + "digest": { + "algorithm": "sha256", + "value": "c67035b1cf31b6fa802c10f761eeb1e5bf5d198c38d159b54fac299957b5aac3" + }, + "schemaVersion": 1 + }, + { + "path": ".fsgg/project.yml", + "digest": { + "algorithm": "sha256", + "value": "ef78f002b33ce22f738bac2c0dbf716db729a7d3ae3e4a68a4ce4b93810ced66" + }, + "schemaVersion": 1 + }, + { + "path": ".fsgg/sdd.yml", + "digest": { + "algorithm": "sha256", + "value": "fe5a7c270a975153e80ab0d08a610c9b302585dcb0b5f7c654841ceced9272cb" + }, + "schemaVersion": 1 + }, + { + "path": "work/coordination-change-risk-mitigation/checklist.md", + "digest": { + "algorithm": "sha256", + "value": "ac1c0ac8b8feafbedd9582ac17b8196e57b46867459a31c380cbb83e0a342548" + }, + "schemaVersion": 1 + }, + { + "path": "work/coordination-change-risk-mitigation/clarifications.md", + "digest": { + "algorithm": "sha256", + "value": "02eedf550b282d9788487b3efbd6f0034d35e5982b70dcf8abf01bd6fa61b18c" + }, + "schemaVersion": 1 + }, + { + "path": "work/coordination-change-risk-mitigation/evidence.yml", + "digest": { + "algorithm": "sha256", + "value": "4f56b80be2007d2e7048e262eb370fdda44619d11da81e75d319e8ac948b45f3" + }, + "schemaVersion": 1 + }, + { + "path": "work/coordination-change-risk-mitigation/plan.md", + "digest": { + "algorithm": "sha256", + "value": "6ac822bae2e476fadcadf67890e437775bafd311f11baf6574cc70c48e1dcab6" + }, + "schemaVersion": 1 + }, + { + "path": "work/coordination-change-risk-mitigation/spec.md", + "digest": { + "algorithm": "sha256", + "value": "596003775028144db71fd9a411385e205ed07488ee164d79471c153bb0ec084e" + }, + "schemaVersion": 1 + }, + { + "path": "work/coordination-change-risk-mitigation/tasks.yml", + "digest": { + "algorithm": "sha256", + "value": "d18dc3eacc78599e0cdcf030e8a8d74c324bb10d35788702e44e3781c5b6083c" + }, + "schemaVersion": 1 + } + ], + "outputDigest": { + "algorithm": "sha256", + "value": "13c832bd909b456434d193bc713829f24830cf8aa55b7e0326628fcd00765ed5" + }, + "currency": "current" + } + ], + "diagnostics": [], + "governanceBoundaries": [] +} \ No newline at end of file diff --git a/registry/coordination-kit-skill-manifest.json b/registry/coordination-kit-skill-manifest.json index 593e4e5da..e8b6b0dc2 100644 --- a/registry/coordination-kit-skill-manifest.json +++ b/registry/coordination-kit-skill-manifest.json @@ -4,7 +4,7 @@ { "id": "check-board", "supplied-by": ".claude/skills/check-board", - "tree-sha256": "b3bfbae182a239daa664a0dddbd82cc364259ebfd173cafad98f869182014076", + "tree-sha256": "98acb5ebab5fc2571a1288596c167c11121fed19487567d55c5d52b4a0af7981", "files": [ { "path": "SKILL.md", @@ -18,7 +18,7 @@ }, { "path": "references/deep-detail.md", - "sha256": "9fdd58ac68000634bc142cee0e8db3df6500c066b32ce4742c1844d95e7012ab", + "sha256": "a9cb0df37ef8d3fc833fe48668160adc075f72a9ce6f79dc6d82afaa1713319f", "executable": false }, { @@ -41,7 +41,7 @@ { "id": "cross-repo-coordination", "supplied-by": ".claude/skills/cross-repo-coordination", - "tree-sha256": "7348ca0437d9ed5dbba07ce9b8b5ac1bb2459af7207204c341edc778e434af04", + "tree-sha256": "ca9695e217787ebbe41a7358b11517d0558f5789566a807adca1e8e40593b1df", "files": [ { "path": "SKILL.md", @@ -65,7 +65,7 @@ }, { "path": "references/deep-detail.md", - "sha256": "caee8be9719ce47fee9f13e029eb1602f431c77864b7cf5d7b69be320a01b312", + "sha256": "8abacbde875b85460b84c60bcfacd13e4713124b4514475d0275e719d88637b0", "executable": false }, { @@ -78,7 +78,7 @@ { "id": "intra-repo-parallel-work", "supplied-by": ".claude/skills/intra-repo-parallel-work", - "tree-sha256": "9f32dad0c6de46c0202416ad6c28241513aff4b63569662d2e8886e4a2a126f8", + "tree-sha256": "307b71bda594bc3adf329dcfba06ac90bd994b4a65938eff483f0382b8708cf8", "files": [ { "path": "SKILL.md", @@ -92,7 +92,7 @@ }, { "path": "references/deep-detail.md", - "sha256": "d00f705c8466f7458fc5a57b4dc018eff9edc92cfc473405d3c6771348871803", + "sha256": "8a5a59968fd1fc12aa6c39c9a5fe35ed193bb604019b642bd14d54a78d120d15", "executable": false }, { @@ -110,11 +110,11 @@ { "id": "pnext-item", "supplied-by": ".claude/skills/pnext-item", - "tree-sha256": "289ccca96d32d33d56c06127ad4c752f0b5390e174b662d62b14bb7bd29b399e", + "tree-sha256": "94ac7f30ba3320f67799888fe262d9cfe72514540b228a4214f539c924943145", "files": [ { "path": "SKILL.md", - "sha256": "c62d6c60fc89137c294b629f11094f315179a9ac3371d9ccb6928aef984ccc7c", + "sha256": "44c2aacecbdbbb4f80f7b2f07379ec6ee38502ac84b5c991ea472b09baba29f3", "executable": false }, { @@ -124,7 +124,7 @@ }, { "path": "references/command-contracts.md", - "sha256": "d54062fbe47b63ad4a77880dde07bd38ac05385b51b888dfe7060de948c74bb8", + "sha256": "4443e2fd1d2370c77c43059c681732be9fc235774bc2f79772e26bb0070a9e38", "executable": false }, { @@ -134,7 +134,7 @@ }, { "path": "references/deep-detail.md", - "sha256": "73d5872566d414631eb7c7ae924be2361251da165e0b276cb74c234e524d09d4", + "sha256": "58bfd1748065eeb84ea6f2695cf5656a3c6d2486eec1b90012da12b7eb252ff7", "executable": false }, { diff --git a/registry/repos.lock b/registry/repos.lock index d7f861efd..a157171f3 100644 --- a/registry/repos.lock +++ b/registry/repos.lock @@ -9,8 +9,8 @@ f7de20e04981ed72ce6bfe886a1776adb78b3926c2a83f315069a3ce8e4fa3f3 .claude/skills/check-board bc040e2ba93b490a31f868497e46eeb2c6a2eea6f27a3fc90bb21361887aefe0 .claude/skills/cross-repo-coordination 7bee25b83b422cf0654178a741de4e90a424c24931ae119004843c5fc74b784f .claude/skills/intra-repo-parallel-work -c62d6c60fc89137c294b629f11094f315179a9ac3371d9ccb6928aef984ccc7c .claude/skills/pnext-item -00b0cb9f002817679620078ab19c3e58f392b5bef115c04971545f3360ec1ea4 scripts/fsgg-coord +44c2aacecbdbbb4f80f7b2f07379ec6ee38502ac84b5c991ea472b09baba29f3 .claude/skills/pnext-item +d8a2c754a16bc298843297dc0b6cc49e7d2502446d9d4a9880bee7aabb2b34f3 scripts/fsgg-coord e1f63cda5b499f4fdd4396626c0bac013c49019daf182336df8c7513d24918ba scripts/fsgg-coord-report 1f2a70607268d549aa59c56e612e654e52021e9b7015e26c8fdaa97a4a3a869e scripts/lib/args.sh fbdedf5e5bb4f85ef048807a430218001f489172210f87acd9bf8b3fbbca0330 scripts/lib/roots.sh diff --git a/scripts/change-completeness b/scripts/change-completeness new file mode 100755 index 000000000..5d885bcb2 --- /dev/null +++ b/scripts/change-completeness @@ -0,0 +1,79 @@ +#!/usr/bin/env bash +set -euo pipefail + +ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +BASE="" +HEAD="HEAD" +PATHS_FILE="" +PR_BODY="" +OUTPUT_FILE="" + +while [ "$#" -gt 0 ]; do + case "$1" in + --base) BASE="${2:?--base needs a revision}"; shift 2 ;; + --head) HEAD="${2:?--head needs a revision}"; shift 2 ;; + --paths-file) PATHS_FILE="${2:?--paths-file needs a path}"; shift 2 ;; + --pr-body) PR_BODY="${2:?--pr-body needs a path}"; shift 2 ;; + --github-output) OUTPUT_FILE="${2:?--github-output needs a path}"; shift 2 ;; + *) echo "change-completeness: unknown argument: $1" >&2; exit 2 ;; + esac +done + +WORK="$(mktemp -d)" +trap 'rm -rf "$WORK"' EXIT +PATHS="$WORK/paths" + +if [ -n "$PATHS_FILE" ]; then + cp "$PATHS_FILE" "$PATHS" +else + [ -n "$BASE" ] || { echo "change-completeness: --base is required when --paths-file is absent" >&2; exit 2; } + git -C "$ROOT" cat-file -e "$BASE^{commit}" 2>/dev/null \ + || { echo "change-completeness: base revision is unavailable: $BASE" >&2; exit 1; } + git -C "$ROOT" cat-file -e "$HEAD^{commit}" 2>/dev/null \ + || { echo "change-completeness: head revision is unavailable: $HEAD" >&2; exit 1; } + git -C "$ROOT" diff --name-only --find-renames "$BASE" "$HEAD" >"$PATHS" +fi + +engine_changed=false +if grep -Eq '^(src/FS\.GG\.Coord\.|tests/FS\.GG\.Coord\.|tests/(m6-decision-cutover|delivery-leading-line|coord-engine-|review-critic-succession-wire|ci-runtime-optimization|change-completeness|change-risk-compatibility)/|scripts/(fsgg-coord|fsgg-coord-guards\.sh|record-board-fixture\.py|read-trx-count\.py|change-completeness)|Directory\.(Build|Packages)|dist/dotnet/Directory\.Build\.props|global\.json|\.github/workflows/coord-engine\.yml)' "$PATHS"; then + engine_changed=true +fi +[ -z "$OUTPUT_FILE" ] || printf 'engine_changed=%s\n' "$engine_changed" >>"$OUTPUT_FILE" + +stage() { printf '\nchange-completeness: %s\n' "$1"; } + +stage "closing-keyword and commit-message contract" +if [ -n "$PR_BODY" ]; then + [ -f "$PR_BODY" ] || { echo "change-completeness: PR body file is unavailable" >&2; exit 1; } + git -C "$ROOT" log --format=%B "$BASE".."$HEAD" >"$WORK/commits.txt" + [ -s "$WORK/commits.txt" ] || { echo "change-completeness: commit-message subject is empty" >&2; exit 1; } + python3 "$ROOT/scripts/check-closing-keywords.py" --body "$PR_BODY" --commits "$WORK/commits.txt" +else + echo "change-completeness: non-PR invocation; no PR body subject" +fi + +stage "SDD ship-verdict provenance" +python3 "$ROOT/scripts/check-ship-verdict-provenance.py" --root "$ROOT" + +if [ "$engine_changed" = true ]; then + stage "locked restore and affected-engine compile" + dotnet restore "$ROOT/tests/FS.GG.Coord.Cli.Kernel.Tests/FS.GG.Coord.Cli.Kernel.Tests.fsproj" --locked-mode + dotnet restore "$ROOT/tests/FS.GG.Coord.Cli.Tests/FS.GG.Coord.Cli.Tests.fsproj" --locked-mode + dotnet restore "$ROOT/tests/FS.GG.Coord.Cli.BoardOps.Tests/FS.GG.Coord.Cli.BoardOps.Tests.fsproj" --locked-mode + + stage "command catalogue, parser, render, write-ness, contract, and help closure" + dotnet test "$ROOT/tests/FS.GG.Coord.Cli.Kernel.Tests/FS.GG.Coord.Cli.Kernel.Tests.fsproj" \ + -c Release --no-restore --filter FullyQualifiedName~CommandSurfaceTests + + stage "handler ownership and production registration" + dotnet test "$ROOT/tests/FS.GG.Coord.Cli.BoardOps.Tests/FS.GG.Coord.Cli.BoardOps.Tests.fsproj" \ + -c Release --no-restore --filter FullyQualifiedName~HandlerRegistrationTests + + stage "delivery, review, declared-path, and focused production-route parity" + dotnet test "$ROOT/tests/FS.GG.Coord.Cli.Tests/FS.GG.Coord.Cli.Tests.fsproj" -c Release --no-restore \ + --filter 'FullyQualifiedName~DeliveryApplicationTests|FullyQualifiedName~ReviewApplicationTests|FullyQualifiedName~VerifyPaths' +else + stage "affected-engine checks omitted: no engine decision boundary changed" +fi + +echo "change-completeness: PASS" diff --git a/scripts/check-paths-coherence.py b/scripts/check-paths-coherence.py index f972c1ea0..66bef365d 100755 --- a/scripts/check-paths-coherence.py +++ b/scripts/check-paths-coherence.py @@ -818,6 +818,28 @@ def note(entry: str, cause: str, trigger: str, verb: str) -> None: f"and a silent skip is how a coherence gate fails open (#266). Refusing to guess." ) + # An unfiltered trigger facing a filtered sibling is a deliberate divergence only when a + # signed marker says why. This is distinct from a genuinely one-sided workflow: both events + # exist, but one must report for every change while the other remains path-sensitive. + reason = allow_divergence(text, where) + if ("pull_request" in on and "push" in on + and ((pr_raw is None) != (push_raw is None)) and reason is not None): + pairs_seen += 1 + if reason == UNSIGNED: + findings.append( + f"{where}: carries `# paths-coherence: allow-divergence` with NO reason. " + "An unfiltered/filtered trigger split must record why it is intentional." + ) + elif reason: + allowed += 1 + print(f" allow {where:<43} one trigger is intentionally unfiltered: {reason}") + else: + findings.append( + f"{where}: one of `pull_request`/`push` is unfiltered while the other declares " + "`paths:`. Sign the intentional split with `# paths-coherence: allow-divergence — `." + ) + continue + # One-sided is a deliberate shape (`build-config-propagate.yml` is push-only, # `reusable-job-id-coherence.yml` is PR-only) and is not this gate's business. if pr_raw is None or push_raw is None: @@ -876,8 +898,8 @@ def note(entry: str, cause: str, trigger: str, verb: str) -> None: # printing green about nothing. if pairs_seen == 0: raise GateError( - "audited every workflow and found NO workflow declaring both `pull_request.paths` and " - "`push.paths`. This repo HAS them, so the trigger reader is broken — examining nothing " + "audited every workflow and found NO comparable or signed-divergent `pull_request`/`push` " + "trigger pair. This repo HAS them, so the trigger reader is broken — examining nothing " "is a failure to audit, not a clean audit (#266)." ) diff --git a/scripts/dashboard-tick.py b/scripts/dashboard-tick.py index 206a11d30..1b53f133e 100755 --- a/scripts/dashboard-tick.py +++ b/scripts/dashboard-tick.py @@ -407,6 +407,45 @@ def annotate(level: str, message: str) -> None: print(f"::{level}::dashboard-tick: {message}") +def receiver_receipt( + journal: str | None, + receipt_dir: str | None, + package: str, + version: str, + repo: str, + dashboard: int, + outcome: str, +) -> tuple[bool, str]: + if journal is None and receipt_dir is None: + return True, "" + if journal is None or receipt_dir is None: + return False, "--journal and --receipt-dir must be supplied together" + target_dir = Path(receipt_dir).resolve() + target_dir.mkdir(parents=True, exist_ok=True) + safe = re.sub(r"[^A-Za-z0-9_.-]", "_", f"{package}-{repo}") + output = target_dir / f"receiver-{safe}.json" + tool = Path(__file__).resolve().with_name("release-saga.py") + command = [ + sys.executable, + str(tool), + "receiver-receipt", + "--manifest", + journal, + "--package", + package, + "--receiver", + repo, + "--detail", + f"Dependency Dashboard #{dashboard}: {outcome}", + "--output", + str(output), + ] + completed = subprocess.run(command, capture_output=True, text=True) + if completed.returncode != 0: + return False, completed.stderr.strip() or "receiver receipt command failed without a diagnostic" + return True, "" + + def run_probe(registry: str | None) -> int: reached, undetermined, refused = [], [], [] for repo in receivers(registry): @@ -445,7 +484,14 @@ def run_probe(registry: str | None) -> int: return 0 -def run_tick(package: str, version: str, registry: str | None, dry_run: bool) -> int: +def run_tick( + package: str, + version: str, + registry: str | None, + dry_run: bool, + journal: str | None, + receipt_dir: str | None, +) -> int: rows = receivers(registry) print(f"telling {len(rows)} receiver(s) about {package} {version}\n") @@ -487,6 +533,13 @@ def run_tick(package: str, version: str, registry: str | None, dry_run: bool) -> annotate("warning", f"{repo}#{number}: {note}") continue if outcome == "already-offered": + recorded, detail = receiver_receipt( + journal, receipt_dir, package, version, repo, number, outcome + ) + if not recorded: + findings.append(f"{repo}#{number}: {detail}") + annotate("error", f"{repo}#{number}: receiver receipt refused: {detail}") + continue reached += 1 print(f" no-op {repo}#{number}: {note}") continue @@ -505,6 +558,13 @@ def run_tick(package: str, version: str, registry: str | None, dry_run: bool) -> findings.append(f"{repo}#{number}: {detail}") annotate("error", f"{repo}#{number}: {detail}") continue + recorded, detail = receiver_receipt( + journal, receipt_dir, package, version, repo, number, outcome + ) + if not recorded: + findings.append(f"{repo}#{number}: {detail}") + annotate("error", f"{repo}#{number}: receiver receipt refused: {detail}") + continue reached += 1 print(f" ticked {repo}#{number}: {note}\n {line.strip()}") @@ -541,6 +601,8 @@ def main(argv: list[str]) -> int: parser.add_argument("--registry", help="override registry/repos.yml (the fixture uses this)") parser.add_argument("--probe", action="store_true", help="read-only credential/reach assertion") parser.add_argument("--dry-run", action="store_true", help="decide and report; write nothing") + parser.add_argument("--journal", help="verified release journal that binds receiver receipts") + parser.add_argument("--receipt-dir", help="append-only receipt output directory outside release assets") args = parser.parse_args(argv) try: @@ -550,7 +612,14 @@ def main(argv: list[str]) -> int: return run_probe(args.registry) if not args.package or not args.version: raise Permanent("--package and --version are both required unless --probe is given") - return run_tick(args.package, args.version, args.registry, args.dry_run) + return run_tick( + args.package, + args.version, + args.registry, + args.dry_run, + args.journal, + args.receipt_dir, + ) except Permanent as error: annotate("error", f"no verdict (permanent): {error}") return 3 diff --git a/scripts/fsgg-coord b/scripts/fsgg-coord index 7ae743f72..1b2f8e9dd 100755 --- a/scripts/fsgg-coord +++ b/scripts/fsgg-coord @@ -190,6 +190,25 @@ fi # REFUSE — do not fall through to some other engine the caller did not choose. if [ -n "${FSGG_COORD_ENGINE_BIN:-}" ]; then [ -x "${FSGG_COORD_ENGINE_BIN}" ] || die "FSGG_COORD_ENGINE_BIN is set but not executable: ${FSGG_COORD_ENGINE_BIN}" + # A packaged engine selected by its ordinary PATH is an alternate location for stable bytes, not a + # self-host transition. Every other explicit binary is a candidate: reads remain available for + # diagnosis, while write-capable verbs require the host-owned stable verifier and typed receipt. + PACKAGED_ENGINE="$(command -v fsgg-coord-engine 2>/dev/null || true)" + if [ -z "$PACKAGED_ENGINE" ] || [ "$PACKAGED_ENGINE" != "$FSGG_COORD_ENGINE_BIN" ]; then + CANDIDATE_TOP="$(git -C "$(dirname "$FSGG_COORD_ENGINE_BIN")" rev-parse --show-toplevel 2>/dev/null || true)" + if [ -n "$CANDIDATE_TOP" ]; then + load_guards "$CANDIDATE_TOP" + # A detached/current checkout with no engine inputs beyond its default branch is another stable + # build location (the stale-guard recovery route). Only authored engine inputs make it a candidate. + if authored_engine_source "$CANDIDATE_TOP"; then + self_host_candidate_guard "$FSGG_COORD_ENGINE_BIN" "${1:-}" "$CANDIDATE_TOP" "${2:-}" + fi + else + [ -n "$TOP" ] || die "an explicit candidate engine cannot be classified outside a git checkout" + load_guards "$TOP" + self_host_candidate_guard "$FSGG_COORD_ENGINE_BIN" "${1:-}" "" "${2:-}" + fi + fi exec "${FSGG_COORD_ENGINE_BIN}" "$@" fi diff --git a/scripts/fsgg-coord-guards.sh b/scripts/fsgg-coord-guards.sh index 8c4db2a71..e1bc34eaa 100644 --- a/scripts/fsgg-coord-guards.sh +++ b/scripts/fsgg-coord-guards.sh @@ -277,7 +277,7 @@ BOARD_WRITES="add adopt child claim comment done flush heartbeat intake op-lock # that reasoning, and `next` cannot be argument-aware at all — its write is gated on board state, not on a # flag. Take the refusal. If a permitted stale dry run is ever wanted, the honest way is for the engine to # declare per-invocation write-ness, not for this shim to re-implement the parser. -BOARD_WRITES_CONDITIONAL="delivery delivery-route graphql next reap reconcile" +BOARD_WRITES_CONDITIONAL="delivery delivery-route graphql next reap reconcile self-host" # READS — permitted (with a warning) on a stale engine, because a stale read misinforms ONE worker where a # stale write corrupts what the fleet shares. This set exists so the partition is total: it is the half that @@ -308,6 +308,37 @@ BOARD_WRITES_CONDITIONAL="delivery delivery-route graphql next reap reconcile" # rather than be evaluated. Long, therefore, on purpose. BOARD_READS="batch board body-edits bootstrap budget command-contract cycle decide diff-audit driver facts field-id followup inbox issues item-id landable lanes lint option-id overlap packet predicate ready scan verify-paths who whoami" +# Candidate selection is a trust transition only when it can mutate shared state. Keep the classification +# beside the stale-engine partition so the self-host gate and stale guard cannot disagree about a new verb. +coord_verb_may_write() { # $1 = verb, $2 = first argument + if [ "$1" = self-host ] && { [ "${2:-}" = verify ] || [ "${2:-}" = replay ]; }; then return 1; fi + case " $BOARD_WRITES $BOARD_WRITES_CONDITIONAL " in + *" $1 "*) return 0 ;; + *) return 1 ;; + esac +} + +# Verify explicit candidate bytes with a DISTINCT stable engine before the candidate sees a write argv. +# The verifier performs no remote IO; a missing receipt/verifier or any disagreement is a hard refusal. +self_host_candidate_guard() { # $1 = candidate binary, $2 = verb, $3 = candidate checkout, $4 = first argument + local candidate="$1" verb="$2" candidate_top="${3:-}" first_arg="${4:-}" stable receipt + coord_verb_may_write "$verb" "$first_arg" || return 0 + receipt="${FSGG_SELF_HOST_RECEIPT:-}" + stable="${FSGG_COORD_STABLE_ENGINE_BIN:-}" + [ -n "$receipt" ] || die "REFUSED — explicit candidate engine '$candidate' may write through '$verb', but FSGG_SELF_HOST_RECEIPT is not set." + [ -f "$receipt" ] || die "REFUSED — self-host receipt does not exist: $receipt" + [ -n "$stable" ] || die "REFUSED — FSGG_COORD_STABLE_ENGINE_BIN must name the shared stable verifier for a candidate write." + [ -x "$stable" ] || die "REFUSED — stable self-host verifier is not executable: $stable" + [ "$stable" != "$candidate" ] || die "REFUSED — the candidate engine cannot verify its own bootstrap receipt; name a distinct stable engine." + if [ -n "$candidate_top" ]; then + "$stable" self-host verify "$receipt" "$candidate" "$candidate_top" >/dev/null \ + || die "REFUSED — the stable engine rejected the self-host bootstrap receipt, candidate bytes, version, or Git heads." + else + "$stable" self-host verify "$receipt" "$candidate" >/dev/null \ + || die "REFUSED — the stable engine rejected the self-host bootstrap receipt, candidate bytes, or version." + fi +} + # STAT THE .dll, NOT THE APPHOST. `fsgg-coord-engine` is the .NET apphost — a fixed ~78 KB native stub, # BYTE-IDENTICAL across every build of every commit. The IL, which is the thing that goes stale, is in # `fsgg-coord-engine.dll` beside it. A guard that measured the apphost would be green on this exact bug. @@ -981,6 +1012,12 @@ stale_guard() { # $1 = top, $2 = engine .dll, $3 = verb, $4 = the verb's first a return 0 fi + if [ "$verb" = "self-host" ] && { [ "${4:-}" = "verify" ] || [ "${4:-}" = "replay" ]; }; then + echo "fsgg-coord: WARNING — the engine is STALE, so its stable self-host verifier may not match the code you are reading." >&2 + printf '%s\n' "$detail" >&2 + return 0 + fi + # ONE SPACE BETWEEN THE SETS, spaces added once around the whole — see the note above the sets. A padded # concatenation would put a DOUBLE space here and refuse the empty verb of a bare invocation. case " $BOARD_WRITES $BOARD_WRITES_CONDITIONAL " in diff --git a/scripts/release-saga.py b/scripts/release-saga.py index ad03b8f67..af2bef444 100644 --- a/scripts/release-saga.py +++ b/scripts/release-saga.py @@ -20,6 +20,7 @@ import zipfile SCHEMA = "fsgg.release-saga/1" +RECEIVER_SCHEMA = "fsgg.release-receiver-receipt/1" FEEDS = ("github", "nuget") CONTENT_ID = re.compile(r"sha256:[0-9a-f]{64}\Z") SOURCE_SHA = re.compile(r"[0-9a-f]{40}\Z") @@ -544,6 +545,108 @@ def command_promote(args: argparse.Namespace) -> None: print("stable channel promoted") +def receiver_identity(data: dict, package_id: str, receiver: str) -> dict[str, str]: + if re.fullmatch(r"[A-Za-z0-9_.-]+/[A-Za-z0-9_.-]+", receiver) is None: + raise ValueError(f"receiver is not an owner/repository name: {receiver}") + packages = package_map(data) + if package_id not in packages: + raise ValueError(f"receiver receipt names unknown package: {package_id}") + for feed in FEEDS: + row = data["state"]["feeds"][feed]["packages"][package_id] + if row["state"] != "verified": + raise ValueError(f"receiver receipt refused; {feed}/{package_id} is not verified") + package = packages[package_id] + delivery_id = hashlib.sha256( + canonical([data["contentId"], package_id, receiver]) + ).hexdigest() + return { + "contentId": data["contentId"], + "packageId": package_id, + "version": data["descriptor"]["version"], + "sourceSha": data["descriptor"]["sourceSha"], + "artifactSha256": package["artifact"]["sha256"], + "receiver": receiver, + "deliveryId": delivery_id, + } + + +def verify_receiver_receipt(data: dict, receipt: dict) -> tuple[str, str]: + if receipt.get("schema") != RECEIVER_SCHEMA: + raise ValueError("receiver receipt has an unknown schema") + identity = receiver_identity(data, receipt.get("packageId", ""), receipt.get("receiver", "")) + for key, expected in identity.items(): + if receipt.get(key) != expected: + raise ValueError(f"receiver receipt {key} does not match its journal-bound identity") + if receipt.get("outcome") != "verified": + raise ValueError("receiver receipt outcome is not verified") + observed_at = receipt.get("observedAt") + if not isinstance(observed_at, str): + raise ValueError("receiver receipt observedAt is missing") + try: + dt.datetime.fromisoformat(observed_at.replace("Z", "+00:00")) + except ValueError as error: + raise ValueError("receiver receipt observedAt is malformed") from error + unsigned = {key: value for key, value in receipt.items() if key != "digest"} + expected_digest = "sha256:" + hashlib.sha256(canonical(unsigned)).hexdigest() + if receipt.get("digest") != expected_digest: + raise ValueError("receiver receipt digest does not match its bound fields") + return identity["packageId"], identity["receiver"] + + +def command_receiver_receipt(args: argparse.Namespace) -> None: + manifest_path = pathlib.Path(args.manifest).resolve() + data = load(manifest_path) + assert_bound(manifest_path, data) + identity = receiver_identity(data, args.package, args.receiver) + unsigned = { + "schema": RECEIVER_SCHEMA, + **identity, + "outcome": "verified", + "observedAt": now(), + "detail": args.detail, + } + receipt = {**unsigned, "digest": "sha256:" + hashlib.sha256(canonical(unsigned)).hexdigest()} + output = pathlib.Path(args.output).resolve() + if output.exists(): + existing = json.loads(output.read_text(encoding="utf-8")) + verify_receiver_receipt(data, existing) + if any(existing.get(key) != receipt.get(key) for key in identity) or existing.get("detail") != args.detail: + raise ValueError("append-only receiver receipt path already contains contradictory evidence") + print(existing["deliveryId"]) + return + write_atomic(output, receipt) + print(receipt["deliveryId"]) + + +def command_verify_receivers(args: argparse.Namespace) -> None: + manifest_path = pathlib.Path(args.manifest).resolve() + data = load(manifest_path) + assert_bound(manifest_path, data) + expected: set[tuple[str, str]] = set() + for value in args.expected: + package_id, separator, receiver = value.partition("=") + if not separator: + raise ValueError("--expected must be PACKAGE=OWNER/REPOSITORY") + receiver_identity(data, package_id, receiver) + expected.add((package_id, receiver)) + if not expected: + raise ValueError("receiver declaration is empty") + found: dict[tuple[str, str], dict] = {} + for value in args.receipt: + receipt = json.loads(pathlib.Path(value).read_text(encoding="utf-8")) + key = verify_receiver_receipt(data, receipt) + if key in found and found[key] != receipt: + raise ValueError(f"contradictory receiver receipts exist for {key[0]}={key[1]}") + found[key] = receipt + missing = expected - set(found) + unexpected = set(found) - expected + if missing: + raise ValueError("missing receiver receipts: " + ", ".join(f"{p}={r}" for p, r in sorted(missing))) + if unexpected: + raise ValueError("undeclared receiver receipts: " + ", ".join(f"{p}={r}" for p, r in sorted(unexpected))) + print(f"verified {len(found)} journal-bound receiver receipt(s)") + + def parser() -> argparse.ArgumentParser: top = argparse.ArgumentParser() commands = top.add_subparsers(dest="command", required=True) @@ -580,6 +683,15 @@ def parser() -> argparse.ArgumentParser: promote = commands.add_parser("promote") promote.add_argument("--manifest", required=True); promote.add_argument("--channel-output") promote.add_argument("--previous-channel"); promote.set_defaults(run=command_promote) + receiver = commands.add_parser("receiver-receipt") + receiver.add_argument("--manifest", required=True); receiver.add_argument("--package", required=True) + receiver.add_argument("--receiver", required=True); receiver.add_argument("--detail", required=True) + receiver.add_argument("--output", required=True); receiver.set_defaults(run=command_receiver_receipt) + verify_receivers = commands.add_parser("verify-receivers") + verify_receivers.add_argument("--manifest", required=True) + verify_receivers.add_argument("--expected", action="append", required=True) + verify_receivers.add_argument("--receipt", action="append", required=True) + verify_receivers.set_defaults(run=command_verify_receivers) return top diff --git a/src/FS.GG.Coord.Cli.BoardOps/HandlerRegistration.fs b/src/FS.GG.Coord.Cli.BoardOps/HandlerRegistration.fs index 1c5218d2d..bb03983d7 100644 --- a/src/FS.GG.Coord.Cli.BoardOps/HandlerRegistration.fs +++ b/src/FS.GG.Coord.Cli.BoardOps/HandlerRegistration.fs @@ -6,59 +6,10 @@ open FS.GG.Coord.Cli.Kernel module HandlerRegistration = type Handler = Context -> Options.Options -> int - type Implementations = - { Add: Handler - Flush: Handler - SetField: Handler - Child: Handler - BodyEdits: Handler - FieldId: Handler - OptionId: Handler - ItemId: Handler - Board: Handler - Bootstrap: Handler - Issues: Handler - Intake: Handler - Say: Handler - Inbox: Handler - RoomOpen: Handler - Comment: Handler } - let commands = - [ Options.Add - Options.Flush - Options.SetField - Options.Child - Options.BodyEdits - Options.FieldId - Options.OptionId - Options.ItemId - Options.BoardCmd - Options.Bootstrap - Options.Issues - Options.IntakeCmd - Options.Say - Options.Inbox - Options.RoomOpen - Options.CommentCmd ] - - let handlers implementations = - [ Options.Add, implementations.Add - Options.Flush, implementations.Flush - Options.SetField, implementations.SetField - Options.Child, implementations.Child - Options.BodyEdits, implementations.BodyEdits - Options.FieldId, implementations.FieldId - Options.OptionId, implementations.OptionId - Options.ItemId, implementations.ItemId - Options.BoardCmd, implementations.Board - Options.Bootstrap, implementations.Bootstrap - Options.Issues, implementations.Issues - Options.IntakeCmd, implementations.Intake - Options.Say, implementations.Say - Options.Inbox, implementations.Inbox - Options.RoomOpen, implementations.RoomOpen - Options.CommentCmd, implementations.Comment ] + Options.commandCatalogue + |> List.choose (fun descriptor -> + if descriptor.HandlerOwner = Options.BoardOps then Some descriptor.Command else None) let validate<'handler> (allCommands: Options.Command list) diff --git a/src/FS.GG.Coord.Cli.BoardOps/HandlerRegistration.fsi b/src/FS.GG.Coord.Cli.BoardOps/HandlerRegistration.fsi index da0849cfd..e83ea4de8 100644 --- a/src/FS.GG.Coord.Cli.BoardOps/HandlerRegistration.fsi +++ b/src/FS.GG.Coord.Cli.BoardOps/HandlerRegistration.fsi @@ -6,26 +6,7 @@ open FS.GG.Coord.Cli.Kernel module HandlerRegistration = type Handler = Context -> Options.Options -> int - type Implementations = - { Add: Handler - Flush: Handler - SetField: Handler - Child: Handler - BodyEdits: Handler - FieldId: Handler - OptionId: Handler - ItemId: Handler - Board: Handler - Bootstrap: Handler - Issues: Handler - Intake: Handler - Say: Handler - Inbox: Handler - RoomOpen: Handler - Comment: Handler } - val commands: Options.Command list - val handlers: implementations: Implementations -> (Options.Command * Handler) list val validate: allCommands: Options.Command list -> registrations: (Options.Command * 'handler) list -> diff --git a/src/FS.GG.Coord.Cli.BoardOps/Handlers.fs b/src/FS.GG.Coord.Cli.BoardOps/Handlers.fs index ed0eeab3a..ddd265731 100644 --- a/src/FS.GG.Coord.Cli.BoardOps/Handlers.fs +++ b/src/FS.GG.Coord.Cli.BoardOps/Handlers.fs @@ -2048,23 +2048,22 @@ module Handlers = // scheduling and mutation boundaries. let handlers = - HandlerRegistration.handlers - { Add = addCmd - Flush = flushCmd - SetField = setField - Child = child - BodyEdits = bodyEditsCmd - FieldId = fieldId - OptionId = optionId - ItemId = itemIdCmd - Board = fun ctx _ -> boardCmd ctx - Bootstrap = bootstrapCmd - Issues = issues - Intake = intakeCmd - Say = say - Inbox = inbox - RoomOpen = roomOpen - Comment = commentCmd } + [ Add, addCmd + Flush, flushCmd + SetField, setField + Child, child + BodyEdits, bodyEditsCmd + FieldId, fieldId + OptionId, optionId + ItemId, itemIdCmd + BoardCmd, fun ctx _ -> boardCmd ctx + Bootstrap, bootstrapCmd + Issues, issues + IntakeCmd, intakeCmd + Say, say + Inbox, inbox + RoomOpen, roomOpen + CommentCmd, commentCmd ] // Program-level registrations are also a BoardOps-family product. Intake validation is the one // tokenless BoardOps route: it parses the draft and validates paths against the local checkout, diff --git a/src/FS.GG.Coord.Cli.Kernel/Options.fs b/src/FS.GG.Coord.Cli.Kernel/Options.fs index a7bf18f74..b26dc42f9 100644 --- a/src/FS.GG.Coord.Cli.Kernel/Options.fs +++ b/src/FS.GG.Coord.Cli.Kernel/Options.fs @@ -5,6 +5,7 @@ module Options = type Command = | Decide | DeliveryCmd + | SelfHostCmd /// .github#2175: inspect the resumable review/repair protocol (`FS.GG.Coord.Review`) — /// live against ` --pr N`, or from a supplied `--snapshot`; the typed surface `pnext-item` /// and the #2135 event projection consume. @@ -95,6 +96,22 @@ module Options = /// printed prose regardless. | TextOnly + type HandlerOwner = + | KernelProgram + | BoardOps + + type MutationKind = + | ReadOnly + | WritesRemoteState + + type CommandDescriptor = + { Command: Command + Verb: string + Render: RenderSupport + Mutation: MutationKind + HandlerOwner: HandlerOwner + Documented: bool } + type Options = { Command: Command Render: Render @@ -390,7 +407,7 @@ IO (read and write the board — $FSGG_COORD_OWNER / $FSGG_COORD_PROJECT, $GITHU head you MEAN to gate, for a caller that just force-pushed (the PR object lags). Neither can green; both are pending (#737) - delivery [--pr N] [--apply] [--json|--text] + delivery [--pr N] [--flip] [--apply] [--json|--text] re-read one claimed item's delivery facts and emit its sole freshness-bound action. WRITES ON PLAIN `--pr N` TOO (.github#2488), not only under `--apply`: whenever the caller @@ -398,8 +415,19 @@ IO (read and write the board — $FSGG_COORD_OWNER / $FSGG_COORD_PROJECT, $GITHU merged, this PATCHes the PR body's `fsgg:pr-authorization` marker current — a runtime-state-gated write no flag turns off, distinct from --apply's SEPARATE, larger effect - (guarded landing: a real merge or the `Complete` transition) + (guarded landing: a real merge or the `Complete` transition). + --flip performs the terminal parent roll-up after typed receipt + creation and the issue/board completion projections delivery --snapshot FILE [--json|--text] the pure, IO-free form — see DECISION above + self-host verify [--text] + stable shared verifier for a candidate-engine receipt; + self-host mint + bind candidate bytes/version, snapshot, evidence and host acceptance + self-host replay + post-merge shared replay agreement (read-only, text) + self-host record append verified authority to its accountable item thread + self-host replay-record + append shared replay agreement to the same item thread claim [--worker W] [--force] take the lock; --json emits a fresh marker/Status receipt. [--refuse-overlap] [--json] --force STEALS: it takes an item another worker holds RIGHT @@ -483,8 +511,9 @@ IO (read and write the board — $FSGG_COORD_OWNER / $FSGG_COORD_PROJECT, $GITHU executor stalls one receiver's queue, and a grant held across an item's lifetime would serialise the whole fleet on one receiver. Refuses unless we are the live winner - done [--flip] [--evidence E] stamp the item done; --flip rolls the parent up (add - [--partial "why"] --partial "why" if this child does NOT complete its parent, #614) + done [--flip] [--pr N] replay a matching typed completion receipt; it cannot mint + [--partial "why"] authority. --flip rolls the parent up (add --partial "why" if + this child does NOT complete its parent, #614) verify-paths --pr N [--repo NAME] did the PR stay inside its issue's touch-set? (OK/DRIFT/ [--issue REF] [--warn] SKIP; --issue names the issue explicitly; --warn advisory) @@ -565,139 +594,78 @@ EXIT CODES — the engine's own (the shim translates them for a caller that stil · 4 unknown (could not reach a verdict — fail-closed, never a retry) """ - /// Which stdout projections each command HAS — see `RenderSupport`. Derived by tracing every - /// `opts.Render` read in `Client.fs`/`Program.fs` to the handler that reaches it, exactly as `scopeOf` - /// below was derived, and NOT from the usage prose. - /// - /// The `Both` default of each row is the mode that command renders in TODAY with no flag. It is not a - /// preference and it is not adjustable in passing: `#1517` shipped `widen` honouring `opts.Render` - /// while its parse arm still inherited the module default of `Json`, which would have flipped the BARE - /// `widen` — the form every recipe runs — from its human receipt to a JSON object. Changing a `Both` - /// default here changes what an existing caller's un-flagged invocation prints. - let renderSupport (c: Command) : RenderSupport = - match c with - // ---- BOTH projections: the handler branches on `opts.Render` ----------------------------------- - | Decide -> Both Json // Program.fs `decide` - | DeliveryCmd -> Both Json // Program.fs `delivery` - | ReviewCmd -> Both Json // Program.fs `review` (ReviewApplication) - | DriverCmd -> Both Json // Program.fs `driver` - | CycleCmd -> Both Json // Program.fs `CycleLedgerApplication` - | LanesView -> Both Json // Program.fs `lanes` - | Facts -> Both Json // Program.fs `facts` — `generate-projections` reads the JSON arm - | BatchCmd -> Both Json // Client.fs `batch` - | Ready -> Both Json // Client.fs `ready` - // Client.fs `reconcile` — and `--apply --json` is a REAL combination (.github#1541), which is the - // statement this row now has to carry, because the `parse` funnel used to contradict it. - // - // #1429 (897b83d, a skills refactor whose subject said nothing about the options surface) added a - // `validate` arm refusing `--apply` with `--json` on this verb. That was a WORKAROUND for a - // handler defect, never a contract, and the thing it removed was the machine projection of the - // org's one MUTATING reconciliation verb: a driver applying a reconciliation could not learn which - // writes landed and which QUEUED against an exhausted budget except by scraping `applied`/`queued` - // prose off stdout. A queued write is not lost — `flush` replays it — but nothing replays it ON ITS - // OWN, so a caller that never learns the write deferred is a caller that never runs `flush`. The - // refusal's own remedy ("inspect the JSON dry run, then apply in human-readable mode") is two - // passes over a board that can change between them, and the second is the unreadable one. - // - // WHAT MADE IT LIFTABLE. Until PR #1537 the `--apply` phase printed its per-write outcome to - // stdout PAST a document that had already ended, so opening the gate would have shipped an - // unparseable stream the moment it opened. #1537 moved the outcome INTO the document - // (`field`/`value`/`outcome`/`error`), put the deferred-write remedy on stderr, and stopped the - // `reap` child's stdout leaking in. The handler was correct first; only the gate remained. - // - // AND THIS ROW IS WHY THERE WAS NOTHING ELSE TO CHANGE. `Both` puts `reconcile` in `jsonReaders`, - // so `--json` has been in its scoped flag set — and therefore in the emitted `command-contract` - // row and the `--help` usage line (`reconcile [--repo NAME] [--apply] [--json]`) — the whole time - // the parser was refusing it. `Text` stays the bare default; nothing about `--apply` changes it. - | Reconcile -> Both Text - // `who`, `budget` and `inbox` share one polarity, and it is the mirror of `ready`/`batch`: the - // human table is what an operator or a worker reads, and `--json` opts into the machine contract - // (case 20/25's rows, `pendingBoardWrites` — #862). - | Who -> Both Text - | Budget -> Both Text - | Claim -> Both Text - // `adopt` produces no stdout of its own — it delegates to `claim`, passing `opts` through, so - // `claim`'s receipt is its receipt. - // - // `take` delegated the same way and INHERITED the row rather than earning it: the one arm it owns, - // the empty queue, printed prose regardless of `Render`, so `take --json` was honoured only when it - // actually claimed something. `.github#1525` closed that in `Client.fs` — the empty arm now emits - // its own `kind:"none"` receipt — so the row is true of BOTH arms rather than of one, and this - // comment records a caveat that was real and is now discharged, not one still standing. - | Adopt -> Both Text - | Take -> Both Text - // `op-lock acquire` EXISTS to be read by a machine: its stdout is the broker's input tuple — - // `grant`, `opkey`, `item`, `generation`, `receiver`, `op` — and the caller that consumes it is a - // shell composing `gh workflow run fsgg-dispatch-broker.yml -f grant=… -f opkey=…`. A text - // projection is kept as the default for the operator reading it by hand, which is the same polarity - // `who` and `budget` chose. `release` is `Both` for symmetry, and because a caller that scripted the - // acquire will script the release from the same harness. - | OpLockAcquire -> Both Text - | OpLockRelease -> Both Text - | Widen -> Both Text // both reach the shared `updateTouchSet` (#1517) - | SetPaths -> Both Text - | Inbox -> Both Text - | Predicate -> Both Text - | DiffAudit -> JsonOnly - | LintCmd -> Both Text - // A critic reading this to answer `.github#2456`'s body-edit provenance question wants the - // per-edit facts (`editedAt`, `editor`) machine-readable — same polarity as `who`/`budget`: a - // human table by default, `--json` opts into the structured document (.github#2477). - | BodyEdits -> Both Text - | GraphQlOps -> JsonOnly - - // ---- JSON ONLY: stdout is a machine document whatever the flag says ---------------------------- - // `scan` DOES match on `opts.Render` (`Program.fs`), and both arms print the same document — - // deliberately, because the snapshot IS the contract and `scan | decide` must keep working. So the - // match decides nothing on stdout, and `--text` was a no-op rather than a rendering: there is no - // human projection of a snapshot to ask for. The PIPELINE is unaffected either way (`scan` bare and - // `scan --text` printed identical bytes); what is refused is only the flag that never did anything. - // - // The now-unreachable `Text` arm and its comment live in `Program.fs`, which is outside this item's - // touch-set. Filed as a follow-up rather than reached into. - | Scan -> JsonOnly - | CommandContractCmd -> JsonOnly - | IntakeCmd -> JsonOnly - // .github#2737: the success document and the refusal document are both JSON on stdout; the - // per-field findings a finder actually reads go to stderr, so there is no text projection. - | PacketCmd -> JsonOnly - | RouteCmd -> JsonOnly - | BoardCmd -> JsonOnly - | Issues -> JsonOnly // the raw REST array; the caller projects it with jq - - // ---- TEXT ONLY: prose, an id, or one verdict word — there is no machine projection to ask for --- - // THIS IS THE #1523 BUCKET. Every row here advertised `--json` on all 40 commands and printed the - // same prose with it as without. Two are load-bearing for the fleet and say why refusal beats - // "make the handler honour it": `whoami --mint` prints `export FSGG_WORKER=…` for `eval`, and - // `done` prints the `FSGG-DONE` stamp every driver greps. A JSON projection nobody consumes, on - // either of those, is a fleet outage bought for nothing. - | WhoAmI -> TextOnly - | Next -> TextOnly - // `reap` reports what it WOULD collect; the destructive collect is gated behind `--apply`, so the - // bare form is a DRY RUN and the thing an operator reads before deciding is prose. - | Reap -> TextOnly - | Landable -> TextOnly // one verdict word; the decision is the exit code - | Release -> TextOnly - | Heartbeat -> TextOnly - | SetField -> TextOnly - | Child -> TextOnly - | Overlap -> TextOnly - | Say -> TextOnly - | RoomOpen -> TextOnly - | CommentCmd -> Both Json - | DoneCmd -> TextOnly - | VerifyPaths -> TextOnly - | Followup -> TextOnly - | Bootstrap -> TextOnly - | FieldId -> TextOnly // a bare id - | OptionId -> TextOnly - | ItemId -> TextOnly - | Add -> TextOnly - // `flush` REPLAYS by default (the opposite polarity to `reap --apply`, see `DryRun`), and what it - // prints is a report an operator reads after the `EX_RATE` back-off. - | Flush -> TextOnly - | Help -> TextOnly - | Version -> TextOnly + // Phase-1 typed authority. Stable metadata is authored once here; parser arms remain explicit + // because their arguments and validation differ, while behavior tests parse every descriptor verb. + let commandCatalogue: CommandDescriptor list = + let row command verb render mutation owner = + { Command = command + Verb = verb + Render = render + Mutation = mutation + HandlerOwner = owner + Documented = true } + + [ row Decide "decide" (Both Json) ReadOnly KernelProgram + row DeliveryCmd "delivery" (Both Json) WritesRemoteState KernelProgram + row SelfHostCmd "self-host" TextOnly WritesRemoteState KernelProgram + row ReviewCmd "review" (Both Json) WritesRemoteState KernelProgram + row DriverCmd "driver" (Both Json) ReadOnly KernelProgram + row CycleCmd "cycle" (Both Json) ReadOnly KernelProgram + row Scan "scan" JsonOnly ReadOnly KernelProgram + row LanesView "lanes" (Both Json) ReadOnly KernelProgram + row Facts "facts" (Both Json) ReadOnly KernelProgram + row CommandContractCmd "command-contract" JsonOnly ReadOnly KernelProgram + row IntakeCmd "intake" JsonOnly WritesRemoteState BoardOps + row PacketCmd "packet" JsonOnly ReadOnly KernelProgram + row RouteCmd "delivery-route" JsonOnly WritesRemoteState KernelProgram + row WhoAmI "whoami" TextOnly ReadOnly KernelProgram + row Budget "budget" (Both Text) ReadOnly KernelProgram + row Next "next" TextOnly WritesRemoteState KernelProgram + row BatchCmd "batch" (Both Json) ReadOnly KernelProgram + row Ready "ready" (Both Json) ReadOnly KernelProgram + row Reconcile "reconcile" (Both Text) WritesRemoteState KernelProgram + row Who "who" (Both Text) ReadOnly KernelProgram + row Reap "reap" TextOnly WritesRemoteState KernelProgram + row Claim "claim" (Both Text) WritesRemoteState KernelProgram + row Adopt "adopt" (Both Text) WritesRemoteState KernelProgram + row Landable "landable" TextOnly ReadOnly KernelProgram + row Take "take" (Both Text) WritesRemoteState KernelProgram + row Release "release" TextOnly WritesRemoteState KernelProgram + row Heartbeat "heartbeat" TextOnly WritesRemoteState KernelProgram + row SetField "set-field" TextOnly WritesRemoteState BoardOps + row Child "child" TextOnly WritesRemoteState BoardOps + row Widen "widen" (Both Text) WritesRemoteState KernelProgram + row SetPaths "set-paths" (Both Text) WritesRemoteState KernelProgram + row Overlap "overlap" TextOnly ReadOnly KernelProgram + row Say "say" TextOnly WritesRemoteState BoardOps + row Inbox "inbox" (Both Text) ReadOnly BoardOps + row DoneCmd "done" TextOnly WritesRemoteState KernelProgram + row VerifyPaths "verify-paths" TextOnly ReadOnly KernelProgram + row Bootstrap "bootstrap" TextOnly ReadOnly BoardOps + row BoardCmd "board" JsonOnly ReadOnly BoardOps + row FieldId "field-id" TextOnly ReadOnly BoardOps + row OptionId "option-id" TextOnly ReadOnly BoardOps + row ItemId "item-id" TextOnly ReadOnly BoardOps + row BodyEdits "body-edits" (Both Text) ReadOnly BoardOps + row GraphQlOps "graphql" JsonOnly WritesRemoteState KernelProgram + row Add "add" TextOnly WritesRemoteState BoardOps + row Flush "flush" TextOnly WritesRemoteState BoardOps + row LintCmd "lint" (Both Text) ReadOnly KernelProgram + row Issues "issues" JsonOnly ReadOnly BoardOps + row Followup "followup" TextOnly ReadOnly KernelProgram + row Predicate "predicate" (Both Text) ReadOnly KernelProgram + row DiffAudit "diff-audit" JsonOnly ReadOnly KernelProgram + row RoomOpen "room open" TextOnly WritesRemoteState BoardOps + row CommentCmd "comment" (Both Json) WritesRemoteState BoardOps + row OpLockAcquire "op-lock acquire" (Both Text) WritesRemoteState KernelProgram + row OpLockRelease "op-lock release" (Both Text) WritesRemoteState KernelProgram + row Help "--help" TextOnly ReadOnly KernelProgram + row Version "--version" TextOnly ReadOnly KernelProgram ] + + let renderSupport (command: Command) = + commandCatalogue + |> List.find (fun descriptor -> descriptor.Command = command) + |> _.Render /// The render mode a BARE invocation of a command is left at — derived from the same declaration that /// decides whether the flag may be given at all, so the two can no longer disagree. @@ -865,7 +833,7 @@ EXIT CODES — the engine's own (the shim translates them for a caller that stil | FTo -> Only [ Say ] | FMessage -> Only [ Say ] | FEvidence -> Only [ DoneCmd ] - | FFlip -> Only [ DoneCmd ] + | FFlip -> Only [ DeliveryCmd; DoneCmd ] | FPartial -> Only [ DoneCmd ] | FPr -> Only [ DeliveryCmd; ReviewCmd; DoneCmd; VerifyPaths ] | FIssue -> Only [ VerifyPaths ] @@ -1054,22 +1022,14 @@ EXIT CODES — the engine's own (the shim translates them for a caller that stil /// through the same helper and was absent; `room` and `reconcile` were absent; and `bootstrap`, believed /// to create the project, is a pair of GraphQL QUERIES that adding would have refused for nothing. /// - /// TOTAL, WITH NO WILDCARD ARM, AND THAT IS THE STRUCTURAL PART. This project sets - /// `TreatWarningsAsErrors`, so FS0025 (incomplete match) is a BUILD ERROR — the same property - /// `renderSupport` and `scopeOf` already buy for the renderers and the flag surface. A verb added to the - /// `Command` union does not default to `Reads`; it does not compile. A `| _ -> Reads` arm added here - /// would silently give that guarantee back, which is the single most damaging edit this file accepts. + /// The base read/write fact now comes from the exhaustive `commandCatalogue`. Only the six genuinely + /// conditional commands remain here, because their argv/runtime gate is richer than the catalogue's + /// conservative `WritesRemoteState`. Catalogue closure makes a new union case without a descriptor red; + /// this function then derives `Reads` or `Writes` without another per-command inventory. /// - /// WHAT IT IS AND IS NOT DERIVED FROM, stated plainly because the honest limit matters more than the - /// claim. The GATE — which flag turns a conditional write on — is typed and cross-checked: it is a - /// `Flag`, spelled through `scopedFlags`, and `CommandSurfaceTests` asserts `scopeOf` really gives that - /// flag to that command. The BASE read/write split is not derivable here at all: it is a property of - /// `Client.fs` control flow, `Options.fs` compiles BEFORE `Client.fs` and cannot reference it, and a - /// text analysis over-approximates badly (advice strings in `who` and `lint` name `claim`, `reap` and - /// `done`). So the rows below are a person's reading of `Client.fs`, held total by the compiler and - /// carrying their evidence in the comment beside them. That is strictly better than a bash string with - /// nothing comparing it to anything — it is not the same thing as proof, and the follow-on that would - /// make it executable (drive every verb at a fake GitHub and fail on any mutating request) is filed. + /// Conditional gates stay typed and cross-checked against the accepted flag surface. `GraphQlOps`, + /// `DeliveryCmd`, and `Next` depend on subcommand or runtime facts argv alone cannot fully express; + /// `Reap`, `Reconcile`, and `Flush` name their explicit flag polarity. /// /// DELIBERATELY NOT READ AT RUN TIME BY THE SHIM, and the issue that asked for this field said so first. /// The engine that would answer "am I stale?" is the stale one; an engine built before this field @@ -1099,120 +1059,25 @@ EXIT CODES — the engine's own (the shim translates them for a caller that stil /// Some invocations mutate it and some do not; the gate says which. | WritesIf of WriteGate - let private writeSurface (c: Command) : WriteSurface = - match c with - // ---- PURE DECISION — no board, no network at all (ADR-0034) ------------------------------------ - | Decide -> Reads - // M4 adds `review record`, which posts the next sealed v2 decision. Classified conservatively - // like `delivery-route`: the read-only inspect spelling does not make the verb safe on a stale - // engine when another argv shape is explicitly an evidence writer. - | ReviewCmd -> Writes - | DriverCmd -> Reads - | CycleCmd -> Reads - | LanesView -> Reads - | Facts -> Reads - | CommandContractCmd -> Reads - | IntakeCmd -> Writes // `intake apply` creates/reuses and projects the receipt-bound issue - | PacketCmd -> Reads // .github#2737: decides over a local file; no board, no network, no post - | RouteCmd -> Writes // `record` appends the validated durable decision receipt - - // ---- LOCAL — a file, an identity, a registry read; no token, no board -------------------------- - | WhoAmI -> Reads // derives/mints an id; `--mint` prints one, it does not register it - | Followup -> Reads // the #1063 queue is a FILE, which is the whole reason it survives EX_RATE - | Predicate -> Reads // ADR-0050 oracle: registry + producer manifests off disk - | DiffAudit -> Reads // immutable git-object inspection; no board or network write - - // ---- READ THE BOARD — GraphQL/REST QUERIES, plus a per-user cache file ------------------------- - | Scan -> Reads // POSTs to `graphql`, which is how a GraphQL READ is spelled - | BatchCmd -> Reads // `next` uncapped; makes NO chore offer, which is what separates the two - | Ready -> Reads - | Who -> Reads - | Budget -> Reads - | Landable -> Reads - | Overlap -> Reads - | VerifyPaths -> Reads - | LintCmd -> Reads - | Issues -> Reads - | Inbox -> Reads // the cursor it advances is `Cache.putInboxCursor` — per-worker, local - | Bootstrap -> Reads // `Board.bootstrap`: two GraphQL queries, then day-cached - | BoardCmd -> Reads - | FieldId -> Reads - | OptionId -> Reads - | ItemId -> Reads - | BodyEdits -> Reads // one `userContentEdits` GraphQL query, budget-attributed like every other read - | GraphQlOps -> WritesIf(NotOnArgv "archive-items mutates; every other subcommand is a typed read") + let private descriptor command = + commandCatalogue |> List.find (fun row -> row.Command = command) - // ---- WRITE THE BOARD, EVERY INVOCATION --------------------------------------------------------- - | Claim -> Writes // POSTs the `fsgg:claim` marker comment and writes Status - | Take -> Writes // schedules, then delegates to `claim` - | Adopt -> Writes // transfers a claim, also via `claim` - | Release -> Writes - | Heartbeat -> Writes - | Add -> Writes // idempotent — `AlreadyOnBoard` skips the mutation, which is state, not argv - | SetField -> Writes - | Child -> Writes // idempotent the same way; an existing sub-issue is not POSTed twice - | Say -> Writes // no lock required, and every invocation POSTs - // Up to FIVE independent writes: board Status, the `--flip` ancestor roll-up (which also CLOSES - // issues over REST), the room close, its own marker release (#533) — and the #733 chore offer, the - // SECOND `Chores.offer` site after `next`. None of that changes the row; it is why the row is here. - | DoneCmd -> Writes - | RoomOpen -> Writes // `Writes.createRoom` + a `Rooms: #room` back-reference onto each named item - | CommentCmd -> Writes // POSTs or PATCHes one explicit comment, then verifies an authoritative re-read - // BOTH WRITE, EVERY INVOCATION, AND NEITHER WRITES THE PROJECT BOARD — which is why the row needs - // saying rather than assuming. The subject is an off-board, closed `[op-lock]` issue, so `who` and - // `reap` never see it (ADR-0041's own note about the chore lock, on a third subject). But the write - // is the same `Writes.claimScoped` POST/DELETE the item CAS makes, against the shared fleet's - // GitHub state, so a STALE engine must be refused it exactly as it is refused `claim` — the - // property `scripts/fsgg-coord-guards.sh` enforces and `tests/coord-engine-parity/shim.sh` §3b - // holds in bijection with this table. `WritesIf` would be wrong in both arms: there is no flag and - // no argv shape under which either of these is a read. - | OpLockAcquire -> Writes // POSTs the `fsgg:claim` grant marker onto the receiver's op-lock issue - | OpLockRelease -> Writes // DELETEs that marker - // Both reach the same `Writes.widen` PATCH through the same `updateTouchSet` helper. `set-paths` - // being the RECOVERY verb is exactly why its absence from the shim's list mattered (#1528). - | Widen -> Writes - | SetPaths -> Writes - - // ---- WRITE UNDER A CONDITION ------------------------------------------------------------------- - | Reap -> WritesIf(OnlyWhenGiven FApply) + let private writeSurface (command: Command) : WriteSurface = + match command with + | GraphQlOps -> WritesIf(NotOnArgv "archive-items mutates; every other subcommand is a typed read") + | Reap | Reconcile -> WritesIf(OnlyWhenGiven FApply) - // NOT `OnlyWhenGiven FApply` (.github#2488 round-1 repair — this used to say that, and after - // `Client.ensureAuthorization` dropped its own `--apply` gate the claim went false: a BARE - // `delivery --pr N`, no flag at all, now PATCHes the PR body's `fsgg:pr-authorization` - // marker whenever the caller holds the item's live claim and the named PR has not yet merged. - // `--apply` still gates the SEPARATE, larger `GuardedLand`/`Complete` mutation - // (`Client.fs`'s `delivery` command handler) — but a consumer trusting `OnlyWhenGiven FApply` - // here would wrongly read a bare status call as non-mutating, which is exactly the "trust this - // field" property (#1534) this type exists to protect. `NotOnArgv` is the precise fit, not a - // fallback: its own doc above already describes exactly this shape ("the condition is not on - // argv AT ALL... a person's reading of `Client.fs`, held total by the compiler") — WHETHER this - // command writes now turns on runtime state (a live claim held by the calling worker, the PR's - // merged status) that no argv parse can see, precisely what that case was written for. | DeliveryCmd -> WritesIf( NotOnArgv - "PATCHes the PR body's fsgg:pr-authorization marker on ANY --pr N invocation, apply \ - or not, whenever the caller holds the referenced item's live claim and the PR has \ - not yet merged — a runtime fact, not a flag; --apply additionally gates the \ - separate GuardedLand/Complete transition" + "PATCHes the PR authorization marker from runtime claim and merge state; --apply additionally gates landing" ) - // AND THIS ROW IS NOT THE SHIM'S ROW — read before wiring the #1534 follow-on gate. The shim puts - // `flush` in BOARD_WRITES (unconditional) and this says `conditional`, and BOTH are right about - // different questions: the shim's two write sets are REFUSED IDENTICALLY under staleness, so its - // split records "is this flag-dependent?" for the reader, while this records "could this invocation - // mutate?" for a consumer. A gate asserting `BOARD_WRITES == {always}` set-for-set therefore reds on - // `flush` over no defect at all. The sound assertion is over the UNION — - // `BOARD_WRITES ∪ BOARD_WRITES_CONDITIONAL == {always} ∪ {conditional}` and - // `BOARD_READS == {never}` — which is exactly the fact the guard acts on. | Flush -> WritesIf(UnlessGiven FDryRun) - | Next -> - WritesIf( - NotOnArgv "after printing its answer it makes the #733 chore offer, which POSTs a claim marker" - ) - - // ---- NOT VERBS — reached by flag, and excluded from the emitted contract entirely --------------- - | Help -> Reads - | Version -> Reads + | Next -> WritesIf(NotOnArgv "after printing its answer it may post the chore offer") + | _ -> + match (descriptor command).Mutation with + | ReadOnly -> Reads + | WritesRemoteState -> Writes /// The flags actually GIVEN, with the spelling to name in a refusal. A flag whose field has a /// non-optional default and no record of having been given (`LeaseMinutes`) cannot appear: "given" and @@ -1275,84 +1140,48 @@ EXIT CODES — the engine's own (the shim translates them for a caller that stil if o.RenderGiven.Contains Text then FText ] |> List.map (fun flag -> flag, spellingOf flag) - /// The argv spelling of a command — the word a refusal must name, because it is the word the caller - /// typed. Total over `Command`, so a new verb cannot be named `%A` by accident. - let commandName (c: Command) : string = - match c with - | Decide -> "decide" - | DeliveryCmd -> "delivery" - | ReviewCmd -> "review" - | DriverCmd -> "driver" - | CycleCmd -> "cycle" - | Scan -> "scan" - | LanesView -> "lanes" - | Facts -> "facts" - | CommandContractCmd -> "command-contract" - | IntakeCmd -> "intake" - | PacketCmd -> "packet" - | RouteCmd -> "delivery-route" - | WhoAmI -> "whoami" - | Budget -> "budget" - | Next -> "next" - | BatchCmd -> "batch" - | Ready -> "ready" - | Reconcile -> "reconcile" - | Who -> "who" - | Reap -> "reap" - | Claim -> "claim" - | Adopt -> "adopt" - | Landable -> "landable" - | Take -> "take" - | Release -> "release" - | Heartbeat -> "heartbeat" - | SetField -> "set-field" - | Child -> "child" - | Widen -> "widen" - | SetPaths -> "set-paths" - | Overlap -> "overlap" - | Say -> "say" - | Inbox -> "inbox" - | DoneCmd -> "done" - | VerifyPaths -> "verify-paths" - | Bootstrap -> "bootstrap" - | BoardCmd -> "board" - | FieldId -> "field-id" - | OptionId -> "option-id" - | ItemId -> "item-id" - | BodyEdits -> "body-edits" - | GraphQlOps -> "graphql" - | Add -> "add" - | Flush -> "flush" - | LintCmd -> "lint" - | Issues -> "issues" - | Followup -> "followup" - | Predicate -> "predicate" - | DiffAudit -> "diff-audit" - | RoomOpen -> "room open" - | CommentCmd -> "comment" - // TWO WORDS, and the first is the one that carries the guard. `tests/coord-engine-parity/shim.sh` - // §3b projects this surface through `awk '{print $1}'` because the shim dispatches on `$1`, so both - // rows below classify as the single token `op-lock` — the same arrangement `room open` already has. - | OpLockAcquire -> "op-lock acquire" - | OpLockRelease -> "op-lock release" - | Help -> "--help" - | Version -> "--version" + let commandName (command: Command) = + commandCatalogue + |> List.find (fun descriptor -> descriptor.Command = command) + |> _.Verb + + let validateCommandCatalogue (expectedCommands: Command list) (descriptors: CommandDescriptor list) = + let duplicateCommands = + descriptors + |> List.groupBy _.Command + |> List.choose (fun (command, rows) -> if rows.Length > 1 then Some command else None) + + let duplicateVerbs = + descriptors + |> List.groupBy _.Verb + |> List.choose (fun (verb, rows) -> if rows.Length > 1 then Some verb else None) + + let expected = expectedCommands |> Set.ofList + let actual = descriptors |> List.map _.Command |> Set.ofList + let missing = Set.difference expected actual |> Set.toList + let unexpected = Set.difference actual expected |> Set.toList + let blankVerbs = descriptors |> List.filter (fun row -> System.String.IsNullOrWhiteSpace row.Verb) |> List.map _.Command + let undocumented = descriptors |> List.filter (fun row -> not row.Documented) |> List.map _.Command + + let errors = + [ if not duplicateCommands.IsEmpty then yield $"duplicate command descriptors: %A{duplicateCommands}" + if not duplicateVerbs.IsEmpty then yield $"duplicate command verbs: %A{duplicateVerbs}" + if not missing.IsEmpty then yield $"missing command descriptors: %A{missing}" + if not unexpected.IsEmpty then yield $"unexpected command descriptors: %A{unexpected}" + if not blankVerbs.IsEmpty then yield $"blank command verbs: %A{blankVerbs}" + if not undocumented.IsEmpty then yield $"undocumented commands: %A{undocumented}" ] + + if errors.IsEmpty then Ok() else Error errors let renderCommandContract () = let commands = - Microsoft.FSharp.Reflection.FSharpType.GetUnionCases typeof - |> Array.choose (fun case -> - if case.GetFields().Length <> 0 then - None - else - let command = - Microsoft.FSharp.Reflection.FSharpValue.MakeUnion(case, [||]) :?> Command - - match command with - | Help - | Version -> None - | _ -> Some command) - |> Array.sortBy commandName + commandCatalogue + |> List.choose (fun descriptor -> + match descriptor.Command with + | Help + | Version -> None + | _ -> Some descriptor) + |> List.sortBy _.Verb use stream = new System.IO.MemoryStream() use writer = @@ -1365,9 +1194,10 @@ EXIT CODES — the engine's own (the shim translates them for a caller that stil writer.WriteString("schema", "fsgg.coord.commands/1") writer.WriteStartArray("commands") - for command in commands do + for descriptor in commands do + let command = descriptor.Command writer.WriteStartObject() - writer.WriteString("name", commandName command) + writer.WriteString("name", descriptor.Verb) writer.WriteStartArray("flags") let flags = @@ -1415,10 +1245,15 @@ EXIT CODES — the engine's own (the shim translates them for a caller that stil // supported document, the gate exits 0, and the fixture goes red asserting the opposite of // what it means. let writes, gate = - match writeSurface command with - | Writes -> "always", None - | Reads -> "never", None - | WritesIf gate -> "conditional", Some gate + match descriptor.Mutation, writeSurface command with + | WritesRemoteState, Writes -> "always", None + | ReadOnly, Reads -> "never", None + | WritesRemoteState, WritesIf gate -> "conditional", Some gate + | catalogue, behavior -> + failwith ( + $"command catalogue mutation classification disagrees for %s{descriptor.Verb}: " + + $"catalogue=%A{catalogue}, behavior=%A{behavior}" + ) writer.WriteString("writes", writes) @@ -2100,6 +1935,7 @@ EXIT CODES — the engine's own (the shim translates them for a caller that stil | "scan" :: rest -> flags (start { defaults with Command = Scan }) rest | "decide" :: rest -> flags (start { defaults with Command = Decide }) rest | "delivery" :: rest -> flags (start { defaults with Command = DeliveryCmd }) rest + | "self-host" :: rest -> flags (start { defaults with Command = SelfHostCmd }) rest | "review" :: rest -> flags (start { defaults with Command = ReviewCmd }) rest | "driver" :: rest -> flags (start { defaults with Command = DriverCmd }) rest | "cycle" :: rest -> flags (start { defaults with Command = CycleCmd }) rest diff --git a/src/FS.GG.Coord.Cli.Kernel/Options.fsi b/src/FS.GG.Coord.Cli.Kernel/Options.fsi index 4c46c86be..6deac15ce 100644 --- a/src/FS.GG.Coord.Cli.Kernel/Options.fsi +++ b/src/FS.GG.Coord.Cli.Kernel/Options.fsi @@ -19,6 +19,7 @@ module Options = type Command = | Decide | DeliveryCmd + | SelfHostCmd /// .github#2175: inspect the resumable review/repair protocol (`FS.GG.Coord.Review`) — /// live against ` --pr N`, or from a supplied `--snapshot`; the typed surface `pnext-item` /// and the #2135 event projection consume. @@ -171,6 +172,22 @@ module Options = /// stdout is ALWAYS human text: `--text` is kept, `--json` is refused. The #1523 bucket. | TextOnly + type HandlerOwner = + | KernelProgram + | BoardOps + + type MutationKind = + | ReadOnly + | WritesRemoteState + + type CommandDescriptor = + { Command: Command + Verb: string + Render: RenderSupport + Mutation: MutationKind + HandlerOwner: HandlerOwner + Documented: bool } + /// Every nullary command case, derived from the union rather than maintained as a second list. val allCommands: Command list @@ -335,7 +352,18 @@ module Options = /// Which stdout projections a command HAS. Derived by tracing every `opts.Render` read in /// `Client.fs`/`Program.fs` to the handler that reaches it — NOT from the usage prose, which /// under-advertised four of the fourteen honouring commands while `scopeOf` over-advertised twenty. - val renderSupport: c: Command -> RenderSupport + val renderSupport: command: Command -> RenderSupport + + /// One descriptor for every nullary command. During phase-1 coexistence it closes declarative + /// projections over the existing parser/render/write behavior and owns handler-family assignment. + val commandCatalogue: CommandDescriptor list + + /// Structural closure for catalogue consumers. Reports every duplicate, missing, unexpected, + /// blank, or undocumented row together so a command addition gets one actionable failure. + val validateCommandCatalogue: + expectedCommands: Command list -> + descriptors: CommandDescriptor list -> + Result /// A `--repo` token → the `RepoScope.Scope` board rows resolve to: a registry short-id maps /// (`sdd` → `FS.GG.SDD`), an `owner/repo` keeps its repo part, a literal name passes through, and @@ -395,7 +423,7 @@ module Options = /// /// Public since #2418, which keys the GraphQL spend ledger by it. Attribution must name the command /// an operator actually typed, so this stays the one spelling rather than a second table beside it. - val commandName: c: Command -> string + val commandName: command: Command -> string /// The parser's accepted command/flag surface, emitted from the same `scopeOf` table that enforces /// the residue rule. This is machine input; documentation validators must not scrape `usage`. diff --git a/src/FS.GG.Coord.Cli/Client.fs b/src/FS.GG.Coord.Cli/Client.fs index fd30caee1..f88899804 100644 --- a/src/FS.GG.Coord.Cli/Client.fs +++ b/src/FS.GG.Coord.Cli/Client.fs @@ -1378,7 +1378,12 @@ module Client = // Bound after `doneCmd` is defined. The delivery adapter precedes the established completion // transaction in this file, while F# binds values top-to-bottom. - let mutable private completeDelivery: Context -> Options -> int = fun _ _ -> failwith "delivery completion is not initialized" + type private CompletionAuthority = + { Facts: Delivery.Snapshot + Transition: Delivery.Transition } + + let mutable private completeDelivery: CompletionAuthority -> Context -> Options -> int = + fun _ _ _ -> failwith "delivery completion is not initialized" type PathVerdictProjection = | DeliveryReceiptProjection @@ -1882,8 +1887,10 @@ module Client = ObligationsDeclared = obligationsDeclared Obligations = obligations ParkedReason = None } - match Delivery.inspect facts, opts.Apply with - | Delivery.Next transition, true when transition.Action = Delivery.GuardedLand -> + let completionDecision = + facts |> Delivery.completionFacts |> Delivery.decideCompletion + match Delivery.inspect facts, completionDecision, opts.Apply with + | Delivery.Next transition, _, true when transition.Action = Delivery.GuardedLand -> // A delivery receipt authorizes only the exact claim generation that was // inspected. Re-read the winning marker immediately before the REST // write so a released, replaced, or stolen claim cannot merge on stale @@ -1919,11 +1926,17 @@ module Client = printfn "{\"schema\":\"fsgg.coord.delivery/1\",\"verdict\":\"applied\",\"action\":\"guardedLand\",\"freshnessToken\":\"%s\",\"actionKey\":\"%s\"}" transition.FreshnessToken transition.ActionKey | Text -> printfn "merged %s at the inspected head" target.Short ExitGreen - | Delivery.Next transition, true when transition.Action = Delivery.Complete -> + | Delivery.Next transition, Delivery.CompletionDecision.ProjectCompletion, true + when transition.Action = Delivery.Complete -> // Delegate the coupled close / board-Done / own-claim-release sequence to // the existing `done` transaction. Its `Done.verify` re-reads the merged // closer and refuses a stale or unrelated PR before any write. - let code = completeDelivery ctx { opts with Args = [ target.Canonical ]; Pr = pr; Apply = false } + let authority = { Facts = facts; Transition = transition } + let code = + completeDelivery + authority + ctx + { opts with Args = [ target.Canonical ]; Pr = pr; Apply = false } if code <> ExitGreen then code else match Cache.pending () with @@ -1932,7 +1945,7 @@ module Client = eprint $"fsgg-coord-engine: delivery completion left %d{List.length pending} queued board write(s); run `flush` and re-inspect before cleanup." ExitNoVerdict | Error error -> fail error - | Delivery.Next transition, true -> + | Delivery.Next transition, _, true -> eprint $"fsgg-coord-engine: delivery --apply is refused: the sole fresh action is %A{transition.Action}, not guarded landing." ExitNoVerdict | _ -> DeliveryApplication.render opts facts @@ -2276,8 +2289,14 @@ module Client = Reads.prLandable ctx.Transport target.Owner target.Repo pr else Types.PrUnknown - let terminalVerdict = - Review.isOrdinaryExhaustionTerminal draft.HeadSha terminalChecks reviewComments + let terminalDecision = + Review.decideOrdinaryExhaustion + { Phase = Review.Ordinary + HeadSha = draft.HeadSha + CurrentClaimGeneration = string claim.Id + Checks = terminalChecks + Comments = reviewComments + WaitState = Some state } let legacyBody = legacy.Body let legacyMatches = legacyMarkerCount = 1 @@ -2300,10 +2319,6 @@ module Client = && draft.Succession.IsNone let exactWait = receipt.Item = target.Canonical - && receipt.Kind = ReviewWait.RepairConfirmation - && receipt.ReviewGeneration = - ReviewWait.generationToken draft.HeadSha ReviewWait.RepairConfirmation Protocol.reviewPolicy.MaxAutomatedRepairRounds - && receipt.ClaimGeneration <> string claim.Id && evidence = roundThreeComment.Url let freshClaim = claim.Id > legacy.Id match Reads.prHeadSha ctx.Transport target.Owner target.Repo pr with @@ -2311,7 +2326,7 @@ module Client = | Ok liveHead when liveHead <> draft.HeadSha -> Error($"the escalation head is stale: draft %s{draft.HeadSha}, pull request %s{liveHead}") | Ok _ when not expectedKinds -> Error "ordinary exhaustion requires exactly initial plus confirmation rounds 1, 2, and 3" - | Ok _ when not terminalVerdict -> + | Ok _ when terminalDecision <> Review.OrdinaryExhaustionDecision.CompletedOrdinaryExhaustion -> Error "ordinary exhaustion requires changes-required through round 2 and either round-3 changes-required or an exact-head round-3 pass with settled red checks" | Ok _ when not legacyMatches -> Error "legacy ordinary-exhaustion evidence is missing, duplicated, stale, or malformed" | Ok _ when not exactDraft -> Error "the escalation draft does not bind the exact exhausted head, round, digest, critic, and backlinks" @@ -2945,7 +2960,7 @@ module Client = PullRequest = fact pullRequest Blockers = fact blockers Delivery = - fact ({ Outstanding = false; DoneStamped = Done.hasReceipt comments }: LifecycleProjection.Delivery) + fact ({ Outstanding = false; DoneStamped = Done.hasReceiptFor ref comments }: LifecycleProjection.Delivery) Issue = fact issue } let intent = @@ -2975,7 +2990,7 @@ module Client = | Ok comments -> let observedAt = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds() let delivery : LifecycleProjection.Delivery = - { Outstanding = false; DoneStamped = Done.hasReceipt comments } + { Outstanding = false; DoneStamped = Done.hasReceiptFor item.Ref comments } let _, selected = lifecycleSelection observedAt item delivery (LifecycleProjection.tryWatermark comments) match selected with @@ -3458,21 +3473,11 @@ scoped credential) and is tracked at .github#2332, not fixable from this repo's |> fun r -> r.Candidates |> List.map (fun c -> c.Item) - // `CLOSED-ISSUE-NOT-DONE` predates the auditable done receipt and used closure as a - // terminal proxy. Keep its established mechanical writer, but feed it only the terminal - // fact it is entitled to project: a freshly read immutable receipt. An unreadable comment - // collection is deliberately equivalent to no receipt here, so a transient REST failure - // can withhold a repair but can never manufacture Done. - let lifecycleItems = - items - |> List.map (fun item -> - if item.State = Closed && item.Status <> Done then - match Reads.commentBodies ctx.Transport item.Ref.Owner item.Ref.Repo item.Ref.Number with - | Ok comments when Done.hasReceipt comments -> item - | Ok _ - | Error _ -> { item with State = Open } - else - item) + // Preserve the issue state exactly as observed. The typed reducer already withholds a + // closed item that has no verified receipt, and all Status chores from the older generic + // derivation are filtered below. Rewriting Closed to Open here hid the very would-correct + // state the receipt rollout needs to observe. + let lifecycleItems = items // #2264: the board column is a projection, not the source of lifecycle truth. Gather the // facts again at the reconciliation boundary and send every coherent observation through @@ -3483,7 +3488,7 @@ scoped credential) and is tracked at .github#2332, not fixable from this repo's // population and is still skipped below; these columns are the small live queue. // // TWO comment threads, not one (round-1 review repair). The watermark and the done receipt - // are ISSUE facts — `Writes.lifecycleWatermark`/`Writes.doneReceipt` both post to `ref`, + // are ISSUE facts — lifecycle watermarks and typed completion receipts both post to `ref`, // the item itself — so `item.Ref.Number`'s thread is the right and only place to read them. // A delivery obligation/receipt is a PR fact: every other caller of // `DeliveryApplication.obligationsFromComments` in this file (`driver --events`'s @@ -3583,10 +3588,23 @@ scoped credential) and is tracked at .github#2332, not fixable from this repo's || item.Status = BoardStatus.Ready) let delivery = - if not needsDeliveryRead then Some (({ Outstanding = false; DoneStamped = false }: LifecycleProjection.Delivery), None) + if not needsDeliveryRead then + Some( + ({ Outstanding = false; DoneStamped = false }: LifecycleProjection.Delivery), + None, + false, + false + ) else match Reads.commentBodies ctx.Transport item.Ref.Owner item.Ref.Repo item.Ref.Number with - | Error _ -> None + | Error error -> + lifecycleHealthRows.Add( + {| current = statusWireName item.Status + intended = $"withheld: completion evidence unreadable: %s{Errors.explain error}" + intent = "unknown" + readComplete = false + subject = item.Ref.Canonical |}) + None | Ok issueComments -> // No PR yet ⇒ nothing has been merged to owe a release obligation, so // `Outstanding = false` — the same "nothing to check" reading @@ -3602,42 +3620,123 @@ scoped credential) and is tracked at .github#2332, not fixable from this repo's outstandingObligations (Reads.prHeadSha ctx.Transport item.Ref.Owner item.Ref.Repo pr) (Reads.commentsWithIdentity ctx.Transport item.Ref.Owner item.Ref.Repo pr) - Some - (({ Outstanding = outstanding - DoneStamped = Done.hasReceipt issueComments }: LifecycleProjection.Delivery), - LifecycleProjection.tryWatermark issueComments) + let completionState = Done.receiptStateFor item.Ref issueComments + let correctionState = Done.completionCorrectionStateFor item.Ref issueComments + match completionState, correctionState with + | Done.InvalidCompletionReceipt errors, _ -> + let detail = String.concat "; " errors + lifecycleHealthRows.Add( + {| current = statusWireName item.Status + intended = $"withheld: invalid delivery completion evidence: %s{detail}" + intent = "unknown" + readComplete = false + subject = item.Ref.Canonical |}) + eprint + $"fsgg-coord-engine: reconcile: %s{item.Ref.Short} has invalid delivery completion evidence: %s{detail}" + None + | _, Done.InvalidCompletionCorrection errors -> + let detail = String.concat "; " errors + lifecycleHealthRows.Add( + {| current = statusWireName item.Status + intended = $"withheld: invalid completion correction evidence: %s{detail}" + intent = "unknown" + readComplete = false + subject = item.Ref.Canonical |}) + eprint + $"fsgg-coord-engine: reconcile: %s{item.Ref.Short} has invalid completion correction evidence: %s{detail}" + None + | receiptState, correctionState -> + let doneStamped = + match receiptState with + | Done.VerifiedCompletionReceipt _ -> true + | Done.LegacyReceipt + | Done.NoReceipt -> false + | Done.InvalidCompletionReceipt _ -> false + let correctionPending = + match correctionState with + | Done.VerifiedCompletionCorrection _ -> true + | Done.NoCompletionCorrection + | Done.InvalidCompletionCorrection _ -> false + let needsCorrection = + item.State = Closed + && (receiptState = Done.NoReceipt || receiptState = Done.LegacyReceipt) + && correctionState = Done.NoCompletionCorrection + let needsCompletionProjection = + match receiptState with + | Done.VerifiedCompletionReceipt _ -> + item.State <> Closed || item.Status <> Done + | _ -> false + Some + (({ Outstanding = outstanding || correctionPending + DoneStamped = doneStamped }: LifecycleProjection.Delivery), + LifecycleProjection.tryWatermark issueComments, + needsCorrection, + needsCompletionProjection) match delivery with | None -> chores, watermarks // an unreadable fact withholds its write; scheduled reconciliation retries. - | Some(delivery, watermark) -> + | Some(delivery, watermark, needsCorrection, needsCompletionProjection) -> let observedAt = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds() let intent, selected = lifecycleSelection observedAt item delivery watermark + let correctionDestination = + if not (List.isEmpty item.Blockers) && not (Blockers.cleared item.Blockers) then + Blocked + else + InReview + let selectedForHealth = + if needsCompletionProjection then + LifecycleProjection.Project(Done, observedAt) + elif needsCorrection then + LifecycleProjection.Project(correctionDestination, observedAt) + else + selected lifecycleHealthRows.Add( {| current = statusWireName item.Status - intended = resultLabel selected + intended = resultLabel selectedForHealth intent = intentLabel intent readComplete = true subject = item.Ref.Canonical |}) - match selected with - | LifecycleProjection.Project(destination, timestamp) -> - match Chore.lifecycleProjection item destination with + if needsCompletionProjection then + match Chore.completionProjection item with + | Some chore -> + chore :: chores, + Map.add item.Ref + ({ ObservedAt = observedAt + Status = Done + Intent = intent }: LifecycleProjection.Watermark) + watermarks + | None -> chores, watermarks + elif needsCorrection then + match Chore.prematureCompletion item correctionDestination with | Some chore -> chore :: chores, Map.add item.Ref - ({ ObservedAt = timestamp - Status = destination + ({ ObservedAt = observedAt + Status = correctionDestination Intent = intent }: LifecycleProjection.Watermark) watermarks | None -> chores, watermarks - // NEITHER A CHORE NOR A WATERMARK (.github#2712 AC2 — "no park, no promote, no - // `Done`, no watermark"). This arm is the second half of the exemption and it - // is not redundant with the reducer's: `advance` decides that no STATUS is - // projected, and this decides that no RECEIPT is persisted either. A watermark - // written here would be a durable ordering fact about a lifecycle the row does - // not have, and `tryWatermark` would keep re-asserting it with a fresh - // `ObservedAt` on every pass. - | LifecycleProjection.Exempt _ -> chores, watermarks - | LifecycleProjection.Withheld _ -> chores, watermarks) ([], Map.empty) + else + match selected with + | LifecycleProjection.Project(destination, timestamp) -> + match Chore.lifecycleProjection item destination with + | Some chore -> + chore :: chores, + Map.add item.Ref + ({ ObservedAt = timestamp + Status = destination + Intent = intent }: LifecycleProjection.Watermark) + watermarks + | None -> chores, watermarks + // NEITHER A CHORE NOR A WATERMARK (.github#2712 AC2 — "no park, no promote, no + // `Done`, no watermark"). This arm is the second half of the exemption and it + // is not redundant with the reducer's: `advance` decides that no STATUS is + // projected, and this decides that no RECEIPT is persisted either. A watermark + // written here would be a durable ordering fact about a lifecycle the row does + // not have, and `tryWatermark` would keep re-asserting it with a fresh + // `ObservedAt` on every pass. + | LifecycleProjection.Exempt _ -> chores, watermarks + | LifecycleProjection.Withheld _ -> chores, watermarks) ([], Map.empty) // Scheduling Status has one authority: the intent reducer above. `Chore.derive` remains // responsible only for non-lifecycle maintenance such as stale-claim cleanup and Class. @@ -4013,6 +4112,68 @@ scoped credential) and is tracked at .github#2332, not fixable from this repo's // definition once another actor can clear `Blocked by`. let resolvedStatus = if field = "Status" then Reads.statusOfName value else None + // The durable correction fact is written before its mutable Status + // projection. A retry may observe the same authority and proceed, but + // contradictory/malformed evidence or a completion receipt that won + // the race refuses the board mutation. + let completionProjectionGate = + match chore.Kind, resolvedStatus with + | Chore.CompletionProjection, Some Done -> + match Reads.commentBodies ctx.Transport chore.Subject.Owner chore.Subject.Repo chore.Subject.Number with + | Error error -> + eprint + $"fsgg-coord-engine: reconcile: %s{chore.Subject.Short} completion receipt could not be re-read before projection: %s{Errors.explain error}" + Error ExitError + | Ok comments -> + match Done.receiptStateFor chore.Subject comments with + | Done.VerifiedCompletionReceipt _ -> + match Writes.closeIssueCompleted ctx.Transport chore.Subject with + | Ok () -> Ok () + | Error error -> + eprint + $"fsgg-coord-engine: reconcile: %s{chore.Subject.Short} completion receipt is valid but issue closure was not freshly verified: %s{Errors.explain error}" + Error ExitError + | state -> + eprint + $"fsgg-coord-engine: reconcile: %s{chore.Subject.Short} completion authority changed before projection: %A{state}" + Error ExitError + | Chore.PrematureCompletion correction, Some actual + when Chore.completionCorrectionStatus correction = actual -> + let destination = Chore.completionCorrectionStatus correction + match + Delivery.createCompletionCorrectionReceipt + chore.Subject.Canonical + destination + DateTimeOffset.UtcNow + with + | Error errors -> + let detail = String.concat "; " errors + eprint + $"fsgg-coord-engine: reconcile: %s{chore.Subject.Short} completion correction could not be authorized: %s{detail}" + Error ExitError + | Ok receipt -> + match Writes.completionCorrectionReceipt ctx.Transport chore.Subject receipt with + | Ok () -> + match Writes.reopenIssue ctx.Transport chore.Subject with + | Ok () -> Ok () + | Error error -> + eprint + $"fsgg-coord-engine: reconcile: %s{chore.Subject.Short} correction receipt landed but issue reopen was not freshly verified: %s{Errors.explain error}" + Error ExitError + | Error error -> + eprint + $"fsgg-coord-engine: reconcile: %s{chore.Subject.Short} completion correction receipt could not be persisted: %s{Errors.explain error}" + Error ExitError + | Chore.PrematureCompletion _, _ -> + eprint + $"fsgg-coord-engine: reconcile: %s{chore.Subject.Short} completion correction has no valid Status destination" + Error ExitError + | Chore.CompletionProjection, _ -> + eprint + $"fsgg-coord-engine: reconcile: %s{chore.Subject.Short} completion projection has no valid Done destination" + Error ExitError + | _ -> Ok () + let blockedGate = if field = "Status" then match resolvedStatus, Map.tryFind chore.Subject lifecycleWatermarks with @@ -4028,7 +4189,9 @@ scoped credential) and is tracked at .github#2332, not fixable from this repo's Ok() let gate = - if field = "Status" then + if Result.isError completionProjectionGate then + completionProjectionGate + elif field = "Status" then // .github#2698 — THE SEAM WITH NO OPERATOR IN IT, and the one // the filed acceptance criterion did not name. A host measured // `reconcile --apply` reporting `LIFECYCLE-PROJECTION-LAG … @@ -4093,7 +4256,10 @@ scoped credential) and is tracked at .github#2332, not fixable from this repo's // a route refusal was reported to the operator as a // "Status=Blocked coherence gate" refusal, naming a gate that had // returned `Ok`. - let routeRefused = Result.isError gate && Result.isOk blockedGate + let routeRefused = + Result.isOk completionProjectionGate + && Result.isError gate + && Result.isOk blockedGate let outcome = match gate with @@ -4127,7 +4293,7 @@ scoped credential) and is tracked at .github#2332, not fixable from this repo's // contains the projected status; otherwise a late event could // be suppressed by a receipt for a mutation that never landed. match chore.Kind, Map.tryFind chore.Subject lifecycleWatermarks with - | Chore.LifecycleProjectionLag _, Some watermark -> + | (Chore.LifecycleProjectionLag _ | Chore.PrematureCompletion _ | Chore.CompletionProjection), Some watermark -> match Writes.lifecycleWatermark ctx.Transport chore.Subject (LifecycleProjection.watermarkMarker watermark) with | Error e -> failed <- true @@ -4171,6 +4337,9 @@ scoped credential) and is tracked at .github#2332, not fixable from this repo's NotAttempted $"%s{chore.Subject.Short} has no current delivery-route receipt, so Status=Ready was NOT written — a row promoted without one is unschedulable. The route is an agent judgement this pass may not make: scripts/fsgg-coord delivery-route record %s{chore.Subject.Short} " )) + | Ok Board.NotOnBoard when Result.isError completionProjectionGate -> + failed <- true + reconcileRow chore (Some(Failed "completion projection authority could not be persisted or verified")) | Ok Board.NotOnBoard when Result.isError gate -> failed <- true reconcileRow chore (Some(Failed "Status=Blocked coherence gate refused the stale reconcile write")) @@ -4904,7 +5073,7 @@ scoped credential) and is tracked at .github#2332, not fixable from this repo's $"fsgg-coord-engine: REFUSING to reap %s{ref.Short} — worker %s{w} (idle %d{idleM}m), PR #%d{pr} is %s{Landable.name verdict}, not open." eprint - $"fsgg-coord-engine: The claim outlived its PR. Do NOT close anything — look at PR #%d{pr} and, if it MERGED, stamp the item: scripts/fsgg-coord done %s{ref.Short} --flip --pr %d{pr}" + $"fsgg-coord-engine: The claim outlived its PR. Do NOT close anything — look at PR #%d{pr} and, if it MERGED, complete delivery: scripts/fsgg-coord delivery %s{ref.Short} --pr %d{pr} --flip --apply" | (PrRed | PrConflicted) as verdict -> // The one genuinely-abandoned case — and the ONLY one that may // advise closing. A conflicted or red PR is not finished work. @@ -5660,7 +5829,7 @@ scoped credential) and is tracked at .github#2332, not fixable from this repo's eprint $"fsgg-coord-engine: worker '%s{w.Id}' ALREADY HOLDS %s{names}. A claim reserves a touch-set, so a second one locks files nobody is editing for the rest of the lease (%d{opts.LeaseMinutes}m) — and `batch` will refuse every item that overlaps it (#516)." - eprint " Finish or drop the item you hold: scripts/fsgg-coord done --flip (or: release )" + eprint " Finish or drop the item you hold: scripts/fsgg-coord delivery --pr --flip --apply (or: release )" // #1620: `--force` now carries a SECOND, destructive power — it STEALS a live claim. // This line points a worker at the flag for the #516 override alone, so it has to say @@ -6440,7 +6609,7 @@ scoped credential) and is tracked at .github#2332, not fixable from this repo's eprint $" gh api -X PUT repos/%s{ref.Owner}/%s{ref.Repo}/pulls/%d{pnum}/merge -f merge_method=squash" - eprint $" scripts/fsgg-coord done %s{ref.Short} --flip" + eprint $" scripts/fsgg-coord delivery %s{ref.Short} --pr %d{pnum} --flip --apply" ExitGreen else rc @@ -6473,7 +6642,7 @@ scoped credential) and is tracked at .github#2332, not fixable from this repo's $"fsgg-coord-engine: PR #%d{pnum} on %s{ref.Short} is ALREADY MERGED — there is nothing to adopt, and nothing to land. The work is done; what is missing is the STAMP." eprint - $" scripts/fsgg-coord done %s{ref.Short} --flip --pr %d{pnum}" + $" scripts/fsgg-coord delivery %s{ref.Short} --pr %d{pnum} --flip --apply" ExitRed | PrClosed -> @@ -6819,7 +6988,7 @@ scoped credential) and is tracked at .github#2332, not fixable from this repo's $"fsgg-coord-engine: landable: PR #%d{pr} is ALREADY MERGED — there is nothing to gate, and --wait does not poll it." eprint - $"fsgg-coord-engine: This is a TERMINAL verdict, not a retry. If you are recovering an item whose worker died between merge and stamp, the work LANDED — go stamp it: scripts/fsgg-coord done --flip --pr %d{pr}" + $"fsgg-coord-engine: This is a TERMINAL verdict, not a retry. If you are recovering an item whose worker died between merge and completion projection, the work LANDED — complete delivery: scripts/fsgg-coord delivery --pr %d{pr} --flip --apply" if state = PrClosed then eprint @@ -9152,7 +9321,7 @@ scoped credential) and is tracked at .github#2332, not fixable from this repo's /// to them. let roomOpen (ctx: Context) (opts: Options) : int = Handlers.roomOpen ctx opts - let doneCmd (ctx: Context) (opts: Options) : int = + let private runDone (completionAuthority: CompletionAuthority option) (ctx: Context) (opts: Options) : int = match oneArg opts "done: an issue ref", worker opts with | Error c, _ | _, Error c -> c @@ -9168,7 +9337,59 @@ scoped credential) and is tracked at .github#2332, not fixable from this repo's match Done.facts ctx.Transport board ref with | Error e -> fail e | Ok facts -> - let verdict = Done.verify opts.Pr opts.Evidence facts + // A correction receipt proves this issue was previously observed CLOSED without + // completion authority and was reopened by reconciliation. Delivery completion may + // therefore verify the historical closing merge while the mutable issue projection + // is OPEN; standalone `done` retains the ordinary CLOSED precondition. + let factsForVerdict = + match completionAuthority, facts.State with + | Some _, Open -> + match Reads.commentBodies ctx.Transport ref.Owner ref.Repo ref.Number with + | Error error -> + failwith( + "delivery completion could not read its correction evidence: " + + Errors.explain error + ) + | Ok comments -> + match Done.completionCorrectionStateFor ref comments with + | Done.VerifiedCompletionCorrection _ -> { facts with State = Closed } + | Done.InvalidCompletionCorrection errors -> + failwith( + "delivery completion found invalid correction evidence: " + + String.concat "; " errors + ) + | Done.NoCompletionCorrection -> facts + | _ -> facts + let verdict = Done.verify opts.Pr opts.Evidence factsForVerdict + let verdict = + match completionAuthority, verdict with + | None, Green(Done.ClosedByPullRequest(actualPr, mergeSha, _, _)) -> + match Reads.commentBodies ctx.Transport ref.Owner ref.Repo ref.Number with + | Error error -> + Red + [ "standalone done could not read typed completion authority: " + + Errors.explain error ] + | Ok comments -> + match Done.receiptStateFor ref comments with + | Done.VerifiedCompletionReceipt receipt + when receipt.PullRequest = actualPr && receipt.MergeSha = mergeSha -> + verdict + | Done.VerifiedCompletionReceipt receipt -> + Red + [ $"standalone done found typed completion authority for PR #%d{receipt.PullRequest} @ %s{receipt.MergeSha}, not the verified closer PR #%d{actualPr} @ %s{mergeSha}" ] + | Done.LegacyReceipt -> + Red + [ "legacy done evidence is not completion authority; run delivery --pr --flip --apply to verify the exact merge and mint a typed receipt" ] + | Done.NoReceipt -> + Red + [ "standalone done cannot mint completion authority; run delivery --pr --flip --apply first" ] + | Done.InvalidCompletionReceipt errors -> + Red + [ "typed completion authority is invalid: " + String.concat "; " errors ] + | None, Green _ -> + Red + [ "standalone done requires typed pull-request completion authority; non-PR completion cannot be projected terminal" ] + | _ -> verdict printfn "%s" (Done.render ref verdict) // .github#2444 — `.github#2427`'s own acceptance criterion, and #733's precedent @@ -9181,17 +9402,83 @@ scoped credential) and is tracked at .github#2332, not fixable from this repo's match verdict with | Verdict.NoVerdict _ -> ExitNoVerdict | Red _ -> ExitRed - | Green _ -> + | Green closure -> // Write durable evidence before the mutable Project projection. If the latter // is deferred, the scheduled lifecycle reconciler can later prove that this was // a verified terminal transition rather than guessing from issue closure. // `renderReceipt`, not `render`: the durable comment deliberately keeps the // passed-over-foreign-closer note for provenance even though stdout no longer // does (.github#2444). - match Writes.doneReceipt ctx.Transport ref (Done.renderReceipt ref verdict) with - | Error e -> - eprint $"fsgg-coord-engine: verified done but could not record its lifecycle receipt: %s{Errors.explain e}" - | Ok() -> () + match completionAuthority, closure with + | Some authority, Done.ClosedByPullRequest(actualPr, mergeSha, _, _) + when authority.Facts.Freshness.PullRequest = Some actualPr -> + match Reads.commentBodies ctx.Transport ref.Owner ref.Repo ref.Number with + | Error error -> + failwith( + "delivery completion could not establish self-host replay authority: " + + Errors.explain error + ) + | Ok comments -> + match Done.selfHostReplayState comments with + | SelfHost.NoBootstrap + | SelfHost.VerifiedReplay _ -> () + | SelfHost.ReplayRequired bootstrap -> + failwith( + $"delivery completion is blocked until the shared engine records post-merge replay for self-host bootstrap %s{bootstrap.Digest}" + ) + | SelfHost.InvalidReplay errors -> + failwith( + "delivery completion found invalid self-host replay evidence: " + + String.concat "; " errors + ) + match + Delivery.advance + authority.Transition.FreshnessToken + authority.Transition.ActionKey + authority.Facts + with + | Delivery.Next current when current.Action = Delivery.Complete -> + match + Delivery.createCompletionReceipt + ref.Canonical + actualPr + mergeSha + DateTimeOffset.UtcNow + current.FreshnessToken + current.ActionKey + (Delivery.completionFacts authority.Facts) + with + | Error errors -> + failwith( + "delivery completion receipt was refused after merge verification: " + + String.concat "; " errors + ) + | Ok receipt -> + match Writes.deliveryCompletionReceipt ctx.Transport ref receipt with + | Ok () -> + if facts.State = Open then + match Writes.closeIssueCompleted ctx.Transport ref with + | Ok () -> () + | Error error -> + failwith( + "delivery completion receipt landed but issue closure could not be freshly verified: " + + Errors.explain error + ) + | Error error -> + failwith( + "verified delivery completion could not append its receipt: " + + Errors.explain error + ) + | decision -> + failwithf "delivery completion transition changed after merge verification: %A" decision + | Some _, Done.ClosedByPullRequest(actualPr, _, _, _) -> + failwithf "delivery completion pull request changed after inspection: %A" actualPr + | Some _, _ -> + failwith "delivery completion requires a verified pull-request merge" + | None, _ -> + // Standalone `done` is now a replay-only projection over a matching typed + // completion receipt. The admission above makes this branch write-free. + () // Stamp the board Done. A board-write failure leaves the stamp GREEN (the work // IS done) and reports the note — the same rule as the bash client. #1151: the // outcome was `|> ignore`d directly under the "reports the note" comment, so a @@ -9415,7 +9702,9 @@ scoped credential) and is tracked at .github#2332, not fixable from this repo's // has no readable/durable disposition. ExitRed - do completeDelivery <- doneCmd + let doneCmd (ctx: Context) (opts: Options) : int = runDone None ctx opts + + do completeDelivery <- fun authority ctx opts -> runDone (Some authority) ctx opts // ---- #498/ADR-0044: the generated artifacts drift is subtracted against ------------------------- @@ -11381,6 +11670,69 @@ scoped credential) and is tracked at .github#2332, not fixable from this repo's eprint "fsgg-coord-engine: graphql: expected project-visibility OWNER TITLE | project-id OWNER NUMBER | repository-policy OWNER NAME | meter | archive-scan PROJECT-ID | archive-items PROJECT-ID ID... | roster-board OWNER TITLE" ExitError + let private selfHostRecord (ctx: Context) (opts: Options) : int = + match opts.Args with + | [ "record"; rawRef; receiptPath ] -> + match parseRef ctx rawRef with + | Error message -> eprint $"fsgg-coord-engine: self-host: %s{message}"; ExitError + | Ok ref -> + try + match File.ReadAllText receiptPath |> SelfHost.tryDecodeReceipt with + | Error errors -> + let detail = String.concat "; " errors + eprint $"fsgg-coord-engine: self-host: %s{detail}" + ExitRed + | Ok None -> + eprint "fsgg-coord-engine: self-host: receipt marker is missing" + ExitRed + | Ok(Some receipt) -> + match Writes.selfHostBootstrapReceipt ctx.Transport ref receipt with + | Error error -> fail error + | Ok () -> + printfn "SELF-HOST-RECORDED %s %s" ref.Short receipt.Digest + ExitGreen + with error -> + eprint $"fsgg-coord-engine: self-host: could not read receipt: %s{error.Message}" + ExitError + | [ "replay-record"; rawRef; receiptPath; snapshotPath; decisionKey; actionKey ] -> + match parseRef ctx rawRef with + | Error message -> eprint $"fsgg-coord-engine: self-host: %s{message}"; ExitError + | Ok ref -> + try + match File.ReadAllText receiptPath |> SelfHost.tryDecodeReceipt with + | Error errors -> + let detail = String.concat "; " errors + eprint $"fsgg-coord-engine: self-host: %s{detail}" + ExitRed + | Ok None -> + eprint "fsgg-coord-engine: self-host: bootstrap receipt marker is missing" + ExitRed + | Ok(Some bootstrap) -> + use stream = File.OpenRead snapshotPath + let snapshotHash = SHA256.HashData stream |> Convert.ToHexString |> _.ToLowerInvariant() + SelfHost.createReplayReceipt + bootstrap + snapshotHash + { DecisionKey = decisionKey; ActionKey = actionKey } + DateTimeOffset.UtcNow + |> function + | Error errors -> + let detail = String.concat "; " errors + eprint $"fsgg-coord-engine: self-host: %s{detail}" + ExitRed + | Ok receipt -> + match Writes.selfHostReplayReceipt ctx.Transport ref receipt with + | Error error -> fail error + | Ok () -> + printfn "SELF-HOST-REPLAY-RECORDED %s %s" ref.Short receipt.Digest + ExitGreen + with error -> + eprint $"fsgg-coord-engine: self-host: could not record replay: %s{error.Message}" + ExitError + | _ -> + eprint "fsgg-coord-engine: self-host needs `record ` or `replay-record `." + ExitError + let run (boardOpsHandlers: Map) (opts: Options) : int = // #548: the bare-`` default is resolved from what the CALLER actually passed, so it must be read // BEFORE the #480 rewrite below replaces `Repo` with the git-remote scope. That rewrite goes through @@ -11462,6 +11814,7 @@ scoped credential) and is tracked at .github#2332, not fixable from this repo's | DoneCmd -> doneCmd ctx opts | VerifyPaths -> verifyPaths ctx opts | GraphQlOps -> graphQlOps ctx opts + | SelfHostCmd -> selfHostRecord ctx opts | LintCmd -> lint ctx opts | RouteCmd -> deliveryRouteCmd ctx opts | other -> failwith $"Client.run received a non-IO command: %A{other}" diff --git a/src/FS.GG.Coord.Cli/FS.GG.Coord.Cli.fsproj b/src/FS.GG.Coord.Cli/FS.GG.Coord.Cli.fsproj index 47893e4aa..e2d147544 100644 --- a/src/FS.GG.Coord.Cli/FS.GG.Coord.Cli.fsproj +++ b/src/FS.GG.Coord.Cli/FS.GG.Coord.Cli.fsproj @@ -130,7 +130,16 @@ bytes under 0.52.0 would make the same version identify different artifacts. Ado coherent set cut from corrected source. All three partial sets are recorded in `registry/dependencies.yml`. - 0.72.0 — verified file-backed comment mutation. + 0.73.0 — typed change-risk authority and receipted completion. + +WHAT MOVED, AND WHY IT IS A MINOR. Review and delivery now advance through typed lifecycle decisions, +one command catalogue owns parser/help/handler/write classification, standalone `done` is nonterminal, +and only the exact `delivery --apply` transition emits completion authority. Candidate writes require a +digest-bound self-host receipt, CI gains a bounded change-completeness gate, and release recovery carries +durable receipts. Packed skills prescribe the new terminal route. These are additive safety and workflow +semantics; no package, command, or public member identity is removed (.github#2830). + +0.72.0 — verified file-backed comment mutation. WHAT MOVED, AND WHY IT IS A MINOR. The coordination client adds `comment create` and explicit-id `comment amend`, reads the exact comment back from the authoritative paginated collection, verifies diff --git a/src/FS.GG.Coord.Cli/Program.fs b/src/FS.GG.Coord.Cli/Program.fs index 22cf1f733..e15ab5d13 100644 --- a/src/FS.GG.Coord.Cli/Program.fs +++ b/src/FS.GG.Coord.Cli/Program.fs @@ -1,6 +1,7 @@ module FS.GG.Coord.Cli.Program open System +open System.Diagnostics open System.IO open System.Reflection open FS.GG.Coord @@ -310,6 +311,153 @@ let private decide (opts: Options) = | Red _ -> ExitRed | NoVerdict _ -> ExitNoVerdict +let private selfHost (opts: Options) = + let readReceipt path = + try + File.ReadAllText path + |> SelfHost.tryDecodeReceipt + |> Result.bind (function + | Some receipt -> Ok receipt + | None -> Error [ "file does not contain a self-host bootstrap receipt" ]) + with ex -> Error [ $"could not read self-host receipt '%s{path}': %s{ex.Message}" ] + + let refuse errors = + eprint ("fsgg-coord-engine: self-host refused: " + String.concat "; " errors) + ExitRed + + let gitValue repo arguments = + let start = ProcessStartInfo("git") + start.WorkingDirectory <- repo + start.UseShellExecute <- false + start.RedirectStandardOutput <- true + start.RedirectStandardError <- true + for argument in arguments do start.ArgumentList.Add argument + use git = Process.Start start + let value = git.StandardOutput.ReadToEnd().Trim() + git.WaitForExit() + if git.ExitCode = 0 && not (String.IsNullOrWhiteSpace value) then Some value else None + + match opts.Args with + | [ "mint"; proposalPath; candidatePath; snapshotPath; outputPath ] -> + try + use proposal = System.Text.Json.JsonDocument.Parse(File.ReadAllText proposalPath) + let root = proposal.RootElement + let text (name: string) (element: System.Text.Json.JsonElement) = element.GetProperty(name).GetString() + let reason = + match text "reason" root with + | "new-schema-case" -> Ok SelfHost.BootstrapReason.NewSchemaCase + | "relocated-decision-boundary" -> Ok SelfHost.BootstrapReason.RelocatedDecisionBoundary + | value -> Error [ $"unknown self-host bootstrap reason '%s{value}'" ] + match reason with + | Error errors -> refuse errors + | Ok reason -> + let evidence = root.GetProperty "evidence" + let host = root.GetProperty "hostAcceptance" + use candidateStream = File.OpenRead candidatePath + use snapshotStream = File.OpenRead snapshotPath + let candidateHash = Security.Cryptography.SHA256.HashData candidateStream |> Convert.ToHexString |> _.ToLowerInvariant() + let snapshotHash = Security.Cryptography.SHA256.HashData snapshotStream |> Convert.ToHexString |> _.ToLowerInvariant() + let start = ProcessStartInfo(candidatePath) + start.UseShellExecute <- false + start.RedirectStandardOutput <- true + start.RedirectStandardError <- true + start.ArgumentList.Add "--version" + use candidate = Process.Start start + let version = candidate.StandardOutput.ReadToEnd().Trim() + candidate.WaitForExit() + if candidate.ExitCode <> 0 then refuse [ "candidate engine could not report its version" ] + else + SelfHost.createReceipt + (text "baseSha" root) + (text "candidateHeadSha" root) + candidateHash + version + (text "sharedRefusal" root) + snapshotHash + reason + { Build = text "build" evidence + Unit = text "unit" evidence + FocusedProductionRoute = text "focusedProductionRoute" evidence + Provenance = text "provenance" evidence + Inversion = text "inversion" evidence } + (text "candidateDecisionKey" root) + (text "candidateActionKey" root) + { Actor = text "actor" host + AcceptedAt = host.GetProperty("acceptedAt").GetDateTimeOffset() } + |> function + | Error errors -> refuse errors + | Ok receipt -> + File.WriteAllText(outputPath, SelfHost.encodeReceipt receipt) + printfn "SELF-HOST-RECEIPT %s" receipt.Digest + ExitGreen + with ex -> refuse [ "could not mint self-host receipt: " + ex.Message ] + | "verify" :: receiptPath :: candidatePath :: repoPaths when List.length repoPaths <= 1 -> + match readReceipt receiptPath with + | Error errors -> refuse errors + | Ok receipt -> + try + use stream = File.OpenRead candidatePath + let actual = Security.Cryptography.SHA256.HashData stream |> Convert.ToHexString |> _.ToLowerInvariant() + if actual <> receipt.CandidateBinarySha256.ToLowerInvariant() then + refuse [ "candidate binary SHA-256 does not match the bootstrap receipt" ] + else + let start = ProcessStartInfo(candidatePath) + start.UseShellExecute <- false + start.RedirectStandardOutput <- true + start.RedirectStandardError <- true + start.ArgumentList.Add "--version" + use candidate = Process.Start start + let reportedVersion = candidate.StandardOutput.ReadToEnd().Trim() + candidate.WaitForExit() + if candidate.ExitCode <> 0 then + refuse [ "candidate engine could not report its version" ] + elif reportedVersion <> receipt.CandidateVersion then + refuse + [ $"candidate reported version '%s{reportedVersion}', not receipt version '%s{receipt.CandidateVersion}'" ] + else + let gitErrors = + match repoPaths with + | [] -> [] + | [ repo ] -> + [ match gitValue repo [ "rev-parse"; "HEAD" ] with + | Some head when head = receipt.CandidateHeadSha -> () + | Some head -> yield $"candidate checkout HEAD '%s{head}' does not match receipt head '%s{receipt.CandidateHeadSha}'" + | None -> yield "candidate checkout HEAD could not be read" + let baseValue = + gitValue repo [ "merge-base"; "HEAD"; "refs/remotes/origin/main" ] + |> Option.orElseWith (fun () -> gitValue repo [ "merge-base"; "HEAD"; "refs/remotes/origin/master" ]) + match baseValue with + | Some actual when actual = receipt.BaseSha -> () + | Some actual -> yield $"candidate checkout base '%s{actual}' does not match receipt base '%s{receipt.BaseSha}'" + | None -> yield "candidate checkout base could not be established" ] + | _ -> [] + match gitErrors, SelfHost.authorizeWrite receipt with + | _ :: _, _ -> refuse gitErrors + | [], Error errors -> refuse errors + | [], Ok () -> + printfn "SELF-HOST-AUTHORIZED %s %s" receipt.CandidateHeadSha receipt.Digest + ExitGreen + with ex -> refuse [ $"could not hash candidate binary '%s{candidatePath}': %s{ex.Message}" ] + | [ "replay"; receiptPath; snapshotPath; decisionKey; actionKey ] -> + match readReceipt receiptPath with + | Error errors -> refuse errors + | Ok receipt -> + try + use stream = File.OpenRead snapshotPath + let actual = Security.Cryptography.SHA256.HashData stream |> Convert.ToHexString |> _.ToLowerInvariant() + if actual <> receipt.SnapshotSha256.ToLowerInvariant() then + refuse [ "replay snapshot SHA-256 does not match the bootstrap receipt" ] + else + match SelfHost.verifyReplay receipt { DecisionKey = decisionKey; ActionKey = actionKey } with + | Error errors -> refuse errors + | Ok () -> + printfn "SELF-HOST-REPLAY-AGREES %s" receipt.Digest + ExitGreen + with ex -> refuse [ $"could not hash replay snapshot '%s{snapshotPath}': %s{ex.Message}" ] + | _ -> + eprint "fsgg-coord-engine: self-host needs `mint `, `verify [repo]`, or `replay `." + ExitError + let private legacyHandler (opts: Options) = match opts.Command with | Help -> @@ -328,6 +476,8 @@ let private legacyHandler (opts: Options) = | Decide -> decide opts | DeliveryCmd when opts.SnapshotFile.IsSome -> DeliveryApplication.run opts | DeliveryCmd -> runClient opts + | SelfHostCmd when opts.Args |> List.tryHead |> Option.exists (fun value -> value = "record" || value = "replay-record") -> runClient opts + | SelfHostCmd -> selfHost opts | ReviewCmd when opts.SnapshotFile.IsSome -> ReviewApplication.run opts | ReviewCmd -> runClient opts | LanesView -> lanes opts @@ -381,6 +531,7 @@ let private legacyCommands = Scan Decide DeliveryCmd + SelfHostCmd ReviewCmd LanesView Facts diff --git a/src/FS.GG.Coord.Cli/ReviewApplication.fs b/src/FS.GG.Coord.Cli/ReviewApplication.fs index 1deeb8f58..3b17648cc 100644 --- a/src/FS.GG.Coord.Cli/ReviewApplication.fs +++ b/src/FS.GG.Coord.Cli/ReviewApplication.fs @@ -299,24 +299,20 @@ module ReviewApplication = expiresAt = receipt.ExpiresAt evidenceRef = receipt.EvidenceRef |} - let private isCompletedOrdinaryExhaustion (binding: Review.Binding) (facts: Review.Facts) (waitState: ReviewWait.State option) = - match binding.Phase, waitState with - | Review.Ordinary, Some (ReviewWait.Completed (receipt, _)) -> - receipt.Kind = ReviewWait.RepairConfirmation - && receipt.ClaimGeneration <> binding.ClaimGeneration - && receipt.ReviewGeneration = - ReviewWait.generationToken - binding.HeadSha - ReviewWait.RepairConfirmation - Protocol.reviewPolicy.MaxAutomatedRepairRounds - && Review.isOrdinaryExhaustionTerminal binding.HeadSha facts.Checks facts.Comments - | _ -> false - - let private hasRecordedRepairPhaseEntry (binding: Review.Binding) (facts: Review.Facts) (waitState: ReviewWait.State option) = + let private ordinaryExhaustionDecision (binding: Review.Binding) (facts: Review.Facts) waitState = + Review.decideOrdinaryExhaustion + { Phase = binding.Phase + HeadSha = binding.HeadSha + CurrentClaimGeneration = binding.ClaimGeneration + Checks = facts.Checks + Comments = facts.Comments + WaitState = waitState } + + let private hasRecordedRepairPhaseEntry (facts: Review.Facts) ordinaryExhaustionCompleted = let phaseFacts = Driver.reviewPhaseFacts facts.Comments - isCompletedOrdinaryExhaustion binding facts waitState && phaseFacts.EscalationPresent + ordinaryExhaustionCompleted && phaseFacts.EscalationPresent - let private waitAuthority (binding: Review.Binding) (facts: Review.Facts) (state: Review.State) (action: Review.NextAction) (waitState: ReviewWait.State option) = + let private waitAuthority (binding: Review.Binding) (facts: Review.Facts) ordinaryExhaustionCompleted (state: Review.State) (action: Review.NextAction) (waitState: ReviewWait.State option) = let dispatchAuthority = match action with | Review.DispatchCritic -> Some(ReviewWait.InitialReview, ReviewWait.generationToken binding.HeadSha ReviewWait.InitialReview 0) @@ -325,7 +321,7 @@ module ReviewApplication = Some(ReviewWait.RepairConfirmation, ReviewWait.generationToken binding.HeadSha ReviewWait.RepairConfirmation round) | _ -> None match waitState, dispatchAuthority with - | _ when hasRecordedRepairPhaseEntry binding facts waitState -> + | _ when hasRecordedRepairPhaseEntry facts ordinaryExhaustionCompleted -> Error [ "the structured ordinary-exhaustion escalation is recorded; enter the fresh repair phase " + "instead of dispatching, resuming, accepting, or manufacturing ordinary round four on the exhausted pull request" ] @@ -362,6 +358,10 @@ module ReviewApplication = (repairAssertionGranted: Review.RepairAssertionReceipt option) (waitState: ReviewWait.State option) : int = + let exhaustionDecision = ordinaryExhaustionDecision binding facts waitState + let ordinaryExhaustionCompleted = + exhaustionDecision = Review.OrdinaryExhaustionDecision.CompletedOrdinaryExhaustion + match Review.inspect binding facts successionGranted repairAssertionGranted with | Error reasons -> match opts.Render with @@ -373,16 +373,13 @@ module ReviewApplication = ExitCode.toInt ExitCode.NoVerdict | Ok verdict -> let verdict = - if isCompletedOrdinaryExhaustion binding facts waitState then - Review.projectCompletedOrdinaryExhaustion binding facts verdict - else - verdict + Review.projectOrdinaryExhaustion exhaustionDecision binding facts verdict let waitStatus, waitReceipt, waitReason = waitProjection waitState let waitStatus = - if hasRecordedRepairPhaseEntry binding facts waitState then Some "repairPhaseEntry" - elif isCompletedOrdinaryExhaustion binding facts waitState then Some "ordinaryExhaustion" + if hasRecordedRepairPhaseEntry facts ordinaryExhaustionCompleted then Some "repairPhaseEntry" + elif ordinaryExhaustionCompleted then Some "ordinaryExhaustion" else waitStatus - match waitAuthority binding facts verdict.State verdict.NextAction waitState, opts.Render with + match waitAuthority binding facts ordinaryExhaustionCompleted verdict.State verdict.NextAction waitState, opts.Render with | Error reasons, Json -> printfn "%s" diff --git a/src/FS.GG.Coord.Core/Chore.fs b/src/FS.GG.Coord.Core/Chore.fs index f7ac3b0e4..4e4f5db29 100644 --- a/src/FS.GG.Coord.Core/Chore.fs +++ b/src/FS.GG.Coord.Core/Chore.fs @@ -13,9 +13,19 @@ module Chore = | Quick -> "quick" | Involved -> "involved" + type CompletionCorrectionStatus = + | CorrectionInReview + | CorrectionBlocked + + let completionCorrectionStatus = function + | CorrectionInReview -> InReview + | CorrectionBlocked -> Blocked + type ChoreKind = | StaleClaim of holder: WorkerId | LifecycleProjectionLag of destination: BoardStatus + | PrematureCompletion of destination: CompletionCorrectionStatus + | CompletionProjection | ClassProjectionLag of declared: ItemClass | KindProjectionLag of declared: ItemKind @@ -23,6 +33,8 @@ module Chore = match this with | StaleClaim _ -> "STALE-CLAIM" | LifecycleProjectionLag _ -> "LIFECYCLE-PROJECTION-LAG" + | PrematureCompletion _ -> "PREMATURE-COMPLETION" + | CompletionProjection -> "COMPLETION-PROJECTION-LAG" | ClassProjectionLag _ -> "CLASS-PROJECTION-LAG" | KindProjectionLag _ -> "KIND-PROJECTION-LAG" @@ -30,6 +42,8 @@ module Chore = match this with | StaleClaim _ -> None | LifecycleProjectionLag destination -> Some("Status", statusWireName destination) + | PrematureCompletion destination -> Some("Status", destination |> completionCorrectionStatus |> statusWireName) + | CompletionProjection -> Some("Status", statusWireName Done) | ClassProjectionLag declared -> Some("Class", itemClassWireName declared) // IN CORE, beside its sibling, never in `Client.fs` — the field mapping lives here precisely // so the write target and the vocabulary are one decision (`Client.fs`'s own note at the @@ -50,6 +64,10 @@ module Chore = $"%s{subject.Short}: %s{holder.Value}'s lease has lapsed and the item has no open `item/` PR — collect the marker and restore the column it overwrote." | LifecycleProjectionLag destination -> $"%s{subject.Short}: fresh lifecycle facts project Status=%s{statusWireName destination}; repair the stale board projection." + | PrematureCompletion destination -> + $"%s{subject.Short}: the issue closed without authoritative completion evidence; preserve a correction receipt and restore the nonterminal Status=%s{destination |> completionCorrectionStatus |> statusWireName}." + | CompletionProjection -> + $"%s{subject.Short}: authoritative completion evidence exists; repair issue closure and Status=Done from that receipt." | ClassProjectionLag declared -> $"%s{subject.Short}: the item's own text declares `Class: %s{itemClassWireName declared}` but the board's Class column does not say so — set Class to %s{itemClassWireName declared}." | KindProjectionLag declared -> @@ -118,12 +136,24 @@ module Chore = if item.Status = destination || destination = NoStatus then None else Some(Chore(item.Ref, LifecycleProjectionLag destination, Quick)) + let prematureCompletion (item: Item) destination = + match destination with + | InReview -> Some(Chore(item.Ref, PrematureCompletion CorrectionInReview, Quick)) + | Blocked -> Some(Chore(item.Ref, PrematureCompletion CorrectionBlocked, Quick)) + | _ -> None + + let completionProjection (item: Item) = + if item.State = Closed && item.Status = Done then None + else Some(Chore(item.Ref, CompletionProjection, Quick)) + let private rank (chore: Chore) = match chore.Kind with | StaleClaim _ -> 0 - | LifecycleProjectionLag _ -> 1 - | ClassProjectionLag _ -> 2 - | KindProjectionLag _ -> 3 + | PrematureCompletion _ -> 1 + | CompletionProjection -> 2 + | LifecycleProjectionLag _ -> 3 + | ClassProjectionLag _ -> 4 + | KindProjectionLag _ -> 5 let offerIncluding (at: SafePoint) (lifecycle: Chore list) = derive at.Items @ lifecycle diff --git a/src/FS.GG.Coord.Core/Chore.fsi b/src/FS.GG.Coord.Core/Chore.fsi index d1eb8ecae..6c2b3a111 100644 --- a/src/FS.GG.Coord.Core/Chore.fsi +++ b/src/FS.GG.Coord.Core/Chore.fsi @@ -11,10 +11,21 @@ module Chore = member Label: string + /// The only safe destinations after premature issue closure. + type CompletionCorrectionStatus = + | CorrectionInReview + | CorrectionBlocked + + val completionCorrectionStatus: CompletionCorrectionStatus -> BoardStatus + /// Non-lifecycle maintenance plus the reducer's one Status repair carrier. type ChoreKind = | StaleClaim of holder: WorkerId | LifecycleProjectionLag of destination: BoardStatus + /// Receipt-free issue closure must be restored to a safe nonterminal projection. + | PrematureCompletion of destination: CompletionCorrectionStatus + /// A typed completion receipt exists but issue/Projects projections are incomplete. + | CompletionProjection | ClassProjectionLag of declared: ItemClass /// The board's `Kind` column disagrees with the item's own `Kind:` line (.github#2712). /// @@ -63,6 +74,12 @@ module Chore = /// Carry the one verified intent-reducer destination into the reconcile write path. val lifecycleProjection: item: Item -> destination: BoardStatus -> Chore option + /// Carry the fail-closed completion correction chosen from the same observed item facts. + val prematureCompletion: item: Item -> destination: BoardStatus -> Chore option + + /// Carry repair of issue closure and Status=Done from existing typed completion authority. + val completionProjection: item: Item -> Chore option + val offer: at: SafePoint -> Chore option /// Rank reducer-produced lifecycle repairs beside maintenance without deriving a second Status authority. val offerIncluding: at: SafePoint -> lifecycle: Chore list -> Chore option diff --git a/src/FS.GG.Coord.Core/Delivery.fs b/src/FS.GG.Coord.Core/Delivery.fs index 684a5c3c1..399fea198 100644 --- a/src/FS.GG.Coord.Core/Delivery.fs +++ b/src/FS.GG.Coord.Core/Delivery.fs @@ -2,8 +2,11 @@ namespace FS.GG.Coord module Delivery = open System + open System.Globalization open System.Security.Cryptography open System.Text + open System.Text.Json + open Types type Stage = | Claimed @@ -159,6 +162,59 @@ module Delivery = Obligations: Obligation list ParkedReason: string option } + type CompletionFacts = + { HeadSha: string + Merged: bool + MergeReachable: bool + IssueClosed: bool + BoardDone: bool + ClaimReleased: bool + PendingWrites: int + CleanupEligible: bool + ObligationsDeclared: bool + Obligations: Obligation list } + + [] + type CompletionDecision = + | NotMerged + | Refused of reason: string + | VerifyOutstandingObligation of name: string + | ProjectCompletion + | CleanupCompletedDelivery + + type VerifiedObligationReceipt = + { Id: string + Kind: string + Evidence: string + HeadSha: string } + + type DeliveryCompletionReceipt = + { Item: string + PullRequest: int + MergeSha: string + MergeReachable: bool + ObligationReceipts: VerifiedObligationReceipt list + PendingBoardWrites: int + FreshnessToken: string + ActionKey: string + CompletedAt: DateTimeOffset + Digest: string } + + // Durable evidence that reconciliation observed premature issue closure before authoritative + // completion. The public contract is documented in Delivery.fsi; implementation-side XML comments + // would be discarded when a sibling signature exists. + type CompletionCorrectionReceipt = + { Item: string + Destination: BoardStatus + ObservedAt: DateTimeOffset + Digest: string } + + [] + let CompletionReceiptMarker = "" + + [] + let CompletionCorrectionMarker = "" + type Action = | ContinueImplementation | RepairReviewHandoff of reason: string @@ -229,7 +285,7 @@ module Delivery = // released, nothing pending) has nothing left to touch, so `CleanupWorktree` does not need to know // what it once reserved — demanding the field here would block a stamped item's cleanup transition // forever on a residual empty fact (.github#2233, the measured `#2225` residue). - let private declaredPathsProblem snapshot = + let private declaredPathsProblem (snapshot: Snapshot) = if snapshot.CleanupEligible then None else @@ -240,7 +296,7 @@ module Delivery = | Known [] -> Some "declared paths" | Known _ -> None - let private validate snapshot = + let private validate (snapshot: Snapshot) = let freshness = snapshot.Freshness [ missing freshness.ItemRef "item ref" missing freshness.ClaimGeneration "claim generation" @@ -255,11 +311,288 @@ module Delivery = declaredPathsProblem snapshot ] |> List.choose id - let private next snapshot stage action = + let private next (snapshot: Snapshot) stage action = let token = freshnessToken snapshot.Freshness let actionKey = digest $"%s{token}\n%A{stage}\n%A{action}" Next { Stage = stage; Action = action; FreshnessToken = token; ActionKey = actionKey } + let completionFacts (snapshot: Snapshot) = + { HeadSha = snapshot.Freshness.HeadSha + Merged = snapshot.Merged + MergeReachable = snapshot.MergeReachable + IssueClosed = snapshot.IssueClosed + BoardDone = snapshot.BoardDone + ClaimReleased = snapshot.ClaimReleased + PendingWrites = snapshot.PendingWrites + CleanupEligible = snapshot.CleanupEligible + ObligationsDeclared = snapshot.ObligationsDeclared + Obligations = snapshot.Obligations } + + let decideCompletion (facts: CompletionFacts) = + if not facts.Merged then + CompletionDecision.NotMerged + elif facts.PendingWrites < 0 then + CompletionDecision.Refused "pending board writes cannot be negative" + elif not facts.ObligationsDeclared then + CompletionDecision.Refused "delivery obligations are undeclared" + else + let duplicate = + facts.Obligations + |> List.groupBy _.Id + |> List.tryFind (fun (_, obligations) -> List.length obligations > 1) + let stale = + facts.Obligations + |> List.tryFind (fun obligation -> obligation.HeadSha <> facts.HeadSha) + let contradictory = + facts.Obligations + |> List.tryFind (fun obligation -> + obligation.Verified <> obligation.Evidence.IsSome + || (obligation.Evidence |> Option.exists String.IsNullOrWhiteSpace)) + + match duplicate, stale, contradictory with + | Some (id, _), _, _ -> + CompletionDecision.Refused($"delivery obligation '%s{id}' is declared more than once") + | _, Some obligation, _ -> + CompletionDecision.Refused( + $"delivery obligation '%s{obligation.Id}' is for head %s{obligation.HeadSha}, not %s{facts.HeadSha}" + ) + | _, _, Some obligation -> + CompletionDecision.Refused( + $"delivery obligation '%s{obligation.Id}' has contradictory verification evidence" + ) + | _ -> + match facts.Obligations |> List.tryFind (fun obligation -> not obligation.Verified) with + | Some obligation -> CompletionDecision.VerifyOutstandingObligation obligation.Id + | None when not facts.MergeReachable -> + CompletionDecision.Refused "merged pull request is not reachable from the default branch" + | None when not facts.IssueClosed || not facts.BoardDone || not facts.ClaimReleased || facts.PendingWrites <> 0 -> + CompletionDecision.ProjectCompletion + | None when not facts.CleanupEligible -> + CompletionDecision.Refused "cleanup is not eligible before completion" + | None -> CompletionDecision.CleanupCompletedDelivery + + let private completionReceiptDigest (receipt: DeliveryCompletionReceipt) = + [ receipt.Item + string receipt.PullRequest + receipt.MergeSha + string receipt.MergeReachable + string receipt.PendingBoardWrites + receipt.FreshnessToken + receipt.ActionKey + receipt.CompletedAt.ToUniversalTime().ToString("O") + yield! + receipt.ObligationReceipts + |> List.sortBy (fun obligation -> obligation.Id, obligation.Kind) + |> List.collect (fun obligation -> + [ obligation.Id + obligation.Kind + obligation.Evidence + obligation.HeadSha ]) ] + |> String.concat "\n" + |> digest + + let createCompletionReceipt item pullRequest mergeSha completedAt freshnessToken actionKey facts = + let missing name value = + if String.IsNullOrWhiteSpace value then Some($"%s{name} is required") else None + let errors = + [ missing "item" item + if pullRequest <= 0 then Some "pull request must be positive" else None + missing "merge SHA" mergeSha + missing "freshness token" freshnessToken + missing "action key" actionKey ] + |> List.choose id + + match errors, decideCompletion facts with + | _ :: _, _ -> Error errors + | [], CompletionDecision.ProjectCompletion -> + let obligations = + facts.Obligations + |> List.map (fun obligation -> + { Id = obligation.Id + Kind = obligation.Kind + Evidence = obligation.Evidence.Value + HeadSha = obligation.HeadSha }) + let unsigned = + { Item = item + PullRequest = pullRequest + MergeSha = mergeSha + MergeReachable = facts.MergeReachable + ObligationReceipts = obligations + PendingBoardWrites = facts.PendingWrites + FreshnessToken = freshnessToken + ActionKey = actionKey + CompletedAt = completedAt + Digest = "" } + Ok { unsigned with Digest = completionReceiptDigest unsigned } + | [], decision -> + Error [ $"completion receipt is not authorized by decision %A{decision}" ] + + let verifyCompletionReceipt (receipt: DeliveryCompletionReceipt) = + let errors = + [ if String.IsNullOrWhiteSpace receipt.Item then yield "item is required" + if receipt.PullRequest <= 0 then yield "pull request must be positive" + if String.IsNullOrWhiteSpace receipt.MergeSha then yield "merge SHA is required" + if not receipt.MergeReachable then yield "merge is not reachable" + if receipt.PendingBoardWrites <> 0 then yield "pending board writes must be zero" + if String.IsNullOrWhiteSpace receipt.FreshnessToken then yield "freshness token is required" + if String.IsNullOrWhiteSpace receipt.ActionKey then yield "action key is required" + if receipt.ObligationReceipts |> List.exists (fun obligation -> + String.IsNullOrWhiteSpace obligation.Id + || String.IsNullOrWhiteSpace obligation.Kind + || String.IsNullOrWhiteSpace obligation.Evidence + || String.IsNullOrWhiteSpace obligation.HeadSha) then + yield "verified obligation receipts must be complete" + let duplicateIds = + receipt.ObligationReceipts + |> List.countBy _.Id + |> List.choose (fun (id, count) -> if count > 1 then Some id else None) + if not (List.isEmpty duplicateIds) then + let names = String.concat ", " duplicateIds + yield $"verified obligation receipts contain duplicate ids: %s{names}" + if completionReceiptDigest { receipt with Digest = "" } <> receipt.Digest then + yield "completion receipt digest does not match its facts" ] + if List.isEmpty errors then Ok () else Error errors + + let encodeCompletionReceipt (receipt: DeliveryCompletionReceipt) = + let obligations = + receipt.ObligationReceipts + |> List.map (fun obligation -> + {| id = obligation.Id + kind = obligation.Kind + evidence = obligation.Evidence + headSha = obligation.HeadSha |}) + |> List.toArray + let payload = + {| schema = "fsgg.coord.delivery-completion/v1" + item = receipt.Item + pullRequest = receipt.PullRequest + mergeSha = receipt.MergeSha + mergeReachable = receipt.MergeReachable + obligationReceipts = obligations + pendingBoardWrites = receipt.PendingBoardWrites + freshnessToken = receipt.FreshnessToken + actionKey = receipt.ActionKey + completedAt = receipt.CompletedAt.ToUniversalTime().ToString("O", CultureInfo.InvariantCulture) + digest = receipt.Digest |} + CompletionReceiptMarker + "\n" + JsonSerializer.Serialize payload + + let tryDecodeCompletionReceipt (body: string) = + if not (body.StartsWith(CompletionReceiptMarker, StringComparison.Ordinal)) then + Ok None + else + try + use document = JsonDocument.Parse(body.Substring(CompletionReceiptMarker.Length).Trim()) + let root = document.RootElement + let requiredString (name: string) (element: JsonElement) = + match element.TryGetProperty name with + | true, value when value.ValueKind = JsonValueKind.String && not (String.IsNullOrWhiteSpace(value.GetString())) -> + value.GetString() + | _ -> invalidArg name "must be a non-empty string" + let requiredInt (name: string) (element: JsonElement) = + match element.TryGetProperty name with + | true, value when value.ValueKind = JsonValueKind.Number -> value.GetInt32() + | _ -> invalidArg name "must be an integer" + let requiredBool (name: string) (element: JsonElement) = + match element.TryGetProperty name with + | true, value when value.ValueKind = JsonValueKind.True -> true + | true, value when value.ValueKind = JsonValueKind.False -> false + | _ -> invalidArg name "must be a boolean" + + if requiredString "schema" root <> "fsgg.coord.delivery-completion/v1" then + invalidArg "schema" "must be fsgg.coord.delivery-completion/v1" + let obligationsElement = root.GetProperty "obligationReceipts" + if obligationsElement.ValueKind <> JsonValueKind.Array then + invalidArg "obligationReceipts" "must be an array" + let obligations = + obligationsElement.EnumerateArray() + |> Seq.map (fun obligation -> + { Id = requiredString "id" obligation + Kind = requiredString "kind" obligation + Evidence = requiredString "evidence" obligation + HeadSha = requiredString "headSha" obligation }) + |> Seq.toList + let receipt: DeliveryCompletionReceipt = + { Item = requiredString "item" root + PullRequest = requiredInt "pullRequest" root + MergeSha = requiredString "mergeSha" root + MergeReachable = requiredBool "mergeReachable" root + ObligationReceipts = obligations + PendingBoardWrites = requiredInt "pendingBoardWrites" root + FreshnessToken = requiredString "freshnessToken" root + ActionKey = requiredString "actionKey" root + CompletedAt = DateTimeOffset.Parse(requiredString "completedAt" root, CultureInfo.InvariantCulture, DateTimeStyles.RoundtripKind) + Digest = requiredString "digest" root } + match verifyCompletionReceipt receipt with + | Ok () -> Ok(Some receipt) + | Error errors -> Error errors + with error -> Error [ error.Message ] + + let private completionCorrectionDigest (receipt: CompletionCorrectionReceipt) = + [ "fsgg.coord.completion-correction/v1" + receipt.Item + statusWireName receipt.Destination + receipt.ObservedAt.ToUniversalTime().ToString("O", CultureInfo.InvariantCulture) ] + |> String.concat "\n" + |> digest + + let verifyCompletionCorrectionReceipt (receipt: CompletionCorrectionReceipt) = + let errors = + [ if String.IsNullOrWhiteSpace receipt.Item then yield "item is required" + match receipt.Destination with + | BoardStatus.InReview + | BoardStatus.Blocked -> () + | destination -> + yield $"completion correction destination must be In review or Blocked, not %s{statusWireName destination}" + if completionCorrectionDigest { receipt with Digest = "" } <> receipt.Digest then + yield "completion correction receipt digest does not match its facts" ] + if List.isEmpty errors then Ok () else Error errors + + let createCompletionCorrectionReceipt (item: string) (destination: BoardStatus) (observedAt: DateTimeOffset) = + let unsigned: CompletionCorrectionReceipt = + { Item = item + Destination = destination + ObservedAt = observedAt + Digest = "" } + let signed = { unsigned with Digest = completionCorrectionDigest unsigned } + verifyCompletionCorrectionReceipt signed |> Result.map (fun () -> signed) + + let encodeCompletionCorrectionReceipt receipt = + let payload = + {| schema = "fsgg.coord.completion-correction/v1" + item = receipt.Item + destination = statusWireName receipt.Destination + observedAt = receipt.ObservedAt.ToUniversalTime().ToString("O", CultureInfo.InvariantCulture) + digest = receipt.Digest |} + CompletionCorrectionMarker + "\n" + JsonSerializer.Serialize payload + + let tryDecodeCompletionCorrectionReceipt (body: string) = + if not (body.StartsWith(CompletionCorrectionMarker, StringComparison.Ordinal)) then + Ok None + else + try + use document = JsonDocument.Parse(body.Substring(CompletionCorrectionMarker.Length).Trim()) + let root = document.RootElement + let requiredString (name: string) : string = + match root.TryGetProperty name with + | true, value when value.ValueKind = JsonValueKind.String && not (String.IsNullOrWhiteSpace(value.GetString())) -> + value.GetString() + | _ -> invalidArg name "must be a non-empty string" + if requiredString "schema" <> "fsgg.coord.completion-correction/v1" then + invalidArg "schema" "must be fsgg.coord.completion-correction/v1" + let destination = + match requiredString "destination" with + | "In review" -> BoardStatus.InReview + | "Blocked" -> BoardStatus.Blocked + | value -> invalidArg "destination" $"must be In review or Blocked, not '%s{value}'" + let receipt: CompletionCorrectionReceipt = + { Item = requiredString "item" + Destination = destination + ObservedAt = DateTimeOffset.Parse(requiredString "observedAt", CultureInfo.InvariantCulture, DateTimeStyles.RoundtripKind) + Digest = requiredString "digest" } + verifyCompletionCorrectionReceipt receipt + |> Result.map (fun () -> Some receipt) + with error -> Error [ error.Message ] + let private handoffProblem snapshot = if not snapshot.ItemBranchCanonical then Some "item branch is not canonical" elif not snapshot.ClosingLinkageCanonical then Some "canonical closing linkage is missing" @@ -348,17 +681,13 @@ module Delivery = match snapshot.ParkedReason with | Some reason when not (String.IsNullOrWhiteSpace reason) -> next snapshot Parked (RouteFollowUp reason) | _ when snapshot.Merged -> - if not snapshot.ObligationsDeclared then NoVerdict "delivery obligations are undeclared" - else - match snapshot.Obligations |> List.tryFind (fun obligation -> not obligation.Verified) with - | Some obligation -> next snapshot MergedAwaitingObligations (VerifyObligation obligation.Id) - | None when not snapshot.MergeReachable -> NoVerdict "merged pull request is not reachable from the default branch" - | None when not snapshot.IssueClosed -> next snapshot MergedAwaitingObligations Complete - | None when not snapshot.BoardDone -> next snapshot MergedAwaitingObligations Complete - | None when not snapshot.ClaimReleased -> next snapshot MergedAwaitingObligations Complete - | None when snapshot.PendingWrites <> 0 -> next snapshot MergedAwaitingObligations Complete - | None when not snapshot.CleanupEligible -> NoVerdict "cleanup is not eligible before completion" - | None -> next snapshot Done CleanupWorktree + match decideCompletion (completionFacts snapshot) with + | CompletionDecision.NotMerged -> NoVerdict "completion facts do not describe a merged pull request" + | CompletionDecision.Refused reason -> NoVerdict reason + | CompletionDecision.VerifyOutstandingObligation name -> + next snapshot MergedAwaitingObligations (VerifyObligation name) + | CompletionDecision.ProjectCompletion -> next snapshot MergedAwaitingObligations Complete + | CompletionDecision.CleanupCompletedDelivery -> next snapshot Done CleanupWorktree | _ when Option.isNone snapshot.Freshness.PullRequest -> next snapshot Implementation ContinueImplementation | _ -> diff --git a/src/FS.GG.Coord.Core/Delivery.fsi b/src/FS.GG.Coord.Core/Delivery.fsi index a916532cb..044149977 100644 --- a/src/FS.GG.Coord.Core/Delivery.fsi +++ b/src/FS.GG.Coord.Core/Delivery.fsi @@ -2,6 +2,7 @@ namespace FS.GG.Coord /// Pure, fail-closed lifecycle decisions for a single claimed coordination item. module Delivery = + open Types /// The durable stage established by the facts currently available for an item. /// /// `ReviewActive` and `Landable` divide the post-handoff window on ONE question, and .github#2575 @@ -122,6 +123,103 @@ module Delivery = Obligations: Obligation list ParkedReason: string option } + /// Complete facts for deciding whether a merged delivery must verify an obligation, project + /// completion, refuse, or may proceed to cleanup. + type CompletionFacts = + { HeadSha: string + Merged: bool + MergeReachable: bool + IssueClosed: bool + BoardDone: bool + ClaimReleased: bool + PendingWrites: int + CleanupEligible: bool + ObligationsDeclared: bool + Obligations: Obligation list } + + [] + type CompletionDecision = + | NotMerged + | Refused of reason: string + | VerifyOutstandingObligation of name: string + | ProjectCompletion + | CleanupCompletedDelivery + + type VerifiedObligationReceipt = + { Id: string + Kind: string + Evidence: string + HeadSha: string } + + /// Durable authority written before issue, board, claim, and cleanup projections. + type DeliveryCompletionReceipt = + { Item: string + PullRequest: int + MergeSha: string + MergeReachable: bool + ObligationReceipts: VerifiedObligationReceipt list + PendingBoardWrites: int + FreshnessToken: string + ActionKey: string + CompletedAt: System.DateTimeOffset + Digest: string } + + /// Durable nonterminal authority emitted after premature closure is observed. This receipt never + /// authorizes Done; it preserves the safe correction across the issue reopen it requests. + type CompletionCorrectionReceipt = + { Item: string + Destination: BoardStatus + ObservedAt: System.DateTimeOffset + Digest: string } + + [] + val CompletionReceiptMarker: string = "" + + [] + val CompletionCorrectionMarker: string = "" + + /// Select only the completion facts from the wider delivery snapshot. + val completionFacts: Snapshot -> CompletionFacts + + /// One completion authority shared by lifecycle projection and live writer admission. + val decideCompletion: CompletionFacts -> CompletionDecision + + /// Mint a digest-bound receipt only for the exact transition currently eligible to project completion. + val createCompletionReceipt: + item: string -> + pullRequest: int -> + mergeSha: string -> + completedAt: System.DateTimeOffset -> + freshnessToken: string -> + actionKey: string -> + facts: CompletionFacts -> + Result + + /// Recompute every structural and digest invariant without consulting mutable projections. + val verifyCompletionReceipt: DeliveryCompletionReceipt -> Result + + /// Stable append-only marker plus deterministic JSON payload. + val encodeCompletionReceipt: DeliveryCompletionReceipt -> string + + /// Ignore unrelated comments, parse matching markers, and reject malformed or digest-invalid receipts. + val tryDecodeCompletionReceipt: body: string -> Result + + /// Mint only a safe nonterminal correction (`In review` or `Blocked`). + val createCompletionCorrectionReceipt: + item: string -> + destination: BoardStatus -> + observedAt: System.DateTimeOffset -> + Result + + /// Reject unsafe destinations, incomplete identity, or changed signed facts. + val verifyCompletionCorrectionReceipt: CompletionCorrectionReceipt -> Result + + /// Stable append-only marker plus deterministic JSON payload. + val encodeCompletionCorrectionReceipt: CompletionCorrectionReceipt -> string + + /// Ignore unrelated comments and fail closed on malformed or digest-invalid correction evidence. + val tryDecodeCompletionCorrectionReceipt: body: string -> Result + /// The one action a worker or host may take next. Judgement remains outside this union. type Action = | ContinueImplementation diff --git a/src/FS.GG.Coord.Core/FS.GG.Coord.Core.fsproj b/src/FS.GG.Coord.Core/FS.GG.Coord.Core.fsproj index da2cddba6..f6998c4a7 100644 --- a/src/FS.GG.Coord.Core/FS.GG.Coord.Core.fsproj +++ b/src/FS.GG.Coord.Core/FS.GG.Coord.Core.fsproj @@ -47,6 +47,8 @@ compiled at all. --> + + " + + [] + let ReplayReceiptMarker = "" + + let private reasonName = function + | BootstrapReason.NewSchemaCase -> "new-schema-case" + | BootstrapReason.RelocatedDecisionBoundary -> "relocated-decision-boundary" + + let private tryReason = function + | "new-schema-case" -> Ok BootstrapReason.NewSchemaCase + | "relocated-decision-boundary" -> Ok BootstrapReason.RelocatedDecisionBoundary + | value -> Error [ $"unknown self-host bootstrap reason '%s{value}'" ] + + let private canonical receipt = + [ receipt.BaseSha + receipt.CandidateHeadSha + receipt.CandidateBinarySha256.ToLowerInvariant() + receipt.CandidateVersion + receipt.SharedRefusal + receipt.SnapshotSha256.ToLowerInvariant() + reasonName receipt.Reason + receipt.Evidence.Build + receipt.Evidence.Unit + receipt.Evidence.FocusedProductionRoute + receipt.Evidence.Provenance + receipt.Evidence.Inversion + receipt.CandidateDecisionKey + receipt.CandidateActionKey + receipt.HostAcceptance.Actor + receipt.HostAcceptance.AcceptedAt.ToUniversalTime().ToString("O") ] + |> String.concat "\n" + + let private digest receipt = + canonical receipt + |> Encoding.UTF8.GetBytes + |> SHA256.HashData + |> Convert.ToHexString + |> _.ToLowerInvariant() + + let private validate receipt = + let required name value = + if String.IsNullOrWhiteSpace value then Some $"%s{name} is required" else None + let errors = + [ required "baseSha" receipt.BaseSha + required "candidateHeadSha" receipt.CandidateHeadSha + required "candidateVersion" receipt.CandidateVersion + required "sharedRefusal" receipt.SharedRefusal + required "build evidence" receipt.Evidence.Build + required "unit evidence" receipt.Evidence.Unit + required "focused production-route evidence" receipt.Evidence.FocusedProductionRoute + required "provenance evidence" receipt.Evidence.Provenance + required "inversion evidence" receipt.Evidence.Inversion + required "candidateDecisionKey" receipt.CandidateDecisionKey + required "candidateActionKey" receipt.CandidateActionKey + required "host acceptance actor" receipt.HostAcceptance.Actor + if receipt.HostAcceptance.AcceptedAt = DateTimeOffset.MinValue then + Some "host acceptance timestamp is required" + else None + if receipt.CandidateBinarySha256.Length <> 64 + || receipt.CandidateBinarySha256 |> Seq.exists (fun c -> not (Uri.IsHexDigit c)) then + Some "candidateBinarySha256 must be exactly 64 hexadecimal characters" + else None ] + |> List.choose id + let errors = + if receipt.SnapshotSha256.Length <> 64 + || receipt.SnapshotSha256 |> Seq.exists (fun c -> not (Uri.IsHexDigit c)) then + "snapshotSha256 must be exactly 64 hexadecimal characters" :: errors + else errors + if List.isEmpty errors then Ok () else Error errors + + let authorizeWrite receipt = + match validate receipt with + | Error errors -> Error errors + | Ok () -> + let expected = digest { receipt with Digest = "" } + if String.Equals(expected, receipt.Digest, StringComparison.Ordinal) then Ok () + else Error [ "self-host bootstrap receipt digest does not match its bound fields" ] + + let createReceipt baseSha candidateHeadSha candidateBinarySha256 candidateVersion sharedRefusal snapshotSha256 reason evidence candidateDecisionKey candidateActionKey hostAcceptance = + let unsigned = + { BaseSha = baseSha + CandidateHeadSha = candidateHeadSha + CandidateBinarySha256 = candidateBinarySha256 + CandidateVersion = candidateVersion + SharedRefusal = sharedRefusal + SnapshotSha256 = snapshotSha256 + Reason = reason + Evidence = evidence + CandidateDecisionKey = candidateDecisionKey + CandidateActionKey = candidateActionKey + HostAcceptance = hostAcceptance + Digest = "" } + match validate unsigned with + | Error errors -> Error errors + | Ok () -> Ok { unsigned with Digest = digest unsigned } + + let verifyReplay (receipt: SelfHostBootstrapReceipt) (replay: Replay) = + authorizeWrite receipt + |> Result.bind (fun () -> + [ if replay.DecisionKey <> receipt.CandidateDecisionKey then + yield "post-merge shared-engine decision key disagrees with the candidate receipt" + if replay.ActionKey <> receipt.CandidateActionKey then + yield "post-merge shared-engine action key disagrees with the candidate receipt" ] + |> function [] -> Ok () | errors -> Error errors) + + let private replayCanonical (receipt: SelfHostReplayReceipt) = + [ receipt.BootstrapDigest.ToLowerInvariant() + receipt.SnapshotSha256.ToLowerInvariant() + receipt.DecisionKey + receipt.ActionKey + receipt.ReplayedAt.ToUniversalTime().ToString("O") ] + |> String.concat "\n" + + let private replayDigest (receipt: SelfHostReplayReceipt) = + replayCanonical receipt + |> Encoding.UTF8.GetBytes + |> SHA256.HashData + |> Convert.ToHexString + |> _.ToLowerInvariant() + + let private validSha (value: string) = + not (isNull value) + && value.Length = 64 + && (value |> Seq.forall Uri.IsHexDigit) + + let private validateReplayReceipt (receipt: SelfHostReplayReceipt) = + [ if not (validSha receipt.BootstrapDigest) then + yield "bootstrapDigest must be exactly 64 hexadecimal characters" + if not (validSha receipt.SnapshotSha256) then + yield "snapshotSha256 must be exactly 64 hexadecimal characters" + if String.IsNullOrWhiteSpace receipt.DecisionKey then yield "decisionKey is required" + if String.IsNullOrWhiteSpace receipt.ActionKey then yield "actionKey is required" + if receipt.ReplayedAt = DateTimeOffset.MinValue then yield "replayedAt is required" ] + |> function [] -> Ok () | errors -> Error errors + + let verifyReplayReceipt (bootstrap: SelfHostBootstrapReceipt) (receipt: SelfHostReplayReceipt) = + authorizeWrite bootstrap + |> Result.bind (fun () -> validateReplayReceipt receipt) + |> Result.bind (fun () -> + let expected = replayDigest { receipt with Digest = "" } + if not (String.Equals(expected, receipt.Digest, StringComparison.Ordinal)) then + Error [ "self-host replay receipt digest does not match its bound fields" ] + elif not (String.Equals(bootstrap.Digest, receipt.BootstrapDigest, StringComparison.Ordinal)) then + Error [ "self-host replay receipt does not name the durable bootstrap authority" ] + elif not (String.Equals(bootstrap.SnapshotSha256, receipt.SnapshotSha256, StringComparison.OrdinalIgnoreCase)) then + Error [ "post-merge shared-engine replay used a different snapshot" ] + else + verifyReplay bootstrap { DecisionKey = receipt.DecisionKey; ActionKey = receipt.ActionKey }) + + let createReplayReceipt (bootstrap: SelfHostBootstrapReceipt) snapshotSha256 (replay: Replay) replayedAt = + let unsigned: SelfHostReplayReceipt = + { BootstrapDigest = bootstrap.Digest + SnapshotSha256 = snapshotSha256 + DecisionKey = replay.DecisionKey + ActionKey = replay.ActionKey + ReplayedAt = replayedAt + Digest = "" } + verifyReplay bootstrap replay + |> Result.bind (fun () -> validateReplayReceipt unsigned) + |> Result.bind (fun () -> + let receipt = { unsigned with Digest = replayDigest unsigned } + verifyReplayReceipt bootstrap receipt |> Result.map (fun () -> receipt)) + + let encodeReceipt receipt = + use stream = new MemoryStream() + use writer = new Utf8JsonWriter(stream) + writer.WriteStartObject() + writer.WriteString("baseSha", receipt.BaseSha) + writer.WriteString("candidateHeadSha", receipt.CandidateHeadSha) + writer.WriteString("candidateBinarySha256", receipt.CandidateBinarySha256) + writer.WriteString("candidateVersion", receipt.CandidateVersion) + writer.WriteString("sharedRefusal", receipt.SharedRefusal) + writer.WriteString("snapshotSha256", receipt.SnapshotSha256) + writer.WriteString("reason", reasonName receipt.Reason) + writer.WriteStartObject("evidence") + writer.WriteString("build", receipt.Evidence.Build) + writer.WriteString("unit", receipt.Evidence.Unit) + writer.WriteString("focusedProductionRoute", receipt.Evidence.FocusedProductionRoute) + writer.WriteString("provenance", receipt.Evidence.Provenance) + writer.WriteString("inversion", receipt.Evidence.Inversion) + writer.WriteEndObject() + writer.WriteString("candidateDecisionKey", receipt.CandidateDecisionKey) + writer.WriteString("candidateActionKey", receipt.CandidateActionKey) + writer.WriteStartObject("hostAcceptance") + writer.WriteString("actor", receipt.HostAcceptance.Actor) + writer.WriteString("acceptedAt", receipt.HostAcceptance.AcceptedAt.ToUniversalTime()) + writer.WriteEndObject() + writer.WriteString("digest", receipt.Digest) + writer.WriteEndObject() + writer.Flush() + ReceiptMarker + "\n" + Encoding.UTF8.GetString(stream.ToArray()) + + let tryDecodeReceipt (body: string) = + if not (body.StartsWith(ReceiptMarker, StringComparison.Ordinal)) then Ok None + else + try + use document = JsonDocument.Parse(body.Substring(ReceiptMarker.Length).TrimStart()) + let root = document.RootElement + let text (name: string) (value: JsonElement) = value.GetProperty(name).GetString() + let evidence = root.GetProperty "evidence" + let acceptance = root.GetProperty "hostAcceptance" + match tryReason (text "reason" root) with + | Error errors -> Error errors + | Ok reason -> + let receipt = + { BaseSha = text "baseSha" root + CandidateHeadSha = text "candidateHeadSha" root + CandidateBinarySha256 = text "candidateBinarySha256" root + CandidateVersion = text "candidateVersion" root + SharedRefusal = text "sharedRefusal" root + SnapshotSha256 = text "snapshotSha256" root + Reason = reason + Evidence = + { Build = text "build" evidence + Unit = text "unit" evidence + FocusedProductionRoute = text "focusedProductionRoute" evidence + Provenance = text "provenance" evidence + Inversion = text "inversion" evidence } + CandidateDecisionKey = text "candidateDecisionKey" root + CandidateActionKey = text "candidateActionKey" root + HostAcceptance = + { Actor = text "actor" acceptance + AcceptedAt = acceptance.GetProperty("acceptedAt").GetDateTimeOffset() } + Digest = text "digest" root } + authorizeWrite receipt |> Result.map (fun () -> Some receipt) + with ex -> + Error [ "invalid self-host bootstrap receipt: " + ex.Message ] + + let encodeReplayReceipt receipt = + use stream = new MemoryStream() + use writer = new Utf8JsonWriter(stream) + writer.WriteStartObject() + writer.WriteString("bootstrapDigest", receipt.BootstrapDigest) + writer.WriteString("snapshotSha256", receipt.SnapshotSha256) + writer.WriteString("decisionKey", receipt.DecisionKey) + writer.WriteString("actionKey", receipt.ActionKey) + writer.WriteString("replayedAt", receipt.ReplayedAt.ToUniversalTime()) + writer.WriteString("digest", receipt.Digest) + writer.WriteEndObject() + writer.Flush() + ReplayReceiptMarker + "\n" + Encoding.UTF8.GetString(stream.ToArray()) + + let tryDecodeReplayReceipt (body: string) = + if not (body.StartsWith(ReplayReceiptMarker, StringComparison.Ordinal)) then Ok None + else + try + use document = JsonDocument.Parse(body.Substring(ReplayReceiptMarker.Length).TrimStart()) + let root = document.RootElement + let text (name: string) = root.GetProperty(name).GetString() + let receipt: SelfHostReplayReceipt = + { BootstrapDigest = text "bootstrapDigest" + SnapshotSha256 = text "snapshotSha256" + DecisionKey = text "decisionKey" + ActionKey = text "actionKey" + ReplayedAt = root.GetProperty("replayedAt").GetDateTimeOffset() + Digest = text "digest" } + validateReplayReceipt receipt + |> Result.bind (fun () -> + let expected = replayDigest { receipt with Digest = "" } + if String.Equals(expected, receipt.Digest, StringComparison.Ordinal) then Ok(Some receipt) + else Error [ "self-host replay receipt digest does not match its bound fields" ]) + with ex -> + Error [ "invalid self-host replay receipt: " + ex.Message ] + + let replayState (comments: string list) = + let bootstraps = + comments + |> List.filter (fun body -> body.StartsWith(ReceiptMarker, StringComparison.Ordinal)) + |> List.map tryDecodeReceipt + let replays = + comments + |> List.filter (fun body -> body.StartsWith(ReplayReceiptMarker, StringComparison.Ordinal)) + |> List.map tryDecodeReplayReceipt + let errors = + [ yield! bootstraps |> List.choose (function Error values -> Some values | _ -> None) |> List.collect id + yield! replays |> List.choose (function Error values -> Some values | _ -> None) |> List.collect id ] + let bootstrapReceipts = bootstraps |> List.choose (function Ok(Some value) -> Some value | _ -> None) + let replayReceipts = replays |> List.choose (function Ok(Some value) -> Some value | _ -> None) + match errors, bootstrapReceipts, replayReceipts with + | _ :: _, _, _ -> InvalidReplay errors + | [], [], [] -> NoBootstrap + | [], [], _ -> InvalidReplay [ "self-host replay evidence exists without bootstrap authority" ] + | [], _ :: _ :: _, _ -> InvalidReplay [ "more than one self-host bootstrap receipt exists" ] + | [], [ bootstrap ], [] -> ReplayRequired bootstrap + | [], [ _ ], _ :: _ :: _ -> InvalidReplay [ "more than one self-host replay receipt exists" ] + | [], [ bootstrap ], [ replay ] -> + match verifyReplayReceipt bootstrap replay with + | Ok () -> VerifiedReplay replay + | Error values -> InvalidReplay values diff --git a/src/FS.GG.Coord.Core/SelfHost.fsi b/src/FS.GG.Coord.Core/SelfHost.fsi new file mode 100644 index 000000000..65afded05 --- /dev/null +++ b/src/FS.GG.Coord.Core/SelfHost.fsi @@ -0,0 +1,92 @@ +namespace FS.GG.Coord + +module SelfHost = + [] + type BootstrapReason = + | NewSchemaCase + | RelocatedDecisionBoundary + + type Evidence = + { Build: string + Unit: string + FocusedProductionRoute: string + Provenance: string + Inversion: string } + + type HostAcceptance = + { Actor: string + AcceptedAt: System.DateTimeOffset } + + type SelfHostBootstrapReceipt = + { BaseSha: string + CandidateHeadSha: string + CandidateBinarySha256: string + CandidateVersion: string + SharedRefusal: string + SnapshotSha256: string + Reason: BootstrapReason + Evidence: Evidence + CandidateDecisionKey: string + CandidateActionKey: string + HostAcceptance: HostAcceptance + Digest: string } + + type Replay = + { DecisionKey: string + ActionKey: string } + + type SelfHostReplayReceipt = + { BootstrapDigest: string + SnapshotSha256: string + DecisionKey: string + ActionKey: string + ReplayedAt: System.DateTimeOffset + Digest: string } + + type ReplayState = + | NoBootstrap + | ReplayRequired of SelfHostBootstrapReceipt + | VerifiedReplay of SelfHostReplayReceipt + | InvalidReplay of errors: string list + + [] + val ReceiptMarker: string = "" + + [] + val ReplayReceiptMarker: string = "" + + val createReceipt: + baseSha: string -> + candidateHeadSha: string -> + candidateBinarySha256: string -> + candidateVersion: string -> + sharedRefusal: string -> + snapshotSha256: string -> + reason: BootstrapReason -> + evidence: Evidence -> + candidateDecisionKey: string -> + candidateActionKey: string -> + hostAcceptance: HostAcceptance -> + Result + + /// The stable shared verifier. A host write must receive Ok from this function immediately before IO. + val authorizeWrite: receipt: SelfHostBootstrapReceipt -> Result + + /// Post-merge shared-engine replay must reproduce the candidate decision and action keys. + val verifyReplay: receipt: SelfHostBootstrapReceipt -> replay: Replay -> Result + + val createReplayReceipt: + bootstrap: SelfHostBootstrapReceipt -> + snapshotSha256: string -> + replay: Replay -> + replayedAt: System.DateTimeOffset -> + Result + + val verifyReplayReceipt: + bootstrap: SelfHostBootstrapReceipt -> receipt: SelfHostReplayReceipt -> Result + + val encodeReceipt: receipt: SelfHostBootstrapReceipt -> string + val tryDecodeReceipt: body: string -> Result + val encodeReplayReceipt: receipt: SelfHostReplayReceipt -> string + val tryDecodeReplayReceipt: body: string -> Result + val replayState: comments: string list -> ReplayState diff --git a/src/FS.GG.Coord.GitHub/Done.fs b/src/FS.GG.Coord.GitHub/Done.fs index 4696dde9e..63091959e 100644 --- a/src/FS.GG.Coord.GitHub/Done.fs +++ b/src/FS.GG.Coord.GitHub/Done.fs @@ -60,9 +60,75 @@ module Done = | ParentLeftOpen of Ref * reasons: string list | NoParent - let hasReceipt (comments: string list) = - comments - |> List.exists (fun body -> body.StartsWith("", StringComparison.Ordinal)) + type ReceiptState = + | NoReceipt + | LegacyReceipt + | VerifiedCompletionReceipt of FS.GG.Coord.Delivery.DeliveryCompletionReceipt + | InvalidCompletionReceipt of errors: string list + + type CompletionCorrectionState = + | NoCompletionCorrection + | VerifiedCompletionCorrection of FS.GG.Coord.Delivery.CompletionCorrectionReceipt + | InvalidCompletionCorrection of errors: string list + + let receiptState (comments: string list) = + let legacy = + comments + |> List.exists (fun body -> + body.StartsWith("", StringComparison.Ordinal)) + let typed = + comments + |> List.filter (fun body -> + body.StartsWith(FS.GG.Coord.Delivery.CompletionReceiptMarker, StringComparison.Ordinal)) + |> List.map FS.GG.Coord.Delivery.tryDecodeCompletionReceipt + let errors = typed |> List.choose (function Error error -> Some error | _ -> None) |> List.collect id + let receipts = typed |> List.choose (function Ok (Some receipt) -> Some receipt | _ -> None) + match errors, receipts with + | _ :: _, _ -> InvalidCompletionReceipt errors + | [], [ receipt ] -> VerifiedCompletionReceipt receipt + | [], _ :: _ :: _ -> InvalidCompletionReceipt [ "more than one delivery completion receipt exists" ] + | [], [] when legacy -> LegacyReceipt + | [], [] -> NoReceipt + + let hasReceipt comments = + match receiptState comments with + | VerifiedCompletionReceipt _ -> true + | LegacyReceipt + | NoReceipt + | InvalidCompletionReceipt _ -> false + + let receiptStateFor (ref: Ref) comments = + match receiptState comments with + | VerifiedCompletionReceipt receipt when receipt.Item <> ref.Canonical -> + InvalidCompletionReceipt + [ $"delivery completion receipt item '%s{receipt.Item}' does not match '%s{ref.Canonical}'" ] + | state -> state + + let hasReceiptFor ref comments = + match receiptStateFor ref comments with + | VerifiedCompletionReceipt _ -> true + | LegacyReceipt + | NoReceipt + | InvalidCompletionReceipt _ -> false + + let completionCorrectionStateFor (ref: Ref) (comments: string list) = + let parsed = + comments + |> List.filter (fun body -> + body.StartsWith(FS.GG.Coord.Delivery.CompletionCorrectionMarker, StringComparison.Ordinal)) + |> List.map FS.GG.Coord.Delivery.tryDecodeCompletionCorrectionReceipt + let errors = parsed |> List.choose (function Error error -> Some error | _ -> None) |> List.collect id + let receipts = parsed |> List.choose (function Ok (Some receipt) -> Some receipt | _ -> None) + match errors, receipts with + | _ :: _, _ -> InvalidCompletionCorrection errors + | [], [ receipt ] when receipt.Item = ref.Canonical -> VerifiedCompletionCorrection receipt + | [], [ receipt ] -> + InvalidCompletionCorrection + [ $"completion correction receipt item '%s{receipt.Item}' does not match '%s{ref.Canonical}'" ] + | [], _ :: _ :: _ -> InvalidCompletionCorrection [ "more than one completion correction receipt exists" ] + | [], [] -> NoCompletionCorrection + + let selfHostReplayState comments = FS.GG.Coord.SelfHost.replayState comments // ---- THE PRECONDITIONS, PURE ------------------------------------------------------------------- diff --git a/src/FS.GG.Coord.GitHub/Done.fsi b/src/FS.GG.Coord.GitHub/Done.fsi index a97fccf57..814f5b530 100644 --- a/src/FS.GG.Coord.GitHub/Done.fsi +++ b/src/FS.GG.Coord.GitHub/Done.fsi @@ -143,13 +143,40 @@ module Done = BoardStatus: BoardStatus Parent: Ref option } + /// Exhaustive durable completion evidence. Legacy evidence is classified for migration diagnostics, + /// but only a verified typed receipt is terminal authority. + type ReceiptState = + | NoReceipt + | LegacyReceipt + | VerifiedCompletionReceipt of FS.GG.Coord.Delivery.DeliveryCompletionReceipt + | InvalidCompletionReceipt of errors: string list + + type CompletionCorrectionState = + | NoCompletionCorrection + | VerifiedCompletionCorrection of FS.GG.Coord.Delivery.CompletionCorrectionReceipt + | InvalidCompletionCorrection of errors: string list + /// Read the facts. The only IO in the decision. val facts: transport: IGitHubTransport -> board: Board.BoardMap -> ref: Ref -> IoResult - /// Recognises the immutable receipt written only by a successful `done` precondition transaction. - /// Absence is deliberately not inferred from a closed issue or a Project Status value. + /// Recognises only digest-verified typed completion authority. Absence is deliberately not inferred + /// from a closed issue, a Project Status value, or a legacy receipt marker. val hasReceipt: comments: string list -> bool + /// Classify malformed and duplicate typed receipts explicitly instead of collapsing them to absence. + val receiptState: comments: string list -> ReceiptState + + /// Bind a typed receipt to the issue thread it is authorizing. + val receiptStateFor: ref: Ref -> comments: string list -> ReceiptState + + /// Subject-bound typed terminal predicate used by lifecycle projections. + val hasReceiptFor: ref: Ref -> comments: string list -> bool + + /// Subject-bound, fail-closed classification of the durable premature-closure correction evidence. + val completionCorrectionStateFor: ref: Ref -> comments: string list -> CompletionCorrectionState + + val selfHostReplayState: comments: string list -> FS.GG.Coord.SelfHost.ReplayState + /// **THE PRECONDITIONS, AS A TOTAL FUNCTION.** No IO. It cannot fail open, because it cannot fail. /// /// `resolvedWithoutPr` is the operator's `--evidence` — `Some reason` asserts *"there is no PR, and here diff --git a/src/FS.GG.Coord.GitHub/Writes.fs b/src/FS.GG.Coord.GitHub/Writes.fs index 9d1275ae7..451418889 100644 --- a/src/FS.GG.Coord.GitHub/Writes.fs +++ b/src/FS.GG.Coord.GitHub/Writes.fs @@ -1268,16 +1268,223 @@ module Writes = postComment transport ref body |> Result.map ignore - // The durable terminal fact for lifecycle reconciliation. A Project field is a projection which can - // be queued or repaired; the receipt is the evidence that the guarded `done` transaction actually - // reached its green preconditions. - let doneReceipt (transport: IGitHubTransport) (ref: Ref) (receipt: string) : IoResult = - let body = - "\n" - + "**Verified done receipt**\n\n" - + receipt + let deliveryCompletionReceipt + (transport: IGitHubTransport) + (ref: Ref) + (receipt: FS.GG.Coord.Delivery.DeliveryCompletionReceipt) + : IoResult = + FS.GG.Coord.Delivery.verifyCompletionReceipt receipt + |> Result.mapError (fun errors -> + Malformed(ref.Short, "invalid delivery completion receipt: " + String.concat "; " errors)) + |> Result.bind (fun () -> + Reads.commentBodies transport ref.Owner ref.Repo ref.Number + |> Result.bind (fun comments -> + let parsed = + comments + |> List.filter (fun body -> + body.StartsWith(FS.GG.Coord.Delivery.CompletionReceiptMarker, StringComparison.Ordinal)) + |> List.map FS.GG.Coord.Delivery.tryDecodeCompletionReceipt + let errors = parsed |> List.choose (function Error error -> Some error | _ -> None) + let receipts = parsed |> List.choose (function Ok (Some value) -> Some value | _ -> None) + if not (List.isEmpty errors) then + Error( + Malformed( + ref.Short, + "an existing delivery completion receipt is unreadable: " + + (errors |> List.collect id |> String.concat "; ") + ) + ) + else + let sameAuthority (existing: FS.GG.Coord.Delivery.DeliveryCompletionReceipt) = + existing.Item = receipt.Item + && existing.PullRequest = receipt.PullRequest + && existing.MergeSha = receipt.MergeSha + && existing.MergeReachable = receipt.MergeReachable + && existing.ObligationReceipts = receipt.ObligationReceipts + && existing.PendingBoardWrites = receipt.PendingBoardWrites + && existing.FreshnessToken = receipt.FreshnessToken + && existing.ActionKey = receipt.ActionKey + match receipts with + | [] -> + postComment transport ref (FS.GG.Coord.Delivery.encodeCompletionReceipt receipt) + |> Result.map ignore + | existing :: rest when sameAuthority existing && List.isEmpty rest -> Ok () + | _ -> + Error( + Malformed( + ref.Short, + "a contradictory or duplicate delivery completion receipt already exists" + ) + ))) - postComment transport ref body |> Result.map ignore + let selfHostBootstrapReceipt + (transport: IGitHubTransport) + (ref: Ref) + (receipt: FS.GG.Coord.SelfHost.SelfHostBootstrapReceipt) + : IoResult = + FS.GG.Coord.SelfHost.authorizeWrite receipt + |> Result.mapError (fun errors -> + Malformed(ref.Short, "invalid self-host bootstrap receipt: " + String.concat "; " errors)) + |> Result.bind (fun () -> + Reads.commentBodies transport ref.Owner ref.Repo ref.Number + |> Result.bind (fun comments -> + let parsed = + comments + |> List.filter (fun body -> + body.StartsWith(FS.GG.Coord.SelfHost.ReceiptMarker, StringComparison.Ordinal)) + |> List.map FS.GG.Coord.SelfHost.tryDecodeReceipt + let errors = parsed |> List.choose (function Error error -> Some error | _ -> None) + let receipts = parsed |> List.choose (function Ok(Some value) -> Some value | _ -> None) + if not (List.isEmpty errors) then + Error( + Malformed( + ref.Short, + "existing self-host bootstrap evidence is unreadable: " + + (errors |> List.collect id |> String.concat "; ") + ) + ) + else + match receipts with + | [] -> + postComment transport ref (FS.GG.Coord.SelfHost.encodeReceipt receipt) + |> Result.map ignore + | [ existing ] when existing = receipt -> Ok () + | _ -> + Error( + Malformed( + ref.Short, + "contradictory or duplicate self-host bootstrap evidence already exists" + ) + ))) + + let completionCorrectionReceipt + (transport: IGitHubTransport) + (ref: Ref) + (receipt: FS.GG.Coord.Delivery.CompletionCorrectionReceipt) + : IoResult = + FS.GG.Coord.Delivery.verifyCompletionCorrectionReceipt receipt + |> Result.mapError (fun errors -> + Malformed(ref.Short, "invalid completion correction receipt: " + String.concat "; " errors)) + |> Result.bind (fun () -> + if receipt.Item <> ref.Canonical then + Error(Malformed(ref.Short, $"completion correction receipt item '%s{receipt.Item}' does not match '%s{ref.Canonical}'")) + else + Reads.commentBodies transport ref.Owner ref.Repo ref.Number + |> Result.bind (fun comments -> + let typedCompletionEvidence = + comments + |> List.filter (fun body -> + body.StartsWith(FS.GG.Coord.Delivery.CompletionReceiptMarker, StringComparison.Ordinal)) + let parsed = + comments + |> List.filter (fun body -> + body.StartsWith(FS.GG.Coord.Delivery.CompletionCorrectionMarker, StringComparison.Ordinal)) + |> List.map FS.GG.Coord.Delivery.tryDecodeCompletionCorrectionReceipt + let errors = parsed |> List.choose (function Error error -> Some error | _ -> None) + let receipts = parsed |> List.choose (function Ok (Some value) -> Some value | _ -> None) + match typedCompletionEvidence, errors, receipts with + | _ :: _, _, _ -> + Error(Malformed(ref.Short, "completion evidence already exists; refusing a premature-completion correction")) + | [], _ :: _, _ -> + Error( + Malformed( + ref.Short, + "existing completion correction evidence is invalid: " + + (errors |> List.collect id |> String.concat "; ") + ) + ) + | [], [], [] -> + postComment transport ref (FS.GG.Coord.Delivery.encodeCompletionCorrectionReceipt receipt) + |> Result.map ignore + | [], [], [ existing ] + when existing.Item = receipt.Item + && existing.Destination = receipt.Destination -> Ok () + | _ -> + Error(Malformed(ref.Short, "a contradictory completion correction receipt already exists")) + )) + + let selfHostReplayReceipt + (transport: IGitHubTransport) + (ref: Ref) + (receipt: FS.GG.Coord.SelfHost.SelfHostReplayReceipt) + : IoResult = + Reads.commentBodies transport ref.Owner ref.Repo ref.Number + |> Result.bind (fun comments -> + match FS.GG.Coord.SelfHost.replayState comments with + | FS.GG.Coord.SelfHost.NoBootstrap -> + Error(Malformed(ref.Short, "self-host replay cannot be recorded without durable bootstrap authority")) + | FS.GG.Coord.SelfHost.InvalidReplay errors -> + Error(Malformed(ref.Short, "invalid self-host evidence: " + String.concat "; " errors)) + | FS.GG.Coord.SelfHost.VerifiedReplay existing when existing = receipt -> Ok () + | FS.GG.Coord.SelfHost.VerifiedReplay _ -> + Error(Malformed(ref.Short, "contradictory self-host replay evidence already exists")) + | FS.GG.Coord.SelfHost.ReplayRequired bootstrap -> + FS.GG.Coord.SelfHost.verifyReplayReceipt bootstrap receipt + |> Result.mapError (fun errors -> + Malformed(ref.Short, "invalid self-host replay receipt: " + String.concat "; " errors)) + |> Result.bind (fun () -> + postComment transport ref (FS.GG.Coord.SelfHost.encodeReplayReceipt receipt) + |> Result.map ignore)) + + let reopenIssue (transport: IGitHubTransport) (ref: Ref) : IoResult = + let payload = """{"state":"open"}""" + let request = + { Method = "PATCH" + Path = $"repos/%s{ref.Owner}/%s{ref.Repo}/issues/%d{ref.Number}" + Query = [] + Body = Json payload + Budget = Rest + IfNoneMatch = None + Subject = ref.Short } + + let attempted = transport.Send request + match Reads.issueState transport ref.Owner ref.Repo ref.Number with + | Ok IssueState.Open -> Ok () + | Ok IssueState.Closed -> + match attempted with + | Error error -> Error error + | Ok _ -> Error(Malformed(ref.Short, "issue reopen was accepted but fresh state is still CLOSED")) + | Error verificationError -> + match attempted with + | Error error -> Error error + | Ok _ -> + Error( + Malformed( + ref.Short, + "issue reopen was accepted but fresh state could not be verified: " + + Errors.explain verificationError + ) + ) + + let closeIssueCompleted (transport: IGitHubTransport) (ref: Ref) : IoResult = + let payload = """{"state":"closed","state_reason":"completed"}""" + let request = + { Method = "PATCH" + Path = $"repos/%s{ref.Owner}/%s{ref.Repo}/issues/%d{ref.Number}" + Query = [] + Body = Json payload + Budget = Rest + IfNoneMatch = None + Subject = ref.Short } + + let attempted = transport.Send request + match Reads.issueState transport ref.Owner ref.Repo ref.Number with + | Ok IssueState.Closed -> Ok () + | Ok IssueState.Open -> + match attempted with + | Error error -> Error error + | Ok _ -> Error(Malformed(ref.Short, "issue close was accepted but fresh state is still OPEN")) + | Error verificationError -> + match attempted with + | Error error -> Error error + | Ok _ -> + Error( + Malformed( + ref.Short, + "issue close was accepted but fresh state could not be verified: " + + Errors.explain verificationError + ) + ) // Persist the ordering receipt only after the caller has freshly verified its board mutation. let lifecycleWatermark (transport: IGitHubTransport) (ref: Ref) (marker: string) : IoResult = diff --git a/src/FS.GG.Coord.GitHub/Writes.fsi b/src/FS.GG.Coord.GitHub/Writes.fsi index 6d971e107..69b00cfef 100644 --- a/src/FS.GG.Coord.GitHub/Writes.fsi +++ b/src/FS.GG.Coord.GitHub/Writes.fsi @@ -697,9 +697,42 @@ module Writes = /// evidence for a driver that later audits an abandoned queue. val followupDisposition: transport: IGitHubTransport -> ref: Ref -> worker: WorkerId -> text: string -> IoResult - /// Posts the immutable receipt that says a `done` precondition check succeeded. The status column is - /// deliberately not used as that evidence: reconciliation may repair or defer that projection later. - val doneReceipt: transport: IGitHubTransport -> ref: Ref -> receipt: string -> IoResult + /// Append a digest-verified delivery completion receipt before mutable terminal projections. + val deliveryCompletionReceipt: + transport: IGitHubTransport -> + ref: Ref -> + receipt: FS.GG.Coord.Delivery.DeliveryCompletionReceipt -> + IoResult + + /// Append stable-verifier-approved candidate-engine authority once on its accountable item thread. + val selfHostBootstrapReceipt: + transport: IGitHubTransport -> + ref: Ref -> + receipt: FS.GG.Coord.SelfHost.SelfHostBootstrapReceipt -> + IoResult + + /// Append post-merge shared-engine agreement bound to the one durable bootstrap authority. + val selfHostReplayReceipt: + transport: IGitHubTransport -> + ref: Ref -> + receipt: FS.GG.Coord.SelfHost.SelfHostReplayReceipt -> + IoResult + + /// Append the subject-bound premature-closure correction authority once. Retries with the same safe + /// destination are idempotent; malformed, duplicate, or contradictory evidence fails closed. + val completionCorrectionReceipt: + transport: IGitHubTransport -> + ref: Ref -> + receipt: FS.GG.Coord.Delivery.CompletionCorrectionReceipt -> + IoResult + + /// Reopen an issue and require a fresh authoritative OPEN read. A lost PATCH response is recovered + /// when readback proves the requested state; an acknowledgement without readback is never success. + val reopenIssue: transport: IGitHubTransport -> ref: Ref -> IoResult + + /// Close an issue as completed and require fresh authoritative CLOSED state. Used only after the + /// typed completion authority is durable when recovering a prior premature-closure correction. + val closeIssueCompleted: transport: IGitHubTransport -> ref: Ref -> IoResult /// Appends a verified lifecycle ordering receipt to an item. val lifecycleWatermark: transport: IGitHubTransport -> ref: Ref -> marker: string -> IoResult diff --git a/src/FS.GG.Drivers/FS.GG.Drivers.csproj b/src/FS.GG.Drivers/FS.GG.Drivers.csproj index 0ad410285..aeaa3de26 100644 --- a/src/FS.GG.Drivers/FS.GG.Drivers.csproj +++ b/src/FS.GG.Drivers/FS.GG.Drivers.csproj @@ -92,6 +92,10 @@ + $(FsggCoherentSetVersion) The .github-authored driver skill bytes (scope: driver, e.g. work-roadmap) as one versioned artifact, with registry/driver-skill-manifest.json as the content-addressed record. The SDD CLI pins it, restores it at build time, and materializes the driver into a scaffold's skill roots at scaffold time (ADR-0054, ADR-0062, ADR-0063; ADR-0014 verify). diff --git a/src/FS.GG.Kit/FS.GG.Kit.csproj b/src/FS.GG.Kit/FS.GG.Kit.csproj index a9be570c3..0c4a82804 100644 --- a/src/FS.GG.Kit/FS.GG.Kit.csproj +++ b/src/FS.GG.Kit/FS.GG.Kit.csproj @@ -530,6 +530,10 @@ + $(FsggCoherentSetVersion) FS-GG coordination kit as one versioned artifact — the shared coordination skills and the fsgg-coord/skill-view client shims, derived from registry/repos.yml. Receivers reference it and materialize the skills onto disk (ADR-0062) instead of byte-copying the kit (ADR-0058: derive, don't restate). diff --git a/tests/FS.GG.Coord.Cli.BoardOps.Tests/ApplicationServiceTests.fs b/tests/FS.GG.Coord.Cli.BoardOps.Tests/ApplicationServiceTests.fs index 19cb3b486..1f2b38d1f 100644 --- a/tests/FS.GG.Coord.Cli.BoardOps.Tests/ApplicationServiceTests.fs +++ b/tests/FS.GG.Coord.Cli.BoardOps.Tests/ApplicationServiceTests.fs @@ -2283,17 +2283,78 @@ module ApplicationServiceTests = /// still says In progress — a `CLOSED-ISSUE-NOT-DONE` chore, whose remedy is Status=Done. A number in /// `rateLimited` meets an exhausted GraphQL budget on its item-id lookup, which is what makes its board /// write QUEUE instead of land (`Errors.isQueueable`: a rate limit, and nothing else, may be deferred). - let private reconcileWorldWithQueries (closed: int list) (rateLimited: Set) (queries: ResizeArray option) = + let private typedCompletionComments (number: int) = + let facts: Delivery.CompletionFacts = + { HeadSha = "head" + Merged = true + MergeReachable = true + IssueClosed = true + BoardDone = false + ClaimReleased = false + PendingWrites = 0 + CleanupEligible = false + ObligationsDeclared = true + Obligations = [] } + + let receipt = + Delivery.createCompletionReceipt + $"FS-GG/FS.GG.SDD#%d{number}" + number + $"merge-%d{number}" + (DateTimeOffset.Parse "2026-08-22T15:00:00Z") + $"freshness-%d{number}" + $"action-%d{number}" + facts + |> Result.defaultWith (String.concat "; " >> failwith) + |> Delivery.encodeCompletionReceipt + + JsonSerializer.Serialize [| {| body = receipt |} |] + + [] + let private SubjectBoundTypedCompletion = "__subject-bound-typed-completion__" + + let private reconcileWorldWithQueriesAndComments + (closed: int list) + (rateLimited: Set) + (queries: ResizeArray option) + (comments: string) = // A successful GraphQL mutation is not itself evidence that the board projection changed. This // fixture therefore models the projection separately: only a subsequent scan after an accepted // mutation observes Done. The rate-limited item never reaches that transition. - let mutable written: Set = Set.empty + let mutable written: Map = Map.empty + let mutable reopened: Set = + if comments.Contains(Delivery.CompletionReceiptMarker, StringComparison.Ordinal) then + Set.ofList closed + else + Set.empty + let projectedStatus = if comments = "[]" then "In review" else "Done" + let mutable storedCommentBodies = + if comments = SubjectBoundTypedCompletion then + [] + else + use document = JsonDocument.Parse comments + document.RootElement.EnumerateArray() + |> Seq.choose (fun entry -> + match entry.TryGetProperty "body" with + | true, body when body.ValueKind = JsonValueKind.String -> Some(body.GetString()) + | _ -> None) + |> List.ofSeq + + let commentsJson number = + if comments = SubjectBoundTypedCompletion then + typedCompletionComments number + else + storedCommentBodies + |> List.mapi (fun index body -> {| id = 9001 + index; body = body |}) + |> List.toArray + |> JsonSerializer.Serialize let items () = closed |> List.map (fun n -> - let status = if written.Contains n then "Done" else "In progress" - $"""{{"status":{{"name":"%s{status}"}},"blockedBy":null,"content":{{"__typename":"Issue","number":%d{n},"title":"item %d{n}","state":"CLOSED","repository":{{"nameWithOwner":"FS-GG/FS.GG.SDD"}}}}}}""") + let status = Map.tryFind n written |> Option.defaultValue "In progress" + let state = if reopened.Contains n then "OPEN" else "CLOSED" + $"""{{"status":{{"name":"%s{status}"}},"blockedBy":null,"content":{{"__typename":"Issue","number":%d{n},"title":"item %d{n}","body":"","state":"%s{state}","repository":{{"nameWithOwner":"FS-GG/FS.GG.SDD"}}}}}}""") |> String.concat "," Fake.Recorder(fun (req: Request) -> @@ -2340,7 +2401,7 @@ module ApplicationServiceTests = match item, field with | Some n, Some "Status" when closed |> List.contains n -> - let status = if written.Contains n then "Done" else "In progress" + let status = Map.tryFind n written |> Option.defaultValue "In progress" ok $"""{{"data":{{"node":{{"fieldValueByName":{{"name":"%s{status}"}}}}}},"rateLimit":{{"cost":1,"remaining":4977}}}}""" | _ -> Error(Errors.NotFound "a targeted verification read addressed an unknown reconcile field") elif document.Contains "updateProjectV2ItemFieldValue" then @@ -2349,7 +2410,7 @@ module ApplicationServiceTests = match v with | VId id when id.StartsWith "PVTI_" -> id.Substring("PVTI_".Length) |> Int32.TryParse |> function | true, n -> Some n | _ -> None | _ -> None) - |> Option.iter (fun n -> written <- written.Add n) + |> Option.iter (fun n -> written <- Map.add n projectedStatus written) ok """{"data":{"updateProjectV2ItemFieldValue":{"clientMutationId":null}}}""" elif document.Contains "projectsV2" then ok @@ -2358,7 +2419,7 @@ module ApplicationServiceTests = // `Done` is an option here because the remedy WRITES it: a single-select write // resolves the value to an option id before it is attempted. ok - """{"data":{"organization":{"projectV2":{"fields":{"nodes":[{"id":"PVTSSF_status","name":"Status","dataType":"SINGLE_SELECT","options":[{"id":"opt_ready","name":"Ready"},{"id":"opt_wip","name":"In progress"},{"id":"opt_done","name":"Done"}]},{"id":"PVTF_blocked","name":"Blocked by","dataType":"TEXT"}]}}}},"rateLimit":{"cost":1,"remaining":4977}}""" + """{"data":{"organization":{"projectV2":{"fields":{"nodes":[{"id":"PVTSSF_status","name":"Status","dataType":"SINGLE_SELECT","options":[{"id":"opt_ready","name":"Ready"},{"id":"opt_wip","name":"In progress"},{"id":"opt_review","name":"In review"},{"id":"opt_done","name":"Done"}]},{"id":"PVTF_blocked","name":"Blocked by","dataType":"TEXT"}]}}}},"rateLimit":{"cost":1,"remaining":4977}}""" elif document.Contains "items(first" then ok $"""{{"data":{{"organization":{{"projectV2":{{"items":{{"pageInfo":{{"hasNextPage":false,"endCursor":null}},"nodes":[%s{items ()}]}}}}}}}},"rateLimit":{{"cost":1,"remaining":4977}}}}""" @@ -2372,10 +2433,41 @@ module ApplicationServiceTests = // A CLOSED candidate is swept with no body, marker, or blocker read (`Scan.snapshot`), so this // exists only to keep an unexpected REST call loud rather than silently empty. | "GET", path when path.EndsWith "/comments" -> - ok "[{\"body\":\"\\nverified\"}]" - | "POST", path when path.EndsWith "/comments" -> ok """{"id":9001}""" + let parts = path.Split '/' + let number = Int32.Parse parts.[parts.Length - 2] + ok (commentsJson number) + | "GET", path when path.StartsWith("repos/FS-GG/FS.GG.SDD/issues/", StringComparison.Ordinal) -> + let number = path.Substring("repos/FS-GG/FS.GG.SDD/issues/".Length) |> Int32.Parse + let state = if reopened.Contains number then "open" else "closed" + ok ($"{{\"state\":\"%s{state}\",\"body\":\"\"}}") + | "PATCH", path when path.StartsWith("repos/FS-GG/FS.GG.SDD/issues/", StringComparison.Ordinal) -> + let number = path.Substring("repos/FS-GG/FS.GG.SDD/issues/".Length) |> Int32.Parse + match req.Body with + | Json payload -> + use document = JsonDocument.Parse payload + match document.RootElement.GetProperty("state").GetString() with + | "open" -> reopened <- reopened.Add number + | "closed" -> reopened <- reopened.Remove number + | state -> failwithf "unexpected issue state %s" state + | _ -> failwith "issue PATCH carried no JSON body" + ok "{}" + | "POST", path when path.EndsWith "/comments" -> + match req.Body with + | Json payload -> + use document = JsonDocument.Parse payload + storedCommentBodies <- + storedCommentBodies @ [ document.RootElement.GetProperty("body").GetString() ] + | _ -> failwith "comment POST carried no JSON body" + ok """{"id":9001}""" | m, p -> Error(Errors.NotFound $"the fixture serves no %s{m} %s{p}")) + let private reconcileWorldWithQueries (closed: int list) (rateLimited: Set) (queries: ResizeArray option) = + reconcileWorldWithQueriesAndComments + closed + rateLimited + queries + SubjectBoundTypedCompletion + let private reconcileWorld (closed: int list) (rateLimited: Set) = reconcileWorldWithQueries closed rateLimited None @@ -3052,7 +3144,7 @@ not be fetched — read %d{commentReads.Count}: %s{threads}%s{err}" Assert.Equal("Done", str "value" queued) // The finding fields are still there — `--apply` ADDS to the dry-run row, it does not replace it. - Assert.Equal("LIFECYCLE-PROJECTION-LAG", str "rule" queued) + Assert.Equal("COMPLETION-PROJECTION-LAG", str "rule" queued) Assert.Equal("quick", str "size" queued) // Exit code UNCHANGED. A deferred write is not a failure — it is a promise the queue keeps. @@ -3103,8 +3195,8 @@ not be fetched — read %d{commentReads.Count}: %s{threads}%s{err}" let expected = "applying (2 mechanical finding(s))" + nl - + " LIFECYCLE-PROJECTION-LAG FS.GG.SDD#101 Status=Done" + nl - + " LIFECYCLE-PROJECTION-LAG FS.GG.SDD#102 Status=Done" + nl + + " COMPLETION-PROJECTION-LAG FS.GG.SDD#101 Status=Done" + nl + + " COMPLETION-PROJECTION-LAG FS.GG.SDD#102 Status=Done" + nl + "judgement findings are report-only: scripts/fsgg-coord lint --repo FS.GG.SDD" + nl + "applied FS.GG.SDD#101 Status=Done" + nl + "queued FS.GG.SDD#102 Status=Done (run scripts/fsgg-coord flush)" + nl @@ -3304,11 +3396,142 @@ not be fetched — read %d{commentReads.Count}: %s{threads}%s{err}" // non-ASCII character, and it does so identically for the old `JsonSerializer` and the new // `Utf8JsonWriter`. Spelled from ASCII so the assertion says which bytes it means. let expected = - """[{"id":"LIFECYCLE-PROJECTION-LAG:FS-GG/FS.GG.SDD#101","remedy":"Status=Done","rule":"LIFECYCLE-PROJECTION-LAG","size":"quick","statement":"FS.GG.SDD#101: fresh lifecycle facts project Status=Done; repair the stale board projection.","subject":"FS.GG.SDD#101"}]""" + """[{"id":"COMPLETION-PROJECTION-LAG:FS-GG/FS.GG.SDD#101","remedy":"Status=Done","rule":"COMPLETION-PROJECTION-LAG","size":"quick","statement":"FS.GG.SDD#101: authoritative completion evidence exists; repair issue closure and Status=Done from that receipt.","subject":"FS.GG.SDD#101"}]""" Assert.Equal(expected, out.Trim()) Assert.Equal(0, code) + let private runReconcileWithHealthReport (world: Fake.Recorder) = + let path = Path.Combine(Path.GetTempPath(), "fsgg-completion-health-" + Guid.NewGuid().ToString "n" + ".json") + let previous = Environment.GetEnvironmentVariable "FSGG_COORD_HEALTH_REPORT" + + try + Environment.SetEnvironmentVariable("FSGG_COORD_HEALTH_REPORT", path) + let code, out, err = runReconcile world (reconcileArgs [ "--json" ]) + code, out, err, File.ReadAllText path + finally + Environment.SetEnvironmentVariable("FSGG_COORD_HEALTH_REPORT", previous) + + if File.Exists path then + File.Delete path + + [] + let ``a closed non-Done row without a completion receipt exposes one dry-run correction without mutating`` () = + let world = reconcileWorldWithQueriesAndComments [ 101 ] Set.empty None "[]" + let code, out, err, report = runReconcileWithHealthReport world + + Assert.Equal(0, code) + Assert.Equal("", err) + let rows = parsedArray out + Assert.Single rows |> ignore + Assert.Equal("PREMATURE-COMPLETION", rows.Head.GetProperty("rule").GetString()) + Assert.Equal("Status=In review", rows.Head.GetProperty("remedy").GetString()) + Assert.False(world.Logged "updateProjectV2ItemFieldValue", $"a receipt-free row reached a mutation: %A{world.Log}") + + use document = JsonDocument.Parse report + let root = document.RootElement + let subjects = root.GetProperty("subjects").EnumerateArray() |> List.ofSeq + Assert.Equal("typed-complete-success/1", root.GetProperty("completeReadBoundary").GetString()) + Assert.Equal(1, root.GetProperty("subjectCount").GetInt32()) + Assert.Single subjects |> ignore + Assert.Equal("FS-GG/FS.GG.SDD#101", subjects.Head.GetProperty("subject").GetString()) + Assert.Equal("In progress", subjects.Head.GetProperty("current").GetString()) + Assert.Equal("In review", subjects.Head.GetProperty("intended").GetString()) + Assert.True(subjects.Head.GetProperty("readComplete").GetBoolean()) + + [] + let ``premature completion apply persists authority then reopens then projects In review`` () = + let world = reconcileWorldWithQueriesAndComments [ 101 ] Set.empty None "[]" + let code, out, err = runReconcile world (reconcileArgs [ "--apply"; "--json" ]) + + Assert.Equal(0, code) + Assert.Equal("", err) + let row = parsedArray out |> List.exactlyOne + Assert.Equal("PREMATURE-COMPLETION", row.GetProperty("rule").GetString()) + Assert.Equal("written", row.GetProperty("outcome").GetString()) + Assert.Equal("In review", row.GetProperty("value").GetString()) + + let firstComment = world.Log |> List.findIndex (fun entry -> entry.Contains "comment-post") + let reopen = world.Log |> List.findIndex (fun entry -> entry.Contains "issue-patch") + let statusWrite = world.Log |> List.findIndex (fun entry -> entry.Contains "item-edit") + Assert.True(firstComment < reopen, $"correction authority was not first: %A{world.Log}") + Assert.True(reopen < statusWrite, $"issue reopen did not precede Status projection: %A{world.Log}") + + let secondCode, secondOut, secondErr = + runReconcile world (reconcileArgs [ "--apply"; "--json" ]) + if secondCode <> 0 then failwithf "second completion projection failed (exit %d): %s\n%s\n%A" secondCode secondErr secondOut world.Log + Assert.Equal("", secondErr) + Assert.Empty(parsedArray secondOut) + Assert.Equal(1, world.Count "issue-patch") + Assert.Equal(1, world.Count "item-edit") + + [] + let ``typed completion receipt repairs an open issue and Status Done idempotently`` () = + let facts: Delivery.CompletionFacts = + { HeadSha = "head" + Merged = true + MergeReachable = true + IssueClosed = true + BoardDone = false + ClaimReleased = false + PendingWrites = 0 + CleanupEligible = false + ObligationsDeclared = true + Obligations = [] } + let receipt = + Delivery.createCompletionReceipt + "FS-GG/FS.GG.SDD#101" + 99 + "merge-sha" + (DateTimeOffset.Parse("2026-08-22T17:00:00Z")) + "freshness" + "action" + facts + |> Result.defaultWith (String.concat "; " >> failwith) + let comments = + JsonSerializer.Serialize [| {| body = Delivery.encodeCompletionReceipt receipt |} |] + let world = reconcileWorldWithQueriesAndComments [ 101 ] Set.empty None comments + + let code, out, err = runReconcile world (reconcileArgs [ "--apply"; "--json" ]) + if code <> 0 then failwithf "completion projection failed (exit %d): %s\n%s\n%A" code err out world.Log + Assert.Equal("", err) + let row = parsedArray out |> List.exactlyOne + Assert.Equal("COMPLETION-PROJECTION-LAG", row.GetProperty("rule").GetString()) + Assert.Equal("Done", row.GetProperty("value").GetString()) + Assert.Equal("written", row.GetProperty("outcome").GetString()) + let close = world.Log |> List.findIndex (fun entry -> entry.Contains "issue-patch") + let statusWrite = world.Log |> List.findIndex (fun entry -> entry.Contains "item-edit") + Assert.True(close < statusWrite, $"issue closure did not precede Status=Done: %A{world.Log}") + + let secondCode, secondOut, secondErr = + runReconcile world (reconcileArgs [ "--apply"; "--json" ]) + if secondCode <> 0 then failwithf "second typed completion projection failed (exit %d): %s\n%s\n%A" secondCode secondErr secondOut world.Log + Assert.Equal("", secondErr) + Assert.Empty(parsedArray secondOut) + Assert.Equal(1, world.Count "issue-patch") + Assert.Equal(1, world.Count "item-edit") + + [] + let ``malformed typed completion evidence is visible in health and never corrected`` () = + let comments = + JsonSerializer.Serialize + [| {| body = Delivery.CompletionReceiptMarker + Environment.NewLine + "{}" |} |] + let world = reconcileWorldWithQueriesAndComments [ 101 ] Set.empty None comments + let code, out, err, report = runReconcileWithHealthReport world + + Assert.Equal(0, code) + Assert.Empty(parsedArray out) + Assert.Contains("invalid delivery completion evidence", err) + Assert.False(world.Logged "updateProjectV2ItemFieldValue", $"invalid evidence reached a mutation: %A{world.Log}") + + use document = JsonDocument.Parse report + let subjects = document.RootElement.GetProperty("subjects").EnumerateArray() |> List.ofSeq + Assert.Single subjects |> ignore + Assert.StartsWith( + "withheld: invalid delivery completion evidence:", + subjects.Head.GetProperty("intended").GetString()) + Assert.False(subjects.Head.GetProperty("readComplete").GetBoolean()) + /// The four environment variables `Identity.resolve` consults, cleared and restored. Clearing ALL of /// them is what makes "no worker id resolves" a property of the TEST rather than of whoever's machine /// is running it — under a Claude Code or opencode harness, `CLAUDE_CODE_SESSION_ID` alone would diff --git a/tests/FS.GG.Coord.Cli.BoardOps.Tests/BlockerLintTests.fs b/tests/FS.GG.Coord.Cli.BoardOps.Tests/BlockerLintTests.fs index 9e695a6d0..2ec5af1ee 100644 --- a/tests/FS.GG.Coord.Cli.BoardOps.Tests/BlockerLintTests.fs +++ b/tests/FS.GG.Coord.Cli.BoardOps.Tests/BlockerLintTests.fs @@ -74,8 +74,10 @@ module BlockerLintTests = Assert.Equal(12, Regex.Matches(source, "Board\\.boardWrite\\b").Count) Assert.Equal(3, Regex.Matches(source, "Board\\.boardWriteBatch\\b").Count) Assert.Equal(3, Regex.Matches(source, "requireCoherentBlockedWrite ctx").Count) - Assert.Equal(1, Regex.Matches(chore, "Some\\(\\\"Status\\\"").Count) + Assert.Equal(3, Regex.Matches(chore, "Some\\(\\\"Status\\\"").Count) Assert.Contains("LifecycleProjectionLag destination -> Some(\"Status\", statusWireName destination)", chore) + Assert.Contains("PrematureCompletion destination -> Some(\"Status\", destination |> completionCorrectionStatus |> statusWireName)", chore) + Assert.Contains("CompletionProjection -> Some(\"Status\", statusWireName Done)", chore) for retired in [ "StatusNotBlocked"; "BlockerCleared"; "ClosedIssueNotDone"; "ClaimStatusLag"; "ClaimReviewLag" ] do Assert.DoesNotContain(retired, chore) diff --git a/tests/FS.GG.Coord.Cli.BoardOps.Tests/HandlerRegistrationTests.fs b/tests/FS.GG.Coord.Cli.BoardOps.Tests/HandlerRegistrationTests.fs index a77c34bde..03391f8ef 100644 --- a/tests/FS.GG.Coord.Cli.BoardOps.Tests/HandlerRegistrationTests.fs +++ b/tests/FS.GG.Coord.Cli.BoardOps.Tests/HandlerRegistrationTests.fs @@ -7,46 +7,28 @@ open FS.GG.Coord.Cli.BoardOps module HandlerRegistrationTests = let private inert _ _ = 0 - let private implementations: HandlerRegistration.Implementations = - { Add = inert - Flush = inert - SetField = inert - Child = inert - BodyEdits = inert - FieldId = inert - OptionId = inert - ItemId = inert - Board = inert - Bootstrap = inert - Issues = inert - Intake = inert - Say = inert - Inbox = inert - RoomOpen = inert - Comment = inert } - [] let ``BoardOps registers each owned command exactly once`` () = - let registrations = HandlerRegistration.handlers implementations + let registrations = Handlers.handlers let result = HandlerRegistration.validate HandlerRegistration.commands registrations Assert.True(Result.isOk result) Assert.Equal(HandlerRegistration.commands.Length, registrations.Length) [] let ``registration validation rejects a duplicate handler`` () = - let registrations = HandlerRegistration.handlers implementations + let registrations = Handlers.handlers let result = HandlerRegistration.validate HandlerRegistration.commands (registrations.Head :: registrations) Assert.True(Result.isError result) [] let ``registration validation rejects a missing handler`` () = - let registrations = HandlerRegistration.handlers implementations |> List.tail + let registrations = Handlers.handlers |> List.tail let result = HandlerRegistration.validate HandlerRegistration.commands registrations Assert.True(Result.isError result) [] let ``registration validation rejects an unexpected handler`` () = - let registrations = HandlerRegistration.handlers implementations + let registrations = Handlers.handlers let unexpected = Options.Help, inert let result = HandlerRegistration.validate HandlerRegistration.commands (unexpected :: registrations) Assert.True(Result.isError result) diff --git a/tests/FS.GG.Coord.Cli.Kernel.Tests/CommandSurfaceTests.fs b/tests/FS.GG.Coord.Cli.Kernel.Tests/CommandSurfaceTests.fs index e6004725e..a1126f39a 100644 --- a/tests/FS.GG.Coord.Cli.Kernel.Tests/CommandSurfaceTests.fs +++ b/tests/FS.GG.Coord.Cli.Kernel.Tests/CommandSurfaceTests.fs @@ -24,97 +24,47 @@ open FS.GG.Coord.Cli.Options /// shrinking it cost a line in a diff instead of costing nothing. module CommandSurfaceTests = - /// The declared command surface: every verb the engine dispatches, and what it dispatches to. - /// - /// A verb leaves the surface only by leaving THIS LIST — a decision in the diff, reviewable, - /// exactly the standard ADR-0040's D.4 disposition manifest set for the five assertions it did - /// dispose of on the record. Adding a verb to the engine without adding it here is caught by the - /// DU cross-check below, so the list cannot silently rot in either direction. + [] + let ``command catalogue is exhaustive unique and behavior-conformant`` () = + let descriptors = Options.commandCatalogue + let commands = descriptors |> List.map _.Command + let verbs = descriptors |> List.map _.Verb + + Assert.True(Options.validateCommandCatalogue Options.allCommands descriptors |> Result.isOk) + Assert.Equal(Options.allCommands |> List.sort, commands |> List.sort) + Assert.Equal(commands.Length, commands |> List.distinct |> List.length) + Assert.Equal(verbs.Length, verbs |> List.distinct |> List.length) + + for descriptor in descriptors do + Assert.Equal(Options.commandName descriptor.Command, descriptor.Verb) + Assert.Equal(Options.renderSupport descriptor.Command, descriptor.Render) + Assert.True(descriptor.Documented) + + [] + let ``command catalogue closure names missing duplicate and undocumented rows`` () = + let descriptor = Options.commandCatalogue |> List.find (fun row -> row.Command = Options.CommentCmd) + let mutant = + Options.commandCatalogue + |> List.filter (fun row -> row.Command <> Options.Help) + |> fun rows -> { descriptor with Documented = false } :: descriptor :: rows + + match Options.validateCommandCatalogue Options.allCommands mutant with + | Ok _ -> failwith "an incomplete duplicated undocumented catalogue was accepted" + | Error errors -> + Assert.Contains("duplicate command descriptors: [CommentCmd]", errors) + Assert.Contains("duplicate command verbs: [\"comment\"]", errors) + Assert.Contains("missing command descriptors: [Help]", errors) + Assert.Contains("undocumented commands: [CommentCmd]", errors) + + /// Positive behavior cases are generated from the catalogue rather than maintained as another + /// writable command inventory. Parsing still observes the real heterogeneous parser arms. let private surface: (string * Command) list = - [ - // DECISION — pure; read state on stdin and touch no network (ADR-0034). - "decide", Decide - "delivery", DeliveryCmd - "review", ReviewCmd - "driver", DriverCmd - "cycle", CycleCmd - "scan", Scan - "lanes", LanesView - "facts", Facts - "command-contract", CommandContractCmd - "intake", IntakeCmd - "packet", PacketCmd - "delivery-route", RouteCmd - - // IO — the client surface the shim execs in place of bash (ADR-0040 Phase D). - "whoami", WhoAmI - "budget", Budget - "next", Next - "batch", BatchCmd - "ready", Ready - "reconcile", Reconcile - "who", Who - "reap", Reap - "claim", Claim - "adopt", Adopt - "landable", Landable - "take", Take - "release", Release - "heartbeat", Heartbeat - "add", Add - "set-field", SetField - "child", Child - "widen", Widen - "set-paths", SetPaths - "overlap", Overlap - "say", Say - "inbox", Inbox - "done", DoneCmd - "verify-paths", VerifyPaths - // #862/#878, landed on main while this gate was being written — and caught BY it: CI builds the - // merge ref, so the DU cross-check went red naming `Flush` on this PR's first run. The verb - // entered the surface, so it cost a line here. That is the whole point (#869). - "flush", Flush - - // The #418 board-map plumbing. - "bootstrap", Bootstrap - "board", BoardCmd - "field-id", FieldId - "option-id", OptionId - "item-id", ItemId - // `.github#2477`: the metered `userContentEdits` read the independent-review contract's - // body-edit provenance check names as authoritative. - "body-edits", BodyEdits - // M6 operational reads and partial archive mutations cross the single typed GraphQL boundary. - "graphql", GraphQlOps - - // The board-health gate (#496) and the REST listing (#446). - "lint", LintCmd - "issues", Issues - - // The follow-up queue (#1063) — LOCAL, like `whoami`: a file, no board, no token. - "followup", Followup - - // The ADR-0050 registry-predicate oracle (#1202) — LOCAL: reads registry + producer manifests, - // no board, no token. - "predicate", Predicate - "diff-audit", DiffAudit - - // `.github#2753`: the verified file-backed comment writer is part of the typed IO surface. - // Keeping it in this inventory makes both dispatch and write-ness coverage fail if the command - // is added to the DU without an emitted contract row. - "comment", CommentCmd - - // Coordination rooms (ADR-0051, #1215). The ONE two-word verb — a `room` namespace so - // `room close`/`room list` have a home; the dispatch check below splits on whitespace for it. - "room open", RoomOpen - - // The per-receiver dispatch fence (`.github#2312` under `.github#1858`). TWO two-word verbs in - // one `op-lock` namespace — the pair is one mechanism and reads as one, and an unknown third - // word is named and refused rather than swallowed into `acquire`'s four positionals. The - // dispatch check below splits on whitespace for them exactly as it does for `room open`. - "op-lock acquire", OpLockAcquire - "op-lock release", OpLockRelease ] + Options.commandCatalogue + |> List.choose (fun descriptor -> + match descriptor.Command with + | Help + | Version -> None + | _ -> Some(descriptor.Verb, descriptor.Command)) /// The two commands with no verb form — they are reached by flag (`--help`, `--version`), so the /// verb inventory cannot account for them and the DU cross-check must be told so explicitly. diff --git a/tests/FS.GG.Coord.Cli.Kernel.Tests/OptionsTests.fs b/tests/FS.GG.Coord.Cli.Kernel.Tests/OptionsTests.fs index 808224877..7ef682269 100644 --- a/tests/FS.GG.Coord.Cli.Kernel.Tests/OptionsTests.fs +++ b/tests/FS.GG.Coord.Cli.Kernel.Tests/OptionsTests.fs @@ -563,6 +563,12 @@ module OptionsTests = let o = parse [ "done"; "FS.GG.SDD#62"; "--flip" ] |> ok Assert.Equal(None, o.Partial) + [] + let ``delivery accepts flip so typed completion can perform the terminal roll-up`` () = + let o = parse [ "delivery"; "FS.GG.SDD#62"; "--pr"; "63"; "--flip"; "--apply" ] |> ok + Assert.True(o.Flip) + Assert.True(o.Apply) + [] let ``#614 --partial with no value is rejected — a partial fix must SAY why`` () = let e = parse [ "done"; "FS.GG.SDD#62"; "--flip"; "--partial" ] |> rejected @@ -866,6 +872,7 @@ module OptionsTests = // (`--help`/`--version` moved too, but are reached by flag and have no bare form to pin), plus // the five (`reap`, `overlap`, `room open`, `followup`, `flush`) already pinned `Text` by hand. "whoami", Text + "self-host", Text "next", Text "reap", Text "landable", Text diff --git a/tests/FS.GG.Coord.Cli.Tests/DeliveryApplicationTests.fs b/tests/FS.GG.Coord.Cli.Tests/DeliveryApplicationTests.fs index fdd94690e..6897d08cd 100644 --- a/tests/FS.GG.Coord.Cli.Tests/DeliveryApplicationTests.fs +++ b/tests/FS.GG.Coord.Cli.Tests/DeliveryApplicationTests.fs @@ -10,6 +10,10 @@ open FS.GG.Coord.GitHub open FS.GG.Coord.GitHub.Transport module DeliveryApplicationTests = + let rec private repoRoot dir = + if File.Exists(Path.Combine(dir, "src/FS.GG.Coord.Cli/Client.fs")) then dir + else repoRoot (Directory.GetParent(dir).FullName) + let commentWithId id body : Driver.ReviewComment = { Id = id; Url = $"https://example.test/{id}"; Body = body } let comment body = commentWithId 1L body @@ -44,6 +48,39 @@ module DeliveryApplicationTests = let review id url body : Driver.ReviewComment = { Id = id; Url = url; Body = body } + [] + let ``completion writer consumes the shared decision instead of rebuilding admission`` () = + let root = repoRoot (Directory.GetCurrentDirectory()) + let writer = File.ReadAllText(Path.Combine(root, "src/FS.GG.Coord.Cli/Client.fs")) + Assert.Equal(1, System.Text.RegularExpressions.Regex.Matches(writer, "Delivery\\.decideCompletion\\b").Count) + Assert.Equal( + 1, + System.Text.RegularExpressions.Regex.Matches( + writer, + "Delivery\\.CompletionDecision\\.ProjectCompletion" + ).Count + ) + + let doneStart = writer.IndexOf("let private runDone", StringComparison.Ordinal) + let doneEnd = writer.IndexOf("let doneCmd", doneStart, StringComparison.Ordinal) + let doneWriter = writer.Substring(doneStart, doneEnd - doneStart) + let selfHostReplay = doneWriter.IndexOf("Done.selfHostReplayState", StringComparison.Ordinal) + let createReceipt = doneWriter.IndexOf("Delivery.createCompletionReceipt", StringComparison.Ordinal) + let receipt = doneWriter.IndexOf("Writes.deliveryCompletionReceipt", StringComparison.Ordinal) + let issueClose = doneWriter.IndexOf("Writes.closeIssueCompleted", receipt, StringComparison.Ordinal) + let boardDone = doneWriter.IndexOf("Board.boardWrite", issueClose, StringComparison.Ordinal) + let claimRelease = doneWriter.IndexOf("Writes.release", boardDone, StringComparison.Ordinal) + Assert.True(receipt >= 0, "delivery completion receipt writer is not wired") + Assert.True(selfHostReplay >= 0, "delivery completion does not inspect durable self-host replay") + Assert.True(createReceipt > selfHostReplay, "completion authority can be minted before self-host replay agrees") + Assert.True(issueClose > receipt, "a corrected issue is closed before the completion receipt") + Assert.True(boardDone > receipt, "Status=Done is projected before the completion receipt") + Assert.True(claimRelease > boardDone, "the claim is released before the receipt and board projection") + Assert.Contains("Delivery.advance", doneWriter) + Assert.Contains("Delivery.createCompletionReceipt", doneWriter) + Assert.DoesNotContain("Writes.doneReceipt", doneWriter) + Assert.DoesNotContain("fsgg:done-receipt v=1", doneWriter) + [] let ``#2207 client delivery adapter retains malformed parser diagnostics`` () = let malformed = diff --git a/tests/FS.GG.Coord.Cli.Tests/DoneStderrTests.fs b/tests/FS.GG.Coord.Cli.Tests/DoneStderrTests.fs index 51bfa086a..9c9b7cbd1 100644 --- a/tests/FS.GG.Coord.Cli.Tests/DoneStderrTests.fs +++ b/tests/FS.GG.Coord.Cli.Tests/DoneStderrTests.fs @@ -95,6 +95,35 @@ module DoneStderrTests = + closingPrs + """]},"timelineItems":{"nodes":[]},"subIssues":{"totalCount":0,"nodes":[]},"projectItems":{"nodes":[{"project":{"number":12},"status":{"name":"In progress"}}]},"parent":null}}},"rateLimit":{"cost":1,"remaining":4977}}""" + let private typedCompletionReceipt = + let completionFacts: FS.GG.Coord.Delivery.CompletionFacts = + { HeadSha = "head" + Merged = true + MergeReachable = true + IssueClosed = true + BoardDone = false + ClaimReleased = false + PendingWrites = 0 + CleanupEligible = false + ObligationsDeclared = true + Obligations = [] } + + FS.GG.Coord.Delivery.createCompletionReceipt + ref.Canonical + 413 + "e605d37" + (DateTimeOffset.Parse "2026-08-22T15:00:00Z") + "freshness" + "action" + completionFacts + |> Result.defaultWith (String.concat "; " >> failwith) + |> FS.GG.Coord.Delivery.encodeCompletionReceipt + + let private completionComments = + "[{\"body\":" + System.Text.Json.JsonSerializer.Serialize typedCompletionReceipt + "}]" + + let mutable private serveTypedCompletionAuthority = true + /// Posted comment bodies, so a test can also assert the durable receipt's divergence from stdout — /// not just that stdout stayed clean. let private postedComments = System.Collections.Generic.List() @@ -122,7 +151,8 @@ module DoneStderrTests = Error(Errors.NotFound "the fixture serves no board WRITE — done's stdout/stderr split is what is under test") | _ -> Error(Errors.NotFound "a graphql call with no document") | "GET", "rate_limit" -> ok """{"resources":{"graphql":{"remaining":4980,"limit":5000}}}""" - | "GET", p when p.EndsWith "issues/9001/comments" -> ok "[]" + | "GET", p when p.EndsWith "issues/9001/comments" -> + ok (if serveTypedCompletionAuthority then completionComments else "[]") | "POST", p when p.EndsWith "issues/9001/comments" -> match req.Body with | Json payload -> @@ -146,7 +176,7 @@ module DoneStderrTests = /// `LandableNotOpenTests.runLandable`/`ForceStealTests.runClaim`: `AssemblyInfo.fs` disables /// cross-class parallelism, so pointing the process-global `FSGG_COORD_CACHE` somewhere private per /// call is safe. - let private runDone () : int * string * string = + let private runDone (withTypedAuthority: bool) : int * string * string = let dir = Path.Combine(Path.GetTempPath(), "fsgg-2444-" + Guid.NewGuid().ToString "n") let previousCache = Environment.GetEnvironmentVariable "FSGG_COORD_CACHE" let previousKitRoot = Environment.GetEnvironmentVariable "FSGG_KIT_ROOT" @@ -159,6 +189,7 @@ module DoneStderrTests = Directory.CreateDirectory dir |> ignore Environment.SetEnvironmentVariable("FSGG_COORD_CACHE", dir) Environment.SetEnvironmentVariable("FSGG_KIT_ROOT", dir) + serveTypedCompletionAuthority <- withTypedAuthority Console.SetOut capturedOut Console.SetError capturedErr @@ -185,7 +216,7 @@ module DoneStderrTests = [] let ``#2444 done's stdout carries only the FSGG-DONE verdict - the passed-over note is not on it`` () = postedComments.Clear() - let code, stdout, stderr = runDone () + let code, stdout, stderr = runDone true Assert.Equal(0, code) Assert.Contains("FSGG-DONE", stdout) @@ -213,16 +244,16 @@ module DoneStderrTests = Assert.Equal(1, occurrences) [] - let ``#2444 the durable receipt comment DELIBERATELY keeps the note stdout no longer carries`` () = + let ``standalone done replays typed authority without appending legacy evidence`` () = + postedComments.Clear() + runDone true |> ignore + Assert.Empty(postedComments) + + [] + let ``standalone done refuses to mint authority when no typed receipt exists`` () = postedComments.Clear() - runDone () |> ignore - - // Exactly one comment posted (the done-receipt) — and it is the RECEIPT, not a repeat of stdout's - // clean line: it deliberately diverges from stdout by keeping the cross-repo provenance note. - Assert.Single(postedComments) |> ignore - let receipt = postedComments.[0] - Assert.Contains("fsgg:done-receipt", receipt) - Assert.Contains("FSGG-DONE", receipt) - Assert.Contains("PR #413", receipt) - Assert.Contains("EHotwagner/S.I.R.#195", receipt) - Assert.Contains("passed over", receipt) + let code, stdout, _ = runDone false + Assert.NotEqual(0, code) + Assert.Contains("FSGG-NOT-DONE", stdout) + Assert.Contains("standalone done cannot mint completion authority", stdout) + Assert.Empty(postedComments) diff --git a/tests/FS.GG.Coord.Cli.Tests/FS.GG.Coord.Cli.Tests.fsproj b/tests/FS.GG.Coord.Cli.Tests/FS.GG.Coord.Cli.Tests.fsproj index c0159a2ce..1d88537bf 100644 --- a/tests/FS.GG.Coord.Cli.Tests/FS.GG.Coord.Cli.Tests.fsproj +++ b/tests/FS.GG.Coord.Cli.Tests/FS.GG.Coord.Cli.Tests.fsproj @@ -19,6 +19,7 @@ the stdout/stderr split. The decode and validation contract is pure and lives in FS.GG.Coord.Core.Tests/FindingPacketTests.fs. --> + diff --git a/tests/FS.GG.Coord.Cli.Tests/ReviewApplicationTests.fs b/tests/FS.GG.Coord.Cli.Tests/ReviewApplicationTests.fs index 4fbbb45ab..6024f815e 100644 --- a/tests/FS.GG.Coord.Cli.Tests/ReviewApplicationTests.fs +++ b/tests/FS.GG.Coord.Cli.Tests/ReviewApplicationTests.fs @@ -3,6 +3,7 @@ namespace FS.GG.Coord.Cli.Tests open System open System.IO open System.Text.Json +open System.Text.RegularExpressions open Xunit open FS.GG.Coord open FS.GG.Coord.Cli @@ -11,6 +12,10 @@ module ReviewApplicationTests = let private head = String.replicate 40 "a" let private subject = "FS-GG/.github#2175/pr/42" + let rec private repoRoot dir = + if File.Exists(Path.Combine(dir, "src/FS.GG.Coord.Cli/ReviewApplication.fs")) then dir + else repoRoot (Directory.GetParent(dir).FullName) + let private snapshot comments checks = JsonSerializer.Serialize {| binding = @@ -50,6 +55,18 @@ module ReviewApplicationTests = try ReviewApplication.renderWithWait opts binding facts waitState, stdout.ToString(), stderr.ToString() finally Console.SetOut oldOut; Console.SetError oldErr + [] + let ``ordinary exhaustion consumers cannot restore a local terminal predicate`` () = + let root = repoRoot (Directory.GetCurrentDirectory()) + let readSide = File.ReadAllText(Path.Combine(root, "src/FS.GG.Coord.Cli/ReviewApplication.fs")) + let writer = File.ReadAllText(Path.Combine(root, "src/FS.GG.Coord.Cli/Client.fs")) + + for source in [ readSide; writer ] do + Assert.Equal(1, Regex.Matches(source, "Review\\.decideOrdinaryExhaustion\\b").Count) + Assert.DoesNotContain("Review.isOrdinaryExhaustionTerminal", source) + + Assert.Contains("Review.projectOrdinaryExhaustion exhaustionDecision", readSide) + [] let empty_thread_dispatches_critic () = let code, output, _ = run "--json" (snapshot (comments []) "pending") diff --git a/tests/FS.GG.Coord.Cli.Tests/SelfHostCliTests.fs b/tests/FS.GG.Coord.Cli.Tests/SelfHostCliTests.fs new file mode 100644 index 000000000..db1bce816 --- /dev/null +++ b/tests/FS.GG.Coord.Cli.Tests/SelfHostCliTests.fs @@ -0,0 +1,157 @@ +namespace FS.GG.Coord.Cli.Tests + +open System +open System.Diagnostics +open System.IO +open System.Security.Cryptography +open Xunit +open FS.GG.Coord.SelfHost + +module SelfHostCliTests = + let private run args = + let engine = Path.Combine(AppContext.BaseDirectory, "fsgg-coord-engine.dll") + let start = ProcessStartInfo("dotnet") + start.UseShellExecute <- false + start.RedirectStandardOutput <- true + start.RedirectStandardError <- true + start.ArgumentList.Add engine + for arg in args do start.ArgumentList.Add arg + use child = Process.Start start + let stdout = child.StandardOutput.ReadToEnd() + let stderr = child.StandardError.ReadToEnd() + child.WaitForExit() + child.ExitCode, stdout, stderr + + let private git directory args = + let start = ProcessStartInfo("git") + start.WorkingDirectory <- directory + start.UseShellExecute <- false + start.RedirectStandardOutput <- true + start.RedirectStandardError <- true + for arg in args do start.ArgumentList.Add arg + use child = Process.Start start + let stdout = child.StandardOutput.ReadToEnd().Trim() + let stderr = child.StandardError.ReadToEnd() + child.WaitForExit() + if child.ExitCode <> 0 then failwithf "git %s failed: %s" (String.concat " " args) stderr + stdout + + let private withReceipt action = + let directory = Path.Combine(Path.GetTempPath(), "fsgg-self-host-" + Guid.NewGuid().ToString "n") + Directory.CreateDirectory directory |> ignore + try + let candidate = Path.Combine(directory, "candidate-engine") + let versionOut = "1.2.0-candidate" + File.WriteAllText(candidate, "#!/bin/sh\n[ \"$1\" = \"--version\" ] && printf '%s\\n' '1.2.0-candidate'\n") + File.SetUnixFileMode(candidate, UnixFileMode.UserRead ||| UnixFileMode.UserWrite ||| UnixFileMode.UserExecute) + let hash = File.ReadAllBytes candidate |> SHA256.HashData |> Convert.ToHexString |> _.ToLowerInvariant() + let snapshot = Path.Combine(directory, "snapshot.json") + File.WriteAllText(snapshot, "{\"snapshot\":1}") + let snapshotHash = File.ReadAllBytes snapshot |> SHA256.HashData |> Convert.ToHexString |> _.ToLowerInvariant() + let receipt = + createReceipt + "base" + "head" + hash + versionOut + "shared refusal" + snapshotHash + BootstrapReason.NewSchemaCase + { Build = "build"; Unit = "unit"; FocusedProductionRoute = "route"; Provenance = "provenance"; Inversion = "inversion" } + "decision" + "action" + { Actor = "host/ron000"; AcceptedAt = DateTimeOffset.Parse "2026-08-22T18:00:00Z" } + |> Result.defaultWith (String.concat "; " >> failwith) + let receiptPath = Path.Combine(directory, "receipt.txt") + File.WriteAllText(receiptPath, encodeReceipt receipt) + action receiptPath candidate snapshot + finally + Directory.Delete(directory, true) + + [] + let ``stable host command verifies exact candidate bytes and refuses drift`` () = + withReceipt (fun receipt candidate _ -> + let code, stdout, _ = run [ "self-host"; "verify"; receipt; candidate ] + Assert.Equal(0, code) + Assert.Contains("SELF-HOST-AUTHORIZED", stdout) + File.WriteAllBytes(candidate, [| 4uy |]) + let refused, _, stderr = run [ "self-host"; "verify"; receipt; candidate ] + Assert.NotEqual(0, refused) + Assert.Contains("does not match", stderr)) + + [] + let ``host mint binds measured candidate and snapshot bytes`` () = + withReceipt (fun receipt candidate snapshot -> + let directory = Path.GetDirectoryName receipt + let proposal = Path.Combine(directory, "proposal.json") + let output = Path.Combine(directory, "minted.txt") + File.WriteAllText( + proposal, + """{"baseSha":"base","candidateHeadSha":"head","sharedRefusal":"shared refusal","reason":"new-schema-case","evidence":{"build":"build","unit":"unit","focusedProductionRoute":"route","provenance":"provenance","inversion":"inversion"},"candidateDecisionKey":"decision","candidateActionKey":"action","hostAcceptance":{"actor":"host/ron000","acceptedAt":"2026-08-22T18:00:00Z"}}""" + ) + let code, stdout, stderr = run [ "self-host"; "mint"; proposal; candidate; snapshot; output ] + Assert.True((code = 0), stderr) + Assert.Contains("SELF-HOST-RECEIPT", stdout) + match File.ReadAllText output |> tryDecodeReceipt with + | Ok(Some minted) -> + let candidateHash = File.ReadAllBytes candidate |> SHA256.HashData |> Convert.ToHexString |> _.ToLowerInvariant() + let snapshotHash = File.ReadAllBytes snapshot |> SHA256.HashData |> Convert.ToHexString |> _.ToLowerInvariant() + Assert.Equal(candidateHash, minted.CandidateBinarySha256) + Assert.Equal(snapshotHash, minted.SnapshotSha256) + Assert.Equal("1.2.0-candidate", minted.CandidateVersion) + | other -> failwithf "expected minted receipt, got %A" other) + + [] + let ``post-merge replay command refuses decision or action disagreement`` () = + withReceipt (fun receipt _ snapshot -> + let code, stdout, _ = run [ "self-host"; "replay"; receipt; snapshot; "decision"; "action" ] + Assert.Equal(0, code) + Assert.Contains("SELF-HOST-REPLAY-AGREES", stdout) + let refused, _, stderr = run [ "self-host"; "replay"; receipt; snapshot; "different"; "action" ] + Assert.NotEqual(0, refused) + Assert.Contains("decision key disagrees", stderr) + File.WriteAllText(snapshot, "changed snapshot") + let stale, _, snapshotError = run [ "self-host"; "replay"; receipt; snapshot; "decision"; "action" ] + Assert.NotEqual(0, stale) + Assert.Contains("snapshot SHA-256", snapshotError)) + + [] + let ``stable verifier binds receipt base and head to the candidate checkout`` () = + let directory = Path.Combine(Path.GetTempPath(), "fsgg-self-host-git-" + Guid.NewGuid().ToString "n") + Directory.CreateDirectory directory |> ignore + try + git directory [ "init"; "-q"; "-b"; "main" ] |> ignore + git directory [ "config"; "user.email"; "self-host@example.invalid" ] |> ignore + git directory [ "config"; "user.name"; "Self Host Test" ] |> ignore + let candidate = Path.Combine(directory, "candidate-engine") + File.WriteAllText(candidate, "#!/bin/sh\n[ \"$1\" = \"--version\" ] && printf '%s\\n' '1.2.0-candidate'\n") + File.SetUnixFileMode(candidate, UnixFileMode.UserRead ||| UnixFileMode.UserWrite ||| UnixFileMode.UserExecute) + git directory [ "add"; "candidate-engine" ] |> ignore + git directory [ "commit"; "-q"; "-m"; "base" ] |> ignore + let baseSha = git directory [ "rev-parse"; "HEAD" ] + git directory [ "update-ref"; "refs/remotes/origin/main"; baseSha ] |> ignore + File.WriteAllText(Path.Combine(directory, "change.txt"), "candidate change") + git directory [ "add"; "change.txt" ] |> ignore + git directory [ "commit"; "-q"; "-m"; "candidate" ] |> ignore + let headSha = git directory [ "rev-parse"; "HEAD" ] + let hash = File.ReadAllBytes candidate |> SHA256.HashData |> Convert.ToHexString |> _.ToLowerInvariant() + let snapshot = Path.Combine(directory, "snapshot.json") + File.WriteAllText(snapshot, "{\"snapshot\":1}") + let snapshotHash = File.ReadAllBytes snapshot |> SHA256.HashData |> Convert.ToHexString |> _.ToLowerInvariant() + let receipt = + createReceipt baseSha headSha hash "1.2.0-candidate" "shared refusal" snapshotHash + BootstrapReason.RelocatedDecisionBoundary + { Build = "build"; Unit = "unit"; FocusedProductionRoute = "route"; Provenance = "provenance"; Inversion = "inversion" } + "decision" "action" + { Actor = "host/ron000"; AcceptedAt = DateTimeOffset.Parse "2026-08-22T18:00:00Z" } + |> Result.defaultWith (String.concat "; " >> failwith) + let receiptPath = Path.Combine(directory, "receipt.txt") + File.WriteAllText(receiptPath, encodeReceipt receipt) + let code, _, stderr = run [ "self-host"; "verify"; receiptPath; candidate; directory ] + Assert.True((code = 0), stderr) + git directory [ "commit"; "--allow-empty"; "-q"; "-m"; "head drift" ] |> ignore + let refused, _, drift = run [ "self-host"; "verify"; receiptPath; candidate; directory ] + Assert.NotEqual(0, refused) + Assert.Contains("does not match receipt head", drift) + finally + Directory.Delete(directory, true) diff --git a/tests/FS.GG.Coord.Core.Tests/DeliveryTests.fs b/tests/FS.GG.Coord.Core.Tests/DeliveryTests.fs index 844abe394..6e2b19991 100644 --- a/tests/FS.GG.Coord.Core.Tests/DeliveryTests.fs +++ b/tests/FS.GG.Coord.Core.Tests/DeliveryTests.fs @@ -1,5 +1,6 @@ namespace FS.GG.Coord.Tests +open System open Xunit open FS.GG.Coord @@ -126,6 +127,293 @@ module DeliveryTests = IssueClosed = false } transition Delivery.MergedAwaitingObligations Delivery.Complete (Delivery.inspect awaitingStamp) + [] + let ``complete delivery decision owns obligations reachability projections and cleanup`` () = + let completed = + { snapshot "head-a" with + Merged = true + MergeReachable = true + IssueClosed = true + BoardDone = true + ClaimReleased = true + PendingWrites = 0 + CleanupEligible = true } + + let decide facts = facts |> Delivery.completionFacts |> Delivery.decideCompletion + Assert.Equal(Delivery.CompletionDecision.NotMerged, decide (snapshot "head-a")) + + let pendingObligation = + { completed with + Obligations = + [ { Id = "nuget" + Kind = "publication" + Evidence = None + HeadSha = "head-a" + Verified = false } ] } + Assert.Equal( + Delivery.CompletionDecision.VerifyOutstandingObligation "nuget", + decide pendingObligation + ) + transition + Delivery.MergedAwaitingObligations + (Delivery.VerifyObligation "nuget") + (Delivery.inspect pendingObligation) + + let unreachable = { completed with MergeReachable = false } + Assert.Equal( + Delivery.CompletionDecision.Refused "merged pull request is not reachable from the default branch", + decide unreachable + ) + + for incomplete in + [ { completed with IssueClosed = false; CleanupEligible = false } + { completed with BoardDone = false; CleanupEligible = false } + { completed with ClaimReleased = false; CleanupEligible = false } + { completed with PendingWrites = 1; CleanupEligible = false } ] do + Assert.Equal(Delivery.CompletionDecision.ProjectCompletion, decide incomplete) + transition Delivery.MergedAwaitingObligations Delivery.Complete (Delivery.inspect incomplete) + + let cleanupIneligible = { completed with CleanupEligible = false } + Assert.Equal( + Delivery.CompletionDecision.Refused "cleanup is not eligible before completion", + decide cleanupIneligible + ) + Assert.Equal(Delivery.CompletionDecision.CleanupCompletedDelivery, decide completed) + transition Delivery.Done Delivery.CleanupWorktree (Delivery.inspect completed) + + [] + let ``bounded delivery completion model keeps reducer projection and writer admission identical`` () = + let obligation id head evidence verified : Delivery.Obligation = + { Id = id + Kind = "publication" + Evidence = evidence + HeadSha = head + Verified = verified } + let obligationCases = + [ "absent", false, [] + "outstanding", true, [ obligation "kit" "head-a" None false ] + "verified", true, [ obligation "kit" "head-a" (Some "https://receipt") true ] + "stale", true, [ obligation "kit" "old-head" (Some "https://receipt") true ] + "contradictory", true, + [ obligation "kit" "head-a" None false + obligation "kit" "head-a" (Some "https://receipt") true ] ] + let decisionClass = function + | Delivery.CompletionDecision.NotMerged -> "notMerged" + | Delivery.CompletionDecision.Refused _ -> "refused" + | Delivery.CompletionDecision.VerifyOutstandingObligation _ -> "verify" + | Delivery.CompletionDecision.ProjectCompletion -> "project" + | Delivery.CompletionDecision.CleanupCompletedDelivery -> "cleanup" + let reducerClass = function + | Delivery.Next transition when transition.Action = Delivery.Complete -> "project" + | Delivery.Next transition when transition.Action = Delivery.CleanupWorktree -> "cleanup" + | Delivery.Next transition -> + match transition.Action with + | Delivery.VerifyObligation _ -> "verify" + | _ -> "unexpected" + | Delivery.NoVerdict _ -> "refused" + + let mutable histories = 0 + for obligationCase, declared, obligations in obligationCases do + for reachable in [ false; true ] do + for issueClosed in [ false; true ] do + for boardDone in [ false; true ] do + for claimReleased in [ false; true ] do + for pendingWrites in [ 0; 1 ] do + for cleanupEligible in [ false; true ] do + histories <- histories + 1 + let candidate = + { snapshot "head-a" with + Merged = true + MergeReachable = reachable + IssueClosed = issueClosed + BoardDone = boardDone + ClaimReleased = claimReleased + PendingWrites = pendingWrites + CleanupEligible = cleanupEligible + ObligationsDeclared = declared + Obligations = obligations } + let decision = + candidate |> Delivery.completionFacts |> Delivery.decideCompletion + let expected = + match obligationCase with + | "absent" + | "stale" + | "contradictory" -> "refused" + | "outstanding" -> "verify" + | _ when not reachable -> "refused" + | _ when not issueClosed || not boardDone || not claimReleased || pendingWrites <> 0 -> + "project" + | _ when not cleanupEligible -> "refused" + | _ -> "cleanup" + let context = + $"obligations=%s{obligationCase}; reachable=%b{reachable}; issueClosed=%b{issueClosed}; boardDone=%b{boardDone}; claimReleased=%b{claimReleased}; pending=%d{pendingWrites}; cleanup=%b{cleanupEligible}" + Assert.True(decisionClass decision = expected, context) + Assert.True(reducerClass (Delivery.inspect candidate) = expected, context) + Assert.Equal( + (expected = "project"), + (decision = Delivery.CompletionDecision.ProjectCompletion) + ) + + Assert.Equal(320, histories) + + [] + let ``delivery completion mutation controls kill obligation head evidence and projection forks`` () = + let obligation id head evidence verified : Delivery.Obligation = + { Id = id + Kind = "publication" + Evidence = evidence + HeadSha = head + Verified = verified } + let terminal = + { snapshot "head-a" with + Merged = true + MergeReachable = true + IssueClosed = true + BoardDone = true + ClaimReleased = true + PendingWrites = 0 + CleanupEligible = true + Obligations = [ obligation "kit" "head-a" (Some "https://receipt") true ] } + let decide facts = facts |> Delivery.completionFacts |> Delivery.decideCompletion + let authoritative = decide terminal + Assert.Equal(Delivery.CompletionDecision.CleanupCompletedDelivery, authoritative) + + Assert.NotEqual( + authoritative, + decide { terminal with Obligations = [ obligation "kit" "old-head" (Some "https://receipt") true ] } + ) + Assert.NotEqual( + authoritative, + decide { terminal with Obligations = [ obligation "kit" "head-a" None true ] } + ) + Assert.NotEqual( + authoritative, + decide + { terminal with + Obligations = + [ obligation "kit" "head-a" None false + obligation "kit" "head-a" (Some "https://receipt") true ] } + ) + Assert.NotEqual(authoritative, decide { terminal with BoardDone = false; CleanupEligible = false }) + + let forked = + { terminal with BoardDone = false; CleanupEligible = false } + |> Delivery.inspect + let action = function + | Delivery.Next transition -> Some transition.Action + | Delivery.NoVerdict _ -> None + Assert.NotEqual(action (Delivery.inspect terminal), action forked) + + [] + let ``delivery completion receipt binds merge obligations pending writes and transition identity`` () = + let verified id evidence : Delivery.Obligation = + { Id = id + Kind = "publication" + Evidence = Some evidence + HeadSha = "head-a" + Verified = true } + let candidate = + { snapshot "head-a" with + Merged = true + MergeReachable = true + IssueClosed = true + BoardDone = false + ClaimReleased = false + PendingWrites = 0 + CleanupEligible = false + Obligations = + [ verified "kit" "https://receipt/kit" + verified "tool" "https://receipt/tool" ] } + let transition = + match Delivery.inspect candidate with + | Delivery.Next value when value.Action = Delivery.Complete -> value + | other -> failwithf "expected completion projection, got %A" other + let completedAt = DateTimeOffset.Parse("2026-08-22T15:00:00Z") + let receipt = + Delivery.createCompletionReceipt + candidate.Freshness.ItemRef + candidate.Freshness.PullRequest.Value + "merge-sha" + completedAt + transition.FreshnessToken + transition.ActionKey + (Delivery.completionFacts candidate) + |> Result.defaultWith (String.concat "; " >> failwith) + + Assert.Equal("merge-sha", receipt.MergeSha) + Assert.Equal(2, receipt.ObligationReceipts.Length) + Assert.NotEmpty(receipt.Digest) + Assert.Equal(Ok (), Delivery.verifyCompletionReceipt receipt) + let encoded = Delivery.encodeCompletionReceipt receipt + Assert.StartsWith(Delivery.CompletionReceiptMarker, encoded) + Assert.Equal(Ok(Some receipt), Delivery.tryDecodeCompletionReceipt encoded) + Assert.Equal(Ok None, Delivery.tryDecodeCompletionReceipt "ordinary comment") + + for tampered in + [ { receipt with MergeSha = "different-merge" } + { receipt with PendingBoardWrites = 1 } + { receipt with FreshnessToken = "different-transition" } + { receipt with + ObligationReceipts = + { receipt.ObligationReceipts.Head with Evidence = "different-evidence" } + :: receipt.ObligationReceipts.Tail } ] do + match Delivery.verifyCompletionReceipt tampered with + | Error _ -> () + | Ok () -> failwithf "tampered completion receipt verified: %A" tampered + + let outstanding = + { candidate with + Obligations = + [ { Id = "kit" + Kind = "publication" + Evidence = None + HeadSha = "head-a" + Verified = false } ] } + Assert.True( + Delivery.createCompletionReceipt + candidate.Freshness.ItemRef + candidate.Freshness.PullRequest.Value + "merge-sha" + completedAt + transition.FreshnessToken + transition.ActionKey + (Delivery.completionFacts outstanding) + |> Result.isError + ) + + [] + let ``completion correction receipt preserves only a safe nonterminal destination`` () = + let observedAt = DateTimeOffset.Parse("2026-08-22T16:00:00Z") + + for destination in [ Types.BoardStatus.InReview; Types.BoardStatus.Blocked ] do + let receipt = + Delivery.createCompletionCorrectionReceipt "FS-GG/.github#2131" destination observedAt + |> Result.defaultWith (String.concat "; " >> failwith) + Assert.Equal(Ok (), Delivery.verifyCompletionCorrectionReceipt receipt) + let encoded = Delivery.encodeCompletionCorrectionReceipt receipt + Assert.StartsWith(Delivery.CompletionCorrectionMarker, encoded) + Assert.Equal(Ok(Some receipt), Delivery.tryDecodeCompletionCorrectionReceipt encoded) + + match Delivery.verifyCompletionCorrectionReceipt { receipt with Item = "other/item#1" } with + | Error errors -> Assert.Contains("completion correction receipt digest does not match its facts", errors) + | Ok () -> failwith "a correction receipt with a changed subject verified" + + for unsafe in + [ Types.BoardStatus.Backlog + Types.BoardStatus.Ready + Types.BoardStatus.InProgress + Types.BoardStatus.Done + Types.BoardStatus.NoStatus ] do + Assert.True( + Delivery.createCompletionCorrectionReceipt "FS-GG/.github#2131" unsafe observedAt + |> Result.isError, + $"unsafe correction destination verified: %A{unsafe}" + ) + + Assert.Equal(Ok None, Delivery.tryDecodeCompletionCorrectionReceipt "ordinary comment") + let malformed = Delivery.CompletionCorrectionMarker + Environment.NewLine + "{}" + Assert.True(Delivery.tryDecodeCompletionCorrectionReceipt malformed |> Result.isError) + [] let ``#2131 cleanup is refused before every done fact agrees`` () = let incomplete = diff --git a/tests/FS.GG.Coord.Core.Tests/FS.GG.Coord.Core.Tests.fsproj b/tests/FS.GG.Coord.Core.Tests/FS.GG.Coord.Core.Tests.fsproj index d3e522fa5..326e829a4 100644 --- a/tests/FS.GG.Coord.Core.Tests/FS.GG.Coord.Core.Tests.fsproj +++ b/tests/FS.GG.Coord.Core.Tests/FS.GG.Coord.Core.Tests.fsproj @@ -18,6 +18,7 @@ + diff --git a/tests/FS.GG.Coord.Core.Tests/ReviewHeadDivergenceTests.fs b/tests/FS.GG.Coord.Core.Tests/ReviewHeadDivergenceTests.fs index c7dd15386..f0f55d26c 100644 --- a/tests/FS.GG.Coord.Core.Tests/ReviewHeadDivergenceTests.fs +++ b/tests/FS.GG.Coord.Core.Tests/ReviewHeadDivergenceTests.fs @@ -96,6 +96,42 @@ module ReviewHeadDivergenceTests = let private ordinaryRoundThreeChain terminalVerdict = ordinaryRoundThreeChainWithPrefix StructuredDecision.ChangesRequired terminalVerdict + let private boundedOrdinaryChain initialVerdict terminalVerdict round head = + let firstHead = if round = 0 then head else String.replicate 40 "0" + let first = initial initialVerdict firstHead + let comments = ResizeArray [ StructuredDecisionTests.reviewComment 1L first ] + let mutable previous = first + for currentRound in 1..round do + let verdict = + if currentRound = round then terminalVerdict + else StructuredDecision.ChangesRequired + let currentHead = if currentRound = round then head else String.replicate 40 (string currentRound) + let current = + following + (currentRound + 1) + previous.Digest + StructuredDecision.Confirmation + verdict + currentRound + currentHead + $"https://review/%d{currentRound}" + comments.Add(StructuredDecisionTests.reviewComment (int64 (currentRound + 1)) current) + previous <- current + comments |> Seq.toList + + let private exhaustionWait claimGeneration head : ReviewWait.WaitReceipt = + { Item = "FS-GG/.github#2819" + ClaimGeneration = claimGeneration + ReviewGeneration = + ReviewWait.generationToken + head + ReviewWait.RepairConfirmation + Protocol.reviewPolicy.MaxAutomatedRepairRounds + Kind = ReviewWait.RepairConfirmation + EnteredAt = DateTimeOffset.Parse("2026-08-22T10:00:00Z") + ExpiresAt = DateTimeOffset.Parse("2026-08-22T11:00:00Z") + EvidenceRef = "https://review/4" } + let private withRetiredAcceptedGeneration (liveComments: Driver.ReviewComment list) = let retiredHead = String.replicate 40 "c" let retiredInitial = initial StructuredDecision.Pass retiredHead @@ -142,6 +178,161 @@ module ReviewHeadDivergenceTests = Assert.False(Review.isOrdinaryExhaustionTerminal movedHead Types.PrRed pass) + [] + let ``complete ordinary exhaustion decision owns checks wait generation and claim turnover`` () = + let receipt: ReviewWait.WaitReceipt = + { Item = "FS-GG/.github#2819" + ClaimGeneration = "old-claim" + ReviewGeneration = + ReviewWait.generationToken + reviewedHead + ReviewWait.RepairConfirmation + Protocol.reviewPolicy.MaxAutomatedRepairRounds + Kind = ReviewWait.RepairConfirmation + EnteredAt = DateTimeOffset.Parse("2026-08-22T10:00:00Z") + ExpiresAt = DateTimeOffset.Parse("2026-08-22T11:00:00Z") + EvidenceRef = "https://review/4" } + + let decide checks claim waitState = + Review.decideOrdinaryExhaustion + { Phase = Review.Ordinary + HeadSha = reviewedHead + CurrentClaimGeneration = claim + Checks = checks + Comments = ordinaryRoundThreeChain StructuredDecision.Pass + WaitState = waitState } + + Assert.Equal(Review.OrdinaryExhaustionDecision.AwaitChecks, decide Types.PrPending "new-claim" (Some(ReviewWait.Completed(receipt, receipt.EvidenceRef)))) + Assert.Equal(Review.OrdinaryExhaustionDecision.HostAcceptanceEligible, decide Types.PrGreen "new-claim" (Some(ReviewWait.Completed(receipt, receipt.EvidenceRef)))) + Assert.Equal(Review.OrdinaryExhaustionDecision.CompletedOrdinaryExhaustion, decide Types.PrRed "new-claim" (Some(ReviewWait.Completed(receipt, receipt.EvidenceRef)))) + + match decide Types.PrRed "old-claim" (Some(ReviewWait.Completed(receipt, receipt.EvidenceRef))) with + | Review.OrdinaryExhaustionDecision.NotExhausted reason -> Assert.Contains("prior claim generation", reason) + | other -> failwithf "same-claim wait was admitted as %A" other + + [] + let ``bounded ordinary exhaustion model keeps reducer projection and writer admission identical`` () = + let oldClaim = "old-claim" + let receipt = exhaustionWait oldClaim reviewedHead + let waitStates = + [ "waiting", ReviewWait.Waiting receipt + "completed", ReviewWait.Completed(receipt, receipt.EvidenceRef) + "cancelled", ReviewWait.Cancelled(receipt, "https://cancel") + "expired", ReviewWait.Recoverable(receipt, "expired") + "malformed", ReviewWait.Invalid [ "malformed wait" ] ] + let claims = [ "same", oldClaim; "renewed", "renewed-claim"; "fresh", "fresh-claim" ] + let checks = [ Types.PrPending; Types.PrGreen; Types.PrRed; Types.PrUnknown ] + let verdicts = + [ StructuredDecision.Pass + StructuredDecision.ChangesRequired + StructuredDecision.Accepted ] + let original = verdictOf Review.Ordinary reviewedHead (ordinaryChain ()) Types.PrPending + let projectionFacts = facts (ordinaryRoundThreeChain StructuredDecision.ChangesRequired) Types.PrRed + let decisionClass = function + | Review.OrdinaryExhaustionDecision.NotExhausted _ -> "notExhausted" + | Review.OrdinaryExhaustionDecision.AwaitChecks -> "awaitChecks" + | Review.OrdinaryExhaustionDecision.HostAcceptanceEligible -> "hostAcceptanceEligible" + | Review.OrdinaryExhaustionDecision.CompletedOrdinaryExhaustion -> "completed" + + let mutable histories = 0 + for initialVerdict in verdicts do + for terminalVerdict in verdicts do + for round in 0..(Protocol.reviewPolicy.MaxAutomatedRepairRounds + 1) do + for check in checks do + for matchingHead in [ true; false ] do + for waitName, waitState in waitStates do + for claimName, currentClaim in claims do + histories <- histories + 1 + let currentHead = if matchingHead then reviewedHead else movedHead + let comments = + boundedOrdinaryChain initialVerdict terminalVerdict round reviewedHead + let decision = + Review.decideOrdinaryExhaustion + { Phase = Review.Ordinary + HeadSha = currentHead + CurrentClaimGeneration = currentClaim + Checks = check + Comments = comments + WaitState = Some waitState } + + let exactShape = + initialVerdict = StructuredDecision.ChangesRequired + && terminalVerdict = StructuredDecision.Pass + && round = Protocol.reviewPolicy.MaxAutomatedRepairRounds + && matchingHead + let terminalChanges = + initialVerdict = StructuredDecision.ChangesRequired + && terminalVerdict = StructuredDecision.ChangesRequired + && round = Protocol.reviewPolicy.MaxAutomatedRepairRounds + && matchingHead + let terminal = terminalChanges || (exactShape && check = Types.PrRed) + let expected = + if terminal && waitName = "completed" && currentClaim <> oldClaim then "completed" + elif exactShape && check = Types.PrPending then "awaitChecks" + elif exactShape && check = Types.PrGreen then "hostAcceptanceEligible" + else "notExhausted" + + let context = + $"initial=%A{initialVerdict}; terminal=%A{terminalVerdict}; round=%d{round}; checks=%A{check}; matchingHead=%b{matchingHead}; wait=%s{waitName}; claim=%s{claimName}" + Assert.True(decisionClass decision = expected, context) + + let writerAdmission = + decision = Review.OrdinaryExhaustionDecision.CompletedOrdinaryExhaustion + Assert.Equal((expected = "completed"), writerAdmission) + + let projected = + Review.projectOrdinaryExhaustion + decision + (binding Review.Ordinary reviewedHead) + projectionFacts + original + Assert.Equal( + (expected = "completed"), + (projected.State = Review.OrdinaryExhaustion) + ) + + Assert.Equal(5400, histories) + + [] + let ``ordinary exhaustion mutation controls kill head check wait claim and consumer forks`` () = + let receipt = exhaustionWait "old-claim" reviewedHead + let completed = ReviewWait.Completed(receipt, receipt.EvidenceRef) + let chain = ordinaryRoundThreeChain StructuredDecision.Pass + let decide head checks claim waitState = + Review.decideOrdinaryExhaustion + { Phase = Review.Ordinary + HeadSha = head + CurrentClaimGeneration = claim + Checks = checks + Comments = chain + WaitState = Some waitState } + + let authoritative = decide reviewedHead Types.PrRed "fresh-claim" completed + Assert.Equal(Review.OrdinaryExhaustionDecision.CompletedOrdinaryExhaustion, authoritative) + + // Each right-hand decision is the answer a one-clause mutant would substitute. If the named + // production clause disappears, the pair converges and this control turns red. + Assert.NotEqual(authoritative, decide movedHead Types.PrRed "fresh-claim" completed) + Assert.NotEqual(authoritative, decide reviewedHead Types.PrPending "fresh-claim" completed) + Assert.NotEqual(authoritative, decide reviewedHead Types.PrRed "fresh-claim" (ReviewWait.Waiting receipt)) + Assert.NotEqual(authoritative, decide reviewedHead Types.PrRed "old-claim" completed) + + let original = verdictOf Review.Ordinary reviewedHead (ordinaryChain ()) Types.PrPending + let projectionFacts = facts chain Types.PrRed + let admitted = + Review.projectOrdinaryExhaustion + authoritative + (binding Review.Ordinary reviewedHead) + projectionFacts + original + let forked = + Review.projectOrdinaryExhaustion + (Review.OrdinaryExhaustionDecision.NotExhausted "mutant consumer fork") + (binding Review.Ordinary reviewedHead) + projectionFacts + original + Assert.NotEqual(admitted.State, forked.State) + [] let ``2819 pre-round pass refuses both shared predicate and exhaustion projection`` () = let comments = @@ -150,7 +341,8 @@ module ReviewHeadDivergenceTests = let original = verdictOf Review.Ordinary reviewedHead comments Types.PrRed let projected = - Review.projectCompletedOrdinaryExhaustion + Review.projectOrdinaryExhaustion + (Review.OrdinaryExhaustionDecision.NotExhausted "pre-round pass") (binding Review.Ordinary reviewedHead) (facts comments Types.PrRed) original @@ -169,7 +361,8 @@ module ReviewHeadDivergenceTests = let original = verdictOf Review.Ordinary reviewedHead comments Types.PrRed let projected = - Review.projectCompletedOrdinaryExhaustion + Review.projectOrdinaryExhaustion + Review.OrdinaryExhaustionDecision.CompletedOrdinaryExhaustion (binding Review.Ordinary reviewedHead) (facts comments Types.PrRed) original diff --git a/tests/FS.GG.Coord.Core.Tests/SelfHostTests.fs b/tests/FS.GG.Coord.Core.Tests/SelfHostTests.fs new file mode 100644 index 000000000..e08331d57 --- /dev/null +++ b/tests/FS.GG.Coord.Core.Tests/SelfHostTests.fs @@ -0,0 +1,159 @@ +namespace FS.GG.Coord.Tests + +open System +open Xunit +open FS.GG.Coord.SelfHost + +module SelfHostTests = + let private evidence = + { Build = "trx:build" + Unit = "trx:unit" + FocusedProductionRoute = "trx:route" + Provenance = "sha256:provenance" + Inversion = "mutation:shared-refusal" } + + let private acceptance = + { Actor = "host/ron000" + AcceptedAt = DateTimeOffset.Parse "2026-08-22T18:00:00Z" } + + let private create reason = + createReceipt + "base-sha" + "candidate-head" + (String.replicate 64 "a") + "1.2.0-candidate" + "shared engine cannot decode self-host-bootstrap/v1" + (String.replicate 64 "c") + reason + evidence + "decision-key" + "action-key" + acceptance + |> Result.defaultWith (String.concat "; " >> failwith) + + [] + [] + [] + let ``every enumerated bootstrap reason round-trips through the stable verifier`` reasonName = + let reason = + if reasonName = "new-schema-case" then + BootstrapReason.NewSchemaCase + else + BootstrapReason.RelocatedDecisionBoundary + let receipt = create reason + Assert.Equal(Ok (), authorizeWrite receipt) + match receipt |> encodeReceipt |> tryDecodeReceipt with + | Ok(Some decoded) -> Assert.Equal(receipt, decoded) + | other -> failwithf "expected verified receipt, got %A" other + + [] + let ``unknown and business-rule disagreement reasons are refused`` () = + let body = + create BootstrapReason.NewSchemaCase + |> encodeReceipt + |> fun value -> value.Replace("new-schema-case", "business-rule-disagreement") + match tryDecodeReceipt body with + | Error errors -> Assert.Contains("unknown", String.concat "; " errors) + | other -> failwithf "expected closed-vocabulary refusal, got %A" other + + [] + let ``digest binds candidate bytes version heads refusal evidence decision action and host`` () = + let receipt = create BootstrapReason.RelocatedDecisionBoundary + let mutations = + [ { receipt with BaseSha = "other-base" } + { receipt with CandidateHeadSha = "other-head" } + { receipt with CandidateBinarySha256 = String.replicate 64 "b" } + { receipt with CandidateVersion = "other-version" } + { receipt with SharedRefusal = "other refusal" } + { receipt with SnapshotSha256 = String.replicate 64 "d" } + { receipt with Evidence = { receipt.Evidence with Unit = "other unit evidence" } } + { receipt with CandidateDecisionKey = "other-decision" } + { receipt with CandidateActionKey = "other-action" } + { receipt with HostAcceptance = { receipt.HostAcceptance with Actor = "other-host" } } ] + for mutation in mutations do + match authorizeWrite mutation with + | Error errors -> Assert.Contains("digest", String.concat "; " errors) + | Ok () -> failwith "a bound receipt field was mutable without invalidating authority" + + [] + let ``incomplete evidence and missing accountable host acceptance mint no receipt`` () = + let attempt evidence acceptance = + createReceipt + "base" + "head" + (String.replicate 64 "a") + "version" + "refusal" + (String.replicate 64 "c") + BootstrapReason.NewSchemaCase + evidence + "decision" + "action" + acceptance + match attempt { evidence with Inversion = "" } acceptance with + | Error errors -> Assert.Contains("inversion evidence", String.concat "; " errors) + | Ok _ -> failwith "incomplete evidence minted authority" + match attempt evidence { acceptance with Actor = "" } with + | Error errors -> Assert.Contains("host acceptance", String.concat "; " errors) + | Ok _ -> failwith "anonymous acceptance minted authority" + + [] + let ``post-merge replay disagreement blocks completion and release`` () = + let receipt = create BootstrapReason.NewSchemaCase + Assert.Equal(Ok (), verifyReplay receipt { DecisionKey = "decision-key"; ActionKey = "action-key" }) + match verifyReplay receipt { DecisionKey = "changed"; ActionKey = "action-key" } with + | Error errors -> Assert.Contains("decision key disagrees", String.concat "; " errors) + | Ok () -> failwith "decision disagreement passed replay" + match verifyReplay receipt { DecisionKey = "decision-key"; ActionKey = "changed" } with + | Error errors -> Assert.Contains("action key disagrees", String.concat "; " errors) + | Ok () -> failwith "action disagreement passed replay" + + [] + let ``durable replay is bound to bootstrap snapshot decision action and time`` () = + let bootstrap = create BootstrapReason.NewSchemaCase + let replay = + createReplayReceipt + bootstrap + bootstrap.SnapshotSha256 + { DecisionKey = "decision-key"; ActionKey = "action-key" } + (DateTimeOffset.Parse "2026-08-22T19:00:00Z") + |> Result.defaultWith (String.concat "; " >> failwith) + Assert.Equal(Ok (), verifyReplayReceipt bootstrap replay) + match replay |> encodeReplayReceipt |> tryDecodeReplayReceipt with + | Ok(Some decoded) -> Assert.Equal(replay, decoded) + | other -> failwithf "expected verified replay receipt, got %A" other + for mutation in + [ { replay with BootstrapDigest = String.replicate 64 "b" } + { replay with SnapshotSha256 = String.replicate 64 "d" } + { replay with DecisionKey = "different" } + { replay with ActionKey = "different" } + { replay with ReplayedAt = replay.ReplayedAt.AddSeconds 1.0 } ] do + match verifyReplayReceipt bootstrap mutation with + | Error _ -> () + | Ok () -> failwith "a replay authority field was mutable without invalidating the digest" + + [] + let ``bootstrap presence requires exactly one agreeing replay before completion`` () = + let bootstrap = create BootstrapReason.NewSchemaCase + let bootstrapBody = encodeReceipt bootstrap + match replayState [] with + | NoBootstrap -> () + | other -> failwithf "ordinary items should be unaffected, got %A" other + match replayState [ bootstrapBody ] with + | ReplayRequired receipt -> Assert.Equal(bootstrap.Digest, receipt.Digest) + | other -> failwithf "bootstrap did not require replay, got %A" other + let replay = + createReplayReceipt bootstrap bootstrap.SnapshotSha256 + { DecisionKey = "decision-key"; ActionKey = "action-key" } + (DateTimeOffset.Parse "2026-08-22T19:00:00Z") + |> Result.defaultWith (String.concat "; " >> failwith) + let replayBody = encodeReplayReceipt replay + match replayState [ bootstrapBody; replayBody ] with + | VerifiedReplay receipt -> Assert.Equal(replay.Digest, receipt.Digest) + | other -> failwithf "agreeing replay was not completion authority, got %A" other + match replayState [ replayBody ] with + | InvalidReplay errors -> Assert.Contains("without bootstrap", String.concat "; " errors) + | other -> failwithf "orphan replay was accepted, got %A" other + match replayState [ bootstrapBody; replayBody; replayBody ] with + | InvalidReplay errors -> Assert.Contains("more than one self-host replay", String.concat "; " errors) + | other -> failwithf "duplicate replay was accepted, got %A" other diff --git a/tests/FS.GG.Coord.GitHub.Tests/DoneFactsTests.fs b/tests/FS.GG.Coord.GitHub.Tests/DoneFactsTests.fs index 7d7ef5040..cfb74b1a5 100644 --- a/tests/FS.GG.Coord.GitHub.Tests/DoneFactsTests.fs +++ b/tests/FS.GG.Coord.GitHub.Tests/DoneFactsTests.fs @@ -70,7 +70,75 @@ let private noSubs = """{"totalCount":0,"nodes":[]}""" let ``#2264 only the immutable done receipt is terminal lifecycle evidence`` () = Assert.False(hasReceipt []) Assert.False(hasReceipt [ "issue closed"; "" ]) - Assert.True(hasReceipt [ "\nverified" ]) + Assert.False(hasReceipt [ "\nverified" ]) + +[] +let ``typed delivery completion receipt is accepted only after digest verification`` () = + let facts: FS.GG.Coord.Delivery.CompletionFacts = + { HeadSha = "head" + Merged = true + MergeReachable = true + IssueClosed = true + BoardDone = false + ClaimReleased = false + PendingWrites = 0 + CleanupEligible = false + ObligationsDeclared = true + Obligations = [] } + let signed = + FS.GG.Coord.Delivery.createCompletionReceipt + "FS-GG/.github#1" + 2 + "merge-sha" + (System.DateTimeOffset.Parse("2026-08-22T15:00:00Z")) + "freshness" + "action" + facts + |> Result.defaultWith (String.concat "; " >> failwith) + let encoded = FS.GG.Coord.Delivery.encodeCompletionReceipt signed + Assert.True(hasReceipt [ encoded ]) + Assert.False(hasReceipt [ encoded.Replace("merge-sha", "tampered-merge") ]) + match receiptState [ encoded ] with + | VerifiedCompletionReceipt actual -> Assert.Equal(signed, actual) + | other -> failwithf "expected verified typed receipt, got %A" other + let anotherRef = { Owner = "FS-GG"; Repo = ".github"; Number = 99 } + match receiptStateFor anotherRef [ encoded ] with + | InvalidCompletionReceipt errors -> Assert.Contains("does not match", String.concat "; " errors) + | other -> failwithf "expected item-binding refusal, got %A" other + Assert.False(hasReceiptFor anotherRef [ encoded ]) + match receiptState [ encoded; encoded ] with + | InvalidCompletionReceipt errors -> Assert.Contains("more than one", String.concat "; " errors) + | other -> failwithf "expected duplicate receipt refusal, got %A" other + match receiptState [ encoded.Replace("merge-sha", "tampered-merge") ] with + | InvalidCompletionReceipt errors -> Assert.Contains("digest", String.concat "; " errors) + | other -> failwithf "expected digest-invalid receipt, got %A" other + Assert.Equal(LegacyReceipt, receiptState [ "\nverified" ]) + Assert.Equal(NoReceipt, receiptState [ "ordinary comment" ]) + +[] +let ``completion correction evidence is subject-bound unique and digest-verified`` () = + let signed = + FS.GG.Coord.Delivery.createCompletionCorrectionReceipt + ref.Canonical + BoardStatus.InReview + (System.DateTimeOffset.Parse("2026-08-22T16:00:00Z")) + |> Result.defaultWith (String.concat "; " >> failwith) + let encoded = FS.GG.Coord.Delivery.encodeCompletionCorrectionReceipt signed + + Assert.Equal(VerifiedCompletionCorrection signed, completionCorrectionStateFor ref [ encoded ]) + Assert.Equal(NoCompletionCorrection, completionCorrectionStateFor ref [ "ordinary comment" ]) + + match completionCorrectionStateFor { ref with Number = 351 } [ encoded ] with + | InvalidCompletionCorrection errors -> Assert.Contains("does not match", String.concat "; " errors) + | other -> failwithf "expected subject mismatch, got %A" other + + match completionCorrectionStateFor ref [ encoded; encoded ] with + | InvalidCompletionCorrection errors -> Assert.Contains("more than one", String.concat "; " errors) + | other -> failwithf "expected duplicate refusal, got %A" other + + match completionCorrectionStateFor ref [ encoded.Replace("In review", "Blocked") ] with + | InvalidCompletionCorrection errors -> Assert.Contains("digest", String.concat "; " errors) + | other -> failwithf "expected digest refusal, got %A" other // ---- the closing act ---------------------------------------------------------------------------------- diff --git a/tests/FS.GG.Coord.GitHub.Tests/WriteTests.fs b/tests/FS.GG.Coord.GitHub.Tests/WriteTests.fs index 8d54a5647..d7ebd5bfb 100644 --- a/tests/FS.GG.Coord.GitHub.Tests/WriteTests.fs +++ b/tests/FS.GG.Coord.GitHub.Tests/WriteTests.fs @@ -2000,6 +2000,247 @@ let ``a follow-up disposition is a durable issue comment, not a worker mailbox m | Ok() -> Assert.True(transport.Logged "comment-post FS-GG/FS.GG.SDD 42") | Error e -> failwith $"the disposition must be recorded on the owed issue — got %A{e}" +[] +let ``delivery completion receipt appends once and refuses contradictory authority`` () = + let completionFacts: FS.GG.Coord.Delivery.CompletionFacts = + { HeadSha = "head-a" + Merged = true + MergeReachable = true + IssueClosed = true + BoardDone = false + ClaimReleased = false + PendingWrites = 0 + CleanupEligible = false + ObligationsDeclared = true + Obligations = [] } + let mint mergeSha completedAt = + FS.GG.Coord.Delivery.createCompletionReceipt + aRef.Canonical + 99 + mergeSha + completedAt + "freshness" + "action" + completionFacts + |> Result.defaultWith (String.concat "; " >> failwith) + let first = mint "merge-a" (System.DateTimeOffset.Parse("2026-08-22T15:00:00Z")) + let retry = mint "merge-a" (System.DateTimeOffset.Parse("2026-08-22T15:01:00Z")) + let contradiction = mint "merge-b" (System.DateTimeOffset.Parse("2026-08-22T15:02:00Z")) + let mutable stored: string option = None + let mutable posts = 0 + let transport = + Fake.Recorder(fun request -> + match request.Method with + | "GET" -> + match stored with + | None -> ok "[]" + | Some body -> ok (comments [ markerWithExactBody 950 body ]) + | "POST" -> + posts <- posts + 1 + match request.Body with + | Json payload -> + use document = System.Text.Json.JsonDocument.Parse payload + stored <- Some(document.RootElement.GetProperty("body").GetString()) + | _ -> failwith "completion receipt POST carried no JSON body" + ok "{\"id\":950}" + | method -> failwithf "unexpected method %s" method) + + Assert.Equal(Ok (), deliveryCompletionReceipt transport aRef first) + Assert.Equal(Ok (), deliveryCompletionReceipt transport aRef retry) + Assert.Equal(1, posts) + match deliveryCompletionReceipt transport aRef contradiction with + | Error(Malformed(_, reason)) -> Assert.Contains("contradictory", reason) + | other -> failwithf "expected contradictory receipt refusal, got %A" other + Assert.Equal(1, posts) + +[] +let ``completion correction receipt appends once and refuses a changed safe destination`` () = + let mint destination observedAt = + FS.GG.Coord.Delivery.createCompletionCorrectionReceipt aRef.Canonical destination observedAt + |> Result.defaultWith (String.concat "; " >> failwith) + let first = mint BoardStatus.InReview (System.DateTimeOffset.Parse("2026-08-22T16:00:00Z")) + let retry = mint BoardStatus.InReview (System.DateTimeOffset.Parse("2026-08-22T16:01:00Z")) + let contradiction = mint BoardStatus.Blocked (System.DateTimeOffset.Parse("2026-08-22T16:02:00Z")) + let mutable stored: string option = None + let mutable posts = 0 + let transport = + Fake.Recorder(fun request -> + match request.Method with + | "GET" -> + match stored with + | None -> ok "[]" + | Some body -> ok (comments [ markerWithExactBody 951 body ]) + | "POST" -> + posts <- posts + 1 + match request.Body with + | Json payload -> + use document = System.Text.Json.JsonDocument.Parse payload + stored <- Some(document.RootElement.GetProperty("body").GetString()) + | _ -> failwith "correction receipt POST carried no JSON body" + ok "{\"id\":951}" + | method -> failwithf "unexpected method %s" method) + + Assert.Equal(Ok (), completionCorrectionReceipt transport aRef first) + Assert.Equal(Ok (), completionCorrectionReceipt transport aRef retry) + Assert.Equal(1, posts) + match completionCorrectionReceipt transport aRef contradiction with + | Error(Malformed(_, reason)) -> Assert.Contains("contradictory", reason) + | other -> failwithf "expected contradictory correction refusal, got %A" other + Assert.Equal(1, posts) + +[] +let ``legacy done evidence can be corrected but cannot block typed migration`` () = + let receipt = + FS.GG.Coord.Delivery.createCompletionCorrectionReceipt + aRef.Canonical + BoardStatus.InReview + (System.DateTimeOffset.Parse("2026-08-22T16:00:00Z")) + |> Result.defaultWith (String.concat "; " >> failwith) + let legacy = "\nverified" + let mutable correction: string option = None + let mutable posts = 0 + let transport = + Fake.Recorder(fun request -> + match request.Method with + | "GET" -> + let bodies = + match correction with + | None -> [ markerWithExactBody 950 legacy ] + | Some body -> [ markerWithExactBody 950 legacy; markerWithExactBody 951 body ] + ok (comments bodies) + | "POST" -> + posts <- posts + 1 + match request.Body with + | Json payload -> + use document = System.Text.Json.JsonDocument.Parse payload + correction <- Some(document.RootElement.GetProperty("body").GetString()) + | _ -> failwith "correction receipt POST carried no JSON body" + ok "{\"id\":951}" + | method -> failwithf "unexpected method %s" method) + + Assert.Equal(Ok (), completionCorrectionReceipt transport aRef receipt) + Assert.Equal(Ok (), completionCorrectionReceipt transport aRef receipt) + Assert.Equal(1, posts) + +[] +let ``self-host bootstrap authority appends once and refuses contradiction`` () = + let evidence: FS.GG.Coord.SelfHost.Evidence = + { Build = "build"; Unit = "unit"; FocusedProductionRoute = "route"; Provenance = "provenance"; Inversion = "inversion" } + let acceptance: FS.GG.Coord.SelfHost.HostAcceptance = + { Actor = "host/ron000"; AcceptedAt = System.DateTimeOffset.Parse("2026-08-22T18:00:00Z") } + let mint action = + FS.GG.Coord.SelfHost.createReceipt "base" "head" (String.replicate 64 "a") "version" "refusal" (String.replicate 64 "c") + FS.GG.Coord.SelfHost.BootstrapReason.NewSchemaCase evidence "decision" action acceptance + |> Result.defaultWith (String.concat "; " >> failwith) + let receipt = mint "action" + let mutable stored: string option = None + let mutable posts = 0 + let transport = + Fake.Recorder(fun request -> + match request.Method with + | "GET" -> + match stored with None -> ok "[]" | Some body -> ok (comments [ markerWithExactBody 960 body ]) + | "POST" -> + posts <- posts + 1 + match request.Body with + | Json payload -> + use document = System.Text.Json.JsonDocument.Parse payload + stored <- Some(document.RootElement.GetProperty("body").GetString()) + | _ -> failwith "self-host receipt POST carried no JSON body" + ok "{\"id\":960}" + | method -> failwithf "unexpected method %s" method) + + Assert.Equal(Ok (), selfHostBootstrapReceipt transport aRef receipt) + Assert.Equal(Ok (), selfHostBootstrapReceipt transport aRef receipt) + Assert.Equal(1, posts) + match selfHostBootstrapReceipt transport aRef (mint "different-action") with + | Error(Malformed(_, reason)) -> Assert.Contains("contradictory", reason) + | other -> failwithf "expected contradictory self-host refusal, got %A" other + +[] +let ``self-host replay appends once only after matching durable bootstrap`` () = + let evidence: FS.GG.Coord.SelfHost.Evidence = + { Build = "build"; Unit = "unit"; FocusedProductionRoute = "route"; Provenance = "provenance"; Inversion = "inversion" } + let bootstrap = + FS.GG.Coord.SelfHost.createReceipt "base" "head" (String.replicate 64 "a") "version" "refusal" (String.replicate 64 "c") + FS.GG.Coord.SelfHost.BootstrapReason.NewSchemaCase evidence "decision" "action" + { Actor = "host/ron000"; AcceptedAt = System.DateTimeOffset.Parse("2026-08-22T18:00:00Z") } + |> Result.defaultWith (String.concat "; " >> failwith) + let replay = + FS.GG.Coord.SelfHost.createReplayReceipt bootstrap bootstrap.SnapshotSha256 + { DecisionKey = "decision"; ActionKey = "action" } + (System.DateTimeOffset.Parse("2026-08-22T19:00:00Z")) + |> Result.defaultWith (String.concat "; " >> failwith) + let mutable bodies = [ FS.GG.Coord.SelfHost.encodeReceipt bootstrap ] + let mutable posts = 0 + let transport = + Fake.Recorder(fun request -> + match request.Method with + | "GET" -> ok (comments (bodies |> List.mapi (fun index body -> markerWithExactBody (970 + index) body))) + | "POST" -> + posts <- posts + 1 + match request.Body with + | Json payload -> + use document = System.Text.Json.JsonDocument.Parse payload + bodies <- bodies @ [ document.RootElement.GetProperty("body").GetString() ] + | _ -> failwith "self-host replay POST carried no JSON body" + ok "{\"id\":971}" + | method -> failwithf "unexpected method %s" method) + Assert.Equal(Ok (), selfHostReplayReceipt transport aRef replay) + Assert.Equal(Ok (), selfHostReplayReceipt transport aRef replay) + Assert.Equal(1, posts) + + let withoutBootstrap = Fake.Recorder(fun request -> if request.Method = "GET" then ok "[]" else failwith "unexpected write") + match selfHostReplayReceipt withoutBootstrap aRef replay with + | Error(Malformed(_, reason)) -> Assert.Contains("without durable bootstrap", reason) + | other -> failwithf "expected missing-bootstrap refusal, got %A" other + +[] +let ``reopenIssue requires fresh OPEN state and recovers a lost PATCH response`` () = + let mutable state = "closed" + let mutable loseResponse = false + let transport = + Fake.Recorder(fun request -> + match request.Method with + | "PATCH" -> + state <- "open" + if loseResponse then Error(Transport "response lost") else ok "{}" + | "GET" -> ok ($"{{\"state\":\"%s{state}\"}}") + | method -> failwithf "unexpected method %s" method) + + Assert.Equal(Ok (), reopenIssue transport aRef) + state <- "closed" + loseResponse <- true + Assert.Equal(Ok (), reopenIssue transport aRef) + + let unverified = + Fake.Recorder(fun request -> + match request.Method with + | "PATCH" -> ok "{}" + | "GET" -> ok "{\"state\":\"closed\"}" + | method -> failwithf "unexpected method %s" method) + match reopenIssue unverified aRef with + | Error(Malformed(_, reason)) -> Assert.Contains("still CLOSED", reason) + | other -> failwithf "expected fresh-state refusal, got %A" other + +[] +let ``closeIssueCompleted requires fresh CLOSED state`` () = + let mutable state = "open" + let transport = + Fake.Recorder(fun request -> + match request.Method with + | "PATCH" -> + match request.Body with + | Json payload -> + Assert.Contains("\"state_reason\":\"completed\"", payload) + state <- "closed" + | _ -> failwith "issue close carried no JSON body" + ok "{}" + | "GET" -> ok ($"{{\"state\":\"%s{state}\"}}") + | method -> failwithf "unexpected method %s" method) + + Assert.Equal(Ok (), closeIssueCompleted transport aRef) + // ---- reap: an expired lease is EVIDENCE of abandonment, not PROOF (#581) ---------------------------- let private staleMarker = diff --git a/tests/change-completeness/run.sh b/tests/change-completeness/run.sh new file mode 100755 index 000000000..eae396843 --- /dev/null +++ b/tests/change-completeness/run.sh @@ -0,0 +1,50 @@ +#!/usr/bin/env bash +set -euo pipefail + +ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)" +WORK="$(mktemp -d)" +trap 'rm -rf "$WORK"' EXIT +pass=0 +fail=0 +ok() { pass=$((pass + 1)); printf 'PASS %s\n' "$1"; } +bad() { fail=$((fail + 1)); printf 'FAIL %s\n' "$1" >&2; } + +printf 'docs/readme.md\n' >"$WORK/docs.paths" +printf 'src/FS.GG.Coord.Core/Review.fs\n' >"$WORK/engine.paths" + +GITHUB_OUT="$WORK/docs.out" "$ROOT/scripts/change-completeness" \ + --paths-file "$WORK/docs.paths" --github-output "$WORK/docs.out" >"$WORK/docs.log" \ + && ok 'unrelated changes take the bounded non-engine route' || bad 'unrelated route failed' +grep -qx 'engine_changed=false' "$WORK/docs.out" && ok 'unrelated changes do not schedule expensive engine work' || bad 'unrelated impact was misclassified' + +GITHUB_OUT="$WORK/engine.out" "$ROOT/scripts/change-completeness" \ + --paths-file "$WORK/engine.paths" --github-output "$WORK/engine.out" >/dev/null \ + && ok 'engine changes run the focused structural route' || bad 'engine route failed' +grep -qx 'engine_changed=true' "$WORK/engine.out" && ok 'engine changes schedule the expensive successor' || bad 'engine impact was misclassified' + +# The production runner must name every structural family. These are observable diagnostics, not prose: +# deleting a stage makes this fixture red before a PR can silently stop running that family. +for label in \ + 'closing-keyword and commit-message contract' \ + 'SDD ship-verdict provenance' \ + 'command catalogue, parser, render, write-ness, contract, and help closure' \ + 'handler ownership and production registration' \ + 'delivery, review, declared-path, and focused production-route parity'; do + grep -Fq "$label" "$ROOT/scripts/change-completeness" && ok "named stage: $label" || bad "missing named stage: $label" +done + +grep -Fq 'needs: change-completeness' "$ROOT/.github/workflows/coord-engine.yml" \ + && ok 'expensive engine job depends on change-completeness' \ + || bad 'engine job can start before change-completeness' +pull_request_trigger="$(sed -n '/^ pull_request:/,/^ push:/p' "$ROOT/.github/workflows/coord-engine.yml")" +if grep -q 'paths:' <<<"$pull_request_trigger"; then + bad 'required change-completeness context is path-filtered' +else + ok 'required change-completeness context reports on every pull-request head' +fi +grep -Fq 'timeout-minutes: 5' "$ROOT/.github/workflows/coord-engine.yml" \ + && ok 'workflow encodes the five-minute target' \ + || bad 'five-minute target is not encoded' + +printf '\nchange-completeness fixture: %d passed, %d failed\n' "$pass" "$fail" +[ "$fail" -eq 0 ] diff --git a/tests/change-risk-compatibility/run.sh b/tests/change-risk-compatibility/run.sh new file mode 100755 index 000000000..b22e10830 --- /dev/null +++ b/tests/change-risk-compatibility/run.sh @@ -0,0 +1,53 @@ +#!/usr/bin/env bash +set -euo pipefail + +ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)" +pass=0 +fail=0 +ok() { pass=$((pass + 1)); printf 'PASS %s\n' "$1"; } +bad() { fail=$((fail + 1)); printf 'FAIL %s\n' "$1" >&2; } +has() { grep -Eq "$2" "$ROOT/$1" && ok "$3" || bad "$3"; } + +# Expand-and-contract: the new authority is live while predecessor inputs still have an explicit, +# fail-closed interpretation instead of disappearing between slices. +has src/FS.GG.Coord.GitHub/Done.fs 'LegacyReceipt' 'legacy completion evidence remains diagnosable during migration' +has scripts/fsgg-coord-guards.sh 'self-host.*verify.*replay' 'candidate read-only verify/replay remains available without write authority' +has scripts/release-saga.py 'commands.add_parser\("promote"\)' 'the predecessor promotion command remains available' +has src/FS.GG.Coord.Cli.Kernel/Options.fs 'commandCatalogue' 'catalogue metadata remains centralized after coexistence' + +# Every compatibility slice has both a green parity artifact and a source inversion that can red. +for artifact in \ + command-catalogue-kernel.test-report.xml \ + lifecycle-model-core.test-report.xml \ + completion-receipts-core.test-report.xml \ + self-host-core.test-report.xml \ + change-completeness-kernel.test-report.xml \ + release-recovery.junit.xml; do + report="$ROOT/work/coordination-change-risk-mitigation/artifacts/$artifact" + if [ -s "$report" ] && python3 - "$report" <<'PY' +import pathlib, sys, xml.etree.ElementTree as ET +root = ET.parse(pathlib.Path(sys.argv[1])).getroot() +if root.tag.endswith("TestRun"): + counters = next(node for node in root.iter() if node.tag.endswith("Counters")) + assert int(counters.attrib.get("failed", "0")) == 0 + assert int(counters.attrib.get("executed", "0")) > 0 +else: + suites = [root] if root.tag.endswith("testsuite") else list(root.iter("testsuite")) + assert suites and sum(int(row.attrib.get("tests", "0")) for row in suites) > 0 + assert sum(int(row.attrib.get("failures", "0")) for row in suites) == 0 +PY + then + ok "observed green compatibility evidence: $artifact" + else + bad "missing, empty, or red compatibility evidence: $artifact" + fi +done + +has tests/FS.GG.Coord.Cli.Kernel.Tests/CommandSurfaceTests.fs 'mutant' 'catalogue slice retains an effective omission inversion' +has tests/FS.GG.Coord.Core.Tests/DeliveryTests.fs 'mutation' 'lifecycle slice retains decision-boundary mutations' +has tests/FS.GG.Coord.Core.Tests/SelfHostTests.fs 'tamper|mutable' 'self-host slice retains digest inversions' +has tests/change-completeness/run.sh 'missing named stage' 'CI slice reds when a structural family disappears' +has tests/release-saga/run.sh 'tampered|expected receiver receipt identity tampering' 'release slice retains receiver-receipt inversion' + +printf '\nchange-risk compatibility: %d passed, %d failed\n' "$pass" "$fail" +[ "$fail" -eq 0 ] diff --git a/tests/coord-engine-e2e/stateful_server.py b/tests/coord-engine-e2e/stateful_server.py index 18dd07cda..2c184001e 100755 --- a/tests/coord-engine-e2e/stateful_server.py +++ b/tests/coord-engine-e2e/stateful_server.py @@ -41,23 +41,25 @@ 43: {"body": "Another item.\n\nPaths: src/Other/**", "state": "OPEN", "status": "Ready"}, 99: {"body": "A parent epic.\n\nPaths: none", "state": "OPEN", "status": "In progress"}, 44: {"body": "A verify-paths subject.\n\nPaths: src/Verify/**", "state": "OPEN", "status": "In progress"}, - # #733 — a `.github` item that is CLOSED while its board column still says Ready. That is - # CLOSED-ISSUE-NOT-DONE: a real chore, derived (never stored), and the one this fixture offers. + # A `.github` item carrying only legacy completion evidence. The change-risk boundary must not + # treat this closed/Ready mismatch as terminal authority or offer it as a completion chore. 50: {"body": "A closed .github item the board still calls Ready.\n\nPaths: src/X/**", "state": "CLOSED", "status": "Ready", "repo": ".github"}, # #733 — the item whose `done` triggers the AfterDone offer. In `.github`, so its offer resolves a lock. 51: {"body": "A finished .github item.\n\nPaths: src/Y/**", "state": "CLOSED", "status": "In review", "repo": ".github"}, - # #1087 — a chore in a RECEIVER (FS.GG.SDD, the default repo): CLOSED while the board still says Ready. - # Before #1087 the SDD offer was refused for want of a lock; now SDD#518 exists and this drains. This is - # the row that proves the rollout — a receiver conscripts a caller, which .github used to do alone. + # A receiver item with legacy completion evidence. Reconciliation reopens it and projects In review; + # it is no longer a CLOSED-ISSUE-NOT-DONE chore because no typed delivery receipt authorizes completion. 45: {"body": "A closed SDD item the board still calls Ready.\n\nPaths: src/Z/**", "state": "CLOSED", "status": "Ready"}, - # .github#2157 — the closed #45 dependency has cleared, but this row is still projected as + # .github#2157 — the closed off-board #48 dependency has cleared, but this row is still projected as # Blocked. Reconcile must make the coupled Status=Ready / Blocked by='' repair as one batch, - # then prove BOTH values on a fresh scan. + # then prove BOTH values on a fresh scan. Keeping the dependency off-board isolates this reducer + # fixture from #45's independent premature-completion correction transaction. + 48: {"body": "A completed off-board dependency.\n\nPaths: src/Dependency/**", + "state": "CLOSED", "status": "Done", "off_board": True}, 47: {"body": "A formerly blocked SDD item.\n\nPaths: src/Blocked/**", - "state": "OPEN", "status": "Blocked", "blocked_by": "FS-GG/FS.GG.SDD#45"}, + "state": "OPEN", "status": "Blocked", "blocked_by": "FS-GG/FS.GG.SDD#48"}, # #1087 — the free-refusal control: an UNROSTERED repo (no chore lock at all). All seven FS-GG repos now # have one, so the honest "no lock" case is a repo `choreLockRef` does not know. `done` here stamps and # offers nothing, WITHOUT a board read — the #733 free-refusal path, now reachable only off-roster. @@ -497,6 +499,8 @@ def graphql(query: str, variables: dict): ISSUES[n]["status"] = "Done" elif "opt_wip" in value or "opt_wip" in inline_options: ISSUES[n]["status"] = "In progress" + elif "opt_review" in value or "opt_review" in inline_options: + ISSUES[n]["status"] = "In review" elif "opt_ready" in value or "opt_ready" in inline_options: ISSUES[n]["status"] = "Ready" elif "opt_backlog" in value or "opt_backlog" in inline_options: @@ -701,6 +705,8 @@ def do_PATCH(self): ISSUES[n]["body"] = body["body"] if n in ISSUES and body.get("state") == "closed": ISSUES[n]["state"] = "CLOSED" + if n in ISSUES and body.get("state") == "open": + ISSUES[n]["state"] = "OPEN" return self._send(200, {"number": n}) self._send(500, {"message": f"fixture: unhandled PATCH {path}"}) @@ -885,7 +891,7 @@ def do_GET(self): with LOCK: ISSUES[47]["off_board"] = False ISSUES[47]["status"] = "Blocked" - ISSUES[47]["blocked_by"] = "FS-GG/FS.GG.SDD#45" + ISSUES[47]["blocked_by"] = "FS-GG/FS.GG.SDD#48" RECONCILE_47_PARTIAL[0] = 0 RECONCILE_47_MISSING[0] = 0 return self._send(200, {"number": 47, "status": "Blocked", "blockedBy": ISSUES[47]["blocked_by"]}) diff --git a/tests/coord-engine-e2e/writes.sh b/tests/coord-engine-e2e/writes.sh index 726d8545c..75bdad40b 100755 --- a/tests/coord-engine-e2e/writes.sh +++ b/tests/coord-engine-e2e/writes.sh @@ -1280,132 +1280,45 @@ sp="$("$ENGINE" set-paths FS.GG.SDD#43 --worker vole-418 --paths 'src/Narrow/**' && ok "#1377: set-paths explicitly replaces (and can narrow) the touch-set" \ || bad "#1377: set-paths is the explicit replacement operation" "rc=$sprc: $sp" -# ---- done stamps a completed item ------------------------------------------------------------------ +# ---- standalone done is nonterminal completion replay ---------------------------------------------- +# Terminal completion authority belongs to `delivery --pr ... --apply`, where the typed lifecycle +# receipt is minted and verified. The compatibility spelling may inspect facts, but it must never +# synthesize the old FSGG-DONE stamp, alter the board, release a claim, or offer a completion chore. +curl -fsS "$FSGG_GITHUB_API_BASE/_fixture/mutations" >/dev/null dn="$(run "done" FS.GG.SDD#42 2>&1)"; dnrc=$? # quoted: the coord VERB, not the loop keyword (SC1010, #648) -[ "$dnrc" -eq 0 ] && printf '%s' "$dn" | grep -q 'FSGG-DONE' \ - && ok "done stamps an item closed by a merged PR" \ - || bad "done stamps a completed item" "rc=$dnrc: $dn" - -# ---- #1151: done SURFACES a DEFERRED Status write, keeps the GREEN stamp, and flush completes it ----- -# The exact condition #1151 closes: on an exhausted budget the Status=Done write returns `Deferred` -# (QUEUED, and nothing replays it on its own). The Green arm used to `|> ignore` that outcome, so `done` -# printed green, exited 0, and said NOTHING about the flush the board now needs — silent drift. It must -# instead keep the green verdict (the WORK is done), DROP the claim (the lock's lifetime is the work's, -# #533), and PRINT the flush remedy. Then `flush` lands the queued stamp. -run claim FS.GG.SDD#42 >/dev/null 2>&1 # a live marker for done to drop -curl -fsS "$FSGG_GITHUB_API_BASE/_fixture/defer-next-field-write" >/dev/null # arm: the next field write RATE-LIMITS -dd="$(run "done" FS.GG.SDD#42 --flip 2>&1)"; ddrc=$? -if [ "$ddrc" -eq 0 ] \ - && printf '%s' "$dd" | grep -q 'FSGG-DONE' \ - && printf '%s' "$dd" | grep -qi 'DEFERRED' \ - && printf '%s' "$dd" | grep -q 'scripts/fsgg-coord flush'; then - ok "#1151: done keeps the GREEN stamp but SURFACES the deferred Status write with flush advice" -else - bad "#1151: done surfaces the deferred Status write with flush advice" "rc=$ddrc: $dd" -fi - -# ...and the claim marker is DROPPED even though the column deferred — the lock must not outlive the work. -after1151="$(curl -fsS "$FSGG_GITHUB_API_BASE/repos/FS-GG/FS.GG.SDD/issues/42/comments")" -printf '%s' "$after1151" | grep -q 'fsgg:claim' \ - && bad "#1151: done drops the claim marker on a deferred write" "the marker survives: $after1151" \ - || ok "#1151: done drops the claim marker even when the Status write DEFERS" - -# ...and flush REPLAYS the queued Status=Done write against the now-healthy server — the stamp is not lost. -fdd="$(run flush 2>&1)"; fddrc=$? -[ "$fddrc" -eq 0 ] && ! printf '%s' "$fdd" | grep -qi 'DROPPED' \ - && ok "#1151: flush replays the deferred Status=Done write (the queued stamp lands)" \ - || bad "#1151: flush replays the deferred stamp" "rc=$fddrc: $fdd" - -# ---- #1086: a worker mid-item in ANOTHER repo is NOT idle, and is offered nothing -------------------- -# The whole of #1086, end to end. `vole-418` holds a live claim on FS.GG.SDD#43 (taken above and never -# released), and is here stamping a `.github` item. Condition 3 says they must not be handed a side-quest: -# they are mid-lease with a live touch-set — in a different repo, which is exactly what makes it invisible. -# -# It was invisible. The offer asked "are you idle?" of a board scoped to `.github`, in which that SDD claim -# does not appear, so the honest guard answered "idle" and handed over the chore. The board is read -# UNFILTERED now and the scope rides in the type, so the claim is seen and the offer is withheld. -# -# IT RUNS FIRST, BEFORE ANY LEG TAKES THE CHORE LOCK, and that ordering is the whole assertion. Written -# after the snipe-733 legs it PASSED WITH THE BUG SIMULATED: snipe-733 holds `.github#1033` by then, so -# vole-418's offer lost the LOCK and returned None for a reason having nothing to do with idleness. A leg -# that cannot fail is not evidence — it is the "shaped to pass" defect this issue's own review history -# (plover-a4cf, #733) caught one level up. So: lock free, chore real, worker busy — one variable. -# -# The chore is REAL and offerable on exactly this board: snipe-733 is handed it by the very next leg. -vb="$("$ENGINE" "done" FS-GG/.github#51 --flip --worker vole-418 2>&1)"; vbrc=$? -[ "$vbrc" -eq 0 ] && printf '%s' "$vb" | grep -q 'FSGG-DONE' && ! printf '%s' "$vb" | grep -qi 'chore' \ - && ok "#1086: a worker holding a claim in ANOTHER repo is not idle — no chore, though one is on offer" \ - || bad "#1086: cross-repo claim makes us busy" "rc=$vbrc: $vb" - -# ---- #733/§4.6: `done` is a SAFE POINT, and it is the one a working fleet reaches -------------------- -# Condition 3 names two boundaries — after `done`, or at `next`. #1056 wired `next`; `Chore.AfterDone` was -# a case Core declared and NOTHING minted. That matters because of WHERE the two sit in the recipe: -# `/pnext-item` takes (§1), stamps (§5), and loops back to `take` (§6), calling `next` only in its -# "take found nothing" DIAGNOSTIC. An offer that fires only at `next` fires only when the board has no -# work — and a board with no work has no fleet to conscript. This leg is the whole claim: stamping an item -# offers a chore. -# -# .github#51 is stamped; .github#50 is the chore (CLOSED, board column still Ready → CLOSED-ISSUE-NOT-DONE). -dc="$("$ENGINE" "done" FS-GG/.github#51 --flip --worker snipe-733 2>&1)"; dcrc=$? -[ "$dcrc" -eq 0 ] && printf '%s' "$dc" | grep -q 'FSGG-DONE' \ - && printf '%s' "$dc" | grep -q '^chore \[quick\] \.github#50: fresh lifecycle facts project Status=Done' \ - && ok "M6: done offers only the direct reducer's receipt-backed lifecycle projection" \ - || bad "M6: done did not offer the direct reducer result" "rc=$dcrc: $dc" - -# THE OFFER IS A COURTESY, AND THE STAMP OUTRANKS IT. The chore rides on STDERR, never stdout: `done`'s -# stdout carries the FSGG-DONE verdict a caller greps, and an offer printed there would corrupt the answer -# it is attached to — the same rule `next` keeps for its item ref. -dso="$("$ENGINE" "done" FS-GG/.github#51 --flip --worker snipe-733 2>/dev/null)" -printf '%s' "$dso" | grep -q 'FSGG-DONE' && ! printf '%s' "$dso" | grep -qi 'chore' \ - && ok "#733: the AfterDone offer is on stderr — done's stdout verdict is untouched" \ - || bad "#733: offer does not pollute done's stdout" "$dso" - -# #1087 — A RECEIVER NOW DRAINS. Before #1087 `choreLockRef` knew only `.github#1033`, so a `done` in any -# receiver was refused for want of a lock and the queue drained in `.github` alone. The six receivers now -# have closed `[chore-lock]` issues (SDD#518 among them) and the map resolves all seven, so stamping an SDD -# item offers an SDD chore under SDD's OWN lock. This is the rollout's whole point, and it reds on pre-#1087 -# code (SDD had no lock). The direct reducer selects the first stale SDD projection (#44 → Ready). -rc="$("$ENGINE" "done" FS.GG.SDD#42 --worker snipe-1087 2>&1)"; rcrc=$? -[ "$rcrc" -eq 0 ] && printf '%s' "$rc" | grep -q 'FSGG-DONE' \ - && printf '%s' "$rc" | grep -q '^chore \[quick\] FS.GG.SDD#44: fresh lifecycle facts project Status=Ready' \ - && ok "M6: receiver done also offers the direct reducer's fresh projection" \ - || bad "M6: receiver done did not offer the direct reducer result" "rc=$rcrc: $rc" - -# AN UNROSTERED REPO IS REFUSED, FOR FREE. All seven FS-GG repos have a lock now, so the honest "no lock" -# case is a repo `choreLockRef` does not know (FS.GG.Legacy). `Chores.offer`'s step 1 is that pure string -# match, placed first "because it spends nothing" — so a `done` there stamps, offers nothing, and never -# reads the board. No assertion on OUTPUT can catch a stray read (the output is identical either way: -# nothing), so the fixture counts board reads and this asserts the count does not move. -br0="$(curl -fsS "$FSGG_GITHUB_API_BASE/_fixture/board-reads" | sed 's/[^0-9]//g')" -dn2="$("$ENGINE" "done" FS.GG.Legacy#60 --worker snipe-1087 2>&1)"; dn2rc=$? -[ "$dn2rc" -eq 0 ] && printf '%s' "$dn2" | grep -q 'FSGG-DONE' && ! printf '%s' "$dn2" | grep -qi 'chore' \ - && ok "#1087: an UNROSTERED repo is offered nothing, and still stamps" \ - || bad "#1087: unrostered repo offers nothing" "rc=$dn2rc: $dn2" -br1="$(curl -fsS "$FSGG_GITHUB_API_BASE/_fixture/board-reads" | sed 's/[^0-9]//g')" -[ "$br0" = "$br1" ] \ - && ok "#1087: an unrostered repo costs NO board read — the free question is asked first (${br0}→${br1})" \ - || bad "#1087: unrostered done spends no board read" "board reads went ${br0} → ${br1}" - -# ---- .github#1535: `next` TAKES THE CHORE LOCK, and `batch` does not -------------------------------- -# The decision #1535 asked for, pinned as behaviour: `next` WRITES. Its contract everywhere a caller met -# it — `/pnext-item` §1, the take exit-code table, and `tests/coord-engine-parity/shim.sh`, which used it -# as the canonical READ verb in the stale-engine guard's read leg for that leg's whole life until #1528 — -# said "tell me what to work on", and after printing that answer it POSTs a claim marker taking the -# repo's chore lock (`.github#1033`, -# ADR-0041). The write is real, it is deliberate (#733/§4.6 conscription), and it is now DECLARED rather -# than discovered. This leg is what stops the declaration and the code drifting apart again. -# -# THE MARKER IS THE ASSERTION, NOT THE PRINTED OFFER. The chore text on stderr is what a human sees, and -# a leg that grepped only for it would pass on an engine that printed the offer and took no lock — the -# offer is a courtesy, the LOCK is the write, and only one of them is #1535's subject. So this reads the -# comment thread on #1033 and asserts a marker naming THIS worker appeared on it. -# -# THE PRECONDITION IS ESTABLISHED, NOT ASSUMED, and that is the whole reason for the release and the -# BEFORE assertion. `snipe-733` still holds #1033 from the AfterDone legs above; a leg written without -# this would find a marker on #1033 either way and pass WITHOUT `next` having written anything — the -# "shaped to pass" defect this file's own #1086 note records being caught one level up. Empty before, -# ours after, one variable. -"$ENGINE" release "FS-GG/.github#1033" --worker snipe-733 >/dev/null 2>&1 +dn_ledger="$(curl -fsS "$FSGG_GITHUB_API_BASE/_fixture/mutations")" +if [ "$dnrc" -ne 0 ] && grep -q 'FSGG-NOT-DONE' <<<"$dn" \ + && grep -q 'delivery --pr' <<<"$dn" && [ "$(jq -r .count <<<"$dn_ledger")" = 0 ]; then + ok "change-risk: standalone done refuses without any remote mutation and names delivery authority" +else + bad "change-risk: standalone done must be a nonterminal replay" "rc=$dnrc output=$dn ledger=$dn_ledger" +fi + +"$ENGINE" claim FS.GG.SDD#42 --worker done-guard >/dev/null 2>&1 +before_done_claim="$(curl -fsS "$FSGG_GITHUB_API_BASE/repos/FS-GG/FS.GG.SDD/issues/42/comments")" +dd="$("$ENGINE" "done" FS.GG.SDD#42 --flip --worker done-guard 2>&1)"; ddrc=$? +after_done_claim="$(curl -fsS "$FSGG_GITHUB_API_BASE/repos/FS-GG/FS.GG.SDD/issues/42/comments")" +if [ "$ddrc" -ne 0 ] && grep -q 'FSGG-NOT-DONE' <<<"$dd" \ + && grep -q 'fsgg:claim' <<<"$before_done_claim" && grep -q 'fsgg:claim' <<<"$after_done_claim" \ + && ! grep -qi 'chore' <<<"$dd"; then + ok "change-risk: standalone done preserves the live claim and cannot conscript a chore" +else + bad "change-risk: nonterminal done must preserve claim authority" "rc=$ddrc output=$dd before=$before_done_claim after=$after_done_claim" +fi +"$ENGINE" release FS.GG.SDD#42 --worker done-guard >/dev/null 2>&1 + +for done_ref in FS-GG/.github#51 FS.GG.SDD#42 FS.GG.Legacy#60; do + done_out="$("$ENGINE" "done" "$done_ref" --flip --worker snipe-733 2>&1)"; done_rc=$? + if [ "$done_rc" -ne 0 ] && grep -q 'FSGG-NOT-DONE' <<<"$done_out" && ! grep -qi 'chore' <<<"$done_out"; then + ok "change-risk: $done_ref cannot complete or offer a chore through standalone done" + else + bad "change-risk: standalone done authority is uniform across repositories" "ref=$done_ref rc=$done_rc output=$done_out" + fi +done + +# ---- next does not conscript legacy completion evidence -------------------------------------------- +# `next` remains conditionally write-capable when it offers an authorized chore. This fixture exposes +# only legacy done markers, so the correct arm is the empty answer with an untouched chore-lock thread. lk0="$(curl -fsS "$FSGG_GITHUB_API_BASE/repos/FS-GG/.github/issues/1033/comments")" printf '%s' "$lk0" | grep -q 'fsgg:claim' \ && bad ".github#1535: the chore lock is FREE before the probe" "a marker survives: $lk0" \ @@ -1442,26 +1355,16 @@ printf '%s' "$bn" | grep -q 'nothing schedulable right now.' \ && ok ".github#1535: ...and it is the same ANSWER — one shared \`nothingSchedulable\` spelling, so the words cannot drift" \ || bad ".github#1535: batch --text prints next's answer" "rc=$bnrc: $bn" -# ...AND `next`, same worker, same board, POSTS. +# Legacy done markers are no longer completion authority, so `next` must not conscript their stale +# projections or take a chore lock for them. A typed delivery receipt is the only terminal source. nx="$("$ENGINE" next --repo .github --worker teal-1535 2>&1)"; nxrc=$? lk1="$(curl -fsS "$FSGG_GITHUB_API_BASE/repos/FS-GG/.github/issues/1033/comments")" -[ "$nxrc" -eq 0 ] && printf '%s' "$lk1" | grep -q 'fsgg:claim' \ - && printf '%s' "$lk1" | grep -q 'worker=teal-1535' \ - && ok ".github#1535: \`next\` POSTs a claim marker to .github#1033 — it WRITES, and is declared so" \ - || bad ".github#1535: next takes the chore lock" "rc=$nxrc: $nx / lock thread: $lk1" - -# ...and the offer it printed names the chore it took the lock FOR, so the write and the reason a caller -# is given for it are the same fact. A lock taken for a chore the caller is never told about would be the -# write with none of the conscription that justifies it. -# -# ANCHORED ON THE CHORE LINE, not searched for `#50` anywhere in the output: `next` also prints `#50` in -# its passed-over list, so an unanchored grep would be satisfied by an offer naming a DIFFERENT subject — -# a leg that cannot see the thing it claims to check. -printf '%s' "$nx" | grep -q '^chore \[quick\] \.github#50:' \ - && ok ".github#1535: the lock \`next\` took is the one the offer it printed names (#50)" \ - || bad ".github#1535: next's offer names its subject" "rc=$nxrc: $nx" - -# Hand the lock back, so nothing downstream inherits a held chore lock from a diagnostic verb. +[ "$nxrc" -eq 0 ] && grep -q 'nothing schedulable right now.' <<<"$nx" \ + && ! grep -q 'fsgg:claim' <<<"$lk1" && ! grep -qi '^chore ' <<<"$nx" \ + && ok "change-risk: next ignores legacy completion markers and takes no chore lock" \ + || bad "change-risk: legacy done evidence must not authorize chore conscription" "rc=$nxrc: $nx / lock thread: $lk1" + +# Defensive cleanup keeps downstream tests isolated if this assertion ever regresses. "$ENGINE" release "FS-GG/.github#1033" --worker teal-1535 >/dev/null 2>&1 # ---- verify-paths: a PR inside its touch-set is OK ------------------------------------------------- @@ -2322,6 +2225,22 @@ must_mutate() { fi } +# `self-host` advertises a write because its `record` arm appends stable-engine-authorized bootstrap +# evidence to the accountable item. Mint the receipt with the candidate's real bytes/version, then +# prove the record arm reaches the fixture comment thread. +self_host_proposal="$CYCLE_FIX/self-host-proposal.json" +self_host_snapshot="$CYCLE_FIX/self-host-snapshot.json" +self_host_receipt="$CYCLE_FIX/self-host-receipt.txt" +printf '%s\n' '{}' >"$self_host_snapshot" +printf '%s\n' '{"baseSha":"fixture-base","candidateHeadSha":"fixture-head","sharedRefusal":"fixture shared engine refused a relocated decision boundary","reason":"relocated-decision-boundary","evidence":{"build":"fixture-build","unit":"fixture-unit","focusedProductionRoute":"fixture-route","provenance":"fixture-provenance","inversion":"fixture-inversion"},"candidateDecisionKey":"fixture-decision","candidateActionKey":"fixture-action","hostAcceptance":{"actor":"host/ron000","acceptedAt":"2026-08-22T12:00:00Z"}}' >"$self_host_proposal" +self_host_mint="$("$ENGINE" self-host mint "$self_host_proposal" "$ENGINE" "$self_host_snapshot" "$self_host_receipt" 2>&1)"; self_host_mint_rc=$? +if [ "$self_host_mint_rc" -eq 0 ] && grep -q 'SELF-HOST-RECEIPT' <<<"$self_host_mint"; then + must_mutate "self-host" run self-host record FS.GG.SDD#42 "$self_host_receipt" +else + mark_contract "self-host" "record-driver-mint-failed" + bad "#1569: self-host receipt must mint before its record mutation" "rc=$self_host_mint_rc output=$self_host_mint" +fi + # #46 is deliberately off-board, so `add` cannot be satisfied by its idempotent existing-item arm. must_mutate "add" run add FS.GG.SDD#46 # Use a new worker: the fixture's normal driver holds an item, and the one-item-per-worker guard @@ -2386,7 +2305,7 @@ printf '%s' "$partial" | jq -e ' map(select(.subject == "FS.GG.SDD#47")) | length == 1 and .[0].outcome == "failed" and (.[0].error | contains("Blocked by")) and - .[0].observed == [{"field":"Status","value":"Ready"},{"field":"Blocked by","value":"FS-GG/FS.GG.SDD#45"}]' >/dev/null 2>&1 \ + .[0].observed == [{"field":"Status","value":"Ready"},{"field":"Blocked by","value":"FS-GG/FS.GG.SDD#48"}]' >/dev/null 2>&1 \ && [ "$partial_rc" -ne 0 ] \ && ok "#2157: partial Status-only projection fails closed and retains both fresh observations" \ || bad "#2157: partial BLOCKER-CLEARED must fail closed" "rc=$partial_rc receipt=$partial" diff --git a/tests/coord-engine-parity/run.sh b/tests/coord-engine-parity/run.sh index 004e2a07a..ccffb84a8 100755 --- a/tests/coord-engine-parity/run.sh +++ b/tests/coord-engine-parity/run.sh @@ -678,7 +678,7 @@ else fi kill "$S585" 2>/dev/null; rm -f "$S585_OUT" -# ---- COMPLETED ITEM DROPS ITS LOCK (case 32): #533 — `done --flip` releases the worker's own claim --- +# ---- LEGACY COMPLETION IS NONTERMINAL: #533's lock is retained until typed delivery authority exists --- # # `done --flip` verified the merge, set Status Done, and rolled the epic up — and, before #533, never # touched the CLAIM MARKER. `release` was the only path that dropped it, and `release` REWRITES Status, so @@ -692,45 +692,39 @@ kill "$S585" 2>/dev/null; rm -f "$S585_OUT" # no dependency) — the machine fact this slice turns on is "is the claim marker still there after done?". dclaims() { python3 -c 'import sys,urllib.request; sys.stdout.write(urllib.request.urlopen("http://127.0.0.1:"+sys.argv[1]+"/repos/FS-GG/FS.GG.SDD/issues/42/comments").read().decode())' "$1" 2>/dev/null; } -# 1. vole-533 stamps #42 (closed by merged PR #7) and DROPS its OWN marker — a finished item stops -# reserving its files. The stamp is still earned; the lock is gone. +# `done` is now a compatibility/replay surface: it cannot mint the completion receipt introduced by the +# typed delivery lifecycle. Even an otherwise valid merged-PR world must therefore remain nonterminal, +# retain its claim, and direct the caller to `delivery --apply`. D1_OUT="$(mktemp)"; DONE_HOLDER=vole-533 python3 "$HERE/done_server.py" >"$D1_OUT" 2>/dev/null & DP1=$! dp1=""; for _ in $(seq 1 50); do dp1="$(head -n1 "$D1_OUT" 2>/dev/null)"; [ -n "$dp1" ] && break; sleep 0.1; done rm -f "$D1_OUT" if [ -n "$dp1" ]; then d1="$(FSGG_GITHUB_API_BASE="http://127.0.0.1:$dp1" FSGG_COORD_CACHE="$(mktemp -d)" \ "$ENGINE" "done" 'FS.GG.SDD#42' --worker vole-533 --pr 7 --flip 2>&1)"; d1rc=$? - [ "$d1rc" -eq 0 ] && printf '%s' "$d1" | grep -q 'FSGG-DONE FS.GG.SDD#42' \ - && ok "#533: the stamp is still earned (green, FSGG-DONE) — dropping the lock does not touch the verdict" \ - || bad "#533: done --flip stamps the item green" "rc=$d1rc: $d1" - # The machine fact: after `done`, the claim marker is GONE. A live marker's `Paths:` keep reserving. + [ "$d1rc" -ne 0 ] && printf '%s' "$d1" | grep -q 'standalone done cannot mint completion authority' \ + && ok "completion boundary: standalone done remains nonterminal and names typed delivery authority" \ + || bad "completion boundary: standalone done must refuse terminal projection" "rc=$d1rc: $d1" printf '%s' "$(dclaims "$dp1")" | grep -q 'worker=vole-533' \ - && bad "#533: a finished item must NOT keep its claim — the marker is still live after done" "$(dclaims "$dp1")" \ - || ok "#533: done --flip DROPS the worker's own claim — the finished item stops reserving its files" + && ok "completion boundary: refusal RETAINS the worker's claim until delivery completes" \ + || bad "completion boundary: legacy refusal must not drop the live claim" "$(dclaims "$dp1")" kill "$DP1" 2>/dev/null else bad "#533 fixture (own marker) bound a port" fi -# 2. It drops ONLY OUR OWN marker. Deleting another worker's claim is `reap`'s job, and it is destructive -# — `done` must not do it silently just because the item is finished. Here other-999 holds #42; vole-533 -# stamps it Done, and the guarantee is structural: a `Held` is obtainable only by confirming the live -# winner is US (verifyHeld), so `release` here CANNOT touch a marker that is not ours. FRESH server. +# A stranger's marker is retained for the same reason, and the legacy call still cannot project Done. D2_OUT="$(mktemp)"; DONE_HOLDER=other-999 python3 "$HERE/done_server.py" >"$D2_OUT" 2>/dev/null & DP2=$! dp2=""; for _ in $(seq 1 50); do dp2="$(head -n1 "$D2_OUT" 2>/dev/null)"; [ -n "$dp2" ] && break; sleep 0.1; done rm -f "$D2_OUT" if [ -n "$dp2" ]; then d2="$(FSGG_GITHUB_API_BASE="http://127.0.0.1:$dp2" FSGG_COORD_CACHE="$(mktemp -d)" \ - "$ENGINE" "done" 'FS.GG.SDD#42' --worker vole-533 --pr 7 --flip 2>&1)" + "$ENGINE" "done" 'FS.GG.SDD#42' --worker vole-533 --pr 7 --flip 2>&1)"; d2rc=$? printf '%s' "$(dclaims "$dp2")" | grep -q 'worker=other-999' \ && ok "#533: ...but it must NOT delete a claim that is not ours — other-999's marker is left intact" \ || bad "#533: done deleted a stranger's claim" "$(dclaims "$dp2")" - printf '%s' "$d2" | grep -q 'still holds its claim' \ - && ok "#533: ...it says so instead — names the other holder, drops only your own lock" \ - || bad "#533: done names the claim it left" "$d2" - printf '%s' "$d2" | grep -qi 'reap' \ - && ok "#533: ...and points at reap — the destructive path a stranger's claim actually needs" \ - || bad "#533: done points at reap for another's claim" "$d2" + [ "$d2rc" -ne 0 ] && printf '%s' "$d2" | grep -q 'standalone done cannot mint completion authority' \ + && ok "completion boundary: another holder cannot make legacy done terminal either" \ + || bad "completion boundary: legacy done must refuse before holder-specific terminal effects" "rc=$d2rc: $d2" kill "$DP2" 2>/dev/null else bad "#533 fixture (stranger's marker) bound a port" @@ -3025,7 +3019,13 @@ if [ -z "$LE_PORT" ]; then bad "lint-epic fixture bound a port"; else fi # ================================================================================================== -# case 14 (no-touch-set-and-done) — the `done --flip` EPIC ROLLUP (#235/#583/#325/#346). Stamping a child +# RETIRED TERMINAL-DONE CORPUS. These fixtures predate the typed delivery-completion receipt and cannot +# answer the additional delivery snapshot queries. Keeping their old terminal assertions active would +# certify the forbidden inversion: standalone `done` minting completion authority. The live compatibility +# assertion now sits in the #533 block above (non-zero, explicit remedy, zero claim deletion); typed merge, +# provenance, evidence, completion, and parent-rollup behavior is covered by the focused delivery suites. +if false; then +# case 14 (no-touch-set-and-done) — the former `done --flip` EPIC ROLLUP (#235/#583/#325/#346). Stamping a child # with --flip climbs to its parent and rolls it up ONLY when genuinely finished: HOLDS while a sibling is # open (#235/#583), FLIPS when every child is Done + closed, REFUSES when the epic BODY declares a child # the sub-issue graph does not contain (#325) — the EpicBody/subIssues check landed for lint, now reused — @@ -3242,6 +3242,7 @@ if [ -z "$DP_PORT" ]; then bad "done-provenance fixture bound a port"; else kill "$DP_SRV" 2>/dev/null fi +fi # retired standalone-done terminal corpus # case 34 (xrepo-touchset-353) — the `overlap` command (#353). `Paths:` tokens are repo-relative, so a # touch-set comparison is only meaningful WITHIN a repo. `overlap` scopes to ONE repo: a same-named token in diff --git a/tests/coord-engine-parity/shim.sh b/tests/coord-engine-parity/shim.sh index 7da057e04..b84c93955 100755 --- a/tests/coord-engine-parity/shim.sh +++ b/tests/coord-engine-parity/shim.sh @@ -84,13 +84,17 @@ unset CLAUDE_CODE_SESSION_ID OPENCODE_SESSION_ID FSGG_AGENT_SESSION_ID FSGG_AGEN export FSGG_WORKER="" # ---- 1. THE WHOLE D.1 CORPUS, THROUGH THE SHIM --------------------------------------------------- -# run.sh drives its engine from FSGG_COORD_ENGINE_BIN. Point it at a wrapper that hands the shim the -# real engine (tier 1) and execs it — so run.sh's 445 assertions are decided by the shim, transparently. -# (The wrapper must RESET the var: run.sh exports it pointing at the wrapper, and the shim would -# otherwise resolve the wrapper as its "explicit bin" and loop.) +# run.sh drives its engine from FSGG_COORD_ENGINE_BIN. Point it at a wrapper that presents the one fixed +# engine as the stable engine on PATH, then hands every argv to the shim. A fixed engine is load-bearing: +# several corpus worlds deliberately `cd` into synthetic repositories to test scope inference, so asking +# the shim to rediscover a source build from each synthetic cwd changes the subject under test. Naming the +# same PATH engine explicitly selects the shim's stable packaged-engine classification and keeps argv, +# cwd, stdout, stderr and exit-code parity measurable. Candidate refusal and accepted-receipt behaviour +# have their own legs below; this leg measures transparent stable-host dispatch, not candidate bootstrap. WRAP="$(mktemp)" cat >"$WRAP" <&1 >/dev/null)"; rc=$? out="$(cd "$FIX" && FSGG_COORD_ENGINE_BIN="$FIXBIN" "$SHIM" release "$FIXREF" 2>/dev/null)" -if [ "$rc" -eq 0 ] && [ -z "$err" ] && printf '%s' "$out" | grep -q 'ENGINE RAN'; then - ok "staleness: an explicit FSGG_COORD_ENGINE_BIN is honoured silently — an instruction, not a hint" +if [ "$rc" -eq 69 ] && printf '%s' "$err" | grep -q 'FSGG_SELF_HOST_RECEIPT' && ! printf '%s' "$out" | grep -q 'ENGINE RAN'; then + ok "self-host: an opaque explicit engine cannot write without typed bootstrap authority" else - bad "staleness: tier 1 must not consult staleness" "rc=$rc out=$out err=$err" + bad "self-host: an opaque explicit engine must fail closed before a write" "rc=$rc out=$out err=$err" fi # ---- 3b. THE VERB PARTITION IS TOTAL AND EXACT (.github#1528) ------------------------------------ @@ -1433,16 +1435,14 @@ else fi rm -f "$D"/src/FS.GG.Coord.Core/f?.fs -# TIER 1 IS EXEMPT, STRUCTURALLY — an explicit bin execs before tier 2 is ever reached. This is why §1's -# corpus, which drives the shim through FSGG_COORD_ENGINE_BIN from a checkout that may well be dirty -# (somebody is always working this repo), cannot be polluted by this guard. +# AN AUTHORED EXPLICIT BIN IS A CANDIDATE. Dirty engine inputs are precisely the self-host population. printf '// WIP\n' >>"$D/$FIXSRC"; touch -d '3 hours ago' "$D/$FIXSRC" err="$(cd "$D" && FSGG_COORD_ENGINE_BIN="$DBIN" "$SHIM" claim "$FIXREF" 2>&1 >/dev/null)"; rc=$? out="$(cd "$D" && FSGG_COORD_ENGINE_BIN="$DBIN" "$SHIM" claim "$FIXREF" 2>/dev/null)" -if [ "$rc" -eq 0 ] && [ -z "$err" ] && printf '%s' "$out" | grep -q 'MAIN ENGINE RAN'; then - ok "dirtiness: an explicit FSGG_COORD_ENGINE_BIN never consults the guard — tier 1 execs first" +if [ "$rc" -eq 69 ] && printf '%s' "$err" | grep -q 'FSGG_SELF_HOST_RECEIPT' && ! printf '%s' "$out" | grep -q 'MAIN ENGINE RAN'; then + ok "self-host: an authored explicit engine cannot write without typed bootstrap authority" else - bad "dirtiness: tier 1 must not consult dirtiness" "rc=$rc out=$out err=$err" + bad "self-host: authored explicit bytes must fail closed before a write" "rc=$rc out=$out err=$err" fi ( cd "$D" && git checkout -q -- "$FIXSRC" ) >/dev/null 2>&1; touch -d '3 hours ago' "$D/$FIXSRC" diff --git a/tests/coord-engine-replay/fixtures/smoke/expected/reconcile.json b/tests/coord-engine-replay/fixtures/smoke/expected/reconcile.json index 41be365f7..ef90dc52a 100644 --- a/tests/coord-engine-replay/fixtures/smoke/expected/reconcile.json +++ b/tests/coord-engine-replay/fixtures/smoke/expected/reconcile.json @@ -8,11 +8,11 @@ "subject": "FS.GG.SDD#44" }, { - "id": "LIFECYCLE-PROJECTION-LAG:FS-GG/FS.GG.SDD#45", - "remedy": "Status=Done", - "rule": "LIFECYCLE-PROJECTION-LAG", + "id": "PREMATURE-COMPLETION:FS-GG/FS.GG.SDD#45", + "remedy": "Status=In review", + "rule": "PREMATURE-COMPLETION", "size": "quick", - "statement": "FS.GG.SDD#45: fresh lifecycle facts project Status=Done; repair the stale board projection.", + "statement": "FS.GG.SDD#45: the issue closed without authoritative completion evidence; preserve a correction receipt and restore the nonterminal Status=In review.", "subject": "FS.GG.SDD#45" }, { diff --git a/tests/coord-guards/run.sh b/tests/coord-guards/run.sh index 6907b8335..1160b18dc 100755 --- a/tests/coord-guards/run.sh +++ b/tests/coord-guards/run.sh @@ -246,27 +246,47 @@ else bad "the lease-specific line must not be printed for verbs that are not the lease renewal" "err=$DRIVE_ERR" fi -# ---- 5. THE ROUTE IS EXECUTED, AND THE CLAIM IS RENEWABLE (.github#2581 acceptance 1) ------------- -# The whole item reduces to this leg. Same fixture, same behind-ness, same shared checkout untouched, -# same head — and the worker's own CURRENT engine named through tier 1. If this is red, the refusal is -# advertising a route that does not work, which is worse than printing nothing. -# -# AND IT IS GREEN AGAINST THE PRE-REPAIR MODULE TOO — SAID PLAINLY, BECAUSE THAT IS THE FINDING, NOT A -# WEAKNESS OF THE LEG. Tier 1 always worked; .github#2581's defect was never that the route was broken, -# it was that the refusal named the ONE checkout the blocked worker must not touch and never mentioned -# this one. So the legs that go red under inversion are §2, §3, §4 and §9 (the text and the -# justification), and this leg is a REGRESSION guard on the property they now advertise: the moment the -# route stops working, the refusal starts lying. +# ---- 5. AN OPAQUE EXPLICIT BINARY IS NOT AUTOMATICALLY TRUSTED ------------------------------------ +# `MYENGINE` is deliberately outside any git checkout. It used to bypass every guard merely because the +# caller named it. The self-host contract makes that absence of provenance a refusal for write verbs. RECOVER_ERR="$ROOT/.recover.err" RECOVER_OUT="$( cd "$BEHIND/wt" && FSGG_COORD_ENGINE_BIN="$MYENGINE" "$SHIM" heartbeat "$FIXREF" 2>"$RECOVER_ERR" )" RECOVER_RC=$? RECOVER_ERR_TXT="$(cat "$RECOVER_ERR")" -if [ "$RECOVER_RC" -eq 0 ] \ - && printf '%s' "$RECOVER_OUT" | grep -q 'MY CURRENT ENGINE RAN: heartbeat' \ - && [ -z "$RECOVER_ERR_TXT" ]; then - ok "the recovery route WORKS: the same blocked worker renews through a CURRENT engine it built — exit 0, no staleness verdict consulted, shared checkout untouched" +if [ "$RECOVER_RC" -eq 69 ] \ + && grep -q 'FSGG_SELF_HOST_RECEIPT' <<<"$RECOVER_ERR_TXT" \ + && ! grep -q 'MY CURRENT ENGINE RAN' <<<"$RECOVER_OUT"; then + ok "an opaque explicit engine cannot write without typed self-host authority" +else + bad "an opaque explicit engine must fail closed before a write" "rc=$RECOVER_RC out=$RECOVER_OUT err=$RECOVER_ERR_TXT" +fi + +# The inverse is equally load-bearing: once a DISTINCT stable verifier accepts the receipt and exact +# candidate path, the candidate receives the original write argv. The verifier is a fixture here; the +# real verifier's digest/bytes/version/head behavior is exercised by SelfHostCliTests. +SELF_HOST_RECEIPT="$ROOT/self-host.receipt" +SELF_HOST_STABLE="$ROOT/stable-engine" +SELF_HOST_LOG="$ROOT/stable.log" +printf '%s\n' 'typed receipt fixture' >"$SELF_HOST_RECEIPT" +cat >"$SELF_HOST_STABLE" <<'EOF' +#!/bin/sh +printf '%s\n' "$*" >"$FSGG_SELF_HOST_TEST_LOG" +[ "$1" = self-host ] && [ "$2" = verify ] && [ "$3" = "$FSGG_SELF_HOST_RECEIPT" ] && [ "$4" = "$FSGG_COORD_ENGINE_BIN" ] +EOF +chmod +x "$SELF_HOST_STABLE" +AUTHORIZED_OUT="$(cd "$BEHIND/wt" && \ + FSGG_SELF_HOST_TEST_LOG="$SELF_HOST_LOG" \ + FSGG_SELF_HOST_RECEIPT="$SELF_HOST_RECEIPT" \ + FSGG_COORD_STABLE_ENGINE_BIN="$SELF_HOST_STABLE" \ + FSGG_COORD_ENGINE_BIN="$MYENGINE" \ + "$SHIM" heartbeat "$FIXREF" 2>/dev/null)" +AUTHORIZED_RC=$? +if [ "$AUTHORIZED_RC" -eq 0 ] \ + && grep -q 'MY CURRENT ENGINE RAN: heartbeat' <<<"$AUTHORIZED_OUT" \ + && grep -q '^self-host verify ' "$SELF_HOST_LOG"; then + ok "a distinct stable verifier authorizes the exact candidate before its write argv runs" else - bad "the printed recovery route must actually lift the refusal" "rc=$RECOVER_RC out=$RECOVER_OUT err=$RECOVER_ERR_TXT" + bad "accepted typed self-host authority must admit the candidate write" "rc=$AUTHORIZED_RC out=$AUTHORIZED_OUT log=$(cat "$SELF_HOST_LOG" 2>/dev/null)" fi # AND THE SHARED CHECKOUT REALLY IS UNTOUCHED — the property that makes the route safe under @@ -461,16 +481,19 @@ else fi # ---- 10. THE SUBJECT IS REACHABLE FROM CI (.github#2581 SB-008) ---------------------------------- -# `scripts/fsgg-coord-guards.sh` was named by NO workflow `paths:` filter anywhere in the repository. -# Since .github#1586 moved the partition and both guards into it, a PR editing only that file started -# `coord-engine.yml` on no path — so §3b and §3c, whose entire subject IS that file, were silent on -# exactly the pull requests that change it (.github#2551's class). +# The required completeness context must exist on every PR, so the PR trigger is intentionally unfiltered. +# The expensive successor still needs exact impact classification, and pushes retain their path filter. +# This proves a guard-only edit reaches both of those path-sensitive decisions without reintroducing the +# selectively silent PR trigger that `.github#2551` identified. CE="$REPO_ROOT/.github/workflows/coord-engine.yml" -n="$(grep -c '"scripts/fsgg-coord-guards.sh"' "$CE" 2>/dev/null || true)" -if [ "${n:-0}" -ge 2 ]; then - ok "coord-engine.yml names scripts/fsgg-coord-guards.sh in both its pull_request and push paths filters ($n occurrences) — the parity gate now runs on the PRs whose subject it is" +pr_trigger="$(sed -n '/^ pull_request:/,/^ push:/p' "$CE")" +push_trigger="$(sed -n '/^ push:/,/^ workflow_dispatch:/p' "$CE")" +if ! grep -q 'paths:' <<<"$pr_trigger" \ + && grep -q '"scripts/fsgg-coord-guards.sh"' <<<"$push_trigger" \ + && grep -q 'fsgg-coord-guards\\\.sh' "$REPO_ROOT/scripts/change-completeness"; then + ok "coord-engine.yml runs change-completeness on every PR, while push filtering and the impact classifier both select the guard module" else - bad "coord-engine.yml must select a change to the guard module in BOTH trigger filters" "occurrences=${n:-0}" + bad "coord-engine.yml must keep PR completeness unfiltered and retain guard-module selection in push + impact classification" fi CG="$REPO_ROOT/.github/workflows/coord-guards.yml" diff --git a/tests/pipefail-assertions/baseline.txt b/tests/pipefail-assertions/baseline.txt index b0dcfa0ad..88d2327f6 100644 --- a/tests/pipefail-assertions/baseline.txt +++ b/tests/pipefail-assertions/baseline.txt @@ -52,10 +52,10 @@ 18 tests/closing-keywords/run.sh 2 tests/coherent-set-version/run.sh 7 tests/coord-engine-e2e/run.sh -79 tests/coord-engine-e2e/writes.sh -326 tests/coord-engine-parity/run.sh +63 tests/coord-engine-e2e/writes.sh +325 tests/coord-engine-parity/run.sh 110 tests/coord-engine-parity/shim.sh -20 tests/coord-guards/run.sh +19 tests/coord-guards/run.sh 21 tests/coordination-sync/run.sh 1 tests/dispatch-preflight/run.sh 10 tests/engine-flag-narrative/run.sh diff --git a/tests/projection/run.sh b/tests/projection/run.sh index 4d51cc9bd..f0970fabe 100755 --- a/tests/projection/run.sh +++ b/tests/projection/run.sh @@ -40,6 +40,7 @@ mkdir -p "$CONTRACT_REPO/scripts" \ git -C "$CONTRACT_REPO" init -q cp "$REPO_ROOT/scripts/generate-projections" "$CONTRACT_REPO/scripts/generate-projections" cp "$REPO_ROOT/scripts/fsgg-coord" "$CONTRACT_REPO/scripts/fsgg-coord" +cp "$REPO_ROOT/scripts/fsgg-coord-guards.sh" "$CONTRACT_REPO/scripts/fsgg-coord-guards.sh" printf '%s\n' 'demo contract' > "$CONTRACT_REPO/.agents/skills/demo/SKILL.md" cp "$CONTRACT_REPO/.agents/skills/demo/SKILL.md" \ "$CONTRACT_REPO/.claude/skills/demo/SKILL.md" diff --git a/tests/release-saga/run.sh b/tests/release-saga/run.sh index 868863922..60fa122a5 100644 --- a/tests/release-saga/run.sh +++ b/tests/release-saga/run.sh @@ -145,6 +145,36 @@ python3 "$TOOL" record-observed --manifest "$WORK/manifest.json" --feed nuget \ --observed "FS.GG.Coord.Cli=$WORK/nuget/FS.GG.Coord.Cli.9.8.7.nupkg" \ --observed "FS.GG.Kit=$WORK/nuget/FS.GG.Kit.9.8.7.nupkg" \ --observed "FS.GG.Drivers=$WORK/nuget/FS.GG.Drivers.9.8.7.nupkg" --detail "fixture public-feed observation" + +mkdir -p "$WORK/receiver-receipts" +python3 "$TOOL" receiver-receipt --manifest "$WORK/manifest.json" --package FS.GG.Kit \ + --receiver FS-GG/FS.GG.SDD --detail "dashboard delivery verified" \ + --output "$WORK/receiver-receipts/kit-sdd.json" >/dev/null +# Exact retry is idempotent and never replaces the append-only receipt. +cp "$WORK/receiver-receipts/kit-sdd.json" "$WORK/receiver-receipts/kit-sdd.before.json" +python3 "$TOOL" receiver-receipt --manifest "$WORK/manifest.json" --package FS.GG.Kit \ + --receiver FS-GG/FS.GG.SDD --detail "dashboard delivery verified" \ + --output "$WORK/receiver-receipts/kit-sdd.json" >/dev/null +cmp "$WORK/receiver-receipts/kit-sdd.before.json" "$WORK/receiver-receipts/kit-sdd.json" +python3 "$TOOL" receiver-receipt --manifest "$WORK/manifest.json" --package FS.GG.Coord.Cli \ + --receiver FS-GG/FS.GG.SDD --detail "dashboard delivery verified" \ + --output "$WORK/receiver-receipts/engine-sdd.json" >/dev/null +python3 "$TOOL" verify-receivers --manifest "$WORK/manifest.json" \ + --expected FS.GG.Kit=FS-GG/FS.GG.SDD --expected FS.GG.Coord.Cli=FS-GG/FS.GG.SDD \ + --receipt "$WORK/receiver-receipts/kit-sdd.json" \ + --receipt "$WORK/receiver-receipts/engine-sdd.json" >/dev/null +if python3 "$TOOL" verify-receivers --manifest "$WORK/manifest.json" \ + --expected FS.GG.Kit=FS-GG/FS.GG.SDD \ + --receipt "$WORK/receiver-receipts/engine-sdd.json" >/dev/null 2>&1; then + echo "expected missing and undeclared receiver receipts to fail closed" >&2; exit 1 +fi +jq '.sourceSha = "ffffffffffffffffffffffffffffffffffffffff"' \ + "$WORK/receiver-receipts/kit-sdd.json" > "$WORK/receiver-receipts/tampered.json" +if python3 "$TOOL" verify-receivers --manifest "$WORK/manifest.json" \ + --expected FS.GG.Kit=FS-GG/FS.GG.SDD \ + --receipt "$WORK/receiver-receipts/tampered.json" >/dev/null 2>&1; then + echo "expected receiver receipt identity tampering to fail closed" >&2; exit 1 +fi python3 "$TOOL" promote --manifest "$WORK/manifest.json" --previous-channel "$WORK/previous-stable.json" \ --channel-output "$WORK/stable.json" # A queued observer after the first successful publication sees the current release as latest. The @@ -294,7 +324,7 @@ assert "release-saga.py assert-reusable" in prepare, "reuse branch no longer ask assert "jq -r .contentId /tmp/prior" not in prepare, "reuse branch compares contentId again (.github#2664)" assert 'cmp "/tmp/prior/' not in prepare, "reuse branch compares raw archive bytes again (.github#2664)" promote = (root / ".github/workflows/release-saga-promote.yml").read_text() -for token in ("assert-identity", "merge-journals", "record-observed", "stable-channel.json", "--draft=false"): +for token in ("assert-identity", "merge-journals", "verify-receivers", "receiver-receipts-", "record-observed", "stable-channel.json", "--draft=false"): assert token in promote or token in (root / "scripts/release-saga-promote-release.sh").read_text(), token for token in ("source_sha=", 'refs/tags/$tag^{}', "head -1 | sed 's:/*$::'", '"${github_base}/${lower}'): assert token in promote, token @@ -302,6 +332,11 @@ assert 'journal_count=$((journal_count + 1))' in promote assert '[ "$journal_count" -eq 3 ]' in promote assert '[ "${#journals[@]}" -eq 3 ]' not in promote assert "release-saga-promote-release.sh" in promote +for workflow in ("release-kit.yml", "release-coord-engine.yml"): + delivery = (root / ".github/workflows" / workflow).read_text() + assert "--journal artifacts/packages/journal-" in delivery, workflow + assert "--receipt-dir artifacts/receiver-receipts" in delivery, workflow + assert "actions/upload-artifact@v6" in delivery, workflow print("production saga topology: pack-once, durable journals, org barrier, resume probes, identity, and promotion wired") PY diff --git a/tests/signature-doc-siting/baseline.txt b/tests/signature-doc-siting/baseline.txt index 58d69f834..fce539c1b 100644 --- a/tests/signature-doc-siting/baseline.txt +++ b/tests/signature-doc-siting/baseline.txt @@ -104,7 +104,7 @@ 58 src/FS.GG.Coord.Cli.Kernel/Identity.fs 161 src/FS.GG.Coord.Cli.Kernel/Kernel.fs -455 src/FS.GG.Coord.Cli.Kernel/Options.fs +436 src/FS.GG.Coord.Cli.Kernel/Options.fs 159 src/FS.GG.Coord.Cli.Kernel/Render.fs 1522 src/FS.GG.Coord.Cli/Client.fs 15 src/FS.GG.Coord.Cli/DeliveryApplication.fs diff --git a/work/2819-pass-red-exhaustion-writer/artifacts/verification.trx b/work/2819-pass-red-exhaustion-writer/artifacts/verification.test-report.xml similarity index 100% rename from work/2819-pass-red-exhaustion-writer/artifacts/verification.trx rename to work/2819-pass-red-exhaustion-writer/artifacts/verification.test-report.xml diff --git a/work/2819-pass-red-exhaustion-writer/evidence.yml b/work/2819-pass-red-exhaustion-writer/evidence.yml index 0001061d9..199b104c7 100644 --- a/work/2819-pass-red-exhaustion-writer/evidence.yml +++ b/work/2819-pass-red-exhaustion-writer/evidence.yml @@ -46,14 +46,14 @@ evidence: checklistResultRefs: [] planDecisionRefs: [PD-001] obligationRefs: [EV001] - artifacts: [work/2819-pass-red-exhaustion-writer/artifacts/verification.trx] + artifacts: [work/2819-pass-red-exhaustion-writer/artifacts/verification.test-report.xml] sourceRefs: - kind: verification path: tests/FS.GG.Coord.Cli.Tests/ReviewApplicationTests.fs result: pass synthetic: false observedRun: - source: work/2819-pass-red-exhaustion-writer/artifacts/verification.trx + source: work/2819-pass-red-exhaustion-writer/artifacts/verification.test-report.xml digest: "sha256:a8f67f1e21e808bc198322b37f2c8ac53f3e4560d2193140fa7c4b35108dce8a" digestContract: exact-bytes-v1 outcome: passed @@ -73,14 +73,14 @@ evidence: checklistResultRefs: [] planDecisionRefs: [PD-002] obligationRefs: [EV002] - artifacts: [work/2819-pass-red-exhaustion-writer/artifacts/verification.trx] + artifacts: [work/2819-pass-red-exhaustion-writer/artifacts/verification.test-report.xml] sourceRefs: - kind: verification path: tests/FS.GG.Coord.Cli.Tests/ReviewApplicationTests.fs result: pass synthetic: false observedRun: - source: work/2819-pass-red-exhaustion-writer/artifacts/verification.trx + source: work/2819-pass-red-exhaustion-writer/artifacts/verification.test-report.xml digest: "sha256:a8f67f1e21e808bc198322b37f2c8ac53f3e4560d2193140fa7c4b35108dce8a" digestContract: exact-bytes-v1 outcome: passed @@ -100,14 +100,14 @@ evidence: checklistResultRefs: [] planDecisionRefs: [PD-003] obligationRefs: [EV003] - artifacts: [work/2819-pass-red-exhaustion-writer/artifacts/verification.trx] + artifacts: [work/2819-pass-red-exhaustion-writer/artifacts/verification.test-report.xml] sourceRefs: - kind: verification path: tests/FS.GG.Coord.Cli.Tests/ReviewApplicationTests.fs result: pass synthetic: false observedRun: - source: work/2819-pass-red-exhaustion-writer/artifacts/verification.trx + source: work/2819-pass-red-exhaustion-writer/artifacts/verification.test-report.xml digest: "sha256:a8f67f1e21e808bc198322b37f2c8ac53f3e4560d2193140fa7c4b35108dce8a" digestContract: exact-bytes-v1 outcome: passed @@ -127,14 +127,14 @@ evidence: checklistResultRefs: [] planDecisionRefs: [PD-004] obligationRefs: [EV004] - artifacts: [work/2819-pass-red-exhaustion-writer/artifacts/verification.trx] + artifacts: [work/2819-pass-red-exhaustion-writer/artifacts/verification.test-report.xml] sourceRefs: - kind: verification path: tests/FS.GG.Coord.Cli.Tests/ReviewApplicationTests.fs result: pass synthetic: false observedRun: - source: work/2819-pass-red-exhaustion-writer/artifacts/verification.trx + source: work/2819-pass-red-exhaustion-writer/artifacts/verification.test-report.xml digest: "sha256:a8f67f1e21e808bc198322b37f2c8ac53f3e4560d2193140fa7c4b35108dce8a" digestContract: exact-bytes-v1 outcome: passed @@ -154,14 +154,14 @@ evidence: checklistResultRefs: [] planDecisionRefs: [PD-005] obligationRefs: [EV005] - artifacts: [work/2819-pass-red-exhaustion-writer/artifacts/verification.trx] + artifacts: [work/2819-pass-red-exhaustion-writer/artifacts/verification.test-report.xml] sourceRefs: - kind: verification path: tests/FS.GG.Coord.Cli.Tests/ReviewApplicationTests.fs result: pass synthetic: false observedRun: - source: work/2819-pass-red-exhaustion-writer/artifacts/verification.trx + source: work/2819-pass-red-exhaustion-writer/artifacts/verification.test-report.xml digest: "sha256:a8f67f1e21e808bc198322b37f2c8ac53f3e4560d2193140fa7c4b35108dce8a" digestContract: exact-bytes-v1 outcome: passed @@ -181,14 +181,14 @@ evidence: checklistResultRefs: [] planDecisionRefs: [PD-006] obligationRefs: [EV006] - artifacts: [work/2819-pass-red-exhaustion-writer/artifacts/verification.trx] + artifacts: [work/2819-pass-red-exhaustion-writer/artifacts/verification.test-report.xml] sourceRefs: - kind: verification path: tests/FS.GG.Coord.Cli.Tests/ReviewApplicationTests.fs result: pass synthetic: false observedRun: - source: work/2819-pass-red-exhaustion-writer/artifacts/verification.trx + source: work/2819-pass-red-exhaustion-writer/artifacts/verification.test-report.xml digest: "sha256:a8f67f1e21e808bc198322b37f2c8ac53f3e4560d2193140fa7c4b35108dce8a" digestContract: exact-bytes-v1 outcome: passed @@ -208,14 +208,14 @@ evidence: checklistResultRefs: [] planDecisionRefs: [] obligationRefs: [EV007] - artifacts: [work/2819-pass-red-exhaustion-writer/artifacts/verification.trx] + artifacts: [work/2819-pass-red-exhaustion-writer/artifacts/verification.test-report.xml] sourceRefs: - kind: verification path: tests/FS.GG.Coord.Cli.Tests/ReviewApplicationTests.fs result: pass synthetic: false observedRun: - source: work/2819-pass-red-exhaustion-writer/artifacts/verification.trx + source: work/2819-pass-red-exhaustion-writer/artifacts/verification.test-report.xml digest: "sha256:a8f67f1e21e808bc198322b37f2c8ac53f3e4560d2193140fa7c4b35108dce8a" digestContract: exact-bytes-v1 outcome: passed @@ -235,14 +235,14 @@ evidence: checklistResultRefs: [] planDecisionRefs: [] obligationRefs: [EV008] - artifacts: [work/2819-pass-red-exhaustion-writer/artifacts/verification.trx] + artifacts: [work/2819-pass-red-exhaustion-writer/artifacts/verification.test-report.xml] sourceRefs: - kind: verification path: tests/FS.GG.Coord.Cli.Tests/ReviewApplicationTests.fs result: pass synthetic: false observedRun: - source: work/2819-pass-red-exhaustion-writer/artifacts/verification.trx + source: work/2819-pass-red-exhaustion-writer/artifacts/verification.test-report.xml digest: "sha256:a8f67f1e21e808bc198322b37f2c8ac53f3e4560d2193140fa7c4b35108dce8a" digestContract: exact-bytes-v1 outcome: passed @@ -262,14 +262,14 @@ evidence: checklistResultRefs: [] planDecisionRefs: [PD-001] obligationRefs: [EV009] - artifacts: [work/2819-pass-red-exhaustion-writer/artifacts/verification.trx] + artifacts: [work/2819-pass-red-exhaustion-writer/artifacts/verification.test-report.xml] sourceRefs: - kind: verification path: tests/FS.GG.Coord.Cli.Tests/ReviewApplicationTests.fs result: pass synthetic: false observedRun: - source: work/2819-pass-red-exhaustion-writer/artifacts/verification.trx + source: work/2819-pass-red-exhaustion-writer/artifacts/verification.test-report.xml digest: "sha256:a8f67f1e21e808bc198322b37f2c8ac53f3e4560d2193140fa7c4b35108dce8a" digestContract: exact-bytes-v1 outcome: passed @@ -289,14 +289,14 @@ evidence: checklistResultRefs: [] planDecisionRefs: [PD-002] obligationRefs: [EV010] - artifacts: [work/2819-pass-red-exhaustion-writer/artifacts/verification.trx] + artifacts: [work/2819-pass-red-exhaustion-writer/artifacts/verification.test-report.xml] sourceRefs: - kind: verification path: tests/FS.GG.Coord.Cli.Tests/ReviewApplicationTests.fs result: pass synthetic: false observedRun: - source: work/2819-pass-red-exhaustion-writer/artifacts/verification.trx + source: work/2819-pass-red-exhaustion-writer/artifacts/verification.test-report.xml digest: "sha256:a8f67f1e21e808bc198322b37f2c8ac53f3e4560d2193140fa7c4b35108dce8a" digestContract: exact-bytes-v1 outcome: passed @@ -316,14 +316,14 @@ evidence: checklistResultRefs: [] planDecisionRefs: [PD-001, PD-003] obligationRefs: [EV011] - artifacts: [work/2819-pass-red-exhaustion-writer/artifacts/verification.trx] + artifacts: [work/2819-pass-red-exhaustion-writer/artifacts/verification.test-report.xml] sourceRefs: - kind: verification path: tests/FS.GG.Coord.Cli.Tests/ReviewApplicationTests.fs result: pass synthetic: false observedRun: - source: work/2819-pass-red-exhaustion-writer/artifacts/verification.trx + source: work/2819-pass-red-exhaustion-writer/artifacts/verification.test-report.xml digest: "sha256:a8f67f1e21e808bc198322b37f2c8ac53f3e4560d2193140fa7c4b35108dce8a" digestContract: exact-bytes-v1 outcome: passed @@ -343,14 +343,14 @@ evidence: checklistResultRefs: [] planDecisionRefs: [PD-002, PD-004] obligationRefs: [EV012] - artifacts: [work/2819-pass-red-exhaustion-writer/artifacts/verification.trx] + artifacts: [work/2819-pass-red-exhaustion-writer/artifacts/verification.test-report.xml] sourceRefs: - kind: verification path: tests/FS.GG.Coord.Cli.Tests/ReviewApplicationTests.fs result: pass synthetic: false observedRun: - source: work/2819-pass-red-exhaustion-writer/artifacts/verification.trx + source: work/2819-pass-red-exhaustion-writer/artifacts/verification.test-report.xml digest: "sha256:a8f67f1e21e808bc198322b37f2c8ac53f3e4560d2193140fa7c4b35108dce8a" digestContract: exact-bytes-v1 outcome: passed @@ -370,14 +370,14 @@ evidence: checklistResultRefs: [] planDecisionRefs: [PD-005, PD-006] obligationRefs: [EV013] - artifacts: [work/2819-pass-red-exhaustion-writer/artifacts/verification.trx] + artifacts: [work/2819-pass-red-exhaustion-writer/artifacts/verification.test-report.xml] sourceRefs: - kind: verification path: tests/FS.GG.Coord.Cli.Tests/ReviewApplicationTests.fs result: pass synthetic: false observedRun: - source: work/2819-pass-red-exhaustion-writer/artifacts/verification.trx + source: work/2819-pass-red-exhaustion-writer/artifacts/verification.test-report.xml digest: "sha256:a8f67f1e21e808bc198322b37f2c8ac53f3e4560d2193140fa7c4b35108dce8a" digestContract: exact-bytes-v1 outcome: passed @@ -397,14 +397,14 @@ evidence: checklistResultRefs: [] planDecisionRefs: [PD-006] obligationRefs: [EV014] - artifacts: [work/2819-pass-red-exhaustion-writer/artifacts/verification.trx] + artifacts: [work/2819-pass-red-exhaustion-writer/artifacts/verification.test-report.xml] sourceRefs: - kind: verification path: tests/FS.GG.Coord.Cli.Tests/ReviewApplicationTests.fs result: pass synthetic: false observedRun: - source: work/2819-pass-red-exhaustion-writer/artifacts/verification.trx + source: work/2819-pass-red-exhaustion-writer/artifacts/verification.test-report.xml digest: "sha256:a8f67f1e21e808bc198322b37f2c8ac53f3e4560d2193140fa7c4b35108dce8a" digestContract: exact-bytes-v1 outcome: passed @@ -424,14 +424,14 @@ evidence: checklistResultRefs: [] planDecisionRefs: [PD-001, PD-002] obligationRefs: [EV015] - artifacts: [work/2819-pass-red-exhaustion-writer/artifacts/verification.trx] + artifacts: [work/2819-pass-red-exhaustion-writer/artifacts/verification.test-report.xml] sourceRefs: - kind: verification path: tests/FS.GG.Coord.Cli.Tests/ReviewApplicationTests.fs result: pass synthetic: false observedRun: - source: work/2819-pass-red-exhaustion-writer/artifacts/verification.trx + source: work/2819-pass-red-exhaustion-writer/artifacts/verification.test-report.xml digest: "sha256:a8f67f1e21e808bc198322b37f2c8ac53f3e4560d2193140fa7c4b35108dce8a" digestContract: exact-bytes-v1 outcome: passed @@ -451,14 +451,14 @@ evidence: checklistResultRefs: [] planDecisionRefs: [] obligationRefs: [EV016] - artifacts: [work/2819-pass-red-exhaustion-writer/artifacts/verification.trx] + artifacts: [work/2819-pass-red-exhaustion-writer/artifacts/verification.test-report.xml] sourceRefs: - kind: verification path: tests/FS.GG.Coord.Cli.Tests/ReviewApplicationTests.fs result: pass synthetic: false observedRun: - source: work/2819-pass-red-exhaustion-writer/artifacts/verification.trx + source: work/2819-pass-red-exhaustion-writer/artifacts/verification.test-report.xml digest: "sha256:a8f67f1e21e808bc198322b37f2c8ac53f3e4560d2193140fa7c4b35108dce8a" digestContract: exact-bytes-v1 outcome: passed @@ -478,14 +478,14 @@ evidence: checklistResultRefs: [] planDecisionRefs: [PD-001] obligationRefs: [EV017] - artifacts: [work/2819-pass-red-exhaustion-writer/artifacts/verification.trx] + artifacts: [work/2819-pass-red-exhaustion-writer/artifacts/verification.test-report.xml] sourceRefs: - kind: verification path: tests/FS.GG.Coord.Cli.Tests/ReviewApplicationTests.fs result: pass synthetic: false observedRun: - source: work/2819-pass-red-exhaustion-writer/artifacts/verification.trx + source: work/2819-pass-red-exhaustion-writer/artifacts/verification.test-report.xml digest: "sha256:a8f67f1e21e808bc198322b37f2c8ac53f3e4560d2193140fa7c4b35108dce8a" digestContract: exact-bytes-v1 outcome: passed diff --git a/work/coordination-change-risk-mitigation/artifacts/change-completeness-boardops.test-report.xml b/work/coordination-change-risk-mitigation/artifacts/change-completeness-boardops.test-report.xml new file mode 100644 index 000000000..277a3056d --- /dev/null +++ b/work/coordination-change-risk-mitigation/artifacts/change-completeness-boardops.test-report.xml @@ -0,0 +1,64 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + [xUnit.net 00:00:00.00] xUnit.net VSTest Adapter v3.1.5+1b188a7b0a (64-bit .NET 10.0.10) +[xUnit.net 00:00:00.06] Discovering: FS.GG.Coord.Cli.BoardOps.Tests +[xUnit.net 00:00:00.10] Discovered: FS.GG.Coord.Cli.BoardOps.Tests +[xUnit.net 00:00:00.11] Starting: FS.GG.Coord.Cli.BoardOps.Tests +[xUnit.net 00:00:00.18] Finished: FS.GG.Coord.Cli.BoardOps.Tests + + + + \ No newline at end of file diff --git a/work/coordination-change-risk-mitigation/artifacts/change-completeness-cli.test-report.xml b/work/coordination-change-risk-mitigation/artifacts/change-completeness-cli.test-report.xml new file mode 100644 index 000000000..ddade915b --- /dev/null +++ b/work/coordination-change-risk-mitigation/artifacts/change-completeness-cli.test-report.xml @@ -0,0 +1,653 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + [xUnit.net 00:00:00.00] xUnit.net VSTest Adapter v3.1.5+1b188a7b0a (64-bit .NET 10.0.10) +[xUnit.net 00:00:00.07] Discovering: FS.GG.Coord.Cli.Tests +[xUnit.net 00:00:00.11] Discovered: FS.GG.Coord.Cli.Tests +[xUnit.net 00:00:00.13] Starting: FS.GG.Coord.Cli.Tests +fsgg-coord-engine: KIT DIGEST — a content-addressed kit source is STALE in `registry/repos.lock`: + .claude/skills/pnext-item + scripts/fsgg-coord +`repos-registry-selftest` reds `main` until it is regenerated (ADR-0019, #469). Run: + scripts/repos.sh relock +Then name `registry/repos.lock` as EXPECTED DRIFT in the PR — do NOT reserve it in the +touch-set. It is a GENERATED, CI-GATED artifact, so a collision in it is a REBASE, not a +decision (#309). Reserving it is the three-worker deadlock #527 removed (#428). + Widen the touch-set (scripts/fsgg-coord widen), or split the PR. + Fix the PR body now — this is unrecoverable once the PR is merged (editing a merged PR's body does not replay the close, .github#2107). +fsgg-coord-engine: KIT DIGEST — a content-addressed kit source is STALE in `registry/repos.lock`: + .claude/skills/pnext-item + scripts/fsgg-coord +`repos-registry-selftest` reds `main` until it is regenerated (ADR-0019, #469). Run: + scripts/repos.sh relock +Then name `registry/repos.lock` as EXPECTED DRIFT in the PR — do NOT reserve it in the +touch-set. It is a GENERATED, CI-GATED artifact, so a collision in it is a REBASE, not a +decision (#309). Reserving it is the three-worker deadlock #527 removed (#428). +fsgg-coord-engine: KIT DIGEST — a content-addressed kit source is STALE in `registry/repos.lock`: + .claude/skills/pnext-item + scripts/fsgg-coord +`repos-registry-selftest` reds `main` until it is regenerated (ADR-0019, #469). Run: + scripts/repos.sh relock +Then name `registry/repos.lock` as EXPECTED DRIFT in the PR — do NOT reserve it in the +touch-set. It is a GENERATED, CI-GATED artifact, so a collision in it is a REBASE, not a +decision (#309). Reserving it is the three-worker deadlock #527 removed (#428). +fsgg-coord-engine: KIT DIGEST — a content-addressed kit source is STALE in `registry/repos.lock`: + .claude/skills/pnext-item + scripts/fsgg-coord +`repos-registry-selftest` reds `main` until it is regenerated (ADR-0019, #469). Run: + scripts/repos.sh relock +Then name `registry/repos.lock` as EXPECTED DRIFT in the PR — do NOT reserve it in the +touch-set. It is a GENERATED, CI-GATED artifact, so a collision in it is a REBASE, not a +decision (#309). Reserving it is the three-worker deadlock #527 removed (#428). +fsgg-coord-engine: KIT DIGEST — a content-addressed kit source is STALE in `registry/repos.lock`: + .claude/skills/pnext-item + scripts/fsgg-coord +`repos-registry-selftest` reds `main` until it is regenerated (ADR-0019, #469). Run: + scripts/repos.sh relock +Then name `registry/repos.lock` as EXPECTED DRIFT in the PR — do NOT reserve it in the +touch-set. It is a GENERATED, CI-GATED artifact, so a collision in it is a REBASE, not a +decision (#309). Reserving it is the three-worker deadlock #527 removed (#428). + Fix the PR body now — this is unrecoverable once the PR is merged (editing a merged PR's body does not replay the close, .github#2107). +[xUnit.net 00:00:01.30] Finished: FS.GG.Coord.Cli.Tests + + + + \ No newline at end of file diff --git a/work/coordination-change-risk-mitigation/artifacts/change-completeness-kernel.test-report.xml b/work/coordination-change-risk-mitigation/artifacts/change-completeness-kernel.test-report.xml new file mode 100644 index 000000000..ae514e458 --- /dev/null +++ b/work/coordination-change-risk-mitigation/artifacts/change-completeness-kernel.test-report.xml @@ -0,0 +1,124 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + [xUnit.net 00:00:00.00] xUnit.net VSTest Adapter v3.1.5+1b188a7b0a (64-bit .NET 10.0.10) +[xUnit.net 00:00:00.04] Discovering: FS.GG.Coord.Cli.Kernel.Tests +[xUnit.net 00:00:00.08] Discovered: FS.GG.Coord.Cli.Kernel.Tests +[xUnit.net 00:00:00.09] Starting: FS.GG.Coord.Cli.Kernel.Tests +[xUnit.net 00:00:00.23] Finished: FS.GG.Coord.Cli.Kernel.Tests + + + + \ No newline at end of file diff --git a/work/coordination-change-risk-mitigation/artifacts/command-catalogue-boardops.test-report.xml b/work/coordination-change-risk-mitigation/artifacts/command-catalogue-boardops.test-report.xml new file mode 100644 index 000000000..6a00372b6 --- /dev/null +++ b/work/coordination-change-risk-mitigation/artifacts/command-catalogue-boardops.test-report.xml @@ -0,0 +1,1686 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + [xUnit.net 00:00:00.00] xUnit.net VSTest Adapter v3.1.5+1b188a7b0a (64-bit .NET 10.0.10) +[xUnit.net 00:00:00.05] Discovering: FS.GG.Coord.Cli.BoardOps.Tests +[xUnit.net 00:00:00.09] Discovered: FS.GG.Coord.Cli.BoardOps.Tests +[xUnit.net 00:00:00.12] Starting: FS.GG.Coord.Cli.BoardOps.Tests +fsgg-coord-engine: not found: stop after reuse binding. The server said so — this is an absence, not a failed read. +fsgg-coord-engine: not found: stop after intent recovery. The server said so — this is an absence, not a failed read. +fsgg-coord-engine: not found: interrupted after persisted create. The server said so — this is an absence, not a failed read. +fsgg-coord-engine: not found: stop after recovered receipt. The server said so — this is an absence, not a failed read. +fsgg-coord-engine: malformed response reading tx-2134: a duplicate candidate matches the title; select reuse or revise the draft. That is a FAILED READ, not an empty answer — refusing to decide from it. +fsgg-coord-engine: malformed response reading tx-2134: a duplicate candidate matches the title; select reuse or revise the draft. That is a FAILED READ, not an empty answer — refusing to decide from it. +fsgg-coord-engine: malformed response reading ready-2134: Ready is refused while the reused/live issue still declares a dependency or human choice. That is a FAILED READ, not an empty answer — refusing to decide from it. +fsgg-coord-engine: malformed response reading blocked-2134: Blocked dependency FS-GG/.github#42 is already resolved. That is a FAILED READ, not an empty answer — refusing to decide from it. +{"schema":"fsgg.coord.intake-result/v1","kind":"applied","draftId":"tx-2134","issue":"FS-GG/.github#77","issueUrl":"https://github.com/FS-GG/.github/issues/77","dedupeDisposition":"create","board":{"owner":"FS-GG","title":"Coordination","number":1,"id":"PVT"},"status":"Backlog","fields":["Status","Class"],"projectionFresh":true,"pendingWrites":0,"judgementQuestion":null} +{"schema":"fsgg.coord.intake-result/v1","kind":"applied","draftId":"tx-2134","issue":"FS-GG/.github#77","issueUrl":"https://github.com/FS-GG/.github/issues/77","dedupeDisposition":"create","board":{"owner":"FS-GG","title":"Coordination","number":1,"id":"PVT"},"status":"Backlog","fields":["Status","Class"],"projectionFresh":true,"pendingWrites":0,"judgementQuestion":null} +fsgg-coord-engine: malformed response reading tx-2134: a duplicate candidate matches the title; select reuse or revise the draft. That is a FAILED READ, not an empty answer — refusing to decide from it. +fsgg-coord-engine: malformed response reading tx-2134: intake receipt '/tmp/fsgg-intake-ac2bdb19b2454a9cb623f28549958c4c/intake-tx-2134.json' is unreadable: 'not-json' is an invalid JSON literal. Expected the literal 'null'. LineNumber: 0 | BytePositionInLine: 1.. That is a FAILED READ, not an empty answer — refusing to decide from it. +fsgg-coord-engine: malformed response reading tx-2134: intake receipt '/tmp/fsgg-intake-ac2bdb19b2454a9cb623f28549958c4c/intake-tx-2134.json' is unreadable: The given key was not present in the dictionary.. That is a FAILED READ, not an empty answer — refusing to decide from it. +paths paths do not exist in target repository FS-GG/.github: definitely/not/a/live/path-2134 +fsgg-coord-engine: not found: stop after receipt recovery. The server said so — this is an absence, not a failed read. +fsgg-coord-engine: vole-418 does not hold FS.GG.SDD#42 — nothing to release. +fsgg-coord-engine: Status=Blocked refuses an incoherent park (.github#2079). +fsgg-coord-engine: set-field --batch refuses: this call clears 'Blocked by' in the SAME batch as 'Status=Blocked' — the row would land with an EMPTY field and no 'Blocked on: human/...' sentinel (.github#2079). Pair 'Status=Blocked' with a non-empty 'Blocked by=<refs>' instead, or record a human park first: add a body line 'Blocked on: human/decision' or 'Blocked on: human/action'. Nothing written. +fsgg-coord-engine: set-field --batch refuses: this call clears 'Blocked by' in the SAME batch as 'Status=Blocked' — the row would land with an EMPTY field and no 'Blocked on: human/...' sentinel (.github#2079). Pair 'Status=Blocked' with a non-empty 'Blocked by=<refs>' instead, or record a human park first: add a body line 'Blocked on: human/decision' or 'Blocked on: human/action'. Nothing written. +fsgg-coord-engine: Status=Blocked refuses an incoherent park (.github#2079). +fsgg-coord-engine: vole-418 does not hold FS.GG.SDD#42 — nothing to release. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1517-07f99dd7fa4a4aef9ea1e4468f947b63 — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1517-07f99dd7fa4a4aef9ea1e4468f947b63 — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +OVERLAP — now collides with FS.GG.SDD#75 (worker otter-9c21) + src/Shared.fs + notified worker otter-9c21 on FS.GG.SDD#75 +fsgg-coord-engine: the updated touch-set COLLIDES with a live claim (this command may or may not be what introduced it) — do NOT keep editing the shared paths until it is resolved. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1517-cb861994d52b4b62830e1606a1034153 — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1517-cb861994d52b4b62830e1606a1034153 — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +OVERLAP — now collides with FS.GG.SDD#75 (worker otter-9c21) + src/Shared.fs + notified worker otter-9c21 on FS.GG.SDD#75 +fsgg-coord-engine: the updated touch-set COLLIDES with a live claim (this command may or may not be what introduced it) — do NOT keep editing the shared paths until it is resolved. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1517-7af3ab6cb72645efb74db1c406f63666 — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1517-7af3ab6cb72645efb74db1c406f63666 — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1517-f17306f99ec34c95849908df0dfb3f61 — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1517-f17306f99ec34c95849908df0dfb3f61 — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1517-d9a85f9aa1d74721aeb4278fb1c8d4fa — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1517-d9a85f9aa1d74721aeb4278fb1c8d4fa — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +OVERLAP — now collides with FS.GG.SDD#75 (worker otter-9c21) + src/Shared.fs + notified worker otter-9c21 on FS.GG.SDD#75 +fsgg-coord-engine: the updated touch-set COLLIDES with a live claim (this command may or may not be what introduced it) — do NOT keep editing the shared paths until it is resolved. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1517-7f7311d68eac47a5a12c767e9284a6bb — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1517-7f7311d68eac47a5a12c767e9284a6bb — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +OVERLAP — now collides with FS.GG.SDD#75 (worker otter-9c21) + src/Shared.fs + notified worker otter-9c21 on FS.GG.SDD#75 +fsgg-coord-engine: the updated touch-set COLLIDES with a live claim (this command may or may not be what introduced it) — do NOT keep editing the shared paths until it is resolved. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1517-ddd001dc3ab443d4b8f1892a07f15d42 — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1517-ddd001dc3ab443d4b8f1892a07f15d42 — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +OVERLAP — now collides with FS.GG.SDD#75 (worker otter-9c21) + src/Shared.fs + notified worker otter-9c21 on FS.GG.SDD#75 +fsgg-coord-engine: the updated touch-set COLLIDES with a live claim (this command may or may not be what introduced it) — do NOT keep editing the shared paths until it is resolved. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1517-573145048642457c8693eca43008505a — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1517-573145048642457c8693eca43008505a — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +OVERLAP — now collides with FS.GG.SDD#75 (worker otter-9c21) + src/Shared.fs + notified worker otter-9c21 on FS.GG.SDD#75 +fsgg-coord-engine: the updated touch-set COLLIDES with a live claim (this command may or may not be what introduced it) — do NOT keep editing the shared paths until it is resolved. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1517-d2d1f2b42e4d4c75b8c8edf9fa358899 — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1517-d2d1f2b42e4d4c75b8c8edf9fa358899 — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +OVERLAP — now collides with FS.GG.SDD#75 (worker otter-9c21) + src/Shared.fs + notified worker otter-9c21 on FS.GG.SDD#75 +fsgg-coord-engine: the updated touch-set COLLIDES with a live claim (this command may or may not be what introduced it) — do NOT keep editing the shared paths until it is resolved. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1517-b5c311a5d6d3428baebf041a9843dfa5 — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1517-b5c311a5d6d3428baebf041a9843dfa5 — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +OVERLAP — now collides with FS.GG.SDD#75 (worker otter-9c21) + src/Shared.fs + notified worker otter-9c21 on FS.GG.SDD#75 +fsgg-coord-engine: the updated touch-set COLLIDES with a live claim (this command may or may not be what introduced it) — do NOT keep editing the shared paths until it is resolved. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1517-7f4aff2f32464086a28fe218789e984a — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1517-7f4aff2f32464086a28fe218789e984a — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +OVERLAP — now collides with FS.GG.SDD#75 (worker otter-9c21) + src/Shared.fs + notified worker otter-9c21 on FS.GG.SDD#75 +fsgg-coord-engine: the updated touch-set COLLIDES with a live claim (this command may or may not be what introduced it) — do NOT keep editing the shared paths until it is resolved. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1740-6c9958aed5c047bbb110fa5399b0d57d — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +considered 3 candidate(s) — this is a measured count, not an assumption. + FS.GG.SDD#74 — Status is In progress + FS.GG.SDD#75 — Status is Blocked + FS.GG.SDD#76 — overlaps in-flight work held by otter-9c21 on FS.GG.SDD#75 (lease EXPIRED — reapable): src/Shared.fs ⇄ src/Shared.fs +this queue is BUSY, not empty. +1 item(s) are QUEUED BEHIND LIVE CLAIMS held by: otter-9c21 + soonest: lease EXPIRED — reapable + 1 of those lease(s) have EXPIRED — collect them: scripts/fsgg-coord reap --repo FS.GG.SDD --apply +wave occupancy: unavailable (no drive-board or work-board host-loop document exists) +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1740-93933c16017a4ca5a5cacaa85759fb31 — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1740-93933c16017a4ca5a5cacaa85759fb31 — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +OVERLAP — now collides with FS.GG.SDD#75 (worker otter-9c21) + src/Shared.fs + notified worker otter-9c21 on FS.GG.SDD#75 +fsgg-coord-engine: the updated touch-set COLLIDES with a live claim (this command may or may not be what introduced it) — do NOT keep editing the shared paths until it is resolved. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1740-10db39e5c27f447a833f622db14af2c9 — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1740-10db39e5c27f447a833f622db14af2c9 — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1517-c3e46fcb09d24122b7c207fa91613bc3 — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1517-c3e46fcb09d24122b7c207fa91613bc3 — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1740-a014bc19097e44dfa40724fffe35c700 — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1740-a014bc19097e44dfa40724fffe35c700 — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +OVERLAP — now collides with FS.GG.SDD#75 (worker otter-9c21) + src/Shared.fs + notified worker otter-9c21 on FS.GG.SDD#75 +fsgg-coord-engine: the updated touch-set COLLIDES with a live claim (this command may or may not be what introduced it) — do NOT keep editing the shared paths until it is resolved. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1740-7f25314943474c07822aafe9cb2dfe9a — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +considered 3 candidate(s) — this is a measured count, not an assumption. + FS.GG.SDD#74 — Status is In progress + FS.GG.SDD#75 — Status is In progress + FS.GG.SDD#76 — overlaps FS.GG.SDD#75, which the board says is In progress with NO claim marker (someone is working outside the protocol — there is no lease to wait out; see: scripts/fsgg-coord who): src/Shared.fs ⇄ src/Shared.fs +wave occupancy: unavailable (no drive-board or work-board host-loop document exists) +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1740-1ebc7ee05e60457ebb749dabc586c86d — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1740-1ebc7ee05e60457ebb749dabc586c86d — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1740-cd078ded13e340daa406edf0e2b821de — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1740-cd078ded13e340daa406edf0e2b821de — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +OVERLAP — now collides with FS.GG.SDD#75 (worker otter-9c21) + src/Shared.fs + notified worker otter-9c21 on FS.GG.SDD#75 +fsgg-coord-engine: the updated touch-set COLLIDES with a live claim (this command may or may not be what introduced it) — do NOT keep editing the shared paths until it is resolved. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1740-e5bdda42b6f645a9bcc4e80bccb97530 — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1740-e5bdda42b6f645a9bcc4e80bccb97530 — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +OVERLAP — now collides with FS.GG.SDD#75 (worker otter-9c21) + src/Shared.fs + notified worker otter-9c21 on FS.GG.SDD#75 +fsgg-coord-engine: the updated touch-set COLLIDES with a live claim (this command may or may not be what introduced it) — do NOT keep editing the shared paths until it is resolved. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1740-0aac5f1b2cbc4996805affeb63206451 — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1740-0aac5f1b2cbc4996805affeb63206451 — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +OVERLAP — now collides with FS.GG.SDD#75 (worker otter-9c21) + src/Shared.fs + notified worker otter-9c21 on FS.GG.SDD#75 +fsgg-coord-engine: the updated touch-set COLLIDES with a live claim (this command may or may not be what introduced it) — do NOT keep editing the shared paths until it is resolved. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1740-5b1327332027414b80afef451e486592 — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1740-5b1327332027414b80afef451e486592 — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +OVERLAP — now collides with FS.GG.SDD#75 (worker otter-9c21) + src/Shared.fs + notified worker otter-9c21 on FS.GG.SDD#75 +fsgg-coord-engine: the updated touch-set COLLIDES with a live claim (this command may or may not be what introduced it) — do NOT keep editing the shared paths until it is resolved. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1740-8115c6fb57cd4abb8f7efcbdf3e42932 — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1740-8115c6fb57cd4abb8f7efcbdf3e42932 — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +OVERLAP — now collides with FS.GG.SDD#75 (worker otter-9c21) + src/Shared.fs + notified worker otter-9c21 on FS.GG.SDD#75 +fsgg-coord-engine: the updated touch-set COLLIDES with a live claim (this command may or may not be what introduced it) — do NOT keep editing the shared paths until it is resolved. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1740-01cbd05d23a04b3999765b2c5047ed30 — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1740-01cbd05d23a04b3999765b2c5047ed30 — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +OVERLAP — now collides with FS.GG.SDD#75 (worker otter-9c21) + src/Shared.fs + notified worker otter-9c21 on FS.GG.SDD#75 +fsgg-coord-engine: the updated touch-set COLLIDES with a live claim (this command may or may not be what introduced it) — do NOT keep editing the shared paths until it is resolved. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1517-67e4b366f02b417786187c381939d19d — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1517-67e4b366f02b417786187c381939d19d — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1517-95d6e450ab294008b202d3b15a76bced — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1517-95d6e450ab294008b202d3b15a76bced — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1517-f4c19477bc1b45919e3053010a41eaa3 — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1517-f4c19477bc1b45919e3053010a41eaa3 — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +OVERLAP — now collides with FS.GG.SDD#75 (worker otter-9c21) + src/Shared.fs + notified worker otter-9c21 on FS.GG.SDD#75 +fsgg-coord-engine: the updated touch-set COLLIDES with a live claim (this command may or may not be what introduced it) — do NOT keep editing the shared paths until it is resolved. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1517-5b0eee40266a45feacc92c8e02afb41b — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1517-5b0eee40266a45feacc92c8e02afb41b — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +OVERLAP — now collides with FS.GG.SDD#75 (worker otter-9c21) + src/Shared.fs + notified worker otter-9c21 on FS.GG.SDD#75 +fsgg-coord-engine: the updated touch-set COLLIDES with a live claim (this command may or may not be what introduced it) — do NOT keep editing the shared paths until it is resolved. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1517-0679ed46bdef44298991a64c9a14c89e — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1517-0679ed46bdef44298991a64c9a14c89e — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1517-929ad14d6506426387da5ce2a0dfc84d — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1517-929ad14d6506426387da5ce2a0dfc84d — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1740-5bb81dba320740058b716a761e72f7e6 — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1740-5bb81dba320740058b716a761e72f7e6 — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +OVERLAP — now collides with FS.GG.SDD#75 (worker otter-9c21) + src/Shared.fs + notified worker otter-9c21 on FS.GG.SDD#75 +fsgg-coord-engine: the updated touch-set COLLIDES with a live claim (this command may or may not be what introduced it) — do NOT keep editing the shared paths until it is resolved. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1740-31014431def4450aa0ea4ee05b56bbb9 — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1740-31014431def4450aa0ea4ee05b56bbb9 — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1740-2336ec8b706a438c9e72e9c4784750b5 — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1740-2336ec8b706a438c9e72e9c4784750b5 — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +OVERLAP — now collides with FS.GG.SDD#75 (worker otter-9c21) + src/Shared.fs + notified worker otter-9c21 on FS.GG.SDD#75 +fsgg-coord-engine: the updated touch-set COLLIDES with a live claim (this command may or may not be what introduced it) — do NOT keep editing the shared paths until it is resolved. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1740-51b90cca399b4b1cbb9756ca8408885e — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1740-51b90cca399b4b1cbb9756ca8408885e — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +OVERLAP — now collides with FS.GG.SDD#75 (worker otter-9c21) + src/Shared.fs + notified worker otter-9c21 on FS.GG.SDD#75 +fsgg-coord-engine: the updated touch-set COLLIDES with a live claim (this command may or may not be what introduced it) — do NOT keep editing the shared paths until it is resolved. +LIVE-CLAIM: worker ghost-777, FS.GG.SDD#42 is open and claimed by other-123; queue retained. +UNKNOWN: could not record disposition for FS.GG.SDD#42: not found: the notice could not be posted. The server said so — this is an absence, not a failed read.. Queue retained. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1740-3c79a9c29df0462aa01b2662fb2c4da1 — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1740-3c79a9c29df0462aa01b2662fb2c4da1 — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1517-814a196279c3429084e07e71875912fe — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1517-814a196279c3429084e07e71875912fe — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1517-936bb5fe215045708108cec068431b5f — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1517-936bb5fe215045708108cec068431b5f — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1740-64fcfb2a5f42461cb8b1292a2103234b — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +considered 3 candidate(s) — this is a measured count, not an assumption. + FS.GG.SDD#74 — Status is In progress + FS.GG.SDD#75 — the issue is closed (the board column says In review; /check-board reconciles it) + FS.GG.SDD#76 — overlaps in-flight work held by curlew-8afd on FS.GG.SDD#75 (lease frees in ~120m): src/Shared.fs ⇄ src/Shared.fs +this queue is BUSY, not empty. +1 item(s) are QUEUED BEHIND LIVE CLAIMS held by: curlew-8afd + soonest: lease frees in ~120m +wave occupancy: unavailable (no drive-board or work-board host-loop document exists) +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1740-113e8bdf8a3c4630a3a54e82541761a8 — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1740-113e8bdf8a3c4630a3a54e82541761a8 — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +OVERLAP — now collides with FS.GG.SDD#75 (worker curlew-8afd) + src/Shared.fs + notified worker curlew-8afd on FS.GG.SDD#75 +fsgg-coord-engine: the updated touch-set COLLIDES with a live claim (this command may or may not be what introduced it) — do NOT keep editing the shared paths until it is resolved. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1517-5d392f7d70474a4cb07c49809811bf3e — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1517-5d392f7d70474a4cb07c49809811bf3e — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +OVERLAP — now collides with FS.GG.SDD#75 (worker otter-9c21) + src/Shared.fs + notified worker otter-9c21 on FS.GG.SDD#75 +fsgg-coord-engine: the updated touch-set COLLIDES with a live claim (this command may or may not be what introduced it) — do NOT keep editing the shared paths until it is resolved. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1517-193d5cc642c44d6188a800320325b92b — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1517-193d5cc642c44d6188a800320325b92b — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +OVERLAP — now collides with FS.GG.SDD#75 (worker otter-9c21) + src/Shared.fs + notified worker otter-9c21 on FS.GG.SDD#75 +fsgg-coord-engine: the updated touch-set COLLIDES with a live claim (this command may or may not be what introduced it) — do NOT keep editing the shared paths until it is resolved. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1517-03a781c6a9d743e38403b2043b9b5a43 — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1517-03a781c6a9d743e38403b2043b9b5a43 — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +OVERLAP — now collides with FS.GG.SDD#75 (worker otter-9c21) + src/Shared.fs + notified worker otter-9c21 on FS.GG.SDD#75 +fsgg-coord-engine: the updated touch-set COLLIDES with a live claim (this command may or may not be what introduced it) — do NOT keep editing the shared paths until it is resolved. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1517-d85e53c06b724ba88ee180af4816dc06 — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1517-d85e53c06b724ba88ee180af4816dc06 — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +OVERLAP — now collides with FS.GG.SDD#75 (worker otter-9c21) + src/Shared.fs + could NOT notify worker otter-9c21 on FS.GG.SDD#75: not found: the notice could not be posted. The server said so — this is an absence, not a failed read. +fsgg-coord-engine: the updated touch-set COLLIDES with a live claim (this command may or may not be what introduced it) — do NOT keep editing the shared paths until it is resolved. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1517-e324313f29a143328a7b9fc14592f1cc — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1517-e324313f29a143328a7b9fc14592f1cc — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +OVERLAP — now collides with FS.GG.SDD#75 (worker otter-9c21) + src/Shared.fs + could NOT notify worker otter-9c21 on FS.GG.SDD#75: not found: the notice could not be posted. The server said so — this is an absence, not a failed read. +fsgg-coord-engine: the updated touch-set COLLIDES with a live claim (this command may or may not be what introduced it) — do NOT keep editing the shared paths until it is resolved. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1740-cf560e18aae249f6a6b2461be8c70e42 — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1740-cf560e18aae249f6a6b2461be8c70e42 — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +OVERLAP — now collides with FS.GG.SDD#75 (worker otter-9c21) + src/Shared.fs + notified worker otter-9c21 on FS.GG.SDD#75 +fsgg-coord-engine: the updated touch-set COLLIDES with a live claim (this command may or may not be what introduced it) — do NOT keep editing the shared paths until it is resolved. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1740-2b262996a3c74718815efd329af09ab2 — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1740-2b262996a3c74718815efd329af09ab2 — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +OVERLAP — now collides with FS.GG.SDD#75 (worker otter-9c21) + src/Shared.fs + notified worker otter-9c21 on FS.GG.SDD#75 +fsgg-coord-engine: the updated touch-set COLLIDES with a live claim (this command may or may not be what introduced it) — do NOT keep editing the shared paths until it is resolved. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1740-13f710f2c6c9495e817d92f015903c20 — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. + FS.GG.SDD#74 — Status is In progress + FS.GG.SDD#75 — Status is Blocked +wave occupancy: unavailable (no drive-board or work-board host-loop document exists) +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1740-246c27adbb7b49f78e7610688c3042c0 — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1740-246c27adbb7b49f78e7610688c3042c0 — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1740-12e4e016487e418f931d400096ea5289 — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1740-12e4e016487e418f931d400096ea5289 — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1740-d2f085dbd6e7486280eff9c972462dc9 — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1740-d2f085dbd6e7486280eff9c972462dc9 — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +OVERLAP — now collides with FS.GG.SDD#75 (worker otter-9c21) + src/Shared.fs + notified worker otter-9c21 on FS.GG.SDD#75 +fsgg-coord-engine: the updated touch-set COLLIDES with a live claim (this command may or may not be what introduced it) — do NOT keep editing the shared paths until it is resolved. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1740-5305f20e3bba42e78e18b5f20195eb15 — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1740-5305f20e3bba42e78e18b5f20195eb15 — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1740-2b31637a69c94caa9c9ba31890d03db3 — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1740-2b31637a69c94caa9c9ba31890d03db3 — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1740-2b31637a69c94caa9c9ba31890d03db3 — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1740-2b31637a69c94caa9c9ba31890d03db3 — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +OVERLAP — now collides with FS.GG.SDD#75 (worker otter-9c21) + src/Shared.fs + notified worker otter-9c21 on FS.GG.SDD#75 +fsgg-coord-engine: the updated touch-set COLLIDES with a live claim (this command may or may not be what introduced it) — do NOT keep editing the shared paths until it is resolved. +[xUnit.net 00:00:01.28] Finished: FS.GG.Coord.Cli.BoardOps.Tests + + + + \ No newline at end of file diff --git a/work/coordination-change-risk-mitigation/artifacts/command-catalogue-kernel.test-report.xml b/work/coordination-change-risk-mitigation/artifacts/command-catalogue-kernel.test-report.xml new file mode 100644 index 000000000..bb7c4046e --- /dev/null +++ b/work/coordination-change-risk-mitigation/artifacts/command-catalogue-kernel.test-report.xml @@ -0,0 +1,1114 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + [xUnit.net 00:00:00.00] xUnit.net VSTest Adapter v3.1.5+1b188a7b0a (64-bit .NET 10.0.10) +[xUnit.net 00:00:00.05] Discovering: FS.GG.Coord.Cli.Kernel.Tests +[xUnit.net 00:00:00.08] Discovered: FS.GG.Coord.Cli.Kernel.Tests +[xUnit.net 00:00:00.11] Starting: FS.GG.Coord.Cli.Kernel.Tests +[xUnit.net 00:00:00.29] Finished: FS.GG.Coord.Cli.Kernel.Tests + + + + \ No newline at end of file diff --git a/work/coordination-change-risk-mitigation/artifacts/compatibility-slices.junit.xml b/work/coordination-change-risk-mitigation/artifacts/compatibility-slices.junit.xml new file mode 100644 index 000000000..18b183987 --- /dev/null +++ b/work/coordination-change-risk-mitigation/artifacts/compatibility-slices.junit.xml @@ -0,0 +1,18 @@ + diff --git a/work/coordination-change-risk-mitigation/artifacts/completion-receipts-boardops.test-report.xml b/work/coordination-change-risk-mitigation/artifacts/completion-receipts-boardops.test-report.xml new file mode 100644 index 000000000..d74fe8de4 --- /dev/null +++ b/work/coordination-change-risk-mitigation/artifacts/completion-receipts-boardops.test-report.xml @@ -0,0 +1,1710 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + [xUnit.net 00:00:00.00] xUnit.net VSTest Adapter v3.1.5+1b188a7b0a (64-bit .NET 10.0.10) +[xUnit.net 00:00:00.07] Discovering: FS.GG.Coord.Cli.BoardOps.Tests +[xUnit.net 00:00:00.12] Discovered: FS.GG.Coord.Cli.BoardOps.Tests +[xUnit.net 00:00:00.15] Starting: FS.GG.Coord.Cli.BoardOps.Tests +fsgg-coord-engine: not found: stop after reuse binding. The server said so — this is an absence, not a failed read. +fsgg-coord-engine: not found: stop after intent recovery. The server said so — this is an absence, not a failed read. +fsgg-coord-engine: not found: interrupted after persisted create. The server said so — this is an absence, not a failed read. +fsgg-coord-engine: not found: stop after recovered receipt. The server said so — this is an absence, not a failed read. +fsgg-coord-engine: malformed response reading tx-2134: a duplicate candidate matches the title; select reuse or revise the draft. That is a FAILED READ, not an empty answer — refusing to decide from it. +fsgg-coord-engine: malformed response reading tx-2134: a duplicate candidate matches the title; select reuse or revise the draft. That is a FAILED READ, not an empty answer — refusing to decide from it. +fsgg-coord-engine: malformed response reading ready-2134: Ready is refused while the reused/live issue still declares a dependency or human choice. That is a FAILED READ, not an empty answer — refusing to decide from it. +fsgg-coord-engine: malformed response reading blocked-2134: Blocked dependency FS-GG/.github#42 is already resolved. That is a FAILED READ, not an empty answer — refusing to decide from it. +{"schema":"fsgg.coord.intake-result/v1","kind":"applied","draftId":"tx-2134","issue":"FS-GG/.github#77","issueUrl":"https://github.com/FS-GG/.github/issues/77","dedupeDisposition":"create","board":{"owner":"FS-GG","title":"Coordination","number":1,"id":"PVT"},"status":"Backlog","fields":["Status","Class"],"projectionFresh":true,"pendingWrites":0,"judgementQuestion":null} +{"schema":"fsgg.coord.intake-result/v1","kind":"applied","draftId":"tx-2134","issue":"FS-GG/.github#77","issueUrl":"https://github.com/FS-GG/.github/issues/77","dedupeDisposition":"create","board":{"owner":"FS-GG","title":"Coordination","number":1,"id":"PVT"},"status":"Backlog","fields":["Status","Class"],"projectionFresh":true,"pendingWrites":0,"judgementQuestion":null} +fsgg-coord-engine: malformed response reading tx-2134: a duplicate candidate matches the title; select reuse or revise the draft. That is a FAILED READ, not an empty answer — refusing to decide from it. +fsgg-coord-engine: malformed response reading tx-2134: intake receipt '/tmp/fsgg-intake-9b65dd4163a14767850b60d02eb23785/intake-tx-2134.json' is unreadable: 'not-json' is an invalid JSON literal. Expected the literal 'null'. LineNumber: 0 | BytePositionInLine: 1.. That is a FAILED READ, not an empty answer — refusing to decide from it. +fsgg-coord-engine: malformed response reading tx-2134: intake receipt '/tmp/fsgg-intake-9b65dd4163a14767850b60d02eb23785/intake-tx-2134.json' is unreadable: The given key was not present in the dictionary.. That is a FAILED READ, not an empty answer — refusing to decide from it. +paths paths do not exist in target repository FS-GG/.github: definitely/not/a/live/path-2134 +fsgg-coord-engine: not found: stop after receipt recovery. The server said so — this is an absence, not a failed read. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1517-216a9c8fb6d74961ad38006bc038f633 — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1517-216a9c8fb6d74961ad38006bc038f633 — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +OVERLAP — now collides with FS.GG.SDD#75 (worker otter-9c21) + src/Shared.fs + notified worker otter-9c21 on FS.GG.SDD#75 +fsgg-coord-engine: the updated touch-set COLLIDES with a live claim (this command may or may not be what introduced it) — do NOT keep editing the shared paths until it is resolved. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1517-c16e860fb86743ffb10b38d01a6f4d41 — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1517-c16e860fb86743ffb10b38d01a6f4d41 — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +OVERLAP — now collides with FS.GG.SDD#75 (worker otter-9c21) + src/Shared.fs + notified worker otter-9c21 on FS.GG.SDD#75 +fsgg-coord-engine: the updated touch-set COLLIDES with a live claim (this command may or may not be what introduced it) — do NOT keep editing the shared paths until it is resolved. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1517-6a7c5b5e25424b9794afca01f8cdb067 — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1517-6a7c5b5e25424b9794afca01f8cdb067 — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1517-7a255777d1584001a7f441c7ece842c0 — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1517-7a255777d1584001a7f441c7ece842c0 — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1517-aa941dbe23a74ae9a3f5003f6c89a7f9 — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1517-aa941dbe23a74ae9a3f5003f6c89a7f9 — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +OVERLAP — now collides with FS.GG.SDD#75 (worker otter-9c21) + src/Shared.fs + notified worker otter-9c21 on FS.GG.SDD#75 +fsgg-coord-engine: the updated touch-set COLLIDES with a live claim (this command may or may not be what introduced it) — do NOT keep editing the shared paths until it is resolved. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1517-9ada22ffc8b34e0da673971f17c492a2 — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1517-9ada22ffc8b34e0da673971f17c492a2 — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +OVERLAP — now collides with FS.GG.SDD#75 (worker otter-9c21) + src/Shared.fs + notified worker otter-9c21 on FS.GG.SDD#75 +fsgg-coord-engine: the updated touch-set COLLIDES with a live claim (this command may or may not be what introduced it) — do NOT keep editing the shared paths until it is resolved. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1517-eb400f255f1649eba622c9267aaf07dc — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1517-eb400f255f1649eba622c9267aaf07dc — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +OVERLAP — now collides with FS.GG.SDD#75 (worker otter-9c21) + src/Shared.fs + notified worker otter-9c21 on FS.GG.SDD#75 +fsgg-coord-engine: the updated touch-set COLLIDES with a live claim (this command may or may not be what introduced it) — do NOT keep editing the shared paths until it is resolved. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1517-61ba95110d104190a5b2fc26eca2f6eb — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1517-61ba95110d104190a5b2fc26eca2f6eb — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +OVERLAP — now collides with FS.GG.SDD#75 (worker otter-9c21) + src/Shared.fs + notified worker otter-9c21 on FS.GG.SDD#75 +fsgg-coord-engine: the updated touch-set COLLIDES with a live claim (this command may or may not be what introduced it) — do NOT keep editing the shared paths until it is resolved. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1517-602fe72ec8824c7398ad990922280e80 — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1517-602fe72ec8824c7398ad990922280e80 — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +OVERLAP — now collides with FS.GG.SDD#75 (worker otter-9c21) + src/Shared.fs + notified worker otter-9c21 on FS.GG.SDD#75 +fsgg-coord-engine: the updated touch-set COLLIDES with a live claim (this command may or may not be what introduced it) — do NOT keep editing the shared paths until it is resolved. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1517-b03236a5238e419e9dab176f129501ae — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1517-b03236a5238e419e9dab176f129501ae — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +OVERLAP — now collides with FS.GG.SDD#75 (worker otter-9c21) + src/Shared.fs + notified worker otter-9c21 on FS.GG.SDD#75 +fsgg-coord-engine: the updated touch-set COLLIDES with a live claim (this command may or may not be what introduced it) — do NOT keep editing the shared paths until it is resolved. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1517-d1de67fcbd314727931d3667fb904de3 — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1517-d1de67fcbd314727931d3667fb904de3 — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +OVERLAP — now collides with FS.GG.SDD#75 (worker otter-9c21) + src/Shared.fs + notified worker otter-9c21 on FS.GG.SDD#75 +fsgg-coord-engine: the updated touch-set COLLIDES with a live claim (this command may or may not be what introduced it) — do NOT keep editing the shared paths until it is resolved. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1740-4dc73099594a43c288f0a32da7ac4b72 — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +considered 3 candidate(s) — this is a measured count, not an assumption. + FS.GG.SDD#74 — Status is In progress + FS.GG.SDD#75 — Status is Blocked + FS.GG.SDD#76 — overlaps in-flight work held by otter-9c21 on FS.GG.SDD#75 (lease EXPIRED — reapable): src/Shared.fs ⇄ src/Shared.fs +this queue is BUSY, not empty. +1 item(s) are QUEUED BEHIND LIVE CLAIMS held by: otter-9c21 + soonest: lease EXPIRED — reapable + 1 of those lease(s) have EXPIRED — collect them: scripts/fsgg-coord reap --repo FS.GG.SDD --apply +wave occupancy: unavailable (no drive-board or work-board host-loop document exists) +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1740-4e7eade866154b87b5938726dda838be — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1740-4e7eade866154b87b5938726dda838be — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +OVERLAP — now collides with FS.GG.SDD#75 (worker otter-9c21) + src/Shared.fs + notified worker otter-9c21 on FS.GG.SDD#75 +fsgg-coord-engine: the updated touch-set COLLIDES with a live claim (this command may or may not be what introduced it) — do NOT keep editing the shared paths until it is resolved. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1740-59b1963f390448b391aa75b7309b709d — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1740-59b1963f390448b391aa75b7309b709d — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1517-e418dec87d734e5eab32c70d30ae5eab — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1517-e418dec87d734e5eab32c70d30ae5eab — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1740-2ad2ca90e2e54686937be923ec0791c4 — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1740-2ad2ca90e2e54686937be923ec0791c4 — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +OVERLAP — now collides with FS.GG.SDD#75 (worker otter-9c21) + src/Shared.fs + notified worker otter-9c21 on FS.GG.SDD#75 +fsgg-coord-engine: the updated touch-set COLLIDES with a live claim (this command may or may not be what introduced it) — do NOT keep editing the shared paths until it is resolved. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1740-e73e4ada05624002a946f1074b9e751f — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +considered 3 candidate(s) — this is a measured count, not an assumption. + FS.GG.SDD#74 — Status is In progress + FS.GG.SDD#75 — Status is In progress + FS.GG.SDD#76 — overlaps FS.GG.SDD#75, which the board says is In progress with NO claim marker (someone is working outside the protocol — there is no lease to wait out; see: scripts/fsgg-coord who): src/Shared.fs ⇄ src/Shared.fs +wave occupancy: unavailable (no drive-board or work-board host-loop document exists) +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1740-93dc474f75104ddebc41809ec175a1df — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1740-93dc474f75104ddebc41809ec175a1df — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1740-c0067f63c783462ca61528a1df2b237d — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1740-c0067f63c783462ca61528a1df2b237d — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +OVERLAP — now collides with FS.GG.SDD#75 (worker otter-9c21) + src/Shared.fs + notified worker otter-9c21 on FS.GG.SDD#75 +fsgg-coord-engine: the updated touch-set COLLIDES with a live claim (this command may or may not be what introduced it) — do NOT keep editing the shared paths until it is resolved. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1740-ca7f0a2a0e7f4c9b839ff6ae5b63d88a — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1740-ca7f0a2a0e7f4c9b839ff6ae5b63d88a — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +OVERLAP — now collides with FS.GG.SDD#75 (worker otter-9c21) + src/Shared.fs + notified worker otter-9c21 on FS.GG.SDD#75 +fsgg-coord-engine: the updated touch-set COLLIDES with a live claim (this command may or may not be what introduced it) — do NOT keep editing the shared paths until it is resolved. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1740-b3716d530a8e4f8c8b9c249c8ddf6f06 — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1740-b3716d530a8e4f8c8b9c249c8ddf6f06 — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +OVERLAP — now collides with FS.GG.SDD#75 (worker otter-9c21) + src/Shared.fs + notified worker otter-9c21 on FS.GG.SDD#75 +fsgg-coord-engine: the updated touch-set COLLIDES with a live claim (this command may or may not be what introduced it) — do NOT keep editing the shared paths until it is resolved. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1740-63582a1957194a16846a9016f7d20474 — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1740-63582a1957194a16846a9016f7d20474 — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +OVERLAP — now collides with FS.GG.SDD#75 (worker otter-9c21) + src/Shared.fs + notified worker otter-9c21 on FS.GG.SDD#75 +fsgg-coord-engine: the updated touch-set COLLIDES with a live claim (this command may or may not be what introduced it) — do NOT keep editing the shared paths until it is resolved. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1740-e4f126d048364f7d919786254879beff — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1740-e4f126d048364f7d919786254879beff — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +OVERLAP — now collides with FS.GG.SDD#75 (worker otter-9c21) + src/Shared.fs + notified worker otter-9c21 on FS.GG.SDD#75 +fsgg-coord-engine: the updated touch-set COLLIDES with a live claim (this command may or may not be what introduced it) — do NOT keep editing the shared paths until it is resolved. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1740-0041279b0a8d4566aec432681df67c55 — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1740-0041279b0a8d4566aec432681df67c55 — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +OVERLAP — now collides with FS.GG.SDD#75 (worker otter-9c21) + src/Shared.fs + notified worker otter-9c21 on FS.GG.SDD#75 +fsgg-coord-engine: the updated touch-set COLLIDES with a live claim (this command may or may not be what introduced it) — do NOT keep editing the shared paths until it is resolved. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1517-2fc7400dc9fe471aa816fce13b50a4a0 — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1517-2fc7400dc9fe471aa816fce13b50a4a0 — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1517-68ce4ca8b9134106a7a7f6146a2a9b3f — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1517-68ce4ca8b9134106a7a7f6146a2a9b3f — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1517-b381196ee84e43e1b7a716593dfe7268 — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1517-b381196ee84e43e1b7a716593dfe7268 — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +OVERLAP — now collides with FS.GG.SDD#75 (worker otter-9c21) + src/Shared.fs + notified worker otter-9c21 on FS.GG.SDD#75 +fsgg-coord-engine: the updated touch-set COLLIDES with a live claim (this command may or may not be what introduced it) — do NOT keep editing the shared paths until it is resolved. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1517-9b5d2f848fa449748422b6d19e760d6f — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1517-9b5d2f848fa449748422b6d19e760d6f — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +OVERLAP — now collides with FS.GG.SDD#75 (worker otter-9c21) + src/Shared.fs + notified worker otter-9c21 on FS.GG.SDD#75 +fsgg-coord-engine: the updated touch-set COLLIDES with a live claim (this command may or may not be what introduced it) — do NOT keep editing the shared paths until it is resolved. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1517-28c88f8770f94bd79a1f6dcf905d956b — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1517-28c88f8770f94bd79a1f6dcf905d956b — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1517-86ec89adb8e24ec29a4d1dc8dc927705 — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1517-86ec89adb8e24ec29a4d1dc8dc927705 — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1740-1878597457f3499e896c87cf9002d2df — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1740-1878597457f3499e896c87cf9002d2df — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +OVERLAP — now collides with FS.GG.SDD#75 (worker otter-9c21) + src/Shared.fs + notified worker otter-9c21 on FS.GG.SDD#75 +fsgg-coord-engine: the updated touch-set COLLIDES with a live claim (this command may or may not be what introduced it) — do NOT keep editing the shared paths until it is resolved. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1740-ff2524c07ead4317b567c161e8d1fffe — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1740-ff2524c07ead4317b567c161e8d1fffe — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1740-a60d5ae760d047c4b7228b7f51415125 — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1740-a60d5ae760d047c4b7228b7f51415125 — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +OVERLAP — now collides with FS.GG.SDD#75 (worker otter-9c21) + src/Shared.fs + notified worker otter-9c21 on FS.GG.SDD#75 +fsgg-coord-engine: the updated touch-set COLLIDES with a live claim (this command may or may not be what introduced it) — do NOT keep editing the shared paths until it is resolved. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1740-92e6e93589414b1e99aa2e29e3192ae2 — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1740-92e6e93589414b1e99aa2e29e3192ae2 — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +OVERLAP — now collides with FS.GG.SDD#75 (worker otter-9c21) + src/Shared.fs + notified worker otter-9c21 on FS.GG.SDD#75 +fsgg-coord-engine: the updated touch-set COLLIDES with a live claim (this command may or may not be what introduced it) — do NOT keep editing the shared paths until it is resolved. +LIVE-CLAIM: worker ghost-777, FS.GG.SDD#42 is open and claimed by other-123; queue retained. +UNKNOWN: could not record disposition for FS.GG.SDD#42: not found: the notice could not be posted. The server said so — this is an absence, not a failed read.. Queue retained. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1740-385a155c73c64e13aa9c40e0651a18cd — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1740-385a155c73c64e13aa9c40e0651a18cd — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1517-627f8139a44f4b03ac13a934a034ff19 — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1517-627f8139a44f4b03ac13a934a034ff19 — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1517-bbe89cb881014b1aafb43bdaed676b90 — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1517-bbe89cb881014b1aafb43bdaed676b90 — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1740-6b24a48899c74fc3af4b1ebebfae98fd — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +considered 3 candidate(s) — this is a measured count, not an assumption. + FS.GG.SDD#74 — Status is In progress + FS.GG.SDD#75 — the issue is closed (the board column says In review; /check-board reconciles it) + FS.GG.SDD#76 — overlaps in-flight work held by curlew-8afd on FS.GG.SDD#75 (lease frees in ~120m): src/Shared.fs ⇄ src/Shared.fs +this queue is BUSY, not empty. +1 item(s) are QUEUED BEHIND LIVE CLAIMS held by: curlew-8afd + soonest: lease frees in ~120m +wave occupancy: unavailable (no drive-board or work-board host-loop document exists) +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1740-96459e1e576b4383bb95a2e832e84d98 — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1740-96459e1e576b4383bb95a2e832e84d98 — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +OVERLAP — now collides with FS.GG.SDD#75 (worker curlew-8afd) + src/Shared.fs + notified worker curlew-8afd on FS.GG.SDD#75 +fsgg-coord-engine: the updated touch-set COLLIDES with a live claim (this command may or may not be what introduced it) — do NOT keep editing the shared paths until it is resolved. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1517-3403b2973cb743629bf78dfb3c9fbd5a — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1517-3403b2973cb743629bf78dfb3c9fbd5a — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +OVERLAP — now collides with FS.GG.SDD#75 (worker otter-9c21) + src/Shared.fs + notified worker otter-9c21 on FS.GG.SDD#75 +fsgg-coord-engine: the updated touch-set COLLIDES with a live claim (this command may or may not be what introduced it) — do NOT keep editing the shared paths until it is resolved. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1517-4edcf011c1834f7d8664e72634a8a249 — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1517-4edcf011c1834f7d8664e72634a8a249 — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +OVERLAP — now collides with FS.GG.SDD#75 (worker otter-9c21) + src/Shared.fs + notified worker otter-9c21 on FS.GG.SDD#75 +fsgg-coord-engine: the updated touch-set COLLIDES with a live claim (this command may or may not be what introduced it) — do NOT keep editing the shared paths until it is resolved. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1517-e6f05e857f5b4a7aa51217fc8f00eaa9 — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1517-e6f05e857f5b4a7aa51217fc8f00eaa9 — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +OVERLAP — now collides with FS.GG.SDD#75 (worker otter-9c21) + src/Shared.fs + notified worker otter-9c21 on FS.GG.SDD#75 +fsgg-coord-engine: the updated touch-set COLLIDES with a live claim (this command may or may not be what introduced it) — do NOT keep editing the shared paths until it is resolved. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1517-36a9c25cdc9c4235b785838a17ed7f35 — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1517-36a9c25cdc9c4235b785838a17ed7f35 — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +OVERLAP — now collides with FS.GG.SDD#75 (worker otter-9c21) + src/Shared.fs + could NOT notify worker otter-9c21 on FS.GG.SDD#75: not found: the notice could not be posted. The server said so — this is an absence, not a failed read. +fsgg-coord-engine: the updated touch-set COLLIDES with a live claim (this command may or may not be what introduced it) — do NOT keep editing the shared paths until it is resolved. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1517-4ecd728596cb4bf0a73750a2685e35cc — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1517-4ecd728596cb4bf0a73750a2685e35cc — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +OVERLAP — now collides with FS.GG.SDD#75 (worker otter-9c21) + src/Shared.fs + could NOT notify worker otter-9c21 on FS.GG.SDD#75: not found: the notice could not be posted. The server said so — this is an absence, not a failed read. +fsgg-coord-engine: the updated touch-set COLLIDES with a live claim (this command may or may not be what introduced it) — do NOT keep editing the shared paths until it is resolved. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1740-3e903969842249e48804164121f38c74 — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1740-3e903969842249e48804164121f38c74 — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +OVERLAP — now collides with FS.GG.SDD#75 (worker otter-9c21) + src/Shared.fs + notified worker otter-9c21 on FS.GG.SDD#75 +fsgg-coord-engine: the updated touch-set COLLIDES with a live claim (this command may or may not be what introduced it) — do NOT keep editing the shared paths until it is resolved. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1740-0057e8f8ac8c47499df416cb6f863deb — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1740-0057e8f8ac8c47499df416cb6f863deb — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +OVERLAP — now collides with FS.GG.SDD#75 (worker otter-9c21) + src/Shared.fs + notified worker otter-9c21 on FS.GG.SDD#75 +fsgg-coord-engine: the updated touch-set COLLIDES with a live claim (this command may or may not be what introduced it) — do NOT keep editing the shared paths until it is resolved. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1740-da4b2b5e7016439a8887464ceffa39f7 — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. + FS.GG.SDD#74 — Status is In progress + FS.GG.SDD#75 — Status is Blocked +wave occupancy: unavailable (no drive-board or work-board host-loop document exists) +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1740-0de5f8b940be4f798e72784e6f16f3c4 — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1740-0de5f8b940be4f798e72784e6f16f3c4 — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1740-91f6eefebc23483583cc5ee3a3136b1f — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1740-91f6eefebc23483583cc5ee3a3136b1f — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1740-3a0c2290dfc447e9841f07f3c43c8732 — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1740-3a0c2290dfc447e9841f07f3c43c8732 — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +OVERLAP — now collides with FS.GG.SDD#75 (worker otter-9c21) + src/Shared.fs + notified worker otter-9c21 on FS.GG.SDD#75 +fsgg-coord-engine: the updated touch-set COLLIDES with a live claim (this command may or may not be what introduced it) — do NOT keep editing the shared paths until it is resolved. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1740-5ac8c1277f344f48b87ac5d0d63d0759 — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1740-5ac8c1277f344f48b87ac5d0d63d0759 — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1740-65eb95d50e964b21b9f75d12a360d895 — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1740-65eb95d50e964b21b9f75d12a360d895 — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1740-65eb95d50e964b21b9f75d12a360d895 — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1740-65eb95d50e964b21b9f75d12a360d895 — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +OVERLAP — now collides with FS.GG.SDD#75 (worker otter-9c21) + src/Shared.fs + notified worker otter-9c21 on FS.GG.SDD#75 +fsgg-coord-engine: the updated touch-set COLLIDES with a live claim (this command may or may not be what introduced it) — do NOT keep editing the shared paths until it is resolved. +fsgg-coord-engine: vole-418 does not hold FS.GG.SDD#42 — nothing to release. +fsgg-coord-engine: Status=Blocked refuses an incoherent park (.github#2079). +fsgg-coord-engine: set-field --batch refuses: this call clears 'Blocked by' in the SAME batch as 'Status=Blocked' — the row would land with an EMPTY field and no 'Blocked on: human/...' sentinel (.github#2079). Pair 'Status=Blocked' with a non-empty 'Blocked by=<refs>' instead, or record a human park first: add a body line 'Blocked on: human/decision' or 'Blocked on: human/action'. Nothing written. +fsgg-coord-engine: set-field --batch refuses: this call clears 'Blocked by' in the SAME batch as 'Status=Blocked' — the row would land with an EMPTY field and no 'Blocked on: human/...' sentinel (.github#2079). Pair 'Status=Blocked' with a non-empty 'Blocked by=<refs>' instead, or record a human park first: add a body line 'Blocked on: human/decision' or 'Blocked on: human/action'. Nothing written. +fsgg-coord-engine: Status=Blocked refuses an incoherent park (.github#2079). +fsgg-coord-engine: vole-418 does not hold FS.GG.SDD#42 — nothing to release. +[xUnit.net 00:00:01.62] Finished: FS.GG.Coord.Cli.BoardOps.Tests + + + + \ No newline at end of file diff --git a/work/coordination-change-risk-mitigation/artifacts/completion-receipts-cli.test-report.xml b/work/coordination-change-risk-mitigation/artifacts/completion-receipts-cli.test-report.xml new file mode 100644 index 000000000..4de2c7d64 --- /dev/null +++ b/work/coordination-change-risk-mitigation/artifacts/completion-receipts-cli.test-report.xml @@ -0,0 +1,3263 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + [xUnit.net 00:00:00.00] xUnit.net VSTest Adapter v3.1.5+1b188a7b0a (64-bit .NET 10.0.10) +[xUnit.net 00:00:00.08] Discovering: FS.GG.Coord.Cli.Tests +[xUnit.net 00:00:00.14] Discovered: FS.GG.Coord.Cli.Tests +[xUnit.net 00:00:00.18] Starting: FS.GG.Coord.Cli.Tests +fsgg-coord-engine: KIT DIGEST — a content-addressed kit source is STALE in `registry/repos.lock`: + .claude/skills/pnext-item +`repos-registry-selftest` reds `main` until it is regenerated (ADR-0019, #469). Run: + scripts/repos.sh relock +Then name `registry/repos.lock` as EXPECTED DRIFT in the PR — do NOT reserve it in the +touch-set. It is a GENERATED, CI-GATED artifact, so a collision in it is a REBASE, not a +decision (#309). Reserving it is the three-worker deadlock #527 removed (#428). + Widen the touch-set (scripts/fsgg-coord widen), or split the PR. + Fix the PR body now — this is unrecoverable once the PR is merged (editing a merged PR's body does not replay the close, .github#2107). +fsgg-coord-engine: KIT DIGEST — a content-addressed kit source is STALE in `registry/repos.lock`: + .claude/skills/pnext-item +`repos-registry-selftest` reds `main` until it is regenerated (ADR-0019, #469). Run: + scripts/repos.sh relock +Then name `registry/repos.lock` as EXPECTED DRIFT in the PR — do NOT reserve it in the +touch-set. It is a GENERATED, CI-GATED artifact, so a collision in it is a REBASE, not a +decision (#309). Reserving it is the three-worker deadlock #527 removed (#428). +fsgg-coord-engine: KIT DIGEST — a content-addressed kit source is STALE in `registry/repos.lock`: + .claude/skills/pnext-item +`repos-registry-selftest` reds `main` until it is regenerated (ADR-0019, #469). Run: + scripts/repos.sh relock +Then name `registry/repos.lock` as EXPECTED DRIFT in the PR — do NOT reserve it in the +touch-set. It is a GENERATED, CI-GATED artifact, so a collision in it is a REBASE, not a +decision (#309). Reserving it is the three-worker deadlock #527 removed (#428). +fsgg-coord-engine: KIT DIGEST — a content-addressed kit source is STALE in `registry/repos.lock`: + .claude/skills/pnext-item +`repos-registry-selftest` reds `main` until it is regenerated (ADR-0019, #469). Run: + scripts/repos.sh relock +Then name `registry/repos.lock` as EXPECTED DRIFT in the PR — do NOT reserve it in the +touch-set. It is a GENERATED, CI-GATED artifact, so a collision in it is a REBASE, not a +decision (#309). Reserving it is the three-worker deadlock #527 removed (#428). +fsgg-coord-engine: KIT DIGEST — a content-addressed kit source is STALE in `registry/repos.lock`: + .claude/skills/pnext-item +`repos-registry-selftest` reds `main` until it is regenerated (ADR-0019, #469). Run: + scripts/repos.sh relock +Then name `registry/repos.lock` as EXPECTED DRIFT in the PR — do NOT reserve it in the +touch-set. It is a GENERATED, CI-GATED artifact, so a collision in it is a REBASE, not a +decision (#309). Reserving it is the three-worker deadlock #527 removed (#428). + Fix the PR body now — this is unrecoverable once the PR is merged (editing a merged PR's body does not replay the close, .github#2107). +fsgg-coord-engine: delivery-route: recording sdd-required ahead of its SDD package (sdd readiness workId does not match 'substituted-2298') — the claimed worker owns producing it before touching Paths. +fsgg-coord-engine: delivery-route: only structured v2 records may be written: revision is required; scope is required; dependencies is required; touchSet is required; policyVersion is required; digest is required +fsgg-coord-engine: delivery-route: recording sdd-required ahead of its SDD package (sdd readiness status is not implementationReady) — the claimed worker owns producing it before touching Paths. +{"kind":"error","exitCode":1,"message":"malformed response reading FS-GG/FS.GG.SDD#42: delivery route is not current: structured route ledger is missing. That is a FAILED READ, not an empty answer \u2014 refusing to decide from it.","rateLimit":null} +fsgg-coord-engine: malformed response reading FS-GG/FS.GG.SDD#42: structured route ledger is missing. That is a FAILED READ, not an empty answer — refusing to decide from it. +{"kind":"error","exitCode":1,"message":"malformed response reading FS-GG/FS.GG.SDD#42: delivery route is not current: structured route ledger is missing. That is a FAILED READ, not an empty answer \u2014 refusing to decide from it.","rateLimit":null} +fsgg-coord-engine: delivery-route: recording sdd-required ahead of its SDD package (sdd spec does not exist: work/no-package-2298/spec.md; sdd readiness evidence does not exist: /tmp/fsgg-2298-e26a9a96cdfd4eaab826c61ef9f330bc/readiness/no-package-2298/analysis.json) — the claimed worker owns producing it before touching Paths. +{"kind":"error","exitCode":1,"message":"malformed response reading FS-GG/FS.GG.SDD#42: delivery route is not current: revision is required; scope is required; dependencies is required; touchSet is required; policyVersion is required; route is required; agent is required; timestamp is required; reasonCodes is required; rationale is required; requiredGates is required; digest is required. That is a FAILED READ, not an empty answer \u2014 refusing to decide from it.","rateLimit":null} +fsgg-coord-engine: comment: source file does not exist: /tmp/3356d82b2fab4a0a9dbd527ea1c7d6cd/missing.md +considered 1 candidate(s) — this is a measured count, not an assumption. + .github#398 — the issue is closed (the board column says Done; /check-board reconciles it) +wave occupancy: {"activeItems":0,"waveCapacity":6,"openSlots":6} +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-2351-063759cbf97841aeb94b71679887f539 — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-2351-c4a654c059f842a9a13af2b21e7548e6 — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-2351-bab0e4a2cdb44847857df2ab5c8b8a37 — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-2351-e6575202b5454eaa8f445357bece9e33 — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: landable: evaluated the host review-acceptance assertion (`fsgg:review-decision/v2`) for PR #801. +fsgg-coord-engine: landable: evaluated the host review-acceptance assertion (`fsgg:review-decision/v2`) for PR #801. +fsgg-coord-engine: landable: PR #801 is not landable — PR #801 carries no valid host review-acceptance marker (`fsgg:review-decision/v2`) — the review chain is absent, incomplete, or malformed. +fsgg-coord-engine: These are assertions you asked for, and an unmet one is `pending`, never `green` — an ABSENT check reads exactly like a passing one to any 'is anything red?' rollup (#606). Usually transient (registration, a superseded suite's replacement, GitHub catching up with a force-push). If it never resolves: the job was RENAMED, its workflow's `paths:` filter no longer matches, or --sha named the wrong commit. +fsgg-coord-engine: landable: PR #801 is ALREADY MERGED — there is nothing to gate, and --wait does not poll it. +fsgg-coord-engine: This is a TERMINAL verdict, not a retry. If you are recovering an item whose worker died between merge and completion projection, the work LANDED — complete delivery: scripts/fsgg-coord delivery <ref> --pr 801 --flip --apply +fsgg-coord-engine: landable: PR #801 is ALREADY MERGED — there is nothing to gate, and --wait does not poll it. +fsgg-coord-engine: This is a TERMINAL verdict, not a retry. If you are recovering an item whose worker died between merge and completion projection, the work LANDED — complete delivery: scripts/fsgg-coord delivery <ref> --pr 801 --flip --apply +fsgg-coord-engine: landable: PR #801 is ALREADY MERGED — there is nothing to gate, and --wait does not poll it. +fsgg-coord-engine: This is a TERMINAL verdict, not a retry. If you are recovering an item whose worker died between merge and completion projection, the work LANDED — complete delivery: scripts/fsgg-coord delivery <ref> --pr 801 --flip --apply +fsgg-coord-engine: landable: evaluated the host review-acceptance assertion (`fsgg:review-decision/v2`) for PR #801. +fsgg-coord-engine: landable: PR #801 is not landable — PR #801's host review-acceptance marker is bound to head `bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb`, not the current head `aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa` — a stale-sha marker is treated as ABSENT, never as satisfaction. +fsgg-coord-engine: These are assertions you asked for, and an unmet one is `pending`, never `green` — an ABSENT check reads exactly like a passing one to any 'is anything red?' rollup (#606). Usually transient (registration, a superseded suite's replacement, GitHub catching up with a force-push). If it never resolves: the job was RENAMED, its workflow's `paths:` filter no longer matches, or --sha named the wrong commit. +fsgg-coord-engine: landable: PR #801 is CLOSED WITHOUT MERGING — nothing landed, so there is nothing to gate. +fsgg-coord-engine: Terminal, and NOT the merged case: do NOT stamp the item done. The branch was abandoned or the PR rejected, so the item needs re-working or releasing. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1620-8352ab8e19844ddb9fc1a518a24f654a — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +STOLE FS.GG.SDD#42 from worker 'snipe-f893' (--force) +fsgg-coord-engine: post-claim Status readback FAILED for FS.GG.SDD#42: not found: the fixture serves no board WRITE — the lock is what is under test. The server said so — this is an absence, not a failed read. +fsgg-coord-engine: the Status board write for FS.GG.SDD#42 was WITHHELD — the item's open-PR probe could not be completed. The lock IS held; the column is UNCHANGED, because a column derived from a fact this process could not read would be an invention. Re-run `claim FS.GG.SDD#42 --json` once the read recovers, or repair the column with `reconcile --apply`. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1620-ababc6cb34394db5a0a99a133a7b63cc — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +STOLE FS.GG.SDD#42 from worker 'snipe-f893' (--force) +fsgg-coord-engine: post-claim Status readback FAILED for FS.GG.SDD#42: not found: the fixture serves no board WRITE — the lock is what is under test. The server said so — this is an absence, not a failed read. +fsgg-coord-engine: the Status board write for FS.GG.SDD#42 was WITHHELD — the item's open-PR probe could not be completed. The lock IS held; the column is UNCHANGED, because a column derived from a fact this process could not read would be an invention. Re-run `claim FS.GG.SDD#42 --json` once the read recovers, or repair the column with `reconcile --apply`. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1620-50f9bc6a1c0c47a5ba58c0e35be4a861 — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: post-claim Status readback FAILED for FS.GG.SDD#42: not found: the fixture serves no board WRITE — the lock is what is under test. The server said so — this is an absence, not a failed read. +fsgg-coord-engine: the Status board write for FS.GG.SDD#42 was WITHHELD — the item's open-PR probe could not be completed. The lock IS held; the column is UNCHANGED, because a column derived from a fact this process could not read would be an invention. Re-run `claim FS.GG.SDD#42 --json` once the read recovers, or repair the column with `reconcile --apply`. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1620-bfa981c6fe194171837ae2fb6caf4795 — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: FS.GG.SDD#42 carries a live marker with YOUR worker id 'vole-418' but a DIFFERENT session (79b9e347) — two workers share one id (#419). Adopting it would put both of you on this item, which is the double-claim ADR-0027 exists to prevent. + Mint a fresh, unique id in THIS shell (do NOT invent one): eval "$(scripts/fsgg-coord whoami --mint)" +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1620-52a8226d64f643a6aac65fe293fad5c7 — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: FS.GG.SDD#42 is already held by snipe-f893 — you did not get it. Wait for the lease to lapse, or work whatever `take` offers instead; `take` advances through its own ranked candidates on a lost race, so no caller re-runs it to retry (.github#2683). +[xUnit.net 00:00:02.51] Finished: FS.GG.Coord.Cli.Tests + + + + \ No newline at end of file diff --git a/work/coordination-change-risk-mitigation/artifacts/completion-receipts-core.test-report.xml b/work/coordination-change-risk-mitigation/artifacts/completion-receipts-core.test-report.xml new file mode 100644 index 000000000..4f0d2a86a --- /dev/null +++ b/work/coordination-change-risk-mitigation/artifacts/completion-receipts-core.test-report.xml @@ -0,0 +1,5544 @@ + + + + + + + + + + + + + + + + + + + + + Ok, passed 100 tests. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Ok, passed 100 tests. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + [xUnit.net 00:00:00.00] xUnit.net VSTest Adapter v3.1.5+1b188a7b0a (64-bit .NET 10.0.10) +[xUnit.net 00:00:00.06] Discovering: FS.GG.Coord.Core.Tests +[xUnit.net 00:00:00.14] Discovered: FS.GG.Coord.Core.Tests +[xUnit.net 00:00:00.20] Starting: FS.GG.Coord.Core.Tests +[xUnit.net 00:00:02.40] Finished: FS.GG.Coord.Core.Tests + + + + \ No newline at end of file diff --git a/work/coordination-change-risk-mitigation/artifacts/completion-receipts-github.test-report.xml b/work/coordination-change-risk-mitigation/artifacts/completion-receipts-github.test-report.xml new file mode 100644 index 000000000..67138c869 --- /dev/null +++ b/work/coordination-change-risk-mitigation/artifacts/completion-receipts-github.test-report.xml @@ -0,0 +1,4024 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + [xUnit.net 00:00:00.00] xUnit.net VSTest Adapter v3.1.5+1b188a7b0a (64-bit .NET 10.0.10) +[xUnit.net 00:00:00.07] Discovering: FS.GG.Coord.GitHub.Tests +[xUnit.net 00:00:00.13] Discovered: FS.GG.Coord.GitHub.Tests +[xUnit.net 00:00:00.17] Starting: FS.GG.Coord.GitHub.Tests +[xUnit.net 00:00:02.33] Finished: FS.GG.Coord.GitHub.Tests + + + + \ No newline at end of file diff --git a/work/coordination-change-risk-mitigation/artifacts/completion-receipts-kernel.test-report.xml b/work/coordination-change-risk-mitigation/artifacts/completion-receipts-kernel.test-report.xml new file mode 100644 index 000000000..af5bc63a9 --- /dev/null +++ b/work/coordination-change-risk-mitigation/artifacts/completion-receipts-kernel.test-report.xml @@ -0,0 +1,1120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + [xUnit.net 00:00:00.00] xUnit.net VSTest Adapter v3.1.5+1b188a7b0a (64-bit .NET 10.0.10) +[xUnit.net 00:00:00.06] Discovering: FS.GG.Coord.Cli.Kernel.Tests +[xUnit.net 00:00:00.11] Discovered: FS.GG.Coord.Cli.Kernel.Tests +[xUnit.net 00:00:00.14] Starting: FS.GG.Coord.Cli.Kernel.Tests +[xUnit.net 00:00:00.36] Finished: FS.GG.Coord.Cli.Kernel.Tests + + + + \ No newline at end of file diff --git a/work/coordination-change-risk-mitigation/artifacts/final-shim-parity.junit.xml b/work/coordination-change-risk-mitigation/artifacts/final-shim-parity.junit.xml new file mode 100644 index 000000000..4c0e1cc9f --- /dev/null +++ b/work/coordination-change-risk-mitigation/artifacts/final-shim-parity.junit.xml @@ -0,0 +1,90 @@ + diff --git a/work/coordination-change-risk-mitigation/artifacts/lifecycle-decisions-cli.test-report.xml b/work/coordination-change-risk-mitigation/artifacts/lifecycle-decisions-cli.test-report.xml new file mode 100644 index 000000000..cbdabc2aa --- /dev/null +++ b/work/coordination-change-risk-mitigation/artifacts/lifecycle-decisions-cli.test-report.xml @@ -0,0 +1,3222 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + [xUnit.net 00:00:00.00] xUnit.net VSTest Adapter v3.1.5+1b188a7b0a (64-bit .NET 10.0.10) +[xUnit.net 00:00:00.06] Discovering: FS.GG.Coord.Cli.Tests +[xUnit.net 00:00:00.11] Discovered: FS.GG.Coord.Cli.Tests +[xUnit.net 00:00:00.14] Starting: FS.GG.Coord.Cli.Tests +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1620-fc1b2460a2084912ab1637a1365868b1 — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +STOLE FS.GG.SDD#42 from worker 'snipe-f893' (--force) +fsgg-coord-engine: post-claim Status readback FAILED for FS.GG.SDD#42: not found: the fixture serves no board WRITE — the lock is what is under test. The server said so — this is an absence, not a failed read. +fsgg-coord-engine: the Status board write for FS.GG.SDD#42 was WITHHELD — the item's open-PR probe could not be completed. The lock IS held; the column is UNCHANGED, because a column derived from a fact this process could not read would be an invention. Re-run `claim FS.GG.SDD#42 --json` once the read recovers, or repair the column with `reconcile --apply`. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1620-12d3ee3a525543c98896711ff89fb3a3 — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +STOLE FS.GG.SDD#42 from worker 'snipe-f893' (--force) +fsgg-coord-engine: post-claim Status readback FAILED for FS.GG.SDD#42: not found: the fixture serves no board WRITE — the lock is what is under test. The server said so — this is an absence, not a failed read. +fsgg-coord-engine: the Status board write for FS.GG.SDD#42 was WITHHELD — the item's open-PR probe could not be completed. The lock IS held; the column is UNCHANGED, because a column derived from a fact this process could not read would be an invention. Re-run `claim FS.GG.SDD#42 --json` once the read recovers, or repair the column with `reconcile --apply`. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1620-111453647dde4f12bad7e860111e27c0 — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: post-claim Status readback FAILED for FS.GG.SDD#42: not found: the fixture serves no board WRITE — the lock is what is under test. The server said so — this is an absence, not a failed read. +fsgg-coord-engine: the Status board write for FS.GG.SDD#42 was WITHHELD — the item's open-PR probe could not be completed. The lock IS held; the column is UNCHANGED, because a column derived from a fact this process could not read would be an invention. Re-run `claim FS.GG.SDD#42 --json` once the read recovers, or repair the column with `reconcile --apply`. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1620-e89eb916b9c34b34ae5c2fe1b56372ce — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: FS.GG.SDD#42 carries a live marker with YOUR worker id 'vole-418' but a DIFFERENT session (79b9e347) — two workers share one id (#419). Adopting it would put both of you on this item, which is the double-claim ADR-0027 exists to prevent. + Mint a fresh, unique id in THIS shell (do NOT invent one): eval "$(scripts/fsgg-coord whoami --mint)" +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1620-8a6b38346f714877b2226f0b6ecbd5c8 — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: FS.GG.SDD#42 is already held by snipe-f893 — you did not get it. Wait for the lease to lapse, or work whatever `take` offers instead; `take` advances through its own ranked candidates on a lost race, so no caller re-runs it to retry (.github#2683). + Widen the touch-set (scripts/fsgg-coord widen), or split the PR. + Fix the PR body now — this is unrecoverable once the PR is merged (editing a merged PR's body does not replay the close, .github#2107). + Fix the PR body now — this is unrecoverable once the PR is merged (editing a merged PR's body does not replay the close, .github#2107). +fsgg-coord-engine: landable: evaluated the host review-acceptance assertion (`fsgg:review-decision/v2`) for PR #801. +fsgg-coord-engine: landable: evaluated the host review-acceptance assertion (`fsgg:review-decision/v2`) for PR #801. +fsgg-coord-engine: landable: PR #801 is not landable — PR #801 carries no valid host review-acceptance marker (`fsgg:review-decision/v2`) — the review chain is absent, incomplete, or malformed. +fsgg-coord-engine: These are assertions you asked for, and an unmet one is `pending`, never `green` — an ABSENT check reads exactly like a passing one to any 'is anything red?' rollup (#606). Usually transient (registration, a superseded suite's replacement, GitHub catching up with a force-push). If it never resolves: the job was RENAMED, its workflow's `paths:` filter no longer matches, or --sha named the wrong commit. +fsgg-coord-engine: landable: PR #801 is ALREADY MERGED — there is nothing to gate, and --wait does not poll it. +fsgg-coord-engine: This is a TERMINAL verdict, not a retry. If you are recovering an item whose worker died between merge and stamp, the work LANDED — go stamp it: scripts/fsgg-coord done <ref> --flip --pr 801 +fsgg-coord-engine: landable: PR #801 is ALREADY MERGED — there is nothing to gate, and --wait does not poll it. +fsgg-coord-engine: This is a TERMINAL verdict, not a retry. If you are recovering an item whose worker died between merge and stamp, the work LANDED — go stamp it: scripts/fsgg-coord done <ref> --flip --pr 801 +fsgg-coord-engine: landable: PR #801 is ALREADY MERGED — there is nothing to gate, and --wait does not poll it. +fsgg-coord-engine: This is a TERMINAL verdict, not a retry. If you are recovering an item whose worker died between merge and stamp, the work LANDED — go stamp it: scripts/fsgg-coord done <ref> --flip --pr 801 +fsgg-coord-engine: landable: evaluated the host review-acceptance assertion (`fsgg:review-decision/v2`) for PR #801. +fsgg-coord-engine: landable: PR #801 is not landable — PR #801's host review-acceptance marker is bound to head `bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb`, not the current head `aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa` — a stale-sha marker is treated as ABSENT, never as satisfaction. +fsgg-coord-engine: These are assertions you asked for, and an unmet one is `pending`, never `green` — an ABSENT check reads exactly like a passing one to any 'is anything red?' rollup (#606). Usually transient (registration, a superseded suite's replacement, GitHub catching up with a force-push). If it never resolves: the job was RENAMED, its workflow's `paths:` filter no longer matches, or --sha named the wrong commit. +fsgg-coord-engine: landable: PR #801 is CLOSED WITHOUT MERGING — nothing landed, so there is nothing to gate. +fsgg-coord-engine: Terminal, and NOT the merged case: do NOT stamp the item done. The branch was abandoned or the PR rejected, so the item needs re-working or releasing. +considered 1 candidate(s) — this is a measured count, not an assumption. + .github#398 — the issue is closed (the board column says Done; /check-board reconciles it) +wave occupancy: {"activeItems":0,"waveCapacity":6,"openSlots":6} +fsgg-coord-engine: delivery-route: recording sdd-required ahead of its SDD package (sdd readiness workId does not match 'substituted-2298') — the claimed worker owns producing it before touching Paths. +fsgg-coord-engine: delivery-route: only structured v2 records may be written: revision is required; scope is required; dependencies is required; touchSet is required; policyVersion is required; digest is required +fsgg-coord-engine: delivery-route: recording sdd-required ahead of its SDD package (sdd readiness status is not implementationReady) — the claimed worker owns producing it before touching Paths. +{"kind":"error","exitCode":1,"message":"malformed response reading FS-GG/FS.GG.SDD#42: delivery route is not current: structured route ledger is missing. That is a FAILED READ, not an empty answer \u2014 refusing to decide from it.","rateLimit":null} +fsgg-coord-engine: malformed response reading FS-GG/FS.GG.SDD#42: structured route ledger is missing. That is a FAILED READ, not an empty answer — refusing to decide from it. +{"kind":"error","exitCode":1,"message":"malformed response reading FS-GG/FS.GG.SDD#42: delivery route is not current: structured route ledger is missing. That is a FAILED READ, not an empty answer \u2014 refusing to decide from it.","rateLimit":null} +fsgg-coord-engine: delivery-route: recording sdd-required ahead of its SDD package (sdd spec does not exist: work/no-package-2298/spec.md; sdd readiness evidence does not exist: /tmp/fsgg-2298-f0204e896dc44765b7ee1675f3aeef27/readiness/no-package-2298/analysis.json) — the claimed worker owns producing it before touching Paths. +{"kind":"error","exitCode":1,"message":"malformed response reading FS-GG/FS.GG.SDD#42: delivery route is not current: revision is required; scope is required; dependencies is required; touchSet is required; policyVersion is required; route is required; agent is required; timestamp is required; reasonCodes is required; rationale is required; requiredGates is required; digest is required. That is a FAILED READ, not an empty answer \u2014 refusing to decide from it.","rateLimit":null} +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-2351-7f5af0bc65e24f4889a7663be1391c86 — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-2351-9157673423354e8b8ad90370d89e748c — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-2351-db8d10320ad246d28743946dda59be5b — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-2351-32bd7c8e42aa4b668e31e8a352e2af1b — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: comment: source file does not exist: /tmp/26331524940d44338999697adeff9ff6/missing.md +[xUnit.net 00:00:02.01] Finished: FS.GG.Coord.Cli.Tests + + + + \ No newline at end of file diff --git a/work/coordination-change-risk-mitigation/artifacts/lifecycle-decisions-core.test-report.xml b/work/coordination-change-risk-mitigation/artifacts/lifecycle-decisions-core.test-report.xml new file mode 100644 index 000000000..621ea2545 --- /dev/null +++ b/work/coordination-change-risk-mitigation/artifacts/lifecycle-decisions-core.test-report.xml @@ -0,0 +1,5508 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Ok, passed 100 tests. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Ok, passed 100 tests. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + [xUnit.net 00:00:00.00] xUnit.net VSTest Adapter v3.1.5+1b188a7b0a (64-bit .NET 10.0.10) +[xUnit.net 00:00:00.05] Discovering: FS.GG.Coord.Core.Tests +[xUnit.net 00:00:00.10] Discovered: FS.GG.Coord.Core.Tests +[xUnit.net 00:00:00.14] Starting: FS.GG.Coord.Core.Tests +[xUnit.net 00:00:00.45] Finished: FS.GG.Coord.Core.Tests + + + + \ No newline at end of file diff --git a/work/coordination-change-risk-mitigation/artifacts/lifecycle-model-core.test-report.xml b/work/coordination-change-risk-mitigation/artifacts/lifecycle-model-core.test-report.xml new file mode 100644 index 000000000..d7c6cd234 --- /dev/null +++ b/work/coordination-change-risk-mitigation/artifacts/lifecycle-model-core.test-report.xml @@ -0,0 +1,5532 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Ok, passed 100 tests. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Ok, passed 100 tests. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + [xUnit.net 00:00:00.00] xUnit.net VSTest Adapter v3.1.5+1b188a7b0a (64-bit .NET 10.0.10) +[xUnit.net 00:00:00.05] Discovering: FS.GG.Coord.Core.Tests +[xUnit.net 00:00:00.11] Discovered: FS.GG.Coord.Core.Tests +[xUnit.net 00:00:00.15] Starting: FS.GG.Coord.Core.Tests +[xUnit.net 00:00:02.00] Finished: FS.GG.Coord.Core.Tests + + + + \ No newline at end of file diff --git a/work/coordination-change-risk-mitigation/artifacts/release-recovery.junit.xml b/work/coordination-change-risk-mitigation/artifacts/release-recovery.junit.xml new file mode 100644 index 000000000..a2f077562 --- /dev/null +++ b/work/coordination-change-risk-mitigation/artifacts/release-recovery.junit.xml @@ -0,0 +1,45 @@ + diff --git a/work/coordination-change-risk-mitigation/artifacts/self-host-boardops.test-report.xml b/work/coordination-change-risk-mitigation/artifacts/self-host-boardops.test-report.xml new file mode 100644 index 000000000..c5b3eb9f4 --- /dev/null +++ b/work/coordination-change-risk-mitigation/artifacts/self-host-boardops.test-report.xml @@ -0,0 +1,1710 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + [xUnit.net 00:00:00.00] xUnit.net VSTest Adapter v3.1.5+1b188a7b0a (64-bit .NET 10.0.10) +[xUnit.net 00:00:00.05] Discovering: FS.GG.Coord.Cli.BoardOps.Tests +[xUnit.net 00:00:00.09] Discovered: FS.GG.Coord.Cli.BoardOps.Tests +[xUnit.net 00:00:00.12] Starting: FS.GG.Coord.Cli.BoardOps.Tests +fsgg-coord-engine: not found: stop after reuse binding. The server said so — this is an absence, not a failed read. +fsgg-coord-engine: not found: stop after intent recovery. The server said so — this is an absence, not a failed read. +fsgg-coord-engine: not found: interrupted after persisted create. The server said so — this is an absence, not a failed read. +fsgg-coord-engine: not found: stop after recovered receipt. The server said so — this is an absence, not a failed read. +fsgg-coord-engine: malformed response reading tx-2134: a duplicate candidate matches the title; select reuse or revise the draft. That is a FAILED READ, not an empty answer — refusing to decide from it. +fsgg-coord-engine: malformed response reading tx-2134: a duplicate candidate matches the title; select reuse or revise the draft. That is a FAILED READ, not an empty answer — refusing to decide from it. +fsgg-coord-engine: malformed response reading ready-2134: Ready is refused while the reused/live issue still declares a dependency or human choice. That is a FAILED READ, not an empty answer — refusing to decide from it. +fsgg-coord-engine: malformed response reading blocked-2134: Blocked dependency FS-GG/.github#42 is already resolved. That is a FAILED READ, not an empty answer — refusing to decide from it. +{"schema":"fsgg.coord.intake-result/v1","kind":"applied","draftId":"tx-2134","issue":"FS-GG/.github#77","issueUrl":"https://github.com/FS-GG/.github/issues/77","dedupeDisposition":"create","board":{"owner":"FS-GG","title":"Coordination","number":1,"id":"PVT"},"status":"Backlog","fields":["Status","Class"],"projectionFresh":true,"pendingWrites":0,"judgementQuestion":null} +{"schema":"fsgg.coord.intake-result/v1","kind":"applied","draftId":"tx-2134","issue":"FS-GG/.github#77","issueUrl":"https://github.com/FS-GG/.github/issues/77","dedupeDisposition":"create","board":{"owner":"FS-GG","title":"Coordination","number":1,"id":"PVT"},"status":"Backlog","fields":["Status","Class"],"projectionFresh":true,"pendingWrites":0,"judgementQuestion":null} +fsgg-coord-engine: malformed response reading tx-2134: a duplicate candidate matches the title; select reuse or revise the draft. That is a FAILED READ, not an empty answer — refusing to decide from it. +fsgg-coord-engine: malformed response reading tx-2134: intake receipt '/tmp/fsgg-intake-900c2eed0fa04fe3ae2208bbf055fe21/intake-tx-2134.json' is unreadable: 'not-json' is an invalid JSON literal. Expected the literal 'null'. LineNumber: 0 | BytePositionInLine: 1.. That is a FAILED READ, not an empty answer — refusing to decide from it. +fsgg-coord-engine: malformed response reading tx-2134: intake receipt '/tmp/fsgg-intake-900c2eed0fa04fe3ae2208bbf055fe21/intake-tx-2134.json' is unreadable: The given key was not present in the dictionary.. That is a FAILED READ, not an empty answer — refusing to decide from it. +paths paths do not exist in target repository FS-GG/.github: definitely/not/a/live/path-2134 +fsgg-coord-engine: not found: stop after receipt recovery. The server said so — this is an absence, not a failed read. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1517-fb59fb7703c94f6b8f305e23de867abc — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1517-fb59fb7703c94f6b8f305e23de867abc — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +OVERLAP — now collides with FS.GG.SDD#75 (worker otter-9c21) + src/Shared.fs + notified worker otter-9c21 on FS.GG.SDD#75 +fsgg-coord-engine: the updated touch-set COLLIDES with a live claim (this command may or may not be what introduced it) — do NOT keep editing the shared paths until it is resolved. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1517-423c93221bb242e4b8e68525da006fc8 — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1517-423c93221bb242e4b8e68525da006fc8 — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +OVERLAP — now collides with FS.GG.SDD#75 (worker otter-9c21) + src/Shared.fs + notified worker otter-9c21 on FS.GG.SDD#75 +fsgg-coord-engine: the updated touch-set COLLIDES with a live claim (this command may or may not be what introduced it) — do NOT keep editing the shared paths until it is resolved. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1517-b5ab2c998bca4f079bf99cd63b245012 — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1517-b5ab2c998bca4f079bf99cd63b245012 — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1517-91c08f7b02834bd5aacce16e1300bf66 — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1517-91c08f7b02834bd5aacce16e1300bf66 — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1517-873c485893b54ea48580910add4969c4 — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1517-873c485893b54ea48580910add4969c4 — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +OVERLAP — now collides with FS.GG.SDD#75 (worker otter-9c21) + src/Shared.fs + notified worker otter-9c21 on FS.GG.SDD#75 +fsgg-coord-engine: the updated touch-set COLLIDES with a live claim (this command may or may not be what introduced it) — do NOT keep editing the shared paths until it is resolved. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1517-5a2db8319b4245eeb671700c83a74cc1 — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1517-5a2db8319b4245eeb671700c83a74cc1 — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +OVERLAP — now collides with FS.GG.SDD#75 (worker otter-9c21) + src/Shared.fs + notified worker otter-9c21 on FS.GG.SDD#75 +fsgg-coord-engine: the updated touch-set COLLIDES with a live claim (this command may or may not be what introduced it) — do NOT keep editing the shared paths until it is resolved. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1517-77a5b81e72a74316b931d072eb509ac8 — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1517-77a5b81e72a74316b931d072eb509ac8 — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +OVERLAP — now collides with FS.GG.SDD#75 (worker otter-9c21) + src/Shared.fs + notified worker otter-9c21 on FS.GG.SDD#75 +fsgg-coord-engine: the updated touch-set COLLIDES with a live claim (this command may or may not be what introduced it) — do NOT keep editing the shared paths until it is resolved. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1517-e441adff475c4a3d896ed17ebb231433 — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1517-e441adff475c4a3d896ed17ebb231433 — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +OVERLAP — now collides with FS.GG.SDD#75 (worker otter-9c21) + src/Shared.fs + notified worker otter-9c21 on FS.GG.SDD#75 +fsgg-coord-engine: the updated touch-set COLLIDES with a live claim (this command may or may not be what introduced it) — do NOT keep editing the shared paths until it is resolved. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1517-9b39d3e6d0844d3fbb3fd21a3bed807f — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1517-9b39d3e6d0844d3fbb3fd21a3bed807f — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +OVERLAP — now collides with FS.GG.SDD#75 (worker otter-9c21) + src/Shared.fs + notified worker otter-9c21 on FS.GG.SDD#75 +fsgg-coord-engine: the updated touch-set COLLIDES with a live claim (this command may or may not be what introduced it) — do NOT keep editing the shared paths until it is resolved. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1517-b99789100a22431ba30b7d56e5e1f33d — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1517-b99789100a22431ba30b7d56e5e1f33d — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +OVERLAP — now collides with FS.GG.SDD#75 (worker otter-9c21) + src/Shared.fs + notified worker otter-9c21 on FS.GG.SDD#75 +fsgg-coord-engine: the updated touch-set COLLIDES with a live claim (this command may or may not be what introduced it) — do NOT keep editing the shared paths until it is resolved. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1517-6434bb0e459a43d5b3efef7b74ffb578 — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1517-6434bb0e459a43d5b3efef7b74ffb578 — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +OVERLAP — now collides with FS.GG.SDD#75 (worker otter-9c21) + src/Shared.fs + notified worker otter-9c21 on FS.GG.SDD#75 +fsgg-coord-engine: the updated touch-set COLLIDES with a live claim (this command may or may not be what introduced it) — do NOT keep editing the shared paths until it is resolved. +fsgg-coord-engine: vole-418 does not hold FS.GG.SDD#42 — nothing to release. +fsgg-coord-engine: Status=Blocked refuses an incoherent park (.github#2079). +fsgg-coord-engine: set-field --batch refuses: this call clears 'Blocked by' in the SAME batch as 'Status=Blocked' — the row would land with an EMPTY field and no 'Blocked on: human/...' sentinel (.github#2079). Pair 'Status=Blocked' with a non-empty 'Blocked by=<refs>' instead, or record a human park first: add a body line 'Blocked on: human/decision' or 'Blocked on: human/action'. Nothing written. +fsgg-coord-engine: set-field --batch refuses: this call clears 'Blocked by' in the SAME batch as 'Status=Blocked' — the row would land with an EMPTY field and no 'Blocked on: human/...' sentinel (.github#2079). Pair 'Status=Blocked' with a non-empty 'Blocked by=<refs>' instead, or record a human park first: add a body line 'Blocked on: human/decision' or 'Blocked on: human/action'. Nothing written. +fsgg-coord-engine: Status=Blocked refuses an incoherent park (.github#2079). +fsgg-coord-engine: vole-418 does not hold FS.GG.SDD#42 — nothing to release. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1740-d7c9b10375fc49c1b1469751043662ad — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +considered 3 candidate(s) — this is a measured count, not an assumption. + FS.GG.SDD#74 — Status is In progress + FS.GG.SDD#75 — Status is Blocked + FS.GG.SDD#76 — overlaps in-flight work held by otter-9c21 on FS.GG.SDD#75 (lease EXPIRED — reapable): src/Shared.fs ⇄ src/Shared.fs +this queue is BUSY, not empty. +1 item(s) are QUEUED BEHIND LIVE CLAIMS held by: otter-9c21 + soonest: lease EXPIRED — reapable + 1 of those lease(s) have EXPIRED — collect them: scripts/fsgg-coord reap --repo FS.GG.SDD --apply +wave occupancy: unavailable (no drive-board or work-board host-loop document exists) +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1740-31d282de44d947d68331c6548ea13569 — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1740-31d282de44d947d68331c6548ea13569 — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +OVERLAP — now collides with FS.GG.SDD#75 (worker otter-9c21) + src/Shared.fs + notified worker otter-9c21 on FS.GG.SDD#75 +fsgg-coord-engine: the updated touch-set COLLIDES with a live claim (this command may or may not be what introduced it) — do NOT keep editing the shared paths until it is resolved. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1740-ad97e966335b47289f76c9736c9bcf85 — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1740-ad97e966335b47289f76c9736c9bcf85 — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1517-a0c6edf9dbab497089c15d6efdfc624f — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1517-a0c6edf9dbab497089c15d6efdfc624f — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1740-2b1d3b7b84a7402abdef77bafb8db2f1 — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1740-2b1d3b7b84a7402abdef77bafb8db2f1 — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +OVERLAP — now collides with FS.GG.SDD#75 (worker otter-9c21) + src/Shared.fs + notified worker otter-9c21 on FS.GG.SDD#75 +fsgg-coord-engine: the updated touch-set COLLIDES with a live claim (this command may or may not be what introduced it) — do NOT keep editing the shared paths until it is resolved. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1740-9669ae2a03a2450ab65f3d8ee310e08f — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +considered 3 candidate(s) — this is a measured count, not an assumption. + FS.GG.SDD#74 — Status is In progress + FS.GG.SDD#75 — Status is In progress + FS.GG.SDD#76 — overlaps FS.GG.SDD#75, which the board says is In progress with NO claim marker (someone is working outside the protocol — there is no lease to wait out; see: scripts/fsgg-coord who): src/Shared.fs ⇄ src/Shared.fs +wave occupancy: unavailable (no drive-board or work-board host-loop document exists) +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1740-9b36236913864312846a655edec748e8 — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1740-9b36236913864312846a655edec748e8 — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1740-525ab0dd22204681926bbc674877879a — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1740-525ab0dd22204681926bbc674877879a — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +OVERLAP — now collides with FS.GG.SDD#75 (worker otter-9c21) + src/Shared.fs + notified worker otter-9c21 on FS.GG.SDD#75 +fsgg-coord-engine: the updated touch-set COLLIDES with a live claim (this command may or may not be what introduced it) — do NOT keep editing the shared paths until it is resolved. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1740-0f3212b5ab424a4eabd12f722e4dbd79 — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1740-0f3212b5ab424a4eabd12f722e4dbd79 — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +OVERLAP — now collides with FS.GG.SDD#75 (worker otter-9c21) + src/Shared.fs + notified worker otter-9c21 on FS.GG.SDD#75 +fsgg-coord-engine: the updated touch-set COLLIDES with a live claim (this command may or may not be what introduced it) — do NOT keep editing the shared paths until it is resolved. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1740-3da6addfe6004e54ab0f2aced4219821 — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1740-3da6addfe6004e54ab0f2aced4219821 — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +OVERLAP — now collides with FS.GG.SDD#75 (worker otter-9c21) + src/Shared.fs + notified worker otter-9c21 on FS.GG.SDD#75 +fsgg-coord-engine: the updated touch-set COLLIDES with a live claim (this command may or may not be what introduced it) — do NOT keep editing the shared paths until it is resolved. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1740-67560e641c3748e599bd9ea34ed9fc7b — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1740-67560e641c3748e599bd9ea34ed9fc7b — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +OVERLAP — now collides with FS.GG.SDD#75 (worker otter-9c21) + src/Shared.fs + notified worker otter-9c21 on FS.GG.SDD#75 +fsgg-coord-engine: the updated touch-set COLLIDES with a live claim (this command may or may not be what introduced it) — do NOT keep editing the shared paths until it is resolved. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1740-2fa308f933134243bbba67fe64eaec4c — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1740-2fa308f933134243bbba67fe64eaec4c — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +OVERLAP — now collides with FS.GG.SDD#75 (worker otter-9c21) + src/Shared.fs + notified worker otter-9c21 on FS.GG.SDD#75 +fsgg-coord-engine: the updated touch-set COLLIDES with a live claim (this command may or may not be what introduced it) — do NOT keep editing the shared paths until it is resolved. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1740-66e0f19683bd49ceb28f4d0d267ee58b — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1740-66e0f19683bd49ceb28f4d0d267ee58b — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +OVERLAP — now collides with FS.GG.SDD#75 (worker otter-9c21) + src/Shared.fs + notified worker otter-9c21 on FS.GG.SDD#75 +fsgg-coord-engine: the updated touch-set COLLIDES with a live claim (this command may or may not be what introduced it) — do NOT keep editing the shared paths until it is resolved. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1517-0b904a5740d441eb8dd7e99d4f5cdce9 — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1517-0b904a5740d441eb8dd7e99d4f5cdce9 — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1517-84938c3b345947efa65ba40a5e5649a7 — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1517-84938c3b345947efa65ba40a5e5649a7 — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1517-bf653916ed5a479db404715c77e0c12c — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1517-bf653916ed5a479db404715c77e0c12c — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +OVERLAP — now collides with FS.GG.SDD#75 (worker otter-9c21) + src/Shared.fs + notified worker otter-9c21 on FS.GG.SDD#75 +fsgg-coord-engine: the updated touch-set COLLIDES with a live claim (this command may or may not be what introduced it) — do NOT keep editing the shared paths until it is resolved. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1517-b2d6ffba84e74ce6b68beba492b32e72 — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1517-b2d6ffba84e74ce6b68beba492b32e72 — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +OVERLAP — now collides with FS.GG.SDD#75 (worker otter-9c21) + src/Shared.fs + notified worker otter-9c21 on FS.GG.SDD#75 +fsgg-coord-engine: the updated touch-set COLLIDES with a live claim (this command may or may not be what introduced it) — do NOT keep editing the shared paths until it is resolved. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1517-8423c835fdac46a2bdc841701cb7ea03 — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1517-8423c835fdac46a2bdc841701cb7ea03 — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1517-bd4a271e886f4c6791868a077844cd5c — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1517-bd4a271e886f4c6791868a077844cd5c — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1740-99a3dbd55cdc487981cf577078b1a13c — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1740-99a3dbd55cdc487981cf577078b1a13c — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +OVERLAP — now collides with FS.GG.SDD#75 (worker otter-9c21) + src/Shared.fs + notified worker otter-9c21 on FS.GG.SDD#75 +fsgg-coord-engine: the updated touch-set COLLIDES with a live claim (this command may or may not be what introduced it) — do NOT keep editing the shared paths until it is resolved. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1740-2cf49ceacb8545fb87aada3bb5320fb6 — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1740-2cf49ceacb8545fb87aada3bb5320fb6 — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1740-021ea175baa043d891cae8b853e5ed78 — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1740-021ea175baa043d891cae8b853e5ed78 — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +OVERLAP — now collides with FS.GG.SDD#75 (worker otter-9c21) + src/Shared.fs + notified worker otter-9c21 on FS.GG.SDD#75 +fsgg-coord-engine: the updated touch-set COLLIDES with a live claim (this command may or may not be what introduced it) — do NOT keep editing the shared paths until it is resolved. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1740-bd5f39b87dc842cbace9632b559629d6 — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1740-bd5f39b87dc842cbace9632b559629d6 — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +OVERLAP — now collides with FS.GG.SDD#75 (worker otter-9c21) + src/Shared.fs + notified worker otter-9c21 on FS.GG.SDD#75 +fsgg-coord-engine: the updated touch-set COLLIDES with a live claim (this command may or may not be what introduced it) — do NOT keep editing the shared paths until it is resolved. +LIVE-CLAIM: worker ghost-777, FS.GG.SDD#42 is open and claimed by other-123; queue retained. +UNKNOWN: could not record disposition for FS.GG.SDD#42: not found: the notice could not be posted. The server said so — this is an absence, not a failed read.. Queue retained. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1740-df08f418fbd64d8284a6d931d70b5ca0 — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1740-df08f418fbd64d8284a6d931d70b5ca0 — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1517-529b116cada348289a12b94562c1a014 — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1517-529b116cada348289a12b94562c1a014 — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1517-199c887fccb34c7285f3ec8ad8a656fb — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1517-199c887fccb34c7285f3ec8ad8a656fb — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1740-2db3a29ab9af4f91a9f6ea54b70b5b3d — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +considered 3 candidate(s) — this is a measured count, not an assumption. + FS.GG.SDD#74 — Status is In progress + FS.GG.SDD#75 — the issue is closed (the board column says In review; /check-board reconciles it) + FS.GG.SDD#76 — overlaps in-flight work held by curlew-8afd on FS.GG.SDD#75 (lease frees in ~120m): src/Shared.fs ⇄ src/Shared.fs +this queue is BUSY, not empty. +1 item(s) are QUEUED BEHIND LIVE CLAIMS held by: curlew-8afd + soonest: lease frees in ~120m +wave occupancy: unavailable (no drive-board or work-board host-loop document exists) +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1740-e488634b62b4448ebd5ddd62a429b0bd — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1740-e488634b62b4448ebd5ddd62a429b0bd — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +OVERLAP — now collides with FS.GG.SDD#75 (worker curlew-8afd) + src/Shared.fs + notified worker curlew-8afd on FS.GG.SDD#75 +fsgg-coord-engine: the updated touch-set COLLIDES with a live claim (this command may or may not be what introduced it) — do NOT keep editing the shared paths until it is resolved. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1517-eb78828dbfbc4f658ddd0f0a172b091e — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1517-eb78828dbfbc4f658ddd0f0a172b091e — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +OVERLAP — now collides with FS.GG.SDD#75 (worker otter-9c21) + src/Shared.fs + notified worker otter-9c21 on FS.GG.SDD#75 +fsgg-coord-engine: the updated touch-set COLLIDES with a live claim (this command may or may not be what introduced it) — do NOT keep editing the shared paths until it is resolved. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1517-812b152e682c4531b721280d23003d49 — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1517-812b152e682c4531b721280d23003d49 — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +OVERLAP — now collides with FS.GG.SDD#75 (worker otter-9c21) + src/Shared.fs + notified worker otter-9c21 on FS.GG.SDD#75 +fsgg-coord-engine: the updated touch-set COLLIDES with a live claim (this command may or may not be what introduced it) — do NOT keep editing the shared paths until it is resolved. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1517-2fbc60c7ac834a48a6336ad4f315b1dc — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1517-2fbc60c7ac834a48a6336ad4f315b1dc — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +OVERLAP — now collides with FS.GG.SDD#75 (worker otter-9c21) + src/Shared.fs + notified worker otter-9c21 on FS.GG.SDD#75 +fsgg-coord-engine: the updated touch-set COLLIDES with a live claim (this command may or may not be what introduced it) — do NOT keep editing the shared paths until it is resolved. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1517-70aa5b8ad38148febdd2dfff6d0909df — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1517-70aa5b8ad38148febdd2dfff6d0909df — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +OVERLAP — now collides with FS.GG.SDD#75 (worker otter-9c21) + src/Shared.fs + could NOT notify worker otter-9c21 on FS.GG.SDD#75: not found: the notice could not be posted. The server said so — this is an absence, not a failed read. +fsgg-coord-engine: the updated touch-set COLLIDES with a live claim (this command may or may not be what introduced it) — do NOT keep editing the shared paths until it is resolved. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1517-4410c322aac042678957c88c40e976cd — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1517-4410c322aac042678957c88c40e976cd — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +OVERLAP — now collides with FS.GG.SDD#75 (worker otter-9c21) + src/Shared.fs + could NOT notify worker otter-9c21 on FS.GG.SDD#75: not found: the notice could not be posted. The server said so — this is an absence, not a failed read. +fsgg-coord-engine: the updated touch-set COLLIDES with a live claim (this command may or may not be what introduced it) — do NOT keep editing the shared paths until it is resolved. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1740-a5d7be5cfed349248dd4fc9e3e9e4405 — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1740-a5d7be5cfed349248dd4fc9e3e9e4405 — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +OVERLAP — now collides with FS.GG.SDD#75 (worker otter-9c21) + src/Shared.fs + notified worker otter-9c21 on FS.GG.SDD#75 +fsgg-coord-engine: the updated touch-set COLLIDES with a live claim (this command may or may not be what introduced it) — do NOT keep editing the shared paths until it is resolved. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1740-4b6d2fb130ef4350b72ab61200857d4d — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1740-4b6d2fb130ef4350b72ab61200857d4d — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +OVERLAP — now collides with FS.GG.SDD#75 (worker otter-9c21) + src/Shared.fs + notified worker otter-9c21 on FS.GG.SDD#75 +fsgg-coord-engine: the updated touch-set COLLIDES with a live claim (this command may or may not be what introduced it) — do NOT keep editing the shared paths until it is resolved. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1740-a854496a7d004832b82baae60b61c132 — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. + FS.GG.SDD#74 — Status is In progress + FS.GG.SDD#75 — Status is Blocked +wave occupancy: unavailable (no drive-board or work-board host-loop document exists) +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1740-1bda9c0bda97431bb5a54eda2e7dd784 — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1740-1bda9c0bda97431bb5a54eda2e7dd784 — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1740-f64b68a9a9534c6885909d3b44726c40 — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1740-f64b68a9a9534c6885909d3b44726c40 — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1740-1a6b143cc3cc42ceb80c828e141f81e7 — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1740-1a6b143cc3cc42ceb80c828e141f81e7 — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +OVERLAP — now collides with FS.GG.SDD#75 (worker otter-9c21) + src/Shared.fs + notified worker otter-9c21 on FS.GG.SDD#75 +fsgg-coord-engine: the updated touch-set COLLIDES with a live claim (this command may or may not be what introduced it) — do NOT keep editing the shared paths until it is resolved. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1740-0b577c9903ec4055abfb4d125da914bb — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1740-0b577c9903ec4055abfb4d125da914bb — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1740-88c6b97ab6ae4fec9bc24ecc8b988e8f — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1740-88c6b97ab6ae4fec9bc24ecc8b988e8f — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1740-88c6b97ab6ae4fec9bc24ecc8b988e8f — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1740-88c6b97ab6ae4fec9bc24ecc8b988e8f — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +OVERLAP — now collides with FS.GG.SDD#75 (worker otter-9c21) + src/Shared.fs + notified worker otter-9c21 on FS.GG.SDD#75 +fsgg-coord-engine: the updated touch-set COLLIDES with a live claim (this command may or may not be what introduced it) — do NOT keep editing the shared paths until it is resolved. +[xUnit.net 00:00:01.31] Finished: FS.GG.Coord.Cli.BoardOps.Tests + + + + \ No newline at end of file diff --git a/work/coordination-change-risk-mitigation/artifacts/self-host-cli.test-report.xml b/work/coordination-change-risk-mitigation/artifacts/self-host-cli.test-report.xml new file mode 100644 index 000000000..95c858e2e --- /dev/null +++ b/work/coordination-change-risk-mitigation/artifacts/self-host-cli.test-report.xml @@ -0,0 +1,3292 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + [xUnit.net 00:00:00.00] xUnit.net VSTest Adapter v3.1.5+1b188a7b0a (64-bit .NET 10.0.10) +[xUnit.net 00:00:00.06] Discovering: FS.GG.Coord.Cli.Tests +[xUnit.net 00:00:00.11] Discovered: FS.GG.Coord.Cli.Tests +[xUnit.net 00:00:00.14] Starting: FS.GG.Coord.Cli.Tests +considered 1 candidate(s) — this is a measured count, not an assumption. + .github#398 — the issue is closed (the board column says Done; /check-board reconciles it) +wave occupancy: {"activeItems":0,"waveCapacity":6,"openSlots":6} +fsgg-coord-engine: landable: evaluated the host review-acceptance assertion (`fsgg:review-decision/v2`) for PR #801. +fsgg-coord-engine: landable: evaluated the host review-acceptance assertion (`fsgg:review-decision/v2`) for PR #801. +fsgg-coord-engine: landable: PR #801 is not landable — PR #801 carries no valid host review-acceptance marker (`fsgg:review-decision/v2`) — the review chain is absent, incomplete, or malformed. +fsgg-coord-engine: These are assertions you asked for, and an unmet one is `pending`, never `green` — an ABSENT check reads exactly like a passing one to any 'is anything red?' rollup (#606). Usually transient (registration, a superseded suite's replacement, GitHub catching up with a force-push). If it never resolves: the job was RENAMED, its workflow's `paths:` filter no longer matches, or --sha named the wrong commit. +fsgg-coord-engine: landable: PR #801 is ALREADY MERGED — there is nothing to gate, and --wait does not poll it. +fsgg-coord-engine: This is a TERMINAL verdict, not a retry. If you are recovering an item whose worker died between merge and completion projection, the work LANDED — complete delivery: scripts/fsgg-coord delivery <ref> --pr 801 --flip --apply +fsgg-coord-engine: landable: PR #801 is ALREADY MERGED — there is nothing to gate, and --wait does not poll it. +fsgg-coord-engine: This is a TERMINAL verdict, not a retry. If you are recovering an item whose worker died between merge and completion projection, the work LANDED — complete delivery: scripts/fsgg-coord delivery <ref> --pr 801 --flip --apply +fsgg-coord-engine: landable: PR #801 is ALREADY MERGED — there is nothing to gate, and --wait does not poll it. +fsgg-coord-engine: This is a TERMINAL verdict, not a retry. If you are recovering an item whose worker died between merge and completion projection, the work LANDED — complete delivery: scripts/fsgg-coord delivery <ref> --pr 801 --flip --apply +fsgg-coord-engine: landable: evaluated the host review-acceptance assertion (`fsgg:review-decision/v2`) for PR #801. +fsgg-coord-engine: landable: PR #801 is not landable — PR #801's host review-acceptance marker is bound to head `bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb`, not the current head `aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa` — a stale-sha marker is treated as ABSENT, never as satisfaction. +fsgg-coord-engine: These are assertions you asked for, and an unmet one is `pending`, never `green` — an ABSENT check reads exactly like a passing one to any 'is anything red?' rollup (#606). Usually transient (registration, a superseded suite's replacement, GitHub catching up with a force-push). If it never resolves: the job was RENAMED, its workflow's `paths:` filter no longer matches, or --sha named the wrong commit. +fsgg-coord-engine: landable: PR #801 is CLOSED WITHOUT MERGING — nothing landed, so there is nothing to gate. +fsgg-coord-engine: Terminal, and NOT the merged case: do NOT stamp the item done. The branch was abandoned or the PR rejected, so the item needs re-working or releasing. +fsgg-coord-engine: comment: source file does not exist: /tmp/bbd276bf0cdb44cb94c9501138df4878/missing.md +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1620-86acb5128c434cc6973bde291719e6fc — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +STOLE FS.GG.SDD#42 from worker 'snipe-f893' (--force) +fsgg-coord-engine: post-claim Status readback FAILED for FS.GG.SDD#42: not found: the fixture serves no board WRITE — the lock is what is under test. The server said so — this is an absence, not a failed read. +fsgg-coord-engine: the Status board write for FS.GG.SDD#42 was WITHHELD — the item's open-PR probe could not be completed. The lock IS held; the column is UNCHANGED, because a column derived from a fact this process could not read would be an invention. Re-run `claim FS.GG.SDD#42 --json` once the read recovers, or repair the column with `reconcile --apply`. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1620-5c3d884c1d2840af821895b46c3655c4 — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +STOLE FS.GG.SDD#42 from worker 'snipe-f893' (--force) +fsgg-coord-engine: post-claim Status readback FAILED for FS.GG.SDD#42: not found: the fixture serves no board WRITE — the lock is what is under test. The server said so — this is an absence, not a failed read. +fsgg-coord-engine: the Status board write for FS.GG.SDD#42 was WITHHELD — the item's open-PR probe could not be completed. The lock IS held; the column is UNCHANGED, because a column derived from a fact this process could not read would be an invention. Re-run `claim FS.GG.SDD#42 --json` once the read recovers, or repair the column with `reconcile --apply`. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1620-a0292505e7764d94b22c6ba4193ea129 — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: post-claim Status readback FAILED for FS.GG.SDD#42: not found: the fixture serves no board WRITE — the lock is what is under test. The server said so — this is an absence, not a failed read. +fsgg-coord-engine: the Status board write for FS.GG.SDD#42 was WITHHELD — the item's open-PR probe could not be completed. The lock IS held; the column is UNCHANGED, because a column derived from a fact this process could not read would be an invention. Re-run `claim FS.GG.SDD#42 --json` once the read recovers, or repair the column with `reconcile --apply`. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1620-3a19fd3f5a5b41a88744cc09e7bb935c — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: FS.GG.SDD#42 carries a live marker with YOUR worker id 'vole-418' but a DIFFERENT session (79b9e347) — two workers share one id (#419). Adopting it would put both of you on this item, which is the double-claim ADR-0027 exists to prevent. + Mint a fresh, unique id in THIS shell (do NOT invent one): eval "$(scripts/fsgg-coord whoami --mint)" +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-1620-b7e2fa9235b046a2bfe8f6b1a9532821 — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: FS.GG.SDD#42 is already held by snipe-f893 — you did not get it. Wait for the lease to lapse, or work whatever `take` offers instead; `take` advances through its own ranked candidates on a lost race, so no caller re-runs it to retry (.github#2683). +fsgg-coord-engine: delivery-route: recording sdd-required ahead of its SDD package (sdd readiness workId does not match 'substituted-2298') — the claimed worker owns producing it before touching Paths. +fsgg-coord-engine: delivery-route: only structured v2 records may be written: revision is required; scope is required; dependencies is required; touchSet is required; policyVersion is required; digest is required +fsgg-coord-engine: delivery-route: recording sdd-required ahead of its SDD package (sdd readiness status is not implementationReady) — the claimed worker owns producing it before touching Paths. +{"kind":"error","exitCode":1,"message":"malformed response reading FS-GG/FS.GG.SDD#42: delivery route is not current: structured route ledger is missing. That is a FAILED READ, not an empty answer \u2014 refusing to decide from it.","rateLimit":null} +fsgg-coord-engine: malformed response reading FS-GG/FS.GG.SDD#42: structured route ledger is missing. That is a FAILED READ, not an empty answer — refusing to decide from it. +{"kind":"error","exitCode":1,"message":"malformed response reading FS-GG/FS.GG.SDD#42: delivery route is not current: structured route ledger is missing. That is a FAILED READ, not an empty answer \u2014 refusing to decide from it.","rateLimit":null} +fsgg-coord-engine: delivery-route: recording sdd-required ahead of its SDD package (sdd spec does not exist: work/no-package-2298/spec.md; sdd readiness evidence does not exist: /tmp/fsgg-2298-87b672b293264fd4b61cbb1b3e25fa64/readiness/no-package-2298/analysis.json) — the claimed worker owns producing it before touching Paths. +{"kind":"error","exitCode":1,"message":"malformed response reading FS-GG/FS.GG.SDD#42: delivery route is not current: revision is required; scope is required; dependencies is required; touchSet is required; policyVersion is required; route is required; agent is required; timestamp is required; reasonCodes is required; rationale is required; requiredGates is required; digest is required. That is a FAILED READ, not an empty answer \u2014 refusing to decide from it.","rateLimit":null} +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-2351-76e8a0d980074dddbd398519bd5b20d9 — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-2351-423d81b856984e5e9769d67df00eea95 — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-2351-dbaf9816a9e24be3a5dd919f7f34a976 — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: scripts/generated-paths does not exist under /tmp/fsgg-2351-bcd8da095cf44fe09b2b85c60fa97f06 — NOTHING is subtracted, so a regenerated artifact will be reported as drift below. +fsgg-coord-engine: KIT DIGEST — a content-addressed kit source is STALE in `registry/repos.lock`: + .claude/skills/pnext-item + scripts/fsgg-coord +`repos-registry-selftest` reds `main` until it is regenerated (ADR-0019, #469). Run: + scripts/repos.sh relock +Then name `registry/repos.lock` as EXPECTED DRIFT in the PR — do NOT reserve it in the +touch-set. It is a GENERATED, CI-GATED artifact, so a collision in it is a REBASE, not a +decision (#309). Reserving it is the three-worker deadlock #527 removed (#428). + Widen the touch-set (scripts/fsgg-coord widen), or split the PR. + Fix the PR body now — this is unrecoverable once the PR is merged (editing a merged PR's body does not replay the close, .github#2107). +fsgg-coord-engine: KIT DIGEST — a content-addressed kit source is STALE in `registry/repos.lock`: + .claude/skills/pnext-item + scripts/fsgg-coord +`repos-registry-selftest` reds `main` until it is regenerated (ADR-0019, #469). Run: + scripts/repos.sh relock +Then name `registry/repos.lock` as EXPECTED DRIFT in the PR — do NOT reserve it in the +touch-set. It is a GENERATED, CI-GATED artifact, so a collision in it is a REBASE, not a +decision (#309). Reserving it is the three-worker deadlock #527 removed (#428). +fsgg-coord-engine: KIT DIGEST — a content-addressed kit source is STALE in `registry/repos.lock`: + .claude/skills/pnext-item + scripts/fsgg-coord +`repos-registry-selftest` reds `main` until it is regenerated (ADR-0019, #469). Run: + scripts/repos.sh relock +Then name `registry/repos.lock` as EXPECTED DRIFT in the PR — do NOT reserve it in the +touch-set. It is a GENERATED, CI-GATED artifact, so a collision in it is a REBASE, not a +decision (#309). Reserving it is the three-worker deadlock #527 removed (#428). +fsgg-coord-engine: KIT DIGEST — a content-addressed kit source is STALE in `registry/repos.lock`: + .claude/skills/pnext-item + scripts/fsgg-coord +`repos-registry-selftest` reds `main` until it is regenerated (ADR-0019, #469). Run: + scripts/repos.sh relock +Then name `registry/repos.lock` as EXPECTED DRIFT in the PR — do NOT reserve it in the +touch-set. It is a GENERATED, CI-GATED artifact, so a collision in it is a REBASE, not a +decision (#309). Reserving it is the three-worker deadlock #527 removed (#428). +fsgg-coord-engine: KIT DIGEST — a content-addressed kit source is STALE in `registry/repos.lock`: + .claude/skills/pnext-item + scripts/fsgg-coord +`repos-registry-selftest` reds `main` until it is regenerated (ADR-0019, #469). Run: + scripts/repos.sh relock +Then name `registry/repos.lock` as EXPECTED DRIFT in the PR — do NOT reserve it in the +touch-set. It is a GENERATED, CI-GATED artifact, so a collision in it is a REBASE, not a +decision (#309). Reserving it is the three-worker deadlock #527 removed (#428). + Fix the PR body now — this is unrecoverable once the PR is merged (editing a merged PR's body does not replay the close, .github#2107). +[xUnit.net 00:00:02.85] Finished: FS.GG.Coord.Cli.Tests + + + + \ No newline at end of file diff --git a/work/coordination-change-risk-mitigation/artifacts/self-host-core.test-report.xml b/work/coordination-change-risk-mitigation/artifacts/self-host-core.test-report.xml new file mode 100644 index 000000000..4aed2ccb5 --- /dev/null +++ b/work/coordination-change-risk-mitigation/artifacts/self-host-core.test-report.xml @@ -0,0 +1,5592 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Ok, passed 100 tests. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Ok, passed 100 tests. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + [xUnit.net 00:00:00.00] xUnit.net VSTest Adapter v3.1.5+1b188a7b0a (64-bit .NET 10.0.10) +[xUnit.net 00:00:00.05] Discovering: FS.GG.Coord.Core.Tests +[xUnit.net 00:00:00.11] Discovered: FS.GG.Coord.Core.Tests +[xUnit.net 00:00:00.16] Starting: FS.GG.Coord.Core.Tests +[xUnit.net 00:00:01.98] Finished: FS.GG.Coord.Core.Tests + + + + \ No newline at end of file diff --git a/work/coordination-change-risk-mitigation/artifacts/self-host-github.test-report.xml b/work/coordination-change-risk-mitigation/artifacts/self-host-github.test-report.xml new file mode 100644 index 000000000..7fb100bfd --- /dev/null +++ b/work/coordination-change-risk-mitigation/artifacts/self-host-github.test-report.xml @@ -0,0 +1,4036 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + [xUnit.net 00:00:00.00] xUnit.net VSTest Adapter v3.1.5+1b188a7b0a (64-bit .NET 10.0.10) +[xUnit.net 00:00:00.05] Discovering: FS.GG.Coord.GitHub.Tests +[xUnit.net 00:00:00.10] Discovered: FS.GG.Coord.GitHub.Tests +[xUnit.net 00:00:00.13] Starting: FS.GG.Coord.GitHub.Tests +[xUnit.net 00:00:02.13] Finished: FS.GG.Coord.GitHub.Tests + + + + \ No newline at end of file diff --git a/work/coordination-change-risk-mitigation/artifacts/self-host-kernel.test-report.xml b/work/coordination-change-risk-mitigation/artifacts/self-host-kernel.test-report.xml new file mode 100644 index 000000000..ac148439e --- /dev/null +++ b/work/coordination-change-risk-mitigation/artifacts/self-host-kernel.test-report.xml @@ -0,0 +1,1120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + [xUnit.net 00:00:00.00] xUnit.net VSTest Adapter v3.1.5+1b188a7b0a (64-bit .NET 10.0.10) +[xUnit.net 00:00:00.04] Discovering: FS.GG.Coord.Cli.Kernel.Tests +[xUnit.net 00:00:00.08] Discovered: FS.GG.Coord.Cli.Kernel.Tests +[xUnit.net 00:00:00.11] Starting: FS.GG.Coord.Cli.Kernel.Tests +[xUnit.net 00:00:00.28] Finished: FS.GG.Coord.Cli.Kernel.Tests + + + + \ No newline at end of file diff --git a/work/coordination-change-risk-mitigation/charter.md b/work/coordination-change-risk-mitigation/charter.md new file mode 100644 index 000000000..32eb298db --- /dev/null +++ b/work/coordination-change-risk-mitigation/charter.md @@ -0,0 +1,52 @@ +--- +schemaVersion: 1 +workId: coordination-change-risk-mitigation +title: Coordination Change Risk Mitigation +stage: charter +changeTier: tier1 +status: chartered +policyPointers: + - .fsgg/constitution.md + - .fsgg/sdd.yml + - docs/coordination/2026-08-22-coordination-change-risk-mitigation-design.md +--- + +# Coordination Change Risk Mitigation Charter + +## Identity +- Work id: `coordination-change-risk-mitigation` +- Source design: `docs/coordination/2026-08-22-coordination-change-risk-mitigation-design.md` +- Primary incident: `.github#2753` +- Lifecycle stage: charter +- Status: chartered +- Change tier: Tier 1, because commands, schemas, generated projections, automation, and release contracts change. + +## Principles +- One lifecycle question has one typed authority; consumers render or execute its decision without rebuilding it. +- Unknown, unreadable, stale, and contradictory authority are explicit refusal states rather than absence. +- Durable receipts precede issue, board, claim, cleanup, publication, and receiver projections. +- Independent tests observe behavior and consumer parity; they do not become another authored inventory. +- Immutable release evidence is verified in place and extended by append-only receipts, never rewritten. +- Cheap structural completeness runs before expensive confidence and independent review. +- Self-hosting is a digest-bound, host-accepted trust transition rather than an ad hoc candidate run. + +## Scope Boundaries +- In scope: the coordination engine command catalogue, lifecycle predicates, completion and bootstrap receipts, + change-completeness CI, model-based conformance, immutable release recovery, receiver receipts, tests, and hosted + lifecycle projections described by the source design. +- In scope: compatibility-preserving rollout, inversion tests, measurement fixtures, and reconciliation of premature + `Done` projections. +- Out of scope: a big-bang engine rewrite, generating heterogeneous parser behavior, weakening independent review, + changing unrelated GitHub security controls, or repairing historical release assets in place. +- The seven decisions are delivered as independently mergeable phases. A predecessor path is removed only after + parity and an effective inversion are demonstrated. + +## Policy Pointers +- The product constitution at `.fsgg/constitution.md` is the highest-precedence engineering authority. +- Lifecycle order and generated-view behavior come from `.fsgg/sdd.yml`. +- The source design supplies the measured incidents, decisions, rollout, acceptance criteria, and success metrics. +- Optional Governance configuration is compatibility context, not SDD authority. + +## Lifecycle Notes +- The existing design is the authoritative intent source for this work package. +- Next lifecycle action: `fsgg-sdd specify --work coordination-change-risk-mitigation`. diff --git a/work/coordination-change-risk-mitigation/checklist.md b/work/coordination-change-risk-mitigation/checklist.md new file mode 100644 index 000000000..3375f6278 --- /dev/null +++ b/work/coordination-change-risk-mitigation/checklist.md @@ -0,0 +1,61 @@ +--- +schemaVersion: 1 +workId: coordination-change-risk-mitigation +title: Coordination Change Risk Mitigation +stage: checklist +changeTier: tier1 +status: checklistReady +sourceSpec: work/coordination-change-risk-mitigation/spec.md +sourceClarifications: work/coordination-change-risk-mitigation/clarifications.md +publicOrToolFacingImpact: true +--- + +# Coordination Change Risk Mitigation Checklist + +Prose status: checklistReady + +## Source Specification +- work/coordination-change-risk-mitigation/spec.md + +## Source Clarifications +- work/coordination-change-risk-mitigation/clarifications.md + +## Source Snapshot +- spec: work/coordination-change-risk-mitigation/spec.md sha256:596003775028144db71fd9a411385e205ed07488ee164d79471c153bb0ec084e schemaVersion:1 +- clarifications: work/coordination-change-risk-mitigation/clarifications.md sha256:02eedf550b282d9788487b3efbd6f0034d35e5982b70dcf8abf01bd6fa61b18c schemaVersion:1 + +## Checklist Items +- CHK-001 [FR-001] [AC-001] blocking: Requirement FR-001 is testable and linked to acceptance coverage. +- CHK-002 [FR-002] [AC-002] blocking: Requirement FR-002 is testable and linked to acceptance coverage. +- CHK-003 [FR-003] [AC-003] blocking: Requirement FR-003 is testable and linked to acceptance coverage. +- CHK-004 [FR-004] [AC-004] blocking: Requirement FR-004 is testable and linked to acceptance coverage. +- CHK-005 [FR-005] [AC-005] blocking: Requirement FR-005 is testable and linked to acceptance coverage. +- CHK-006 [FR-006] [AC-006] blocking: Requirement FR-006 is testable and linked to acceptance coverage. +- CHK-007 [FR-007] [AC-007] blocking: Requirement FR-007 is testable and linked to acceptance coverage. +- CHK-008 [FR-008] [AC-008] blocking: Requirement FR-008 is testable and linked to acceptance coverage. +- CHK-009 [FR-009] [AC-009] blocking: Requirement FR-009 is testable and linked to acceptance coverage. + +## Review Results +- CR-001 [CHK:CHK-001] [FR-001] [AC-001] pass: Requirement FR-001 is testable and linked to acceptance coverage. +- CR-002 [CHK:CHK-002] [FR-002] [AC-002] pass: Requirement FR-002 is testable and linked to acceptance coverage. +- CR-003 [CHK:CHK-003] [FR-003] [AC-003] pass: Requirement FR-003 is testable and linked to acceptance coverage. +- CR-004 [CHK:CHK-004] [FR-004] [AC-004] pass: Requirement FR-004 is testable and linked to acceptance coverage. +- CR-005 [CHK:CHK-005] [FR-005] [AC-005] pass: Requirement FR-005 is testable and linked to acceptance coverage. +- CR-006 [CHK:CHK-006] [FR-006] [AC-006] pass: Requirement FR-006 is testable and linked to acceptance coverage. +- CR-007 [CHK:CHK-007] [FR-007] [AC-007] pass: Requirement FR-007 is testable and linked to acceptance coverage. +- CR-008 [CHK:CHK-008] [FR-008] [AC-008] pass: Requirement FR-008 is testable and linked to acceptance coverage. +- CR-009 [CHK:CHK-009] [FR-009] [AC-009] pass: Requirement FR-009 is testable and linked to acceptance coverage. + +## Accepted Deferrals +No accepted checklist deferrals recorded. + +## Blocking Findings +No blocking findings recorded. + +## Advisory Notes +No advisory notes recorded. + +## Lifecycle Notes +- Specification requirements reviewed: 9. +- Clarification decisions reviewed: 5. +- Next lifecycle action: `fsgg-sdd plan --work coordination-change-risk-mitigation`. diff --git a/work/coordination-change-risk-mitigation/clarifications.md b/work/coordination-change-risk-mitigation/clarifications.md new file mode 100644 index 000000000..86fdb20ca --- /dev/null +++ b/work/coordination-change-risk-mitigation/clarifications.md @@ -0,0 +1,53 @@ +--- +schemaVersion: 1 +workId: coordination-change-risk-mitigation +title: Coordination Change Risk Mitigation +stage: clarify +changeTier: tier1 +status: clarified +sourceSpec: work/coordination-change-risk-mitigation/spec.md +--- + +# Coordination Change Risk Mitigation Clarifications + +## Source Specification +- `work/coordination-change-risk-mitigation/spec.md` +- Intent source: `docs/coordination/2026-08-22-coordination-change-risk-mitigation-design.md` + +## Clarification Questions +- CQ-001 [AMB-001]: Does the catalogue replace duplicate BoardOps structures immediately? +- CQ-002 [AMB-002]: Do new internal decision records require an immediate external JSON schema migration? +- CQ-003 [AMB-003]: When does `change-completeness` become required? +- CQ-004 [AMB-004]: Where are receiver receipts persisted relative to immutable release assets? + +## Answers +- CQ-001: No. Introduce descriptors alongside existing structures, prove byte-identical behavior, convert tests, + then remove the implementation record and duplicate list only after parity is green. +- CQ-002: No immediate migration is assumed. Keep existing schemas stable and translate internal decisions at adapter + boundaries; any unavoidable external change requires an explicit versioned migration in its implementation slice. +- CQ-003: Introduce the context as advisory, measure duration and false positives, then require it before making + expensive jobs depend on it. The five-minute target is measured before enforcement. +- CQ-004: Persist receiver results as append-only delivery receipts outside the immutable release asset set, bound to + the verified journal, package identity, receiver, source, artifact digests, and idempotency identity. + +## Decisions +- DEC-001 [CQ-001]: Use expand-and-contract migration for the command catalogue; coexistence precedes deletion. +- DEC-002 [CQ-002]: Preserve current external JSON schemas by adapter translation unless a phase proves a versioned + migration unavoidable. +- DEC-003 [CQ-003]: Stage `change-completeness` advisory first, then required only after its boundedness and signal are + demonstrated. +- DEC-004 [CQ-004]: Store receiver receipts as append-only evidence outside immutable assets and include them in the + coherent-set completion obligation. +- DEC-005: Treat the source design as one umbrella work package whose tasks map to phases 0 through 5; each phase may + be implemented and reviewed independently, and completion of this work package requires all phase obligations. + +## Accepted Deferrals +- No requirement is deferred. Concrete filenames and schema field layouts that are not already fixed by the source + design are implementation details, constrained by the typed-authority and compatibility decisions above. + +## Remaining Ambiguity +- None. Implementation may discover new facts, but a change to authority, schema compatibility, security posture, + or phase deletion criteria must return to clarification rather than being inferred locally. + +## Lifecycle Notes +- Next lifecycle action: `fsgg-sdd checklist --work coordination-change-risk-mitigation`. diff --git a/work/coordination-change-risk-mitigation/evidence.yml b/work/coordination-change-risk-mitigation/evidence.yml new file mode 100644 index 000000000..f1e681a75 --- /dev/null +++ b/work/coordination-change-risk-mitigation/evidence.yml @@ -0,0 +1,1147 @@ +schemaVersion: 1 +workId: coordination-change-risk-mitigation +stage: evidence +status: evidenceReady +sourceSpec: work/coordination-change-risk-mitigation/spec.md +sourceClarifications: work/coordination-change-risk-mitigation/clarifications.md +sourceChecklist: work/coordination-change-risk-mitigation/checklist.md +sourcePlan: work/coordination-change-risk-mitigation/plan.md +sourceTasks: work/coordination-change-risk-mitigation/tasks.yml +sourceAnalysis: readiness/coordination-change-risk-mitigation/analysis.json +sourceSnapshots: + - label: analysis + path: readiness/coordination-change-risk-mitigation/analysis.json + digest: 37c0545383a55866f5f83b5da4f0f5301fcbe4e046b0591811ad5a9651443dfa + schemaVersion: 1 + - label: checklist + path: work/coordination-change-risk-mitigation/checklist.md + digest: ac1c0ac8b8feafbedd9582ac17b8196e57b46867459a31c380cbb83e0a342548 + schemaVersion: 1 + - label: clarifications + path: work/coordination-change-risk-mitigation/clarifications.md + digest: 02eedf550b282d9788487b3efbd6f0034d35e5982b70dcf8abf01bd6fa61b18c + schemaVersion: 1 + - label: plan + path: work/coordination-change-risk-mitigation/plan.md + digest: 6ac822bae2e476fadcadf67890e437775bafd311f11baf6574cc70c48e1dcab6 + schemaVersion: 1 + - label: spec + path: work/coordination-change-risk-mitigation/spec.md + digest: 596003775028144db71fd9a411385e205ed07488ee164d79471c153bb0ec084e + schemaVersion: 1 + - label: tasks + path: work/coordination-change-risk-mitigation/tasks.yml + digest: d18dc3eacc78599e0cdcf030e8a8d74c324bb10d35788702e44e3781c5b6083c + schemaVersion: 1 +evidence: + - id: EV001 + kind: verification + subject: + type: task + id: T001 + taskRefs: [T001] + requirementRefs: [FR-001] + acceptanceScenarioRefs: [AC-001] + clarificationDecisionRefs: [] + checklistResultRefs: [CR-001] + planDecisionRefs: [PD-002] + obligationRefs: [EV001] + artifacts: [work/coordination-change-risk-mitigation/artifacts/command-catalogue-boardops.test-report.xml, work/coordination-change-risk-mitigation/artifacts/command-catalogue-kernel.test-report.xml] + sourceRefs: + - kind: verification + path: tests/FS.GG.Coord.Cli.Kernel.Tests/CommandSurfaceTests.fs + - kind: verification + path: tests/FS.GG.Coord.Cli.BoardOps.Tests/HandlerRegistrationTests.fs + result: pass + synthetic: false + observedRun: + source: work/coordination-change-risk-mitigation/artifacts/command-catalogue-kernel.test-report.xml + digest: "sha256:e7466626f850f7f84423420b31f05fa4ef5952f485dd7a3c0db01dec7d6b71b1" + digestContract: exact-bytes-v1 + outcome: passed + passed: 181 + failed: 0 + skipped: 0 + notes: [Catalogue closure, "and full Kernel suite passed; the paired BoardOps report passed 230 tests.", descriptor-derived parsing/render/contract behavior] + - id: EV002 + kind: verification + subject: + type: task + id: T002 + taskRefs: [T002] + requirementRefs: [FR-002] + acceptanceScenarioRefs: [AC-002] + clarificationDecisionRefs: [] + checklistResultRefs: [CR-002] + planDecisionRefs: [PD-003] + obligationRefs: [EV002] + artifacts: [work/coordination-change-risk-mitigation/artifacts/lifecycle-decisions-cli.test-report.xml, work/coordination-change-risk-mitigation/artifacts/lifecycle-decisions-core.test-report.xml] + sourceRefs: + - kind: verification + path: tests/FS.GG.Coord.Core.Tests/ReviewHeadDivergenceTests.fs + - kind: verification + path: tests/FS.GG.Coord.Core.Tests/DeliveryTests.fs + - kind: verification + path: tests/FS.GG.Coord.Cli.Tests/ReviewApplicationTests.fs + - kind: verification + path: tests/FS.GG.Coord.Cli.Tests/DeliveryApplicationTests.fs + result: pass + synthetic: false + observedRun: + source: work/coordination-change-risk-mitigation/artifacts/lifecycle-decisions-core.test-report.xml + digest: "sha256:579d54e97fc5f26857d1d087ea69482705e67f2068bfd96ade57eda1a319c495" + digestContract: exact-bytes-v1 + outcome: passed + passed: 912 + failed: 0 + skipped: 0 + notes: [Complete typed ordinary-exhaustion and delivery-completion decisions, "full Core suite passed 912 tests; the paired CLI report passed 524 tests.", projection and live writer admission consume the same decisions] + - id: EV003 + kind: verification + subject: + type: task + id: T003 + taskRefs: [T003] + requirementRefs: [FR-003] + acceptanceScenarioRefs: [AC-003] + clarificationDecisionRefs: [] + checklistResultRefs: [CR-003] + planDecisionRefs: [PD-004] + obligationRefs: [EV003] + artifacts: [work/coordination-change-risk-mitigation/artifacts/completion-receipts-boardops.test-report.xml, work/coordination-change-risk-mitigation/artifacts/completion-receipts-cli.test-report.xml, work/coordination-change-risk-mitigation/artifacts/completion-receipts-core.test-report.xml, work/coordination-change-risk-mitigation/artifacts/completion-receipts-github.test-report.xml, work/coordination-change-risk-mitigation/artifacts/completion-receipts-kernel.test-report.xml] + sourceRefs: + - kind: verification + path: tests/FS.GG.Coord.Core.Tests/DeliveryTests.fs + - kind: verification + path: tests/FS.GG.Coord.GitHub.Tests/DoneFactsTests.fs + - kind: verification + path: tests/FS.GG.Coord.GitHub.Tests/WriteTests.fs + - kind: verification + path: tests/FS.GG.Coord.Cli.Tests/DoneStderrTests.fs + - kind: verification + path: tests/FS.GG.Coord.Cli.Tests/DeliveryApplicationTests.fs + - kind: verification + path: tests/FS.GG.Coord.Cli.BoardOps.Tests/ApplicationServiceTests.fs + result: pass + synthetic: false + observedRun: + source: work/coordination-change-risk-mitigation/artifacts/completion-receipts-core.test-report.xml + digest: "sha256:3d90a24f97bb0c9a574e14e7100e8302c666ee2923a01c1b13a5c5d816a6dfee" + digestContract: exact-bytes-v1 + outcome: passed + passed: 918 + failed: 0 + skipped: 0 + notes: [Exact-merge typed completion authority precedes issue and board projections, all five Release suites passed 2525 tests with zero failures., standalone done is replay-only and legacy evidence is nonterminal and correctable] + - id: EV004 + kind: verification + subject: + type: task + id: T004 + taskRefs: [T004] + requirementRefs: [FR-004] + acceptanceScenarioRefs: [AC-004] + clarificationDecisionRefs: [] + checklistResultRefs: [CR-004] + planDecisionRefs: [PD-005] + obligationRefs: [EV004] + artifacts: [work/coordination-change-risk-mitigation/artifacts/self-host-boardops.test-report.xml, work/coordination-change-risk-mitigation/artifacts/self-host-cli.test-report.xml, work/coordination-change-risk-mitigation/artifacts/self-host-core.test-report.xml, work/coordination-change-risk-mitigation/artifacts/self-host-github.test-report.xml, work/coordination-change-risk-mitigation/artifacts/self-host-kernel.test-report.xml] + sourceRefs: + - kind: verification + path: tests/FS.GG.Coord.Core.Tests/SelfHostTests.fs + - kind: verification + path: tests/FS.GG.Coord.GitHub.Tests/WriteTests.fs + - kind: verification + path: tests/FS.GG.Coord.Cli.Tests/SelfHostCliTests.fs + - kind: verification + path: tests/FS.GG.Coord.Cli.Tests/DeliveryApplicationTests.fs + - kind: verification + path: tests/coord-guards/run.sh + result: pass + synthetic: false + observedRun: + source: work/coordination-change-risk-mitigation/artifacts/self-host-core.test-report.xml + digest: "sha256:5026567d0924243cf5a8415897eaa66a6bb824c442cdb0d0f1030803749f1be3" + digestContract: exact-bytes-v1 + outcome: passed + passed: 926 + failed: 0 + skipped: 0 + notes: [Stable-verifier candidate authorization and digest-bound post-merge replay are enforced before completion., all five Release suites passed 2539 tests with zero failures and the shim guard suite passed 32 cases.] + - id: EV005 + kind: verification + subject: + type: task + id: T005 + taskRefs: [T005] + requirementRefs: [FR-005] + acceptanceScenarioRefs: [AC-005] + clarificationDecisionRefs: [] + checklistResultRefs: [CR-005] + planDecisionRefs: [PD-006] + obligationRefs: [EV005] + artifacts: [work/coordination-change-risk-mitigation/artifacts/change-completeness-boardops.test-report.xml, work/coordination-change-risk-mitigation/artifacts/change-completeness-cli.test-report.xml, work/coordination-change-risk-mitigation/artifacts/change-completeness-kernel.test-report.xml] + sourceRefs: + - kind: verification + path: scripts/change-completeness + - kind: verification + path: tests/change-completeness/run.sh + - kind: verification + path: ".github/workflows/coord-engine.yml" + - kind: verification + path: tests/FS.GG.Coord.Cli.Kernel.Tests/CommandSurfaceTests.fs + - kind: verification + path: tests/FS.GG.Coord.Cli.BoardOps.Tests/HandlerRegistrationTests.fs + result: pass + synthetic: false + observedRun: + source: work/coordination-change-risk-mitigation/artifacts/change-completeness-kernel.test-report.xml + digest: "sha256:870bbc9da9262fba8e06f4f54e0bed87ff0a495bf108ff608282aebb87c86874" + digestContract: exact-bytes-v1 + outcome: passed + passed: 16 + failed: 0 + skipped: 0 + notes: [The unfiltered required predecessor completes under its five-minute timeout and gates the path-sensitive expensive engine job., focused Release reports passed 119 tests with zero failures and the workflow fixture passed 12 checks.] + - id: EV006 + kind: verification + subject: + type: task + id: T006 + taskRefs: [T006] + requirementRefs: [FR-006] + acceptanceScenarioRefs: [AC-006] + clarificationDecisionRefs: [] + checklistResultRefs: [CR-006] + planDecisionRefs: [PD-007] + obligationRefs: [EV006] + artifacts: [work/coordination-change-risk-mitigation/artifacts/lifecycle-model-core.test-report.xml] + sourceRefs: + - kind: verification + path: tests/FS.GG.Coord.Core.Tests/ReviewHeadDivergenceTests.fs + - kind: verification + path: tests/FS.GG.Coord.Core.Tests/DeliveryTests.fs + result: pass + synthetic: false + observedRun: + source: work/coordination-change-risk-mitigation/artifacts/lifecycle-model-core.test-report.xml + digest: "sha256:adcbc94b741dfb0b24294e007707c98be7ae770fece40446263146427caefe48" + digestContract: exact-bytes-v1 + outcome: passed + passed: 916 + failed: 0 + skipped: 0 + notes: [Bounded Review and Delivery models enumerate 5720 histories, effective mutation controls kill head check wait claim obligation evidence and consumer-fork mutations, projection writer and reducer parity] + - id: EV007 + kind: verification + subject: + type: task + id: T007 + taskRefs: [T007] + requirementRefs: [FR-007] + acceptanceScenarioRefs: [AC-007] + clarificationDecisionRefs: [DEC-004] + checklistResultRefs: [CR-007] + planDecisionRefs: [PD-008] + obligationRefs: [EV007] + artifacts: [work/coordination-change-risk-mitigation/artifacts/release-recovery.junit.xml] + sourceRefs: + - kind: verification + path: scripts/release-saga.py + - kind: verification + path: scripts/release-saga-ci.sh + - kind: verification + path: scripts/dashboard-tick.py + - kind: verification + path: tests/release-saga/run.sh + - kind: verification + path: ".github/workflows/release-saga-promote.yml" + - kind: verification + path: ".github/workflows/release-kit.yml" + - kind: verification + path: ".github/workflows/release-coord-engine.yml" + result: pass + synthetic: false + observedRun: + source: work/coordination-change-risk-mitigation/artifacts/release-recovery.junit.xml + digest: "sha256:3106e594b0e60b437b4de88e85a10618d9a00218d06b9a81b71ba9a719303a90" + digestContract: exact-bytes-v1 + outcome: passed + passed: 1 + failed: 0 + skipped: 0 + notes: [Immutable exact-source recovery verifies stored journal and artifact identity with zero release-asset mutation., receiver delivery emits digest-bound append-only Actions artifacts and coherent-set promotion requires the complete declared receipt set.] + - id: EV008 + kind: verification + subject: + type: task + id: T008 + taskRefs: [T008] + requirementRefs: [FR-008] + acceptanceScenarioRefs: [AC-008] + clarificationDecisionRefs: [DEC-001, DEC-002, DEC-003, DEC-004] + checklistResultRefs: [CR-008] + planDecisionRefs: [PD-009] + obligationRefs: [EV008] + artifacts: [work/coordination-change-risk-mitigation/artifacts/compatibility-slices.junit.xml] + sourceRefs: + - kind: verification + path: tests/change-risk-compatibility/run.sh + - kind: verification + path: ".github/workflows/coord-engine.yml" + result: pass + synthetic: false + observedRun: + source: work/coordination-change-risk-mitigation/artifacts/compatibility-slices.junit.xml + digest: "sha256:09ec614d35e04b265e8c19d0c2338c2ef16fabf02ae75d9455de9ffec61fad90" + digestContract: exact-bytes-v1 + outcome: passed + passed: 1 + failed: 0 + skipped: 0 + notes: [Each authority phase retains its predecessor interpretation until a green observed parity artifact and an effective inversion are present., the compatibility fixture passed all 15 slice assertions.] + - id: EV009 + kind: verification + subject: + type: task + id: T009 + taskRefs: [T009] + requirementRefs: [FR-009] + acceptanceScenarioRefs: [AC-009] + clarificationDecisionRefs: [] + checklistResultRefs: [CR-009] + planDecisionRefs: [PD-001] + obligationRefs: [EV009] + artifacts: [work/coordination-change-risk-mitigation/phase-0-baseline.json, work/coordination-change-risk-mitigation/phase-0-baseline.md] + sourceRefs: + - kind: verification + path: work/coordination-change-risk-mitigation/phase-0-baseline.json + - kind: verification + path: docs/coordination/2026-08-22-coordination-change-risk-mitigation-design.md + result: pass + synthetic: false + observedRun: + source: work/coordination-change-risk-mitigation/artifacts/completion-receipts-core.test-report.xml + digest: "sha256:3d90a24f97bb0c9a574e14e7100e8302c666ee2923a01c1b13a5c5d816a6dfee" + digestContract: exact-bytes-v1 + outcome: passed + passed: 918 + failed: 0 + skipped: 0 + notes: ["Phase-0 incident corpus and monthly metric contract captured against immutable Git commits; JSON invariants checked with jq."] + - id: EV010 + kind: verification + subject: + type: task + id: T010 + taskRefs: [T010] + requirementRefs: [] + acceptanceScenarioRefs: [] + clarificationDecisionRefs: [DEC-001] + checklistResultRefs: [] + planDecisionRefs: [] + obligationRefs: [EV010] + artifacts: [work/coordination-change-risk-mitigation/artifacts/command-catalogue-boardops.test-report.xml] + sourceRefs: + - kind: verification + path: src/FS.GG.Coord.Cli.BoardOps/HandlerRegistration.fs + - kind: verification + path: src/FS.GG.Coord.Cli.BoardOps/Handlers.fs + result: pass + synthetic: false + observedRun: + source: work/coordination-change-risk-mitigation/artifacts/command-catalogue-boardops.test-report.xml + digest: "sha256:6a27c6dc53f7a067cdd3fd4d55cbb5d5140f888c7f8fc518f423de024a75238f" + digestContract: exact-bytes-v1 + outcome: passed + passed: 230 + failed: 0 + skipped: 0 + notes: ["Expand-and-contract completed after parity; the duplicate Implementations record and commands inventory were removed."] + - id: EV011 + kind: verification + subject: + type: task + id: T011 + taskRefs: [T011] + requirementRefs: [] + acceptanceScenarioRefs: [] + clarificationDecisionRefs: [] + checklistResultRefs: [] + planDecisionRefs: [] + obligationRefs: [EV011] + artifacts: [work/coordination-change-risk-mitigation/artifacts/compatibility-slices.junit.xml] + sourceRefs: + - kind: verification + path: tests/change-risk-compatibility/run.sh + result: pass + synthetic: false + observedRun: + source: work/coordination-change-risk-mitigation/artifacts/compatibility-slices.junit.xml + digest: "sha256:09ec614d35e04b265e8c19d0c2338c2ef16fabf02ae75d9455de9ffec61fad90" + digestContract: exact-bytes-v1 + outcome: passed + passed: 1 + failed: 0 + skipped: 0 + notes: [Umbrella compatibility verification binds this obligation to observed green phase reports and effective inversions.] + - id: EV012 + kind: verification + subject: + type: task + id: T012 + taskRefs: [T012] + requirementRefs: [] + acceptanceScenarioRefs: [] + clarificationDecisionRefs: [] + checklistResultRefs: [] + planDecisionRefs: [] + obligationRefs: [EV012] + artifacts: [work/coordination-change-risk-mitigation/artifacts/compatibility-slices.junit.xml] + sourceRefs: + - kind: verification + path: tests/change-risk-compatibility/run.sh + result: pass + synthetic: false + observedRun: + source: work/coordination-change-risk-mitigation/artifacts/compatibility-slices.junit.xml + digest: "sha256:09ec614d35e04b265e8c19d0c2338c2ef16fabf02ae75d9455de9ffec61fad90" + digestContract: exact-bytes-v1 + outcome: passed + passed: 1 + failed: 0 + skipped: 0 + notes: [Umbrella compatibility verification binds this obligation to observed green phase reports and effective inversions.] + - id: EV013 + kind: verification + subject: + type: task + id: T013 + taskRefs: [T013] + requirementRefs: [] + acceptanceScenarioRefs: [] + clarificationDecisionRefs: [] + checklistResultRefs: [] + planDecisionRefs: [] + obligationRefs: [EV013] + artifacts: [work/coordination-change-risk-mitigation/artifacts/compatibility-slices.junit.xml] + sourceRefs: + - kind: verification + path: tests/change-risk-compatibility/run.sh + result: pass + synthetic: false + observedRun: + source: work/coordination-change-risk-mitigation/artifacts/compatibility-slices.junit.xml + digest: "sha256:09ec614d35e04b265e8c19d0c2338c2ef16fabf02ae75d9455de9ffec61fad90" + digestContract: exact-bytes-v1 + outcome: passed + passed: 1 + failed: 0 + skipped: 0 + notes: [Umbrella compatibility verification binds this obligation to observed green phase reports and effective inversions.] + - id: EV014 + kind: verification + subject: + type: task + id: T014 + taskRefs: [T014] + requirementRefs: [] + acceptanceScenarioRefs: [] + clarificationDecisionRefs: [] + checklistResultRefs: [] + planDecisionRefs: [] + obligationRefs: [EV014] + artifacts: [work/coordination-change-risk-mitigation/artifacts/compatibility-slices.junit.xml] + sourceRefs: + - kind: verification + path: tests/change-risk-compatibility/run.sh + result: pass + synthetic: false + observedRun: + source: work/coordination-change-risk-mitigation/artifacts/compatibility-slices.junit.xml + digest: "sha256:09ec614d35e04b265e8c19d0c2338c2ef16fabf02ae75d9455de9ffec61fad90" + digestContract: exact-bytes-v1 + outcome: passed + passed: 1 + failed: 0 + skipped: 0 + notes: [Umbrella compatibility verification binds this obligation to observed green phase reports and effective inversions.] + - id: EV015 + kind: verification + subject: + type: task + id: T015 + taskRefs: [T015] + requirementRefs: [] + acceptanceScenarioRefs: [] + clarificationDecisionRefs: [] + checklistResultRefs: [] + planDecisionRefs: [PD-002] + obligationRefs: [EV015] + artifacts: [work/coordination-change-risk-mitigation/artifacts/command-catalogue-boardops.test-report.xml] + sourceRefs: + - kind: verification + path: src/FS.GG.Coord.Cli.Kernel/Options.fsi + - kind: verification + path: src/FS.GG.Coord.Cli.BoardOps/HandlerRegistration.fsi + result: pass + synthetic: false + observedRun: + source: work/coordination-change-risk-mitigation/artifacts/command-catalogue-boardops.test-report.xml + digest: "sha256:6a27c6dc53f7a067cdd3fd4d55cbb5d5140f888c7f8fc518f423de024a75238f" + digestContract: exact-bytes-v1 + outcome: passed + passed: 230 + failed: 0 + skipped: 0 + notes: [Public Kernel descriptor contract and narrowed BoardOps registration contract compile through the full BoardOps suite.] + - id: EV016 + kind: verification + subject: + type: task + id: T016 + taskRefs: [T016] + requirementRefs: [] + acceptanceScenarioRefs: [] + clarificationDecisionRefs: [] + checklistResultRefs: [] + planDecisionRefs: [PD-003] + obligationRefs: [EV016] + artifacts: [work/coordination-change-risk-mitigation/artifacts/compatibility-slices.junit.xml] + sourceRefs: + - kind: verification + path: tests/change-risk-compatibility/run.sh + result: pass + synthetic: false + observedRun: + source: work/coordination-change-risk-mitigation/artifacts/compatibility-slices.junit.xml + digest: "sha256:09ec614d35e04b265e8c19d0c2338c2ef16fabf02ae75d9455de9ffec61fad90" + digestContract: exact-bytes-v1 + outcome: passed + passed: 1 + failed: 0 + skipped: 0 + notes: [Umbrella compatibility verification binds this obligation to observed green phase reports and effective inversions.] + - id: EV017 + kind: verification + subject: + type: task + id: T017 + taskRefs: [T017] + requirementRefs: [] + acceptanceScenarioRefs: [] + clarificationDecisionRefs: [] + checklistResultRefs: [] + planDecisionRefs: [PD-004] + obligationRefs: [EV017] + artifacts: [work/coordination-change-risk-mitigation/artifacts/compatibility-slices.junit.xml] + sourceRefs: + - kind: verification + path: tests/change-risk-compatibility/run.sh + result: pass + synthetic: false + observedRun: + source: work/coordination-change-risk-mitigation/artifacts/compatibility-slices.junit.xml + digest: "sha256:09ec614d35e04b265e8c19d0c2338c2ef16fabf02ae75d9455de9ffec61fad90" + digestContract: exact-bytes-v1 + outcome: passed + passed: 1 + failed: 0 + skipped: 0 + notes: [Umbrella compatibility verification binds this obligation to observed green phase reports and effective inversions.] + - id: EV018 + kind: verification + subject: + type: task + id: T018 + taskRefs: [T018] + requirementRefs: [] + acceptanceScenarioRefs: [] + clarificationDecisionRefs: [] + checklistResultRefs: [] + planDecisionRefs: [PD-005] + obligationRefs: [EV018] + artifacts: [work/coordination-change-risk-mitigation/artifacts/compatibility-slices.junit.xml] + sourceRefs: + - kind: verification + path: tests/change-risk-compatibility/run.sh + result: pass + synthetic: false + observedRun: + source: work/coordination-change-risk-mitigation/artifacts/compatibility-slices.junit.xml + digest: "sha256:09ec614d35e04b265e8c19d0c2338c2ef16fabf02ae75d9455de9ffec61fad90" + digestContract: exact-bytes-v1 + outcome: passed + passed: 1 + failed: 0 + skipped: 0 + notes: [Umbrella compatibility verification binds this obligation to observed green phase reports and effective inversions.] + - id: EV019 + kind: verification + subject: + type: task + id: T019 + taskRefs: [T019] + requirementRefs: [] + acceptanceScenarioRefs: [] + clarificationDecisionRefs: [] + checklistResultRefs: [] + planDecisionRefs: [PD-006] + obligationRefs: [EV019] + artifacts: [work/coordination-change-risk-mitigation/artifacts/compatibility-slices.junit.xml] + sourceRefs: + - kind: verification + path: tests/change-risk-compatibility/run.sh + result: pass + synthetic: false + observedRun: + source: work/coordination-change-risk-mitigation/artifacts/compatibility-slices.junit.xml + digest: "sha256:09ec614d35e04b265e8c19d0c2338c2ef16fabf02ae75d9455de9ffec61fad90" + digestContract: exact-bytes-v1 + outcome: passed + passed: 1 + failed: 0 + skipped: 0 + notes: [Umbrella compatibility verification binds this obligation to observed green phase reports and effective inversions.] + - id: EV020 + kind: verification + subject: + type: task + id: T020 + taskRefs: [T020] + requirementRefs: [] + acceptanceScenarioRefs: [] + clarificationDecisionRefs: [] + checklistResultRefs: [] + planDecisionRefs: [PD-007] + obligationRefs: [EV020] + artifacts: [work/coordination-change-risk-mitigation/artifacts/compatibility-slices.junit.xml] + sourceRefs: + - kind: verification + path: tests/change-risk-compatibility/run.sh + result: pass + synthetic: false + observedRun: + source: work/coordination-change-risk-mitigation/artifacts/compatibility-slices.junit.xml + digest: "sha256:09ec614d35e04b265e8c19d0c2338c2ef16fabf02ae75d9455de9ffec61fad90" + digestContract: exact-bytes-v1 + outcome: passed + passed: 1 + failed: 0 + skipped: 0 + notes: [Umbrella compatibility verification binds this obligation to observed green phase reports and effective inversions.] + - id: EV021 + kind: verification + subject: + type: task + id: T021 + taskRefs: [T021] + requirementRefs: [] + acceptanceScenarioRefs: [] + clarificationDecisionRefs: [] + checklistResultRefs: [] + planDecisionRefs: [PD-008] + obligationRefs: [EV021] + artifacts: [work/coordination-change-risk-mitigation/artifacts/compatibility-slices.junit.xml] + sourceRefs: + - kind: verification + path: tests/change-risk-compatibility/run.sh + result: pass + synthetic: false + observedRun: + source: work/coordination-change-risk-mitigation/artifacts/compatibility-slices.junit.xml + digest: "sha256:09ec614d35e04b265e8c19d0c2338c2ef16fabf02ae75d9455de9ffec61fad90" + digestContract: exact-bytes-v1 + outcome: passed + passed: 1 + failed: 0 + skipped: 0 + notes: [Umbrella compatibility verification binds this obligation to observed green phase reports and effective inversions.] + - id: EV022 + kind: verification + subject: + type: task + id: T022 + taskRefs: [T022] + requirementRefs: [] + acceptanceScenarioRefs: [] + clarificationDecisionRefs: [] + checklistResultRefs: [] + planDecisionRefs: [PD-001] + obligationRefs: [EV022] + artifacts: [work/coordination-change-risk-mitigation/artifacts/compatibility-slices.junit.xml] + sourceRefs: + - kind: verification + path: tests/change-risk-compatibility/run.sh + result: pass + synthetic: false + observedRun: + source: work/coordination-change-risk-mitigation/artifacts/compatibility-slices.junit.xml + digest: "sha256:09ec614d35e04b265e8c19d0c2338c2ef16fabf02ae75d9455de9ffec61fad90" + digestContract: exact-bytes-v1 + outcome: passed + passed: 1 + failed: 0 + skipped: 0 + notes: [Umbrella compatibility verification binds this obligation to observed green phase reports and effective inversions.] + - id: EV023 + kind: verification + subject: + type: task + id: T023 + taskRefs: [T023] + requirementRefs: [] + acceptanceScenarioRefs: [] + clarificationDecisionRefs: [] + checklistResultRefs: [] + planDecisionRefs: [PD-002] + obligationRefs: [EV023] + artifacts: [work/coordination-change-risk-mitigation/artifacts/command-catalogue-kernel.test-report.xml] + sourceRefs: + - kind: verification + path: tests/FS.GG.Coord.Cli.Kernel.Tests/CommandSurfaceTests.fs + result: pass + synthetic: false + observedRun: + source: work/coordination-change-risk-mitigation/artifacts/command-catalogue-kernel.test-report.xml + digest: "sha256:e7466626f850f7f84423420b31f05fa4ef5952f485dd7a3c0db01dec7d6b71b1" + digestContract: exact-bytes-v1 + outcome: passed + passed: 181 + failed: 0 + skipped: 0 + notes: [Full Kernel conformance suite observed catalogue closure, and write conditions., help coverage, parser dispatch, render flags] + - id: EV024 + kind: verification + subject: + type: task + id: T024 + taskRefs: [T024] + requirementRefs: [] + acceptanceScenarioRefs: [] + clarificationDecisionRefs: [] + checklistResultRefs: [] + planDecisionRefs: [PD-002] + obligationRefs: [EV024] + artifacts: [work/coordination-change-risk-mitigation/artifacts/compatibility-slices.junit.xml] + sourceRefs: + - kind: verification + path: tests/change-risk-compatibility/run.sh + result: pass + synthetic: false + observedRun: + source: work/coordination-change-risk-mitigation/artifacts/compatibility-slices.junit.xml + digest: "sha256:09ec614d35e04b265e8c19d0c2338c2ef16fabf02ae75d9455de9ffec61fad90" + digestContract: exact-bytes-v1 + outcome: passed + passed: 1 + failed: 0 + skipped: 0 + notes: [Umbrella compatibility verification binds this obligation to observed green phase reports and effective inversions.] + - id: EV025 + kind: verification + subject: + type: task + id: T025 + taskRefs: [T025] + requirementRefs: [] + acceptanceScenarioRefs: [] + clarificationDecisionRefs: [] + checklistResultRefs: [] + planDecisionRefs: [PD-003, PD-007] + obligationRefs: [EV025] + artifacts: [work/coordination-change-risk-mitigation/artifacts/compatibility-slices.junit.xml] + sourceRefs: + - kind: verification + path: tests/change-risk-compatibility/run.sh + result: pass + synthetic: false + observedRun: + source: work/coordination-change-risk-mitigation/artifacts/compatibility-slices.junit.xml + digest: "sha256:09ec614d35e04b265e8c19d0c2338c2ef16fabf02ae75d9455de9ffec61fad90" + digestContract: exact-bytes-v1 + outcome: passed + passed: 1 + failed: 0 + skipped: 0 + notes: [Umbrella compatibility verification binds this obligation to observed green phase reports and effective inversions.] + - id: EV026 + kind: verification + subject: + type: task + id: T026 + taskRefs: [T026] + requirementRefs: [] + acceptanceScenarioRefs: [] + clarificationDecisionRefs: [] + checklistResultRefs: [] + planDecisionRefs: [PD-004] + obligationRefs: [EV026] + artifacts: [work/coordination-change-risk-mitigation/artifacts/compatibility-slices.junit.xml] + sourceRefs: + - kind: verification + path: tests/change-risk-compatibility/run.sh + result: pass + synthetic: false + observedRun: + source: work/coordination-change-risk-mitigation/artifacts/compatibility-slices.junit.xml + digest: "sha256:09ec614d35e04b265e8c19d0c2338c2ef16fabf02ae75d9455de9ffec61fad90" + digestContract: exact-bytes-v1 + outcome: passed + passed: 1 + failed: 0 + skipped: 0 + notes: [Umbrella compatibility verification binds this obligation to observed green phase reports and effective inversions.] + - id: EV027 + kind: verification + subject: + type: task + id: T027 + taskRefs: [T027] + requirementRefs: [] + acceptanceScenarioRefs: [] + clarificationDecisionRefs: [] + checklistResultRefs: [] + planDecisionRefs: [PD-005] + obligationRefs: [EV027] + artifacts: [work/coordination-change-risk-mitigation/artifacts/compatibility-slices.junit.xml] + sourceRefs: + - kind: verification + path: tests/change-risk-compatibility/run.sh + result: pass + synthetic: false + observedRun: + source: work/coordination-change-risk-mitigation/artifacts/compatibility-slices.junit.xml + digest: "sha256:09ec614d35e04b265e8c19d0c2338c2ef16fabf02ae75d9455de9ffec61fad90" + digestContract: exact-bytes-v1 + outcome: passed + passed: 1 + failed: 0 + skipped: 0 + notes: [Umbrella compatibility verification binds this obligation to observed green phase reports and effective inversions.] + - id: EV028 + kind: verification + subject: + type: task + id: T028 + taskRefs: [T028] + requirementRefs: [] + acceptanceScenarioRefs: [] + clarificationDecisionRefs: [] + checklistResultRefs: [] + planDecisionRefs: [PD-006] + obligationRefs: [EV028] + artifacts: [work/coordination-change-risk-mitigation/artifacts/compatibility-slices.junit.xml] + sourceRefs: + - kind: verification + path: tests/change-risk-compatibility/run.sh + result: pass + synthetic: false + observedRun: + source: work/coordination-change-risk-mitigation/artifacts/compatibility-slices.junit.xml + digest: "sha256:09ec614d35e04b265e8c19d0c2338c2ef16fabf02ae75d9455de9ffec61fad90" + digestContract: exact-bytes-v1 + outcome: passed + passed: 1 + failed: 0 + skipped: 0 + notes: [Umbrella compatibility verification binds this obligation to observed green phase reports and effective inversions.] + - id: EV029 + kind: verification + subject: + type: task + id: T029 + taskRefs: [T029] + requirementRefs: [] + acceptanceScenarioRefs: [] + clarificationDecisionRefs: [] + checklistResultRefs: [] + planDecisionRefs: [PD-007] + obligationRefs: [EV029] + artifacts: [work/coordination-change-risk-mitigation/artifacts/compatibility-slices.junit.xml] + sourceRefs: + - kind: verification + path: tests/change-risk-compatibility/run.sh + result: pass + synthetic: false + observedRun: + source: work/coordination-change-risk-mitigation/artifacts/compatibility-slices.junit.xml + digest: "sha256:09ec614d35e04b265e8c19d0c2338c2ef16fabf02ae75d9455de9ffec61fad90" + digestContract: exact-bytes-v1 + outcome: passed + passed: 1 + failed: 0 + skipped: 0 + notes: [Umbrella compatibility verification binds this obligation to observed green phase reports and effective inversions.] + - id: EV030 + kind: verification + subject: + type: task + id: T030 + taskRefs: [T030] + requirementRefs: [] + acceptanceScenarioRefs: [] + clarificationDecisionRefs: [] + checklistResultRefs: [] + planDecisionRefs: [PD-008] + obligationRefs: [EV030] + artifacts: [work/coordination-change-risk-mitigation/artifacts/compatibility-slices.junit.xml] + sourceRefs: + - kind: verification + path: tests/change-risk-compatibility/run.sh + result: pass + synthetic: false + observedRun: + source: work/coordination-change-risk-mitigation/artifacts/compatibility-slices.junit.xml + digest: "sha256:09ec614d35e04b265e8c19d0c2338c2ef16fabf02ae75d9455de9ffec61fad90" + digestContract: exact-bytes-v1 + outcome: passed + passed: 1 + failed: 0 + skipped: 0 + notes: [Umbrella compatibility verification binds this obligation to observed green phase reports and effective inversions.] + - id: EV031 + kind: verification + subject: + type: task + id: T031 + taskRefs: [T031] + requirementRefs: [] + acceptanceScenarioRefs: [] + clarificationDecisionRefs: [] + checklistResultRefs: [] + planDecisionRefs: [PD-009] + obligationRefs: [EV031] + artifacts: [work/coordination-change-risk-mitigation/artifacts/compatibility-slices.junit.xml] + sourceRefs: + - kind: verification + path: tests/change-risk-compatibility/run.sh + result: pass + synthetic: false + observedRun: + source: work/coordination-change-risk-mitigation/artifacts/compatibility-slices.junit.xml + digest: "sha256:09ec614d35e04b265e8c19d0c2338c2ef16fabf02ae75d9455de9ffec61fad90" + digestContract: exact-bytes-v1 + outcome: passed + passed: 1 + failed: 0 + skipped: 0 + notes: [Umbrella compatibility verification binds this obligation to observed green phase reports and effective inversions.] + - id: EV032 + kind: verification + subject: + type: task + id: T032 + taskRefs: [T032] + requirementRefs: [] + acceptanceScenarioRefs: [] + clarificationDecisionRefs: [] + checklistResultRefs: [] + planDecisionRefs: [] + obligationRefs: [EV032] + artifacts: [work/coordination-change-risk-mitigation/artifacts/command-catalogue-boardops.test-report.xml] + sourceRefs: + - kind: verification + path: src/FS.GG.Coord.Cli.BoardOps/Handlers.fs + result: pass + synthetic: false + observedRun: + source: work/coordination-change-risk-mitigation/artifacts/command-catalogue-boardops.test-report.xml + digest: "sha256:6a27c6dc53f7a067cdd3fd4d55cbb5d5140f888c7f8fc518f423de024a75238f" + digestContract: exact-bytes-v1 + outcome: passed + passed: 230 + failed: 0 + skipped: 0 + notes: [Compatibility path was retained through parity, then contracted without changing handler behavior.] + - id: EV033 + kind: verification + subject: + type: task + id: T033 + taskRefs: [T033] + requirementRefs: [] + acceptanceScenarioRefs: [] + clarificationDecisionRefs: [] + checklistResultRefs: [] + planDecisionRefs: [] + obligationRefs: [EV033] + artifacts: [work/coordination-change-risk-mitigation/artifacts/compatibility-slices.junit.xml] + sourceRefs: + - kind: verification + path: tests/change-risk-compatibility/run.sh + result: pass + synthetic: false + observedRun: + source: work/coordination-change-risk-mitigation/artifacts/compatibility-slices.junit.xml + digest: "sha256:09ec614d35e04b265e8c19d0c2338c2ef16fabf02ae75d9455de9ffec61fad90" + digestContract: exact-bytes-v1 + outcome: passed + passed: 1 + failed: 0 + skipped: 0 + notes: [Umbrella compatibility verification binds this obligation to observed green phase reports and effective inversions.] + - id: EV034 + kind: verification + subject: + type: task + id: T034 + taskRefs: [T034] + requirementRefs: [] + acceptanceScenarioRefs: [] + clarificationDecisionRefs: [] + checklistResultRefs: [] + planDecisionRefs: [] + obligationRefs: [EV034] + artifacts: [work/coordination-change-risk-mitigation/artifacts/compatibility-slices.junit.xml] + sourceRefs: + - kind: verification + path: tests/change-risk-compatibility/run.sh + result: pass + synthetic: false + observedRun: + source: work/coordination-change-risk-mitigation/artifacts/compatibility-slices.junit.xml + digest: "sha256:09ec614d35e04b265e8c19d0c2338c2ef16fabf02ae75d9455de9ffec61fad90" + digestContract: exact-bytes-v1 + outcome: passed + passed: 1 + failed: 0 + skipped: 0 + notes: [Umbrella compatibility verification binds this obligation to observed green phase reports and effective inversions.] + - id: EV035 + kind: verification + subject: + type: task + id: T035 + taskRefs: [T035] + requirementRefs: [] + acceptanceScenarioRefs: [] + clarificationDecisionRefs: [] + checklistResultRefs: [] + planDecisionRefs: [] + obligationRefs: [EV035] + artifacts: [work/coordination-change-risk-mitigation/artifacts/compatibility-slices.junit.xml] + sourceRefs: + - kind: verification + path: tests/change-risk-compatibility/run.sh + result: pass + synthetic: false + observedRun: + source: work/coordination-change-risk-mitigation/artifacts/compatibility-slices.junit.xml + digest: "sha256:09ec614d35e04b265e8c19d0c2338c2ef16fabf02ae75d9455de9ffec61fad90" + digestContract: exact-bytes-v1 + outcome: passed + passed: 1 + failed: 0 + skipped: 0 + notes: [Umbrella compatibility verification binds this obligation to observed green phase reports and effective inversions.] + - id: EV036 + kind: verification + subject: + type: task + id: T036 + taskRefs: [T036] + requirementRefs: [] + acceptanceScenarioRefs: [] + clarificationDecisionRefs: [] + checklistResultRefs: [] + planDecisionRefs: [] + obligationRefs: [EV036] + artifacts: [work/coordination-change-risk-mitigation/artifacts/compatibility-slices.junit.xml] + sourceRefs: + - kind: verification + path: tests/change-risk-compatibility/run.sh + result: pass + synthetic: false + observedRun: + source: work/coordination-change-risk-mitigation/artifacts/compatibility-slices.junit.xml + digest: "sha256:09ec614d35e04b265e8c19d0c2338c2ef16fabf02ae75d9455de9ffec61fad90" + digestContract: exact-bytes-v1 + outcome: passed + passed: 1 + failed: 0 + skipped: 0 + notes: [Umbrella compatibility verification binds this obligation to observed green phase reports and effective inversions.] + - id: EV037 + kind: verification + subject: + type: task + id: T037 + taskRefs: [T037] + requirementRefs: [] + acceptanceScenarioRefs: [] + clarificationDecisionRefs: [] + checklistResultRefs: [] + planDecisionRefs: [PD-001] + obligationRefs: [EV037] + artifacts: [work/coordination-change-risk-mitigation/artifacts/compatibility-slices.junit.xml] + sourceRefs: + - kind: verification + path: tests/change-risk-compatibility/run.sh + result: pass + synthetic: false + observedRun: + source: work/coordination-change-risk-mitigation/artifacts/compatibility-slices.junit.xml + digest: "sha256:09ec614d35e04b265e8c19d0c2338c2ef16fabf02ae75d9455de9ffec61fad90" + digestContract: exact-bytes-v1 + outcome: passed + passed: 1 + failed: 0 + skipped: 0 + notes: [Umbrella compatibility verification binds this obligation to observed green phase reports and effective inversions.] + - id: EV038 + kind: verification + subject: + type: task + id: T038 + taskRefs: [T038] + requirementRefs: [] + acceptanceScenarioRefs: [] + clarificationDecisionRefs: [] + checklistResultRefs: [] + planDecisionRefs: [PD-002] + obligationRefs: [EV038] + artifacts: [work/coordination-change-risk-mitigation/artifacts/command-catalogue-kernel.test-report.xml] + sourceRefs: + - kind: verification + path: src/FS.GG.Coord.Cli.Kernel/Options.fs + result: pass + synthetic: false + observedRun: + source: work/coordination-change-risk-mitigation/artifacts/command-catalogue-kernel.test-report.xml + digest: "sha256:e7466626f850f7f84423420b31f05fa4ef5952f485dd7a3c0db01dec7d6b71b1" + digestContract: exact-bytes-v1 + outcome: passed + passed: 181 + failed: 0 + skipped: 0 + notes: [Command contract and positive conformance cases are deterministic catalogue projections.] + - id: EV039 + kind: verification + subject: + type: task + id: T039 + taskRefs: [T039] + requirementRefs: [] + acceptanceScenarioRefs: [] + clarificationDecisionRefs: [] + checklistResultRefs: [] + planDecisionRefs: [PD-004] + obligationRefs: [EV039] + artifacts: [work/coordination-change-risk-mitigation/artifacts/compatibility-slices.junit.xml] + sourceRefs: + - kind: verification + path: tests/change-risk-compatibility/run.sh + result: pass + synthetic: false + observedRun: + source: work/coordination-change-risk-mitigation/artifacts/compatibility-slices.junit.xml + digest: "sha256:09ec614d35e04b265e8c19d0c2338c2ef16fabf02ae75d9455de9ffec61fad90" + digestContract: exact-bytes-v1 + outcome: passed + passed: 1 + failed: 0 + skipped: 0 + notes: [Umbrella compatibility verification binds this obligation to observed green phase reports and effective inversions.] +lifecycleNotes: + - "Next lifecycle action: verify." diff --git a/work/coordination-change-risk-mitigation/phase-0-baseline.json b/work/coordination-change-risk-mitigation/phase-0-baseline.json new file mode 100644 index 000000000..dc9436e3e --- /dev/null +++ b/work/coordination-change-risk-mitigation/phase-0-baseline.json @@ -0,0 +1,73 @@ +{ + "schemaVersion": 1, + "workId": "coordination-change-risk-mitigation", + "capturedAt": "2026-08-22", + "sourceHead": "e31132dec1a93a260a76916c6807ed630c7cba17", + "sample": { + "enginePullRequests": 4, + "incidentCount": 5, + "minimumMonthlyEnginePullRequests": 20 + }, + "commandAddition": { + "incident": ".github#2753", + "mergeCommit": "484f23fff1d113581c3c4c8410b76479420d9a79", + "authoredInventoryLocations": 12, + "locations": [ + "Options.Command union case", + "Options help row", + "Options.renderSupport arm", + "Options.writeDisposition arm", + "Options verb arm", + "HandlerRegistration.Implementations field", + "HandlerRegistration.commands row", + "HandlerRegistration.handlers row", + "CommandSurfaceTests command row", + "OptionsTests bare-render row", + "HandlerRegistrationTests implementation field", + "ApplicationServiceTests dispatch arm" + ], + "targetReductionPercent": 50 + }, + "observedIncidents": [ + { + "item": ".github#2753", + "mergeCommit": "484f23fff1d113581c3c4c8410b76479420d9a79", + "class": "command metadata and handler registration amplification" + }, + { + "item": ".github#2773", + "mergeCommit": "a6adfe306b98acc19b3920414efb47d75f4f4333", + "class": "delivery and verify-paths classifier divergence" + }, + { + "item": ".github#2819", + "mergeCommit": "e31132dec1a93a260a76916c6807ed630c7cba17", + "class": "review projection and escalation-writer divergence" + }, + { + "item": ".github#2820", + "mergeCommit": "340cbfa3aad6768b0fb34a6ae8ad717a15e45242", + "class": "immutable release recovery attempted asset mutation" + }, + { + "item": ".github#643", + "mergeCommit": "6f916e42", + "class": "narrative closing keyword projected premature completion" + } + ], + "monthlyMetrics": [ + "median authored inventory locations per command addition", + "median time to first actionable CI failure", + "percentage of critic findings that are structural completeness omissions", + "review rounds consumed before a semantically reviewable head", + "projection and writer divergence incidents", + "items corrected from premature Done", + "self-host transitions with a complete bootstrap receipt", + "releases requiring manual journal or receiver-state intervention" + ], + "invariantTargets": { + "projectionWriterDivergences": 0, + "prematureDoneStates": 0, + "unreceiptedSelfHostWrites": 0 + } +} diff --git a/work/coordination-change-risk-mitigation/phase-0-baseline.md b/work/coordination-change-risk-mitigation/phase-0-baseline.md new file mode 100644 index 000000000..83702d372 --- /dev/null +++ b/work/coordination-change-risk-mitigation/phase-0-baseline.md @@ -0,0 +1,38 @@ +# Phase 0 baseline: coordination change amplification + +Snapshot date: 2026-08-22 +Source head: `e31132dec1a93a260a76916c6807ed630c7cba17` + +The machine-readable snapshot is `phase-0-baseline.json`. It freezes the incident corpus and metric +definitions before a new authority is introduced. It deliberately does not manufacture elapsed-time or +review-ledger values that cannot be recovered from committed repository state. + +## Command-addition baseline + +The `.github#2753` merge added `comment` at twelve independently authored inventory locations: five in +`Options`, three in `HandlerRegistration`, and four in positive test or dispatch inventories. This count +excludes the command's actual handler behavior, transport implementation, negative tests, documentation, +SDD artifacts, generated readiness views, packaging, and registry updates; it measures only repeated facts +that the catalogue design intends to derive or close mechanically. + +The target is at least a 50% reduction in authored inventory locations. With this baseline, a future nullary +command must require at most six such locations, while the design's stronger target remains one descriptor +and one handler binding. + +## Frozen incident corpus + +- `.github#2753` at merge `484f23ff`: command metadata and handler registration amplification. +- `.github#2773` at merge `a6adfe30`: delivery and `verify-paths` classifier divergence. +- `.github#2819` at merge `e31132de`: review projection and escalation-writer divergence. +- `.github#2820` at merge `340cbfa3`: immutable recovery attempted to mutate release evidence. +- `.github#643` at commit `6f916e42`: narrative text triggered a premature completion projection. + +These are references to immutable Git objects and committed work artifacts. Later fixtures may minimize +their facts, but must retain the incident and source-commit binding. + +## Monthly measurement contract + +Report the eight metric names in `phase-0-baseline.json` over at least twenty engine pull requests. Every +report must name its exact PR sample and observation window. A missing observation is reported as unknown, +not zero. Projection/writer divergence, premature `Done`, and unreceipted self-host writes have invariant +targets of zero; the metrics are not permission to average those failures away. diff --git a/work/coordination-change-risk-mitigation/plan.md b/work/coordination-change-risk-mitigation/plan.md new file mode 100644 index 000000000..b9e4f188b --- /dev/null +++ b/work/coordination-change-risk-mitigation/plan.md @@ -0,0 +1,137 @@ +--- +schemaVersion: 1 +workId: coordination-change-risk-mitigation +title: Coordination Change Risk Mitigation +stage: plan +changeTier: tier1 +status: planned +sourceSpec: work/coordination-change-risk-mitigation/spec.md +sourceClarifications: work/coordination-change-risk-mitigation/clarifications.md +sourceChecklist: work/coordination-change-risk-mitigation/checklist.md +publicOrToolFacingImpact: true +--- + +# Coordination Change Risk Mitigation Plan + +Prose status: planned + +## Source Snapshot +- spec: work/coordination-change-risk-mitigation/spec.md sha256:596003775028144db71fd9a411385e205ed07488ee164d79471c153bb0ec084e schemaVersion:1 +- clarifications: work/coordination-change-risk-mitigation/clarifications.md sha256:02eedf550b282d9788487b3efbd6f0034d35e5982b70dcf8abf01bd6fa61b18c schemaVersion:1 +- checklist: work/coordination-change-risk-mitigation/checklist.md sha256:ac1c0ac8b8feafbedd9582ac17b8196e57b46867459a31c380cbb83e0a342548 schemaVersion:1 + +## Plan Scope +- Execute phases 0 through 5 from the source design as an expand-and-contract program; every phase is independently + mergeable and reversible, and no phase silently absorbs another phase's authority or cleanup. +- Preserve existing wire schemas during compatibility slices. New internal discriminated unions and records translate + at adapter boundaries until a separately reviewed schema migration is required. +- Keep full suites, production-shaped HTTP tests, independent review, provenance checks, and release gates. The new + catalogue and models remove authored duplication, not independent observation. +- Treat source snapshots from `.github#2753`, `#2773`, `#2819`, `#2820`, and `#643` as the initial behavioral corpus. + +## Plan Decisions +- PD-001 [AC-009] [FR-009] complete: Phase 0 records command-addition edit count, first-actionable-red time, + structural-review findings, review rounds, divergence and premature-completion incidents, self-host receipts, and + release interventions; freeze incident snapshots before adding authority. +- PD-002 [AC-001] [FR-001] complete: Phase 1 adds the kernel-owned `CommandDescriptor` catalogue beside existing + tables, exposes one `(Command * Handler)` binding list from BoardOps, derives positive conformance cases, and removes + duplicate structures only after byte-identical contract/help output and an effective missing-member inversion pass. +- PD-003 [AC-002] [FR-002] complete: Phase 2 introduces complete fact and decision types for ordinary exhaustion, + delivery completion, host acceptance, merge authorization, and recovery; route every projection and writer through + the returned decision and add a source gate against consumer-local fact matching. +- PD-004 [AC-003] [FR-003] complete: Phase 3 appends `DeliveryCompletionReceipt` before projections, converts close + automation to reconciliation dispatch, observes would-correct behavior, then enables fail-closed reopen/status + correction and finally requires the receipt. +- PD-005 [AC-004] [FR-004] complete: Phase 4 binds candidate bytes, version, base/head, refusal, evidence, decision and + action keys in `SelfHostBootstrapReceipt`; only the stable shared verifier plus accountable host acceptance may + authorize a write, and post-merge shared-engine replay blocks completion on disagreement. +- PD-006 [AC-005] [FR-005] complete: Phase 4 also introduces `change-completeness` as advisory, measures duration and + false positives, then makes it required and a prerequisite of expensive mutation jobs and critic dispatch without + removing their path-sensitive execution. +- PD-007 [AC-006] [FR-006] complete: Build bounded Review and Delivery reference models over verdict/check/round/head/ + wait/claim/obligation classes and assert `projection == writer == reducer`; retain production-shaped HTTP fixtures + and add a mutation for each new shared boundary that forks or removes one predicate clause. +- PD-008 [AC-007] [FR-007] complete: Phase 5 keeps promotion as the only immutability transition, makes immutable retry + verify existing journals with zero asset writes, persists append-only receiver receipts outside the asset set, and + includes every declared receiver in coherent-set completion. +- PD-009 [AC-008] [FR-008] complete: Gate every predecessor-path deletion on behavior parity plus a demonstrated + inversion, record rollback as restoring the coexistence path for that phase, and never combine deletion with first + introduction of its replacement. + +## Contract Impact +- PC-001 [PD-002] command surface: Catalogue descriptors become the source for verb, render support, mutation kind, + documentation coverage, and expected handler ownership; parser behavior remains explicit. +- PC-002 [PD-003] lifecycle decisions: Complete typed fact/decision contracts become the in-process authority shared + by projection, admission, and reduction while current JSON is translated at adapters. +- PC-003 [PD-004] completion evidence: `DeliveryCompletionReceipt` becomes the durable authority for closure, `Done`, + claim release, and cleanup projections. +- PC-004 [PD-005] self-host evidence: `SelfHostBootstrapReceipt` and its enumerated reason vocabulary become required + inputs to any candidate-engine write path. +- PC-005 [PD-006] CI contract: `change-completeness` becomes a required context and dependency predecessor after its + advisory qualification period. +- PC-006 [PD-007] conformance contract: Each shared decision boundary declares a bounded reference model and an + effective divergence mutation. +- PC-007 [PD-008] release contract: Receiver delivery receipts become append-only coherent-set obligations outside + immutable assets. + +## Verification Obligations +- VO-001 [PD-001] baseline: Record reproducible phase-0 measurements and freeze incident snapshots before authority + migration, including the exact sample and timestamp for every metric. +- VO-002 [PD-002] [PC-001] catalogueConformance: Prove descriptor closure over nullary union cases, unique verbs, + parser/render/help/write/documentation conformance, exact BoardOps handler ownership, and byte-identical public + output during coexistence. +- VO-003 [PD-002] [PC-001] catalogueMutation: Remove one descriptor, handler, parser arm, render implementation, and + write classification in turn and observe a named `change-completeness` failure for each. +- VO-004 [PD-003] [PD-007] [PC-002] lifecycleParity: Run the bounded state cross-products and prove projection, + writer admission, and reducer transition agree for every generated history. +- VO-005 [PD-004] [PC-003] completionReconciliation: Exercise exact-merge success plus absent, stale, contradictory, + unreachable, pending-board-write, and auto-closed-without-receipt cases, proving receipt-first idempotent correction. +- VO-006 [PD-005] [PC-004] selfHostTrust: Exercise every allowed bootstrap reason and refuse unknown reasons, + business-rule disagreement, digest/version/head drift, incomplete evidence, missing host acceptance, and replay + disagreement with zero remote mutation. +- VO-007 [PD-006] [PC-005] ciOrdering: Measure the focused gate under ordinary changes, prove structural reds occur + before critic dispatch, and inspect workflow dependencies showing expensive jobs cannot start before it settles. +- VO-008 [PD-007] [PC-006] modelMutation: Remove each predicate clause or fork one consumer and record an observed + focused-suite failure before restoring and rerunning green. +- VO-009 [PD-008] [PC-007] releaseRecovery: Rehearse mutable, promoted-immutable, partial-feed, and partial-receiver + histories; assert zero immutable asset writes and verified receipts for every required receiver. +- VO-010 [PD-009] compatibilityAndRollback: For every phase, capture before/after parity, effective inversion, the exact + predecessor deletion, and a rollback rehearsal that restores the coexistence path without data loss. + +## Performance Intent +- `change-completeness` targets completion within five minutes for ordinary changes and adds no unnecessary network + sweep; longer mutation, derived, and cross-repository checks remain later stages. +- Shared lifecycle decisions operate over already collected complete facts and do not add duplicate GitHub reads. +- Monthly metrics cover at least twenty engine PRs before claiming the command-change amplification target. + +## Migration Posture +- PM-001 [PC-001] expandContract: Catalogue and legacy command tables coexist until byte/behavior parity and inversion. +- PM-002 [PC-002] compatibleAdapters: New internal decisions translate to existing JSON schemas unless a separately + versioned migration is explicitly approved. +- PM-003 [PC-003] stagedAuthority: Completion correction runs in observe-only mode before writes and becomes required + only after reconciliation evidence is stable. +- PM-004 [PC-005] advisoryToRequired: `change-completeness` is advisory until its duration and false-positive rate are + measured, then becomes required before dependency rewiring. +- PM-005 [PC-007] appendOnly: Receiver receipts extend release evidence without rewriting promoted assets or journals. + +## Generated View Impact +- GV-001 [PD-001] workModel: `readiness/coordination-change-risk-mitigation/work-model.json` and `analysis.json` are + regenerated from current lifecycle sources by `fsgg-sdd analyze`; they are projections and are never hand-edited. +- GV-002 [PD-002] commandProjections: Command contracts, help coverage, render defaults, write classification, and + positive conformance cases become deterministic projections over the catalogue. +- GV-003 [PD-004] completionProjections: Issue state, Projects status, claim, and cleanup become reconcilable projections + over the completion receipt rather than authorities. + +## Accepted Deferrals +No accepted plan deferrals recorded. + +## Planning Findings +No blocking planning findings recorded. + +## Advisory Notes +- The source design's monthly success targets remain outcome measures, not permission to weaken fail-closed behavior. +- Exact implementation touch sets must be declared per phase because this umbrella plan intentionally spans the + coordination engine, tests, workflows, and release lifecycle. + +## Lifecycle Notes +- Next lifecycle action: `fsgg-sdd tasks --work coordination-change-risk-mitigation`. diff --git a/work/coordination-change-risk-mitigation/spec.md b/work/coordination-change-risk-mitigation/spec.md new file mode 100644 index 000000000..995f6ac51 --- /dev/null +++ b/work/coordination-change-risk-mitigation/spec.md @@ -0,0 +1,106 @@ +--- +schemaVersion: 1 +workId: coordination-change-risk-mitigation +title: Coordination Change Risk Mitigation +stage: specify +changeTier: tier1 +status: specified +publicOrToolFacingImpact: true +--- + +# Coordination Change Risk Mitigation Specification + +Prose status: specified + +## User Value + +A coordination-engine contributor can change a command or lifecycle rule at one typed authority boundary and +receive an actionable structural failure before expensive CI or independent review. Operators can trust that +review, merge, completion, self-hosting, and release recovery advance only from exact, durable evidence rather +than from duplicated projections or issue state. + +## Scope +- SB-001: Introduce one kernel-owned command catalogue for declarative command metadata and one BoardOps handler + binding list. +- SB-002: Introduce complete fact and decision types for disputed review, delivery, merge, completion, and recovery + transitions, consumed by both read and write paths. +- SB-003: Make completion receipt-gated and reconcile GitHub issue and Projects projections from that receipt. +- SB-004: Introduce digest-bound self-host bootstrap receipts with host acceptance and post-merge replay. +- SB-005: Add a bounded `change-completeness` gate before expensive mutation jobs and critic dispatch. +- SB-006: Add bounded model-based Review and Delivery conformance with effective consumer-divergence mutations. +- SB-007: Preserve immutable release recovery and add append-only receiver delivery receipts. +- SB-008: Deliver the change through independently mergeable compatibility slices with baseline and monthly metrics. + +## Non-Goals +- SB-009: Do not generate the `Command` union or heterogeneous parser behavior. +- SB-010: Do not replace independent tests with catalogue self-assertion or remove full/mutation/release suites. +- SB-011: Do not treat issue closure, Projects status, comments, dashboards, or candidate-engine output as completion + authority. +- SB-012: Do not rewrite immutable release assets or broaden bootstrap reasons to business-rule disagreement. +- SB-013: Do not delete predecessor paths until parity and an effective inversion have passed. + +## User Stories +- US-001 (P1): As a command author, I add declarative metadata once and receive named failures for any missing parser, + renderer, handler, documentation, or write-classification behavior. +- US-002 (P1): As a lifecycle operator, I see the same transition verdict on projections and writers because both + consume one complete typed decision. +- US-003 (P1): As a delivery owner, I know `Done` means the exact merge and every declared obligation are receipted, + reachable, and free of pending board writes. +- US-004 (P1): As a host accepting an engine self-change, I can audit the exact candidate bytes, refusal reason, + evidence, decision keys, and post-merge replay. +- US-005 (P2): As a reviewer, structural omissions are rejected before my bounded review round is consumed. +- US-006 (P1): As a release operator, I can resume receiver delivery after promotion without mutating immutable assets. + +## Acceptance Scenarios +- AC-001 [US-001] [FR-001]: Given a nullary command addition, when change completeness runs, then one authored + descriptor and one handler binding derive all metadata and positive cases, while removal of any required behavior + produces a named red. +- AC-002 [US-002] [FR-002]: Given every bounded review verdict, check state, round, head, wait, and claim generation, + when projection, writer admission, and reducer transition are evaluated, then all three return the same decision. +- AC-003 [US-003] [FR-003]: Given a merged item with absent, stale, contradictory, or incomplete obligation evidence, + when completion is reconciled, then no valid completion receipt is appended and `Done` is refused or corrected. +- AC-004 [US-004] [FR-004]: Given a shared engine that refuses for an enumerated bootstrap reason, when a candidate + proposes a transition, then no write occurs without a digest-bound receipt, stable-verifier acceptance, accountable + host acceptance, and post-merge replay. +- AC-005 [US-005] [FR-005]: Given an authored structural omission, when CI is scheduled, then `change-completeness` + reports the actionable red before critic dispatch and targets completion within five minutes. +- AC-006 [US-002] [FR-006]: Given the bounded Review and Delivery state spaces, when any one shared predicate clause + is removed or one consumer forks the decision, then the model suite fails. +- AC-007 [US-006] [FR-007]: Given a promoted immutable release with partial receiver delivery, when recovery runs, + then it verifies the existing journal, performs zero release-asset writes, resumes receivers, and appends every + required receiver receipt outside the immutable asset set. +- AC-008 [US-001] [US-005] [FR-008]: Given each rollout phase, when its predecessor path is considered for removal, + then byte/behavior parity and an effective inversion have passed, and the phase remains independently reversible. +- AC-009 [US-003] [US-006] [FR-009]: Given at least twenty engine PRs and a monthly measurement window, when metrics + are reported, then command edit count, first-actionable-red time, structural critic findings, review rounds, + divergences, premature `Done`, self-host receipts, and release interventions are all measured. + +## Functional Requirements +- FR-001: The engine MUST own one exhaustive command catalogue and one BoardOps handler binding list, deriving declarative command metadata and conformance cases while keeping heterogeneous parser arms explicit. (Stories: US-001; Acceptance: AC-001) +- FR-002: Every disputed lifecycle transition MUST expose one complete typed fact input and decision output consumed unchanged by projection and writer admission; writers may add only freshness, idempotency, and effect mechanics. (Stories: US-002; Acceptance: AC-002) +- FR-003: Completion MUST require an exact-merge `DeliveryCompletionReceipt` proving reachability, verified declared obligations, no contradictions, and zero pending board writes before projecting issue closure or `Status=Done`. (Stories: US-003; Acceptance: AC-003) +- FR-004: Candidate-engine writes MUST require an enumerated bootstrap reason, a digest-bound `SelfHostBootstrapReceipt`, stable-verifier validation, accountable host acceptance, and post-merge shared-engine replay. (Stories: US-004; Acceptance: AC-004) +- FR-005: A required `change-completeness` context MUST run structural closure, parity, path, message, provenance, and focused route checks before independent review and expensive mutation work, with a five-minute ordinary-change target. (Stories: US-005; Acceptance: AC-005) +- FR-006: Bounded Review and Delivery models MUST prove projection decision, writer admission, and reducer transition parity, and MUST include effective mutations that make every consumer red on divergence. (Stories: US-002; Acceptance: AC-006) +- FR-007: Immutable release recovery MUST verify existing journal and artifact identity, perform zero asset mutation, resume downstream delivery, and append verified receiver receipts outside the immutable asset set. (Stories: US-006; Acceptance: AC-007) +- FR-008: Rollout MUST use independently mergeable, reversible compatibility slices and MUST retain predecessor paths until behavior parity and an effective inversion pass. (Stories: US-001, US-005; Acceptance: AC-008) +- FR-009: The implementation MUST establish phase-0 baselines and monthly success metrics, with zero divergence, premature `Done`, and unreceipted self-host writes as invariant targets. (Stories: US-003, US-006; Acceptance: AC-009) + +## Ambiguities +- AMB-001: Whether the command catalogue should initially coexist with or immediately replace the BoardOps + `Implementations` record and duplicate commands list. +- AMB-002: Which existing JSON schemas must change for lifecycle decisions and receipts versus translating new + internal types at current adapter boundaries. +- AMB-003: When `change-completeness` becomes required rather than advisory. +- AMB-004: Where receiver delivery receipts live so they remain append-only and outside immutable release assets. + +## Public Or Tool-Facing Impact +- Command-contract, help, render, write-classification, and documentation projections become catalogue-derived. +- New completion, bootstrap, and receiver-receipt contracts become durable tool-facing evidence. +- GitHub close events and Projects automation become reconciliation triggers rather than completion authority. +- CI gains the `change-completeness` context and dependency ordering. +- Existing JSON schemas remain stable during the compatibility phase unless a separately versioned migration is + explicitly accepted. + +## Lifecycle Notes +- Next lifecycle action: `fsgg-sdd clarify --work coordination-change-risk-mitigation`. diff --git a/work/coordination-change-risk-mitigation/tasks.yml b/work/coordination-change-risk-mitigation/tasks.yml new file mode 100644 index 000000000..f28e39116 --- /dev/null +++ b/work/coordination-change-risk-mitigation/tasks.yml @@ -0,0 +1,427 @@ +schemaVersion: 1 +work: + id: coordination-change-risk-mitigation + title: "Coordination Change Risk Mitigation" + stage: tasks + status: tasksReady + sourceSpec: work/coordination-change-risk-mitigation/spec.md + sourceClarifications: work/coordination-change-risk-mitigation/clarifications.md + sourceChecklist: work/coordination-change-risk-mitigation/checklist.md + sourcePlan: work/coordination-change-risk-mitigation/plan.md + publicOrToolFacingImpact: true + +sources: + - label: spec + path: work/coordination-change-risk-mitigation/spec.md + digest: 596003775028144db71fd9a411385e205ed07488ee164d79471c153bb0ec084e + schemaVersion: 1 + - label: clarifications + path: work/coordination-change-risk-mitigation/clarifications.md + digest: 02eedf550b282d9788487b3efbd6f0034d35e5982b70dcf8abf01bd6fa61b18c + schemaVersion: 1 + - label: checklist + path: work/coordination-change-risk-mitigation/checklist.md + digest: ac1c0ac8b8feafbedd9582ac17b8196e57b46867459a31c380cbb83e0a342548 + schemaVersion: 1 + - label: plan + path: work/coordination-change-risk-mitigation/plan.md + digest: 6ac822bae2e476fadcadf67890e437775bafd311f11baf6574cc70c48e1dcab6 + schemaVersion: 1 +tasks: + - id: T001 + title: Implement requirement FR-001 + status: done + owner: sdd + dependencies: [T009] + requirements: [FR-001] + decisions: [] + sourceIds: [AC-001, FR-001, PD-002] + requiredSkills: [] + requiredEvidence: [EV001] + - id: T002 + title: Implement requirement FR-002 + status: done + owner: sdd + dependencies: [T001] + requirements: [FR-002] + decisions: [] + sourceIds: [AC-002, FR-002, PD-003] + requiredSkills: [] + requiredEvidence: [EV002] + - id: T003 + title: Implement requirement FR-003 + status: done + owner: sdd + dependencies: [T002, T006] + requirements: [FR-003] + decisions: [] + sourceIds: [AC-003, FR-003, PD-004] + requiredSkills: [] + requiredEvidence: [EV003] + - id: T004 + title: Implement requirement FR-004 + status: done + owner: sdd + dependencies: [T003] + requirements: [FR-004] + decisions: [] + sourceIds: [AC-004, FR-004, PD-005] + requiredSkills: [] + requiredEvidence: [EV004] + - id: T005 + title: Implement requirement FR-005 + status: done + owner: sdd + dependencies: [T003] + requirements: [FR-005] + decisions: [] + sourceIds: [AC-005, FR-005, PD-006] + requiredSkills: [] + requiredEvidence: [EV005] + - id: T006 + title: Implement requirement FR-006 + status: done + owner: sdd + dependencies: [T002] + requirements: [FR-006] + decisions: [] + sourceIds: [AC-006, FR-006, PD-007] + requiredSkills: [] + requiredEvidence: [EV006] + - id: T007 + title: Implement requirement FR-007 + status: done + owner: sdd + dependencies: [T004, T005, T006] + requirements: [FR-007] + decisions: [] + sourceIds: [AC-007, FR-007, PD-008] + requiredSkills: [] + requiredEvidence: [EV007] + - id: T008 + title: Implement requirement FR-008 + status: done + owner: sdd + dependencies: [T007] + requirements: [FR-008] + decisions: [] + sourceIds: [AC-008, FR-008, PD-009] + requiredSkills: [] + requiredEvidence: [EV008] + - id: T009 + title: Implement requirement FR-009 + status: done + owner: sdd + dependencies: [] + requirements: [FR-009] + decisions: [] + sourceIds: [AC-009, FR-009, PD-001] + requiredSkills: [] + requiredEvidence: [EV009] + - id: T010 + title: Implement clarification decision DEC-001 + status: done + owner: sdd + dependencies: [T001] + requirements: [] + decisions: [DEC-001] + sourceIds: [DEC-001] + requiredSkills: [] + requiredEvidence: [EV010] + - id: T011 + title: Implement clarification decision DEC-002 + status: done + owner: sdd + dependencies: [T002] + requirements: [] + decisions: [DEC-002] + sourceIds: [DEC-002] + requiredSkills: [] + requiredEvidence: [EV011] + - id: T012 + title: Implement clarification decision DEC-003 + status: done + owner: sdd + dependencies: [T005] + requirements: [] + decisions: [DEC-003] + sourceIds: [DEC-003] + requiredSkills: [] + requiredEvidence: [EV012] + - id: T013 + title: Implement clarification decision DEC-004 + status: done + owner: sdd + dependencies: [T007] + requirements: [] + decisions: [DEC-004] + sourceIds: [DEC-004] + requiredSkills: [] + requiredEvidence: [EV013] + - id: T014 + title: Implement clarification decision DEC-005 + status: done + owner: sdd + dependencies: [T008] + requirements: [] + decisions: [DEC-005] + sourceIds: [DEC-005] + requiredSkills: [] + requiredEvidence: [EV014] + - id: T015 + title: Update contract surface PC-001 + status: done + owner: sdd + dependencies: [T001] + requirements: [] + decisions: [] + sourceIds: [PC-001, PD-002] + requiredSkills: [] + requiredEvidence: [EV015] + - id: T016 + title: Update contract surface PC-002 + status: done + owner: sdd + dependencies: [T002] + requirements: [] + decisions: [] + sourceIds: [PC-002, PD-003] + requiredSkills: [] + requiredEvidence: [EV016] + - id: T017 + title: Update contract surface PC-003 + status: done + owner: sdd + dependencies: [T003] + requirements: [] + decisions: [] + sourceIds: [PC-003, PD-004] + requiredSkills: [] + requiredEvidence: [EV017] + - id: T018 + title: Update contract surface PC-004 + status: done + owner: sdd + dependencies: [T004] + requirements: [] + decisions: [] + sourceIds: [PC-004, PD-005] + requiredSkills: [] + requiredEvidence: [EV018] + - id: T019 + title: Update contract surface PC-005 + status: done + owner: sdd + dependencies: [T005] + requirements: [] + decisions: [] + sourceIds: [PC-005, PD-006] + requiredSkills: [] + requiredEvidence: [EV019] + - id: T020 + title: Update contract surface PC-006 + status: done + owner: sdd + dependencies: [T006] + requirements: [] + decisions: [] + sourceIds: [PC-006, PD-007] + requiredSkills: [] + requiredEvidence: [EV020] + - id: T021 + title: Update contract surface PC-007 + status: done + owner: sdd + dependencies: [T007] + requirements: [] + decisions: [] + sourceIds: [PC-007, PD-008] + requiredSkills: [] + requiredEvidence: [EV021] + - id: T022 + title: Record verification evidence VO-001 + status: done + owner: sdd + dependencies: [T009] + requirements: [] + decisions: [] + sourceIds: [PD-001, VO-001] + requiredSkills: [] + requiredEvidence: [EV022] + - id: T023 + title: Record verification evidence VO-002 + status: done + owner: sdd + dependencies: [T015] + requirements: [] + decisions: [] + sourceIds: [PC-001, PD-002, VO-002] + requiredSkills: [] + requiredEvidence: [EV023] + - id: T024 + title: Record verification evidence VO-003 + status: done + owner: sdd + dependencies: [T015] + requirements: [] + decisions: [] + sourceIds: [PC-001, PD-002, VO-003] + requiredSkills: [] + requiredEvidence: [EV024] + - id: T025 + title: Record verification evidence VO-004 + status: done + owner: sdd + dependencies: [T016, T020] + requirements: [] + decisions: [] + sourceIds: [PC-002, PD-003, PD-007, VO-004] + requiredSkills: [] + requiredEvidence: [EV025] + - id: T026 + title: Record verification evidence VO-005 + status: done + owner: sdd + dependencies: [T017] + requirements: [] + decisions: [] + sourceIds: [PC-003, PD-004, VO-005] + requiredSkills: [] + requiredEvidence: [EV026] + - id: T027 + title: Record verification evidence VO-006 + status: done + owner: sdd + dependencies: [T018] + requirements: [] + decisions: [] + sourceIds: [PC-004, PD-005, VO-006] + requiredSkills: [] + requiredEvidence: [EV027] + - id: T028 + title: Record verification evidence VO-007 + status: done + owner: sdd + dependencies: [T019] + requirements: [] + decisions: [] + sourceIds: [PC-005, PD-006, VO-007] + requiredSkills: [] + requiredEvidence: [EV028] + - id: T029 + title: Record verification evidence VO-008 + status: done + owner: sdd + dependencies: [T020] + requirements: [] + decisions: [] + sourceIds: [PC-006, PD-007, VO-008] + requiredSkills: [] + requiredEvidence: [EV029] + - id: T030 + title: Record verification evidence VO-009 + status: done + owner: sdd + dependencies: [T021] + requirements: [] + decisions: [] + sourceIds: [PC-007, PD-008, VO-009] + requiredSkills: [] + requiredEvidence: [EV030] + - id: T031 + title: Record verification evidence VO-010 + status: done + owner: sdd + dependencies: [T008, T022, T023, T024, T025, T026, T027, T028, T029, T030] + requirements: [] + decisions: [] + sourceIds: [PD-009, VO-010] + requiredSkills: [] + requiredEvidence: [EV031] + - id: T032 + title: Handle migration posture PM-001 + status: done + owner: sdd + dependencies: [T015] + requirements: [] + decisions: [] + sourceIds: [PC-001, PM-001] + requiredSkills: [] + requiredEvidence: [EV032] + - id: T033 + title: Handle migration posture PM-002 + status: done + owner: sdd + dependencies: [T016] + requirements: [] + decisions: [] + sourceIds: [PC-002, PM-002] + requiredSkills: [] + requiredEvidence: [EV033] + - id: T034 + title: Handle migration posture PM-003 + status: done + owner: sdd + dependencies: [T017] + requirements: [] + decisions: [] + sourceIds: [PC-003, PM-003] + requiredSkills: [] + requiredEvidence: [EV034] + - id: T035 + title: Handle migration posture PM-004 + status: done + owner: sdd + dependencies: [T019] + requirements: [] + decisions: [] + sourceIds: [PC-005, PM-004] + requiredSkills: [] + requiredEvidence: [EV035] + - id: T036 + title: Handle migration posture PM-005 + status: done + owner: sdd + dependencies: [T021] + requirements: [] + decisions: [] + sourceIds: [PC-007, PM-005] + requiredSkills: [] + requiredEvidence: [EV036] + - id: T037 + title: Refresh generated view impact GV-001 + status: done + owner: sdd + dependencies: [T031] + requirements: [] + decisions: [] + sourceIds: [GV-001, PD-001] + requiredSkills: [] + requiredEvidence: [EV037] + - id: T038 + title: Refresh generated view impact GV-002 + status: done + owner: sdd + dependencies: [T015] + requirements: [] + decisions: [] + sourceIds: [GV-002, PD-002] + requiredSkills: [] + requiredEvidence: [EV038] + - id: T039 + title: Refresh generated view impact GV-003 + status: done + owner: sdd + dependencies: [T017] + requirements: [] + decisions: [] + sourceIds: [GV-003, PD-004] + requiredSkills: [] + requiredEvidence: [EV039] +acceptedDeferrals: [] +findings: [] +advisoryNotes: + - "Optional Governance pointers remain compatibility facts only." + - "Break-glass dependency correction: the 1.1.0 generator flattened all FR tasks to parallel roots; the hybrid artifact directly sequences phases 0 through 5. Regenerating tasks without preserving these edges reintroduces that drift." +lifecycleNotes: + - "Next lifecycle action: fsgg-sdd analyze --work coordination-change-risk-mitigation."