Add LUCID to the CLI, inspect, skill, notebook and llms.txt - #37
Merged
Conversation
LUCID was reachable only from Python. Adds the four surfaces every other
algorithm already has.
- CLI: `causal-ts deconfound GRAPH --data CSV [--strategy adaptive|tetrad|pds]`
post-processes a graph saved by `discover`. Not registered in
`discover --algorithm`: LUCID corrects a graph, it doesn't discover one.
- inspect: facts["latent_factor"] {detected, spectral_ratio, tau}, taken from
LUCID's own router. recommend_config suggests .deconfound() only when detected
is True, and never changes the algorithm/CI-test choice. detected is tri-state:
False means no factor structure this test can see, not "no confounding" (a 2-3
variable confounder is invisible to it); None means the check couldn't run
(NaN, d<2, T<d+3).
- skill: SKILL.md surfaces latent_factor with that caveat, plus a "many
contemporaneous edges -> deconfound" step in the playbook.
- notebook: new section 5, sections 5-9 renumbered. CDNOTS reports 23 spurious
lag-0 edges; .deconfound() removes all 23 and keeps every true edge
(F1 0.20 -> 0.86). Also fixes three stale spots: run_cdnots_gated unpacked as
a 3-tuple, the p-value demo needing return_pvals=True, and a wrap_graph table
that predates GraceResult inheriting the DoWhy methods.
- llms.txt: adds LUCID; also fixes the GRACE snippets, which unpacked
run_cdnots_gated / run_stability_selection as 3-tuples (both return a single
GraceResult, so the documented code raised TypeError).
Also corrects two LucidResult docstrings that conflated the router's
"pervasive" label with any detected factor: `R > tau` selects sf or pervasive
(only regime says which), and n_factors counts eigenvalues above the MP bulk
regardless of regime (sf -> 1, pervasive -> 2, sparse -> 0).
315/315 tests (7 new), notebook runs clean, lint clean.
Dependency Review✅ No vulnerabilities or license issues or OpenSSF Scorecard issues found.Scanned FilesNone |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
LUCID was reachable only from Python. Adds the four surfaces every other algorithm
already has.
causal-ts deconfound GRAPH --data CSV [--strategy adaptive|tetrad|pds],post-processing a graph saved by
discover. Not registered indiscover --algorithm:LUCID corrects a graph, it doesn't discover one.
facts["latent_factor"] {detected, spectral_ratio, tau}, taken fromLUCID's own router so the two can't drift.
recommend_configsuggests.deconfound()only when
detectedis True, and never changes the algorithm/CI-test choice.SKILL.mdsurfaceslatent_factor, plus a "many contemporaneous edges →deconfound" step in the interpretation playbook.
.deconfound()removes all 23 and keeps every true edge (F1 0.20 → 0.86). One lag-1false positive survives, which the notebook points out rather than hides.
detectedis tri-state on purpose:Falsemeans no factor structure this test can see— not "no confounding", since a 2–3 variable confounder leaves no dominant
eigenvalue and stays invisible.
Nonemeans the check couldn't run (NaN,d<2,T<d+3), kept distinct fromFalseso "didn't check" is never read as "checked andfound nothing".
Drive-by fixes
Both were blocking or actively wrong, and are in files this PR already touches:
api_reference.ipynbwouldn't execute:run_cdnots_gatedunpacked as a 3-tuple, thep-value demo needed
return_pvals=True, and awrap_graphtable predatedGraceResultinheriting the DoWhy methods.llms.txt's GRACE snippets unpackedrun_cdnots_gated/run_stability_selectionas 3-tuples — both return a single
GraceResult, so the documented code raisedTypeErrorfor anyone following it.LucidResultdocstrings conflated the router's"pervasive"label with anydetected factor:
R > tauselectssforpervasive(onlyregimesays which),and
n_factorscounts eigenvalues above the MP bulk regardless of regime(verified: sf → 1, pervasive → 2, sparse → 0).
Test plan
three guard paths (returning
None, notFalse), nudge-only-on-positive, andthat algorithm choice is unaffected
api_reference.ipynbexecutes end to end: 0 error cellsgenerate→discover→deconfound) for all threestrategies plus
--jsonand the ignored-flag warningblack(24 pin) /isort/flake8, exact CI invocationmarkdownlintclean onSKILL.md,codespellclean on allchanged files; no YAML/shell/workflow files touched
sphinx-buildwarning set identical to baseline