@unson/brainbase-mcp 0.3.1 → 0.4.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 +29 -0
- package/contracts/judgment-dag/digest.json +32 -0
- package/contracts/judgment-dag/fixture.json +21 -0
- package/contracts/judgment-dag/schema.json +80 -0
- package/contracts/judgment-dag/source-lock.json +25 -0
- package/dist/judgment-dag-core.d.ts +113 -0
- package/dist/judgment-dag-core.js +439 -0
- package/dist/judgment-dag.d.ts +8 -0
- package/dist/judgment-dag.js +7 -0
- package/docs/architecture/judgment-dag-core.md +313 -0
- package/docs/management/judgment-dag-milestones.md +143 -0
- package/package.json +22 -2
package/README.md
CHANGED
|
@@ -8,6 +8,35 @@ Ontology 2.0.0は、ローカルファイルへ持ち運べる意味契約に、
|
|
|
8
8
|
|
|
9
9
|
このリポジトリに、社内BrainbaseのUI、セッション実行基盤、xterm転送、ワークフロー管制、SNS運用、ホスト型バックエンド、Infisical設定、雲孫の社内データは含みません。それらは社内版`brainbase-unson`の範囲です。
|
|
10
10
|
|
|
11
|
+
## Judgment DAG公開契約
|
|
12
|
+
|
|
13
|
+
Judgment DAGの型と副作用のない事前検証は、公開`./judgment-dag` subpath(`@unson/brainbase-mcp/judgment-dag`)から利用できます。機械可読の4つの契約ファイルは次のとおりです。
|
|
14
|
+
|
|
15
|
+
- `contracts/judgment-dag/schema.json`
|
|
16
|
+
- `contracts/judgment-dag/fixture.json`
|
|
17
|
+
- `contracts/judgment-dag/source-lock.json`
|
|
18
|
+
- `contracts/judgment-dag/digest.json`
|
|
19
|
+
|
|
20
|
+
最小の検証例:
|
|
21
|
+
|
|
22
|
+
```ts
|
|
23
|
+
import { readFileSync } from 'node:fs';
|
|
24
|
+
import { validateJudgmentDAG } from '@unson/brainbase-mcp/judgment-dag';
|
|
25
|
+
|
|
26
|
+
const fixtureUrl = import.meta.resolve(
|
|
27
|
+
'@unson/brainbase-mcp/contracts/judgment-dag/fixture.json'
|
|
28
|
+
);
|
|
29
|
+
const dag = JSON.parse(readFileSync(new URL(fixtureUrl), 'utf8'));
|
|
30
|
+
const checked = validateJudgmentDAG(dag);
|
|
31
|
+
console.log(checked.execution_order); // deterministic node-ID ascending tie-break
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
`node.depends_on`と`relation: "depends_on"` edgeは完全なmirrorであり、missing・cycle・reverse-layer・scope不一致は実行前に拒否されます。
|
|
35
|
+
|
|
36
|
+
配布済みconsumerは、installed package rootから`source-lock.sources`と`digest.files`の各package-relative pathをSHA-256で再計算し、`digest.files`をpath順に`path + NUL + sha256 + LF`で連結したaggregate digestまでreadbackします。`source-lock`はimmutableな`repository`と`accepted_base_commit`を示し、`src/`のような非同梱ファイルはhash対象にしません。
|
|
37
|
+
|
|
38
|
+
この契約はrunner、artifact、execution log、replay/evaluation、Execution/Evaluation mutation protectionを含まないJ0-2非目標のcore sliceです。
|
|
39
|
+
|
|
11
40
|
## マニュアル
|
|
12
41
|
|
|
13
42
|
Read the public onboarding manual at [brainbase.pages.dev](https://brainbase.pages.dev/). It guides users through five phases: choose one real use case, register approved work context, prove the first value, add only necessary sources, and operationalize Skills, routines, and MCP.
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
{
|
|
2
|
+
"contract": "judgment-dag-core",
|
|
3
|
+
"algorithm": "sha256",
|
|
4
|
+
"canonicalization": "UTF-8 lines sorted by path as path + NUL + sha256 + LF",
|
|
5
|
+
"files": [
|
|
6
|
+
{
|
|
7
|
+
"path": "contracts/judgment-dag/fixture.json",
|
|
8
|
+
"sha256": "c191ea129c55c97d131998698a79f656c900150fb97abb4715aa44d2abca39c5"
|
|
9
|
+
},
|
|
10
|
+
{
|
|
11
|
+
"path": "contracts/judgment-dag/schema.json",
|
|
12
|
+
"sha256": "af783617e76dc3cdc878210311821f9b0e982b31102ab6bf46ad726d5423745d"
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
"path": "contracts/judgment-dag/source-lock.json",
|
|
16
|
+
"sha256": "c7b3020fe3952d90bd8ed991f613be66c0798983bb6cc2285a9aefff7ab2f0e9"
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
"path": "docs/architecture/judgment-dag-core.md",
|
|
20
|
+
"sha256": "24305aaa97df9c734d468c49f52784e94b77a4f506bae41d482bee05625d7e2a"
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
"path": "docs/management/judgment-dag-milestones.md",
|
|
24
|
+
"sha256": "ef51313f33de64f702fd6c86012984bd70cf99eeca5b4f4cfc27f6cb266172bd"
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
"path": "README.md",
|
|
28
|
+
"sha256": "7cd5721b9a932f5b43dd01557dfbcd8ea73563d5d23337fabdd322367d678e28"
|
|
29
|
+
}
|
|
30
|
+
],
|
|
31
|
+
"digest": "fd5587b97cf343290c7d6c78f365d2d78bef668b04578e5ab55c67886ba0e827"
|
|
32
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
{
|
|
2
|
+
"id": "j0-valid",
|
|
3
|
+
"version": "2026-08-20.1",
|
|
4
|
+
"nodes": [
|
|
5
|
+
{ "id": "context.customer", "node_type": "observation", "layer": "context", "scope": { "type": "project", "id": "project-j0-fixture" }, "version": "1.0.0", "description": "customer observation", "depends_on": [], "input_contract": "fixture.input.v1", "output_contract": "fixture.output.v1", "runner_type": "deterministic", "authority": ["fixture-owner"], "confidence": 1, "valid_from": "2026-08-20T00:00:00.000Z", "valid_to": null, "provenance": [{ "source": "j0-fixture", "reference": "context.customer" }], "evaluation": { "criteria": ["context.customer is evaluated"] } },
|
|
6
|
+
{ "id": "context.account", "node_type": "observation", "layer": "context", "scope": { "type": "project", "id": "project-j0-fixture" }, "version": "1.0.0", "description": "account observation", "depends_on": [], "input_contract": "fixture.input.v1", "output_contract": "fixture.output.v1", "runner_type": "deterministic", "authority": ["fixture-owner"], "confidence": 1, "valid_from": "2026-08-20T00:00:00.000Z", "valid_to": null, "provenance": [{ "source": "j0-fixture", "reference": "context.account" }], "evaluation": { "criteria": ["context.account is evaluated"] } },
|
|
7
|
+
{ "id": "judgment.fit", "node_type": "judgment", "layer": "judgment", "scope": { "type": "project", "id": "project-j0-fixture" }, "version": "1.0.0", "description": "fit judgment", "depends_on": ["context.customer", "context.account"], "input_contract": "fixture.input.v1", "output_contract": "fixture.output.v1", "runner_type": "deterministic", "authority": ["fixture-owner"], "confidence": 1, "valid_from": "2026-08-20T00:00:00.000Z", "valid_to": null, "provenance": [{ "source": "j0-fixture", "reference": "judgment.fit" }], "evaluation": { "criteria": ["judgment.fit is evaluated"] } },
|
|
8
|
+
{ "id": "resource.scope", "node_type": "resource", "layer": "resource", "scope": { "type": "project", "id": "project-j0-fixture" }, "version": "1.0.0", "description": "resource scope", "depends_on": ["judgment.fit"], "input_contract": "fixture.input.v1", "output_contract": "fixture.output.v1", "runner_type": "deterministic", "authority": ["fixture-owner"], "confidence": 1, "valid_from": "2026-08-20T00:00:00.000Z", "valid_to": null, "provenance": [{ "source": "j0-fixture", "reference": "resource.scope" }], "evaluation": { "criteria": ["resource.scope is evaluated"] } },
|
|
9
|
+
{ "id": "execution.proposal", "node_type": "execution", "layer": "execution", "scope": { "type": "project", "id": "project-j0-fixture" }, "version": "1.0.0", "description": "execution proposal", "depends_on": ["resource.scope"], "input_contract": "fixture.input.v1", "output_contract": "fixture.output.v1", "runner_type": "deterministic", "authority": ["fixture-owner"], "confidence": 1, "valid_from": "2026-08-20T00:00:00.000Z", "valid_to": null, "provenance": [{ "source": "j0-fixture", "reference": "execution.proposal" }], "evaluation": { "criteria": ["execution.proposal is evaluated"] } },
|
|
10
|
+
{ "id": "execution.outcome", "node_type": "outcome", "layer": "execution", "scope": { "type": "project", "id": "project-j0-fixture" }, "version": "1.0.0", "description": "execution outcome", "depends_on": ["execution.proposal"], "input_contract": "fixture.input.v1", "output_contract": "fixture.output.v1", "runner_type": "deterministic", "authority": ["fixture-owner"], "confidence": 1, "valid_from": "2026-08-20T00:00:00.000Z", "valid_to": null, "provenance": [{ "source": "j0-fixture", "reference": "execution.outcome" }], "evaluation": { "criteria": ["execution.outcome is evaluated"] } },
|
|
11
|
+
{ "id": "evaluation.result", "node_type": "evaluation", "layer": "evaluation", "scope": { "type": "project", "id": "project-j0-fixture" }, "version": "1.0.0", "description": "evaluation result", "depends_on": ["execution.outcome"], "input_contract": "fixture.input.v1", "output_contract": "fixture.output.v1", "runner_type": "deterministic", "authority": ["fixture-owner"], "confidence": 1, "valid_from": "2026-08-20T00:00:00.000Z", "valid_to": null, "provenance": [{ "source": "j0-fixture", "reference": "evaluation.result" }], "evaluation": { "criteria": ["evaluation.result is evaluated"] } }
|
|
12
|
+
],
|
|
13
|
+
"edges": [
|
|
14
|
+
{ "from": "context.customer", "to": "judgment.fit", "relation": "depends_on" },
|
|
15
|
+
{ "from": "context.account", "to": "judgment.fit", "relation": "depends_on" },
|
|
16
|
+
{ "from": "judgment.fit", "to": "resource.scope", "relation": "depends_on" },
|
|
17
|
+
{ "from": "resource.scope", "to": "execution.proposal", "relation": "depends_on" },
|
|
18
|
+
{ "from": "execution.proposal", "to": "execution.outcome", "relation": "depends_on" },
|
|
19
|
+
{ "from": "execution.outcome", "to": "evaluation.result", "relation": "depends_on" }
|
|
20
|
+
]
|
|
21
|
+
}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"$id": "https://github.com/Unson-LLC/brainbase/blob/develop/contracts/judgment-dag/schema.json",
|
|
4
|
+
"title": "Brainbase Judgment DAG core contract",
|
|
5
|
+
"type": "object",
|
|
6
|
+
"additionalProperties": false,
|
|
7
|
+
"required": ["id", "version", "nodes", "edges"],
|
|
8
|
+
"properties": {
|
|
9
|
+
"id": { "$ref": "#/$defs/identifier" },
|
|
10
|
+
"version": { "type": "string", "minLength": 1, "pattern": "\\S" },
|
|
11
|
+
"nodes": { "type": "array", "items": { "$ref": "#/$defs/node" } },
|
|
12
|
+
"edges": { "type": "array", "items": { "$ref": "#/$defs/edge" } }
|
|
13
|
+
},
|
|
14
|
+
"$defs": {
|
|
15
|
+
"identifier": {
|
|
16
|
+
"type": "string",
|
|
17
|
+
"minLength": 1,
|
|
18
|
+
"pattern": "^(?![\\s\\S]*[\\u0000-\\u001F\\u007F])(?=[\\s\\S]*\\S)[\\s\\S]+$"
|
|
19
|
+
},
|
|
20
|
+
"metadata": {
|
|
21
|
+
"anyOf": [
|
|
22
|
+
{ "type": "string" },
|
|
23
|
+
{ "type": "number" },
|
|
24
|
+
{ "type": "boolean" },
|
|
25
|
+
{ "type": "null" },
|
|
26
|
+
{ "type": "array", "items": { "$ref": "#/$defs/metadata" } },
|
|
27
|
+
{ "type": "object", "additionalProperties": { "$ref": "#/$defs/metadata" } }
|
|
28
|
+
]
|
|
29
|
+
},
|
|
30
|
+
"scope": {
|
|
31
|
+
"type": "object",
|
|
32
|
+
"additionalProperties": false,
|
|
33
|
+
"required": ["type", "id"],
|
|
34
|
+
"properties": {
|
|
35
|
+
"type": { "enum": ["personal", "project", "organization"] },
|
|
36
|
+
"id": { "$ref": "#/$defs/identifier" }
|
|
37
|
+
}
|
|
38
|
+
},
|
|
39
|
+
"node": {
|
|
40
|
+
"type": "object",
|
|
41
|
+
"additionalProperties": false,
|
|
42
|
+
"required": ["id", "node_type", "layer", "scope", "version", "description", "depends_on", "input_contract", "output_contract", "runner_type"],
|
|
43
|
+
"properties": {
|
|
44
|
+
"id": { "$ref": "#/$defs/identifier" },
|
|
45
|
+
"node_type": { "enum": ["observation", "judgment", "decision", "resource", "execution", "outcome", "evaluation"] },
|
|
46
|
+
"layer": { "enum": ["context", "judgment", "resource", "execution", "evaluation"] },
|
|
47
|
+
"scope": { "$ref": "#/$defs/scope" },
|
|
48
|
+
"version": { "type": "string", "minLength": 1, "pattern": "\\S" },
|
|
49
|
+
"description": { "type": "string", "minLength": 1, "pattern": "\\S" },
|
|
50
|
+
"depends_on": { "type": "array", "items": { "$ref": "#/$defs/identifier" }, "uniqueItems": true },
|
|
51
|
+
"input_contract": { "type": "string", "minLength": 1, "pattern": "\\S" },
|
|
52
|
+
"output_contract": { "type": "string", "minLength": 1, "pattern": "\\S" },
|
|
53
|
+
"runner_type": { "enum": ["deterministic", "agent", "human", "committee", "external"] },
|
|
54
|
+
"authority": { "$ref": "#/$defs/metadata" },
|
|
55
|
+
"confidence": { "type": "number", "minimum": 0, "maximum": 1 },
|
|
56
|
+
"valid_from": { "type": ["string", "null"] },
|
|
57
|
+
"valid_to": { "type": ["string", "null"] },
|
|
58
|
+
"provenance": { "type": "array", "items": { "$ref": "#/$defs/metadata" } },
|
|
59
|
+
"evaluation": { "$ref": "#/$defs/metadata" }
|
|
60
|
+
},
|
|
61
|
+
"allOf": [
|
|
62
|
+
{ "if": { "properties": { "node_type": { "const": "observation" } } }, "then": { "properties": { "layer": { "const": "context" } } } },
|
|
63
|
+
{ "if": { "properties": { "node_type": { "enum": ["judgment", "decision"] } } }, "then": { "properties": { "layer": { "const": "judgment" } } } },
|
|
64
|
+
{ "if": { "properties": { "node_type": { "const": "resource" } } }, "then": { "properties": { "layer": { "const": "resource" } } } },
|
|
65
|
+
{ "if": { "properties": { "node_type": { "enum": ["execution", "outcome"] } } }, "then": { "properties": { "layer": { "const": "execution" } } } },
|
|
66
|
+
{ "if": { "properties": { "node_type": { "const": "evaluation" } } }, "then": { "properties": { "layer": { "const": "evaluation" } } } }
|
|
67
|
+
]
|
|
68
|
+
},
|
|
69
|
+
"edge": {
|
|
70
|
+
"type": "object",
|
|
71
|
+
"additionalProperties": false,
|
|
72
|
+
"required": ["from", "to", "relation"],
|
|
73
|
+
"properties": {
|
|
74
|
+
"from": { "$ref": "#/$defs/identifier" },
|
|
75
|
+
"to": { "$ref": "#/$defs/identifier" },
|
|
76
|
+
"relation": { "enum": ["depends_on", "supports", "contradicts", "gates", "supersedes", "produces", "evaluated_by", "triggers"] }
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
|
3
|
+
"contract": "judgment-dag-core",
|
|
4
|
+
"repository": "https://github.com/Unson-LLC/brainbase",
|
|
5
|
+
"status": "accepted",
|
|
6
|
+
"accepted_base_commit": "7e5d5693f988f4ba84072c5910ef32f0e70871e1",
|
|
7
|
+
"sources": [
|
|
8
|
+
{
|
|
9
|
+
"kind": "architecture",
|
|
10
|
+
"path": "docs/architecture/judgment-dag-core.md",
|
|
11
|
+
"sha256": "24305aaa97df9c734d468c49f52784e94b77a4f506bae41d482bee05625d7e2a"
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
"kind": "milestones",
|
|
15
|
+
"path": "docs/management/judgment-dag-milestones.md",
|
|
16
|
+
"sha256": "ef51313f33de64f702fd6c86012984bd70cf99eeca5b4f4cfc27f6cb266172bd"
|
|
17
|
+
}
|
|
18
|
+
],
|
|
19
|
+
"notes": [
|
|
20
|
+
"Outcome is produced and recorded by the Execution DAG and maps to the execution layer.",
|
|
21
|
+
"This J0 contract slice does not implement runner, artifact, execution-log, replay, evaluation, or mutation protection; those remain J0-2 non-goals and unverified.",
|
|
22
|
+
"Public DAG identifiers reject C0 and DEL control characters so dependency pair keys cannot collide.",
|
|
23
|
+
"J0 multi-tenancy evidence is limited to exact scope equality; cross-scope authorization, runtime, secret, database, and deployment are non-goals."
|
|
24
|
+
]
|
|
25
|
+
}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared semantic contract for the local Judgment DAG kernel.
|
|
3
|
+
*
|
|
4
|
+
* This module deliberately contains only the contract and preflight checks.
|
|
5
|
+
* Runners, artifact stores, replay, and public MCP/CLI adapters belong to
|
|
6
|
+
* later milestones and must not be coupled to this core surface.
|
|
7
|
+
*/
|
|
8
|
+
export declare const JUDGMENT_DAG_NODE_TYPES: readonly ["observation", "judgment", "decision", "resource", "execution", "outcome", "evaluation"];
|
|
9
|
+
export type JudgmentDAGNodeType = (typeof JUDGMENT_DAG_NODE_TYPES)[number];
|
|
10
|
+
export declare const JUDGMENT_DAG_LAYERS: readonly ["context", "judgment", "resource", "execution", "evaluation"];
|
|
11
|
+
export type JudgmentDAGLayer = (typeof JUDGMENT_DAG_LAYERS)[number];
|
|
12
|
+
/**
|
|
13
|
+
* The accepted ontology has five layers. An outcome is the result produced
|
|
14
|
+
* by the Execution DAG; it is not a sixth layer of its own.
|
|
15
|
+
*/
|
|
16
|
+
export declare const JUDGMENT_DAG_NODE_TYPE_TO_LAYER: Readonly<{
|
|
17
|
+
readonly observation: "context";
|
|
18
|
+
readonly judgment: "judgment";
|
|
19
|
+
readonly decision: "judgment";
|
|
20
|
+
readonly resource: "resource";
|
|
21
|
+
readonly execution: "execution";
|
|
22
|
+
readonly outcome: "execution";
|
|
23
|
+
readonly evaluation: "evaluation";
|
|
24
|
+
}>;
|
|
25
|
+
export declare const JUDGMENT_DAG_SCOPE_TYPES: readonly ["personal", "project", "organization"];
|
|
26
|
+
export type JudgmentDAGScopeType = (typeof JUDGMENT_DAG_SCOPE_TYPES)[number];
|
|
27
|
+
export declare const JUDGMENT_DAG_RUNNER_TYPES: readonly ["deterministic", "agent", "human", "committee", "external"];
|
|
28
|
+
export type JudgmentDAGRunnerType = (typeof JUDGMENT_DAG_RUNNER_TYPES)[number];
|
|
29
|
+
export declare const JUDGMENT_DAG_EDGE_RELATIONS: readonly ["depends_on", "supports", "contradicts", "gates", "supersedes", "produces", "evaluated_by", "triggers"];
|
|
30
|
+
export type JudgmentDAGEdgeRelation = (typeof JUDGMENT_DAG_EDGE_RELATIONS)[number];
|
|
31
|
+
/**
|
|
32
|
+
* Exact JSON object keys accepted by the runtime contract. Metadata records
|
|
33
|
+
* are intentionally not listed here because their nested keys are arbitrary.
|
|
34
|
+
*/
|
|
35
|
+
export declare const JUDGMENT_DAG_ALLOWED_KEYS: Readonly<{
|
|
36
|
+
readonly root: readonly ["id", "version", "nodes", "edges"];
|
|
37
|
+
readonly node: readonly ["id", "node_type", "layer", "scope", "version", "description", "depends_on", "input_contract", "output_contract", "runner_type", "authority", "confidence", "valid_from", "valid_to", "provenance", "evaluation"];
|
|
38
|
+
readonly scope: readonly ["type", "id"];
|
|
39
|
+
readonly edge: readonly ["from", "to", "relation"];
|
|
40
|
+
}>;
|
|
41
|
+
export type JudgmentDAGMetadata = string | number | boolean | null | readonly JudgmentDAGMetadata[] | {
|
|
42
|
+
readonly [key: string]: JudgmentDAGMetadata;
|
|
43
|
+
};
|
|
44
|
+
export interface JudgmentDAGScope {
|
|
45
|
+
readonly type: JudgmentDAGScopeType;
|
|
46
|
+
readonly id: string;
|
|
47
|
+
}
|
|
48
|
+
export interface JudgmentDAGNode {
|
|
49
|
+
readonly id: string;
|
|
50
|
+
readonly node_type: JudgmentDAGNodeType;
|
|
51
|
+
readonly layer: JudgmentDAGLayer;
|
|
52
|
+
readonly scope: JudgmentDAGScope;
|
|
53
|
+
readonly version: string;
|
|
54
|
+
readonly description: string;
|
|
55
|
+
readonly depends_on: readonly string[];
|
|
56
|
+
readonly input_contract: string;
|
|
57
|
+
readonly output_contract: string;
|
|
58
|
+
readonly runner_type: JudgmentDAGRunnerType;
|
|
59
|
+
readonly authority?: JudgmentDAGMetadata;
|
|
60
|
+
readonly confidence?: number;
|
|
61
|
+
readonly valid_from?: string | null;
|
|
62
|
+
readonly valid_to?: string | null;
|
|
63
|
+
readonly provenance?: readonly JudgmentDAGMetadata[];
|
|
64
|
+
readonly evaluation?: JudgmentDAGMetadata | null;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* For a `depends_on` relation, `from` is the dependency and `to` is the
|
|
68
|
+
* dependent node. This keeps the edge direction aligned with execution flow.
|
|
69
|
+
*/
|
|
70
|
+
export interface JudgmentDAGEdge {
|
|
71
|
+
readonly from: string;
|
|
72
|
+
readonly to: string;
|
|
73
|
+
readonly relation: JudgmentDAGEdgeRelation;
|
|
74
|
+
}
|
|
75
|
+
export interface JudgmentDAG {
|
|
76
|
+
readonly id: string;
|
|
77
|
+
readonly version: string;
|
|
78
|
+
readonly nodes: readonly JudgmentDAGNode[];
|
|
79
|
+
readonly edges: readonly JudgmentDAGEdge[];
|
|
80
|
+
}
|
|
81
|
+
export type JudgmentDAGValidationCode = 'invalid_contract' | 'duplicate_node' | 'missing_dependency' | 'scope_boundary_violation' | 'reverse_layer_dependency' | 'cycle';
|
|
82
|
+
export interface JudgmentDAGValidationDetails {
|
|
83
|
+
readonly node_id?: string;
|
|
84
|
+
readonly dependency_id?: string;
|
|
85
|
+
readonly node_layer?: JudgmentDAGLayer;
|
|
86
|
+
readonly dependency_layer?: JudgmentDAGLayer;
|
|
87
|
+
readonly cycle?: readonly string[];
|
|
88
|
+
}
|
|
89
|
+
export declare class JudgmentDAGValidationError extends Error {
|
|
90
|
+
readonly code: JudgmentDAGValidationCode;
|
|
91
|
+
readonly node_id?: string;
|
|
92
|
+
readonly dependency_id?: string;
|
|
93
|
+
readonly node_layer?: JudgmentDAGLayer;
|
|
94
|
+
readonly dependency_layer?: JudgmentDAGLayer;
|
|
95
|
+
readonly cycle?: readonly string[];
|
|
96
|
+
constructor(code: JudgmentDAGValidationCode, message: string, details?: JudgmentDAGValidationDetails);
|
|
97
|
+
}
|
|
98
|
+
export interface JudgmentDAGValidationResult {
|
|
99
|
+
readonly valid: true;
|
|
100
|
+
readonly dag_id: string;
|
|
101
|
+
readonly dag_version: string;
|
|
102
|
+
readonly execution_order: readonly string[];
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Validate a DAG before any runner can execute it.
|
|
106
|
+
*
|
|
107
|
+
* The input is never mutated. Dependencies declared on nodes and explicit
|
|
108
|
+
* `depends_on` edges are both checked. They are two required representations
|
|
109
|
+
* of the same dependency topology and must be exact mirrors; other edge
|
|
110
|
+
* relations are not part of the execution topology.
|
|
111
|
+
*/
|
|
112
|
+
export declare function validateJudgmentDAG(value: unknown): JudgmentDAGValidationResult;
|
|
113
|
+
export declare function assertValidJudgmentDAG(value: unknown): asserts value is JudgmentDAG;
|
|
@@ -0,0 +1,439 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared semantic contract for the local Judgment DAG kernel.
|
|
3
|
+
*
|
|
4
|
+
* This module deliberately contains only the contract and preflight checks.
|
|
5
|
+
* Runners, artifact stores, replay, and public MCP/CLI adapters belong to
|
|
6
|
+
* later milestones and must not be coupled to this core surface.
|
|
7
|
+
*/
|
|
8
|
+
export const JUDGMENT_DAG_NODE_TYPES = Object.freeze([
|
|
9
|
+
'observation',
|
|
10
|
+
'judgment',
|
|
11
|
+
'decision',
|
|
12
|
+
'resource',
|
|
13
|
+
'execution',
|
|
14
|
+
'outcome',
|
|
15
|
+
'evaluation'
|
|
16
|
+
]);
|
|
17
|
+
export const JUDGMENT_DAG_LAYERS = Object.freeze([
|
|
18
|
+
'context',
|
|
19
|
+
'judgment',
|
|
20
|
+
'resource',
|
|
21
|
+
'execution',
|
|
22
|
+
'evaluation'
|
|
23
|
+
]);
|
|
24
|
+
/**
|
|
25
|
+
* The accepted ontology has five layers. An outcome is the result produced
|
|
26
|
+
* by the Execution DAG; it is not a sixth layer of its own.
|
|
27
|
+
*/
|
|
28
|
+
export const JUDGMENT_DAG_NODE_TYPE_TO_LAYER = Object.freeze({
|
|
29
|
+
observation: 'context',
|
|
30
|
+
judgment: 'judgment',
|
|
31
|
+
decision: 'judgment',
|
|
32
|
+
resource: 'resource',
|
|
33
|
+
execution: 'execution',
|
|
34
|
+
outcome: 'execution',
|
|
35
|
+
evaluation: 'evaluation'
|
|
36
|
+
});
|
|
37
|
+
export const JUDGMENT_DAG_SCOPE_TYPES = Object.freeze([
|
|
38
|
+
'personal',
|
|
39
|
+
'project',
|
|
40
|
+
'organization'
|
|
41
|
+
]);
|
|
42
|
+
export const JUDGMENT_DAG_RUNNER_TYPES = Object.freeze([
|
|
43
|
+
'deterministic',
|
|
44
|
+
'agent',
|
|
45
|
+
'human',
|
|
46
|
+
'committee',
|
|
47
|
+
'external'
|
|
48
|
+
]);
|
|
49
|
+
export const JUDGMENT_DAG_EDGE_RELATIONS = Object.freeze([
|
|
50
|
+
'depends_on',
|
|
51
|
+
'supports',
|
|
52
|
+
'contradicts',
|
|
53
|
+
'gates',
|
|
54
|
+
'supersedes',
|
|
55
|
+
'produces',
|
|
56
|
+
'evaluated_by',
|
|
57
|
+
'triggers'
|
|
58
|
+
]);
|
|
59
|
+
/**
|
|
60
|
+
* Exact JSON object keys accepted by the runtime contract. Metadata records
|
|
61
|
+
* are intentionally not listed here because their nested keys are arbitrary.
|
|
62
|
+
*/
|
|
63
|
+
export const JUDGMENT_DAG_ALLOWED_KEYS = Object.freeze({
|
|
64
|
+
root: Object.freeze(['id', 'version', 'nodes', 'edges']),
|
|
65
|
+
node: Object.freeze([
|
|
66
|
+
'id',
|
|
67
|
+
'node_type',
|
|
68
|
+
'layer',
|
|
69
|
+
'scope',
|
|
70
|
+
'version',
|
|
71
|
+
'description',
|
|
72
|
+
'depends_on',
|
|
73
|
+
'input_contract',
|
|
74
|
+
'output_contract',
|
|
75
|
+
'runner_type',
|
|
76
|
+
'authority',
|
|
77
|
+
'confidence',
|
|
78
|
+
'valid_from',
|
|
79
|
+
'valid_to',
|
|
80
|
+
'provenance',
|
|
81
|
+
'evaluation'
|
|
82
|
+
]),
|
|
83
|
+
scope: Object.freeze(['type', 'id']),
|
|
84
|
+
edge: Object.freeze(['from', 'to', 'relation'])
|
|
85
|
+
});
|
|
86
|
+
export class JudgmentDAGValidationError extends Error {
|
|
87
|
+
code;
|
|
88
|
+
node_id;
|
|
89
|
+
dependency_id;
|
|
90
|
+
node_layer;
|
|
91
|
+
dependency_layer;
|
|
92
|
+
cycle;
|
|
93
|
+
constructor(code, message, details = {}) {
|
|
94
|
+
super(message);
|
|
95
|
+
this.name = 'JudgmentDAGValidationError';
|
|
96
|
+
this.code = code;
|
|
97
|
+
this.node_id = details.node_id;
|
|
98
|
+
this.dependency_id = details.dependency_id;
|
|
99
|
+
this.node_layer = details.node_layer;
|
|
100
|
+
this.dependency_layer = details.dependency_layer;
|
|
101
|
+
this.cycle = details.cycle;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
const LAYER_INDEX = {
|
|
105
|
+
context: 0,
|
|
106
|
+
judgment: 1,
|
|
107
|
+
resource: 2,
|
|
108
|
+
execution: 3,
|
|
109
|
+
evaluation: 4
|
|
110
|
+
};
|
|
111
|
+
function isRecord(value) {
|
|
112
|
+
return value !== null && typeof value === 'object' && !Array.isArray(value);
|
|
113
|
+
}
|
|
114
|
+
function isString(value) {
|
|
115
|
+
return typeof value === 'string';
|
|
116
|
+
}
|
|
117
|
+
function isNonEmptyString(value) {
|
|
118
|
+
return isString(value) && value.trim().length > 0;
|
|
119
|
+
}
|
|
120
|
+
function isSafeIdentifier(value) {
|
|
121
|
+
return isNonEmptyString(value) && !/[\u0000-\u001F\u007F]/u.test(value);
|
|
122
|
+
}
|
|
123
|
+
function isOneOf(values, value) {
|
|
124
|
+
return isString(value) && values.includes(value);
|
|
125
|
+
}
|
|
126
|
+
function invalidContract(message) {
|
|
127
|
+
throw new JudgmentDAGValidationError('invalid_contract', message);
|
|
128
|
+
}
|
|
129
|
+
function requireRecord(value, path) {
|
|
130
|
+
if (!isRecord(value)) {
|
|
131
|
+
invalidContract(`${path} must be an object`);
|
|
132
|
+
}
|
|
133
|
+
return value;
|
|
134
|
+
}
|
|
135
|
+
function requireExactKeys(value, allowedKeys, path) {
|
|
136
|
+
for (const key of Object.keys(value)) {
|
|
137
|
+
if (!allowedKeys.includes(key)) {
|
|
138
|
+
invalidContract(`${path}.${key} is not an allowed contract field`);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
function requireNonEmptyString(value, path) {
|
|
143
|
+
if (!isNonEmptyString(value)) {
|
|
144
|
+
invalidContract(`${path} must be a non-empty string`);
|
|
145
|
+
}
|
|
146
|
+
return value;
|
|
147
|
+
}
|
|
148
|
+
function requireIdentifier(value, path) {
|
|
149
|
+
if (!isSafeIdentifier(value)) {
|
|
150
|
+
invalidContract(`${path} must be a non-empty string without control characters`);
|
|
151
|
+
}
|
|
152
|
+
return value;
|
|
153
|
+
}
|
|
154
|
+
function requireArray(value, path) {
|
|
155
|
+
if (!Array.isArray(value)) {
|
|
156
|
+
invalidContract(`${path} must be an array`);
|
|
157
|
+
}
|
|
158
|
+
return value;
|
|
159
|
+
}
|
|
160
|
+
function validateMetadata(value, path, active = new Set()) {
|
|
161
|
+
if (value === null || typeof value === 'string' || typeof value === 'boolean') {
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
164
|
+
if (typeof value === 'number') {
|
|
165
|
+
if (Number.isFinite(value)) {
|
|
166
|
+
return;
|
|
167
|
+
}
|
|
168
|
+
invalidContract(`${path} must contain only finite JSON numbers`);
|
|
169
|
+
}
|
|
170
|
+
if (typeof value !== 'object') {
|
|
171
|
+
invalidContract(`${path} must contain JSON-compatible metadata`);
|
|
172
|
+
}
|
|
173
|
+
const objectValue = value;
|
|
174
|
+
if (active.has(objectValue)) {
|
|
175
|
+
invalidContract(`${path} must not contain cyclic metadata`);
|
|
176
|
+
}
|
|
177
|
+
active.add(objectValue);
|
|
178
|
+
if (Array.isArray(value)) {
|
|
179
|
+
for (let index = 0; index < value.length; index += 1) {
|
|
180
|
+
if (!(index in value)) {
|
|
181
|
+
invalidContract(`${path}[${index}] must be defined`);
|
|
182
|
+
}
|
|
183
|
+
validateMetadata(value[index], `${path}[${index}]`, active);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
else {
|
|
187
|
+
const prototype = Object.getPrototypeOf(value);
|
|
188
|
+
if (prototype !== Object.prototype && prototype !== null) {
|
|
189
|
+
invalidContract(`${path} must contain only plain metadata objects`);
|
|
190
|
+
}
|
|
191
|
+
for (const [key, child] of Object.entries(value)) {
|
|
192
|
+
validateMetadata(child, `${path}.${key}`, active);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
active.delete(objectValue);
|
|
196
|
+
}
|
|
197
|
+
function validateNode(value, index) {
|
|
198
|
+
const path = `nodes[${index}]`;
|
|
199
|
+
const node = requireRecord(value, path);
|
|
200
|
+
requireExactKeys(node, JUDGMENT_DAG_ALLOWED_KEYS.node, path);
|
|
201
|
+
const nodeType = node.node_type;
|
|
202
|
+
const layer = node.layer;
|
|
203
|
+
const runnerType = node.runner_type;
|
|
204
|
+
const scope = requireRecord(node.scope, `${path}.scope`);
|
|
205
|
+
requireExactKeys(scope, JUDGMENT_DAG_ALLOWED_KEYS.scope, `${path}.scope`);
|
|
206
|
+
if (!isOneOf(JUDGMENT_DAG_NODE_TYPES, nodeType)) {
|
|
207
|
+
invalidContract(`${path}.node_type is not a supported node type`);
|
|
208
|
+
}
|
|
209
|
+
if (!isOneOf(JUDGMENT_DAG_LAYERS, layer)) {
|
|
210
|
+
invalidContract(`${path}.layer is not a supported layer`);
|
|
211
|
+
}
|
|
212
|
+
if (!isOneOf(JUDGMENT_DAG_RUNNER_TYPES, runnerType)) {
|
|
213
|
+
invalidContract(`${path}.runner_type is not a supported runner type`);
|
|
214
|
+
}
|
|
215
|
+
if (!isOneOf(JUDGMENT_DAG_SCOPE_TYPES, scope.type)) {
|
|
216
|
+
invalidContract(`${path}.scope.type is not a supported scope type`);
|
|
217
|
+
}
|
|
218
|
+
if (JUDGMENT_DAG_NODE_TYPE_TO_LAYER[nodeType] !== layer) {
|
|
219
|
+
invalidContract(`${path}.layer does not match ${path}.node_type`);
|
|
220
|
+
}
|
|
221
|
+
requireIdentifier(node.id, `${path}.id`);
|
|
222
|
+
requireIdentifier(scope.id, `${path}.scope.id`);
|
|
223
|
+
requireNonEmptyString(node.version, `${path}.version`);
|
|
224
|
+
requireNonEmptyString(node.description, `${path}.description`);
|
|
225
|
+
requireNonEmptyString(node.input_contract, `${path}.input_contract`);
|
|
226
|
+
requireNonEmptyString(node.output_contract, `${path}.output_contract`);
|
|
227
|
+
const dependencies = requireArray(node.depends_on, `${path}.depends_on`);
|
|
228
|
+
for (let index = 0; index < dependencies.length; index += 1) {
|
|
229
|
+
requireIdentifier(dependencies[index], `${path}.depends_on[${index}]`);
|
|
230
|
+
}
|
|
231
|
+
if (new Set(dependencies).size !== dependencies.length) {
|
|
232
|
+
invalidContract(`${path}.depends_on must not contain duplicate node IDs`);
|
|
233
|
+
}
|
|
234
|
+
if (node.confidence !== undefined &&
|
|
235
|
+
(typeof node.confidence !== 'number' || !Number.isFinite(node.confidence) ||
|
|
236
|
+
node.confidence < 0 || node.confidence > 1)) {
|
|
237
|
+
invalidContract(`${path}.confidence must be a number between 0 and 1`);
|
|
238
|
+
}
|
|
239
|
+
for (const field of ['valid_from', 'valid_to']) {
|
|
240
|
+
if (node[field] !== undefined && node[field] !== null && !isString(node[field])) {
|
|
241
|
+
invalidContract(`${path}.${field} must be a string or null`);
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
if (node.provenance !== undefined && !Array.isArray(node.provenance)) {
|
|
245
|
+
invalidContract(`${path}.provenance must be an array`);
|
|
246
|
+
}
|
|
247
|
+
if (node.authority !== undefined) {
|
|
248
|
+
validateMetadata(node.authority, `${path}.authority`);
|
|
249
|
+
}
|
|
250
|
+
if (node.provenance !== undefined) {
|
|
251
|
+
validateMetadata(node.provenance, `${path}.provenance`);
|
|
252
|
+
}
|
|
253
|
+
if (node.evaluation !== undefined) {
|
|
254
|
+
validateMetadata(node.evaluation, `${path}.evaluation`);
|
|
255
|
+
}
|
|
256
|
+
return node;
|
|
257
|
+
}
|
|
258
|
+
function validateEdge(value, index, nodeById) {
|
|
259
|
+
const path = `edges[${index}]`;
|
|
260
|
+
const edge = requireRecord(value, path);
|
|
261
|
+
requireExactKeys(edge, JUDGMENT_DAG_ALLOWED_KEYS.edge, path);
|
|
262
|
+
const from = requireIdentifier(edge.from, `${path}.from`);
|
|
263
|
+
const to = requireIdentifier(edge.to, `${path}.to`);
|
|
264
|
+
if (!isOneOf(JUDGMENT_DAG_EDGE_RELATIONS, edge.relation)) {
|
|
265
|
+
invalidContract(`${path}.relation is not a supported edge relation`);
|
|
266
|
+
}
|
|
267
|
+
if (!nodeById.has(from) || !nodeById.has(to)) {
|
|
268
|
+
throw new JudgmentDAGValidationError('missing_dependency', `${path} references a node that is not in the DAG`, { node_id: to, dependency_id: from });
|
|
269
|
+
}
|
|
270
|
+
return edge;
|
|
271
|
+
}
|
|
272
|
+
function edgeKey(from, to) {
|
|
273
|
+
// A delimiter-based key aliases pairs such as ("a\0b", "c") and
|
|
274
|
+
// ("a", "b\0c"). JSON preserves the pair structure even if an unsafe
|
|
275
|
+
// identifier reaches this internal helper, while public identifiers are
|
|
276
|
+
// rejected by the schema/runtime before this point.
|
|
277
|
+
return JSON.stringify([from, to]);
|
|
278
|
+
}
|
|
279
|
+
function edgePairLabel(pair) {
|
|
280
|
+
const [from, to] = JSON.parse(pair);
|
|
281
|
+
return `${from} -> ${to}`;
|
|
282
|
+
}
|
|
283
|
+
function findCycle(nodes, dependenciesByNode) {
|
|
284
|
+
const state = new Map();
|
|
285
|
+
const path = [];
|
|
286
|
+
function visit(nodeId) {
|
|
287
|
+
const currentState = state.get(nodeId) ?? 0;
|
|
288
|
+
if (currentState === 1) {
|
|
289
|
+
const cycleStart = path.indexOf(nodeId);
|
|
290
|
+
return [...path.slice(cycleStart), nodeId];
|
|
291
|
+
}
|
|
292
|
+
if (currentState === 2) {
|
|
293
|
+
return undefined;
|
|
294
|
+
}
|
|
295
|
+
state.set(nodeId, 1);
|
|
296
|
+
path.push(nodeId);
|
|
297
|
+
for (const dependencyId of [...(dependenciesByNode.get(nodeId) ?? [])].sort()) {
|
|
298
|
+
const cycle = visit(dependencyId);
|
|
299
|
+
if (cycle !== undefined) {
|
|
300
|
+
return cycle;
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
path.pop();
|
|
304
|
+
state.set(nodeId, 2);
|
|
305
|
+
return undefined;
|
|
306
|
+
}
|
|
307
|
+
for (const nodeId of nodes.map((node) => node.id).sort()) {
|
|
308
|
+
const cycle = visit(nodeId);
|
|
309
|
+
if (cycle !== undefined) {
|
|
310
|
+
return cycle;
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
return undefined;
|
|
314
|
+
}
|
|
315
|
+
/**
|
|
316
|
+
* Validate a DAG before any runner can execute it.
|
|
317
|
+
*
|
|
318
|
+
* The input is never mutated. Dependencies declared on nodes and explicit
|
|
319
|
+
* `depends_on` edges are both checked. They are two required representations
|
|
320
|
+
* of the same dependency topology and must be exact mirrors; other edge
|
|
321
|
+
* relations are not part of the execution topology.
|
|
322
|
+
*/
|
|
323
|
+
export function validateJudgmentDAG(value) {
|
|
324
|
+
const dag = requireRecord(value, 'dag');
|
|
325
|
+
requireExactKeys(dag, JUDGMENT_DAG_ALLOWED_KEYS.root, 'dag');
|
|
326
|
+
const dagId = requireIdentifier(dag.id, 'dag.id');
|
|
327
|
+
const dagVersion = requireNonEmptyString(dag.version, 'dag.version');
|
|
328
|
+
const nodeValues = requireArray(dag.nodes, 'dag.nodes');
|
|
329
|
+
const edgeValues = requireArray(dag.edges, 'dag.edges');
|
|
330
|
+
const nodes = nodeValues.map(validateNode);
|
|
331
|
+
const nodeById = new Map();
|
|
332
|
+
for (const node of nodes) {
|
|
333
|
+
if (nodeById.has(node.id)) {
|
|
334
|
+
throw new JudgmentDAGValidationError('duplicate_node', `DAG contains duplicate node ID: ${node.id}`, { node_id: node.id });
|
|
335
|
+
}
|
|
336
|
+
nodeById.set(node.id, node);
|
|
337
|
+
}
|
|
338
|
+
const dependenciesByNode = new Map(nodes.map((node) => [node.id, new Set()]));
|
|
339
|
+
const dependentsByNode = new Map(nodes.map((node) => [node.id, []]));
|
|
340
|
+
const dependencyPairs = new Set();
|
|
341
|
+
const nodeDependencyPairs = new Set();
|
|
342
|
+
function addDependency(dependencyId, dependentId) {
|
|
343
|
+
const dependent = nodeById.get(dependentId);
|
|
344
|
+
const dependency = nodeById.get(dependencyId);
|
|
345
|
+
if (dependent === undefined || dependency === undefined) {
|
|
346
|
+
throw new JudgmentDAGValidationError('missing_dependency', `Node ${dependentId} depends on missing node ${dependencyId}`, { node_id: dependentId, dependency_id: dependencyId });
|
|
347
|
+
}
|
|
348
|
+
if (dependency.scope.type !== dependent.scope.type || dependency.scope.id !== dependent.scope.id) {
|
|
349
|
+
throw new JudgmentDAGValidationError('scope_boundary_violation', `Dependency ${dependencyId} -> ${dependentId} crosses an exact scope boundary`, { node_id: dependentId, dependency_id: dependencyId });
|
|
350
|
+
}
|
|
351
|
+
const pair = edgeKey(dependencyId, dependentId);
|
|
352
|
+
if (dependencyPairs.has(pair)) {
|
|
353
|
+
return;
|
|
354
|
+
}
|
|
355
|
+
dependencyPairs.add(pair);
|
|
356
|
+
dependenciesByNode.get(dependentId)?.add(dependencyId);
|
|
357
|
+
dependentsByNode.get(dependencyId)?.push(dependentId);
|
|
358
|
+
const dependencyLayerIndex = LAYER_INDEX[dependency.layer];
|
|
359
|
+
const dependentLayerIndex = LAYER_INDEX[dependent.layer];
|
|
360
|
+
if (dependencyLayerIndex > dependentLayerIndex) {
|
|
361
|
+
throw new JudgmentDAGValidationError('reverse_layer_dependency', `Node ${dependentId} in layer ${dependent.layer} depends on later layer ` +
|
|
362
|
+
`${dependency.layer} node ${dependencyId}`, {
|
|
363
|
+
node_id: dependentId,
|
|
364
|
+
dependency_id: dependencyId,
|
|
365
|
+
node_layer: dependent.layer,
|
|
366
|
+
dependency_layer: dependency.layer
|
|
367
|
+
});
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
for (const node of nodes) {
|
|
371
|
+
for (const dependencyId of node.depends_on) {
|
|
372
|
+
nodeDependencyPairs.add(edgeKey(dependencyId, node.id));
|
|
373
|
+
addDependency(dependencyId, node.id);
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
const seenEdges = new Set();
|
|
377
|
+
const edgeDependencyPairs = new Set();
|
|
378
|
+
const edges = edgeValues.map((value, index) => validateEdge(value, index, nodeById));
|
|
379
|
+
for (const edge of edges) {
|
|
380
|
+
const key = `${edge.relation}:${edgeKey(edge.from, edge.to)}`;
|
|
381
|
+
if (seenEdges.has(key)) {
|
|
382
|
+
invalidContract(`edges contains duplicate relation ${key}`);
|
|
383
|
+
}
|
|
384
|
+
seenEdges.add(key);
|
|
385
|
+
if (edge.relation === 'depends_on') {
|
|
386
|
+
edgeDependencyPairs.add(edgeKey(edge.from, edge.to));
|
|
387
|
+
addDependency(edge.from, edge.to);
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
for (const pair of nodeDependencyPairs) {
|
|
391
|
+
if (!edgeDependencyPairs.has(pair)) {
|
|
392
|
+
invalidContract(`depends_on edge is missing for node dependency ${edgePairLabel(pair)}`);
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
for (const pair of edgeDependencyPairs) {
|
|
396
|
+
if (!nodeDependencyPairs.has(pair)) {
|
|
397
|
+
invalidContract(`node dependency is missing for depends_on edge ${edgePairLabel(pair)}`);
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
const cycle = findCycle(nodes, dependenciesByNode);
|
|
401
|
+
if (cycle !== undefined) {
|
|
402
|
+
throw new JudgmentDAGValidationError('cycle', `DAG contains a dependency cycle: ${cycle.join(' -> ')}`, { cycle });
|
|
403
|
+
}
|
|
404
|
+
const remainingDependencies = new Map([...dependenciesByNode.entries()].map(([id, dependencies]) => [id, dependencies.size]));
|
|
405
|
+
const ready = nodes
|
|
406
|
+
.filter((node) => remainingDependencies.get(node.id) === 0)
|
|
407
|
+
.map((node) => node.id)
|
|
408
|
+
.sort();
|
|
409
|
+
const executionOrder = [];
|
|
410
|
+
while (ready.length > 0) {
|
|
411
|
+
const completedNodeId = ready.shift();
|
|
412
|
+
if (completedNodeId === undefined) {
|
|
413
|
+
break;
|
|
414
|
+
}
|
|
415
|
+
executionOrder.push(completedNodeId);
|
|
416
|
+
for (const dependentId of [...(dependentsByNode.get(completedNodeId) ?? [])].sort()) {
|
|
417
|
+
const remaining = (remainingDependencies.get(dependentId) ?? 0) - 1;
|
|
418
|
+
remainingDependencies.set(dependentId, remaining);
|
|
419
|
+
if (remaining === 0) {
|
|
420
|
+
ready.push(dependentId);
|
|
421
|
+
ready.sort();
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
// This is defensive after findCycle, but keeps the preflight invariant
|
|
426
|
+
// explicit if the topology implementation changes later.
|
|
427
|
+
if (executionOrder.length !== nodes.length) {
|
|
428
|
+
throw new JudgmentDAGValidationError('cycle', 'DAG does not have a complete topological order');
|
|
429
|
+
}
|
|
430
|
+
return {
|
|
431
|
+
valid: true,
|
|
432
|
+
dag_id: dagId,
|
|
433
|
+
dag_version: dagVersion,
|
|
434
|
+
execution_order: executionOrder
|
|
435
|
+
};
|
|
436
|
+
}
|
|
437
|
+
export function assertValidJudgmentDAG(value) {
|
|
438
|
+
validateJudgmentDAG(value);
|
|
439
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Side-effect-free public entrypoint for the Judgment DAG core contract.
|
|
3
|
+
*
|
|
4
|
+
* The package root remains the MCP server entrypoint. Consumers that only
|
|
5
|
+
* need to validate a DAG can import this subpath without starting MCP.
|
|
6
|
+
*/
|
|
7
|
+
export { JUDGMENT_DAG_EDGE_RELATIONS, JUDGMENT_DAG_ALLOWED_KEYS, JUDGMENT_DAG_LAYERS, JUDGMENT_DAG_NODE_TYPE_TO_LAYER, JUDGMENT_DAG_NODE_TYPES, JUDGMENT_DAG_RUNNER_TYPES, JUDGMENT_DAG_SCOPE_TYPES, JudgmentDAGValidationError, assertValidJudgmentDAG, validateJudgmentDAG } from './judgment-dag-core.js';
|
|
8
|
+
export type { JudgmentDAG, JudgmentDAGEdge, JudgmentDAGEdgeRelation, JudgmentDAGLayer, JudgmentDAGMetadata, JudgmentDAGNode, JudgmentDAGNodeType, JudgmentDAGRunnerType, JudgmentDAGScope, JudgmentDAGScopeType, JudgmentDAGValidationCode, JudgmentDAGValidationDetails, JudgmentDAGValidationResult } from './judgment-dag-core.js';
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Side-effect-free public entrypoint for the Judgment DAG core contract.
|
|
3
|
+
*
|
|
4
|
+
* The package root remains the MCP server entrypoint. Consumers that only
|
|
5
|
+
* need to validate a DAG can import this subpath without starting MCP.
|
|
6
|
+
*/
|
|
7
|
+
export { JUDGMENT_DAG_EDGE_RELATIONS, JUDGMENT_DAG_ALLOWED_KEYS, JUDGMENT_DAG_LAYERS, JUDGMENT_DAG_NODE_TYPE_TO_LAYER, JUDGMENT_DAG_NODE_TYPES, JUDGMENT_DAG_RUNNER_TYPES, JUDGMENT_DAG_SCOPE_TYPES, JudgmentDAGValidationError, assertValidJudgmentDAG, validateJudgmentDAG } from './judgment-dag-core.js';
|
|
@@ -0,0 +1,313 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Brainbase Judgment DAG Core
|
|
3
|
+
status: accepted
|
|
4
|
+
date: 2026-08-20
|
|
5
|
+
scope: OSS Brainbase / shared core
|
|
6
|
+
supersedes_in_part: docs/architecture/brainbase-memory-loop-product-boundary.md
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# Brainbase Judgment DAG Core
|
|
10
|
+
|
|
11
|
+
## Decision
|
|
12
|
+
|
|
13
|
+
Brainbase OSS and organization deployments share the same Judgment DAG semantic model and runtime core.
|
|
14
|
+
|
|
15
|
+
Brainbase is not only a memory/knowledge store. Its core responsibility is to externalize, preserve, replay, evaluate, and improve the structure by which a person or organization turns context into judgment and action.
|
|
16
|
+
|
|
17
|
+
The prior product boundary that limited OSS Brainbase to `Remember / Organize / Retrieve / Learn` is revised. Brainbase owns the **judgment substrate**; Mana may own autonomous operating loops, continuous follow-through, and outcome ownership on top of that substrate.
|
|
18
|
+
|
|
19
|
+
```text
|
|
20
|
+
Brainbase = Remember / Organize / Retrieve / Judge / Replay / Learn
|
|
21
|
+
Mana = Operate / Prioritize continuously / Act autonomously / Follow-through
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
Brainbase may represent and execute judgment nodes. It does not become an always-on autonomous operator merely because it can execute a DAG.
|
|
25
|
+
|
|
26
|
+
## Core hypothesis
|
|
27
|
+
|
|
28
|
+
A person or organization can be modeled as a stateful system that repeatedly executes a directed judgment graph:
|
|
29
|
+
|
|
30
|
+
```text
|
|
31
|
+
State(t)
|
|
32
|
+
↓
|
|
33
|
+
Context / Observation DAG
|
|
34
|
+
↓
|
|
35
|
+
Judgment DAG
|
|
36
|
+
↓
|
|
37
|
+
Resource / Risk DAG
|
|
38
|
+
↓
|
|
39
|
+
Execution DAG
|
|
40
|
+
↓
|
|
41
|
+
Outcome
|
|
42
|
+
↓
|
|
43
|
+
Evaluation DAG
|
|
44
|
+
↓
|
|
45
|
+
State(t+1) + DAG update
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
The durable asset is not the document corpus itself. It is the reusable structure connecting evidence, assumptions, judgments, decisions, commitments, actions, outcomes, and updates.
|
|
49
|
+
|
|
50
|
+
## Shared five-layer model
|
|
51
|
+
|
|
52
|
+
### Layer 1: Context DAG
|
|
53
|
+
Produces normalized observations and state required by downstream judgment.
|
|
54
|
+
|
|
55
|
+
Allowed:
|
|
56
|
+
- facts and observations
|
|
57
|
+
- metrics and snapshots
|
|
58
|
+
- entity resolution
|
|
59
|
+
- source provenance
|
|
60
|
+
- temporal validity
|
|
61
|
+
|
|
62
|
+
Forbidden:
|
|
63
|
+
- strategic choice
|
|
64
|
+
- resource allocation
|
|
65
|
+
- external action
|
|
66
|
+
|
|
67
|
+
### Layer 2: Judgment DAG
|
|
68
|
+
Produces reusable interpretations and decisions from Context outputs.
|
|
69
|
+
|
|
70
|
+
Examples:
|
|
71
|
+
- priority judgment
|
|
72
|
+
- pricing judgment
|
|
73
|
+
- product fit judgment
|
|
74
|
+
- go/no-go judgment
|
|
75
|
+
- policy selection
|
|
76
|
+
|
|
77
|
+
Forbidden:
|
|
78
|
+
- direct mutation of execution state
|
|
79
|
+
- hidden reads from raw sources that bypass Context contracts
|
|
80
|
+
- direct resource commitment
|
|
81
|
+
|
|
82
|
+
### Layer 3: Resource / Risk DAG
|
|
83
|
+
Converts judgments into bounded commitments.
|
|
84
|
+
|
|
85
|
+
Examples:
|
|
86
|
+
- budget
|
|
87
|
+
- time allocation
|
|
88
|
+
- staffing
|
|
89
|
+
- risk limit
|
|
90
|
+
- approval threshold
|
|
91
|
+
- scope
|
|
92
|
+
|
|
93
|
+
Forbidden:
|
|
94
|
+
- reimplementing upstream business judgment
|
|
95
|
+
- performing the external action itself
|
|
96
|
+
|
|
97
|
+
### Layer 4: Execution DAG
|
|
98
|
+
Turns approved commitments into actions and records execution artifacts.
|
|
99
|
+
|
|
100
|
+
An **outcome** is the result that the Execution DAG generates and records. It is
|
|
101
|
+
an execution-layer node, not an independent sixth layer. The canonical node
|
|
102
|
+
type-to-layer mapping is `observation -> context`, `judgment/decision ->
|
|
103
|
+
judgment`, `resource -> resource`, `execution/outcome -> execution`, and
|
|
104
|
+
`evaluation -> evaluation`.
|
|
105
|
+
|
|
106
|
+
Examples:
|
|
107
|
+
- create task
|
|
108
|
+
- send proposal
|
|
109
|
+
- deploy software
|
|
110
|
+
- sign/route contract
|
|
111
|
+
- schedule meeting
|
|
112
|
+
|
|
113
|
+
Forbidden:
|
|
114
|
+
- silently changing upstream judgment or policy
|
|
115
|
+
- acquiring authority that was not granted by the DAG
|
|
116
|
+
|
|
117
|
+
### Layer 5: Evaluation DAG
|
|
118
|
+
Compares outcomes against explicit goals and evaluation criteria.
|
|
119
|
+
|
|
120
|
+
Examples:
|
|
121
|
+
- forecast error
|
|
122
|
+
- KPI pass/fail
|
|
123
|
+
- decision quality
|
|
124
|
+
- resource efficiency
|
|
125
|
+
- user value confirmation
|
|
126
|
+
|
|
127
|
+
Evaluation can propose an update to a judgment/policy/DAG version; it does not silently rewrite canonical judgment without the required authority.
|
|
128
|
+
|
|
129
|
+
## Node contract
|
|
130
|
+
|
|
131
|
+
A shared Judgment DAG node SHOULD converge on the following semantic contract:
|
|
132
|
+
|
|
133
|
+
```text
|
|
134
|
+
id
|
|
135
|
+
node_type
|
|
136
|
+
layer
|
|
137
|
+
scope
|
|
138
|
+
version
|
|
139
|
+
description
|
|
140
|
+
|
|
141
|
+
depends_on[]
|
|
142
|
+
input_contract
|
|
143
|
+
output_contract
|
|
144
|
+
|
|
145
|
+
runner_type
|
|
146
|
+
deterministic
|
|
147
|
+
agent
|
|
148
|
+
human
|
|
149
|
+
committee
|
|
150
|
+
external
|
|
151
|
+
|
|
152
|
+
authority
|
|
153
|
+
confidence
|
|
154
|
+
valid_from
|
|
155
|
+
valid_to
|
|
156
|
+
provenance
|
|
157
|
+
|
|
158
|
+
evaluation
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
Initial node types should stay intentionally small:
|
|
162
|
+
|
|
163
|
+
```text
|
|
164
|
+
observation
|
|
165
|
+
judgment
|
|
166
|
+
decision
|
|
167
|
+
resource
|
|
168
|
+
execution
|
|
169
|
+
outcome
|
|
170
|
+
evaluation
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
The `outcome` node type therefore remains in the Execution layer even though
|
|
174
|
+
the flow diagram shows it between Execution and Evaluation.
|
|
175
|
+
|
|
176
|
+
Ontology growth must be driven by failed real use cases, not by speculative completeness.
|
|
177
|
+
|
|
178
|
+
## Edge contract
|
|
179
|
+
|
|
180
|
+
Knowledge/identity relations and judgment dependencies are different concepts and must not be collapsed.
|
|
181
|
+
|
|
182
|
+
Judgment DAG edges include:
|
|
183
|
+
|
|
184
|
+
```text
|
|
185
|
+
depends_on
|
|
186
|
+
supports
|
|
187
|
+
contradicts
|
|
188
|
+
gates
|
|
189
|
+
supersedes
|
|
190
|
+
produces
|
|
191
|
+
evaluated_by
|
|
192
|
+
triggers
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
`depends_on` defines executable DAG topology. `node.depends_on` is the
|
|
196
|
+
topology SSOT: every dependency pair must have exactly one matching
|
|
197
|
+
`relation=depends_on` edge, and every `relation=depends_on` edge must have
|
|
198
|
+
exactly one matching node dependency. The edge is a required complete mirror,
|
|
199
|
+
not an optional duplicate declaration; a one-sided or mismatched
|
|
200
|
+
representation is `invalid_contract`. Relations such as `member_of`,
|
|
201
|
+
`owned_by`, or `accountable_for` remain graph semantics and can be referenced
|
|
202
|
+
by DAG nodes.
|
|
203
|
+
|
|
204
|
+
## Scope model: personal and organization use the same DAG
|
|
205
|
+
|
|
206
|
+
Do not create separate `PersonalDecision` and `CompanyDecision` schemas.
|
|
207
|
+
|
|
208
|
+
A node is scoped instead:
|
|
209
|
+
|
|
210
|
+
```text
|
|
211
|
+
scope:
|
|
212
|
+
type: personal | project | organization
|
|
213
|
+
id: <scope-id>
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
This enables promotion:
|
|
217
|
+
|
|
218
|
+
```text
|
|
219
|
+
Personal Judgment
|
|
220
|
+
↓ evidence / repeated success
|
|
221
|
+
Project Judgment
|
|
222
|
+
↓ promotion / authority
|
|
223
|
+
Organization Policy
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
A judgment can therefore move from an individual's learned heuristic into an organizational capability without translation into a separate schema.
|
|
227
|
+
|
|
228
|
+
J0-1 does not implement cross-scope promotion or authority evidence. Before
|
|
229
|
+
execution, both nodes in every dependency pair must have exactly equal
|
|
230
|
+
`scope.type` and `scope.id`; otherwise validation fails closed with the
|
|
231
|
+
machine-readable code `scope_boundary_violation`. A structurally valid DAG is
|
|
232
|
+
not evidence of execution authority, approval, or promotion. Those governance
|
|
233
|
+
boundaries remain later-scope work.
|
|
234
|
+
|
|
235
|
+
## Runtime principles inherited from FX / keiba DAG work
|
|
236
|
+
|
|
237
|
+
Brainbase adopts the architecture lessons proven in the `sintariran/FX` and `sintariran/keiba` DAG systems:
|
|
238
|
+
|
|
239
|
+
1. **Layer ownership is explicit.** A downstream layer must not reimplement an upstream decision.
|
|
240
|
+
2. **Inputs and outputs cross typed contracts.** No hidden state side channels.
|
|
241
|
+
3. **Dependencies are validated before execution.** Missing or reverse-layer dependencies are errors.
|
|
242
|
+
4. **Every run produces artifacts and an execution log.** A judgment must be replayable and auditable.
|
|
243
|
+
5. **DAG versions are first-class.** A changed judgment structure is a new version, not an invisible mutation.
|
|
244
|
+
6. **Evaluation is separate from execution.** Metrics must not be gamed by modifying the system under evaluation.
|
|
245
|
+
|
|
246
|
+
## OSS / organization boundary
|
|
247
|
+
|
|
248
|
+
The Judgment DAG core is OSS-level product capability.
|
|
249
|
+
|
|
250
|
+
OSS includes:
|
|
251
|
+
- node/edge semantic model
|
|
252
|
+
- dependency validation
|
|
253
|
+
- local execution runtime
|
|
254
|
+
- human and agent runners
|
|
255
|
+
- local artifact/execution log
|
|
256
|
+
- versioning
|
|
257
|
+
- replay/evaluation primitives
|
|
258
|
+
- personal/project/organization scope primitives
|
|
259
|
+
- basic authority metadata
|
|
260
|
+
|
|
261
|
+
Organization/Enterprise adds operational concerns rather than a different brain model:
|
|
262
|
+
- organization identity and directory integration
|
|
263
|
+
- robust RBAC / authority graph
|
|
264
|
+
- approval and escalation workflows
|
|
265
|
+
- multi-user concurrency
|
|
266
|
+
- managed connectors
|
|
267
|
+
- audit/compliance retention
|
|
268
|
+
- hosted runtime and HA
|
|
269
|
+
- cross-project governance
|
|
270
|
+
- enterprise security boundaries
|
|
271
|
+
|
|
272
|
+
## Mana boundary after this decision
|
|
273
|
+
|
|
274
|
+
Mana is no longer defined as the only place where judgment can occur.
|
|
275
|
+
|
|
276
|
+
Brainbase owns **what the judgment graph is, what it depends on, who/what can run it, what it produced, and how it evaluated**.
|
|
277
|
+
|
|
278
|
+
Mana owns the higher-order operating behavior that repeatedly decides *when* to run graphs, prioritizes across goals, initiates work, monitors progress, follows through, and intervenes over time.
|
|
279
|
+
|
|
280
|
+
```text
|
|
281
|
+
Brainbase: executable organizational cognition
|
|
282
|
+
Mana: autonomous organizational operation
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
## Non-goals
|
|
286
|
+
|
|
287
|
+
- Do not migrate the entire Brainbase ontology to a large Company Ontology in one release.
|
|
288
|
+
- Do not make all knowledge executable.
|
|
289
|
+
- Do not let an LLM infer authority implicitly.
|
|
290
|
+
- Do not create a single monolithic company DAG.
|
|
291
|
+
- Do not auto-promote personal judgments into organization policy without explicit evidence and authority.
|
|
292
|
+
|
|
293
|
+
## First proving ground
|
|
294
|
+
|
|
295
|
+
`Brainbase Deployment` is the first dogfooding domain.
|
|
296
|
+
|
|
297
|
+
The initial DAG should capture:
|
|
298
|
+
|
|
299
|
+
```text
|
|
300
|
+
Customer Context
|
|
301
|
+
↓
|
|
302
|
+
Maturity / Problem Structure Judgment
|
|
303
|
+
↓
|
|
304
|
+
Deployment Pattern Selection
|
|
305
|
+
↓
|
|
306
|
+
Scope / Resource Decision
|
|
307
|
+
↓
|
|
308
|
+
Proposal / Implementation
|
|
309
|
+
↓
|
|
310
|
+
Outcome Evaluation
|
|
311
|
+
```
|
|
312
|
+
|
|
313
|
+
Human judgment can initially be a runner. Each repeated decision should then be tested for delegation to an agent. The key success signal is a falling count of decisions that still require the original expert directly.
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Brainbase Judgment DAG Milestones
|
|
3
|
+
status: active
|
|
4
|
+
date: 2026-08-20
|
|
5
|
+
scope: OSS Brainbase
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Brainbase Judgment DAG Milestones
|
|
9
|
+
|
|
10
|
+
This roadmap replaces any implicit assumption that OSS Brainbase stops at memory retrieval. The next milestones make the shared Judgment DAG core real without prematurely building a complete enterprise ontology.
|
|
11
|
+
|
|
12
|
+
## M0 — Architecture lock
|
|
13
|
+
|
|
14
|
+
Goal: freeze semantic boundaries before implementation.
|
|
15
|
+
|
|
16
|
+
Exit criteria:
|
|
17
|
+
- `judgment-dag-core.md` is accepted.
|
|
18
|
+
- Personal and organization scopes share one node/edge model.
|
|
19
|
+
- Brainbase/Mana boundary is documented as cognition vs autonomous operation.
|
|
20
|
+
- FX/keiba lessons are explicitly adopted: layered ownership, typed boundaries, artifact logs, versioning, evaluation separation.
|
|
21
|
+
|
|
22
|
+
## M1 — Local DAG kernel
|
|
23
|
+
|
|
24
|
+
Goal: execute a small deterministic DAG locally.
|
|
25
|
+
|
|
26
|
+
Deliverables:
|
|
27
|
+
- `JudgmentDAGNode` / edge types
|
|
28
|
+
- `depends_on` validation
|
|
29
|
+
- layer validation
|
|
30
|
+
- deterministic runner
|
|
31
|
+
- execution artifact store
|
|
32
|
+
- execution log
|
|
33
|
+
- DAG version identifier
|
|
34
|
+
|
|
35
|
+
Exit criteria:
|
|
36
|
+
- A DAG with Context → Judgment → Resource → Execution → Evaluation runs deterministically.
|
|
37
|
+
- Missing dependency and reverse-layer dependency fail before execution.
|
|
38
|
+
- Every node output is inspectable after execution.
|
|
39
|
+
- Existing Brainbase Graph/Decision storage remains compatible.
|
|
40
|
+
|
|
41
|
+
## M2 — Human + Agent judgment runners
|
|
42
|
+
|
|
43
|
+
Goal: allow a judgment node to be performed by a human or an agent without changing DAG semantics.
|
|
44
|
+
|
|
45
|
+
Deliverables:
|
|
46
|
+
- `runner_type = human | agent | deterministic | external`
|
|
47
|
+
- pending human-step representation
|
|
48
|
+
- agent input/output contract
|
|
49
|
+
- explicit authority metadata
|
|
50
|
+
- confidence/provenance recording
|
|
51
|
+
|
|
52
|
+
Exit criteria:
|
|
53
|
+
- The same judgment node can be run manually and by an agent.
|
|
54
|
+
- Outputs can be compared without hidden context.
|
|
55
|
+
- Agent execution cannot silently acquire additional authority.
|
|
56
|
+
|
|
57
|
+
## M3 — Replay and evaluation
|
|
58
|
+
|
|
59
|
+
Goal: make judgment quality testable rather than anecdotal.
|
|
60
|
+
|
|
61
|
+
Deliverables:
|
|
62
|
+
- immutable run snapshot / artifact reference
|
|
63
|
+
- replay against historical context
|
|
64
|
+
- explicit goal/evaluation criteria
|
|
65
|
+
- outcome attachment
|
|
66
|
+
- pass/fail or scored evaluation
|
|
67
|
+
- node-level comparison between versions
|
|
68
|
+
|
|
69
|
+
Exit criteria:
|
|
70
|
+
- A prior DAG version can be replayed against a recorded context.
|
|
71
|
+
- A new version can be compared with the prior version without rewriting historical artifacts.
|
|
72
|
+
- Evaluation cannot mutate the event set it evaluates.
|
|
73
|
+
|
|
74
|
+
## M4 — Brainbase Deployment dogfood
|
|
75
|
+
|
|
76
|
+
Goal: externalize the first real expert judgment process.
|
|
77
|
+
|
|
78
|
+
Initial flow:
|
|
79
|
+
|
|
80
|
+
```text
|
|
81
|
+
Customer Context
|
|
82
|
+
-> Maturity Judgment
|
|
83
|
+
-> Problem Structure Judgment
|
|
84
|
+
-> Deployment Pattern
|
|
85
|
+
-> Scope / Resource Decision
|
|
86
|
+
-> Proposal / Implementation
|
|
87
|
+
-> Outcome Evaluation
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
Exit criteria:
|
|
91
|
+
- At least one real deployment is represented end-to-end.
|
|
92
|
+
- Human-only judgment nodes are explicit.
|
|
93
|
+
- Each expert escalation is logged as a missing/uncertain DAG capability rather than disappearing into chat.
|
|
94
|
+
- KPI: number of decisions requiring the original expert is measurable per deployment.
|
|
95
|
+
|
|
96
|
+
## M5 — Scope promotion
|
|
97
|
+
|
|
98
|
+
Goal: prove Personal → Project → Organization judgment promotion using one schema.
|
|
99
|
+
|
|
100
|
+
Deliverables:
|
|
101
|
+
- scope metadata
|
|
102
|
+
- promotion candidate workflow
|
|
103
|
+
- evidence links
|
|
104
|
+
- authority/approval gate
|
|
105
|
+
- supersession handling
|
|
106
|
+
|
|
107
|
+
Exit criteria:
|
|
108
|
+
- A personal judgment can become project guidance and then organization policy without schema conversion.
|
|
109
|
+
- The historical personal/project records remain queryable.
|
|
110
|
+
- Promotion never occurs solely because an LLM repeats the same output.
|
|
111
|
+
|
|
112
|
+
## M6 — Organization-ready primitives
|
|
113
|
+
|
|
114
|
+
Goal: keep the core reusable while allowing enterprise products to extend it.
|
|
115
|
+
|
|
116
|
+
Deliverables in OSS core:
|
|
117
|
+
- authority references
|
|
118
|
+
- approval hooks
|
|
119
|
+
- organization scope primitives
|
|
120
|
+
- audit event contract
|
|
121
|
+
- connector/runtime adapter interfaces
|
|
122
|
+
|
|
123
|
+
Not required in OSS M6:
|
|
124
|
+
- SSO/SCIM
|
|
125
|
+
- enterprise directory sync
|
|
126
|
+
- HA hosted runtime
|
|
127
|
+
- compliance retention policies
|
|
128
|
+
- full multi-user approval UI
|
|
129
|
+
|
|
130
|
+
Exit criteria:
|
|
131
|
+
- `brainbase-unson` can implement enterprise authority/governance without forking the DAG semantic model.
|
|
132
|
+
|
|
133
|
+
## Product metric hierarchy
|
|
134
|
+
|
|
135
|
+
The roadmap is not complete merely because graph/node counts increase. Measure:
|
|
136
|
+
|
|
137
|
+
1. **Replayability** — can Brainbase explain and rerun why a judgment occurred?
|
|
138
|
+
2. **Delegatability** — can an agent/another human run the node using explicit contracts?
|
|
139
|
+
3. **Expert escalation count** — how often is tacit expert judgment still required?
|
|
140
|
+
4. **Outcome calibration** — do judgment versions improve against declared goals?
|
|
141
|
+
5. **Promotion quality** — are reusable judgments correctly distinguished from case-specific decisions?
|
|
142
|
+
|
|
143
|
+
The primary dogfood KPI is **expert escalation count per deployment**, not total stored knowledge.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@unson/brainbase-mcp",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"description": "Local-first Brainbase MCP server and personal onboarding kit.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -10,12 +10,31 @@
|
|
|
10
10
|
},
|
|
11
11
|
"main": "dist/index.js",
|
|
12
12
|
"types": "dist/index.d.ts",
|
|
13
|
+
"exports": {
|
|
14
|
+
".": {
|
|
15
|
+
"types": "./dist/index.d.ts",
|
|
16
|
+
"import": "./dist/index.js"
|
|
17
|
+
},
|
|
18
|
+
"./judgment-dag": {
|
|
19
|
+
"types": "./dist/judgment-dag.d.ts",
|
|
20
|
+
"import": "./dist/judgment-dag.js"
|
|
21
|
+
},
|
|
22
|
+
"./dist/*": "./dist/*",
|
|
23
|
+
"./contracts/judgment-dag/schema.json": "./contracts/judgment-dag/schema.json",
|
|
24
|
+
"./contracts/judgment-dag/fixture.json": "./contracts/judgment-dag/fixture.json",
|
|
25
|
+
"./contracts/judgment-dag/source-lock.json": "./contracts/judgment-dag/source-lock.json",
|
|
26
|
+
"./contracts/judgment-dag/digest.json": "./contracts/judgment-dag/digest.json",
|
|
27
|
+
"./package.json": "./package.json"
|
|
28
|
+
},
|
|
13
29
|
"bin": {
|
|
14
30
|
"brainbase-mcp": "dist/index.js",
|
|
15
31
|
"brainbase": "dist/cli.js"
|
|
16
32
|
},
|
|
17
33
|
"files": [
|
|
18
34
|
"dist",
|
|
35
|
+
"contracts",
|
|
36
|
+
"docs/architecture/judgment-dag-core.md",
|
|
37
|
+
"docs/management/judgment-dag-milestones.md",
|
|
19
38
|
"README.md",
|
|
20
39
|
"LICENSE",
|
|
21
40
|
"SECURITY.md"
|
|
@@ -40,6 +59,7 @@
|
|
|
40
59
|
"onboard:seed": "node dist/cli.js onboard:seed",
|
|
41
60
|
"onboard:demo": "node dist/cli.js onboard:demo",
|
|
42
61
|
"onboard:install": "node dist/cli.js onboard:install",
|
|
62
|
+
"contracts:generate": "node scripts/generate-judgment-dag-contract-artifacts.mjs",
|
|
43
63
|
"release:plan": "node scripts/npm-release.mjs plan",
|
|
44
64
|
"release:validate": "node scripts/npm-release.mjs validate",
|
|
45
65
|
"release:publish": "node scripts/npm-release.mjs publish",
|
|
@@ -62,5 +82,5 @@
|
|
|
62
82
|
"engines": {
|
|
63
83
|
"node": ">=20"
|
|
64
84
|
},
|
|
65
|
-
"gitHead": "
|
|
85
|
+
"gitHead": "0ee5db39ac8f91a484628cc07a2df21cdfb149b7"
|
|
66
86
|
}
|