Skip to main content

g6-graph-reasoning

Use when conclusions spread over a graph of people, services, accounts or documents from facts that are only partly certain (trust, risk, popularity, reliability scores) and you are about to state how sure a conclusion is, or to combine rules that might contradict each other, from your own reading.

Source facts

Repository
basicisabc1994/g6solver
Last source activity
October 26, 2026 at 01:52
Detected SKILL.md language
English
Stars
0
Forks
0

Install options

The review-first prompt is selected by default. You can switch to a direct command or download a local copy.

Review the source files

Read SKILL.md and any companion files shown by SkillsMP before deciding whether to install.

Showing SKILL.md

SKILL.md
Source instructions · Read-only preview
name
g6-graph-reasoning
description
Use when conclusions spread over a graph of people, services, accounts or documents from facts that are only partly certain (trust, risk, popularity, reliability scores) and you are about to state how sure a conclusion is, or to combine rules that might contradict each other, from your own reading.
# G6 graph reasoning Works out the truth interval `[lower, upper]` of each label on a graph's nodes and edges from facts and annotated rules, in the style of PyReason, on a pure-Python fixpoint over exact rational intervals. Every interpretation is checked before it is reported, and a contradiction is blocked with both sides' derivations, never resolved silently. ## When to use it - You are about to say "this account is risky", "this supplier is trustworthy" or "this user is influential" from facts that are themselves uncertain. - Rules chain over edges (friends of friends, dependencies of dependencies) and each rule's head interval, or an annotation function, should set how sure the conclusion is. - Two rules may push the same conclusion in opposite directions, and you need to know if they collide. - You need to show how a conclusion's bounds were reached, step by step down to the facts. ## When not to use it - Every fact is plainly true or false: use `datalog`, which also cross-checks on a second engine. - Probabilities from data, or cause and effect: use `causal`. - Logic over numbers or a counterexample: use `formal`. - A conclusion that rests on source passages: use `grounding`. ## Ops - `reason`: the truth interval of every label on the graph's nodes and edges (or those named in `labels`) that the facts and annotated rules give, checked for closure, support and soundness. - `query`: the interval of one `atom` (such as `popular(alice)`), with the steps that set its lower and upper bounds. - `explain`: why an interval holds, as its derivation down to the facts, or why it stayed unknown. - `check`: the parse, interval, arity, safety and stratification report, and whether PyReason could cross-check the model, with nothing evaluated. ## Reading the result The language: facts `friend(alice, bob).` (true), `friend(carol, dave) : [0.9, 1].`, rules `popular(x) : [0.7, 1] <- friend(x, y) : [0.9, 1], popular(y) : [0.7, 1].`, clause thresholds (`at least 2`, `at least 50%`) and annotation functions from a fixed set (`average`, `average_lower`, `maximum`, `minimum`, `product`). The graph and facts may also come as JSON in `graph` and `facts`. An answer's `bounds` and `status` (`true`, `false`, `between` or `unknown`) say how sure it is. - `qualified-draft`, `G6_E_GRAPH_REASONING_ONE_ENGINE`: the pure-Python engine ran and the check passed; `G6_E_GRAPH_REASONING_ENGINE_ANSWER` when PyReason ran too and agreed; `G6_E_GRAPH_REASONING_NOT_EVALUATED` for `check`, which evaluates nothing. These codes are on `warning_card.code`; the result's own `code` is empty. Nothing here is `verified`. - `blocked-escalated`: `G6_E_GRAPH_REASONING_CONFLICT` (with `conflict`: the atom, the interval it had, the one that met it, and both derivations), `G6_E_GRAPH_REASONING_CERTIFICATE_REFUTED`, `G6_E_GRAPH_REASONING_ENGINES_DISAGREE`, `G6_E_GRAPH_REASONING_PARSE_ERROR` and the other model refusals, each with line and column. ## Alone and composed Alone, over MCP: `g6_invoke("graph_reasoning", "query", params_json)`. From Python: `from g6.graph_reasoning import reason, query, explain, check_model`. Composed: - Rules whose facts are all certain belong in `datalog`; move them there for its second engine. - Give `coding_agent_gate`'s `verify_answer` the reply as an evidence item of kind `log` before reporting a conclusion that rests on it (it counts as caller-declared), and keep the interval, not a rounded "yes". ## Failure modes it catches - `overstated_certainty` (a conclusion stated with more certainty than the facts give): each label carries the interval its facts give or its rules' heads assign (or an annotation function computes), in exact fractions; an uncertain edge lowers a conclusion only if the rule's head interval or annotation says so, and one nothing supports stays `unknown` at `[0, 1]`. The support check shows every interval comes from a fact or a rule whose body held, so nothing rests on itself. - `contradictory_rules` (rules that contradict each other without anyone noticing): a step that would leave an interval empty is a conflict, blocked with `G6_E_GRAPH_REASONING_CONFLICT` and both sides' derivations, where PyReason by default resets such an atom to `[0, 1]`. ## Blind spots - The intervals are what your facts and rules say. A fact given too much confidence passes every check, and a rule with no head interval assigns `[1, 1]` once its body holds, however uncertain the body was. - A conflict is found only when both sides (a fact or a rule) reach the same atom with the given facts; rules that would contradict on other facts are not flagged. - One static fixpoint over a fixed graph: no timesteps, rule delays, facts over time, edge inference or head functions; what it does not read is refused, not ignored. - PyReason 3.7.0 does not import on this library's Python, so in practice only the pure-Python engine runs, and the card says so. - Size and time limits (at most 60 seconds) refuse large models. ## What it needs - Nothing outside G6: a pure-Python engine over exact rational intervals, with no extra. PyReason is used as a second engine only if it imports as it is, which PyReason 3.7.0 does not on this library's Python, so it is not an extra. - No op runs code, writes a file or reaches the network, so none is sensitive. ## Examples ```g6-example op=query {"program": "friend(alice, bob). friend(bob, carol). friend(carol, dave) : [0.9, 1].\npopular(dave).\npopular(x) : [0.7, 1] <- friend(x, y) : [0.9, 1], popular(y) : [0.7, 1].\n", "atom": "popular(alice)"} ``` `answer.bounds` is `[0.7, 1.0]` with `status` `between`: alice is popular at least to 0.7, not certainly, and `answer.derivation` walks back through bob, carol and dave to the facts. ```g6-example op=reason {"program": "trusted(a) : [0.8, 1]. flagged(a).\ntrusted(x) : [0, 0.3] <- flagged(x).\n"} ``` The reply is `blocked-escalated` with `G6_E_GRAPH_REASONING_CONFLICT`: `conflict.before` is `[0.8, 1.0]` from the fact, `conflict.met` is `[0.0, 0.3]` from the rule, and nothing is reported as the answer. ```python from g6.graph_reasoning import query, reason social = """ friend(alice, bob). friend(bob, carol). friend(carol, dave) : [0.9, 1]. popular(dave). popular(x) : [0.7, 1] <- friend(x, y) : [0.9, 1], popular(y) : [0.7, 1]. """ alice = query(social, "popular(alice)") assert alice.answer["bounds"] == [0.7, 1.0] and alice.answer["status"] == "between" assert alice.completion_state == "qualified-draft" clash = reason("trusted(a) : [0.8, 1]. flagged(a).\ntrusted(x) : [0, 0.3] <- flagged(x).") assert clash.code == "G6_E_GRAPH_REASONING_CONFLICT" and clash.conflict["atom"] == "trusted(a)" ``` ## The four open problems - **Learning signals.** Not yet: it writes nothing to a run ledger itself. Each catch is a labelled result with its own `G6_E_GRAPH_REASONING_*` code and, for a conflict, both derivations in `evidence`; recording it is the caller's step today. - **Evaluators the model cannot influence.** The engine and the closure, support and soundness checks are the package's own code with its own matcher; no model call runs anywhere in the package. The caller writes the facts and rules, never the check. - **Transfer by failure mode.** The checks belong to annotated logic, not to a task: an empty interval is a conflict in any graph. Not yet: its catch rate on task families it was not built on has not been measured. - **Enough held-out cases.** Not yet: its own catch rate and false-alarm rate are not judged by a sequential test. A repeated workflow that uses it can be tuned with `g6.metaharness`, whose gate judges a change on held-out cases.
View on GitHub