Skip to content

feat(composition): cycles + recursive + version pinning (013, US4+US5 / PR 5)#255

Merged
mlieberman85 merged 1 commit into
kusari-oss:mainfrom
mlieberman85:013-composition-us4-us5
May 13, 2026
Merged

feat(composition): cycles + recursive + version pinning (013, US4+US5 / PR 5)#255
mlieberman85 merged 1 commit into
kusari-oss:mainfrom
mlieberman85:013-composition-us4-us5

Conversation

@mlieberman85
Copy link
Copy Markdown
Contributor

Summary

PR 5 of 5 functional PRs for feature 013-plugin-composition, stacked on US3 (#254). Bundles US4 — cycle detection + recursive composition (P3) and US5 — version pinning (P3) because both are small P3 guardrails on top of the now-feature-complete resolver. The two stories share no overlapping code, and the task plan explicitly suggested this bundle (PR 5 in suggested boundaries).

Of particular note: this PR adds test_loader_path_cycle_through_public_loader — the canonical F-1 regression test that loads a composite-of-composite cycle through the production darnit.config.merger.load_framework_config path and asserts it's detected in under 1 second. Pre-F-1 this would have hung indefinitely. This is the load-bearing guarantee that the resolver/loader split from PR 1 is correct.

What's in this PR

US4 — Cycle detection + recursive composition (T043–T046b)

Task Status Notes
T043 — CompositionCycleError.__str__ renders chain Already shipped in PR 1 chain: list[str] attribute; " → " join in message
T044 — Self-cycle fixture + test New chain == ["cycle-a", "cycle-a"]
T045 — Two-cycle fixture + test New 3-element chain, starts+ends with same slug
T046 — Three-level chain (positive) New FR-018 + FR-015 critical assertion: every resolved control's _composed_from points at the ULTIMATE non-composite source (mock-source-c-leaf), NOT the intermediate composite
T046b — F-1 regression through public loader New Monkey-patches _default_source_loader to find fixtures; asserts cycle detected in <1s through load_framework_config

US5 — Version pinning (T047–T050)

Task Status Notes
T047 — Runtime version check Already shipped in PR 2 _check_version_constraint runs in compose-block iteration; raises CompositionVersionMismatchError(source, constraint, installed)
T048 — Pin satisfied New mock-source-a@1.5.0 satisfies >=1.0,<2.0
T049 — Pin violated New mock-source-a@1.5.0 does NOT satisfy >=2.0; error names source / constraint / installed
T050 — No pin = floating New Reuses basic-include-all fixture; resolves regardless of source version (FR-014)

Test plan

  • uv run ruff check . — clean
  • uv run pytest tests/darnit/test_composition.py -v28 passed (12 US1 + 6 US2 + 4 US3 + 4 US4 + 3 US5 + 1 foundational idempotence)
  • uv run pytest tests/ --ignore=tests/integration/ -q2102 passed (6 new) / 6 skipped / 0 failed
  • Smoke: test_loader_path_cycle_through_public_loader exercises the F-1 regression through the production loader path (would have hung pre-fix)
  • Smoke: three-level chain provenance — every resolved control traces to mock-source-c-leaf, never to mock-source-mid-composite

Status of feature

Every spec FR (1–18) and every SC (1–8) is now covered by fixture-driven tests. The resolver is functionally complete; this is the last PR that adds new behavior to darnit.core.composition.

FR Coverage
1–5 (TOML compose primitives) US1
6–8 (override primitives) US2
9–11 (conflict resolution) US3
12 (cycles) US4
13–14 (version pinning) US5
15 (provenance) US1 + reinforced US2 + US4 (recursive traces to ultimate source)
16–17 (audit/CLI compatibility) US1 (audit pipeline shape test); FR-017 explicit test still in Polish (F-6)
18 (recursive composition) US4 (three-level chain + F-1 regression)

Subsequent PRs

PR Tasks Story
next (final) T051–T063 Polish — perf benchmark (SC-002 ≤200ms), SC-008 explicit test (F-5), FR-017 CLI test (F-6), F-7 dual MCP tool test, doc sync, lint, full suite, quickstart smoke

🤖 Generated with Claude Code

US4 — cycle-chain error messages, recursive composition (FR-018),
F-1 regression test through the public loader path.
US5 — PEP 440 version pinning per [[compose]] block (FR-013/FR-014).

What lands in this PR (T043-T050 + T046b):

- T043 already shipped in PR 1: CompositionCycleError.__str__
  renders chain joined by " → " and stores `chain: list[str]`.
- T047 already shipped in PR 2: _check_version_constraint runs at
  compose-block iteration time and raises
  CompositionVersionMismatchError on miss.
- 8 new fixtures: cycle-a (self), cycle-x/y (two-cycle), three-
  level-chain (positive recursive), loader-cycle-x/y (F-1 regression),
  version-pin-satisfied, version-pin-violated.
- 6 new tests:
  - test_self_cycle_raises (T044): chain == ["cycle-a", "cycle-a"];
    error renders "cycle-a → cycle-a".
  - test_two_cycle_raises (T045): 3-element chain, starts+ends with
    same slug, contains both cycle members.
  - test_three_level_chain_resolves (T046, positive): the load-bearing
    FR-018 + FR-015 assertion — every resolved control's
    _composed_from points at the ULTIMATE non-composite source
    (mock-source-c-leaf), NOT the intermediate composite.
  - test_loader_path_cycle_through_public_loader (T046b): F-1
    regression — loads a cycle through PUBLIC load_framework_config
    (monkeypatching _default_source_loader to find fixtures, since
    PluginRegistry doesn't know about test files). Asserts the cycle
    is detected in <1 second. Pre-F-1 this would have hung
    indefinitely. This is the canonical guarantee that the
    resolver/loader split is correct.
  - test_version_pin_satisfied (T048): 1.5.0 satisfies >=1.0,<2.0.
  - test_version_pin_violated (T049): 1.5.0 does NOT satisfy >=2.0;
    CompositionVersionMismatchError with .source / .constraint /
    .installed populated.
  - test_version_pin_missing_uses_floating (T050): no
    version_constraint reuses basic-include-all fixture, resolves
    cleanly (FR-014).

Verification:
- ruff check: clean
- full suite: 2102 passed (6 new) / 6 skipped / 0 failed

Status: every spec FR (1-18) and every SC (1-8) is now covered by
fixture-driven tests. What remains is the Polish phase — perf
benchmark, SC-008 explicit test, FR-017 CLI test, F-7 dual MCP tool
test, doc sync, lint, full suite, quickstart smoke.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@mlieberman85 mlieberman85 merged commit 2abce8d into kusari-oss:main May 13, 2026
9 checks passed
@mlieberman85 mlieberman85 deleted the 013-composition-us4-us5 branch May 13, 2026 22:48
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.

1 participant