Skip to content

fix(triage): resolve issue-field ids repo-scoped, and fail when triage records no state - #10

Merged
azlekov merged 1 commit into
mainfrom
fix/triage-field-ids-repo-scoped
Aug 20, 2026
Merged

fix(triage): resolve issue-field ids repo-scoped, and fail when triage records no state#10
azlekov merged 1 commit into
mainfrom
fix/triage-field-ids-repo-scoped

Conversation

@azlekov

@azlekov azlekov commented Aug 20, 2026

Copy link
Copy Markdown
Contributor

What was wrong

Triage set the issue type and area:* labels but silently wrote no fields on some issues, reporting success either way. dodi-smart/kodni.me#160 is the reported case; #159 and #173 the same week, while #161 and #174 came out fully populated. That split is what made it read as flaky.

The prompt told the agent to resolve field ids from /orgs/{org}/issue-fields. run-agent runs on an OIDC-exchanged Claude App token, and gh api /orgs/dodi-smart/installations shows that installation holding repo-scoped permissions only — not a single organization_* permission. Every /orgs/* path returns 403 Resource not accessible by integration, REST and GraphQL alike.

setIssueFieldValue itself is authorised by repo issues: write and works. Only the id lookup was closed. So the outcome depended on whether the agent improvised another id source after the documented one 403'd — some did, some reported honestly that they could not and stopped.

What this changes

  • Repo-scoped catalog. Ids come from repository(owner,name){ issueFields } — same org-level fields, same node ids, no org access needed. Verified live against kodni.me.
  • Enumerated options. The prompt now lists the valid option names. Without them an agent wrote Effort: XS, which is not an option (High | Medium | Low).
  • The job checks itself. A final step re-reads Triage state and fails if it is unset. Nothing was red before: an unset state means issue-implement.yml refuses the issue, so the break surfaced days later on a different workflow with the causing run out of view — DODI-00007 one layer in. The read is repo-scoped on purpose; a check using a stronger token than the agent had would pass where the agent failed.

Also records the node-id-vs-database-id trap and the fieldId / issueFieldId naming trap directly in the prompt, since both produce errors that point nowhere near the cause.

Rejected

  • Grant the Claude App an org permission — needs an org admin, must survive every reinstall, and fixes nothing for anyone else installing this standard whose App is scoped identically.
  • Mint the dodi-smart-github-assistant token in run-agent — that App does carry org permissions, but none of them is an issue-fields permission, so it would not have worked either.

Verification

Per DODI-00013 this cannot be tested on its own PR. After merge and tag, triage a throwaway issue and assert:

gh api /repos/dodi-smart/kodni.me/issues/<n> --jq '[.issue_field_values[].issue_field_name]'

The three stuck issues (#159, #160, #173) have been backfilled by hand from the values their own triage comments justified.

Governed by DODI-00022 (recorded in dev-standards), added to AGENTS.md. The companion PR there carries the decision record and two checks that fetch this file over the API — merge this one first, or those checks fail.

🤖 Generated with Claude Code

…e records no state

Triage was setting the issue type and area labels but silently writing no
fields on some issues, and reporting success either way.

The prompt told the agent to resolve field ids from
/orgs/{org}/issue-fields. run-agent runs on an OIDC-exchanged Claude App
token, and that installation holds repo-scoped permissions only — no
organisation permission at all — so every /orgs/* path returns 403
"Resource not accessible by integration", REST and GraphQL alike.

setIssueFieldValue itself is authorised by repo issues:write and works.
Only the id lookup was closed, so the outcome depended on whether the
agent improvised another id source after the documented one 403'd. Some
did and wrote all four fields; others followed the instruction, reported
honestly that they could not, and stopped. Same workflow, same token.

Resolve ids from repository(owner,name){ issueFields } instead: same
org-level fields, same node ids, no org access needed. Enumerate the valid
option names in the prompt too — with no list an agent wrote Effort=XS,
which is not an option.

Add a final verification step that re-reads Triage state and fails the job
if it is unset. Nothing was red before: an unset state means
issue-implement refuses the issue, so the break surfaced days later on a
different workflow with the causing run out of view. The read is
repo-scoped on purpose — a check using a stronger token than the agent had
would pass where the agent failed.

Why: /orgs/* is 403 for a repo-scoped App installation; the failure landed
on the id lookup alone, which is why it read as flaky rather than broken.
Rejected: granting the Claude App an org permission (needs an admin, does
not help anyone else installing this standard); minting the org App token
in run-agent (that App has no issue-fields permission either).
Refs: DODI-00022, DODI-00007, DODI-00001

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@azlekov
azlekov merged commit 98dc943 into main Aug 20, 2026
1 check passed
@azlekov
azlekov deleted the fix/triage-field-ids-repo-scoped branch August 20, 2026 11:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant