import { m as BreakerWay, n as BreakerWayInstanceState } from './index-CD1VEhzs.js'; import '@xyflow/react'; /** * Public types for the power validation engine (PRD workstream C6). * * The engine ships **zero default rules**. Consumers pass a rule array to * {@link runPowerValidation}; the standards catalogue * (`docs/electrical-validation-rules-2026-08-14.md`) is available as the * opt-in {@link standardPowerRules} preset, which is tree-shaken away when it * is not imported. */ /** * Issue severity. Mirrors the fault-finder `DiagramHighlightSeverity` * vocabulary (minus `complete`, which is a UI-only state). * @public */ type PowerIssueSeverity = "error" | "warning" | "info"; /** * How much authority an issue carries. * * - `standard` — traceable to a published standard or code (NEC, IEC, BS 7671). * - `convention` — widely-followed industry practice, not a code requirement. * - `heuristic` — this library's own advisory. **Must not** cite a standard. * @public */ type PowerRuleBasis = "standard" | "convention" | "heuristic"; /** * A single validation finding. Shaped so a fault-finder panel that already * renders `DiagramHighlightIssue` can consume it directly: `id`, `severity`, * `message`, and the target id arrays are the same fields. * @public */ interface PowerIssue { /** Unique id for this finding (stable across runs for the same graph). */ id: string; /** Id of the rule that produced it. */ ruleId: string; severity: PowerIssueSeverity; basis: PowerRuleBasis; /** Concise, actionable, one sentence. */ message: string; /** Nodes to highlight. */ nodeIds?: string[]; /** Edges to highlight. */ edgeIds?: string[]; /** Breaker ways to highlight, as `way-element` keys (`#`). */ wayIds?: string[]; /** Optional rule-specific detail (numbers behind the message). */ details?: Record; } /** * What a rule may return: `severity`/`basis`/`ruleId` are filled in by the * engine from the rule definition and config when the rule omits them. * @public */ type PowerIssueDraft = Omit & { ruleId?: string; severity?: PowerIssueSeverity; basis?: PowerRuleBasis; }; /** Loose structural node input. `NetworkNode` satisfies it. @public */ interface PowerGraphNode { id: string; type?: string; data?: Record; } /** Loose structural edge input. `NetworkEdge` satisfies it. @public */ interface PowerGraphEdge { id: string; source: string; target: string; sourceHandle?: string | null; targetHandle?: string | null; type?: string; data?: Record; } /** * Per-rule configuration, merged over the rule's own defaults. * @public */ interface PowerRuleConfig { /** Set `false` to skip the rule entirely. */ enabled?: boolean; /** Force every issue from this rule to a severity. */ severity?: PowerIssueSeverity; /** Rule-specific options (thresholds, ladders, field names). */ options?: Record; } /** * Engine configuration. * @public */ interface PowerValidationConfig { /** Options merged under every rule's options (e.g. a shared `voltageV`). */ defaults?: Record; /** Per-rule overrides keyed by rule id. */ rules?: Record; /** * Explicit power sources (board incomers). When omitted the engine infers * them: a source-capable node with no incoming supply edge is a root. */ sourceNodeIds?: string[]; /** * Pre-computed energisation overlay. See {@link PowerEnergizationLike} — * pass the result of `computeEnergization` (workstream C4). */ energization?: PowerEnergizationLike; } /** * Energisation overlay (PRD C4), structurally compatible with * `EnergizationResult` from `utils/power-energization.ts` — pass the result of * `computeEnergization` straight through `config.energization`. * * The engine models it structurally rather than importing the module, so the * validation entry stays independent of the energisation implementation and a * consumer can hand in an overlay from their own solver. Rules that need * energisation (PWR-A07) return no issues when it is absent. * @public */ interface PowerEnergizationLike { /** Power state keyed by node id, for every node that consumes power. */ devices?: Record; /** Per-edge overlay keyed by edge id. */ edges?: Record; /** Ids of nodes power reaches (sources included). */ energizedNodeIds?: readonly string[]; } /** Options resolved for the rule currently being evaluated. @public */ type PowerRuleOptions = Record; /** * A supply element: either a node (`nodeId`) or one breaker way on a board * (`#`). Ancestor sets are expressed in these keys so a rule * can tell "the two feeds share a board" from "the two feeds share a way". * @public */ type PowerElementKey = string; /** An oriented power edge: supply side → load side. @public */ interface PowerLink { edge: PowerGraphEdge; edgeId: string; /** Node feeding power into the link. */ supplyNodeId: string; /** Node receiving power from the link. */ loadNodeId: string; supplyHandle?: string; loadHandle?: string; /** Way id when the supply end lands on a distribution-board breaker way. */ wayId?: string; /** `#` when {@link PowerLink.wayId} is set. */ wayKey?: PowerElementKey; } /** A breaker way paired with its owning board. @public */ interface PowerWayRef { boardId: string; board: PowerGraphNode; way: BreakerWay; wayKey: PowerElementKey; state?: BreakerWayInstanceState; } /** A connector resolved at one end of a power edge. @public */ interface ResolvedPowerConnector { /** Connector designation, e.g. `C13`, `C14`, `C19`, `C20`, `AC`. */ type: string; /** Rated amperage when known (IEC ratings; see `connectors.ts`). */ amperage?: number; /** `inlet` = male equipment side, `connector` = female cord side. */ role?: "inlet" | "connector" | "unknown"; } /** * Shared graph utilities handed to every rule. Rule authors should never walk * `nodes`/`edges` by hand — everything a Tier A/B rule needs is here. * @public */ interface PowerValidationContext { /** All input nodes. */ nodes: readonly PowerGraphNode[]; /** All input edges (power and non-power). */ edges: readonly PowerGraphEdge[]; /** Oriented power links only. */ links: readonly PowerLink[]; /** Root supply nodes (board incomers). */ sourceNodeIds: readonly string[]; /** Options resolved for the rule currently being evaluated. */ options: PowerRuleOptions; /** Severity resolved for the rule currently being evaluated. */ severity: PowerIssueSeverity; /** Energisation overlay, when the consumer supplied one. */ energization?: PowerEnergizationLike; getNode(nodeId: string): PowerGraphNode | undefined; isPowerEdge(edge: PowerGraphEdge): boolean; isSourceCapable(nodeId: string): boolean; /** A node with at least one feed and no downstream link — a leaf consumer. */ isConsumer(nodeId: string): boolean; /** Links delivering power *into* this node (its feeds). */ getFeeds(nodeId: string): PowerLink[]; /** Links delivering power *out of* this node. */ getDownstreamLinks(nodeId: string): PowerLink[]; /** Every node reachable downstream (excludes the start node). */ getDownstreamNodeIds(nodeId: string): string[]; /** Every node reachable upstream (excludes the start node). */ getUpstreamNodeIds(nodeId: string): string[]; /** Every node reachable downstream of one link (includes its load node). */ getDownstreamNodeIdsOfLink(edgeId: string): string[]; /** * Supply elements upstream of a link, inclusive of the link's own way and * supply node. Keys are {@link PowerElementKey}s. */ getAncestorsOfLink(edgeId: string): Set; /** Supply elements upstream of a node. */ getAncestors(nodeId: string): Set; /** Hop distance from the nearest source (sources = 0). */ getDepth(elementKey: PowerElementKey): number; /** The intersecting element furthest from any source, or `undefined`. */ getDeepestShared(a: Iterable, b: Iterable): PowerElementKey | undefined; /** Every breaker way in the graph. */ getWays(): PowerWayRef[]; /** Links fed by one way. */ getWayLinks(wayKey: PowerElementKey): PowerLink[]; /** * Sum a draw field over every consumer downstream of a way, in watts. * `fallbackField` is used per node when the primary field is absent. */ sumDownstreamDrawW(wayKey: PowerElementKey, field: "maximumDrawW" | "allocatedDrawW", fallbackField?: "maximumDrawW" | "allocatedDrawW"): number; /** Connector at one end of an edge, resolved from the node's ports. */ getEndpointConnector(nodeId: string, handleId: string | null | undefined): ResolvedPowerConnector | undefined; /** Both ends of a link, supply end first. */ getLinkConnectors(edgeId: string): { supply?: ResolvedPowerConnector; load?: ResolvedPowerConnector; }; /** Split an element key into its parts. */ parseElementKey(key: PowerElementKey): { nodeId: string; wayId?: string; }; /** Build an element key. */ elementKey(nodeId: string, wayId?: string): PowerElementKey; /** Human label for an element, for use in messages. */ describeElement(key: PowerElementKey): string; } /** * A validation rule. `evaluate` receives the shared context with `options` and * `severity` already resolved for this rule. * @public */ interface PowerRule { id: string; name: string; basis: PowerRuleBasis; defaultSeverity: PowerIssueSeverity; /** Options merged under `config.defaults` and `config.rules[id].options`. */ defaultOptions?: PowerRuleOptions; /** Short description surfaced in rule pickers. */ description?: string; evaluate(ctx: PowerValidationContext): PowerIssueDraft[]; } /** Result of one engine run. @public */ interface PowerValidationResult { issues: PowerIssue[]; /** Rule ids that ran (disabled rules excluded). */ evaluatedRuleIds: string[]; /** Rule ids skipped because config disabled them. */ skippedRuleIds: string[]; /** Non-fatal problems: duplicate rule ids, rules that threw. */ warnings: string[]; } /** Options accepted by {@link runPowerValidation}. @public */ interface RunPowerValidationOptions { /** The rules to run. The engine has no defaults. */ rules: readonly PowerRule[]; config?: PowerValidationConfig; } /** * The power validation engine. * * It ships **zero rules**: `runPowerValidation` evaluates exactly the rules the * consumer passes in. Its job is (1) build the shared graph context once, (2) * merge config over each rule's defaults, (3) run each rule in isolation so one * throwing rule cannot take the run down, and (4) normalise the drafts each * rule returns into fully-populated {@link PowerIssue}s. */ /** * Run a set of power rules over a diagram graph. * * @param nodes - Diagram nodes (`NetworkNode[]` satisfies the input shape). * @param edges - Diagram edges; non-power edges are ignored by the graph model. * @param options - `rules` is required (no defaults); `config` carries per-rule * enablement, severity overrides, and thresholds. * @public */ declare function runPowerValidation(nodes: readonly PowerGraphNode[], edges: readonly PowerGraphEdge[], options: RunPowerValidationOptions): PowerValidationResult; /** * IEC 60320 coupler facts used by the connector rules (PWR-A05 / PWR-A06). * * Terminology (catalogue schema note): C14/C16/C20/C22 are **inlets** (male, * equipment side); C13/C15/C19/C21 are **connectors** (female, cord side). The * word "plug" is ambiguous and is not used. * * Why the table lives here and not in `utils/power-connectors.ts`: * `POWER_CONNECTORS` is the *rendering* table — it drives port geometry and * colour for the connector types the renderer can draw (C13/C14/C19/C20/AC). * The validation catalogue needs the high-temperature C15/C16 and C21/C22 * families, which have no rendering entry yet, plus a directed mate table and * a region axis that mean nothing to the renderer. Amperages come from the * region table here first, falling back to `POWER_CONNECTORS` for types it * does not list, so the two never disagree on shared types. */ /** Region a connector's rating is quoted under. @public */ type PowerConnectorRegion = "IEC" | "UL"; /** * Ratings are region-dependent (C13 = 10 A IEC / 15 A UL, C19 = 16 A IEC / * 20 A NA), so the rating rules take a `region` option rather than hardcoding * one set: `config.defaults.region` for every rule, overridable per rule via * `config.rules[id].options.region`. NEMA (5-15P, L5-30P, L6-30P, L21-30P) is a documented follow-up. * @public */ declare const IEC_60320_AMPERAGE: Record>>; /** Inlets are the male, equipment-mounted half. @public */ declare const IEC_60320_INLETS: readonly ["C14", "C16", "C20", "C22"]; /** Connectors are the female, cord-mounted half. @public */ declare const IEC_60320_CONNECTORS: readonly ["C13", "C15", "C19", "C21"]; /** * Directed mate table: which cord connectors each inlet accepts. * * - `C14 ← C13, C15` — the high-temperature C15 is backward-compatible downward. * - `C16 ← C15` only; **`C16 ← C13` is rejected** (the C16 keying ridge). * - `C20 ← C19, C21` — the high-temperature C21 is backward-compatible * downward, exactly like C15 → C14. * - `C22 ← C21` only; **`C22 ← C19` is rejected** (the C22 keying ridge). * - Cross-family `C13 ↔ C20` and `C19 ↔ C14` are hard errors: the 10 A / 16 A * envelopes are deliberately keyed apart. * @public */ declare const IEC_60320_MATES: Record; /** Role of a connector designation, or `unknown` for unmodelled types. @public */ declare function getConnectorRole(type: string): "inlet" | "connector" | "unknown"; /** * Rated amperage for a connector designation. The region table above is * consulted first, because it is the only one that knows the IEC/UL split; * the renderer's region-agnostic `POWER_CONNECTORS` entry is the fallback for * types the region table does not list. Returns `undefined` for unmodelled * types (e.g. `AC` under a non-IEC region) rather than guessing. */ declare function getConnectorAmperage(type: string, region?: PowerConnectorRegion): number | undefined; /** Whether an IEC 60320 pairing is mechanically valid. */ declare function isValidIecMate(inlet: string, connector: string): boolean; /** * Power graph model shared by every validation rule. * * The input graph is undirected (React Flow edges carry no electrical * direction), so the builder orients it: it finds the supply roots, breadth- * first-searches outward, and records each power edge as a {@link PowerLink} * with a supply end and a load end. Everything else — feeds, descendants, * ancestor sets, per-way load sums — is derived from that orientation. */ /** * Node types that can originate or distribute power. Kept as a set so the * connection-rule widening in PRD C3 and this engine agree on one list. * @public */ declare const POWER_SOURCE_CAPABLE_NODE_TYPES: readonly string[]; /** * Build a supply-element key: a node id, or `#`. A `#` or `%` * inside the node id is percent-escaped (`%23` / `%25`) so the key always * splits back correctly; the way id is kept verbatim. * @public */ declare function powerElementKey(nodeId: string, wayId?: string): PowerElementKey; /** Split a supply-element key back into its parts. @public */ declare function parsePowerElementKey(key: PowerElementKey): { nodeId: string; wayId?: string; }; /** Whether an edge carries power. @public */ declare function isPowerEdge(edge: PowerGraphEdge): boolean; interface BuildPowerGraphOptions { sourceNodeIds?: readonly string[]; energization?: PowerEnergizationLike; /** Region the connector ratings are read under (default `IEC`). */ connectorRegion?: PowerConnectorRegion; } /** * Build the shared rule context. `options`/`severity` are placeholders here — * the engine rebinds them per rule before calling `evaluate`. */ declare function buildPowerValidationContext(nodes: readonly PowerGraphNode[], edges: readonly PowerGraphEdge[], options?: BuildPowerGraphOptions): PowerValidationContext; /** * Tier A of the standards catalogue — every rule computable from the C1/C2 * model with no new fields. * * Implements `docs/electrical-validation-rules-2026-08-14.md` Tier A: * PWR-A01…A07 and A09…A12. A08 ("breaker state must not alter topology") is an * invariant test over the library, not a graph rule, so it is deliberately * absent here. * * Every rule is a graph sum or comparison. None of them simulate electricity. */ /** * NEC 210.20(A) / BS 7671 433.1.1: every path from a device back to a source * must pass through overcurrent protection — here, a distribution-board * breaker way. */ declare const pwrA01UnprotectedTap: PowerRule; /** * Uptime Tier III/IV redundancy: the A and B feeds of a dual-corded device must * not converge upstream. Error when they share a way or an intermediate * board/PDU; warning when the only shared element is the incomer itself. */ declare const pwrA02SharedUpstream: PowerRule; /** Uptime dual-corded practice: A and B must land on different PDUs. */ declare const pwrA03SamePdu: PowerRule; /** * Uptime Tier III: a device with fewer feeds than `expectedFeeds` (default 2) * cannot survive a maintenance outage on its single path. A device that * declares `expectedFeeds: 1` downgrades the finding to info. */ declare const pwrA04SingleCorded: PowerRule; /** * IEC 60320 directed mate table. Only pairings where one end resolves to an * inlet and the other to a cord connector are judged — an unmodelled or * one-sided pairing is skipped rather than guessed at. */ declare const pwrA05ConnectorMismatch: PowerRule; /** * IEC 60320 + NEC 240.4: a cord rated below the breaker protecting it is the * weakest link on the circuit. `scope` defaults to `downstream` (the whole * path below the way, as the catalogue defines it); set it to `direct` to * judge only the cords landing on the way itself. * * The downstream walk stops at the next protective device. A sub-board's ways * are judged on their own, and a PDU that declares its outlet/bank protection * (`outletProtectionA`) has the cords below it judged against that rating — * so a 32 A way feeding a strip with 16 A banks and C13 cords is not reported * against the 32 A breaker. A strip that declares no protection is still * judged against the upstream way (the conservative catalogue reading). */ declare const pwrA06ConnectorUnderBreaker: PowerRule; /** * Operational rule driven by the energisation overlay (PRD C4). Returns no * issues when the consumer supplied no `config.energization` — this rule never * recomputes energisation itself. */ declare const pwrA07UnpoweredByBreaker: PowerRule; /** * IEC 60898-1 preferred currents / NEC 240.6(A) standard ratings. * * Info only, and deliberately so: NEC 240.6(B)/(C) explicitly permit * non-standard ratings, and the IEC list below is secondary-sourced (the 8 A * and 125 A entries in particular) pending verification against a purchased * copy of the standard. Both ladders are configurable. */ declare const IEC_60898_RATING_LADDER: readonly number[]; declare const NEC_240_6_RATING_LADDER: readonly number[]; declare const pwrA09NonStandardRating: PowerRule; /** * Topology sanity. Dual-feed convergence at a consuming device is legitimate * and forms a cycle only *through* that device, so consumers are excluded from * the graph before cycle detection; what survives is a genuine ring between * distribution elements. */ declare const pwrA10PowerLoop: PowerRule; /** * A practical bound, not a load figure: if every cord downstream of a way drew * its full plate rating at once, would the breaker hold? Messages say so * explicitly — this is not measured utilisation. */ declare const pwrA11WayConnectorBound: PowerRule; /** * Cable-management advisory only. This is **our** heuristic: it must never be * presented as a code requirement and must not cite BS 7671 (a real voltage-drop * check needs conductor csa, which the edge model does not carry — see B07). */ declare const pwrA12LengthAdvisory: PowerRule; /** * Circuit/cord semantics over a materialised edge list — the graph-side twin of * the interactive `defaultValidateConnection`. Every pairing the canvas refuses * is judged here, citing the same reason constant, so a diagram assembled by * import or by script is graded exactly as one drawn by hand: * * - a way must land on a PDU/board **inlet** — never on a device IEC inlet or a * PDU outlet, which are the two ends of a *cord* * (`CIRCUIT_TERMINATION_REASON`); * - two ways are never wired together (`WAY_TO_WAY_REASON`); * - nothing but a way feeds an inlet, so an outlet-to-inlet daisy chain is a * finding (`PDU_INLET_FEED_REASON`); * - a cord runs outlet → inlet, never outlet → outlet * (`OUTLET_TO_OUTLET_REASON`). * * **Grading, and the pre-inlet-model migration path.** A way landing on an * outlet of a strip that declares *no* inlet is not a wiring error the author * can fix by re-routing: the strip has nowhere else for the circuit to land. * That grades `warning` and the message names the migration. As soon as the * strip declares an inlet — or the landing is a device inlet — there is a * correct destination, and it is an `error`. * * Scope hedge, matching PWR-A05: only endpoints the model can actually place * are judged. An unmodelled handle resolves to `unknown` and is skipped rather * than guessed at, so graphs authored before the inlet model do not light up * with findings the author cannot act on. * * Energisation is deliberately untouched: a daisy chain physically conducts, so * `computeEnergization` still propagates through it. This rule flags it; it * does not pretend the cable is dead. */ declare const pwrA13CircuitTermination: PowerRule; /** Tier A of the catalogue, in catalogue order. @public */ declare const tierAPowerRules: readonly PowerRule[]; /** * Tier B core of the standards catalogue — the load-vs-breaker rules that read * the NetBox-compatible draw fields (`maximumDrawW`, `allocatedDrawW`) and the * board's derating configuration. * * Implemented here: PWR-B01, PWR-B02, PWR-B03 (the catalogue's "load core"), * plus the two nesting rules PWR-B04 / PWR-B05, which need only the board * relation the graph already provides. * * Units follow NetBox verbatim so a sync is a straight field copy: draw is in * **watts**. Current is `P / (V · PF)` at the way's circuit voltage — the * board's line-to-neutral `voltageV` for a single-pole way, its line-to-line * voltage for a 2-pole way, and `P / (√3 · V_LL · PF)` for a three-phase way * (see `wayCircuitVoltage`). */ /** * NEC 210.19/210.20 continuous-load sizing, expressed the way NetBox expresses * it: Σ nameplate watts, converted to amps at the board voltage and phase * factor, against `ratingA × maxUtilization`. Nameplate sums are an upper * bound, not measured utilisation — the message says so. */ declare const pwrB01BreakerOverSubscribed: PowerRule; /** * NetBox's `allocated_draw` budget view: the same sum over the design budget, * falling back to nameplate per device where no budget is set. A warning, not * an error — the budget is a planning figure. */ declare const pwrB02BreakerOverAllocated: PowerRule; /** * The derating regime itself is configuration, so this rule audits that * configuration rather than the graph: it reports boards whose `codeMode` and * `maxUtilization` disagree, boards that never declared a mode (and so are * being judged under the default), and any diversity factor other than 1. * * NEC 210.20(A) requires 125% sizing for continuous load (≡ 80% loading), with * 100% permitted only where the assembly is listed for it. BS 7671 433.1.1 has * no equivalent rule, so IEC mode runs at 100%. The BS 7671 / On-Site-Guide * diversity tables are domestic and retail; continuous IT load has diversity * ≈ 1.0, which is why `diversityFactor` defaults to 1. */ declare const pwrB03DeratingMode: PowerRule; /** * IEC 60947-2 Annex A defines selectivity as a *tested* limit current published * per manufacturer, so a rating ratio can only ever be a screen. Between two * MCBs there is essentially no discrimination in the short-circuit region at * all — both magnetic elements trip. This rule therefore never emits a positive * "selective" verdict and always hedges its wording. */ declare const pwrB04SelectivityScreen: PowerRule; /** Corollary of B04, and unambiguous: an upstream breaker must not be smaller. */ declare const pwrB05UpstreamBelowDownstream: PowerRule; /** * Load (current) imbalance across the phases of a multi-phase PDU strip. * * **Phase attribution convention.** Outlets are attributed round-robin from the * top — outlet `p` on an `n`-phase strip sits on phase `(p - 1) % n`, via * `toOutletPhaseIndex`. Real strips vary (some bank outlets per phase), * but the number is only meaningful if the diagram and the consuming * application attribute outlets identically, so the convention is fixed and * shared rather than inferred. Positions come from the endpoint classifier, so * a strip whose outlets carry explicit ids (`rear-power-1`) is attributed the * same as one using bare numbers; `attributedCount`/`totalLinks` in the issue * details report how many cords the number covers. * * Convention, not standard: **voltage** unbalance is the standardized quantity * (NEMA MG-1, EN 50160) and is measured, not diagrammable. This checks * load imbalance, whose real justification is per-phase breaker headroom — the * message must never cite NEMA MG-1. Nameplate sums are an upper bound, not * measured draw, and only strips where **every** phase carries load are judged. */ declare const pwrB08PhaseImbalance: PowerRule; /** Tier B core (B01–B03), the nesting pair (B04/B05), and B08. @public */ declare const tierBPowerRules: readonly PowerRule[]; /** * Helpers shared by the standard rule preset. Not part of the engine — a * consumer writing custom rules may use them, but nothing here is required. */ /** √3, the three-phase factor (NetBox's 1.732, copied verbatim). */ declare const THREE_PHASE_FACTOR = 1.732; /** * The √3 factor for a three-phase way, else 1. Pair it with the way's * **line-to-line** voltage (see {@link wayCircuitVoltage}). */ declare function phaseFactor(way: BreakerWay): number; /** * Watts → amps: `I = P / (V × factor × PF)`. `voltageV` must be the voltage * that matches `factor` — line-to-neutral (or line-to-line for a 2-pole * circuit) with factor 1, line-to-line with factor √3 for a three-phase way. * `powerFactor` defaults to 1 (watts treated as volt-amperes, NetBox's * convention); a lower power factor raises the current. */ declare function wattsToAmps(watts: number, voltageV: number, factor: number, powerFactor?: number): number; /** Region defaults for the nominal line-to-neutral (phase) voltage. */ declare const DEFAULT_PHASE_VOLTAGE_V: Readonly>; /** * Where a board's circuit voltages came from: * - `explicit` — `phaseVoltageV` and/or `lineToLineVoltageV` were declared; * - `legacy` — only the single `voltageV` was declared; it is used as-is for * every way (line-to-neutral reading for single-pole ways, line-to-line for * 2-pole/three-phase ways), which is only right when the board's ways are all * one kind — PWR-B03 flags the ambiguous cases; * - `default` — nothing declared; the code-mode default is assumed. */ type VoltageBasis = "explicit" | "legacy" | "default"; interface ResolvedDerating { codeMode: "NEC" | "IEC"; /** Continuous-load ceiling as a percentage of the breaker rating. */ maxUtilization: number; /** Kept available but defaulted to 1: continuous IT load has no diversity. */ diversityFactor: number; /** * The board's declared `voltageV` (option → board), or the line-to-neutral * default when none is declared. Kept for compatibility; the load rules read * {@link ResolvedDerating.phaseVoltageV} / {@link ResolvedDerating.lineToLineVoltageV}. */ voltageV: number; /** Voltage a single-pole way supplies (line-to-neutral). */ phaseVoltageV: number; /** Voltage a 2-pole or three-phase way supplies (line-to-line). */ lineToLineVoltageV: number; /** Power factor applied to watt → amp conversion (default 1). */ powerFactor: number; /** How the voltages were resolved — see {@link VoltageBasis}. */ voltageBasis: VoltageBasis; } /** * Resolve the derating regime for one way (PWR-B03). * * NEC 210.19/210.20 require 125% sizing for continuous load, which is 80% * loading on a standard breaker. BS 7671 has no equivalent rule (433.1.1 is * `Ib ≤ In ≤ Iz`), so `IEC` mode defaults to 100%. Precedence: explicit rule * option → board field → code default. * * Voltages (rule option → board field): * - `phaseVoltageV` / `lineToLineVoltageV` — the explicit pair; either one * derives the other by √3. * - otherwise `voltageV` — the legacy single board voltage, used unchanged for * every way kind. * - otherwise the code-mode default: 120/208 V (`NEC`), 230/400 V (`IEC`). */ declare function resolveDerating(ref: PowerWayRef, options: PowerRuleOptions): ResolvedDerating; /** The kind of circuit a way supplies, for its voltage basis. */ declare function wayCircuitKind(way: BreakerWay): "three-phase" | "two-pole" | "single-pole"; /** * The voltage basis of one way's circuit, for watt → amp conversion: * * - a way's own `voltageV` wins (the circuit voltage as wired; line-to-line * for a three-phase way); * - three-phase (`phase: "3P"` or `poles: 3`): line-to-line voltage, factor √3 * — `I = P / (√3 · V_LL)`, i.e. `P / (3 · V_LN)`; * - two-pole (`poles: 2`, e.g. a US 208 V circuit): line-to-line, factor 1; * - otherwise (single-pole `L1`/`L2`/`L3`): line-to-neutral, factor 1. */ declare function wayCircuitVoltage(way: BreakerWay, derating: Pick): { voltageV: number; factor: number; basis: "way" | "three-phase" | "line-to-line" | "line-to-neutral"; }; /** * `standardPowerRules` — the OPT-IN standards preset. * * The engine ships no rules. This preset is the catalogue in * `docs/electrical-validation-rules-2026-08-14.md` expressed as rule objects, * and it is only in your bundle if you import it. Take it wholesale, filter it, * reconfigure it through `config.rules`, or ignore it and pass your own rules. * * Not included, deliberately: * - **PWR-A08** — "breaker state must not alter topology" is an invariant over * the library itself, verified by a unit test, not a graph rule. * - **Tier C** (selectivity guarantees, trip curves, arc-flash, earth-loop * impedance, voltage drop without conductor csa, measured utilisation) — * not computable from a diagram, and a confident wrong answer there is a * safety hazard. */ /** * The full preset: Tier A (A01–A07, A09–A12) + Tier B core (B01–B03) and the * nesting pair (B04/B05). * @public */ declare const standardPowerRules: readonly PowerRule[]; /** Look up one preset rule by catalogue id. @public */ declare function getStandardPowerRule(id: string): PowerRule | undefined; export { type BuildPowerGraphOptions, DEFAULT_PHASE_VOLTAGE_V, IEC_60320_AMPERAGE, IEC_60320_CONNECTORS, IEC_60320_INLETS, IEC_60320_MATES, IEC_60898_RATING_LADDER, NEC_240_6_RATING_LADDER, POWER_SOURCE_CAPABLE_NODE_TYPES, type PowerConnectorRegion, type PowerElementKey, type PowerEnergizationLike, type PowerGraphEdge, type PowerGraphNode, type PowerIssue, type PowerIssueDraft, type PowerIssueSeverity, type PowerLink, type PowerRule, type PowerRuleBasis, type PowerRuleConfig, type PowerRuleOptions, type PowerValidationConfig, type PowerValidationContext, type PowerValidationResult, type PowerWayRef, type ResolvedDerating, type ResolvedPowerConnector, type RunPowerValidationOptions, THREE_PHASE_FACTOR, type VoltageBasis, buildPowerValidationContext, getConnectorAmperage, getConnectorRole, getStandardPowerRule, isPowerEdge, isValidIecMate, parsePowerElementKey, phaseFactor, powerElementKey, pwrA01UnprotectedTap, pwrA02SharedUpstream, pwrA03SamePdu, pwrA04SingleCorded, pwrA05ConnectorMismatch, pwrA06ConnectorUnderBreaker, pwrA07UnpoweredByBreaker, pwrA09NonStandardRating, pwrA10PowerLoop, pwrA11WayConnectorBound, pwrA12LengthAdvisory, pwrA13CircuitTermination, pwrB01BreakerOverSubscribed, pwrB02BreakerOverAllocated, pwrB03DeratingMode, pwrB04SelectivityScreen, pwrB05UpstreamBelowDownstream, pwrB08PhaseImbalance, resolveDerating, runPowerValidation, standardPowerRules, tierAPowerRules, tierBPowerRules, wattsToAmps, wayCircuitKind, wayCircuitVoltage };