Add blueprint workflow CLI commands#385
Conversation
📝 WalkthroughWalkthroughThis PR adds two new CLI commands for blueprint materialization and release auditing. The ChangesBlueprint CLI Enhancement
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@src/casecrawler/cli.py`:
- Around line 2076-2080: The CLI is calling DatasetStore.list_blueprints(...)
with limit=None which forces an eager load of every blueprint into memory
(blueprints) and makes export-blueprints / validate-blueprints /
materialize-blueprints OOM-prone; instead either (A) change the DatasetStore API
to provide a streaming/paginated iterator (e.g., stream_blueprints or make
list_blueprints yield an iterator) and consume that here, or (B) replace the
single call with a paginated loop that repeatedly calls list_blueprints with a
fixed batch size and a cursor/offset until no more results, processing each
batch as you go; update the CLI paths (export-blueprints, validate-blueprints,
materialize-blueprints) to use the streaming/paginated approach rather than
limit=None so blueprints are processed in bounded batches.
- Around line 2164-2176: The current loop calls materializer.materialize per
blueprint and may persist partial results before a later blueprint fails
release-readiness; first preflight all selected blueprints by calling
store.get_blueprint_validation_report(...) and invoking
materializer.materialize(...) in a dry-run/preflight mode (or call a
validation-only API) for each blueprint to detect
ValueError/require_release_ready failures, raising click.ClickException
immediately if any fail; only after all blueprints pass the preflight, run a
second loop that calls materializer.materialize(...) for real (the existing
call) to perform writes. Ensure you reference the existing symbols blueprint,
store.get_blueprint_validation_report, materializer.materialize, and the
require_release_ready flag when implementing the two-phase
preflight-then-materialize change.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: 9a10abd2-ff0f-424f-a5af-7e7483936752
📒 Files selected for processing (2)
src/casecrawler/cli.pytests/test_cli_synthetic.py
| blueprints = store.list_blueprints( | ||
| dataset_id=dataset_id, | ||
| cohort_plan_id=cohort_plan_id, | ||
| limit=1_000_000, | ||
| limit=None, | ||
| ) |
There was a problem hiding this comment.
Unbounded scans still eagerly load every blueprint into memory.
DatasetStore.list_blueprints() returns a full Python list, so limit=None turns these CLI paths into all-at-once loads. On large datasets, export-blueprints, validate-blueprints, and materialize-blueprints can become OOM-prone or stall before doing useful work. If the intent is truly unbounded processing, this needs a paged/streaming store API rather than removing the cap at the call site.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/casecrawler/cli.py` around lines 2076 - 2080, The CLI is calling
DatasetStore.list_blueprints(...) with limit=None which forces an eager load of
every blueprint into memory (blueprints) and makes export-blueprints /
validate-blueprints / materialize-blueprints OOM-prone; instead either (A)
change the DatasetStore API to provide a streaming/paginated iterator (e.g.,
stream_blueprints or make list_blueprints yield an iterator) and consume that
here, or (B) replace the single call with a paginated loop that repeatedly calls
list_blueprints with a fixed batch size and a cursor/offset until no more
results, processing each batch as you go; update the CLI paths
(export-blueprints, validate-blueprints, materialize-blueprints) to use the
streaming/paginated approach rather than limit=None so blueprints are processed
in bounded batches.
| for blueprint in blueprints: | ||
| validation_report = store.get_blueprint_validation_report( | ||
| blueprint.blueprint_id | ||
| ) | ||
| try: | ||
| materializer.materialize( | ||
| blueprint, | ||
| validation_report=validation_report, | ||
| store=store, | ||
| require_release_ready=require_release_ready, | ||
| ) | ||
| except ValueError as exc: | ||
| raise click.ClickException(str(exc)) from exc |
There was a problem hiding this comment.
Avoid partial materialization on a later release-readiness failure.
Because records are persisted inside the same loop that can still raise on a later blueprint, this command can exit non-zero after already saving a partial dataset. Preflight the selected blueprints first, then materialize once the whole batch is known to be eligible.
💡 One way to make the command fail before any writes
materializer = BlueprintMaterializer()
+ validation_reports = {
+ blueprint.blueprint_id: store.get_blueprint_validation_report(blueprint.blueprint_id)
+ for blueprint in blueprints
+ }
+
+ if require_release_ready:
+ for blueprint in blueprints:
+ report = validation_reports[blueprint.blueprint_id]
+ if report is None or not report.research_release_ready:
+ raise click.ClickException(
+ "Blueprint must be research release ready before materialization."
+ )
+
materialized_count = 0
for blueprint in blueprints:
- validation_report = store.get_blueprint_validation_report(
- blueprint.blueprint_id
- )
try:
materializer.materialize(
blueprint,
- validation_report=validation_report,
+ validation_report=validation_reports[blueprint.blueprint_id],
store=store,
require_release_ready=require_release_ready,
)🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@src/casecrawler/cli.py` around lines 2164 - 2176, The current loop calls
materializer.materialize per blueprint and may persist partial results before a
later blueprint fails release-readiness; first preflight all selected blueprints
by calling store.get_blueprint_validation_report(...) and invoking
materializer.materialize(...) in a dry-run/preflight mode (or call a
validation-only API) for each blueprint to detect
ValueError/require_release_ready failures, raising click.ClickException
immediately if any fail; only after all blueprints pass the preflight, run a
second loop that calls materializer.materialize(...) for real (the existing
call) to perform writes. Ensure you reference the existing symbols blueprint,
store.get_blueprint_validation_report, materializer.materialize, and the
require_release_ready flag when implementing the two-phase
preflight-then-materialize change.
Summary
Tests
Summary by CodeRabbit
Release Notes
New Features
materialize-blueprintsCLI command to generate synthetic record scaffolds from blueprints with optional release-ready validationexport-blueprint-release-summaryCLI command to output blueprint release readiness summary in JSON formatChanges
export-blueprintsandvalidate-blueprintscommands now retrieve all persisted blueprints (previously limited to fixed threshold)Tests