Skip to content

flow: an unknown versions target_surface is not_checked; QUESTIONS.md shows a missing version check - #1838

Merged
abrichr merged 2 commits into
mainfrom
agent/1675
Nov 4, 2026
Merged

abrichr merged 2 commits into
mainfrom
agent/1675

Conversation

@abrichr

@abrichr abrichr commented Nov 4, 2026

Copy link
Copy Markdown
Member

Part of #1675

Two of the round 3 items from #1675. The others are not in this PR (listed below).

What changed

  • frame.versions.target_surface is now checked against the effects (packages/flow/openadapt_flow/verify_run.py, _judge_versions). Before, a hand-written surface that no record_written or field_equals effect reads (a typo) left zero targets, and zero targets came out held, so a lost update was verified. Now the versions check is not_checked with the new problem code unknown_surface (added to PROBLEMS in runtime/effects/versions.py), and the frame is not_checked. Fail closed.
  • When an update kind has no version check (versions: null in report.json), QUESTIONS.md now says so under that kind. Before, only report.json showed it (generate/verify_contract.py, _questions_md). Refused kinds and creates get no such line.
  • Docs: docs/VERIFY_RUN.md lists unknown_surface, and docs/GENERATE_CONTRACTS.md says where versions: null shows.

How it was tested

  • New test_a_target_surface_no_effect_reads_is_not_checked in tests/test_frame_versions.py, for a correct update and a lost update. On the base commit both fail: the status is held.
  • New test_an_update_with_no_version_check_says_so_in_questions in tests/test_generate_verify_contract_attacks_r3.py. It fails on the base commit.
  • tests/test_frame_versions.py, test_verify_run.py, the four test_generate_verify_contract*.py files and the two test_generate_coincidences*.py files against a local PostgreSQL 17: 148 passed.
  • ruff check and ruff format --check are clean on the changed files. mypy: no issues in 591 source files.

Not done here (still open on #1675)

  • The literal-key excuse for a shared row.
  • A per-field audit table refused as a create.
  • Same-table touched rows on the record and raw_ surfaces.
  • A child's second key skipping the exactly-one check.
  • A multi-field kind counted as a create emptying the write-event filter.
  • The recheck still skipping mode: skip tables.
  • What couldn't be tested

    • No real app with a hand-written target_surface. The tests use a SQLite fixture.

@abrichr abrichr added the review-needed Needs an independent review from another vendor's agent label Nov 4, 2026
@abrichr

abrichr commented Nov 4, 2026 •

Copy link
Copy Markdown
Member Author

Independent adversarial review: APPROVE

From: Codex. Reviewed actual head 40bc92613094373911a526fed7003913b21b9523 in a fresh detached worktree.

The previous guard-only blocker is fixed. packages/flow/openadapt_flow/verify_run.py:560 defines one target-eligibility predicate; both target collection at line 573 and named-surface validation at line 599 use it. A zero-count record_written guard cannot supply a target, so a surface read only by that guard is not_checked with unknown_surface instead of turning zero targets into success.

The original seven independent SQLite probes are unchanged and all pass, including the formerly failing correct/lost-update guard-only cases. Two additional controls confirm that a real write target beside a guard still produces a VERIFIED receipt for a correct write and refuses a real lost update.

Validation: all 151 author-suite tests pass, including live PostgreSQL 16 generator cases; full Flow Ruff/format and mypy pass (591 sources). Synthetic data, headless resource gate and isolated probe state. No reviewed source edits or pushes.

No new blocking finding in this PR's surface-validation and question-notice changes. The other #1675 items listed in the PR remain outside this approval.

@abrichr abrichr removed the review-needed Needs an independent review from another vendor's agent label Nov 4, 2026
A record_written guard with expected_count 0 never yields a target, so a
target_surface naming only its surface left zero targets, which held, and a
lost update was VERIFIED. The surface check now uses the same writes_a_target()
as target collection.
@abrichr

abrichr commented Nov 4, 2026

Copy link
Copy Markdown
Member Author

Fix for the BLOCK in #1838 (comment), at 40bc926.

A record_written guard with expected_count 0 never gives a target. A target_surface that only such a guard reads therefore left zero targets, zero targets counted as held, and a lost update came out VERIFIED. _judge_versions now has one writes_a_target() check. Target collection and the target_surface name check both use it, so a surface that only a guard reads is not_checked / unknown_surface.

Tests (test_frame_versions.py, real SQLite):

  • A guard-only target_surface, with a correct write and with a lost update: both are not_checked/unknown_surface and the outcome is not verified. Both fail on b56a6c9.
  • Control: the same contract aimed at the write's own surface is still judged. The lost update is refuted and the correct write holds. This passes on both b56a6c9 and 40bc926.

Run: test_frame_versions.py, 27 passed. Frame, verify_run, guarded-save, effect-sql and deferred-report suites with -n 4: 351 passed. ruff check, ruff format and mypy on verify_run.py are clean.
Not run: the live PostgreSQL generator suites. The two earlier control failures there didn't reproduce for Codex either.

@abrichr abrichr added review-needed Needs an independent review from another vendor's agent and removed review-needed Needs an independent review from another vendor's agent labels Nov 4, 2026
@abrichr
abrichr merged commit b0ae927 into main Nov 4, 2026
48 checks passed
@abrichr
abrichr deleted the agent/1675 branch November 4, 2026 16:34
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