Skip to content

refactor(delphi): UMAP/EVōC pipeline — library-first stages, in-process orchestration - #2627

Draft
jucor wants to merge 3 commits into
edgefrom
jc/umap-inprocess-stages
Draft

refactor(delphi): UMAP/EVōC pipeline — library-first stages, in-process orchestration#2627
jucor wants to merge 3 commits into
edgefrom
jc/umap-inprocess-stages

Conversation

@jucor

@jucor jucor commented Jul 18, 2026

Copy link
Copy Markdown
Collaborator

Refactors the UMAP/EVōC pipeline orchestration from shell-subprocess calls to library-first in-process calls, per Julien's request: keep every stage independently runnable as a script (modularity for experiments), but have run_delphi.py import and call stage entry points instead of spawning interpreters.

What changed (3 commits)

  1. Stage extractionumap_narrative/stages/ gains importable modules (comment_extremity, comment_priorities, datamapplot_layer); the numbered scripts (501_…, 502_…, 700_…) become 3–6-line shims with byte-identical CLIs (verified --help for all).
  2. Runner abstractionstages/runner.py: one run_stage(stage, argv) function dispatching in-process (default) or subprocess (DELPHI_STAGE_ISOLATION=subprocess escape hatch, per stage). Stage outcome (return / sys.exit / argparse error / crash) is normalized to a subprocess-style exit code so the orchestrator's error handling is unchanged. 25 new tests (tests/test_stage_runner.py): clean imports without network/heavy side effects, shim→module mapping, dispatch, argparse isolation.
  3. Orchestratorrun_delphi.py calls run_stage with byte-identical argv (before/after table in the commit body). Stage order, abort-vs-warn semantics, env contracts, and DynamoDB checkpointing are all preserved.

Notes

  • polismath/run_math_pipeline.py (the math stage) stays subprocess-pinned — owned by the parity workstream; the runner treats target=None as subprocess-only.
  • Benefits realized: one-time model/torch loads instead of per-stage interpreter restarts, real stack traces instead of exit codes, stages importable in notebooks/pytest.
  • Pre-existing latent bug deliberately preserved (content-preserving discipline): run_delphi passes --verbose to two stages that don't define it; argparse exit 2 flows through the same warn/skip path as before.
  • Gate: full public suite green on this branch (429 passed / 17 skipped / 47 xfailed = edge baseline + 25 new tests, zero regressions).

🤖 Generated with Claude Code

Move the numbered stage scripts' logic into an importable stages/ package so
the orchestrator can call them in-process, while keeping each stage runnable
standalone from the CLI:

  501_calculate_comment_extremity.py -> stages/comment_extremity.py
  502_calculate_priorities.py        -> stages/comment_priorities.py
  700_datamapplot_for_layer.py       -> stages/datamapplot_layer.py

Each numbered script becomes a 3-6 line CLI shim (from stages.<name> import
main; sys.exit(main())). Every stage main() now accepts an optional argv so it
can be invoked in-process without mutating global sys.argv. run_pipeline.main
gains the same argv parameter; reset_conversation gains a cli(argv) wrapper
while keeping main(zid, rid) intact for existing callers/tests.

Content-preserving: no algorithm or output changes. test_501 updated to import
the moved module (patch targets follow the code). Full suite: 570 passed,
17 skipped, 47 xfailed (unchanged from baseline).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Refactors the Delphi UMAP/EVōC orchestration so delphi/run_delphi.py executes pipeline stages via importable, in-process entry points (with a subprocess escape hatch), while keeping the numbered stage scripts as thin CLI shims for backwards-compatible standalone execution.

Changes:

  • Added a stage runner (stages/runner.py) that normalizes in-process execution outcomes into subprocess-style exit codes and supports DELPHI_STAGE_ISOLATION=subprocess.
  • Extracted stage logic into importable modules under umap_narrative/stages/ and converted 501/502/700 scripts into delegation shims.
  • Updated the orchestrator (run_delphi.py) and key stages (run_pipeline.py, reset_conversation.py) to support argv-based entry points for in-process calls, plus added tests for dispatch and import hygiene.

Reviewed changes

