Skip to content

Fix: registered algorithms silently produced no graph via the CLI - #38

Merged
fesanghary merged 1 commit into
mainfrom
fix-algorithm-plugin-cli
Aug 29, 2026
Merged

Fix: registered algorithms silently produced no graph via the CLI#38
fesanghary merged 1 commit into
mainfrom
fix-algorithm-plugin-cli

Conversation

@fesanghary

Copy link
Copy Markdown
Contributor

Summary

causal-ts discover --algorithm <plugin> silently produced nothing. discover's
if/elif chain covers only the built-ins and had no else, so a registered third-party
algorithm passed validation, printed "Results saved to…", exited 0, and wrote a
summary.json with no graph at all.

  • cli.py — added the else branch: runs run_algorithm(...) and saves
    estimated_graph.npy like every other branch. The edge-list/diagnostics code after the
    chain already reloads the graph from disk, so it picks this up for free.
  • algorithms/__init__.py — added causalts.algorithms entry-point discovery, so an
    installed distribution reaches the causal-ts command without the caller importing
    anything. Scans once, lazily; a broken plugin warns and is skipped; a plugin can never
    shadow a built-in name.
  • cli.py--validate is now rejected for plugins. Its bootstrap re-discovery
    closure only special-cases cdnots/cdnots+ and otherwise re-runs CEDAR — dead code
    for grace/grace-ss (rejected earlier in the same file), but the new else branch
    makes it reachable for plugins, where it would have silently annotated the plugin's
    edges with CEDAR's persistence values.
  • custom_algorithm.ipynb — Step 6 claimed "once your module is imported, the CLI
    picks up your algorithm automatically." That can't work: the CLI is a separate process
    that never imports the caller's code. Replaced with the entry-point workflow that
    actually works, plus two smaller instances of the same overclaim in cells 0 and 13.

Only df/ci_test/max_lag reach a plugin from the CLI. Forwarding CDNOTS/CEDAR-specific
flags like --alpha or --include-c has no defined meaning for an arbitrary plugin, so
that limit is documented rather than guessed at.

Test plan

  • Fresh venv, real pip-installed plugin package, real causal-ts console script
    (not python -m / PYTHONPATH): before install --algorithm granger is rejected;
    after install it appears in --algorithm's choices and produces a real 7-edge graph
  • --validate + plugin → clean BadParameter, exit 2, nothing written
  • Built-in --validate still works (persistence.npy written); GRACE's existing
    --validate guard still fires; unknown algorithm still rejected
  • 13 new tests, self-contained (pass with zero plugins installed)
  • 328/328 full suite; custom_algorithm.ipynb executes 0 errors
  • black(24 pin)/isort/flake8/codespell clean

discover's if/elif chain covers only the built-ins and had no else, so
--algorithm <plugin-name> passed validation, printed "Results saved to...",
exited 0, and wrote a summary.json with no graph at all. Reproduced with a
real pip-installed third-party package before fixing, and again after.

- cli.py: added the else branch. Runs run_algorithm(df=df, ci_test=ci,
  max_lag=max_lag), saves estimated_graph.npy like every other branch. The
  edge-list/diagnostics code after the chain already reloads the graph from
  disk, so it picks this up for free.
- algorithms/__init__.py: added entry-point discovery, so an installed
  distribution reaches the causal-ts command without the caller importing
  anything. list_algorithms() builds --algorithm's choices at cli.py import
  time, and entry points are scanned inside it, so no cli.py change was
  needed for this half. Scans once, lazily. A plugin that fails to import
  warns and is skipped; a plugin can never shadow a built-in name.
- cli.py: --validate is rejected for plugins. Its bootstrap re-discovery
  closure only special-cases cdnots/cdnots+ and otherwise re-runs CEDAR --
  dead code for grace/grace-ss (rejected earlier, same file), but the new
  else-branch makes it reachable for plugins, where it would silently
  annotate the plugin's edges with CEDAR's persistence values.
- custom_algorithm.ipynb: Step 6 claimed "once your module is imported, the
  CLI picks up your algorithm automatically" -- false, since the CLI runs in
  a separate process that never imports the caller's code. Replaced with the
  entry-point workflow that actually works, plus two smaller instances of
  the same overclaim in cells 0 and 13.

Only df/ci_test/max_lag reach a plugin from the CLI; forwarding
CDNOTS/CEDAR-specific flags like --alpha or --include-c has no defined
meaning for an arbitrary plugin, so that limit is documented rather than
guessed at.

Tested end to end in a fresh venv with a real pip-installed plugin package
(not just python -m / PYTHONPATH tricks): before install, --algorithm
rejects the name; after, it appears in --algorithm's choices and produces a
real graph via the plain installed causal-ts command; --validate is
rejected with nothing written. Built-ins, GRACE's existing --validate
guard, and unknown-algorithm rejection all unaffected. 13 new tests,
328/328 full suite, notebook runs clean, lint clean.
@fesanghary
fesanghary requested a review from a team as a code owner August 29, 2026 20:11
@github-actions

Copy link
Copy Markdown

⚠️ Deprecation Warning: The deny-licenses option is deprecated for possible removal in the next major release. For more information, see issue 997.

Dependency Review

✅ No vulnerabilities or license issues or OpenSSF Scorecard issues found.

Scanned Files

None

@fesanghary
fesanghary merged commit 3e21476 into main Aug 29, 2026
10 checks passed
@fesanghary
fesanghary deleted the fix-algorithm-plugin-cli branch August 30, 2026 00:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant