Repository navigation
feat(ghpost): set an issue type through gh-post - #1034
Conversation
a8036bb to
953a851
Compare
There was a problem hiding this comment.
Reviewed head: 953a851
Review: CHANGES REQUESTED
Loosens: yes — internal/ghpost/issue_type_internal_test.go:4 adds a file-wide paralleltest exemption; no repository gate configuration changes.
Owner-tier: no
Acceptance criteria
Read the live #1030 body, labels and both Refinement comments, including the AC11 READY refinement and updatedAt 2026-11-01T06:09:43Z. This review uses the current AC11 wording.
| AC | Result | Evidence on the reviewed head |
|---|---|---|
| AC1 | Met | internal/ghpost/issue_type.go:101 resolves the repository type, internal/ghpost/issue_type.go:145 writes it and internal/ghpost/issue_type.go:157 reads it back; internal/ghpost/issue_type_internal_test.go:50 covers all four names on an untyped issue. |
| AC2 | Met | internal/ghpost/issue_type.go:162 reports previous and requested values; internal/ghpost/issue_type_internal_test.go:66 checks the changed state and both output values. |
| AC3 | Met for the specified type-only form | internal/ghpost/issue_type.go:141 returns before mutation; internal/ghpost/issue_type_internal_test.go:75 checks success, the unchanged message and no type/body write. See F1 for accompanying metadata edits. |
| AC4 | Met | internal/ghpost/issue_type.go:17 and internal/ghpost/issue_type.go:24 reject unsupported names; internal/ghpost/run.go:53 returns status 2 before repository/identity calls; internal/ghpost/issue_type_internal_test.go:84 checks the message and zero calls. |
| AC5 | Met | internal/ghpost/issue_type.go:116 refuses a missing repository type with its name and environment status; internal/ghpost/issue_type_internal_test.go:96 checks lookup and no mutation. |
| AC6 | Met | internal/ghpost/issue_type.go:121 refuses a missing issue before any write and names it; internal/ghpost/issue_type_internal_test.go:106 covers that result. |
| AC7 | Met | internal/ghpost/issue_type.go:126 checks viewerCanUpdateMetadata before body/type writes and names the repository; internal/ghpost/issue_type_internal_test.go:115 verifies denial and no mutation. |
| AC8 | Met | internal/ghpost/state.go:30 avoids reading stdin, and internal/ghpost/issue_type.go:130 avoids content editing without an explicit body or metadata; internal/ghpost/issue_type_internal_test.go:125 checks exactly one type mutation and no issue edit. |
| AC9 | Met | internal/ghpost/run.go:63 reads the supplied body and internal/ghpost/run.go:87 scans it before identity or writes; internal/ghpost/issue_type_internal_test.go:134 checks a clean combined write and refusal of both writes for a seeded-secret finding. |
| AC10 | Met for the specified successful/refused cases | internal/ghpost/run.go:42 opens the type audit before request execution and internal/ghpost/issue_type.go:58 records issue, requested type and outcome; internal/ghpost/issue_type_internal_test.go:155 checks success, unchanged, invalid, undefined, missing, access, secret, identity and input cases. |
| AC11 | Not fully met | internal/ghpost/issue_type_internal_test.go:203 is hermetic: it checks usage and package shell-file absence, has no t.Skip, and depends on neither git state nor origin/main. Exact-head path scope is listed below. However, internal/ghpost/issue_type_internal_test.go:24 adds executable shell fixture logic, and internal/ghpost/issue_type_internal_test.go:4 adds a lint exemption. See F2 and F3. |
Feature behavior lives in Go. The production changes introduce no shell logic, gate configuration, guard allowlist entry or owner-tier path. The literal confirmation that the entire change adds no shell logic/check exemption cannot be made because of F2/F3.
Exact-head scope and size
I ran git diff --name-status origin/main...HEAD in the existing checkout whose HEAD is exactly 953a851. origin/main is 37f71fd, matching the PR base. The complete result and classifications follow; no other changed path exists.
| Status | Changed path | Classification | Owner-tier |
|---|---|---|---|
| M | internal/ghpost/args.go | Go code | no |
| M | internal/ghpost/help.go | Go code, including usage prose | no |
| A | internal/ghpost/issue_type.go | Go code | no |
| A | internal/ghpost/issue_type_internal_test.go | Go tests, counted as code | no |
| M | internal/ghpost/label.go | Go code | no |
| M | internal/ghpost/run.go | Go code | no |
| M | internal/ghpost/state.go | Go code | no |
All changed paths are Go files. No CODEOWNERS, agent-skills.conf, .agents/review-instructions.md, config/claude/automode.json, .claude/settings*.json, .codex/config.toml, workflow/action, lib.sh, agent.sh, guard script or merge-pr script changes. No guard allowlist entry changes.
Size measured independently with scc 4.1.0 on this exact checkout: 385 changed code lines = 380 added + 5 deleted, against 800; 0 changed prose-file lines = 0 added + 0 deleted, against 2000. Tests are included: 192 test code lines and 193 other Go code lines. I extracted each path's added/deleted lines from git diff --unified=0 origin/main...HEAD and counted the two sides with scc as Go; comments and blanks are excluded. The raw diff is 416 additions plus 6 deletions. My measurement is one code line below the builder's stated 386; either is below the hard limit. No prose/documentation file changed; embedded usage text counts with help.go as code.
Comparing git diff a8036bb..HEAD shows only internal/ghpost/issue_type_internal_test.go changed: os/exec becomes os, and AC11's git-diff assertion becomes the package directory assertion. Every AC1-AC10 test and production implementation is byte-for-byte unchanged. There is no new t.Skip or weakened AC1-AC10 assertion. AC11 keeps its --type usage assertion and replaces its old origin/main-dependent scope assertion under the current live refinement; it does not silently keep testing the old contract. This review independently supplies the full changed-path check. AC11 itself invokes no setup helper and has no inherited Windows skip. Other AC tests retain the pre-existing setup helper's Windows skip at internal/ghpost/run_internal_test.go:27.
Checks, signature and documentation
The single requested statusCheckRollup read showed every individual check COMPLETED/SUCCESS. All four test matrix jobs passed on this head: ubuntu-24.04, ubuntu-24.04-arm, macos-15 and windows-2025. Both Bats jobs and the Python tests also passed. The earlier head's four failing test jobs are not failures on this head. Mechanical gates were not rerun.
Mergeability from that read: MERGEABLE; mergeStateStatus: BLOCKED.
Re-read the exact-head coverage and CodeQL contexts. Coverage's conclusion is SUCCESS, but its upload failed HTTP 403 because Code quality is not enabled for the repository; the existing fail-on-error: false makes that upload nonfatal (.github/workflows/ci.yml:237). Therefore the context does not establish a successfully published coverage report. CodeQL is SUCCESS and explicitly reports no new alerts in code changed by this PR; both analyze (go) and analyze (actions) also concluded SUCCESS.
GitHub's commit verification for this head reports verified: true, reason: valid. The branch has one commit with Assisted-by and Signed-off-by trailers. The PR has provenance:agent-assisted. Closing references in the PR and commit are only Fixes #1030.
Usage documents --type and its accepted values at internal/ghpost/help.go:31. No standalone doc file changed. The production flag documentation is present; the generic default-stdin guidance at internal/ghpost/help.go:22 should also describe the type-only exception introduced at internal/ghpost/state.go:30.
Findings
- F1 [P1] Preserve the issue body when combining --type with metadata. At internal/ghpost/issue_type.go:130, any metadata flag sends the request through postContent even when no body file was supplied. The new internal/ghpost/state.go:30 branch has already discarded stdin, leaving body nil. internal/ghpost/run.go:353 preserves omitted bodies only for PR edits; internal/ghpost/run.go:360 therefore constructs an issue edit with --body-file - and empty input. For example, gh-post issue edit 12 --repo owner/repo --type Feature --add-label triaged clears the existing issue body before changing its type. The same occurs with --title, assignee and milestone flags, and even when the type is already unchanged. Omit the body flag for this metadata-only issue edit unless a body file was explicitly provided, and add a regression asserting the existing body survives. This finding comes from tracing the exact-head command construction, without rerunning gates.
- F2 [P2] The change adds a check exemption, so it is not tightens-only. internal/ghpost/issue_type_internal_test.go:4 newly suppresses paralleltest for the entire file. That linter is enabled at .golangci.yml:101, and nolint is explicitly a loosening marker at .agents/agent-skills.conf:6. The environment-changing fixture explains the implementation choice, but an existing convention does not make a newly added exemption disappear. Remove the added exemption through a test arrangement compatible with the check, or resolve its policy/scope exception explicitly before treating this as Loosens: no. No repository gate definition or owner-tier path changed.
- F3 [P2] AC11's literal no-new-shell-logic requirement is unmet by the fake client. internal/ghpost/issue_type_internal_test.go:24 adds a POSIX shell program with new case branches, access checks and mutation simulation, writes it as an executable gh, and executes it through the existing process harness. Keeping that program inside a Go raw string makes the diff Go-file-only, but does not make the added logic Go. Use a Go fake for this new behavior, or obtain an explicit refinement that permits shell test fixtures; the current AC11 has no such exception. The hermetic AC11 filename test cannot detect this embedded shell program.
Round-1 findings: 0 closed, 3 open. Loosens: yes for F2. This change does not only tighten checks. Existing scan and posting identity checks still precede the new type write (internal/ghpost/run.go:87 and internal/ghpost/run.go:200), and no new exemption was added to those security checks. The coverage upload exception predates this change.
Over-engineering
No separate over-engineering finding. The added parser, type lookup/read-back and refusal audit helpers serve AC1-AC10; there is no new configuration knob or speculative guard layer. F1 has the simpler form described above: omit an unrequested body edit.
Base definition of done
- D1 — Unmet: the published PR Verification lists commands but does not cite AC1-AC11 individually with command/result or link evidence; no merged head exists yet. This review's AC table does not replace the author's required Verification section.
- D2 — Unmet: this exact-head independent review requests changes; F1-F3 remain open.
- D3 — Partial: all reported required/check contexts passed on this head, but the added lint exemption has no demonstrated exact-head owner approval. Coverage's upload limitation is stated above.
- D4 — Partial: gitleaks and CI leak steps passed. CI's exact-range leak log explicitly says no private values were loaded, so it does not prove the private-strings-list scan. The review body is separately scanned with check-leaks-with-lists before posting; repository private-list completion remains unverified without rerunning prohibited gates.
- D5 — Partial: GitHub verifies the sole head commit's signature (valid); the future squash has not occurred.
- D6 — Partial: help.go:31 documents the new flag, but help.go:22 still promises default stdin for content operations while state.go:30 ignores it with --type unless --body-file is explicit. Clarify this exception.
- D7 — Partial: the current commit has Assisted-by and the PR has provenance:agent-assisted; future squash trailers remain to be verified.
- D8 — Met: independently measured 385/800 code and 0/2000 prose-file lines, including tests and both diff sides.
- D9 — Unmet while findings remain open: no deferred findings/follow-ups are listed under Related. Fix the findings in this PR or file and link any accepted deferral with the required Problem and numbered ACs.
- D10 — Unmet until merge: the sole closing reference is Fixes #1030; the merge, board Done state and final Status comment do not exist yet.
Round: 1 of 3
Refinement requires a type before anyone can mark an issue ready, and gh-post could create issues and edit their bodies and labels but not set a type. An agent that filed or revised an issue had to wait for a person to set it, or make a raw API write that the posting rule bars. Adding a type flag to issue edit puts this write behind the same identity, leak, and audit checks as every other posting operation. An edit that changes only the type and metadata must not read stdin as a replacement body, or it would blank the description. Fixes #1030 Assisted-by: claude-code:claude-sonnet-5-5 Signed-off-by: Tony Burns <tony@tonyburns.net>
953a851 to
e945fe2
Compare
There was a problem hiding this comment.
Reviewed head: e945fe2
Review: APPROVED
Loosens: no
Owner-tier: no
Acceptance criteria
Read #1030 live, its refinement:ready label, and every Refinement comment (the original READY round 2 and AC11 READY round 1). Its updatedAt remains 2026-11-01T06:09:43Z. AC11 wording is unchanged from that live refinement: “Non-functional: the change is Go only, adds no shell logic, and touches no gate, guard allowlist entry or owner-tier path. A Go test asserts the package has no shell files and still documents --type in its usage text. Review verifies the rest of the diff scope on the exact head, and the review brief lists the changed paths.” This review judges that wording.
| AC | Result | Exact-head evidence |
|---|---|---|
| AC1 | Met | internal/ghpost/issue_type.go:101 resolves the repository type, internal/ghpost/issue_type.go:145 updates it, and internal/ghpost/issue_type.go:157 reads it back; internal/ghpost/issue_type_internal_test.go:135 covers all four allowed types on an untyped issue, including read-back and mutation ID assertions. |
| AC2 | Met | internal/ghpost/issue_type.go:162 reports the old and new names; internal/ghpost/issue_type_internal_test.go:152 checks both output names and the new state. |
| AC3 | Met | internal/ghpost/issue_type.go:141 skips the type mutation when unchanged; internal/ghpost/issue_type_internal_test.go:162 checks success, the unchanged message and no write. Explicit accompanying content/metadata edits still run, as documented in the PR. |
| AC4 | Met | internal/ghpost/issue_type.go:19 validates the four names; internal/ghpost/run.go:53 returns status 2 before repository or identity calls; internal/ghpost/issue_type_internal_test.go:172 checks --type in the error and zero GitHub calls. |
| AC5 | Met | internal/ghpost/issue_type.go:116 refuses after lookup and before update, naming the undefined type; internal/ghpost/issue_type_internal_test.go:185 checks status 2, lookup, and no mutation. |
| AC6 | Met | internal/ghpost/issue_type.go:121 refuses a missing issue and names its number; internal/ghpost/issue_type_internal_test.go:196 checks status 2 and no mutation. |
| AC7 | Met | internal/ghpost/issue_type.go:126 checks viewerCanUpdateMetadata before either write and names the repository; internal/ghpost/issue_type_internal_test.go:206 checks refusal, access lookup and no mutation. |
| AC8 | Met | internal/ghpost/state.go:30 avoids implicit stdin, and internal/ghpost/issue_type.go:130 skips the content command without body/metadata flags; internal/ghpost/issue_type_internal_test.go:217 checks exactly one mutation and no issue edit or body payload. |
| AC9 | Met | internal/ghpost/run.go:63 reads the explicit body and internal/ghpost/run.go:87 scans it before identity/write; internal/ghpost/issue_type_internal_test.go:227 checks clean combined writes and that a seeded-secret finding prevents both writes. |
| AC10 | Met | internal/ghpost/run.go:42 starts the audit before execution, and internal/ghpost/issue_type.go:58 records issue, requested type and outcome; internal/ghpost/issue_type_internal_test.go:249 checks success, unchanged, invalid, undefined, missing, access, secret, identity and input cases. |
| AC11 | Met | internal/ghpost/issue_type_internal_test.go:298 checks usage and package shell-file absence. It has no t.Skip, invokes no setup helper, and depends on neither git state nor origin/main. The complete exact-head scope check below confirms Go only, no added shell logic, no gate, no guard allowlist entry, and no owner-tier path. The new fake is Go at internal/ghpost/issue_type_internal_test.go:23. |
Feature behavior and its new fake live in tested Go. Help at internal/ghpost/help.go:24 explains the stdin exception, and internal/ghpost/help.go:32 documents --type and all accepted values. No standalone documentation impact beyond that usage text; no configuration migration or compatibility deprecation is introduced.
Exact-head scope
I ran git diff --name-status origin/main...HEAD myself in the clean existing checkout at exactly e945fe2. The current local origin/main is d7a42bb; its merge base with HEAD is 37f71fd, the stated PR base. The full result is:
| Status | Changed path | Counts as | Owner-tier |
|---|---|---|---|
| M | internal/ghpost/args.go | Go code | no |
| M | internal/ghpost/help.go | Go code, including embedded usage prose | no |
| A | internal/ghpost/issue_type.go | Go code | no |
| A | internal/ghpost/issue_type_internal_test.go | Go tests, included in the code limit | no |
| M | internal/ghpost/label.go | Go code | no |
| M | internal/ghpost/run.go | Go code | no |
| M | internal/ghpost/state.go | Go code | no |
Confirmation: Go only, no added shell logic, no gate, no guard allowlist entry, no owner-tier path. No CODEOWNERS, any agent-skills.conf, .agents/review-instructions.md, config/claude/automode.json, .claude/settings*.json, .codex/config.toml, .github/workflows/, .github/actions/, lib.sh, agent.sh, guard*.sh or merge-pr scripts changed.
I also ran git diff 953a8512969d40b3880f60818f34e47135547847..e945fe24b7244945c1be2b0e9a760545d2c686c0 --name-status. Its entire result is:
M internal/ghpost/help.go
M internal/ghpost/issue_type_internal_test.go
M internal/ghpost/run.go
That delta is confined to F1-F3: preserving the body, removing the lint exemption, replacing the embedded shell fake with Go, activating that fake in existing tests, and adding the metadata regression. The one usage sentence in help.go is the only companion documentation change; it resolves the round-1 D6 mismatch and describes F1's body/input semantics. No unrelated change or speculative layer appears.
Compared AC functions with the round-1 head: AC1-AC10 assertions are byte-for-byte unchanged after excluding the added t.Setenv(fakeGHEnv, "1") activation lines. AC11 is byte-for-byte unchanged from 953a851. Compared with a8036bb, AC1-AC10 retain those same assertions and meaning; AC11 alone replaces the git/origin/main-dependent scope assertion with the hermetic directory assertion specified by the current live refinement. Its --type assertion remains. No t.Skip or weakened AC1-AC10 assertion was added. AC11 itself neither skips nor needs git refs. The pre-existing shared setup at internal/ghpost/run_internal_test.go:26 still skips fixture-based cases on Windows; that is unchanged and is not a new exemption.
Size
Independently measured with scc 4.1.0 on this exact checkout, using the installed macOS binary of that version. For each changed path I extracted added and deleted lines separately from git diff --unified=0 origin/main...HEAD, then counted each side as Go with scc (comments and blanks excluded).
- Code: 487 / 800 changed code lines = 481 added + 6 deleted. All seven paths above count as code; 290 are Go test code lines and 197 are other Go code lines.
- Prose files: 0 / 2000 changed lines = 0 added + 0 deleted. No prose/documentation file changed. Embedded help text is counted with help.go as code.
- Raw diff: 531 additions + 9 deletions = 540 lines. Both size limits pass; no size P1.
The same method measures the prior reviewed head at 385 code lines (380 added + 5 deleted), reproducing round 1. This head increases that by 102 code lines: tests increase from 192 to 290 (+98) for the Go process fake and regression, and other Go increases from 193 to 197 (+4) for body preservation and usage. Raw churn increases by 118 lines (422 to 540). The supplied 386-line measurement does not describe this exact head; the independently measured 487 does, and remains under 800.
Round-1 findings, verbatim
- F1 [P1] Preserve the issue body when combining --type with metadata. At internal/ghpost/issue_type.go:130, any metadata flag sends the request through postContent even when no body file was supplied. The new internal/ghpost/state.go:30 branch has already discarded stdin, leaving body nil. internal/ghpost/run.go:353 preserves omitted bodies only for PR edits; internal/ghpost/run.go:360 therefore constructs an issue edit with --body-file - and empty input. For example, gh-post issue edit 12 --repo owner/repo --type Feature --add-label triaged clears the existing issue body before changing its type. The same occurs with --title, assignee and milestone flags, and even when the type is already unchanged. Omit the body flag for this metadata-only issue edit unless a body file was explicitly provided, and add a regression asserting the existing body survives. This finding comes from tracing the exact-head command construction, without rerunning gates.
- F2 [P2] The change adds a check exemption, so it is not tightens-only. internal/ghpost/issue_type_internal_test.go:4 newly suppresses paralleltest for the entire file. That linter is enabled at .golangci.yml:101, and nolint is explicitly a loosening marker at .agents/agent-skills.conf:6. The environment-changing fixture explains the implementation choice, but an existing convention does not make a newly added exemption disappear. Remove the added exemption through a test arrangement compatible with the check, or resolve its policy/scope exception explicitly before treating this as Loosens: no. No repository gate definition or owner-tier path changed.
- F3 [P2] AC11's literal no-new-shell-logic requirement is unmet by the fake client. internal/ghpost/issue_type_internal_test.go:24 adds a POSIX shell program with new case branches, access checks and mutation simulation, writes it as an executable gh, and executes it through the existing process harness. Keeping that program inside a Go raw string makes the diff Go-file-only, but does not make the added logic Go. Use a Go fake for this new behavior, or obtain an explicit refinement that permits shell test fixtures; the current AC11 has no such exception. The hermetic AC11 filename test cannot detect this embedded shell program.
Round-2 disposition
- F1 closed — internal/ghpost/run.go:354 includes typed issue edits in omitted-body preservation, returning before --body-file is added when no body file was given. Explicit body files retain their old behavior. internal/ghpost/issue_type_internal_test.go:308 checks metadata editing with both an untyped and an already-Feature issue, requiring the label edit and no body payload. That shared command construction also covers title, assignee and milestone flags. internal/ghpost/help.go:24 now documents the input exception.
- F2 closed — the new file-wide paralleltest exemption is gone. I searched every changed file on the exact head: no paralleltest directive or any other nolint directive remains in the PR's files, and no t.Skip appears there. Environment-changing tests use t.Setenv directly; AC11 retains t.Parallel (internal/ghpost/issue_type_internal_test.go:138, internal/ghpost/issue_type_internal_test.go:299).
- F3 closed — internal/ghpost/issue_type_internal_test.go:23 uses TestMain to re-execute the Go test binary as gh; internal/ghpost/issue_type_internal_test.go:43 implements the fake responses in Go; internal/ghpost/issue_type_internal_test.go:120 links that executable. No embedded shell program or shell fake remains in the new issue-type test file. The unchanged shared setup still creates its old shell fixture (internal/ghpost/run_internal_test.go:40); setupIssueType immediately removes it at internal/ghpost/issue_type_internal_test.go:122 before any gh execution. No shell logic was added or executes as the issue-type fake.
Findings: 0 open, 3 closed. No new defect found on this head.
Loosens: no. This change does not loosen, weaken, skip or add an exemption to any gate or check. It removes the added lint exemption, so the check-related delta only tightens. Body scans still precede the identity guard and writes (internal/ghpost/run.go:87, internal/ghpost/run.go:200); the new access guard precedes both writes (internal/ghpost/issue_type.go:126). No gate definition, guard allowlist entry or owner-tier path changes. The existing coverage upload exception described below is unchanged.
Over-engineering
No P2 over-engineering finding. The type lookup, access check, read-back, audit and Go subprocess fake serve AC1-AC10 and F3. There is no new config knob, speculative guard or unnecessary layer. F1 uses the existing command builder's omitted-body handling rather than a second edit path.
Checks, signature and mergeability
Read statusCheckRollup exactly once: every individual check is COMPLETED/SUCCESS. This head's four test jobs all passed: ubuntu-24.04, ubuntu-24.04-arm, macos-15 and windows-2025. The Python job and both Bats jobs passed too. The earlier head's four failing test jobs are resolved in this head's reported results. Mechanical gates were not rerun.
Mergeable: MERGEABLE; mergeStateStatus: BLOCKED at that read. Approval does not itself establish that every branch-policy condition is satisfied.
Re-read the exact-head Coverage and CodeQL contexts:
- Coverage: SUCCESS, but its annotation and job log report HTTP 403 because Code quality is not enabled for the repository. The existing nonfatal upload setting means this green context does not prove a published coverage report. The log's COMMIT_OID matches this head.
- CodeQL: SUCCESS, explicitly “No new alerts in code changed by this pull request”; its head_sha matches this head. Both analyze (go) and analyze (actions) also passed.
GitHub's commit verification for e945fe2 reports verified: true, reason: valid. The PR has a single commit carrying Assisted-by and Signed-off-by trailers and the provenance:agent-assisted label. Closing references in both the PR and commit are only Fixes #1030.
Base definition of done
- D1 — Author Verification now cites AC1-AC11 individually with commands and passing results, plus the metadata regression. This review supplies exact-head evidence above; verification of the eventual merged head remains pending merge.
- D2 — This independent review approves this exact head and closes F1-F3; no deferred finding remains.
- D3 — All reported contexts pass on this head; Loosens: no, so no loosening waiver is needed. Coverage upload limitation is disclosed above.
- D4 — Gitleaks and CI leak steps passed, and this review body is scanned with check-leaks-with-lists before posting. The CI leak log says no private values were loaded, so the repository-wide private-list scan is not established by that CI evidence. No prohibited gate rerun was performed.
- D5 — GitHub verifies the sole branch commit's signature as valid. The future squash signature remains pending merge.
- D6 — internal/ghpost/help.go:24 and internal/ghpost/help.go:32 match the stdin behavior and accepted --type values. No standalone document update is needed for this CLI extension.
- D7 — The branch commit has Assisted-by and the PR has provenance:agent-assisted. Future squash trailers remain pending merge.
- D8 — Independently measured 487/800 code and 0/2000 prose-file lines, additions plus deletions, including tests.
- D9 — All three findings are fixed in this PR; no follow-up or deferred finding needs an issue or Related entry.
- D10 — Fixes #1030 is the sole closing reference. Actual merge, board Done and final Status comment naming the merge commit remain pending merge.
Round: 2 of 3
Summary
gh-post issue edit <N> --type <Feature|Defect|Chore|Spike>sets or changes an issue's type. An unchanged type skips the type mutation, while accompanying body or metadata edits still run. A type change with metadata flags and no body file leaves the issue body intact. The audit log records the issue, the requested type, and the outcome.Why
Refinement requires a type before anyone can mark an issue ready. Agents could file and revise issues through
gh-postbut not set a type, so an issue waited on a person or a raw API call that the posting rule bars. The type write now goes through the same identity, leak, and audit checks as the other posting operations.Verification
go test ./internal/ghpost -run 'TestIssueEditTypeAC1$' -count=1go test ./internal/ghpost -run 'TestIssueEditTypeAC2$' -count=1go test ./internal/ghpost -run 'TestIssueEditTypeAC3$' -count=1go test ./internal/ghpost -run 'TestIssueEditTypeAC4$' -count=1go test ./internal/ghpost -run 'TestIssueEditTypeAC5$' -count=1go test ./internal/ghpost -run 'TestIssueEditTypeAC6$' -count=1go test ./internal/ghpost -run 'TestIssueEditTypeAC7$' -count=1go test ./internal/ghpost -run 'TestIssueEditTypeAC8$' -count=1go test ./internal/ghpost -run 'TestIssueEditTypeAC9$' -count=1go test ./internal/ghpost -run 'TestIssueEditTypeAC10$' -count=1go test ./internal/ghpost -run 'TestIssueEditTypeAC11$' -count=1--typekeep the bodygo test ./internal/ghpost -run 'TestIssueEditTypeMetadataKeepsBody' -count=1go test ./internal/ghpost -count=1GOOS=windows go vet ./internal/ghpostmise run lint-goRisk
A wrong type write would change an issue's type without the intended audit entry. The change stays inside
internal/ghpostand doesn't add shell logic. It doesn't change a gate, a guard allowlist entry, or an owner path. Reverting it removes the flag and leaves every other posting operation as before.Compatibility: none
Related
Fixes #1030