Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
90 changes: 73 additions & 17 deletions src/verification.py
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,17 @@ def streaming_reasoner(
reasoning_futures = {}
validation_futures = {}
submitted = set()
failed = set() # files that raised unhandled errors; don't retry forever

def _submit_file(file_path, ext):
# Submit a ready file for reasoning/verification.
submitted.add(file_path)
language = EXT_TO_LANG.get(ext, "C")
future = executor.submit(
_verify_single_file, file_path, input_dir, output_dir, language, work_dir, resume
)
reasoning_futures[future] = file_path
logging.info(f"Submitted: {file_path}")

while True:
# Scan for new ready files
Expand All @@ -138,6 +149,8 @@ def streaming_reasoner(
continue
if file_path in submitted:
continue
if file_path in failed:
continue
if not is_file_ready(file_path):
continue

Expand Down Expand Up @@ -207,6 +220,7 @@ def streaming_reasoner(
print(f"[{completed_count}/{num_functions}] {rel_path}: {label}")
except Exception as exc:
logging.error(f"Error verifying {fpath}: {exc}")
failed.add(fpath)

# Collect completed validation futures (non-blocking)
val_done = [f for f in validation_futures if f.done()]
Expand Down Expand Up @@ -247,7 +261,7 @@ def streaming_reasoner(
except Exception as exc:
logging.error(f"Validation error for {fpath}: {exc}")

# Check if all expected files have been processed
# Check if all expected files have been processed successfully
all_reasoning_done = (
expected_files is not None
and processed >= expected_files
Expand All @@ -257,27 +271,69 @@ def streaming_reasoner(
logging.info("All files verified and validated. Done.")
break

# Terminal state: every expected file is either processed or failed.
# Report failures explicitly instead of claiming success.
all_terminal = (
expected_files is not None
and (processed | failed) >= expected_files
and not reasoning_futures
and not validation_futures
)
if all_terminal and failed:
logging.error(
f"All files finished, but {len(failed)} file(s) failed verification."
)
for ff in sorted(failed):
rel_path = os.path.relpath(ff, proj_dir) if proj_dir else os.path.relpath(ff, input_dir)
print(f"[failed] {rel_path}: verification error")
break

# Detect if spec generation subprocesses exited before all files are ready
_all_procs = spec_procs if spec_procs else None
if _all_procs is not None and all(_spec_task_done(p) for p in _all_procs):
unready = (expected_files or set()) - processed
if unready and not reasoning_futures and not validation_futures:
# Final scan: producers may have finished writing markers after the
# last regular scan, so check remaining expected files once more.
newly_ready = False
for file_path in (expected_files or set()) - processed - submitted - failed:
ext = os.path.splitext(file_path)[1]
if ext not in EXT_TO_LANG:
continue
if not is_file_ready(file_path):
continue
_submit_file(file_path, ext)
newly_ready = True
if newly_ready:
logging.info(
"All spec producers done; rescan found newly ready files, submitting them."
)
continue

unready = (expected_files or set()) - processed - failed
if not reasoning_futures and not validation_futures:
exit_codes = [_spec_task_exit_code(p) for p in _all_procs]
if not processed:
# No function got a spec at all – this is an error
logging.warning(
f"Spec generation process(es) exited (codes {exit_codes}) "
f"but no .spec.json/.info.json sidecar pairs were created."
)
else:
# Some functions are missing specs; leave them pending for retry.
logging.warning(
f"Spec generation process(es) exited (codes {exit_codes}), "
f"{len(unready)} files missing specs, leaving them pending for retry."
if unready:
if not processed:
# No function got a spec at all – this is an error
logging.warning(
f"Spec generation process(es) exited (codes {exit_codes}) "
f"but no .spec.json/.info.json sidecar pairs were created."
)
else:
# Some functions are missing specs; leave them pending for retry.
logging.warning(
f"Spec generation process(es) exited (codes {exit_codes}), "
f"{len(unready)} files missing specs, leaving them pending for retry."
)
for uf in sorted(unready):
rel_path = os.path.relpath(uf, proj_dir) if proj_dir else os.path.relpath(uf, input_dir)
print(f"[pending] {rel_path}: no spec yet; will retry")
if failed:
logging.error(
f"{len(failed)} file(s) failed verification and will not be retried."
)
for uf in sorted(unready):
rel_path = os.path.relpath(uf, proj_dir) if proj_dir else os.path.relpath(uf, input_dir)
print(f"[pending] {rel_path}: no spec yet; will retry")
for ff in sorted(failed):
rel_path = os.path.relpath(ff, proj_dir) if proj_dir else os.path.relpath(ff, input_dir)
print(f"[failed] {rel_path}: verification error")
break

time.sleep(poll_interval)
Expand Down