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
|
@@ -0,0 +1,382 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright 2026 Nathanael Braun
|
|
3
|
+
* @author : Nathanael BRAUN <pp9ping@gmail.com>
|
|
4
|
+
*
|
|
5
|
+
* This program is free software: you can redistribute it and/or modify
|
|
6
|
+
* it under the terms of the GNU Affero General Public License as published by
|
|
7
|
+
* the Free Software Foundation, either version 3 of the License, or
|
|
8
|
+
* (at your option) any later version.
|
|
9
|
+
*
|
|
10
|
+
* This program is distributed in the hope that it will be useful,
|
|
11
|
+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
12
|
+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
13
|
+
* GNU Affero General Public License for more details.
|
|
14
|
+
*
|
|
15
|
+
* You should have received a copy of the GNU Affero General Public License
|
|
16
|
+
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
var isArray = require('is').array;
|
|
20
|
+
var debug = require('../log').defaultLogger;// module fallback; applyTo rebinds to graph._log
|
|
21
|
+
var dmerge = require('deepmerge');
|
|
22
|
+
var { compileExpression } = require('../expr');
|
|
23
|
+
|
|
24
|
+
function Concept( _, graph, parent ) {
|
|
25
|
+
this.init(_, graph, parent);
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
Concept.prototype = {
|
|
29
|
+
_static : Concept,
|
|
30
|
+
/**
|
|
31
|
+
* Init & mount child concepts
|
|
32
|
+
* @param record
|
|
33
|
+
* @param graph
|
|
34
|
+
* @param parent
|
|
35
|
+
*/
|
|
36
|
+
init : function ( record, graph, parent ) {
|
|
37
|
+
var me = this,
|
|
38
|
+
cKeys = record.childConcepts && Object.keys(record.childConcepts) || [];
|
|
39
|
+
|
|
40
|
+
me._schema = record;
|
|
41
|
+
graph._conceptLib[record._id] = this;
|
|
42
|
+
if ( cKeys.length ) {
|
|
43
|
+
this._openConcepts = {};
|
|
44
|
+
this._openConceptsRequires = {};
|
|
45
|
+
|
|
46
|
+
cKeys.map(
|
|
47
|
+
function ( v ) {
|
|
48
|
+
me._openConcepts[v] = new Concept(record.childConcepts[v], graph, me);
|
|
49
|
+
me._openConceptsRequires[v] =
|
|
50
|
+
isArray(record.childConcepts[v].require) ? record.childConcepts[v].require
|
|
51
|
+
: record.childConcepts[v].require && [record.childConcepts[v].require] || [];
|
|
52
|
+
}
|
|
53
|
+
);
|
|
54
|
+
}
|
|
55
|
+
else
|
|
56
|
+
this.isLeaf = true;
|
|
57
|
+
|
|
58
|
+
// generate the assert fn (asserts + ensure, &&-joined)
|
|
59
|
+
this._compileAssert();
|
|
60
|
+
this._id = record._id;
|
|
61
|
+
this._name = record._name;
|
|
62
|
+
this._parent = parent;
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
},
|
|
66
|
+
/**
|
|
67
|
+
* (Re)compile this concept's applicability test from its current `_schema`
|
|
68
|
+
* (assert + ensure expressions, &&-joined). Called at init and again by
|
|
69
|
+
* `patch()` so a hot-patched assert takes effect immediately.
|
|
70
|
+
*/
|
|
71
|
+
_compileAssert: function () {
|
|
72
|
+
var record = this._schema,
|
|
73
|
+
asserts = isArray(record.assert) && record.assert
|
|
74
|
+
|| record.assert && [record.assert]
|
|
75
|
+
|| [],
|
|
76
|
+
ensure = isArray(record.ensure) && record.ensure
|
|
77
|
+
|| record.ensure && [record.ensure]
|
|
78
|
+
|| [];
|
|
79
|
+
|
|
80
|
+
asserts = asserts.concat(ensure);
|
|
81
|
+
|
|
82
|
+
var _assertFn = compileExpression(asserts, { empty: true });
|
|
83
|
+
this._assertTest = function ( scope, graph ) {
|
|
84
|
+
return _assertFn(function ( ref ) { return scope.getRef(ref); });
|
|
85
|
+
};
|
|
86
|
+
return this;
|
|
87
|
+
},
|
|
88
|
+
/**
|
|
89
|
+
* Hot-patch this expert: deep-merge `updates` into `_schema` and recompile
|
|
90
|
+
* the applicability test. Arrays (assert/ensure/require/provider) are
|
|
91
|
+
* REPLACED, not concatenated, so patching an assert overrides the old one.
|
|
92
|
+
* Re-evaluating live objects against the patched expert is the graph's job
|
|
93
|
+
* (see Graph.patchConcept).
|
|
94
|
+
* @param updates partial concept schema
|
|
95
|
+
*/
|
|
96
|
+
patch : function ( updates ) {
|
|
97
|
+
this._schema = dmerge(this._schema, updates, { arrayMerge: function ( dest, src ) { return src; } });
|
|
98
|
+
this._compileAssert();
|
|
99
|
+
return this;
|
|
100
|
+
},
|
|
101
|
+
/**
|
|
102
|
+
* Apply-correlated context logger for a provider: ctx {concept,target,type,applyId}.
|
|
103
|
+
* A METHOD (not a stored property) because a Concept instance is shared across many
|
|
104
|
+
* scopes and concurrent async applies would race a mutable field. `applyId` is read
|
|
105
|
+
* from `scope._applyId` (set by applyTo for the duration of the apply). A provider
|
|
106
|
+
* that logs asynchronously should capture `const log = concept.log(scope)` EARLY so
|
|
107
|
+
* the child snapshots the right applyId. Used to later retrieve a concept's apply-logs
|
|
108
|
+
* via graph.logger.tail(n, {concept|applyId}) — without storing anything on the graph.
|
|
109
|
+
*/
|
|
110
|
+
log : function ( scope ) {
|
|
111
|
+
var graph = scope._graph,
|
|
112
|
+
t = scope._ && (scope._.Node ? 'node' : scope._.Segment ? 'segment' : 'object');
|
|
113
|
+
return graph._log.child({
|
|
114
|
+
concept: this._name, conceptId: this._id,
|
|
115
|
+
target : scope._ && scope._._id, type: t, applyId: scope._applyId
|
|
116
|
+
});
|
|
117
|
+
},
|
|
118
|
+
/**
|
|
119
|
+
* Search Parent concept by name
|
|
120
|
+
* @param parent [Concept|undefined]
|
|
121
|
+
*/
|
|
122
|
+
hasParent : function ( cn ) {
|
|
123
|
+
var c = this;
|
|
124
|
+
while ( c = c._parent )
|
|
125
|
+
if ( c._name === cn )
|
|
126
|
+
return c;
|
|
127
|
+
},
|
|
128
|
+
/**
|
|
129
|
+
* Search Parent concept by id
|
|
130
|
+
* @param parent [Concept|undefined]
|
|
131
|
+
*/
|
|
132
|
+
hasParentId : function ( cid ) {
|
|
133
|
+
var c = this;
|
|
134
|
+
while ( c = c._parent )
|
|
135
|
+
if ( c._id === cid )
|
|
136
|
+
return c;
|
|
137
|
+
},
|
|
138
|
+
/**
|
|
139
|
+
* Return an async task that will cast the applicable concepts
|
|
140
|
+
* @param scope
|
|
141
|
+
* @param graph
|
|
142
|
+
* @returns {Function}
|
|
143
|
+
*/
|
|
144
|
+
applyTo : function ( scope, graph ) {
|
|
145
|
+
var me = this;
|
|
146
|
+
// onCast detection: is this the not-cast -> cast transition? (symmetric to `cleaner`,
|
|
147
|
+
// which fires on cast -> uncast). Captured BEFORE we record the mapping: re-applies
|
|
148
|
+
// during a trial/iteration loop see it already mapped (no re-fire); an uncast deletes
|
|
149
|
+
// the mapping (Entity.unCast) so a later recast fires onCast again (re-subscribe).
|
|
150
|
+
var firstCast = !scope._mappedConcepts[me._name];
|
|
151
|
+
// will push or return task (or just inc some sema)
|
|
152
|
+
scope._mappedConcepts[me._name] = me;
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
return function ( graph, flow ) {
|
|
156
|
+
var debug = graph._log;// route the engine's own provider diagnostics per-graph
|
|
157
|
+
|
|
158
|
+
// oscillation backstop (#11.c.1): bound how many times this (target, concept)
|
|
159
|
+
// applies within an episode (the tally resets on each healthy settle). Over the
|
|
160
|
+
// ceiling -> record WHY in the `divergent` array fact + skip this apply; that
|
|
161
|
+
// fact is a non-cast condition (Concept.isApplicableTo) so the concept de-casts.
|
|
162
|
+
if ( graph._applyCount ) {
|
|
163
|
+
var _ck = scope._._id + '/' + me._name;
|
|
164
|
+
graph._applyCount[_ck] = (graph._applyCount[_ck] || 0) + 1;
|
|
165
|
+
if ( graph._applyCount[_ck] > graph._applyCap ) {
|
|
166
|
+
graph._markDivergent && graph._markDivergent(scope, me, graph._applyCount[_ck]);
|
|
167
|
+
return;
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
// Mint a per-apply id and expose it on the Entity (NOT on `scope._`, so it is
|
|
172
|
+
// never serialized) for the duration of this apply. It tags both the trace
|
|
173
|
+
// record (mkCtx below) and any logs the provider emits via concept.log(scope),
|
|
174
|
+
// so an apply's logs and its trace can be joined afterwards by applyId.
|
|
175
|
+
var applyId = ++graph._applyId;
|
|
176
|
+
scope._applyId = applyId;
|
|
177
|
+
var dlog = me.log(scope);// apply-correlated logger for the engine's own diagnostics
|
|
178
|
+
|
|
179
|
+
// trace context: attributes the mutation(s) this apply produces back to
|
|
180
|
+
// this concept (read by Graph.pushMutation -> cfg.onConceptApply).
|
|
181
|
+
var startTm = Date.now(),
|
|
182
|
+
why = me._computeWhy(scope),
|
|
183
|
+
mkCtx = function ( kind, ms ) {
|
|
184
|
+
return { conceptId: me._id, conceptName: me._name, targetId: scope._._id, kind: kind, why: why, ms: ms, applyId: applyId };
|
|
185
|
+
};
|
|
186
|
+
|
|
187
|
+
if ( me._schema.provider ) {// call the concept data provider
|
|
188
|
+
var p = isArray(me._schema.provider) ? me._schema.provider[0] : me._schema.provider,
|
|
189
|
+
argz = isArray(me._schema.provider) && me._schema.provider.slice(1),
|
|
190
|
+
providers = graph.static._providers, checkTm;
|
|
191
|
+
|
|
192
|
+
// stats
|
|
193
|
+
|
|
194
|
+
let execTm = Date.now();
|
|
195
|
+
|
|
196
|
+
p = p.split("::");
|
|
197
|
+
if ( providers[p[0]] && providers[p[0]][p[1]] ) {
|
|
198
|
+
|
|
199
|
+
flow.wait();// inc async flow
|
|
200
|
+
// P2 fix: flow.wait() is unconditional, so the lock MUST be released exactly once on
|
|
201
|
+
// every provider outcome — a mutation, NO mutation (idempotent skip), an error-only cb,
|
|
202
|
+
// or a synchronous throw. Releasing only inside the `r && pushMutation` callback leaked
|
|
203
|
+
// the lock whenever the provider returned no mutation, wedging the stabilize loop forever
|
|
204
|
+
// (`_stabilizing` stuck true). releaseFlow() guarantees a single balanced release.
|
|
205
|
+
var _released = false;
|
|
206
|
+
var releaseFlow = function () { if ( !_released ) { _released = true; flow.release(); } };
|
|
207
|
+
|
|
208
|
+
//debug.info(graph.cfg.label + " : Do provider ", p, 'on', scope._._id);
|
|
209
|
+
try {
|
|
210
|
+
checkTm = setTimeout(() => {
|
|
211
|
+
dlog.warn("still waiting on provider %s (25s)", p.join('::'))
|
|
212
|
+
}, 25000)
|
|
213
|
+
providers[p[0]][p[1]](
|
|
214
|
+
graph, me, scope, argz,
|
|
215
|
+
function ( e, r ) {
|
|
216
|
+
clearTimeout(checkTm);
|
|
217
|
+
|
|
218
|
+
// stats
|
|
219
|
+
graph._statsByProvider[p] = graph._statsByProvider[p] || 0;
|
|
220
|
+
graph._statsByProvider[p] += (Date.now() - execTm);
|
|
221
|
+
|
|
222
|
+
//debug.info(graph.cfg.label + " : Done provider ", p, 'on', scope._._id);
|
|
223
|
+
if ( r ) graph.pushMutation(r, scope._._id, 0, 0, 0, refs => {
|
|
224
|
+
//debug.info(graph.cfg.label + " : Done provider ", p, 'on', scope._._id);
|
|
225
|
+
releaseFlow()// w8 bagrefs b4 next cycle
|
|
226
|
+
}, mkCtx('provider', Date.now() - execTm));// so bagrefs will be w8 before the graph restart ... :/
|
|
227
|
+
else releaseFlow();// no mutation (idempotent skip / error-only cb) — still release or the loop never settles (P2)
|
|
228
|
+
e && dlog.warn("provider %s failed", p.join('::'), e);
|
|
229
|
+
});
|
|
230
|
+
} catch ( e ) {
|
|
231
|
+
releaseFlow();// provider threw synchronously after flow.wait() — release or deadlock (P2)
|
|
232
|
+
dlog.error("provider %s threw on %s", p.join('::'), scope._._id, e);
|
|
233
|
+
setTimeout(() => {
|
|
234
|
+
throw e
|
|
235
|
+
});
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
}
|
|
239
|
+
else {
|
|
240
|
+
scope.set(me._name, true, graph);// no provider wired -> flag the concept true so the graph can still settle
|
|
241
|
+
dlog.log("provider not found: %s", p.join('::'));
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
}
|
|
245
|
+
else if ( me._schema.type == "enum" ) {// enum are not used for now
|
|
246
|
+
graph.pushMutation(
|
|
247
|
+
{
|
|
248
|
+
$_id : "_parent",
|
|
249
|
+
[me._name]: me.isLeaf && [] || Object.keys(me._openConcepts)
|
|
250
|
+
},
|
|
251
|
+
scope._._id, 0, 0, 0, 0, mkCtx('enum', Date.now() - startTm)
|
|
252
|
+
);
|
|
253
|
+
}
|
|
254
|
+
else {
|
|
255
|
+
// scope.set(me._name, true, graph);
|
|
256
|
+
graph.pushMutation(
|
|
257
|
+
{
|
|
258
|
+
$_id : "_parent",
|
|
259
|
+
[me._name]: me._schema.defaultValue || true
|
|
260
|
+
},
|
|
261
|
+
scope._._id, 0, 0, 0, 0, mkCtx('default', Date.now() - startTm)
|
|
262
|
+
);
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
// if there a tpl in the concept definition apply it
|
|
266
|
+
if ( me._schema.applyMutations ) {
|
|
267
|
+
graph.pushMutation(me._schema.applyMutations, scope._._id, 0, 0, 0, 0, mkCtx('applyMutations', Date.now() - startTm));
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
// onCast lifecycle hook (the standing-cluster keystone) — symmetric to `cleaner`.
|
|
271
|
+
// Fires ONCE on the not-cast -> cast transition (firstCast), so a live subscription /
|
|
272
|
+
// handle is set up exactly once. Convention: store the handle on `scope._liveHandles`
|
|
273
|
+
// (off `_`, never serialized); the concept's `cleaner` tears it down on uncast. A
|
|
274
|
+
// re-apply does NOT re-fire it; an uncast -> recast does (re-subscribe). Balanced flow
|
|
275
|
+
// release on every outcome (mutation / none / throw) — the P2 lesson.
|
|
276
|
+
if ( firstCast && me._schema.onCast ) {
|
|
277
|
+
var op = isArray(me._schema.onCast) ? me._schema.onCast[0] : me._schema.onCast,
|
|
278
|
+
oargz = isArray(me._schema.onCast) && me._schema.onCast.slice(1),
|
|
279
|
+
oprov = graph.static._providers, ops = op.split("::");
|
|
280
|
+
if ( oprov[ops[0]] && oprov[ops[0]][ops[1]] ) {
|
|
281
|
+
flow.wait();
|
|
282
|
+
var _oReleased = false, oRelease = function () { if ( !_oReleased ) { _oReleased = true; flow.release(); } };
|
|
283
|
+
try {
|
|
284
|
+
oprov[ops[0]][ops[1]](graph, me, scope, oargz, function ( e, r ) {
|
|
285
|
+
if ( r ) graph.pushMutation(r, scope._._id, 0, 0, 0, oRelease, mkCtx('onCast', 0));
|
|
286
|
+
else oRelease();
|
|
287
|
+
e && dlog.warn("onCast %s failed", op, e);
|
|
288
|
+
});
|
|
289
|
+
} catch ( e ) { oRelease(); dlog.error("onCast %s threw on %s", op, scope._._id, e); }
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
// if the concept implies a graph sync (allowing concepts to be applied on server )
|
|
294
|
+
if ( me._schema.syncAfter ) {
|
|
295
|
+
// graph.stabilize(()=>graph.sync());
|
|
296
|
+
}
|
|
297
|
+
};
|
|
298
|
+
},
|
|
299
|
+
/**
|
|
300
|
+
* "Why it fired": for each `require`, the resolved value and the revision of
|
|
301
|
+
* the object that holds it (object-granular — the _rev of the last mutation
|
|
302
|
+
* that touched that object, not necessarily the specific key). Used by the
|
|
303
|
+
* trace (cfg.onConceptApply). Resolves without `follow` so it adds no watchers.
|
|
304
|
+
* @param scope the Entity the concept is being cast on
|
|
305
|
+
*/
|
|
306
|
+
_computeWhy : function ( scope ) {
|
|
307
|
+
var requires = isArray(this._schema.require) && this._schema.require
|
|
308
|
+
|| this._schema.require && [this._schema.require]
|
|
309
|
+
|| [];
|
|
310
|
+
return requires.map(function ( c ) {
|
|
311
|
+
var value = scope.getRef(c), producedAtRev = null;
|
|
312
|
+
try {
|
|
313
|
+
if ( c.indexOf(':') !== -1 ) {
|
|
314
|
+
var box = scope.getRef(c.slice(0, c.lastIndexOf(':') + 1));// trailing-colon -> the object
|
|
315
|
+
producedAtRev = box && box._ ? box._._rev : (box && box._rev) || null;
|
|
316
|
+
}
|
|
317
|
+
else producedAtRev = scope._ && scope._._rev;
|
|
318
|
+
} catch ( e ) { producedAtRev = null; }
|
|
319
|
+
return { require: c, value: value, producedAtRev: producedAtRev };
|
|
320
|
+
});
|
|
321
|
+
},
|
|
322
|
+
/**
|
|
323
|
+
* Side-effect-free applicability gate — true iff this concept should cast on
|
|
324
|
+
* `scope`. A GATE, not a trigger: it only runs when the object is (re)tested.
|
|
325
|
+
* Checked in order:
|
|
326
|
+
* 1. autoCast:false → never auto-casts (manual/triggered only).
|
|
327
|
+
* 2. divergent → if the object carries a divergent record for this concept
|
|
328
|
+
* (blew the apply ceiling), refuse to (re)cast (#11.c.1).
|
|
329
|
+
* 3. require → every `require` ref must resolve; getRef(c, true) installs
|
|
330
|
+
* a FOLLOW watcher so the object is re-tested when a missing
|
|
331
|
+
* require later appears (this is how casting waits on inputs).
|
|
332
|
+
* 4. assert/ensure → the compiled _assertTest must be true.
|
|
333
|
+
* @param {Entity} scope
|
|
334
|
+
* @param {Graph} graph
|
|
335
|
+
* @returns {boolean}
|
|
336
|
+
*/
|
|
337
|
+
isApplicableTo: function ( scope, graph ) {
|
|
338
|
+
if ( this._schema.autoCast === false ) {
|
|
339
|
+
return;
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
// divergent fact = non-cast condition (#11.c.1): a (target, concept) that blew the
|
|
343
|
+
// apply ceiling carries a reason record in `divergent`; it must not (re)cast.
|
|
344
|
+
var _dv = scope._ && scope._.divergent;
|
|
345
|
+
if ( _dv && _dv.length )
|
|
346
|
+
for ( var _i = 0; _i < _dv.length; _i++ )
|
|
347
|
+
if ( _dv[_i] && _dv[_i].concept === this._name ) return false;
|
|
348
|
+
|
|
349
|
+
var me = this,
|
|
350
|
+
requires = isArray(me._schema.require) && me._schema.require
|
|
351
|
+
|| me._schema.require && [me._schema.require]
|
|
352
|
+
|| [];
|
|
353
|
+
requires = requires.filter(function ( c ) {
|
|
354
|
+
// getRef(c, true): read the require AND install a follow-watcher, so the
|
|
355
|
+
// object is re-tested if this require is produced later. Keep the UNRESOLVED
|
|
356
|
+
// ones (0 is a valid value, not "missing").
|
|
357
|
+
var ref = scope.getRef(c, true);
|
|
358
|
+
return (!ref && (ref != 0)) && true || null;
|
|
359
|
+
});
|
|
360
|
+
|
|
361
|
+
// applicable iff no require is still unresolved AND the assert/ensure test holds
|
|
362
|
+
return !requires.length
|
|
363
|
+
&& this._assertTest(scope, graph);
|
|
364
|
+
},
|
|
365
|
+
/**
|
|
366
|
+
* Remove the follow-watchers this concept's requires installed on `scope`
|
|
367
|
+
* (the inverse of the getRef(c, true) calls in isApplicableTo) — used when the
|
|
368
|
+
* concept is retracted so a defunct cast no longer destabilizes the object.
|
|
369
|
+
* @param scope
|
|
370
|
+
* @param graph
|
|
371
|
+
*/
|
|
372
|
+
unRefRequires : function ( scope, graph ) {
|
|
373
|
+
var me = this,
|
|
374
|
+
requires = isArray(me._schema.require) && me._schema.require
|
|
375
|
+
|| me._schema.require && [me._schema.require]
|
|
376
|
+
|| [];
|
|
377
|
+
requires = requires.filter(function ( c ) {
|
|
378
|
+
return !graph.getRef(c, scope, true, true) && true || null;
|
|
379
|
+
});
|
|
380
|
+
}
|
|
381
|
+
};
|
|
382
|
+
module.exports = Concept;
|