Repository navigation
Code Tribunal 3.0.0
Upgrade
Follow the 3.0 upgrade: pause reviews,
migrate state to v2 offline, remove retired configuration, then adopt the
SHA-pinned GitHub reusable caller or protected GitLab direct include together
with both 3.0 images. A rollback restores the saved deployment and v1 state
together.
Changed
-
Read Cursor's final text output rather than its aggregated JSON result.
Intermediate answer drafts can no longer make an otherwise valid final batch
ambiguous; conflicting JSON roots in the final answer still fail validation. -
Breaking: remove severity downgrading (S11). Delete the entire
critiqueYAML
section, includingcritique.allow_severity_downgrade. Critics' severity
suggestions remain informational dissent; final severity, independent support,
noise demotion and absence-based resolution retain their existing rules. -
Breaking: new inline comments use a single line (S15), with spanning ranges
shown in their body. Deleteposting.inline_multiline; failed creates go
directly to summary fallback. Old/new/context sides, historical multiline
threads, human commands and thread identity remain supported; existing comment
positions do not move. -
Inline markers stop writing the unused zero
source=attribute. Historical
markers remain readable and marker-only differences do not force thread edits.
The shorter marker frees visible-body space near the platform limit, so some
previously truncated bodies may refresh once. Rollback to 2.0.3 is no longer
supported; rolling back state to 2.1.x requires the saved v1 exports. -
Simplify artifact contract tests (S12): remove the reflection-based schema/type
comparator and test concrete production output and malformed admission instead.
JSON schemas retain wire-contract authority; production types remain internal
annotations. -
Breaking: each
finding_batch.v2andcritique_batch.v2is the complete
execution outcome (S06), with timing and bounded redacted diagnostics. Status
JSON mirrors,adapter_status.v1and consensus--status-dirare removed;
out/status/keeps only diagnostic text. Accepted counts and review eligibility
are derived from the payload rather than stored. Pooling and consensus share
admission that binds every present outcome, including failures, to its filename,
registry seat and exact run/config. Missing outcomes degrade health; malformed
or misbound present outcomes fail integrity validation.batch_missingis
removed from unreleasedconsensus.v3. Upgrade both images and canonical
invocations together and generate fresh artifacts from prepare.
Publication/state and eligibility policy are unchanged. -
Breaking: configuration moves to
review_config.v4(S04). Prepare resolves
shipped defaults, sparse custom reviewer settings and operator overrides once;
downstream stages validate the complete manifest configuration without reading
YAML or reapplying environment overrides. Consensus and post no longer accept
--config. One blind critique round, all supported inline sides, FYI summary
placement, stale-head protection and external-fork secret refusal are
unconditional. Delete their old YAML switches andAI_REVIEW_CRITIQUE_ENABLED;
unsupported keys andAI_REVIEW_variables receive generic migration errors.
Per-version removal tables and environment tombstones are deleted. Explicit
effort: nullor the existingunsetenvironment value clears inherited
effort. Absence-based resolution is unchanged. Upgrade the canonical
workflow/include and both images together and run fresh artifacts from prepare;
see the configuration migration. -
Breaking: GitLab supports protected direct includes only (N02). The child stage
wrapper andparent_pipelinerules are removed; replace the trigger job with a
top-level include and retain theai_reviewstage before upgrading. The trust
auditor no longer takes--mode. Protect the CI composition and restrict
pipeline variables as described in the GitLab installation
guide. Panel, lifecycle and hostile canaries
run in the MR pipeline itself. -
Breaking: GitHub consumers call
.github/workflows/ai-review-reusable.ymlat a
reviewed release SHA (N03). The copied canonical template and synchronization
tooling are deleted; this repository uses a small same-commit caller. Caller
Actions variables remain the configuration source, and secrets are inherited or
passed by name. Optional required checks change fromposttoai-review / postwith the documented caller. The canary runs through the caller and
reusable workflow; historical 2.1 publication retries retain their original
byte-parity check. See the GitHub installation
guide. -
Breaking: state v2 lives inside the bot's summary comment (S14/N04). An explicit
offline converter,scripts/migrate_state_v2.py, preserves thread IDs and human
dispositions from exported v1 notes; pause reviews, apply its emitted update,
and remove the obsolete state note before switching images. Runtime rejects v1,
corrupt, duplicate and inaccessible state. The wrapper checksum,
self-referentialstate_note_id, unread history, candidate/title/symbol
aliases, unreadremap_statusand legacydropstate decisions are removed.
Checksum, load-error, marker-recovery, per-status retention and
max_state_bytescontrols are removed (the platform comment limit bounds the
ledger); active records and human dispositions are preserved, with a fixed tail
of five automatically resolved records. Matching uses issue IDs, source finding
IDs and path/category/context hashes. Posting uses each current group's prepared
anchor instead of fetching another diff and remapping old coordinates (N14).
Same-revision bot-thread reconciliation recovers from interrupted publication
for current finding/command identities, or all eligible open roots when no
ledger exists. GitHub checks thread resolution before reuse so resurfaced
compacted findings stay visible. Compacted, absent roots are not re-imported.
State is validated before writing, supported returned thread-ID sizes are
reserved before publication, and GitHub repository renames/transfers refresh the
stored slug on load. See the state migration and missing-ledger repair in
docs/operations.md. -
Breaking: reviewers author compact
locationranges and finding content;
trusted finalization derives paths, line codes, context hashes, fingerprints and
finding IDs from the prepared diff (S05). Critiques use short pool-local IDs
such asF001, resolved against the exact run/config/critic-bound pool held in
runner memory. Unknown IDs fail the critique batch. Numericconfidenceis
removed from findings and critiques; severity, stable finding IDs and content
determine caps and representatives. Every candidate is validated before the cap,
so malformed and cap-omitted findings have separate counts in the existing
run-health report.finding_batch.v2,critique_batch.v2and
pooled_findings.v2replace v1; generate fresh artifacts with one image pair
instead of replaying old ones. -
Breaking: consensus uses only this run's evidence (N11).
consensus.v3assigns
signature-derived issue IDs and removesissue_id_source,state_match,
group.body_hash, thedropdecision andsummary.drop_count;run_healthis
required. Prepare no longer writesstate_aliases.json, and consensus no longer
accepts--state. Posting alone matches the latest authenticated state,
preserving historical thread IDs and human commands. Ambiguous or
already-claimed matches use summary fallback without changing the reducer's
decision or automatically resolving candidate threads. Re-run from prepare with
one image pair; v2 consensus artifacts are rejected. -
Reviewer output is captured in private temporary files instead of memory and
pump threads (S09). The runner checks a 32 MiB budget per stream every 100 ms
and reports excess output asmodel_errorwith bounded, redacted stdout and
stderr tails, preserving process-group cleanup and stage timeouts. After
normal completion, job logs show only the final 4,000 redacted stderr
characters. The internalAI_REVIEW_STREAM_ADAPTER_LOGSswitch is removed;
bounded, redacted parse and timeout artifacts remain available. Diagnostics
redact complete secret spans before truncation, including multiline keys.
Unicode secret values and control-character whitespace remain masked across
tail boundaries. Incomplete private-key blocks are redacted through
end-of-file, and repeated malformed PEM or JWT prefixes are scanned without
quadratic rescans, keeping timeout diagnostics responsive. Rendered findings
may keep prose after a standalone backtick-quoted PEM header; key blocks and
recognizable key payloads after it stay masked. Output-limit log tails
neutralize GitHub Actions workflow commands on every diagnostic line.
The CLI restores normal child reaping whenSIGCHLDwas inherited as ignored;
process-group cleanup retains the leader PID until signalling, preventing ID
reuse races. -
Input preparation resolves GitHub revision metadata through the platform
client and checks the revision before collection and manifest publication
(N17). The workflow's JavaScript resolver is removed; automatic runs check out
their event SHA and manual runs pass the checked-out PR head SHA for validation
against the API, including on the currently pinned image. Prepare uses
python -Pwith the trusted image's import path to prevent checkout packages
from running before the fork check. Forks remain refused before input
collection. The manifest no longer writes the unreaddiff_sha256and
repo_snapshot_sha256fields; effective-config and whole-manifest bindings
remain. -
Configuration is resolved into frozen typed settings and shared through each
runtime stage (N05). Defaults are centralized, and prepare no longer loads the
configuration twice. The public YAML options and environment-drift checks
remain; omitted defaults are now explicit in the manifest's effective config.
Invalid integer settings report configuration errors naming the full setting
path, including limits, state retention, and reviewer finding caps. -
Reviewer workspace, isolated-home, environment, CLI argument and schema setup
is declared in the trusted registry and shared in Python (N08). Claude now has
an isolated home, and its image-build probes use the runtime invocation. The
remaining shell adapters only check prerequisites and invoke their CLI. -
Mock reviews and critiques are selected only by the Python runner with
AI_REVIEW_LOCAL_MOCK=1andAI_REVIEW_ALLOW_LOCAL_MOCK=true(S03).
Real adapters always fail on a missing CLI or credential. The shell and
OpenCode mock fallback paths, per-seatAI_REVIEW_REQUIRE_REAL_*controls,
and refusal-text matching are removed; deterministic canary scenarios and
artifact formats remain the same. -
Reviewer output parsing now uses the codec declared in the trusted reviewer
registry (N06). The retired OpenCode CLI stream formats and stage inference
are removed. Current answer-text fallbacks and versioned batch artifacts are
unchanged; adapter mocks emit the selected reviewer's transport format. -
The runner launches the OpenCode seat as
python -m ai_review.opencode_client
under its own interpreter, andadapters/opencode.shis deleted (N07). The
OpenCode server's environment now carries only its own settings, and an image
that shipped a pinnedopencodebut lost it fails instead of falling back to
the mock. The runner also pins every seat'sPYTHONPATHto its own package
instead of forwarding the ambient value. Configuration, prompts, requests and
output are unchanged.
Known limitations
The live GitHub fork-skip check remains pending: no separate authorized namespace
was available for a temporary fork of the demo. Same-repository automatic/manual
caller verification does not establish fork behavior; the canonical fork guard
continues to have regression coverage.
The GitLab hostile campaign uses an unprotected in-project source rather than a
fork. Cursor's deny policy has invocation coverage but no live hostile permission
probe, so Cursor remains outside the default roster. The uniform mock does not
exercise below-quorum FYI, unmappable inline fallback, majority-noise demotion or
invalid-location loss live; regression tests cover these paths. Live truncation,
platform-visible comment re-anchoring and the symlink containment variant remain
outside this release's evidence. Non-default effort routes beyond the configured
Codex medium external-caller check remain unproven. Updating a
thread body does not move its original platform diff position.
Release identity
- Runtime source (R):
a9208beed5ef0244ebfad9602937c59469fcb944 - Release commit (P):
3113d1c0ed914bdfa6c2741059686687d1c8d968 - Base image:
ghcr.io/seanleecoder/code-tribunal/ai-review-base:3.0-a9208beed5ef0244ebfad9602937c59469fcb944@sha256:46a22aa49e9df4c1a09523df9960bfed0e59772bfef3bdfc7c62ea8d55637dd6 - Reviewer image:
ghcr.io/seanleecoder/code-tribunal/ai-review-reviewer:3.0-a9208beed5ef0244ebfad9602937c59469fcb944@sha256:6c4259eb7a3a95b3f2568033856c5c1e50aaefb181b0bcf76b5eb660af911e83 - Candidate Canary: https://github.com/seanleecoder/code-tribunal/actions/runs/41353175842
- panel / github: full panel, 6 threads posted, cleanup succeeded
- panel / gitlab: full panel, 4 threads posted, cleanup succeeded
- lifecycle / github: 7/7 steps passed
- lifecycle / gitlab: 6/6 steps passed
- hostile / gitlab: 5/5 steps passed
- Publication: https://github.com/seanleecoder/code-tribunal/actions/runs/41354902025
Verify an image's build provenance, for example the reviewer image:
gh attestation verify oci://ghcr.io/seanleecoder/code-tribunal/ai-review-reviewer:3.0-a9208beed5ef0244ebfad9602937c59469fcb944@sha256:6c4259eb7a3a95b3f2568033856c5c1e50aaefb181b0bcf76b5eb660af911e83 \
--repo seanleecoder/code-tribunal \
--predicate-type https://slsa.dev/provenance/v1 \
--source-ref refs/heads/main --source-digest a9208beed5ef0244ebfad9602937c59469fcb944 \
--cert-identity https://github.com/seanleecoder/code-tribunal/.github/workflows/publish-ai-review-images.yml@refs/heads/main