feat: complete production workflow migration

This commit is contained in:
2026-08-06 14:29:57 +08:00
parent 7f215e79c4
commit 8df5266abb
448 changed files with 56937 additions and 14619 deletions
+57 -2
View File
@@ -8,7 +8,7 @@ import pytest
from gyxx_flow.core.context import RunContext
from gyxx_flow.core.layout import DataLayout
from gyxx_flow.core.records import RunJournal
from gyxx_flow.core.records import RunJournal, RunMode
from gyxx_flow.ops import IdempotencyConflict, Outbox, RunIndex
@@ -18,6 +18,7 @@ def _journal(
workflow_id: str = "shop.weekly",
business_date: str = "2026-07-27",
suffix: str = "abc123",
mode: RunMode = "unknown",
) -> RunJournal:
context = RunContext.create(
workflow_id,
@@ -25,7 +26,7 @@ def _journal(
now=datetime(2026, 7, 27, 4, 0, tzinfo=timezone.utc),
random_suffix=suffix,
)
return RunJournal.create(DataLayout(root), context)
return RunJournal.create(DataLayout(root), context, mode=mode)
def test_run_index_snapshots_journals_and_supports_structured_queries(tmp_path: Path) -> None:
@@ -43,6 +44,7 @@ def test_run_index_snapshots_journals_and_supports_structured_queries(tmp_path:
first_record = index.index_journal(first)
second_record = index.index_journal(second.path)
assert first_record.mode == "unknown"
assert first_record.status == "success"
assert second_record.error == "collector failed"
assert index.get(first_record.run_id) == first_record
@@ -80,6 +82,59 @@ def test_run_index_rejects_malformed_journal_without_writing_index(tmp_path: Pat
assert index.query() == ()
def test_run_index_preserves_mode_and_accepts_legacy_records(tmp_path: Path) -> None:
journal = _journal(tmp_path, mode="dry_run")
journal.start_step("collect.attempt-1", attempt=1)
journal.finish_step("collect.attempt-1", status="skipped", error="dry-run")
journal.finalize("success")
index = RunIndex(tmp_path)
current = index.index_journal(journal)
assert current.mode == "dry_run"
assert current.schema_version == 2
current_payload = json.loads(
(tmp_path / "state" / "ops" / "run-index" / f"{current.run_id}.json").read_text(
encoding="utf-8"
)
)
assert current_payload["mode"] == "dry_run"
assert current_payload["schema_version"] == 2
current_payload.pop("mode")
current_payload["schema_version"] = 1
(tmp_path / "state" / "ops" / "run-index" / f"{current.run_id}.json").write_text(
json.dumps(current_payload),
encoding="utf-8",
)
legacy = index.get(current.run_id)
assert legacy is not None
assert legacy.mode == "unknown"
assert legacy.schema_version == 1
def test_run_index_treats_a_legacy_journal_without_mode_as_unknown(tmp_path: Path) -> None:
journal = _journal(tmp_path, suffix="legacy1", mode="execute")
payload = json.loads(journal.path.read_text(encoding="utf-8"))
payload.pop("mode")
journal.path.write_text(json.dumps(payload), encoding="utf-8")
record = RunIndex(tmp_path).index_journal(journal)
assert record.mode == "unknown"
assert record.schema_version == 2
def test_run_journal_rejects_an_invalid_mode_before_creating_files(tmp_path: Path) -> None:
context = RunContext.create("shop.weekly", "2026-07-27", random_suffix="badmode")
with pytest.raises(ValueError, match="run mode"):
RunJournal.create(DataLayout(tmp_path), context, mode="preview") # type: ignore[arg-type]
assert not (tmp_path / "runs").exists()
def test_outbox_enqueue_is_atomic_and_idempotent(tmp_path: Path) -> None:
outbox = Outbox(tmp_path)