refactor(schema): scaffold schemes/lifecycle/ + register stub LifecycleScheme [LTV-Pg.1]#111
Merged
Merged
Conversation
…leScheme [LTV-Pg.1]
First half of the schema reorg (LTV-Pg). Gives the lifecycle scheme its own
home and makes it a registered peer of lead_scoring, ahead of building its
pipeline (M3–M6). Byte-identical; lead-scoring catalog unchanged.
- New leadforge/schemes/lifecycle/ package:
- entities.py — the 5 lifecycle rows (CustomerLifecycleRow,
SubscriptionLifecycleRow, SubscriptionEventRow, HealthSignalRow, InvoiceRow)
+ LIFECYCLE_ROW_TYPES / LIFECYCLE_TABLE_NAMES, moved from schema/entities.py.
AccountRow / EntityRowProtocol / _empty_df are shared and imported from
leadforge.schema.entities.
- relationships.py — LIFECYCLE_CONSTRAINTS, moved from schema/relationships.py
(reuses the shared FKConstraint).
- __init__.py — stub LifecycleScheme (build_world/write_bundle raise
NotImplementedError until M3–M6); self-registers. schemes/__init__ imports it.
- schema/entities.py and schema/relationships.py: lifecycle definitions removed;
breadcrumb comments point to the new home. ALL_ROW_TYPES / ALL_CONSTRAINTS
unchanged.
- tests/schema/test_lifecycle_entities.py → tests/schemes/lifecycle/test_entities.py
with updated imports; tests/schemes/test_registry.py gains lifecycle
registration + stub-raises-NotImplementedError tests.
- CHANGELOG, CLAUDE.md (both layouts), roadmap (Pg split into Pg.1/Pg.2),
agent-plan updated.
available_schemes() → ("lead_scoring", "lifecycle"). Verified byte-identical
(14/14 files); full suite 1534 passed / 51 skipped; ruff + mypy clean (92 files).
Note: class-level extraction from the shared schema/entities.py can't be a git
rename (multiple classes pulled from a multi-class file); the lifecycle rows
were only added in #104 so the history loss is shallow.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This comment has been minimized.
This comment has been minimized.
There was a problem hiding this comment.
Pull request overview
Scaffolds a new lifecycle generation scheme package as a registered peer of lead_scoring, relocating the lifecycle-specific schema contracts (rows + FK constraints) out of the shared leadforge.schema modules while keeping the lead-scoring catalog unchanged.
Changes:
- Added
leadforge/schemes/lifecycle/with lifecycle entity row dataclasses + lifecycle FK constraints. - Registered a stub
LifecycleScheme(raisesNotImplementedError) and ensured it is imported for registry side effects. - Updated tests and documentation/changelog to reflect the new module locations and registry behavior.
Reviewed changes
Copilot reviewed 12 out of 13 changed files in this pull request and generated no comments.
Show a summary per file
| File | Description |
|---|---|
leadforge/schemes/lifecycle/entities.py |
Adds lifecycle-only entity row dataclasses and lifecycle table registries (LIFECYCLE_ROW_TYPES, LIFECYCLE_TABLE_NAMES). |
leadforge/schemes/lifecycle/relationships.py |
Adds lifecycle-only FK constraint registry (LIFECYCLE_CONSTRAINTS) using shared FKConstraint. |
leadforge/schemes/lifecycle/__init__.py |
Introduces and self-registers stub LifecycleScheme (lifecycle). |
leadforge/schemes/__init__.py |
Imports lifecycle scheme module for registration side effects. |
leadforge/schema/entities.py |
Removes lifecycle-specific rows/registries from shared schema, leaving lead-scoring catalog intact (breadcrumb comment). |
leadforge/schema/relationships.py |
Removes lifecycle constraints from shared schema (breadcrumb comment). |
tests/schemes/test_registry.py |
Adds tests for lifecycle scheme registration and stub behavior. |
tests/schemes/lifecycle/test_entities.py |
Updates imports to the new lifecycle scheme module locations. |
docs/ltv/roadmap.md |
Updates roadmap to reflect Pg.1/Pg.2 split and records Pg.1 as PR #111. |
CLAUDE.md |
Updates repo layout documentation to include the new lifecycle scheme package. |
CHANGELOG.md |
Notes lifecycle schema/registry relocation and scheme registration. |
.agent-plan.md |
Updates the agent plan narrative for the Pg.1/Pg.2 split. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Self-review: schemes/lifecycle/entities.py imported a private symbol (`_empty_df`) across packages — a leading-underscore name signals module-internal, so importing it elsewhere is a smell. Promote it to a public shared helper `make_empty_dataframe` in leadforge.schema.entities (used by both the lead-scoring rows and the lifecycle rows); the cross-module import is now legitimate. No behaviour change (verified byte-identical, 14/14); full suite passes; ruff + mypy clean. (When LTV-Pg.2 moves lead-scoring rows out of schema/entities.py, make_empty_dataframe + EntityRowProtocol stay as the shared primitives.) Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
pr-agent-context report: No unresolved review comments, failing checks, or actionable patch coverage gaps were found on PR #111 in repository https://github.com/leadforge-dev/leadforge. Treat this PR as all clear unless new signals appear.Run metadata: |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
First half of the schema reorg (
LTV-Pg.1, milestoneLTV-M2). Givesthe lifecycle scheme its own package and makes it a registered peer of
lead_scoring, ahead of building its pipeline (M3–M6). Byte-identical;lead-scoring catalog untouched.
Changes
New
leadforge/schemes/lifecycle/:entities.py— the 5 lifecycle rows (CustomerLifecycleRow,SubscriptionLifecycleRow,SubscriptionEventRow,HealthSignalRow,InvoiceRow) +LIFECYCLE_ROW_TYPES/LIFECYCLE_TABLE_NAMES, moved fromschema/entities.py.AccountRow/EntityRowProtocol/_empty_dfareshared and imported from
leadforge.schema.entities.relationships.py—LIFECYCLE_CONSTRAINTS, moved fromschema/relationships.py(reuses the sharedFKConstraint).__init__.py— stubLifecycleScheme(build_world/write_bundleraiseNotImplementedErroruntil M3–M6); self-registers.schemes/__init__imports it.schema/entities.py/schema/relationships.py: lifecycle defs removed withbreadcrumb comments;
ALL_ROW_TYPES/ALL_CONSTRAINTSunchanged.Tests: lifecycle entity test moved to
tests/schemes/lifecycle/test_entities.py;test_registry.pygains lifecycle-registered + stub-raises-NotImplementedErrortests.
Why a stub now
Registering
lifecyclebefore its pipeline exists lets the registry, recipescheme:resolution, and tests treat it as a first-class peer. Calling it failsloudly (
NotImplementedError) rather than silently — and no recipe targets ityet, so the stub is never invoked in real runs.
Verification
ruff+mypyclean (92 files).BUNDLE_SCHEMA_VERSIONunchanged.Note
Class-level extraction from the shared multi-class
schema/entities.pycan't bea git rename; the lifecycle rows were only added in #104, so history loss is
shallow.
Next
LTV-Pg.2— split the lead-scoring schema (rows /ALL_ROW_TYPES/ALL_CONSTRAINTS/LEAD_SNAPSHOT_FEATURES/ task specs) out of sharedschema/intoschemes/lead_scoring/, completing the M2 reorg.🤖 Generated with Claude Code