# tools/core/runners/converge.runner.ts

> 216 lines of code and 47 definitions.

Tree: Coordination tree
Language: typescript
Canonical: https://banes-lab.com/anatomy/coordination#file-coordination-tools-core-runners-converge-runner-ts
Source text: https://banes-lab.com/assets/sources/source.f042cef913498792a728747da3fa4c51dbb730ea8adfaaa4fd5a329ce9e7d96e.generated.txt

## Definitions

- `rosterLine` (lexical_declaration, line 172, exported)
- `holdsRecord` (lexical_declaration, line 67)
- `isSignOffRow` (lexical_declaration, line 71)
- `runSignature` (lexical_declaration, line 229, exported)
- `runReadMark` (lexical_declaration, line 193, exported)
- `withSignOffRow` (lexical_declaration, line 87)
- `outstandingNeed` (lexical_declaration, line 119)
- `runArchiveMove` (lexical_declaration, line 177, exported)
- `NEEDS_FIELD` (lexical_declaration, line 26)
- `ABSENT` (lexical_declaration, line 28)
- `TOOL_STAMP` (lexical_declaration, line 30, exported)
- `SignRequest` (interface_declaration, line 32, exported)
- `SignOutcome` (interface_declaration, line 39, exported)
- `signOffLine` (lexical_declaration, line 44)
- `opener` (lexical_declaration, line 45)
- `SIGN_OFF_HEADING` (lexical_declaration, line 61)
- `OWNER_ROW` (lexical_declaration, line 63)
- `PLACEHOLDER` (lexical_declaration, line 65)
- `cut` (lexical_declaration, line 72)
- `character` (lexical_declaration, line 78)
- `banner` (lexical_declaration, line 88)
- `index` (lexical_declaration, line 91)
- `line` (lexical_declaration, line 92)
- `row` (lexical_declaration, line 109)
- `insert` (lexical_declaration, line 114)
- `needs` (lexical_declaration, line 128)
- `stated` (lexical_declaration, line 133)
- `NOT_READ` (lexical_declaration, line 147)
- `AWAITING` (lexical_declaration, line 149)
- `TOKEN_BREAKS` (lexical_declaration, line 151)
- `letters` (lexical_declaration, line 153, exported)
- `out` (lexical_declaration, line 154, exported)
- `token` (lexical_declaration, line 156, exported)
- `pad` (lexical_declaration, line 173, exported)
- `notReadAt` (lexical_declaration, line 201, exported)
- `awaitingAt` (lexical_declaration, line 202, exported)
- `pending` (lexical_declaration, line 208, exported)
- `done` (lexical_declaration, line 209, exported)
- `before` (lexical_declaration, line 234, exported)
- `lines` (lexical_declaration, line 235, exported)
- `at` (lexical_declaration, line 236, exported)
- `raised` (lexical_declaration, line 243, exported)
- `witnessed` (lexical_declaration, line 248, exported)
- `need` (lexical_declaration, line 258, exported)
- `signature` (lexical_declaration, line 263, exported)
- `written` (lexical_declaration, line 268, exported)
- `witness` (lexical_declaration, line 270, exported)

## Uses

