File size: 14,823 Bytes
1e251f3
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
"""NBW public cells and the exact six W5/K1 greedy checks. Dry by default; numbers/hashes only."""
from __future__ import annotations

import argparse
import ast
import hashlib
import json
import math
import os
import statistics
import threading
import time
from pathlib import Path
from typing import cast

from offload.gb10_budget import window_cells as wc
from offload.gb10_budget.capture import load_bench
from offload.launch.windows import pf1_window as pf
from offload.launch.windows import up2_checks as ck
from offload.prefill_maxlen.evidence import Json, number, record
from offload.prefill_trace.window_requests import corpus

GREEDY_SCRIPT = pf.CAMPAIGN / 'W5/greedy_check.py'
GREEDY_SHA = 'e40c52c0e9ab13d46df9b9cf49020ad87034d8651e4585e741b5eb14ef4f0845'
REFERENCE = pf.CAMPAIGN / 'K1-production/greedy-post.jsonl'
CELLS = {c.name: c for c in (
    wc.Cell('short-b1', ('short',), estimate_s=60),
    wc.Cell('32k-b1', ('32k-0',), estimate_s=90),
    wc.Cell('32k-b2', ('32k-0', '32k-1'), estimate_s=120),
    wc.Cell('32k-b3', ('32k-0', '32k-1', '32k-2'), estimate_s=150))}
PROMPTS = {key: wc.PROMPTS[key] for key in ('short', '32k-0', '32k-1', '32k-2')}


class Http(wc.Http):
    def stream(self, body: dict[str, Json], first: threading.Event) -> dict[str, Json]:
        # Fixed work, including a natural early EOS; every arm uses the same setting.
        return super().stream({**body, 'ignore_eos': True}, first)


def build(api: wc.Api, materials: str, hashes: dict[str, Json]) -> dict[str, Json]:
    ck.require(wc.busy(api.metrics()) == 0, 'serve busy before public prompt construction')
    prompts: dict[str, Json] = {}
    for prompt in PROMPTS.values():
        chars, tokens = wc.cut(materials, prompt, api.tokens)
        text = wc.render(materials, prompt.offset, chars)
        prompts[prompt.key] = {'offset': prompt.offset, 'target': prompt.target, 'chars': chars,
                               'tokens': tokens, 'sha256': hashlib.sha256(text.encode()).hexdigest()}
    return {'corpus_sha256': hashes, 'prompts': prompts}


def texts_from(cuts: dict[str, Json], materials: str, hashes: dict[str, Json]) -> dict[str, tuple[str, int]]:
    ck.require(cuts.get('corpus_sha256') == hashes, 'public corpus changed')
    rows = record(cuts['prompts'])
    ck.require(set(rows) == set(PROMPTS), 'incomplete prompt cuts')
    out: dict[str, tuple[str, int]] = {}
    for key, prompt in PROMPTS.items():
        row = record(rows[key])
        ck.require(row.get('offset') == prompt.offset and row.get('target') == prompt.target, 'prompt plan changed')
        text = wc.render(materials, prompt.offset, int(number(row['chars'])))
        ck.require(hashlib.sha256(text.encode()).hexdigest() == row.get('sha256'), 'prompt bytes changed')
        tokens = int(number(row['tokens']))
        ck.require(prompt.target * .98 <= tokens <= prompt.target, 'prompt tokens outside registered band')
        out[key] = text, tokens
    return out


def metric_delta(before: dict[str, float], after: dict[str, float], name: str) -> float:
    keys = {k for k in before.keys() | after.keys() if k.split('{')[0] == name}
    ck.require(bool(keys) and all(k in after and after[k] >= before.get(k, 0) for k in keys),
               f'missing/reset server counter {name}')
    return sum(after[k] - before.get(k, 0) for k in keys)


