19 Commits
Author SHA1 Message Date
wassnameandClaudypoo 469788c418 rename package tinymfv -> moralmaps (repo -> moral-maps)
Import name tinymfv -> moralmaps, pip name tiny-mfv -> moral-maps, GitHub
URLs wassname/tinymfv -> wassname/moral-maps. HuggingFace dataset id
wassname/tiny-mfv left as-is (separate namespace, published data artifact).
Historical docs/spec/* and RESEARCH_JOURNAL keep their dated paths.

Co-Authored-By: Claudypoo <288921227+claudypoo@users.noreply.github.com>
2026-07-09 10:41:49 +08:00
wassnameandClaudypoo ca76c0e05e title/bibtex/toml: 'moral and value maps for LLMs' (WVS-first, drop 'local'); WVS row in datasets table
Co-Authored-By: Claudypoo <288921227+claudypoo@users.noreply.github.com>
2026-07-09 10:23:13 +08:00
wassnameandClaudypoo 31b93aec57 maps: route every map through labelplace; drop textalloc + adjustText deps
plot_ipsative_pca (society codes + zone names + base/steer) and plot_range_zoom now use
labelplace.allocate_labels, the same placer as the WVS/value maps, so all maps read
alike: zone names hug their hull, points sit adjacent, short leader only when crowded.
Labels are collected then placed AFTER the crop so the pixel-space allocator sees the
final window. The compass rose is deterministic radial-outward (a rose is not a map --
the nearest-clear-slot search fought the radial layout). No map imports textalloc now.

Co-Authored-By: Claudypoo <288921227+claudypoo@users.noreply.github.com>
2026-07-05 14:21:01 +08:00
wassnameandClaudypoo e7810e4a0d maps: one adjustText pass for ALL value-map labels incl zone names
The zone names (Latin America, African-Islamic, ...) were nailed to their hull's
top vertex and bypassed the label allocator, so they landed in crowded spots while
open space sat nearby. Now every label -- country, model star, zone name, steer --
goes through a single adjustText call (force repulsion off the dots and each other,
leader lines), and each zone label is seeded at its hull's OUTWARD-most vertex so it
starts in the sparse margin. Also widen the family-colour hue spacing (grok now
near-black, clear of gpt blue; llama/gemini/gemma separated). textalloc stays for
the compass/range insets for now.

Co-Authored-By: Claudypoo <288921227+claudypoo@users.noreply.github.com>
2026-07-05 12:47:24 +08:00
wassnameandClaudypoo 520cbc04a4 pyproject: allow-direct-references so the git openrouter_wrapper dep builds
Hatchling rejects a direct git reference in an optional-dependency unless this
flag is set; without it uv could not build tiny-mfv and every 'uv run' failed.

Co-Authored-By: Claudypoo <288921227+claudypoo@users.noreply.github.com>
2026-07-05 08:25:28 +08:00
wassnameandClaudypoo 1261fabac8 read_api: use wassname/openrouter_wrapper (stamina retry) + save all raw responses
Replace the hand-rolled OpenAI client with openrouter_wrapper.openrouter_request,
which backs off on 429/provider/upstream/malformed errors (a rate-limited model no
longer kills the run), so retry logic doesn't diverge from the rest of the stack.
read_items_sampled now carries the raw sample texts; wvs_map appends every response
to wvs_iw_responses.jsonl (audit trail -- these API calls cost money).

Co-Authored-By: Claudypoo <288921227+claudypoo@users.noreply.github.com>
2026-07-05 08:11:53 +08:00
wassnameandClaudypoo 44c1fa0595 Zone regions: merged union of natural per-country shapes; turn off 16pf
Replace stacked translucent discs (which darkened at overlaps) with a shapely
union per zone -> one merged shape, uniform alpha. Each country's territory is now
its REAL spread ellipse from its respondent/haze cloud (natural varying shape), not
a fixed disc; sizes are rescaled so the median country ~ a legible radius (raw
within-country spread >> between-country, would fill the plot). Every country sits
in its zone, 2-country zones have area. MFV/WVS (country means only) fall back to a
fixed disc. 16pf turned off (unreadable even at 6 macro zones). Adds shapely to the
maps extra.

Co-Authored-By: Claudypoo <288921227+claudypoo@users.noreply.github.com>
2026-07-04 20:52:25 +08:00
wassnameandClaudypoo f5efbd24bd Add sampling readout for logprob-less API models (OpenRouter)
read_api.read_items_sampled samples N chat completions at temperature and uses the
empirical answer frequency as the per-item categorical p, emitting the same row
shape the logprob reader does -- so E/profile/entropy flow through the identical
per_item_categorical + reducers and a frontier model without logprobs drops onto
the same map. pmass_allowed becomes the parse rate (sampling coherence gate); C/LO
are omitted by design (log of a frequency has -inf zeros). This is the Economist's
'average of ten responses' method.

UAT (docs/reviews/p3_api_sampling_uat.md): E_mc == E_logprob to <=0.01 (unbiased),
llama-3.1-8b sampled E lands on the same [1,5] scale, parse-rate gate flags
off-format draws.

Co-Authored-By: Claudypoo <288921227+claudypoo@users.noreply.github.com>
2026-07-04 19:39:18 +08:00
wassname 4b38de685e cleanup: remove legacy dataset creation artifacts 2026-06-25 20:21:49 +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 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
wassnameandClaude Opus 4.7 ce5d8c349d guided: hybrid natural+forced eval (architecture-independent, no KV slicing)
Phase 1: batched generate with min_new_tokens=max_new_tokens so cache is uniform
length across the batch (no early stop at </think>). Phase 2: single batched
forced-suffix forward over that cache. Per-sample classification picks
gen.scores at the natural answer position (case a), forced logits (case b
interrupted), or NaN (case c emitted </think> but no answer).

Drops _slice_pkv_one + per-sample fork. The slice helper used layer.keys /
layer.values which crashes on Qwen3.5/3.6 LinearAttentionLayer (gated-delta-net
recurrent state has no .keys/.values). Uniform-length batched cache sidesteps
the cache surface entirely.

Bumps transformers>=5.7 for the Qwen3.5/3.6 gated-delta-net cached-forward
bugfix (resolves to 5.9.0).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-23 06:54:54 +00:00
wassname d411af3569 default conditions to other_violate only; drop "negation" wording
The "negation" mention in pyproject + __init__ docstring was stale —
the actual second pass is internal fwd+rev enum-order debias inside
guided_rollout (position-bias cancellation), not a negation framing.

self_violate is not in Clifford 2015 classic (other-violation only).
Default `evaluate(..., conditions=...)` to ("other_violate",); callers
who want both can opt in explicitly. Halves walltime per eval.

CONDITIONS in data.py still lists both (other_violate, self_violate)
as available — the change is only the evaluate() default.
2026-05-20 22:03:00 +00:00
wassname c96d02a675 refactor 2026-05-08 15:15:14 +08:00
wassname ac1c8cf7bb package 2026-05-02 16:51:15 +08:00
wassnameandClaude Opus 4.7 a9412ee226 move openrouter-wrapper to dev-only dep group
Only used by scripts/0{2,4,6}_*.py for data prep, not by the installable
src/tinymfv/ package. Keeping it in [project].dependencies leaked a local
editable path dep into the built wheel's runtime requires.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-01 05:38:35 +08:00
wassname 252e62abb7 decent 2026-04-30 21:22:07 +08:00
wassname a155f5594b valdiation 2026-04-30 20:08:12 +08:00
wassname ebf161b658 init 2026-04-30 17:10:09 +08:00