Operator: Andrew. Written 2026-10-29 23:42 Sydney. Follows Experiment_001_checkpoint_7.md (kept, never overwritten; _6, _5, _4, _3, _2 and Experiment_001_checkpoint.md also kept). Status: recorder 1.3.0 built and delivered (Experiment 002's prefill injection), tested only against a scripted stand-in server, not yet run on the real 4B. No experiment has been run since checkpoint 7. The rest of the session was design talk (section 6), nothing built from it. Resume: paste this file into a fresh conversation and attach NaturalRecorder_v1.3.0.zip, Exp000_queries_v1.0.0.zip, Hotwords_v2.1.0.zip and Memstore_Clone_v1.0.16.zip (or the newest Memstore tree). This file is written to stand alone for the work ahead; for the full text of risks 1 to 40 and the 000/001 results, Experiment_001_checkpoint_7.md is the reference (risks 1 to 13 are in _2, 14 to 21 in _3, 22 to 24 in _5, 25 to 29 in _6, 30 to 40 in _7; this file adds 41 to 50). Where files differ, the newest wins. Terms: LLM1 = the chat model (Qwen3-4B). LLM2 = the second module that would weight or add words (also the name of the second 4B copy, "4b2", port 8082). RAG = choosing stored arrays that match the query (here hotwords.py pseudo). The pool = the top 50 candidates at one step. Prefill = tokens placed at the start of the assistant's turn so the model reads them as already said. A token = the unit the model reads and writes (a piece of text from its fixed vocabulary of about 152,000 entries), not quite a word. Greedy = at every step the single most likely token is taken, so the same prompt always gives the same reply.
Standing aim: find out whether a second module (LLM2 plus retrieval) can move LLM1's next-word candidacy inside the query's subject, so a corrected mistake is not repeated.
hotwords.db only, D = both. Only A and B have been run.--boost). Shown to move the frame, not the fact, and to cascade.-np 1 = one slot and one prompt cache per server. The recorder runs on 8082; nothing else goes to 8082 during a run. Greedy output is identical on 8080 and 8082 (600 steps checked).python3.6 has SQLite and is the one to use; python3.8 has no SQLite. Everything runs from /root/memstore. Run folders are named in UTC.memstore.db (8 approved entries: ids 1 to 8) and hotwords.db (fresh store since the operator moved the old one to hotwords_chats_1027.db). HOTWORDS_DB in the environment picks the store.add, pseudo, show, top, stats; no delete, no nudge. pseudo --format json returns query_terms (the query's own array, ranked) and rag_terms (related terms from stored arrays, with weights), rag_arrays, fuzzy_matches. Fuzzy matching is only for plain words of 5 or more letters (1 edit up to 8 letters, 2 from 9); words with digits and words under 5 letters never fuzzy-match.hotwords_store_stage.py) still writes every chat into hotwords.db. Switching it off (enabled=no in stages.control) before any ladder run is the operator's decision; not yet made.NaturalRecorder_v1.3.0.zip unzips to NaturalRecorder/ (natural_recorder.py 1.3.0, NATURAL_RECORDER_MANUAL.md 1.3.0). Earlier zips (1.2.1, 1.2.0, 1.1.0, 1.0.0) are kept. New options on run:
| Option | Meaning |
|---|---|
--inject-top N |
Inject the N hottest terms retrieved for the query. Needs --hotwords (or --inject-terms-file). |
--hotwords PATH, --hotwords-python PYTHON |
hotwords.py and the interpreter for it (on the Clone python3.6). Its pseudo --file - --format json runs once per query (the query goes in on standard input). |
--inject-source rag|query|both |
Which terms: rag (default) = the related terms from stored arrays, because the query's own words are already in the prompt; query = the query's own array; both. |
--inject-terms-file PATH |
Ranked terms, one per line, hottest first; with --inject-top N the first N. |
--inject-text TEXT |
Literal text (the "ceiling": the stored sentence). Cannot be combined with the term options. |
--inject-frame TEMPLATE |
Wrap the terms, e.g. "On the Clone, regarding {terms}:" (must contain {terms}). Default: the bare list "term, term, term". |
--inject-step N |
0 (default) = the very start of the reply; N = forced after the model has chosen N tokens. |
Saved per reply (qNNN_rNN.json, key inject): applied/reason, terms, terms_available, source, frame, retrieval (arrays and weighted terms), text, ids, tokens, applied_at_step, natural (the model's own pool at the injection point: the first injected token's id, text, rank and probability in the top 50, null when absent, and the natural top 5), reply_text_with_inject, reply_with_inject_sha256. reply_text and reply_sha256 hold only the model's own tokens, comparable with a natural run. prompt_tokens excludes the injection; inject_tokens counts it. The steps file holds only the steps the model chose. run.json settings carry the inject options.
Changes the operator did not ask for (all listed in the delivery): injected text is tokenized with special tags switched off; an injected run's replies are left out of pairs.jsonl (queries only) so they cannot reach hotwords.db (risk 36); a reply that could not be injected (no terms retrieved, or the reply ended before the step) runs natural and says why. The --inject-frame option was proposed in the critique and covered by the go.
Tests (stand-in server only, a scripted chain "The Clone runs Apple OS" / "…CentOS 6.10, which is end-of-life" when "CentOS" is in the context; hotwords.py pseudo run for real on a small test store): natural run unchanged; hotwords top 2 at step 0; terms file at step 3 (reply became "The Clone runs CentOS 6.10, which is end-of-life", natural probability of " CentOS" recorded as not in the top 50); literal text at step 0 (natural probability 0.95, rank 1); frame; injection beyond the reply's end (reported, runs natural); no terms retrieved (reported, runs natural); four usage errors. In the test store the retrieved terms for the Q3-style query were runs, centos, end-of-life: "runs" is filler (risk 35 in miniature). Compiled on Python 3.13; not run on the Clone's Python 3.6; no f-strings or newer syntax used.
Release card (as delivered): version/date bumped done; manual history done; version shown at start done; zip with never-reused version done; xmllint not needed; unrequested changes listed done; legacy zipper not needed.
--repeat 3 --max-steps 600, then 20) is still not done; the claim rests on the 8080/8082 comparison and the repeated Q3 runs. Sampling mode varies by design.--force-path option; not built).pseudo test on Q3 first (the shared-vocabulary problem: Q3 shares only "Clone" with entry 1); switch the store stage off first.pseudo test on Q3.hotwords.py nudge TERM +0.3 stored in a side table and applied only in pseudo.vocab command for the recorder (proposed): dump all ids with their pieces and flags (leading space, letters, digits, special, partial multi-byte), via /detokenize one id at a time (about 152,000 calls, a few minutes; kept as a file). Would show how the fact words and names split, give a tokenizer-aware word-start flag (risk 28), test the multi-byte theory for the "no candidates" fault, and possibly give an outside rarity reference from the id order (byte-level vocabularies merge the commonest pairs first, so the id roughly tracks frequency: believed true for Qwen, not verified; answers risk 16). A no-code first look: curl -s http://127.0.0.1:8080/tokenize -d '{"content":" CentOS 6.10 end-of-life MAOIs SSRIs","with_pieces":true}' (needs with_pieces in the build). Test words to try: long chemical names, 25I-NBOMe, 2C-B-FLY, 5-MeO-DMT, CentOS6.10 with no space, camelCase/snake_case versions of an identifier, Cyrillic look-alike letters, zero-width characters, emoji with joiners, long digit strings.--force-path.hotwords.py top --words into --inject-terms-file), unrelated to the query: if they move the reply as much as query-matched terms, the effect is a general nudge, not retrieval. Include a few of the operator's own off-the-likely-path queries next to the plain ones.relate block that matches the reply's words back to the hot terms by spelling key (appears or not, first step); 1.4.0 = compare command, --force-path, vocab, corrected word-start flag. Also a manual nudge for hotwords.py with pinned names and aliases (item 5, 6). Prior-art search on the specific combination (full pool recorded per step, deterministic baseline, unaided-facts pass test, pre-written fail criterion, operator-set importance) is offered, not done; the operator's "nobody else would think of it" was not accepted as stated (the parts are known: kNN-LM, contextual biasing, prefilling).Problem: Experiment 002 had no tool; reweighting inside the pool cannot reach facts the model does not hold, and the 4B confabulates smoothly about the operator's systems. Resolution so far: recorder 1.3.0 puts retrieved terms at the start of the reply and records what the model did with them, including the natural probability of the first injected token; the metrics to read it are designed (section 6, item 8) but not built; nothing has run on the real server.
hotwords.db in plain text.Delivered this session (all kept, never overwritten): NaturalRecorder_v1.3.0.zip (new). Earlier: NaturalRecorder_v1.2.1.zip, v1.2.0, v1.1.0, v1.0.0; Exp000_queries_v1.0.0.zip; Hotwords_v2.1.0.zip (unchanged); Memstore_Clone_v1.0.16.zip (unchanged). Nothing else delivered; this checkpoint is the only other file.
pseudo test on Q3 (HOTWORDS_DB=/root/memstore/hw_test.db; add only the approved entries, then pseudo on Q3); switch off hotwords_store_stage.py; wait for the video job; first run recorder 1.3.0 on the Clone's Python 3.6 (probe, then one natural Q3 run to confirm nothing changed).--inject-top 1, 3, 6, 10 (bare list), then the framed variant, then the --inject-text ceiling and the global-top control; then Q4 and Q5; controls Q1 and Q9; compare each with A and B. Pass: after only subject-level terms are injected the model supplies connected facts unaided (for Q3: 6.10, end-of-life, limits, no pkill) and stays fluent. Fail: drift to a generic answer, loss of fluency, or a fluent wrong answer.memstore.py inject WORDS --limit); conditions C and D; hotwords.py on the Clone's Python versions.nudge command with pinned names and aliases; the prior-art search; whether to add embeddings (after the Q3 pseudo test).remove.Claude: [Month DD, YYYY, HH:MM:SS AM/PM] (casual mode), real Sydney time from code run immediately before each reply.pkill/kill on services (ordered shutdowns only). Never rename his scripts or files. Deployment timing is his call.@version/@date; manual with version history; version shown once at start; zip with a dotted, never-reused version; xmllint --noout on XML; list unrequested changes BEFORE making them; end with a release card (include "legacy zipper used" only for SMF package zips)._N, never reused (next is _9). Prefers short conversations and a fresh chat per chapter. A PDF transcript, when asked for, matches claude.ai's print style, is checked visually, and takes a new numbered name each time.