Enforce draft KV strong-sync for CP HiCache hits
CP HiCache host hits must not advertise target residency unless the draft payload is also valid when EAGLE/MTP draft HiCache is attached. This closes target-only metadata paths by making the CP host-valid predicate and load replay fail fast, resets draft host storage with the target host pool, and records the P1-P3 strong-sync plan state. The page-index validator is restored for CPU/fake-test tensors only, preserving unit-test coverage for malformed page spans without reintroducing CUDA hot-path host sync. Constraint: CP shared KV + HiCache + EAGLE/MTP cannot safely demote malformed target/draft metadata to an ordinary cache miss Rejected: keep permissive fallback for missing draft_host_indices | it can look like a successful cache hit while poisoning speculative acceptance Rejected: re-enable generic CUDA tensor page validation | it can force host sync in the HiCache transfer hot path Confidence: high Scope-risk: moderate Reversibility: clean Directive: Do not add silent fallback around CP draft HiCache metadata; unexpected target/draft divergence should fail fast with node/rank context Tested: remote container targeted tests: 5 passed Tested: remote container files test_cp_hicache_metadata.py and test_hicache_controller_cp.py: 77 passed Tested: remote container test_page_index_utils.py: 8 passed Tested: local git diff --check and py_compile for modified Python files Not-tested: full CP shared KV + HiCache + EAGLE/MTP ETE Co-authored-by: OmX <omx@oh-my-codex.dev>
This commit is contained in:
@@ -541,6 +541,34 @@ class TestHiCacheControllerCPLoad(TestHiCacheControllerCPWrite):
|
||||
self.assertEqual(host_pool.loads, [])
|
||||
self.assertEqual(len(controller.ack_load_queue), 1)
|
||||
|
||||
def test_cp_load_zero_owned_rejects_missing_draft_metadata_when_draft_attached(self):
|
||||
host_pool = FakeHostPool(torch.tensor([], dtype=torch.int64))
|
||||
allocator = FakeAllocator(alloc_result=torch.arange(64, 68, dtype=torch.int64))
|
||||
controller = self.make_controller(
|
||||
host_pool,
|
||||
allocator=allocator,
|
||||
cp_rank=3,
|
||||
draft_host_pool=FakeHostPool(torch.tensor([], dtype=torch.int64)),
|
||||
draft_mem_pool_device=FakeDevicePool("draft"),
|
||||
)
|
||||
node = TreeNode()
|
||||
node.host_len = 4
|
||||
node.cp_hicache = CpHiCacheNodeMetadata(
|
||||
logical_len=4,
|
||||
owned_positions=torch.empty((0,), dtype=torch.int64),
|
||||
host_indices=torch.empty((0,), dtype=torch.int64),
|
||||
page_owners=torch.tensor([0], dtype=torch.int8),
|
||||
page_size=4,
|
||||
)
|
||||
|
||||
with self.assertRaisesRegex(RuntimeError, "draft KV restore requested"):
|
||||
controller.load_cp([node], node_id=33)
|
||||
|
||||
self.assertEqual(allocator.owner_alloc_calls, [[0]])
|
||||
self.assertEqual(allocator.frees[0].tolist(), [64, 65, 66, 67])
|
||||
self.assertEqual(controller.load_queue, [])
|
||||
self.assertEqual(controller.draft_load_queue, [])
|
||||
|
||||
def test_cp_load_queues_cpu_host_indices_before_backend_moves(self):
|
||||
host_pool = FakeHostPool(torch.tensor([100, 101, 102, 103], dtype=torch.int64))
|
||||
allocator = FakeAllocator(alloc_result=torch.arange(64, 80, dtype=torch.int64))
|
||||
|
||||
Reference in New Issue
Block a user