Repository navigation
feat(pflash): unified view with the SSD session cache (stacked on #746) - #840
Conversation
CI failed on
|
5278f73 to
ac7ba45
Compare
ac7ba45 to
41f4feb
Compare
…t and agent turns Behind PFLASH_UNIFIED=1 (read at startup; unset runs the release code unchanged). After the shared learned query and pins, the newest turn's large uncached content -- the user messages since the last reply, or tool outputs of tools in PFLASH_REGION_TOOLS (names or *) -- is paged: whole lines between cuts where both tokenisations start a token, ranked by the drafter's candidate scores under the release keep-ratio curve, served as raw target token slices with a preamble and line-count markers. Later turns continue the stored view token for token; a new user question recalls unheld units of earlier regions as labelled excerpts before the question (PFLASH_RECALL=0 turns it off). Re-reads are found by content and served verbatim; history is never paged. Counters under /props pflash.unified, trace schema 3. The region module (server/src/server/pflash_unified.*) is format-agnostic: line structure is plain lines or the escaped lines of a JSON string, whichever has more; markers, preamble and labels are format-neutral; no harness-specific formats. - The unified view owns continuations: without a strict-selection environment they are served raw (raw.no_strict_selection), never by the FlowKV path. - Re-read coverage runs after paging, so a newest message served verbatim (cap, layout, unscored) still covers the lines it repeats; a unit is held when its informative lines are covered. - A turn served raw instead of continuing a stored view leaves a raw view when the raw prompt fits, so later turns do not resume the replaced view. - Regions keep their unwidened cap; a stage-2 widened pass widens it once, at paging and at recall alike. Tests: region helpers, paging/recall/re-read through the server, distinct target and drafter tokenizers (separator-only and unavailable line cuts, escaped JSON lines, continued-prefix equality). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Without a gate, recall ranks a region's unheld units and fills the
region's paging cap at every user question, so a pasted document comes
back in full after a few questions whatever is asked. Two opt-in arms:
- PFLASH_RECALL_GATE=<theta>: the head's mass on unheld units over its
mass on every non-pinned candidate (D/S). Below theta nothing is
appended. Above it, unheld units are taken best first across regions,
each under its region's cap, until D/S < theta. Pinned candidates and
what this request's new regions dropped are outside S; a non-finite
lift fails closed (recall.unscorable); deficit_after is computed from
the units that survive the cap trim.
- PFLASH_RECALL_SOURCE=fresh: recall only unheld units the drafter's own
selection for the question keeps (any token in a kept span).
Either arm skips the drafter pass when every unit of every region is held.
Bad values, both arms at once, or an arm with PFLASH_RECALL=0 fail
startup. The view record carries recall_gate {decision, theta, context
mass, deficit before/after, new_dropped_mass, trimmed_units}.
PFLASH_RECALL_TRACE_UNITS records each region's units for an offline
recall replay.
Tests: gate and source arms, NaN lift fails closed, a paste arriving with
the question (S excludes new drops), served == planned deficit, a
document and its question sent as two user messages page like one.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
PFLASH_UNIFIED=1 joins the release configuration, so under the flag it now runs with the measured settings and no
other unified knob: every tool's output may be paged (PFLASH_REGION_TOOLS unset = "*", empty = none) and recall is
gated at theta 0.075 (PFLASH_RECALL_GATE; "off" = ungated). The fresh recall source is removed
(PFLASH_RECALL_SOURCE now fails startup).
Requests the unified view cannot serve well go to the chat view and are served exactly as without the flag,
instead of a raw prefill: the not-ready cases (no messages array, unreadable turns, remote drafter),
a generation prompt or text it cannot match, and a conversation it would start whose uncached, unpinned history
before the newest turn -- with newest content it cannot cut into lines -- is a prefill threshold's worth ("uncached",
or "reset_uncached" when a stored view could not continue). A cold history the view would prefill raw is
compressed by the chat view's cache admission; a tool session there keeps its release behaviour. The reason is
counted (handback.<reason>), kept through the raw fallback and traced as pflash.unified = {decision: handback}.
A reset hand-back drops the replaced view's lineage, so no later turn continues it or an ancestor of it. Without a
strict-selection environment the view serves nothing; startup now says so.
Tests: hand-back requests are byte-identical to a flag-off run (cold chat
history, unsplittable paste, no selection environment, a reset that no
longer fits, whose next turn no longer continues the replaced view);
defaults give tools "*" and gate 0.075.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…rofile
Admission counts the disk session cache. The restorable prefix is the
deeper of the RAM snapshot and the deepest disk entry for the prompt
(DiskPrefixCache::longest_prefix, an index lookup that reads no file; ties
go to RAM), in the chat view's cache admission and in the unified view's
admission and hand-back check, so after a restart or an eviction a
conversation the disk holds is not treated as cold. The disk counts only
with --kv-cache-dir set and the request's disk scope Full. With the disk
cache on, admission records and log lines carry the cached source; with it
off they are unchanged.
Shortened conversations survive a restart and eviction. With the disk
session cache on, the unified views are kept in <kv-cache-dir>/.pflash-views
(skipped by the KV cache's scan): written when the RAM view store evicts
them and at shutdown before the KV flush, read when a request finds no view
in RAM (a longer one on disk wins). One file per view, a one-line header
that startup indexes, then the view as JSON; views written under another
identity (model, template, context) are never read; at most 256 views,
least recently written dropped first, with the cache's TTL checked at every
lookup. A view read from disk is checked in full (lines, cuts, per-line and
per-unit vectors, token ranges, each region's digest against its bytes,
each unit cut against both tokenisations) before use; one that fails is
deleted and the request proceeds without it. A prompt served from a view
gets a disk KV key for the tokens it served. A restarted server numbers new
conversations after the largest lineage on disk. The drafter's own scoring
state stays in RAM.
The release profile serves the unified view: with a trained scoring head,
PFLASH_UNIFIED=1 joins its environment defaults; PFLASH_UNIFIED=0 keeps
the chat view.
- The request probe's own pins (the question it finds and its recency pin)
stay whole when the unified view pages a message.
- A selection without per-candidate scores (legacy or split scorer, fold
strategy) is handed back to the chat view ("unscored_selection"); a
failed drafter pass is refused under PFLASH_FAIL_CLOSED=1.
- A raw fallback after a PFlash failure, and a hand-back to the chat view
once the request is accepted, drop the unified views the request would
continue, in RAM and on disk; a refused request keeps them.
- A repeated request is answered with the stored view only when the view
holds every span the request pins.
Tests: restart with the history on disk (unified and chat view), disk scope
and missing entries, view JSON round-trip and fail-closed fields, the disk
view store across a restart (index, prefix and identity checks, forks, cap,
lineage drop, broken body, TTL, partial write, digest mismatch), a restart
through the server keeping a shortened chat's served prefix, probe pins,
unscored selections, drafter failure with and without fail-closed, refused
reset then retry, a repeat with a new pin.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
41f4feb to
0749c15
Compare
Stacked on #746 (head
eca7265bd). #746's branch lives on a fork, so this PR targetsmainand its diff also shows #746's commits. This PR's own commits areeca7265bd..HEAD, listed below. Merge it together with #746: it is the PFlash mechanism the PFlash v2 post describes and measures. The SSD session cache it builds on is already inmain(#839).What it does
Unified view, on by default with a trained head.
PFLASH_UNIFIED=1joins #746's release profile, so a server started with the head and probe GGUFs serves chats and agent sessions with one mechanism.PFLASH_UNIFIED=0keeps #746's chat view.What gets paged. Only the newest turn's long uncached content: the user messages since the last reply, or the outputs of the last tool calls (every tool by default,
PFLASH_REGION_TOOLS). It needs at least--prefill-threshold(16K) droppable tokens and lines to cut at.How it is cut. At line starts. A note says the content was shortened, and a marker says how many lines were left out. The request probe's pins (the question it finds and its recency pin) stay whole. History is never paged again.
Later turns. They continue the stored view token for token, so the prefix cache keeps working.
Recall. A new user question brings back left-out lines as excerpts at the start of its message, through a need-based gate: nothing comes back when the lines the view does not hold carry less than θ = 0.075 of the question's score mass (
PFLASH_RECALL_GATE).Hand-back. Requests the view cannot serve well go to the chat view and are served exactly as without the flag:
A hand-back or a raw fallback ends the conversation's unified views, so no later turn revives a shortened history.
On the SSD session cache (
--kv-cache-dir, #839):<kv-cache-dir>/.pflash-views, written when they leave RAM and at shutdown, and read on a RAM miss. A prompt served from a view gets a disk KV key: the tokens it served.With the disk cache off, decisions, records and log lines are unchanged.
R9700 checks
Setup:
--kv-cache-dirwith defaults.Every chat answer was correct in every arm.
Release-profile default check. A launch with only the model files (head, probes, drafter) installs
PFLASH_UNIFIED=1, the release threshold and curve, and gate 0.075. Its served prompt is byte-identical to a launch with the release environment set explicitly.Final build (
ac7ba4526), rebased onto #746. The paged chat and its post-restart question serve byte-identical prompts to the build before the rebase:TTFT was 10.4 s for t1 and 4.4 s for t2.
Known limit
The unified view does not keep #746's query pin (
PFLASH_QUERY_PIN). The drafter computes that pin inside its own selection, and this view replaces that selection, so the pin is never applied here. The post's numbers were measured this way.On the post's public R9700 runs (six sets plus LongCodeQA), the pinned text was cut in 19 of 228 paged requests. In none of those 19 did this view get wrong an answer that full prefill got right. Most of the cut pins were not the question: in LongCodeQA they land on the repository header, license or code of conduct. Passing the pin through to the view is a follow-up.
Tests
test_server_unit(HIP gfx1201 build,HIP_VISIBLE_DEVICES=-1): 994 passed, 0 failed, 6 skipped. They cover:PFLASH_FAIL_CLOSED.Commits
a69a9cdeafeat(pflash): format-agnostic region module for the unified view (stage 1)44469d925feat(pflash): PFLASH_UNIFIED serves one view/recall mechanism for chat and agent turns0d36150e9fix(pflash): unified view review fixes (FlowKV fence, re-read holds, reset view, single widening)82fa2b5a0feat(pflash): need-based recall gate and fresh-minus-held recall source for the unified view6e5e469c7feat(pflash): PFLASH_RECALL_TRACE_UNITS records each region's units for an offline recall replaydf0e9c69cfix(server): recall gate review fixes (fresh any-overlap, NaN fail-closed, new-region drops, served deficit)e87ac2000fix(server): unified view takes every user message since the last reply as the newest turn678a85284feat(server): unified view release defaults, hand-back to the chat view55c923fc3feat(pflash): admission counts the disk session cache, in the unified view too6755e53b8feat(pflash): shortened conversations survive a restart and eviction on the SSD cache9e88f91c1feat(pflash): the release profile serves the unified view3ffd0fa6efix(pflash): unified view review fixes before it ships as the release defaultac7ba4526fix(pflash): unified view keeps views until a hand-back is served, and checks repeats and disk views🤖 Generated with Claude Code