Copilot reviewed 13 out of 13 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
delphi/umap_narrative/stages/runner.py Introduces in-process/subprocess stage execution abstraction and stage registry.
delphi/umap_narrative/stages/datamapplot_layer.py New importable DataMapPlot stage module with main(argv) entry point.
delphi/umap_narrative/stages/comment_priorities.py New importable priorities stage module with main(argv) entry point.
delphi/umap_narrative/stages/comment_extremity.py New importable extremity stage module with main(argv) entry point.
delphi/umap_narrative/stages/init.py Documents the new importable-stage layout and shim strategy.
delphi/umap_narrative/run_pipeline.py Makes main() accept argv for in-process orchestration.
delphi/umap_narrative/reset_conversation.py Adds cli(argv) wrapper so orchestration can call it without touching sys.argv.
delphi/umap_narrative/700_datamapplot_for_layer.py Replaced full script with a thin shim delegating to stages.datamapplot_layer.
delphi/umap_narrative/502_calculate_priorities.py Replaced full script with a thin shim delegating to stages.comment_priorities.
delphi/umap_narrative/501_calculate_comment_extremity.py Replaced full script with a thin shim delegating to stages.comment_extremity.
delphi/tests/test_stage_runner.py Adds test coverage for runner dispatch behavior, shim wiring, and import hygiene.
delphi/tests/test_501_calculate_comment_extremity.py Updates test imports/patch targets to the new stage module location.
delphi/run_delphi.py Switches orchestration from subprocess spawning to run_stage(...) calls.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +40 to +55
# Prepare arguments for the boto3 resource.
boto3_kwargs = {
'region_name': os.environ.get('AWS_REGION', 'us-east-1'),
'aws_access_key_id': os.environ.get('AWS_ACCESS_KEY_ID', 'dummy'),
'aws_secret_access_key': os.environ.get('AWS_SECRET_ACCESS_KEY', 'dummy')
}

# Only add the endpoint_url if it's actually provided.
# If it's None (like in a production environment), boto3 will correctly
# use its default AWS endpoint resolution.
if endpoint_url:
boto3_kwargs['endpoint_url'] = endpoint_url

# Initialize DynamoDB connection using the prepared arguments
self.dynamodb = boto3.resource('dynamodb', **boto3_kwargs)

Comment thread delphi/umap_narrative/stages/comment_priorities.py Outdated
Comment thread delphi/umap_narrative/stages/datamapplot_layer.py Outdated
Comment thread delphi/umap_narrative/stages/datamapplot_layer.py Outdated
Comment thread delphi/tests/test_stage_runner.py
jucor added 2 commits July 21, 2026 20:48
Introduce stages/runner.py: a small Stage value type + run_stage(stage, argv,
isolation) dispatcher and a STAGES registry. In-process is the default;
DELPHI_STAGE_ISOLATION=subprocess restores per-stage subprocess execution as an
escape hatch. run_stage converts a stage's outcome (return value, sys.exit,
argparse error, or crash) into a subprocess-style exit code, so the orchestrator
keeps its existing per-stage abort/warn control flow. The math pipeline
(delphi/polismath/, owned by another workstream) is registered subprocess-only.

Adds tests/test_stage_runner.py (25 tests): env-flag resolution, in-process vs
subprocess dispatch, exit-code conversion, subprocess-only pinning, argparse
isolation via sys.argv poisoning, no-network-at-import for each stage module,
and shim->module delegation.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…tage

Replace each subprocess.run(stage) in the orchestrator with run_stage(STAGES[...],
argv). Stages now run in-process by default (heavy imports -- sentence-transformers,
torch, umap, evoc, datamapplot -- paid once instead of once per subprocess), while
DELPHI_STAGE_ISOLATION=subprocess restores the old behaviour.

Content-preserving: identical stage order (reset -> math -> umap-pipeline ->
extremity -> priorities -> datamapplot-per-layer), identical per-stage argv,
identical error semantics (reset/math abort on nonzero; umap/extremity/priorities/
datamapplot warn-and-continue), and the DynamoDB layer-discovery block, env-var
contracts (OLLAMA_MODEL/OLLAMA_HOST/MAX_VOTES/BATCH_SIZE/DELPHI_APP_PATH/PYTHONPATH/
DYNAMODB_ENDPOINT) and colored logging are all unchanged. Heavy stage deps are
imported lazily, so --help and orchestrator import stay cheap.

