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: 9 additions & 0 deletions server/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1069,6 +1069,12 @@ if(DFLASH27B_TESTS)
list(APPEND _raw_unit_test_targets test_recurrent_snapshot)
endif()

# 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")
set(_server_unit_sources
test/test_unit_main.cpp
Expand Down Expand Up @@ -1230,6 +1236,9 @@ if(DFLASH27B_TESTS)
# 'make check' — build every registered unit-test target, including the
# lightweight feature gate added on main, then run the complete CTest set.
set(_check_deps ${_raw_unit_test_targets})
if(TARGET test_draft_contract)
list(APPEND _check_deps test_draft_contract)
endif()
if(TARGET test_platform_compat)
list(APPEND _check_deps test_platform_compat)
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;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

intentional no consumer for this field in this PR?


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