Skip to content

fix(devtools): shard resumable testmon seeding - #3956

Merged
Sinity merged 14 commits into
masterfrom
feature/fix/testmon-sharded-seed
Aug 12, 2026
Merged

fix(devtools): shard resumable testmon seeding#3956
Sinity merged 14 commits into
masterfrom
feature/fix/testmon-sharded-seed

Conversation

@Sinity

@Sinity Sinity commented Aug 11, 2026

Copy link
Copy Markdown
Owner

Summary

Make the pytest-testmon seed resumable and bounded by deterministic serial shards.

Problem

The previous seed ran 21,079 non-integration tests in one xdist invocation, timed out after 45 minutes, and produced no eligible seed. Raising the timeout or weakening release checks would hide failures and preserve an unusable harness.

Solution

Collect the complete correctness-test node set before testmon writes, partition it into deterministic 256-node shards, run one shard at a time with one SQLite writer, checkpoint shard/node outcomes, resume unfinished shards, and require a terminal complete failure-free graph before publishing seed.json. Protocol version 7 invalidates old incomplete receipts. Benchmark campaigns remain explicit and are excluded from the correctness/testmon seed.

Verification

  • devtools test tests/unit/devtools/test_verify.py tests/unit/devtools/test_testmon_state.py tests/unit/devtools/test_checkout_guard.py — 185 passed before the marker correction; 185 passed after it
  • devtools verify --quick — all 25 steps passed
  • End-to-end seed run is in progress at exact head a50b4b548; no release seed is claimed yet.

This is a self-contained test-harness correction; no Beads state was changed.

Summary by CodeRabbit

  • Improvements

    • Archive search indexes now record freshness after background processing, improving visibility into whether search results are up to date.
    • Archive convergence more reliably publishes and tracks raw sessions, attachments, and parsed data.
    • Cold-reopen and delegated-session processing are more resilient across recovery and replay workflows.
  • Bug Fixes

    • Improved test and subprocess isolation to prevent verification state from overwriting parent results.
    • Corrected lifecycle reporting for setup, execution, and teardown phases.

Problem: the 21k-node seed wrote to one testmon database through xdist workers and hit the bounded pytest timeout before it could publish a complete baseline.

What changed: collect the full selected node set first, partition it deterministically, and execute each shard serially with one testmon writer. Persist shard-level node outcomes after every shard and resume only unfinished shards. Release publication now requires a terminal shard ledger as well as complete, failure-free graph coverage.
@coderabbitai

coderabbitai Bot commented Aug 11, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@Sinity, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 29 minutes

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 7dd09545-9672-4b95-874f-b59a2c463576

📥 Commits

Reviewing files that changed from the base of the PR and between 1203919 and 31e0836.

📒 Files selected for processing (4)
  • polylogue/daemon/fts_startup.py
  • tests/conftest.py
  • tests/infra/convergence_harness.py
  • tests/unit/devtools/test_pytest_progress_plugin.py
📝 Walkthrough

Walkthrough

Changes

Testmon verification

Layer / File(s) Summary
Pytest report and environment handling
tests/conftest.py, tests/unit/test_pytest_temp_policy.py, tests/unit/devtools/test_pytest_progress_plugin.py
Pytest report handling uses hookwrapper=True. Managed verification variables survive environment cleanup. Subprocess and phase-report tests cover the updated behavior.
Testmon seed filtering and capacity
devtools/checkout_guard.py, devtools/verify.py, tests/unit/devtools/test_verify.py
The seed protocol advances to version 7. Benchmark tests are excluded, seed runs allow up to 10 workers, and verification expectations reflect the updated commands.

FTS freshness convergence

Layer / File(s) Summary
FTS freshness stage
polylogue/daemon/convergence_stages.py
A default convergence stage records archive-wide FTS freshness after insight processing and supports path, batch, and session execution.
Publication-aware convergence harness
tests/infra/convergence_harness.py
The harness publishes raw sessions and attachments through blob storage, consumes publication receipts, records source metadata, supports empty FTS fixtures, and validates supported archive surfaces.

Annotation fixture corrections

Layer / File(s) Summary
Data-driven annotation fixtures
tests/unit/annotations/test_durable_storage.py, tests/unit/annotations/test_importer.py
Annotation tests reopen archives in writable mode and derive delegation evidence references from archived actions.

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

Sequence Diagram(s)

sequenceDiagram
  participant ConvergencePipeline
  participant InsightMaterialization
  participant FTSFreshnessStage
  ConvergencePipeline->>InsightMaterialization: materialize insights
  ConvergencePipeline->>FTSFreshnessStage: execute fts_freshness stage
  FTSFreshnessStage->>ConvergencePipeline: record archive-wide freshness snapshot
Loading

Possibly related PRs

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 30.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly describes the main change: making devtools Testmon seeding resumable through sharding.
Description check ✅ Passed The description covers the summary, problem, solution, verification, and self-contained scope with relevant technical details.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/fix/testmon-sharded-seed

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

❤️ Share

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

@Sinity

Sinity commented Aug 11, 2026

Copy link
Copy Markdown
Owner Author

@codex review

Please review exact head 136c2ef18 for testmon correctness. Focus on shard completeness, SQLite writer safety, resume behavior after timeout/partial node outcomes, and whether any path can publish a green seed without every expected node actually passing.

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

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

