Skip to content

kas-scoped-transfer-cli#645

Merged
ksmuczynski merged 3 commits into
stagingfrom
kas-scoped-transfer-cli
Apr 10, 2026
Merged

kas-scoped-transfer-cli#645
ksmuczynski merged 3 commits into
stagingfrom
kas-scoped-transfer-cli

Conversation

@ksmuczynski

@ksmuczynski ksmuczynski commented Apr 10, 2026

Copy link
Copy Markdown
Contributor

Summary

This PR adds a new oco scoped-transfer command for running targeted legacy imports by PointID. It also adds the scoped transfer service behind that command, fixes scoped behavior in the well and water-level paths, reduces misleading log noise during scoped runs, and adds regression tests for the main scoped behaviors.

Why

This PR addresses the following problem / context:
The existing transfer workflow was built for broad or full-dataset runs, which made it hard to safely run and validate an import for one site or a small set of PointIDs. While building the scoped CLI, a few issues showed up in the well and water-level paths where the legacy behavior did not map cleanly to targeted runs. The output was also noisy enough that it could be hard to tell what mattered during a scoped transfer.

This PR creates a dedicated scoped-transfer workflow so targeted imports can be run more safely, more predictably, and with clearer operator feedback.

How

Implementation summary - the following was changed / added / removed:
Added a new oco scoped-transfer CLI command with:

  • --pointid support for targeted runs
  • optional --only / --skip family selection
  • dry-run support
  • human-readable and JSON output
  • short startup messages so long runs do not look stuck

Added the scoped transfer service in services/scoped_transfer.py with:

  • family registry and dependency expansion
  • family planners for dry-run reporting
  • scoped execution flow with per-family summary results
  • scoped filtering helpers for direct PointID and prefix-based tables

Added scoped wrappers / behavior fixes for key transfer paths:

  • scoped well handling so duplicate checks only apply to the requested PointID set
  • scoped water-level handling with rerun-safe skipping by GlobalID
  • water-level contact collision fallback that reuses existing contacts instead of failing the row group
  • reuse of legacy helper logic for water-level sample and observation creation to reduce drift

Reduced misleading log output in scoped CLI mode by suppressing known legacy warnings that are expected or irrelevant in targeted runs, including:

  • duplicate PointID warnings outside the requested scope
  • orphan-prevention summary warnings from reused transferers
  • owner secondary-contact warnings that do not affect scoped transfer results

Added regression coverage in tests/test_scoped_transfer_cli.py for:

  • CLI output behavior
  • dry-run planning behavior
  • chemistry planner behavior
  • water-level contact collision reuse
  • scoped duplicate filtering
  • scoped log suppression

Notes

Any special considerations, workarounds, or follow-up work to note?

  • The scoped transfer path reuses legacy transferers where that made sense, but applies scoped filtering and targeted behavior fixes in the CLI/service layer.
  • kas-transfer-select-pointids-and-data was used as the behavioral reference for scoping rules, rerun/idempotency behavior, and water-level contact handling.
  • Some implementation differences from legacy still remain, but they are considered acceptable where scoped behavior now matches the validated results.
  • The regression tests here are mainly to preserve the scoped CLI behavior validated during this work.

Add a new `oco scoped-transfer` command and the supporting scoped transfer service for running legacy transfers by PointID.

This adds scoped planning and execution, dependency expansion, family-level summary output, scoped well handling, scoped water-level idempotency, and contact-collision fallback reuse. It also suppresses legacy transfer warnings that are misleading in scoped CLI runs.
…coped transfer CLI and services

Add focused tests for scoped transfer CLI output and planning behavior.

This covers water-level contact collision reuse, scoped duplicate filtering and scoped log suppression for the targeted transfer workflow.

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

Adds a new oco scoped-transfer CLI workflow and supporting service layer to run targeted legacy transfers by specific PointID(s), including scoped filtering/behavior fixes for wells and water-level imports and regression tests to preserve the new scoped behavior.

Changes:

  • Added scoped-transfer CLI command with --pointid, --only/--skip, --dry-run, and human/JSON output modes.
  • Introduced services/scoped_transfer.py implementing family planning/execution, dependency expansion, scoped filtering helpers, and scoped transferer wrappers/fixes.
  • Added regression tests covering CLI output, dry-run planning, chemistry planning, scoped duplicate filtering, water-level contact collision reuse, and log suppression.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.

File Description
cli/cli.py Adds the scoped-transfer command and output formatting/exit-code behavior.
services/scoped_transfer.py Implements scoped transfer runtime, family registry, planners/executors, scoped transferer variants, and logging noise suppression.
tests/test_scoped_transfer_cli.py Adds unit/regression tests for scoped CLI/service behaviors.

Comment on lines +1940 to +1944
else:
matched_pointids.update(runtime.options.pointids)

missing = sorted(set(runtime.options.pointids) - matched_pointids)
if missing:

Copilot AI Apr 10, 2026

Copy link

Choose a reason for hiding this comment

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

The preflight PointID validation can miss partially-matching scopes: when any non-well/non-site-type family has applicable rows, the else branch marks all requested PointIDs as matched (matched_pointids.update(runtime.options.pointids)), so a run like --pointid A --pointid B --only waterlevels will not report B as missing if only A has rows. Track matched PointIDs from the filtered source data for each family (e.g., by returning/deriving a matched set from each planner) instead of assuming all requested PointIDs matched when any row exists.

Copilot uses AI. Check for mistakes.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

This only affects preflight validation, not the actual scoped filtering during execution, so it should not transfer the wrong records. I agree the right fix is to track matched PointIDs per planner, but I’m going to leave that as a follow-up to keep this PR focused on the scoped-transfer work.

Comment on lines +151 to +152
re.compile(r"^\d+ PointIDs have duplicates; will skip\.$"),
re.compile(r"^Duplicate PointIDs: "),

Copilot AI Apr 10, 2026

Copy link

Choose a reason for hiding this comment

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

The scoped log filter currently suppresses the duplicate-PointID messages ("PointIDs have duplicates; will skip." / "Duplicate PointIDs:"). After scoping ScopedWellTransferer’s duplicate check to the requested PointIDs, these messages become actionable (they explain why a requested PointID produced a no-op). Consider not filtering these patterns in scoped mode, or emitting a scoped-specific message (or ScopedFamilyResult.detail) that remains visible.

Suggested change
re.compile(r"^\d+ PointIDs have duplicates; will skip\.$"),
re.compile(r"^Duplicate PointIDs: "),

Copilot uses AI. Check for mistakes.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I think this is fine to leave as follow-up work for now. If it becomes an issue in real use, I'd prefer to show it in the scoped summary/detail output instead of re-enabling the raw legacy log messages.

Introduce a comprehensive guide for the `oco scoped-transfer` CLI command, including examples, common scenarios, troubleshooting tips, and JSON output details. Also, link the guide in `README.md`.
@ksmuczynski ksmuczynski merged commit 6471060 into staging Apr 10, 2026
8 checks passed
@ksmuczynski ksmuczynski deleted the kas-scoped-transfer-cli branch April 10, 2026 22:01
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.

3 participants