Skip to content

fix(provenance): the late sweep may only complete TERMINAL worker attempts - #63

Merged
stranske merged 13 commits into
mainfrom
claude/recursing-stonebraker-98ee3e
Aug 23, 2026
Merged

fix(provenance): the late sweep may only complete TERMINAL worker attempts#63
stranske merged 13 commits into
mainfrom
claude/recursing-stonebraker-98ee3e

Conversation

@stranske

@stranske stranske commented Aug 23, 2026

Copy link
Copy Markdown
Owner

Follow-up to the one CodeRabbit thread on #42 that was never verified against the code — thread 3837879039. Verified real before patching, with the caveat that CodeRabbit's own check used a synthetic in-memory table it invented rather than the real schema, so the finding needed independent confirmation.

The defect

resolve_unresolved_worker_attempts selected on operation_role='worker' AND resolved_model IS NULL AND profile_id IS NOT NULL with no status predicate. The profile attempt row is written started before the subprocess is spawned (dispatcher.py:1511, exp_abcd.py:412), so an in-flight attempt matched every clause. adapters.cli_reported_model reads the first model in the session log within a 2h window of started_ts, and that log exists from the moment the CLI starts — so a run still executing probes clean.

Reproduced on a real tmp ledger via the real code path:

before:  ('r-inflight', 'started', None, None)          # worker still running
after:   ('r-inflight', 'complete', 'gpt-5.6-terra', 1787490879)

That is the one row shape CLAUDE.md §2 permits to support an exact-model claim — a successful operation_role=worker attempt with a provider-resolved model — minted for a worker that had not finished and could still fall back, retry onto another model, or fail outright. It corrupts the Brain silently rather than failing loudly.

The status lifecycle

status writer terminal? eligible?
started pre-dispatch record_execution_attempt no — in flight no
unresolved complete_profile_attempt_unresolved yes yes — the drain
complete complete_profile_attempt yes already resolved (excluded by resolved_model IS NULL)
failed complete_profile_attempt_unresolved(status="failed"), dispatcher.py:999 yes, but never ran no

The filter is status='unresolved', which also excludes failed (profile_process_start_failed): terminal, but the process never started, so there is no served model to recover and resolving it from a neighbouring session in the 2h window would be pure invention. CodeRabbit's rationale named only started.

Not a starved drain

A started row is excluded only while it is in flight. Its own completion closes it to complete (resolved — no sweep needed) or unresolved (eligible on the next pass), so the exclusion clears itself without the sweep's help. Measured read-only on the live ledger: 56 candidates before the filter, 56 after — every genuinely drainable row is already unresolved.

Exclusions are counted, never silently narrowed: excluded_not_terminal reports them keyed by status, beside candidates, matching the existing excluded_unreportable convention. candidates: 0 next to {"started": 3} reads as "wait for those runs to finish"; candidates: 0 alone reads as "the sweep is broken".

Coverage

One new test pins all three cases — terminal unresolved is swept, in-flight started is left alone, never-ran failed is left alone. All three runs share one workspace so the probe resolves for every one of them, making the status filter the only thing that can protect the two ineligible rows.

Deliberate break→revert, both ways:

  • In-test: a connection proxy strips the status clause, restoring the pre-fix query; asserts the corruption reappears (a running worker stamped with an exact model and a completion timestamp it never earned).
  • At source: deleting the clause from the query fails the test on the in-flight assertion; restored, green.

Verification

python3 verify.py388 passed, 0 failed, 0 skipped, 83/83 selftests, 5/5 gates, in the worktree and from a mirror-shaped copy at a different path. The exec mirror was independently confirmed green at its current 387 baseline (synced to af6654d, so current with main and missing only this fix). The mirror sync is deliberately left undone — per CLAUDE.md §1 it is the circuit breaker between an agent's change and the dispatcher, so it is due after merge, not before.

Floor 387 → 388, hand-edited with rationale (--update-floor clobbers the note). No ceiling moved and nothing new is skipped: the test builds its own tmp ledger and rollout fixture, so it runs on a bare runner. Ruff unchanged from the HEAD baseline (9 pre-existing findings, none added).

Three sibling follow-up branches are in flight against this same main; if .verify-floor.json conflicts, resolve as the union and re-measure on the new merge result rather than taking either number.

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Bug Fixes

    • Reconciliation now processes only terminal unresolved attempts, leaving in-progress and failed attempts unchanged.
    • Added reporting for excluded attempts by status.
    • Eligible attempts continue to resolve using the model information reported by the CLI.
  • Tests

    • Added regression coverage for reconciliation behavior, including safeguards against incorrectly completing active work.
    • Updated verification records to reflect 392 passing tests.

…empts

CodeRabbit finding on PR #42 (thread 3837879039), verified real against the
real code path before patching.

`resolve_unresolved_worker_attempts` selected on `operation_role='worker' AND
resolved_model IS NULL AND profile_id IS NOT NULL` with no status predicate. The
profile attempt row is written `started` BEFORE the subprocess is spawned
(dispatcher.py:1511, exp_abcd.py:412), so an IN-FLIGHT attempt matched every
clause. `adapters.cli_reported_model` reads the FIRST model in the session log
within a 2h window of `started_ts`, and that log exists from the moment the CLI
starts -- so a run still executing probes clean, and `--apply` stamped it
`complete` with a resolved model and a `completed_ts` off the sweep's own clock.
Reproduced on a real tmp ledger: a `started` row with completed_ts NULL became
('complete', 'gpt-5.6-terra', <sweep time>).

That is the one row shape CLAUDE.md §2 allows to support an exact-model claim --
a successful `operation_role=worker` attempt with a provider-resolved model --
minted for a worker that had not finished and could still fall back, retry onto
another model, or fail outright. It corrupts the Brain silently rather than
failing loudly.

The filter is `status='unresolved'`, which also excludes `failed` (dispatcher's
`profile_process_start_failed`): terminal, but it never ran, so there is no
served model to recover and resolving it from a neighbouring session in the
window would be invention. CodeRabbit's rationale named only `started`.

Not a starved drain: a `started` row is excluded only while in flight -- its own
completion closes it to `complete` (resolved, no sweep needed) or `unresolved`
(eligible next pass), so the exclusion clears itself without the sweep's help.
Measured read-only on the live ledger: 56 candidates before the filter, 56
after; every genuinely drainable row is already `unresolved`.

Exclusions are counted, never silently narrowed: `excluded_not_terminal` reports
them keyed by status, beside `candidates`, matching the existing
`excluded_unreportable` convention. `candidates: 0` next to `{started: 3}` reads
as "wait for those runs"; `candidates: 0` alone reads as "the sweep is broken".

Coverage: one new test pins all three cases -- terminal `unresolved` IS swept,
in-flight `started` is left alone, never-ran `failed` is left alone -- with all
three sharing one workspace so the probe resolves for every one of them and the
status filter is the only thing that can protect the two ineligible rows.
Includes an in-test deliberate break (a connection proxy that strips the status
clause, restoring the pre-fix query) asserting the corruption reappears.
Separately demonstrated break->revert at the source: deleting the clause from
the query fails the test on the in-flight assertion; restored, green.

FLOOR 387 -> 388, hand-edited with rationale (--update-floor clobbers the note).
No ceiling moved and nothing new is skipped: the test builds its own tmp ledger
and rollout fixture, so it runs on a bare runner.

verify.py: 388 passed, 0 failed, 0 skipped, 83/83 selftests, 5/5 gates -- in the
worktree and from a mirror-shaped copy at a different path. Ruff unchanged from
the HEAD baseline (9 pre-existing findings, none added).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Aug 23, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

You’ve reached a temporary PR review limit under our Fair Usage Limits Policy.

Your current included review allowance is based on your included PR review attempts over the past 7 days.

Next review available in: 19 minutes

Limit details: You’ve used the included review currently available. Your 74 included PR review attempts over the past 7 days set your current allowance at 1 review per hour.

Your organization has reached its usage spending cap. Adjust your spending cap in the billing tab.

How can I continue?

Wait for the limit to reset, then comment @coderabbitai review or push new commits to the PR.

An organization admin can change what happens after included review limits in Billing.

How do review limits work?

CodeRabbit enforces per-developer PR review limits within each organization.

