Skip to content

refactor(api): GenerationScheme protocol + registry [LTV-Pd]#107

Merged
shaypal5 merged 3 commits into
mainfrom
refactor/generation-scheme-registry
Jun 10, 2026
Merged

refactor(api): GenerationScheme protocol + registry [LTV-Pd]#107
shaypal5 merged 3 commits into
mainfrom
refactor/generation-scheme-registry

Conversation

@shaypal5

Copy link
Copy Markdown
Contributor

Summary

First step of the peer-schemes architecture (LTV-Pd, milestone
LTV-M2). Introduces the generation-scheme abstraction and routes
Generator.generate() through it, wrapping the existing lead-scoring pipeline
as the first registered scheme. Pure refactor — lead-scoring output is
byte-identical
(verified below).

What's added

  • leadforge/schemes/base.pyGenerationScheme protocol,
    SCHEME_REGISTRY, register_scheme / get_scheme / available_schemes,
    UnknownSchemeError. The protocol covers the generation half
    (build_population + simulate) wired through Generator; render dispatch
    is added later (LTV-M6).
  • leadforge/schemes/lead_scoring/__init__.pyLeadScoringScheme,
    delegating to leadforge.simulation.{population,engine} (those modules
    relocate under this package in LTV-Pe); self-registers on import.
  • leadforge/schemes/__init__.py — imports built-in schemes for their
    registration side effect; re-exports the registry API.
  • Recipe gains a scheme field (default "lead_scoring"), parsed in
    from_dict; b2b_saas_procurement_v1/recipe.yaml declares it explicitly.
  • WorldSpec gains scheme (default "lead_scoring"); from_recipe threads
    recipe.scheme; Generator.generate() resolves and runs the scheme via
    get_scheme() instead of calling build_population/simulate_world directly.

World-graph sampling and bundle rendering stay in their current paths (only
lead_scoring is registered and run); they move under the scheme abstraction
in later LTV-M2/LTV-M6 PRs.

Byte-identical verification

Generated a pinned-timestamp student_public bundle (seed 42, intro,
80/160/200) on main and on this branch and compared SHA-256 of every file:

✅ BYTE-IDENTICAL: all 14 bundle files hash identically (main vs LTV-Pd)

Tests

tests/schemes/test_registry.py (15): registry resolution, runtime_checkable
protocol conformance, conflict/unknown handling, Recipe.scheme
parsing/validation, WorldSpec default, Generator threading + end-to-end
dispatch (incl. unknown-scheme error path).

  • Full suite: 1495 passed / 51 skipped (+15).
  • ruff check + ruff format --check clean; mypy leadforge/ clean (87 files).
  • BUNDLE_SCHEMA_VERSION unchanged.

🤖 Generated with Claude Code

First step of the peer-schemes architecture (LTV-M2). Introduces the
generation-scheme abstraction and routes Generator.generate() through it,
wrapping the existing lead-scoring pipeline as the first registered scheme.
Lead-scoring output is unchanged (the wrapper delegates to the identical
functions); this PR is a pure refactor.

- leadforge/schemes/base.py — GenerationScheme protocol, SCHEME_REGISTRY,
  register_scheme/get_scheme/available_schemes, UnknownSchemeError. The
  protocol covers the generation half (build_population + simulate) wired
  through Generator; render dispatch is added later (LTV-M6).
- leadforge/schemes/lead_scoring/__init__.py — LeadScoringScheme, delegating
  to leadforge.simulation.{population,engine} (relocated under this package in
  LTV-Pe); self-registers on import.
- leadforge/schemes/__init__.py — imports built-in schemes for their
  registration side effect; re-exports the registry API.
- Recipe gains a `scheme` field (default "lead_scoring"); parsed in from_dict.
  b2b_saas_procurement_v1/recipe.yaml declares `scheme: lead_scoring`.
- WorldSpec gains `scheme` (default "lead_scoring"); from_recipe threads
  recipe.scheme through; Generator.generate() resolves and runs the scheme via
  get_scheme() instead of calling build_population/simulate_world directly.

World-graph sampling and bundle rendering still run in their current paths
(lead-scoring only registered); they move under the scheme abstraction in
later M2/M6 PRs.

Tests: tests/schemes/test_registry.py (15) — registry resolution, protocol
conformance, conflict/unknown handling, Recipe.scheme parsing/validation,
WorldSpec default, Generator threading + end-to-end dispatch. Full suite 1495
passed / 51 skipped; ruff + mypy clean (87 files).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@shaypal5 shaypal5 added this to the dataset: leadforge-ltv-v1 milestone Jun 10, 2026
@shaypal5 shaypal5 added type: refactor Code change with no behavior difference layer: core core/ primitives (RNG, IDs, models, exceptions) layer: api api/ public Python surface labels Jun 10, 2026
Copilot AI review requested due to automatic review settings June 10, 2026 08:05
@shaypal5 shaypal5 added status: needs review Ready for review dataset: leadforge-ltv-v1 Issue/PR scoped to the b2b_saas_ltv_v1 LTV dataset workstream labels Jun 10, 2026

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.

Copilot encountered an error and was unable to review this pull request. You can try again by re-requesting a review.

Check off LTV-Pd, link PR #107, note the byte-identical verification, and
advance the agent-plan status to LTV-Pe next.

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

This comment has been minimized.

…V-Pd]

Acts on a hostile self-review of the first revision. The original cut the
abstraction at build_population/simulate with lead-scoring-shaped signatures
(world_graph, category_latent_correlations, latent_touch_intensity,
PopulationResult/SimulationResult), leaving graph sampling, difficulty
interpretation, and bundle assembly hardcoded in Generator.generate(). That
seam could not accommodate a non-lead-scoring scheme — defeating the point of
extracting it early.

Changes:
- GenerationScheme protocol is now a single `build_world(config, narrative,
  **options) -> WorldBundle`. No lead-scoring types leak into the contract;
  scheme-specific flags ride through **options.
- LeadScoringScheme.build_world owns the whole lead-scoring pipeline: hidden-DAG
  sampling, difficulty-profile → DifficultyParams + category-latent
  correlations (extracted to _resolve_difficulty), population, simulation, and
  WorldBundle assembly. Generator.generate() is now scheme-agnostic
  (override resolution + dispatch only).
- Fix dropped-scheme bug: build_world sets spec.scheme=self.name, so
  bundle.spec.scheme reflects the actual scheme (was always the default).
- DEFAULT_SCHEME constant in core.models removes the duplicated "lead_scoring"
  literal across Recipe/WorldSpec; a test guards LeadScoringScheme.name ==
  DEFAULT_SCHEME.
- Tests: regression for bundle.spec.scheme, determinism through the scheme
  path, name/default drift guard; protocol-conformance test annotated as the
  weak structural check it is.

Verified still byte-identical to main (14/14 files of a pinned-timestamp
bundle). Full suite 1498 passed / 51 skipped; ruff + mypy clean.

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 #107 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: 27262915205 attempt 1
Comment timestamp: 2026-06-10T08:17:19.588580+00:00
PR head commit: 8d29cf60cfbcda84664a1e9e5857bf2aea466edd

@shaypal5 shaypal5 merged commit 901bc0a into main Jun 10, 2026
9 of 10 checks passed
@shaypal5 shaypal5 deleted the refactor/generation-scheme-registry branch June 10, 2026 08:49
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: core core/ primitives (RNG, IDs, models, exceptions) status: needs review Ready for review type: refactor Code change with no behavior difference

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants