fix(surveyor): count unresolved review threads with a fail-closed helper - #235
Conversation
The surveyor counted pentad field (b) with an inline paginated GraphQL read, so a failed read, a first-page-only read and a genuine zero all reported 0. Ship count-unresolved-review-threads.sh, which owns the paginated read in memory, checks fetched against totalCount and reports UNKNOWN (exit 2) on any incomplete or malformed read; admit it in the read-only guard only as the exact sibling, in flag form, run alone; and require it for field (b), reporting unresolved=unknown on anything but a complete read. Fixes #231 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011Aut24ni8XbKPYyY5mYrbb
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011Aut24ni8XbKPYyY5mYrbb
Evidence at head
|
CI's ShellCheck reports SC2015 on the counter's repeated-flag guards. Use explicit if-statements and refresh the pinned runtime-asset digest. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011Aut24ni8XbKPYyY5mYrbb
Lint fix at head
|
The surveyor's non-negotiable Safety section still called the default-branch classifier "the one bundled compound forge read", which contradicts field (b) now requiring the unresolved-thread counter. Name both helpers, scope the step-4 "recognises only this sibling" sentence to the classifier, and stop the README claiming nothing else local can run under the guard (a consumer may declare stdin-only classifiers). Surveyor definition digest refreshed with refresh-desired-state-digests.sh. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011Aut24ni8XbKPYyY5mYrbb
@coderabbitai review Generated by Claude Code |
Rate Limit Exceeded
|
devantler
left a comment
There was a problem hiding this comment.
🤖 Generated by the Agentic Engineer
Self-review (fallback — CodeRabbit, Codex and Cursor Bugbot unavailable)
Reviewed commit: 85105b3aa691ac87203a66e04495701eea7d5692
- CodeRabbit: requested at this head (comment 5784495227, 21:30Z); replied "Rate Limit Exceeded" at 2026-09-22T21:31:08Z (comment 5784496747) — no review ran at this head
- Codex: usage limit reached (measured 2026-09-22T20:53:06Z on monorepo#3507; maintainer-only, not re-requested)
- Cursor Bugbot: usage limit reached (measured 2026-09-22T20:53:35Z on monorepo#3507; maintainer-only, not re-requested)
What I checked (independent reviewer, not the author):
- Guard allow-rule is exact. The counter is admitted only as the guard's own
pwd -Psibling, matched as a quoted (literal)casepattern, at pipeline position 0, with exactly--repo OWNER/REPOand a positive--pr— and only when the whole command is one segment. Probed 24 shapes against the guard at this head:| cat,| jq, a trailing|,|| true,&& true,>/tmp/x,>&-,--repo=…,--,$PR/${PR}/$Roperands, a relative or../-normalisable path, a bare basename,bash <counter>, and the counter consuming aghpipeline all deny; only the flag form (optionally with2>&1,>/dev/null,>&2) allows.--repo ../..is admitted but is passed as GraphQL variables, never a path. A consumer-declared classifier path equal to the counter still hits the counter branch first, so it cannot be admitted mid-pipeline. - Fail-closed counter. Every non-complete outcome prints
UNKNOWN <reason>and exits 2: usage, missinggh/jq,ghnon-zero (including a later-page failure after page 1 printed), empty output, missing/nullreviewThreads, a node without a booleanisResolved, a non-integer or negativetotalCount, totals that change between pages, andfetched != totalCount. The only zero is a complete parsed read.owner/name/querygo through-f(raw, no@fileexpansion);--pris validated numeric before-F. The query is a fixed read;GH_TELEMETRY=0is exported. - Tests prove it (RED/GREEN + ablations). Independently confirmed RED:
main's guard denies the counter (a read must begin with a forge command). My own ablation removing the guard's single-segment check makes exactly the two pipeline tests fail (403/2). The counter suite's ablations (no--paginate, no truncation check, no per-node check) each flip to the dangerous result. - Surveyor contract. Field (b) forbids inline counting, prescribes the helper by resolved path, maps anything but status 0/1 with the exact line to
unresolved=unknown, and routes unknown into the existing fail-closed digest rules (neverREVIEW-READY/MERGE-READY). Fixed in 85105b3: the non-negotiable Safety section still called the classifier "the one bundled compound forge read", contradicting field (b) (P1); plus two wording nits (step 4 "recognises only this sibling"; README "nothing else local runs under the guard" ignored consumer-declared classifiers). - Release hygiene. Version 5.2.0 → 5.2.1 moved in all four places; changelog entry present; desired-state digests (counter, guard, surveyor definition) regenerated with
refresh-desired-state-digests.shand--checkpasses. No synced skill tree touched (bundled-skill guard: no bundled tree touched). No Python, no workflow change. - Local validation at 8482baa (full) and 85105b3 (affected suites): ShellCheck 0.11.0 over all 31 scripts,
validate-manifests.sh, version-bump gate, digest--check,guard-gh-json-fields.sh, everyscripts/*.test.shand everyplugins/*/scripts/*.test.sh— all exit 0 (guard 405/0, counter 26/0, adapter 51/0, review contract 72 clauses).
Verdict: no P0/P1 findings
Generated by Claude Code
User evaluation at head
|
Why
The surveyor counted a pull request's unresolved review threads by hand, so a failed or incomplete read looked exactly like "no open threads". That count decides whether a PR may be promoted and merged, and it once reported zero while a major finding was still open.
What
The plugin now ships a small tested helper that reports the thread count only when it has read every thread, and says "unknown" otherwise. The surveyor must use it and treat "unknown" as incomplete, never as zero; the read-only guard allows exactly that helper, run on its own. Consumers that install runtime files individually need to add the new helper.
Fixes #231
🤖 Generated with Claude Code
https://claude.ai/code/session_011Aut24ni8XbKPYyY5mYrbb
Generated by Claude Code