def summarize(result: dict[str, Json], before: dict[str, float], after: dict[str, float]) -> dict[str, Json]:
    streams = ck.rows(result['streams'])
    ck.require(len(streams) == result['batch'], 'cell stream count mismatch')
    rates: list[float] = []
    ttfts: list[float] = []
    for stream in streams:
        usage = record(stream['usage'])
        ck.require(usage.get('completion_tokens') == 1500 and stream.get('finish') == 'length', 'cell output budget incomplete')
        first, last = record(stream['first_by_kind_s']), record(stream['last_by_kind_s'])
        span = max(number(v) for v in last.values()) - min(number(v) for v in first.values())
        ck.require(span > 0, 'no measured decode span')
        rate = 1499 / span
        stream['decode_tps'] = rate
        rates.append(rate)
        ttfts.append(number(stream['ttft_s']))
    rounds = metric_delta(before, after, 'vllm:spec_decode_num_drafts_total')
    accepted = metric_delta(before, after, 'vllm:spec_decode_num_accepted_tokens_total')
    seconds = metric_delta(before, after, 'vllm:request_decode_time_seconds_sum')
    ck.require(rounds > 0 and seconds > 0, 'no spec rounds/server decode time')
    return {**result, 'median_decode_tps': statistics.median(rates), 'median_ttft_s': statistics.median(ttfts),
            'acceptance_per_round': accepted / rounds, 'spec_request_rounds': rounds,
            'server_decode_ms_per_spec_request_round': 1000 * seconds / rounds,
            'round_time_scope': 'server request-decode duration sum / spec request-round count; includes terminal effects; not engine step wall time',
            'metrics_before': cast(Json, before), 'metrics_after': cast(Json, after),
            'status': 'MEASURED unprofiled client timing and server counters'}


def greedy_inputs() -> tuple[list[str], list[dict[str, Json]]]:
    ck.require(pf.digest(GREEDY_SCRIPT) == GREEDY_SHA, 'W5 greedy source changed')
    assignments = [n for n in ast.parse(GREEDY_SCRIPT.read_text()).body if isinstance(n, ast.Assign)
                   and any(isinstance(t, ast.Name) and t.id == 'PROMPTS' for t in n.targets)]
    ck.require(len(assignments) == 1, 'greedy PROMPTS missing')
    prompts = ast.literal_eval(assignments[0].value)
    reference = [record(cast(Json, json.loads(line))) for line in REFERENCE.read_text().splitlines()]
    ck.require(isinstance(prompts, list) and len(prompts) == 6 and all(isinstance(p, str) for p in prompts), 'six greedy prompts required')
    ck.require([r.get('i') for r in reference] == list(range(6)) and all(isinstance(r.get('text'), str) for r in reference),
               'six ordered K1 reference outputs required')
    return cast(list[str], prompts), reference


# W8 (2026-10-24, LANES.md "W8 native A/B DONE"; W8/neartie_check.py): the native drafter changes the target's
# verify-row shapes, so greedy text can flip at near-ties (C1 = C2 6/6, C1 vs X 4/6 divergent; every divergence a near-tie
# on a 0.5-nat logit grid or an exact tie). A native divergence therefore passes only when, at its first differing token,
# both tokens are in the target's top-20 and within NEAR_TIE_NATS of each other; anything else is a STOP.
NEAR_TIE_NATS = 0.5 + 1e-3
MODEL = 'DeepSeek-V4.1-Flash-1017-EXL3-Spark-TP2'


def token_ids(value: Json) -> list[int]:
    ck.require(isinstance(value, list) and all(isinstance(t, int) and not isinstance(t, bool) for t in value), 'token ids expected')
    return cast(list[int], value)


