Imported from whhe/ai-workshop (
skills/resolve-review-comments/SKILL.md). Install upstream withnpx skills add whhe/ai-workshop --skill resolve-review-comments. Copyright stays with the author.
IRON LAW: No review-automation trigger caused by this workflow's planned publication events may be accepted or released until the final SHA is the authoritative remote head and every workflow-planned context write in the frozen publication plan except the atomic operation that emits the final trigger is authoritative. A context write may occur before the final SHA is remote when it is authoritatively proven non-triggering. A triggering or unknown context write may occur earlier only when documented suppression, batching, or coalescing guarantees that it cannot emit, accept, or schedule a trigger before those conditions hold and that the eventual trigger is bound to the final SHA and frozen context. Delaying run start after trigger acceptance is not safe. Verify the final trigger-producing write authoritatively before a thread transition.
Resolve Review Comments
Workflow
- 1. Preflight and trigger inventory
- 2. Fetch complete review context ⛔ BLOCKING
- 3. Build the item ledger and triage ⛔ BLOCKING
- 4. Implement fixes
- 5. Review-fix loop (max 3 iterations)
- 6. Commit and obtain publication approval
- 7. Synchronize replies and PR/MR context ⛔ BLOCKING
- 8. Push and transition threads
- 9. Verify automation and completeness
Global Rules
- Self-contained execution: Select one available platform interface at preflight. Prefer a purpose-built GitHub or GitLab interface that exposes pagination, threads, comments, metadata, and runs. Otherwise use
gh/GitHub GraphQL or GitLab REST against the exact PR/MR host. Keep triage, code changes, review, replies, and description drafting in this workflow; do not depend on another skill. - Bounded autonomous authorization: Determine authorization intent from the meaning of the complete user request, never from a hard-coded keyword, exact phrase, command token, language, or regex. Select
authorization mode: autonomousonly when the request clearly identifies one PR/MR, delegates the end-to-end review-resolution workflow, authorizes the repository and review-system mutations needed for closure, and asks not to receive repeated confirmation or authorization prompts. Examples in documentation are illustrative, not a whitelist. When any dimension is missing, ambiguous, scoped more narrowly, or contradicted elsewhere in the request, selectauthorization mode: guarded. In autonomous mode, record a standing authorization envelope at preflight that permits triage, attributable edits, tests, replies, PR/MR metadata updates, Resolve/Reopen transitions, and review-automation interaction only for the current PR/MR. Include commit or push only when the trusted-base repository rules expressly permit advance authorization for that operation; a repository-mandated post-diff commit confirmation or separate push confirmation remains a mandatory checkpoint in every mode and cannot be waived by a request to avoid repeated prompts. Bind any permitted push authority to the authoritative source repository, full head ref, and a final SHA produced solely from attributable task changes. Validate every concrete mutation against the envelope before executing it. No operation outside the recorded envelope inherits authorization. Any scope expansion requires stopping and reporting the exact expansion. Do not repeat confirmation or authorization prompts for an operation inside the envelope, except at a mandatory repository checkpoint. If a material Clarify remains, a required check fails or cannot be verified, task attribution is unsafe, guarded drift recovery fails, safe trigger ordering cannot be proven, a remote result remains ambiguous, publication ownership is lost, or an unapproved destructive action is required, stop and report the exact blocker without asking a follow-up question. Do not treat generic advance acceptance of unknown test gaps, destructive targets, remote destinations, or ambiguous outcomes as authorization. - Complete collection: Exhaust every page, cursor, continuation token, and nested comment connection before filtering. A partial response never proves that no work remains.
- Item-level ledger: Track stable comment/note IDs separately from thread/discussion IDs. A previously seen thread does not prove that its current replies were seen.
- Minimal scope: Implement only accepted feedback and required caller updates. Add or update a targeted test only when it protects a changed observable contract or an uncovered, stable regression; preserve unrelated and pre-existing work.
- Verification scope: Treat any test permission in the standing envelope as permission for targeted verification only. Reuse existing checks first; do not run broad suites or add tests solely for coverage, symmetry, or implementation branches.
- No review metadata in repository outputs: Commit messages and PR/MR title/body must be understandable from the repository diff and history alone. Do not include reviewer names, comment IDs, or phrases such as “address review.”
- Replay safety: Before each reply or metadata write, refresh its exact target. After an ambiguous result, reconcile the complete exact target through the recorded visibility bound. Reuse one unique exact effect and apply the approval-gated duplicate rule to multiple matches. When no effect appears and the precondition remains unchanged, permit at most one identical retry only if the event is proven non-triggering or the provider applies the same idempotency key; otherwise stop. Reconcile again after that retry and never make a second retry.
- Concurrent publication safety: Prefer an exclusive publication lease keyed by provider, repository stable ID, and PR/MR number, and hold it through final verification. Lease acquire, renew, and release must each be authoritatively proven non-triggering; a mechanism with a triggering, unknown, or merely suppressed lifecycle event is not eligible as this lease. Before the final pre-push freshness read, require its remaining lifetime to exceed a recorded combined upper bound for that read, the push attempt and allowed push reconciliation, and the post-push critical section. After the freshness read, re-check that the remaining lifetime still covers the push and critical-section bound; renew only before repeating the freshness read, never inside the critical section. Without such a lease, freeze the exact remote head, metadata, item fingerprints, reply targets, thread states, and trigger evidence as an optimistic guard, then revalidate the applicable values immediately before each write. This path does not claim atomic exclusion from another publisher. Send an unsuppressed
triggeringorunknownnon-idempotent write only at the next trigger-safe position frozen in the publication plan, after every applicable context and final-SHA precondition holds. A covered write may occur earlier only when a documented mechanism prevents it from emitting, accepting, or scheduling a review trigger until a named release operation after those preconditions hold, and binds the eventual trigger to the final SHA and frozen publication context. A debounce or delayed run start after trigger acceptance is insufficient. Send a triggering, unknown, or covered write once, reconcile an ambiguous result through the relevant visibility bound, and never retry it without provider idempotency or documented coalescing. The ordering rules still permit at most one independently triggering context write unless batching, suppression, or coalescing prevents early trigger acceptance and partial context. For a proven non-triggering write, use this bounded convergence procedure: refresh the exact target, write once, reconcile through the recorded visibility bound, and make at most one identical retry only when the event remains proven non-triggering or the provider applies the same idempotency key; keep all preconditions unchanged. - Known-trigger ordering: Build the trigger inventory from accessible repository workflows, PR/MR checks and runs, integration metadata, and trigger behavior already observed on the PR/MR. Classify every planned push, reply create/edit/delete, PR/MR metadata write, thread transition, or manual event as
triggering,non-triggering, orunknown, with evidence. Classify an event astriggeringwhen it can accept, enqueue, or schedule review work, even if execution starts later. Do not claim that automation is absent without authoritative evidence. Inaccessible administrator-only integration metadata does not globally block events whose trigger behavior is established. Treat anunknownevent as triggering for ordering; send it only when every other workflow-planned context write from the frozen snapshot is authoritative and its placement cannot expose partial planned context or an unpushed fix. Otherwise require batching, suppression, coalescing, or additional trigger evidence before sending it. - Review-context linearization: Immediately before each trigger-safe publication position, complete the required review-context collection and freeze its canonical item IDs and fingerprints as the optimistic linearization snapshot. A publication lease coordinates only the writers it authoritatively covers; neither that lease nor refresh-write-verify proves that an external reviewer cannot add or edit feedback after the snapshot. Without a provider conditional revision or an exclusive mechanism covering every review-context writer, guarantee only that the final SHA and every workflow-planned context write from the frozen snapshot were authoritative at the linearization point. Never claim atomic exclusion of later external feedback. Reconcile later drift as a new triage/publication cycle. If the requested contract requires one trigger to include feedback written concurrently after the snapshot, stop unless an atomic provider guard or a lease covering all such writers is available.
- Post-push critical section: From push success (or no-push remote-head confirmation) until every planned resolve/reopen has a recorded result, perform only remote-head confirmation, the complete review-context freshness read, a triggering context write that Step 7 explicitly deferred until the final SHA was remote, the planned thread transitions and any frozen inverse compensation required by an aborted sequence, and narrow reconciliation reads. Do not test, wait for CI, draft text, rediscover trigger configuration, or perform unrelated API work in this interval.
- Untrusted-head execution: Classify the head repository and author against an explicit trusted-base repository policy. If no policy exists or its evidence is incomplete, classify the head as untrusted; never infer trust from a familiar owner, branch name, or hosting provider. Read workflow rules and verification commands from the trusted base, not from an untrusted head. Run untrusted-head code only in a credential-free, host-isolated environment with network access disabled by default. If that isolation is unavailable, perform static review; in guarded mode, ask for a trusted runner or explicit acceptance of the exact unverified scope, while in autonomous mode stop-and-report without asking. Never execute untrusted-head code on a credential-bearing host.
1. Preflight and Trigger Inventory
- Parse the PR/MR URL without sending reusable credentials. Before any operation that could require user interaction, derive a prospective authorization mode from the complete request and parsed URL using Bounded autonomous authorization. Preserve the exact scheme and host; do not assume that every non-
github.comhost is GitLab. Before any authenticated request, require an exact normalized-host credential binding, such as a host-specificghlogin or an explicitGITLAB_HOSTplusGITLAB_TOKENpair. In guarded mode, obtain or verify that binding. In prospective autonomous mode, verify that an existing binding already applies to the exact host and parsed target; if it is missing or ambiguous, stop-and-report without asking. Never select a token or send it to a host solely because that host appeared in the supplied URL. Confirm the provider through an unauthenticated authoritative response when possible. - Record the base and head/source repository stable IDs, owners/projects, canonical clone URLs, PR/MR number, title, body, base and head full refs, local HEAD, and authoritative remote head SHA. Bind one authenticated canonical head-repository URL and the full head ref as the explicit push destination. A configured Git remote that resolves to the same repository may be recorded as an alias but is not required; never derive the destination from a local branch or remote name. Stop if the authoritative repository/ref is missing or ambiguous.
- Confirm the prospective authorization mode against the authoritative PR/MR identity and freeze it. Freeze guarded mode when autonomous intent was not prospectively established. For prospective autonomous mode, require every autonomous-intent dimension to match the authoritative identity or stop-and-report without asking. In autonomous mode, freeze the standing authorization envelope (
standing envelope) containing: the original request; current PR/MR identity; allowed operations (triage,edit,test,reply,update-metadata,resolve,reopen,trigger-and-wait-for-review,acquire-publication-lease,renew-publication-lease,release-publication-lease, pluscommitorpushonly when the trusted-base repository rules permit standing authorization); authoritative source repository; full head ref;final SHA: pending;interaction policy: do-not-request-reconfirmation-except-mandatory-repository-checkpoints; andblocker policy: stop-and-report. Limit all three lease operations to the exact key formed by the current provider, authoritative source-repository stable ID, and PR/MR number; no other lease target is authorized. - Verify that the checkout is based on the authoritative remote head. A detached checkout or differently named local branch is valid when the destination URL and full ref are explicitly bound. If local HEAD differs from the remote head, move to an isolated checkout at the remote head unless every ahead commit and hunk is explicitly attributed to this task and authorized for publication by guarded approval or the standing envelope; never proceed from a behind or diverged base.
- Record pre-existing staged, unstaged, and untracked paths and hunks separately. If any pre-existing staged, unstaged, or untracked change exists, continue only in an isolated checkout at the authoritative remote head with its own worktree and index, or stop before editing. Hunk non-overlap or permission to preserve the baseline does not make a dirty worktree a valid verification environment. Never unstage, overwrite, or commit baseline entries merely to prepare this task.
- Classify the head as trusted or untrusted using the trusted-base repository policy. If no such policy exists or the evidence is incomplete, record
untrustedby default. Record the evidence, the trusted source of workflow instructions and verification commands, and the credential/network/process isolation available for executing head-controlled code. - Select and record one platform interface and the authenticated identity. Confirm that it can:
- enumerate all required review collections with pagination;
- fetch a thread/discussion directly by full ID;
- create replies and update PR/MR metadata;
- resolve and reopen threads when supported;
- inspect known review-automation runs or outputs.
- Build a known trigger inventory. Inspect accessible workflow/configuration files, current checks and runs, installed integration metadata, and prior bot activity on this PR/MR. For each planned remote event and each known comment-producing automation, record:
- event classification:
triggering,non-triggering, orunknown, with evidence; - event kind: publication-lease acquire/renew/release, push, reply create/edit/compensating-create/duplicate-delete, PR/MR metadata edit, planned or compensating resolve/reopen, or manual action;
- actor or command filters;
- how a resulting run or bot output will be identified;
- whether multiple events are suppressed, ignored, or coalesced.
- event classification:
- Record an observation-start time, one finite total Step 9 verification budget, and finite event-delivery, run-queue, and comment-visibility bounds. Use provider or repository guidance when available; otherwise record conservative finite assumptions that fit within the budget. The budget and bounds must survive every workflow re-entry.
- Record a baseline of current related run IDs/statuses and current bot-authored item IDs. Exhaust pagination. Immediately assign every observed run a provisional classification in this priority order: (a)
must-passwhen authoritative trigger or reviewed-SHA evidence associates it with this publication or the eventual final SHA; (b) otherwisemust-reconcilewhile it is active; (c) otherwisehistoricalwhen it is terminal. Use these provisional classifications during the first Step 2 collection and triage. Immediately before the first permitted trigger, or at no-push remote-head confirmation when no trigger is selected, refresh every observed run and record the boundary classification using the same priority; preserve any existingmust-pass. Creation or lifecycle updates after the observation start do not establish a final-SHA association by themselves. Amust-passrun requires an acceptable conclusion; amust-reconcilerun must become terminal and have its complete output reconciled but its conclusion does not gate publication; a historical run remains subject to output reconciliation, but its old conclusion alone does not gate publication. On every later run/output enumeration, re-evaluate every observed run with all currently available trigger and reviewed-SHA evidence, and immediately upgrade an existinghistoricalormust-reconcilerun tomust-passwhen later evidence associates it with this publication or the final SHA. Never downgrade amust-passrun. A historical or must-reconcile output that still applies to the current head remains actionable. If no automation is found, record the evidence asnot observed; recordnoneonly when authoritative configuration proves absence.
Before publication, choose an order in which the final SHA is remote and all replies and required PR/MR context in the frozen publication plan are authoritative before the first review-automation trigger caused by a planned publication event can be accepted or released:
- If push accepts or releases a review trigger, first publish every reply and metadata write that is non-triggering or covered by the no-early-trigger guarantee, then push.
- If one unsuppressed reply or metadata write accepts or releases a review trigger, perform every other permitted context write first and that operation last among context writes. Dispatch any manual action only after the thread-transition critical section.
- If multiple workflow-planned context writes can each accept independent review triggers, continue only when documented actor filters, suppression, batching, or coalescing prevent every earlier write from accepting or scheduling a trigger and bind one eventual trigger to the final SHA and frozen publication context. Otherwise stop before the first such write and report that no safe ordering is available.
- Multiple thread transitions may each accept independent review triggers after the final SHA is remote and every required reply and PR/MR metadata write is authoritative. Process them serially in the post-push critical section, record every trigger occurrence, and reconcile every resulting run; do not require suppression, batching, or coalescing merely to hide intermediate thread states.
- Treat a planned
unknownevent like a triggering event for ordering. If sending it could expose a partial set of replies or metadata, stop before the first remote write. In guarded mode, request trigger evidence or a suppression/coalescing mechanism. In autonomous mode, stop-and-report that safe ordering cannot be proven without asking. - A thread transition may trigger a run after push, but every reply and required PR/MR metadata update must already be authoritative.
- In either publication mode, never allow a triggering or unknown reply/metadata event to accept or release a review trigger before an immediate authoritative check confirms that the final SHA is the remote head. The context write itself may occur earlier only when documented suppression, batching, or coalescing prevents that write from accepting or scheduling a trigger, defers trigger acceptance to a named release operation after every workflow-planned context write from the frozen snapshot is authoritative, and binds the resulting run to the final SHA and frozen publication context. Otherwise, in push mode continue only when push is proven non-triggering and Step 7 can defer the single selected context trigger to Step 8; in no-push mode, defer that single selected context trigger to Step 8. If push and a workflow-planned context write independently accept review triggers, and neither suppression nor batching prevents the earlier trigger, stop before the first remote write.
2. Fetch Complete Review Context ⛔ BLOCKING
For every list query, record the interface or endpoint, page/batch count, and terminal evidence that no continuation remains.
GitHub
Fetch all of the following:
- GraphQL
pullRequest.reviewThreads, without filtering onisResolved; - every thread’s complete nested
commentsconnection; - all PR issue comments;
- all submitted reviews with non-empty top-level bodies, including reviews whose state is
DISMISSED; exclude only unpublished/pending reviews.
REST pull-request review comments do not expose thread resolved state, so they cannot replace the GraphQL thread collection. Mark top-level review bodies and issue comments reply_only; they receive a general PR comment and have no thread transition.
Do not drop a top-level review body because the review was dismissed. Dismissal changes the review state, not the existence of its body. Record the review state and reviewed SHA, then triage the body against the current head; use Superseded only with current-code evidence.
GitLab
Fetch every page of merge-request discussions and any separate notes collection used by the selected interface. If notes is empty, record the excluded placeholder and continue before reading notes[0]. Otherwise determine the containing discussion type from its root note (notes[0]), not from a nonexistent discussion-level resolved field. Enumerate every note; exclude system notes individually, and assign every other note the kind of its containing discussion:
| Root note state | Treatment of non-system notes in the discussion |
|---|---|
system: true |
Exclude each system note; treat any non-system note as general-comment, reply_only |
system: false, resolvable: false |
general-comment, reply_only |
system: false, resolvable: true |
review-thread-comment; use the root note’s resolved value for thread state |
Enumerate every note in each non-empty discussion. Store the full discussion ID separately for transitions.
Review-Automation Outputs
Enumerate related review-automation runs again, assign a provisional classification to every newly observed run using Step 1, and fetch the complete output of every observed terminal run, including check annotations, summaries, job reports, and equivalent findings that were not also published as comments or notes. Do not defer a terminal output merely because the first-trigger boundary has not occurred. Do not mark a run reconciled until each independent actionable finding in that output is represented in the item ledger. When the same finding is also published as a comment or note with an authoritative cross-reference, keep the automation output as Context linked to that canonical comment/note instead of creating a second actionable record.
If a historical output is authoritatively unavailable because the provider reports that it expired, was deleted, or was erased, do not invent its content and do not block forever waiting for it to reappear. Record an automation-output tombstone with the stable run/output ID, reviewed SHA, terminal status, exact unavailability evidence, and body_sha256: N/A. Identify the equivalent review scope and add one replacement action to the trigger inventory and mutation authorization ledger; do not dispatch it while fetching or triaging. Dispatch it only through the Step 8 manual-trigger gate after the final SHA is remote, classify it as a new must-pass run, and reconcile its complete output through the normal ledger path. Link the tombstone to that replacement run; only the authoritative tombstone plus a terminal, acceptable, fully reconciled final-SHA replacement closes the unavailable historical output. If equivalent review scope cannot be identified or executed, stop and report the unverified scope. Unavailable must-reconcile or must-pass output never qualifies for this historical replacement rule.
Canonical Item Identity
Use only these item kinds:
| Kind | GitHub | GitLab |
|---|---|---|
review-thread-comment |
Pull-request review-thread comment | Non-system note in a resolvable discussion |
general-comment |
PR issue comment | Non-system note in a non-resolvable discussion |
review-summary |
Submitted top-level review body, including DISMISSED |
Not applicable |
automation-output |
Terminal check/run output, including annotations and summaries | Terminal pipeline/job output, including reports and findings |
Use the GitHub GraphQL node ID (or REST node_id) when available, with the numeric REST ID as an alias. Use the exact GitLab note ID. For automation-output, use the provider's stable run/output ID; when one run has independently pageable output channels, append the provider channel ID, never a page-local index. If the provider exposes no stable output-channel ID, use one row for the complete run and keep each independent finding as an action record. If an interface exposes only a fallback ID, retain it until an authoritative response proves its alias. Stop on conflicting aliases.
For each current comment, note, or review summary, record exact body text and body_sha256 = sha256:<digest>, where <digest> is the 64 lowercase hexadecimal digits of SHA-256 over the UTF-8 API body after JSON decoding, without whitespace, Unicode, or line-ending normalization.
For automation-output, assemble every textual output field and annotation from the fully paginated provider response as records (kind, channel_id, member_id, payload). kind is field or annotation, and channel_id is the stable provider output-channel ID or the empty string when none exists. For a textual field, use its field name as member_id and its exact returned UTF-8 text as payload.
For an annotation, include every decoded annotation-object field by default, including path/range, level or severity, title, message, and raw details. Exclude a field only when authoritative provider schema identifies its exact field path as transport-only or volatile; record the path and evidence, and stop if content/location fields cannot be distinguished safely. Encode the remaining object as UTF-8 RFC 8785 JSON Canonicalization Scheme (JCS) bytes and use those bytes as payload. Use a stable provider annotation ID as member_id when available. Otherwise group byte-identical canonical payloads, sort groups lexicographically by payload bytes, and assign each occurrence in a group a zero-based ordinal; use sha256:<payload-hash>:occurrence:<n> as member_id, where <payload-hash> is the 64 lowercase hexadecimal digits of SHA-256 over payload and <n> is the shortest unsigned base-10 ASCII representation with no leading zeros. This treats annotations as a multiset: provider response order cannot change the fingerprint, while any content or location change does.
Stop on duplicate (kind, channel_id, member_id) tuples, then sort all records component-by-component: compare kind, then channel_id, then member_id as unsigned UTF-8 byte strings, and let the first unequal component determine the order. Compute body_sha256 = sha256:<digest> over UTF8("resolve-review-comments:automation-output:v1") || U64BE(record_count) || concat(U64BE(len(component_bytes)) || component_bytes for kind, channel_id, member_id, payload in each record), with <digest> encoded as 64 lowercase hexadecimal digits. Encode the first three components as UTF-8; payload is the exact field UTF-8 or annotation JCS bytes defined above. Every length is an unsigned 64-bit big-endian byte count. Do not normalize content outside JCS. Record the platform revision/update time when exposed.
An initial item in an already resolved thread is a historical Context candidate only when durable processing evidence exists, an authoritative resolution boundary proves that the current item revision predates the last resolution, or the repository owner/reviewer explicitly identifies it as historical. Processing evidence and a resolution boundary prove prior handling, not current applicability. For actionable-looking feedback, inspect the current head and record Context only when the prior disposition still holds; if the finding applies again or current applicability cannot be established, return it to triage. Otherwise triage the unprocessed non-system item even though the thread is currently resolved; this prevents feedback added after an earlier resolution from being silently skipped. When a current marker is valid for the source revision and current head, reuse its disposition and published reply result in the ledger. A newly observed external reply or externally edited item after the initial baseline always returns to triage. A workflow-emitted item already recorded in the ledger is an expected effect; return it to triage only if its body or durable identity changed, its source item or workflow-event link is invalid, or any required reply marker or compensation chain became ambiguous.
Treat a structurally valid processing marker written by the authenticated writer as a candidate, not proof of prior processing. Resolve its platform, item kind, and full item ID to one non-self source item in this PR/MR; require the marker body_sha256 to equal that source item's exact current fingerprint, validate the disposition and marker-covered SHA under the current-head rules above, and require one unambiguous compensation chain. Only then record the marker-bearing item as Context with origin: workflow-emitted and link it to the source item key; it does not process itself and must not receive another reply. If the source exists but its current fingerprint differs, record the marker-bearing item as stale workflow Context, do not treat it as processing evidence, and return the source item to triage. If the source is missing, retain the marker-bearing item as orphaned workflow Context only when the current ledger already contains that exact reply ID and marker linked to the source and a complete comparison authoritatively moved the source row to removed history; preserve that link to the removed source row. Otherwise stop on a malformed marker, a missing/cross-PR/self source, or an ambiguous source/compensation chain.
For an actionable bot-authored reply_only item associated with a historical or must-reconcile run, record the authoritative run ID and reviewed head SHA. When a valid current processing marker covers the item revision, reuse its disposition and reply result. Otherwise classify it as Superseded only when inspection of the current head proves that the finding was fixed or made inapplicable after the reviewed SHA; cite that evidence in the reply. If the finding still applies, triage it as actionable; if the run/head association or current applicability cannot be established, use Clarify rather than silently treating it as Context or repeatedly choosing Skip. An edited item or one associated with the current head always returns to triage.
Apply the same current-head rules to each action in an automation-output item. Record the authoritative run/output ID, reviewed head SHA, and exact annotation location or summary section for each action. Publish any required disposition reply as one general PR/MR comment for the complete output item. A terminal output is reconciled only after its current fingerprint has a ledger row, every independent finding has a decision, and any required reply is authoritative.
3. Build the Item Ledger and Triage ⛔ BLOCKING
Maintain one ledger row per canonical item. A Markdown table, JSON object, or equivalent structured record is acceptable, but every row must contain:
| Field group | Required values |
|---|---|
| Identity | platform, item kind, full canonical item ID, aliases, thread/discussion ID or reply_only |
| Source | author stable ID, origin, processed source item key or workflow event key when workflow-emitted, path/line or reply target, revision/update time, exact body_sha256 or N/A for an authoritative historical-output tombstone, current resolved/actionable state |
| Decision | stable per-action records with Implement / Superseded / Skip / Clarify / Context, rationale, affected files, aggregate item decision, and accepted-Skip closure evidence or N/A |
| Publication | At triage: planned reply/no-reply and pending for future values. Before the first remote write: workflow final SHA, marker-covered SHA, exact reply text, and deterministic marker. For an exact-syntax manual-trigger command item: exact command text, workflow event key, and marker: N/A. After the write: reply/item ID and result |
| Transition | At triage: observed pre-transition state, desired state, and planned Resolve/Reopen/No-op or N/A. After Step 8: transition result |
pending is a valid lifecycle value, not a missing ledger field. The Step 3 gate requires complete Identity, Source, and Decision values plus publication/transition plans; it must not require a future SHA, remote ID, or operation result. Replace each pending value at the step that authoritatively produces it, and freeze all remaining publication inputs in Step 7.
Classify every independently actionable request within each item:
| Decision | Meaning |
|---|---|
| Implement | Correct and applicable; change code and add or update targeted tests only when the changed contract or an uncovered stable regression warrants them |
| Superseded | Correct when written but demonstrably fixed, removed, or made inapplicable on the current head; cite the current code/diff evidence and make no new change |
| Skip | Incorrect, harmful, or conflicting; write a technical reason |
| Clarify | Intent cannot be determined safely; resolve under the mode-specific triage gate below |
| Context | Non-actionable acknowledgement, workflow reply, system/status information, or initial historical resolved item; record why |
Keep one canonical item row, but add a stable action key and decision for every independent request in that row. Use aggregate item decision Implement when at least one actionable record is Implement and every actionable record is Implement or Superseded, Superseded when all actionable records are Superseded, Skip when all are Skip, Mixed when Skip occurs with Implement or Superseded, Clarify while any action awaits clarification, and Context only when no actionable request exists. Mixed is an aggregate value, not a per-action decision. For an open inline finding tied to an older reviewed SHA, use Superseded rather than Skip only after the current head proves that the finding no longer applies.
Deduplicate items only by canonical item identity and action records only within the same current item revision. Similar text is not identity. Preserve old revisions as history and make decisions from the current revision only.
Keep a Skip as the original decision when a later item closes it. Mark that action accepted-Skip for thread-state computation only when the original reviewer or a repository owner explicitly withdraws the request or accepts the published technical rationale, or when authoritative actor and ordering evidence proves that such a person resolved the thread after the exact Skip reply became visible. Record the accepting item or transition identity and timestamp. A generic acknowledgement, an unattributed resolution, or an automation-produced state change is not acceptance. Treat closure evidence as current-state evidence: if the accepting item is edited or deleted, or its actor/order proof no longer validates, clear accepted-Skip and return the action to triage. Preserve the original Skip decision and reply as history; do not relabel it Superseded or post another reply solely for closure.
For each thread, compute one desired state from current action records:
- Resolved when it has at least one actionable record and every actionable record is Implement, Superseded, or a Skip with valid
accepted-Skipclosure evidence. - Open when any current action record is an unaccepted Skip or Clarify.
- Unchanged when it contains only neutral Context.
Compare that desired state with the observed pre-transition state. Plan Resolve only for open → resolved, Reopen only for resolved → open, and No-op when the thread is already in the desired state or the desired state is Unchanged. reply_only items use N/A.
Immediately before presenting the triage table, repeat the complete Step 2 run/output enumeration and review-context collection. Fetch and ledger every run now observed terminal, then freeze the run IDs, statuses, output fingerprints, canonical item IDs, and item fingerprints as the triage linearization snapshot. A run still active at this snapshot remains provisional must-reconcile; if it becomes terminal later, the next mandatory run/output enumeration returns its output to triage before publication. This snapshot does not claim atomic exclusion of later external changes.
Present the complete item-and-action triage table from that snapshot before editing. Do not begin code changes until every current item and action record is classified and every Clarify is resolved. In guarded mode, obtain user confirmation for Skip decisions unless the current request already explicitly authorized the presented triage, and ask the user to resolve any Clarify that authoritative context cannot resolve. In autonomous mode, record each Skip rationale and proceed without asking; a material Clarify that cannot be resolved from authoritative context invokes stop-and-report.
Every item with aggregate decision Implement, Superseded, Skip, or Mixed must have exactly one planned workflow reply covering all of its current action records. A valid existing marked reply may satisfy this requirement and must be reused. no-reply is allowed only for Context when no status response is required; Clarify cannot pass the gate.
4. Implement Fixes
Read trusted-base repository instructions and the target plus surrounding code before each change. Apply every Implement action record in dependency order, including Implement records inside a Mixed item. For every Superseded record, verify and cite the current code or intervening diff that already satisfies it; do not create a no-op change.
For each fix:
- Reproduce or verify the issue with the smallest relevant check when possible.
- Apply the minimal code change. Add or update a targeted test only when the changed observable contract or an uncovered stable regression warrants it; do not add duplicate tests for pure refactors, docs, configuration, or wiring-only changes.
- Run the smallest focused compilation, linting, existing test, or manual check that meaningfully verifies the change, then broaden only when the change crosses a boundary. Require every executed check to pass before publication; a known failing check always blocks publication. If a warranted check cannot run because trusted isolation or a prerequisite is unavailable, record the exact unverified scope and impact. In guarded mode, obtain explicit user acceptance before publication. In autonomous mode, stop-and-report without asking.
- Update callers and dependents only when the changed contract requires it.
5. Review-Fix Loop
Run at most three iterations over the entire accumulated diff.
- Map affected callers, consumers, implementers, importers, tests, and documented contracts.
- Re-read the full diff and affected code with the default assumption that the changes are wrong. If an isolated reviewer is available, provide only project conventions, the full diff, and the affected-code list—not fix rationale or earlier findings. Otherwise perform the same fresh-context review inline.
- Try to construct realistic failures for:
- caller or compatibility breakage;
- authorization, tenant isolation, or data-loss problems;
- null/empty values, concurrency, partial failure, and resource bounds;
- missing or non-discriminating tests where the changed risk warrants stronger verification;
- inconsistent fixes across items.
- Report findings with file, line range, code evidence, and impact. On iterations one and two, fix all in-scope findings, rerun focused verification, then restart from the full diff.
Only observable failures and documented-contract violations are findings. Publication requires the Step 4 verification gate plus a clean full-diff verdict after the latest modification. If iteration three finds anything, do not modify or publish; stop and report the findings. Any further fix requires a newly authorized review cycle, so no final change can bypass a clean adversarial review.
6. Commit and Obtain Publication Approval
- Re-fetch the exact head repository URL, full head ref, and remote head before commit preparation. Stop if the repository/ref mapping or SHA changed.
- Compare both the worktree and index with the preflight baseline and identify attributable paths and hunks. Never stage a baseline hunk.
- If uncommitted attributable code changes exist, show the final diff. Follow the trusted-base repository's commit-approval rule in every authorization mode. When it requires confirmation after the final diff, wait for that explicit confirmation; preflight or standing authorization cannot replace it. Otherwise, in guarded mode obtain explicit commit approval unless the current request already authorized commit, and in autonomous mode require every staged candidate to be attributable and
committo be present in the standing envelope before proceeding. If no uncommitted task change exists, record that no new commit approval or commit is required. - Follow repository commit rules; otherwise use Conventional Commits. Do not include review metadata.
- If approved uncommitted task changes exist, stage only those attributable hunks. Immediately before commit, inspect the complete
git diff --cachedand require every staged hunk to be attributable and approved; if any baseline staged entry is present, use an isolated checkout with its own index or stop. Never unstage or overwrite baseline index entries to make this check pass. Re-read the staged diff, create the approved commit or commits, then confirm that every remaining uncommitted hunk belongs to the preflight baseline or stop. - Capture the final local SHA and show every commit plus the complete
remote_head..final_shadiff. Prove that every commit and hunk is attributable to this task. In autonomous mode, replace the envelope's pending final SHA with this exact SHA only after proving that every included commit and hunk is attributable to the current task. When the workflow re-enters for new feedback on the same PR/MR and requires new attributable code changes, first invalidate the prior publication/final-SHA binding and restorefinal SHA: pending, but only if the PR/MR identity, authoritative source repository, full head ref, and recorded envelope scope are unchanged; then repeat the complete commit/hunk attribution proof before binding the new exact final SHA. This same-scope rebinding does not require renewed authorization. Revalidate that the PR/MR identity, authoritative source repository, full head ref, and recorded envelope scope still equal the envelope before initial binding or rebinding. Any identity, repository, ref, or scope mismatch invalidates standing push authority and triggers stop-and-report; do not ask for replacement authorization in the same execution. If no code change is needed and local HEAD already equals remote head, usepublication mode: no-push; otherwise usepublication mode: push. Never create an empty commit or publish an unattributed ahead commit. - In
publication mode: push, materialize the exact final SHA, authoritative head repository URL, and full head ref. Follow the trusted-base repository's push-approval rule in every authorization mode. When it requires a separate explicit push request or confirmation, obtain it for that exact tuple; neither commit approval nor the standing envelope replaces it. Otherwise, in guarded mode obtain explicit push approval for that tuple, and in autonomous mode require the tuple to match the standing envelope after its final-SHA binding before proceeding; a mismatch invokes stop-and-report. Inpublication mode: no-push, record that no push approval or refspec exists.
7. Synchronize Replies and PR/MR Context ⛔ BLOCKING
- Repeat the complete Step 2 fetch and directly re-fetch every processed thread/discussion. Compare canonical item IDs and fingerprints bidirectionally with the ledger before any remote write. Merge new or edited items, preserve deleted external items as removed history, and return to triage on any new, edited, deleted, or missing external item or action without a decision. Return to Step 7 planning without writing if an expected workflow-emitted effect is missing or changed.
- Re-fetch the exact head repository URL, full head ref, remote head, title, and body. Record the remote head as
expected_old_shabound to that URL and ref. Stop on any unexpected change. - Derive the desired PR/MR title and body from repository templates and the final repository diff/history. Follow the repository's PR/MR title convention when one exists; otherwise use Conventional Commits format. Update only when needed; never add review metadata or reference files outside the repository.
- Build a candidate publication plan with the final SHA, expected old SHA, exact reply operations, current metadata, expected critical-section entry metadata, expected final metadata after any deferred write, which metadata depends on the pending SHA, aggregate thread dispositions, the ordered transition operations and their inverse compensations, and the transition-plus-compensation time bound.
- Immediately before the first remote write, rebuild the complete known-trigger inventory from the same authoritative sources used at preflight, now including every exact candidate-plan operation. Compare it with the preflight evidence and re-run the ordering decision. Stop without writing if evidence changed for an event that can no longer be ordered safely. Otherwise freeze the refreshed inventory and safe order into the publication plan. Do not call this plan the frozen ledger: authoritative pre-push replies still need their own item rows and publication results.
Before any lease operation or other remote write, freeze a mode-neutral mutation authorization ledger with one row per planned mutation. Cover push; publication-lease acquire, renew, and release; reply create, edit, and compensating-create; metadata update and restore; Resolve/Reopen and every inverse; manual trigger; and duplicate delete. Each row records operation kind, exact target, payload or desired state, inverse compensation when applicable, authorization source, authorization scope, and eventual result. A lease row's exact target is the current PR/MR-scoped provider/repository-stable-ID/number key. In guarded mode, require every row to be covered by explicit preauthorization in the current request or explicit confirmation of that exact ledger. In autonomous mode, require every row except duplicate delete and a repository-checkpoint-approved push to match the standing envelope; record the exact post-diff or separate-push confirmation as the authorization source for any operation excluded from the envelope by repository rules. A duplicate delete instead requires the independent exact-ID grant below. The ledger records authorization and never creates or expands it. An unlisted mutation is prohibited. Before any operation substitution or compensation, refresh or add its exact row, re-run trigger ordering, re-match its authorization source and scope, and record that result; return to this gate before writing if the frozen ledger changes. All lease, optimistic-guard, reconciliation, compensation, verification, and completion requirements remain mandatory.
Before the first remote write, revalidate the acquire row and acquire the recorded exclusive publication lease only when its acquire, renew, and release operations are each authoritatively proven non-triggering. Record its owner token and expiry, renew it before expiry only through a revalidated renew row, and release it authoritatively after final verification or after recording every compensation on an early stop. If no eligible lease is available, use the lease-free path. If lease ownership is lost, stop all writes and reconcile remote state. Without a lease, freeze the optimistic guard defined in Concurrent publication safety and record the immediately revalidated preconditions for every write. For each triggering or unknown non-idempotent write, require the frozen order to designate it as the next trigger-safe operation and never retry it without provider idempotency or documented coalescing. Require every other write to be proven non-triggering, suppressed, coalesced, or safely convergent. Otherwise stop without mutating remote state.
After the lease or lease-free guard is established, publish context in the frozen trigger-safe order. In both publication modes, execute only context writes proven non-triggering or covered by a documented mechanism that prevents those writes from accepting or scheduling a review trigger, defers trigger acceptance until the final SHA is remote and every planned context write is authoritative, and binds the resulting run to that SHA and context. Keep a covered event classified as triggering or unknown and record the named later operation that releases the trigger. A delayed run start after an earlier trigger is not sufficient. When exactly one context write lacks that guarantee and push is proven non-triggering or the mode is no-push, freeze that operation and defer it to Step 8. Do not send any other unsuppressed triggering or unknown context write in this step.
Every workflow-authored reply, including a required status reply to a Context item, consists of the exact human-readable reply, one LF, and one final marker line:
resolve-review-comments:v1 {"platform":"github","item_kind":"review-thread-comment","item_id":"<full-id>","body_sha256":"sha256:<source-hash>","disposition":"Implement","final_sha":"<full-sha>","supersedes_reply_id":null}
Use github or gitlab, the canonical kind and full ID, the current source fingerprint, the marker-covered SHA, the aggregate item disposition (including Superseded, Mixed, or Context for a required status reply), and the prior full reply ID when compensating. Normally the marker-covered SHA is the workflow final SHA. When an eligible ancestor marker is reused, preserve its original SHA and record the current workflow final SHA separately in the ledger. The marker makes an exact successful reply reusable across retries.
Before each reply:
Treat reply create, edit, compensating create, and duplicate delete as distinct frozen trigger-inventory and mutation-authorization-ledger operations. Re-run both gates before substituting one operation for another.
- Re-fetch the exact item/thread and complete target reply collection.
- If the source changed or is missing, return to triage.
- If the exact intended reply text and marker already exist from the authenticated writer and the marker-covered SHA is the current remote head or the exact pending local SHA based on that remote head, reuse the reply ID and do not post again.
- If a marker from the same writer covers the same item revision, disposition, and still-accurate human-readable reply but its SHA is only an ancestor of the current head, inspect the intervening diff and current implementation. Reuse it unchanged only when the recorded disposition and reply remain true; preserve its marker-covered SHA in the ledger.
- If a marker from the same writer covers the same item revision but the intended text or disposition changed, or the ancestor check failed because the newer final SHA invalidated the reply, edit that reply when supported and permitted by the frozen trigger order. Otherwise publish one permitted compensating reply whose
supersedes_reply_idis the prior full reply ID. Record one acyclic chain with one terminal reply; stop on forks, cycles, or multiple terminal replies. - Otherwise post once and record the returned full reply ID.
- After every successful or ambiguous create, re-fetch the complete target replies and match exact body + marker + authenticated author. One match is authoritative. With multiple matches, stop and report every full canonical ID without creating, editing, deleting, or retrying another reply. Delete exact duplicates only under an independent exact-ID duplicate-delete grant naming the exact retain/delete IDs and recorded as that ledger row's authorization source. In guarded mode, obtain explicit confirmation for those exact IDs unless the current request already grants them. The default autonomous envelope does not authorize deletion; in autonomous mode, proceed only when the current request already contains that separate exact-ID grant, otherwise stop-and-report without asking. The grant does not expand the standing envelope. Immediately before each granted deletion, refresh the target, revalidate trigger order and the ledger row, delete only an authenticated-writer exact duplicate, and verify the granted retained reply is the unique match.
- On timeout or another ambiguous response, continue the complete reconciliation through the recorded comment-visibility bound. Reuse one unique match. With zero matches and an unchanged source/target, make one identical retry only when the reply event is proven non-triggering or uses the same provider idempotency key, then repeat step 7; otherwise stop. Never make a second retry.
Reply rules:
These rules govern reply content only. Keep the aggregate thread disposition frozen from Step 3 and execute every Resolve/Reopen mutation only in Step 8.
- Implement: state every Implement result and, when the item also has Superseded actions, their current-code or intervening-diff evidence. If sent before push, identify the final local SHA as the prepared fix and state that remote publication will be verified separately; use wording that remains true after a later push, and do not edit or post a second reply solely to announce publication. If deferred until after remote-head confirmation, say the change is published in the final SHA. Never claim an unpushed SHA is remote.
- Superseded: cite the current code or intervening diff that already removed the finding and state that no new change was required.
- Skip: state the technical reason.
- Mixed: state every applicable Implement result, Superseded current-code or intervening-diff evidence, and Skip reason in one reply.
- Clarify: cannot reach publication until resolved.
- Context: do not reply unless a status response is required; when required, use the same marker and replay-safety procedure with disposition
Context.
After every context write, record its authoritative result and any newly observed automation run or bot item. For every authoritative workflow-authored reply, update the source item's publication result and upsert exactly one reply row by canonical item ID as Context with origin: workflow-emitted and its source item key. If observed behavior contradicts the recorded event classification, stop every forward publication mutation, add the event to the trigger inventory, and perform a complete read-only re-fetch. Permit only the frozen safe compensation in the pre-publication abort procedure, then release the lease when permitted and report that the already delivered event may have exposed partial context. Do not restart this step or Step 7 in the same execution; replanning cannot repair an already accepted trigger.
Proceed only after every non-deferred known reply and required metadata update is authoritative and the single deferred trigger operation, if any, is frozen exactly in the publication plan. Re-fetch the complete current review context and metadata and reconcile every non-deferred planned effect with a bidirectional canonical-ID comparison. If any external item is new, edited, deleted, or missing, or any current external action lacks a decision, preserve removed rows as history and return to triage without freezing publication state. If an expected workflow-emitted effect is missing or changed, return to the start of Step 7 without rewriting history or silently recreating it. Otherwise freeze the critical-section ledger and metadata baselines. The critical-section ledger must include exactly one row for every current item and every pre-push workflow-emitted reply; keep the deferred operation separate until Step 8 executes and records its effect.
Define one pre-publication abort procedure for every stop or return after a Step 7 remote write and before push success or no-push confirmation. For each title/body value recorded in the publication plan as depending on the pending SHA, refresh the exact field and restore its recorded pre-write value only when the current value still equals this workflow's desired value, the compensation is permitted by the refreshed trigger order and a re-matched exact ledger row, and any acquired publication lease is still owned and valid. A lost lease or changed lease-free guard permits reconciliation reads but no compensation write. Verify every attempted restoration authoritatively. When a safe restoration is unavailable, make no compensating write and record the exact stale metadata value in the stop report. A truthful prepared-fix reply does not require deletion; reuse or supersede it on the next Step 7 entry. Invoke this procedure before leaving Step 7 or the pre-publication portion of Step 8 for any drift, lost guard or lease, changed trigger evidence, or failed push.
8. Push and Transition Threads
Before entering either publication mode:
- Prove that any held publica
Truncated - read the full file at https://github.com/whhe/ai-workshop/blob/f88764434e3f60ad1677bfa0bca3de80bb6943cc/skills/resolve-review-comments/SKILL.md.
