Skip to content

refactor: shared bundle-writing orchestrator [LTV-Pn.4d]#128

Merged
shaypal5 merged 2 commits into
mainfrom
refactor/shared-bundle-orchestrator
Jun 16, 2026
Merged

refactor: shared bundle-writing orchestrator [LTV-Pn.4d]#128
shaypal5 merged 2 commits into
mainfrom
refactor/shared-bundle-orchestrator

Conversation

@shaypal5

Copy link
Copy Markdown
Contributor

Summary

Final sub-PR of the split LTV-Pn.4 — and the last carried M2 cleanup (#1, shared render orchestration). Both schemes' write_bundle ran the same on-disk sequence (mkdir → relational → task splits → card → dictionary → exposure → manifest), differing only in content. This lifts that sequence into one place.

render/bundle.pywrite_bundle_envelope

Owns the shared I/O and the file-ordering the manifest's hashing depends on, with no scheme-specific logic. A scheme computes its final exposure-projected relational frames, its per-task TaskExport(manifest, frame) list, its rendered dataset card, its visible feature catalog, and its manifest params — then delegates.

Both LeadScoringScheme.write_bundle and LifecycleScheme.write_bundle are now thin: scheme-specific content computation + one envelope call.

One wrinkle handled cleanly: the dataset card needs table row counts (computed during the relational write). Each scheme computes {name: len(df)} on its final frames — identical to write_relational_tables' return (redaction drops columns, not rows) — and renders the card before delegating.

Byte-identity

All four bundles — lead_scoring + lifecycle, each in research_instructor + student_public — verified byte-identical against a pre-refactor SHA-256 reference of every file. The orchestration moved; no output changed.

Tests

New tests/render/test_bundle_envelope.py pins the envelope's own contract (all artefacts written; manifest passthrough fields incl. motif_family/extra_fields; multiple task dirs; no metadata/ in snapshot-safe mode) on a minimal bundle. Full suite 1877 passed / 51 skipped, ruff + mypy clean.

Milestone

This completes LTV-Pn.4 and discharges the last of the three carried M2 cleanups. Next: LTV-Po — the b2b_saas_ltv_v1 recipe assets + end-to-end Generator.from_recipe(...), where the deferred recipe-driven difficulty resolution and the narrative-consumption decision also come due.

🤖 Generated with Claude Code

Final sub-PR of the split LTV-Pn.4 (and the last carried M2 cleanup, #1).
Both schemes' write_bundle performed the same on-disk sequence — mkdir →
relational tables → task splits → dataset card → feature dictionary → exposure
metadata → manifest — differing only in the *content*.  Lift that sequence into
one place.

- New render/bundle.py: write_bundle_envelope(bundle, root, *, relational,
  tasks, dataset_card, feature_specs, generation_scheme, redacted, motif_family,
  relational_snapshot_safe, structural_redactions, extra_fields,
  generation_timestamp) + a TaskExport(manifest, frame) record.  It owns the I/O
  and the file-ordering the manifest's hashing depends on; it contains no
  scheme-specific logic.
- LeadScoringScheme.write_bundle and LifecycleScheme.write_bundle now compute
  only their scheme-specific content (which relational frames + snapshot-safe
  projection, which task exports, which card, which visible features, which
  manifest params) and delegate to the envelope.
- The dataset card needs table row counts; each scheme computes
  {name: len(df)} on its final frames (identical to write_relational_tables'
  counts — redaction drops columns, not rows) and renders the card before
  delegating.

Byte-identity: all FOUR bundles — lead_scoring + lifecycle, each in
research_instructor + student_public — verified byte-identical against a
pre-refactor SHA-256 reference of every file.  The orchestration moved; no
output changed.

Tests: new tests/render/test_bundle_envelope.py pins the envelope contract
(all artefacts written, manifest passthrough fields, multiple task dirs,
no metadata in snapshot-safe mode) on a minimal bundle.  Full suite 1877
passed / 51 skipped; ruff + mypy clean.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings June 15, 2026 15:11
@shaypal5 shaypal5 added this to the dataset: leadforge-ltv-v1 milestone Jun 15, 2026
@shaypal5 shaypal5 added type: refactor Code change with no behavior difference layer: render render/ bundle and artifact output layer: api api/ public Python surface dataset: leadforge-ltv-v1 Issue/PR scoped to the b2b_saas_ltv_v1 LTV dataset workstream labels Jun 15, 2026
@github-actions

This comment has been minimized.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Pull request overview

This PR factors the shared “write bundle to disk” orchestration out of individual schemes into a single, scheme-agnostic envelope function (write_bundle_envelope). Both LeadScoringScheme.write_bundle and LifecycleScheme.write_bundle now focus on computing scheme-specific content (frames, tasks, card, visible features, manifest params) and delegate the deterministic I/O sequence (tables → tasks → card → dictionary → exposure → manifest) to the shared renderer.

Changes:

  • Added leadforge/render/bundle.py with write_bundle_envelope and a TaskExport container to standardize task export inputs.
  • Refactored lifecycle and lead-scoring schemes to delegate bundle writing to the new envelope while preserving their scheme-specific computation steps.
  • Added tests/render/test_bundle_envelope.py to pin the envelope’s contract (artifact outputs, manifest passthrough fields, multi-task behavior, and snapshot-safe metadata omission).

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated no comments.

Show a summary per file
File Description
leadforge/render/bundle.py Introduces the shared bundle-writing envelope (I/O ordering + manifest build/write).
leadforge/schemes/lead_scoring/__init__.py Refactors scheme bundle writing to compute content then call write_bundle_envelope.
leadforge/schemes/lifecycle/__init__.py Refactors scheme bundle writing to compute content then call write_bundle_envelope (incl. lifecycle structural redactions passthrough).
tests/render/test_bundle_envelope.py Adds focused tests validating the envelope’s filesystem outputs and manifest behavior.
docs/ltv/roadmap.md Marks LTV-Pn.4d as completed and links PR #128.
.agent-plan.md Updates project plan/status text to reflect the refactor completion.

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

…LTV-Pn.4d]

Self-review of the orchestrator extraction: lead-scoring's write_bundle now
writes tasks through the shared bundle envelope, so the
schemes.lead_scoring.render.tasks wrapper is no longer on the write-bundle path
— its docstring still claimed it kept the default "so existing call sites are
unchanged," which is now stale.  The wrapper is not dead: it remains a tested
convenience (its 7 test consumers rely on the CONVERTED_WITHIN_90_DAYS default),
so removing it would only churn tests to pass an explicit task and reverse the
deliberate Pn.3 layout.  Docstring updated to state it's the scheme's
default-task helper, off the write path since Pn.4d.

No behaviour change.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@github-actions

Copy link
Copy Markdown

pr-agent-context report:

No unresolved review comments, failing checks, or actionable patch coverage gaps were found on PR #128 in repository https://github.com/leadforge-dev/leadforge. Treat this PR as all clear unless new signals appear.

Run metadata:

Tool ref: v4
Tool version: 4.0.21
Trigger: commit pushed
Workflow run: 27561943458 attempt 1
Comment timestamp: 2026-06-15T16:49:08.200588+00:00
PR head commit: 641888c2ab669266c8abd23dc515a76513feab0a

@shaypal5 shaypal5 merged commit 6507be4 into main Jun 16, 2026
10 checks passed
@shaypal5 shaypal5 deleted the refactor/shared-bundle-orchestrator branch June 16, 2026 07:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

dataset: leadforge-ltv-v1 Issue/PR scoped to the b2b_saas_ltv_v1 LTV dataset workstream layer: api api/ public Python surface layer: render render/ bundle and artifact output type: refactor Code change with no behavior difference

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants