Skip to content

feat(bin): sort a failed required check as code bug, flaky, or environment, opt-in - #47

Closed
talktejas wants to merge 6 commits into
mainfrom
fm/fm-jev-failed-check-sort
Closed

talktejas wants to merge 6 commits into
mainfrom
fm/fm-jev-failed-check-sort

Conversation

@talktejas

Copy link
Copy Markdown
Owner

Intent

A research report on using Jev (TypeSafe's decision-only model) in the coding workflow proposed ten integrations in one table. The answer on row 9: "implement". Later, on merging: "merge all jev items".

Row 9 as it was shown:

  • What it does: Sort a failed automated check: code bug, flaky test, or broken environment. Fixed rules decide first (passed on retry means flaky; connection errors with no code change means environment). Only the unclear ones go to Jev. It never re-runs a test and never turns a failure green.
  • Where it plugs in: bin/fm-pr-state.sh, the step that already reads a pull request's reported checks
  • What it saves: A worker is not sent to "fix" a failure that is not in its code.
  • Who else does it: jev-ci-triage (https://github.com/criguex/jev-ci-triage, 0 stars): a 6-case demo only, and it reports the same input scoring 0.61, 0.62 and 0.91 on repeat calls. jev-flaky-detective (https://github.com/JevForge/jev-flaky-detective, 0 stars). Evidence is thin.
  • Build size: Medium
  • If Jev is unsure or down: Marked "unknown"; the worker investigates as today.

Stated with the table: Jev only picks from a fixed list; in every row, if Jev is unsure or down, work carries on exactly as today.

Rulings given the same evening on earlier rows, which apply to every Jev item: nothing a worker typed in its shell is ever sent to TypeSafe; no project's source code or diff is sent unless that project is explicitly named for it; Jev advises and never becomes the only thing that blocks, merges, approves or discards anything; a fix or feature adds nothing beyond what the row describes.

What Changed

  • bin/fm-pr-state.sh accepts a new --sort-failed-checks option. With it and TYPESAFE_API_KEY available, each failed required check gets one extra advisory line, FAILED CHECK SORT: <check>: <class> (<why>), where the class is code bug, flaky, environment, or unknown. Without the option or the key, output is unchanged. The line is a label only: no check is re-run, no reported result changes, and the exit status is unaffected.
  • New bin/fm-check-sort-lib.sh does the sort. Fixed rules decide first from GitHub reads: another attempt of the same workflow run passing the check on the same head commit means flaky; a connection-error marker in the failed-step log plus the same check failing on the base branch means environment. Anything else goes to Jev as one fixed-choice question over the check name and a trimmed tail of the failed-step log. flaky and environment answers need a stricter 0.8 confidence floor, and code bug uses the shared floor. Every other outcome is unknown, including a Jev error or timeout, an unclear choice, and a check with no readable job log. Only the first 3 failed checks are sorted; the rest print unknown (not sorted).
  • bin/fm-jev-lib.sh adds fm_jev_code_allowed, backed by a new local config/jev-code-projects list. A failure log is sent to Jev only for a repository listed there as its exact <owner>/<repo>; an unlisted repository's unclear failure is unknown with no call. The branch also adds tests/fm-pr-state.test.sh cases and test-family routing in bin/fm-test-run.sh, plus docs in docs/configuration.md, docs/scripts.md, AGENTS.md, and a new docs/verification/failed-check-sort.md.

🤖 Generated with Claude Code

Risk Assessment

✅ Low: The sort is advisory, off unless a caller passes --sort-failed-checks and a key is present, sends a log only for an exact owner/repo entry, labels only the three fixed choices, and every failure path falls back to unknown without touching blocker lines or exit status; the earlier rounds' fixes hold in the current code and the one remaining issue is a rare job-selection edge.

Testing

Drove bin/fm-pr-state.sh live against real open pull requests on github.com (cli/cli#13788, vercel/next.js#99644, rust-lang/cargo#17518, kubernetes/kubernetes#142693) with real gh behind a logging pass-through and curl replaced by a shim that logs and refuses, so nothing left the machine for typesafe.ai. The default call matched the base commit's output and made the same two GitHub reads; with the option, each failed required check got one FAILED CHECK SORT line while blocker lines and exit status stayed the same; unlisted and near-miss allow-list entries made no model call; an exactly listed repository made one call that was blocked and printed unknown; the key reached no gh child and was not on curl's argv or environment. The focused hermetic test tests/fm-pr-state.test.sh also passed and is the only coverage for the Jev-answered labels, the flaky and environment rules, and the bound of three. No full suite was run. No screenshot: this is a CLI-only change, so the evidence is a CLI transcript.

  • Live validation: ✅ go - 9 of 13 scenarios driven live against the product
Scenario Result Live Evidence
Reading a pull request without the option prints and reads exactly what it did before the change, even with a key and a listed repository ✅ pass live live-transcript.txt: default vs base on cli/cli#13788 and default-listed vs base-nextjs on vercel/next.js#99644: identical output, 2 gh calls each (pr view, pr checks), 0 curl calls. The first…
Passing --sort-failed-checks adds one FAILED CHECK SORT line per failed required check and leaves blocker lines and exit status unchanged ✅ pass live live-transcript.txt sorted (cli/cli#13788, three lines), unlisted-nextjs, unlisted-cargo: output minus the SORT lines equals the default output, exit 0. Pending checks on kubernetes#142693 got n…
With no key available the option reads nothing extra and prints no extra line ✅ pass live live-transcript.txt nokey: output and gh calls identical to the default call, 2 gh calls, 0 curl calls
An unlisted repository's unclear failure is labelled unknown and its log is not sent ✅ pass live live-transcript.txt unlisted-nextjs and unlisted-cargo: job log read (non-empty, 56 and 188 lines), label unknown, 0 curl calls, using the real home whose config lists no project
Adversarial: a commented-out entry, a bare repository name, a same-named repository under another owner, a name-prefix entry and a leading-space entry do not allow the send ✅ pass live live-transcript.txt nearmiss-list on vercel/next.js#99644 with the key in the environment: label unknown, 0 curl calls
With the repository listed exactly and Jev unreachable, the check is labelled unknown and the blocker report is intact ✅ pass live live-transcript.txt exact-jev-down: exactly one POST attempt to https://api.typesafe.ai/v1/systemone, refused by the shim; output FAILED CHECK SORT: thank you, next: unknown, blocker lines unchang…
The Jev key never reaches a gh child process, curl's arguments or curl's environment ✅ pass live live-transcript.txt: gh_children_with_key=0 on every run including those with the key exported by the caller; the curl line shows key_in_env=no key_in_argv=no with the header passed as `-H @/dev/f…
A failed required check that is not a GitHub Actions job is labelled unknown with no log read ✅ pass live live-transcript.txt nonactions-k8s: two prow checks each unknown, one check-runs read per check, no gh run view, 0 curl calls
The sort never re-runs a check or changes what a check reported ✅ pass live live-transcript.txt: every gh call logged across all sorted runs is a read (pr view, pr checks, api -X GET, run view --log-failed); no rerun or write call appears
A listed repository's unclear failure gets a real Jev answer and is labelled code bug, flaky or environment above its floor, unknown below it ⏸️ untested no Authority: the real firstmate home (~/p/firstmate) has a key but no config/jev-code-projects, so no project is named for sending its failure log to typesafe.ai, and naming one is the user's de…
Fixed rule: a check that another attempt of the same workflow run passed is labelled flaky, and a same-attempt same-named job or a different run's pass is not ⏸️ untested no No open pull request could be found whose required check passed in one attempt and failed in a later attempt of the same run; producing one needs write access to re-run jobs on a repository with requi…
Fixed rule: a connection error in the failed log plus the same check failing on the base branch is labelled environment ⏸️ untested no Needs a real pull request whose failed required check logs a connection error while the base branch fails the same check; none was available and it cannot be manufactured without pushing to a reposito…
Only the first three failed required checks are sorted; a fourth is printed as unknown (not sorted) ⏸️ untested no No open pull request with four or more failed required checks was found among the public repositories searched (cli/cli, vercel/next.js, rust-lang/cargo, kubernetes/kubernetes, astral-sh/uv, denoland/…
Evidence: Live CLI transcript of every driven run, with per-run gh and curl call logs

Source: Live CLI transcript of every driven run, with per-run gh and curl call logs

# Live transcript: bin/fm-pr-state.sh failed check sort (target 1a31aca, base d0dd8b5)
# Real gh against github.com via a logging pass-through shim. curl replaced by a shim that logs and refuses,
# so nothing was sent to typesafe.ai in any run. Key read by the product from the real firstmate home's .env
# (which lists no project) or passed in the environment; its value appears in no log.

## Round 1: cli/cli#13788 (3 failed required checks, job logs expired)
== base gh_calls=2 curl_calls=0
MERGEABILITY: unknown
REQUIRED CHECK: build (ubuntu-latest) (FAILURE)
REQUIRED CHECK: build (macos-latest) (FAILURE)
REQUIRED CHECK: build (windows-latest) (FAILURE)
== default gh_calls=2 curl_calls=0
REQUIRED CHECK: build (ubuntu-latest) (FAILURE)
REQUIRED CHECK: build (macos-latest) (FAILURE)
REQUIRED CHECK: build (windows-latest) (FAILURE)
== sorted gh_calls=8 curl_calls=0
REQUIRED CHECK: build (ubuntu-latest) (FAILURE)
REQUIRED CHECK: build (macos-latest) (FAILURE)
REQUIRED CHECK: build (windows-latest) (FAILURE)
FAILED CHECK SORT: build (ubuntu-latest): unknown
FAILED CHECK SORT: build (macos-latest): unknown
FAILED CHECK SORT: build (windows-latest): unknown
== nokey gh_calls=2 curl_calls=0
REQUIRED CHECK: build (ubuntu-latest) (FAILURE)
REQUIRED CHECK: build (macos-latest) (FAILURE)
REQUIRED CHECK: build (windows-latest) (FAILURE)
note: base printed a transient 'MERGEABILITY: unknown' on the first read; two repeat rounds of base vs default were byte-identical.

## Round 2
== unlisted-nextjs :: fm-pr-state.sh --sort-failed-checks https://github.com/vercel/next.js/pull/99644
exit=0 gh_calls=4 curl_calls=0 gh_children_with_key=0
DRAFT: pull request is not ready for review
REQUIRED CHECK: thank you, next (FAILURE)
FAILED CHECK SORT: thank you, next: unknown
  gh pr view https://github.com/vercel/next.js/pull/99644 --json state,mergedAt,isDraft,headRefOid,author,mergeable,reviewDecision
  gh pr checks https://github.com/vercel/next.js/pull/99644 --required --json
  gh api -X GET /repos/vercel/next.js/commits/b1928d2a91142154b023252ea038207a2d1466e8/check-runs -f
  gh run view --job 111577458417 --log-failed
== unlisted-cargo :: fm-pr-state.sh --sort-failed-checks https://github.com/rust-lang/cargo/pull/17518
exit=0 gh_calls=4 curl_calls=0 gh_children_with_key=0
DRAFT: pull request is not ready for review
REQUIRED CHECK: conclusion (FAILURE)
FAILED CHECK SORT: conclusion: unknown
  gh pr view https://github.com/rust-lang/cargo/pull/17518 --json state,mergedAt,isDraft,headRefOid,author,mergeable,reviewDecision
  gh pr checks https://github.com/rust-lang/cargo/pull/17518 --required --json
  gh api -X GET /repos/rust-lang/cargo/commits/d414a2ca11bfbd2f1c15871b2e9a4ffbc776e6f9/check-runs -f
  gh run view --job 108321532286 --log-failed
== nonactions-k8s :: fm-pr-state.sh --sort-failed-checks https://github.com/kubernetes/kubernetes/pull/142693
exit=0 gh_calls=4 curl_calls=0 gh_children_with_key=0
REQUIRED CHECK: pull-kubernetes-unit (ERROR)
REQUIRED CHECK: pull-kubernetes-verify (ERROR)
REQUIRED CHECK: pull-kubernetes-e2e-gce (PENDING)
REQUIRED CHECK: pull-kubernetes-node-e2e-containerd (PENDING)
FAILED CHECK SORT: pull-kubernetes-unit: unknown
FAILED CHECK SORT: pull-kubernetes-verify: unknown
  gh pr view https://github.com/kubernetes/kubernetes/pull/142693 --json state,mergedAt,isDraft,headRefOid,author,mergeable,reviewDecision
  gh pr checks https://github.com/kubernetes/kubernetes/pull/142693 --required --json
  gh api -X GET /repos/kubernetes/kubernetes/commits/773b9b50391d1462dd8f7749803a91ff5d37efcc/check-runs -f
  gh api -X GET /repos/kubernetes/kubernetes/commits/773b9b50391d1462dd8f7749803a91ff5d37efcc/check-runs -f
== nearmiss-list :: fm-pr-state.sh --sort-failed-checks https://github.com/vercel/next.js/pull/99644
exit=0 gh_calls=4 curl_calls=0 gh_children_with_key=0
DRAFT: pull request is not ready for review
REQUIRED CHECK: thank you, next (FAILURE)
FAILED CHECK SORT: thank you, next: unknown
  gh pr view https://github.com/vercel/next.js/pull/99644 --json state,mergedAt,isDraft,headRefOid,author,mergeable,reviewDecision
  gh pr checks https://github.com/vercel/next.js/pull/99644 --required --json
  gh api -X GET /repos/vercel/next.js/commits/b1928d2a91142154b023252ea038207a2d1466e8/check-runs -f
  gh run view --job 111577458417 --log-failed
== default-listed :: fm-pr-state.sh https://github.com/vercel/next.js/pull/99644
exit=0 gh_calls=2 curl_calls=0 gh_children_with_key=0
DRAFT: pull request is not ready for review
REQUIRED CHECK: thank you, next (FAILURE)
  gh pr view https://github.com/vercel/next.js/pull/99644 --json state,mergedAt,isDraft,headRefOid,author,mergeable,reviewDecision
  gh pr checks https://github.com/vercel/next.js/pull/99644 --required --json
== exact-jev-down :: fm-pr-state.sh --sort-failed-checks https://github.com/vercel/next.js/pull/99644
exit=0 gh_calls=4 curl_calls=1 gh_children_with_key=0
DRAFT: pull request is not ready for review
REQUIRED CHECK: thank you, next (FAILURE)
FAILED CHECK SORT: thank you, next: unknown
curl BLOCKED key_in_env=no key_in_argv=no :: -sS --max-time 5 -o /tmp/tmp.iBEvi8oLXI -w %{http_code} -X POST https://api.typesafe.ai/v1/systemone -H Content-Type: application/json -H @/dev/fd/3 --data-binary @- 
  gh pr view https://github.com/vercel/next.js/pull/99644 --json state,mergedAt,isDraft,headRefOid,author,mergeable,reviewDecision
  gh pr checks https://github.com/vercel/next.js/pull/99644 --required --json
  gh api -X GET /repos/vercel/next.js/commits/b1928d2a91142154b023252ea038207a2d1466e8/check-runs -f
  gh run view --job 111577458417 --log-failed
== base-nextjs :: fm-pr-state.sh https://github.com/vercel/next.js/pull/99644
exit=0 gh_calls=2 curl_calls=0 gh_children_with_key=0
DRAFT: pull request is not ready for review
REQUIRED CHECK: thank you, next (FAILURE)
  gh pr view https://github.com/vercel/next.js/pull/99644 --json state,mergedAt,isDraft,headRefOid,author,mergeable,reviewDecision
  gh pr checks https://github.com/vercel/next.js/pull/99644 --required --json
default-listed vs base output: IDENTICAL
Evidence: Output of the focused hermetic test tests/fm-pr-state.test.sh

Source: Output of the focused hermetic test tests/fm-pr-state.test.sh

ok - a passing required check and a skipped one leave nothing to report
ok - a terminal pull request reports that state and nothing else
ok - draft state blocks readiness
ok - stale changes-requested verdicts explain a blocking review decision
ok - approved PR ignores stale changes-requested history
ok - current changes-requested review blocks readiness
ok - a CHANGES_REQUESTED decision is always reported
ok - the author's own review is never listed as a blocker
ok - a pending approval is not reported as a blocker
ok - required failure blocks readiness
ok - the default call reads and prints what it does without the sort, key and listed repository present
ok - without a key the report and the GitHub reads are unchanged
ok - fixed rules label flaky and environment failures without asking the model
ok - only a listed repository's unclear failure is asked, and every doubt is unknown
ok - with the model down the blocker lines are intact and the check is unknown
ok - given gh's sentence, an unreported required check is unconfirmed, other check lookup failures refuse
ok - given gh's sentence, a head with no reported checks is unverified rather than ready
ok - help states what empty output means and what is out of scope
ok - unknown and conflicting mergeability block readiness
ok - argument and lookup refusals exit nonzero
Evidence: Sort on an unlisted repository with a readable log (vercel/next.js#99644)
$ bin/fm-pr-state.sh --sort-failed-checks https://github.com/vercel/next.js/pull/99644
exit=0 gh_calls=4 curl_calls=0 gh_children_with_key=0
DRAFT: pull request is not ready for review
REQUIRED CHECK: thank you, next (FAILURE)
FAILED CHECK SORT: thank you, next: unknown
Evidence: Same pull request, repository listed exactly, Jev unreachable
exit=0 gh_calls=4 curl_calls=1 gh_children_with_key=0
DRAFT: pull request is not ready for review
REQUIRED CHECK: thank you, next (FAILURE)
FAILED CHECK SORT: thank you, next: unknown
curl BLOCKED key_in_env=no key_in_argv=no :: -sS --max-time 5 -o /tmp/tmp.iBEvi8oLXI -w %{http_code} -X POST https://api.typesafe.ai/v1/systemone -H Content-Type: application/json -H @/dev/fd/3 --data-binary @-
Evidence: Default call (no option), key present and repository listed
$ bin/fm-pr-state.sh https://github.com/vercel/next.js/pull/99644
exit=0 gh_calls=2 curl_calls=0
DRAFT: pull request is not ready for review
REQUIRED CHECK: thank you, next (FAILURE)
(output identical to the base commit's script)

Pipeline

Updates from git push no-mistakes

✅ **intent** - passed

✅ No issues found.

✅ **Rebase** - passed

✅ No issues found.

⚠️ **Review** - 1 info
  • ⚠️ bin/fm-pr-state.sh:141 - The only programmatic caller of fm-pr-state.sh is the watcher's routine-wake triage (bin/fm-watch.sh:1715), which throws the label away: any REQUIRED CHECK line already makes it return 1. With the key in .env, every declared-pause recheck of a task whose PR has a failed required check now runs the full sort inside the watcher's 30 s timeout: per check a check-runs read, a job-log download, possibly two base-branch reads and a 5 s Jev call, for up to three checks. For a listed project it also sends the failure log to typesafe.ai with no reader. The wake outcome is unchanged, but the watcher stalls longer and the same log is re-sent on every recheck. The remedy, not the defect, needs authorization: skipping the sort for that caller means a new opt-out switch or moving where the sort is invoked.
  • ⚠️ bin/fm-check-sort-lib.sh:118 - The allow-list is checked against ${repo##*/}, the repository name without its owner. Listing firstmate (or a common name such as api) in config/jev-code-projects therefore allows the failure log of any &lt;owner&gt;/&lt;that-name&gt; pull request passed to fm-pr-state.sh to be sent to typesafe.ai, including a fork or an unrelated same-named repository. The ruling is "no project's source code or diff is sent unless that project is explicitly named for it". The docs state the basename comparison, so this is deliberate, but whether a bare repository name counts as explicitly naming the project is a policy decision; matching owner/repo would be the narrower form.
  • ⚠️ bin/fm-check-sort-lib.sh:54 - Unrequired component: FM_CHECK_SORT_AWAY_FLOOR=0.8, a second confidence floor for flaky and environment beside the shared FM_JEV_CONFIDENCE_FLOOR. Row 9 only requires that an unsure answer becomes unknown, and "a fix or feature adds nothing beyond what the row describes". The floor is backed by the live evidence in docs/verification/failed-check-sort.md (a process failure labelled environment at 0.65 to 0.73) and only makes labels more conservative, but it is a second definition of the floor. Confirm keeping it, or remove it and use the shared floor.
  • ⚠️ bin/fm-check-sort-lib.sh:51 - Unrequired component: FM_CHECK_SORT_MAX=3. Only the first three failed required checks are sorted; a fourth gets no FAILED CHECK SORT line at all, not even unknown. Row 9 describes sorting a failed check and falling back to unknown, with no cap, and the docs say a line is added "under each failed required check". Either remove the cap, or confirm it and accept that later checks are silently unlabelled.
  • ⚠️ bin/fm-check-sort-lib.sh:101 - Unrequired component: the FM_CHECK_SORT_EVIDENCE line filter with its fall-back to the whole log. Only lines matching error|fail|... are sent, so the surrounding context of a failure is dropped before Jev sees it; 0 failed style summary lines still match. Row 9 does not ask for a filtering stage; sending the last 4000 characters of the failed-step log is the narrower form. The verification record motivates the filter (summary lines crowd out the cause), so confirm or remove.
  • ℹ️ bin/fm-check-sort-lib.sh:63 - Row 9's "passed on retry means flaky" cannot be observed from this plug-in point in its usual order: a check that failed and then passed on retry is green and never reaches the sort. The rule as implemented fires only when an earlier attempt of the same run passed and the latest attempt failed. That is the only reachable form inside fm-pr-state.sh and is labelled correctly; noted so the narrow coverage is understood.

🔧 Fix applied.
2 issues (1 warning, 1 info) still open:

  • ⚠️ bin/fm-check-sort-lib.sh:108 - The verdict filter accepts any .choice that is not unclear. _fm_jev_ask in bin/fm-jev-lib.sh checks that choice is a string and that the probability keys match the criteria, but never that choice is one of those keys. A reply such as {choice:&#34;banana&#34;, confidence:0.9} with well-formed probabilities therefore prints FAILED CHECK SORT: &lt;check&gt;: banana (jev, confidence 0.9), and because the output is jq -r, a choice containing a newline would print an extra line in fm-pr-state.sh's report. The header and docs say the class is one of four and that a malformed answer is unknown. Fix: only label when .choice is code_bug, flaky or environment; everything else is unknown.
  • ℹ️ docs/scripts.md:145 - After the fix round the sort runs only when a caller passes --sort-failed-checks, and no code path passes it: the watcher deliberately does not, and firstmate is expected to by hand. The option is documented in docs/configuration.md and the script's own help, but the script index row for fm-pr-state.sh in docs/scripts.md still describes only the blocker read, and AGENTS.md mentions only the config file. A firstmate that finds the command through the index will never produce the label. Add the option to that row.

🔧 Fix applied.
1 warning still open:

  • ⚠️ bin/fm-check-sort-lib.sh:70 - Rule 1 labels a check flaky whenever any check run with the same name and the same /actions/runs/&lt;id&gt; URL succeeded, but it never checks that the passing run belongs to a different attempt. Check runs carry no attempt number, so two jobs of one attempt that share a name look identical to a retry. Concrete case: a matrix job with a static name: test yields several check runs named test in one run; one leg passes and one fails on a real code bug, gh pr checks reports test as failed, and the sort prints flaky (rule: another attempt of the same run passed) with no log read and no Jev call. That is the label that tells a worker the failure is not in its code, and it bypasses the stricter 0.8 floor meant to guard it. Fix: when a same-run pass is found, confirm the passing and failing jobs have different run_attempt values (gh api /repos/&lt;repo&gt;/actions/jobs/&lt;id&gt; --jq .run_attempt) before printing flaky; otherwise fall through to the log path. The test passed_too 5 fixture would still pass with the code wrong, because it never models two same-attempt jobs.

🔧 Fix applied.
1 info still open:

  • ℹ️ bin/fm-check-sort-lib.sh:72 - The job to sort is chosen as the highest-id GitHub Actions check run of that name whose conclusion is anything other than success, so skipped, neutral and cancelled runs qualify. Concrete case: two workflows on the same head both have a job named test; workflow A's test fails (id 20) and workflow B's test is skipped by an if: (id 30). gh pr checks reports test as failed, the sort picks job 30, its --log-failed output is empty, and the line is unknown although a failing job with a log exists. In the rarer variant where B's test passed on attempt 1 and was skipped on a re-run, rule 1 compares the skipped job with that pass and prints flaky (rule: ...) for A's real failure. Fix: select only conclusions that are failures (failure, timed_out, startup_failure, action_required, cancelled) rather than != &#34;success&#34;. Same root: when two workflows both report a failed test, both names resolve to the same highest-id job and one failure is never looked at.
✅ **Test** - passed

✅ No issues found.

  • Live validation: ✅ go - 9 of 13 scenarios driven live against the product
Scenario Result Live Evidence
Reading a pull request without the option prints and reads exactly what it did before the change, even with a key and a listed repository ✅ pass live live-transcript.txt: default vs base on cli/cli#13788 and default-listed vs base-nextjs on vercel/next.js#99644: identical output, 2 gh calls each (pr view, pr checks), 0 curl calls. The first…
Passing --sort-failed-checks adds one FAILED CHECK SORT line per failed required check and leaves blocker lines and exit status unchanged ✅ pass live live-transcript.txt sorted (cli/cli#13788, three lines), unlisted-nextjs, unlisted-cargo: output minus the SORT lines equals the default output, exit 0. Pending checks on kubernetes#142693 got n…
With no key available the option reads nothing extra and prints no extra line ✅ pass live live-transcript.txt nokey: output and gh calls identical to the default call, 2 gh calls, 0 curl calls
An unlisted repository's unclear failure is labelled unknown and its log is not sent ✅ pass live live-transcript.txt unlisted-nextjs and unlisted-cargo: job log read (non-empty, 56 and 188 lines), label unknown, 0 curl calls, using the real home whose config lists no project
Adversarial: a commented-out entry, a bare repository name, a same-named repository under another owner, a name-prefix entry and a leading-space entry do not allow the send ✅ pass live live-transcript.txt nearmiss-list on vercel/next.js#99644 with the key in the environment: label unknown, 0 curl calls
With the repository listed exactly and Jev unreachable, the check is labelled unknown and the blocker report is intact ✅ pass live live-transcript.txt exact-jev-down: exactly one POST attempt to https://api.typesafe.ai/v1/systemone, refused by the shim; output FAILED CHECK SORT: thank you, next: unknown, blocker lines unchang…
The Jev key never reaches a gh child process, curl's arguments or curl's environment ✅ pass live live-transcript.txt: gh_children_with_key=0 on every run including those with the key exported by the caller; the curl line shows key_in_env=no key_in_argv=no with the header passed as `-H @/dev/f…
A failed required check that is not a GitHub Actions job is labelled unknown with no log read ✅ pass live live-transcript.txt nonactions-k8s: two prow checks each unknown, one check-runs read per check, no gh run view, 0 curl calls
The sort never re-runs a check or changes what a check reported ✅ pass live live-transcript.txt: every gh call logged across all sorted runs is a read (pr view, pr checks, api -X GET, run view --log-failed); no rerun or write call appears
A listed repository's unclear failure gets a real Jev answer and is labelled code bug, flaky or environment above its floor, unknown below it ⏸️ untested no Authority: the real firstmate home (~/p/firstmate) has a key but no config/jev-code-projects, so no project is named for sending its failure log to typesafe.ai, and naming one is the user's de…
Fixed rule: a check that another attempt of the same workflow run passed is labelled flaky, and a same-attempt same-named job or a different run's pass is not ⏸️ untested no No open pull request could be found whose required check passed in one attempt and failed in a later attempt of the same run; producing one needs write access to re-run jobs on a repository with requi…
Fixed rule: a connection error in the failed log plus the same check failing on the base branch is labelled environment ⏸️ untested no Needs a real pull request whose failed required check logs a connection error while the base branch fails the same check; none was available and it cannot be manufactured without pushing to a reposito…
Only the first three failed required checks are sorted; a fourth is printed as unknown (not sorted) ⏸️ untested no No open pull request with four or more failed required checks was found among the public repositories searched (cli/cli, vercel/next.js, rust-lang/cargo, kubernetes/kubernetes, astral-sh/uv, denoland/…
  • FM_HOME=~/p/firstmate bin/fm-pr-state.sh https://github.com/cli/cli/pull/13788 compared with the same call on the base commit's script (d0dd8b5), three rounds
  • bin/fm-pr-state.sh --sort-failed-checks https://github.com/cli/cli/pull/13788 with the real home's key and no listed project
  • bin/fm-pr-state.sh --sort-failed-checks https://github.com/cli/cli/pull/13788 with an empty home (no key)
  • bin/fm-pr-state.sh --sort-failed-checks on vercel/next.js#99644 and rust-lang/cargo#17518 (readable job logs, repository unlisted)
  • bin/fm-pr-state.sh --sort-failed-checks https://github.com/kubernetes/kubernetes/pull/142693 (failed required checks that are not GitHub Actions jobs)
  • bin/fm-pr-state.sh --sort-failed-checks on vercel/next.js#99644 with a fixture allow-list of near misses: # vercel/next.js, next.js, someoneelse/next.js, vercel/next.js-fork, vercel/next.js
  • bin/fm-pr-state.sh (no option) on vercel/next.js#99644 with the key in the environment and vercel/next.js listed
  • bin/fm-pr-state.sh --sort-failed-checks on vercel/next.js#99644 with vercel/next.js listed and curl refused (Jev unreachable)
  • bash tests/fm-pr-state.test.sh
✅ **Document** - passed

✅ No issues found.

🔧 **Lint** - 1 issue found → auto-fixed ✅
  • ⚠️ linter found issues (exit code 1)

🔧 Fix applied.
✅ Re-checked - no issues remain.

✅ **Push** - passed

✅ No issues found.

…onment

bin/fm-pr-state.sh adds one advisory FAILED CHECK SORT line under each failed
required check when TYPESAFE_API_KEY is available. Fixed rules decide first
from GitHub reads (another attempt of the same run passed means flaky; a
connection error on a check the base branch also fails means environment);
only an undecided failure is put to Jev as one fixed-choice question through
bin/fm-jev-lib.sh, and only for a repository listed in
config/jev-code-projects. Every doubt prints unknown. Without the key the
command reads and prints exactly what it did before. The label never re-runs
a check and never changes a blocker line or the exit status.
@talktejas

Copy link
Copy Markdown
Owner Author

Superseded by #50, which carries this change's final content together with the other three Jev items on one branch.

@talktejas talktejas closed this Oct 5, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant