merge-pull refuses a head at whose fingerprint a run failed a required step (policy-failed, naming run, module, step), from the module's own state failed-steps kept from step-ended, with the seen keys of every step end and the deletion once no watched branch's head nor open pull request's head names a commit. The two tools read it with its fill and drop a key after the hand act. Builds: design 47 G §39, §83, §84, §85, §135, §475, §487, §548 Claude-Session: https://claude.ai/code/session_01JG73KEq4zoDfM9WtYpcQgZ
63 lines
3.4 KiB
TypeScript
63 lines
3.4 KiB
TypeScript
// **The first registrations switch the merge on** (novox/hq design 47 §95, §353): until the catalog half has said its first
|
|
// `registration-changed`, the seat git's `merge-pull` refuses every merge naming the missing registrations, because a merge
|
|
// made with no Approve could reach the old assigner, which writes wants from the trunk with no pipeline. The module learns it
|
|
// two ways, both through the seat `mesh-catalog`: its verb `registrations` asked at the start (a restart after the first
|
|
// registrations were written), and its event `registration-changed` (the first being written, or heard again from the
|
|
// seat's kept stream). Neither is the holder's state or a module named.
|
|
|
|
import {
|
|
seat as CATALOG, verbs as CATALOG_VERBS, events as CATALOG_EVENTS,
|
|
type RegistrationChangedEvent, type RegistrationsAnswer, type RegistrationsInput,
|
|
} from "@novox/mesh-delivery-contracts-mesh-catalog";
|
|
|
|
/** The seat verb asked, as the manifest's `invokes` names it. */
|
|
export const REGISTRATIONS_VERB = `seat:${CATALOG}.${CATALOG_VERBS.registrations}`;
|
|
/** The seat event heard, as the manifest's `consumes` names it. */
|
|
export const REGISTRATION_CHANGED_EVENT = `${CATALOG}.${CATALOG_EVENTS.registrationChanged}`;
|
|
|
|
export class Registrations {
|
|
private first = false;
|
|
private byRepository = new Map<string, Set<string>>();
|
|
constructor(private readonly ask: (verb: string, input: RegistrationsInput) => Promise<unknown>,
|
|
private readonly log: (line: string) => void = () => {}) {}
|
|
|
|
/** Whether the first registrations are written: the one fact the merge switches on. */
|
|
get written(): boolean {
|
|
return this.first;
|
|
}
|
|
|
|
/** The watched branches the registrations name, by their origin repository (`<owner>/<name>`) as of the last read. */
|
|
get watched(): ReadonlyMap<string, ReadonlySet<string>> {
|
|
return this.byRepository;
|
|
}
|
|
|
|
/** One `registration-changed`: the first registration written, however many were before this module started. */
|
|
hear(ev: RegistrationChangedEvent | undefined): void {
|
|
if (!ev || typeof ev.module !== "string" || ev.module === "") {
|
|
throw new Error(`not a ${REGISTRATION_CHANGED_EVENT} event: ${JSON.stringify(ev ?? null).slice(0, 200)}`);
|
|
}
|
|
if (!this.first) this.log(`the first registration is written (${ev.module}); merge-pull merges from here`);
|
|
this.first = true;
|
|
}
|
|
|
|
/** The start's first view, asked again after each `registration-changed`: any registration held is the first written, and its
|
|
* watched branches are read. A failed ask is said and left to the event. */
|
|
async start(): Promise<void> {
|
|
try {
|
|
let a: unknown = await this.ask(REGISTRATIONS_VERB, {});
|
|
if (typeof a === "string") a = JSON.parse(a);
|
|
const r = (a as RegistrationsAnswer | undefined)?.registrations;
|
|
if (!Array.isArray(r)) throw new Error(`${REGISTRATIONS_VERB} answered no registrations: ${JSON.stringify(a ?? null).slice(0, 200)}`);
|
|
const by = new Map<string, Set<string>>();
|
|
for (const x of r) for (const b of x.branches ?? []) (by.get(x.origin) ?? by.set(x.origin, new Set()).get(x.origin)!).add(b);
|
|
this.byRepository = by;
|
|
if (r.length > 0) {
|
|
this.first = true;
|
|
this.log(`${r.length} registrations are held; merge-pull merges`);
|
|
}
|
|
} catch (err) {
|
|
this.log(`the registrations could not be read: ${err instanceof Error ? err.message : String(err)}; merge-pull waits for registration-changed`);
|
|
}
|
|
}
|
|
}
|