polylogue/devtools/verify.py

Lines 2809 to 2812 in 136c2ef

elif use_database_fallback and recorded.get(nodeid) == "passed":
outcome, reason = "passed", "testmon database recorded success"
elif use_database_fallback and recorded.get(nodeid) == "failed":
outcome, reason = "failed", "testmon database recorded failure"

P1 Badge Do not use stale database rows as shard outcomes

When a shard is interrupted after collection but before one or more selected nodes start, seed mode may already have successful rows for those nodes because it updates an existing testmon database. This fallback labels those unexecuted nodes as passed; _checkpoint_testmon_seed_shard can consequently persist the shard as complete, and an interrupted outer verify followed by resume skips it and may publish a green seed without those nodes running. The pre-sharding finalizer deliberately disabled this fallback for exactly this case, so shard completion should likewise require current-shard events rather than pre-existing SQLite results.

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

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

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

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread devtools/verify.py Outdated
Comment on lines +2611 to +2613
expected = _testmon_seed_expected_nodeids(prepared) if prepared.get("resume") else []
if not expected:
expected = _seed_selection_nodeids(selection or {}) or []

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Validate resumed shards against the current collection

On a resumed seed, a nonempty prior ledger always wins and the collection produced immediately before this call is ignored. If collection changes without changing the resume identity—for example, environment- or external-data-dependent parametrization—the resumed run executes only the old shards and can publish a green seed while omitting nodes present in the current collection. Compare the fresh complete selection with the persisted expected set and invalidate or extend the shard plan when they differ.

Useful? React with 👍 / 👎.

@Sinity

Sinity commented Aug 11, 2026

Copy link
Copy Markdown
Owner Author

@codex review

Please review exact head a50b4b548 after the end-to-end discovery pass. Confirm the seed preserves the repository marker contract by excluding benchmark campaigns from the correctness/testmon corpus, while retaining scale/slow selection and complete shard coverage.

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

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 136c2ef18c

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

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

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

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread devtools/verify.py Outdated
# Collection produces the exact corpus contract before any testmon
# write. Shards below are generated from this ledger and run one
# at a time, so pytest-testmon has exactly one SQLite writer.
pytest_cmd.extend(["-m", base_marker, "--collect-only", "-n", "0"])

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Exclude benchmark campaigns from the seed marker

The new collection ledger uses only the scale/slow expression, so devtools verify --seed-testmon selects every @pytest.mark.benchmark test and permanently includes those nodes in the shard plan. The repository config's --benchmark-disable disables measurement but does not deselect the benchmark body, while pytest --help confirms that -m is the option that limits tests by marker; therefore expensive benchmark campaigns under tests/benchmarks/ run as part of the correctness/testmon seed and can exhaust the bounded seed runtime. Add not benchmark to this marker expression while preserving the existing slow and scale clauses.

Useful? React with 👍 / 👎.

