# tools/rules/role.rule.ts

> 70 lines of code and 8 definitions.

Tree: Coordination tree
Language: typescript
Canonical: https://banes-lab.com/anatomy/coordination#file-coordination-tools-rules-role-rule-ts
Source text: https://banes-lab.com/assets/sources/source.07b37b899060c42e7126b8278528fcb45093309230eb9ea34e1494252fbb7d3d.generated.txt

## Definitions

- `finding` (lexical_declaration, line 9)
- `check` (method_definition, line 34, exported)
- `rule` (lexical_declaration, line 33, exported)
- `scoped` (lexical_declaration, line 35, exported)
- `template` (lexical_declaration, line 54, exported)
- `letters` (lexical_declaration, line 55, exported)
- `shapes` (lexical_declaration, line 57, exported)
- `coverage` (lexical_declaration, line 62, exported)

## Source

```typescript
import { ROLE_ROOT, ROLE_TEMPLATE } from "../core/constants/template.constants.ts";
import type { RuleContext, RuleDeclaration, RuleResult } from "../core/types/rule.types.ts";
import { checkRoleCoverage, checkRoleShape } from "../core/inspectors/role.inspector.ts";
import { AGENT_INDEX } from "../core/constants/board.constants.ts";
import type { Finding } from "../core/types/segment.types.ts";
import { activeSeatLetters } from "../core/inspectors/index.inspector.ts";
import { underRoots } from "../core/filters/scope.filter.ts";

const finding = function finding(
    path: string,
    kind: string,
    locus: string,
    actual: string,
    expected: string,
    decide: string,
): Finding {
    return {
        actual,
        expected,
        healed: false,
        line: 1,
        locus,
        path,
        remediation: { action: "declare", decide, deterministic: false, from: locus, target: path, to: null },
        rule: `role/${kind}`,
        stack: [
            { check: "role", resolved: path },
            { check: kind, resolved: locus },
        ],
    };
};

export const rule: RuleDeclaration = {
    check(context: RuleContext): RuleResult {
        const scoped = underRoots(context.paths, [ROLE_ROOT]);

        if (!context.exists(ROLE_TEMPLATE)) {
            return {
                derivations: { letters: [], roles: scoped.length },
                findings: [
                    finding(
                        ROLE_TEMPLATE,
                        "templateAbsent",
                        "role",
                        "the role template the section contract derives from does not exist",
                        "a role template carrying the frontmatter operands and the section headings every role document answers to",
                        "the contract is DERIVED from the template rather than transcribed into this check, so an absent template leaves the check with nothing to enforce — and a check resolving its contract to an empty set passes every document vacuously, which is the shape a green reports over a surface nobody governs. Raise the template rather than restoring a transcribed list",
                    ),
                ],
                healed: [],
            };
        }

        const template = context.read(ROLE_TEMPLATE);
        const letters = activeSeatLetters(context.read(AGENT_INDEX));

        const shapes = scoped.flatMap((path) =>
            checkRoleShape(path, context.read(path), template, (kind, locus, actual, expected, decide) =>
                finding(path, kind, locus, actual, expected, decide),
            ),
        );
        const coverage = checkRoleCoverage(letters, scoped, (kind, locus, actual, expected, decide) =>
            finding(AGENT_INDEX, kind, locus, actual, expected, decide),
        );

        return { derivations: { letters, roles: scoped.length }, findings: [...shapes, ...coverage], healed: [] };
    },
    extensions: [".md"],
    heals: false,
    invariant: "every role document carries the same section set and the same declared operands",
    jurisdiction: "taxonomy",
    kinds: ["templateAbsent", "roleMissing", "roleFieldMissing", "roleSectionMissing", "measuredSectionUnfilled"],
    reads: [AGENT_INDEX, ROLE_TEMPLATE],

    stage: "content",

    wholeScopeOnly: true,
};
```