For paid Pro and Pro+ reviews, CodeRabbit uses a developer's included PR review attempts over the past 7 days to set the current hourly allowance. At typical activity levels, the full plan allowance applies. Higher sustained activity can lower the allowance until earlier attempts leave the 7-day window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: a9977501-2b61-4fcc-851f-5ec32cae5998

📥 Commits

Reviewing files that changed from the base of the PR and between 596a622 and f5e215c.

📒 Files selected for processing (2)
  • .verify-floor.json
  • test_feedback_model_provenance.py

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 67d69edc-ff0c-4285-ad28-dae0bac0d1ef

📥 Commits

Reviewing files that changed from the base of the PR and between a19cf41 and 596a622.

📒 Files selected for processing (1)
  • langsmith-fleet-worker-attempt.json

Included review availability: 0 reviews are currently available. Your included PR review attempts over the past 7 days set your current allowance at 3 reviews per hour.


📝 Walkthrough

Walkthrough

The reconciliation resolver now processes only terminal unresolved worker attempts. It reports excluded non-terminal attempts by status. Regression coverage verifies the behavior and updates the recorded verification total to 392 tests.

Changes

Worker Attempt Reconciliation

Layer / File(s) Summary
Terminal attempt filtering
ledger_reconcile.py
The resolver now excludes started and failed attempts, and returns their status counts in excluded_not_terminal.
Reconciliation regression coverage
test_feedback_model_provenance.py, .verify-floor.json, langsmith-fleet-worker-attempt.json
The regression test validates terminal resolution, preservation of excluded attempts, status reporting, and the prior unfiltered-query behavior. The verification record reports 392 passed tests. Worker metadata records the updated timestamp and PR number.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Merge Risk: 🔵 Low · up to 596a6

The change prevents the late sweep from resolving in-flight or never-started worker attempts, limiting model provenance updates to terminal unresolved attempts. The PR is mergeable with owner awareness that the regression test should be maintained if the query formatting changes.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check. Docstring coverage is scoped to functions touched by this diff. Analyzed 0 functions across 0 files. (1 skipped: 1 unsupported.)
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.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the main fix: limiting the late sweep to terminal worker attempts.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch claude/recursing-stonebraker-98ee3e

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

…asured

Only `.verify-floor.json` conflicted, the collision this file's own note predicts
and which the branch note had already flagged as likely.

#59 (improvement-log accessor) raised the floor 387 -> 391 on main with four new
tests; this branch raised it 387 -> 388 with one. Resolved as the UNION, not by
taking a side: #59's rationale is retained and the count was RE-MEASURED on the
merge result rather than either number being carried over. 392 collected,
independently confirmed by `pytest --collect-only` before trusting the arithmetic
-- taking a side is what once put the floor 8 tests below reality.

verify.py on the merge result: 392 passed, 0 failed, 0 skipped, 84/84 selftests,
43/43 can-fire, 5/5 gates green.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@stranske-keepalive

stranske-keepalive Bot commented Aug 23, 2026

Copy link
Copy Markdown

Workflow source detected

PR #63 now has valid workflow source context (origin=review_followup).

No linked GitHub issue is required for this PR.

@stranske-keepalive

stranske-keepalive Bot commented Aug 23, 2026

Copy link
Copy Markdown

Automated Status Summary

Head SHA: 0a30a7c
Latest Runs: ⏳ pending — Gate
Required: core tests (3.12): ⏳ pending, core tests (3.13): ⏳ pending, docker smoke: ⏳ pending, gate: ⏳ pending

Workflow / Job Result Logs
(no jobs reported) ⏳ pending

Coverage Overview

  • Coverage history entries: 1

Coverage Trend

Metric Value
Current 48.10%
Baseline 0.00%
Delta +48.10%
Minimum 70.00%
Status ❌ Below minimum

Top Coverage Hotspots (lowest coverage)

File Coverage Missing
outcomes.py 9.0% 243
watch.py 9.6% 431
capability_recurrence_check.py 10.4% 421
durability_sweep.py 12.2% 339
keepalive_shadow.py 13.0% 282
capability_outcome_bridge.py 13.5% 295
keepalive_outcomes.py 14.0% 339
adversarial.py 14.1% 164
langsmith_fetch.py 14.3% 409
gh_capacity.py 14.6% 228
runtime_ac_panel.py 14.7% 290
capability_advisor.py 14.8% 807
redirect_shadow.py 16.9% 476
cross_repo_lane.py 17.3% 268
experiment_recovery.py 18.4% 164

