Skip to main content

g6-causal

Use when an answer says one thing causes, drives or improves another, or estimates an effect from data, and you are about to choose which variables to control for, call an effect identifiable, or report a causal number from a correlation, a regression or your own reading of a diagram.

Source facts

Repository
basicisabc1994/g6solver
Last source activity
October 30, 2026 at 10:47
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-causal
description
Use when an answer says one thing causes, drives or improves another, or estimates an effect from data, and you are about to choose which variables to control for, call an effect identifiable, or report a causal number from a correlation, a regression or your own reading of a diagram.
# G6 causal Works out from a causal graph whether an effect can be estimated and how, estimates it with DoWhy from inline rows, and tries to knock the estimate down. The graph questions are answered by exact algorithms in pure Python and, when DoWhy is installed, by DoWhy too; the two must agree. ## When to use it - You are about to write "X increases Y", "the campaign caused the uplift" or "controlling for Z, the effect is". - You must choose which variables to adjust for, and some might be colliders or mediators. - There is an unobserved confounder and you need to know whether an instrument or a frontdoor route still identifies the effect. - You have rows of data and a graph, and want an estimate with a confidence interval that has faced refuters. ## When not to use it - You have no causal graph and cannot state one: nothing in G6 discovers the graph from data, so first write down the assumptions with a person. - A causal claim in prose that you need graded against its evidence: use `epistemic_integrity`'s `adjudicate`. - Rules over facts with no causal reading: use `datalog`. - Plain descriptive statistics: ordinary Python. ## Ops - `d_separated`: whether `given` d-separates `x` from `y`, with a path left open when it does not. - `backdoor_paths`: every path from `treatment` to `outcome` that starts with an arrow into the treatment, each open or blocked. - `adjustment_sets`: every minimal set of observed variables to control for, by the backdoor criterion. - `instruments`: every observed instrumental variable for the treatment and outcome. - `identify`: whether the effect is identifiable by the backdoor, frontdoor or instrumental-variable criterion, with the estimand written out, or why not. - `estimate_effect`: the effect from inline `data` rows by `method` (`backdoor.linear_regression`, propensity-score stratification or weighting, `iv.instrumental_variable` or `frontdoor.two_stage_regression`), with its 95% confidence interval, recomputed by G6 for linear regression and tried by DoWhy's placebo, random-common-cause and data-subset refuters (`refute`, `simulations`, `seed`). ## Reading the result `graph` is JSON (`{"nodes": [...], "edges": [["Z", "T"], ...], "unobserved": [...]}`) or DOT (`digraph { Z -> T; U [observed=no]; }`). The answer is in `answer`; an estimate in `estimate`, `confidence_interval`, `refutations` and `recomputation`. - `qualified-draft`, `G6_E_CAUSAL_GRAPH_ANSWER` (both engines agreed) or `G6_E_CAUSAL_ONE_ENGINE` (pure Python only). - `qualified-draft`, `G6_E_CAUSAL_ESTIMATE`: the engines agreed on the identification, every refuter that tested the estimate passed and, for linear regression, G6's least-squares fit matched. `G6_E_CAUSAL_REFUTATION_INCOMPLETE` names a refuter that could not test it; `G6_E_CAUSAL_REFUTATION_OFF` means you turned refutation off. - `blocked-escalated`: `G6_E_CAUSAL_REFUTED` and `G6_E_CAUSAL_CERTIFICATE_REFUTED` (the numbers kept), `G6_E_CAUSAL_ENGINES_DISAGREE`, `G6_E_CAUSAL_NOT_IDENTIFIABLE` (from `estimate_effect`; `identify` answers `qualified-draft` with `identifiable` false and the reason), `G6_E_CAUSAL_GRAPH_CYCLE` and the other graph refusals. Every `qualified-draft` card says the answer rests on the graph, which data cannot confirm. Nothing here is `verified`. ## Alone and composed Alone, over MCP: `g6_invoke("causal", "adjustment_sets", params_json)`. From Python: `from g6.causal import adjustment_sets, identify, estimate_effect`. Composed: - Run `identify` first; its route tells you which `method` fits `estimate_effect` (a mismatch is refused with `G6_E_CAUSAL_METHOD_NOT_APPLICABLE`). - The claim you then write in prose goes to `epistemic_integrity`'s `adjudicate`; give `coding_agent_gate`'s `verify_answer` the causal reply as an evidence item of kind `log` (it counts as caller-declared). ## Failure modes it catches - `correlation_as_cause` (taking a correlation for a cause): `estimate_effect` refuses unless the graph identifies the effect (`G6_E_CAUSAL_NOT_IDENTIFIABLE`). An identified estimate is tried by a placebo treatment, an added random common cause and data subsets unless `refute` is false; a refuter that contradicts it, judged by G6 against the confidence interval, blocks it (`G6_E_CAUSAL_REFUTED`), and one that could not test it is named (`G6_E_CAUSAL_REFUTATION_INCOMPLETE`), never counted as a pass. - `wrong_adjustment` (controlling for the wrong variables): `adjustment_sets` gives every minimal backdoor set from exact graph algorithms, `backdoor_paths` shows which paths a set leaves open, and DoWhy's answer must agree with G6's or the reply is blocked. ## Blind spots - Everything rests on the graph. A missing confounder you did not draw, or an arrow the wrong way, gives a confident wrong answer that passes every check. - `identify` checks three criteria (backdoor, frontdoor, instrumental variable), not the complete do-calculus: "not identifiable" may mean another identification exists, and the reason says so. - Only linear regression is recomputed independently; the other estimators are DoWhy's, tried by refuters only. - Refuters test robustness to their specific changes, not truth; passing them does not rule out a bias they cannot reach. With `refute` false none runs, and the estimate is still `qualified-draft` (`G6_E_CAUSAL_REFUTATION_OFF`). - An instrumental-variable estimand is the average effect only if the effect is the same for every unit; otherwise it is a local effect, as the estimand text says. - Data come as inline rows, within size limits. A DoWhy call that has started is not interrupted by `time_limit`. ## What it needs - `pip install "g6[causal] @ git+https://github.com/basicisabc1994/g6solver"` for DoWhy, imported only when an op runs. Without it the graph ops still answer in pure Python (`G6_E_CAUSAL_ONE_ENGINE`), and `estimate_effect` is `blocked-escalated` with `G6_E_CAUSAL_ENGINE_UNAVAILABLE` and the install line. - No outside program. No op runs code, reads a file or reaches the network, so none is sensitive. ## Examples ```g6-example op=adjustment_sets {"graph": {"nodes": ["Z", "T", "Y"], "edges": [["Z", "T"], ["Z", "Y"], ["T", "Y"]]}, "treatment": "T", "outcome": "Y"} ``` `answer.sets` is `[["Z"]]`, with the estimand that adjusts for `Z`; the reply is `qualified-draft`. ```g6-example op=identify {"graph": "digraph { U [observed=no]; W -> T; U -> T; U -> Y; T -> Y }", "treatment": "T", "outcome": "Y"} ``` The confounder `U` is unobserved, so no backdoor set exists; `answer.route` is `iv`, with `W` the instrument and the Wald-ratio estimand and its assumptions written out. ```python from g6.causal import adjustment_sets, backdoor_paths graph = "digraph { Z -> T; Z -> Y; T -> Y }" sets = adjustment_sets(graph, "T", "Y", engine="python") assert sets.answer["sets"] == [["Z"]] and sets.completion_state == "qualified-draft" paths = backdoor_paths(graph, "T", "Y", engine="python").answer assert paths["open"] == 1 and paths["paths"][0]["rendered"] == "T <- Z -> Y" cycle = adjustment_sets("digraph { T -> Y; Y -> T }", "T", "Y", engine="python") assert cycle.completion_state == "blocked-escalated" and cycle.code == "G6_E_CAUSAL_GRAPH_CYCLE" ``` ## 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_CAUSAL_*` code and, for a refuted estimate, every number in `evidence`; recording it is the caller's step today. - **Evaluators the model cannot influence.** The graph criteria, the recomputation and the judgement of each refuter are the package's own code, with DoWhy as a second engine; no model call runs anywhere in the package. The caller supplies the graph and the rows, never the check. - **Transfer by failure mode.** The criteria belong to causal graphs, not to a task: the backdoor criterion applies to 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