@adrkit/evaluator 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +23 -0
- package/dist/LICENSE +201 -0
- package/dist/NOTICE +11 -0
- package/dist/assertions/evaluate.d.ts +36 -0
- package/dist/assertions/jsonpath.d.ts +20 -0
- package/dist/assertions/limits.d.ts +21 -0
- package/dist/assertions/registry.d.ts +20 -0
- package/dist/assertions/rego.d.ts +27 -0
- package/dist/catalog.d.ts +39 -0
- package/dist/compare.d.ts +10 -0
- package/dist/crypto/sha256.d.ts +10 -0
- package/dist/identity/directory.d.ts +23 -0
- package/dist/index.d.ts +24 -0
- package/dist/index.js +2064 -0
- package/dist/keys.d.ts +27 -0
- package/dist/pass0.d.ts +19 -0
- package/dist/patch/project.d.ts +20 -0
- package/dist/report/aggregate.d.ts +21 -0
- package/dist/report/assemble.d.ts +16 -0
- package/dist/report/order.d.ts +19 -0
- package/dist/report/serialize.d.ts +42 -0
- package/dist/routing/accepted-assertion.d.ts +12 -0
- package/dist/routing/route.d.ts +18 -0
- package/dist/routing/target.d.ts +20 -0
- package/dist/rules/affects-overlap.d.ts +13 -0
- package/dist/rules/affects-resolvable.d.ts +14 -0
- package/dist/rules/assertions-compile.d.ts +12 -0
- package/dist/rules/assertions-pass.d.ts +13 -0
- package/dist/rules/context.d.ts +21 -0
- package/dist/rules/decider-resolvable.d.ts +10 -0
- package/dist/rules/expiry-sane.d.ts +11 -0
- package/dist/rules/id-unique.d.ts +11 -0
- package/dist/rules/kernel.d.ts +16 -0
- package/dist/rules/no-orphan-refs.d.ts +12 -0
- package/dist/rules/schema-valid.d.ts +11 -0
- package/dist/rules/scope-hierarchy.d.ts +14 -0
- package/dist/rules/supersession-consistent.d.ts +12 -0
- package/dist/targets/canonical.d.ts +37 -0
- package/dist/targets/package.d.ts +11 -0
- package/dist/targets/path.d.ts +10 -0
- package/dist/targets/registry.d.ts +11 -0
- package/dist/types.d.ts +360 -0
- package/package.json +54 -0
- package/src/assertions/evaluate.ts +214 -0
- package/src/assertions/jsonpath.ts +95 -0
- package/src/assertions/limits.ts +57 -0
- package/src/assertions/registry.ts +38 -0
- package/src/assertions/rego.ts +272 -0
- package/src/catalog.ts +263 -0
- package/src/compare.ts +13 -0
- package/src/crypto/sha256.ts +101 -0
- package/src/identity/directory.ts +69 -0
- package/src/index.ts +81 -0
- package/src/keys.ts +55 -0
- package/src/pass0.ts +163 -0
- package/src/patch/project.ts +51 -0
- package/src/report/aggregate.ts +59 -0
- package/src/report/assemble.ts +43 -0
- package/src/report/order.ts +53 -0
- package/src/report/serialize.ts +152 -0
- package/src/routing/accepted-assertion.ts +39 -0
- package/src/routing/route.ts +105 -0
- package/src/routing/target.ts +104 -0
- package/src/rules/affects-overlap.ts +55 -0
- package/src/rules/affects-resolvable.ts +83 -0
- package/src/rules/assertions-compile.ts +18 -0
- package/src/rules/assertions-pass.ts +21 -0
- package/src/rules/context.ts +31 -0
- package/src/rules/decider-resolvable.ts +55 -0
- package/src/rules/expiry-sane.ts +30 -0
- package/src/rules/id-unique.ts +57 -0
- package/src/rules/kernel.ts +33 -0
- package/src/rules/no-orphan-refs.ts +102 -0
- package/src/rules/schema-valid.ts +49 -0
- package/src/rules/scope-hierarchy.ts +108 -0
- package/src/rules/supersession-consistent.ts +138 -0
- package/src/targets/canonical.ts +114 -0
- package/src/targets/package.ts +41 -0
- package/src/targets/path.ts +32 -0
- package/src/targets/registry.ts +23 -0
- package/src/types.ts +445 -0
package/dist/keys.d.ts
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @adrkit/evaluator — canonical key helpers.
|
|
3
|
+
*
|
|
4
|
+
* The compact assertion key and the canonical target key are the two identity
|
|
5
|
+
* strings that keep the report byte-stable and collision-safe (data-model §4/§5).
|
|
6
|
+
* Both are pure string functions.
|
|
7
|
+
*/
|
|
8
|
+
import type { Adr, Assertion } from '@adrkit/core';
|
|
9
|
+
import type { AssertionKey, CanonicalTargetId, CanonicalTargetKey } from './types.js';
|
|
10
|
+
/** Compact standard `JSON.stringify([log ?? "", path, id])` — no added whitespace. */
|
|
11
|
+
export declare function makeAssertionKey(log: string | undefined, path: string, id: string): AssertionKey;
|
|
12
|
+
/** The canonical assertion key for one assertion declared on one record. */
|
|
13
|
+
export declare function assertionKeyForAssertion(record: Adr, assertion: Assertion): AssertionKey;
|
|
14
|
+
/**
|
|
15
|
+
* A key is canonical iff parsing it yields exactly three strings AND the original
|
|
16
|
+
* key is byte-equal to the compact re-serialization. Whitespace-padded or otherwise
|
|
17
|
+
* noncanonical spellings are rejected, never normalized.
|
|
18
|
+
*/
|
|
19
|
+
export declare function isCanonicalAssertionKey(key: string): boolean;
|
|
20
|
+
/** Parse a canonical assertion key back into its three string components. */
|
|
21
|
+
export declare function parseAssertionKey(key: string): {
|
|
22
|
+
readonly log: string;
|
|
23
|
+
readonly path: string;
|
|
24
|
+
readonly id: string;
|
|
25
|
+
} | undefined;
|
|
26
|
+
/** Stable `${kind}:${id}` serialization used for equality/intersection/ordering. */
|
|
27
|
+
export declare function canonicalTargetKey(id: CanonicalTargetId): CanonicalTargetKey;
|
package/dist/pass0.d.ts
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @adrkit/evaluator — Pass 0 orchestrator.
|
|
3
|
+
*
|
|
4
|
+
* Pure, total function of `input` (FR-006): same input ⇒ same typed input error or
|
|
5
|
+
* byte-identical report + patch. It performs NO clock/network/db/filesystem access,
|
|
6
|
+
* mutates nothing, imports no adapter/model, and routes without approving or
|
|
7
|
+
* persisting anything. Missing backing degrades to inert, never a thrown error or a
|
|
8
|
+
* fabricated pass/fail.
|
|
9
|
+
*
|
|
10
|
+
* Behaviour is built up across the user stories: the schema-invalid short-circuit and
|
|
11
|
+
* the input-contract branch (T021), the structural rules (US1), the externally-backed
|
|
12
|
+
* rules (US3), routing (US4), and patch projection (US5).
|
|
13
|
+
*/
|
|
14
|
+
import type { Pass0Evaluation, Pass0Input } from './types.js';
|
|
15
|
+
/**
|
|
16
|
+
* Evaluate a proposal under Pass 0. Total: returns either a typed input-contract error
|
|
17
|
+
* (no report/patch) or an evaluated `{ report, patch }`.
|
|
18
|
+
*/
|
|
19
|
+
export declare function evaluatePass0(input: Pass0Input): Pass0Evaluation;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @adrkit/evaluator — schema-compatible patch projection (§9, R8/R12, T052).
|
|
3
|
+
*
|
|
4
|
+
* Projects the eleven rule results down to the committed four-field
|
|
5
|
+
* `DeterministicFinding` shape — VIOLATIONS ONLY (rule failures at their fixed
|
|
6
|
+
* severity) — plus `escalate` and existing-enum `escalationReasons` in fixed trigger
|
|
7
|
+
* order. It strips every operational-only field (reason codes, canonical target ids,
|
|
8
|
+
* source refs, snapshot ids, candidate/related refs, recordPath, lower-level evidence):
|
|
9
|
+
* that richness stays on `Pass0Report`. `adr` is copied only when it validates strictly
|
|
10
|
+
* as a core `AdrRef`, so a filesystem path can never be reinterpreted as an ADR
|
|
11
|
+
* reference. The evaluator RETURNS the patch; it never writes any record, review state,
|
|
12
|
+
* database, or index.
|
|
13
|
+
*/
|
|
14
|
+
import { type DeterministicFinding } from '@adrkit/core';
|
|
15
|
+
import type { EvaluationPatch, Pass0Report, RuleResult } from '../types.js';
|
|
16
|
+
/** A rule result is a violation iff it failed at its fixed severity. */
|
|
17
|
+
export declare function isViolation(result: RuleResult): boolean;
|
|
18
|
+
/** Project one violating rule result into the committed DeterministicFinding shape. */
|
|
19
|
+
export declare function projectFinding(result: RuleResult): DeterministicFinding;
|
|
20
|
+
export declare function projectPatch(report: Pass0Report): EvaluationPatch;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @adrkit/evaluator — deterministic finding aggregation (T026, C11).
|
|
3
|
+
*
|
|
4
|
+
* A rule may make several observations but yields exactly one aggregate `RuleResult`.
|
|
5
|
+
* Status precedence is `fail > inert > pass`; `not-evaluated` is set only by the
|
|
6
|
+
* orchestrator (schema-invalid or `assertions-pass` after a compile failure). The
|
|
7
|
+
* aggregate `reason` is the first code, in the rule's fixed catalog precedence, among
|
|
8
|
+
* the winning-status sub-findings — so mixed fail/inert fixtures are byte-stable
|
|
9
|
+
* rather than discovery-order dependent. All sub-findings are retained and sorted by
|
|
10
|
+
* the stable secondary comparator.
|
|
11
|
+
*/
|
|
12
|
+
import { type ReasonCode, type RuleId } from '../catalog.js';
|
|
13
|
+
import type { RuleEvidence, RuleFinding, RuleResult } from '../types.js';
|
|
14
|
+
/** One underlying observation a rule makes; aggregated into a single RuleResult. */
|
|
15
|
+
export interface SubResult {
|
|
16
|
+
readonly status: 'pass' | 'fail' | 'inert';
|
|
17
|
+
readonly reason: ReasonCode;
|
|
18
|
+
readonly finding?: RuleFinding;
|
|
19
|
+
}
|
|
20
|
+
/** Aggregate one rule's sub-results into its single RuleResult (findings sorted). */
|
|
21
|
+
export declare function aggregate(rule: RuleId, subs: readonly SubResult[], evidence?: RuleEvidence): RuleResult;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @adrkit/evaluator — report assembly.
|
|
3
|
+
*
|
|
4
|
+
* Places the eleven RuleResults in fixed rubric order, appends the routing decision
|
|
5
|
+
* (never a twelfth rule), and computes `outcome`. Secondary finding ordering and
|
|
6
|
+
* canonical byte serialization are added in US2 (T027/T028).
|
|
7
|
+
*/
|
|
8
|
+
import { type RuleId } from '../catalog.js';
|
|
9
|
+
import type { Pass0Report, RoutingDecision, RuleResult } from '../types.js';
|
|
10
|
+
/** `returned` iff any rule failed at `error` severity; otherwise `ok`. */
|
|
11
|
+
export declare function computeOutcome(results: readonly RuleResult[]): 'ok' | 'returned';
|
|
12
|
+
/**
|
|
13
|
+
* Assemble the report from a rule→result map. Exactly eleven results are emitted in
|
|
14
|
+
* fixed rubric order (C11); a missing rule is a programming error.
|
|
15
|
+
*/
|
|
16
|
+
export declare function assembleReport(proposalPath: string, resultsByRule: ReadonlyMap<RuleId, RuleResult>, routing: RoutingDecision): Pass0Report;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @adrkit/evaluator — deterministic ordering (R11).
|
|
3
|
+
*
|
|
4
|
+
* Stable secondary comparators for `RuleFinding`s within a rule and for the patch's
|
|
5
|
+
* `deterministicFindings`. Precedence (data-model §5/§7): candidate `AdrRef`, related
|
|
6
|
+
* `AdrRef`, matcher/assertion key, canonical target key, `recordPath`, `field`,
|
|
7
|
+
* `message`. `RuleFinding.adr` is strictly an `AdrRef`; a path never enters this order
|
|
8
|
+
* as `adr`. The eleven rule results keep fixed rubric order and routing keeps trigger
|
|
9
|
+
* order — those arrays are never sorted.
|
|
10
|
+
*/
|
|
11
|
+
import { type RuleId } from '../catalog.js';
|
|
12
|
+
import type { CanonicalTargetId, RuleFinding } from '../types.js';
|
|
13
|
+
/** Stable secondary comparator for RuleFindings within a single rule. */
|
|
14
|
+
export declare function compareRuleFindings(a: RuleFinding, b: RuleFinding): number;
|
|
15
|
+
export declare function sortRuleFindings(findings: readonly RuleFinding[]): RuleFinding[];
|
|
16
|
+
/** Index of a rule in the fixed rubric order (for assembly). */
|
|
17
|
+
export declare function ruleIndex(rule: RuleId): number;
|
|
18
|
+
/** Comparator for a set-like array of canonical target ids (evidence). */
|
|
19
|
+
export declare function compareCanonicalTargetIds(a: CanonicalTargetId, b: CanonicalTargetId): number;
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @adrkit/evaluator — canonical serialization (T028, R11).
|
|
3
|
+
*
|
|
4
|
+
* Produces byte-reproducible `report` and `patch` bytes. Serialization is a hand-written
|
|
5
|
+
* ITERATIVE emitter (no recursion, no `JSON.stringify` key reordering) so that:
|
|
6
|
+
* - object keys are emitted in strict code-unit order — including integer-like keys
|
|
7
|
+
* (`{"2":..,"10":..}` ⇒ `{"10":..,"2":..}`), which `JSON.stringify` would reorder
|
|
8
|
+
* numerically (finding #7);
|
|
9
|
+
* - EVERY own JSON key is retained and emitted, including `__proto__`/`constructor`
|
|
10
|
+
* smuggled through a null-prototype parse (finding #1); and
|
|
11
|
+
* - hostile deep input cannot overflow the stack (finding #5) — the emitter uses an
|
|
12
|
+
* explicit work stack, and untrusted data is depth/node-bounded by `withinJsonLimits`
|
|
13
|
+
* before it ever reaches here.
|
|
14
|
+
*
|
|
15
|
+
* The deterministic payload carries NO timestamp, run id, or duration — caller
|
|
16
|
+
* `runMetadata` lives in the envelope, outside these bytes (FR-005).
|
|
17
|
+
*/
|
|
18
|
+
import type { EvaluationPatch, Pass0Report } from '../types.js';
|
|
19
|
+
type Json = null | boolean | number | string | Json[] | {
|
|
20
|
+
[key: string]: Json;
|
|
21
|
+
};
|
|
22
|
+
/**
|
|
23
|
+
* Canonical JSON string with keys in code-unit order. `pretty` matches
|
|
24
|
+
* `JSON.stringify(x, null, 2)` formatting exactly (2-space indent, `": "`, LF).
|
|
25
|
+
*/
|
|
26
|
+
export declare function canonicalStringify(root: unknown, pretty?: boolean): string;
|
|
27
|
+
/**
|
|
28
|
+
* Canonical JS structure with keys recursively sorted (code unit) — used for structural
|
|
29
|
+
* equality comparisons and CLI envelope building, NOT for byte emission. Output objects
|
|
30
|
+
* are null-prototype so a smuggled `__proto__` own key is retained rather than dropped.
|
|
31
|
+
*/
|
|
32
|
+
export declare function canonicalize(value: unknown): Json;
|
|
33
|
+
/** Canonical JSON bytes: code-unit-sorted keys, 2-space indent, single trailing LF. */
|
|
34
|
+
export declare function canonicalBytes(value: unknown): string;
|
|
35
|
+
export declare function serializeReport(report: Pass0Report): string;
|
|
36
|
+
export declare function serializePatch(patch: EvaluationPatch): string;
|
|
37
|
+
export interface CanonicalArtifacts {
|
|
38
|
+
readonly report: string;
|
|
39
|
+
readonly patch: string;
|
|
40
|
+
}
|
|
41
|
+
export declare function serializeArtifacts(report: Pass0Report, patch: EvaluationPatch): CanonicalArtifacts;
|
|
42
|
+
export {};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @adrkit/evaluator — accepted-ADR assertion routing evidence (T048, C4).
|
|
3
|
+
*
|
|
4
|
+
* The `contradicts-accepted-adr` trigger is proven when the proposal canonically
|
|
5
|
+
* overlaps an accepted ADR (rule 6) AND an assertion on that overlapping accepted ADR
|
|
6
|
+
* FAILS against the supplied proposed / current-HEAD input. Unlike `scope-hierarchy`,
|
|
7
|
+
* this does NOT require org scope, domain applicability, or a base-green transition —
|
|
8
|
+
* only the proposed-side failure. Pure; reuses the same engine registry.
|
|
9
|
+
*/
|
|
10
|
+
import type { RuleContext } from '../rules/context.js';
|
|
11
|
+
import type { CanonicalTargetKey } from '../types.js';
|
|
12
|
+
export declare function contradictsAcceptedAdr(ctx: RuleContext, proposalTargetKeys: ReadonlySet<CanonicalTargetKey>): boolean;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @adrkit/evaluator — escalation routing (T046, R10/C4/C7).
|
|
3
|
+
*
|
|
4
|
+
* A declarative OR over the eight deterministically-proven Pass 0 triggers, computed
|
|
5
|
+
* AFTER the eleven rule results (never a twelfth rule). Each trigger emits an ordered
|
|
6
|
+
* proven/not-proven evidence status; missing optional evidence is "not-proven", never a
|
|
7
|
+
* fabricated escalation. When escalation is proven, a single active human is resolved
|
|
8
|
+
* (deciders -> CODEOWNERS -> catalog); otherwise the target is `not-required`.
|
|
9
|
+
*/
|
|
10
|
+
import type { RuleContext } from '../rules/context.js';
|
|
11
|
+
import type { RecordTargetResolution } from '../targets/canonical.js';
|
|
12
|
+
import type { RoutingDecision, TriggerEvidenceStatus } from '../types.js';
|
|
13
|
+
/** All eight triggers as `not-proven`, in fixed order (used for schema-invalid reports). */
|
|
14
|
+
export declare function allNotProven(): readonly TriggerEvidenceStatus[];
|
|
15
|
+
/** The deterministic non-escalated routing decision (schema-invalid short-circuit). */
|
|
16
|
+
export declare function notRequiredRouting(): RoutingDecision;
|
|
17
|
+
/** Evaluate the eight triggers and resolve the target if escalation is proven. */
|
|
18
|
+
export declare function computeRouting(ctx: RuleContext, proposalTargets: RecordTargetResolution, contradictsAccepted: boolean): RoutingDecision;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @adrkit/evaluator — named-human routing target (T047, R9/C7).
|
|
3
|
+
*
|
|
4
|
+
* Resolves a single active human in fixed source order: (1) proposal `deciders`, (2)
|
|
5
|
+
* CODEOWNERS owners for the proposal's resolved paths, (3) catalog owners for its
|
|
6
|
+
* resolved entities. Exact source-local ordering: deciders in declaration order; unique
|
|
7
|
+
* paths sorted by canonical path key, each taking the LAST matching CODEOWNERS rule's
|
|
8
|
+
* owners in declaration order; unique entities sorted by canonical target key, each
|
|
9
|
+
* appending catalog owners in snapshot order. Candidates are stable-deduplicated at
|
|
10
|
+
* first occurrence (never globally identity-sorted). A missing/inactive direct human is
|
|
11
|
+
* skipped; the first team that does not resolve to exactly one active human is an
|
|
12
|
+
* ambiguity barrier that immediately yields `unresolved`.
|
|
13
|
+
*/
|
|
14
|
+
import type { IdentityIndex } from '../identity/directory.js';
|
|
15
|
+
import type { CanonicalTargetId, IdentityDirectorySnapshot, PrincipalRef, RouteTarget } from '../types.js';
|
|
16
|
+
/**
|
|
17
|
+
* Resolve the escalation target. Called only when escalation is proven; a non-escalated
|
|
18
|
+
* run uses `route.target.not-required` at the routing layer.
|
|
19
|
+
*/
|
|
20
|
+
export declare function resolveRouteTarget(index: IdentityIndex, deciders: readonly PrincipalRef[], directory: IdentityDirectorySnapshot, resolvedPaths: readonly string[], resolvedEntities: readonly CanonicalTargetId[]): RouteTarget;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @adrkit/evaluator — rule 6: affects-overlap (warn).
|
|
3
|
+
*
|
|
4
|
+
* Finite canonical-target-key intersection of the proposal with each ACCEPTED ADR,
|
|
5
|
+
* computed once per (proposal, accepted-ADR) pair (R4). Primary precedence (§3.1):
|
|
6
|
+
* any non-empty intersection ⇒ warn (`accepted-intersection`); otherwise no accepted
|
|
7
|
+
* ADRs ⇒ pass (`no-accepted-corpus`); otherwise absent required pair backing ⇒ inert
|
|
8
|
+
* (`backing-absent`); otherwise a fully evaluated accepted corpus with no intersection
|
|
9
|
+
* ⇒ pass (`none`).
|
|
10
|
+
*/
|
|
11
|
+
import type { RuleContext } from './context.js';
|
|
12
|
+
import type { RuleResult } from '../types.js';
|
|
13
|
+
export declare function evaluateAffectsOverlap(ctx: RuleContext): RuleResult;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @adrkit/evaluator — rule 5: affects-resolvable (warn).
|
|
3
|
+
*
|
|
4
|
+
* Validates EACH proposal matcher independently, not only the union (finding #2): a
|
|
5
|
+
* matcher that resolves to real targets cannot mask another positive matcher with
|
|
6
|
+
* present backing that resolves to ZERO. ADR-0009 semantics are preserved — negation
|
|
7
|
+
* subtracts, and a different-repo qualifier contributes no local match. Per positive
|
|
8
|
+
* matcher: ≥1 resolved id ⇒ pass; present backing + zero ids ⇒ warn (`zero-targets`);
|
|
9
|
+
* a missing inventory (`backing-absent`) or resolver (`resolver-absent`) ⇒ inert. A
|
|
10
|
+
* negation-only record resolves to the empty set ⇒ warn. No affects ⇒ trivially pass.
|
|
11
|
+
*/
|
|
12
|
+
import type { RuleContext } from './context.js';
|
|
13
|
+
import type { RuleResult } from '../types.js';
|
|
14
|
+
export declare function evaluateAffectsResolvable(ctx: RuleContext): RuleResult;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @adrkit/evaluator — rule 8: assertions-compile (error).
|
|
3
|
+
*
|
|
4
|
+
* Each assertion declares exactly one source and the approved engine profile validates
|
|
5
|
+
* it. Neither/both source ⇒ error; a failed source/artifact validation ⇒ error; a
|
|
6
|
+
* missing engine, resolved file content, or compiled artifact ⇒ inert; no assertions ⇒
|
|
7
|
+
* pass (`none`). Consumes the shared per-evaluation assertion outcomes so each assertion
|
|
8
|
+
* is compiled/validated exactly once (R7). One aggregate result.
|
|
9
|
+
*/
|
|
10
|
+
import type { AssertionOutcomes } from '../assertions/evaluate.js';
|
|
11
|
+
import type { RuleResult } from '../types.js';
|
|
12
|
+
export declare function evaluateAssertionsCompile(outcomes: AssertionOutcomes): RuleResult;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @adrkit/evaluator — rule 9: assertions-pass (warn).
|
|
3
|
+
*
|
|
4
|
+
* Evaluates each compiled assertion against its resolved input. A false result or a
|
|
5
|
+
* deterministic engine evaluation error ⇒ warn; a missing engine/input ⇒ inert; no
|
|
6
|
+
* assertions ⇒ pass (`none`). A compile FAILURE makes this whole rule
|
|
7
|
+
* `not-evaluated.prereq-failed` — enforced by the orchestrator, which only calls this
|
|
8
|
+
* rule when assertions-compile did not fail. Consumes the shared per-evaluation
|
|
9
|
+
* outcomes (one compile per assertion). One aggregate result.
|
|
10
|
+
*/
|
|
11
|
+
import type { AssertionOutcomes } from '../assertions/evaluate.js';
|
|
12
|
+
import type { RuleResult } from '../types.js';
|
|
13
|
+
export declare function evaluateAssertionsPass(outcomes: AssertionOutcomes): RuleResult;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @adrkit/evaluator — per-rule evaluation context.
|
|
3
|
+
*
|
|
4
|
+
* Assembled once by the orchestrator after `schema-valid` passes. Rules read only
|
|
5
|
+
* from this immutable context; none performs I/O.
|
|
6
|
+
*/
|
|
7
|
+
import type { Adr } from '@adrkit/core';
|
|
8
|
+
import type { Pass0Input, ProposalResolution } from '../types.js';
|
|
9
|
+
export interface RuleContext {
|
|
10
|
+
readonly input: Pass0Input;
|
|
11
|
+
/** The typed proposal (schema-valid passed). */
|
|
12
|
+
readonly proposed: Adr;
|
|
13
|
+
readonly resolution: ProposalResolution;
|
|
14
|
+
/** Full corpus records, INCLUDING the candidate (data-model §2). */
|
|
15
|
+
readonly corpusRecords: readonly Adr[];
|
|
16
|
+
/** Accepted ADRs in the corpus, EXCLUDING the candidate. */
|
|
17
|
+
readonly acceptedRecords: readonly Adr[];
|
|
18
|
+
readonly evaluationDate: string;
|
|
19
|
+
}
|
|
20
|
+
/** Records in the corpus that are accepted and are not the candidate proposal. */
|
|
21
|
+
export declare function acceptedRecordsExcludingCandidate(records: readonly Adr[], proposalPath: string): readonly Adr[];
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @adrkit/evaluator — rule 10: decider-resolvable (warn).
|
|
3
|
+
*
|
|
4
|
+
* Every declared proposal decider must resolve through the immutable identity
|
|
5
|
+
* directory to exactly one active principal (R9). None declared, a zero match, or an
|
|
6
|
+
* ambiguous match is a warn; an absent directory is inert. Exactly one aggregate result.
|
|
7
|
+
*/
|
|
8
|
+
import type { RuleContext } from './context.js';
|
|
9
|
+
import type { RuleResult } from '../types.js';
|
|
10
|
+
export declare function evaluateDeciderResolvable(ctx: RuleContext): RuleResult;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @adrkit/evaluator — rule 11: expiry-sane (info).
|
|
3
|
+
*
|
|
4
|
+
* `reviewBy` is compared to the caller-supplied `evaluationDate` — NO clock is read.
|
|
5
|
+
* Absent `reviewBy`, or one strictly after the evaluation date, passes; a `reviewBy`
|
|
6
|
+
* on or before the evaluation date is `info` (`past-or-equal`). Both are ISO `YYYY-MM-DD`
|
|
7
|
+
* strings, which compare correctly lexicographically.
|
|
8
|
+
*/
|
|
9
|
+
import type { RuleContext } from './context.js';
|
|
10
|
+
import type { RuleResult } from '../types.js';
|
|
11
|
+
export declare function evaluateExpirySane(ctx: RuleContext): RuleResult;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @adrkit/evaluator — rule 2: id-unique (error).
|
|
3
|
+
*
|
|
4
|
+
* Identity is scoped by `[record.log ?? "", id]` over the candidate-inclusive corpus
|
|
5
|
+
* plus optional federated-log snapshots (T018). A duplicate of the candidate's key
|
|
6
|
+
* fails (`id-unique.collision`); equal ids in different named logs pass. Exactly one
|
|
7
|
+
* aggregate result is emitted (C11).
|
|
8
|
+
*/
|
|
9
|
+
import type { RuleContext } from './context.js';
|
|
10
|
+
import type { RuleResult } from '../types.js';
|
|
11
|
+
export declare function evaluateIdUnique(ctx: RuleContext): RuleResult;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @adrkit/evaluator — rule kernel (result builders).
|
|
3
|
+
*
|
|
4
|
+
* Re-exports the canonical aggregation (`report/aggregate.ts`) and provides the small
|
|
5
|
+
* result builders rules use for clean pass / inert / not-evaluated outcomes. Keeping a
|
|
6
|
+
* single `aggregate` implementation avoids drift between rules and report assembly.
|
|
7
|
+
*/
|
|
8
|
+
import { type ReasonCode, type RuleId } from '../catalog.js';
|
|
9
|
+
import type { RuleFinding, RuleResult } from '../types.js';
|
|
10
|
+
export { aggregate, type SubResult } from '../report/aggregate.js';
|
|
11
|
+
/** A clean pass with no sub-findings, using the rule's `.ok` reason by default. */
|
|
12
|
+
export declare function passResult(rule: RuleId, reason?: ReasonCode): RuleResult;
|
|
13
|
+
/** An inert (degraded) result — backing absent, never a violation. */
|
|
14
|
+
export declare function inertResult(rule: RuleId, reason: ReasonCode, finding?: RuleFinding): RuleResult;
|
|
15
|
+
/** A not-evaluated result (schema-invalid short-circuit or prereq-failed only). */
|
|
16
|
+
export declare function notEvaluated(rule: RuleId, reason: 'not-evaluated.schema-invalid' | 'not-evaluated.prereq-failed'): RuleResult;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @adrkit/evaluator — rule 4: no-orphan-refs (error).
|
|
3
|
+
*
|
|
4
|
+
* Local `supersedes` / `relatesTo` targets must resolve. A federated ref (`<log>:<id>`)
|
|
5
|
+
* resolves against a supplied federated-log snapshot; a federated ref whose log has NO
|
|
6
|
+
* snapshot is inert (`federated-log-absent`), never an orphan failure (C2). `supersededBy`
|
|
7
|
+
* is owned by supersession-consistent and is not re-reported here. Exactly one aggregate
|
|
8
|
+
* result (C11); status precedence keeps a dangling failure above a federated inert.
|
|
9
|
+
*/
|
|
10
|
+
import type { RuleContext } from './context.js';
|
|
11
|
+
import type { RuleResult } from '../types.js';
|
|
12
|
+
export declare function evaluateNoOrphanRefs(ctx: RuleContext): RuleResult;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @adrkit/evaluator — rule 1: schema-valid (error).
|
|
3
|
+
*
|
|
4
|
+
* Reads only the parse/contract findings on `proposalPath` (data-model §3). Any such
|
|
5
|
+
* finding => fail (error); the orchestrator then emits ten `not-evaluated` results
|
|
6
|
+
* (C11). Lower-level rule/path/id/field/pattern evidence is preserved in report-only
|
|
7
|
+
* `RuleFinding` fields; `RuleFinding.adr` stays strictly an AdrRef and never holds a
|
|
8
|
+
* filesystem path (T017).
|
|
9
|
+
*/
|
|
10
|
+
import type { ProposalResolution, RuleResult } from '../types.js';
|
|
11
|
+
export declare function evaluateSchemaValid(resolution: ProposalResolution): RuleResult;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @adrkit/evaluator — rule 7: scope-hierarchy (error).
|
|
3
|
+
*
|
|
4
|
+
* A `component` proposal that overlaps an APPLICABLE accepted `org` ADR whose assertion
|
|
5
|
+
* was GREEN on the supplied base input and FAILS on the supplied proposed input is an
|
|
6
|
+
* attributable contradiction ⇒ error (research §R5). Domain applicability is explicit:
|
|
7
|
+
* an org ADR with no domain is global; otherwise it applies only on exact domain
|
|
8
|
+
* equality. The evaluator itself compiles + evaluates the accepted assertion (it never
|
|
9
|
+
* accepts a precomputed verdict). Missing engine/source/base/proposed evidence is inert;
|
|
10
|
+
* a non-component proposal or one with no applicable org overlap passes.
|
|
11
|
+
*/
|
|
12
|
+
import type { RuleContext } from './context.js';
|
|
13
|
+
import type { RuleResult } from '../types.js';
|
|
14
|
+
export declare function evaluateScopeHierarchy(ctx: RuleContext): RuleResult;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @adrkit/evaluator — rule 3: supersession-consistent (error).
|
|
3
|
+
*
|
|
4
|
+
* New deterministic reciprocity + cycle checks over the corpus snapshot (research
|
|
5
|
+
* §R3), reusing `buildAdrGraph` for EDGES ONLY. Reciprocity: `A supersedes B` iff
|
|
6
|
+
* `B.supersededBy === A`. `dangling-supersededBy` is owned exclusively by this rule
|
|
7
|
+
* (C2) and suppresses the redundant non-reciprocal finding for the same ref. Cycles
|
|
8
|
+
* in the supersedes relation fail with `cycle`. Exactly one aggregate result (C11).
|
|
9
|
+
*/
|
|
10
|
+
import type { RuleContext } from './context.js';
|
|
11
|
+
import type { RuleResult } from '../types.js';
|
|
12
|
+
export declare function evaluateSupersessionConsistent(ctx: RuleContext): RuleResult;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @adrkit/evaluator — canonical target normalization + record resolution (T035, R4/ADR-0009).
|
|
3
|
+
*
|
|
4
|
+
* Resolves a record's `affects` matchers to a finite canonical target-id set, honoring
|
|
5
|
+
* ADR-0009 semantics: union non-negated matches, subtract matching negations, require
|
|
6
|
+
* at least one positive matcher (negation-only ⇒ empty), and apply a `repo` qualifier
|
|
7
|
+
* only when it equals the caller-supplied current resolution `log` (a different-repo
|
|
8
|
+
* qualifier contributes no local match). The current log is passed explicitly to every
|
|
9
|
+
* resolver port; it is never inferred from a record's source `log`.
|
|
10
|
+
*/
|
|
11
|
+
import type { Adr, AffectsType } from '@adrkit/core';
|
|
12
|
+
import type { CanonicalTargetId, CanonicalTargetKey, TargetInventorySnapshots, TargetResolutionRegistry } from '../types.js';
|
|
13
|
+
/** Normalize a repo-relative path id to posix form (no leading `./`, no backslashes). */
|
|
14
|
+
export declare function normalizePathId(path: string): string;
|
|
15
|
+
export declare function makeTargetId(kind: AffectsType, id: string): CanonicalTargetId;
|
|
16
|
+
/** The outcome of resolving a single applied `affects` matcher. */
|
|
17
|
+
export interface MatcherResolution {
|
|
18
|
+
readonly type: AffectsType;
|
|
19
|
+
readonly pattern: string;
|
|
20
|
+
readonly negate: boolean;
|
|
21
|
+
/** `resolved` includes a different-repo matcher (deterministic empty locally). */
|
|
22
|
+
readonly status: 'resolved' | 'inert-backing' | 'inert-resolver';
|
|
23
|
+
readonly ids: readonly CanonicalTargetId[];
|
|
24
|
+
}
|
|
25
|
+
export interface RecordTargetResolution {
|
|
26
|
+
/** Final, unique, canonically-ordered target ids (positive − negated). */
|
|
27
|
+
readonly targets: readonly CanonicalTargetId[];
|
|
28
|
+
readonly targetKeys: ReadonlySet<CanonicalTargetKey>;
|
|
29
|
+
/** Per-applied-matcher outcomes, so each matcher can be validated independently (C3, finding #2). */
|
|
30
|
+
readonly matchers: readonly MatcherResolution[];
|
|
31
|
+
readonly hasMatchers: boolean;
|
|
32
|
+
readonly hasPositiveMatcher: boolean;
|
|
33
|
+
}
|
|
34
|
+
/** True if any matcher could not be resolved (missing inventory or resolver port). */
|
|
35
|
+
export declare function anyMatcherInert(resolution: RecordTargetResolution): boolean;
|
|
36
|
+
/** Resolve one record's affects matchers against the registry + inventory. */
|
|
37
|
+
export declare function resolveRecordTargets(record: Adr, registry: TargetResolutionRegistry, inventory: TargetInventorySnapshots, resolutionLog: string | undefined): RecordTargetResolution;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @adrkit/evaluator — built-in `package` target resolver.
|
|
3
|
+
*
|
|
4
|
+
* Reuses core's neutral `matchPackagePattern` grammar (name + optional semver range)
|
|
5
|
+
* over a complete dependency inventory, per dependency — without copying the grammar
|
|
6
|
+
* or importing semver directly (that stays a core-internal concern). A missing
|
|
7
|
+
* `dependencies` inventory is inert (backing-absent); an unparseable pattern resolves
|
|
8
|
+
* to the empty set. Pure.
|
|
9
|
+
*/
|
|
10
|
+
import type { TargetResolverPort } from '../types.js';
|
|
11
|
+
export declare function createPackageTargetResolver(): TargetResolverPort;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @adrkit/evaluator — built-in `path` target resolver.
|
|
3
|
+
*
|
|
4
|
+
* Reuses core's neutral repo-relative path-glob primitive (`matchPathPattern`) over a
|
|
5
|
+
* complete tracked-path inventory — it never copies the grammar. A missing
|
|
6
|
+
* `trackedPaths` inventory is inert (backing-absent); a bad/leading-slash pattern
|
|
7
|
+
* resolves to the empty set (⇒ affects-resolvable zero-targets, not a throw). Pure.
|
|
8
|
+
*/
|
|
9
|
+
import type { TargetResolverPort } from '../types.js';
|
|
10
|
+
export declare function createPathTargetResolver(): TargetResolverPort;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @adrkit/evaluator — target resolver registry.
|
|
3
|
+
*
|
|
4
|
+
* A registry is a pure lookup from `AffectsType` to a deterministic resolver port.
|
|
5
|
+
* A lookup miss makes the corresponding matcher inert (`resolver-absent`), never a
|
|
6
|
+
* failure. Ports are built only by trusted composition code — never selected by JSON.
|
|
7
|
+
*/
|
|
8
|
+
import type { TargetResolutionRegistry, TargetResolverPort } from '../types.js';
|
|
9
|
+
export declare function createTargetResolutionRegistry(ports: readonly TargetResolverPort[]): TargetResolutionRegistry;
|
|
10
|
+
/** A registry with no resolvers — every target matcher is `resolver-absent` inert. */
|
|
11
|
+
export declare const emptyTargetResolutionRegistry: TargetResolutionRegistry;
|