Skip to content

feat(e2e): historian eval lane runner script and CI wiring (U7) - #73

Open
ahrav wants to merge 1 commit into
stack/historian-eval-04-corpus-governancefrom
stack/historian-eval-05-ci
Open

feat(e2e): historian eval lane runner script and CI wiring (U7)#73
ahrav wants to merge 1 commit into
stack/historian-eval-04-corpus-governancefrom
stack/historian-eval-05-ci

Conversation

@ahrav

@ahrav ahrav commented Aug 27, 2026

Copy link
Copy Markdown
Owner

Stack 5/5 for the historian structural eval lane (beads magic-context-x4l.11). Base: #72 (corpus + governance).

run-historian-eval.ts drives three modes:

  • --lint: freeze lint plus corpus-level hard-negative family coverage.
  • --mutations: the invalid-state battery with per-class output.
  • --live: scenario runs against the dev split or a frozen release (env: ANTHROPIC_API_KEY, HISTORIAN_EVAL_MODEL, HISTORIAN_EVAL_PROBE_MODEL), aggregated into one schema-versioned report with the KTD8 exit mapping: 0 green, 1 red (any FAIL or ERROR), 2 run-fatal (any false-authoritative FAIL).

CI split (R14): per-PR runs only the deterministic parts with no credentials (historian-eval-deterministic job in ci.yml: unit selection + lint + battery). Live runs are scheduled or operator-dispatched via historian-eval.yml; the corpus selector flows through env into a closed case statement — never template interpolation — so a crafted dispatch input cannot execute with the API key in scope. Defaults to the dev split until the operator freezes releases/v1.

README documents the layout, the raw-output scorer seam for task x4l.13 (metamorphic lane, now unblocked), the operator gates (U2 live prototype run, U5 3-run stability audits, freeze), and every deviation from the plan discovered at implementation time (verification bridge, claim-memory bootstrap for magic-context-e1c, matcher-keyed scripting, live-mode probe-payload capture limits, force-band trigger numbers).

Stack: 1/5 plumbing → 2/5 contract → 3/5 engine → 4/5 corpus+governance → 5/5 (this)

@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for security reviews. Please try again later.

@coderabbitai

coderabbitai Bot commented Aug 27, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 9f80899f-79ef-4479-b1ba-a731b96c0ab8

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Comment @coderabbitai help to get the list of available commands.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 064feb2291

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

const { scenarios, releaseVersion } = loadCorpus(args);
const mode = liveModeFromEnv();
const sha = repoCommitSha();
const artifactsRoot = join(dirname(resolve(args.reportPath)), "historian-eval-runs");

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Preserve replayable snapshot paths in archived run records

In the scheduled/dispatch workflow, resolving the report path makes every artifactDir absolute, and runScenario serializes the resulting absolute contextDbSnapshotPath into each run record. After GitHub uploads and an operator downloads the artifact, that runner-local path no longer exists, while scoreRunRecord opens it directly; consequently the archived records cannot provide the documented byte-identical re-scoring. Store a portable path relative to the run record/artifact root and resolve it when replaying.

Useful? React with 👍 / 👎.

