# core/aggregators/concern.aggregator.ts

> 132 lines of code and 31 definitions.

Tree: GovLab Quality
Language: typescript
Layer: processing
Canonical: https://banes-lab.com/anatomy/quality#file-quality-core-aggregators-concern-aggregator-ts
Source text: https://banes-lab.com/source/quality/core/aggregators/concern.aggregator.ts.txt

Listed in [core/aggregators](https://banes-lab.com/api/source/quality/core/aggregators.md), after [core/aggregators/catalog.aggregator.ts](https://banes-lab.com/source/quality/core/aggregators/catalog.aggregator.ts.md).

## Definitions

- `tallyConcerns` (lexical_declaration, line 89)
- `controlOf` (lexical_declaration, line 122)
- `concernControls` (lexical_declaration, line 136, exported)
- `ConcernTally` (interface_declaration, line 7)
- `KnobLookup` (type_alias_declaration, line 15)
- `PRIMARY_RANK` (lexical_declaration, line 17)
- `numericDefault` (lexical_declaration, line 19)
- `text` (lexical_declaration, line 23)
- `digits` (lexical_declaration, line 24)
- `bridgedKnob` (lexical_declaration, line 34)
- `bridgeKnobs` (lexical_declaration, line 41)
- `toolKnob` (lexical_declaration, line 49)
- `knobName` (lexical_declaration, line 50)
- `knob` (lexical_declaration, line 53)
- `knobLookup` (lexical_declaration, line 61, exported)
- `bridge` (lexical_declaration, line 66, exported)
- `key` (lexical_declaration, line 68, exported)
- `own` (lexical_declaration, line 69, exported)
- `seen` (lexical_declaration, line 70, exported)
- `primaryThreshold` (lexical_declaration, line 75)
- `candidates` (lexical_declaration, line 76)
- `[primary]` (lexical_declaration, line 84)
- `def` (lexical_declaration, line 85)
- `byConcern` (lexical_declaration, line 93)
- `concern` (lexical_declaration, line 95)
- `tool` (lexical_declaration, line 97)
- `tally` (lexical_declaration, line 98)
- `knobs` (lexical_declaration, line 105)
- `threshold` (lexical_declaration, line 111)
- `control` (lexical_declaration, line 123)
- `sorted` (lexical_declaration, line 125)

## Contained in

- [core/aggregators](https://banes-lab.com/anatomy/quality/folder-quality-core-aggregators.md)

## Linked from

- [core/aggregators](https://banes-lab.com/anatomy/quality/folder-quality-core-aggregators.md)

## Source

```typescript
import type { CatalogRule, ConcernControl, RuleKnob } from "#types/catalog.types";
import type { ConceptKnob, KnobConcept } from "#types/canon.types";
import { PRIMARY_KNOBS, SECONDARY_KNOBS, UNRANKED } from "#configuration/constants/knob.constants";
import { stringArrayField, stringField } from "#core/selectors/record.selector";
import { isDigit } from "@govlab/constants";

interface ConcernTally {
    options: Set<string>;
    rules: number;
    thresholdDefaults: number[];
    thresholdKnobByTool: Record<string, string>;
    tools: Set<string>;
}

type KnobLookup = (tool: string, ruleId: string) => RuleKnob[];

const PRIMARY_RANK = new Map(PRIMARY_KNOBS.map((knob, rank) => [knob, rank]));

const numericDefault = function numericDefault(value: unknown): number | null {
    if (typeof value === "number") {
        return value;
    }
    const text = typeof value === "string" ? value : "";
    let digits = "";
    for (const char of text) {
        if (!isDigit(char) && digits !== "") {
            break;
        }
        digits += isDigit(char) ? char : "";
    }
    return digits === "" ? null : Number(digits);
};

const bridgedKnob = function bridgedKnob(knob: ConceptKnob | undefined): string | null {
    if (knob === undefined || knob.fixed === true) {
        return null;
    }
    return typeof knob.knob === "string" && knob.knob !== "" ? knob.knob : null;
};

const bridgeKnobs = function bridgeKnobs(
    rules: readonly CatalogRule[],
    knobConcepts: Readonly<Record<string, KnobConcept>>,
): Map<string, RuleKnob[]> {
    const bridge = new Map<string, RuleKnob[]>();
    for (const [concept, knobConcept] of Object.entries(knobConcepts)) {
        for (const rule of rules) {
            const tool = stringField(rule, "tool");
            const toolKnob = knobConcept.tools[tool];
            const knobName = bridgedKnob(toolKnob);
            if (knobName !== null && stringArrayField(rule, "canonical").includes(concept)) {
                const key = `${tool}:${rule.ruleId}`;
                const knob: RuleKnob = { default: numericDefault(toolKnob?.default), knob: knobName, threshold: true };
                bridge.set(key, [...(bridge.get(key) ?? []), knob]);
            }
        }
    }
    return bridge;
};

export const knobLookup = function knobLookup(
    rules: readonly CatalogRule[],
    ruleKnobs: Readonly<Record<string, RuleKnob[]>>,
    knobConcepts: Readonly<Record<string, KnobConcept>>,
): KnobLookup {
    const bridge = bridgeKnobs(rules, knobConcepts);
    return (tool, ruleId) => {
        const key = `${tool}:${ruleId}`;
        const own = ruleKnobs[key] ?? [];
        const seen = new Set(own.map((knob) => knob.knob));
        return [...own, ...(bridge.get(key) ?? []).filter((knob) => !seen.has(knob.knob))];
    };
};

const primaryThreshold = function primaryThreshold(knobs: readonly RuleKnob[]): { def: number; knob: string } | null {
    const candidates = knobs
        .filter((knob) => knob.threshold && knob.default !== null && knob.default !== undefined)
        .filter((knob) => !SECONDARY_KNOBS.has(knob.knob.toLowerCase()))
        .toSorted(
            (a, b) =>
                (PRIMARY_RANK.get(a.knob.toLowerCase()) ?? UNRANKED) -
                (PRIMARY_RANK.get(b.knob.toLowerCase()) ?? UNRANKED),
        );
    const [primary] = candidates;
    const def = primary ? numericDefault(primary.default) : null;
    return primary && def !== null ? { def, knob: primary.knob } : null;
};

const tallyConcerns = function tallyConcerns(
    rules: readonly CatalogRule[],
    knobsFor: KnobLookup,
): Map<string, ConcernTally> {
    const byConcern = new Map<string, ConcernTally>();
    for (const rule of rules) {
        const concern = stringField(rule, "concern");
        if (concern !== "") {
            const tool = stringField(rule, "tool");
            const tally = byConcern.get(concern) ?? {
                options: new Set<string>(),
                rules: 0,
                thresholdDefaults: [],
                thresholdKnobByTool: {},
                tools: new Set<string>(),
            };
            const knobs = knobsFor(tool, rule.ruleId);
            tally.tools.add(tool);
            tally.rules += 1;
            for (const knob of knobs) {
                tally.options.add(knob.knob);
            }
            const threshold = primaryThreshold(knobs);
            if (threshold !== null) {
                tally.thresholdDefaults.push(threshold.def);
                tally.thresholdKnobByTool[tool] ??= threshold.knob;
            }
            byConcern.set(concern, tally);
        }
    }
    return byConcern;
};

const controlOf = function controlOf(tally: ConcernTally): ConcernControl {
    const control: ConcernControl = { rules: tally.rules, severity: "error", tools: tally.tools.size, value: true };
    if (tally.thresholdDefaults.length > 0) {
        const sorted = tally.thresholdDefaults.toSorted((a, b) => a - b);
        control.value = Math.min(...tally.thresholdDefaults);
        control.valueDerivation = `highest-lowest (strictest all rules settle on) = min of defaults [${sorted.join(", ")}]`;
        control.knobPerTool = tally.thresholdKnobByTool;
    }
    if (tally.options.size > 0) {
        control.configOptions = [...tally.options].toSorted((a, b) => a.localeCompare(b));
    }
    return control;
};

export const concernControls = function concernControls(
    rules: readonly CatalogRule[],
    knobsFor: KnobLookup,
): [string, ConcernControl][] {
    return [...tallyConcerns(rules, knobsFor)]
        .map(([id, tally]): [string, ConcernControl] => [id, controlOf(tally)])
        .toSorted((a, b) => b[1].tools - a[1].tools || b[1].rules - a[1].rules);
};
```
