@integraledger/lcp-verify 0.9.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/CHANGELOG.md +13 -0
- package/LICENSE +202 -0
- package/NOTICE +14 -0
- package/README.md +116 -0
- package/dist/composition.d.ts +53 -0
- package/dist/composition.d.ts.map +1 -0
- package/dist/composition.js +54 -0
- package/dist/composition.js.map +1 -0
- package/dist/index.d.ts +104 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +100 -0
- package/dist/index.js.map +1 -0
- package/dist/report.d.ts +72 -0
- package/dist/report.d.ts.map +1 -0
- package/dist/report.js +38 -0
- package/dist/report.js.map +1 -0
- package/dist/required.d.ts +47 -0
- package/dist/required.d.ts.map +1 -0
- package/dist/required.js +63 -0
- package/dist/required.js.map +1 -0
- package/dist/steps.d.ts +182 -0
- package/dist/steps.d.ts.map +1 -0
- package/dist/steps.js +404 -0
- package/dist/steps.js.map +1 -0
- package/package.json +61 -0
- package/src/composition.ts +100 -0
- package/src/index.ts +277 -0
- package/src/report.ts +100 -0
- package/src/required.ts +99 -0
- package/src/steps.ts +517 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { discoveryIntegrityStep, frcNonGatingStep, offerBoundStep, operationsStep, proportionalityStep, } from "./composition.js";
|
|
2
|
+
import { computeVerified, } from "./required.js";
|
|
3
|
+
import { acceptanceStep, authorityStep, authorityStepFromWalk, commitmentStep, fingerprintStep, recourseStep, referencePlacementStep, resolvePartyStep, settlementStep, } from "./steps.js";
|
|
4
|
+
export { discoveryIntegrityStep, frcNonGatingStep, offerBoundStep, operationsStep, proportionalityStep, readCompositionSlots, } from "./composition.js";
|
|
5
|
+
export { jcsCanonicalize, serializeReport, } from "./report.js";
|
|
6
|
+
export { computeVerified, REQUIRED_STEPS, } from "./required.js";
|
|
7
|
+
export { acceptanceStep, authorityStep, authorityStepFromWalk, commitmentStep, fingerprintStep, RCS4_REQUIRED_ROLES, recourseStep, referencePlacementStep, resolvePartyStep, settlementStep, } from "./steps.js";
|
|
8
|
+
/** Run the walk at the caller-specified `depth` (default `"structural"`) and emit the vector-anchored, JCS-serializable report. */
|
|
9
|
+
export async function verify(input) {
|
|
10
|
+
if (input.authorityWalk !== undefined && input.authorityChain !== undefined)
|
|
11
|
+
throw new Error("verify: authorityWalk and authorityChain are mutually exclusive — a walked chain is already the readout, and flattening it alongside would ask which of two answers about the same chain to believe");
|
|
12
|
+
const steps = [
|
|
13
|
+
{
|
|
14
|
+
name: "atr-fingerprint",
|
|
15
|
+
outcome: await fingerprintStep(input.atrBytes, input.settledAtrHash),
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
name: "settlement-enumeration",
|
|
19
|
+
outcome: settlementStep(input.settlements),
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
name: "buyer-acceptance",
|
|
23
|
+
outcome: await acceptanceStep(input.acceptance, input.settledAtrHash, input.acceptanceVerifier),
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
name: "authority-attenuation",
|
|
27
|
+
// One step name either way: the report's shape does not change with how the caller obtained its
|
|
28
|
+
// chain, only how much the walk was able to say about it.
|
|
29
|
+
outcome: input.authorityWalk !== undefined
|
|
30
|
+
? authorityStepFromWalk(input.authorityWalk)
|
|
31
|
+
: authorityStep(input.authorityChain),
|
|
32
|
+
},
|
|
33
|
+
{ name: "commitment-vs-leaf", outcome: commitmentStep(input.commitment) },
|
|
34
|
+
{
|
|
35
|
+
name: "recourse-elections",
|
|
36
|
+
outcome: recourseStep(input.atrBytes, input.evidenceRoles),
|
|
37
|
+
},
|
|
38
|
+
{ name: "resolve-party", outcome: resolvePartyStep(input.identity) },
|
|
39
|
+
];
|
|
40
|
+
// Append the TC-4 composition steps ONLY when a composition slot is supplied — the slot is additive:
|
|
41
|
+
// a TC-0..TC-3 report that supplies none is byte-identical to one produced without the slot existing.
|
|
42
|
+
// The appended steps flow through the same `anyFailed`/`computeVerified` machinery as every other.
|
|
43
|
+
if (input.composition !== undefined) {
|
|
44
|
+
steps.push({ name: "offer-bound", outcome: offerBoundStep(input.composition) }, { name: "operations-bound", outcome: operationsStep(input.composition) }, {
|
|
45
|
+
name: "discovery-integrity",
|
|
46
|
+
outcome: discoveryIntegrityStep(input.composition),
|
|
47
|
+
}, {
|
|
48
|
+
name: "proportionality-declared",
|
|
49
|
+
outcome: proportionalityStep(input.composition),
|
|
50
|
+
}, {
|
|
51
|
+
name: "frc-non-gating",
|
|
52
|
+
outcome: frcNonGatingStep(input.composition),
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
// Append the reference-placement step ONLY when a placement slot is supplied — its own `if`, because a
|
|
56
|
+
// placement is independent of a composition and a record may carry either, both, or neither. Absent ⇒
|
|
57
|
+
// nothing is appended and existing reports stay byte-identical, which is what makes the slot additive.
|
|
58
|
+
// Supplied ⇒ it flows through the same `anyFailed`/`computeVerified` machinery as every other step, so
|
|
59
|
+
// a placement that CONTRADICTS the record impeaches `supportedClass` to TC-0 — the one power the step
|
|
60
|
+
// grants it. Without this block the step would appear in no report and impeach nothing.
|
|
61
|
+
if (input.placement !== undefined) {
|
|
62
|
+
steps.push({
|
|
63
|
+
name: "reference-placement",
|
|
64
|
+
outcome: referencePlacementStep(input.placement, input.settledAtrHash),
|
|
65
|
+
});
|
|
66
|
+
}
|
|
67
|
+
const anyFailed = steps.some((s) => s.outcome.status === "failed");
|
|
68
|
+
const found = input.settlements ?? [];
|
|
69
|
+
const depth = input.depth ?? "structural";
|
|
70
|
+
const claimed = input.claimedClass ?? "TC-2";
|
|
71
|
+
const stepsForVerified = steps.map((s) => ({
|
|
72
|
+
name: s.name,
|
|
73
|
+
outcome: s.outcome,
|
|
74
|
+
}));
|
|
75
|
+
return {
|
|
76
|
+
verified: computeVerified(stepsForVerified, claimed, depth),
|
|
77
|
+
// The BUYER's stated level: the report's assurance answers "at what assurance did the party who
|
|
78
|
+
// committed resolve?" — the seller's own level rides in the record's identity slot and the package.
|
|
79
|
+
// `buyer` is optional-chained on purpose: `RecordIdentity` requires it, but this readout must be TOTAL
|
|
80
|
+
// over the same half-shaped input `resolvePartyStep` is total over (an untyped caller, a foreign
|
|
81
|
+
// conformance subject). A walk that throws on a malformed record cannot report the malformation.
|
|
82
|
+
//
|
|
83
|
+
// The fallback is NOT a ladder value. `wallet-signature-only` would be conservative in
|
|
84
|
+
// direction, since it never inflates, but still a level the verifier elected for a record that stated
|
|
85
|
+
// none, and the floor of a ladder reads as a finding rather than as silence. `no-assurance-stated` is
|
|
86
|
+
// the SAME token `resolvePartyStep` emits for this condition (steps.ts), so absence has one spelling
|
|
87
|
+
// across the step and the report instead of contradicting itself inside a single run.
|
|
88
|
+
assurance: input.identity?.buyer?.assurance ?? "no-assurance-stated",
|
|
89
|
+
supportedClass: anyFailed ? "TC-0" : claimed,
|
|
90
|
+
asOf: input.asOf,
|
|
91
|
+
steps,
|
|
92
|
+
coverage: input.coverage,
|
|
93
|
+
settlements: { found, multiplySettled: found.length > 1 },
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
/** Discriminant helper — did any step fail (the honest impeachment signal)? */
|
|
97
|
+
export function anyStepFailed(report) {
|
|
98
|
+
return report.steps.some((s) => s.outcome.status === "failed");
|
|
99
|
+
}
|
|
100
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/report.d.ts
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The `VerificationReport` and its **deterministic serialization — RFC 8785 (JCS) canonical JSON**.
|
|
3
|
+
* The protocol promises byte-identical reports across independent implementations: the report is RECOMPUTED by
|
|
4
|
+
* every verifier, and JCS is exactly the multi-producer-convergence case it exists for. This is NOT the
|
|
5
|
+
* ATR rule and the two must never be conflated — canonicalization is banned for the *ATR* because it has
|
|
6
|
+
* one producer and the exact received bytes are the fingerprint; the *report* has many producers.
|
|
7
|
+
*
|
|
8
|
+
* All monetary values in reports are decimal-integer base-unit STRINGS, so JCS's
|
|
9
|
+
* ECMAScript number serialization never touches money. JCS = recursively sort object keys by UTF-16 code
|
|
10
|
+
* units (JS default string sort), then serialize with JSON's escaping + ECMAScript number formatting
|
|
11
|
+
* (which already match RFC 8785 §3.2.2). Confirmed byte-for-byte against an independent JCS implementation.
|
|
12
|
+
*/
|
|
13
|
+
import type { HaltClass } from "@integraledger/lcp-binding-core";
|
|
14
|
+
/** Verification depth: structural (presence/absence readout, verified always false) vs mechanical
|
|
15
|
+
* (inputs gathered over live ports; verified is an honest function of the walk). */
|
|
16
|
+
export type VerifyDepth = "structural" | "mechanical";
|
|
17
|
+
/** A step outcome — aligned to `report.schema.json`. */
|
|
18
|
+
export type StepOutcome = {
|
|
19
|
+
status: "proved";
|
|
20
|
+
} | {
|
|
21
|
+
status: "failed";
|
|
22
|
+
haltClass: HaltClass;
|
|
23
|
+
} | {
|
|
24
|
+
status: "indeterminate";
|
|
25
|
+
} | {
|
|
26
|
+
status: "not-attempted";
|
|
27
|
+
depth: string;
|
|
28
|
+
};
|
|
29
|
+
/** One named step of the walk and how it came out. The `name` is a {@link StepName} in this
|
|
30
|
+
* implementation but is typed as `string` here so a foreign implementation's report is representable —
|
|
31
|
+
* a report type that cannot hold another engine's step cannot be used to compare against it. */
|
|
32
|
+
export interface VerificationStep {
|
|
33
|
+
name: string;
|
|
34
|
+
outcome: StepOutcome;
|
|
35
|
+
}
|
|
36
|
+
/** The output of a verification walk — the artifact a stranger reads instead of re-running it.
|
|
37
|
+
*
|
|
38
|
+
* Read `steps` before `verified`. `verified` is a summary that is FALSE at structural depth by
|
|
39
|
+
* construction, so a `false` may mean "impeached" or merely "not attempted mechanically", and only the
|
|
40
|
+
* step list distinguishes them. `supportedClass` is what the record honestly supports, not what the
|
|
41
|
+
* caller asked for. Several fields are `string` rather than a union on purpose: this type has to be able
|
|
42
|
+
* to hold another implementation's answer, including a wrong one. */
|
|
43
|
+
export interface VerificationReport {
|
|
44
|
+
/** Honest function of depth: `false` at structural (presence/absence → class); at mechanical, raised by
|
|
45
|
+
* `computeVerified` iff every class-required step is `proved` and none `failed`. */
|
|
46
|
+
verified: boolean;
|
|
47
|
+
/** The stated assurance level — never a bare boolean. One of the four ladder values
|
|
48
|
+
* (`wallet-signature-only` | `domain-controlled` | `attested` | `legal-party`), or
|
|
49
|
+
* `no-assurance-stated` where the record states none. Left as `string` rather than a union for the same
|
|
50
|
+
* reason `supportedClass` is: a foreign implementation's report must be representable before it can be
|
|
51
|
+
* compared, and a type that refuses to hold a wrong value cannot report one. */
|
|
52
|
+
assurance: string;
|
|
53
|
+
/** The transaction class the record honestly supports — an honest readout, never a target. */
|
|
54
|
+
supportedClass: string;
|
|
55
|
+
/** The settlement's chain-anchored time every validity check is evaluated against. */
|
|
56
|
+
asOf: string;
|
|
57
|
+
steps: VerificationStep[];
|
|
58
|
+
/** Supplied ports/bindings — coverage is part of honest depth. */
|
|
59
|
+
coverage: {
|
|
60
|
+
ports: string[];
|
|
61
|
+
bindings: string[];
|
|
62
|
+
};
|
|
63
|
+
settlements: {
|
|
64
|
+
found: unknown[];
|
|
65
|
+
multiplySettled: boolean;
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
/** RFC 8785 JCS canonical JSON string for any JSON value (keys sorted by UTF-16 code units, no whitespace). */
|
|
69
|
+
export declare function jcsCanonicalize(value: unknown): string;
|
|
70
|
+
/** The report's canonical bytes (UTF-8 of its JCS form) — the byte-for-byte target. */
|
|
71
|
+
export declare function serializeReport(report: VerificationReport): Uint8Array;
|
|
72
|
+
//# sourceMappingURL=report.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"report.d.ts","sourceRoot":"","sources":["../src/report.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iCAAiC,CAAC;AAEjE;qFACqF;AACrF,MAAM,MAAM,WAAW,GAAG,YAAY,GAAG,YAAY,CAAC;AAEtD,wDAAwD;AACxD,MAAM,MAAM,WAAW,GACnB;IAAE,MAAM,EAAE,QAAQ,CAAA;CAAE,GACpB;IAAE,MAAM,EAAE,QAAQ,CAAC;IAAC,SAAS,EAAE,SAAS,CAAA;CAAE,GAC1C;IAAE,MAAM,EAAE,eAAe,CAAA;CAAE,GAC3B;IAAE,MAAM,EAAE,eAAe,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AAE/C;;iGAEiG;AACjG,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,WAAW,CAAC;CACtB;AAED;;;;;;sEAMsE;AACtE,MAAM,WAAW,kBAAkB;IACjC;yFACqF;IACrF,QAAQ,EAAE,OAAO,CAAC;IAClB;;;;qFAIiF;IACjF,SAAS,EAAE,MAAM,CAAC;IAClB,8FAA8F;IAC9F,cAAc,EAAE,MAAM,CAAC;IACvB,sFAAsF;IACtF,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,gBAAgB,EAAE,CAAC;IAC1B,kEAAkE;IAClE,QAAQ,EAAE;QAAE,KAAK,EAAE,MAAM,EAAE,CAAC;QAAC,QAAQ,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC;IAClD,WAAW,EAAE;QAAE,KAAK,EAAE,OAAO,EAAE,CAAC;QAAC,eAAe,EAAE,OAAO,CAAA;KAAE,CAAC;CAC7D;AAyBD,+GAA+G;AAC/G,wBAAgB,eAAe,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAUtD;AAED,uFAAuF;AACvF,wBAAgB,eAAe,CAAC,MAAM,EAAE,kBAAkB,GAAG,UAAU,CAEtE"}
|
package/dist/report.js
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Emit the canonical text DIRECTLY from the sorted key list — never by re-assigning sorted keys onto an
|
|
3
|
+
* object and handing it to `JSON.stringify`. JS object property order puts integer-like keys FIRST, in
|
|
4
|
+
* ascending numeric order, whatever the insertion order (the same engine behaviour `kernel.assemble`
|
|
5
|
+
* refuses integer-like slot names over), so the object round-trip silently re-sorts `{"10":…,"9":…}` to
|
|
6
|
+
* `9,10` while RFC 8785 §3.2.3 requires UTF-16 code-unit order — `"1" (0x31) < "9" (0x39)`. Two conformant
|
|
7
|
+
* implementations would then disagree byte-for-byte on the same report, which is the one thing this buys.
|
|
8
|
+
* Reachable through `settlements.found` (caller-supplied objects). Pinned by `vectors/report/serialization.json`.
|
|
9
|
+
*/
|
|
10
|
+
function serializeCanonical(v) {
|
|
11
|
+
if (Array.isArray(v))
|
|
12
|
+
return `[${v.map(serializeCanonical).join(",")}]`;
|
|
13
|
+
if (v !== null && typeof v === "object") {
|
|
14
|
+
const obj = v;
|
|
15
|
+
// Default Array#sort compares by UTF-16 code units — exactly RFC 8785's ordering.
|
|
16
|
+
const parts = Object.keys(obj)
|
|
17
|
+
.sort()
|
|
18
|
+
.map((k) => `${JSON.stringify(k)}:${serializeCanonical(obj[k])}`);
|
|
19
|
+
return `{${parts.join(",")}}`;
|
|
20
|
+
}
|
|
21
|
+
// Primitives: JSON's own escaping + ECMAScript number formatting already match RFC 8785 §3.2.2.
|
|
22
|
+
return JSON.stringify(v);
|
|
23
|
+
}
|
|
24
|
+
/** RFC 8785 JCS canonical JSON string for any JSON value (keys sorted by UTF-16 code units, no whitespace). */
|
|
25
|
+
export function jcsCanonicalize(value) {
|
|
26
|
+
// Round-trip through JSON first so `toJSON`, dropped `undefined`/function members, and non-finite
|
|
27
|
+
// numbers resolve EXACTLY as JSON.stringify defines them; `serializeCanonical` then sees pure JSON
|
|
28
|
+
// and owns only the ordering rule.
|
|
29
|
+
const json = JSON.stringify(value);
|
|
30
|
+
if (json === undefined)
|
|
31
|
+
throw new Error("value is not JSON-serializable (JCS is defined only over JSON values)");
|
|
32
|
+
return serializeCanonical(JSON.parse(json));
|
|
33
|
+
}
|
|
34
|
+
/** The report's canonical bytes (UTF-8 of its JCS form) — the byte-for-byte target. */
|
|
35
|
+
export function serializeReport(report) {
|
|
36
|
+
return new TextEncoder().encode(jcsCanonicalize(report));
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=report.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"report.js","sourceRoot":"","sources":["../src/report.ts"],"names":[],"mappings":"AA4DA;;;;;;;;GAQG;AACH,SAAS,kBAAkB,CAAC,CAAU;IACpC,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC;QAAE,OAAO,IAAI,CAAC,CAAC,GAAG,CAAC,kBAAkB,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC;IACxE,IAAI,CAAC,KAAK,IAAI,IAAI,OAAO,CAAC,KAAK,QAAQ,EAAE,CAAC;QACxC,MAAM,GAAG,GAAG,CAA4B,CAAC;QACzC,kFAAkF;QAClF,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC;aAC3B,IAAI,EAAE;aACN,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,kBAAkB,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;QACpE,OAAO,IAAI,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC;IAChC,CAAC;IACD,gGAAgG;IAChG,OAAO,IAAI,CAAC,SAAS,CAAC,CAAC,CAAW,CAAC;AACrC,CAAC;AAED,+GAA+G;AAC/G,MAAM,UAAU,eAAe,CAAC,KAAc;IAC5C,kGAAkG;IAClG,mGAAmG;IACnG,mCAAmC;IACnC,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;IACnC,IAAI,IAAI,KAAK,SAAS;QACpB,MAAM,IAAI,KAAK,CACb,uEAAuE,CACxE,CAAC;IACJ,OAAO,kBAAkB,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC;AAC9C,CAAC;AAED,uFAAuF;AACvF,MAAM,UAAU,eAAe,CAAC,MAA0B;IACxD,OAAO,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,eAAe,CAAC,MAAM,CAAC,CAAC,CAAC;AAC3D,CAAC"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import type { VerifyDepth } from "./report.js";
|
|
2
|
+
export type { VerifyDepth };
|
|
3
|
+
/** The transaction-class ladder. Higher classes require strictly more steps, so a record supporting TC-3
|
|
4
|
+
* supports every class below it. A class is a CLAIM about what a record can support — it is never a
|
|
5
|
+
* quality score, and nothing in this package tries to reach a higher one. */
|
|
6
|
+
export type TransactionClass = "TC-0" | "TC-1" | "TC-2" | "TC-3" | "TC-4";
|
|
7
|
+
/** Every step the walk can append, in one closed union. Closed because `REQUIRED_STEPS` is keyed by these
|
|
8
|
+
* names and a typo would silently make a required step unfindable — which `computeVerified` would read as
|
|
9
|
+
* "not proved", failing safe but for the wrong reason. */
|
|
10
|
+
export type StepName = "atr-fingerprint" | "settlement-enumeration" | "buyer-acceptance" | "authority-attenuation" | "commitment-vs-leaf" | "recourse-elections" | "resolve-party" | "offer-bound" | "operations-bound" | "discovery-integrity" | "proportionality-declared" | "frc-non-gating" | "reference-placement";
|
|
11
|
+
/**
|
|
12
|
+
* What each class MECHANICALLY requires to be `proved` before `verified` can hold, derived row-for-row from
|
|
13
|
+
* The class requirements (see `vectors/verify/mechanical.json`, the authored-from-spec truth table):
|
|
14
|
+
*
|
|
15
|
+
* PAY (value settles) ................. `settlement-enumeration` TC-1 +
|
|
16
|
+
* IDN (identity, stated assurance) .... `resolve-party` TC-1 +
|
|
17
|
+
* TRM/WLD (fingerprint + weld) ........ `atr-fingerprint` TC-2 +
|
|
18
|
+
* TRM-6 (signed acceptance) ........... `buyer-acceptance` TC-3 +
|
|
19
|
+
* ATA (authority + delegation chain) .. `authority-attenuation`, `commitment-vs-leaf` TC-3 +
|
|
20
|
+
* RCS-1/2/4 (forum, law, package) ..... `recourse-elections` TC-3 +
|
|
21
|
+
* OFR/OPS/DSC (commerce plane) ........ the four composition steps TC-4
|
|
22
|
+
*
|
|
23
|
+
* The ladder is CUMULATIVE: a class requires every rung below it, which is why TC-4 cannot hold without the
|
|
24
|
+
* TC-3 acceptance. It is also EXACT: a class never requires a step it does not depend on — TRM is not a TC-1
|
|
25
|
+
* rung, so a TC-1 record with an unattempted fingerprint still verifies.
|
|
26
|
+
*
|
|
27
|
+
* DECLARED GAP — ASP (spend authority, verifiable bounds) is marked from TC-1 and has NO step here: the bounds
|
|
28
|
+
* live inside the rail's own settlement authorization (an EIP-3009 `value`, an escrow `PaymentInfo` cap) and
|
|
29
|
+
* `verify` is pure over supplied inputs with no rail decoder. RCS-4 reaches it indirectly — `recourse-elections`
|
|
30
|
+
* requires the `spend artifact` role in the retained package, so the artifact is kept and referenced even though
|
|
31
|
+
* its bounds are not re-derived here. Closing it properly is a rail-decoder work item, named rather than omitted.
|
|
32
|
+
*
|
|
33
|
+
* `frc-non-gating` is DELIBERATELY absent from TC-4: it impeaches when it FAILS (a signal that gated settlement)
|
|
34
|
+
* but its ABSENCE never blocks (FRC is a downstream consequence, not a v1 requirement).
|
|
35
|
+
*/
|
|
36
|
+
export declare const REQUIRED_STEPS: Record<TransactionClass, readonly StepName[]>;
|
|
37
|
+
/** Whether a walk affirms the claimed class. Three rules, in order: **structural depth is always `false`**
|
|
38
|
+
* (a presence/absence readout never affirms liveness), any `failed` step impeaches the whole walk, and
|
|
39
|
+
* otherwise every step required by the claimed class must be `proved`. A step that is absent, or
|
|
40
|
+
* `indeterminate`, is not `proved` — absent inputs never prove. */
|
|
41
|
+
export declare function computeVerified(steps: readonly {
|
|
42
|
+
name: StepName;
|
|
43
|
+
outcome: {
|
|
44
|
+
status: string;
|
|
45
|
+
};
|
|
46
|
+
}[], claimedClass: TransactionClass, depth: VerifyDepth): boolean;
|
|
47
|
+
//# sourceMappingURL=required.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"required.d.ts","sourceRoot":"","sources":["../src/required.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE/C,YAAY,EAAE,WAAW,EAAE,CAAC;AAC5B;;8EAE8E;AAC9E,MAAM,MAAM,gBAAgB,GAAG,MAAM,GAAG,MAAM,GAAG,MAAM,GAAG,MAAM,GAAG,MAAM,CAAC;AAC1E;;2DAE2D;AAC3D,MAAM,MAAM,QAAQ,GAChB,iBAAiB,GACjB,wBAAwB,GACxB,kBAAkB,GAClB,uBAAuB,GACvB,oBAAoB,GACpB,oBAAoB,GACpB,eAAe,GAEf,aAAa,GACb,kBAAkB,GAClB,qBAAqB,GACrB,0BAA0B,GAC1B,gBAAgB,GAMhB,qBAAqB,CAAC;AAe1B;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,eAAO,MAAM,cAAc,EAAE,MAAM,CAAC,gBAAgB,EAAE,SAAS,QAAQ,EAAE,CAYxE,CAAC;AAEF;;;oEAGoE;AACpE,wBAAgB,eAAe,CAC7B,KAAK,EAAE,SAAS;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,OAAO,EAAE;QAAE,MAAM,EAAE,MAAM,CAAA;KAAE,CAAA;CAAE,EAAE,EACjE,YAAY,EAAE,gBAAgB,EAC9B,KAAK,EAAE,WAAW,GACjB,OAAO,CAOT"}
|
package/dist/required.js
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
/** PAY + IDN — the attribution rungs every class from TC-1 up carries. */
|
|
2
|
+
const TC1 = ["settlement-enumeration", "resolve-party"];
|
|
3
|
+
/** + TRM/WLD: the fingerprint step IS the weld check (recomputed hash vs the hash the settlement committed). */
|
|
4
|
+
const TC2 = [...TC1, "atr-fingerprint"];
|
|
5
|
+
/** + TRM-6 + ATA + RCS-1/2/4 — the definition of the class, verbatim. */
|
|
6
|
+
const TC3 = [
|
|
7
|
+
...TC2,
|
|
8
|
+
"buyer-acceptance",
|
|
9
|
+
"authority-attenuation",
|
|
10
|
+
"commitment-vs-leaf",
|
|
11
|
+
"recourse-elections",
|
|
12
|
+
];
|
|
13
|
+
/**
|
|
14
|
+
* What each class MECHANICALLY requires to be `proved` before `verified` can hold, derived row-for-row from
|
|
15
|
+
* The class requirements (see `vectors/verify/mechanical.json`, the authored-from-spec truth table):
|
|
16
|
+
*
|
|
17
|
+
* PAY (value settles) ................. `settlement-enumeration` TC-1 +
|
|
18
|
+
* IDN (identity, stated assurance) .... `resolve-party` TC-1 +
|
|
19
|
+
* TRM/WLD (fingerprint + weld) ........ `atr-fingerprint` TC-2 +
|
|
20
|
+
* TRM-6 (signed acceptance) ........... `buyer-acceptance` TC-3 +
|
|
21
|
+
* ATA (authority + delegation chain) .. `authority-attenuation`, `commitment-vs-leaf` TC-3 +
|
|
22
|
+
* RCS-1/2/4 (forum, law, package) ..... `recourse-elections` TC-3 +
|
|
23
|
+
* OFR/OPS/DSC (commerce plane) ........ the four composition steps TC-4
|
|
24
|
+
*
|
|
25
|
+
* The ladder is CUMULATIVE: a class requires every rung below it, which is why TC-4 cannot hold without the
|
|
26
|
+
* TC-3 acceptance. It is also EXACT: a class never requires a step it does not depend on — TRM is not a TC-1
|
|
27
|
+
* rung, so a TC-1 record with an unattempted fingerprint still verifies.
|
|
28
|
+
*
|
|
29
|
+
* DECLARED GAP — ASP (spend authority, verifiable bounds) is marked from TC-1 and has NO step here: the bounds
|
|
30
|
+
* live inside the rail's own settlement authorization (an EIP-3009 `value`, an escrow `PaymentInfo` cap) and
|
|
31
|
+
* `verify` is pure over supplied inputs with no rail decoder. RCS-4 reaches it indirectly — `recourse-elections`
|
|
32
|
+
* requires the `spend artifact` role in the retained package, so the artifact is kept and referenced even though
|
|
33
|
+
* its bounds are not re-derived here. Closing it properly is a rail-decoder work item, named rather than omitted.
|
|
34
|
+
*
|
|
35
|
+
* `frc-non-gating` is DELIBERATELY absent from TC-4: it impeaches when it FAILS (a signal that gated settlement)
|
|
36
|
+
* but its ABSENCE never blocks (FRC is a downstream consequence, not a v1 requirement).
|
|
37
|
+
*/
|
|
38
|
+
export const REQUIRED_STEPS = {
|
|
39
|
+
"TC-0": [],
|
|
40
|
+
"TC-1": TC1,
|
|
41
|
+
"TC-2": TC2,
|
|
42
|
+
"TC-3": TC3,
|
|
43
|
+
"TC-4": [
|
|
44
|
+
...TC3,
|
|
45
|
+
"offer-bound",
|
|
46
|
+
"operations-bound",
|
|
47
|
+
"discovery-integrity",
|
|
48
|
+
"proportionality-declared",
|
|
49
|
+
],
|
|
50
|
+
};
|
|
51
|
+
/** Whether a walk affirms the claimed class. Three rules, in order: **structural depth is always `false`**
|
|
52
|
+
* (a presence/absence readout never affirms liveness), any `failed` step impeaches the whole walk, and
|
|
53
|
+
* otherwise every step required by the claimed class must be `proved`. A step that is absent, or
|
|
54
|
+
* `indeterminate`, is not `proved` — absent inputs never prove. */
|
|
55
|
+
export function computeVerified(steps, claimedClass, depth) {
|
|
56
|
+
if (depth === "structural")
|
|
57
|
+
return false; // structural = presence/absence readout, never affirms liveness
|
|
58
|
+
if (steps.some((s) => s.outcome.status === "failed"))
|
|
59
|
+
return false; // any failure impeaches
|
|
60
|
+
const required = REQUIRED_STEPS[claimedClass];
|
|
61
|
+
return required.every((name) => steps.find((s) => s.name === name)?.outcome.status === "proved");
|
|
62
|
+
}
|
|
63
|
+
//# sourceMappingURL=required.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"required.js","sourceRoot":"","sources":["../src/required.ts"],"names":[],"mappings":"AA+BA,0EAA0E;AAC1E,MAAM,GAAG,GAAwB,CAAC,wBAAwB,EAAE,eAAe,CAAC,CAAC;AAC7E,gHAAgH;AAChH,MAAM,GAAG,GAAwB,CAAC,GAAG,GAAG,EAAE,iBAAiB,CAAC,CAAC;AAC7D,yEAAyE;AACzE,MAAM,GAAG,GAAwB;IAC/B,GAAG,GAAG;IACN,kBAAkB;IAClB,uBAAuB;IACvB,oBAAoB;IACpB,oBAAoB;CACrB,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,MAAM,CAAC,MAAM,cAAc,GAAkD;IAC3E,MAAM,EAAE,EAAE;IACV,MAAM,EAAE,GAAG;IACX,MAAM,EAAE,GAAG;IACX,MAAM,EAAE,GAAG;IACX,MAAM,EAAE;QACN,GAAG,GAAG;QACN,aAAa;QACb,kBAAkB;QAClB,qBAAqB;QACrB,0BAA0B;KAC3B;CACF,CAAC;AAEF;;;oEAGoE;AACpE,MAAM,UAAU,eAAe,CAC7B,KAAiE,EACjE,YAA8B,EAC9B,KAAkB;IAElB,IAAI,KAAK,KAAK,YAAY;QAAE,OAAO,KAAK,CAAC,CAAC,gEAAgE;IAC1G,IAAI,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,KAAK,QAAQ,CAAC;QAAE,OAAO,KAAK,CAAC,CAAC,wBAAwB;IAC5F,MAAM,QAAQ,GAAG,cAAc,CAAC,YAAY,CAAC,CAAC;IAC9C,OAAO,QAAQ,CAAC,KAAK,CACnB,CAAC,IAAI,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,IAAI,CAAC,EAAE,OAAO,CAAC,MAAM,KAAK,QAAQ,CAC1E,CAAC;AACJ,CAAC"}
|
package/dist/steps.d.ts
ADDED
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The verification walk as an ordered table of typed steps. At STRUCTURAL depth each step is
|
|
3
|
+
* presence/absence → outcome plus the pure checks it can do over supplied inputs (no live ports):
|
|
4
|
+
* `proved | failed(haltClass) | indeterminate | not-attempted(depth)`. A step whose inputs are absent is
|
|
5
|
+
* `not-attempted(<why>)` — coverage is honest depth, never a silent pass. These outcomes are depth-agnostic;
|
|
6
|
+
* `verified` is computed FROM them by `computeVerified` (index.ts); the live-port gathering that raises
|
|
7
|
+
* coverage to mechanical depth is the buyer gate's.
|
|
8
|
+
*
|
|
9
|
+
* Three rules hold across every step, and all three exist so the walk can never flatter a record:
|
|
10
|
+
* - ABSENT INPUTS NEVER PROVE. An empty authority chain, an acceptance with no verifier to check its
|
|
11
|
+
* signature, an identity with no resolution chain — each is `not-attempted`, never `proved`.
|
|
12
|
+
* - CONTRADICTIONS FAIL, GAPS DO NOT. `failed` is reserved for a record that contradicts itself (a
|
|
13
|
+
* fingerprint that does not match, a link that widens its parent, a signature that does not verify);
|
|
14
|
+
* it impeaches `supportedClass` to TC-0. Missing evidence is a gap: `not-attempted`, which leaves
|
|
15
|
+
* `verified` false without impeaching a record that simply did not carry that rung.
|
|
16
|
+
* - EVERY STEP IS TOTAL. Steps read their slots through `present` and shape-check before dereferencing,
|
|
17
|
+
* because the callers they exist for are untyped — a foreign conformance subject, an unvalidated
|
|
18
|
+
* intake. A malformed slot reads out as a gap, never as a `failed`: the caller's shape error says
|
|
19
|
+
* nothing about whether the record is self-consistent, and a walk that throws cannot report the
|
|
20
|
+
* malformation it was handed.
|
|
21
|
+
*
|
|
22
|
+
* The authority step is the load-bearing one. Every link must have been PERMITTED by its parent (ATA-3 —
|
|
23
|
+
* the parent was delegable, it had depth left, and the link stated a depth that fits beneath what the
|
|
24
|
+
* parent held; an unstated depth is unbounded and therefore an escalation like any other), must ATTENUATE
|
|
25
|
+
* (`authority.isWithin`), and must be UNREVOKED and UNEXPIRED as-of settlement. Each failure is
|
|
26
|
+
* `failed(verification-failure)`, never `proved`, so the walk can never affirm a forged chain — whether the
|
|
27
|
+
* forgery widened the bounds or the authority to delegate them. These are the same four gates
|
|
28
|
+
* `authority.linkAttenuates` enforces at issuance; producer and verifier must not diverge, and
|
|
29
|
+
* `vectors/{authority/link-attenuates,verify/authority-walk}.json` pin both halves against each other.
|
|
30
|
+
*
|
|
31
|
+
* `authorityStep` reads a FLATTENED chain, every field of which is a derived fact it must take on trust.
|
|
32
|
+
* `authorityStepFromWalk` is the path that removes that trust — it consumes `authority.walkChain`'s
|
|
33
|
+
* readout directly, so the caller never flattens anything. Both are exported: the flattened door stays
|
|
34
|
+
* open because a foreign conformance subject may legitimately derive its links some other way, and this
|
|
35
|
+
* module's totality rule means such a caller gets an honest readout rather than a compile wall.
|
|
36
|
+
*/
|
|
37
|
+
import { type Bounds, type ChainWalkResult, type IdentityResolution, type SignatureVerifier, type SignedAcceptance } from "@integraledger/lcp-authority";
|
|
38
|
+
import type { StepOutcome } from "./report.js";
|
|
39
|
+
/**
|
|
40
|
+
* One link in the ATA chain, pre-resolved to what the structural walk checks — the verification-time
|
|
41
|
+
* mirror of `authority.linkAttenuates`, whose four issuance gates it must all carry: the parent permitted
|
|
42
|
+
* delegation, the parent had depth left, this link's depth fits beneath it, and the bounds are contained.
|
|
43
|
+
*
|
|
44
|
+
* `parentDelegable` is REQUIRED, not optional, and that is the point: `GrantSubject.delegable` is
|
|
45
|
+
* non-delegable by default, so "the caller did not thread the flag" and "the parent refused delegation"
|
|
46
|
+
* would be the same absent value — the exact ambiguity that turns an unverified rung into a proved one.
|
|
47
|
+
* Requiring it makes the unstated case a compile error at the callsite instead of a silent pass.
|
|
48
|
+
*/
|
|
49
|
+
export interface AuthorityLink {
|
|
50
|
+
bounds: Bounds;
|
|
51
|
+
parentBounds: Bounds;
|
|
52
|
+
/** ATA-3: did the PARENT grant permit delegation at all? A link below a non-delegable parent is forged. */
|
|
53
|
+
parentDelegable: boolean;
|
|
54
|
+
/** The parent's remaining delegation depth (0 = leaf, nothing may descend). Absent = unbounded. */
|
|
55
|
+
parentMaxDepth?: number;
|
|
56
|
+
/** This link's OWN remaining depth. It may not exceed `parentMaxDepth - 1` — a link cannot mint itself
|
|
57
|
+
* more latitude to delegate onward than the parent it descends from held.
|
|
58
|
+
*
|
|
59
|
+
* Absent = unbounded, which is why omitting it BELOW A DEPTH-BOUNDED PARENT is itself an escalation and
|
|
60
|
+
* fails. Inferring `parentMaxDepth - 1` from the parent instead would be a silent fallback, and it would
|
|
61
|
+
* also leave the next hop's `parentMaxDepth` unstated, disengaging this gate for the rest of the chain.
|
|
62
|
+
* Under an unbounded parent the link may hold any depth, including none. */
|
|
63
|
+
maxDepth?: number;
|
|
64
|
+
/** Revoked as-of settlement, from the hash-pinned status-list snapshot.
|
|
65
|
+
*
|
|
66
|
+
* REQUIRED, for the same reason `parentDelegable` is: "the flattener never consulted a status list"
|
|
67
|
+
* and "the walk checked the pinned snapshot and the link is unrevoked" are otherwise the same absent
|
|
68
|
+
* value, and one of them proves. `authority.WalkedLink` already states it always, never defaulted, so
|
|
69
|
+
* a walk-fed caller satisfies this for free and only a hand-flattener feels it — which is the point.
|
|
70
|
+
*
|
|
71
|
+
* The compile error is not the whole gate, and must not be relied on as one — at runtime an absent value reads as
|
|
72
|
+
* unrevoked and PROVED, on the grounds that the corpus pinned that reading cross-implementation. The
|
|
73
|
+
* corpus was the thing to change, and on 2026-08-08 it was: absence now reads `not-attempted` with
|
|
74
|
+
* depth `no-revocation-stated`, and a non-boolean reads `malformed-authority-chain`. Type and runtime
|
|
75
|
+
* agree, so the untyped caller this step exists for gets the same answer a typed one is prevented from
|
|
76
|
+
* asking. */
|
|
77
|
+
revoked: boolean;
|
|
78
|
+
/** Temporally active as-of settlement (expiry). REQUIRED on the same grounds as `revoked` — an
|
|
79
|
+
* unstated liveness and a checked-and-live one must not be the same value. Runtime matches: absent is
|
|
80
|
+
* `not-attempted` with depth `no-liveness-stated`, its OWN token rather than revocation's, so a report
|
|
81
|
+
* never describes an expiry gap as something about revocation. */
|
|
82
|
+
active: boolean;
|
|
83
|
+
}
|
|
84
|
+
/** Both parties' resolutions as the record's `identity` slot carries them (IDN-1/IDN-3). */
|
|
85
|
+
export interface RecordIdentity {
|
|
86
|
+
seller: IdentityResolution;
|
|
87
|
+
buyer: IdentityResolution;
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* RCS-4's required evidence roles — the specification's own enumeration of a self-contained package: the terms
|
|
91
|
+
* artifact and fingerprint; the acceptance signature and its authority chain (ATA-6); the spend-authorization
|
|
92
|
+
* artifact or a verifiable reference to it (ASP-5); the identity attestations relied on and their assurance
|
|
93
|
+
* levels (IDN-3); the settlement reference and weld; timestamps. Its own conditional clause — fulfillment and
|
|
94
|
+
* order-state, "where performance is disputed" (OPS-2) — is conditional and therefore NOT required here.
|
|
95
|
+
*/
|
|
96
|
+
export declare const RCS4_REQUIRED_ROLES: readonly string[];
|
|
97
|
+
/** Recompute the fingerprint over the retrieved ATR bytes and compare to what the settlement committed. */
|
|
98
|
+
export declare function fingerprintStep(atrBytes: Uint8Array | undefined, settledAtrHash: string | undefined): Promise<StepOutcome>;
|
|
99
|
+
/** Settlement enumeration across supplied forward-indexable bindings (multiply-settled flag). */
|
|
100
|
+
export declare function settlementStep(settlements: unknown[] | undefined): StepOutcome;
|
|
101
|
+
/**
|
|
102
|
+
* TRM-6: the buyer's acceptance over the fingerprint, SIGNED and TIMESTAMPED. The signature is checked
|
|
103
|
+
* through `authority.verifyAcceptance` over the injected `SignatureVerifier` port (the EVM implementation
|
|
104
|
+
* — EOA EIP-191/712 and smart-account ERC-1271/6492 — is `binding-evm-common`'s).
|
|
105
|
+
*
|
|
106
|
+
* WITHOUT A VERIFIER THIS STEP CANNOT PROVE. A signature nobody checked is not evidence of a signature, so
|
|
107
|
+
* an acceptance presented with no verifier is `not-attempted("no-signature-verifier")` — the honest readout
|
|
108
|
+
* of "this record carries an acceptance whose cryptography this verifier was not equipped to check".
|
|
109
|
+
* `signedAt` needs no separate gate: `SignedAcceptance` requires it, so an untimestamped acceptance is
|
|
110
|
+
* unrepresentable rather than rejected at runtime — illegal states are not constructible.
|
|
111
|
+
*/
|
|
112
|
+
export declare function acceptanceStep(acceptance: SignedAcceptance | undefined, settledAtrHash: string | undefined, verifier: SignatureVerifier | undefined): Promise<StepOutcome>;
|
|
113
|
+
/** Walk the ATA chain: every link attenuates (isWithin), is unrevoked, and is unexpired as-of settlement. */
|
|
114
|
+
export declare function authorityStep(chain: AuthorityLink[] | undefined): StepOutcome;
|
|
115
|
+
/**
|
|
116
|
+
* The WALK-FED authority step — `authority.walkChain`'s readout mapped onto a `StepOutcome`. Prefer it.
|
|
117
|
+
*
|
|
118
|
+
* `authorityStep` accepts any `AuthorityLink[]`, which makes whoever produced that array a trusted
|
|
119
|
+
* oracle: every field on a link is a DERIVED fact (`parentDelegable`, `parentMaxDepth`, `parentBounds`,
|
|
120
|
+
* `revoked`, `active`), and the step takes each at face value. A flattener that never verified custody —
|
|
121
|
+
* never checked that link N+1 was signed by link N's subject, never dereferenced a status list — yields a
|
|
122
|
+
* confident `proved`. A caller that walks first constructs no link at all and cannot make that mistake.
|
|
123
|
+
*
|
|
124
|
+
* The mapping needs no interpretation, because `ChainWalkResult` already draws this module's own line:
|
|
125
|
+
* `refused` is a reasoned CONTRADICTION (a spliced link, an issuer discontinuity, a forged widening, a
|
|
126
|
+
* revoked grant) and carries the halt class with it; `not-attempted` is the walk's honest GAP, its depth
|
|
127
|
+
* passed through verbatim; `walked` hands over links whose every field the walk STATED rather than
|
|
128
|
+
* defaulted. Re-proving those links through `authorityStep` is deliberate rather than redundant — it is
|
|
129
|
+
* what stops the custody walk and the verification step from drifting apart, and
|
|
130
|
+
* `packages/conformance/the repository's walk-readout tests` pins that the walk's output is exactly what the step
|
|
131
|
+
* proves. Total over untyped input like every step here: an unrecognized readout carries no links, so it
|
|
132
|
+
* falls through to `authorityStep`'s own gap rather than throwing.
|
|
133
|
+
*/
|
|
134
|
+
export declare function authorityStepFromWalk(walk: ChainWalkResult | undefined): StepOutcome;
|
|
135
|
+
/** ATA-4: the accepted commitment must be contained by the leaf grant's bounds. */
|
|
136
|
+
export declare function commitmentStep(c: {
|
|
137
|
+
commitment: Bounds;
|
|
138
|
+
leafBounds: Bounds;
|
|
139
|
+
} | undefined): StepOutcome;
|
|
140
|
+
/**
|
|
141
|
+
* RCS-1/2/4: the elections the record carries and the package it produced.
|
|
142
|
+
*
|
|
143
|
+
* The elections are read from THE HASHED RECORD ITSELF — `atrBytes` parsed as the LCP envelope — never from
|
|
144
|
+
* a caller-supplied side channel, because RCS-1 requires the forum designation "recorded inside the terms
|
|
145
|
+
* record" (TRM-9). What this step proves is therefore what was welded.
|
|
146
|
+
*
|
|
147
|
+
* This step NEVER returns `failed`. An unelected forum is a record that did not reach for the rung, not a
|
|
148
|
+
* record that contradicts itself, and impeaching `supportedClass` to TC-0 over it would misreport a
|
|
149
|
+
* perfectly coherent TC-2. Likewise a non-machine-readable ATR (a ratified prose template, a PDF) is an
|
|
150
|
+
* honest coverage gap: a human forum can read a governing-law clause a verifier cannot.
|
|
151
|
+
*/
|
|
152
|
+
export declare function recourseStep(atrBytes: Uint8Array | undefined, evidenceRoles: readonly string[] | undefined): StepOutcome;
|
|
153
|
+
/**
|
|
154
|
+
* IDN-1/IDN-3: both parties resolve, each at a STATED assurance level, over a non-empty resolution chain.
|
|
155
|
+
*
|
|
156
|
+
* IDN-2 — does the chain terminate in an accountable party rather than a bare key? — is deliberately NOT a
|
|
157
|
+
* gate here. It is the counterparty-trust question a BUYER's policy asks (`authority.isConsequentialConformant`,
|
|
158
|
+
* applied by the gate), not a property of the record's class: a record that honestly states
|
|
159
|
+
* `wallet-signature-only` is conformant at its level, and IDN-3's whole discipline is that the low level
|
|
160
|
+
* stated honestly passes while an unstated level does not.
|
|
161
|
+
*/
|
|
162
|
+
export declare function resolvePartyStep(identity: RecordIdentity | undefined): StepOutcome;
|
|
163
|
+
/** The placement slot: what a commerce protocol's own document yielded, and nothing else. `extracted` is
|
|
164
|
+
* the `LegalContextRef` a `ReferencePlacementAdapter.extract` returned. Absent ⇒ the step is a gap. */
|
|
165
|
+
export interface PlacementInput {
|
|
166
|
+
readonly extracted?: unknown;
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* The reference-placement step — did the reference found in the protocol's native field match this record?
|
|
170
|
+
*
|
|
171
|
+
* REPORTED, NEVER REQUIRED: no class lists it in `REQUIRED_STEPS`, so its absence never blocks, and it
|
|
172
|
+
* impeaches only when it FAILS — the `frc-non-gating` pattern exactly. A protocol that never settles has
|
|
173
|
+
* nothing to enumerate, and letting a placement stand in for a settlement rung would let a record that
|
|
174
|
+
* moved no money read as classed.
|
|
175
|
+
*
|
|
176
|
+
* Total, like every step: the shape checks stay even though the arguments are typed, because the callers
|
|
177
|
+
* this exists for are untyped — a foreign conformance subject, an unvalidated intake. A malformed
|
|
178
|
+
* extraction is a GAP, never a `failed`: the caller's shape error says nothing about whether the record
|
|
179
|
+
* contradicts itself.
|
|
180
|
+
*/
|
|
181
|
+
export declare function referencePlacementStep(placement: PlacementInput | undefined, settledAtrHash: string | undefined): StepOutcome;
|
|
182
|
+
//# sourceMappingURL=steps.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"steps.d.ts","sourceRoot":"","sources":["../src/steps.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AACH,OAAO,EACL,KAAK,MAAM,EACX,KAAK,eAAe,EAEpB,KAAK,kBAAkB,EAEvB,KAAK,iBAAiB,EACtB,KAAK,gBAAgB,EAEtB,MAAM,8BAA8B,CAAC;AAEtC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE/C;;;;;;;;;GASG;AACH,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,MAAM,CAAC;IACf,YAAY,EAAE,MAAM,CAAC;IACrB,2GAA2G;IAC3G,eAAe,EAAE,OAAO,CAAC;IACzB,mGAAmG;IACnG,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB;;;;;;iFAM6E;IAC7E,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;;;;;;;;;;;kBAYc;IACd,OAAO,EAAE,OAAO,CAAC;IACjB;;;uEAGmE;IACnE,MAAM,EAAE,OAAO,CAAC;CACjB;AAED,4FAA4F;AAC5F,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,kBAAkB,CAAC;IAC3B,KAAK,EAAE,kBAAkB,CAAC;CAC3B;AAcD;;;;;;GAMG;AACH,eAAO,MAAM,mBAAmB,EAAE,SAAS,MAAM,EAShD,CAAC;AA8BF,2GAA2G;AAC3G,wBAAsB,eAAe,CACnC,QAAQ,EAAE,UAAU,GAAG,SAAS,EAChC,cAAc,EAAE,MAAM,GAAG,SAAS,GACjC,OAAO,CAAC,WAAW,CAAC,CAUtB;AAED,iGAAiG;AACjG,wBAAgB,cAAc,CAC5B,WAAW,EAAE,OAAO,EAAE,GAAG,SAAS,GACjC,WAAW,CAMb;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,cAAc,CAClC,UAAU,EAAE,gBAAgB,GAAG,SAAS,EACxC,cAAc,EAAE,MAAM,GAAG,SAAS,EAClC,QAAQ,EAAE,iBAAiB,GAAG,SAAS,GACtC,OAAO,CAAC,WAAW,CAAC,CAWtB;AAED,6GAA6G;AAC7G,wBAAgB,aAAa,CAAC,KAAK,EAAE,aAAa,EAAE,GAAG,SAAS,GAAG,WAAW,CAmF7E;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,qBAAqB,CACnC,IAAI,EAAE,eAAe,GAAG,SAAS,GAChC,WAAW,CAQb;AAED,mFAAmF;AACnF,wBAAgB,cAAc,CAC5B,CAAC,EAAE;IAAE,UAAU,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAE,GAAG,SAAS,GACxD,WAAW,CAgBb;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,YAAY,CAC1B,QAAQ,EAAE,UAAU,GAAG,SAAS,EAChC,aAAa,EAAE,SAAS,MAAM,EAAE,GAAG,SAAS,GAC3C,WAAW,CAiCb;AAED;;;;;;;;GAQG;AACH,wBAAgB,gBAAgB,CAC9B,QAAQ,EAAE,cAAc,GAAG,SAAS,GACnC,WAAW,CA0Bb;AAED;wGACwG;AACxG,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,SAAS,CAAC,EAAE,OAAO,CAAC;CAC9B;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,sBAAsB,CACpC,SAAS,EAAE,cAAc,GAAG,SAAS,EACrC,cAAc,EAAE,MAAM,GAAG,SAAS,GACjC,WAAW,CA8Bb"}
|