Skip to content

feat(querygen): add planning-batch checkpoint artifact and read engine#239

Open
henrycgbaker wants to merge 1 commit into
feat/querygen-resumable/03-paths-and-fingerprintsfrom
feat/querygen-resumable/04-planning-batch-artifact
Open

feat(querygen): add planning-batch checkpoint artifact and read engine#239
henrycgbaker wants to merge 1 commit into
feat/querygen-resumable/03-paths-and-fingerprintsfrom
feat/querygen-resumable/04-planning-batch-artifact

Conversation

@henrycgbaker

@henrycgbaker henrycgbaker commented May 29, 2026

Copy link
Copy Markdown
Collaborator

Stack (6 open PRs): #236#237#238#239#240#241#242

Chain goal: Add per-batch checkpoint/resume to querygen so a re-run with the same run_id skips already-completed work. Nests resumable state under <run_dir>/checkpoints/, writes a frozen Stage 1 result (planning + dedup) plus per-batch Stage 1 and Stage 2 artifacts, and orchestrates resume behind a fail-fast config-drift gate (--force overrides) so checkpoints are never silently reused under changed settings.

This PR (3/6): First of three vertical artifact slices. Adds per-batch checkpointing for Stage 1 planning, plus the generic read engine all three artifact readers (this PR's, #240's, #241's) delegate to.


What

  • PlanningBatchArtifact schema (querygen_output.py) with extra="forbid" + 1:1 candidate_ids/blueprints model_validator.
  • assemble_planning_batch_artifact stamps pragmata_version + created_at internally.
  • export_planning_batch_artifact — atomic JSON write via the helper from refactor(core): add shared atomic_write_text helper, adopt in querygen planning-summary export #237.
  • read_checkpoint_artifact (engine): returns (artifact, list[DriftedField])(artifact, []) reusable, (None, []) absent, (None, drifted) config-drifted; raises on damaged file (caller self-heals).
  • DriftedField@dataclass(frozen=True, slots=True) with field/stored/expected, in line with core's frozen-dataclass container convention.
  • read_planning_batch_artifact — thin typed wrapper over the engine (matches the existing read_planning_summary_artifact per-artifact typed-reader house pattern).

Why

The read engine is the reusable core of the whole stack: every checkpoint read (#240's frozen result, #241's realization batches, #242's orchestration) goes through read_checkpoint_artifact, so the drift/absent/damaged trichotomy is defined once here and the later PRs only add typed wrappers.

Test plan

  • tests/unit/core/querygen/test_planning_batches.py — schema, round-trip, header-mismatch (drift) per field, version-mismatch, malformed/extra-field, length-validator.

@github-actions github-actions Bot added feature Adds or expands user-facing functionality size: M 200-499 LOC labels May 29, 2026
@henrycgbaker henrycgbaker added contracts Changes schemas, type contracts, or validation logic for inputs, outputs, and persisted artifacts querygen Changes affecting the synthetic query generation tool labels May 29, 2026
saschagobel pushed a commit that referenced this pull request Jun 4, 2026
…n planning-summary export (#237)

**Stack (6 open PRs):** #237#238#239#240#241#242 

**Chain goal:** Add per-batch checkpoint/resume to querygen so a re-run
with the same `run_id` skips already-completed work. Nests resumable
state under `<run_dir>/checkpoints/`, writes a frozen Stage 1 result
(planning + dedup) plus per-batch Stage 1 and Stage 2 artifacts, and
orchestrates resume behind a fail-fast config-drift gate (`--force`
overrides) so checkpoints are never silently reused under changed
settings.

**This PR (1/6):** Extracts the tmpfile + atomic-rename idiom into a
shared `core/atomic_io.py` helper and adopts it for querygen's
planning-summary write — the atomic-write primitive every later
checkpoint artifact (#239–242) writes through.

---

## What
- `core/atomic_io.py` — `atomic_write_text` context manager:
PID+uuid-uniquified tempfile, `Path.replace` for the atomic rename, no
fsync (matches house style).
- Querygen `export.py` adopts it for `export_planning_summary` (indented
JSON for human-scannable persisted artifacts).
- **Note:** annotation `record_builder`/`export_runner` should adopt
`atomic_write_text` in a follow-up — kept out here to keep this PR's
dependency surface to querygen only.

## Why
Extracts the tmpfile + atomic-rename idiom (previously duplicated inline
in two annotation sites — `record_builder.write_partition_manifest` and
`export_runner.write_export_csv`) into one shared core helper, then
adopts it for querygen's planning-summary write. Reaches the rule-of-3
with the upcoming querygen artifact writes in #239–242.

## Test plan
- [x] `tests/unit/core/test_atomic_io.py` — round-trip +
temp-cleanup-on-exception.
@saschagobel saschagobel self-requested a review June 5, 2026 13:22
@saschagobel saschagobel marked this pull request as ready for review June 5, 2026 13:22

@saschagobel saschagobel left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

The PlanningBatchArtifact boundary itself makes sense to me for Stage 1 crash recovery, and the assemble/export/read split is broadly in line with the existing artifact pattern.

My concern is with the generic read/drift engine introduced here. DriftedField and read_checkpoint_artifact() feel heavier than needed for a first crash-resumability pass, especially because the broader stack currently moves toward config-drift handling and partial reuse under changed settings. For v1, I think we can keep this much simpler: checkpoint absent → run; checkpoint present and compatible with the same run_id / same effective settings → reuse; checkpoint incompatible → fail clearly. That likely only needs a small internal checkpoint read helper, not a reusable drift framework returning (artifact, list[DriftedField]).

So I’d suggest simplifying here and keeping the planning-batch reader focused on strict same-run compatibility.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

contracts Changes schemas, type contracts, or validation logic for inputs, outputs, and persisted artifacts feature Adds or expands user-facing functionality querygen Changes affecting the synthetic query generation tool size: M 200-499 LOC

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants