v0.5.5
Three fixes. The first one had been merging past a reviewer nobody noticed.
merge-shepherd reads the PR's decision, not one bot's opinion (#156)
recheck filtered reviews to coderabbitai, so a human reviewer's
CHANGES_REQUESTED was invisible: the graph answered RECHECKED, the gate
comment told the operator that review status was no longer theirs to confirm,
and merge was authorised to use --admin on a rationale — "verify passed,
CI concluded, comments triaged" — that contained no human. It did not hang. It
merged, and left no failed row to notice.
Both waits now read reviewDecision (every reviewer) and mergeStateStatus
from the same call, and judge the whole check rollup rather than one entry.
A second thing came out of the same diagnosis: some conditions a wait observes
cannot resolve on their own. A rate-limited bot that never reviewed, a
rebutted CHANGES_REQUESTED, a branch that is BEHIND — those are latches, and
polling them burns money and ends in a timeout that names nothing. They now
answer LATCHED <what>; unblock: <act> on the first read, with zero polls, and
the remedy is the first line of the failed node's artifact. Chasing that took
four operator interventions in two days; the graph now says what each of them
was.
(The unified story — "every wait assumes time resolves the condition" — was
tested and only partly held. What survived: the graph modelled PR readiness as
one bot's opinion plus a check rollup and never read the two fields GitHub
computes.)
A node that can observe no tool denial is told so (#154, #157)
A fourth advisory sweep: a node declaring neither allowed_tools nor
success_check.verify has no way to notice a denial. dontAsk denies
without asking, and a hand-written node inherits your settings — so on a machine
without a blanket grant, that node does nothing, explains the denial in prose,
and a result_matches: '^DONE' check passes on the explanation. Reported by a
second machine, from a transcript.
The measurement is the uncomfortable part: 62 of 150 nodes hit, and 61 of
those 62 are this maintainer's own lanes — pr nodes that push branches and
open pull requests while declaring no tools at all. They had never failed only
because this machine grants Bash(*). The single noise hit was fixed in the
graph rather than silenced. Advisory, never a load error: a hand-written graph
is the user's own reviewed artifact.
init tops the tree up, and where you save a graph decides whether it can reuse one (#158)
use: resolves only against the entry file's own fragments/ sibling — a
boundary ADR 0013 argues for and this release keeps. The consequence was never
written down, and it was the whole story: of 80 lanes with a pr node, 77
sat directly in /tmp, where use: cannot load at all. Reuse was not
refused; it was unreachable. The code change needed for reach was zero
lines — what was missing was a storage convention, now documented with the
prescription in the resolution error itself.
Separately, init refused the whole command if any target existed, so a tree
created before a fragment shipped could never receive it — pr-publish landed
in v0.5.3 and could not reach anyone who ran init earlier. A re-run now tops
up: existing files are kept and reported, missing ones written. The
no-overwrite promise is unchanged; skip-existing cannot produce the
half-replaced tree the all-or-nothing refusal existed to prevent.
Install: go install github.com/jitokim/oh-my-graph/cmd/oh-my-graph@v0.5.5
Full changelog: https://github.com/jitokim/oh-my-graph/blob/v0.5.5/CHANGELOG.md