diff --git a/packages/infinity_context_server/infinity_context_server/retrieval_profile_composition.py b/packages/infinity_context_server/infinity_context_server/retrieval_profile_composition.py index b71be507..f9167ec9 100644 --- a/packages/infinity_context_server/infinity_context_server/retrieval_profile_composition.py +++ b/packages/infinity_context_server/infinity_context_server/retrieval_profile_composition.py @@ -118,6 +118,7 @@ async def reconcile_active( ) -> ActiveReconciliationResult: """Renew the active lease from a bounded, restart-safe physical observation.""" + reconciliation_started = monotonic() owner = self.runtime_owner if not isinstance(owner, RuntimeFenceOwner): raise RuntimeError("retrieval_profile_reconciliation_runtime_identity_missing") @@ -203,9 +204,10 @@ async def reconcile_active( operation = await self.registry.reconciliation_operation( active.profile_id, runtime_owner=owner ) + lease_now = now + timedelta(seconds=max(0.0, monotonic() - reconciliation_started)) evidence = await self.registry.activation_evidence( active.profile_id, - now=now, + now=lease_now, reconciliation_operation=operation, runtime_owner=owner, ) @@ -215,8 +217,8 @@ async def reconcile_active( evidence, operation=operation, runtime_owner=owner, - now=now, - expires_at=now + lease_ttl, + now=lease_now, + expires_at=lease_now + lease_ttl, drifted=not decision.accepted, mutation_epoch=mutation_epoch, ) diff --git a/tests/e2e/test_locator_lane_lease_continuity_postgres.py b/tests/e2e/test_locator_lane_lease_continuity_postgres.py index 2e5ce181..8b46f3c8 100644 --- a/tests/e2e/test_locator_lane_lease_continuity_postgres.py +++ b/tests/e2e/test_locator_lane_lease_continuity_postgres.py @@ -161,14 +161,18 @@ async def attest(*_args, **_kwargs): observation_now = current.expires_at - renew_before / 2 assert timedelta(0) < current.expires_at - observation_now < renew_before await assert_ready() + requested_now = observation_now result = await service.reconcile_active( now=observation_now, lease_ttl=lease_ttl, renew_before=renew_before ) assert result.complete and result.renewed and result.outcome == "applied" - renewed = await assert_ready() + renewed = await registry.active_lease(now=observation_now) + assert renewed is not None assert renewed.lease_id != current.lease_id - assert renewed.issued_at == observation_now - assert renewed.expires_at == observation_now + lease_ttl + assert renewed.issued_at >= requested_now + assert renewed.expires_at - renewed.issued_at == lease_ttl + observation_now = renewed.issued_at + await assert_ready() assert renewed.expires_at > current.expires_at assert writes == ["postgres_keyword", "qdrant_dense"] * 3 async with engine.connect() as connection: diff --git a/tests/server/test_active_reconciliation_identity.py b/tests/server/test_active_reconciliation_identity.py index a2ba3d3c..d854b8e7 100644 --- a/tests/server/test_active_reconciliation_identity.py +++ b/tests/server/test_active_reconciliation_identity.py @@ -65,6 +65,25 @@ def test_active_reconciliation_binds_exact_runtime_release_and_lifecycle_identit assert observed_operations == ["reconcile-1", "reconcile-3"] +def test_active_reconciliation_starts_lease_after_slow_attestation(monkeypatch) -> None: + owner = _owner("generation-current") + registry = _Registry(owner) + service = _service(owner, registry) + _accept_attestation(monkeypatch) + ticks = iter((100.0, 140.0)) + monkeypatch.setattr( + "infinity_context_server.retrieval_profile_composition.monotonic", + lambda: next(ticks), + ) + + result = asyncio.run(service.reconcile_active(now=NOW)) + + assert result.complete is True + assert result.renewed is True + assert registry.lease.issued_at == NOW + timedelta(seconds=40) + assert registry.lease.expires_at == NOW + timedelta(seconds=70) + + def test_runtime_start_and_clean_restart_are_generation_aware() -> None: first_owner = _owner("generation-first") registry = _Registry(None)