From fad69c0272dd36989db7b81d8f5b5a8790a7a65f Mon Sep 17 00:00:00 2001 From: Jeongkyu Shin Date: Wed, 14 Oct 2026 00:45:52 +0900 Subject: [PATCH 1/4] fix(models): correct RWKV7 prefill state contract --- src/models/rwkv7.rs | 197 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 195 insertions(+), 2 deletions(-) diff --git a/src/models/rwkv7.rs b/src/models/rwkv7.rs index 50500cb42..c0a1e680b 100644 --- a/src/models/rwkv7.rs +++ b/src/models/rwkv7.rs @@ -203,6 +203,7 @@ fn wkv7_step_ops( // y = state @ r[..., None] let r_expanded = mlxcel_core::expand_dims(r, -1); let y = mlxcel_core::matmul(&new_state, &r_expanded); + let y = mlxcel_core::squeeze_axis(&y, -1); (y, new_state) } @@ -1065,6 +1066,17 @@ impl LanguageModel for Rwkv7 { false // Padding tokens corrupt RWKV recurrent state } + fn supports_chunked_prefill(&self) -> bool { + // A multi-token forward without a sequence ID deliberately starts an + // independent prompt by replacing the model-owned recurrent state. + // DirectEngine supplies a stable ID and does not hit that reset, but + // the capability must also be safe for legacy no-ID callers. Returning + // false makes every caller that honors the capability, DirectEngine + // included, keep the full prompt in one prefill call, trading + // chunk-bounded transient memory for correct no-ID semantics. + false + } + fn supports_batching(&self) -> bool { false // RWKV7 uses internal RNN-like state, not compatible with per-sequence KV isolation } @@ -1108,10 +1120,191 @@ fn make_rwkv7_cache(num_hidden_layers: usize) -> Vec { #[cfg(test)] mod tests { - use super::{Rwkv7Cache, make_rwkv7_cache}; + use super::{Rwkv7, Rwkv7Cache, Rwkv7Config, make_rwkv7_cache}; use crate::models::model_owned::ModelOwnedSequenceState; use mlxcel_core::cache::SequenceId; - use mlxcel_core::{dtype, generate::ModelStateSnapshot}; + use mlxcel_core::generate::{LanguageModel, ModelStateSnapshot}; + use mlxcel_core::weights::WeightMap; + use mlxcel_core::{MlxArray, UniquePtr, dtype}; + + fn rwkv7_test_config() -> Rwkv7Config { + serde_json::from_value(serde_json::json!({ + "model_type": "rwkv7", + "vocab_size": 32, + "hidden_size": 8, + "intermediate_size": 16, + "head_dim": 4, + "num_hidden_layers": 1, + "a_low_rank_dim": 2, + "v_low_rank_dim": 2, + "gate_low_rank_dim": 2, + "decay_low_rank_dim": 2, + "tie_word_embeddings": true + })) + .expect("RWKV7 test config must parse") + } + + fn varied(shape: &[i32], seed: usize) -> UniquePtr { + let len: usize = shape.iter().map(|dim| *dim as usize).product(); + let values: Vec = (0..len) + .map(|index| { + let magnitude = ((index + seed) % 17 + 1) as f32 * 0.005; + if (index + seed) % 2 == 0 { + magnitude + } else { + -magnitude + } + }) + .collect(); + mlxcel_core::from_slice_f32(&values, shape) + } + + fn ones(shape: &[i32]) -> UniquePtr { + mlxcel_core::full_f32(shape, 1.0, dtype::FLOAT32) + } + + fn rwkv7_test_weights() -> WeightMap { + let mut weights = WeightMap::new(); + let mut seed = 1usize; + let mut put_varied = |weights: &mut WeightMap, name: String, shape: &[i32]| { + weights.insert(name, varied(shape, seed)); + seed += 1; + }; + + put_varied(&mut weights, "model.embeddings.weight".into(), &[32, 8]); + weights.insert("model.layers.0.pre_norm.weight".into(), ones(&[8])); + + let attn = "model.layers.0.attn"; + for name in ["x_r", "x_w", "x_k", "x_v", "x_a", "x_g"] { + put_varied(&mut weights, format!("{attn}.{name}"), &[8]); + } + for name in ["k_k", "k_a", "r_k"] { + put_varied(&mut weights, format!("{attn}.{name}"), &[8]); + } + for name in ["r_proj", "k_proj", "v_proj", "o_proj"] { + put_varied(&mut weights, format!("{attn}.{name}.weight"), &[8, 8]); + } + put_varied(&mut weights, format!("{attn}.g_norm.weight"), &[8]); + put_varied(&mut weights, format!("{attn}.g_norm.bias"), &[8]); + for name in ["w_lora", "a_lora", "g_lora"] { + put_varied( + &mut weights, + format!("{attn}.{name}.lora.0.weight"), + &[2, 8], + ); + put_varied( + &mut weights, + format!("{attn}.{name}.lora.2.weight"), + &[8, 2], + ); + } + + let ffn = "model.layers.0.ffn"; + put_varied(&mut weights, format!("{ffn}.key.weight"), &[16, 8]); + put_varied(&mut weights, format!("{ffn}.value.weight"), &[8, 16]); + put_varied(&mut weights, format!("{ffn}.x_k"), &[8]); + weights.insert("model.layers.0.attn_norm.weight".into(), ones(&[8])); + weights.insert("model.layers.0.ffn_norm.weight".into(), ones(&[8])); + weights.insert("model.norm.weight".into(), ones(&[8])); + weights + } + + fn build_rwkv7_test_model(weights: &WeightMap, config: &Rwkv7Config) -> Rwkv7 { + Rwkv7::from_weights(weights, config.clone()).expect("RWKV7 test model must load") + } + + fn to_vec_f32(array: &MlxArray) -> Vec { + let array = mlxcel_core::astype(array, dtype::FLOAT32); + mlxcel_core::array_evaluated_bytes(&array) + .expect("RWKV7 test logits must evaluate") + .chunks_exact(4) + .map(|chunk| f32::from_ne_bytes([chunk[0], chunk[1], chunk[2], chunk[3]])) + .collect() + } + + fn assert_logits_close(got: &[f32], want: &[f32], context: &str) { + assert_eq!(got.len(), want.len(), "{context}: logit count differs"); + for (index, (&got, &want)) in got.iter().zip(want).enumerate() { + assert!( + got.is_finite() && want.is_finite(), + "{context}: logit[{index}] is not finite: got={got}, want={want}" + ); + let abs = (got - want).abs(); + let rel = abs / want.abs().max(1.0); + assert!( + abs < 1e-3 || rel < 1e-3, + "{context}: logit[{index}] differs: got={got}, want={want}, abs={abs}, rel={rel}" + ); + } + } + + #[test] + fn rwkv7_loaded_model_chunking_contract_is_safe() { + let config = rwkv7_test_config(); + let weights = rwkv7_test_weights(); + + let contaminated = build_rwkv7_test_model(&weights, &config); + let policy: &dyn LanguageModel = &contaminated; + assert!(!policy.supports_chunked_prefill()); + + let mut contaminated_caches = contaminated.make_caches(); + let contaminant = mlxcel_core::from_slice_i32(&[1], &[1, 1]); + let contaminant_logits = contaminated.forward(&contaminant, &mut contaminated_caches, None); + mlxcel_core::eval(&contaminant_logits); + + let target = mlxcel_core::from_slice_i32(&[7, 11, 13], &[1, 3]); + let reset_logits = contaminated.forward(&target, &mut contaminated_caches, None); + + let fresh = build_rwkv7_test_model(&weights, &config); + let mut fresh_caches = fresh.make_caches(); + let fresh_logits = fresh.forward(&target, &mut fresh_caches, None); + assert_logits_close( + &to_vec_f32(&reset_logits), + &to_vec_f32(&fresh_logits), + "a new no-ID prompt after stale state", + ); + + let continued = build_rwkv7_test_model(&weights, &config); + let mut continued_caches = continued.make_caches(); + let continued_id = SequenceId::from_raw(2_286_001); + continued.prepare_sequence_state(continued_id); + let prefix = mlxcel_core::from_slice_i32(&[2, 3], &[1, 2]); + let prefix_logits = continued.forward_with_sequence_id( + &prefix, + Some(continued_id), + &mut continued_caches, + None, + ); + mlxcel_core::eval(&prefix_logits); + let suffix = mlxcel_core::from_slice_i32(&[5, 8, 12], &[1, 3]); + let continued_logits = continued.forward_with_sequence_id( + &suffix, + Some(continued_id), + &mut continued_caches, + None, + ); + + let one_pass = build_rwkv7_test_model(&weights, &config); + let mut one_pass_caches = one_pass.make_caches(); + let one_pass_id = SequenceId::from_raw(2_286_002); + one_pass.prepare_sequence_state(one_pass_id); + let full_prompt = mlxcel_core::from_slice_i32(&[2, 3, 5, 8, 12], &[1, 5]); + let one_pass_logits = one_pass.forward_with_sequence_id( + &full_prompt, + Some(one_pass_id), + &mut one_pass_caches, + None, + ); + let continued_values = to_vec_f32(&continued_logits); + let one_pass_values = to_vec_f32(&one_pass_logits); + let suffix_len = continued_values.len(); + assert!(one_pass_values.len() > suffix_len); + assert_logits_close( + &continued_values, + &one_pass_values[one_pass_values.len() - suffix_len..], + "stable sequence-ID continuation", + ); + } #[test] fn rwkv7_cache_snapshot_restore_round_trips_state_shapes() { From ab449880295ef2a6bbab906dfda733a4defeae67 Mon Sep 17 00:00:00 2001 From: Jeongkyu Shin Date: Wed, 14 Oct 2026 00:47:16 +0900 Subject: [PATCH 2/4] docs: record RWKV7 prefill contract fix --- .../2297-rwkv7-chunked-prefill-20261014.en.md | 37 +++++++++++++++++++ .../2297-rwkv7-chunked-prefill-20261014.ko.md | 37 +++++++++++++++++++ 2 files changed, 74 insertions(+) create mode 100644 TECHNICAL_REPORTS/2297-rwkv7-chunked-prefill-20261014.en.md create mode 100644 TECHNICAL_REPORTS/2297-rwkv7-chunked-prefill-20261014.ko.md diff --git a/TECHNICAL_REPORTS/2297-rwkv7-chunked-prefill-20261014.en.md b/TECHNICAL_REPORTS/2297-rwkv7-chunked-prefill-20261014.en.md new file mode 100644 index 000000000..b48e7c1f1 --- /dev/null +++ b/TECHNICAL_REPORTS/2297-rwkv7-chunked-prefill-20261014.en.md @@ -0,0 +1,37 @@ +# PR #2297: Correct the RWKV7 no-ID chunked prefill contract + +**Date**: 2026-10-14 +**Status**: Implemented; CUDA build and focused GPU validation passed +**Risk**: Medium (prefill policy plus a recurrent output-shape correction) + +## Summary + +This change declares that RWKV7 does not support cache-level chunked prefill. A multi-token call without a sequence ID deliberately replaces the fallback recurrent state so separate prompts remain independent; advertising chunk continuation to legacy no-ID callers could therefore discard earlier chunks. Current DirectEngine calls carry a stable sequence ID and continue using their per-sequence model-owned state. + +The loaded-model regression also exposed an existing shape defect in RWKV7's recurrent output. The implementation now removes the singleton column axis produced by the step matrix product before stacking timesteps. + +## Problems + +RWKV7 inherited the default `supports_chunked_prefill() == true` even though its no-ID path resets recurrent state at the start of every multi-token forward. A caller that split one prompt into multiple no-ID chunks could receive logits computed without the earlier chunks. + +During focused GPU validation, the real one-layer fixture aborted with a native broadcast exception between shapes `(2,4)` and `(1,1,2,4,1)`. This was a production forward defect rather than invalid fixture geometry. `wkv7_step_ops` computed `state @ r[..., None]` as `[B, H, D, 1]`; stacking step outputs then produced `[B, T, H, D, 1]`. `LayerNormPerHead` expects activations shaped `[B, T, H, D]` so its `[H, D]` weight can broadcast across batch and time. + +## Design + +- Override `supports_chunked_prefill()` to return `false` while preserving the existing independent-prompt reset behavior. +- Squeeze only the final singleton axis of each recurrent step output. The output contract becomes `[B, H, D]` per step and `[B, T, H, D]` after stacking, while recurrent state stays `[B, H, D, D]`. +- Build a real one-layer model from deterministic nonzero synthetic weights. +- Contaminate the fallback state with a single token, then prove a new multi-token no-ID prompt matches the same prompt on a fresh model. +- Split a prompt across two calls with one stable sequence ID and compare the continuation logits with the matching suffix of a one-pass prompt. + +## Verification + +The initial root and surgery CUDA `test-fast` build graph passed in 14 minutes 26 seconds. The first focused GPU run then reached the real RWKV7 forward path and reproduced the shape defect with the native broadcast exception recorded above. After the fix, the CUDA graph rebuilt successfully in 2 minutes 22 seconds. The GPU-locked `rwkv7_` suite passed 5 of 5 tests, including the loaded one-layer contract regression in 0.64 seconds. The fixture loads deterministic nonzero synthetic weights through the production model loader; no external checkpoint run was performed or claimed. `git diff --check` passes. + +## Tradeoff + +Every caller that honors the model capability, including DirectEngine and cache-less callers, now receives a whole-prompt prefill plan. This can use more peak transient memory for long prompts than chunk-bounded prefill. DirectEngine still supplies a stable sequence ID, and this change does not claim that its previous state handling truncated prompts. + +## Change summary + +One Rust model file changes. Production changes include the capability override and one recurrent output-axis correction. The regression adds one loaded-model contract test without new dependencies. diff --git a/TECHNICAL_REPORTS/2297-rwkv7-chunked-prefill-20261014.ko.md b/TECHNICAL_REPORTS/2297-rwkv7-chunked-prefill-20261014.ko.md new file mode 100644 index 000000000..0eed36c97 --- /dev/null +++ b/TECHNICAL_REPORTS/2297-rwkv7-chunked-prefill-20261014.ko.md @@ -0,0 +1,37 @@ +# PR #2297: RWKV7 no-ID chunked prefill 계약 수정 + +**날짜**: 2026-10-14 +**상태**: 구현 완료, CUDA build 및 focused GPU 검증 통과 +**위험도**: 중간 (prefill 정책과 recurrent 출력 shape 수정) + +## 요약 + +이 변경은 RWKV7이 cache-level chunked prefill을 지원하지 않는다고 선언합니다. Sequence ID가 없는 다중 토큰 호출은 서로 독립적인 프롬프트를 보장하기 위해 fallback recurrent state를 의도적으로 교체하므로, legacy no-ID 호출자에게 chunk continuation을 제공하면 앞선 chunk를 잃을 수 있습니다. 현재 DirectEngine 호출은 안정적인 sequence ID를 전달하며 기존 per-sequence model-owned state를 계속 사용합니다. + +Loaded-model 회귀 테스트는 기존 RWKV7 recurrent 출력의 shape 결함도 드러냈습니다. 이제 각 step의 matrix product가 만든 singleton column 축을 제거한 뒤 timestep을 쌓습니다. + +## 문제 + +RWKV7은 no-ID 경로가 모든 다중 토큰 forward 시작 시 recurrent state를 초기화하는데도 기본값인 `supports_chunked_prefill() == true`를 상속했습니다. 하나의 프롬프트를 여러 no-ID chunk로 나누는 호출자는 앞선 chunk 없이 계산된 logits를 받을 수 있었습니다. + +Focused GPU 검증 중 실제 one-layer fixture가 `(2,4)`와 `(1,1,2,4,1)` shape 사이의 native broadcast 예외로 중단됐습니다. 이 문제는 fixture geometry가 아니라 production forward의 결함이었습니다. `wkv7_step_ops`는 `state @ r[..., None]` 결과를 `[B, H, D, 1]`로 만들었고, 각 step 출력을 그대로 쌓아 `[B, T, H, D, 1]`을 만들었습니다. `LayerNormPerHead`는 `[H, D]` weight가 batch와 time 축에 broadcast될 수 있도록 `[B, T, H, D]` activation을 기대합니다. + +## 설계 + +- 기존 독립 프롬프트 초기화 동작을 유지하면서 `supports_chunked_prefill()`이 `false`를 반환하도록 override합니다. +- 각 recurrent step 출력의 마지막 singleton 축만 제거합니다. 출력 계약은 step마다 `[B, H, D]`, stacking 뒤 `[B, T, H, D]`가 되고 recurrent state는 `[B, H, D, D]`를 유지합니다. +- 0이 아닌 결정적 synthetic weight로 실제 one-layer 모델을 구성합니다. +- 단일 토큰으로 fallback state를 오염시킨 뒤 새 다중 토큰 no-ID 프롬프트가 새 모델의 동일 프롬프트와 같은지 검증합니다. +- 하나의 안정적인 sequence ID로 프롬프트를 두 번에 나누어 실행하고 continuation logits를 one-pass 프롬프트의 동일 suffix와 비교합니다. + +## 검증 + +최초 root 및 surgery CUDA `test-fast` build graph는 14분 26초에 통과했습니다. 이어진 첫 focused GPU 실행은 실제 RWKV7 forward 경로에 도달해 위 native broadcast 예외로 shape 결함을 재현했습니다. 수정 후 CUDA graph는 2분 22초에 다시 빌드됐습니다. GPU lock 아래 `rwkv7_` suite는 5개 테스트 모두 통과했고, 실제 one-layer loaded-model contract 회귀는 0.64초에 통과했습니다. Fixture는 production loader를 통해 0이 아닌 결정적 synthetic weight를 적재하며, 외부 체크포인트 실행을 수행하거나 주장하지 않습니다. `git diff --check`는 통과했습니다. + +## 트레이드오프 + +이제 DirectEngine과 cache-less caller를 포함해 model capability를 따르는 모든 호출자가 whole-prompt prefill plan을 사용합니다. 긴 프롬프트에서는 chunk-bounded prefill보다 peak transient memory가 늘 수 있습니다. DirectEngine은 계속 안정적인 sequence ID를 제공하며, 이 변경은 기존 DirectEngine 상태 처리가 프롬프트를 잘랐다고 주장하지 않습니다. + +## 변경 요약 + +Rust 모델 파일 하나를 변경합니다. Production 변경은 capability override와 recurrent 출력 축 수정 하나이며, 새 의존성 없이 실제 loaded-model contract test 하나를 추가합니다. From b423e658b289dbe1e1133c0822c98188fb80b877 Mon Sep 17 00:00:00 2001 From: Jeongkyu Shin Date: Wed, 14 Oct 2026 01:00:55 +0900 Subject: [PATCH 3/4] docs: record RWKV7 contract retry --- TECHNICAL_REPORTS/2297-rwkv7-chunked-prefill-20261014.en.md | 2 ++ TECHNICAL_REPORTS/2297-rwkv7-chunked-prefill-20261014.ko.md | 2 ++ 2 files changed, 4 insertions(+) diff --git a/TECHNICAL_REPORTS/2297-rwkv7-chunked-prefill-20261014.en.md b/TECHNICAL_REPORTS/2297-rwkv7-chunked-prefill-20261014.en.md index b48e7c1f1..6af786a15 100644 --- a/TECHNICAL_REPORTS/2297-rwkv7-chunked-prefill-20261014.en.md +++ b/TECHNICAL_REPORTS/2297-rwkv7-chunked-prefill-20261014.en.md @@ -28,6 +28,8 @@ During focused GPU validation, the real one-layer fixture aborted with a native The initial root and surgery CUDA `test-fast` build graph passed in 14 minutes 26 seconds. The first focused GPU run then reached the real RWKV7 forward path and reproduced the shape defect with the native broadcast exception recorded above. After the fix, the CUDA graph rebuilt successfully in 2 minutes 22 seconds. The GPU-locked `rwkv7_` suite passed 5 of 5 tests, including the loaded one-layer contract regression in 0.64 seconds. The fixture loads deterministic nonzero synthetic weights through the production model loader; no external checkpoint run was performed or claimed. `git diff --check` passes. +The broader contract gate also passed across a controlled retry. The initial run passed every stage before Python tooling, then the timing-sensitive ROCm guard fixtures reported one missed 2.5-second monitor sample and one holder-metadata `FileNotFoundError` while concurrent native builds and external load saturated the host. No product or test source was changed. After lowering the competing build priority, both named guard tests passed; the full Python tooling suite passed 123 tests and the WebUI suite passed 49 tests. + ## Tradeoff Every caller that honors the model capability, including DirectEngine and cache-less callers, now receives a whole-prompt prefill plan. This can use more peak transient memory for long prompts than chunk-bounded prefill. DirectEngine still supplies a stable sequence ID, and this change does not claim that its previous state handling truncated prompts. diff --git a/TECHNICAL_REPORTS/2297-rwkv7-chunked-prefill-20261014.ko.md b/TECHNICAL_REPORTS/2297-rwkv7-chunked-prefill-20261014.ko.md index 0eed36c97..afe1286ec 100644 --- a/TECHNICAL_REPORTS/2297-rwkv7-chunked-prefill-20261014.ko.md +++ b/TECHNICAL_REPORTS/2297-rwkv7-chunked-prefill-20261014.ko.md @@ -28,6 +28,8 @@ Focused GPU 검증 중 실제 one-layer fixture가 `(2,4)`와 `(1,1,2,4,1)` shap 최초 root 및 surgery CUDA `test-fast` build graph는 14분 26초에 통과했습니다. 이어진 첫 focused GPU 실행은 실제 RWKV7 forward 경로에 도달해 위 native broadcast 예외로 shape 결함을 재현했습니다. 수정 후 CUDA graph는 2분 22초에 다시 빌드됐습니다. GPU lock 아래 `rwkv7_` suite는 5개 테스트 모두 통과했고, 실제 one-layer loaded-model contract 회귀는 0.64초에 통과했습니다. Fixture는 production loader를 통해 0이 아닌 결정적 synthetic weight를 적재하며, 외부 체크포인트 실행을 수행하거나 주장하지 않습니다. `git diff --check`는 통과했습니다. +전체 contract gate도 통제된 재실행을 거쳐 통과했습니다. 최초 실행은 Python tooling 이전의 모든 단계를 통과했지만, concurrent native build와 외부 부하가 호스트를 포화시킨 동안 timing-sensitive ROCm guard fixture에서 2.5초 monitor sample 누락 1건과 holder metadata `FileNotFoundError` 1건이 발생했습니다. Product 및 test source는 변경하지 않았습니다. 경쟁 build의 우선순위를 낮춘 뒤 해당 guard 테스트 두 개가 모두 통과했고, 전체 Python tooling 123개와 WebUI 49개 테스트도 통과했습니다. + ## 트레이드오프 이제 DirectEngine과 cache-less caller를 포함해 model capability를 따르는 모든 호출자가 whole-prompt prefill plan을 사용합니다. 긴 프롬프트에서는 chunk-bounded prefill보다 peak transient memory가 늘 수 있습니다. DirectEngine은 계속 안정적인 sequence ID를 제공하며, 이 변경은 기존 DirectEngine 상태 처리가 프롬프트를 잘랐다고 주장하지 않습니다. From 1f1d3af046c6266172625b9c2889524d703cdb04 Mon Sep 17 00:00:00 2001 From: Jeongkyu Shin Date: Wed, 14 Oct 2026 01:20:32 +0900 Subject: [PATCH 4/4] docs: qualify RWKV7 validation after MLX refresh --- TECHNICAL_REPORTS/2297-rwkv7-chunked-prefill-20261014.en.md | 4 ++++ TECHNICAL_REPORTS/2297-rwkv7-chunked-prefill-20261014.ko.md | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/TECHNICAL_REPORTS/2297-rwkv7-chunked-prefill-20261014.en.md b/TECHNICAL_REPORTS/2297-rwkv7-chunked-prefill-20261014.en.md index 6af786a15..715050689 100644 --- a/TECHNICAL_REPORTS/2297-rwkv7-chunked-prefill-20261014.en.md +++ b/TECHNICAL_REPORTS/2297-rwkv7-chunked-prefill-20261014.en.md @@ -30,6 +30,10 @@ The initial root and surgery CUDA `test-fast` build graph passed in 14 minutes 2 The broader contract gate also passed across a controlled retry. The initial run passed every stage before Python tooling, then the timing-sensitive ROCm guard fixtures reported one missed 2.5-second monitor sample and one holder-metadata `FileNotFoundError` while concurrent native builds and external load saturated the host. No product or test source was changed. After lowering the competing build priority, both named guard tests passed; the full Python tooling suite passed 123 tests and the WebUI suite passed 49 tests. +## Dependency refresh + +The validation above was recorded before the branch merged main commit `4b0c4519` from PR #2298. The merge commit `9b05507b` brings in the new MLX pin and CUDA/Metal overlay bases without changing `src/models/rwkv7.rs`; its SHA-256 remains `fa18e8e5e33f4af42fe7c7c8574e55db8578f90724d3a70d0cad4a7cf10adea7`. Focused runtime revalidation on the new pin is pending and is not claimed by this report. + ## Tradeoff Every caller that honors the model capability, including DirectEngine and cache-less callers, now receives a whole-prompt prefill plan. This can use more peak transient memory for long prompts than chunk-bounded prefill. DirectEngine still supplies a stable sequence ID, and this change does not claim that its previous state handling truncated prompts. diff --git a/TECHNICAL_REPORTS/2297-rwkv7-chunked-prefill-20261014.ko.md b/TECHNICAL_REPORTS/2297-rwkv7-chunked-prefill-20261014.ko.md index afe1286ec..fa4c90153 100644 --- a/TECHNICAL_REPORTS/2297-rwkv7-chunked-prefill-20261014.ko.md +++ b/TECHNICAL_REPORTS/2297-rwkv7-chunked-prefill-20261014.ko.md @@ -30,6 +30,10 @@ Focused GPU 검증 중 실제 one-layer fixture가 `(2,4)`와 `(1,1,2,4,1)` shap 전체 contract gate도 통제된 재실행을 거쳐 통과했습니다. 최초 실행은 Python tooling 이전의 모든 단계를 통과했지만, concurrent native build와 외부 부하가 호스트를 포화시킨 동안 timing-sensitive ROCm guard fixture에서 2.5초 monitor sample 누락 1건과 holder metadata `FileNotFoundError` 1건이 발생했습니다. Product 및 test source는 변경하지 않았습니다. 경쟁 build의 우선순위를 낮춘 뒤 해당 guard 테스트 두 개가 모두 통과했고, 전체 Python tooling 123개와 WebUI 49개 테스트도 통과했습니다. +## 의존성 갱신 + +위 검증 결과는 브랜치가 PR #2298의 main commit `4b0c4519`를 병합하기 전에 기록했습니다. Merge commit `9b05507b`는 새 MLX pin과 CUDA/Metal overlay base를 가져오지만 `src/models/rwkv7.rs`를 바꾸지 않았고, 해당 파일의 SHA-256은 `fa18e8e5e33f4af42fe7c7c8574e55db8578f90724d3a70d0cad4a7cf10adea7`로 유지됩니다. 새 pin의 focused runtime 재검증은 대기 중이며 이 보고서는 해당 결과를 주장하지 않습니다. + ## 트레이드오프 이제 DirectEngine과 cache-less caller를 포함해 model capability를 따르는 모든 호출자가 whole-prompt prefill plan을 사용합니다. 긴 프롬프트에서는 chunk-bounded prefill보다 peak transient memory가 늘 수 있습니다. DirectEngine은 계속 안정적인 sequence ID를 제공하며, 이 변경은 기존 DirectEngine 상태 처리가 프롬프트를 잘랐다고 주장하지 않습니다.