Skip to content

docs: propose multi-harness community benchmark plan for Legal Quants input - #7

Merged
ai-agent-on-behalf-of-john-hughes[bot] merged 24 commits into
mainfrom
docs/multi-harness-community-benchmark-plan
Jul 8, 2026
Merged

docs: propose multi-harness community benchmark plan for Legal Quants input#7
ai-agent-on-behalf-of-john-hughes[bot] merged 24 commits into
mainfrom
docs/multi-harness-community-benchmark-plan

Conversation

@johnjhughes

@johnjhughes johnjhughes commented May 29, 2026

Copy link
Copy Markdown
Collaborator

Summary

Adds docs/plans/multi-harness-community-benchmark-2026-05-29.md — a proposed plan (not yet approved or implemented) for a community-facing multi-harness benchmark that sits alongside, and remains strictly separate from, the protected official LegalForecastBench path.

This PR is up for community input, especially from Legal Quants. Merging it accepts the plan as a starting point for discussion; the design is explicitly open to revision before any of the 17 work items are scheduled.

What the plan proposes

  • Additive package legalforecast/multiharness/ that reuses existing evals/packet/prompt/parser/scoring/accounting code without rewriting the protected official path.
  • Canonical task families with explicit scoring modes (legalforecast_mtd + lfb_brier, harvey_lab + lab_native). Community rows are grouped by (family, scoring_mode, selection_sha256); no cross-suite winner is computed.
  • Language-agnostic command-adapter protocol (adapter.json manifest + capabilities / run CLI over JSON) so contributors can ship a script/CLI rather than packaging Python.
  • Host-owned sandbox policy emitting sandbox.plan.json per run; tool containers default to --network=none with provider egress confined to the host adapter process.
  • Harvey LAB integration via a pinned CLI bridge (capabilities probed and recorded; not vendored).
  • First-class adapter tracks for LQ.AI, Hermes Agent, and OpenClaw, with OpenAI Responses/Codex-style and Claude Agent SDK as provider/runtime baselines.
  • Partial-run shards as first-class submissions with strict compatibility keys for composite-row rollups and per-shard contributor attribution.
  • Two-layer registry: GitHub PRs under community/submissions/** as the reviewed registry of record; Hugging Face Datasets / GitHub Releases as immutable large-artifact mirrors referenced by URL + SHA-256.
  • Two separate static publication surfaces: LegalForecastBench Official Results and LegalForecastBench Community Harness Comparisons (working names; final naming open for Legal Quants approval).
  • Provenance and presentation surfaces replace the deprecated result-tier taxonomy (result_tier, verified-community, community-unverified, alpha-non-canonical are explicitly banned in submission validation, consistent with .agents/AGENTS.md).
  • Conformance suite runnable without provider credentials so contributors can self-verify adapters before submission.
  • Dedicated community validation workflow with contents: read only, no OIDC, no AWS credentials, no provider secrets, and no protected official environment.

Requesting community input

Particularly from Legal Quants and other folks who would actually run this, feedback would be most valuable on:

1. Which adapters should be included as first-class

The plan currently proposes LQ.AI, Hermes Agent, and OpenClaw as first-class tracks, with OpenAI Responses/Codex-style and Claude Agent SDK as provider/runtime baselines. Open questions:

  • Are there harnesses, agent frameworks, or legal-AI platforms missing from this list that the community considers important?
  • Should any of the proposed first-class tracks be demoted to "community-contributed example" or vice versa?
  • Are there licensing, terms-of-service, or attribution constraints we should know about for any candidate harness?

2. How folks would like to run them

The plan assumes a few defaults that are open for discussion:

  • Sandbox baseline: Docker/Podman with --network=none for tool containers, provider egress only from the host adapter process. Is that the right default? Do contributors expect to run without containers (bare process), or with a different isolation backend?
  • Adapter integration mode per harness: command-manifest bridge (external CLI), in-process Python adapter, or native plugin? For each of LQ.AI / Hermes Agent / OpenClaw, which mode does the community prefer for v1?
  • Auth modes: API keys per adapter, user-installed CLIs reusing existing subscriptions (where terms allow), or self-hosted deployments (LQ.AI, Hermes)? Each adapter must record its auth mode in artifacts — what level of disclosure do contributors expect?
  • Compute: should the plan assume contributors run locally, on rented compute, or both? Does the community want a "compute sponsor" credit field?
  • Hugging Face vs GitHub Releases vs other for large artifact mirrors — preferences?

The adapter-selection and runtime-mode questions above are community-driven decisions that should be resolved by Legal Quants reviewers rather than implementation defaults.

3. Naming and branding

Working names are LegalForecastBench Official Results and LegalForecastBench Community Harness Comparisons. Final naming, attribution language, and any Legal Quants co-branding are open.

Scope of this PR

  • Docs only: one new file, docs/plans/multi-harness-community-benchmark-2026-05-29.md (637 lines).
  • No code changes. No new package, no new workflows, no schema changes, no dependency changes.
  • No deprecated taxonomy reintroduced: the plan respects the .agents/AGENTS.md decision to drop preregistration protocols and result-tier classification.

Test plan

  • Review the plan's stated separation between the protected official path and the proposed community path (sections "Local official publication and community constraints", Item 14).
  • Confirm the plan's deprecated-taxonomy avoidance matches .agents/AGENTS.md:11-16 (Item 11 banned fields list).
  • Sanity-check the proposed package boundary against existing seams (Item 1 file list; "Local evaluation seams" section).
  • Community review: respond to the adapter-selection and runtime-mode questions above.

Note

Medium Risk
Large additive surface (publication guardrails, community artifacts, tag-triggered PyPI publish) but official eval workflows stay separate; main risk is mis-published community content or a bad release artifact, mitigated by validation workflows and release_check gates.

Overview
This PR implements the multi-harness community benchmark (not just the plan doc): a new legalforecast/multiharness/ layer with canonical schemas, LFB/LAB task loading, deterministic selection, host-owned sandbox plans, command adapters, conformance, runner, community package/validate/aggregate, and a legalforecast multiharness CLI wired into the main legalforecast entrypoint.

CI and release: Adds Community Multi-Harness Validation (format/lint/pyright, multiharness + community tests, submission validation, guardrail scans, aggregate dry-run; on main, rebuilds community site artifact) and Publish Python Package (v* tags run release_check, PyPI trusted publish, GitHub release assets). scripts/release_check.py gains no-network multiharness smokes (inspect, index, conformance, dry-run run, community aggregate).

Contributor surfaces: New docs (multiharness-adapter-spec, community-submissions, per-adapter guides), examples/adapters/ no-network fixture_bridge.py profiles (LQ.AI, Hermes, OpenClaw, OpenAI Responses, Claude SDK), and checked-in community/submissions/2026/ example packages for those five tracks.

Docs/product alignment: README documents community multi-harness vs official benchmark; MODEL_RELEASE_DATES.md and pilot model names shift to the checked-in pilot registry keys (Gemini 3 Flash Preview, GPT-5.4 mini, Claude Sonnet 4.6). The planning doc is updated with an implementation status section.

Reviewed by Cursor Bugbot for commit afd4a4c. Bugbot is set up for automated code reviews on this repo. Configure here.

Summary by CodeRabbit

  • Documentation
    • Expanded the community multi-harness benchmark plan, adapter docs, and community submission/validation guidance.
    • Added multi-harness adapter spec and adapter/provider baseline documentation.
  • New Features
    • Introduced the community multi-harness validation + aggregation workflow, including generation of registry artifacts and a community static comparison site.
  • CI / Automation
    • Added PR validation and main-branch static-site rebuild workflows, plus multiharness checks in the release pipeline.
    • Updated model pilot anchor dates and pilot model list.
  • Tests
    • Added end-to-end and schema/guardrail coverage for community submissions, aggregation, and static sites.

Copilot AI review requested due to automatic review settings May 29, 2026 19:31
@coderabbitai

coderabbitai Bot commented May 29, 2026

Copy link
Copy Markdown

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 39a395a6-f13c-42ee-be3b-4dbf7d8cb075

📥 Commits

Reviewing files that changed from the base of the PR and between a60fb98 and 6d75a66.

📒 Files selected for processing (6)
  • legalforecast/multiharness/community.py
  • legalforecast/multiharness/conformance.py
  • legalforecast/multiharness/harvey_lab_adapter.py
  • tests/test_community_submission.py
  • tests/test_multiharness_conformance.py
  • tests/test_multiharness_harvey_lab_adapter.py

Walkthrough

This PR adds the multi-harness benchmark stack: canonical schemas and validation, adapter execution and conformance, deterministic run orchestration, community submission packaging and aggregation, publication surfaces, documentation, workflows, and tests.

Changes

Multi-harness Stack Foundation

Layer / File(s) Summary
Docs and plan
docs/*, README.md, MODEL_RELEASE_DATES.md, examples/adapters/*, community/submissions/.gitkeep
The benchmark plan, adapter docs, community-submission docs, README anchors, model release anchors, example adapter manifests, and community submissions scaffolding are updated together.
Core schema and selection
legalforecast/multiharness/*
Canonical record types, validation helpers, selection logic, sandbox policy planning, task loaders, and adapter-facing abstractions are added for multi-harness runs.
Adapters, conformance, and runner
legalforecast/multiharness/*, tests/test_multiharness_*, examples/adapters/*
Command adapters, the built-in LFB and Harvey LAB adapters, artifact projection, conformance checks, deterministic run orchestration, and their tests are added.
Community packaging and publication
legalforecast/multiharness/community.py, legalforecast/publication/*, tests/test_community_*, tests/test_static_result_sites.py, tests/test_release_bundle.py
Community submission packaging, validation, aggregation, comparison reporting, static site generation, and release-bundle metadata are added with validation tests.
Workflows and release checks
.github/workflows/*, scripts/*, tests/test_*workflow.py, tests/test_release_check.py
The validation and publish workflows, release-check smoke steps, package hashing, and the matching workflow/release-check tests are updated to cover the new stack.

Estimated code review effort: 5 (Critical) | ~120 minutes

Possibly related issues

Poem

🐰 I hopp'd through schemas, docs, and run-plan trees,
Then sandboxed rabbits raced with ease.
Community carrots now line the trail,
And benchmark breezes set the sail.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title is related to the main change: a proposed docs plan for a community multi-harness benchmark.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch docs/multi-harness-community-benchmark-plan

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

Copilot AI 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.

Pull request overview

Documentation-only PR adding a proposed plan for a community multi-harness benchmark that runs alongside the protected official LegalForecastBench path. The document is explicitly up for Legal Quants input and proposes no code changes.

Changes:

  • Adds a 637-line plan file describing a new additive legalforecast/multiharness/ package, command-adapter protocol, host-owned sandbox policy, LAB CLI bridge, two-layer registry, and separate community publication surface.
  • Defines 17 sequenced work items, risks, open questions, and references.
  • Avoids reintroducing the deprecated result-tier taxonomy per .agents/AGENTS.md.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@ai-agent-on-behalf-of-john-hughes

Copy link
Copy Markdown
Contributor

End-to-end review of the multi-harness layer (tip afd4a4c)

Verdict: approve / ready to merge, with one PR-hygiene fix (stale description) and non-blocking follow-ups tracked in a separate issue. Reviewed in an isolated worktree at afd4a4c; everything below was executed, not just read.

1. Wiring — verified working

  • uv run legalforecast multiharness --help works and exposes tasks, adapters, conformance, run, report, community.
  • Ran the exact multiharness smoke subset that scripts/release_check.py runs (prepare_multiharness_smoke_inputs + the 5 steps: adapters inspect, tasks index, conformance, run --dry-run, community aggregate --dry-run) plus _validate_multiharness_smoke_artifactsall pass, no network required.
  • All 5 fixture adapter manifests under examples/adapters/ (lq-ai, hermes-agent, openclaw, openai-responses, claude-agent-sdk) pass the conformance suite (status: passed).
  • All 5 checked-in community/submissions/2026/*/submission.json packages pass validate_submission_file.
  • Full quality gates on the branch: 602 passed / 2 skipped, ruff format --check clean, ruff check clean, pyright 0 errors.

2. Official/community boundary — holds up in code

  • Every submission must carry the not_official_legalforecastbench_result attestation plus 3 others (legalforecast/multiharness/community.py:65-75); validation rejects missing attestations.
  • Deprecated result-tier fields (result_tier, tier) and values (official, verified-community, community-unverified, alpha-non-canonical, private-debug) are banned by scanner in legalforecast/multiharness/validation.py, consistent with the repo scope decision. release_bundle.py drops RESULT_TIER in favor of RELEASE_STATUS — good cleanup of the deprecated taxonomy.
  • Publication surfaces are fully separate: render_official_results_site vs render_community_results_site with distinct schema versions; the community site headline is "Community Harness Comparisons" with an explicit "not official LegalForecastBench results" notice; reporting outputs repeat the non-official disclaimer.
  • community-multiharness-validation.yaml runs with permissions: contents: read, no OIDC, no AWS, no provider secrets; it validates submissions, guardrail-scans public artifacts, and only uploads the community site as a build artifact. No path writes into official registries or artifacts.
  • Public records are scanned for secret-like fields, secret-value patterns (incl. AKIA keys, bearer headers), and provider account IDs.

3. Sandbox — network-off default confirmed, with an honest caveat

  • CLI default network policy is none; --allow-provider-egress is the explicit opt-in that flips to provider_egress_host_only. Either way build_container_plan hardcodes --network=none for the tool container, plus --cap-drop ALL, no-new-privileges, pids/memory/cpu limits, and mount path-traversal validation.
  • Caveat (docs are honest about this — spec troubleshooting says live container enforcement "should be tested separately before a real public run"): the sandbox is currently plan-only. The runner writes sandbox.plan.json and runs adapters directly on the host (container_invocation: "skipped"); and the command-adapter subprocess inherits the full host env — allowed_provider_env_vars is recorded, not enforced as an env allowlist. Both are tracked as follow-ups.

4. Spec/docs accuracy

docs/multiharness-adapter-spec.md and docs/community-submissions.md match the implementation on every point I checked: schema/family names (legalforecast_mtd/harvey_lab/contract_only per spec.py:56-57), the two-phase capabilities/run protocol, argv-only (no shell=True) invocation, supports_sandbox_policy: true conformance requirement, attestation list, grouping key (family, scoring_mode, selection_sha256), and aggregate output layout. No divergences found.

