Say a pull request nobody checks as a delivery held, owned by mesh-delivery (hq issue 347)
mesh/merge-gate pass: builds gitea, mesh-delivery → novox; no bus step; every machine composes with the change as it did without (4 of 4 compose)
mesh/repo-check pass: its merge-check.sh passed, each part in its toolchain: merge-check.sh (go), merge-check-typescript.sh (typescript)
mesh/delivery superseded: a newer delivery to the same trunk took over its walk

The confirmation review asked for the delivery domain's own vocabulary
instead of a provider standing. A gitea health check would need a `tools`
list (turning gitea's tools into seat verbs), a check of another kind
beside it, and would hold the forge's own deliveries at the first-node
gate; so the delivery's owner says it, with the word it already has.

- gitea_open_pulls (gitea): every open pull request from the forge itself,
  with what its base requires and the statuses its head has.
- mesh-delivery asks it every five minutes and keeps its own first-seen
  time per head (the forge's update time moves on every comment). A head
  on a base requiring mesh/merge-gate OR mesh/repo-check (hq requires only
  the second) with neither for ten minutes is a `stalled` line in state
  `unannounced`, which the controller raises as delivery.<id>.stalled (D14);
  H2 has nothing to close. Once announced it is a delivery of its own.
- The gitea-side watcher and its provider standing are gone.
This commit is contained in:
jochen
2026-10-09 13:14:36 +02:00
parent bcc6b3f52a
commit 32d55beb47
16 changed files with 323 additions and 110 deletions
+34
View File
@@ -54,6 +54,20 @@ export interface GiteaPull {
body?: string;
}
/** An open pull request with what its base requires and what its head has: what gitea_open_pulls answers. */
export interface OpenPull {
owner: string;
repo: string;
number: number;
base: string;
head_sha: string;
html_url?: string;
/** The contexts the base branch's protection requires; none when it requires none, or cannot be read. */
required: string[];
/** The contexts the head has a status of, in any state. */
statuses: string[];
}
/** A commit status, as the forge keeps it: what a pull request shows beside its head commit. */
export interface CommitStatus {
state: "pending" | "success" | "error" | "failure" | "warning";
@@ -280,6 +294,26 @@ export class GiteaClient {
return out;
}
/** **Every open pull request, from the forge itself** (novox/hq issue 347): with what its base's protection
* requires and the contexts its head has a status of, in any state. What mesh-delivery reads to say a pull
* request the mesh was never asked to check; asked of the forge, never of what the announcer remembers, so a
* fault in the announcer cannot hide itself. Reads only. */
async openPulls(): Promise<OpenPull[]> {
const out: OpenPull[] = [];
const rules = new Map<string, BranchProtection[] | undefined>();
for (const found of await this.searchOpenPulls()) {
const full = `${found.owner}/${found.name}`;
const pull = await this.getPullRequest(found.owner, found.name, found.number);
if (pull.state !== "open" || !pull.head_sha) continue;
if (!rules.has(full)) rules.set(full, await this.branchProtections(found.owner, found.name).catch(() => undefined));
const rule = rules.get(full)?.find((p) => (p.rule_name ?? p.branch_name) === (pull.base || "main"));
const statuses = Object.keys(await this.commitStatuses(found.owner, found.name, pull.head_sha));
out.push({ owner: found.owner, repo: found.name, number: pull.number, base: pull.base ?? "", head_sha: pull.head_sha,
html_url: pull.html_url, required: rule?.enable_status_check ? (rule.status_check_contexts ?? []) : [], statuses });
}
return out;
}
async getPullRequest(owner: string, repo: string, index: number): Promise<GiteaPull> {
indexOf(index);
return GiteaClient.mapPull(await this.request<any>(`/repos/${owner}/${repo}/pulls/${index}`));