# PR#130: hs-review --attach Posts the Checked Draft and Its Diagrams to the PR Version: minor > **WARNING:** This document describes only the change applied in this PR. > It may already be outdated once the next PR is merged. > Historic PR documentation is not maintained along with new PRs; treat it as a snapshot. ## Related Links - [PR#129](2026-10-20-PR#129-hs-review-diagrams.md): hs-review puts the diagrams of PR Lens next to its draft. ## Problem `hs-review` writes a draft, `report.md`, and the SVGs of PR Lens next to it (Hostsharing-internal tool). The human checks the draft and then posts it by hand: copy the text into a PR comment, attach each SVG, fix the links. ## Non-Goals - No new review: `--attach` posts the draft that is there. - No posting of an unchecked draft. ## Specification ### Feature: hs-review --attach posts the checked draft #### Scenario#130.01: a checked draft is posted with its diagrams … so that the human posts the review and its diagrams with one command. - **Given** a draft of `hs-review` for the head of the PR, without the line "> **Draft:** …", and its SVGs next to it - **When** the human runs `hs-review --attach` - **Then** the PR gets a comment with the draft under the account of the human, the SVGs as its attachments and the images linked to them ##### Verified by - [test_reviewreport.AttachTest.test_a_checked_draft_is_posted_with_its_diagrams](../../tests/test_reviewreport.py) - [test_reviewreport.AttachTest.test_a_failed_upload_leaves_no_comment_and_allows_a_retry](../../tests/test_reviewreport.py) #### Scenario#130.02: a draft that is not ready is refused … so that no unchecked, outdated or duplicate review reaches the PR. - **Given** a draft that still has the line "> **Draft:** …", or is for another head, or whose head has a posted draft already - **When** the human runs `hs-review --attach` - **Then** it posts nothing and names the reason ##### Verified by - [test_reviewreport.AttachTest.test_an_unchecked_draft_is_refused](../../tests/test_reviewreport.py) - [test_reviewreport.AttachTest.test_a_draft_of_another_head_is_refused](../../tests/test_reviewreport.py) - [test_reviewreport.AttachTest.test_a_second_post_for_the_same_head_is_refused](../../tests/test_reviewreport.py) - [test_reviewreport.AttachTest.test_a_missing_svg_is_refused_before_any_write](../../tests/test_reviewreport.py) - [test_reviewreport.AttachTest.test_a_finding_that_quotes_the_draft_line_is_no_refusal](../../tests/test_reviewreport.py) ## Solution - `tools/review-report --attach` reads `report.md` of the PR and checks it before the first write: the head in its title is the head of the PR, the draft line is gone, werkrevisor and Codex reviewed the same commit, each linked SVG lies next to it, and no comment holds `` yet. - It posts the draft with a pending marker, uploads the SVGs as attachments of the comment, and sets the marker `` with the last edit, which points the images to them; the sentence "Attach the SVGs next to this file when you post." stays out. - A failed upload or edit deletes the comment again, so a retry is not refused as a duplicate. - The draft line and the warning of different commits count only in the header, before the first `###`; a finding may quote them. - A lock file next to the draft keeps two runs of `--attach` for one PR apart. - `GiteaClient.delete_issue_comment` is new. - `~/bin/hs-review` (Hostsharing-internal, not in this repository) passes `--attach` on, and takes `HOSTSHARING_GITEA_REVIEW_TOKEN` instead of the read token for it; both belong to the account of the human.