5. Notes for merge

  • The PR description is stale — it still says "Docs only: one new file, no code changes," but the branch now carries the full implementation (~15k added lines across 107 files, including two new workflows). Please update the body before merge so the review record matches the diff.
  • publish-package.yaml is new release infrastructure (PyPI trusted publishing + GitHub release upload) riding in a community-layer PR; the pypi GitHub environment needs protection rules configured before any v* tag, and third-party actions are pinned by major tag, not SHA.
  • Merge-order: feat/official-benchmark-hardening is stacked on afd4a4c (this PR's tip is the merge-base) and already integrates verify_review_blockers into release_check.py — so merging this PR first is clean; verify_review_blockers.py intentionally does not exist on this branch.

Remaining gaps before the first real multi-harness test are collected in a NON-BLOCKING follow-up issue.

@ai-agent-on-behalf-of-john-hughes

Copy link
Copy Markdown
Contributor

Multi-harness layer: architecture summary and merge readiness

This branch now carries the full LegalQuants multi-harness implementation (previously only the plan doc was pushed; the remainder landed today — pushed via the documented break-glass path during the 2026-07-03 Cloudflare Durable Objects incident affecting the secure-gate approval plane).

What's here:

  • Repo-owned adapter protocol (docs/multiharness-adapter-spec.md): canonical schemas, task loaders, and deterministic task selection, so this repo — not any harness's own CLI — owns orchestration.
  • Command adapters + sandbox plans with network disabled by default; provider egress is opt-in and declared per adapter.
  • Conformance checks with first-class tests; all five checked-in fixture adapter tracks pass: LQ.AI, Hermes Agent, OpenClaw, OpenAI Responses, Claude Agent SDK.
  • Harvey LAB bridge for running LAB tasks through the same adapter boundary.
  • Community submission pipeline (community/submissions/): packaging, validation workflow, aggregation, and a separate static community site — with a required not_official_legalforecastbench_result attestation and code-level guardrails keeping community output strictly separate from official LegalForecastBench results.

Merge readiness: an end-to-end review ran against this exact commit (see review comment above): CLI, release-check smokes, adapter conformance, and the official/community boundary all verified — verdict ready-to-merge. Pre-merge housekeeping worth doing: the PR title/description still describe the original docs-only proposal and should be refreshed to reflect the implementation.

Follow-ups before the first real multi-harness test are tracked in #10 (sandbox container execution is currently plan-only, env allowlist enforcement, real adapter/LAB pinning beyond fixtures, PyPI trusted-publisher setup for the bundled publish workflow, branding/mirror decisions). These are explicitly non-blocking for the official API benchmark, which continues in #11 (based on this branch; it will be rebased onto main once this merges).

Comment on lines +114 to +115
"<p>Use the linked run cards and methodology artifacts to inspect the "
"frozen cycle, model registry, scoring configuration, and release bundle.</p>",
@property
def manifest(self) -> AdapterManifest:
"""Public adapter manifest."""
...

def capabilities(self, workspace: Path) -> AdapterCapabilities:
"""Return adapter capabilities, writing private artifacts under workspace."""
...

def prepare(self, request: RunRequest, workspace: Path) -> AdapterPreparation:
"""Validate and prepare a request before execution."""
...

def run(self, request: RunRequest, workspace: Path) -> RunResult:
"""Run one request and return a validated canonical result."""
...
_CLI_PLAN_SCHEMA_VERSION = "legalforecast.multiharness.cli_plan.v1"
_SELECTION_MANIFEST_SCHEMA_VERSION = "legalforecast.multiharness.selection_manifest.v1"
_REPORT_SCHEMA_VERSION = "legalforecast.multiharness.report.v1"
_COMMUNITY_DEFERRED_MESSAGE = (

lab_command: tuple[str, ...]
lab_root: Path | None = None
manifest: AdapterManifest = field(default_factory=lambda: harvey_lab_manifest())
class LfbNativeAdapter:
"""Run LFB packets through the repo's local no-network fixture harness."""

manifest: AdapterManifest = field(default_factory=lambda: lfb_native_manifest())

@cursor cursor 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.

Cursor Bugbot has reviewed your changes and found 2 potential issues.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit afd4a4c. Configure here.

files: |
tmp/release-check/dist/*.whl
tmp/release-check/dist/*.tar.gz
tmp/release-check/dist/package-artifact-hashes.json

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Manual publish creates branch releases

Medium Severity

The publish job runs softprops/action-gh-release whenever the workflow is a tag push or workflow_dispatch has publish enabled, but the job never checks for a version tag. On manual dispatch from a branch, the release step can attach wheels to a GitHub Release for that branch ref instead of a v* tag.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit afd4a4c. Configure here.

"../fixture_bridge.py",
"--profile",
"lq-ai"
],

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Fixture adapter omits Python interpreter

Medium Severity

First-class adapter manifests invoke ../fixture_bridge.py as the executable argv entry, while contributor docs show uv run python for the same bridge. CommandAdapter does not use a shell, so on Windows and on Unix without execute permission the capabilities/run phases can fail before any conformance or community example run.

Additional Locations (2)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit afd4a4c. Configure here.

@coderabbitai coderabbitai 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.

Actionable comments posted: 12

🧹 Nitpick comments (5)
legalforecast/multiharness/task_loaders.py (1)

155-155: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick win

Redundant git rev-parse HEAD subprocess call per task.

load_task_directory calls self._lab_commit() for every task, and load_task_index calls load_task_directory once per task.json file found. For a suite with many tasks this spawns one git subprocess per task to compute the same commit hash for self.lab_root repeatedly, adding unnecessary process-spawn overhead to what should be a constant lookup.

♻️ Cache the lab commit lookup
     def __init__(
         self,
         lab_root: Path,
         *,
         suite_version: str = DEFAULT_LAB_SUITE_VERSION,
     ) -> None:
         if not suite_version.strip():
             raise ValueError("suite_version must be non-empty")
         self.lab_root = lab_root
         self.suite_version = suite_version
+        self._cached_lab_commit: str | None | object = _UNSET

Then in _lab_commit, check self._cached_lab_commit before shelling out, and cache the result (including the "no commit found" case) on first computation, e.g. via functools.cached_property instead of a plain method.

Also applies to: 164-233, 234-244

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@legalforecast/multiharness/task_loaders.py` at line 155, The task loading
path is repeatedly shelling out for the same lab commit hash on every task.
Update the commit lookup used by load_task_directory/load_task_index so
_lab_commit on the task loader caches its result after the first call, including
the “no commit found” case, and reuse that cached value for all task.json files
instead of invoking git rev-parse HEAD each time. Consider using a
cached_property or an equivalent _cached_lab_commit field to keep the lookup
constant-time.
.github/workflows/community-multiharness-validation.yaml (1)

39-40: 🔒 Security & Privacy | 🔵 Trivial | ⚡ Quick win

Harden checkout steps against credential persistence.

Neither actions/checkout@v6 step sets persist-credentials: false, so the GitHub token remains in the local git config for the rest of the job. Low risk here given permissions: contents: read and no broader artifact upload of the checkout dir, but it's cheap to harden per the flagged advisory.

🔒 Proposed fix
       - name: Check out repository
         uses: actions/checkout@v6
+        with:
+          persist-credentials: false

Apply the same change to both checkout steps (Line 40 and Line 121).

Also applies to: 120-121

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/community-multiharness-validation.yaml around lines 39 -
40, The checkout steps using actions/checkout@v6 should be hardened by disabling
credential persistence so the GitHub token is not left in the local git config.
Update both checkout invocations in the workflow to set persist-credentials to
false on the existing checkout step definitions, including the Check out
repository step and the other checkout step mentioned in the review.

Source: Linters/SAST tools

tests/test_community_publication.py (1)

131-146: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Consider asserting the output directory is clean after a guardrail failure.

This test confirms PublicationGuardrailError is raised on a leaked secret, but doesn't verify that tmp_path / "aggregate" contains no residual files (or the secret) afterward. Given build_community_aggregate writes several files before validating (see companion comment in community_aggregate.py), a regression test here would catch future leaks even if the exception is still raised correctly.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@tests/test_community_publication.py` around lines 131 - 146, The guardrail
test for build_community_aggregate only checks that PublicationGuardrailError is
raised, but it should also verify the output_dir stays clean after failure.
Update test_community_aggregate_rejects_public_secret_leak to assert the
aggregate directory has no residual files or leaked secret content after
build_community_aggregate aborts, using the existing tmp_path and
CommunityAggregateConfig setup.
legalforecast/multiharness/community.py (1)

879-884: 📐 Maintainability & Code Quality | 🔵 Trivial

Narrow "private" path blocklist may diverge from actual guardrail enforcement.

_validate_public_artifact_path only rejects path segments literally starting with "private". Test fixtures elsewhere (tests/test_community_submission.py) exercise a PublicationGuardrailError for a path like "source-documents/raw.json", which this local check would not catch — the real rejection apparently comes from validate_public_record/enforce_publication_guardrails elsewhere. Having two divergent path-safety checks (one narrow, local; one presumably broader, external) risks false negatives if only this local check is relied upon in a code path that skips the other.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@legalforecast/multiharness/community.py` around lines 879 - 884, The local
path validation in _validate_public_artifact_path is narrower than the real
publication guardrails and can miss unsafe paths like source-documents/raw.json.
Update this helper so it uses the same path-safety rules as
validate_public_record/enforce_publication_guardrails, or delegate directly to
that shared validation logic, and keep the MultiHarnessValidationError behavior
consistent with the rest of the publication checks.
legalforecast/publication/static_sites.py (1)

375-388: 📐 Maintainability & Code Quality | 🔵 Trivial

_file_sha256/_media_type duplicated across files.

Near-identical implementations exist in legalforecast/multiharness/community.py (Lines 929-947) and examples/adapters/fixture_bridge.py. Consider extracting a shared helper (e.g., in legalforecast._json_io or a new small hashing/media-type module).

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@legalforecast/publication/static_sites.py` around lines 375 - 388, The
_file_sha256 and _media_type helpers are duplicated in static_sites.py and other
modules, so consolidate them into a shared utility instead of keeping
near-identical copies. Move the common logic into a reusable helper module (for
example a small hashing/media-type helper such as legalforecast._json_io or a
new shared module), then update static_sites.py and the matching helpers in
community.py and fixture_bridge to call the shared functions. Keep the existing
behavior and naming at the call sites where possible, but centralize the
implementation to avoid further drift.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.github/workflows/publish-package.yaml:
- Around line 27-30: The checkout step in the release-check job is unnecessarily
persisting git credentials for the rest of the job. Update the actions/checkout
usage in the release-check workflow to set persist-credentials to false so
credentials are not left available while uv run scripts/release_check.py
installs dependencies and runs tests; use the existing Check out repository step
as the place to apply this change.
- Around line 29-32: Update the workflow action pins in publish-package by
bumping actions/checkout from v6 to the current major v7, and
actions/download-artifact from v6 to v8; also change astral-sh/setup-uv from the
moving v7 major pin to a specific immutable v8.x release such as v8.2.0, while
leaving actions/upload-artifact as-is since its current major is already
correct.

In `@legalforecast/multiharness/cli.py`:
- Around line 493-508: _cmd_community_validate_submission writes the plan/result
JSON with a passed status before the real validation happens, so a failing
validation can leave a false success artifact. Update this handler to run
validate_submission_file(submission) before calling write_json_object for the
non-dry-run path, or otherwise only emit passed after validation succeeds; keep
the dry_run branch emitting planned. Use _cmd_community_validate_submission,
validate_submission_file, and write_json_object to locate the change.

In `@legalforecast/multiharness/community.py`:
- Around line 652-703: The _submission_shards grouping currently uses family,
scoring_mode, adapter_id, adapter_version, and model_key, but it later reads
suite_version from shard_rows[0], so mixed suite versions can be merged into one
CommunitySubmissionShard. Update the grouping key in _submission_shards to
include suite_version, or add an explicit validation/assertion before building
the shard that all rows in the group share the same suite_version; use
_request_task_field and the CommunitySubmissionShard construction as the main
places to adjust.

In `@legalforecast/multiharness/harvey_lab_adapter.py`:
- Around line 112-138: prepare() is invoking the LAB CLI help probe twice
through capability checks, causing duplicate subprocess work and extra failure
risk. Reuse the result from self.capabilities(workspace) or have prepare() call
self.command_capabilities(workspace) once and derive both capabilities and
blockers from that single result. Update HarveyLabCliAdapter.prepare so the
command_capabilities() call is not repeated, while preserving the existing
validation and AdapterPreparation return values.

In `@legalforecast/multiharness/reporting.py`:
- Around line 135-147: Escape Markdown cell content before constructing the
report table in the row-building loop so values cannot break pipe-delimited
formatting. Update the table generation in the rows iteration to sanitize the
displayed fields from the row object, especially row_id, model_key, adapter_id,
adapter_version, and conformance_status, so any embedded pipes or newlines are
rendered safely. Keep the fix localized to the reporting table assembly logic in
the rows loop.

In `@legalforecast/multiharness/runner.py`:
- Line 76: `MultiHarnessRunConfig.max_parallelism` is validated and hashed but
never affects execution, so `_MultiHarnessRunner.run()` still processes
`row_plans` one by one. Update the runner to actually honor `max_parallelism` by
dispatching row execution through a bounded concurrent mechanism in
`_MultiHarnessRunner.run()` while keeping `_execute_row()` unchanged, and make
sure the config value controls the degree of parallelism instead of being
metadata only.
- Around line 557-576: The _artifact_index walk is too broad and can include
stale files from prior runs when output_dir is reused with resume=True. Update
_artifact_index to scope enumeration to the current run’s row workspaces derived
from rows/row_plans plus the fixed top-level artifacts written by
_write_run_outputs, instead of using root.rglob("*") over everything under
output_dir. Preserve the existing ArtifactRecord construction and filtering
logic, but only feed it files that belong to the current manifest/run selection.
- Around line 312-336: _execute_row() is writing request.json and
sandbox.plan.json before _resume_result() can validate the workspace, which
allows stale row state to bypass the hash check; move those writes until after
the resume decision or only write them for a fresh run. Also update
_artifact_index() so it only scans the current run’s outputs (or clears old
output artifacts first) to avoid publishing leftovers from prior runs, and make
run() actually honor max_parallelism by executing rows concurrently instead of
always processing them sequentially.

In `@legalforecast/multiharness/sandbox.py`:
- Around line 146-151: The _mount_arg helper builds a --mount string by
interpolating source and target directly, so commas in either value can break
the mount spec. Update _mount_arg to guard against or reject comma-containing
values before returning the bind mount string, and keep the existing readonly
handling intact so the mount argv cannot be silently split into extra fields.

In `@legalforecast/publication/community_aggregate.py`:
- Around line 76-121: build_community_aggregate() currently writes the registry,
reports, public submissions, and site output directly into config.output_dir
before enforce_publication_guardrails() runs, so a failed guardrail check can
leave behind a partially published bundle. Update build_community_aggregate() to
stage all outputs in a temporary working directory first, run
enforce_publication_guardrails() against that staged path, and only then promote
or move the approved bundle into config.output_dir; keep the existing flow
around _write_reports(), render_community_results_site(), and
_write_artifact_manifests() but make them operate on the staged location.

In `@legalforecast/publication/static_sites.py`:
- Around line 92-121: The artifact URLs are being generated from the source
artifact directories, but the site is written to a separate output tree, so the
links can point to paths that are not actually published. Update
render_official_results_site and the shared _artifact_links path-building logic
so hrefs are relative to the generated site location (or copy the referenced
artifacts into the site output before writing HTML), and ensure the links
produced by _link_list still resolve correctly from the published page.

---

Nitpick comments:
In @.github/workflows/community-multiharness-validation.yaml:
- Around line 39-40: The checkout steps using actions/checkout@v6 should be
hardened by disabling credential persistence so the GitHub token is not left in
the local git config. Update both checkout invocations in the workflow to set
persist-credentials to false on the existing checkout step definitions,
including the Check out repository step and the other checkout step mentioned in
the review.

In `@legalforecast/multiharness/community.py`:
- Around line 879-884: The local path validation in
_validate_public_artifact_path is narrower than the real publication guardrails
and can miss unsafe paths like source-documents/raw.json. Update this helper so
it uses the same path-safety rules as
validate_public_record/enforce_publication_guardrails, or delegate directly to
that shared validation logic, and keep the MultiHarnessValidationError behavior
consistent with the rest of the publication checks.

In `@legalforecast/multiharness/task_loaders.py`:
- Line 155: The task loading path is repeatedly shelling out for the same lab
commit hash on every task. Update the commit lookup used by
load_task_directory/load_task_index so _lab_commit on the task loader caches its
result after the first call, including the “no commit found” case, and reuse
that cached value for all task.json files instead of invoking git rev-parse HEAD
each time. Consider using a cached_property or an equivalent _cached_lab_commit
field to keep the lookup constant-time.

In `@legalforecast/publication/static_sites.py`:
- Around line 375-388: The _file_sha256 and _media_type helpers are duplicated
in static_sites.py and other modules, so consolidate them into a shared utility
instead of keeping near-identical copies. Move the common logic into a reusable
helper module (for example a small hashing/media-type helper such as
legalforecast._json_io or a new shared module), then update static_sites.py and
the matching helpers in community.py and fixture_bridge to call the shared
functions. Keep the existing behavior and naming at the call sites where
possible, but centralize the implementation to avoid further drift.

In `@tests/test_community_publication.py`:
- Around line 131-146: The guardrail test for build_community_aggregate only
checks that PublicationGuardrailError is raised, but it should also verify the
output_dir stays clean after failure. Update
test_community_aggregate_rejects_public_secret_leak to assert the aggregate
directory has no residual files or leaked secret content after
build_community_aggregate aborts, using the existing tmp_path and
CommunityAggregateConfig setup.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 8213d126-4fae-43e5-a546-a8d09e8643ce

📥 Commits

Reviewing files that changed from the base of the PR and between fec5be0 and afd4a4c.

📒 Files selected for processing (107)
  • .github/workflows/community-multiharness-validation.yaml
  • .github/workflows/publish-package.yaml
  • MODEL_RELEASE_DATES.md
  • README.md
  • community/submissions/.gitkeep
  • community/submissions/2026/README.md
  • community/submissions/2026/claude-agent-sdk-fixture-baseline/artifact-manifest.json
  • community/submissions/2026/claude-agent-sdk-fixture-baseline/canonical-runs.jsonl
  • community/submissions/2026/claude-agent-sdk-fixture-baseline/conformance-report.json
  • community/submissions/2026/claude-agent-sdk-fixture-baseline/hf-upload-plan.json
  • community/submissions/2026/claude-agent-sdk-fixture-baseline/public-summary.json
  • community/submissions/2026/claude-agent-sdk-fixture-baseline/row-results.jsonl
  • community/submissions/2026/claude-agent-sdk-fixture-baseline/run-manifest.json
  • community/submissions/2026/claude-agent-sdk-fixture-baseline/selection-manifest.json
  • community/submissions/2026/claude-agent-sdk-fixture-baseline/submission.json
  • community/submissions/2026/hermes-agent-fixture-bridge/artifact-manifest.json
  • community/submissions/2026/hermes-agent-fixture-bridge/canonical-runs.jsonl
  • community/submissions/2026/hermes-agent-fixture-bridge/conformance-report.json
  • community/submissions/2026/hermes-agent-fixture-bridge/hf-upload-plan.json
  • community/submissions/2026/hermes-agent-fixture-bridge/public-summary.json
  • community/submissions/2026/hermes-agent-fixture-bridge/row-results.jsonl
  • community/submissions/2026/hermes-agent-fixture-bridge/run-manifest.json
  • community/submissions/2026/hermes-agent-fixture-bridge/selection-manifest.json
  • community/submissions/2026/hermes-agent-fixture-bridge/submission.json
  • community/submissions/2026/lq-ai-fixture-bridge/artifact-manifest.json
  • community/submissions/2026/lq-ai-fixture-bridge/canonical-runs.jsonl
  • community/submissions/2026/lq-ai-fixture-bridge/conformance-report.json
  • community/submissions/2026/lq-ai-fixture-bridge/hf-upload-plan.json
  • community/submissions/2026/lq-ai-fixture-bridge/public-summary.json
  • community/submissions/2026/lq-ai-fixture-bridge/row-results.jsonl
  • community/submissions/2026/lq-ai-fixture-bridge/run-manifest.json
  • community/submissions/2026/lq-ai-fixture-bridge/selection-manifest.json
  • community/submissions/2026/lq-ai-fixture-bridge/submission.json
  • community/submissions/2026/openai-responses-fixture-baseline/artifact-manifest.json
  • community/submissions/2026/openai-responses-fixture-baseline/canonical-runs.jsonl
  • community/submissions/2026/openai-responses-fixture-baseline/conformance-report.json
  • community/submissions/2026/openai-responses-fixture-baseline/hf-upload-plan.json
  • community/submissions/2026/openai-responses-fixture-baseline/public-summary.json
  • community/submissions/2026/openai-responses-fixture-baseline/row-results.jsonl
  • community/submissions/2026/openai-responses-fixture-baseline/run-manifest.json
  • community/submissions/2026/openai-responses-fixture-baseline/selection-manifest.json
  • community/submissions/2026/openai-responses-fixture-baseline/submission.json
  • community/submissions/2026/openclaw-fixture-bridge/artifact-manifest.json
  • community/submissions/2026/openclaw-fixture-bridge/canonical-runs.jsonl
  • community/submissions/2026/openclaw-fixture-bridge/conformance-report.json
  • community/submissions/2026/openclaw-fixture-bridge/hf-upload-plan.json
  • community/submissions/2026/openclaw-fixture-bridge/public-summary.json
  • community/submissions/2026/openclaw-fixture-bridge/row-results.jsonl
  • community/submissions/2026/openclaw-fixture-bridge/run-manifest.json
  • community/submissions/2026/openclaw-fixture-bridge/selection-manifest.json
  • community/submissions/2026/openclaw-fixture-bridge/submission.json
  • docs/adapters/hermes-agent.md
  • docs/adapters/lq-ai.md
  • docs/adapters/openclaw.md
  • docs/adapters/provider-baselines.md
  • docs/community-submissions.md
  • docs/multiharness-adapter-spec.md
  • docs/plans/multi-harness-community-benchmark-2026-05-29.md
  • examples/adapters/claude-agent-sdk/adapter-manifest.json
  • examples/adapters/fixture_bridge.py
  • examples/adapters/hermes-agent/adapter-manifest.json
  • examples/adapters/lq-ai/adapter-manifest.json
  • examples/adapters/openai-responses/adapter-manifest.json
  • examples/adapters/openclaw/adapter-manifest.json
  • legalforecast/cli.py
  • legalforecast/multiharness/__init__.py
  • legalforecast/multiharness/adapters.py
  • legalforecast/multiharness/artifacts.py
  • legalforecast/multiharness/cli.py
  • legalforecast/multiharness/command_adapter.py
  • legalforecast/multiharness/community.py
  • legalforecast/multiharness/conformance.py
  • legalforecast/multiharness/harvey_lab_adapter.py
  • legalforecast/multiharness/lfb_native.py
  • legalforecast/multiharness/reporting.py
  • legalforecast/multiharness/runner.py
  • legalforecast/multiharness/sandbox.py
  • legalforecast/multiharness/selection.py
  • legalforecast/multiharness/spec.py
  • legalforecast/multiharness/task_loaders.py
  • legalforecast/multiharness/validation.py
  • legalforecast/publication/__init__.py
  • legalforecast/publication/community_aggregate.py
  • legalforecast/publication/release_bundle.py
  • legalforecast/publication/static_sites.py
  • legalforecast/reporting/pilot_readiness.py
  • scripts/AGENTS.md
  • scripts/release_check.py
  • tests/test_community_examples.py
  • tests/test_community_multiharness_workflow.py
  • tests/test_community_publication.py
  • tests/test_community_submission.py
  • tests/test_multiharness_cli.py
  • tests/test_multiharness_command_adapter.py
  • tests/test_multiharness_conformance.py
  • tests/test_multiharness_external_adapters.py
  • tests/test_multiharness_harvey_lab_adapter.py
  • tests/test_multiharness_lfb_native.py
  • tests/test_multiharness_runner.py
  • tests/test_multiharness_sandbox.py
  • tests/test_multiharness_selection.py
  • tests/test_multiharness_spec.py
  • tests/test_multiharness_task_loaders.py
  • tests/test_publish_package_workflow.py
  • tests/test_release_bundle.py
  • tests/test_release_check.py
  • tests/test_static_result_sites.py
✅ Files skipped from review due to trivial changes (47)
  • examples/adapters/openai-responses/adapter-manifest.json
  • examples/adapters/claude-agent-sdk/adapter-manifest.json
  • examples/adapters/openclaw/adapter-manifest.json
  • community/submissions/2026/claude-agent-sdk-fixture-baseline/public-summary.json
  • community/submissions/2026/hermes-agent-fixture-bridge/run-manifest.json
  • community/submissions/2026/openai-responses-fixture-baseline/selection-manifest.json
  • community/submissions/2026/hermes-agent-fixture-bridge/hf-upload-plan.json
  • community/submissions/2026/claude-agent-sdk-fixture-baseline/selection-manifest.json
  • community/submissions/2026/openclaw-fixture-bridge/run-manifest.json
  • community/submissions/2026/README.md
  • community/submissions/2026/lq-ai-fixture-bridge/selection-manifest.json
  • community/submissions/2026/openclaw-fixture-bridge/selection-manifest.json
  • community/submissions/2026/openclaw-fixture-bridge/public-summary.json
  • community/submissions/2026/openai-responses-fixture-baseline/artifact-manifest.json
  • examples/adapters/lq-ai/adapter-manifest.json
  • community/submissions/2026/hermes-agent-fixture-bridge/public-summary.json
  • community/submissions/2026/openclaw-fixture-bridge/row-results.jsonl
  • community/submissions/.gitkeep
  • community/submissions/2026/hermes-agent-fixture-bridge/selection-manifest.json
  • community/submissions/2026/hermes-agent-fixture-bridge/conformance-report.json
  • community/submissions/2026/hermes-agent-fixture-bridge/canonical-runs.jsonl
  • community/submissions/2026/lq-ai-fixture-bridge/run-manifest.json
  • community/submissions/2026/lq-ai-fixture-bridge/row-results.jsonl
  • community/submissions/2026/claude-agent-sdk-fixture-baseline/conformance-report.json
  • community/submissions/2026/openai-responses-fixture-baseline/row-results.jsonl
  • legalforecast/reporting/pilot_readiness.py
  • docs/adapters/openclaw.md
  • community/submissions/2026/claude-agent-sdk-fixture-baseline/hf-upload-plan.json
  • community/submissions/2026/openai-responses-fixture-baseline/public-summary.json
  • community/submissions/2026/claude-agent-sdk-fixture-baseline/run-manifest.json
  • scripts/AGENTS.md
  • community/submissions/2026/lq-ai-fixture-bridge/canonical-runs.jsonl
  • docs/adapters/lq-ai.md
  • community/submissions/2026/lq-ai-fixture-bridge/conformance-report.json
  • community/submissions/2026/hermes-agent-fixture-bridge/submission.json
  • docs/adapters/provider-baselines.md
  • legalforecast/publication/init.py
  • docs/adapters/hermes-agent.md
  • community/submissions/2026/openai-responses-fixture-baseline/conformance-report.json
  • examples/adapters/hermes-agent/adapter-manifest.json
  • community/submissions/2026/lq-ai-fixture-bridge/public-summary.json
  • community/submissions/2026/lq-ai-fixture-bridge/submission.json
  • community/submissions/2026/openclaw-fixture-bridge/conformance-report.json
  • README.md
  • docs/multiharness-adapter-spec.md
  • community/submissions/2026/openclaw-fixture-bridge/artifact-manifest.json
  • docs/plans/multi-harness-community-benchmark-2026-05-29.md

Comment on lines +27 to +30
steps:
- name: Check out repository
uses: actions/checkout@v6

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔒 Security & Privacy | 🟡 Minor | ⚡ Quick win

Persist git credentials disabled for release-check checkout.

release-check never pushes to the repo (job permission is contents: read), yet the checkout step keeps credentials persisted for the whole job while uv run scripts/release_check.py executes dependency installs/tests. Set persist-credentials: false to reduce the blast radius if that step is ever compromised.

🔒 Proposed fix
       - name: Check out repository
         uses: actions/checkout@v6
+        with:
+          persist-credentials: false
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
steps:
- name: Check out repository
uses: actions/checkout@v6
steps:
- name: Check out repository
uses: actions/checkout@v6
with:
persist-credentials: false
🧰 Tools
🪛 zizmor (1.26.1)

[warning] 28-29: credential persistence through GitHub Actions artifacts (artipacked): does not set persist-credentials: false

(artipacked)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/publish-package.yaml around lines 27 - 30, The checkout
step in the release-check job is unnecessarily persisting git credentials for
the rest of the job. Update the actions/checkout usage in the release-check
workflow to set persist-credentials to false so credentials are not left
available while uv run scripts/release_check.py installs dependencies and runs
tests; use the existing Check out repository step as the place to apply this
change.

Source: Linters/SAST tools

Comment on lines +29 to +32
uses: actions/checkout@v6

- name: Install uv
uses: astral-sh/setup-uv@v7

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔒 Security & Privacy | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🌐 Web query:

What is the latest version of astral-sh/setup-uv GitHub Action?

💡 Result:

The latest version of the astral-sh/setup-uv GitHub Action is v8.2.0, released on June 3, 2026 [1][2]. It is recommended to use the immutable tag (e.g., astral-sh/setup-uv@v8.2.0) or the specific git hash when referencing the action in your workflows to enhance security [3]. By default, if no version is specified in the action configuration, the action will attempt to detect the required uv version from configuration files (such as uv.toml or pyproject.toml) or install the latest available version [1].

Citations:


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Show the workflow file around the referenced lines.
nl -ba .github/workflows/publish-package.yaml | sed -n '1,120p'

Repository: johnhughes3/LegalForecastBench

Length of output: 208


🌐 Web query:

What is the latest maintained major version of actions/checkout GitHub Action as of July 2026?

💡 Result:

As of July 3, 2026, the latest major version of the actions/checkout GitHub Action is v7 [1][2]. It was released on June 18, 2026 [1][3].

Citations:


🌐 Web query:

What are the latest maintained major versions of actions/upload-artifact and actions/download-artifact GitHub Actions as of July 2026?

💡 Result:

As of July 3, 2026, the latest major versions of the official GitHub Actions for artifacts are as follows: - actions/upload-artifact: v7 [1][2] - actions/download-artifact: v8 [3] For actions/upload-artifact, the latest stable release is v7.0.1, released on April 10, 2026 [4][1]. For actions/download-artifact, the latest stable release is v8.0.1, released on March 11, 2026 [3]. These versions run on Node.js 24 and require a minimum Actions Runner version of 2.327.1 [3][5]. Users of self-hosted runners are advised to ensure their runners are updated before upgrading to these versions [3][5].

Citations:


🌐 Web query:

What is the latest maintained major version of astral-sh/setup-uv GitHub Action as of July 2026?

💡 Result:

As of July 3, 2026, the latest maintained major version of the astral-sh/setup-uv GitHub Action is v8 [1][2]. The latest specific release within this major version is v8.2.0, which was published on June 3, 2026 [1][2]. Note that starting with v8.0.0, released in March 2026, the project shifted to an immutable release model [3][4]. As a security measure to protect against supply chain attacks, the maintainers stopped publishing and supporting minor or major moving tags (such as @v8) [4]. Consequently, users are advised to pin their workflows to specific immutable versions (e.g., @v8.2.0) or full commit SHA hashes [1][4].

Citations:


🏁 Script executed:

#!/bin/bash
set -euo pipefail

sed -n '1,120p' .github/workflows/publish-package.yaml | cat -n

Repository: johnhughes3/LegalForecastBench

Length of output: 2685


🏁 Script executed:

#!/bin/bash
set -euo pipefail

python3 - <<'PY'
from pathlib import Path
p = Path('.github/workflows/publish-package.yaml')
for i, line in enumerate(p.read_text().splitlines(), 1):
    if 1 <= i <= 120:
        print(f"{i:4d} {line}")
PY

Repository: johnhughes3/LegalForecastBench

Length of output: 2527


🏁 Script executed:

#!/bin/bash
set -euo pipefail

awk 'NR>=1 && NR<=120 { printf "%4d %s\n", NR, $0 }' .github/workflows/publish-package.yaml

Repository: johnhughes3/LegalForecastBench

Length of output: 2527


Update the workflow action pins. .github/workflows/publish-package.yaml:29-32,60-61

  • actions/checkout@v6 is behind the current major (v7).
  • actions/download-artifact@v6 is behind the current major (v8).
  • astral-sh/setup-uv@v7 should move to a specific immutable v8.x release (for example v8.2.0); actions/upload-artifact@v7 already matches the current major.
🧰 Tools
🪛 zizmor (1.26.1)

[error] 32-32: runtime artifacts potentially vulnerable to a cache poisoning attack (cache-poisoning): this step

(cache-poisoning)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/publish-package.yaml around lines 29 - 32, Update the
workflow action pins in publish-package by bumping actions/checkout from v6 to
the current major v7, and actions/download-artifact from v6 to v8; also change
astral-sh/setup-uv from the moving v7 major pin to a specific immutable v8.x
release such as v8.2.0, while leaving actions/upload-artifact as-is since its
current major is already correct.

Comment on lines +493 to +508
def _cmd_community_validate_submission(args: argparse.Namespace) -> int:
submission = cast(Path, args.submission)
write_json_object(
cast(Path, args.output),
{
"schema_version": _CLI_PLAN_SCHEMA_VERSION,
"command": "community validate-submission",
"dry_run": cast(bool, args.dry_run),
"submission": submission.as_posix(),
"status": "planned" if cast(bool, args.dry_run) else "passed",
"checks": _community_validation_checks(),
},
)
if not cast(bool, args.dry_run):
validate_submission_file(submission)
return 0

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Output written with "status": "passed" before validation actually runs.

In the non-dry-run branch, the plan/result JSON is written first with "status": "passed", and validate_submission_file(submission) is only called afterward. If validation raises, the artifact on disk still falsely claims "passed", even though the process will exit with an error. This is inconsistent with every other handler in this file (_cmd_adapters_inspect, _cmd_conformance, _cmd_run, _cmd_community_package), which all perform the real work before or in place of writing a success status.

🐛 Proposed fix: validate before writing status
 def _cmd_community_validate_submission(args: argparse.Namespace) -> int:
     submission = cast(Path, args.submission)
-    write_json_object(
-        cast(Path, args.output),
-        {
-            "schema_version": _CLI_PLAN_SCHEMA_VERSION,
-            "command": "community validate-submission",
-            "dry_run": cast(bool, args.dry_run),
-            "submission": submission.as_posix(),
-            "status": "planned" if cast(bool, args.dry_run) else "passed",
-            "checks": _community_validation_checks(),
-        },
-    )
-    if not cast(bool, args.dry_run):
-        validate_submission_file(submission)
+    dry_run = cast(bool, args.dry_run)
+    status = "planned"
+    if not dry_run:
+        validate_submission_file(submission)
+        status = "passed"
+    write_json_object(
+        cast(Path, args.output),
+        {
+            "schema_version": _CLI_PLAN_SCHEMA_VERSION,
+            "command": "community validate-submission",
+            "dry_run": dry_run,
+            "submission": submission.as_posix(),
+            "status": status,
+            "checks": _community_validation_checks(),
+        },
+    )
     return 0
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
def _cmd_community_validate_submission(args: argparse.Namespace) -> int:
submission = cast(Path, args.submission)
write_json_object(
cast(Path, args.output),
{
"schema_version": _CLI_PLAN_SCHEMA_VERSION,
"command": "community validate-submission",
"dry_run": cast(bool, args.dry_run),
"submission": submission.as_posix(),
"status": "planned" if cast(bool, args.dry_run) else "passed",
"checks": _community_validation_checks(),
},
)
if not cast(bool, args.dry_run):
validate_submission_file(submission)
return 0
def _cmd_community_validate_submission(args: argparse.Namespace) -> int:
submission = cast(Path, args.submission)
dry_run = cast(bool, args.dry_run)
status = "planned"
if not dry_run:
validate_submission_file(submission)
status = "passed"
write_json_object(
cast(Path, args.output),
{
"schema_version": _CLI_PLAN_SCHEMA_VERSION,
"command": "community validate-submission",
"dry_run": dry_run,
"submission": submission.as_posix(),
"status": status,
"checks": _community_validation_checks(),
},
)
return 0
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@legalforecast/multiharness/cli.py` around lines 493 - 508,
_cmd_community_validate_submission writes the plan/result JSON with a passed
status before the real validation happens, so a failing validation can leave a
false success artifact. Update this handler to run
validate_submission_file(submission) before calling write_json_object for the
non-dry-run path, or otherwise only emit passed after validation succeeds; keep
the dry_run branch emitting planned. Use _cmd_community_validate_submission,
validate_submission_file, and write_json_object to locate the change.

Comment thread legalforecast/multiharness/community.py
Comment on lines +112 to +138
def prepare(self, request: RunRequest, workspace: Path) -> AdapterPreparation:
capabilities = self.capabilities(workspace)
if request.adapter.adapter_id != self.manifest.adapter_id:
raise HarveyLabCliAdapterError(
"run request adapter ID does not match manifest"
)
if request.adapter.adapter_version != self.manifest.adapter_version:
raise HarveyLabCliAdapterError(
"run request adapter version does not match manifest"
)
if request.task.family != "harvey_lab":
raise HarveyLabCliAdapterError(
"Harvey LAB adapter requires harvey_lab task"
)
if request.task.scoring_mode != "lab_native":
raise HarveyLabCliAdapterError(
"Harvey LAB adapter requires lab_native mode"
)
command_capabilities = self.command_capabilities(workspace)
if command_capabilities.blockers:
formatted = "; ".join(command_capabilities.blockers)
raise HarveyLabCliAdapterError(formatted)
return AdapterPreparation(
manifest=self.manifest,
capabilities=capabilities,
workspace=workspace,
)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🚀 Performance & Scalability | 🟠 Major | ⚡ Quick win

prepare() runs the LAB CLI --help probe twice.

self.capabilities(workspace) (line 113) internally calls self.command_capabilities(workspace), which invokes the external LAB command with --help. prepare() then calls self.command_capabilities(workspace) again directly (line 130) to inspect blockers, triggering a second subprocess invocation of the same probe for every single run(). This doubles external-process latency and risk of subprocess failures/timeouts on a path that already has a timeout budget.

♻️ Proposed fix to avoid duplicate probing
     def prepare(self, request: RunRequest, workspace: Path) -> AdapterPreparation:
-        capabilities = self.capabilities(workspace)
+        command_capabilities = self.command_capabilities(workspace)
+        capabilities = AdapterCapabilities(
+            adapter_id=self.manifest.adapter_id,
+            adapter_version=self.manifest.adapter_version,
+            supported_families=("harvey_lab",),
+            supported_scoring_modes=("lab_native",),
+            supports_sandbox_policy=True,
+            capabilities_sha256=_record_sha256(command_capabilities.to_record()),
+        )
+        write_json_object(
+            workspace / "lab-command-capabilities.json",
+            command_capabilities.to_record(),
+        )
         if request.adapter.adapter_id != self.manifest.adapter_id:
             raise HarveyLabCliAdapterError(
                 "run request adapter ID does not match manifest"
             )
         if request.adapter.adapter_version != self.manifest.adapter_version:
             raise HarveyLabCliAdapterError(
                 "run request adapter version does not match manifest"
             )
         if request.task.family != "harvey_lab":
             raise HarveyLabCliAdapterError(
                 "Harvey LAB adapter requires harvey_lab task"
             )
         if request.task.scoring_mode != "lab_native":
             raise HarveyLabCliAdapterError(
                 "Harvey LAB adapter requires lab_native mode"
             )
-        command_capabilities = self.command_capabilities(workspace)
         if command_capabilities.blockers:
             formatted = "; ".join(command_capabilities.blockers)
             raise HarveyLabCliAdapterError(formatted)
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
def prepare(self, request: RunRequest, workspace: Path) -> AdapterPreparation:
capabilities = self.capabilities(workspace)
if request.adapter.adapter_id != self.manifest.adapter_id:
raise HarveyLabCliAdapterError(
"run request adapter ID does not match manifest"
)
if request.adapter.adapter_version != self.manifest.adapter_version:
raise HarveyLabCliAdapterError(
"run request adapter version does not match manifest"
)
if request.task.family != "harvey_lab":
raise HarveyLabCliAdapterError(
"Harvey LAB adapter requires harvey_lab task"
)
if request.task.scoring_mode != "lab_native":
raise HarveyLabCliAdapterError(
"Harvey LAB adapter requires lab_native mode"
)
command_capabilities = self.command_capabilities(workspace)
if command_capabilities.blockers:
formatted = "; ".join(command_capabilities.blockers)
raise HarveyLabCliAdapterError(formatted)
return AdapterPreparation(
manifest=self.manifest,
capabilities=capabilities,
workspace=workspace,
)
def prepare(self, request: RunRequest, workspace: Path) -> AdapterPreparation:
command_capabilities = self.command_capabilities(workspace)
capabilities = AdapterCapabilities(
adapter_id=self.manifest.adapter_id,
adapter_version=self.manifest.adapter_version,
supported_families=("harvey_lab",),
supported_scoring_modes=("lab_native",),
supports_sandbox_policy=True,
capabilities_sha256=_record_sha256(command_capabilities.to_record()),
)
write_json_object(
workspace / "lab-command-capabilities.json",
command_capabilities.to_record(),
)
if request.adapter.adapter_id != self.manifest.adapter_id:
raise HarveyLabCliAdapterError(
"run request adapter ID does not match manifest"
)
if request.adapter.adapter_version != self.manifest.adapter_version:
raise HarveyLabCliAdapterError(
"run request adapter version does not match manifest"
)
if request.task.family != "harvey_lab":
raise HarveyLabCliAdapterError(
"Harvey LAB adapter requires harvey_lab task"
)
if request.task.scoring_mode != "lab_native":
raise HarveyLabCliAdapterError(
"Harvey LAB adapter requires lab_native mode"
)
if command_capabilities.blockers:
formatted = "; ".join(command_capabilities.blockers)
raise HarveyLabCliAdapterError(formatted)
return AdapterPreparation(
manifest=self.manifest,
capabilities=capabilities,
workspace=workspace,
)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@legalforecast/multiharness/harvey_lab_adapter.py` around lines 112 - 138,
prepare() is invoking the LAB CLI help probe twice through capability checks,
causing duplicate subprocess work and extra failure risk. Reuse the result from
self.capabilities(workspace) or have prepare() call
self.command_capabilities(workspace) once and derive both capabilities and
blockers from that single result. Update HarveyLabCliAdapter.prepare so the
command_capabilities() call is not repeated, while preserving the existing
validation and AdapterPreparation return values.

Comment on lines +312 to +336
def _execute_row(self, plan: _RowPlan) -> MultiHarnessRunRow:
plan.workspace.mkdir(parents=True, exist_ok=True)
private_logs = plan.workspace / "private-logs"
private_logs.mkdir(parents=True, exist_ok=True)
write_json_object(plan.workspace / "request.json", plan.request.to_record())
write_json_object(
plan.workspace / "sandbox.plan.json",
build_container_plan(plan.request.sandbox_policy).to_record(),
)

resumed = False
lfb_record: Mapping[str, Any] | None = None
try:
resumed_result = self._resume_result(plan)
if resumed_result is not None:
result, lfb_record = resumed_result
resumed = True
else:
result, lfb_record = self._run_adapter(plan)
except Exception as exc:
if self.config.incomplete_run_policy == "fail_fast":
raise
(private_logs / "error.txt").write_text(_plain_error(exc), encoding="utf-8")
result = _failure_result(plan, exc)
write_json_object(plan.workspace / "result.json", result.to_record())

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

git ls-files legalforecast/multiharness/runner.py tests/test_multiharness_runner.py

Repository: johnhughes3/LegalForecastBench

Length of output: 239


🏁 Script executed:

sed -n '1,260p' legalforecast/multiharness/runner.py
printf '\n====\n'
sed -n '260,420p' legalforecast/multiharness/runner.py
printf '\n====\n'
sed -n '420,620p' legalforecast/multiharness/runner.py
printf '\n====\n'
sed -n '1,260p' tests/test_multiharness_runner.py
printf '\n====\n'
sed -n '260,520p' tests/test_multiharness_runner.py

Repository: johnhughes3/LegalForecastBench

Length of output: 36186


🏁 Script executed:

rg -n "max_parallelism" legalforecast/multiharness/runner.py tests/test_multiharness_runner.py

Repository: johnhughes3/LegalForecastBench

Length of output: 514


Don’t reuse stale row state or stale artifacts.

  • _execute_row() writes request.json before _resume_result() reads it back, so the hash check can no longer catch a mismatched workspace; move those writes behind the resume decision.
  • _artifact_index() walks the whole output_dir, so leftovers from prior runs can be published in the current artifact-index.json; scope it to the current run outputs or clear the directory first.
  • max_parallelism is validated and serialized, but run() still processes rows sequentially, so that setting has no effect.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@legalforecast/multiharness/runner.py` around lines 312 - 336, _execute_row()
is writing request.json and sandbox.plan.json before _resume_result() can
validate the workspace, which allows stale row state to bypass the hash check;
move those writes until after the resume decision or only write them for a fresh
run. Also update _artifact_index() so it only scans the current run’s outputs
(or clears old output artifacts first) to avoid publishing leftovers from prior
runs, and make run() actually honor max_parallelism by executing rows
concurrently instead of always processing them sequentially.

Comment on lines +557 to +576
def _artifact_index(root: Path) -> list[dict[str, Any]]:
artifacts: list[dict[str, Any]] = []
for path in sorted(item for item in root.rglob("*") if item.is_file()):
if path.name == "artifact-index.json":
continue
relative = path.relative_to(root).as_posix()
artifacts.append(
ArtifactRecord(
artifact_id=_artifact_id(relative),
path=relative,
sha256=_file_sha256(path),
media_type=_media_type(path),
public=(
not relative.startswith("rows/") or "/private-logs/" not in relative
),
size_bytes=path.stat().st_size,
).to_record()
)
return artifacts

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Artifact index is an unscoped directory walk; stale files from prior incompatible runs can leak into a resumed run's published index.

_artifact_index walks every file under output_dir via root.rglob("*") with no filtering by the current run's row_plans/manifest. If output_dir is reused across runs with resume=True but a different task selection (e.g., different --limit/families), leftover row directories and artifacts from the earlier, no-longer-selected tasks remain on disk and get included in the new artifact-index.json as if they belonged to the current run — undermining the accuracy of what's published for that run.

Consider scoping the walk to the current row workspaces plus known top-level output files (derived from rows/row_plans and the fixed artifact names written by _write_run_outputs), rather than every file under output_dir.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@legalforecast/multiharness/runner.py` around lines 557 - 576, The
_artifact_index walk is too broad and can include stale files from prior runs
when output_dir is reused with resume=True. Update _artifact_index to scope
enumeration to the current run’s row workspaces derived from rows/row_plans plus
the fixed top-level artifacts written by _write_run_outputs, instead of using
root.rglob("*") over everything under output_dir. Preserve the existing
ArtifactRecord construction and filtering logic, but only feed it files that
belong to the current manifest/run selection.

Comment on lines +146 to +151
def _mount_arg(record: Mapping[str, str]) -> str:
source = record["source"]
target = record["target"]
mode = record["mode"]
readonly = ",readonly" if mode == "ro" else ""
return f"type=bind,src={source},dst={target}{readonly}"

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔒 Security & Privacy | 🟡 Minor | ⚡ Quick win

Unescaped commas in --mount value can corrupt the mount spec.

_mount_arg builds type=bind,src=...,dst=... by naive string interpolation. Docker/Podman treat , as the field separator for --mount; if source or target ever contains a comma, the resulting argv entry silently splits into unintended extra fields (potentially exposing/mounting an unintended path) instead of failing loudly.

🔧 Proposed guard
 def _mount_arg(record: Mapping[str, str]) -> str:
     source = record["source"]
     target = record["target"]
     mode = record["mode"]
+    if "," in source or "," in target:
+        raise ValueError("mount source/target must not contain ','")
     readonly = ",readonly" if mode == "ro" else ""
     return f"type=bind,src={source},dst={target}{readonly}"
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
def _mount_arg(record: Mapping[str, str]) -> str:
source = record["source"]
target = record["target"]
mode = record["mode"]
readonly = ",readonly" if mode == "ro" else ""
return f"type=bind,src={source},dst={target}{readonly}"
def _mount_arg(record: Mapping[str, str]) -> str:
source = record["source"]
target = record["target"]
mode = record["mode"]
if "," in source or "," in target:
raise ValueError("mount source/target must not contain ','")
readonly = ",readonly" if mode == "ro" else ""
return f"type=bind,src={source},dst={target}{readonly}"
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@legalforecast/multiharness/sandbox.py` around lines 146 - 151, The _mount_arg
helper builds a --mount string by interpolating source and target directly, so
commas in either value can break the mount spec. Update _mount_arg to guard
against or reject comma-containing values before returning the bind mount
string, and keep the existing readonly handling intact so the mount argv cannot
be silently split into extra fields.

Comment on lines +76 to +121
def build_community_aggregate(
config: CommunityAggregateConfig,
) -> CommunityAggregateResult:
"""Build the reviewed community registry and static comparison reports."""

submissions = _load_submission_inputs(config.submissions_dir)
config.output_dir.mkdir(parents=True, exist_ok=True)
registry_dir = config.output_dir / "registry"
reports_dir = config.output_dir / "reports"
public_submissions_dir = config.output_dir / "submissions"
registry_dir.mkdir(parents=True, exist_ok=True)
reports_dir.mkdir(parents=True, exist_ok=True)
public_submissions_dir.mkdir(parents=True, exist_ok=True)

group_task_ids = _group_task_ids(submissions)
rows = _comparison_rows(submissions, group_task_ids)
registry_records = [_normalized_submission_record(item) for item in submissions]
coverage_records = _coverage_records(rows)
contributors = _contributor_index(submissions)
adapter_model_index = _adapter_model_index(rows)
shard_groups = _compatible_shard_groups(submissions, rows)

write_jsonl_objects(registry_dir / "submissions.jsonl", registry_records)
write_jsonl_objects(registry_dir / "task-coverage.jsonl", coverage_records)
write_json_object(registry_dir / "contributors.json", contributors)
write_json_object(registry_dir / "adapters-models.json", adapter_model_index)
write_json_object(registry_dir / "compatible-shard-groups.json", shard_groups)
write_json_object(
registry_dir / "site-summary.json",
_site_summary(submissions, rows, shard_groups),
)
for item in submissions:
write_json_object(
public_submissions_dir / f"{item.manifest.submission_id}.json",
_normalized_submission_record(item),
)

_write_reports(reports_dir, rows)
render_community_results_site(
community_aggregate_dir=config.output_dir,
output_dir=config.output_dir / "site",
)
enforce_publication_guardrails(
PublicationGuardrailConfig(public_paths=(config.output_dir,))
)
_write_artifact_manifests(config.output_dir)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔒 Security & Privacy | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '\n== community_aggregate.py ==\n'
sed -n '1,220p' legalforecast/publication/community_aggregate.py

printf '\n== guardrails implementation ==\n'
rg -n "def enforce_publication_guardrails|class PublicationGuardrailConfig|PublicationGuardrailConfig" legalforecast -S

printf '\n== guardrail/tests references ==\n'
rg -n "test_community_aggregate_rejects_public_secret_leak|enforce_publication_guardrails|community_aggregate" tests legalforecast -S

Repository: johnhughes3/LegalForecastBench

Length of output: 15139


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '\n== publication_guardrails.py (relevant parts) ==\n'
sed -n '1,260p' legalforecast/publication/publication_guardrails.py

printf '\n== test_community_publication.py ==\n'
sed -n '1,240p' tests/test_community_publication.py

printf '\n== community multiharness workflow references ==\n'
rg -n "upload|artifact|output_dir|if: always|community-aggregate|publication" .github tests legalforecast/multiharness/cli.py -S

Repository: johnhughes3/LegalForecastBench

Length of output: 50386


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '\n== community aggregate CLI ==\n'
sed -n '500,540p' legalforecast/multiharness/cli.py

printf '\n== workflow references (community aggregate) ==\n'
rg -n "community-aggregate|community aggregate|output-dir|upload-artifact|if: always|always\(" .github/workflows tests -S

printf '\n== static_sites guardrail ordering ==\n'
sed -n '150,210p' legalforecast/publication/static_sites.py

Repository: johnhughes3/LegalForecastBench

Length of output: 8783


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '\n== community-multiharness-validation workflow excerpt ==\n'
sed -n '96,150p' .github/workflows/community-multiharness-validation.yaml

printf '\n== other community aggregate call sites ==\n'
rg -n "build_community_aggregate\(|community aggregate" legalforecast tests .github/workflows -S

Repository: johnhughes3/LegalForecastBench

Length of output: 3196


Stage community aggregate output before guardrails

build_community_aggregate() writes public registry/report/site files into config.output_dir before calling enforce_publication_guardrails(). If the guardrail check fails, the directory is left populated with the tainted bundle; writing to a temp dir and promoting it only after the scan would make the failure path safer.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@legalforecast/publication/community_aggregate.py` around lines 76 - 121,
build_community_aggregate() currently writes the registry, reports, public
submissions, and site output directly into config.output_dir before
enforce_publication_guardrails() runs, so a failed guardrail check can leave
behind a partially published bundle. Update build_community_aggregate() to stage
all outputs in a temporary working directory first, run
enforce_publication_guardrails() against that staged path, and only then promote
or move the approved bundle into config.output_dir; keep the existing flow
around _write_reports(), render_community_results_site(), and
_write_artifact_manifests() but make them operate on the staged location.

Comment on lines +92 to +121
def render_official_results_site(
*,
official_artifacts_dir: Path,
output_dir: Path,
) -> StaticSiteResult:
"""Render an official-only static site from official aggregate artifacts."""

output_dir.mkdir(parents=True, exist_ok=True)
rows = _official_rows(official_artifacts_dir)
artifact_links = _artifact_links(official_artifacts_dir)
body = [
"<main>",
"<h1>LegalForecastBench Official Results</h1>",
(
"<p class='lede'>Official benchmark results are produced only by the "
"protected LegalForecastBench evaluation workflow and official "
"aggregation artifacts.</p>"
),
"<section><h2>Score Table</h2>",
_official_table(rows),
"</section>",
"<section><h2>Methodology and Run Cards</h2>",
"<p>Use the linked run cards and methodology artifacts to inspect the "
"frozen cycle, model registry, scoring configuration, and release bundle.</p>",
_link_list(artifact_links),
"</section>",
"</main>",
]
_write_site(output_dir, "\n".join(body), OFFICIAL_RESULTS_SITE_SCHEMA_VERSION)
return _site_result(output_dir)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Check whether cli.py / release_bundle.py colocate source artifacts and site output_dir
rg -n 'render_official_results_site|render_community_results_site' --type=py -C5

Repository: johnhughes3/LegalForecastBench

Length of output: 168


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '\n== files ==\n'
git ls-files 'legalforecast/publication/*' 'legalforecast/*' | sed -n '1,200p'

printf '\n== static_sites outline ==\n'
ast-grep outline legalforecast/publication/static_sites.py --view expanded || true

printf '\n== renderer and link helpers ==\n'
python3 - <<'PY'
from pathlib import Path
p = Path("legalforecast/publication/static_sites.py")
text = p.read_text()
for start, end in [(1,220),(220,360)]:
    print(f"\n--- {p}:{start}-{end} ---")
    for i, line in enumerate(text.splitlines(), 1):
        if start <= i <= end:
            print(f"{i:4d}: {line}")
PY

printf '\n== search for output_dir / artifact copies ==\n'
rg -n "output_dir|artifact_links|copy_source|symlink|source-artifacts|official_artifacts_dir|community_aggregate_dir|render_official_results_site|render_community_results_site" legalforecast -C 3

Repository: johnhughes3/LegalForecastBench

Length of output: 50387


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '\n== call sites ==\n'
rg -n "render_official_results_site|render_community_results_site" legalforecast/cli.py legalforecast/publication -C 4

printf '\n== release bundle site layout ==\n'
python3 - <<'PY'
from pathlib import Path
p = Path("legalforecast/publication/release_bundle.py")
text = p.read_text().splitlines()
for start, end in [(1,220),(220,420)]:
    print(f"\n--- {p}:{start}-{end} ---")
    for i, line in enumerate(text, 1):
        if start <= i <= end:
            print(f"{i:4d}: {line}")
PY

Repository: johnhughes3/LegalForecastBench

Length of output: 16920


🏁 Script executed:

#!/bin/bash
set -euo pipefail

rg -n "render_official_results_site" legalforecast -C 4

Repository: johnhughes3/LegalForecastBench

Length of output: 746


Artifact links resolve against the source tree, not the published site.

_artifact_links() builds hrefs from official_artifacts_dir / community_aggregate_dir, but the HTML is written to a separate site directory. In render_community_results_site(...), that makes the links point at output_dir/site/... instead of the files in output_dir, so they 404 unless the artifacts are copied into the site tree first. The same pattern in render_official_results_site(...) has the same risk if it’s used with a distinct output dir.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@legalforecast/publication/static_sites.py` around lines 92 - 121, The
artifact URLs are being generated from the source artifact directories, but the
site is written to a separate output tree, so the links can point to paths that
are not actually published. Update render_official_results_site and the shared
_artifact_links path-building logic so hrefs are relative to the generated site
location (or copy the referenced artifacts into the site output before writing
HTML), and ensure the links produced by _link_list still resolve correctly from
the published page.

… input

Adds docs/plans/multi-harness-community-benchmark-2026-05-29.md, a
proposed plan for community review by Legal Quants and other
contributors. The plan is intentionally additive: it preserves the
protected official LegalForecastBench path (main-only workflows,
official S3/OIDC boundaries, official aggregation guardrails) and
introduces a separate community surface for multi-harness comparisons.

Key features of the proposal:

- New isolated package legalforecast/multiharness/ with canonical
  schemas for tasks, adapter capabilities, run requests/results,
  sandbox policies, conformance reports, and community submissions.
  Reuses existing evals/packet/prompt/parser/scoring/accounting code
  rather than duplicating benchmark logic.
- Canonical task families with explicit scoring modes
  (legalforecast_mtd + lfb_brier, harvey_lab + lab_native). Community
  rows are grouped by (family, scoring_mode, selection_sha256); no
  single cross-suite winner is computed.
- Language-agnostic command-adapter protocol (adapter.json manifest +
  `capabilities` / `run` CLI commands over JSON) as the public
  contribution surface, so contributors can ship a script/CLI without
  packaging Python into this repo. Subprocess execution never uses
  shell=True; stdout/stderr stay private unless summarized.
- Host-owned sandbox policy planner that emits a sandbox.plan.json
  per run, with Docker/Podman backends, --network=none for tool
  containers by default, and provider egress confined to the host
  adapter process under declared env vars (no Docker-in-Docker, no
  LAB-in-LFB nesting).
- Harvey LAB integration as a pinned CLI bridge rather than vendoring
  or importing unstable internals; capabilities are probed and
  recorded, native LAB scores.json is normalized into community
  artifacts, and LAB report.html/transcripts default to private.
- First-class adapter tracks for LQ.AI, Hermes Agent, and OpenClaw,
  with OpenAI Responses/Codex-style and Claude Agent SDK adapters as
  provider/runtime baselines. Each track records harness-specific
  provenance (e.g. inference tier, terminal backend, runtimePlan).
- Partial-run shards are first-class: each submission records
  selection_sha256, selectors, adapter/model/sandbox/run-config
  hashes, and shard/composite-group IDs. Composite rows only roll up
  when compatibility keys match and task IDs do not overlap, and
  every shard contributor is credited separately.
- Two-layer registry: GitHub PRs under community/submissions/** are
  the reviewed registry of record (audit trail + attribution +
  moderation); Hugging Face Datasets or GitHub Releases mirror large
  artifacts by immutable URL + SHA-256. No custom upload service in
  v1; the "database" is versioned JSON/JSONL/Parquet rebuilt on every
  accepted change.
- Two separate static publication surfaces, generated by Python
  renderers in v1: "LegalForecastBench Official Results" (consumes
  existing official aggregate artifacts) and "LegalForecastBench
  Community Harness Comparisons" (consumes community aggregate
  artifacts, with LAB and LFB rendered in separate sections and
  non-official disclaimers). Final naming is open for Legal Quants
  approval.
- Provenance and presentation surfaces replace the deprecated
  result-tier taxonomy (result_tier, verified-community,
  community-unverified, alpha-non-canonical are explicitly banned in
  submission validation, consistent with .agents/AGENTS.md).
- Adapter conformance suite (`legalforecast multiharness conformance`)
  runs without provider credentials by default and emits a
  plain-English report so non-maintainers can verify an adapter
  before submission.
- Dedicated community validation workflow that uses contents:read
  only, no id-token:write, no AWS credentials, no provider secrets,
  and no official protected environment.
- Attribution per row credits LegalForecastBench / John Hughes /
  Legal Quants (infrastructure), Harvey (task source where LAB tasks
  are used), adapter authors, submission authors/runners, and
  declared model/provider identity.

Structure: 17 work items with explicit dependencies, sizing, key
files, done-when criteria, and a recommended execution order that
builds a testable core (schemas → loaders → selection → sandbox →
adapter protocol → LFB native adapter → conformance → runner)
before the LAB CLI bridge, CLI surface, community
submission/aggregation/site, validation workflow, docs, release
checks, and first-class external adapter tracks.

Open questions flagged for community input: final public names for
the two sites; exact installation/version pinning and adapter mode
(command bridge vs in-process vs native plugin) for LQ.AI, Hermes,
and OpenClaw; organization/repo names and retention policy for the
Hugging Face artifact mirror; whether HF upload helpers ship in v1
or stay manual.
Copilot AI review requested due to automatic review settings July 7, 2026 14:57
@ai-agent-on-behalf-of-john-hughes
ai-agent-on-behalf-of-john-hughes Bot force-pushed the docs/multi-harness-community-benchmark-plan branch from afd4a4c to a60fb98 Compare July 7, 2026 14:57
@johnjhughes
johnjhughes removed the request for review from Copilot July 7, 2026 14:57

@coderabbitai coderabbitai 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.

Actionable comments posted: 4

♻️ Duplicate comments (2)
legalforecast/multiharness/reporting.py (1)

109-148: 🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win

Markdown table cells still unescaped.

row_id, model_key, adapter_id, adapter_version, and conformance_status can still contain | or newlines, breaking the table formatting, as previously flagged.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@legalforecast/multiharness/reporting.py` around lines 109 - 148, The Markdown
table in render_community_comparison_markdown still writes raw row fields into
cells, so values containing pipe characters or newlines can break formatting.
Update the row rendering to escape or sanitize row_id, model_key, adapter_id,
adapter_version, and conformance_status before concatenating them into the
table, and normalize any embedded newlines so each cell stays single-line.
legalforecast/multiharness/community.py (1)

652-703: 🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win

Shard homogeneity still not enforced for suite_version (and now also sandbox_policy_hash).

The grouping key (family, scoring_mode, adapter_id, adapter_version, model_key) still omits suite_version, so rows with different suite versions can land in the same shard while suite_version is copied only from shard_rows[0]. The same gap now also applies to sandbox_policy_hash, which is likewise derived only from shard_rows[0] — a shard could silently misreport the sandbox policy for some of its rows. compatible_shard_group_id (built from family/scoring_mode/selection_sha256 only) inherits the same blind spot.

🧩 Proposed fix: include suite_version in the grouping key and assert sandbox consistency
-    groups: dict[tuple[str, str, str, str, str], list[Mapping[str, Any]]] = {}
+    groups: dict[tuple[str, str, str, str, str, str], list[Mapping[str, Any]]] = {}
     for row in rows:
         request = requests[_required_row_str(row, "row_id")]
         family = _required_row_str(row, "family")
         scoring_mode = _request_task_field(request, "scoring_mode")
+        suite_version = _request_task_field(request, "suite_version")
         adapter_id = _required_row_str(row, "adapter_id")
         adapter_version = _required_row_str(row, "adapter_version")
         model_key = _required_row_str(row, "model_key")
         groups.setdefault(
-            (family, scoring_mode, adapter_id, adapter_version, model_key),
+            (family, scoring_mode, suite_version, adapter_id, adapter_version, model_key),
             [],
         ).append(row)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@legalforecast/multiharness/community.py` around lines 652 - 703, The
_submission_shards function still groups rows without considering suite_version,
so mixed suite versions can be combined and suite_version is then taken from
shard_rows[0]. Update the grouping key in _submission_shards to include
suite_version, and ensure compatible_shard_group_id still matches the shard’s
true grouping semantics. Also verify sandbox_policy_hash is consistent across
all rows in each shard by checking the sandbox_policy /
sandbox.plan.json-derived hash for every row, not just shard_rows[0], and reject
or split any mismatched rows.
🧹 Nitpick comments (3)
legalforecast/multiharness/command_adapter.py (1)

94-138: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick win

run() re-invokes capabilities() unnecessarily via prepare().

run() calls prepare(), which always re-fetches capabilities from the adapter subprocess even when the caller (e.g., conformance.py) already validated capabilities moments earlier. For real (non-fixture) external harnesses this means an extra, potentially expensive process launch on every run() call. Consider caching capabilities per adapter instance/workspace, or accepting already-validated capabilities as an optional parameter to prepare/run.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@legalforecast/multiharness/command_adapter.py` around lines 94 - 138,
`CommandAdapter.run()` is triggering an extra `capabilities()` subprocess call
through `prepare()` even when the adapter was just validated. Update `prepare()`
and/or `run()` in `CommandAdapter` so previously fetched capabilities can be
reused for the same adapter instance/workspace instead of always re-fetching
them, and keep the existing validation checks against `request.adapter`,
`request.task.family`, and `request.task.scoring_mode` using the cached
`capabilities` value.
.github/workflows/community-multiharness-validation.yaml (1)

5-11: 🚀 Performance & Scalability | 🔵 Trivial | 💤 Low value

Broad docs/** trigger runs full test/lint/type-check suite for any docs edit.

Any change under docs/** (including unrelated doc edits) triggers the entire validation job (sync, format, lint, pyright, full pytest run). Consider narrowing this to only the multi-harness/community docs paths that actually need code validation, to avoid unnecessary CI cost on pure documentation PRs.

Also applies to: 15-22

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/community-multiharness-validation.yaml around lines 5 -
11, The workflow trigger in the community-multiharness validation job is too
broad because `docs/**` causes the full validation suite to run for any
documentation-only edit. Narrow the `paths` filter in the community validation
workflow so it only matches the specific community/multiharness docs locations
that should require code validation, using the existing workflow trigger block
to keep unrelated docs changes from launching sync, lint, type-check, and full
pytest runs.
scripts/release_check.py (1)

543-608: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Consider a triple-quoted template instead of a manually joined line list.

_fixture_adapter_script() builds ~65 lines of Python source as a list of individually quoted, comma-joined strings. It's syntactically correct but harder to read/maintain than an inline heredoc-style string.

♻️ Proposed refactor using a triple-quoted template
 def _fixture_adapter_script() -> str:
-    return "\n".join(
-        (
-            "from __future__ import annotations",
-            ...
-        )
-    )
+    return textwrap.dedent(
+        """\
+        from __future__ import annotations
+        import argparse
+        import json
+        import pathlib
+        import sys
+        ...
+        """
+    )
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@scripts/release_check.py` around lines 543 - 608, The
_fixture_adapter_script() helper is constructing a long Python script via a
manually joined list of strings, which is hard to read and maintain. Refactor it
to return a single triple-quoted template string instead, preserving the same
behavior for capabilities(), run(), and the sys.argv phase dispatch while
keeping the generated script identical in output.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.github/workflows/community-multiharness-validation.yaml:
- Around line 39-41: The workflow’s checkout steps are persisting Git
credentials longer than needed, which widens exposure during later steps that
run external code. Update both actions/checkout usages in the
community-multiharness-validation job to disable credential persistence by
setting persist-credentials to false, keeping the checkout behavior limited to
read-only repository access.

In `@legalforecast/multiharness/conformance.py`:
- Around line 120-142: The sandbox_negative_control check is marked as passed
without any real validation. Update the conformance flow in conformance.py
around the sandbox negative control artifact generation and the
checks["sandbox_negative_control"] assignment so it either performs an actual
assertion from the adapter/fixture run results or is removed/demoted if it is
only a recorded expectation; use the existing _artifact_for, write_json_object,
and _passed symbols as the anchor points when wiring in the real verification.

In `@legalforecast/multiharness/harvey_lab_adapter.py`:
- Around line 428-446: The `_run_subprocess` helper currently converts only
`subprocess.TimeoutExpired` into `HarveyLabCliAdapterError`, so missing or
misconfigured executables can still escape as raw `FileNotFoundError`/`OSError`.
Update `_run_subprocess` to catch those launch failures alongside the existing
timeout handling and re-raise them as `HarveyLabCliAdapterError` with an
actionable message that includes the command context from
`argv`/`self.lab_command`. Keep the existing timeout behavior intact so all
subprocess startup and execution failures follow the module’s domain-error
contract.
- Around line 411-421: The _lab_commit helper is calling subprocess.run for git
rev-parse without any timeout, so it can block the capabilities/prepare/run flow
indefinitely. Update _lab_commit in harvey_lab_adapter.py to use the same
bounded subprocess pattern as _run_subprocess, adding a timeout and handling
timeout/failure by returning "unknown" or equivalent fallback. Keep the change
localized to _lab_commit so the git HEAD lookup cannot hang the overall adapter.

---

Duplicate comments:
In `@legalforecast/multiharness/community.py`:
- Around line 652-703: The _submission_shards function still groups rows without
considering suite_version, so mixed suite versions can be combined and
suite_version is then taken from shard_rows[0]. Update the grouping key in
_submission_shards to include suite_version, and ensure
compatible_shard_group_id still matches the shard’s true grouping semantics.
Also verify sandbox_policy_hash is consistent across all rows in each shard by
checking the sandbox_policy / sandbox.plan.json-derived hash for every row, not
just shard_rows[0], and reject or split any mismatched rows.

In `@legalforecast/multiharness/reporting.py`:
- Around line 109-148: The Markdown table in
render_community_comparison_markdown still writes raw row fields into cells, so
values containing pipe characters or newlines can break formatting. Update the
row rendering to escape or sanitize row_id, model_key, adapter_id,
adapter_version, and conformance_status before concatenating them into the
table, and normalize any embedded newlines so each cell stays single-line.

---

Nitpick comments:
In @.github/workflows/community-multiharness-validation.yaml:
- Around line 5-11: The workflow trigger in the community-multiharness
validation job is too broad because `docs/**` causes the full validation suite
to run for any documentation-only edit. Narrow the `paths` filter in the
community validation workflow so it only matches the specific
community/multiharness docs locations that should require code validation, using
the existing workflow trigger block to keep unrelated docs changes from
launching sync, lint, type-check, and full pytest runs.

In `@legalforecast/multiharness/command_adapter.py`:
- Around line 94-138: `CommandAdapter.run()` is triggering an extra
`capabilities()` subprocess call through `prepare()` even when the adapter was
just validated. Update `prepare()` and/or `run()` in `CommandAdapter` so
previously fetched capabilities can be reused for the same adapter
instance/workspace instead of always re-fetching them, and keep the existing
validation checks against `request.adapter`, `request.task.family`, and
`request.task.scoring_mode` using the cached `capabilities` value.

In `@scripts/release_check.py`:
- Around line 543-608: The _fixture_adapter_script() helper is constructing a
long Python script via a manually joined list of strings, which is hard to read
and maintain. Refactor it to return a single triple-quoted template string
instead, preserving the same behavior for capabilities(), run(), and the
sys.argv phase dispatch while keeping the generated script identical in output.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 51bbb3aa-5f6b-4fd6-9d02-df4de016e4a0

📥 Commits

Reviewing files that changed from the base of the PR and between afd4a4c and a60fb98.

📒 Files selected for processing (107)
  • .github/workflows/community-multiharness-validation.yaml
  • .github/workflows/publish-package.yaml
  • MODEL_RELEASE_DATES.md
  • README.md
  • community/submissions/.gitkeep
  • community/submissions/2026/README.md
  • community/submissions/2026/claude-agent-sdk-fixture-baseline/artifact-manifest.json
  • community/submissions/2026/claude-agent-sdk-fixture-baseline/canonical-runs.jsonl
  • community/submissions/2026/claude-agent-sdk-fixture-baseline/conformance-report.json
  • community/submissions/2026/claude-agent-sdk-fixture-baseline/hf-upload-plan.json
  • community/submissions/2026/claude-agent-sdk-fixture-baseline/public-summary.json
  • community/submissions/2026/claude-agent-sdk-fixture-baseline/row-results.jsonl
  • community/submissions/2026/claude-agent-sdk-fixture-baseline/run-manifest.json
  • community/submissions/2026/claude-agent-sdk-fixture-baseline/selection-manifest.json
  • community/submissions/2026/claude-agent-sdk-fixture-baseline/submission.json
  • community/submissions/2026/hermes-agent-fixture-bridge/artifact-manifest.json
  • community/submissions/2026/hermes-agent-fixture-bridge/canonical-runs.jsonl
  • community/submissions/2026/hermes-agent-fixture-bridge/conformance-report.json
  • community/submissions/2026/hermes-agent-fixture-bridge/hf-upload-plan.json
  • community/submissions/2026/hermes-agent-fixture-bridge/public-summary.json
  • community/submissions/2026/hermes-agent-fixture-bridge/row-results.jsonl
  • community/submissions/2026/hermes-agent-fixture-bridge/run-manifest.json
  • community/submissions/2026/hermes-agent-fixture-bridge/selection-manifest.json
  • community/submissions/2026/hermes-agent-fixture-bridge/submission.json
  • community/submissions/2026/lq-ai-fixture-bridge/artifact-manifest.json
  • community/submissions/2026/lq-ai-fixture-bridge/canonical-runs.jsonl
  • community/submissions/2026/lq-ai-fixture-bridge/conformance-report.json
  • community/submissions/2026/lq-ai-fixture-bridge/hf-upload-plan.json
  • community/submissions/2026/lq-ai-fixture-bridge/public-summary.json
  • community/submissions/2026/lq-ai-fixture-bridge/row-results.jsonl
  • community/submissions/2026/lq-ai-fixture-bridge/run-manifest.json
  • community/submissions/2026/lq-ai-fixture-bridge/selection-manifest.json
  • community/submissions/2026/lq-ai-fixture-bridge/submission.json
  • community/submissions/2026/openai-responses-fixture-baseline/artifact-manifest.json
  • community/submissions/2026/openai-responses-fixture-baseline/canonical-runs.jsonl
  • community/submissions/2026/openai-responses-fixture-baseline/conformance-report.json
  • community/submissions/2026/openai-responses-fixture-baseline/hf-upload-plan.json
  • community/submissions/2026/openai-responses-fixture-baseline/public-summary.json
  • community/submissions/2026/openai-responses-fixture-baseline/row-results.jsonl
  • community/submissions/2026/openai-responses-fixture-baseline/run-manifest.json
  • community/submissions/2026/openai-responses-fixture-baseline/selection-manifest.json
  • community/submissions/2026/openai-responses-fixture-baseline/submission.json
  • community/submissions/2026/openclaw-fixture-bridge/artifact-manifest.json
  • community/submissions/2026/openclaw-fixture-bridge/canonical-runs.jsonl
  • community/submissions/2026/openclaw-fixture-bridge/conformance-report.json
  • community/submissions/2026/openclaw-fixture-bridge/hf-upload-plan.json
  • community/submissions/2026/openclaw-fixture-bridge/public-summary.json
  • community/submissions/2026/openclaw-fixture-bridge/row-results.jsonl
  • community/submissions/2026/openclaw-fixture-bridge/run-manifest.json
  • community/submissions/2026/openclaw-fixture-bridge/selection-manifest.json
  • community/submissions/2026/openclaw-fixture-bridge/submission.json
  • docs/adapters/hermes-agent.md
  • docs/adapters/lq-ai.md
  • docs/adapters/openclaw.md
  • docs/adapters/provider-baselines.md
  • docs/community-submissions.md
  • docs/multiharness-adapter-spec.md
  • docs/plans/multi-harness-community-benchmark-2026-05-29.md
  • examples/adapters/claude-agent-sdk/adapter-manifest.json
  • examples/adapters/fixture_bridge.py
  • examples/adapters/hermes-agent/adapter-manifest.json
  • examples/adapters/lq-ai/adapter-manifest.json
  • examples/adapters/openai-responses/adapter-manifest.json
  • examples/adapters/openclaw/adapter-manifest.json
  • legalforecast/cli.py
  • legalforecast/multiharness/__init__.py
  • legalforecast/multiharness/adapters.py
  • legalforecast/multiharness/artifacts.py
  • legalforecast/multiharness/cli.py
  • legalforecast/multiharness/command_adapter.py
  • legalforecast/multiharness/community.py
  • legalforecast/multiharness/conformance.py
  • legalforecast/multiharness/harvey_lab_adapter.py
  • legalforecast/multiharness/lfb_native.py
  • legalforecast/multiharness/reporting.py
  • legalforecast/multiharness/runner.py
  • legalforecast/multiharness/sandbox.py
  • legalforecast/multiharness/selection.py
  • legalforecast/multiharness/spec.py
  • legalforecast/multiharness/task_loaders.py
  • legalforecast/multiharness/validation.py
  • legalforecast/publication/__init__.py
  • legalforecast/publication/community_aggregate.py
  • legalforecast/publication/release_bundle.py
  • legalforecast/publication/static_sites.py
  • legalforecast/reporting/pilot_readiness.py
  • scripts/AGENTS.md
  • scripts/release_check.py
  • tests/test_community_examples.py
  • tests/test_community_multiharness_workflow.py
  • tests/test_community_publication.py
  • tests/test_community_submission.py
  • tests/test_multiharness_cli.py
  • tests/test_multiharness_command_adapter.py
  • tests/test_multiharness_conformance.py
  • tests/test_multiharness_external_adapters.py
  • tests/test_multiharness_harvey_lab_adapter.py
  • tests/test_multiharness_lfb_native.py
  • tests/test_multiharness_runner.py
  • tests/test_multiharness_sandbox.py
  • tests/test_multiharness_selection.py
  • tests/test_multiharness_spec.py
  • tests/test_multiharness_task_loaders.py
  • tests/test_publish_package_workflow.py
  • tests/test_release_bundle.py
  • tests/test_release_check.py
  • tests/test_static_result_sites.py
✅ Files skipped from review due to trivial changes (44)
  • community/submissions/2026/openclaw-fixture-bridge/row-results.jsonl
  • community/submissions/2026/README.md
  • community/submissions/2026/openclaw-fixture-bridge/canonical-runs.jsonl
  • scripts/AGENTS.md
  • community/submissions/2026/hermes-agent-fixture-bridge/run-manifest.json
  • community/submissions/2026/lq-ai-fixture-bridge/hf-upload-plan.json
  • community/submissions/2026/claude-agent-sdk-fixture-baseline/public-summary.json
  • community/submissions/2026/openclaw-fixture-bridge/public-summary.json
  • community/submissions/2026/lq-ai-fixture-bridge/row-results.jsonl
  • community/submissions/2026/claude-agent-sdk-fixture-baseline/conformance-report.json
  • community/submissions/2026/openclaw-fixture-bridge/artifact-manifest.json
  • examples/adapters/lq-ai/adapter-manifest.json
  • docs/adapters/openclaw.md
  • community/submissions/2026/hermes-agent-fixture-bridge/selection-manifest.json
  • examples/adapters/openai-responses/adapter-manifest.json
  • community/submissions/2026/claude-agent-sdk-fixture-baseline/artifact-manifest.json
  • docs/adapters/provider-baselines.md
  • community/submissions/.gitkeep
  • community/submissions/2026/hermes-agent-fixture-bridge/public-summary.json
  • community/submissions/2026/openai-responses-fixture-baseline/selection-manifest.json
  • community/submissions/2026/claude-agent-sdk-fixture-baseline/run-manifest.json
  • community/submissions/2026/openai-responses-fixture-baseline/hf-upload-plan.json
  • community/submissions/2026/lq-ai-fixture-bridge/canonical-runs.jsonl
  • community/submissions/2026/lq-ai-fixture-bridge/artifact-manifest.json
  • community/submissions/2026/openclaw-fixture-bridge/conformance-report.json
  • docs/adapters/lq-ai.md
  • community/submissions/2026/lq-ai-fixture-bridge/conformance-report.json
  • community/submissions/2026/lq-ai-fixture-bridge/public-summary.json
  • community/submissions/2026/openai-responses-fixture-baseline/run-manifest.json
  • community/submissions/2026/openai-responses-fixture-baseline/public-summary.json
  • community/submissions/2026/hermes-agent-fixture-bridge/row-results.jsonl
  • community/submissions/2026/lq-ai-fixture-bridge/run-manifest.json
  • community/submissions/2026/openai-responses-fixture-baseline/row-results.jsonl
  • community/submissions/2026/hermes-agent-fixture-bridge/canonical-runs.jsonl
  • community/submissions/2026/openclaw-fixture-bridge/submission.json
  • community/submissions/2026/claude-agent-sdk-fixture-baseline/hf-upload-plan.json
  • community/submissions/2026/openai-responses-fixture-baseline/submission.json
  • legalforecast/reporting/pilot_readiness.py
  • README.md
  • community/submissions/2026/openai-responses-fixture-baseline/artifact-manifest.json
  • community/submissions/2026/claude-agent-sdk-fixture-baseline/canonical-runs.jsonl
  • docs/adapters/hermes-agent.md
  • community/submissions/2026/hermes-agent-fixture-bridge/conformance-report.json
  • docs/multiharness-adapter-spec.md
🚧 Files skipped from review as they are similar to previous changes (34)
  • community/submissions/2026/lq-ai-fixture-bridge/selection-manifest.json
  • community/submissions/2026/hermes-agent-fixture-bridge/submission.json
  • community/submissions/2026/hermes-agent-fixture-bridge/artifact-manifest.json
  • examples/adapters/hermes-agent/adapter-manifest.json
  • legalforecast/publication/init.py
  • community/submissions/2026/claude-agent-sdk-fixture-baseline/row-results.jsonl
  • community/submissions/2026/openclaw-fixture-bridge/selection-manifest.json
  • examples/adapters/claude-agent-sdk/adapter-manifest.json
  • community/submissions/2026/openclaw-fixture-bridge/hf-upload-plan.json
  • community/submissions/2026/openai-responses-fixture-baseline/conformance-report.json
  • examples/adapters/openclaw/adapter-manifest.json
  • community/submissions/2026/claude-agent-sdk-fixture-baseline/selection-manifest.json
  • community/submissions/2026/openai-responses-fixture-baseline/canonical-runs.jsonl
  • community/submissions/2026/hermes-agent-fixture-bridge/hf-upload-plan.json
  • tests/test_release_bundle.py
  • legalforecast/multiharness/adapters.py
  • tests/test_community_examples.py
  • legalforecast/cli.py
  • tests/test_community_multiharness_workflow.py
  • legalforecast/multiharness/init.py
  • community/submissions/2026/openclaw-fixture-bridge/run-manifest.json
  • tests/test_publish_package_workflow.py
  • tests/test_multiharness_selection.py
  • tests/test_multiharness_sandbox.py
  • tests/test_multiharness_external_adapters.py
  • legalforecast/multiharness/sandbox.py
  • community/submissions/2026/claude-agent-sdk-fixture-baseline/submission.json
  • legalforecast/publication/static_sites.py
  • legalforecast/publication/release_bundle.py
  • community/submissions/2026/lq-ai-fixture-bridge/submission.json
  • legalforecast/multiharness/spec.py
  • legalforecast/multiharness/validation.py
  • legalforecast/publication/community_aggregate.py
  • legalforecast/multiharness/cli.py

Comment on lines +39 to +41
- name: Check out repository
uses: actions/checkout@v6

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔒 Security & Privacy | 🟡 Minor | ⚡ Quick win

Disable credential persistence on checkout.

Neither checkout step sets persist-credentials: false. The job only needs contents: read and never pushes, so leaving credentials persisted for the whole job (including uv run steps that execute installed/third-party code) needlessly widens the blast radius if that step is compromised.

🔒 Proposed fix
       - name: Check out repository
         uses: actions/checkout@v6
+        with:
+          persist-credentials: false

Apply the same change to both occurrences (lines 39-41 and 120-122).

Also applies to: 120-122

🧰 Tools
🪛 zizmor (1.26.1)

[warning] 39-40: credential persistence through GitHub Actions artifacts (artipacked): does not set persist-credentials: false

(artipacked)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/community-multiharness-validation.yaml around lines 39 -
41, The workflow’s checkout steps are persisting Git credentials longer than
needed, which widens exposure during later steps that run external code. Update
both actions/checkout usages in the community-multiharness-validation job to
disable credential persistence by setting persist-credentials to false, keeping
the checkout behavior limited to read-only repository access.

Source: Linters/SAST tools

Comment thread legalforecast/multiharness/conformance.py Outdated
Comment thread legalforecast/multiharness/harvey_lab_adapter.py
Comment thread legalforecast/multiharness/harvey_lab_adapter.py
@ai-agent-on-behalf-of-john-hughes

Copy link
Copy Markdown
Contributor

[awt-judge] Opus decision

Decision: block_for_fixes
Reasoning: CI is green, but I confirmed four correctness/integrity defects in the newly added multi-harness code that will directly affect published community conformance and shard rollups. The sandbox_negative_control check unconditionally reports 'passed' with no assertion, giving the community conformance report a fake security signal. The _submission_shards grouping key omits suite_version and blindly copies sandbox_policy_hash from shard_rows[0], so mixed-suite or mixed-sandbox rows can be silently rolled up under one shard's metadata. The Harvey LAB adapter leaks raw OSError/FileNotFoundError outside the HarveyLabCliAdapterError contract and calls git rev-parse HEAD with no timeout, allowing the capabilities/prepare/run flow to hang. These are conservative merge blockers; the remaining Codex/CodeRabbit items (credential persistence, Markdown cell escaping, capabilities caching, docs/** trigger scope, _fixture_adapter_script refactor) can be deferred to follow-up issues.
Head SHA: a60fb98
Model: opus

Codex action items

Action Items for Codex

Critical Blockers (must fix before merge)

  1. legalforecast/multiharness/conformance.py lines 120-142 — fake sandbox_negative_control pass.

    • Current behavior: writes a static expectation JSON and sets checks["sandbox_negative_control"] = _passed(...) unconditionally, so every conformance report certifies the negative control regardless of adapter behavior.
    • Required fix: tie the check to an actual assertion — e.g., verify that the LFB/Harvey fixture runs completed without any provider-credential env vars being present or requested, and mark the check _failed(...) when that invariant is violated. Use the existing _artifact_for, write_json_object, and _passed/_failed anchors.
    • If a real assertion cannot be wired in this PR, remove the entry rather than shipping a permanently-green signal; do not leave an unconditional pass in the published conformance surface.
  2. legalforecast/multiharness/community.py lines 686-708 — shard grouping omits suite_version and blindly trusts shard_rows[0] for sandbox policy.

    • Current behavior: the grouping key is (family, scoring_mode, adapter_id, adapter_version, model_key). Rows from different suite_versions or different sandbox_policy_hashs can land in the same shard, and both suite_version and sandbox_policy_hash are then copied from shard_rows[0] — silently misreporting the shard's metadata.
    • Required fix: add suite_version to the grouping key so shards are homogeneous in suite version, and assert that sandbox_policy_hash (derived from each row's sandbox.plan.json/sandbox_policy) matches across every row in a shard. Reject or split any group whose rows disagree, and confirm compatible_shard_group_id still reflects the true grouping semantics.
    • Add or extend a test in tests/test_community_multiharness_workflow.py (or tests/test_community_submission.py) proving that heterogeneous suite_version/sandbox_policy_hash inputs are split or rejected rather than merged.
  3. legalforecast/multiharness/harvey_lab_adapter.py lines 428-446 — _run_subprocess leaks non-HarveyLabCliAdapterError exceptions.

    • Current behavior: only subprocess.TimeoutExpired is caught. A missing/misconfigured lab_command[0] raises FileNotFoundError/OSError, escaping the module's domain-error contract and producing raw tracebacks instead of the plain-English conformance failures the plan promises (Item 7).
    • Required fix: add except OSError as exc: and re-raise as HarveyLabCliAdapterError with a message that includes the argv/self.lab_command context. Keep the existing timeout handling intact.
  4. legalforecast/multiharness/harvey_lab_adapter.py lines 411-421 — _lab_commit runs git rev-parse without a timeout.

    • Current behavior: subprocess.run(["git", "-C", str(path), "rev-parse", "HEAD"], ...) has no timeout=, so a hung git process or credential prompt can block capabilities/prepare/run indefinitely.
    • Required fix: apply the same bounded pattern as _run_subprocess — pass timeout=10, wrap in try/except (subprocess.TimeoutExpired, OSError), and return "unknown" on failure. Keep the change localized to _lab_commit.

Expected Outcome

  • sandbox_negative_control either performs a real assertion tied to the actual fixture runs or is removed from the conformance report; a targeted test proves it can fail when credentials would be required.
  • _submission_shards refuses to merge rows with mismatched suite_version or sandbox_policy_hash, with a test demonstrating the split/reject behavior.
  • Every subprocess.run in harvey_lab_adapter.py is bounded by a timeout and every startup failure maps to HarveyLabCliAdapterError with an actionable message.
  • Full Community Multi-Harness Validation and CI workflows stay green after the fixes.

Deferred to follow-up (not blocking this merge)

  • .github/workflows/community-multiharness-validation.yaml lines 39-41 and 120-122: add persist-credentials: false to both actions/checkout@v6 uses.
  • .github/workflows/community-multiharness-validation.yaml lines 5-11 / 15-22: narrow the docs/** triggers to community/multiharness-relevant doc paths.
  • legalforecast/multiharness/reporting.py lines 109-148: escape | and normalize newlines in Markdown table cells for row_id, model_key, adapter_id, adapter_version, conformance_status.
  • legalforecast/multiharness/command_adapter.py lines 94-138: cache capabilities() per adapter instance so run() does not relaunch the adapter subprocess every call.
  • scripts/release_check.py lines 543-608: replace the manually joined string list in _fixture_adapter_script() with a textwrap.dedent triple-quoted template.

PR description drift (nice to fix while you're in there)

  • The PR body still asserts "Docs only: one new file... No code changes." The diff actually adds a full legalforecast/multiharness/ package, a new CI workflow, community submissions, and tests. Please update the description before merge so reviewers do not miss the code surface.
Codex follow-up guidance

Focus on the four critical blockers first; run uv run pytest -q tests/test_multiharness_conformance.py tests/test_community_multiharness_workflow.py tests/test_multiharness_harvey_lab_adapter.py plus the full community/multi-harness suite listed in the workflow after each fix. Only after those pass, address the deferred nitpicks in a follow-up commit or issue.

Copilot AI review requested due to automatic review settings July 8, 2026 14:51
@johnjhughes
johnjhughes removed the request for review from Copilot July 8, 2026 14:51
@ai-agent-on-behalf-of-john-hughes

Copy link
Copy Markdown
Contributor

[awt-judge] Codex pushed after 45 minutes.

Replying to: #7 (comment)
New head SHA: 6d75a66

_WARNING = "warning"
_LFB_FIXTURE_REQUEST_ID = "conformance:lfb-fixture"
_LAB_FIXTURE_REQUEST_ID = "conformance:lab-fixture"
_ADAPTER_SPEC_PATH = "docs/multiharness-adapter-spec.md"
@ai-agent-on-behalf-of-john-hughes

Copy link
Copy Markdown
Contributor

[awt-judge] Opus decision

Decision: approve_with_issue
Reasoning: Re-evaluated all four prior-judge blockers against head 6d75a66. Every one is now correctly fixed and covered by new tests (harvey_lab_adapter.py:411-421 wraps git rev-parse with timeout=10 and (TimeoutExpired, OSError) fallback; _run_subprocess adds an OSError → HarveyLabCliAdapterError re-raise; conformance.py _write_sandbox_negative_control now aggregates fixture evidence, computes provider-credential violations via _sandbox_negative_control_violations, and calls _failed(...) when violations exist; community.py _submission_shards adds suite_version to the grouping key AND raises MultiHarnessValidationError when a shard's rows disagree on sandbox_policy_hash). CodeRabbit's own bot marked each blocker '✅ Addressed in commit 6d75a66'. All 5 CI checks (CI, Community Multi-Harness Validation, CodeQL python, CodeQL actions, Code Quality) pass. Only enhancement-class items remain (persist-credentials:false on checkout, docs/** trigger scoping, Markdown table cell escaping, capabilities() caching, _fixture_adapter_script textwrap.dedent refactor, and PR description drift). None break functionality, so they are appropriate for a follow-up issue.
Head SHA: 6d75a66
Model: opus

Follow-up artifact (if needed)

Title: Multi-harness benchmark: hardening and hygiene follow-ups

Follow-up items deferred from PR #7 (all non-blocking; core blockers were fixed in 6d75a66).

Workflow hardening

  • .github/workflows/community-multiharness-validation.yaml L39-41 and L120-122: add persist-credentials: false to both actions/checkout@v6 uses to minimize on-runner token exposure.
  • .github/workflows/community-multiharness-validation.yaml L5-11 / L15-22: narrow the docs/** triggers to community/multiharness-relevant doc paths so unrelated doc-only PRs don't spin up the validation workflow.

Reporting polish

  • legalforecast/multiharness/reporting.py L109-148: escape | and normalize embedded newlines in Markdown table cells for row_id, model_key, adapter_id, adapter_version, and conformance_status, so malformed identifiers can't break table rendering.

Performance

  • legalforecast/multiharness/command_adapter.py L94-138: cache capabilities() per adapter instance so run() does not relaunch the adapter subprocess for every call.

Maintainability

  • scripts/release_check.py L543-608: replace the manually joined string list in _fixture_adapter_script() with a textwrap.dedent triple-quoted template.

Docs drift

  • PR docs: propose multi-harness community benchmark plan for Legal Quants input #7's body still asserts 'Docs only: one new file... No code changes.' but the merged diff added the full legalforecast/multiharness/ package, a new CI workflow, community submissions, and tests. Update the PR description (or a follow-up changelog note) to reflect the actual code surface so future spelunkers aren't misled.

Optional security review

  • ast-grep flagged CWE-78 on subprocess.run(tuple(argv), ...) in harvey_lab_adapter._run_subprocess. Confirm argv cannot be influenced by untrusted input (manifest-driven only) and document that boundary, or add explicit allow-listing/validation of lab_command[0].

@ai-agent-on-behalf-of-john-hughes
ai-agent-on-behalf-of-john-hughes Bot merged commit 536fbf9 into main Jul 8, 2026
9 of 10 checks passed
@johnjhughes
johnjhughes deleted the docs/multi-harness-community-benchmark-plan branch July 8, 2026 15:45
ai-agent-on-behalf-of-john-hughes Bot pushed a commit that referenced this pull request Jul 9, 2026
… labeling, inference wiring

Replacement for #11, which GitHub closed automatically when its base branch docs/multi-harness-community-benchmark-plan was deleted after #7 merged.

This keeps the official benchmark hardening stack visible and reviewable against main now that #7 has landed.

Original PR: #11

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **High Risk**
> Changes touch the official GitHub Actions eval path (labels integrity gates, multi-ablation matrix, cost caps, S3 aggregation), which are security- and correctness-critical for published benchmark results.
> 
> **Overview**
> **Official benchmark workflow** is expanded so dispatch can run **multiple ablations**, require a **frozen labels file**, and **fail closed** if `labels_sha256` in the run-input manifest does not match the labels JSONL before the matrix fans out. Matrix build adds **projected model cost** caps (from registry pricing and packet token estimates), **repeat sampling** for selected cases, and stricter input validation. Per-case jobs now write to a **cycle-scoped S3 results root** and pass **repeat count**; a new **aggregate-results** job downloads artifacts and runs `legalforecast.publication.official_aggregate` (optional baselines, cycle-power metadata), then **syncs public bundles to S3** and uploads CI artifacts.
> 
> **Release and community surfaces** add a **`v*` tag workflow** that reruns `scripts/release_check.py` and can publish wheels/sdist to PyPI plus GitHub release assets, and a **community multi-harness validation** workflow (tests, submission validation, publication guardrails, dry-run aggregate; on `main`, builds a static-site artifact). Checked-in **fixture community submission packages** and **adapter/contributor docs** document the non-official multi-harness path.
> 
> **Project docs** update agent beads sync to a **centralized Dolt server** (no `bd dolt push/pull`), refresh **pilot model release anchors** and workflow defaults, add **labeling protocol** and README positioning (Brier skill vs baselines, contamination/snapshot caveats), and note deprecated preregistration/result-tier concepts in agent scope.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit 5789966. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->

<!-- This is an auto-generated comment: release notes by coderabbit.ai -->

## Summary by CodeRabbit

* **New Features**
  * Added repeat-run benchmarking, lawyer review/adjudication flow, packet render verification, and richer leaderboard/cadence reporting.
  * Expanded model registry and release metadata tracking for clearer release-date anchoring.
* **Bug Fixes**
  * Tightened release-anchor checks, leakage screening, and validation for model/version consistency.
  * Improved handling of missing or ambiguous labeling details.
* **Documentation**
  * Updated docs and release notes guidance for benchmark setup, labeling protocol, and prior-art positioning.
* **Chores**
  * Refreshed workflow action pins and release-check automation.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
ai-agent-on-behalf-of-john-hughes Bot pushed a commit that referenced this pull request Jul 12, 2026
## Summary

- fail closed before legacy Bedrock subprocess work when Claude Sonnet 5 is selected, including matching Bedrock IDs and ARNs
- harden multiharness result secret hygiene for fail-fast cleanup, native writes, and resumed artifacts
- pin the command-adapter environment allowlist regression against a planted `FAKE_SECRET`
- refresh eligibility terminology and record the actual scope delivered by PR #7
- finish the remaining non-workflow #14 cleanup, including stable `textwrap.dedent` fixture rendering

## Validation

- `uv run ruff format`
- `uv run ruff check --fix`
- `uv run pyright`
- `uv run pytest -q` (928 passed, 2 skipped)

Fixes #26

Fixes #31

Refs #10

Refs #14

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Medium Risk**
> Touches live model routing and multiharness public artifact hygiene on eval/community paths; behavior is intentionally stricter (Sonnet 5 Bedrock blocked, resume/fail-fast secret checks) rather than broad refactors.
> 
> **Overview**
> Hardens **live eval** and **community multiharness** paths around misconfiguration and credential leakage, with small doc and release-smoke cleanup.
> 
> **Claude Sonnet 5 + legacy Bedrock** now **fails closed** with `LiveModelConfigError` before any Bedrock `InvokeModel` subprocess when `LFB_ANTHROPIC_RUNTIME` selects Bedrock, including Bedrock-style model ID overrides and ARNs. Operators are told to unset the runtime env var and use the direct Anthropic API instead of attempting unsupported legacy transport.
> 
> **Multiharness** runs **`validate_no_secret_values`** on resumed `result.json`, native LFB results before public write, and existing post-run checks. Under **`fail_fast`**, a rejected post-run result **deletes** `result.json` so a failed secret scan cannot leave a public artifact (native path included). Tests cover resume when secrets were planted in stale results and fail-fast cleanup for command and native rows.
> 
> **Command-adapter** env allowlist tests use a planted **`FAKE_SECRET`** instead of a generically named undeclared var. **Eligibility** docstring for `decision_entered_on_or_after_model_deployment` now refers to **`series_release_timestamp`** (UTC date), not “deployment date.” **ADR 0001** records the real merged scope of PR #7’s community multiharness work and is linked from the docs index. **Release-check** fixture adapter script rendering uses **`textwrap.dedent`** with a **pinned length/SHA-256** stability test.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit 8de0eaa. Bugbot is set up for automated code reviews on this repo. Configure [here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->

<!-- This is an auto-generated comment: release notes by coderabbit.ai -->

## Summary by CodeRabbit

* **Bug Fixes**
  * Added clearer validation for unsupported legacy Bedrock configurations using Sonnet 5, preventing requests from reaching the runtime.
  * Improved run security by detecting secrets in resumed and native results.
  * Failed runs now remove publicly visible result files when validation rejects their output.

* **Documentation**
  * Added an architectural decision record documenting the community multi-harness scope and its distinction from official benchmarks.

* **Tests**
  * Added coverage for blocked model configurations, secret leakage prevention, fail-fast cleanup, and stable release-check output.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
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