Commit Graph
25 Commits
Author SHA1 Message Date
coolguyandClaude Opus 4.7 b6863b3ba0 Fix ColorSharedNetwork to use real per-color encoding layout
ColorSharedNetwork previously sliced the input vector into n_colors equal
chunks (input_dim // n_colors). The slice boundaries do not align with the
actual encoding layout: adjacent slices contain phase flags, hand slots,
expedition state, scores, etc. mixed together. The "color-shared" encoder
was therefore sharing weights across semantically unrelated chunks, not
across per-color blocks. The single archived run that exercised this path
(2026-05-07_092137_color_shared_attention_1000iter) was killed at iter 41
and produced no eval data, so we have no measurement of whether a real
per-color architecture would help.

Adds compute_lost_cities_color_layout(input_dim) which returns explicit
per-color and common index lists for the standard Lost Cities encoding
(n_colors=5, hand_size=8, n_ranks=9). It recognises input_dim values
171, 219, 249, 297 across derived_playability and slot_aware_playability
flag combinations.

Per-color block (39 dims when derived_playability is on): both players'
expedition state for that color, discard top, public-histogram row,
pending-discard one-hot bit, legal-action draw-pile bit, and the
derived_playability per-color block. Slot-aware features are slot-major
and stay in common.

ColorSharedNetwork.forward now indexes per-color blocks via the layout
when input_dim matches a known schema. For other dims (unit tests,
non-Lost Cities use), it falls back to chunked slicing with a UserWarning
- preserves backward compatibility for tests but makes the legacy
behaviour visible.

No fair test of the new architecture was run as part of this commit.
Documented in docs/plans/deep-cfr-selectivity.md section 7.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-10 14:42:32 +09:00
coolguyandClaude Opus 4.7 f63c4b8059 Strip heuristic input features and add selectivity diagnostics
Audit of the Deep CFR information-state encoding identified two tiers of
non-pure features and removed both:

- Tier 3 (judgment): is_bad_open_candidate, open_risk_score,
  is_safe_continuation. Same heuristic family used to label bad_open in
  evaluation, embedded as model input.
- Tier 2 (projection): recoverable_score_no_bonus,
  recoverable_margin_no_bonus, min_needed_to_break_even,
  cards_needed_for_bonus, has_bonus_path. Mechanical but assumption-laden
  ("commit and play all currently-playable cards"). The no_bonus form is
  asymmetric: it amplifies the immediate -20 penalty while truncating the
  +20 bonus upside, biasing the model toward the same "don't open" basin
  the diagnostics already flagged.

Input dim 365 -> 297. DERIVED_PLAYABILITY_PER_COLOR 19 -> 15;
SLOT_AWARE_PLAYABILITY_PER_SLOT 12 -> 6. Test shape assertions updated.

Also adds selectivity diagnostic infrastructure used to reach this point:
- traversal.outcome_unsampled_first_open_prior_alpha config field with
  signed-prior overlay on unsampled first-open advantage targets (A1).
- analyze_first_open_counterfactual.py --post-policy to swap the
  policy_player rollout policy and isolate selection bias (D1).
- analyze_first_open_followup.py to inspect post-forced-open behavior
  (E2): same-color play vs discard counts, other-open rate, terminal
  hand composition.

Findings recorded in docs/plans/deep-cfr-selectivity.md sections 3-6.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-10 14:26:16 +09:00
coolguy 1593135313 Record first-open replay result 2026-05-10 02:44:10 +09:00
coolguy c570fc3ea5 Add first-open replay reweighting 2026-05-09 23:46:55 +09:00
coolguy 7c3a3499dc Add first-open counterfactual audit 2026-05-09 17:06:06 +09:00
coolguy ba54032703 Add first-open target audit 2026-05-09 16:36:43 +09:00
coolguy c246260a8b Document Deep CFR selectivity findings 2026-05-09 12:38:05 +09:00
coolguyandClaude Opus 4.7 0f85fa85b3 Close librarian: full archive promote-survey + parallel dispatch
Second survey processed the remaining 12 archives via gemini after
the first batch of 3 was accepted. 12 drafts, 0 skips, 0 errors.
Every draft carries a deterministic Last-verified header
(2026-05-08, commit 5c221fb) thanks to the post-processing fix
landed in the previous commit. All 12 accepted into docs/research/
verbatim:

  deep-cfr-evaluation-profile-plan
  deep-cfr-legacy-experiment-reproduction
  deep-cfr-legacy-runtime-comparison
  deep-cfr-performance-experiments
  deep-cfr-profile-advantage-memory-split
  deep-cfr-profile
  deep-cfr-regret-fallback-audit
  deep-cfr-v0-gap-vs-coolrl
  deep-cfr-v0-plan
  fast-engine-next-optimizations
  post-a-optimization-calculus
  test-coverage-notes

docs/archive/ is now fully covered: every entry either has a
research counterpart by stem or by tail-match.

Also extracts _dispatch_one and adds --parallel N to
scripts/librarian_survey.py. ThreadPoolExecutor over the per-archive
work is safe because subprocess.run is network-bound (no GIL fight)
and each thread writes to its own output filename. Default stays
1 (sequential); --parallel 4 is the recommended speedup for large
surveys. The two surveys above ran sequentially; future runs can
opt in.

Plan declares librarian closed for new feature work. MEMORY drift
fixup and duplicate-merge modes stay deferred until a real input
surfaces. Stage 1 (5 deterministic checks) and Stage 2 (promote +
survey) remain operational.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-08 02:33:51 +09:00
coolguyandClaude Opus 4.7 5c221fb3c6 Accept first survey batch + add commit-hash post-processing
Spot-check of the three drafts gemini produced in the --max 3
survey smoke test: all cited file paths exist, line numbers and
function names land within 1-2 lines of actual symbols
(game.pyx:217 cdef class GameState, evaluate.py:220 batched-entropy
block, trainer.py:892 _evaluate_parallel, action_distribution at
evaluate.py:238 with cited code at line 250 inside it). Numbers
cross-checked against archives match. Conclusions preserved.

The one systemic weakness was the Last-verified commit field:
gemini left a `<short-hash>` placeholder, a literal `HEAD`, or
omitted the commit entirely depending on the call. Fixed in two
places:

1. Manually patched the three drafts before acceptance and copied
   them into docs/research/.
2. Added _current_commit_sha and _post_process_draft helpers to
   both librarian_survey.py and librarian_promote.py. The drafts
   now go through `**Last verified:**` line normalization that
   substitutes today's date and `git rev-parse --short HEAD`
   before being written to disk. Future runs converge
   deterministically.

Net: docs/research/ gains classic-port-notes.md,
deep-cfr-batched-evaluation.md, and deep-cfr-evaluation-profile.md.
12 archive entries remain unprocessed.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-08 01:52:08 +09:00
coolguyandClaude Opus 4.7 b0b385591b Add librarian survey mode for batch promote-scan
scripts/librarian_survey.py walks docs/archive/*.md and dispatches
every entry without a research counterpart through the same prompt
assembly as librarian_promote.py. Outputs land under
runs/tmp/librarian-survey-<timestamp>/, classified into:
  <stem>.md            draft, ready to copy into docs/research/
  <stem>.SKIP.txt      LLM's one-line "not promotable" reason
  <stem>.ERROR.txt     CLI stderr if the call itself failed

Counterpart detection uses exact stem match plus a tail-match
heuristic so research notes that intentionally drop a domain prefix
still suppress their archive. Verified against the current tree:
docs/archive/deep-cfr-opponent-policy-network-divergence-* is
correctly recognized as already covered by
docs/research/opponent-policy-network-divergence.md.

--dry-run lists candidates and suggested research targets without
calling the LLM. --max N caps processed archives per run, useful as
a cost guard. Sequential dispatch; one LLM call per archive.

Plan updated to mark survey mode complete.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-08 01:18:28 +09:00
coolguyandClaude Opus 4.7 f5ce49682e Close first librarian promote round-trip + add --accept flag
scripts/librarian_promote.py gains a --accept flag that copies the
generated draft to the suggested docs/research/ target in the same
invocation. This is explicit per-invocation opt-in, not auto-apply:
the operator types --accept knowingly, the cp is still a deliberate
acceptance decision, just expressed in one command instead of two.

docs/research/option-a-bench-result.md is the first promoted note,
generated by gemini from
docs/archive/option-a-bench-result-2026-05-07.md and accepted
verbatim. Spot-check verified that cited file:line locations match
current source (traversal.pyx:473-475 and
inference_server.py:226-228 carry the cited code), the Last-verified
header reflects today's date and HEAD, and the durable conclusion
(sync-blocking policy boundary as the structural ceiling, not IPC
plumbing) is preserved.

This closes the end-to-end loop the librarian was designed for:
oversize check surfaced docs/performance.md, the routing pass split
durable analysis into the archive entry, the promote dispatcher
turned the archive entry into a research draft, and the human
accept step landed it as a tracked research note. Took one LLM call.

Removes the now-resolved ignore-list entry for
docs/research/option-a-bench-result.md (the file exists; the
forward reference is real).

scripts/librarian.sh exits 0 against the working tree.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-08 00:31:59 +09:00
coolguyandClaude Opus 4.7 8bbed31670 Add librarian Stage 2 v1: promote dispatcher
scripts/librarian_promote.py is the first Stage 2 piece: a
vendor-agnostic LLM dispatcher that drafts a docs/research/ note
from a given docs/archive/ entry. It assembles the prompt by
stitching scripts/librarian-prompt.md (system) onto the archive
body with a "draft a research note per the rules above" task
instruction, then shells out to the CLI selected by LIBRARIAN_LLM
({claude|codex|gemini}; default claude). The LLM's stdout is
captured to runs/tmp/librarian-promote-<timestamp>-draft.md for
human review — the script never writes into docs/research/ itself.

Refusal cases:
- path not under docs/archive/
- target docs/research/<stem>.md already exists (after stripping any
  -YYYY-MM-DD suffix)
- archive missing

If the LLM judges the archive non-promotable, it is instructed to
return a single SKIP: <reason> line instead of fabricating a draft.

--show-prompt prints the assembled prompt without invoking the LLM,
useful for inspecting what would be sent.

Plan updated: Stage 2 v1 marked complete; remaining Stage 2 work
(MEMORY drift fixup, duplicate-merge, survey mode) catalogued.
Next concrete step is a smoke test against one real archive entry.

Adds one ignore-list entry for docs/research/option-a-bench-result.md
which appears in the plan as a hypothetical accept target.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-08 00:05:38 +09:00
coolguyandClaude Opus 4.7 1cd9950bd3 Refactor docs/performance.md per librarian routing rule
docs/performance.md grew to 914 lines because dated experiments and
design analyses kept getting appended instead of routed to
docs/archive/ and docs/research/ as AGENTS.md prescribes. The
oversize check from librarian Stage 1 surfaced the file; this commit
acts on that finding by extracting the parts that belong elsewhere
and trimming the source to a focused current-state reference.

Extracts (verbatim from the original prose, with cross-link headers
and a brief routing note added at top):

- docs/archive/deep-cfr-performance-experiments-2026-05-07.md
  bundles torch.compile (regression), AMP (regression), GPU forward
  profiling (decision support), and Option B interleaved traversal
  (pass) — same date, same theme.
- docs/research/batched-traversal-inference-decision.md captures the
  durable A vs B vs C rationale with a closing "Outcome" pointer to
  the post-bench archive doc.
- docs/archive/post-a-optimization-calculus-2026-05-07.md preserves
  the forward-looking sequencing recorded pre-bench.
- docs/archive/option-a-bench-result-2026-05-07.md preserves the
  regression diagnosis and re-enable criteria.

docs/performance.md is now 345 lines, holds sections 1–9 (current
runtime / bottleneck / device / AMP status / batching / eval /
TensorRT / priorities), and ends with a "See Also" linking the four
extracts.

Also reworded the AGENTS.md soft-cap rule from a bare "~500-line
soft cap" to clarify the intent: the cap is a *routing trigger* (is
content piling up that should live in archive/research?), not a
split mandate. Reduces the risk of future agents shredding a useful
doc just to satisfy a number.

scripts/librarian.sh now exits 0 against the working tree.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-07 23:57:39 +09:00
coolguyandClaude Opus 4.7 6ecb233bdd Complete librarian Stage 1: stale plans + MEMORY drift
Adds the last two deterministic Stage 1 checks and wires them into
scripts/librarian.sh:

- librarian_check_stale_plans.py: per docs/plans/*.md, uses
  `git log -1 --format=%cs` to get the last commit date and flags
  plans untouched in 60+ days. Plans should be either active or
  archived; long silence is drift.
- librarian_check_memory_drift.py: validates the user-memory dir
  (~/.claude/projects/<slug>/memory). Each MEMORY.md index line
  must point at a real file with frontmatter (name, description,
  type ∈ {user, feedback, project, reference}); no orphaned memory
  files. Memory dir is derived from repo root for portability.

Both run clean against current state.

Stage 1 declared complete. Promotable-archive and duplicate-prose
detection are moved to Stage 2 in the plan because both need LLM
judgment to avoid false positives — not pattern matching.

Next concrete step is the open Stage 1 finding from yesterday:
docs/performance.md at 914 lines, due for a split into sub-topic
notes.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-07 23:44:25 +09:00
coolguyandClaude Opus 4.7 5a1b944931 Add librarian Stage 1 oversize check
Third Stage 1 piece: scripts/librarian_check_oversize.py walks
non-archive markdown files and flags any over the 500-line soft cap
declared in AGENTS.md. Wired into scripts/librarian.sh.

Caught one real finding on first run: docs/performance.md at 914
lines. Splitting it into sub-topic notes is a separate cleanup task
— surfaced for the user, not auto-applied.

Updates docs/plans/librarian.md Progress + sets the next concrete
step to a stale-plan checker.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-07 23:31:37 +09:00
coolguyandClaude Opus 4.7 7a3127de5d Add librarian Stage 1 orchestrator (scripts/librarian.sh)
Single entry point that runs every Stage 1 check in order and
aggregates exit codes — both checks always run so users see all
findings in one pass. Two checks wired up today (lychee link
integrity, file:line citations), more land incrementally as Stage 1
grows.

Removes scripts/librarian.sh from the ignore list now that the file
exists. Updates docs/plans/librarian.md Progress + Next Step.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-07 23:24:45 +09:00
coolguyandClaude Opus 4.7 a899af4d7e Add librarian Stage 1 citation checker with ignore list
scripts/librarian_check_citations.py extracts file:line references from
inline-code spans across docs/**/*.md and verifies each path exists
(and, if cited with a line number, is within range). Skips
docs/archive/ and docs/plans/archive/ which are read-only by policy.

Caught one real drift in docs/research/optimization_sequencing.md: the
note pointed at docs/plans/amp_trainer.md, which had moved into
docs/plans/archive/.

scripts/librarian-ignore.txt holds fnmatch globs for citations that are
intentionally future-tense (planned files described in the plan docs
themselves). Used sparingly so the checker stays useful as a drift
signal.

Updates docs/plans/librarian.md Progress + Next Step. Next concrete
step is a thin scripts/librarian.sh orchestrator over both checkers.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-07 23:22:34 +09:00
coolguyandClaude Opus 4.7 b9bbb4fcf7 Bootstrap librarian Stage 1 with lychee link checker
Captures the full librarian design (two-layer architecture, three-stage
pipeline, vendor-agnostic via LIBRARIAN_LLM env, propose-only / no
auto-apply) in docs/plans/librarian.md. Lands the first concrete Stage 1
piece: scripts/librarian_check_links.py, a lychee --offline wrapper
ported from ~/dev/coolrl/src/coolrl/dev/check_doc_links.py.

Also moves the librarian prompt from .claude/agents/ (Claude Code only)
to scripts/librarian-prompt.md so any CLI can load it as a system
prompt later. Fixes one stale README link the new checker caught:
docs/classic-port-notes.md → docs/archive/classic-port-notes.md.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-07 23:15:06 +09:00
coolguyandCodex 102f8cc91d Support average strategy in interleaved traversal
Co-Authored-By: Codex <codex@openai.com>
2026-05-07 23:07:47 +09:00
coolguyandCodex 2ce70ea804 Record option b interleaved benchmark
Co-Authored-By: Codex <codex@openai.com>
2026-05-07 22:59:49 +09:00
coolguyandCodex 240ef552c6 Add non-default interleaved traversal scheduler
Co-Authored-By: Codex <codex@openai.com>
2026-05-07 22:49:38 +09:00
coolguyandCodex 3e0a5db853 Prototype option b traversal interleaving
Add an experiment-only explicit-continuation traversal prototype that batches policy requests, records CPU/CUDA parity results, and updates the Option B plan with Phase 0/1 evidence.

Co-Authored-By: Codex <codex@openai.com>
2026-05-07 22:30:59 +09:00
coolguyandCodex e5ba247fcc Refresh optimization plans
Archive implemented AMP, Option A inference-server, and Cython heuristic plans. Add the active Option B interleaved traversal plan and update model-size/torch.compile plans to reflect the current traversal scheduling conclusion.

Co-Authored-By: Codex <codex@openai.com>
2026-05-07 22:15:09 +09:00
coolguyandClaude Opus 4.7 ad0be89857 Document model-size experiment plan (keystone for AMP/compile/TRT unblock)
The experiment finds a model size where (a) learning-curve gains
justify compute, and (b) forward time is large enough to amortize
AMP/compile/TensorRT overhead. Outcome gates re-enabling those four
deferred optimizations and Option A.

Tested grid: hidden={512,768,1024,1536} × layers={3,4,6,8} subset.
200 iterations per config on home (RTX 3090), single seed initially,
second seed for boundary configs. Eval cadence held at default.

Decision tree included for: success → recommend new default and
trigger downstream plans; null → document and stay; expensive-but-
better → defer until AMP/compile/TRT land.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-07 20:18:32 +09:00
coolguyandClaude Opus 4.7 befe29fc57 Document Option A bench result, post-A calculus, plans, and cost reports
performance.md additions:
- Batched Traversal Inference design decision (A vs B vs C with
  rationale).
- Option A bench result and structural ceiling (realized batch ~7.2,
  IPC overhead exceeds GPU gain at small model size).
- Post-A optimization calculus: why compile/TensorRT remain
  iter-neutral today and become meaningful only after model growth
  and/or denser eval. Sequencing matters; do not retest these on the
  current small model.
- Free-threaded Python (3.13t/3.14t) note: cleanest endpoint in
  principle, but PyTorch maturity + Cython nogil audit cost block
  near-term adoption.

docs/plans/ (4 plan documents for Codex execution):
- batched_traversal_inference_server.md (executed; deferred).
- amp_trainer.md.
- torch_compile.md.
- cython_safe_heuristic_bots.md (executed; first-pass landed).

docs/reports/ (3 cost reports):
- cost_pytorch_free_threaded_2026-05-07.md: WAIT 3-6 months;
  PyTorch wheels exist but our Cython is the gating cost.
- cost_cython_nogil_audit_2026-05-07.md: medium effort, traversal.pyx
  carries 90% of blockers; Steps 1-3 (cfr_math/encoding nogil
  keywords, TraversalStats cdef class) are safe and cheap, Steps
  4-6 wait for triggers.
- cost_pytorch_cuda_multithread_2026-05-07.md: risky;
  optimizer.step / load_state_dict race silently with concurrent
  forward; per-thread default streams unset means naive threading
  serializes on default stream anyway.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-07 20:05:38 +09:00