From c3e701404f59857f6aa9564cf63b99012e9eb9fd Mon Sep 17 00:00:00 2001 From: dusterbloom <32869278+dusterbloom@users.noreply.github.com> Date: Wed, 15 Jul 2026 18:19:06 +0200 Subject: [PATCH] refactor(draft): codify proposal row layout --- server/CMakeLists.txt | 9 ++++++++- server/src/draft/draft_contract.h | 31 +++++++++++++++++++++++++++++ server/src/internal.h | 6 ++++++ server/test/test_draft_contract.cpp | 28 ++++++++++++++++++++++++++ 4 files changed, 73 insertions(+), 1 deletion(-) create mode 100644 server/src/draft/draft_contract.h create mode 100644 server/test/test_draft_contract.cpp diff --git a/server/CMakeLists.txt b/server/CMakeLists.txt index dacd851bb..89c664e86 100644 --- a/server/CMakeLists.txt +++ b/server/CMakeLists.txt @@ -1003,6 +1003,12 @@ if(DFLASH27B_TESTS) # ─── Unit tests (no GPU, no model files) ──────────────────────────── enable_testing() + # Pure proposal-shape contract test: no ggml, GPU, or model files. + add_executable(test_draft_contract test/test_draft_contract.cpp) + target_include_directories(test_draft_contract PRIVATE + ${CMAKE_CURRENT_SOURCE_DIR}/src) + add_test(NAME draft_contract COMMAND test_draft_contract) + if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/test/test_server_unit.cpp") add_executable(test_server_unit test/test_server_unit.cpp) target_sources(test_server_unit PRIVATE @@ -1035,7 +1041,7 @@ if(DFLASH27B_TESTS) # 'make check' — builds test targets then runs ctest if(TARGET test_server_unit) - set(_check_deps test_server_unit) + set(_check_deps test_server_unit test_draft_contract) if(TARGET test_deepseek4_unit) list(APPEND _check_deps test_deepseek4_unit) endif() @@ -1047,6 +1053,7 @@ if(DFLASH27B_TESTS) else() add_custom_target(check COMMAND ${CMAKE_CTEST_COMMAND} --output-on-failure + DEPENDS test_draft_contract COMMENT "Building and running unit tests (server unit tests skipped — CURL not found)" ) endif() diff --git a/server/src/draft/draft_contract.h b/server/src/draft/draft_contract.h new file mode 100644 index 000000000..6205e0508 --- /dev/null +++ b/server/src/draft/draft_contract.h @@ -0,0 +1,31 @@ +#pragma once + +namespace dflash::common { + +// Draft artifacts expose one of two row layouts. Existing DFlash and DS4 +// DSpark artifacts include the accepted seed in row zero; proposal-only +// artifacts such as Bonsai rely on the runtime to prepend the accepted anchor +// before target verification. +enum class DraftProposalLayout { + SeedThenProposals, + ProposalsOnly, +}; + +struct DraftProposalShape { + int draft_rows = 0; + DraftProposalLayout layout = DraftProposalLayout::SeedThenProposals; + + constexpr int first_proposal_row() const noexcept { + return layout == DraftProposalLayout::ProposalsOnly ? 0 : 1; + } + + constexpr int proposal_count() const noexcept { + const int count = draft_rows - first_proposal_row(); + return count > 0 ? count : 0; + } + + // Verification always includes the already accepted anchor exactly once. + constexpr int verify_width() const noexcept { return 1 + proposal_count(); } +}; + +} // namespace dflash::common diff --git a/server/src/internal.h b/server/src/internal.h index ea43482fc..14df9c8ba 100644 --- a/server/src/internal.h +++ b/server/src/internal.h @@ -25,6 +25,7 @@ #include "gguf.h" #include "dflash27b.h" +#include "draft/draft_contract.h" namespace dflash::common { @@ -314,6 +315,11 @@ struct DraftWeights { int n_target_layers = DFLASH27B_DRAFT_N_TARGET_LAYERS; // captured target layers (5) std::vector capture_layer_ids; // explicit captured target-layer ids (GGUF dflash.target_layer_ids); empty = derive from count int mask_token_id = DFLASH27B_DRAFT_MASK_TOKEN_ID; // noise mask token + DraftProposalLayout proposal_layout = DraftProposalLayout::SeedThenProposals; + + DraftProposalShape proposal_shape() const { + return DraftProposalShape{block_size, proposal_layout}; + } // Optional Domino causal correction head. When present, greedy chain // speculative decode corrects each draft token with a lightweight GRU diff --git a/server/test/test_draft_contract.cpp b/server/test/test_draft_contract.cpp new file mode 100644 index 000000000..c7ca05b4f --- /dev/null +++ b/server/test/test_draft_contract.cpp @@ -0,0 +1,28 @@ +#include "draft/draft_contract.h" + +using namespace dflash::common; + +constexpr DraftProposalShape legacy{16, DraftProposalLayout::SeedThenProposals}; +static_assert(legacy.first_proposal_row() == 1); +static_assert(legacy.proposal_count() == 15); +static_assert(legacy.verify_width() == 16); + +constexpr DraftProposalShape native{4, DraftProposalLayout::ProposalsOnly}; +static_assert(native.first_proposal_row() == 0); +static_assert(native.proposal_count() == 4); +static_assert(native.verify_width() == 5); + +constexpr DraftProposalShape anchor_only{1, DraftProposalLayout::SeedThenProposals}; +static_assert(anchor_only.proposal_count() == 0); +static_assert(anchor_only.verify_width() == 1); + +constexpr DraftProposalShape empty_native{0, DraftProposalLayout::ProposalsOnly}; +static_assert(empty_native.proposal_count() == 0); +static_assert(empty_native.verify_width() == 1); + +constexpr DraftProposalShape default_shape{}; +static_assert(default_shape.layout == DraftProposalLayout::SeedThenProposals); +static_assert(default_shape.proposal_count() == 0); +static_assert(default_shape.verify_width() == 1); + +int main() { return 0; }