- [tools/core/analyzers/board.analyzer.ts](https://banes-lab.com/source/coordination/tools/core/analyzers/board.analyzer.ts.md)
- [tools/core/strings/converge.strings.ts](https://banes-lab.com/source/coordination/tools/core/strings/converge.strings.ts.md)

## Used by

- [tools/core/runners/venue.runner.ts](https://banes-lab.com/source/coordination/tools/core/runners/venue.runner.ts.md)

## Source

```typescript
import {
    NEEDS_FIELD_EMPTY,
    NEEDS_FIELD_MISSING,
    NEEDS_NO_RECORD,
    alreadyRead,
    alreadySigned,
    moveFailed,
    moved,
    needOutstanding,
    notConvened,
    readMarked,
    rosterContended,
    rosterLinesMissing,
    signOffBlockMissing,
    signOffContended,
    signOffRowAdded,
    signatureContended,
    signed,
    venueMissingForRead,
    venueMissingForSign,
} from "../strings/converge.strings.ts";

import { existsSync, linkSync, readFileSync, unlinkSync, writeFileSync } from "node:fs";
import { boardRecords } from "../analyzers/board.analyzer.ts";

const NEEDS_FIELD = "Needs";

const ABSENT = "—";

export const TOOL_STAMP = "[written by the sign form]";

export interface SignRequest {
    readonly target: string;
    readonly absolute: string;
    readonly agent: string;
    readonly text: string;
}

export interface SignOutcome {
    readonly message: string;
    readonly code: number;
}

const signOffLine = function signOffLine(lines: readonly string[], agent: string): number {
    const opener = `${agent}:`;

    for (let index = 0; index < lines.length; index += 1) {
        const line = lines[index] ?? "";
        if (!line.startsWith(opener)) {
            continue;
        }
        if (line.length > opener.length && (line[opener.length] ?? "") !== " ") {
            continue;
        }
        return index;
    }

    return -1;
};

const SIGN_OFF_HEADING = "SIGN-OFF";

const OWNER_ROW = "owner:";

const PLACEHOLDER = "<unsigned>";

const holdsRecord = function holdsRecord(venue: string, agent: string): boolean {
    return boardRecords(venue).some((record) => record.kind === "agent" && record.label.endsWith(` ${agent}`));
};

const isSignOffRow = function isSignOffRow(line: string): boolean {
    const cut = line.indexOf(":");
    if (cut <= 0) {
        return false;
    }

    for (let index = 0; index < cut; index += 1) {
        const character = line.charAt(index);
        if (character < "A" || character > "Z") {
            return false;
        }
    }

    return true;
};

const withSignOffRow = function withSignOffRow(lines: readonly string[], agent: string): string[] | null {
    let banner = -1;
    let at = -1;

    for (let index = 0; index < lines.length; index += 1) {
        const line = lines[index] ?? "";

        if (banner === -1) {
            if (line.includes(SIGN_OFF_HEADING)) {
                banner = index;
            }
            continue;
        }
        if (isSignOffRow(line) || line.startsWith(OWNER_ROW)) {
            at = index;
        }
    }

    if (banner === -1) {
        return null;
    }

    const row = `${agent}:     ${PLACEHOLDER}`;
    if (at === -1) {
        return [...lines.slice(0, banner + 1), "", row, ...lines.slice(banner + 1)];
    }

    const insert = (lines[at] ?? "").startsWith(OWNER_ROW) ? at : at + 1;

    return [...lines.slice(0, insert), row, ...lines.slice(insert)];
};

const outstandingNeed = function outstandingNeed(venue: string, agent: string): string {
    for (const record of boardRecords(venue)) {
        if (record.kind !== "agent") {
            continue;
        }
        if (!record.label.endsWith(` ${agent}`)) {
            continue;
        }

        const needs = record.fields.get(NEEDS_FIELD);
        if (needs === undefined) {
            return NEEDS_FIELD_MISSING;
        }

        const stated = needs.trim();
        if (stated === ABSENT) {
            return "";
        }
        if (stated.length === 0) {
            return NEEDS_FIELD_EMPTY;
        }

        return stated;
    }

    return NEEDS_NO_RECORD;
};

const NOT_READ = "NOT-READ:";

const AWAITING = "READ AND AWAITING:";

const TOKEN_BREAKS = new Set([" ", ",", "\t"]);

export const letters = function letters(line: string, opener: string): string[] {
    const out: string[] = [];

    let token = "";
    for (const character of `${line.slice(opener.length)} `) {
        if (!TOKEN_BREAKS.has(character)) {
            token += character;
            continue;
        }

        if (token.length > 0 && token !== ABSENT && !out.includes(token)) {
            out.push(token);
        }
        token = "";
    }

    return out;
};

export const rosterLine = function rosterLine(opener: string, held: readonly string[]): string {
    const pad = opener === NOT_READ ? "        " : " ";
    return `${opener}${pad}${held.length === 0 ? ABSENT : held.join(" ")}`;
};

export const runArchiveMove = function runArchiveMove(
    absolute: string,
    destination: string,
    target: string,
): SignOutcome {
    try {
        linkSync(absolute, destination);
    } catch (error) {
        return { code: 2, message: moveFailed(target, String(error)) };
    }

    unlinkSync(absolute);

    return { code: 0, message: moved(target) };
};

export const runReadMark = function runReadMark(request: SignRequest): SignOutcome {
    if (!existsSync(request.absolute)) {
        return { code: 2, message: venueMissingForRead(request.target) };
    }

    const before = readFileSync(request.absolute, "utf8");
    const lines = before.split("\n");

    const notReadAt = lines.findIndex((line) => line.startsWith(NOT_READ));
    const awaitingAt = lines.findIndex((line) => line.startsWith(AWAITING));

    if (notReadAt === -1 || awaitingAt === -1) {
        return { code: 2, message: rosterLinesMissing(request.target) };
    }

    const pending = letters(lines[notReadAt] ?? "", NOT_READ).filter((letter) => letter !== request.agent);
    const done = letters(lines[awaitingAt] ?? "", AWAITING);

    if (done.includes(request.agent)) {
        return { code: 0, message: alreadyRead(request.agent, request.target) };
    }

    const written = [...lines];
    written[notReadAt] = rosterLine(NOT_READ, pending);
    written[awaitingAt] = rosterLine(AWAITING, [...done, request.agent]);

    const witness = readFileSync(request.absolute, "utf8");
    if (witness !== before) {
        return { code: 2, message: rosterContended(request.target) };
    }

    writeFileSync(request.absolute, written.join("\n"), "utf8");

    return { code: 0, message: readMarked(request.agent, request.target) };
};

export const runSignature = function runSignature(request: SignRequest): SignOutcome {
    if (!existsSync(request.absolute)) {
        return { code: 2, message: venueMissingForSign(request.target) };
    }

    const before = readFileSync(request.absolute, "utf8");
    const lines = before.split("\n");
    const at = signOffLine(lines, request.agent);

    if (at === -1) {
        if (!holdsRecord(before, request.agent)) {
            return { code: 2, message: notConvened(request.agent, request.target) };
        }

        const raised = withSignOffRow(lines, request.agent);
        if (raised === null) {
            return { code: 2, message: signOffBlockMissing(request.target) };
        }

        const witnessed = readFileSync(request.absolute, "utf8");
        if (witnessed !== before) {
            return { code: 2, message: signOffContended(request.target) };
        }

        writeFileSync(request.absolute, raised.join("\n"), "utf8");

        return { code: 0, message: signOffRowAdded(request.agent, request.target) };
    }

    const need = outstandingNeed(before, request.agent);
    if (need.length > 0) {
        return { code: 2, message: needOutstanding(request.agent, request.target, need) };
    }

    const signature = `${request.agent}:     ${request.text} ${TOOL_STAMP}`;
    if ((lines[at] ?? "") === signature) {
        return { code: 0, message: alreadySigned(request.agent, request.target) };
    }

    const written = [...lines.slice(0, at), signature, ...lines.slice(at + 1)].join("\n");

    const witness = readFileSync(request.absolute, "utf8");
    if (witness !== before) {
        return { code: 2, message: signatureContended(request.target) };
    }

    writeFileSync(request.absolute, written, "utf8");

    return { code: 0, message: signed(request.agent, request.target, TOOL_STAMP) };
};
```
