Runtime 403/404 from the resolve endpoint is misclassified as "resolution unsupported" #8
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
During the j4k/review pilot probe (j4k/review#71), the wrapper at pin
e40abca1334188538aeade64a16d76d54ec35c9elogged on both reconcile passes:and left every finding conversation with
resolver: null.The server is
16.0.2-j4k.1+gitea-1.22.0— a-j4kfork that has the conversation-resolution REST API — andfgj pr review resolveresolved those same conversations minutes later. So the API is present and working; the wrapper's capability detection is what's wrong.Effect: on every enrolled repository, superseded findings get a reply comment but stay visually unresolved, and someone has to resolve them by hand.
Observed on runs 32755 (reconcile at 14:32:34Z) and 32804 (15:05:17Z) on 2026-08-25.
Two corrections from investigating this while enrolling
j4k/dynamic-tools(PR #7), both narrowing where the fix goes.The version probe is not what fails.
probeResolution(src/forge/client.ts:73-81) testsmeta.version.includes("-j4k"), and this instance answers{"version":"16.0.2-j4k.1+gitea-1.22.0", …}— so it returnstrue. The title's "misdetected" points at the wrong line.The receipts confirm which branch fired. Both runs recorded here logged:
That string is emitted only from the
resolve()/unresolve()catch block insrc/reconcile/dispositions.ts:47-53. ThesupportsResolution() === falsebranch prints a different one — "this instance has no conversation-resolution API — projecting dispositions as replies only" (dispositions.ts:156-158) — and it does not appear. Probe passed; thePOST …/reviews/{id}/comments/{comment}/resolutionitself was refused. The route exists on the server:swagger.v1.jsondocumentsrepoResolvePullReviewCommentwith200,403,404.The blocker to diagnosing it further is the logging.
isResolutionDegradation(src/reconcile/conversation-markers.ts:58-64) collapses403and404into one verdict:and the catch block logs a fixed string that discards the status and the URL. So the report cannot say whether the Actions task token lacked resolve permission (
403) or hit a routing problem (404) — and those need different fixes. Logging the status and the request URL on the degradation path is a prerequisite for closing this.Worth noting the blast radius while it's open:
supportedis reassigned from each projection result (dispositions.ts:167,180), so one refusal disables resolution for every remaining conversation in the pass, not just the one that failed.Conversation-resolution capability misdetected on code.j4k.devto Runtime 403/404 from the resolve endpoint is misclassified as "resolution unsupported"Fixed in PR #11; retitled to name the real fault, since the version probe was never the bug.
isResolutionDegradationis replaced byclassifyResolutionFailure, which takes the probe's verdict as an argument. On a probe-confirmed-j4kinstance a 403 or 404 fromPOST .../reviews/{id}/comments/{comment}/resolutionis now logged as a refusal, quoting the status and the endpoint verbatim; "unsupported" is left for instances whose probe found no-j4k.ForgeRequestErrorcarries the request URL so the diagnostic can name it. The pass still degrades to replies rather than failing the run.That fixes the label, not the refusal. Whatever status
code.j4k.devactually returned will be visible in the next reconcile log on the new pin, and if it is a 403 the Actions task token still needs resolve permission granted server-side. Leaving this open until a run shows the real status and that side is settled.