Operator Task Issue Creator¶
Issue2104, plan C10a. The code is the port
IOperatorTaskIssueCreator, the pure
OperatorTaskIssueCreation
(tests) and the adapter
AppTokenGitHubOperatorTaskIssueCreator
(fake-GitHub tests).
Status: live, behind the task key. The adapter is a scoped service. The confirm route (C10b)
calls CreateAsync once, and only after a Committed TryBeginAttemptAsync (task store). The status
route calls ListSinceAsync to reconcile an unknown outcome.
Token. The adapter uses the dev-e-bot App installation that DispatchTenantPolicy.ResolveTokenInstallationIdOrDefault
maps for the server-derived repo tenant. invotek uses the default install. The adapter never calls
TenantGitHubToken.ResolveAsync, which falls back to the GITHUB_TOKEN PAT (plan D11). If the tenant lookup or the
mint fails, no GitHub call is made: the create is Refused (no_app_token) and the list is null.
CreateAsync(repoTenant, repo, title, body)¶
Some requests are refused before any token or call: a repo other than exactly dashecorp/dashe-website
(repo_not_allowed), a blank tenant (no_tenant), or a blank title or body (empty_issue).
The call is one POST /repos/dashecorp/dashe-website/issues with exactly {title, body} and no labels, following
SelfImprovementService.FileNewIssueAsync. The mint and the POST each have their own 8 s bound. The method takes no caller
token, so a disconnected Worker cannot cancel a POST that GitHub may already have received. It never retries.
| GitHub answer | Result (reason) |
|---|---|
201 with a positive number |
Created(number, https://github.com/{repo}/issues/{number}). The URL is built, not read. |
| 4xx | Refused (http_<status>): GitHub created nothing. |
201 without a readable number, or any other status |
Ambiguous (unreadable_created or http_<status>) |
| Timeout, or transport fault | Ambiguous (timeout or transport) |
With LOCATION set and the repo's tenant fenced at this location, the POST never reaches GitHub: LocationFenceGitHubHandler
answers a synthetic 503 (X-Rig-Location-Fenced), so the result is Ambiguous (http_503) although nothing was created.
See multi-location fencing (rig-conductor#2561).
ListSinceAsync(repoTenant, repo, since)¶
With the same checks and token, the adapter reads one page:
GET /repos/dashecorp/dashe-website/issues?state=all&sort=created&direction=desc&per_page=100&since=<UTC second>. GitHub's
since filters on updated_at, so the adapter keeps only items with created_at >= since, and drops pull requests. The status
route (C10b) reconciles only when exactly one issue that the App filed (user.login is dev-e-bot[bot],
OperatorTaskIssueCreation.AppAuthor) carries the exact requestId and attemptId marker. An issue by any other author is
ignored, and an App issue that names the requestId with a damaged, duplicated or other-attempt marker makes the answer
ambiguous (nothing is bound). Issue search is never used, and the body is data, not evidence.
The result is null, never an empty list, in these cases:
- a non-2xx answer, or a body that is not an array;
- an item without a readable created_at or number;
- a fault or a timeout;
- a full page whose oldest item is still inside the window, because more matches may be on the next page.