Commit Graph
145 Commits
Author SHA1 Message Date
wassnameandClaudypoo 2d76166cbd showcase: add ordinal steer-effect plot (delta-contrast C dumbbell)
The E map/range are for human comparison; this new per-instrument foundation_dcontrast
figure shows the steer in the sensitive contrast readout (steered minus base C, +C vs -C),
the ordinal twin of the MFV dlogit dumbbell. read_profiles gains a value_col so it reads
either E ('mean') or C. This is the figure that shows what we steered for; the E range hides it.

Co-Authored-By: Claudypoo <288921227+claudypoo@users.noreply.github.com>
2026-06-25 19:20:25 +08:00
wassnameandClaudypoo ecd2affac4 ordinal readouts: keep raw lp, add sensitive logit contrast C + log-odds
The default ordinal readout was the expected Likert score E = sum k*p_k, which is
insensitive to steering: dE/dl_j = p_j(j-E) vanishes when the model answers confidently
(peaked at the mode), so a steer that reallocates the tails barely moves E. read.py threw
away the raw logprobs after renormalizing, so nothing downstream could recover the signal.

- read.py keeps the raw lp_gather (the primitive) + the think traces on every row.
- readouts.py: pure functions of lp -- expected_score E (human-comparable), logit_contrast
  C = sum (k-mid)*lp_k (primary steer signal: dC/dl_j = w_j, no p_j suppression, normalizer-
  invariant, dC = w.dl exactly), agree_logodds LO (readable 2-bin direction), entropy.
- per_item_categorical also frame-averages the logprobs (exact for the linear contrast).
- administer returns profile_C alongside profile_E, per-item E/C/LO/entropy with bootstrap
  CIs for both, and the raw per-(item,frame) rows with lp + think for downstream reconstruction.

Unit check: on a peaked-at-4 dist under a small disagree steer, dE=-0.11 but dC=-1.80
(=w.dl exactly) and dLO=-0.60; C identical on raw logits vs renormalized logprobs.

Co-Authored-By: Claudypoo <288921227+claudypoo@users.noreply.github.com>
2026-06-25 19:14:04 +08:00
wassnameandClaudypoo 3580bffedd add AGENTS.md: fail-fast conventions + the lp_gather primitive
Co-Authored-By: Claudypoo <288921227+claudypoo@users.noreply.github.com>
2026-06-25 18:53:11 +08:00
wassnameandClaudypoo abfe0e1649 remove dead shuffle_dimensions negative-control (unwired accretion)
Co-Authored-By: Claudypoo <288921227+claudypoo@users.noreply.github.com>
2026-06-25 18:53:11 +08:00
wassnameandClaudypoo 2850c31659 fail-fast: drop silent corruption paths in measurement code
guided.py: non-finite answer-slot logits were clamped with nan_to_num(+-1e4),
fabricating a confident answer from a blown-up (steered/quantized) forward pass.
Mark the row incoherent (pmass=0, lp=NaN) instead -- same 'do not compare' signal
as the case-(c) collapse the pipeline already handles.

data.py: load_vignettes silently inner-joined the two condition files and dropped
mismatched ids, so a missing rewrite would change N (and every metric) without
failing. Assert the id sets are identical instead.

Co-Authored-By: Claudypoo <288921227+claudypoo@users.noreply.github.com>
2026-06-25 18:53:11 +08:00
wassnameandClaudypoo dfa9cdfe5a quiet per-eval logging (INFO->DEBUG) + trim README to use-focused 120 lines
Per-eval INFO lines (rows/think_tokens/aux-stats/first-row/profile/demos) demoted to
DEBUG so a consumer calling evaluate() ~47x/run is not drowned; one-time + WARNING+ kept.
README 308->120: cut process-archeology + per-instrument showcase, added crisp dlogit
and SI definitions for new users.

Co-Authored-By: Claudypoo <288921227+claudypoo@users.noreply.github.com>
2026-06-25 18:51:39 +08:00
wassnameandClaudypoo 2160304541 plots: MFV reuses shared ipsative map + range in z-space; fix range coherence-gate
MFV got two bespoke figures (z-emphasis bars + dlogit dumbbell). Per GPT-5.5 code
review, reuse the geometry not the ordinal semantics: a _mfv_zspace adapter feeds the
same plot_ipsative_pca + plot_range the ordinal instruments use, in z-scored relative-
emphasis space (logit-violation and 1-5 wrongness cannot share a raw axis). Keep the
dlogit dumbbell as a raw-magnitude diagnostic; drop the bespoke map_emphasis.

