$ cat workspace-template.yaml

O

Ontology Node Test Bench 3

// 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.

utility
#ontology#test#diagnostics#knowledge-graph#test-bench

// Canvas Preview

canvas.flow

// Instruction

instruction.md

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 four write nodes at the bottom run only if the user opts in, and they clean up after themselves.

The nodes (and what each proves)

  • Search · entity mode (ontology-search, mode=entity) — name-first lexical/kNN search. Output results + count.
  • Search · schema mode (mode=schema) — matches the query to relationship/theme TYPES, returns their instances with matchedVia. Output results.
  • Search · hybrid mode (mode=hybrid) — both arms, RRF-fused.
  • Entity 360 (ontology-entity-360) — full profile of ONE object id. Inputs objectId, maxNamesPerType. Outputs entity, summaryText, linkCounts.
  • Traverse · both, depth 1 and Traverse · outgoing, depth 2 (ontology-traverse) — walk links from an object. Inputs objectId, linkType, direction, depth. Output result.
  • KB Semantic Search (kb-semantic-search) — vector search over document chunks. Output documentIds (WIRED into From Documents), chunkTexts.
  • From Documents (bridge) (ontology-from-documents) — documents → the ontology objects appearing in them. documentIds is wired from KB Semantic Search. Outputs entities, links, truncated.
  • Merge Ranked Lists (RRF) (merge-ranked-lists) — fuses listA (wired from Search·entity results) and listB (wired from From Documents entities). Outputs items, itemsText, topId.
  • Create Object / Set Property / Create Link / Delete (ontology-create-object / -set-property / -create-link / -delete) — the write path. Run as a self-cleaning round-trip; Delete removes what Create made.

Phase 1 — Configure

  1. Make ONE requestUserDecision bundling: (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.
  2. Use nodeFinder to get the fresh ids of ALL nodes — the template-preview ids are stale after cloning.
  3. Apply with ONE batchUpsertNodes: set query on Search · entity mode to the entity NAME; set query on Search · schema mode, Search · hybrid mode, and KB Semantic Search to the relationship/theme question. Replace every {{query}} placeholder. Leave id/type inputs (Entity 360 objectId, Traverse objectId/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 > 0 and the top result is a NAMED entity matching the probe; WARN if empty; FAIL on error. Keep the top result's id and typeId for later.
  • schema — PASS if results is non-empty AND every result carries matchedVia.mode = "schema". Then inspect the TOP result's matchedVia.typeName and typeScore: a typeScore around 0.7–0.9 is a healthy semantic (kNN) match; a typeScore around 7 means a LEXICAL-noise type won (a known regression) — mark WARN and name the offending type. FAIL if no result carries matchedVia.mode = "schema".
  • hybrid — PASS if count > 0.

B. Entity 360 + Traverse (need an id from Search·entity):

  • Set Entity 360 objectId to the top entity id from Search·entity (batchUpsertNodes), run it. PASS if entity is populated and linkCounts lists link types. Note a link-type NAME from linkCounts (or from entity's links) — you need it for Traverse.
  • Set both Traverse nodes' objectId to the same id and linkType to the link-type name you found; run both. PASS if result returns (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 documentIds is non-empty; WARN if empty (nothing in the KB matched — note it).
  • Run From Documents. PASS if entities is non-empty; WARN if empty (the matched documents mention no accessible objects — still valid). Note truncated.
  • Run Merge Ranked Lists. PASS if items/itemsText are populated and topId is 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 the four write nodes SKIPPED. This chain is SELF-CONTAINED and SAFE BY CONSTRUCTION: Create Object's id output is WIRED into Set Property targetId, Create Link sourceObjectId/targetObjectId, and Delete targetId. A wired input overrides any value on the node, so these nodes ALWAYS act on the throwaway object created here and can NEVER touch a real entity. HARD RULE: never put an object id from a search / entity / traverse / merge node onto ANY write node.

  1. Create Object — set objectTypeId to a typeId you kept from Search-entity's results. Leave identityKey at its fixed value ontology-testbench-throwaway (this is what keeps the throwaway distinct from every real entity) and properties at the default. Run. It returns the throwaway id. PASS if an id comes back.
  2. Set Property — leave targetId EMPTY (wired from Create Object); set only properties. Run. PASS if it returns the throwaway id, NOT a real entity id.
  3. Create Link — leave sourceObjectId and targetObjectId EMPTY (both wired from Create Object, so this is a self-link on the throwaway); set linkTypeId to a real link-type id (from Entity 360 if available, else mark SKIP). Run. PASS if it returns an id.
  4. Delete — leave targetId EMPTY (wired from Create Object). Run this EVEN IF an earlier write step failed (cleanup). PASS if it returns deleted_at for the throwaway. Deleting the throwaway cascades its self-link, leaving 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 the created object was 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 Delete always tears down what Create made.

// Dependencies

$ git log --oneline

v1.1.3
HEAD
2026-08-03
v1.1.22026-08-03
v1.1.12026-08-03
v1.1.02026-07-24
v1.0.12026-07-24
v1.0.02026-07-24