fix(jobs): bind completed effects to checkpoints

This commit is contained in:
2026-07-12 04:54:00 +02:00
parent c964920f16
commit b6a52995ae
5 changed files with 174 additions and 7 deletions
+48
View File
@@ -62,6 +62,22 @@ class Vectors:
return 0
class InterruptingVectors(Vectors):
def __init__(self):
super().__init__()
self.batches = []
self.interrupt = True
def upsert(self, collection, records):
self.batches.append([value.record.id for value in records])
if self.interrupt:
self.interrupt = False
self.records.append(records[0])
raise KeyboardInterrupt("process interruption after partial write")
self.records.extend(records)
return len(records)
def item(name, fingerprint):
return SourceObject(
source_id=f"fs:{name}", uri=f"file:///safe/{name}.md", fingerprint=f"sha256:{fingerprint}"
@@ -309,3 +325,35 @@ def test_job_pipeline_rejects_corrupt_required_artifacts_before_resume(
input_fingerprint="sha256:" + "2" * 64,
resume_run_id=crashed.name,
)
def test_vector_intent_is_reconciled_after_process_interruption_without_duplicate_upsert(tmp_path):
one = item("one", "a")
vectors = InterruptingVectors()
candidate = pipeline(
tmp_path, Source([(one, "a" * 250)]), vectors=vectors,
policy=ChunkPolicy(version="chunk-v1", max_chars=100),
)
with pytest.raises(KeyboardInterrupt):
candidate.run_as_job(
workspace_id="demo", workspace_root=tmp_path,
config_fingerprint="sha256:" + "1" * 64,
input_fingerprint="sha256:" + "2" * 64,
)
runs = tmp_path / ".tht-jobs" / "evidence" / "runs"
interrupted = next(runs.iterdir())
checkpoint = __import__("json").loads((interrupted / "checkpoint.json").read_text())
vector_stage = checkpoint["stages"][3]
assert vector_stage["status"] == "running"
assert vector_stage["effect_state"] == "intent"
first_written = vectors.batches[0][0]
result = candidate.run_as_job(
workspace_id="demo", workspace_root=tmp_path,
config_fingerprint="sha256:" + "1" * 64,
input_fingerprint="sha256:" + "2" * 64,
resume_run_id=interrupted.name,
)
assert result.status == "succeeded" and result.published is True
assert first_written not in vectors.batches[1]
assert len(vectors.records) == 3