Also fix a real bug the review found: plot_ordinal gated the map/SPLOM trajectory to
coherent c (pmass >= 0.95*base) but still passed ALL cs to range/range_zoom, so the
figures disagreed on which poles were valid. Range/zoom now use the same coh_cs.
plot_range gains an ylabel param (MFV is z-space, not 1-M); draw_steer asserts sorted
cs; MFV asserts only Social Norms is dropped.

Co-Authored-By: Claudypoo <288921227+claudypoo@users.noreply.github.com>
2026-06-25 15:51:40 +08:00
wassnameandClaudypoo fe0d27b9bd maps: more bottom padding + clearer minimap title
Bump the bottom legend strip (PAD_B 0.52->0.62) and lower/shrink the compass + minimap insets so
the compass title clears the lowest data points. Rename the minimap title "full space" ->
"all human respondents" (says what the backdrop cloud is).

Co-Authored-By: Claudypoo <288921227+claudypoo@users.noreply.github.com>
2026-06-25 11:48:31 +08:00
wassnameandClaudypoo 22f4f64201 maps: deterministic bottom legend strip (compass left, minimap right)
Replace the per-plot least-crowded-corner heuristic (+ label pruning) with a fixed layout: pad the
y-axis bottom by PAD_B of the data range to reserve a clean strip, then always place the minimap
bottom-right (reads like a small map) and the compass bottom-left. Insets are opaque so the backdrop
haze stays behind them. Same on every instrument, no dependence on where the trajectory heads, and
drops the crowd/rank/prune code + the now-unused pad param.

Co-Authored-By: Claudypoo <288921227+claudypoo@users.noreply.github.com>
2026-06-25 11:46:12 +08:00
wassnameandClaudypoo 5d2e0c3630 maps: violin SPLOM diagonals, de-grid off-diagonals, label-aware compass
- SPLOM diagonal: replace the confusing histogram/rug + vertical AI rules with a horizontal violin
  of the human spread + the AI base/+C/-C as the same trajectory dots used off-diagonal (1-D
  analogue), so the diagonal reads the same way as the rest. Unifies full + zoom (no branch).
- SPLOM off-diagonal: jitter the respondent cloud -- MFQ-2 ordinal scores land on a lattice that
  reads as grid-dots; jitter softens it to a density (it is the human joint covariance backdrop).
- Compass corner now counts text labels (society codes, steer labels), not just data points, and a
  final pass drops any society label still under the compass/minimap box. No legend-over-label.

Co-Authored-By: Claudypoo <288921227+claudypoo@users.noreply.github.com>
2026-06-25 10:58:00 +08:00
wassnameandClaudypoo 00dca35f85 maps: place-or-omit society labels, unconditional society+steer crop, readable zoom diagonals
- Society labels: pin each ISO code beside its dot (small fixed offset) and DROP any that would
  collide rather than fling it far on a leader line -- close or omitted, never ambiguous.
- Crop to societies + steer for EVERY instrument (drop the synthetic/real branch): the human cloud
  (mfq2 respondents too) is far wider than the societies, so it buried them in a central blob. The
  cloud stays a clipped backdrop + a "full space" minimap shows where the frame sits.
- SPLOM zoom diagonals: the narrow window slices the marginal into solid blocks, so swap the
  histogram for a visible mid-panel society rug + the AI steer rules. Full SPLOM keeps the histogram.
- Minimap: no labels (inset too small); orientation comes from the viewport rectangle.

Co-Authored-By: Claudypoo <288921227+claudypoo@users.noreply.github.com>
2026-06-25 10:49:17 +08:00
wassnameandClaudypoo 761bf7412a maps: drop society label leader-lines (draw_lines=False)
The textalloc leader lines made a spider-web across the map; 2-letter ISO codes
are short enough to sit beside their dot with only a small overlap-avoidance
nudge. Cleaner, less ink, label stays next to its point in almost all cases.