Low Coverage Files (<50.0%)

File Coverage Missing
outcomes.py 9.0% 243
watch.py 9.6% 431
capability_recurrence_check.py 10.4% 421
durability_sweep.py 12.2% 339
keepalive_shadow.py 13.0% 282
capability_outcome_bridge.py 13.5% 295
keepalive_outcomes.py 14.0% 339
adversarial.py 14.1% 164
langsmith_fetch.py 14.3% 409
gh_capacity.py 14.6% 228
runtime_ac_panel.py 14.7% 290
capability_advisor.py 14.8% 807
redirect_shadow.py 16.9% 476
cross_repo_lane.py 17.3% 268
experiment_recovery.py 18.4% 164

Updated automatically; will refresh on subsequent CI/Docker completions.


Keepalive checklist

Scope

No scope information available

Tasks

  • No tasks defined

Acceptance criteria

  • No acceptance criteria defined

@stranske

stranske commented Aug 23, 2026

Copy link
Copy Markdown
Owner Author

Runner dispatch state for autofix on PR #63. Do not edit.

@stranske

stranske commented Aug 23, 2026

Copy link
Copy Markdown
Owner Author

Runner dispatch state for codex on PR #63. Do not edit.

@github-actions

github-actions Bot commented Aug 23, 2026

Copy link
Copy Markdown
Contributor

Workflow state fingerprint for Agents Gate Followups. Do not edit.

@github-actions

github-actions Bot commented Aug 23, 2026

Copy link
Copy Markdown
Contributor

Workflow state fingerprint for Keepalive Loop Reporter. Do not edit.

@stranske

Copy link
Copy Markdown
Owner Author

CI red here is #60's repo-wide breakage, not this change

All six Python checks on this PR (lint-ruff, lint-format, typecheck-mypy, python 3.12, python 3.13, summary) die at the same shared install step, before any tool runs:

Error: .../.github/workflows/autofix-versions.env is required;
       refusing to install unpinned tooling.

Job 97205943081, step 8 Install dependencies = failure, step 9 Ruff (lint) = skipped. Ruff never executed, so nothing here was measured against this diff.

Evidence it is not this branch:

So this PR cannot show green CI until #60 lands. Nothing to fix here; sequencing only.

Checked against the config #60 is about to introduce

Since #60 adds the repo's first ruff.toml, this change will be linted for the first time when that merges. Verified now against #60's branch config so this PR is not what breaks the newly-working gate:

ruff check --config <#60 ruff.toml>  ledger_reconcile.py test_feedback_model_provenance.py  →  All checks passed!
black --line-length 100 --check      ledger_reconcile.py test_feedback_model_provenance.py  →  2 files unchanged

Note line-length = 100 and select = ["E4","E7","E9","F","I"] there, with E501 deliberately unselected — the two added lines that exceeded 100 columns were already rewrapped to that convention before this was known, so no follow-up is needed.

Local verdict on the merge result stands: verify.py392 passed, 0 failed, 0 skipped, 84/84 selftests, 43/43 can-fire, 5/5 gates green.

@github-actions github-actions Bot added the autofix Let bots format/lint automatically label Aug 23, 2026
@github-actions github-actions Bot added the autofix:patch Autofix patch available label Aug 23, 2026
@github-actions

Copy link
Copy Markdown
Contributor

Autofix updated these files:

  • improvement_log.py
  • test_improvement_log.py

@github-actions github-actions Bot removed the autofix:patch Autofix patch available label Aug 23, 2026
Only `langsmith-fleet-worker-attempt.json` conflicted (add/add). It is not
source: it is a per-run artifact the Codex autofix runner writes into the working
tree and commits, so every PR through that runner overwrites the previous PR's
copy -- main's says `pr_number: 61`, this branch's autofix commit wrote `63`.
Whichever value wins is meaningless, so it is resolved to MAIN's copy, leaving
this PR's diff limited to the sweep fix rather than gratuitously rewriting an
unrelated artifact. Flagged separately; a tracked runtime artifact that every PR
rewrites will keep conflicting until it stops being tracked.

