@eir-labs/coltrane 0.24.37 → 0.24.39
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/dist/src/chart.js +5 -3
- package/dist/src/chart.js.map +1 -1
- package/dist/src/cli.d.ts +1 -1
- package/dist/src/institution_enforcement.d.ts +6 -0
- package/dist/src/institution_enforcement.js +6 -1
- package/dist/src/institution_enforcement.js.map +1 -1
- package/dist/src/mcp.js +1 -1
- package/dist/src/mcp.js.map +1 -1
- package/dist/src/releases.d.ts +46 -0
- package/dist/src/releases.js +51 -5
- package/dist/src/releases.js.map +1 -1
- package/dist/src/reuse.d.ts +1 -1
- package/dist/src/version.d.ts +1 -1
- package/dist/src/version.js +1 -1
- package/package.json +1 -1
- package/releases.json +177 -0
- package/skills/obligation-adjudicate/fixtures/dead-name-on-missing-fact.json +47 -0
- package/skills/obligation-adjudicate/fixtures/debtor-cannot-certify-itself.json +43 -0
- package/skills/obligation-adjudicate/fixtures/decides-what-it-can.json +43 -0
- package/skills/obligation-adjudicate/fixtures/empty-never-passes.json +15 -0
- package/skills/obligation-adjudicate/fixtures/names-the-operator-it-wanted.json +48 -0
- package/skills/obligation-adjudicate/fixtures/no-check-is-not-a-pass.json +35 -0
- package/skills/obligation-adjudicate/fixtures/proposed-is-not-in-force.json +40 -0
- package/skills/obligation-adjudicate/fixtures/unattributed-snapshot-refused.json +47 -0
- package/skills/obligation-adjudicate/meta.json +12 -0
- package/skills/obligation-adjudicate/skill.mjs +91 -0
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "dead-name-on-missing-fact",
|
|
3
|
+
"description": "A declared input the snapshot does not supply is DEAD_NAME, never a pass",
|
|
4
|
+
"input": {
|
|
5
|
+
"laws": [
|
|
6
|
+
{
|
|
7
|
+
"slug": "needs-fact",
|
|
8
|
+
"status": "executed",
|
|
9
|
+
"bearer": "org:eir-labs",
|
|
10
|
+
"law": {
|
|
11
|
+
"attributes": "Eir Labs Inc.",
|
|
12
|
+
"deontic": "obliged",
|
|
13
|
+
"aim": "pay the FY1 balance",
|
|
14
|
+
"conditions": "by 2027-03-31",
|
|
15
|
+
"or_else": "the GK may invoice interest",
|
|
16
|
+
"debtor": "org:eir-labs",
|
|
17
|
+
"creditor": "org:eir-gk",
|
|
18
|
+
"check": {
|
|
19
|
+
"predicate": "(= a b)",
|
|
20
|
+
"inputs": {
|
|
21
|
+
"a": "x",
|
|
22
|
+
"b": "y"
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
],
|
|
28
|
+
"facts": {
|
|
29
|
+
"facts": {
|
|
30
|
+
"a": 1
|
|
31
|
+
},
|
|
32
|
+
"supplied_by": "org:eir-gk"
|
|
33
|
+
}
|
|
34
|
+
},
|
|
35
|
+
"assertions": [
|
|
36
|
+
{
|
|
37
|
+
"path": "results.0.outcome",
|
|
38
|
+
"op": "equals",
|
|
39
|
+
"value": "DEAD_NAME"
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
"path": "pass",
|
|
43
|
+
"op": "equals",
|
|
44
|
+
"value": false
|
|
45
|
+
}
|
|
46
|
+
]
|
|
47
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "debtor-cannot-certify-itself",
|
|
3
|
+
"description": "A snapshot supplied by the debtor is refused",
|
|
4
|
+
"input": {
|
|
5
|
+
"laws": [
|
|
6
|
+
{
|
|
7
|
+
"slug": "self-served",
|
|
8
|
+
"status": "executed",
|
|
9
|
+
"bearer": "org:eir-labs",
|
|
10
|
+
"law": {
|
|
11
|
+
"attributes": "Eir Labs Inc.",
|
|
12
|
+
"deontic": "obliged",
|
|
13
|
+
"aim": "pay the FY1 balance",
|
|
14
|
+
"conditions": "by 2027-03-31",
|
|
15
|
+
"or_else": "the GK may invoice interest",
|
|
16
|
+
"debtor": "org:eir-labs",
|
|
17
|
+
"creditor": "org:eir-gk",
|
|
18
|
+
"check": {
|
|
19
|
+
"predicate": "(= a b)",
|
|
20
|
+
"inputs": {
|
|
21
|
+
"a": "x",
|
|
22
|
+
"b": "y"
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
],
|
|
28
|
+
"facts": {
|
|
29
|
+
"supplied_by": "org:eir-labs",
|
|
30
|
+
"facts": {
|
|
31
|
+
"a": 1,
|
|
32
|
+
"b": 1
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
},
|
|
36
|
+
"assertions": [
|
|
37
|
+
{
|
|
38
|
+
"path": "results.0.outcome",
|
|
39
|
+
"op": "equals",
|
|
40
|
+
"value": "refused"
|
|
41
|
+
}
|
|
42
|
+
]
|
|
43
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "decides-what-it-can",
|
|
3
|
+
"description": "An obligation whose predicate uses only implemented operators is decided",
|
|
4
|
+
"input": {
|
|
5
|
+
"laws": [
|
|
6
|
+
{
|
|
7
|
+
"slug": "w8-on-file",
|
|
8
|
+
"status": "executed",
|
|
9
|
+
"bearer": "org:eir-labs",
|
|
10
|
+
"law": {
|
|
11
|
+
"attributes": "Eir Labs Inc.",
|
|
12
|
+
"deontic": "obliged",
|
|
13
|
+
"aim": "pay the FY1 balance",
|
|
14
|
+
"conditions": "by 2027-03-31",
|
|
15
|
+
"or_else": "the GK may invoice interest",
|
|
16
|
+
"debtor": "org:eir-labs",
|
|
17
|
+
"creditor": "org:eir-gk",
|
|
18
|
+
"check": {
|
|
19
|
+
"predicate": "(=> (has payee w8) (require (backed_by_form w8)))",
|
|
20
|
+
"inputs": {
|
|
21
|
+
"payee": "principal",
|
|
22
|
+
"w8": "instrument-ref"
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
],
|
|
28
|
+
"facts": {
|
|
29
|
+
"facts": {
|
|
30
|
+
"payee": "org:eir-gk",
|
|
31
|
+
"w8": "instrument-ref:w8ben-e-2026"
|
|
32
|
+
},
|
|
33
|
+
"supplied_by": "org:eir-gk"
|
|
34
|
+
}
|
|
35
|
+
},
|
|
36
|
+
"assertions": [
|
|
37
|
+
{
|
|
38
|
+
"path": "checks.0.method",
|
|
39
|
+
"op": "equals",
|
|
40
|
+
"value": "evaluate(check, fact-snapshot)"
|
|
41
|
+
}
|
|
42
|
+
]
|
|
43
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "names-the-operator-it-wanted",
|
|
3
|
+
"description": "A payment predicate comes back UNDECIDED naming the comparison it needed",
|
|
4
|
+
"input": {
|
|
5
|
+
"laws": [
|
|
6
|
+
{
|
|
7
|
+
"slug": "fy1-balance",
|
|
8
|
+
"status": "executed",
|
|
9
|
+
"bearer": "org:eir-labs",
|
|
10
|
+
"law": {
|
|
11
|
+
"attributes": "Eir Labs Inc.",
|
|
12
|
+
"deontic": "obliged",
|
|
13
|
+
"aim": "pay the FY1 balance",
|
|
14
|
+
"conditions": "by 2027-03-31",
|
|
15
|
+
"or_else": "the GK may invoice interest",
|
|
16
|
+
"debtor": "org:eir-labs",
|
|
17
|
+
"creditor": "org:eir-gk",
|
|
18
|
+
"check": {
|
|
19
|
+
"predicate": "(>= paid_minor due_minor)",
|
|
20
|
+
"inputs": {
|
|
21
|
+
"paid_minor": "money",
|
|
22
|
+
"due_minor": "money"
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
],
|
|
28
|
+
"facts": {
|
|
29
|
+
"facts": {
|
|
30
|
+
"paid_minor": 0,
|
|
31
|
+
"due_minor": 6151477
|
|
32
|
+
},
|
|
33
|
+
"supplied_by": "org:eir-gk"
|
|
34
|
+
}
|
|
35
|
+
},
|
|
36
|
+
"assertions": [
|
|
37
|
+
{
|
|
38
|
+
"path": "results.0.outcome",
|
|
39
|
+
"op": "equals",
|
|
40
|
+
"value": "UNDECIDED"
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
"path": "operators_wanted.0",
|
|
44
|
+
"op": "equals",
|
|
45
|
+
"value": ">="
|
|
46
|
+
}
|
|
47
|
+
]
|
|
48
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "no-check-is-not-a-pass",
|
|
3
|
+
"description": "An obligation with no check is unadjudicable, not a pass",
|
|
4
|
+
"input": {
|
|
5
|
+
"laws": [
|
|
6
|
+
{
|
|
7
|
+
"slug": "prose-only",
|
|
8
|
+
"status": "executed",
|
|
9
|
+
"law": {
|
|
10
|
+
"attributes": "Eir Labs",
|
|
11
|
+
"deontic": "obliged",
|
|
12
|
+
"aim": "use commercially reasonable efforts",
|
|
13
|
+
"conditions": "at all times",
|
|
14
|
+
"or_else": "the record states none"
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
],
|
|
18
|
+
"facts": {
|
|
19
|
+
"facts": {},
|
|
20
|
+
"supplied_by": "org:eir-gk"
|
|
21
|
+
}
|
|
22
|
+
},
|
|
23
|
+
"assertions": [
|
|
24
|
+
{
|
|
25
|
+
"path": "results.0.outcome",
|
|
26
|
+
"op": "equals",
|
|
27
|
+
"value": "unadjudicable"
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
"path": "pass",
|
|
31
|
+
"op": "equals",
|
|
32
|
+
"value": false
|
|
33
|
+
}
|
|
34
|
+
]
|
|
35
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "proposed-is-not-in-force",
|
|
3
|
+
"description": "A proposed bearing law is not adjudicated at all",
|
|
4
|
+
"input": {
|
|
5
|
+
"laws": [
|
|
6
|
+
{
|
|
7
|
+
"slug": "not-yet",
|
|
8
|
+
"status": "proposed",
|
|
9
|
+
"bearer": "org:eir-labs",
|
|
10
|
+
"law": {
|
|
11
|
+
"attributes": "Eir Labs Inc.",
|
|
12
|
+
"deontic": "obliged",
|
|
13
|
+
"aim": "pay the FY1 balance",
|
|
14
|
+
"conditions": "by 2027-03-31",
|
|
15
|
+
"or_else": "the GK may invoice interest",
|
|
16
|
+
"debtor": "org:eir-labs",
|
|
17
|
+
"creditor": "org:eir-gk",
|
|
18
|
+
"check": {
|
|
19
|
+
"predicate": "(= a b)",
|
|
20
|
+
"inputs": {
|
|
21
|
+
"a": "x",
|
|
22
|
+
"b": "y"
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
],
|
|
28
|
+
"facts": {
|
|
29
|
+
"facts": {},
|
|
30
|
+
"supplied_by": "org:eir-gk"
|
|
31
|
+
}
|
|
32
|
+
},
|
|
33
|
+
"assertions": [
|
|
34
|
+
{
|
|
35
|
+
"path": "results.0.outcome",
|
|
36
|
+
"op": "equals",
|
|
37
|
+
"value": "not-in-force"
|
|
38
|
+
}
|
|
39
|
+
]
|
|
40
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "unattributed-snapshot-refused",
|
|
3
|
+
"description": "A snapshot naming no supplier is refused: absence declines rather than passes",
|
|
4
|
+
"input": {
|
|
5
|
+
"laws": [
|
|
6
|
+
{
|
|
7
|
+
"slug": "anon",
|
|
8
|
+
"status": "executed",
|
|
9
|
+
"bearer": "org:eir-labs",
|
|
10
|
+
"law": {
|
|
11
|
+
"attributes": "Eir Labs",
|
|
12
|
+
"deontic": "obliged",
|
|
13
|
+
"aim": "pay",
|
|
14
|
+
"conditions": "by then",
|
|
15
|
+
"or_else": "interest",
|
|
16
|
+
"debtor": "org:eir-labs",
|
|
17
|
+
"creditor": "org:eir-gk",
|
|
18
|
+
"check": {
|
|
19
|
+
"predicate": "(= a b)",
|
|
20
|
+
"inputs": {
|
|
21
|
+
"a": "x",
|
|
22
|
+
"b": "y"
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
],
|
|
28
|
+
"facts": {
|
|
29
|
+
"facts": {
|
|
30
|
+
"a": 1,
|
|
31
|
+
"b": 1
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
},
|
|
35
|
+
"assertions": [
|
|
36
|
+
{
|
|
37
|
+
"path": "results.0.outcome",
|
|
38
|
+
"op": "equals",
|
|
39
|
+
"value": "refused"
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
"path": "pass",
|
|
43
|
+
"op": "equals",
|
|
44
|
+
"value": false
|
|
45
|
+
}
|
|
46
|
+
]
|
|
47
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
{
|
|
2
|
+
"slug": "obligation-adjudicate",
|
|
3
|
+
"version": 1,
|
|
4
|
+
"skill_type": "verification",
|
|
5
|
+
"input_type": "bearing-law",
|
|
6
|
+
"output_type": "obligation-adjudication",
|
|
7
|
+
"determinism_ratio": 1.0,
|
|
8
|
+
"permission": {
|
|
9
|
+
"tier": 1
|
|
10
|
+
},
|
|
11
|
+
"description": "The first caller of evaluate(). Takes executed bearing laws and a fact snapshot, evaluates each law's check, and seals one verdict per obligation: PERMIT, DENY, UNDECIDED (with the operators the predicate asked for and the evaluator does not implement), DEAD_NAME (a declared input the snapshot does not supply), unadjudicable (no check), not-in-force (status proposed), or refused (the snapshot came from the debtor — an obligor does not certify its own discharge). It does not widen the operator set: the operators an obligation actually wanted are reported, so the next one implemented is chosen by a real obligation rather than a design guess. Tier 1 because it imports the engine's evaluator."
|
|
12
|
+
}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
// obligation-adjudicate — the first caller of the predicate evaluator. Deterministic, no model.
|
|
2
|
+
//
|
|
3
|
+
// evaluate() has been in this engine with no production call-site: a mechanism with passing tests
|
|
4
|
+
// and nothing wired to it. This chair is the wire. It takes bearing-law records and a fact
|
|
5
|
+
// snapshot, evaluates each law's `check`, and seals one verdict per obligation.
|
|
6
|
+
//
|
|
7
|
+
// It deliberately does NOT widen the operator set. Every obligation whose predicate needs an
|
|
8
|
+
// operator the evaluator lacks comes back UNDECIDED, named, with the operator that was missing —
|
|
9
|
+
// so the next operator to implement is chosen by an obligation that asked for it rather than by
|
|
10
|
+
// a design guess. U is never rounded into a decision; that is the evaluator's own discipline and
|
|
11
|
+
// this chair keeps it.
|
|
12
|
+
//
|
|
13
|
+
// Decisions it makes on its own, and why:
|
|
14
|
+
// - an obligation with NO check is `unadjudicable`, not a pass. A clause the machine cannot
|
|
15
|
+
// decide is prose-tier work and belongs with a person.
|
|
16
|
+
// - a `proposed` bearing law is not adjudicated at all: nothing is in force until it is executed.
|
|
17
|
+
// - an obligor may not certify its own discharge, so this chair refuses to adjudicate a law whose
|
|
18
|
+
// fact snapshot was supplied by the debtor (`facts.supplied_by === law.debtor`).
|
|
19
|
+
import { evaluate, KNOWN_OPERATORS } from "../../dist/src/institution_enforcement.js";
|
|
20
|
+
|
|
21
|
+
/** Operators a predicate names that the evaluator does not implement. Textual, deliberately: the
|
|
22
|
+
* point is to REPORT what an obligation asked for, not to decide it. */
|
|
23
|
+
function missingOperators(predicate) {
|
|
24
|
+
const heads = String(predicate ?? "").match(/\(\s*([^\s()]+)/g) ?? [];
|
|
25
|
+
const named = heads.map((h) => h.replace(/^\(\s*/, ""));
|
|
26
|
+
// The evaluator's own set, imported rather than copied: a copy would keep naming an operator as
|
|
27
|
+
// missing after it was implemented, which is backwards for a field whose whole job is "build this
|
|
28
|
+
// one next". One home, two readers.
|
|
29
|
+
return [...new Set(named.filter((op) => !KNOWN_OPERATORS.has(op)))];
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export default function run(input, context) {
|
|
33
|
+
const up = context && Array.isArray(context.upstream) ? context.upstream : [];
|
|
34
|
+
const laws = input?.laws ?? up.filter((u) => u?.domain_type === "bearing-law").map((u) => u.data) ?? [];
|
|
35
|
+
const snapshot = input?.facts ?? {};
|
|
36
|
+
const facts = snapshot.facts ?? snapshot;
|
|
37
|
+
|
|
38
|
+
const results = [];
|
|
39
|
+
for (const law of laws) {
|
|
40
|
+
const slug = String(law?.slug ?? law?.subject_ref ?? "(unnamed)");
|
|
41
|
+
const status = String(law?.status ?? "");
|
|
42
|
+
const check = law?.law?.check;
|
|
43
|
+
const debtor = law?.law?.debtor ?? law?.bearer;
|
|
44
|
+
|
|
45
|
+
if (status === "proposed") {
|
|
46
|
+
results.push({ obligation: slug, outcome: "not-in-force", why: "status is proposed; nothing is in force until it is executed" });
|
|
47
|
+
continue;
|
|
48
|
+
}
|
|
49
|
+
if (!check || !check.predicate) {
|
|
50
|
+
results.push({ obligation: slug, outcome: "unadjudicable", why: "the law carries no check — a clause the machine cannot decide is a person's" });
|
|
51
|
+
continue;
|
|
52
|
+
}
|
|
53
|
+
// An obligor does not certify its own discharge — and an UNATTRIBUTED snapshot cannot be shown
|
|
54
|
+
// not to come from the debtor, so absence declines rather than passes. A settlement resting on
|
|
55
|
+
// facts nobody stands behind is the case this rule exists for.
|
|
56
|
+
if (!snapshot.supplied_by) {
|
|
57
|
+
results.push({ obligation: slug, outcome: "refused", why: "the fact snapshot names no supplier; an unattributed snapshot cannot be shown not to come from the debtor" });
|
|
58
|
+
continue;
|
|
59
|
+
}
|
|
60
|
+
if (debtor && snapshot.supplied_by === debtor) {
|
|
61
|
+
results.push({ obligation: slug, outcome: "refused", why: `the fact snapshot was supplied by the debtor (${debtor}); an obligor does not certify its own discharge` });
|
|
62
|
+
continue;
|
|
63
|
+
}
|
|
64
|
+
const verdict = evaluate({ predicate: check.predicate, inputs: check.inputs ?? {} }, facts);
|
|
65
|
+
const missing = verdict === "UNDECIDED" ? missingOperators(check.predicate) : [];
|
|
66
|
+
results.push({
|
|
67
|
+
obligation: slug,
|
|
68
|
+
outcome: verdict,
|
|
69
|
+
why: verdict === "DEAD_NAME" ? "a declared input the snapshot does not supply" :
|
|
70
|
+
verdict === "UNDECIDED" ? (missing.length ? `operators the evaluator does not implement: ${missing.join(", ")}` : "the predicate could not be reduced from these facts") :
|
|
71
|
+
"decided from the snapshot",
|
|
72
|
+
needs_operators: missing,
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
const settled = results.filter((r) => r.outcome === "PERMIT" || r.outcome === "DENY");
|
|
77
|
+
const needs_person = results.filter((r) => !["PERMIT", "DENY", "not-in-force"].includes(r.outcome));
|
|
78
|
+
return {
|
|
79
|
+
id: "obligation-adjudication",
|
|
80
|
+
target_ref: String(input?.matter ?? "obligations"),
|
|
81
|
+
// An empty set is not a clean sweep: nothing adjudicated is nothing proved.
|
|
82
|
+
pass: results.length > 0 && needs_person.length === 0,
|
|
83
|
+
checks: results.length
|
|
84
|
+
? results.map((r) => ({ method: "evaluate(check, fact-snapshot)", target_ref: r.obligation, result: `${r.outcome}: ${r.why}` }))
|
|
85
|
+
: [{ method: "evaluate(check, fact-snapshot)", target_ref: "none", result: "no obligations supplied" }],
|
|
86
|
+
results,
|
|
87
|
+
settled: settled.map((r) => r.obligation),
|
|
88
|
+
needs_person: needs_person.map((r) => r.obligation),
|
|
89
|
+
operators_wanted: [...new Set(results.flatMap((r) => r.needs_operators ?? []))],
|
|
90
|
+
};
|
|
91
|
+
}
|