Co-Authored-By: Claudypoo <288921227+claudypoo@users.noreply.github.com>
2026-06-25 10:31:36 +08:00
wassnameandClaudypoo eb433f1cdc plot showcase: relative coherence gate + persona vec_label
Trajectory coherence gate was absolute (pmass<0.9); make it relative -- keep a
c only if pmass >= 95% of the base (c=0) pmass, else drop it entirely (no hollow
markers). Read vec_label from summary.json so non-authority personas label
correctly instead of the hardcoded "Authority/Care axis".

Co-Authored-By: Claudypoo <288921227+claudypoo@users.noreply.github.com>
2026-06-25 09:09:02 +08:00
wassnameandClaudypoo a2fe33ac53 maps: foundation SPLOM + minimap, crop synthetic-haze maps to societies+steer
- plot_splom: KxK pairs-plot (mfq2 real joint only -- others ship independent-
  marginal haze that would fabricate off-diagonal correlation). lower=joint
  scatter w/ AI base->steer trajectory, diag=marginal+AI rules, upper=Pearson r
  sized by |r|. Ordered by PC1 loading so binding (authority/loyalty) cluster.
  full + AI-zoom (macro/micro). NaN-safe at collapsed poles.
- ipsative map: synthetic haze is far wider than the societies, so it now crops to
  societies+steer (haze clips) and adds a 'full space' minimap with a viewport
  rectangle -- readable big5/16pf/humor maps with macro context kept.
- compass labels via textalloc (was overlapping); NaN-safe crop.

Co-Authored-By: Claudypoo <288921227+claudypoo@users.noreply.github.com>
2026-06-25 08:45:01 +08:00
wassnameandClaudypoo 9b13db3390 maps: multi-C trajectory overlay on ipsative map (path + hollow-at-incoherent + adaptive compass)
Driver writes the signed c-multiplier per row; plotter feeds the full c-sweep to
the range (already multi-c capable) and a connected path to the map. Headline
arrows point to calibrated c=+-1; trajectory dots at |c|>1 extend beyond, growing
with |c|, drawn hollow where admin pmass fell below the coherence floor. Compass
moves to the least-crowded corner so the +c arm (which heads toward its own
loading) stops colliding with it.

Co-Authored-By: Claudypoo <288921227+claudypoo@users.noreply.github.com>
2026-06-25 08:35:29 +08:00
wassnameandClaudypoo 50bdf8d235 plot: automatic MFV foundation-emphasis map vs human cultures
MFV had only the dlogit dumbbell, no human comparison. Add plot_mfv_map: per-
foundation relative emphasis (z across foundations) of model base/+C/-C against
the 5 MFV human cultures (JimenezLeal+Yamada), z-scoring each profile so the
model's logit scale and humans' 1-5 wrongness compare by pattern. Social Norms
dropped (no human norm). Shows the model over-weights Care/Authority vs humans
and +C lowers Authority emphasis. Keeps the dumbbell too.

Co-Authored-By: Claudypoo <288921227+claudypoo@users.noreply.github.com>
2026-06-25 07:33:42 +08:00
wassnameandClaudypoo 0e92e66415 maps: human haze on all ipsative maps (synthetic resample for big5/16pf/humor)
Split the PCA-fit basis from the scattered cloud in plot_ipsative_pca: add a
'haze' arg so instruments with only society-level mean+sd get a backdrop
(marginal Normal resample per country) without that resample dictating the
axes. mfq2 keeps its real Atari respondents (fit + haze). Previously only mfq2
had any human scatter; big5/16pf/humor showed bare society dots.

Co-Authored-By: Claudypoo <288921227+claudypoo@users.noreply.github.com>
2026-06-25 07:30:37 +08:00
wassnameandClaudypoo 5be5451e13 journal: coherent-C sweep -- mfq2 coherent to C=3, showcase C=1 validated
job 234: ordinal pmass 1.0 at both poles up to C=3.0, steer grows 0.129->0.324.
C=1 is well inside the coherent range. Joint-coherent C is bounded by the side
instruments' -C neutral-degeneracy (a model property at C=1), not ordinal
coherence. Completes the goal's "sweep for the largest coherent C" clause.

Co-Authored-By: Claudypoo <288921227+claudypoo@users.noreply.github.com>
2026-06-25 04:57:37 +08:00
wassnameandClaudypoo f5fc6302d4 validation: 82.6% is irreproducible -- its OWN code gives 0.780 on Qwen3-4B
Ran the exact 2026-05-08 eval (worktree at commit b20ec56, word readout) on
Qwen3-4B: top1 0.780, not 0.826. Every eval version agrees on ~0.78 (digit 0.773,
word-current 0.788, word-original 0.780). The 82.6% was a stale/erroneous table
entry, not a target this model reaches under any pipeline. Canonical value 0.773.

