From cb960237d3e265ee5fef0e1f31bcb723d0e4305b Mon Sep 17 00:00:00 2001 From: Jason Woltje Date: Thu, 13 Aug 2026 12:17:10 -0500 Subject: [PATCH] test(lease): assert promotion wiring against composed base+overlay template The lease-overlay split (a42d5e2e) moved the promotion hooks out of the base Claude settings template; the wiring test still read the base alone and failed on the absent UserPromptSubmit event, stopping the whole test:framework-shell chain. The test now composes base + lease overlay the way a launched seat does (hook event arrays concatenate, base first) and asserts the same wiring contract against that view. Reported-by: goals (clean-head probe on 5e154310) --- .../src/lease-broker/promotion_trigger_unittest.py | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/packages/mosaic/src/lease-broker/promotion_trigger_unittest.py b/packages/mosaic/src/lease-broker/promotion_trigger_unittest.py index 3f5deff1..0026f457 100644 --- a/packages/mosaic/src/lease-broker/promotion_trigger_unittest.py +++ b/packages/mosaic/src/lease-broker/promotion_trigger_unittest.py @@ -23,6 +23,7 @@ COMPLETE_PATH = TOOLS / "promote-complete.py" OBSERVER_CLIENT_PATH = TOOLS / "receipt-observer-client.py" RECEIPT_CHALLENGE_PATH = TOOLS / "receipt_challenge.py" CLAUDE_SETTINGS = FRAMEWORK / "runtime/claude/settings.json" +CLAUDE_LEASE_OVERLAY = FRAMEWORK / "runtime/claude/lease-overlay.json" CLAUDE_COMMAND = FRAMEWORK / "runtime/claude/commands/mosaic-promote.md" SESSION_ID = "a" * 64 CHALLENGE = "b" * 64 @@ -569,8 +570,15 @@ class PromotionCompleteTest(PromotionHookFixture): class PromotionTemplateWiringTest(unittest.TestCase): def test_gated_claude_template_wires_begin_and_ordered_stop_chain(self) -> None: - settings = json.loads(CLAUDE_SETTINGS.read_text(encoding="utf-8")) - hooks = settings["hooks"] + base = json.loads(CLAUDE_SETTINGS.read_text(encoding="utf-8")) + overlay = json.loads(CLAUDE_LEASE_OVERLAY.read_text(encoding="utf-8")) + # A launched seat composes base + lease overlay; hook event arrays + # concatenate with base entries first, so wiring is asserted against + # the composed view rather than either file alone. + hooks: dict[str, list] = {} + for layer in (base["hooks"], overlay["hooks"]): + for event, groups in layer.items(): + hooks.setdefault(event, []).extend(groups) submit_commands = [ hook["command"] for group in hooks["UserPromptSubmit"]