Promotion: pre-freeze batch — stage enablement, claim scoring, sal-v2 groundwork - #1019
Draft
modelmirror wants to merge 46 commits into
Draft
Promotion: pre-freeze batch — stage enablement, claim scoring, sal-v2 groundwork#1019modelmirror wants to merge 46 commits into
modelmirror wants to merge 46 commits into
Conversation
Bumps the python group with 4 updates: [apsw](https://github.com/rogerbinns/apsw), [boto3](https://github.com/boto/boto3), [ruff](https://github.com/astral-sh/ruff) and [types-pyyaml](https://github.com/python/typeshed). Updates `apsw` from 3.53.3.1 to 3.53.4.0 - [Release notes](https://github.com/rogerbinns/apsw/releases) - [Changelog](https://github.com/rogerbinns/apsw/blob/master/doc/changes.rst) - [Commits](rogerbinns/apsw@3.53.3.1...3.53.4.0) Updates `boto3` from 1.43.53 to 1.43.59 - [Release notes](https://github.com/boto/boto3/releases) - [Commits](boto/boto3@1.43.53...1.43.59) Updates `ruff` from 0.15.22 to 0.16.0 - [Release notes](https://github.com/astral-sh/ruff/releases) - [Changelog](https://github.com/astral-sh/ruff/blob/main/CHANGELOG.md) - [Commits](astral-sh/ruff@0.15.22...0.16.0) Updates `types-pyyaml` from 6.0.12.20260518 to 6.0.12.20260724 - [Commits](https://github.com/python/typeshed/commits) --- updated-dependencies: - dependency-name: apsw dependency-version: 3.53.4.0 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: python - dependency-name: boto3 dependency-version: 1.43.59 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: python - dependency-name: ruff dependency-version: 0.16.0 dependency-type: direct:development update-type: version-update:semver-minor dependency-group: python - dependency-name: types-pyyaml dependency-version: 6.0.12.20260724 dependency-type: direct:development update-type: version-update:semver-patch dependency-group: python ... Signed-off-by: dependabot[bot] <support@github.com>
Bumps the actions group with 4 updates: [github/codeql-action/init](https://github.com/github/codeql-action), [github/codeql-action/analyze](https://github.com/github/codeql-action), [aws-actions/configure-aws-credentials](https://github.com/aws-actions/configure-aws-credentials) and [anthropics/claude-code-action](https://github.com/anthropics/claude-code-action). Updates `github/codeql-action/init` from 4.37.3 to 4.37.4 - [Release notes](https://github.com/github/codeql-action/releases) - [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md) - [Commits](github/codeql-action@e4fba86...f205ea1) Updates `github/codeql-action/analyze` from 4.37.3 to 4.37.4 - [Release notes](https://github.com/github/codeql-action/releases) - [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md) - [Commits](github/codeql-action@e4fba86...f205ea1) Updates `aws-actions/configure-aws-credentials` from 6.2.2 to 6.2.3 - [Release notes](https://github.com/aws-actions/configure-aws-credentials/releases) - [Changelog](https://github.com/aws-actions/configure-aws-credentials/blob/main/CHANGELOG.md) - [Commits](aws-actions/configure-aws-credentials@517a711...e6de054) Updates `anthropics/claude-code-action` from 1.0.180 to 1.0.183 - [Release notes](https://github.com/anthropics/claude-code-action/releases) - [Commits](anthropics/claude-code-action@fa7e2f0...be7b93b) --- updated-dependencies: - dependency-name: github/codeql-action/init dependency-version: 4.37.4 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: actions - dependency-name: github/codeql-action/analyze dependency-version: 4.37.4 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: actions - dependency-name: aws-actions/configure-aws-credentials dependency-version: 6.2.3 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: actions - dependency-name: anthropics/claude-code-action dependency-version: 1.0.183 dependency-type: direct:production update-type: version-update:semver-patch dependency-group: actions ... Signed-off-by: dependabot[bot] <support@github.com>
…on-6d89d027fe chore(deps): bump the python group with 4 updates
…staging/actions-d662d045fd chore(deps): bump the actions group with 4 updates
) Sweeps the committed docs surfaces for statements written before the first staging-to-main promotion that no longer describe the current design: main-base requireability, the sync-staging bootstrap caveat, the auto deploy-environment resolution, the run-seed refresh/dedupe tail, the counsel column's legacy rows, denial-sampling present-tense leftovers, the sal-v1 feature list, the inert interim reserve, and CLI/backtest dispatch surfaces. Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
chore: sync main into staging
The main-base merge-routing job joins main's required status checks (ruleset 'main: require PR'), closing the gap where a mis-routed feature PR went red without being blocked. Updates every surface that records the required set: the pinned list in tests/test_required_checks.py, the ci.yml comments, the promotion section and one-time-setup checklist in docs/pipeline.md, the ruleset inventories in docs/security.md, and the public copy in SECURITY.md. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
chore: sync main into staging
… procedure example Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
chore: record main-base as a required check on main
* fix(corpus): drop cluster-joined fields from bulk circuit rows The bulk export's docket-to-opinion-cluster join is misjoined on the circuit slices (19th-century cluster text and OCR-garbled judge names on 2018-19 dockets — an id-space collision in the staged join), so the storage projection drops summary, precedential_status, judges, and panel for a bulk-sourced non-SCOTUS row instead of storing text the join cannot vouch for. Those columns take the incoming value on upsert, so a re-served bulk row also clears any stored misjoin. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * docs: record the bulk-circuit cluster-field carve-out per review Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(corpus): extend the bulk-circuit carve-out to the citation fields citation_count is populated on 1.36M of 1.56M non-SCOTUS rows — the same row count as precedential_status — so the misjoined cluster join supplied it too, and it feeds the outcome-evidence predicates. citations rides along for provenance symmetry (empty on every circuit row today). Docs in corpus/README.md and the replica section of docs/data-pipeline.md record the carve-out where a pivot implementer will read it. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
* fix(corpus): max-latch has_opinion across upserts The presence bit is monotone — an opinion once linked is never unlinked — and every writer asserts it (NOT NULL, default False), so without a latch a docket-only re-ingest flips a stored True back to False and the case silently drops out of query --full and every presence check. Joins the distribution_count / escalation-signal max-latch family; the model validator already keeps the bit monotonic in memory. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * chore: tighten the latch comment per review Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
…rompt) (#1002) * fix(metrics): version-pin the band base-rate pool A band name is meaningful only under the salience version that assigned it, and the nested risk sets compound a mismatch: moving one cutpoint moves every rate below it. _pooled_band_rate now pools only statpack Terms whose salience_version matches the version that produced the band (the frozen context's version on the risk-set path, the live scorer's on the terminal path); no matching Term yields the contracted None, so brier_skill_score is omitted rather than computed against a blend no version ever defined. All committed Terms are sal-v1, so no published number moves. Rule recorded in docs/salience.md beside the base-rate contract. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * docs: correct the version-pin rationale per review The cutpoint-move mechanism sentence was wrong — a moved cutpoint changes membership of exactly one risk set, since the moved rows sit inside every weaker band's risk set either way — so the rationale rests on the populations-sharing-a-label argument alone. The bias/variance paragraph's bounded-window clause is reconciled with the pin (the window carries no versioning duty), the fallback chain's terminal-basis mirror case is named, and the doc anchors on the public entry points. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * prompt(evaluate): carry the version pin to the agent-side baseline The evaluator agent, not the code path, publishes forward skill — and its pooling recipe read the band table with no version check, so a transition-time cell would compute exactly the cross-version number the pin forbids. The table's heading names its salience version; on a mismatch with the prediction's frozen version the agent omits the baseline and flags it. docs/salience.md names the agent-side half beside the code rule. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * chore: object sentinel for the context fixture per review Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
* docs(outcome-decomposition): pre-register the pre-freeze scope Adds the eighth forecastability test (a baseline within rounding of 0 lets shotgunning back in through the level tests 1-7 never check); records that Prediction.context closes the as-at-prediction end of an increment claim, replacing the one-field-away text; states the scope decision that claim scoring sits outside the frozen process (the evaluator prompt's do-not-score rule is itself digest-hashed), so the first declared set arrives as a deliberate new process version; and fixes the mechanical-semantic agreement definition (Kendall tau-b, intersection-only with printed n and a suppression floor of 10, a record-not-predictor availability mask, never pooled or ranked) so defining it after grades exist cannot be a judgment call. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * docs: reproducible arithmetic and selection guards per stats review The worked example states its p (0.74 is exact for p=0.5; p=1 reads ~0.99); the eighth test grounds its failure mode in the realized total collapsing to a Bernoulli draw rather than in the rule's expectation, and marks itself the stated exception to the fineness preference; the agreement intersection counts operational absences beside its n; the context-block coverage boundary is named time-skewed; the noting rate carries its public-record provenance. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * docs+schema: finish the premise flip per review The correction that Prediction.context closes the prediction-time end left four passages asserting the old premise — the failure narrative, the scoreable-today intro, the withdrawn-claim table row, and the signals-block presence paragraph (whose antecedent the rewrite had stolen; it now names Outcome.signals and contrasts the context block's signals_observable line). The ResolutionSignals docstring and the Outcome.signals description said the opposite of the doc they cite, so they are corrected with the schema regenerated. The coverage sentence states plainly that every committed prediction predates the block. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
…ntity (#1006) * docs(salience): pre-register the sal-v2 intent; pin the carve-out identity Records the two-cohort sal-v2 design before the freeze fixes sal-v1: an arrival cohort with a load-bearing random-sample component (the only cohort whose skill transfers to live prospective use) and an escalation cohort on its own risk-set baselines, never pooled; a new frozen version, never an in-place edit; fitting deferred to the denial-complete re-walk with the replay bar recomputed there. The emergent identity between the carve-out set and the high band (floor in config, cutpoint in code) is now pinned by an exhaustive lattice test plus a public-predicate check. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * test: drive the lattice through the public scorer per review Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
* chore(metrics): bound the base-rate lookback at ten Terms salience.base_rate_lookback_terms moves 0 -> 10, matching statpack.markdown_terms, so the scored baseline and the band table the agents anchor on share one window by construction and cannot silently diverge as walked Terms accumulate. With nine Terms walked the bound excludes nothing: every published skill number is unchanged. Docs and the shipped-value pin updated in step. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * docs: bring every shipped-window statement to the new value per review metrics/README.md, the segment_base_rate docstring, the outcome-decomposition free-variance example, the SalienceConfig field comment, the StatpackConfig docstring, and the cert back-test's None-fallback docstring all stated the old shipped value as fact; each now states the ten-Term window (or names the field default as the absent-file fallback it is). The between-Terms timing clause returns to the config comment. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
* fix(pipeline): only case-baseline events earn forecast cells Two halves of one leak. (a) A substantive motion event minted on a cert docket rode the case into every predict queue — live re-poll, selection sweep, route_result, pull, and the matrix's default-event resolution — where a cell would be forecast by the cert-shaped prompt and scored against cert band base rates. The new store.forecastable_events seam filters prediction targeting to petition/appeal kinds; open_events stays unfiltered for evaluate, outcome detection, rotation, and the corpus service, because a motion's ground truth is still tracked. (b) A decided docket whose one open event is a motion inherited the case-level cert disposition in detect_resolution; the committed ledger carries exactly that shape. Attribution now requires a case-baseline (petition/appeal) event id; anything else lands unrecorded with its own reason. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * test+docs: pin the two case-baseline encodings together per review Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * docs+test: seam coverage and stale open-events prose per review The pull-queue payload test pins that a changed case with an open stay motion queues predict with the baseline event only; every surface that described the predict default as 'all open events' (the --event help, the matrix docstrings, pipeline.md's trigger diagram, data-pipeline.md, open_events' own docstring, the salience sweep prose) now says case-baseline events; the UnrecordedOutcome contract acknowledges the slugified event-id interpolation. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * chore: rewrap the open_events docstring Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
* feat(events): carry the decision stage on the event surface Every event definition — corpus row and materialized event.yaml — now names the decision standard that governs it (cert / interim / merits), stamped at minting: a SCOTUS petition's baseline event is cert-stage, a circuit appeal declares none. Nullable and additive, so every committed record and every older corpus opens and validates unchanged. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * docs+schemas: null stage means unrecorded, not standard-free; stale neighbors Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(corpus): tolerate pre-stage remote blobs; stamp interim on SCOTUS applications Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * test: hoist the corpus_ranged import to module level Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Serves metrics/statpack.{json,md}: beside the sal-v1 salience-band axis the
pack gains a stage section for the interim application docket (strict YYAnnn
form), pack-level and per application-Term year — counts by parsed ask
(extension / substantive / unknown, never-parsed kept apart), and over the
substantive slice only the resolved/granted counts, a raw descriptive grant
rate, and the escalation-signal counts (response requested, referred to the
Court, amicus on file). This is the accumulating cohort that will eventually
ground an interim segment base rate; until one is specified the published cut
is descriptive only, and extensions never pool into any rate.
Modeled as its own section type (StatPackInterim, no salience_version), fed by
the same single corpus pass, and omitted from the serialized pack — not
emitted as null — while the corpus holds no application rows, so a pack built
from an application-free corpus serializes with no interim key at all (pinned
by a committed-pack round-trip regression test). Resolved counts gate on
machine-readable interim dispositions and out-of-vocabulary kind values fold
visibly into the unknown bucket, so corrupt external input can neither deflate
the rate nor break the kind-split identity. The cert sections, Term entries,
and band tables are untouched; a merits sibling joins the same way once a
merits judgment column exists to feed it.
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
…s scoring (#1013) The declared cert-stage set of three (disposition, relist-increment, cvsg-increment) under pipeline.claims: the declaration table, the resolvers with the availability mask, strictly-prior baselines (disposition reuses prediction_base_rate; the increments are honestly baseline-less until the statpack carries per-Term relist/CVSG cuts), and the score_claims orchestrator wiring the pre-registered claim_score rule. Prediction.claims and Evaluation.claim_scores carry the blocks (optional, so committed records validate); both prompts carry the claim contract; the outcome-decomposition doc states the declared set as current design. Issue #903 (mechanical family only — the semantic family stays pre-registered). Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
#1014) Artifact: metrics/leaderboard.json grows a stage axis — the ranked board is explicitly the cert stage, any non-cert stage reports its own unranked per-predictor block under `stages` (omitted while empty), and every stratum block now carries `skill_scored`, the visible denominator behind `mean_brier_skill_score`. Verified a no-op on the committed artifact: all 9 committed cells stratify as cert and the rebuilt board is byte-identical to the committed metrics/leaderboard.json, so the file is deliberately not regenerated here (the metrics refresh owns it). Upstream of the board, outcome attribution is stage-routed: the case-level cert disposition attributes to the open event whose stage is cert — an open interim motion beside it stays open instead of forcing a refusal — with the case-baseline id-prefix rule kept as the stage-less fallback and every refusal reason preserved verbatim. The stratification join (store.iter_stratified_evaluations) reads each event's stage off its event.yaml, normalizing a null stage on petition/appeal kinds to cert. Reviewed by code-reviewer, stats-reviewer, and docs-reviewer; their blockers (a committed-data byte test that would redden path-jailed collect PRs, and a false universal claim about pre-vocabulary events) are fixed — the byte test now round-trips the committed artifact against its own schema instead of rebuilding from data/. Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
…e section (#1015) Groundwork for the merits base rate (#1009): granted SCOTUS cases' stored terminal docket entries now feed a deterministic merits axis. - pipeline/judgment.py: sentence-anchored parser from a disposition entry onto the Judgment vocabulary (plain verbs with the lower-court prose gap, in-part variants in either order, DIG, equally divided, and the canonical GVR order behind its cert recital), the disturbed projection (DIG / equally divided leave the judgment below standing), a best-effort authorship reader, and the backfill pass over granted rows reading the same stored-snapshot path the salience replay uses. - corpus: additive merits_judgment / merits_decided columns owned by the backfill pass (keep-stored upsert latch, set_merits_judgment sole writer); the decided_before retrieval mask now strips the pair fail-closed unless merits_decided provably precedes the clock, so query priors carry no post-clock outcome facts into replay cells. - CLI: backfill-merits-judgments (dry-run default, --apply), idempotent, with degradation counted (no_snapshot / no_match / stale), runnable standalone or from the run-seed corpus-writer lane. - statpack: the merits stage section (per-grant-Term counts, six-way judgment distribution, descriptive disturbed rate with its coverage beside it), omitted byte-identically while no row carries a judgment; claim contract in metrics/README.md. Artifact served: the statpack's merits stage section, and downstream the merits Brier baseline feed. Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
…1016) Artifact: a truthfully-labeled interim event surface — the precondition for interim prediction. A SCOTUS YYAnnn application docket is a stay/injunction motion governed by the interim standard, not a cert petition, but its baseline event was minted cert-shaped (evt-petition-disposition / kind=petition / stage=cert). This PR makes the event surface say what the docket is: - default_event mints kind=motion / evt-motion-disposition / stage=interim for application dockets (strict YYAnnn key, the same identity the live channel addresses and the migration converges on); cert dockets and circuit appeals unchanged. - corpus.rename_event: atomic upsert-new + delete-old primitive; the resolved latch is MAX across the old row, the incoming event, and any pre-existing row under the new id; casestore events mirror re-mirrored; same-identity and missing-subject calls fail loud. - application_migration.relabel_application_baseline_events + CLI relabel-application-events (dry-run default): deterministic, offline, idempotent corpus migration renaming the cert-shaped baselines. Skips and reports (never folds) a case with committed ledger artifacts under the old identity or an entry-pinned evt-motion-disposition row. - pipeline.outcome: form-keyed application guard (tolerant recognizer) — an application docket never takes the cert rule regardless of its baseline's current shape, closing the deploy-to-migration window; its resolution routes to the unrecorded queue with a reason naming the interim standard. Interim outcome recording is stage-keyed and ships with the interim predict path, backfilling from the row's disposition. Migration execution (corpus-writer lane; interactive sessions cannot dispatch workflows — run where the corpus is pulled, serialized with the corpus-write concurrency group): uv run fedcourts corpus-pull uv run fedcourts relabel-application-events # dry-run; review counts + skips uv run fedcourts relabel-application-events --apply uv run fedcourts corpus-push git add corpus/corpus.db.ref && git commit -m "corpus: relabel application-docket baseline events to motion/interim" # push via the data lane, as run-seed's maintenance sweeps do Reviewed by code-reviewer and stats-reviewer subagents; both blockers fixed in their suggested direction (form-keyed outcome guard + migration skip guards, conditioned application-rotation visibility prose with a scope-latched test). Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
…1017) * feat(metrics): add the claim-score surface and its judge validation The artifact is metrics/claim-scores.json — the #904 predicted-reasoning analytics surface: per predictor x stratum mechanical claim-total means with the floor and lift beside them, per-claim mean scores, the largest single-claim contribution, and the pre-registered per-stratum Kendall tau-b judge validation (mechanical claim total vs reasoning_quality) over the intersection population, suppressed below 10 pairs with the counts still published. Committed in its honest fully-suppressed state: no committed evaluation carries a claim_scores block yet. `fedcourts claim-scores` produces it, sharing the leaderboard's stratified join and frozen-scope default; the refresh plan lists it and the corpus-status gate tracks it. The run-analytics workflow's "Regenerate the metrics artifacts" step still needs the one-line addition `uv run fedcourts claim-scores` after `uv run fedcourts leaderboard` (workflows are maintainer-lane, so it is not part of this change). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * refactor(claim-metrics): resolve reviewer findings on the claim-score surface The event is the reporting unit: blocks deduplicate to one per (case, event) before averaging (the newest evaluation's block wins where copies could ever differ), with `cells` beside `events` as the raw census and `scored_events` as the one denominator of the three means. The judge validation publishes `pair_events` beside the per-cell `pairs` its suppression keys on, so evaluator multiplicity is visible where it matters most. The contract now also states the process-version comparability rule and that the absence counts cover committed cells only; the inverted `cells_with_claims` description is fixed; `kendall_tau_b` is public now that two modules call it. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
…nted dockets in the live rotation (#1018) The artifact is the open merits event (evt-order-judgment, kind order, stage merits, opened on the grant date) plus a granted docket that keeps polling toward its judgment: previously a cert grant resolved the petition event and the docket exited corpus.live_rotation (disposition latched), so no channel would ever observe the merits decision. - resolve_case mints the merits event after outcome attribution (the detection pass never sees it among the open set), SCOTUS-only, for granted / granted-in-part; gvr and summary-reversal terminate the case at the cert order and mint nothing. Idempotent via the events upsert's (case_id, event_id) key and resolved MAX-latch; the ledger event.yaml is written from the post-upsert state so it honours the same latch. - live_rotation admits a granted-set docket carrying an open merits-stage event until date_decided lands; the granted-set SQL literal is built from schemas.GRANTED_DISPOSITIONS (moved from outcome._GRANTED as the single source). A retained granted docket's stale conference date is masked out of the distributed-leads ordering. - Re-polls of a retained granted docket are a clean no-op: when a resolved cert-home already carries the (still granted-set, still undated-decided) disposition, nothing is recorded or triaged; a latched date_decided or a mutated disposition falls through to the conservative unrecorded surface. - The merits event is ground truth tracking only: kind order is not forecastable, so no predict cell fans out and no judgment detection resolves it yet. Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
) A GVR and a summary reversal grant the petition and dispose of the judgment in the same order, so neither is followed by briefing, argument, or a separate judgment to forecast. The minting rule already excluded them; the judgment backfill and the statpack's merits section did not, admitting every row with a cert grant date. That put a near-certain vacatur into the rate meant to describe argued cases — on the real corpus, 555 of 1,235 admitted rows were GVRs, and 98 of 244 parsed judgments came from them, inflating the disturbed rate from 0.740 to 0.844 with cases no one was asked to predict. One definition now governs every merits-population question — which grants mint the event, which rows the backfill parses, which rows the statpack describes — so the population that is predicted is the population the base rate is measured over. Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Artifact: retrieval logs that cannot carry a credential into a committed artifact. `retrieval_log.json` is harvested from the engine's own transcript, which records whatever a tool call carried — not what the agent chose to write. A codex payload keyed `message` put a Fernet-encrypted token into a query slice verbatim, and the collect job's secret scan withheld the whole run's PR: the gate did its job, but the capture path had no redaction at all. `fedcourtsai.secretscan` now owns `redact_credentials()`, a pure rewrite of credential-shaped runs to a `[redacted:<rule>]` marker: the scan's own structured patterns plus Fernet, JWT, `sk-`, `AIza`/`ya29.`; a credential-keyword/auth-header assignment rule; and, as a last resort, the scan's calibrated entropy discriminator at a 64-char floor rather than 40, because a redaction false positive silently eats evidence the leakage grading reads while a scan false positive costs one human look. `fedcourtsai.retrieval` applies it to every string it harvests, ahead of the 500-char cut, over a fixed window so an agent cannot choose how much work capture does. Redaction is not a gate — it lets through a run the scan would have withheld — so `record-retrieval` reports how many calls it rewrote and warns when the count is non-zero, and the shapes it cannot name still meet the scan. Measured over the committed ledger: 0 of 32,880 transcript strings in 413 retrieval logs are altered, and the widened keyword list flags no new line in 7,239 data files. Touches SECURITY.md and docs/security.md, which describe the outcome this changes for one artifact — maintainer lane, not self-merge. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…ial-redaction fix(retrieval): redact credential-shaped values at capture
…e reserve (#1020) * feat(interim): open the interim predict gates, quota'd by the salience reserve The artifact is the first fundable interim predict cell — gates open, quota enforced, outcomes recordable. A substantive SCOTUS application (stay, injunction, vacatur) now enters predict scope, its motion/interim baseline becomes forecastable, the live application rotation queues it forward on a docket change (daily-debounced, leakage-guarded by a form-keyed interim disposal scan), the selection pass funds up to interim_reserve_slots (5) concurrent applications by displacing rank fill inside the current conference's N, and a machine-matched interim resolution records the stage-keyed outcome.json (interim vocabulary, disposing-entry date, no cert signals block). Skill over the interim stage stays unscored: the segment base rate and its estimator publish only at the pre-registered 25-substantive- resolved floor, and an application cell's frozen context carries no cert band so no cert-population baseline can reach it. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * fix(interim): gate the interim fan-out on the application docket form A cert docket carries interim-stage events too — an entry-pinned stay or injunction motion on the petition's own docket — and a cert docket is in scope, so the stage and scope rules alone admitted one. Its cell would then freeze the petition's salience band as its conditioning, scoring an interim forecast against a cert population. The docket form is what the admission's own contract already described; now the code implements it. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> * fix(interim): refuse an application docket's cert-shaped baseline Narrowing the scope rules to admit substantive applications releases their predict_excluded latch, and an application whose baseline still reads petition-kind then satisfied the case-baseline rule on the strength of the kind alone — forecasting a stay application under the cert contract, against a cert population. Discovery mints an application's baseline as the interim-stage motion, but a row minted before that rule keeps the cert-shaped id, so forecastability must be correct on its own terms: the migration changes which event is forecast, never whether a mislabeled one is. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
…im cells (#1022) The artifact is the first runnable interim cell — its prompt contract and its offline proof. The interim predict gates are open, so a stay/injunction application now fans out to the same predict/evaluate cells cert petitions do, against prompts that described only the cert stage. Both prompts now select on the `stage` the provisioned `event.yaml` records. The cert content is framed as the cert path and otherwise unchanged; an interim section states what the event resolves to, what the record carries in place of the cert signals (the escalation ladder), and what a predictor may not treat as a yardstick. The interim rules, keyed to what the code does: - The resolver emits four labels only (`granted`/`denied`/`withdrawn`/ `dismissed`) and matches denial language first, so `probability` is P(an unqualified grant) — scoring partial relief as a grant would over-state the forecast on the mixed shadow-docket shape. - No `claims` block: only petition-kind events declare a set. - The evaluator computes `correct`/`brier_score` identically and omits `segment_base_rate` and `brier_skill_score` with `base_rate_basis` null, no flag — a standing stage rule, not a per-cell anomaly. No interim segment base rate is published until the pre-registered 25-resolved floor. - The band rules key on the frozen conditioning rather than the docket's shape, so an interim cell that carries a cert band declines it and flags the mismatch instead of anchoring on a population it does not belong to. The offline proof: the fixture corpus gains a resolved substantive stay application (`26A11`), whose motion baseline carries `Stage.interim`, and the cascade smoke drives it provision -> predict -> interim outcome -> evaluate -> validate, landing it in the leaderboard's unranked `interim` block. The stub now answers the declared cert claim set, so the cert path exercises that contract too. The rules the smoke composes are pinned at their own seams: the absent cert baseline, the interim `signals` guard, and the fixture's agreement with the production event mint. Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
…aseline (#1025) The artifact is the scoreable merits cell: a judgment, P(disturbed) as the Brier axis, a mandatory per-Justice vote block, and the baseline that makes a skill claim meaningful. Schema. `Prediction.judgment` mirrors `Outcome.judgment`, with a model validator holding "judgment set => votes non-empty" — the half a prediction can enforce alone, since it does not carry its event's stage. The other half is a `validate` check reading the committed `event.yaml`: a merits-stage event's latest-per-predictor prediction must carry a judgment. `Evaluation.judgment_correct` records the exact-match on the full vocabulary, and `Evaluation.base_rate_salience_version` records which salience version the segment base rate was read under — harness-stamped in `stamp-cell --role evaluator` from the recorded basis, never the evaluator's word. Detection. The live poll latches `merits_judgment` / `merits_decided` at ingest through the shared parser on a granted cert docket, the corpus upsert latches the pair atomically, and outcome detection resolves the open merits-stage event from those columns alone — one deterministic seam rather than two. A merits outcome records `other` for the cert vocabulary it has no member of, carries the result on the judgment axis, and declares judgment-disturbed as `actual_granted`, so one Brier formula serves every stage. Resolving the event closes the case's last open event and the docket leaves the rotation. Scoring. `merits_base_rate` pools the statpack merits section's per-grant-Term `disturbed` over `parsed`, strictly-prior. That section's population is already the scored population — the grants that open a merits proceeding, the same rule that mints the event — so the baseline is measured over exactly the cases a merits cell is drawn from, and a GVR's near-certain vacatur (a cert-stage disposition the cert sections already carry) never anchors a merits forecast. The pool is keyed on the grant Term on both sides (read from the merits event's `opened_at`), because the docket-number Term runs a Term later for a summer-docketed pre-October grant and would admit the case's own cohort; it must also clear a stated minimum sample, since the section exists from its first parsed judgment and `brier_skill` masks exactly the cells a degenerate baseline got right. On a merits cell `correct` is the judgment match, so the stage block's accuracy is a real number rather than a constant the predictor sets. `merits-v1` declares one claim, `judgment-disturbed`. The per-Justice vote, split, and authorship claims were tested against the eight forecastability tests and dropped: no committed resolution channel (docket text discloses no provenance denominator), no strictly-prior committed baseline, and a nine-to-one re-encoding of one correlated insight. The vote block stays mandatory as elicitation, scored intersection-only when a real vote source lands. Merits cells still do not fan out — the merits event is not a forecastable kind until its prompt contract ships, so a cell can never run ahead of the prompt that defines it. Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Add docs/predicted-artifacts.md, a per-artifact walk of everything one predict cell writes: prediction.json with its per-stage differences (cert, interim, merits), the two prose documents, retrieval.md, flags.json, and tooling.json — plus the harness-written files and stamps a cell does not author, and a short cross-reference to what the evaluate side does with a prediction. The purpose is to make what a prediction constitutes legible without reading the pydantic models. Every JSON example is invented data and validates against its model. README's data-model section and AGENTS.md's doc table point at it. Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
… proof The artifact is the first runnable merits cell: the prompt contract that tells a predictor and an evaluator what a merits event is, the fan-out that mints one, the provisioning guard that lets it keep its snapshot, and an offline cascade that drives it end to end. Prompts. `predict.md` gains `### Stage: merits`: the judgment vocabulary, `probability` read as P(disturbed) with DIG and an equally divided affirmance declared undisturbed, the mandatory vote block and why naming a Justice costs nothing, what the granted docket does and does not disclose (the merits briefs and the argument are recorded as events, never as text, and the provisioned documents are cert-stage), the cert signals and the frozen salience band being spent rather than wrong, the statpack merits section on its stated terms — the ten-Term window counted rather than read off an untruncated table, the 30-parsed floor, the grant-Term axis, the censoring direction — and the one declared `merits-v1` claim. `evaluate.md` gains the matching rules: `correct` routed on the outcome's judgment, `judgment_correct` beside it, the merits baseline in `segment_base_rate`, and `base_rate_basis` left null — which is what makes the harness stamp `base_rate_salience_version` null, correct because the merits pool is no salience-band product. No merits cell publishes a skill score. `docs/decision-model.md` pre-registers that no merits skill number may be published against a pool whose grant Terms carry unlabelled GVRs, and that the fan-out owes a label-independent guard first. That guard is not built. Detecting the contaminated Terms per cell was considered and rejected: the escapees show up as a partly-labelled Term rather than an empty one, and the table an evaluator can read is keyed on the docket-number Term, so the test would pass exactly the Terms the pack's own caveat names. So `brier_skill_score` is omitted on every merits cell, stated in the prompt and enforced by a new `validate` check rather than left to prose. `segment_base_rate` is still recorded — the pool the cell faced is a fact about the run, and recording it is not a skill claim over it. Fan-out. `store.forecastable_events` gains the merits admission, keyed on the merits stage, an unlatched judgment, and `opens_merits_proceeding` on the row — the same predicate that mints the event and that the statpack merits section measures its rate over, re-checked so a docket re-resolved to `gvr` sheds its cell. The guard test it replaces is now five, one per arm. The residue the predicate cannot close — predict scope excludes IFP grants, the merits population does not — is stated at the seam with its size rather than bounded away. Provisioning. The forward-cell leakage guard is keyed on the event, because one docket carries several events' outcomes at once: a granted docket's grant order is a disclosed cert outcome and is also what opens the merits proceeding, so without the key every merits cell would be refused by the entry that minted it and would run snapshot-less and context-less. On the merits event the test is a parsed judgment plus the cert scan's own recall minus its one cert-before- judgment grant branch — the conservative parser alone would let "Opinion Issued" through, and the two failure costs point in opposite directions. Proof. The offline cascade smoke drives a merits cell provision -> stub predict -> judgment outcome -> evaluate -> validate over the fixture's granted docket, and asserts it lands in the leaderboard's unranked `merits` stages block with nothing entering the cert board. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
feat(prompts): the merits stage contract, and the merits fan-out
…ing seam (#1028) The artifact: a semantic reasoning-scoring seam that exists, is exercised end to end against synthetic graded fixtures, and produces nothing. It serves no published number today by design — it exists so that when opinion bodies land, iterating on the methodology is a declaration plus a prompt rather than a new shape. `semantic-v0` is **alpha**: provisional, never tested against a real opinion, and explicitly not a pre-registered commitment of the kind `cert-v1` and `merits-v1` are. What makes that honest rather than a loophole is that nothing depends on it — the process freeze governs the digest (prompt bytes plus the resolved actor config), no prompt asks a cell for a semantic claim, so no digest moves, no cell produces a grade, and no committed artifact carries one. The mechanical family's contract is untouched, and the new section states that where the two appear to conflict the pre-registered rule governs. The load-bearing design decision: a semantic grade is **never** run through `claim_score`. That rule needs a harness-computed prior from strictly-prior history, a proposition like "the majority rests on textualist grounds" has no such frequency, and every route to manufacturing one fails against a rule this document already carries. So a semantic claim earns an ordinal grade — supported / partially-supported / unsupported, plus `not-addressed` as an availability mask that is a property of the record — reported descriptively with leave-one-out inter-grader agreement beside it. Whether any baseline is ever derivable is left open as an empirical question for when text exists. - `docs/outcome-decomposition.md`: the methodology, quarantined from the pre-registered body — the claim vocabulary sketched with the eight tests applied candidate by candidate (and one alpha test the eight cannot supply), the grading protocol, the agreement requirement, the supersession rule, and what remains unbuilt. - `pipeline/semantic.py`: declaration tables that are empty on purpose and authoritative over any grader's block, plus the descriptive roll-up. - Schema blocks optional everywhere, so every committed artifact still validates; `Stratum` moves to `schemas` so a census can type its population on the closed vocabulary. - `metrics/README.md`: what may and may not be read off a grade, written before the surface exists so a first publication has a contract to meet. Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
The artifact: an evaluate cell whose grader forms `reasoning_quality` — the semantic side of the pre-registered judge validation — without the predictor's identity in view. `docs/outcome-decomposition.md` registered this as the precondition on scoring semantic claims and recorded that the harness could not deliver it, because the evaluator read `predictions/<predictor_id>/<run_id>/` and wrote under a path keyed on the same id. `fedcourtsai.blinding` supplies both halves. `provision_blinded_predictions` stages each predictor's latest prediction into the gitignored `record/blinded/<alias>/` under an opaque alias assigned by a keyed shuffle over the run, case, and event — never predictor-id sort order, which would leave the alias a lookup performed by inspection. Identity fields are masked, the prose is staged under harness-chosen names, and predictor ids, evaluator ids, and engine/model names are scrubbed from every staged byte; `usage.json`, `tooling.json`, and `flags.json` are not staged at all. `unblind_evaluations` renames the alias-keyed output onto the real predictor ids, rewrites the `predictor_id` field, and resolves aliases in the evaluator's prose and flags so a leakage note reaching a maintainer names a predictor. Ordering is load-bearing and documented in four places: un-aliasing runs before `stamp-cell --role evaluator`, whose prediction join misses under an alias and drops `claim_scores` and `base_rate_salience_version` silently rather than failing. `validate`'s `check_evaluation_targets` resolves the same join and is the loud backstop. What this buys is stated where the numbers are read rather than claimed broadly: it removes the predictor's *name*, and the engine stays legible from the staged transcript's tool vocabulary, which the leakage grading needs intact. `metrics/README.md` now carries the rule that blinded and unblinded grades are two populations. The workflow wiring ships separately as a maintainer-lane PR (`.github/workflows/` is not this lane), so this half is inert until that lands. The two must reach `main` in the same promotion batch: the prompt change moves all three evaluator digests, and a digest that moves without the information-set change it advertises is worse than no digest move. Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Artifact: `metrics/leaderboard.json`. Each `LeaderboardStratum` (and each stage block) gains `population_realized_term_skill_score` with its own `realized_term_skill_scored` denominator — the same salience band and the same risk-set basis as the existing skill column, scored against the grant rate the case's OWN October Term realized rather than the strictly-prior pool. The two decompose skill per cell. Prior-Term skill rewards knowing the level AND discriminating within it, so a Term that ran hot or cold credits or penalises every predictor for the shift. Realized-Term skill holds the level at what obtained and leaves discrimination: a predictor with the Term's level right but no ability to separate its cases reads positive on the first and ~0 on the second, and one that beat history while losing to the Term reads positive then negative. The baseline is leave-one-out — the scored case sits inside its own Term's rate, and one case moves a seventy-row band by well over a point. The pack publishes no grant count, so the numerator is reconstructed as `round(rate * weighted_resolved)` (a ratio of integer weighted counts) and the case comes off it on the pack's own grant-family definition, promoted to `schemas.GRANT_FAMILY_DISPOSITIONS` so `analytics` and the subtraction cannot diverge — `granted-in-part` is a granted binary outcome the published rate's numerator never counted. `REALIZED_BAND_RATE_MIN_RESOLVED` (30) binds on both the leave-one-out weighted denominator and the observed row count behind it, since a reweighted Term can clear a weighted 31 on five real petitions. It is ex post: no predictor could have known its Term's realized rate, so it never ranks (the rank key is untouched), is never pooled or averaged with the prior-Term column, and carries its scope rules in the claim contract — cert stage only, version-pinned, statpack-vintage, and mid-Term grant-depleted in a direction that does not average out. Computed at board build from the committed pack rather than carried on a cell, because a Term's own rate keeps moving until the Term closes; `run-analytics` therefore regenerates the board after the pack, and `corpus-status`'s hand-regeneration message names the same order. Both columns now aggregate as a population ratio, `1 - sum(brier) / sum(baseline_brier)`, rather than a mean of per-cell ratios, and are renamed `population_*` so the estimator travels with the number rather than only with its description (the `mean_*` fields beside them really are per-cell means). The per-cell ratio caps at +1 but is unbounded below, so under cert's class imbalance a mean of ratios is dominated by low-baseline denial cells and pays a predictor to under-forecast the rare event: on the committed pack's OT2025 segments an always-deny forecaster means to +0.94 / +0.75 / -0.40 across the bands against +0.002 to +0.03 for the honest level-only forecaster, an inverted ordering that also swings on band mix. The ratio of sums prices the same forecaster at -0.05 / -0.20 / -0.75. Because the prior column's value is now derived from the cell's recorded `segment_base_rate` and outcome rather than read off its recorded ratio — the aggregate needs the baseline term, which a ratio cannot yield back on a cell whose Brier is zero — and `Evaluation` constrains no relation between its own numbers, the derivation is checked against the record: a cell whose recorded skill does not reproduce from its own inputs is omitted, visibly, from `skill_scored`, rather than published on a baseline it was never graded against. The board is empty and no digest is frozen, so no published number moves, and the committed `metrics/leaderboard.json` rebuilds byte-identically. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
feat(metrics): realized-Term skill beside prior-Term skill, and a corrected aggregation
…sweeps Three steps, all maintainer-lane, all inert until their code is on main. run-evaluate gains the blinding bracket: stage each predictor's latest prediction under an opaque alias before the agent runs, un-alias before the stamp. The second position is load-bearing — stamp-cell joins an evaluation to its prediction on predictor_id, and under an alias that join misses and drops claim_scores and base_rate_salience_version silently rather than failing. run-seed gains two convergence sweeps beside the scope reconcile it mirrors: the application-baseline relabel and the merits-judgment backfill. Both belong in the lane rather than a dev checkout because the corpus pointer is a git file the writers commit to main and corpus-push is last-writer-wins, so a stale local copy republishes over concurrent walks; the corpus-write concurrency group is what serializes them. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
chore(workflows): wire blind grading, and the two corpus convergence sweeps
…rics The artifact is committed and the CLI is tested, but nothing regenerated it — the refresh rolled the leaderboard, backtest, statpack and scope manifest and stopped there, so the claim-score board would have gone stale the moment the first evaluation carried a claim block. Placed beside the leaderboard, outside the corpus gate: it reads only the committed ledger, and pairing the two evaluation-derived artifacts means they refresh from one tree state rather than two. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…efresh chore(workflows): regenerate the claim-score board with the other metrics
An earlier single-open-event attribution shortcut duplicated a petition's cert disposition onto sibling events; such records still sit in the committed ledger and would otherwise be frozen into the pre-registration record. A copy is identified by duplication — the outcome repeats a case-baseline sibling's (actual_disposition, resolved_at, actual_granted) exactly — not by date ordering, which is a faithful upstream shape on this docket source rather than evidence of fabrication. Repair deletes the outcome and reopens the event in both stores, corpus first so an interrupted run stays detectable. Only non-baseline events are repaired: reopening a case-baseline event makes it the stage-less fallback's target, so the resolution pass would rewrite what was deleted. A duplication between two case-baseline events is reported for triage, as are an event the corpus does not know and one carrying committed agent output. Closes #1010. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…outcomes fix(ledger): reopen outcomes copied from a sibling case-baseline event
At SCOTUS the petition is the case, and nothing separately predictable arrives by appeal — the "notice of appeal" wording reaches a SCOTUS docket inside a record-transmittal line from the court below. Minting on it produces a second case-baseline id, the one shape _cert_disposition_target cannot disambiguate, so the case-level disposition attaches to whichever of the two it lands on rather than to the petition it decides. The existing petition collapse now covers both kinds. Adds remove-unmintable-events for the rows already written that way: an entry-pinned SCOTUS event carrying a case-baseline id, dropped from the ledger directory then the corpus row — the convergent order for a corpus-driven scan, since the row is the sweep's detection handle. It refuses an event carrying committed agent output, one whose outcome copies no case-baseline sibling's, and an unrecognized directory shape. Closes #1033. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
…-guard fix(events): a SCOTUS appeal entry collapses into the case baseline
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Promotion batch (draft — held until the batch completes)
Do not merge yet. This drafts the next staging→main promotion so the batch is visible as it assembles. The maintainer-dispatched
promoteworkflow re-runs the gate, sync and freshness checks at merge time regardless. Merges as a merge commit (promotion ancestry rule).Landed on staging
Stage enablement — cert, interim and merits are one pipeline now
stageon the event surface (cert / interim / merits), stamped at minting, ranged-blob tolerantskill_scoredpublishes the skill mean's true denominatorevt-motion-disposition/ interim, with an idempotent migrationinterim_reserve_slots: 5enforced inside N, interim outcomes recordedPrediction.judgment, P(disturbed) as the Brier axis, mandatory votes,merits-v1, the registered baseline, andEvaluation.base_rate_salience_versionClaim scoring and its surface
cert-v1mechanical claim set, declared and harness-scored (moves every actor digest)metrics/claim-scores.jsonand the judge-validation tau-b, suppressed below n=10Scoring the predictors, not just the predictions
Security
SECURITY.md)Workflows (maintainer-merged)
claim-scoresin the metrics refreshLedger hygiene
reopen-misattributed-outcomes: the repair for outcomes copied from a case-baseline siblingremove-unmintable-eventsfor the row already written that wayBoth change no data by merging; their
--apply+data/commit is a maintainer step, because neither collect jail admits deleting anoutcome.json.Docs
docs/predicted-artifacts.md: what one prediction consists of, every example machine-validatedEarlier in the window: #1000–#1006 (corpus fixes, version-pinned band pool, pre-registration docs, lookback pin, forecastable-events seam, sal-v2 intent).
Still to join
Issues this batch closes
#903, #904, #1007, #1008, #1009 already hand-closed on staging merge; #864, #907 and #963 close after promotion. #1010 and #1033 close when the two ledger applies land as a
data/commit onmain— the tools are merged; the records are not yet removed.Maintainer actions
run-seed's writer lane, so neither needs a dispatch — they converge on the schedule against the pointer the writers own (corpus-pushis last-writer-wins, so a dev-checkout run would silently discard concurrent writes).data/commit, in this order:outcome.jsonand rewrites anevent.yaml, whichassert_within_jail(adds only) andassert_cleanup_within_jail(deletes underpredictions/only) both refuse. Independent of the promotion; touches onlydata/.mainthat lacks the redaction fix), then freshfedcourts process-digest --allon the promoted tree → paste into chore(metrics): freeze the proc-v1 process digests #991 → merge-commit chore(metrics): freeze the proc-v1 process digests #991 → bless (metrics: bless the settled process digest into the frozen set and record the freeze commit #907).