Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion server/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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()
Expand All @@ -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()
Expand Down
31 changes: 31 additions & 0 deletions server/src/draft/draft_contract.h
Original file line number Diff line number Diff line change
@@ -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
6 changes: 6 additions & 0 deletions server/src/internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
#include "gguf.h"

#include "dflash27b.h"
#include "draft/draft_contract.h"

namespace dflash::common {

Expand Down Expand Up @@ -314,6 +315,11 @@ struct DraftWeights {
int n_target_layers = DFLASH27B_DRAFT_N_TARGET_LAYERS; // captured target layers (5)
std::vector<int> 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
Expand Down
28 changes: 28 additions & 0 deletions server/test/test_draft_contract.cpp
Original file line number Diff line number Diff line change
@@ -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; }
Loading