Comment thread devtools/verify.py Outdated
Comment on lines +2678 to +2682
outcomes = _seed_node_outcomes_from_events(
artifact_dir / "events.jsonl" if artifact_dir is not None else Path(".missing-testmon-events"),
expected_nodeids=nodeids,
database=database,
pytest_step=step,

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Require fresh reports before completing a shard

When a shard times out or crashes after collection but before emitting node reports, this call leaves use_database_fallback=True, so pre-existing passing rows in testmondata classify every unexecuted node as passed. Because the selection ledger is written during collection, selection_matches is also true and the shard is checkpointed as complete; a resumed run then skips it and can publish a green current-tree seed without executing that shard. Disable database fallback for shard checkpoints, or otherwise require fresh terminal events before assigning COMPLETE.

Useful? React with 👍 / 👎.

@Sinity

Sinity commented Aug 11, 2026

Copy link
Copy Markdown
Owner Author

@codex review

Please review exact head 31761e978 after the end-to-end run exposed and fixed a second selection defect: marker filtering admitted unmarked tests under tests/benchmarks/. The seed now structurally excludes that explicit campaign directory while retaining complete non-integration correctness coverage and fail-closed shard accounting.

@chatgpt-codex-connector

Copy link
Copy Markdown

Codex Review: Didn't find any major issues. 👍

Reviewed commit: 31761e9785

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

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

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

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 3

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

Inline comments:
In `@devtools/verify.py`:
- Around line 2617-2642: The expected node IDs must be normalized before shard
validation and digest generation. In devtools/verify.py lines 2617-2642, update
_prepare_testmon_seed_shards to sort expected after fallback selection and hash
the normalized order. In tests/unit/devtools/test_verify.py lines 332-370, use
fixture node IDs in a non-sorted collection order and compute expected_digest
from sorted IDs so the resume round-trip verifies normalization.

In `@tests/unit/devtools/test_pytest_progress_plugin.py`:
- Around line 14-23: The autouse fixture _restore_plugin_state must preserve
supervisor-provided event destinations during pytest execution instead of
deleting them globally. Move environment clearing into the specific direct
plugin-call setup that needs test-owned paths, and retain managed values for the
lifecycle; add a regression test confirming a plugin test writes its node event
to the supervisor ledger.

In `@tests/unit/devtools/test_verify.py`:
- Around line 332-370: Update the resume test fixture to use node IDs whose
collection order differs from sorted order, while preserving the shard
assignment. Compute _atomic_payload["expected_digest"] from sorted(expected),
and update the selection.json and events.jsonl fixtures to reference the ordered
shard node (ordered[0]). Keep the existing completed-shard and resume assertions
unchanged.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

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

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 478134a7-9d12-456c-8476-7d883579eebe

📥 Commits

Reviewing files that changed from the base of the PR and between 8b69a6b and 265cf41.

📒 Files selected for processing (7)
  • devtools/checkout_guard.py
  • devtools/testmon_state.py
  • devtools/verify.py
  • tests/conftest.py
  • tests/unit/devtools/test_pytest_progress_plugin.py
  • tests/unit/devtools/test_verify.py
  • tests/unit/test_pytest_temp_policy.py

Comment thread devtools/verify.py Outdated
Comment thread tests/unit/devtools/test_pytest_progress_plugin.py Outdated
Comment thread tests/unit/devtools/test_verify.py Outdated

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

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 265cf41b09

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

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

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

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread devtools/verify.py Outdated
Comment on lines +3425 to +3426
if shard_rc != 0 and exit_code == 0:
exit_code = shard_rc

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Stop launching shards after a supervisor timeout

When a shard hits the 45-minute runtime cap or the stall timeout, this loop records its nonzero exit but continues launching every remaining shard. Since _run applies the timeout independently to each invocation, a 64-shard seed can now consume up to 64 times the configured cap, and repeated resource failures are retried immediately instead of leaving the durable ledger for a later resume. Break after timeout, stall, interruption, or resource-preflight diagnoses while still allowing ordinary test failures to populate the remaining dependency graph.

Useful? React with 👍 / 👎.

Comment thread tests/conftest.py Outdated
"POLYLOGUE_PYTEST_EVENTS_PATH",
"POLYLOGUE_PYTEST_SELECTION_PATH",
"POLYLOGUE_PYTEST_SUMMARY_PATH",
"POLYLOGUE_PYTEST_CONTAINMENT_PATH",

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Do not expose the outer containment receipt inside tests

During a managed verify run, preserving POLYLOGUE_PYTEST_CONTAINMENT_PATH makes tests that call _run with a pytest... label—several tests in tests/unit/devtools/test_verify.py do this—start their nested supervisor against the outer shard's receipt. When the nested process marks that shared receipt finished, the outer _run_pytest_with_heartbeat loop reads it as its own supervisor having exited while output pipes remain open and can force-kill the still-running shard after the grace period. Keep the event-ledger variables needed by the progress plugin, but scrub or replace the containment path for code executed inside each test.

Useful? React with 👍 / 👎.

Comment thread tests/conftest.py Outdated
_MANAGED_VERIFY_ENV = frozenset(
{
"POLYLOGUE_VERIFY_RUN_ID",
"POLYLOGUE_PYTEST_RUN_ID",

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Give nested managed runs a distinct pytest run ID

When a managed focused run and a test-invoked _run both select the same basetemp root, preserving POLYLOGUE_PYTEST_RUN_ID makes the nested run reuse the outer pytest session's basetemp name. The nested _run unconditionally calls cleanup_managed_pytest_basetemp on completion, so tests such as the real _run exercises in tests/unit/devtools/test_verify.py can delete the outer session's basetemp—including active tmp_path fixtures—while the shard is still executing. Scrub this control-plane ID in the per-test fixture so nested runs mint their own identifier; monkeypatch teardown can restore the outer ID before session finish.

Useful? React with 👍 / 👎.

@Sinity

Sinity commented Aug 12, 2026

Copy link
Copy Markdown
Owner Author

@codex review

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

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: e97c329a5e

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

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

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

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread devtools/verify.py Outdated
Comment on lines +2650 to +2651
command = [argument for argument in collection_command if argument != "--collect-only"]
command.extend(["--testmon", "--testmon-noselect", *nodeids])

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Preserve reports from every seed shard

For any seed containing multiple shards, this copies the collection command's fixed --junitxml=.cache/test-reports/verify-latest.xml and --json-report-file=.cache/verify/last-pytest.json arguments into every shard. _run clears those paths before each pytest invocation, so the final shard erases all earlier shard reports; if an earlier shard fails and a later one passes, evidence_dashboard._pytest_health() subsequently reports an ok result and counts only the last shard despite the seed failing overall. Checked pytest --help, which defines --junitxml=path as creating a report at the specified path. Give shards distinct report paths or merge their reports into the canonical artifacts.

Useful? React with 👍 / 👎.

Comment thread devtools/verify.py Outdated
Comment on lines +3403 to +3405
for shard in shards:
if shard.get("status") == SeedShardStatus.COMPLETE.value:
continue

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Re-run completed shards when their graph is incomplete

When all tests emit terminal reports but testmon leaves a missing or orphaned dependency edge, _checkpoint_testmon_seed_shard() still marks each shard complete, while finalization correctly leaves the overall attempt incomplete. The next matching invocation is therefore considered resumable but skips every shard here, performs no database repair, and finalizes the same incomplete graph again; subsequent resumes repeat forever. Only skip a completed shard after confirming its recorded graph remains complete, or invalidate the completed statuses when final graph validation fails.

Useful? React with 👍 / 👎.

Sinity added 2 commits August 12, 2026 10:17
Problem: the fresh convergence-property seed exposed fixture failures before the intended laws could run. Raw and attachment references were admitted without published bytes, append fixtures required an inapplicable FTS mutation, and readiness fixtures lacked parser-authority receipts.

What changed: publish fixture raw and attachment blobs through the archive publisher, record complete parser census evidence for admitted raws, refresh the FTS freshness ledger after both stages, and preserve the raw-replay mutation's intended comparator failure when raw acquisition is bypassed.

Compatibility: test infrastructure only; production convergence behavior is unchanged.
Keep cold annotation reads on the default read-only archive handle and reopen a writable handle for retries. Derive delegation target and evidence identities from persisted action rows so the fixture follows the current message identity law.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

♻️ Duplicate comments (1)
devtools/verify.py (1)

2623-2636: 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

Normalize fresh selection node IDs before persistence.

_testmon_seed_expected_nodeids validates expected_digest from sorted(expected). Line 2636 hashes the unsorted collection order when this is a new seed. A non-lexical collection then fails validation on resume and cannot recover its persisted expected node IDs.

  • devtools/verify.py#L2623-L2636: sort expected after the selection fallback and before shard validation and digest generation.
  • tests/unit/devtools/test_verify.py#L310-L345: pass prepared to checkpointing, or assert its persisted expected node IDs and digest, so unsorted collection input verifies this contract.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@devtools/verify.py` around lines 2623 - 2636, The fresh selection flow in
devtools/verify.py lines 2623-2636 must sort expected after the selection
fallback and before validate_seed_shard_ledger and digest generation, ensuring
persisted node IDs and expected_digest use canonical lexical order. Update
tests/unit/devtools/test_verify.py lines 310-345 to pass prepared to
checkpointing or assert the persisted expected node IDs and digest using
unsorted input.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@tests/unit/devtools/test_pytest_progress_plugin.py`:
- Around line 103-105: Strengthen the assertions over the test_report events in
the test by requiring exactly three reports, all for the configured target
nodeid, with setup/call/teardown phases, expected passed outcomes, and run_id
equal to "subprocess-regression". Validate the complete payload identity rather
than only comparing the set of when values.

---

Duplicate comments:
In `@devtools/verify.py`:
- Around line 2623-2636: The fresh selection flow in devtools/verify.py lines
2623-2636 must sort expected after the selection fallback and before
validate_seed_shard_ledger and digest generation, ensuring persisted node IDs
and expected_digest use canonical lexical order. Update
tests/unit/devtools/test_verify.py lines 310-345 to pass prepared to
checkpointing or assert the persisted expected node IDs and digest using
unsorted input.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

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

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 4794ac48-eae7-4177-a5ff-594f0cc8eccb

📥 Commits

Reviewing files that changed from the base of the PR and between 265cf41 and 0f60850.

📒 Files selected for processing (7)
  • devtools/verify.py
  • tests/conftest.py
  • tests/infra/convergence_harness.py
  • tests/unit/annotations/test_durable_storage.py
  • tests/unit/annotations/test_importer.py
  • tests/unit/devtools/test_pytest_progress_plugin.py
  • tests/unit/devtools/test_verify.py
💤 Files with no reviewable changes (1)
  • tests/conftest.py

Comment thread tests/unit/devtools/test_pytest_progress_plugin.py Outdated
Problem: serial explicit-node shards replaced pytest-testmon's controller-owned xdist write path, stretching the seed into dozens of process startups.

Restore one managed xdist pytest-testmon invocation, retain event-backed per-node outcomes and graph validation, and remove the shard-only receipt protocol.

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

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 0f60850904

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

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

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

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread tests/conftest.py
Comment on lines +409 to +410
"POLYLOGUE_PYTEST_SELECTION_PATH",
"POLYLOGUE_PYTEST_SUMMARY_PATH",

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Isolate nested pytest selection ledgers

When a seed shard runs one of the load-sensitive supervisor tests on a host with user systemd, preserving this path lets tests/unit/devtools/test_pytest_supervisor.py::_xdist_controller_cmd() inherit the outer shard's selection destination through env = os.environ.copy(). That nested pytest invocation loads the progress plugin and overwrites selection.json with its single temporary node; _checkpoint_testmon_seed_shard() then sees a selection mismatch, marks the otherwise executed shard incomplete, and every resume repeats the same failure. Preserve the event stream if needed, but scrub or replace the selection and summary destinations for pytest processes launched by test code.

AGENTS.md reference: AGENTS.md:L338-L341

Useful? React with 👍 / 👎.

Comment thread tests/infra/convergence_harness.py Outdated
from polylogue.daemon.fts_startup import record_fts_freshness_snapshot_sync

with sqlite3.connect(archive.root / "index.db") as conn:
record_fts_freshness_snapshot_sync(conn)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Exercise freshness through the production convergence route

When the insights stage materializes new work-event rows after the FTS stage, this direct call repairs the freshness ledger inside the harness even though record_fts_freshness_snapshot_sync() has no production caller and is not one of the DaemonConverger stages. Consequently the derived-readiness property can remain green if the real post-ingest convergence route leaves session_work_events_fts stale or unreadable; wire the refresh into the production stage sequence, or assert the state left by that sequence without repairing it in the test harness.

AGENTS.md reference: AGENTS.md:L168-L172

Useful? React with 👍 / 👎.

Comment thread tests/infra/convergence_harness.py Outdated
revision=RawRevisionEnvelope(
logical_source_key=str(make_session_id(session.source_name, session.provider_session_id)),
kind=RawRevisionKind.FULL,
source_revision=content_hash,

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Use the raw blob digest as the source revision

When these convergence fixtures exercise retained-raw replay or revision-governance paths, this records the normalized parsed-session content_hash as RawRevisionEnvelope.source_revision. Production admit_raw_observation() instead records the retained payload digest (blob_hash.hex()), and downstream retention and repair code treats a full revision as that blob identity; the synthetic source.db therefore contains authority evidence that cannot be produced by ingestion and can mask or create false reindex results. Use raw_blob_hash here and retain content_hash only for SessionWritePayload.

AGENTS.md reference: AGENTS.md:L138-L144

Useful? React with 👍 / 👎.

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

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 602474e034

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

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

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

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

_TESTMON_STATE_MARKER = _TESTMON_STATE_DIR / "seed.json"
_TESTMON_SEED_ATTEMPT = _TESTMON_STATE_DIR / "seed-attempt.json"
_TESTMON_SEED_PROTOCOL_VERSION = 6
_TESTMON_SEED_PROTOCOL_VERSION = 7

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Match the checkout guard to the emitted seed protocol

In linked worktrees, devtools.verify still writes and bootstraps protocol-6 seed markers (devtools/verify.py:219), but this guard now validates them as protocol 7. Consequently, a freshly bootstrapped or completed seed is classified as invalid_testmon_seed, and subsequent devtools verify/devtools test invocations exit during the checkout guard. Bump the verifier's protocol constant in the same change, or leave this validator at 6.

AGENTS.md reference: AGENTS.md:L338-L341

Useful? React with 👍 / 👎.

Comment thread devtools/verify.py Outdated
# them are correctness-shaped and lack the benchmark marker, so a
# marker expression alone cannot keep performance probes out of
# the correctness/testmon corpus.
"--ignore=tests/benchmarks",

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Preserve correctness tests under tests/benchmarks

Because this argument is in the common pytest command, it excludes the entire directory from default, seed, lab, and --all runs. Checked local pytest --help: --ignore=path means “Ignore path during collection.” This also drops unmarked correctness tests such as tests/benchmarks/test_scale_tiers.py::test_scale_small_*, whose module explicitly declares them part of the default verify gate, so marker-based scale coverage disappears and --all is no longer the documented full non-integration diagnostic. Exclude actual benchmark campaigns without ignoring the whole directory.

AGENTS.md reference: AGENTS.md:L342-L343

Useful? React with 👍 / 👎.

Comment thread tests/infra/convergence_harness.py Outdated
Comment on lines +297 to +298
if source_conn.execute("SELECT 1 FROM raw_sessions WHERE raw_id = ?", (raw_id,)).fetchone() is not None:
record_current_parser_source_census(source_conn, raw_id, parser_sessions=[session])

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Derive parser census from the published raw payload

When this fixture is used for retained-raw replay or revision-governance checks, this records a current-parser receipt from the already-constructed in-memory session rather than from the bytes just published. _raw_payload() serializes a normalized ParsedSession.model_dump(), not Codex wire records; Codex lowering consumes its messages list and loses the top-level provider_session_id, while census_parse_worker does not use the stored native-id override for this FULL revision, so replay falls back to a filename-derived ID such as 000-revision-chain. The receipt therefore certifies parser output that the retained bytes cannot reproduce, masking replay failures; publish real Codex-shaped bytes or parse the published payload before recording the census.

AGENTS.md reference: AGENTS.md:L153-L156

Useful? React with 👍 / 👎.

"POLYLOGUE_PYTEST_SELECTION_PATH",
"POLYLOGUE_PYTEST_SUMMARY_PATH",
):
monkeypatch.delenv(name, raising=False)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Preserve outer event destinations during plugin tests

During a managed devtools verify --seed-testmon run, this autouse fixture deletes the outer progress plugin's event destinations for the entire setup and call phases of every test in this module. The outer plugin reads these variables dynamically from pytest_runtest_logreport, so it records the start and eventual teardown after monkeypatch restoration but no call report; seed finalization disables database fallback and classifies each affected node as missing, making the shard/attempt permanently incomplete on every resume. Isolate destinations only around direct helper calls or in the nested subprocess environment rather than scrubbing them for the lifetime of the outer test.

AGENTS.md reference: AGENTS.md:L338-L341

Useful? React with 👍 / 👎.

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

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: bf960b0705

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

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

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

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread tests/conftest.py
Comment on lines +406 to +408
"POLYLOGUE_VERIFY_RUN_ID",
"POLYLOGUE_PYTEST_EVENTS_DIR",
"POLYLOGUE_PYTEST_EVENTS_PATH",

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Isolate nested pytest events from the seed ledger

When a test launches a nested pytest process during a managed seed, preserving this event directory and the outer POLYLOGUE_VERIFY_RUN_ID makes the nested process append reports that are indistinguishable from the outer run's evidence. _seed_node_outcomes_from_events() accepts every report by node ID without checking PID or execution provenance, so if the nested process passes another expected node and the outer run terminates before executing that node itself, finalization can treat it as freshly passed. Preserve the outer plugin environment for the parent process, but give subprocess pytest runs a separate event destination/run ID or filter their events out.

AGENTS.md reference: AGENTS.md:L338-L341

Useful? React with 👍 / 👎.

Comment thread polylogue/daemon/convergence_stages.py Outdated
make_embed_stage(db_path, defer=embed_defer),
make_claude_workflow_stage(db_path),
make_insights_stage(db_path),
make_fts_freshness_stage(db_path),

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Avoid full-archive FTS scans after every ingest batch

On a large archive, registering this always-applicable stage in the default production sequence makes every live converge_batch() call execute fts_invariant_snapshot_sync(). That snapshot performs exact counts and missing/excess/identity joins across the complete blocks and FTS surfaces, even when the batch contains one small append or the preceding insight stage had no work, turning incremental ingest into repeated O(archive-size) scans. Record freshness incrementally from the changed subjects or defer the exact archive-wide snapshot to a bounded quiet/global-maintenance pass.

AGENTS.md reference: AGENTS.md:L168-L179

Useful? React with 👍 / 👎.

Comment thread polylogue/daemon/convergence_stages.py Outdated
Comment on lines +756 to +758
with open_connection(archive_db) as conn:
_record_convergence_fts_freshness_sync(conn)
return True

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Propagate freshness snapshot failures to convergence debt

When an exact freshness query raises sqlite3.Error—for example because an FTS shadow table is unreadable—record_fts_freshness_snapshot_sync() logs and returns without updating the ledger, after which this function still returns True. The converger therefore marks fts_freshness done and records no retryable debt, leaving either a stale/empty ledger or an obsolete ready row until an unrelated future pass happens to refresh it. Return a success signal from the snapshot helper or re-raise the failure so this stage remains retryable.

AGENTS.md reference: AGENTS.md:L168-L176

Useful? React with 👍 / 👎.

Comment thread tests/infra/convergence_harness.py Outdated
Comment on lines +281 to +283
kind=RawRevisionKind.FULL,
source_revision=raw_blob_hash,
acquisition_generation=index,

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Classify append fixtures through raw admission

When the append-prefix property passes append_only=True, the raw row is given source_index=-1 but this code still asserts every observation as an independent FULL revision with a corpus-position generation. Production raw admission instead derives the generation from the previously acquired head and records a byte-prefix successor as APPEND with predecessor/baseline offsets, or quarantines an ambiguous payload; rotated fixture order therefore creates authority evidence that production cannot emit and can keep retained-replay/append tests green when the real revision chain is broken. Route these bytes through the production admission classifier or construct the envelope from the actual predecessor relation.

AGENTS.md reference: AGENTS.md:L114-L122

Useful? React with 👍 / 👎.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 5

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

Inline comments:
In `@polylogue/daemon/convergence_stages.py`:
- Line 401: Update the convergence stage around
record_fts_freshness_snapshot_sync so the recorder returns an explicit success
status, returning False when snapshot generation catches sqlite3.Error and
succeeds otherwise. In DaemonConverger’s stage handling, propagate that result
and return False instead of reporting convergence success when freshness
snapshot recording fails.
- Around line 754-757: Remove the direct connection_profile import from the
daemon convergence stage and replace the
open_connection/_record_convergence_fts_freshness_sync flow with an existing
operations, insights, or api boundary for the archive freshness update. Keep the
same archive operation behavior while ensuring daemon surface code no longer
imports storage internals.
- Around line 756-757: Update the convergence freshness callback around
DaemonConverger to stop importing or calling open_connection directly. Route the
_record_convergence_fts_freshness_sync write through an existing allowed
daemon-boundary interface in insights, operations, or api, while preserving the
current freshness-recording behavior.

In `@tests/conftest.py`:
- Around line 648-650: Update _restore_plugin_state in tests/conftest.py to
clear POLYLOGUE_PYTEST_SELECTION_PATH and POLYLOGUE_PYTEST_SUMMARY_PATH only for
direct helper calls, preserving supervisor-managed destinations during report
hooks; retain the subprocess regression behavior. In
tests/unit/devtools/test_pytest_progress_plugin.py lines 20-27, adjust the
affected test expectations or setup to reflect the preserved destinations.

In `@tests/unit/devtools/test_pytest_progress_plugin.py`:
- Around line 106-115: Extend the test around subprocess.run to create sentinel
contents in both selection and summary destination files before launching the
child process. After the child exits, read both files and assert their contents
remain unchanged, alongside the existing reports assertions.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

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

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 83012f64-fbd4-4192-a972-b9fda44ce7a0

📥 Commits

Reviewing files that changed from the base of the PR and between 0f60850 and 1203919.

📒 Files selected for processing (6)
  • devtools/verify.py
  • polylogue/daemon/convergence_stages.py
  • tests/conftest.py
  • tests/infra/convergence_harness.py
  • tests/unit/devtools/test_pytest_progress_plugin.py
  • tests/unit/devtools/test_verify.py

Comment thread polylogue/daemon/convergence_stages.py Outdated
Comment thread polylogue/daemon/convergence_stages.py Outdated
Comment thread polylogue/daemon/convergence_stages.py Outdated
Comment on lines +756 to +757
with open_connection(archive_db) as conn:
_record_convergence_fts_freshness_sync(conn)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

ast-grep outline polylogue/daemon/convergence.py --items all --match 'DaemonConverger|converge'
rg -nP --type=py -C 4 '\.(?:execute|execute_many|execute_sessions)\s*\(' polylogue/daemon
rg -nP --type=py -C 4 'ProcessPoolExecutor|ThreadPoolExecutor|multiprocessing|Process\(|converge_sessions' polylogue/daemon

Repository: Sinity/polylogue

Length of output: 50373


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '%s\n' '--- DaemonConverger implementation ---'
sed -n '150,590p' polylogue/daemon/convergence.py

printf '%s\n' '--- DaemonConverger call sites ---'
rg -n -P --type=py -C 6 'DaemonConverger\s*\(|\.converge_(?:file|batch|sessions|all)\s*\(' polylogue

printf '%s\n' '--- Worker and process boundaries ---'
rg -n -P --type=py -C 8 'ProcessPoolExecutor|ThreadPoolExecutor|multiprocessing|multiprocessing\.|concurrent\.futures|worker|worker_process|Process\s*\(' polylogue/daemon polylogue | head -n 500

printf '%s\n' '--- Freshness stage definition and callback wiring ---'
rg -n -P -C 10 'make_fts_freshness_stage|_record_convergence_fts_freshness_sync|record_fts_freshness_snapshot_sync|open_connection\s*\(' polylogue/daemon/convergence_stages.py

Repository: Sinity/polylogue

Length of output: 50372


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '%s\n' '--- Freshness stage wiring ---'
rg -n -P -C 14 'make_fts_freshness_stage|_record_convergence_fts_freshness_sync|record_fts_freshness_snapshot_sync|open_connection\s*\(' polylogue/daemon/convergence_stages.py

printf '%s\n' '--- Convergence construction and execution ---'
sed -n '1720,1780p' polylogue/daemon/cli.py
sed -n '2500,2605p' polylogue/daemon/cli.py
rg -n -P -C 12 'converger\s*=|_converger|Converger|converge_file|converge_batch|converge_sessions' polylogue/sources/live/batch.py polylogue/daemon/cli.py

printf '%s\n' '--- Live batch worker boundary ---'
rg -n -P -C 12 'process_pool_executor|ProcessPoolExecutor|executor\.(map|submit)|worker|_run_batch|_validate_record_sync' polylogue/sources/live/batch.py polylogue/pipeline/services polylogue/daemon/cli.py | head -n 500

Repository: Sinity/polylogue

Length of output: 50372


🏁 Script executed:

#!/bin/bash
set -euo pipefail

python3 - <<'PY'
import ast
from pathlib import Path

root = Path("polylogue")
target_methods = {"converge_file", "converge_batch", "converge_sessions", "converge_all"}
process_names = {
    "ProcessPoolExecutor",
    "process_pool_executor",
    "multiprocessing",
    "Process",
}

for path in sorted(root.rglob("*.py")):
    try:
        tree = ast.parse(path.read_text(), filename=str(path))
    except (OSError, SyntaxError):
        continue

    for node in ast.walk(tree):
        if isinstance(node, ast.Call):
            func = node.func
            if isinstance(func, ast.Attribute) and func.attr in target_methods:
                print(f"CONVERGENCE_CALL {path}:{node.lineno}: .{func.attr}()")
            if isinstance(func, ast.Name) and func.id in process_names:
                print(f"PROCESS_CALL {path}:{node.lineno}: {func.id}()")
            if isinstance(func, ast.Attribute) and func.attr in process_names:
                print(f"PROCESS_CALL {path}:{node.lineno}: .{func.attr}()")

    for node in ast.walk(tree):
        if isinstance(node, ast.ImportFrom) and node.module:
            imported = {alias.name for alias in node.names}
            if imported & process_names:
                print(f"PROCESS_IMPORT {path}:{node.lineno}: {node.module}: {sorted(imported & process_names)}")
        elif isinstance(node, ast.Import):
            imported = {alias.name.split(".")[0] for alias in node.names}
            if imported & process_names:
                print(f"PROCESS_IMPORT {path}:{node.lineno}: {sorted(imported & process_names)}")
PY

Repository: Sinity/polylogue

Length of output: 1646


Route the freshness write through an allowed daemon boundary.

DaemonConverger has no process-pool convergence call sites, so this callback does not need a main-process queue. However, record() directly imports polylogue.storage.sqlite.connection_profile.open_connection, which violates the daemon boundary. Route the write through insights, operations, or api.

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

In `@polylogue/daemon/convergence_stages.py` around lines 756 - 757, Update the
convergence freshness callback around DaemonConverger to stop importing or
calling open_connection directly. Route the
_record_convergence_fts_freshness_sync write through an existing allowed
daemon-boundary interface in insights, operations, or api, while preserving the
current freshness-recording behavior.

Source: Coding guidelines

Comment thread tests/conftest.py Outdated
Comment thread tests/unit/devtools/test_pytest_progress_plugin.py

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

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: a55b7f5503

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

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

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

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread tests/conftest.py Outdated
Comment on lines +649 to +652
if (
os.environ.get("PYTEST_CURRENT_TEST")
and os.environ.get("POLYLOGUE_VERIFY_RUN_ID")
and not os.environ.get("POLYLOGUE_PYTEST_NESTED_PRIVATE")

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Preserve the outer managed test's event environment

When pytest is launched by managed devtools verify, pytest sets PYTEST_CURRENT_TEST before autouse fixture setup, so this predicate is true in the outer test process itself rather than only in nested subprocesses. It deletes the run/event destinations before setup and call reports, and the progress plugin reads those variables dynamically, causing seed finalization to classify current nodes as missing and refuse to publish the testmon seed. Fresh evidence after the earlier nested-ledger finding is that isolation has moved into this root autouse fixture with a predicate that also matches every outer test; isolate the subprocess environment at launch instead.

AGENTS.md reference: AGENTS.md:L338-L341

Useful? React with 👍 / 👎.

Comment on lines +287 to +288
if admission.arm.value not in {"baseline", "append", "supersede"}:
raise AssertionError(f"raw fixture admission was not executable: {admission!r}")

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Generate byte-prefix payloads before requiring append admission

When the rich convergence corpus processes its two revisions of the same native session, _raw_payload() serializes each revision as a complete JSON document while the composer changes the title, metadata, and existing message text. The second payload is therefore neither equal to nor a byte-prefix extension of the first, so admit_raw_observation() returns REFUSED_AMBIGUOUS and this assertion aborts build_converged_archive() before the append-prefix property can run. Fresh evidence after the prior raw-admission comment is that the harness now invokes the production classifier, but its synthetic revision bytes still cannot satisfy that classifier; construct genuinely growing bytes or model these as independent full observations.

Useful? React with 👍 / 👎.

@Sinity
Sinity merged commit 595c4d9 into master Aug 12, 2026
2 checks passed
@Sinity
Sinity deleted the feature/fix/testmon-sharded-seed branch August 12, 2026 10:35

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

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 31e08362ba

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

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

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

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

from polylogue.storage.blob_publication import ArchiveBlobPublisher, consume_blob_publication_receipt
from polylogue.storage.sqlite.archive_tiers.bootstrap import initialize_archive_tier
from polylogue.storage.sqlite.archive_tiers.source_write import write_source_raw_session
from polylogue.storage.sqlite.archive_tiers.raw_admission import PriorRawHead, admit_raw_observation

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Retarget the removed raw-writer mutation hook

When test_convergence_property_raw_replay_mutation_red_twin runs, its monkeypatch.setattr(convergence_harness, "write_source_raw_session", ...) now raises AttributeError because this change removes that imported module attribute and routes ingestion through admit_raw_observation. The affected/full verification therefore fails before exercising the mutation assertion; retarget the mutation at the new admission path or preserve an injectable raw-writer seam.

AGENTS.md reference: AGENTS.md:L342-L343

Useful? React with 👍 / 👎.

selected = _validate_session_indexes(pathology, session_indexes)
source_paths: list[Path] = []
session_ids: list[str] = []
prior_heads: dict[str, PriorRawHead] = {}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Carry prior raw heads across ingest batches

When a logical session's revisions are split across calls to ingest_convergence_pathology—as test_convergence_property_append_prefix_matches_full explicitly does for its prefix and delta—this per-call empty map forgets the head already stored in source.db. The delta is consequently admitted with prior_head=None as another asserted generation-0 baseline rather than an append/supersede revision, so its durable authority facts diverge from the one-call archive and the property no longer models resumable production ingestion. Resolve the prior head from the existing source tier or carry it between calls.

AGENTS.md reference: AGENTS.md:L342-L343

Useful? React with 👍 / 👎.

Sinity added a commit that referenced this pull request Aug 12, 2026
## Summary

Record complete testmon seed outcomes without treating fixture teardown
as proof that the test body passed.

## Problem

Interrupted or worker-disrupted shards can retain `test_finished` plus a
passing teardown report without a call-phase report. A failed test can
therefore be incorrectly terminalized and skipped on resume; an
unrecorded call can be treated as passed.

## Solution

- record complete per-node seed outcomes and preserve resumable shard
state;
- require call-phase evidence or a corroborating testmon result before
accepting a passing teardown;
- keep missing, failed, worker-crash, timeout, and interrupted outcomes
distinct;
- isolate unit-test testmon caches so checkout-integrity tests observe
real state;
- preserve the managed event ledger across the host environment scrub.

## Verification

- `.venv/bin/python -m devtools test tests/unit/devtools/test_verify.py
tests/unit/devtools/test_testmon_state.py
tests/unit/devtools/test_checkout_guard.py
tests/unit/devtools/test_pytest_progress_plugin.py` — 196 passed;
- `.venv/bin/python -m devtools verify --quick` — 25/25 steps passed at
`eda8751e3`;
- current-head Codex review was addressed with a regression test for
teardown-only evidence.

This PR is self-contained on top of the already-merged testmon sharding
work in #3956.

<!-- polylogue-pr-scope:v2
{
  "assigned_beads": [],
  "dispositions": [],
  "mutated_beads": [],
"scope_digest":
"79a7984a9ec80a157c96dc8d28561159c642c15de3793837eff751fa7eac34a1",
  "scope_kind": "self_contained",
  "version": 2
}
-->


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

## Summary by CodeRabbit

* **New Features**
* Added durable, resumable test verification through deterministic
shards.
* Verification now records per-shard progress and outcomes, allowing
interrupted runs to continue safely.
* Added validation to ensure complete and consistent test coverage
before finalizing results.

* **Bug Fixes**
* Improved handling of teardown outcomes so incomplete tests are not
incorrectly marked as successful.
  * Benchmark tests are excluded from standard verification collection.
  * Improved freshness and readiness checks for search-related data.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant