[P0] Implement normalized skill catalog graph projection and validation #250

Closed
opened 2026-08-26 17:13:01 +00:00 by lost-rob0t · 1 comment
lost-rob0t commented 2026-08-26 17:13:01 +00:00 (Migrated from github.com)

Parent: #173
Related: #117/#197, #168-#172, #183

Live baseline

Canonical main: 267697bef10a3fffff7c093e1435ece770e7444b.

Merged #197 already provides the confined standard-compatible SKILL.md loader, closed metadata.prolog-rlm normalization, normalized relationship fields (requires, suggests, conflicts, supersedes), prompt-unit conversion into the one rlm_prompt_compiler, progressive body/resource disclosure, and host-owned activation policy.

Current prolog/rlm_skill.pl stores those relationship fields on the normalized skill record, but repository search finds no public/internal skill_graph projection. This is the remaining implementation gap from #173; do not create another loader, selector, prompt compiler, or separately-authored graph file.

Goal

Derive an inspectable typed skill graph only from the existing normalized skill catalog records.

The graph is routing/dependency metadata. It is inert and must never grant capability, authority, effect permission, execution, permanence, or trusted provenance.

Smallest public contract

Follow current structured-outcome conventions. API may be named to fit the repository, but should provide one canonical catalog-to-graph operation, conceptually:

skill_catalog_graph(+Catalog, -Outcome).

Successful output should be closed/ground metadata containing deterministic nodes, typed edges, diagnostics, and a stable material fingerprint derived from the normalized catalog graph material.

Do not load SKILL.md bodies or resource contents to build/query the graph.

Node contract

Every active normalized catalog skill is one node, including standard-only isolated skills.

Expose bounded inert metadata sufficient for graph/lifecycle consumers, including:

  • skill(Name) identity;
  • category;
  • automatic vs explicit-user activation state;
  • host-derived source;
  • package/root identity/reference already present in the normalized record;
  • host-derived skill fingerprint.

Do not copy instruction bodies into graph nodes.

Edge contract

Derive only explicit normalized relationships:

requires(A, B)     directed hard dependency
suggests(A, B)     directed soft relationship
conflicts(A, B)    symmetric semantic conflict
supersedes(A, B)   directed suppression/replacement declaration

Targets may be closed compiler units such as skill(Name), tool(Name), or resource(Name) exactly as already normalized by rlm_skill.

For deterministic graph output, normalize/deduplicate emitted edges. A single authored conflict may project a canonical symmetric representation, but do not make the skill body or natural-language description a source of graph edges.

Required validation

TDD the graph validator against current normalized records. At minimum:

  1. self requires, conflicts, or supersedes => structural error;
  2. hard skill(...) requirement cycle => structural error with deterministic cycle evidence;
  3. supersedes cycle among skills => structural error;
  4. same source skill both requires and conflicts the same target => structural error;
  5. same source skill both requires and supersedes the same target => structural error;
  6. unresolved hard requires(..., skill(Missing)) => structural error;
  7. unresolved suggests/conflicts/supersedes targets => explicit diagnostics unless another existing host catalog resolves that closed unit; do not invent a target;
  8. standard-only skill => isolated valid graph node;
  9. graph projection/query does not read instruction bodies/resources;
  10. graph metadata is ground/closed and contains no executable handler/callable.

Do not silently repair contradictions to obtain a graph.

Analysis / design boundary

Reuse skill_catalog_skills/2 and the already-normalized skill dicts. Graph projection must not reparse YAML/JSON or maintain a second skill record.

Keep compiler ownership unchanged:

SKILL.md -> normalized skill
              |          |
              |          +-> read-only typed graph
              +-> prompt_unit -> rlm_prompt_compiler

Graph validation may reject an invalid catalog graph, but graph membership alone must not activate a skill or influence provider packing outside the existing compiler contract.

Adversarial cases

  • malicious body text describes fake dependencies: no graph effect;
  • allowed-tools compatibility metadata attempts authority grant: no graph/authority grant;
  • relationship target is syntactically closed but absent: report according to hard-vs-soft semantics;
  • graph traversal cannot cause skill body/resource loading;
  • graph query cannot return package credentials, handlers, or arbitrary callables;
  • cycles are detected deterministically independent of skill filesystem discovery order;
  • repeated equivalent relationships do not create nondeterministic duplicate output;
  • graph fingerprint changes when normalized relationship material changes and remains stable when only unconsumed body access state changes.

Decision gate

GO only for a read-only graph projection/validation layer over existing normalized catalog records. HOLD/re-design if implementation requires a second loader, selector, compiler, lifecycle database, executable metadata, or downstream product-specific policy.

Verification

  • focused graph tests;
  • current skill-loader/compiler tests;
  • canonical deterministic suite;
  • benchmark/conformance + deep recursion;
  • CLI/trace smoke;
  • Nix flake;
  • clean SWI pack install;
  • Tree-sitter FFI;
  • configured REAL/Paid OpenRouter gates on the exact candidate head.

Any changed head invalidates prior evidence.

Non-goals

  • no #170 lifecycle/promotion state;
  • no #171 evolution/mutation policy;
  • no #168/#169 evaluation implementation;
  • no model-inferred graph edges;
  • no skill-based authority/capability grants;
  • no Agent Zero or AgentProlog UI/product code;
  • no second prompt compiler/selector.
Parent: #173 Related: #117/#197, #168-#172, #183 ## Live baseline Canonical `main`: `267697bef10a3fffff7c093e1435ece770e7444b`. Merged #197 already provides the confined standard-compatible `SKILL.md` loader, closed `metadata.prolog-rlm` normalization, normalized relationship fields (`requires`, `suggests`, `conflicts`, `supersedes`), prompt-unit conversion into the one `rlm_prompt_compiler`, progressive body/resource disclosure, and host-owned activation policy. Current `prolog/rlm_skill.pl` stores those relationship fields on the normalized skill record, but repository search finds no public/internal `skill_graph` projection. This is the remaining implementation gap from #173; do not create another loader, selector, prompt compiler, or separately-authored graph file. ## Goal Derive an inspectable typed skill graph **only from the existing normalized skill catalog records**. The graph is routing/dependency metadata. It is inert and must never grant capability, authority, effect permission, execution, permanence, or trusted provenance. ## Smallest public contract Follow current structured-outcome conventions. API may be named to fit the repository, but should provide one canonical catalog-to-graph operation, conceptually: ```prolog skill_catalog_graph(+Catalog, -Outcome). ``` Successful output should be closed/ground metadata containing deterministic nodes, typed edges, diagnostics, and a stable material fingerprint derived from the normalized catalog graph material. Do not load SKILL.md bodies or resource contents to build/query the graph. ## Node contract Every active normalized catalog skill is one node, including standard-only isolated skills. Expose bounded inert metadata sufficient for graph/lifecycle consumers, including: - `skill(Name)` identity; - category; - automatic vs explicit-user activation state; - host-derived source; - package/root identity/reference already present in the normalized record; - host-derived skill fingerprint. Do not copy instruction bodies into graph nodes. ## Edge contract Derive only explicit normalized relationships: ```text requires(A, B) directed hard dependency suggests(A, B) directed soft relationship conflicts(A, B) symmetric semantic conflict supersedes(A, B) directed suppression/replacement declaration ``` Targets may be closed compiler units such as `skill(Name)`, `tool(Name)`, or `resource(Name)` exactly as already normalized by `rlm_skill`. For deterministic graph output, normalize/deduplicate emitted edges. A single authored conflict may project a canonical symmetric representation, but do not make the skill body or natural-language description a source of graph edges. ## Required validation TDD the graph validator against current normalized records. At minimum: 1. self `requires`, `conflicts`, or `supersedes` => structural error; 2. hard `skill(...)` requirement cycle => structural error with deterministic cycle evidence; 3. `supersedes` cycle among skills => structural error; 4. same source skill both `requires` and `conflicts` the same target => structural error; 5. same source skill both `requires` and `supersedes` the same target => structural error; 6. unresolved hard `requires(..., skill(Missing))` => structural error; 7. unresolved `suggests`/`conflicts`/`supersedes` targets => explicit diagnostics unless another existing host catalog resolves that closed unit; do not invent a target; 8. standard-only skill => isolated valid graph node; 9. graph projection/query does not read instruction bodies/resources; 10. graph metadata is ground/closed and contains no executable handler/callable. Do not silently repair contradictions to obtain a graph. ## Analysis / design boundary Reuse `skill_catalog_skills/2` and the already-normalized skill dicts. Graph projection must not reparse YAML/JSON or maintain a second skill record. Keep compiler ownership unchanged: ```text SKILL.md -> normalized skill | | | +-> read-only typed graph +-> prompt_unit -> rlm_prompt_compiler ``` Graph validation may reject an invalid catalog graph, but graph membership alone must not activate a skill or influence provider packing outside the existing compiler contract. ## Adversarial cases - malicious body text describes fake dependencies: no graph effect; - `allowed-tools` compatibility metadata attempts authority grant: no graph/authority grant; - relationship target is syntactically closed but absent: report according to hard-vs-soft semantics; - graph traversal cannot cause skill body/resource loading; - graph query cannot return package credentials, handlers, or arbitrary callables; - cycles are detected deterministically independent of skill filesystem discovery order; - repeated equivalent relationships do not create nondeterministic duplicate output; - graph fingerprint changes when normalized relationship material changes and remains stable when only unconsumed body access state changes. ## Decision gate **GO** only for a read-only graph projection/validation layer over existing normalized catalog records. HOLD/re-design if implementation requires a second loader, selector, compiler, lifecycle database, executable metadata, or downstream product-specific policy. ## Verification - focused graph tests; - current skill-loader/compiler tests; - canonical deterministic suite; - benchmark/conformance + deep recursion; - CLI/trace smoke; - Nix flake; - clean SWI pack install; - Tree-sitter FFI; - configured REAL/Paid OpenRouter gates on the exact candidate head. Any changed head invalidates prior evidence. ## Non-goals - no #170 lifecycle/promotion state; - no #171 evolution/mutation policy; - no #168/#169 evaluation implementation; - no model-inferred graph edges; - no skill-based authority/capability grants; - no Agent Zero or AgentProlog UI/product code; - no second prompt compiler/selector.
lost-rob0t commented 2026-08-26 18:14:51 +00:00 (Migrated from github.com)

RAGE realization + exact-head verification for the normalized skill catalog graph.

Baseline: canonical main remained 267697bef10a3fffff7c093e1435ece770e7444b. The existing transaction rage/250-skill-catalog-graph first produced exact head 6f7d809049aace02e1604330dcb82469ea631525; canonical CI discovered 79 suites / 898 tests and passed 897 with exactly one failure: standard_skill_projects_to_isolated_inert_node failed with an instantiation error because the test bound Node inside assertion(Graph.nodes = [Node]) and dereferenced it afterward. No production/load failure was present.

Recovery: commit 3d391781e20421c94635ebd92d16178883b7e6dd changes exactly one test line, moving Graph.nodes = [Node] outside assertion/1. It does not modify production graph behavior or weaken any assertion.

Adversarial decision: GO for this slice. The implementation is read-only over normalized rlm_skill catalog records; graph membership is not activation/authority; no body/resource text creates edges; no handler/callable is introduced; structural cycles/contradictions and unresolved hard dependencies fail explicitly; soft/external targets remain diagnostics; ordering and graph material are canonicalized; rlm_prompt_compiler remains the sole provider-selection authority. Downstream Agent Zero / AgentProlog product policy is not duplicated here.

Fresh exact-head verification on 3d391781e20421c94635ebd92d16178883b7e6dd is green:

  • canonical PlUnit: 79 suites / 898 discovered / 898 passed / 0 failed / 0 timeout / 0 blocked / 0 fixme;
  • deterministic benchmark/conformance: 16/16 pass;
  • deep-recursion experiment: 15/15 pass;
  • CLI/trace + fresh-process graph/artifact restart + whitespace: pass;
  • credential-backed REAL OpenRouter: core, structured repair, benchmark, depth 0/1/2, CLI smoke all pass;
  • Paid OpenRouter: pass;
  • Nix flake: pass;
  • clean SWI-pack install: pass;
  • Tree-sitter FFI: pass.

PR #256 now owns this transaction. Engineering decision is GO; merge remains subject to the repository's explicit merge-on-green authorization gate.

RAGE realization + exact-head verification for the normalized skill catalog graph. Baseline: canonical `main` remained `267697bef10a3fffff7c093e1435ece770e7444b`. The existing transaction `rage/250-skill-catalog-graph` first produced exact head `6f7d809049aace02e1604330dcb82469ea631525`; canonical CI discovered 79 suites / 898 tests and passed 897 with exactly one failure: `standard_skill_projects_to_isolated_inert_node` failed with an instantiation error because the test bound `Node` inside `assertion(Graph.nodes = [Node])` and dereferenced it afterward. No production/load failure was present. Recovery: commit `3d391781e20421c94635ebd92d16178883b7e6dd` changes exactly one test line, moving `Graph.nodes = [Node]` outside `assertion/1`. It does not modify production graph behavior or weaken any assertion. Adversarial decision: **GO** for this slice. The implementation is read-only over normalized `rlm_skill` catalog records; graph membership is not activation/authority; no body/resource text creates edges; no handler/callable is introduced; structural cycles/contradictions and unresolved hard dependencies fail explicitly; soft/external targets remain diagnostics; ordering and graph material are canonicalized; `rlm_prompt_compiler` remains the sole provider-selection authority. Downstream Agent Zero / AgentProlog product policy is not duplicated here. Fresh exact-head verification on `3d391781e20421c94635ebd92d16178883b7e6dd` is green: - canonical PlUnit: **79 suites / 898 discovered / 898 passed / 0 failed / 0 timeout / 0 blocked / 0 fixme**; - deterministic benchmark/conformance: 16/16 pass; - deep-recursion experiment: 15/15 pass; - CLI/trace + fresh-process graph/artifact restart + whitespace: pass; - credential-backed REAL OpenRouter: core, structured repair, benchmark, depth 0/1/2, CLI smoke all pass; - Paid OpenRouter: pass; - Nix flake: pass; - clean SWI-pack install: pass; - Tree-sitter FFI: pass. PR #256 now owns this transaction. Engineering decision is GO; merge remains subject to the repository's explicit merge-on-green authorization gate.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
nsaspy/prolog-rlm#250
No description provided.