Skip to content

feat(evaluation): shared acceptance corpus + candidate-agnostic cross-review harness - #6

Merged
OCPdev25 merged 1 commit into
masterfrom
eval/corpus-harness
Sep 17, 2026
Merged

OCPdev25 merged 1 commit into
masterfrom
eval/corpus-harness

Conversation

@obvious-autobuild

Copy link
Copy Markdown
Contributor

Human author: Gilbert Polanco (gilbertpolanco42@gmail.com)

Why

The arena cross-review needs to judge all four candidates (arena/candidate-a|b|c|d) against the same acceptance corpus, run through the same harness, or results are not comparable. Today there is no shared corpus: each review would improvise its own tests, and candidate quality would be judged on unequal ground. This PR lands that shared ground truth as data, plus a narrow adapter contract so any candidate's entry-creation and timeline-read entry points can execute it unchanged.

What

  • Corpus as data — six JSON fixtures under evaluation/fixtures/, expectations independent of any candidate code:
    1. 01-multi-event-narrative — one narrative → 3 events, exact count/categories/quantities and transcript order pinned.
    2. 02-relative-time-timezones — 8 cases pinning exact absolute instants ("this morning", "yesterday 6pm", "an hour ago", "just now") across America/New_York, Pacific/Auckland (NZST and NZDT) and UTC; conventions documented in the fixture and README; expected instants machine-computed against the IANA tzdb (DST-safe).
    3. 03-malformed-extraction — hostile raw input (control chars, DEL): entry still created with 0 events (contract: extraction failure never blocks capture), raw preserved.
    4. 04-retry-double-submit — same captureId twice → Created then IdempotentReplay, exactly one entry/event on the timeline.
    5. 05-raw-fidelity — SHA-256 byte equality of the raw transcript across a validation failure and a retry (created entry, replay, timeline read); hostile fixtures include NUL/DEL/CRLF/tabs/emoji/combining marks/trailing whitespace.
    6. 06-reload-persistence — timeline identical (canonical-JSON deep-equal) across a simulated cold start.
  • Adapter interface — evaluation/src/adapter.ts: CandidateAdapter = createEntry (full pipeline, settles before resolve) / readTimeline / reload, results as a discriminated union (Created | IdempotentReplay | Rejected). Narrow on purpose; wire shapes mirror the Effect v4 schema contract (unix-ms numbers, _tag literals, absent-not-null optionals). One deliberate addition: WireEntry.captureId, the duplicate-protection key.
  • Fixed runner — src/runner.ts executes each fixture identically for every candidate; adapter exceptions surface as fixture failures, never crashes.
  • Worked example — src/example/example-adapter.ts (in-memory, contract-shaped, DST-aware relative-time resolution) proves the corpus is executable.
  • Negative control — src/example/broken-adapter.ts plants duplicate-on-retry + transcript-trim faults; the harness flags 5/6 fixtures, proving the checks bite.
  • README — adapter contract, time conventions, exact commands, per-fixture evidence, what is/isn't pinned.

Scope guard: touches evaluation/** only; no candidate branches read; zero runtime dependencies (bun primary runner, tsx alternative documented).

How to Review

  • Start at evaluation/README.md (contract + commands), then src/adapter.ts (the interface cross-review adapters will implement) and src/runner.ts (the fixed protocols).
  • Fixture expectations to scrutinize: the eight absolute instants in 02 (verify against a tzdb if you like — each was machine-computed, notably NZDT 1790571600000 and US-EST 1793574000000).
  • Intentionally excluded: candidate adapters (attached at cross-review), NLP-quality benchmarking beyond the pinned fixtures, publish/review transitions and multi-child scoping (corpus scope is one child's draft timeline), repo-level CI wiring (PR ci: add PR pipeline (pnpm via corepack, turbo typecheck, tests, build) #3 owns the pipeline).
  • Deliberate choice: fixture 4/5 pin IdempotentReplay as the defined double-submit outcome; rejection on extraction failure would violate the schema contract's "events may be empty — extraction failure never blocks capture", so fixture 3 pins creation + 0 events instead.

Test Evidence

Run on this branch (bun 1.3.14, tsc 5.9.3 strict):

  • bun src/run.ts → 6/6 fixtures PASS, exit 0 (worked example adapter; all six fixtures execute: 1 + 8 + 1 + 1 + 2 + 2 = 15 adapter workloads).
  • bun src/run.ts --adapter=./src/example/broken-adapter.ts --expect-failure → faults caught, exit 0: duplicate-on-retry (expected IdempotentReplay, got Created), SHA-256 byte-fidelity violations on created/replayed/timeline surfaces, missing events.
  • bun install && bun run typecheck → exit 0 (strict, noUncheckedIndexedAccess, verbatimModuleSyntax).

🔗 Obvious Project · 🧵 Obvious Thread

Corpus as data (6 JSON fixtures, expectations independent of candidate
code): multi-event narrative (count/order), relative-time across
America/New_York, Pacific/Auckland (NZST + NZDT) and UTC with documented
conventions and machine-computed IANA instants, malformed extraction
(failure never blocks capture, raw preserved), retry/double-submit on the
same captureId (exactly one event, IdempotentReplay), raw fidelity
(SHA-256 byte equality across validation failure and retry), and reload
persistence (timeline identical across simulated cold start).

Harness: narrow CandidateAdapter interface stated in types
(createEntry/readTimeline/reload), fixed per-fixture runner protocols,
worked example adapter over the Effect v4 schema contract wire shapes,
and a deliberately broken negative control proving the checks bite.

README documents the adapter contract, conventions, and exact commands.

Co-authored-by: Gilbert Polanco <gilbertpolanco42@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants