$ cat workspace-template.yaml
Ontology Node Test Bench
// A test bench that instantiates EVERY ontology node (search x3 for entity/schema/hybrid, traverse x2, entity-360, kb-search -> from-documents bridge, merge RRF, and a self-cleaning create/set/link/delete write chain). The instruction drives the agent to configure, run, and evaluate each node against pass/fail criteria and produce a consolidated report. Use to smoke-test the whole ontology stack after a deploy.
// Canvas Preview
// Instruction
Ontology Node Test Bench
Overview
This workspace instantiates EVERY ontology node so you can exercise each one against the LIVE governed graph and judge its result. Some nodes appear MULTIPLE times to cover their variants (Search is here three times — entity, schema, hybrid modes; Traverse twice — different direction/depth). You are the test driver: configure each node, run it, read its output, and mark it PASS / WARN / FAIL against the criteria below, then present one consolidated report. Most of the bench is READ-ONLY; the write nodes at the bottom run only if the user opts in — they form a self-contained island (two throwaway objects plus a link between them) that fully tears itself down afterward and can never touch a real entity.
The nodes (and what each proves)
- Search · entity mode (
ontology-search, mode=entity) — name-first lexical/kNN search. Outputresults+count. - Search · schema mode (mode=schema) — matches the query to relationship/theme TYPES, returns their instances with
matchedVia. Outputresults. - Search · hybrid mode (mode=hybrid) — both arms, RRF-fused.
- Entity 360 (
ontology-entity-360) — full profile of ONE object id. InputsobjectId,maxNamesPerType. Outputsentity,summaryText,linkCounts. - Traverse · both, depth 1 and Traverse · outgoing, depth 2 (
ontology-traverse) — walk links from an object. InputsobjectId,linkType,direction,depth. Outputresult. - KB Semantic Search (
kb-semantic-search) — vector search over document chunks. OutputdocumentIds(WIRED into From Documents),chunkTexts. - From Documents (bridge) (
ontology-from-documents) — documents → the ontology objects appearing in them.documentIdsis wired from KB Semantic Search. Outputsentities,links,truncated. - Merge Ranked Lists (RRF) (
merge-ranked-lists) — fuseslistA(wired from Search·entityresults) andlistB(wired from From Documentsentities). Outputsitems,itemsText,topId. - Create Object ×2 / Set Property / Create Link / Delete ×3 (
ontology-create-object/-set-property/-create-link/-delete) — the write path, built as a self-contained island: two throwaway objects (A, B), a link A→B between them, then three Deletes that remove both objects and the link. No field here ever references a real entity.
Phase 1 — Configure
- Make ONE
requestUserDecisionbundling: (a) an entity NAME that exists in the graph to probe (default "MAECI"); (b) a relationship/theme question (default "chi ha promulgato le leggi | who promulgated the law"); (c) run the WRITE nodes too? (default No — read-only). Keep a free-text box last. Do not prompt again after this. - Use
nodeFinderto get the fresh ids of ALL nodes — the template-preview ids are stale after cloning. - Apply with ONE
batchUpsertNodes: setqueryon Search · entity mode to the entity NAME; setqueryon Search · schema mode, Search · hybrid mode, and KB Semantic Search to the relationship/theme question. Replace every{{query}}placeholder. Leave id/type inputs (Entity 360objectId, TraverseobjectId/linkType, the write nodes) empty for now — you fill them from earlier outputs in later phases.
Phase 2 — Run the READ nodes and evaluate
Run each with nodeExecutor, read with getNodeOutput, and record a verdict.
A. The three Search variants (run all three):
- entity — PASS if
count > 0and the top result is a NAMED entity matching the probe; WARN if empty; FAIL on error. Keep the top result'sidandtypeIdfor later. - schema — PASS if
resultsis non-empty AND every result carriesmatchedVia.mode = "schema". Then inspect the TOP result'smatchedVia.typeNameandtypeScore: atypeScorearound 0.7–0.9 is a healthy semantic (kNN) match; atypeScorearound 7 means a LEXICAL-noise type won (a known regression) — mark WARN and name the offending type. FAIL if no result carriesmatchedVia.mode = "schema". - hybrid — PASS if
count > 0.
B. Entity 360 + Traverse (need an id from Search·entity):
- Set Entity 360
objectIdto the top entity id from Search·entity (batchUpsertNodes), run it. PASS ifentityis populated andlinkCountslists link types. Note a link-type NAME fromlinkCounts(or fromentity's links) — you need it for Traverse. - Set both Traverse nodes'
objectIdto the same id andlinkTypeto the link-type name you found; run both. PASS ifresultreturns (endpoints may be empty — an isolated entity is still a valid, non-error result; say so). Compare depth-1 vs depth-2 reach.
C. Bridge pipeline (KB → From Documents → Merge — wired, so run downstream and upstream resolves):
- Run KB Semantic Search. PASS if
documentIdsis non-empty; WARN if empty (nothing in the KB matched — note it). - Run From Documents. PASS if
entitiesis non-empty; WARN if empty (the matched documents mention no accessible objects — still valid). Notetruncated. - Run Merge Ranked Lists. PASS if
items/itemsTextare populated andtopIdis set. This proves the RRF fusion of the lexical (listA) and bridge (listB) arms.
Phase 3 — Write nodes (ONLY if the user opted in)
Skip this whole phase if writes were declined; mark every write node SKIPPED.
How the safety actually works — read this before touching a write node. A wired edge only fills an input the node left EMPTY; a value you TYPE onto a node WINS and the wire is ignored. So this island is safe ONLY because you leave every object-id and link-id field BLANK — the wires then route each write onto the throwaways created here. HARD RULE: never type an object id or link id taken from a Search / Entity 360 / Traverse / Merge / From-Documents result onto ANY write node. The ONLY fields you set in this phase are TYPE ids (objectTypeId, linkTypeId) — types are catalog entries, not real entity instances, so setting them is safe.
The island: Create Object A and Create Object B mint two throwaways; Set Property patches A; Create Link joins A→B; Delete ×3 removes A, B, and the link. Every object/link id flows through a wire, so nothing here can reach a real entity.
- Create Object · throwaway A — set
objectTypeIdto atypeIdyou kept from Search·entity's results. LeaveidentityKeyat its fixed valueontology-testbench-throwaway; leavepropertiesat the default. Run. PASS if anidcomes back. - Create Object · throwaway B — same idea; set
objectTypeIdto any real object-type id (reusing A's is fine). LeaveidentityKeyat its fixed valueontology-testbench-throwaway-b. Run. PASS if anidcomes back. (B exists so Create Link has a second distinct throwaway endpoint — no real entity is ever needed.) - Set Property — leave
targetIdEMPTY (wired from A); set onlyproperties. Run. PASS if it returns A's throwaway id (NOT a real entity id). - Create Link — leave BOTH
sourceObjectIdandtargetObjectIdEMPTY (wired from A and B). Set ONLYlinkTypeIdto a real link-type id (from Entity 360 if available, else mark SKIP). Run. PASS if it returns anid; notedowngrade_refused. - Delete · throwaway object A, Delete · throwaway object B, Delete · throwaway link — leave every
targetIdEMPTY (each is wired: to A, to B, and to Create Link's link id). Run all THREE, EVEN IF an earlier write step failed (cleanup). PASS if each returns adeleted_at. After these three the island leaves the graph exactly as found. NEVER delete anything else.
Phase 4 — Report
Run verification, then present ONE markdown table: a row per node instance (name, PASS/WARN/FAIL/SKIP, and the one-line reason/observation). Lead with an overall verdict (FAIL if any FAIL, else WARN if any WARN, else PASS). Call out specifically: any schema result that matched a lexical-noise type (high typeScore), any empty bridge/KB result (with the likely cause), and — if writes ran — confirm both throwaway objects and the test link were deleted. In followUp, offer to re-run with a different probe query, or to run the write nodes (they self-clean). No write confirmation is needed beyond the Phase 1 opt-in, since the three Deletes always tear down everything Create made.
// Dependencies
1from node import OntologySearch # v1.4.02from node import OntologyEntity360 # v1.0.33from node import OntologyTraverse # v1.0.04from node import KBSemanticSearch # v1.4.05from node import OntologyFromDocuments # v1.0.06from node import MergeRankedLists # v1.3.07from node import OntologyCreateObject # v1.0.08from node import OntologySetProperty # v1.0.09from node import OntologyCreateLink # v1.0.010from node import OntologyDelete # v1.0.0// Variables
1query:2 type: undefined3 label: "Test Query"4 description: "The probe query. Entity-mode search wants a NAME; schema/hybrid + KB search want the RELATION/THEME words. The instruction refines it per node. Default probes both."5 required: undefined