def near_tie(api: wc.Http, prompt: str, reference: str, text: str,
             threshold: float = NEAR_TIE_NATS, *, record_distribution: bool = False,
             probe_salt: str | None = None) -> dict[str, Json]:
    """WIN2 opt-ins (defaults unchanged): record_distribution keeps the probe's top-20 and prefix token ids in the row
    (window output only, never git) so a later control arm can measure the distribution difference at the same prefix
    (greedy_kl); probe_salt sends a cache_salt so the probe does not reuse the generation's prefix cache."""
    p = token_ids(api.post('/tokenize', {'model': MODEL, 'messages': [{'role': 'user', 'content': prompt}],
                                         'add_generation_prompt': True, 'chat_template_kwargs': {'thinking': False}})['tokens'])
    ta = token_ids(api.post('/tokenize', {'model': MODEL, 'prompt': reference, 'add_special_tokens': False})['tokens'])
    tb = token_ids(api.post('/tokenize', {'model': MODEL, 'prompt': text, 'add_special_tokens': False})['tokens'])
    j = next((k for k, (u, v) in enumerate(zip(ta, tb)) if u != v), None)
    ck.require(j is not None, 'greedy divergence is a length/prefix difference, not a token near-tie')
    index = cast(int, j)
    prefix = [*p, *ta[:index]]
    body: dict[str, Json] = {'model': MODEL, 'prompt': cast(Json, prefix), 'max_tokens': 1, 'temperature': 0,
                             'logprobs': 20, 'return_tokens_as_token_ids': True, 'priority': 10}
    if probe_salt is not None:
        ck.require(bool(probe_salt.strip()), 'empty probe cache salt')
        body['cache_salt'] = probe_salt
    r = api.post('/v1/completions', body)
    logprobs = record(record(ck.rows(r['choices'])[0])['logprobs'])
    tops = logprobs['top_logprobs']
    ck.require(isinstance(tops, list) and len(tops) == 1, 'one top-logprob position expected')
    top = record(cast(list[Json], tops)[0])
    lps = {int(str(k).split(':')[1]): float(number(v)) for k, v in top.items()}
    a, b = ta[index], tb[index]
    best = max(lps.values())
    ok = a in lps and b in lps and abs(lps[a] - lps[b]) <= threshold and max(lps[a], lps[b]) >= best - threshold
    result: dict[str, Json] = {'token_index': index, 'near_tie': ok,
            'margin_nats': None if a not in lps or b not in lps else round(abs(lps[a] - lps[b]), 4),
            'gap_to_top_nats': None if a not in lps or b not in lps else round(best - max(lps[a], lps[b]), 4)}
    if record_distribution:
        result.update(top20_logprobs=cast(Json, dict(top)), probe_prefix_token_ids=cast(Json, prefix),
                      reference_token_id=a, experiment_token_id=b)
    return result


def greedy(api: wc.Http, deadline: float, prompts: list[str], reference: list[dict[str, Json]],
           output: Path, near_tie_nats: float = NEAR_TIE_NATS, *, record_distribution: bool = False,
           probe_salt_prefix: str | None = None) -> dict[str, Json]:
    # near_tie_nats defaults to NBW's registered 0.501; only a caller's own registration may pass another
    # (TV1 r10: NDM 2026-10-27 "You can loosen the nats to .9").
    rows: list[Json] = []
    for i, prompt in enumerate(prompts):
        ck.require(time.time() + 30 < deadline, 'greedy submission deadline reached')
        ck.require(wc.busy(api.metrics()) == 0, 'serve busy before greedy check')
        # Exactly W5 greedy_check.run settings; text lives in memory only.
        response = api.post('/v1/chat/completions', {
            'model': MODEL, 'messages': [{'role': 'user', 'content': prompt}],
            'temperature': 0, 'max_tokens': 300, 'chat_template_kwargs': {'thinking': False}})
        choices = ck.rows(response['choices'])
        ck.require(len(choices) == 1, 'greedy choices mismatch')
        text = record(choices[0]['message'])['content']
        ck.require(isinstance(text, str), 'greedy text missing')
        same = text == reference[i]['text']
        row: dict[str, Json] = {'i': i, 'identical': same, 'sha256': hashlib.sha256(str(text).encode()).hexdigest(),
                                'reference_sha256': hashlib.sha256(str(reference[i]['text']).encode()).hexdigest()}
        if not same:
            row.update(near_tie(api, prompt, str(reference[i]['text']), str(text), near_tie_nats,
                                record_distribution=record_distribution,
                                probe_salt=None if probe_salt_prefix is None else f'{probe_salt_prefix}:probe:{i}'))
        rows.append(row)
        output.write_text(json.dumps({'checks': rows}, allow_nan=False) + '\n')
        ck.require(same or row.get('near_tie') is True, f'greedy divergence on K1 reference prompt {i} is not a near-tie')
    ck.require(len(rows) == 6, 'six greedy checks required')
    identical = sum(1 for r in rows if record(r)['identical'] is True)
    return {'checks': rows, 'identical': identical, 'near_tie': 6 - identical}