Comment on lines +60 to +61
} else {
throw new Error(`unknown argument: ${arg}`);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Support the documented mutation-evidence output option

When an operator follows either documented freeze command using --mutations --evidence <path>, argument parsing reaches this branch and exits with unknown argument: --evidence; runMutations also never writes the evidence artifact. This breaks the README's stated operator workflow for generating reviewable mutation evidence, so either implement the option and serialize the returned battery artifact or remove that option from the documented freeze procedure.

Useful? React with 👍 / 👎.

Comment on lines +88 to +90
function runLint(scenarios: readonly HistorianEvalScenario[]): number {
const diagnostics = scenarios.flatMap((scenario) => lintScenario(scenario));
const families = new Set(scenarios.flatMap((scenario) => scenario.families));

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Reject duplicate scenario IDs during corpus lint

If two development JSON files accidentally declare the same scenario ID, each document can pass lintScenario and the corpus is reported clean because no corpus-level uniqueness check runs here. The default live lane then maps both scenarios to the same historian-eval-runs/<id> directory, and the second iteration deletes and overwrites the first run record while the aggregate report still counts both scores. Reject duplicate IDs before mutation or live execution, as the frozen-release promotion path already does.

Useful? React with 👍 / 👎.

Comment on lines +51 to +54
- name: Install opencode
run: |
curl -fsSL https://opencode.ai/install | bash
echo "$HOME/.opencode/bin" >> "$GITHUB_PATH"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Pin or record the OpenCode version used by live evaluations

Whenever the OpenCode installer begins serving a new release, otherwise identical weekly evaluations start running against a different harness/runtime, but the serialized system tuple records only the repository SHA, model IDs, parser implementation, and chunk budget. Reports from before and after that upgrade therefore appear to have the same system identity even though request routing or session behavior may have changed, undermining longitudinal comparisons. Install a pinned OpenCode release or add its resolved version to the recorded system tuple.

Useful? React with 👍 / 👎.

@kilo-code-bot

kilo-code-bot Bot commented Aug 27, 2026

Copy link
Copy Markdown

Code Review Summary

Status: No Issues Found | Recommendation: Merge

Files Reviewed (4 files)
  • .github/workflows/ci.yml
  • .github/workflows/historian-eval.yml
  • packages/e2e-tests/historian-eval/README.md
  • packages/e2e-tests/scripts/run-historian-eval.ts
Previous Review Summary (commit 064feb2)

Current summary above is authoritative. Previous snapshots are kept for context only.

Previous review (commit 064feb2)

Status: No Issues Found | Recommendation: Merge

Files Reviewed (4 files)
  • .github/workflows/ci.yml
  • .github/workflows/historian-eval.yml
  • packages/e2e-tests/historian-eval/README.md
  • packages/e2e-tests/scripts/run-historian-eval.ts

Reviewed by gemini-3.7-flash · Input: 148.4K · Output: 13.6K · Cached: 1M

run-historian-eval.ts drives three modes: --lint (freeze lint plus
corpus-level family coverage), --mutations (the invalid-state battery
with per-class output), and --live (scenario runs against the dev split
or a frozen release, aggregated into one schema-versioned report with
the KTD8 exit mapping: 0 green, 1 red, 2 run-fatal on any false-
authoritative FAIL).

Per-PR CI runs only the deterministic parts with no credentials
(historian-eval-deterministic job); live scenario runs are scheduled or
operator-dispatched via historian-eval.yml, where the corpus selector
flows through env into a closed case statement rather than template
interpolation so a crafted dispatch input cannot execute with the API
key in scope. The lane README documents the layout, the raw-output
scorer seam for task x4l.13, the operator gates (live prototype run,
3-run stability audits, freeze), and every deviation from the plan
discovered at implementation time.
@ahrav
ahrav force-pushed the stack/historian-eval-05-ci branch from 064feb2 to 511d673 Compare August 27, 2026 06:33

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 511d673b9c

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

contents: read

jobs:
live-lane:

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Restrict secret-bearing dispatches to the default branch

A user with permission to dispatch workflows can select a non-default repository branch, and actions/checkout will check out that selected ref before this job exposes HISTORIAN_EVAL_ANTHROPIC_API_KEY. Such a branch can modify the runner or package lifecycle scripts to exfiltrate the secret without merging; gate manual dispatches on github.ref == refs/heads/<default branch> as the repository's reference-host workflow does.

Useful? React with 👍 / 👎.

Comment on lines +127 to +129
const [providerID, ...modelParts] = probeModel.split("/");
if (!providerID || modelParts.length === 0) {
throw new Error("HISTORIAN_EVAL_PROBE_MODEL must be provider/model");

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Reject empty model components before starting live runs

When HISTORIAN_EVAL_PROBE_MODEL is set to a value such as anthropic/, split("/") produces one empty model component, so this check accepts it and the runner performs the expensive historian work before every probe fails through an invalid model route. The historian model is not shape-validated at all. Validate that both configured routes have a nonempty provider and nonempty model portion before iterating over the corpus.

Useful? React with 👍 / 👎.

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.

1 participant