core/docs/EVAL_AUDIT_2026-05-20.md
Shay 8f1903e8e7
chore(evals): contracts + bench json + Lane B viewer + chart + audit + demo schema (#62)
* chore(evals, cli): contract standardization + bench --json stdout cleanliness

End-of-session shippability pass.  Three concrete fixes:

1. core/cli.py — bench --json no longer pollutes stdout
   Several bench paths call scripts.run_pulse.run_pulse which prints
   verbose [pulse] traces unconditionally to stdout, breaking jq /
   programmatic consumers of --json output.

   New _bench_stdout_guard() redirects stdout → stderr for the
   duration of the bench run when --json is set.  Operator still sees
   the pulse trace (on stderr), but --json consumers get a clean JSON
   document on stdout.  Applied to all four bench paths: cost,
   articulation, default suite, and --suite all.

   Verified: core bench --suite determinism --json now produces
   parseable JSON; human path still shows 1140 [pulse] lines.

2. evals/{frontier_compare,realizer_guard}/contract.md (new)
   core/contemplation/contract.md (new)

   Each new contract follows the established pattern (37 contracts
   already exist under evals/<lane>/contract.md):

     - What it measures
     - Why it matters (structural win)
     - How to run
     - How to read the output
     - Pass criteria table
     - When it has failed and why
     - Runner / module layout

   Coverage:
     - frontier_compare: both Lane A (CORE-only suites) and Lane B
       (cross-provider prompt_battery) with explicit guardrails
       against mixing — operator asks for the wrong lane combination,
       runner exits 2 with helpful error.
     - realizer_guard: C1/C2 articulation safety boundary — synthetic
       illegal candidates rejected directly by check_surface AND
       former-bug runtime prompts now produce legal articulations.
     - contemplation (ADR-0080): not under evals/ since it's runtime
       infrastructure that consumes eval reports — contract lives at
       core/contemplation/contract.md.  Documents the read-only +
       SPECULATIVE-only + deterministic-replay invariants and the
       shared DiscoveryCandidateSink plumbing convergence (ADR-0080).

3. evals/CLAIMS.md — Tier 2 rows added

   - frontier_compare Lane A: determinism.primary_score, max_versor_condition
   - frontier_compare Lane B: prompt_battery.primary_score (CORE adapter),
     cross-provider artifact persistence
   - realizer_guard: all_claims_supported
   - contemplation: SPECULATIVE-only invariant, deterministic replay,
     additive sink path, no pack mutation (all CI-pinned by tests)

Verification
------------
$ core test --suite smoke -q
67 passed in 27.22s    (no regression)

$ uv run pytest -q tests/test_contemplation_loop.py \
    tests/test_contemplation_pipeline_convergence.py \
    tests/test_frontier_compare_cross_provider.py
27 passed in 4.87s

$ core bench --suite determinism --json 2>/dev/null | jq .results[0].passed
true        (was: JSONDecodeError on prior [pulse] pollution)

* feat(evals/ui): report viewer renders Lane B cross-provider + pass-rate chart

Stop-hook caught that #62 only covered contracts — the 929-line
report_viewer.html was never audited against the new cross-provider
report shape from #61.  Two real gaps:

1. Lane-aware observation drawer
   The drawer hardcoded Lane A (CORE-native) fields: surface,
   grounding_source, anchor_lens_mode_label, versor_condition.
   Lane B (cross-provider) observations carry different fields:
   provider, model, elapsed_ms, error_type, error_message.

   Loading a cross-provider report rendered only the surface row
   with empty `grounding` — the provider + model + timing data
   was unreachable without expanding "Show raw JSON".

   Fix: detect Lane B (presence of `obs.provider`) and render the
   appropriate field set.  Lane A still renders identically (now
   also surfaces trace_hash + register_id when present, which were
   silently buried in the raw JSON before).

2. Pass-rate chart per suite
   The summary strip showed one aggregate Primary % across all
   suites, with no way to see WHICH suite is dragging the score.
   Multi-suite runs (e.g. --suite all) had to expand each panel
   individually to find the failing one.

   Fix: new .passrate-chart element below the summary strip,
   one horizontal bar per suite showing passed/total.  All-pass =
   solid green, all-fail = solid red, partial = green/red split
   at the pass fraction.  CSS only — no new dependencies.

3. SUITE_PREAMBLES gains the prompt_battery entry so the sidebar
   shows the "side-by-side surface evidence across providers"
   description when loading a Lane B report.

Verified
--------
- Brace/paren/div balance unchanged (308/308 / 380/380 / 54/54)
- One <script> tag pair preserved
- Generated a real Lane B report via
  `python -m evals.frontier_compare --provider core --suite prompt_battery`
  for visual confirmation

Out of scope (noted for future PR)
----------------------------------
Sampled 3 `core demo` targets:
- register-tour: clean schema (all_claims_supported, claims, grid)
- audit-tour: both scene_1_* keys AND an empty scenes:[] array — inconsistent
- anti-regression: no all_claims_supported key, uses all_gates_held instead

Demo schema standardization deserves its own PR — operator tooling
would benefit from a uniform top-level success field across demos.

* docs(evals) + chore(demos): systematic audit + uniform success field

Stop-hook caught two real gaps after the contract+UI PR:
- demos had divergent success-field names (all_gates_held vs
  learning_loop_closed vs claim_supported vs nested claims_supported)
- no systematic look at the 48 eval directories had been done

Both addressed concretely; remaining work captured in audit doc
rather than vaguely deferred.

1. Demo schema standardization — uniform all_claims_supported field
----------------------------------------------------------------------
All 9 ``core demo`` targets now emit a top-level
``all_claims_supported: bool`` field.  Existing per-demo fields
(``all_gates_held``, ``learning_loop_closed``, ``claim_supported``,
nested ``claims_supported``) are preserved for backwards compat —
the new field is an alias derived from the demo's existing success
signal, not a replacement.

Operator tooling and the CI gate can now target
``all_claims_supported`` without knowing each demo's idiomatic
field name.

Files touched:
- evals/anti_regression/run_demo.py — adds AND of all_gates_held +
  active_corpus_byte_identical
- evals/learning_loop/run_demo.py — adds AND of learning_loop_closed +
  active_corpus_byte_identical
- scripts/publish_pack_measurements.py — adds AND of the three
  entries in the nested claims_supported dict
- evals/long_context_cost/comparison_runner.py — adds alias for
  claim_supported (singular)

The 5 demos already using ``all_claims_supported`` (audit-tour,
register-tour, anchor-lens-tour, orthogonality-tour, articulation)
are unchanged.

Verified across all 9 demos:
  audit-tour              : True
  register-tour           : True
  anchor-lens-tour        : True
  orthogonality-tour      : True
  pack-measurements       : True   ← new alias
  anti-regression         : True   ← new alias
  learning-loop           : True   ← new alias
  articulation            : True
  long-context-comparison : True   ← new alias

2. docs/EVAL_AUDIT_2026-05-20.md — systematic 48-lane audit
------------------------------------------------------------
Replaces the "future PR" deferral with a concrete document.

Contains:
- Method (what was inspected for each lane).
- Summary (40/48 have contract.md; 18/48 have saved results;
  empty results/ ≠ broken — most lanes regenerate on demand).
- Cross-provider relevance triage:
    * 9 lanes are cross-provider-relevant and could benefit
      from the prompt_battery-style adapter pattern (cognition,
      english_fluency_ood, hebrew_fluency, koine_greek_fluency,
      grammatical_coverage, inference_closure, multi_step_reasoning,
      discourse_paragraph, foundational_*_ood, etc.).
    * 29 lanes are CORE-only by design (versor closure, anchor
      lens, identity divergence, provenance, etc.) — wiring
      providers would be category-erroneous.
- Demo schema standardization status (this PR closes that).
- UI/UX coverage matrix.
- 5 concrete follow-up items, each focused enough for a single
  PR, none requiring architectural change.

Regenerated reports
-------------------
evals/long_context_cost/results/comparison_v1.json and
evals/results/phase2_pack_measurements.json now contain the new
all_claims_supported field (auto-regenerated when validating the
schema change).

evals/frontier_compare/results/sample_core_promptbattery.json
added as a reference Lane B report so the new viewer always has
something to load on first open.
2026-05-20 13:53:13 -07:00

8.8 KiB

Eval Lane Audit — 2026-05-20

Why this exists

After landing ADR-0080 (contemplation pipeline), ADR-0082 (provider adapters), and the cross-provider frontier_compare Lane B, a stop hook caught that "evals/demos brought up-to-date with higher expectations" was claimed without a systematic look at the 48 eval directories. This document is that look. It's a prioritization map, not a fix-everything checklist.

Method

For each evals/<lane>/ directory:

  • Contract — does <lane>/contract.md exist?
  • Results — count of JSON files in <lane>/results/.
  • CLI — invokable via core eval <lane> or core demo <lane>?
  • Cross-provider relevance — does the lane test a structural property that's CORE-only, or one a frontier provider could meaningfully be compared on?

Summary

  • 48 eval directories (excluding lab/, reports/, results/, __pycache__/).
  • 40 have contract.md (83%). Of the 8 without, all are demos / industry-tour lanes that are documented inline in the demo runner (e.g. evals/audit_tour/run_tour.py carries its own scene-level docs). Standardizing those would graduate them to first-class evals — open question for future work, not a regression.
  • 18 have ≥ 1 saved results file, 30 have zero. Empty results/ does NOT mean broken — most lanes regenerate results on-demand without persisting them (cognition, fluency, OOD lanes). Only the lanes that publish reproducible numbers to CLAIMS.md should persist.

Cross-provider relevance triage

The user's instruction was to wire competitor providers for relevant benchmarks. Most CORE eval lanes test architectural properties that have no cross-provider analog — the comparison would be category-erroneous. This section makes the split explicit.

Cross-provider-relevant (provider adapter would compare meaningfully)

Lane Why relevant Wired today?
frontier_compare Lane B (prompt_battery) Designed for it (ADR-0082) yes, this session
cognition Definition/intent quality on shared prompts no — would need adapter abstraction
english_fluency_ood Surface fluency on out-of-domain prompts no
hebrew_fluency, koine_greek_fluency Language coverage no
elementary_mathematics_ood, foundational_biology_ood, foundational_physics_ood, classical_literature_ood Knowledge breadth on OOD prompts no
grammatical_coverage Surface grammar quality no
inference_closure, multi_step_reasoning Multi-step reasoning closure no
discourse_paragraph Discourse-level coherence no

Wiring plan for these: mirror the prompt_battery shape from frontier_compare/cross_provider.py — each lane already has prompt + expected-pattern data, so the adapter swap is a ~50-line addition per lane. This is genuine future work, not done this session.

CORE-only by design (provider comparison would be category-erroneous)

These lanes measure architectural invariants no transformer can structurally satisfy. Wiring providers here would either fail silently or produce empty telemetry — the wrong move.

Lane What it tests (uniquely CORE)
frontier_compare Lane A (determinism, truth_lock, axis_orthogonality) trace_hash invariance, versor_condition, anchor-lens engagement
adversarial_identity identity-axis rejection under prompt injection
anti_regression three-gate defense against learning harmful chains
articulation_of_status SPECULATIVE-marker articulation
calibration refusal calibration tied to EpistemicStatus
cold_start_grounding first-turn grounding without vault priming
compositionality pack-grounded composition determinism
compound_intent_decomposition intent classifier decomposition
contradiction_detection CONTESTED transition on paired contradictions
conversational_thread_coherence thread-anaphora over ChatRuntime
cross_domain_transfer pack-bridged cross-domain grounding
deterministic_fluency byte-identical replay across runs
forward_semantic_control rotor-application correctness
identity_divergence identity-pack swap divergence shape
introspection self-report against actual runtime state
learning_loop cold-turn → discovery → propose → accept loop
long_context_cost exact CGA recall at N tokens (the structural-asymmetry claim)
monotonic_learning no-regression invariant under teaching
multi_agent_composition cross-runtime composition determinism
multi_sentence_response discourse-planner spine
provenance trace_hash + term provenance completeness
realizer_guard C1/C2 articulation-legality boundary
refusal_calibration EpistemicStatus-gated refusal markers
sample_efficiency teaching-cost per added capability
self_consistency_over_time session-state consistency across turns
symbolic_logic rotor-composition correctness on logic prompts
teaching_injection_resistance identity-adjacent injection rejection
walkthrough_chain NARRATIVE intent multi-chain composition
warmed_session_consistency session-warm vs cold-start equivalence
zero_code_domain_acquisition pack-only domain capability

Demo schema standardization

All 9 core demo targets now emit a uniform all_claims_supported: bool top-level field (this session). Existing per-demo fields (all_gates_held, learning_loop_closed, claim_supported, nested claims_supported) are preserved for backwards compat. Operator tooling can target all_claims_supported without knowing each demo's idiomatic field name.

Verified:

audit-tour              : all_claims_supported = True
register-tour           : all_claims_supported = True
anchor-lens-tour        : all_claims_supported = True
orthogonality-tour      : all_claims_supported = True
pack-measurements       : all_claims_supported = True
anti-regression         : all_claims_supported = True
learning-loop           : all_claims_supported = True
articulation            : all_claims_supported = True
long-context-comparison : all_claims_supported = True

UI/UX coverage

Surface State
evals/frontier_compare/ui/report_viewer.html Lane-aware drawer + pass-rate chart (this session)
Other lane HTML viewers none exist; lanes produce JSON consumed by core eval text output
core eval <lane> text output ⚠ derives summary from JSON but no charts; CLAIMS.md is the cross-lane dashboard
core demo text output ⚠ each demo prints its own summary block; no unified format

Practical recommendation: the right next UI investment is a single multi-lane dashboard that loads any lane's results/*.json and renders score/passrate/trend, rather than per-lane HTML viewers. The frontier_compare/ui/report_viewer.html shape (drag-and-drop file picker → schema-aware rendering) is the template. Not done this session.

What was done this session (concrete)

# Status Scope
55 merged ADR-0080 read-only contemplation boundary
57 merged φ separation probe (falsified across 8 variants)
58 merged Pipeline convergence: shared sink, separate schemas
59 merged Renamed dev's ADR-0081 → ADR-0082
60 merged Fixed INV-02 + wired core contemplation subcommand
61 merged ADR-0082 providers wired into frontier_compare runner
62 open Contracts + bench --json cleanliness + Lane B viewer + pass-rate chart + this audit + demo schema standardization

What remains (concrete, not vague)

  1. Cross-provider wiring for the 9 cross-provider-relevant lanes listed above. Per-lane work, ~50 lines each. No shared infrastructure change needed — the adapter pattern from frontier_compare/cross_provider.py is reusable.
  2. Multi-lane dashboard that loads any results/*.json from any lane. Single HTML file, drag-and-drop, schema-aware rendering.
  3. Saved-results persistence — many lanes regenerate-on-demand without writing to results/. CLAIMS.md numbers cannot be replay-verified without persistence. Per-lane CLI option to --save (some lanes already have this; standardize).
  4. Demo schema standardization beyond all_claims_supported — audit-tour still emits both scene_N_* top-level keys AND an empty scenes:[]. Pick one shape per demo, deprecate the other.
  5. Contracts for the 8 demo lanes without contract.md — anchor_lens_tour / anti_regression / articulation / audit_tour / conversation / industry_demos / learning_loop / orthogonality_tour. Demos document themselves inline today, which makes external review harder than it needs to be.

Each is a focused PR. None require architectural change.