def main(argv: list[str] | None = None) -> int:
    ap = argparse.ArgumentParser(description=__doc__)
    ap.add_argument('--execute', action='store_true')
    ap.add_argument('--data-dir', type=Path, default=Path('/opt/dsv41/data/bench-data'))
    ap.add_argument('--output', type=Path, required=True)
    ap.add_argument('--cuts', type=Path)
    ap.add_argument('--cell', choices=tuple(CELLS))
    ap.add_argument('--mode', choices=('build', 'cell', 'greedy'), required=True)
    ap.add_argument('--deadline-utc', type=float, default=0)
    ap.add_argument('--salt', default='')
    ap.add_argument('--ledger', type=Path)
    # WIN2-R2 (R-NBW request): greedy near-tie registration and the greedy_kl opt-ins on the command line; the defaults
    # keep NBW's registered 0.501 nat and the unchanged request bodies.
    ap.add_argument('--near-tie-nats', type=float, default=NEAR_TIE_NATS,
                    help="greedy mode: the runner's registered near-tie limit in nats (default NBW's 0.501)")
    ap.add_argument('--record-distribution', action='store_true', help='greedy mode: keep top-20 + prefix (greedy_kl)')
    ap.add_argument('--probe-salt-prefix', help='greedy mode: cache_salt prefix for the near-tie probes')
    args = ap.parse_args(argv)
    if not (math.isfinite(args.near_tie_nats) and 0 < args.near_tie_nats < 5):
        ap.error('--near-tie-nats must be a finite positive limit below 5 nats')
    if not args.execute:
        print('DRY RUN: NBW four public cells, T=1/top_p=1, 1500 tokens; six W5/K1 greedy checks; no network or file')
        return 0
    ck.require(os.environ.get('WINDOW_COORDINATOR') == 'Deepseek/coordinator', 'coordinator required')
    ck.require(not args.output.exists(), 'fresh cell output required')
    ck.require(time.time() < args.deadline_utc, 'submission deadline reached')
    api = Http(wc.URL)
    if args.mode == 'greedy':
        result = greedy(api, args.deadline_utc, *greedy_inputs(), args.output, args.near_tie_nats,
                        record_distribution=args.record_distribution, probe_salt_prefix=args.probe_salt_prefix)
    else:
        materials, hashes = corpus(args.data_dir)
        if args.mode == 'build':
            result = build(api, materials, hashes)
        else:
            ck.require(args.cuts is not None and args.cell is not None and bool(args.salt), 'cell/cuts/salt required')
            texts = texts_from(ck.read(cast(Path, args.cuts)), materials, hashes)
            bench = cast(wc.Counters, load_bench())
            before = bench.parse_metrics(api.metrics())
            plan = wc.Plan(args.deadline_utc, pf.MEM_FLOOR_KB, [], args.salt, args.ledger)
            result = wc.run_cell(api, CELLS[args.cell], texts, plan)
            time.sleep(2)  # counter publication, excluded from measured request timing
            after = bench.parse_metrics(api.metrics())
            result['spec'] = bench.spec_delta(before, after)
            result = summarize(result, before, after)
    args.output.write_text(json.dumps(result, allow_nan=False) + '\n')
    return 0


if __name__ == '__main__':
    raise SystemExit(main())