feat: check in workflow contract manifest

This commit is contained in:
lda
2026-08-03 07:46:50 +07:00 Verified
parent b100675658
commit fe3889c9b4
4 changed files with 8431 additions and 0 deletions
+43
View File
@@ -0,0 +1,43 @@
# Task 4 Report
## Scope
Implemented the workflow contract manifest module CLI and checked in the manifest artifact required by Task 4.
Created:
- `src/wf_contract_manifest/__main__.py`
- `tests/wf_contract_manifest/test_cli.py`
- `contracts/workflow-api.manifest.json`, generated by `python -m wf_contract_manifest write`
The CLI supports only the module commands `write` and `check`; no project script was added.
## TDD Evidence
The CLI tests were written before the production module. The required RED run failed during collection with:
`ModuleNotFoundError: No module named 'wf_contract_manifest.__main__'`
After implementing the module CLI, the CLI test file passed with `3 passed`.
## Verification
- CLI tests: `3 passed`
- All manifest tests: `51 passed`
- Ruff: `All checks passed!`
- basedpyright: `0 errors, 0 warnings, 0 notes`
- `git diff --check`: passed
- Module generation: wrote `contracts/workflow-api.manifest.json`
- Module drift check: checked the generated manifest successfully
- Independent bounded JSON assertions:
- operations: `70`
- component schemas: `126`
- component errors: `1`
- first method: `workflow.admin.auth.delete`
- last method: `workflow.sources.list`
## Review And Concerns
The CLI follows the exact Task 4 interface and catches the manifest, drift, and value errors specified by the brief. The generated JSON was not hand-edited. No Task 4 concerns remain.
The worktree contained a pre-existing staged deletion of `.superpowers/sdd/task-2-report.md`; it was preserved and excluded from the Task 4 staging set.
File diff suppressed because it is too large Load Diff
+40
View File
@@ -0,0 +1,40 @@
from __future__ import annotations
import argparse
import sys
from collections.abc import Sequence
from .generate import generate_manifest
from .io import (
DEFAULT_MANIFEST_PATH,
ManifestDriftError,
check_manifest,
write_manifest,
)
from .model import ManifestError
def _parser() -> argparse.ArgumentParser:
parser = argparse.ArgumentParser(description="Manage the checked workflow API contract manifest.")
parser.add_argument("command", choices=("write", "check"))
return parser
def main(argv: Sequence[str] | None = None) -> int:
args = _parser().parse_args(argv)
try:
manifest = generate_manifest()
if args.command == "write":
path = write_manifest(manifest, DEFAULT_MANIFEST_PATH)
print(f"wrote {path}")
else:
check_manifest(manifest, DEFAULT_MANIFEST_PATH)
print(f"checked {DEFAULT_MANIFEST_PATH}")
except (ManifestError, ManifestDriftError, ValueError) as error:
print(str(error), file=sys.stderr)
return 1
return 0
if __name__ == "__main__":
raise SystemExit(main())
+51
View File
@@ -0,0 +1,51 @@
from __future__ import annotations
from pathlib import Path
import pytest
from wf_contract_manifest import (
ContractManifest,
ManifestDriftError,
manifest_from_openrpc,
)
from wf_contract_manifest.__main__ import main
from .fixtures import synthetic_openrpc_document
def _manifest() -> ContractManifest:
return manifest_from_openrpc(synthetic_openrpc_document())
def test_write_generates_once_and_writes_requested_contract(monkeypatch, tmp_path: Path) -> None:
manifest = _manifest()
calls: list[tuple[object, Path]] = []
monkeypatch.setattr("wf_contract_manifest.__main__.generate_manifest", lambda: manifest)
monkeypatch.setattr(
"wf_contract_manifest.__main__.write_manifest",
lambda value, path: calls.append((value, path)) or path,
)
monkeypatch.setattr("wf_contract_manifest.__main__.DEFAULT_MANIFEST_PATH", tmp_path / "manifest.json")
assert main(["write"]) == 0
assert calls == [(manifest, tmp_path / "manifest.json")]
def test_check_returns_nonzero_and_prints_drift_guidance(monkeypatch, capsys) -> None:
monkeypatch.setattr("wf_contract_manifest.__main__.generate_manifest", _manifest)
def fail_check(_manifest, _path) -> None:
raise ManifestDriftError("stale; run `python -m wf_contract_manifest write`")
monkeypatch.setattr("wf_contract_manifest.__main__.check_manifest", fail_check)
assert main(["check"]) == 1
assert "python -m wf_contract_manifest write" in capsys.readouterr().err
def test_rejects_unknown_command() -> None:
with pytest.raises(SystemExit) as exc_info:
main(["unknown"])
assert exc_info.value.code == 2