Co-Authored-By: Claudypoo <288921227+claudypoo@users.noreply.github.com>
2026-06-25 04:42:49 +08:00
wassnameandClaudypoo 52b9688de5 README: word readout reads 0.788 not 0.826 -- 0.83 unreachable in current eval
Tested the documented cause (the old word-first-token gather): top1 0.788 on
Qwen3-4B, only ~1.5pt above digit (0.773), not the table's 0.826. So even
reverting the readout does not recover it; the 82.6% came from the broader
2026-05-08 pipeline. Current eval tops out ~0.77-0.79 by every lever.

Co-Authored-By: Claudypoo <288921227+claudypoo@users.noreply.github.com>
2026-06-25 04:29:17 +08:00
wassnameandClaudypoo 3ece864460 add word-readout diagnostic (confirm validation-table 0.826 under old method)
Throwaway probe (like probe_mfv_think_budget): reuses the current _rollout core but
gathers foundation-WORD first tokens + word-keyed schema + no rev-reversal -- the
pre-e4e0f4d readout that produced the 82.6% validation number. Canonical evaluate()
stays digit-only. Confirms whether the showcase model matches the validation table
under the table's own method.

Co-Authored-By: Claudypoo <288921227+claudypoo@users.noreply.github.com>
2026-06-25 04:22:14 +08:00
wassnameandClaudypoo 4800066c1d README: model scale also caps top1 at 0.773 (Qwen3-8B), closing the 0.83 question
Third independent lever ruled out: Qwen3-8B reads exactly 0.773 like Qwen3-4B, so
0.83 is unreachable with the debiased digit readout at any fitting model size. The
gap is purely the superseded word-readout method.

Co-Authored-By: Claudypoo <288921227+claudypoo@users.noreply.github.com>
2026-06-25 04:12:02 +08:00
wassnameandClaudypoo d9fecd503d explain MFV top1 0.77 vs 0.83: it's the word->digit readout debiasing
Exhausted the legitimate levers on the current (digit) readout: top1 0.72 (think
64), 0.77 (256, 512 collapses), 0.72 (BMA n_samples=8). The 82.6% required the old
word-first-token readout, replaced deliberately to drop the uneven-first-piece
word prior. 0.773 is the honest ceiling; 0.83 would need reverting the debiasing
(research poison). README note + journal updated.

Co-Authored-By: Claudypoo <288921227+claudypoo@users.noreply.github.com>
2026-06-25 03:59:30 +08:00
wassnameandClaudypoo 58377ae863 probe: add n_samples/temperature for BMA top1 test
Co-Authored-By: Claudypoo <288921227+claudypoo@users.noreply.github.com>
2026-06-25 03:34:34 +08:00
wassnameandClaudypoo 639a6cd3d5 journal: unify ordinal reader, one-vector showcase on Qwen3-4B, think ablation
Records the eval unification, the Qwen3.5 -C collapse + bs=1 demo NaN fragility,
the cleaner Qwen3-4B showcase, the monotone think-budget ablation, and the
"MFV base broken" misread correction + stale 82.6% top1.

Co-Authored-By: Claudypoo <288921227+claudypoo@users.noreply.github.com>
2026-06-25 03:32:24 +08:00
wassnameandClaudypoo 1c8326d0ea README: add think-budget sensitivity (UAT2 -- steer delta grows with think)
MFQ-2 mean |steer delta| rises monotonically with the think budget: 0.068 (1) ->
0.149 (64) -> 0.319 (128) -> 0.682 (256), pmass >= 0.95. Proves the unified reader's
think budget carries the steer. Past ~512 the model closes </think> and the
readout collapses (coherent ceiling). Source: ablation_think_budget.py, job 228.

Co-Authored-By: Claudypoo <288921227+claudypoo@users.noreply.github.com>
2026-06-25 03:31:15 +08:00
wassnameandClaudypoo d2a5cab4c9 README: fix -C side-instrument claims (neutral-collapse, not bidirectional)
Fresh-eyes audit caught it: big5/16pf/humor -C poles pin to the neutral midpoint
3.0 (degenerate profile, though pmass stays ~1.0), not the bidirectional move I
wrote. Only mfq2 and MFV are genuinely bidirectional at -C. Fixed big5
agreeableness -C (3.0 not 2.85) and minor MFV roundings.

