You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
feat(admin): /dispatch graph, the topology as text (issue #54)
The graph's first consumer: renderGraph (pure, render.mjs) formats the
assembled model as folder groups, triggers with run stats and dangling
badges, skills with reachability badges, and edges labelled by their
evidence class, then the counters and the caps line, which renders
ALWAYS: edges without their bounds invite the reader to extrapolate an
unbounded chain fabric out of a depth-1, width-2 reality.
assembleGraph (index.ts, the assembleCosts twin) reads triggers FRESH
every call (OQ-008: a cached topology is a stale topology), the
resident schedulers, one bounded record scan, and the enumerations
through collectGraphInputs. Deliberately NOT an LLM-callable tool: the
enumeration spawns git per folder, and the topology is for the
operator's eyes (DES-CLI-SURFACE ungated tier; tool-count pin stands).
readTriggers now also returns the RAW entries count, because the
attribution range guard must accept an index pointing at an
unusable-but-present row.
New wiring pin: USAGE and KNOWN_SUBCOMMANDS agree member-for-member
(two copies of one list that nothing pinned together until this
amendment widened both).
Specs: NEW REQ-TOPOLOGY-GRAPH (honesty rules as requirements, the
REQ-COST-ANALYTICS discipline applied to topology).
REQ-ADMIN-VIA-PI-EXTENSION and DES-ADMIN-VIA-PI-EXTENSION AMENDED
(command list). REQ-COST-ANALYTICS UNCHANGED, checked. Docs:
docs/graph.md, README and workflows.md cross-links.
Suite in the CI posture: 2120 pass, 0 skipped; admin bundle builds.
Signed-off-by: Rob Boerman <robboerman@live.nl>
out.push("","injected skills (trigger-reachable, never AI-reachable):");
428
+
for(constnofinjected){
429
+
constmarks=(flagsByNode.get(n.id)??[]).includes("injected-ai-trigger") ? " [ai-trigger: allow is a silent no-op here]" : "";
430
+
out.push(` ${n.name} (${n.dir})${marks}`);
431
+
}
432
+
}
433
+
434
+
out.push("");
435
+
if((m.meta?.unattributedRuns??0)>0)out.push(`${m.meta.unattributedRuns} runs unattributed (triggers file changed since they ran, or they predate attribution)`);
assert.match(out,/labelany\[ai\]->triage{2}\(runs12,lastfailed\)/,"forge runs join via the persisted index");
461
+
assert.match(out,/->notify{2}observedx3/,"an observed edge carries its count");
462
+
assert.match(out,/->notify{2}mention\(potential,strong;canneverfire:targethasnoai-triggerallow\)/,"a mention of a non-eligible target says it can never fire");
["Graph: triggers and flows","","no triggers configured","","edges: -> configured, observed xN (from records), mention (potential; a mention is not a promise)","caps: chain depth <= 1, <= 2 per job, same folder only, window 30d"].join("\n"),
483
+
"the empty render is exact-equality pinned, caps included",
484
+
);
485
+
});
486
+
487
+
test("renderGraph surfaces truncation and dropped edges rather than pretending coverage",()=>{
0 commit comments