refactor: consolidate skill docs, add anti-drift tests, and apply audit fixes
DLO-13: Restructure vlm-library-workflow skill as safety contract layer. - Rewrite SKILL.md (69 lines): safety contract, execution threshold semantics, six-step high-risk loop, decision rules, phase skeleton - Delete redundant references (cli-reference, workflow, command-recipes, dev-guide) - Add triage.md (failure mapping + preflight) and dev-map.md (module→test mapping) - Add tests/test_docs_consistency.py: 78 parametrized tests verifying documented vlm commands exist in CLI registry - Add CSV path mismatch test to test_plan_review.py (4th safety gate path) - Delete vlm-expert.skill (Gemini package, 7 months stale) and README Gemini section DLO-2 audit fixes: rate limiter injection, symmetric quarantine categories, review-plan safety gates, parser improvements, planner validation. CLI modularization: commands/ directory with one module per command group.
This commit is contained in:
@@ -76,6 +76,63 @@ def test_build_identity_lookup_and_enrich(tmp_path):
|
||||
assert enriched[0]["source_name"] == "Show.S01E01.mkv"
|
||||
|
||||
|
||||
def test_enrich_review_rows_sidecars_column(tmp_path):
|
||||
op = FileOperation(
|
||||
operation_type="move",
|
||||
source_path=tmp_path / "dl/Show.S01E01.mkv",
|
||||
destination_path=tmp_path / "lib/series/Show/Season 01/S01E01.mkv",
|
||||
reason="organize",
|
||||
has_conflict=False,
|
||||
review_context={
|
||||
"title": "Show",
|
||||
"category": "series",
|
||||
"season": 1,
|
||||
"episode": 1,
|
||||
"sidecars": [
|
||||
{"name": "Show.S01E01.zh.srt", "source_path": str(tmp_path / "dl/Show.S01E01.zh.srt"), "proposed_destination_path": str(tmp_path / "lib/series/Show/Season 01/Show.S01E01.zh.srt")},
|
||||
{"name": "Show.S01E01.nfo", "source_path": str(tmp_path / "dl/Show.S01E01.nfo"), "proposed_destination_path": str(tmp_path / "lib/series/Show/Season 01/Show.S01E01.nfo")},
|
||||
],
|
||||
},
|
||||
)
|
||||
plan = _minimal_plan([op])
|
||||
rows = [
|
||||
{
|
||||
"index": "1",
|
||||
"operation_type": "move",
|
||||
"risk_flags": "",
|
||||
"source_path": str(op.source_path),
|
||||
"destination_path": str(op.destination_path),
|
||||
"reason": op.reason,
|
||||
}
|
||||
]
|
||||
enriched = enrich_review_rows(rows, plan, library_root=tmp_path / "lib")
|
||||
assert enriched[0]["sidecars"] == "Show.S01E01.zh.srt, Show.S01E01.nfo"
|
||||
|
||||
|
||||
def test_enrich_review_rows_sidecars_empty_by_default(tmp_path):
|
||||
op = FileOperation(
|
||||
operation_type="move",
|
||||
source_path=tmp_path / "dl/Show.S01E01.mkv",
|
||||
destination_path=tmp_path / "lib/series/Show/Season 01/S01E01.mkv",
|
||||
reason="organize",
|
||||
has_conflict=False,
|
||||
review_context={"title": "Show", "category": "series", "season": 1, "episode": 1},
|
||||
)
|
||||
plan = _minimal_plan([op])
|
||||
rows = [
|
||||
{
|
||||
"index": "1",
|
||||
"operation_type": "move",
|
||||
"risk_flags": "",
|
||||
"source_path": str(op.source_path),
|
||||
"destination_path": str(op.destination_path),
|
||||
"reason": op.reason,
|
||||
}
|
||||
]
|
||||
enriched = enrich_review_rows(rows, plan, library_root=tmp_path / "lib")
|
||||
assert enriched[0].get("sidecars", "") == ""
|
||||
|
||||
|
||||
def test_check_review_requirements_missing_csv(tmp_path):
|
||||
plan_path = tmp_path / "plan.json"
|
||||
op = FileOperation(
|
||||
@@ -137,6 +194,30 @@ def test_check_review_requirements_passes_after_apply_review(tmp_path):
|
||||
assert errors == []
|
||||
|
||||
|
||||
def test_check_review_requirements_detects_csv_path_mismatch(tmp_path):
|
||||
plan_path = tmp_path / "plan.json"
|
||||
csv_path = tmp_path / "review.csv"
|
||||
other_csv = tmp_path / "other.csv"
|
||||
op = FileOperation(
|
||||
operation_type="move",
|
||||
source_path=tmp_path / "a.mkv",
|
||||
destination_path=tmp_path / "lib/a.mkv",
|
||||
reason="Series needs manual review (season exceeds configured threshold)",
|
||||
has_conflict=True,
|
||||
)
|
||||
plan = _minimal_plan([op])
|
||||
save_plan(plan, plan_path)
|
||||
rows, _ = review_plan(plan)
|
||||
save_review_csv(rows, csv_path)
|
||||
save_review_csv(rows, other_csv)
|
||||
|
||||
updated = apply_review_to_plan(load_plan(plan_path), csv_path)
|
||||
save_plan(updated, plan_path)
|
||||
|
||||
errors = check_review_requirements(load_plan(plan_path), plan_path, other_csv)
|
||||
assert any("does not match" in e for e in errors)
|
||||
|
||||
|
||||
def test_planner_noop_manual_review_does_not_block_execute_gate(tmp_path):
|
||||
plan_path = tmp_path / "plan.json"
|
||||
op = FileOperation(
|
||||
|
||||
Reference in New Issue
Block a user