Co-Authored-By: Claudypoo <288921227+claudypoo@users.noreply.github.com>
2026-06-25 03:06:28 +08:00
wassnameandClaudypoo 82985b7bdd switch showcase to Qwen3-4B: coherent all poles, clean bidirectional steer
Qwen3-4B (the validation-table model) gives a fully coherent showcase: base/+C/-C
all pmass ~1.0 on ordinals and emitted_close <=9/264 on MFV, no -C collapse (that
was Qwen3.5-4B's gated-delta-net fragility). The Authority/Care vector moves the
MFV foundations apart bidirectionally (+C raises violations, -C lowers them and
raises "not wrong"), and also shifts agreeableness/16pf/humor -- a broad persona
axis, not an MFT-only or off-axis-null steer. Refresh the stale 82.6% validation
top1 to the reproducible 77.3%. README rewritten to match.

Co-Authored-By: Claudypoo <288921227+claudypoo@users.noreply.github.com>
2026-06-25 03:02:41 +08:00
wassnameandClaudypoo 2cb580e202 README: correct mfq2 range text to match final figure (-C collapses loyalty/authority)
The old "+C lowers all, -C raises all" no longer matches: +C lowers most, -C is
mixed and collapses loyalty/authority into NaN (missing blue arm). Describe the
coherent +C arm as the readable steer and the -C pole as past coherent range.

Co-Authored-By: Claudypoo <288921227+claudypoo@users.noreply.github.com>
2026-06-25 02:24:27 +08:00
wassnameandClaudypoo 12027350b9 README: report MFV showcase (base+pos coherent, -C over-steers), un-retract
The MFV base readout is coherent on Qwen3.5-4B (the earlier "excluded, base
incoherent" note was a misattribution of the -C pole's collapse + the bs=1 demo
NaN to base). +C is a moderate coherent steer; -C over-steers into the uniform
"everything is a violation" collapse, mirroring the ordinal -C instability. Adds
the MFV foundation-delta figure and the C-sweep follow-up note.

Co-Authored-By: Claudypoo <288921227+claudypoo@users.noreply.github.com>
2026-06-25 02:22:37 +08:00
wassnameandClaudypoo 1140c0dd34 render showcase from final run (MFV base+pos coherent, -C over-steers)
MFV base discriminates (logit spread Social Norms -0.43 .. Loyalty -5.79, not
uniform -> coherent, emitted_close 4/264). +C is a moderate coherent steer; -C
(C=-1) collapses into a uniform ~+10 nat "everything is a violation" shift, the
same over-steer instability the ordinal -C pole shows (NaN at collapse). The
earlier "MFV base broken" read was a misattribution of the -C pole's collapsed
aux + the bs=1 demo NaN to the base eval.

Co-Authored-By: Claudypoo <288921227+claudypoo@users.noreply.github.com>
2026-06-25 02:21:39 +08:00
wassnameandClaudypoo aa1ca1800f add MFV think-budget probe to test case-(c) collapse diagnosis
MFV pmass=0.1664 == 44/264 non-closing rows. Sweeps think budget to confirm the
collapse is guided.py case (c) (closed-think discards the forced read) and
whether a short budget recovers coherence without a researched-semantics change.

Co-Authored-By: Claudypoo <288921227+claudypoo@users.noreply.github.com>
2026-06-24 21:26:47 +08:00
wassnameandClaudypoo 9a52bf3641 nan-aware zoom y-limits; render valid ordinal showcase on unified eval
plot_range_zoom crashed on the NaN-at-collapse cells (a collapsed steer pole
reads NaN by design, "do not compare"). nanmin/nanmax frame the un-collapsed
cells; draw_steer already skips the NaN arm. Figures are the first valid
ordinal showcase: mfq2/big5/16pf/humor pmass 0.99+ and the steer registers at
think=64 (mfq2 care 3.86 base -> 3.13 at C=+1), unlike the old think=0 run.

Co-Authored-By: Claudypoo <288921227+claudypoo@users.noreply.github.com>
2026-06-24 21:23:43 +08:00
wassnameandClaudypoo d20f717251 maps: respondent-haze ipsative map + glossed axes (port from mft_honesty)
plot_ipsative_pca gains an optional respondents arg: when given it fits the
ipsative PCA basis on the individual cloud (3902 Atari respondents) and scatters
them behind the society dots, with an envelope-core crop, matching the
mft_honesty fig_pca_ipsative the project standardized on. Axis labels carry a
foundation-loading gloss. respondents=None keeps the old society-only behavior.

Bundles atari_study2_raw.csv + a respondent_profiles loader (keying verbatim
from Atari Code_Study2.R) so tinymfv owns the data, no mft_honesty dependency.
plot_steer_showcase passes respondents for mfq2 only.

Co-Authored-By: Claudypoo <288921227+claudypoo@users.noreply.github.com>
2026-06-24 15:49:24 +08:00
wassnameandClaudypoo 9d3741fb45 Unify ordinal survey readout onto the guided think-then-read core
administer()/read_items() now route through _rollout_natural_or_forced (the
nominal MFV core) instead of a think=0 single forward, so an activation steer
accrues over the think trace before the prefilled answer slot is read (spec
moral_aliens_engine.md, resolved decision: ordinal needs a think budget). The
only per-instrument difference is the answer-token set + the downstream reducer.

force_only on the shared core: the ordinal "(" prefill is one common char, so
natural-emission detection would match it by chance in the think trace and read
logits mid-think; surveys always force-read the answer slot. Nominal path keeps
natural emission (force_only defaults False). max_think_tokens floor is 1.

Smoke (tiny-random): ordinal + nominal both run; force-only demo reads the
forced ( slot.

Co-Authored-By: Claudypoo <288921227+claudypoo@users.noreply.github.com>
2026-06-24 15:37:47 +08:00
wassnameandClaudypoo 39d098f065 README: retract MFV showcase finding -- base readout was incoherent
The Qwen3.5-4B MFV base eval failed its own coherence canary (pmass=0.42,
top1_acc=0.28, mean_js/nll=NaN, demo p[f]=NaN), so the +6..+9 nat "everything is
a violation" deltas were a readout-collapse artifact, not a steering effect.
Remove the dumbbell + delta table + claim; keep only the coherent ordinal
showcase. MFV sensitivity delta lands once the vignette readout is coherent.

Co-Authored-By: Claudypoo <288921227+claudypoo@users.noreply.github.com>
2026-06-24 14:51:38 +08:00
wassnameandClaudypoo 1b1910973a README: repoint hero images to the fresh Qwen3.5-4B showcase
The two top images still pointed at the pre-run figures; swap them for the real
mfq2 map/range from this run and drop the orphaned old PNGs.

Co-Authored-By: Claudypoo <288921227+claudypoo@users.noreply.github.com>
2026-06-24 14:45:53 +08:00
wassnameandClaudypoo 5d0f19fcb6 README: real all-instrument steering showcase (Qwen3.5-4B)
One iso-KL calibrated mean-diff Authority/Care vector (C=+0.38) administered
across all 5 instruments from a steering-lite run_allinstr_showcase run.

- MFV dumbbell + delta table: -C lifts every violation-logit +6..+9 nats (the
  "everything is a violation" moral alien), +C near-inert except Social Norms -2.16.
- MFQ-2 map + range: near-uniform endorsement shift, every pole inside the human band.
- big5/16pf/humor ranges: off-axis nulls; humor base is itself the outlier.

Co-Authored-By: Claudypoo <288921227+claudypoo@users.noreply.github.com>
2026-06-24 14:02:16 +08:00
wassnameandClaudypoo d8af90c6e3 scripts: plot a steering run across all instruments (dogfood the maps)
Consume a steering-lite all-instrument run dir and render, per instrument,
tinymfv's ipsative map + range + zoom (ordinal) and a per-foundation Delta-logit
dumbbell (MFV), against the bundled human cloud. The showcase that exercises
tinymfv.maps end-to-end on real steering before publishing the lib.

Co-Authored-By: Claudypoo <288921227+claudypoo@users.noreply.github.com>
2026-06-24 13:21:49 +08:00
wassnameandClaudypoo e2c6c9cfe8 maps: restore joint dots on main-range arms (poles stay head-only)
The c=+-1,+-2 steps were dropped from the main range as clutter, but they
carry the steer's spacing/curvature; bring them back small (ms*0.6) while
the calibrated poles (cs[0]/cs[-1] = -+signed_C) keep head-only arrowheads.

Co-Authored-By: Claudypoo <288921227+claudypoo@users.noreply.github.com>
2026-06-24 12:33:18 +08:00
wassnameandClaudypoo 95b397cabf maps: base->pole fan arrows + human/AI brackets + trimmed titles
plot_range/plot_range_zoom now draw the steer via a shared draw_steer: two arms
fanning from the base dot (red +c, blue -c), each a line + constant-size triangle
head pointing away from base (matches plot_ipsative_pca's base->pole convention,
not the old -c->+c single arrow). Marker heads not FancyArrows so short arms don't
shrink/flip; arms x-offset so a non-bidirectional steer reads as two parallel arms;
poles are head-only (no dot blob); interior step dots off on the main range, on in
the zoom. human/AI direct-label brackets pinned to the panel top. Legend prose out
of the suptitle (short headline only); callers put it in the figure caption.

Co-Authored-By: Claudypoo <288921227+claudypoo@users.noreply.github.com>
2026-06-24 12:15:33 +08:00
wassnameandClaudypoo 48bb900f45 revert F1: keep NaN-at-collapse in the answer-token renorm (it is the signal)
The prior commit "fixed" p_a/pmass into a softmax to avoid NaN at coherence collapse.
That was wrong for this codebase: renormalizing within allowed tokens discards the mass,
so a distribution built from ~zero mass and one from real mass look equally comparable
after renorm -- they are not (the mean of 10 != the mean of 130). p/pmass -> NaN at
collapse poisons that item's factor, which is the honest "do not compare" signal, not a
bug. softmax was a silent fallback fabricating a comparable-looking number from incoherent
output. Restored, with a comment so it does not get re-"fixed". (Over-trusted the external
reviewer here against the repo's own no-defensive-programming rule.)

Co-Authored-By: Claudypoo <288921227+claudypoo@users.noreply.github.com>
2026-06-23 21:31:15 +08:00
wassnameandClaudypoo d5876a46d3 correctness fixes from gpt-5.5 review (ordinal path + fail-fast asserts)
Second external review (gpt-5.5, correctness-focused) on the post-cleanup tree.
Found no off-by-one/double-flip in the ordinal canonicalization+keying. Fixed the
parts I agreed with and could verify on the path the experiment uses:
- read.py: NaN-safe answer-token renorm. p_a/pmass poisons the profile with NaN when
  pmass underflows to 0 at coherence collapse -- exactly when pmass should just flag it.
  softmax(logp_allowed) is identical when pmass>0 and stable at collapse.
- maps.ipsative_pca: move SVD sign-stabilization INTO the helper so it and
  plot_ipsative_pca share one orientation (saved coords could otherwise mirror the figure).
- instrument: assert ordinal answer_space is ['1'..scale_max] IN ORDER (reduce_ordinal
  weights by position; a reordered space silently inverts E) -- was length-only.
- instrument.per_item_categorical: assert per-item dimension/sign agree across frames and
  frames are distinct, instead of silently averaging under rows[0]'s metadata.
- pyproject: move matplotlib+textalloc to an optional `maps` extra; evals stay headless.
- tests: drop imports of the deleted reduce_nominal/expected_value, inline the expectation,
  remove the now-impossible nominal-reducer test.

Deferred (flagged to maintainer): two NaN/window issues in guided.py's forced-choice
rollout (nominal evaluate() path) -- not exercised by this experiment, can't smoke-test,
and the NaN-as-collapse-signal there is a deliberate design.

Verified: experiment smoke green on all 4 instruments (no assert false-fires), 6 pure
unit tests pass, headless import clean, 16pf map renders.

Co-Authored-By: Claudypoo <288921227+claudypoo@users.noreply.github.com>
2026-06-23 21:25:33 +08:00
wassnameandClaudypoo 5333893345 lock: matplotlib dep tree (contourpy etc.)
Co-Authored-By: Claudypoo <288921227+claudypoo@users.noreply.github.com>
2026-06-23 20:40:05 +08:00
wassnameandClaudypoo 442bc5bba3 address external API review: lazy maps, prune dead code, type administer return
Whole-library review (deepseek-v4-pro) flagged tinymfv as not-yet-ready as a shared
dep. Fixes for the parts I agreed with:
- lazy `maps` import via module __getattr__ so `import tinymfv` stays headless/fast
  (no forced matplotlib) for numeric-only consumers; `tinymfv.maps.*` still works.
- trim __all__ to the front door (entrypoints + types + data api); plumbing stays
  importable but out of `import *`.
- delete dead code: reduce_nominal + REDUCERS (evaluate folds its profile inline),
  expected_value, HF_REPO, ROOT, _DEFAULT_FORCED_HINT.
- type administer's return as a TypedDict (AdministerResult/ItemRow/ItemFrameRow) so
  the schema is documented + checkable without reading source; still a plain dict at
  runtime (zero consumer churn).
- maps.plot_ipsative_pca: parametrize the legend labels (defaults preserve output)
  and rename hon/dis -> pos/neg so a non-honesty steer gets a correct legend.
- drop 'canary' jargon and panel/review-# archaeology from comments.

Verified: `import tinymfv` no longer loads matplotlib; lazy maps still resolves;
experiment mfq2 smoke green through the typed administer.

Co-Authored-By: Claudypoo <288921227+claudypoo@users.noreply.github.com>
2026-06-23 20:40:04 +08:00
wassnameandClaudypoo 494a9bbfa9 eval: verbose as int level (1=terse free-form 64ch default, 2=full demos)
Default eval logs were dominated by DEMO A/B full prompt+generation dumps at every
monitor step. verbose is now a level: 1 (default) prints the one-line aux stats plus
the free-reasoning generation collapsed to 64 chars (no prompt), bracketed by blank
lines so it stands apart from the steer demos; 2 reproduces the full first-row trace,
profile table, and complete DEMO B. bool callers still work (True->1, False->0).

Co-Authored-By: Claudypoo <288921227+claudypoo@users.noreply.github.com>
2026-06-23 10:51:05 +08:00
wassnameandClaudypoo 913befd308 administer: return per_item_frame (per-(item,frame) keyed rows)
The frame-averaged per_item drops the per-framing granularity that experiment
analyses need (MFQ-2 map's framing-bias diagnostic + paired base-vs-steer delta).
These rows are already computed in the by_dim_frame loop, so returning them is free.

Co-Authored-By: Claudypoo <288921227+claudypoo@users.noreply.github.com>
2026-06-23 10:23:02 +08:00
wassnameandClaudypoo 0bef8b0d3d instrument: fail-fast asserts from external review (#57)
deepseek-v4-pro review of the admin->tinymfv port (algebra proven correct, diff
8.25e-08 = float noise). Closes its flagged fail-fast gaps:
- per_item_categorical asserts uniform frame count per item (else the per-item
  average would silently reweight a factor)
- reduce_ordinal asserts dimension is not None (no phantom-factor pooling)
- administer asserts every ordinal item carries meta['task'] (else build_prompt
  would silently drop the response-scale legend and the profile would be junk)
Also commits maps.py + viz deps from the stage-3 port.

Co-Authored-By: Claudypoo <288921227+claudypoo@users.noreply.github.com>
2026-06-23 09:41:36 +08:00
wassnameandClaudypoo 99c01604dd instrument: add ordinal survey readout (read + administer + registry + data)
Port the answer-token survey readout from the weight_steer_honesty experiment
(mft_honesty.admin) onto the instrument.py canonicalize-at-reader design:
- read.py: generalized answer-token reader (any answer_space + prefill)
- administer.py: read all frames -> per_item_categorical -> reduce_ordinal -> profile
- instruments.py: build MFQ-2/Big5/16PF/HSQ Instruments from bundled survey JSONs
- instrument.py: add display + human_csv fields for the map layer
- data/: survey JSONs + human country CSVs (lean: no raw survey responses)

Parity: experiment's parity_administer_check.py shows max per-foundation diff
8.25e-08 vs admin.administer on the tiny model (same function of same logits).

Co-Authored-By: Claudypoo <288921227+claudypoo@users.noreply.github.com>
2026-06-23 09:04:35 +08:00
wassnameandClaudypoo f0f04667ff docs: refresh range example (ends are arrowheads only)
Co-Authored-By: Claudypoo <288921227+claudypoo@users.noreply.github.com>
2026-06-23 08:27:57 +08:00