Skip to content

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, carries Planned and the agent-ready time, so the comment and event reads happen once, not on every poll.
  • Failed names each read that did not answer. repo_not_allowed, no_tenant and app_token mean no call was made. The others are issue, pulls, pr, comments, events, reviews and runs: a non-2xx answer, an unreadable shape, a fault, a timeout, or no GITHUB_TOKEN for the run. A null part next to a failure is unknown, not absent. The other reads still run.
  • The TaskSpec comment only feeds the queued detail 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}:

  • href is 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.