Full suite: 595 passed (570 baseline + 25 stage-runner), 17 skipped, 47 xfailed.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@jucor
jucor force-pushed the jc/umap-inprocess-stages branch from 80fe512 to 49b8114 Compare July 21, 2026 19:50
@github-actions

Copy link
Copy Markdown

Delphi Coverage Report

File Stmts Miss Cover
init.py 2 0 100%
benchmarks/bench_pca.py 128 107 16%
benchmarks/bench_repness.py 81 65 20%
benchmarks/bench_update_votes.py 38 28 26%
benchmarks/benchmark_utils.py 34 24 29%
components/init.py 1 0 100%
components/config.py 165 133 19%
conversation/init.py 2 0 100%
conversation/conversation.py 1108 259 77%
conversation/manager.py 131 42 68%
database/init.py 1 0 100%
database/dynamodb.py 395 189 52%
database/postgres.py 306 206 33%
pca_kmeans_rep/init.py 5 0 100%
pca_kmeans_rep/clusters.py 257 21 92%
pca_kmeans_rep/corr.py 98 17 83%
pca_kmeans_rep/pca.py 135 18 87%
pca_kmeans_rep/repness.py 208 9 96%
regression/init.py 4 0 100%
regression/clojure_comparer.py 188 20 89%
regression/comparer.py 887 720 19%
regression/datasets.py 135 27 80%
regression/recorder.py 36 27 25%
regression/utils.py 138 94 32%
run_math_pipeline.py 261 114 56%
umap_narrative/500_generate_embedding_umap_cluster.py 210 109 48%
umap_narrative/501_calculate_comment_extremity.py 6 6 0%
umap_narrative/502_calculate_priorities.py 6 6 0%
umap_narrative/700_datamapplot_for_layer.py 6 6 0%
umap_narrative/701_static_datamapplot_for_layer.py 310 310 0%
umap_narrative/702_consensus_divisive_datamapplot.py 432 432 0%
umap_narrative/801_narrative_report_batch.py 785 785 0%
umap_narrative/802_process_batch_results.py 268 268 0%
umap_narrative/803_check_batch_status.py 183 183 0%
umap_narrative/llm_factory_constructor/init.py 2 2 0%
umap_narrative/llm_factory_constructor/model_provider.py 192 192 0%
umap_narrative/polismath_commentgraph/init.py 1 0 100%
umap_narrative/polismath_commentgraph/cli.py 270 270 0%
umap_narrative/polismath_commentgraph/core/init.py 3 3 0%
umap_narrative/polismath_commentgraph/core/clustering.py 108 108 0%
umap_narrative/polismath_commentgraph/core/embedding.py 104 104 0%
umap_narrative/polismath_commentgraph/lambda_handler.py 219 219 0%
umap_narrative/polismath_commentgraph/schemas/init.py 2 0 100%
umap_narrative/polismath_commentgraph/schemas/dynamo_models.py 160 9 94%
umap_narrative/polismath_commentgraph/tests/conftest.py 17 17 0%
umap_narrative/polismath_commentgraph/tests/test_clustering.py 74 74 0%
umap_narrative/polismath_commentgraph/tests/test_embedding.py 55 55 0%
umap_narrative/polismath_commentgraph/tests/test_storage.py 87 87 0%
umap_narrative/polismath_commentgraph/utils/init.py 3 0 100%
umap_narrative/polismath_commentgraph/utils/converter.py 283 237 16%
umap_narrative/polismath_commentgraph/utils/group_data.py 354 336 5%
umap_narrative/polismath_commentgraph/utils/storage.py 584 518 11%
umap_narrative/reset_conversation.py 163 53 67%
umap_narrative/run_pipeline.py 453 312 31%
umap_narrative/stages/comment_extremity.py 112 53 53%
umap_narrative/stages/comment_priorities.py 134 134 0%
umap_narrative/stages/datamapplot_layer.py 502 502 0%
umap_narrative/stages/runner.py 81 13 84%
utils/general.py 62 41 34%
Total 10975 7564 31%

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.

2 participants