`.verify-floor.json` merged cleanly this time: #61 added no net new tests, so
main stayed at 391. RE-MEASURED rather than assumed, per the rule in that file --
`pytest --collect-only` reports 392, which is main's 391 plus this branch's one
new test, matching the already-recorded value. No adjustment needed.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@stranske

Copy link
Copy Markdown
Owner Author

Conflicts resolved; workflow source added

Conflict was langsmith-fleet-worker-attempt.json alone (add/add) — not source, but a per-run artifact the Codex autofix runner writes into the tree and commits, so every PR through that runner overwrites the previous one's copy. Main's says "pr_number": "61" (landed via #61); this branch's autofix commit e8d8706 wrote "63", 24 seconds apart. Whichever wins is meaningless, so it is resolved to main's copy, keeping this PR's diff limited to the sweep fix. Filed separately — a tracked runtime artifact that every run rewrites will keep conflicting on every concurrent PR until it stops being tracked, and per CLAUDE.md §1 it is evidence, not tool.

.verify-floor.json merged cleanly this time: #61 added no net new tests, so main stayed at 391. Re-measured anyway rather than assumed, per that file's own rule — pytest --collect-only reports 392, which is main's 391 plus this branch's one test, matching the recorded value. No adjustment.

Workflow source: added <!-- workflow-source:review_followup --> to the PR body, which is what this PR is.

Autofix's df19929 reformatted improvement_log.py / test_improvement_log.py#59's files, not this change's. Those are now byte-identical to main, so they contribute nothing to this diff. Diff vs origin/main is exactly three files: ledger_reconcile.py, test_feedback_model_provenance.py, .verify-floor.json.

verify.py on the new merge result: 392 passed, 0 failed, 0 skipped, 84/84 selftests, 43/43 can-fire, 5/5 gates green. Remaining CI red is still the missing autofix-versions.env pin file that #60 fixes — the install step dies before Ruff runs, so nothing here has been measured against this diff.

CodeRabbit thread 3838730241 on #63, verified: the break keyed on an exact
substring including the trailing space, so a reformatted query would make
`str.replace` a silent no-op. The filter would keep protecting the row, the
corruption assertion would fail, and its message would blame the fix rather than
the stale fixture. It fails RED either way -- no false green -- but it misdiagnoses,
and in this repo a check has to name its own cause.

Two guards, because there are two ways to go stale, and only one was proposed:

1. The clause MOVES within a still-recognisable query -- asserted per statement,
   naming the clause it expected and printing the actual SQL.
2. The query itself becomes UNRECOGNISABLE, so nothing is ever stripped -- caught
   after the run by `stripped`. The review's guarded snippet asserts only WHEN the
   FROM/JOIN + ORDER BY signature matches, so a rewrite that changes the signature
   leaves the break silently inert and its assert never runs. That is the same hole
   one level up.

Not the review's first proposal, which is tautological: `broken != sql or clause
not in sql` cannot fail, since `clause in sql` makes `broken != sql` necessarily
true and the other branch covers the rest. Its second snippet is the right shape
and is what guard 1 implements.

The candidate query is identified by its FROM/JOIN plus ORDER BY fragments; the
not-terminal count query shares the FROM/JOIN but ends in GROUP BY, so it is not
mistaken for the candidate and other SQL passes through untouched.

Both guards demonstrated then reverted:
  clause "unresolved" -> " = 'unresolved' "  =>  "deliberate break is STALE: the
    candidate query no longer contains ... Update this fixture" + the real SQL
  ORDER BY r.ts DESC -> ASC (valid rewrite)  =>  "deliberate break never fired:
    nothing matched the candidate query's ... the assertions below prove nothing"

No new test, so the floor stays 392 (re-measured: 392 collected). verify.py: 392
passed, 0 failed, 0 skipped, 84/84 selftests, 5/5 gates. Clean under #60's
incoming ruff config and black -l 100.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…e-measured

#60 landed the `.github/workflows/autofix-versions.env` pin file that every
Python check on this PR was dying on, at the shared `Install dependencies` step
before any tool ran. It also brings this repo's first `ruff.toml` and `mypy.ini`,
so this change is linted for real for the first time rather than under Ruff's
88-column defaults.

Checked against the config that actually landed, not the branch preview:
  ruff check ledger_reconcile.py test_feedback_model_provenance.py  -> passed
  ruff check .                        (the Gate's own command)      -> passed
  black --line-length 100 --check     on both files                 -> unchanged

`.verify-floor.json` conflicted, as it has every round. Resolved as the UNION:
main's note is kept whole (it carries #60's +11 tests and the #64/#65 rationale)
with this branch's entry appended, and the count RE-MEASURED on the merge result
rather than either side's number -- `pytest --collect-only` reports 403, which is
main's 402 plus this branch's one test. No ceiling moved; nothing new is skipped.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
#56 makes `collected` an EQUALITY rather than a minimum, so a floor that sits
below reality now goes RED instead of passing quietly. That turns "assume 402+1"
from a bad habit into a hard failure, which is the right direction and the reason
every round of this branch measured instead of deriving.

Union as before: main's note kept whole, this branch's entry appended, and the
count MEASURED on the merge result -- `pytest --collect-only` reports 403. Main
stayed at 402 across #56, so #56 added no collected tests and 403 is main's 402
plus this branch's one test. No ceiling moved.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@stranske

Copy link
Copy Markdown
Owner Author

CI is green — the change has now actually been measured

#60 merged, so the Install dependencies blocker is gone and the Python jobs ran against this diff for the first time:

check result
Gate / gate pass
python ci / lint-ruff pass
python ci / lint-format pass
python ci / python 3.12 pass
python ci / python 3.13 pass
summary pass
test-quality pass
ledger validation pass
python ci / typecheck-mypy skipped — deliberate, per #60's mypy.ini

54 checks: 25 pass, 29 skipping, 0 failing; combined commit status success. MERGEABLE / UNSTABLE appears to reflect the skipped checks rather than any failure — nothing is in a non-success state.

Also merged since: #56, which makes collected an equality rather than a minimum. That is why the floor was re-measured on every round of this branch instead of derived — pytest --collect-only reports 403 (main's 402 plus this branch's one test), and an assumed number would now be a hard RED rather than a quiet pass.

verify.py on the final merge result: 403 passed, 0 failed, 0 skipped, 84/84 selftests, 43/43 can-fire, 5/5 gates green.

One note on the diff

langsmith-fleet-worker-attempt.json shows 4 changed lines (emitted_at, pr_number). That is not part of this fix — it is the Codex autofix runner rewriting its own artifact, which it did three times on this branch. I resolved it to main's copy once; subsequent runs rewrote it again, and fighting it just invites another rewrite. Filed separately: a tracked runtime artifact that every run rewrites will keep conflicting on every concurrent PR. The substantive diff remains ledger_reconcile.py + test_feedback_model_provenance.py + the floor.

# Conflicts:
#	.verify-floor.json
#	langsmith-fleet-worker-attempt.json
The automated merge of origin/main spliced this branch's floor entry mid-token:
"FLOOR 407 -> 408 on 2026-08-23 (CodeRabbit follow-up ..." became "3 on
2026-08-23 (CodeRabbit follow-up ...", losing which transition the entry records.

The counts were already correct and agree with my own resolution of the same
conflict (408/408, re-measured independently: `pytest --collect-only` reports 408
= main fc1fd42's 407 plus this branch's one test). Only the prose was damaged, but
this note is the sole record of WHY each floor moved, so a fragment that no longer
names its transition is exactly the kind of unreadable evidence this file exists
to prevent.

Kept the automated merge's #68 entry rather than my own wording: it documents the
union more fully and gives the artifact resolution a provenance rationale --
main's NEWER langsmith-fleet worker-attempt record is retained, because
discarding a newer provenance observation to win a merge would corrupt exactly
the causal-provenance evidence CLAUDE.md section 2 protects. That is a better
reason than the one I used ("it is meaningless either way").

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Seventh floor union on this branch. main a247a55 records 410; the merge result
MEASURES 411 with `pytest --collect-only -q` -- main's 410 plus this branch's one
test. Measured, never derived: #56 made `collected` an EQUALITY, so an assumed
number is a hard RED.

#69 also flips CI coverage ON, so this branch's merge is the first to be measured
under it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@stranske
stranske merged commit 0593eeb into main Aug 23, 2026
26 checks passed
stranske pushed a commit that referenced this pull request Aug 23, 2026
langsmith-fleet-worker-attempt.json is a per-run CI provenance record, not
source. reusable-codex-run.yml (in stranske/Workflows) rewrites it on every
invocation and uploads it as artifact langsmith-fleet-v1-worker-attempt-<pr>.
It became tracked in 2118f57, and because gitignore does not apply to an
already-tracked path, the runner's `git add -A` commit step staged it on every
run: ten commits across PRs #59/#61/#62/#63, one add/add conflict per concurrent
PR, and a silently widened diff on each.

Nothing reads it from the tree. The langsmith-fleet/v1 consumers here
(langsmith_pull.py, langsmith_fetch.py) ingest the NDJSON Actions artifact
`langsmith-fleet.ndjson`; neither names this path. The 30-day artifact upload
already provides the replacement path, so untracking loses no provenance.
stranske/Workflows reached the same verdict for its own copy.

The ignore entry sits outside the synced WORKFLOWS STATUS FILES block, since
that block mirrors a consumer template which does not carry this pattern and
would drop it on the next rewrite.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
stranske added a commit that referenced this pull request Aug 23, 2026
langsmith-fleet-worker-attempt.json is a per-run CI provenance record, not
source. reusable-codex-run.yml (in stranske/Workflows) rewrites it on every
invocation and uploads it as artifact langsmith-fleet-v1-worker-attempt-<pr>.
It became tracked in 2118f57, and because gitignore does not apply to an
already-tracked path, the runner's `git add -A` commit step staged it on every
run: ten commits across PRs #59/#61/#62/#63, one add/add conflict per concurrent
PR, and a silently widened diff on each.

Nothing reads it from the tree. The langsmith-fleet/v1 consumers here
(langsmith_pull.py, langsmith_fetch.py) ingest the NDJSON Actions artifact
`langsmith-fleet.ndjson`; neither names this path. The 30-day artifact upload
already provides the replacement path, so untracking loses no provenance.
stranske/Workflows reached the same verdict for its own copy.

The ignore entry sits outside the synced WORKFLOWS STATUS FILES block, since
that block mirrors a consumer template which does not carry this pattern and
would drop it on the next rewrite.

Co-authored-by: t <t@e>
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
stranske pushed a commit that referenced this pull request Aug 23, 2026
…rop a claim #3210 falsifies

This branch ended up with two independent explanations of the same rule, because a
concurrent session added `4b5764a` while this branch already carried its own block.
Both were correct; having both in a file whose header is specifically about
gitignore-comment discipline is not.

Kept from the second block, because the first did not have it:
- the artifact was tracked from 2118f57, not merely "on main until today";
- ten commits across PRs #59/#61/#62/#63 rewrote it, one add/add conflict per
  concurrent PR, silently widening unrelated diffs;
- untracking loses no provenance — the producer already uploads the same bytes as
  Actions artifact `langsmith-fleet-v1-worker-attempt-<pr>` with 30-day retention,
  which is the only reason the file is written at all.

Dropped from it, because it is about to become false: "that block mirrors Workflows'
templates/consumer-repo/.gitignore, which does NOT carry this pattern". Workflows
PR #3210 adds exactly these two patterns to that template at Template-Version 6. The
placement above the managed block is still right, but the reason is that a version
bump rewrites the block wholesale — not that the template lacks the pattern.

Also drops that block's bare literal `langsmith-fleet-worker-attempt.json`, which was
already subsumed by the root-anchored `/langsmith-fleet*.json` above it.

Comments only. Verified identical behaviour with `git check-ignore`: the root artifact
and artifacts/langsmith/ stay ignored, docs/contracts/schemas/langsmith-fleet-v1.schema.json
and langsmith_*.py stay committable, and no tracked file is shadowed by any pattern.
427 collected = floor 427; black, ruff and the 11 guard tests unchanged.
@stranske
stranske deleted the claude/recursing-stonebraker-98ee3e branch August 23, 2026 22:37
stranske added a commit that referenced this pull request Aug 23, 2026
…both stranded post-merge (#84)

Both branches were held back from the branch cleanup because their tips carried commits pushed AFTER
their PR merged, so "PR merged" did not mean "work landed". Verified per-symbol rather than by diff
size — both branches are thousands of lines behind main, so a raw diff conflates stale with unlanded.

#42 / commit 4e0d6ae — `adapters.py` catalog resolution. Main has `advertised_models` and NONE of
the generalisation around it: `advertised_catalog`, `_advertised_catalog`, `_cached_catalog`,
`agy_log_for`, `AGY_LOG_SUFFIX`, `CATALOG_ROUTING_TAGS`, `_catalog_model_id` were all absent. This is
learning-loop provenance code (CLAUDE.md 2: "never treat a generic trace model as provider
resolution"), and its whole point is that THE CATALOG IS THE AUTHORITY — a label resolves against the
ids the CLI actually advertises, with routing TAGS (`auto`, `default`, `cli-default`) refused as
non-identities. The commit's own note records that `VENDOR_MODEL_RE` rejects 42 of 204 real cursor ids,
so shape-matching an id the CLI itself advertised is both redundant and wrong.

Cherry-picked; `adapters.py`, `dispatcher.py` and `ledger_reconcile.py` applied clean. Two conflicts:
  * `.verify-floor.json` — took main's. A floor is a property of the MERGE RESULT, never carried in
    from a branch, so it is re-measured below.
  * `test_feedback_model_provenance.py` — TWO DIFFERENT tests in one region: main's
    `test_late_sweep_completes_terminal_attempts_never_one_in_flight` (from #63) and the branch's
    `test_gemini_provenance_reads_the_per_run_log_before_the_conversation_store`. Kept BOTH; they are
    independent.

#34 / commit c1dc9a7 — README item 11 for `evidence_acquisition.py`, which main documented nowhere
(zero occurrences). Every factual claim was re-verified against main's code rather than trusted:
`capabilities.unblock()` exists; `ORCH_EVIDENCE_ACQUISITION_MAX_FEEDS`/`_MAX_ITEMS` default to 1 and
3; `LIVE_FLAG = "ORCH_EVIDENCE_ACQUISITION"` with SHADOW as the documented default; and the quoted
summary line matches the format string verbatim (`feedable {n} / capped {n} / candidates {n} /
fed {n}`). It is the drainable-vs-blocking line the latched-gate rule asks for, and it was the only
place that reported it.

DELIBERATE-BREAK -> REVERT: emptying `CATALOG_ROUTING_TAGS` fires
`assert model_id_for_label("cursor", "Auto (default)") is None` in adapters' OWN selftest; reverted
clean. Worth recording that `pytest test_feedback_model_provenance.py` did NOT catch that break —
the guard is covered by a `--selftest`, not by a test_*.py, which is precisely why `verify.py` is the
gate and a pytest subset is not. A redundant pytest test written before checking was dropped.

FLOOR 427 -> 428, one new test, note appended not replaced.

Verified FRESH-STATE (both ORCH_STATE_DIR and ORCH_LOCAL_RUNTIME at empty dirs, reproducing CI):
VERIFIED — 420 passed, 0 failed, 79 selftests, 3/5 gates green, 8 tests + 5 selftests + 2 gates
skipped for named prerequisites; 420 + 8 = 428 = floor. ruff + black -l 100 clean.

NOT FIXED HERE, and not caused here: on this machine `test_capabilities.py`'s
`test_gate_blocks_execution_is_opt_in_and_narrow` and `test_evidence_gate_kind_is_not_blanket_observer`
fail on PRISTINE main too — the hourly fleet tick mutated the machine-local ledger and
range-lane-rollout now classifies `matched_not_invoked` instead of `deliberately_gated`. Ledger STATE,
not code; they skip with a named reason under a fresh ledger, which is what CI uses.

Co-authored-by: Tim Stranske <tim@stranskemo.com>
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

autofix Let bots format/lint automatically

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant