skynet-graph 1.2.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/CONTRIBUTING.md +22 -0
- package/LICENSE +661 -0
- package/README.md +245 -0
- package/bin/sg +20 -0
- package/concepts/README.md +23 -0
- package/concepts/_substrate/Claim/Confidence/Trusted.json +6 -0
- package/concepts/_substrate/Claim/Confidence.json +10 -0
- package/concepts/_substrate/Claim/Freshness/Stale.json +7 -0
- package/concepts/_substrate/Claim/Freshness.json +5 -0
- package/concepts/_substrate/Claim/Verification/Refuted.json +6 -0
- package/concepts/_substrate/Claim/Verification.json +6 -0
- package/concepts/_substrate/Claim.json +4 -0
- package/concepts/_substrate/Frontier/InBeam.json +6 -0
- package/concepts/_substrate/Frontier/Stuck.json +6 -0
- package/concepts/_substrate/Frontier.json +5 -0
- package/concepts/_substrate/Intake/ToTask.json +22 -0
- package/concepts/_substrate/Intake/Typed.json +10 -0
- package/concepts/_substrate/Intake.json +27 -0
- package/concepts/_substrate/Task/Answer.json +12 -0
- package/concepts/_substrate/Task/Complexity/Atomic.json +5 -0
- package/concepts/_substrate/Task/Complexity/Compound/Expansion.json +7 -0
- package/concepts/_substrate/Task/Complexity/Compound.json +6 -0
- package/concepts/_substrate/Task/Complexity.json +6 -0
- package/concepts/_substrate/Task/EvalComplexity.json +13 -0
- package/concepts/_substrate/Task/ReportUp.json +6 -0
- package/concepts/_substrate/Task/Rollup.json +10 -0
- package/concepts/_substrate/Task.json +5 -0
- package/concepts/clinical/Diagnosis/Medication.json +6 -0
- package/concepts/clinical/Diagnosis.json +15 -0
- package/concepts/clinical/Observation/LabValue/OutOfRange.json +6 -0
- package/concepts/clinical/Observation/LabValue.json +5 -0
- package/concepts/clinical/Observation.json +6 -0
- package/concepts/common/Document/pathBasket.json +6 -0
- package/concepts/common/Document.json +3 -0
- package/concepts/common/Edge/Distance.json +13 -0
- package/concepts/common/Edge/Stay/LongStay.json +8 -0
- package/concepts/common/Edge/Stay.json +8 -0
- package/concepts/common/Edge/Travel/LongTravel.json +16 -0
- package/concepts/common/Edge/Travel/ShortTravel.json +11 -0
- package/concepts/common/Edge/Travel/targetNode.json +7 -0
- package/concepts/common/Edge/Travel.json +7 -0
- package/concepts/common/Edge.json +3 -0
- package/concepts/common/Vertice.json +3 -0
- package/concepts/supply/Fulfillment.json +10 -0
- package/concepts/supply/Inventory/Reorder.json +7 -0
- package/concepts/supply/Inventory.json +5 -0
- package/concepts/supply/Procurement/SupplierConfirm.json +6 -0
- package/concepts/supply/Procurement.json +8 -0
- package/concepts/supply/Transport.json +5 -0
- package/doc/API.md +556 -0
- package/doc/CAPABILITIES.md +373 -0
- package/doc/MODELISATION.md +511 -0
- package/doc/architecture.md +267 -0
- package/doc/concept-as-graph.md +379 -0
- package/doc/concept-learning.md +168 -0
- package/doc/creative-loop-map.md +202 -0
- package/doc/original-2016-doc.md +148 -0
- package/doc/usage.md +501 -0
- package/lib/authoring/abstract.js +401 -0
- package/lib/authoring/abstraction.js +190 -0
- package/lib/authoring/adapt.js +393 -0
- package/lib/authoring/ancestry.js +216 -0
- package/lib/authoring/author.js +147 -0
- package/lib/authoring/bounded-merge.js +57 -0
- package/lib/authoring/canon.js +158 -0
- package/lib/authoring/clock.js +123 -0
- package/lib/authoring/combinator.js +92 -0
- package/lib/authoring/compete.js +76 -0
- package/lib/authoring/compose-hotspot.js +314 -0
- package/lib/authoring/compress.js +279 -0
- package/lib/authoring/concept-net.js +254 -0
- package/lib/authoring/concepts.js +66 -0
- package/lib/authoring/context-project.js +277 -0
- package/lib/authoring/contract.js +476 -0
- package/lib/authoring/corpus-pack.js +125 -0
- package/lib/authoring/cost-probe.js +86 -0
- package/lib/authoring/crystallize.js +555 -0
- package/lib/authoring/dag-decompose.js +256 -0
- package/lib/authoring/dataset-adapter.js +253 -0
- package/lib/authoring/debug-provider.js +92 -0
- package/lib/authoring/decompose.js +343 -0
- package/lib/authoring/emittability.js +236 -0
- package/lib/authoring/equilibrium.js +160 -0
- package/lib/authoring/extract.js +153 -0
- package/lib/authoring/forest.js +55 -0
- package/lib/authoring/forge-fallback.js +116 -0
- package/lib/authoring/givens.js +121 -0
- package/lib/authoring/glossary.js +177 -0
- package/lib/authoring/grammar-graph.js +191 -0
- package/lib/authoring/granularity.js +80 -0
- package/lib/authoring/graph-net.js +108 -0
- package/lib/authoring/ground.js +148 -0
- package/lib/authoring/higher-order.js +85 -0
- package/lib/authoring/hotspot.js +132 -0
- package/lib/authoring/hysteresis.js +85 -0
- package/lib/authoring/index.js +106 -0
- package/lib/authoring/lattice-morphism.js +61 -0
- package/lib/authoring/lattice-pack.js +148 -0
- package/lib/authoring/leaf-io.js +77 -0
- package/lib/authoring/library.js +156 -0
- package/lib/authoring/lifecycle.js +92 -0
- package/lib/authoring/loop.js +193 -0
- package/lib/authoring/master-loop.js +132 -0
- package/lib/authoring/mdl.js +209 -0
- package/lib/authoring/memo-stability.js +122 -0
- package/lib/authoring/method-explorer.js +138 -0
- package/lib/authoring/method-pack.js +181 -0
- package/lib/authoring/method.js +202 -0
- package/lib/authoring/mine.js +510 -0
- package/lib/authoring/mount.js +119 -0
- package/lib/authoring/negotiate.js +100 -0
- package/lib/authoring/parametric.js +139 -0
- package/lib/authoring/reaggregate.js +75 -0
- package/lib/authoring/rebalance.js +157 -0
- package/lib/authoring/recall.js +135 -0
- package/lib/authoring/registry.js +350 -0
- package/lib/authoring/relearn.js +147 -0
- package/lib/authoring/retention.js +89 -0
- package/lib/authoring/segment-proxy.js +114 -0
- package/lib/authoring/serve-leaf.js +64 -0
- package/lib/authoring/slot-aware-serve.js +77 -0
- package/lib/authoring/sound-invoke.js +59 -0
- package/lib/authoring/split-serve.js +74 -0
- package/lib/authoring/ste.js +239 -0
- package/lib/authoring/stock.js +101 -0
- package/lib/authoring/store.js +94 -0
- package/lib/authoring/supervise.js +138 -0
- package/lib/authoring/support.js +131 -0
- package/lib/authoring/task-mirror.js +51 -0
- package/lib/authoring/typed-loop.js +160 -0
- package/lib/authoring/validate.js +569 -0
- package/lib/authoring/widen.js +88 -0
- package/lib/combos/appliance.js +189 -0
- package/lib/combos/critique.js +377 -0
- package/lib/combos/defaults.js +86 -0
- package/lib/combos/durable-runner.js +115 -0
- package/lib/combos/forge.js +209 -0
- package/lib/combos/index.js +86 -0
- package/lib/combos/learning-library.js +253 -0
- package/lib/combos/mixture-serve.js +193 -0
- package/lib/combos/plan-loop.js +192 -0
- package/lib/combos/proxy-cache.js +272 -0
- package/lib/combos/self-mod.js +94 -0
- package/lib/durable/audit.js +102 -0
- package/lib/durable/checkpoint-store.js +550 -0
- package/lib/durable/fold.js +62 -0
- package/lib/durable/interpreter.js +242 -0
- package/lib/durable/xlate.js +185 -0
- package/lib/graph/Graph.js +2486 -0
- package/lib/graph/expr.js +307 -0
- package/lib/graph/index.js +26 -0
- package/lib/graph/log.js +134 -0
- package/lib/graph/objects/Concept.js +382 -0
- package/lib/graph/objects/Entity.js +503 -0
- package/lib/graph/objects/Node.js +57 -0
- package/lib/graph/objects/PathMap.js +557 -0
- package/lib/graph/objects/Segment.js +100 -0
- package/lib/graph/tasks/stabilize.js +59 -0
- package/lib/graph/tasks/taskflow.js +247 -0
- package/lib/index.js +122 -0
- package/lib/load.js +132 -0
- package/lib/providers/backends.js +117 -0
- package/lib/providers/borderline.js +129 -0
- package/lib/providers/cache.js +226 -0
- package/lib/providers/canonicalize.js +198 -0
- package/lib/providers/constat.js +107 -0
- package/lib/providers/geo.js +53 -0
- package/lib/providers/index.js +116 -0
- package/lib/providers/intake.js +263 -0
- package/lib/providers/llm-local.js +88 -0
- package/lib/providers/llm.js +236 -0
- package/lib/providers/local-host.js +197 -0
- package/lib/providers/merge-consistency.js +162 -0
- package/lib/providers/nogood.js +149 -0
- package/lib/providers/reason-loop.js +223 -0
- package/lib/providers/semiring.js +285 -0
- package/lib/providers/solver-fork.js +163 -0
- package/lib/providers/stats.js +228 -0
- package/lib/providers/verify.js +120 -0
- package/lib/runtime/index.js +135 -0
- package/lib/runtime/invoke-pool.js +92 -0
- package/lib/runtime/protocol.js +210 -0
- package/lib/runtime/transport-socket.js +77 -0
- package/lib/runtime/worker-entry.js +31 -0
- package/lib/sg/cli.js +601 -0
- package/lib/sg/log-sinks.js +214 -0
- package/lib/sg/mcp.js +395 -0
- package/lib/sg/proxy-run.js +66 -0
- package/lib/sg/serve-demo.js +185 -0
- package/lib/sg/serve.js +205 -0
- package/lib/sg/trace.js +118 -0
- package/lib/studio/protocol.js +45 -0
- package/lib/studio/public/app.js +310 -0
- package/lib/studio/public/components/ConceptEditor.js +43 -0
- package/lib/studio/public/components/ConceptTree.js +43 -0
- package/lib/studio/public/components/CorpusPanel.js +68 -0
- package/lib/studio/public/components/ForkTree.js +36 -0
- package/lib/studio/public/components/GrammarGraph.js +99 -0
- package/lib/studio/public/components/GraphCanvas.js +156 -0
- package/lib/studio/public/components/Inspector.js +48 -0
- package/lib/studio/public/components/LearningPanel.js +85 -0
- package/lib/studio/public/components/PromptConsole.js +46 -0
- package/lib/studio/public/components/ProviderTrace.js +39 -0
- package/lib/studio/public/components/SessionSplit.js +47 -0
- package/lib/studio/public/components/TilingOverlay.js +40 -0
- package/lib/studio/public/components/Timeline.js +57 -0
- package/lib/studio/public/index.html +26 -0
- package/lib/studio/public/styles.css +185 -0
- package/lib/studio/public/ws.js +58 -0
- package/lib/studio/server.js +130 -0
- package/lib/studio/session.js +397 -0
- package/lib/studio/studio.js +149 -0
- package/package.json +42 -0
package/doc/API.md
ADDED
|
@@ -0,0 +1,556 @@
|
|
|
1
|
+
# Skynet-Graph — Public API
|
|
2
|
+
|
|
3
|
+
The stable surface of the engine as of the V1 "Neurosymbolic Reasoning Graph" (formerly "MOE Graph") Phase-0 work. Skynet-graph is a
|
|
4
|
+
**library**: a host app embeds the engine, supplies *concept definitions* (the experts) and
|
|
5
|
+
*provider functions* (the effectful work), and drives the graph through mutations.
|
|
6
|
+
|
|
7
|
+
Mental model: data objects (nodes, segments) carry **typed facts**. **Concepts** are declarative
|
|
8
|
+
rules that become applicable when their `require`/`assert` conditions hold against the facts; when
|
|
9
|
+
they cast, they add more facts and/or new child segments, which makes other concepts applicable —
|
|
10
|
+
a forward-chaining cascade that runs to a fixpoint (**stabilization**). Mutations destabilize;
|
|
11
|
+
stabilization re-casts/uncasts; repeat until nothing more fires. See `CLAUDE.md` and `doc/original-2016-doc.md`
|
|
12
|
+
for the concept-schema and the embedded reference/template DSLs.
|
|
13
|
+
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
## Construction
|
|
17
|
+
|
|
18
|
+
```js
|
|
19
|
+
const Graph = require('skynet-graph'); // native CommonJS — no build step
|
|
20
|
+
const graph = new Graph(record, conf, conceptMap);
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
- **`record`** — the initial graph. Either a serialized snapshot `{ graph: "<json string>", lastRev }`
|
|
24
|
+
or a plain `{ lastRev, nodes:[…], segments:[…], freeNodes:[…] }` (or `{ conceptMaps:[…] }`, each
|
|
25
|
+
tagged with `Node:true` / `Segment:true`). Nodes/segments are `{ _id, … }`; segments also need
|
|
26
|
+
`originNode` / `targetNode`. Arbitrary typed facts (e.g. `Position`, `Distance`) live right on the
|
|
27
|
+
object record.
|
|
28
|
+
- **`conf`** — overrides merged onto `Graph.prototype.cfg`. Common fields:
|
|
29
|
+
| field | meaning |
|
|
30
|
+
|---|---|
|
|
31
|
+
| `label` | name for logs |
|
|
32
|
+
| `autoMount` | start stabilizing immediately (default `true`) |
|
|
33
|
+
| `isMaster` | master vs client (client forwards mutations via `pushToMaster`) |
|
|
34
|
+
| `conceptSets` | which keys of `conceptMap` to `deepmerge` into the active tree (default `["common"]`) |
|
|
35
|
+
| `onStabilize(graph, tokens)` | called once the graph settles (the main hook) |
|
|
36
|
+
| `bagRefManagers` | external-data ref managers (default `caipi` matches `/^db:(.+)$/`) |
|
|
37
|
+
- **`conceptMap`** — host-supplied, keyed by concept-set name (`{ common: <tree> }`). The tree is a
|
|
38
|
+
nested `childConcepts` hierarchy. `lib/authoring/concepts.js#buildConceptTree(dir)` assembles one
|
|
39
|
+
from the `concepts/<set>/` directory.
|
|
40
|
+
|
|
41
|
+
---
|
|
42
|
+
|
|
43
|
+
## Lifecycle & stabilization
|
|
44
|
+
|
|
45
|
+
```js
|
|
46
|
+
new Graph(seed, {
|
|
47
|
+
autoMount: true, isMaster: true, conceptSets: ['common'], bagRefManagers: {},
|
|
48
|
+
onStabilize(g) { /* graph has reached a fixpoint */ }
|
|
49
|
+
}, { common: tree });
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
- **`onStabilize`** fires every time the graph reaches a coherent fixpoint — after the initial mount
|
|
53
|
+
and after every mutation/rollback/patch settles. It is the primary place to read results and to
|
|
54
|
+
drive the next step.
|
|
55
|
+
- **`graph.stabilize(cb?)`** — ensure the task loop is running; `cb` fires once on the next settle.
|
|
56
|
+
- A snapshot is captured on every settle (see History).
|
|
57
|
+
|
|
58
|
+
---
|
|
59
|
+
|
|
60
|
+
## Mutations
|
|
61
|
+
|
|
62
|
+
```js
|
|
63
|
+
graph.pushMutation(template, targetId, force?, atomId?, initialRefBag?, cb?);
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
Apply a mutation template that creates/updates objects and marks them unstable. The template uses the
|
|
67
|
+
`$`-prefixed reference/template DSL (`$_id`, `$$_id`, `$key` ref, `$$key` bagRef, `_incoming`/`_outgoing`
|
|
68
|
+
nesting). Example (grow the graph):
|
|
69
|
+
|
|
70
|
+
```js
|
|
71
|
+
graph.pushMutation([
|
|
72
|
+
{ _id: 'tokyo', Node: true, Position: { lat: 35.6762, lng: 139.6503 } },
|
|
73
|
+
{ _id: 'long2', Segment: true, originNode: 'paris', targetNode: 'tokyo' }
|
|
74
|
+
]);
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
Providers emit the same templates from their callback (see Providers). After mutating outside an
|
|
78
|
+
`onStabilize` turn, call `graph.stabilize()` if the loop isn't already running.
|
|
79
|
+
|
|
80
|
+
---
|
|
81
|
+
|
|
82
|
+
## State & history
|
|
83
|
+
|
|
84
|
+
| method | returns |
|
|
85
|
+
|---|---|
|
|
86
|
+
| `graph.serialize()` | `{ lastRev, graph: "<json>" }` snapshot of the whole graph |
|
|
87
|
+
| `graph.getCurrentRevision()` | current revision number |
|
|
88
|
+
| `graph.getRevisions()` | ascending list of revisions with captured snapshots |
|
|
89
|
+
| `graph.getSnapshot(rev)` / `graph.diffRevisions(a, b)` | snapshot at `rev` / added·removed·changed between revs |
|
|
90
|
+
| `graph.rollbackTo(rev)` | re-mount that snapshot, drop later ones (linear undo), re-stabilize — restores **rules too** |
|
|
91
|
+
| `graph.exportConcepts()` | the LIVE concept tree as a serializable record (reflects `addConcept`/`patchConcept`) — feed to `corpus-pack` / `exportConceptsToDir` |
|
|
92
|
+
|
|
93
|
+
```js
|
|
94
|
+
const revA = g.getCurrentRevision();
|
|
95
|
+
g.pushMutation(/* … grow … */); // -> settles at revB
|
|
96
|
+
// later:
|
|
97
|
+
g.rollbackTo(revA); // the growth is undone, onStabilize re-fires at revA
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
Snapshots are full `serialize()` copies captured on each settle (delta-replay is a later optimization).
|
|
101
|
+
|
|
102
|
+
---
|
|
103
|
+
|
|
104
|
+
## Sub-agents — fork / merge
|
|
105
|
+
|
|
106
|
+
Spin up an independent child graph (a sandboxed sub-agent, optionally with a *different* concept set =
|
|
107
|
+
different capabilities), let it work a sub-problem, and reintegrate its result.
|
|
108
|
+
|
|
109
|
+
```js
|
|
110
|
+
const child = graph.fork(subSeed, {
|
|
111
|
+
label: 'child', conceptSets: ['worker'], // child-only capabilities
|
|
112
|
+
reintegrateInto: 'root', // target object in the PARENT
|
|
113
|
+
project: (child) => ({ $$_id: 'root', mergedWork: child._objById['sub']._etty._.work })
|
|
114
|
+
});
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
- **`fork(seed?, conf?)`** → a new child `Graph`. `seed` omitted ⇒ forks this graph's current snapshot.
|
|
118
|
+
Reuses this graph's concept library unless `conf.conceptMap` overrides it. With `conf.reintegrateInto`
|
|
119
|
+
(+ optional `conf.project`), the child auto-`merge`s back on its own stabilize.
|
|
120
|
+
- **`merge(child, targetId, project?)`** — apply `project(child)` (a mutation template) onto `targetId`
|
|
121
|
+
in this graph, then `child.destroy()`. Default `project` attaches the child's serialized graph.
|
|
122
|
+
|
|
123
|
+
---
|
|
124
|
+
|
|
125
|
+
## Hot-patching experts — patchConcept
|
|
126
|
+
|
|
127
|
+
Change a live concept (an "expert") and re-evaluate the whole graph against it, both directions, with
|
|
128
|
+
no restart or rebuild.
|
|
129
|
+
|
|
130
|
+
```js
|
|
131
|
+
graph.patchConcept('Far', { assert: ['$Distance.inKm > 500'] });
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
- **`patchConcept(nameOrId, updates, cb?)`** — deep-merges `updates` into the concept's schema
|
|
135
|
+
(**arrays REPLACE, not concatenate** — so `{assert:[…]}` overrides), recompiles its applicability
|
|
136
|
+
test, then for every live object: newly-applicable + not cast ⇒ cast; cast + no-longer-applicable ⇒
|
|
137
|
+
**uncast (cascading to child concepts)**; then re-stabilizes.
|
|
138
|
+
- **`getConceptByName(nameOrId)`** — resolve a concept by its library id, else by `_name`.
|
|
139
|
+
|
|
140
|
+
Tightening an assert retracts the concept where it no longer holds *and its dependent children*;
|
|
141
|
+
loosening one casts it onto newly-qualifying objects.
|
|
142
|
+
|
|
143
|
+
---
|
|
144
|
+
|
|
145
|
+
## Manual concept control & accessors
|
|
146
|
+
|
|
147
|
+
| method | meaning |
|
|
148
|
+
|---|---|
|
|
149
|
+
| `graph.castConcept(objId, conceptId, cb?)` | force-cast a concept onto an object, re-stabilize |
|
|
150
|
+
| `graph.unCastConcept(objId, conceptId, cb?)` | force-uncast, re-stabilize |
|
|
151
|
+
| `graph.getConcept(id)` | concept instance by library id |
|
|
152
|
+
| `graph.getRef(exp, scope?, follow?, unref?)` | resolve a reference path (`a:b:c`, `$key`) from a scope |
|
|
153
|
+
| `graph.getEtty(id)` | the Entity wrapper for an object id |
|
|
154
|
+
| `graph.getPaths(fromId, toId, skip?)` / `graph.getOpenPathOf(id)` | path discovery / a `PathMap` |
|
|
155
|
+
| `graph.on(evt, cb)` / `graph.un(evt, cb)` | subscribe/unsubscribe (`"stabilize"`, `"destroy"`) |
|
|
156
|
+
| `graph.destroy()` | tear down the graph and its objects |
|
|
157
|
+
|
|
158
|
+
Object internals: `graph._objById[id]._etty` is the Entity; `…._etty._` is the raw typed facts record
|
|
159
|
+
(e.g. `graph._objById['long']._etty._.Distance.inKm`).
|
|
160
|
+
|
|
161
|
+
---
|
|
162
|
+
|
|
163
|
+
## Providers
|
|
164
|
+
|
|
165
|
+
A provider does the effectful work a concept needs (geo math, an API/DB call, an LLM call) and emits
|
|
166
|
+
facts. The engine looks them up in `Graph._providers` (host-wired — the engine does **not** auto-load
|
|
167
|
+
them). A concept references one as `"Namespace::fn"` (optionally `["ns::fn", …args]`).
|
|
168
|
+
|
|
169
|
+
**Contract:**
|
|
170
|
+
|
|
171
|
+
```js
|
|
172
|
+
Graph._providers = {
|
|
173
|
+
Namespace: {
|
|
174
|
+
fn(graph, concept, scope, argz, cb) {
|
|
175
|
+
// …compute…
|
|
176
|
+
cb(err, mutationTemplate); // template applied onto the scope object (`$_id:'_parent'`)
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
};
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
`scope` is the object's Entity; read its context with `graph.getRef('originNode:Position', scope)`.
|
|
183
|
+
Return `cb(null, null)` to no-op (e.g. wait for a dependency).
|
|
184
|
+
|
|
185
|
+
### Packaged base providers (host opt-in)
|
|
186
|
+
|
|
187
|
+
```js
|
|
188
|
+
const Graph = require('skynet-graph');
|
|
189
|
+
const { register, CommonGeo, createLLMProvider } = require('skynet-graph/lib/providers');
|
|
190
|
+
|
|
191
|
+
register(Graph, [ { CommonGeo }, createLLMProvider({ ask: myBackend }) ]);
|
|
192
|
+
// register(Graph) with no selection wires the defaults (Geo + a default LLM client)
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
- **`CommonGeo`** → `CommonGeo::Distance` — haversine great-circle distance between two node
|
|
196
|
+
`Position`s, emitting `{ Distance: { inKm } }`. Drives `concepts/common/Edge/Distance.json`.
|
|
197
|
+
(`haversineKm(a, b)` is also exported as a pure function.)
|
|
198
|
+
- **`createLLMProvider({ ask, parseJSON?, namespace? })`** → `{ LLM: { complete } }`, a generic
|
|
199
|
+
concept↔prompt runner. The concept supplies a `prompt` block:
|
|
200
|
+
|
|
201
|
+
```json
|
|
202
|
+
{ "provider": ["LLM::complete"],
|
|
203
|
+
"prompt": { "system": "You judge.", "user": "Step: ${label}",
|
|
204
|
+
"maxTokens": 500, "json": true, "as": "Classification" } }
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
`system`/`user` interpolate `${ref}` tokens (resolved against the scope via `graph.getRef`);
|
|
208
|
+
`json:true` salvages the reply (robust to "thinking" preambles — returns the last balanced JSON);
|
|
209
|
+
the result is written back as facts (merged if a plain object, or stored under `as`). Backend errors
|
|
210
|
+
are captured as an `llmError` fact so the graph still settles. The backend is **pluggable** — pass
|
|
211
|
+
any `ask({system,user,maxTokens})`; the bundled `makeAsk(opts)` **dispatches on `opts.api` / env
|
|
212
|
+
`LLM_API`** — `anthropic` (default, `/v1/messages`) or `openai` (`/v1/chat/completions`, for
|
|
213
|
+
vLLM / llama.cpp / LM-Studio; reads `choices[0].message.content` and falls back to
|
|
214
|
+
`reasoning_content` for reasoning models). `makeOpenAIAsk` / `makeAnthropicAsk` are exported too.
|
|
215
|
+
All configurable via `LLM_BASE` / `LLM_MODEL` / `LLM_KEY` or `{ base, model, key }`.
|
|
216
|
+
|
|
217
|
+
#### Canonicalization barrier — the `facts` / `prose` contract
|
|
218
|
+
|
|
219
|
+
An `LLM::complete` expert whose output **feeds downstream experts** must not let raw prose onto a
|
|
220
|
+
dependency edge: two semantically-equal replies differ textually, so a `require`/`ensure` keyed on prose
|
|
221
|
+
re-keys every run and the memo never hits (risk **K1**, `doc/MODELISATION.md` §4.2). Declare a `facts`
|
|
222
|
+
schema and the provider writes **only** those discrete, canonicalized keys as *tracked* facts; the free
|
|
223
|
+
text lands on an *untracked* prose key; a stable `<name>FactsDigest` is emitted as an explicit memo key.
|
|
224
|
+
|
|
225
|
+
```json
|
|
226
|
+
{ "provider": ["LLM::complete"],
|
|
227
|
+
"prompt": {
|
|
228
|
+
"system": "Classify the risk.", "user": "Step: ${label}",
|
|
229
|
+
"facts": { // the tracked, discrete spine
|
|
230
|
+
"severity": { "enum": ["low","medium","high"] }, // snapped to a closed vocabulary
|
|
231
|
+
"priceK": { "grain": 100, "from": "price" }, // numeric rounded to a grain; read raw `price`
|
|
232
|
+
"count": { "type": "int" } // int | number | bool | id | string
|
|
233
|
+
},
|
|
234
|
+
"prose": "summary" // free text -> UNTRACKED key (default: `<name>Prose`)
|
|
235
|
+
} }
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
Snapping is **deterministic only** (never embedding similarity — a fuzzy false-hit graves a wrong fact
|
|
239
|
+
that *propagates*). An out-of-vocabulary enum **fails closed**: the fact is `null` and the key is listed
|
|
240
|
+
in `<name>CanonMiss` (visible, never a silent wrong snap). Helpers are exported for direct use:
|
|
241
|
+
`canonFacts(raw, schema) -> { facts, misses }`, `canonValue(raw, spec)`, `digest(facts)`.
|
|
242
|
+
With no `facts` schema declared, the provider keeps its legacy merge/`as` behavior (back-compatible).
|
|
243
|
+
- **`register(Graph, fragments?)`** merges provider-map fragments onto `Graph._providers`, preserving
|
|
244
|
+
any already set.
|
|
245
|
+
|
|
246
|
+
### Verification — verdict facts + `ensure` defeasance
|
|
247
|
+
|
|
248
|
+
The engine maintains **coherence**, never **truth** (K3): a hallucinated-but-valid fact propagates and
|
|
249
|
+
retracts cleanly. Verification makes unreliability *visible and non-propagating* by emitting discrete
|
|
250
|
+
**verdict facts** that downstream concepts gate on via `ensure` — a refuted fact auto-retracts its
|
|
251
|
+
dependents (refutation *is* defeasance; no new engine path). Verdicts are discrete (the typed-fact spine),
|
|
252
|
+
never prose, and **never overwrite** the checked fact. `createVerifier()` (from `skynet-graph/lib/providers`)
|
|
253
|
+
returns `{ Verify: { check }, Vote: { tally } }`; `checks` and `majority` are exported too.
|
|
254
|
+
|
|
255
|
+
Three patterns (all engine-verified; pick by reactivity need):
|
|
256
|
+
|
|
257
|
+
1. **Deterministic verifier = a concept whose `ensure` IS the invariant** — full `expr.js` grammar (uncapped):
|
|
258
|
+
`{ "_name":"BudgetOK", "require":["cost","cap"], "ensure":["$cost <= $cap"] }`. Its self-flag is the verdict;
|
|
259
|
+
a target change re-tests it and auto-retracts. A consumer **nested** under it (`childConcepts`) cascade-
|
|
260
|
+
retracts on refutation. Prefer this — deterministic checkers ≫ LLM-refuters, and it is reactive.
|
|
261
|
+
2. **Independent verdict provider** `Verify::check` — for a check that runs as an effect (external lookup /
|
|
262
|
+
LLM-refuter): `{ "provider":["Verify::check"], "verify":{ "target":"$x", "check":"range", "params":{"min":0,"max":100}, "as":"x" } }`
|
|
263
|
+
writes `xVerdict`/`xVerified`/`xVerifiedAgainst` (provenance), never `$x`. Downstream gates `ensure:["$xVerified == true"]`.
|
|
264
|
+
(A provider verifier is **cast-once** — it re-runs only on uncast/recast; use pattern 1 for reactive re-checking.)
|
|
265
|
+
3. **k-of-n voting** `Vote::tally` — self-consistency: n strategies `{__push}` a vote into a grow-only array;
|
|
266
|
+
a `Vote` concept gated `ensure:["$votes.length == $expected"]` emits `consensus` + `confidence = agree/n`;
|
|
267
|
+
downstream gates `ensure:["$confidence >= 0.7"]`. Treat `confidence` as a heuristic, never proof (a biased
|
|
268
|
+
model votes confidently wrong). Independence discipline: the refuter must not be the call that produced the fact.
|
|
269
|
+
|
|
270
|
+
Deterministic checkers: `range`, `oneOf`, `equals`, `approx`, `nonEmpty` — `(value, params) -> { pass, reason }`,
|
|
271
|
+
extend via `createVerifier({ checks: { … } })`.
|
|
272
|
+
|
|
273
|
+
### Freshness / TTL — time as a fact
|
|
274
|
+
|
|
275
|
+
The engine has no internal wall-clock (replay stays hermetic). Time enters as an ordinary fact on a
|
|
276
|
+
`clock` free-node; a time-bound concept gates freshness in an `ensure`. Advancing the clock re-tests
|
|
277
|
+
exactly the concepts that follow it, so a fact that has gone **stale auto-retracts** (and its dependents
|
|
278
|
+
cascade) — the cache-poisoning fix (an LLM/API fact otherwise lives forever). The whole pattern is plain
|
|
279
|
+
seed + mutation, no dedicated API:
|
|
280
|
+
|
|
281
|
+
```js
|
|
282
|
+
// seed: { freeNodes: [ { _id:'clock', tick:0 } ], nodes: [ { _id:'n', source:'db', sensedAt:0 } ] }
|
|
283
|
+
// concept: { "require":["source"], "ensure":["$$clock:tick - $sensedAt < 2"], "provider":["AI::sense"] }
|
|
284
|
+
// ($$clock — DOUBLE-$, a GLOBAL free-node ref; a single $clock is a key on the current scope)
|
|
285
|
+
g.pushMutation('clock', { $$_id: 'clock', tick: 3 }); // tick 0 -> 3: the fact is now stale -> retracts + cascades
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
- **Invalidation is automatic and reliable.** **Refetch is host-triggered** — a provider is cast-once, so a
|
|
289
|
+
stale provider-fact re-derives only on uncast→recast (retract the cast flag, restabilize). A provider
|
|
290
|
+
stamps its fetch time from the clock node.
|
|
291
|
+
- Pitfall: an `ensure` with `||` (`"$x==null || $$clock:tick-$x<t"`) **short-circuits watcher registration** —
|
|
292
|
+
seed the stamp so the freshness operand always evaluates, or split the fetch from the freshness gate.
|
|
293
|
+
|
|
294
|
+
---
|
|
295
|
+
|
|
296
|
+
## Author-time concept validation
|
|
297
|
+
|
|
298
|
+
A host-side validator enforces the typed-fact discipline **before** a concept tree reaches the engine —
|
|
299
|
+
the safety gate for hand- or AI-authored concepts. It validates *structure*, never the expression grammar.
|
|
300
|
+
|
|
301
|
+
```js
|
|
302
|
+
const { validateConceptTree, validateOrThrow } = require('skynet-graph/lib/authoring/validate');
|
|
303
|
+
const { errors, warnings } = validateConceptTree(tree, { palette: ['LLM::complete', 'CommonGeo::Distance'] });
|
|
304
|
+
```
|
|
305
|
+
|
|
306
|
+
Checks: every concept has a `_name` (the self-flag — without it the engine re-fires it forever);
|
|
307
|
+
`assert`/`ensure` parse under the real evaluator (`lib/graph/expr.js`) and don't touch `constructor`/`__proto__`;
|
|
308
|
+
`provider` ∈ a vetted `palette` (advisory warning, or an error under `{ strict: true }`); and the valuable
|
|
309
|
+
one — **ref soundness**: a `require`/`ensure`/`assert` that keys on a **prose** fact (a declared `prose`
|
|
310
|
+
key, or the `<name>Prose`/`<name>CanonMiss` defaults) is **rejected** (it would fragment the memo, K1),
|
|
311
|
+
and a bare dependency on a child-set (`expandedInto`/`answeredBy`/…) without `.length` is **warned** (the
|
|
312
|
+
"all-children-answered" footgun — `getRef` has no quantifier). `validateOrThrow` throws on the first error.
|
|
313
|
+
|
|
314
|
+
### Mixture-of-Reasoners regime providers (host opt-in, additive)
|
|
315
|
+
|
|
316
|
+
All are `require('skynet-graph/lib/providers')` factories; pair each with its ready-made concept-tree
|
|
317
|
+
fragment. The deterministic core is untouched.
|
|
318
|
+
|
|
319
|
+
| factory | wires | concept-tree helper |
|
|
320
|
+
|---|---|---|
|
|
321
|
+
| `createSemiring()` | `Semiring::reduce` — fold `{__push}`ed contributions under `boolean`/`logodds`/`maxplus`/`probor` | `semiringConceptTree({ semiring, contribKey, bands? })` |
|
|
322
|
+
| `createSemiring()` (pareto family) | multi-criteria **skyline SELECT** → `selectedId`/`frontIds`/`frontSize` | `selectConceptTree({ criteria, lex })` — the Candidate→Selected cluster |
|
|
323
|
+
| `createStats()` | `Stats::{report,grandMean,shrink}` — hierarchical Beta-Binomial shrinkage | `shrinkageConceptTree(...)` |
|
|
324
|
+
| `createNogood()` | `Nogood::guard` — learned sound-skip of dead-ends | `nogoodGuardConcept()` / `guardTrial(schema)` |
|
|
325
|
+
| `createVerifier()` | `Verify::check` (verdict facts) + `Vote::tally` (k-of-n) | — |
|
|
326
|
+
| `createConsistency()` | `Merge::combine` — sheaf-style agree/borderline/conflict bands | `consistencyConceptTree()` |
|
|
327
|
+
| `createSolver({ solve })` | `Solve::run` — a C-regime **fork** that searches; crosses only the snapped model | `solverConceptTree()` |
|
|
328
|
+
| `createConstat()` | `Constat::record` — typed lesson-on-retraction `{claim,retractedBecause,certaintyBand,atRev}` | — |
|
|
329
|
+
|
|
330
|
+
Pure helpers: `paretoFront` / `paretoSelect` / `makePareto` / `dominates` / `reduceSemiring`
|
|
331
|
+
(`lib/providers/semiring.js`).
|
|
332
|
+
|
|
333
|
+
### Tiling, grammar graph & corpus exchange (`lib/authoring/`)
|
|
334
|
+
|
|
335
|
+
- **`treeDecomposition(tree)` / `forkPlan(tree)`** (`decompose.js`) — derive, off the concept-dependency
|
|
336
|
+
graph, the separator interface + the candidate forks + each fork's **frontier alphabet** + the treewidth
|
|
337
|
+
cost bound (`partitionPays`). Feeds `fork`/`merge` and `validateMergeProjection`.
|
|
338
|
+
- **`conceptFactGraph(conceptMap)`** (`grammar-graph.js`) — the concept↔fact flux graph: produced /
|
|
339
|
+
consumed facts **with polarity**, cross-corpus links, writer-collisions, entry points, tiling overlay.
|
|
340
|
+
- **`.sgc` corpus exchange** (`corpus-pack.js`): `deriveManifest` (produces/consumes alphabet, required
|
|
341
|
+
providers), `packCorpus` / `unpackCorpus` (a portable bundle of the *authored grammar*). Disk round-trip:
|
|
342
|
+
`Graph.loadConceptMap(dir, { validate })` ↔ `exportConceptsToDir(tree, dir)` (`lib/load.js`).
|
|
343
|
+
|
|
344
|
+
### The support grammar (`lib/authoring/support.js`)
|
|
345
|
+
|
|
346
|
+
`supportConceptTree({ criteria, lex })` + `makeSupportProviders({ evalFn, expandFn, proposeFn,
|
|
347
|
+
escalateFn, escalateBar, rollupFn })` compose the decompose loop with the per-segment
|
|
348
|
+
**Propose → Pareto-SELECT → Adopt** alternative-search trio + escalation on `Stuck`. Inject the content
|
|
349
|
+
functions (deterministic in tests, an LLM in production).
|
|
350
|
+
|
|
351
|
+
### Concept-as-graph: the method toolkit (`lib/authoring/`)
|
|
352
|
+
|
|
353
|
+
The LLM-driven **Use 2** mechanism — forge / crystallize / reuse typed methods on top of the substrate.
|
|
354
|
+
Host-side, ZERO-CORE, additive (the base hand-authoring use needs none of it). This is the mechanism the
|
|
355
|
+
two preprints measure; their replay artifacts ship under `artifact/`.
|
|
356
|
+
|
|
357
|
+
- **`abstract.js`** — F6 abstractivation: `relativize`/`instantiate` (id/frontier holes), `antiUnify` (Plotkin
|
|
358
|
+
LGG), `methodTransform` (the cache `{onStore,onReplay}`), `emitMethodAsSubgraph` (re-mountable parameterized
|
|
359
|
+
method via `Graph#getMutationFromPath`). The cross-problem structural-transfer keystone.
|
|
360
|
+
- **`crystallize.js`** (+ `mine.js`, `abstraction.js`, `memo-stability.js`) — `crystallize`/`adopt`/`consolidate`:
|
|
361
|
+
mine a producer→consumer chain → compose → MDL/utility gate (`abstraction.evaluate` scores model calls) →
|
|
362
|
+
install fail-closed (memo-stability). `crystallizeStructural` distils a recurrent **structural** cast into a
|
|
363
|
+
re-mountable defeasible method with a **declared** frontier (`mine.js#declaredCtx`) reified as
|
|
364
|
+
`schema.frontier` (a `FrontierSignature` — `{params:[{name,sort,field,role}], summaryFacts, appConditions}`,
|
|
365
|
+
serializes with the tree) + a `libraryKey` (the O(1) dispatch index) + `lintFrontier`; a soundness gate refuses a
|
|
366
|
+
method that would leak a learning id at replay (un-holed / base-prefix-phantom / collapsed endpoints).
|
|
367
|
+
- **`library.js` · `adapt.js`** — the method-library index + the adapt-or-forge controller. `library.js`:
|
|
368
|
+
`makeLibrary`/`indexMethod`/`dispatch(lib, target, scopeFacts)` — an **O(1) bucket lookup on `libraryKey`** →
|
|
369
|
+
refine by application-conditions → ranked candidates (a lookup, never a corpus search). `adapt.js`:
|
|
370
|
+
`adaptOrForge({lib,target,scopeFacts,forge,verify})` — retrieve(hit, 0 calls) / forge-or-adapt(reuse
|
|
371
|
+
neighbours) / verifier-gate(contract) / index-back(amortise). Structure-mapping (Gentner) over learned methods.
|
|
372
|
+
- **`method.js`** — the concept-as-graph host toolkit (the middle spine): `applySubgraphArg` / `mapTemplate` /
|
|
373
|
+
`mapSubgraph` (a method receives + applies a sub-graph param; `Map` fans a body per element with fresh ids),
|
|
374
|
+
`lintMethod(def)` (the decidability invariants + the footprint/frame check), `selectCluster` (case-parameterized
|
|
375
|
+
selection by mutually-exclusive typed gates).
|
|
376
|
+
|
|
377
|
+
### C-contract — composition soundness & the un-learn loop (`lib/authoring/contract.js`)
|
|
378
|
+
|
|
379
|
+
The defeasible separation-triple checker (Use 2's soundness). Exposed on the facade as deep-path; ZERO-CORE.
|
|
380
|
+
|
|
381
|
+
- **`checkCompose(m1, m2, opts)`** → `{ verdict:'sound'|'unsound'|'escalate', shared, perKey, reasons, needsOracle }`
|
|
382
|
+
— `post(m1) ⊨ pre(m2)` over `write(m1)∩read(m2)`, by per-key **abstract-domain** entailment (`normalize` /
|
|
383
|
+
`entailsKey`); never false-accepts (out-of-fragment / under-determined → `escalate`). `opts.oracle` for an
|
|
384
|
+
effecting m1 (G2).
|
|
385
|
+
- **`assertPost(contract, factsAfter, touchedKeys, opts)`** → `{ ok, violations, blame }` — the runtime monitor:
|
|
386
|
+
G1 frame-completeness (touched ⊆ declared write), the post must hold, G2 the effect-tag oracle.
|
|
387
|
+
- **`footprintCycles(methods)`** → cycles of retractable methods (Tarjan-SCC; G3, reject before they oscillate).
|
|
388
|
+
- **`reviseOnBlame(contract, {key,value})`** → a NEW contract with the pre specialized (CEGIS — un-learn, not
|
|
389
|
+
removal). **`satisfies(atoms, facts)`** — is a method applicable to a case (selection after a revision).
|
|
390
|
+
**`acceptRate(verdicts)`** — the measured typed-coverage fraction.
|
|
391
|
+
|
|
392
|
+
### Durable executor — run methods as workflow-nets (`lib/durable/`)
|
|
393
|
+
|
|
394
|
+
The "execute" half of the build/execute separation: a thin durable substrate that runs case records through a
|
|
395
|
+
compiled method-net (the belief / durable boundary). ZERO-CORE; on the facade as `Graph.durable` +
|
|
396
|
+
`Graph.createCheckpointStore({file})`.
|
|
397
|
+
|
|
398
|
+
- **`checkpoint-store.js`** — `createMemoryCheckpointStore()` / `createSqliteCheckpointStore({file})` (one
|
|
399
|
+
contract). The durable **marking** (`ensureRun`/`inject`/`claim`/`move`/`fail`/`joinArrive`/`failGroup`/
|
|
400
|
+
`track`/`rollbackInflight`/`marking`/`stats`), the content-addressed **memo** (`memoGet`/`memoSet`), the
|
|
401
|
+
createdRefs rollback. Crash-safety = lease-expiry + `rollbackInflight` + a **fencing token** (a monotonic
|
|
402
|
+
persisted leaseId; a re-claimed lease fences out a zombie worker).
|
|
403
|
+
- **`xlate.js`** — `compileMethod(spec) → net` (a select+task+map+reduce spec → a workflow-net), `validateNet`
|
|
404
|
+
(structural lint), `indexByFrom`.
|
|
405
|
+
- **`interpreter.js`** — `runFlow(store, runId, net, { runTask, keyOf?, foldKeyOf?, oracle?, assertStep?, lease?,
|
|
406
|
+
batch?, maxSteps? })` → measured counters. Drains records: typed `select`, content-memoized `task`, `map`
|
|
407
|
+
fan-out, the fold-back `join`/`fold`. A per-step `contract` is asserted before commit (a violation quarantines
|
|
408
|
+
+ blames). Async (real LLM micro-tasks). Resumable (call again after `rollbackInflight`).
|
|
409
|
+
- **`fold.js`** — `foldSiblings(siblings, reduce)` (the JOIN's monoid algebra; commutative = order-independent),
|
|
410
|
+
`monoids()`, `isCommutative(name)`.
|
|
411
|
+
- **`audit.js`** — `auditRun(store, runId)` → `{ records: { <id>: {status, terminal, result, blame, lineage…} },
|
|
412
|
+
totals }` (the derivation forest + verdict + blame), `auditSummary(audit)` (one line per record).
|
|
413
|
+
|
|
414
|
+
### Learned concepts — population training, plasticity & serving (`lib/authoring/`)
|
|
415
|
+
|
|
416
|
+
Train concepts as neural-net populations instead of hand-authoring them, then bake the frozen result
|
|
417
|
+
back into the engine. Host-side, ZERO-CORE, shelved (kept for the curious).
|
|
418
|
+
|
|
419
|
+
- **`equilibrium.js`** — gradient through a fixpoint (Deep Equilibrium Models / implicit diff):
|
|
420
|
+
`solveFixpoint(F, z0, {maxIter,tol})` (Picard to `z*`), `implicitGrad(Jz, Jtheta, gradL, {mode})`
|
|
421
|
+
(`mode:'direct'` dense adjoint solve or `{neumann:K}`), `spectralRadius(Jz)` (the `ρ` regime
|
|
422
|
+
instrument), `numJac(fn, point)` (finite-difference Jacobian of one sweep).
|
|
423
|
+
- **`concept-net.js`** — a population of concept-units (gate-NN × update-NN):
|
|
424
|
+
`ringPopulation(K)` / `chainPopulation(K)` / `widePopulation(K)` (builders) →
|
|
425
|
+
`train(pop, {X,T,steps,lr,hard})` (learn at the fixpoint, returns `{theta,loss0,loss,rho}`),
|
|
426
|
+
`grad` / `loss`, `evolve({makePop,X,T,maxK,margin})` (grow the form by success, utility-gated),
|
|
427
|
+
`bakePopulation(pop, theta)` → `{conceptTree, providers}` (serve a frozen population as real engine
|
|
428
|
+
concepts), `unrollPopulation(pop, N)` → `{pop, tieTheta, readout}` (serve a *cyclic* population by
|
|
429
|
+
unrolling its fixpoint to depth N; a direct cyclic bake deadlocks).
|
|
430
|
+
- **`lifecycle.js`** — the plasticity ledger: `createLifecycle()` → `register` / `record(name, ok)` /
|
|
431
|
+
`plasticity(name)` (the unified knob `p∈[0,1]`) / `regime(name)` / `reputation(name)`. Thread
|
|
432
|
+
`plasticity` into `createLLMProvider({ ask, plasticity })` (→ temperature) or `createNet(net,
|
|
433
|
+
{ plasticity })` (→ STE exploration noise) so `p=1` explores / `p=0` serves deterministically.
|
|
434
|
+
|
|
435
|
+
### Combos (`Graph.combos.*`) — thin, delivered assemblies
|
|
436
|
+
|
|
437
|
+
Each combo composes existing bricks with the product posture ON by default (fail-closed, memo/store
|
|
438
|
+
ON, validator ON); none is a required path — the bricks stay usable "à nu". Full guide:
|
|
439
|
+
`doc/usage.md` §9; per-capability maturity + numbers: [CAPABILITIES.md](CAPABILITIES.md).
|
|
440
|
+
|
|
441
|
+
| combo | role |
|
|
442
|
+
|---|---|
|
|
443
|
+
| `createAppliance` (C1) | typed-QA appliance: intake → reason loop → typed refusal → memo |
|
|
444
|
+
| `createDurableRunner` (C2) | durable workflow runner (compile / run / resume / audit) |
|
|
445
|
+
| `createLearningLibrary` (C3) | learning method library: cost ladder + crystallize + blame/credit + `.sgc` |
|
|
446
|
+
| `reactiveKG` (C4) | the engine's original Use-1 preset over `fromDirs` (builtins ON) |
|
|
447
|
+
| `createSelfMod` (C5) | supervised self-modification (opt-in, guarded; `rollbackTo` = the guarantee) |
|
|
448
|
+
| `createProxyCache` (C6) | local-first proxy cache / distiller (covered → local at 0 frontier calls) |
|
|
449
|
+
| `createPlanLoop` (C7) | the hierarchical plan loop (the piece-by-piece zoom); `decompose`/`serveLeaf` injected |
|
|
450
|
+
| `createMixtureServe` (C8) | orientation menu + optional `preRoute` over a low-quant target (the runtime cross-agreement trust tier is REFUTED at scale — fail-closed default) |
|
|
451
|
+
| `createCriticalMind` (C9) | the external critical mind: `run({topic, statements?, viewpoints?})` → typed ledger + verdict or honest UNDECIDED (mechanical only at the measured margin bound) |
|
|
452
|
+
|
|
453
|
+
The C7 bricks are standalone `lib/authoring/` modules: `dag-decompose`, `context-project` (with the
|
|
454
|
+
`stratComplete` stratified rendering), `givens` (`numberGivens` / `cellGivens` / `seedOf` / `labelsOf` —
|
|
455
|
+
`labelsOf` implements the measured CELLS rule: label an input iff its provenance is a structured table
|
|
456
|
+
cell, and pass it as `run(task, { givens, labels })`), `leaf-io`.
|
|
457
|
+
|
|
458
|
+
### Studio (embeddable web workbench)
|
|
459
|
+
|
|
460
|
+
`const server = Graph.createStudioServer({ Graph, root, ask, logger })` — an http+ws server over a
|
|
461
|
+
registry of live `Graph` sessions, driving a no-build React UI. Wire ops (`lib/studio/protocol.js`):
|
|
462
|
+
`grammarGraph` · `corpusManifest` · `exportCorpus` / `importCorpus` (`.sgc`) · `providerTrace` ·
|
|
463
|
+
`mergePreview` · `forkPlan` · `fork`/`merge`/`selectSession` · `mutate`/`run`/`state` ·
|
|
464
|
+
`revisions`/`snapshot`/`rollback`/`diff` · `validateConcept`/`patchConcept`/`addConcept` · `prompt`.
|
|
465
|
+
Events include a Session-derived `retract` (the red-flash signal). Also via `bin/sg studio`.
|
|
466
|
+
|
|
467
|
+
## Logging & diagnostics
|
|
468
|
+
|
|
469
|
+
One logger per graph (`graph._log`, exposed as `graph.logger`). Levels, severity descending:
|
|
470
|
+
`error > warn > log > info > verbose` — a record reaches sinks iff `rank(level) <= rank(threshold)`
|
|
471
|
+
(default `warn`, or env `SG_LOG_LEVEL`; the `sg run` CLI overrides its own session to `info`). A `LogRecord` is `{ level, ts, label, ctx, msg, args }` and is
|
|
472
|
+
JSON-serializable (Errors in `args` are reduced to `{name,message,stack}`).
|
|
473
|
+
|
|
474
|
+
**Configure** (in `cfg`, e.g. via `new Graph(seed, conf, conceptMap)` or `Graph.fromDirs({conf})`):
|
|
475
|
+
|
|
476
|
+
| key | meaning |
|
|
477
|
+
|---|---|
|
|
478
|
+
| `cfg.logger` | inject a logger instance (`Graph.createLogger(...)`); overrides the rest |
|
|
479
|
+
| `cfg.logLevel` | threshold name for the auto-built logger |
|
|
480
|
+
| `cfg.onLog(record)` | convenience sink fn |
|
|
481
|
+
|
|
482
|
+
**`graph.logger` interface** (the debugger/host hook):
|
|
483
|
+
|
|
484
|
+
| method | returns |
|
|
485
|
+
|---|---|
|
|
486
|
+
| `addSink(fn)` / `removeSink(fn)` | register/unregister `fn(record)` |
|
|
487
|
+
| `tail(n, filter?)` | last `n` records; `filter` = `{concept?, target?, applyId?, level?}` |
|
|
488
|
+
| `records` | the bounded ring buffer (default 500) |
|
|
489
|
+
| `setLevel(name)` / `level` | get/set the threshold |
|
|
490
|
+
| `child(ctx)` | a logger that merges `ctx` into every record |
|
|
491
|
+
|
|
492
|
+
**Provider logging contract** (no provider-signature change): inside a provider, reach a context logger via
|
|
493
|
+
`scope.log` (ctx `{target,type}`) or `concept.log(scope)` (ctx `{concept,target,type,applyId}`):
|
|
494
|
+
|
|
495
|
+
```js
|
|
496
|
+
function work ( graph, concept, scope, argz, cb ) {
|
|
497
|
+
const log = concept.log(scope); // capture early (freezes applyId for async)
|
|
498
|
+
log.verbose('prompt', prompt);
|
|
499
|
+
log.warn('input missing on %s', scope._._id);
|
|
500
|
+
cb(null, { $_id: '_parent', Worked: true });
|
|
501
|
+
}
|
|
502
|
+
```
|
|
503
|
+
|
|
504
|
+
Each concept-apply mints `graph._applyId`, stamped into **both** the contextual logger and the
|
|
505
|
+
`cfg.onConceptApply` trace record. So the logs a concept produced *while applying* are retrievable with
|
|
506
|
+
`graph.logger.tail(n, { concept })` or `{ applyId }`, and join the trace by `applyId` — all **without
|
|
507
|
+
storing anything on the graph objects** (logs live in the logger, never as facts). For full history beyond
|
|
508
|
+
the bounded buffer, attach a sink (file/studio).
|
|
509
|
+
|
|
510
|
+
**CLI:** `sg run … [--log-level <lvl>] [--log-mode dashboard|plain] [--log-plain] [--log-file <path>]
|
|
511
|
+
[--log-file-level <lvl>]`. A styled boot banner prints at startup. `dashboard` = TTY mode where colored
|
|
512
|
+
logs scroll normally under a live **status bar pinned at the bottom** (graph state, unstable node/segment
|
|
513
|
+
counts, main-loop queue size, rev, applies, provider time, elapsed); degrades to plain off a TTY. `plain` =
|
|
514
|
+
line output (logs → stderr, run summary → stdout). `--log-file` writes `.jsonl` (machine-readable) or
|
|
515
|
+
formatted text. **Workers:** pass `logger` to `createGraphWorker`/`spawnGraph` and a dispatched graph's
|
|
516
|
+
log records re-emit into it, tagged `{worker:true}`.
|
|
517
|
+
|
|
518
|
+
`Graph.createLogger({ label, level, onRecord, capacity, console })` builds a logger standalone.
|
|
519
|
+
|
|
520
|
+
## Serving surfaces (`lib/sg/serve.js`, `lib/sg/mcp.js`)
|
|
521
|
+
|
|
522
|
+
Two zero-dep, zero-integration fronts over the combos (full guide: `doc/usage.md` §10):
|
|
523
|
+
|
|
524
|
+
- **`sg serve`** — an OpenAI-compatible endpoint (`POST /v1/chat/completions`, `GET /v1/models`) over the
|
|
525
|
+
C6 proxy cache. `createServeHandler({proxy, model, onAnswer})` is the PURE request handler (stub-testable);
|
|
526
|
+
`startServeServer({handler, port, host})` is the node:http wrapper. Provenance on every completion:
|
|
527
|
+
headers `x-sg-served-from|arm|cost|coverage|saved|sgc-version` + `usage.sg_*` mirror; `stream:true` is simulated SSE.
|
|
528
|
+
The v1 wire contract: the query = the LAST user turn (a QA cache, not a dialog engine).
|
|
529
|
+
- **`sg mcp`** — an MCP tools server (stdio JSON-RPC). `createMcpServer({tools, serverInfo})` is the pure
|
|
530
|
+
dispatcher; `defaultTools(wiring)` wires the base tools — `ask` (answer OR a STRUCTURED typed refusal),
|
|
531
|
+
`drift`, `metrics`, `lattice_load` (growth through `loadLattice` — the only registry write path),
|
|
532
|
+
`methods_describe`, `lattice_rings`, `trace_tail` — plus the ASSISTANT lanes: SOFT `hint` /
|
|
533
|
+
`state_recall` / `state_note` / `plan_sync` (the typed task delta, JTMS `reopen` included), HARD
|
|
534
|
+
`propose` (gate-tested; `force` → recorded-untrusted, never admission), INSTANCES `graph_invoke` /
|
|
535
|
+
`graph_instances`, and the C9 `critique` tool (typed ledger + verdict or honest UNDECIDED; OPEN
|
|
536
|
+
points + UNDECIDED = a typed data request — re-call with `statements`). `stockWiring(sgc)` /
|
|
537
|
+
`--stock <f.sgc>` wires `hint`/`propose` from a forged stock; `startMcpStdio` is the line-framed
|
|
538
|
+
transport.
|
|
539
|
+
- **`sg flow run <module.js>`** — the C2 durable runner as a CLI; the module exports
|
|
540
|
+
`{ spec, runTask | makeRunTask(), keyOf?, STREAM? }`.
|
|
541
|
+
- **Intake depth back-check** — `require('lib/providers/intake.js').makeProseBackCheck({ask, proseOf?,
|
|
542
|
+
onBlame?})` → a ready-made independent verifier for `createIntake({backCheck})` (a 'fail' downgrades the
|
|
543
|
+
intake to `untyped`; judged-wrong keys surface via `onBlame`).
|
|
544
|
+
|
|
545
|
+
## Running in-repo
|
|
546
|
+
|
|
547
|
+
```bash
|
|
548
|
+
npm test # unit + integration (node:test, native CJS — no Babel)
|
|
549
|
+
node examples/integrated-demo/run.js --replay # the public verifiable: 7 checks, deterministic, no GPU
|
|
550
|
+
node examples/run-basic.js # non-LLM end-to-end stabilization over the real `common` set
|
|
551
|
+
node examples/run-problem.js # LLM-driven plan decomposition (needs an endpoint; see lib/providers/llm.js)
|
|
552
|
+
node bin/sg run --concepts ./concepts --builtins # standalone CLI boot
|
|
553
|
+
```
|
|
554
|
+
|
|
555
|
+
The engine is native CommonJS and runs directly under Node (no build step; `tests/_boot.js` just sets
|
|
556
|
+
`__SERVER__`).
|