Operator Task Snapshot Reader and dashecorp.com Probe¶
Issue2104, plan C11a. The code is the ports in
IOperatorTaskSnapshotReader, the pure
OperatorTaskSnapshotReading
(tests), and the adapters
GitHubTaskSnapshotReader and
DashecorpSiteProbe
(fake-HTTP tests).
Status: live behind the status route (C11b). GET /api/cockpit/task/status calls both for a Submitted task, at most once
per 30 s per request and never after a terminal stage, and passes their output to the
stage projector.
ReadAsync(repoTenant, repo, issueNumber, template, previous)¶
template is the task's own registered template, passed by the status route at call time (#2274). The PR's diff verdict
is judged against it (OperatorTaskDiffPolicy.Decide), never against an injected default.
v1 reads only dashecorp/dashe-website, for a named tenant, as the issue creator does.
Every read but one uses the dev-e-bot App installation that DispatchTenantPolicy maps for the repo tenant, never the
GITHUB_TOKEN PAT (D11). The deploy run uses GITHUB_TOKEN, as MergeGate does, because the App has no actions
permission (B2). Each call is one attempt with an 8 s bound.
| Read, in order | When | Gives |
|---|---|---|
issues/{n} |
always | number, created_at, label names, closed_at when closed |
pulls?state=all&sort=created&direction=desc&per_page=30 |
always | among the PRs whose body links #n with a closing keyword: the newest merged one, else the newest not closed, else the newest (a newer duplicate closed without merging never shadows the merged PR) |
pulls/{pr} |
a linked PR exists | head SHA, created_at, draft, closed_at; the merge SHA and merged_at only when merged |
issues/{n}/comments |
queued: open, no agent-ready, no PR, no plan seen yet |
Planned: a comment has a TaskSpec heading |
issues/{n}/events |
while the agent-ready time is unknown and agent-ready is on or a PR links the issue, whatever the PR state (so a first read after the PR opened, or after a restart, still backfills implementing); once known, the memo carries it |
the last labeled agent-ready time |
pulls/{pr}/reviews |
an open, non-draft PR | review-e-bot's latest APPROVED, CHANGES_REQUESTED or DISMISSED review, when it approves exactly the head (the C11b nudge) |
actions/workflows/deploy.yml/runs?head_sha={mergeSha}&per_page=5 |
merged, with a 40-hex merge SHA | the newest run's status, conclusion, updated_at and html_url |
previous, the last snapshot of the same issue, carriesPlannedand the agent-ready time, so the comment and event reads happen once, not on every poll.Failednames each read that did not answer.repo_not_allowed,no_tenantandapp_tokenmean no call was made. The others areissue,pulls,pr,comments,events,reviewsandruns: a non-2xx answer, an unreadable shape, a fault, a timeout, or noGITHUB_TOKENfor the run. A null part next to a failure is unknown, not absent. The other reads still run.- The TaskSpec comment only feeds the
queueddetail line. Comments can be edited, so they are not evidence.
ProbeAsync(template, mergeSha) and ReadPreStateAsync(template, requestId)¶
The caller passes the task's own template (#2274), and the probe holds none of its own. It sends one
GET <template.PageUrl>?rig_verify=<mergeSha> (or ?rig_propose=<requestId> for the propose route's pre-state) with
Cache-Control: no-cache, a desktop Chrome User-Agent (m13) and no credentials, bounded at 10 s and never retried.
PageUrl is derived from the template's Path, never declared: website/index.html is https://dashecorp.com/,
and website/<dir>/index.html is https://dashecorp.com/<dir>/. So the page read cannot drift from the file the diff
policy lets the PR change. It is not part of the digested intent, so v1's digest is unchanged. A file the site does not serve
as a page has no page to verify, and throws. DashecorpAnchor.ExtractHref reads the href of the one anchor carrying the
template's AnchorClasses, and the template judges it. The probe never compares bytes, because Cloudflare rewrites parts of
the page. The result is {href, satisfied, checkedAt}:
hrefis null when the page has no such anchor, or more than one.- The whole result is null when the SHA is not 40 lowercase hex characters, and then no call is made.
- It is also null when the page cannot be read: a non-2xx answer, a body over 2 MiB, a fault or the timeout.
Whether Cloudflare lets the probe through from the cluster is UNVERIFIED (plan risk 7). The fallback is the operator's curl.