📝 Experiment_001_checkpoint_2.mdv4.6.0 · 2026-10-19

Experiments 000, 001, 002 — Checkpoint (2)

Operator: Andrew. Written 2026-10-27 04:44 Sydney. Supersedes Experiment_001_checkpoint.md (that file is kept, never overwritten). Status: design only. No program written or delivered. Resume: paste this file into a fresh conversation. Next step is build step 1 (the recorder). Related file: MEMSTORE_CLONE_CHECKPOINT_2026-10-27_2.md (global parameters: /root/memstore, Python 3.6 on the Clone, Qwen 4B on 8080 and 0.5B on 8081, memstore corrections, memtok).

1. Aim

Find out whether a second module (LLM2 plus retrieval) can move LLM1's next-word candidacy, strictly inside the query's subject, and whether that is worth having compared with plain retrieval in the prompt. Candidacy = a word's standing in the pool at the moment of selection (eligibility after the sampler's cuts, then weight).

2. The three experiments

Experiment 000 — background variation (control and archive)

Experiment 001 — reweight only (no new words)

Experiment 002 — adding words, heavier weights

Order: 000, then 001, then 002.

3. Components and decisions

1. Problem & Resolution

Problem: no standard exists for measuring how much an outside weighting moves LLM1's next-word candidacy, nor for proving it stayed inside the subject, nor for knowing how much replies vary when nothing changes. Resolution (design): the three experiments above, with a recorded natural baseline, an automatically built and saved context definition, and stage-by-stage saved outputs.

2. Risk Analysis

  1. Retrieval quality sets containment. Off-subject passages give off-subject weights even though every candidate is legitimate. Mitigation: similarity floor, fall back to natural.
  2. Common words win by default. Mitigation: lift against background frequency, stopword filter.
  3. Lean in the 001 blend: supported candidates move toward the weights, unsupported are untouched. Normalise first, compare with natural.
  4. Phrase pointers can fire by chance. Drop when the next word does not match, and after a window.
  5. Subword fragments versus whole words: influence only at word starts.
  6. The automatic subject can be wrong and everything follows it. Logged per run, with scores. Inheritance is the riskiest case, flagged.
  7. Weak effect expected in 001: one candidate usually dominates, so a halved blend rarely changes the word. Judge by candidacy shifts.
  8. 002: grammar breaks if arbitrary words are injected (hence anchoring); copying and content drift at high α; in-subject is not the same as correct at that point.
  9. Greedy decoding may not be repeatable on this server; 000 checks it.
  10. One tokenizer must be used throughout, or pool entries are not comparable. Check the 4B and 0.5B vocabularies (ids 311, 728, 32671).
  11. The files hold query excerpts. Permissions and caps as above.
  12. Rarity-based subject choice can pick an incidental word such as a typo or a name. Recurrence term, cap, and visible scores limit it.
  13. Attention-based "referenced words" record needs Hugging Face transformers (not llama-server) and is deferred.

3. Code Change

None delivered. First deliverable would be contextdef.py with commands build, show <id>, list. The recorder comes before it (build step 1). All deliveries follow the standing delivery rules, including the release card.

Pseudo code (001; 002 adds the lines marked):

SETTINGS (written into every run record)
MODEL_FILE, PROMPT_TEMPLATE, N_CAND=50, BLEND=0.5
SIM_FLOOR=? MIN_OVERLAP=? PHRASE_MAX_N=3 PHRASE_WINDOW=? MAX_STEPS
[002] ALPHA, N_NEW=5, MAX_BOOST=5.0

run_query(query, history):
ctx = build_context_definition(query, history) # rules only, no model
docs = retrieve(ctx) # once per reply
docs = [d for d in docs if d.sim >= SIM_FLOOR]
table = build_support_table(docs) # words + phrases -> lift, vecs[]
normal = generate("natural"); infl = generate("influenced")
fixed = score_along_path(normal.ids) # fixed-context comparison
write_report(ctx, docs, table, normal, infl, fixed)

generate(mode):
ids = prompt_ids(query, ctx); active = [] # active = phrase pointers
loop until end-of-reply or MAX_STEPS:
cand = llm1_top50(ids) # raw: temp 1, no cuts
p1 = normalise(cand.p) # over the 50
p = p1
if mode == "influenced" and at_word_start(ids):
[002] cand += anchored_injection(active, table, N_NEW) # next words of active phrases only
w = support_weights(cand, table, active) # LLM2's job (counting first)
if count(w > 0) >= MIN_OVERLAP:
[001] p = normalise([(p1[c]+w[c])/2 if w[c]>0 else p1[c] for c in cand])
[002] p = normalise([(1-ALPHA)*p1[c] + ALPHA*w[c] for c in cand], boost capped by MAX_BOOST)
pick = argmax(p); record(step, cand, p1, p, pick)
ids += pick.id; active = advance_pointers(active, pick, table)
return ids

support_weights(cand, table, active):
for c in cand:
s[c] = max( table.word_lift(c.word),
max over phrases in active whose next word matches c: phrase.lift )
return normalise(s) # 0 where unsupported

advance_pointers(active, pick, table):
step forward pointers whose next word == pick.word; drop the rest
start pointers for phrases whose first word == pick.word
drop pointers older than PHRASE_WINDOW or finished

table entry: { text, words[], vecs[] (1 for a word, 2+ for a phrase), lift, n_docs }
lift = (freq in retrieved) / (freq in ordinary text), smoothed and capped

4. Build order

  1. Natural-run recorder (raw top 50 per step, fixed context). This is the standard. Experiment 000 runs on it.
  2. Context definition builder, saved files and index; retrieval once per reply with the similarity floor.
  3. Support table, counting weights, blend, candidacy comparison. Experiment 001.
  4. Injection and the α dial. Experiment 002.
  5. Only then the LLM2 model pass in place of counting, judged against step 3.

5. Open items

6. Standing operator rules (carry forward)