Files
violin/tests/guard/test_auto_friction_log.py
Violin 119e0c1600 feat(guard): friction auto-logs at block time + record-as-you-go contract
Agent was deferring framework feedback and state writes to closeout, then
reconstructing what happened from conversation memory after compression —
the exact mechanism that fabricates false positives.

- Guard now self-logs: _check_command_internal appends a Guard Block/Review
  row to state/framework_feedback.md at the moment check_command rejects a
  command (only when the file exists, i.e. benchmark engagements; no-op
  otherwise). Friction is captured with zero agent bookkeeping.
- SKILL.md Operational Contract: 'Record as you go' — after EVERY
  violin_review_batch, immediately update hypothesis board + coverage matrix
  + PTT in the same turn; never batch state writes to closeout, never
  reconstruct tests from memory. State files are the only source of truth.
- 5 new tests: block-row append, no-op without file/errors, dedupe, pipe
  escaping.

243 tests pass, ruff clean.
2026-08-11 13:41:51 +01:00

79 lines
2.9 KiB
Python

"""Tests for automatic guard-friction logging (framework feedback as it happens)."""
from __future__ import annotations
from pathlib import Path
from plugins.violin_guard.command import CheckResult
from plugins.violin_guard.handlers.base import _log_guard_friction
def _feedback_file(eng_dir: Path) -> Path:
return eng_dir / "state" / "framework_feedback.md"
def test_log_guard_friction_appends_block_row(tmp_path: Path) -> None:
eng_dir = tmp_path / "eng"
(eng_dir / "state").mkdir(parents=True)
feedback = _feedback_file(eng_dir)
feedback.write_text(
"# Violin Framework Feedback & Friction Log\n\n| Timestamp | Category | Issue | Impact | Prevention |\n|---|---|---|---|---|\n",
encoding="utf-8",
)
result = CheckResult()
result.add_error("destructive filesystem deletion (rm -rf) is blocked")
_log_guard_friction(eng_dir, result, "rm -rf /")
text = feedback.read_text(encoding="utf-8")
assert "Guard Block" in text
assert "rm -rf" in text
assert "destructive filesystem deletion" in text
def test_log_guard_friction_noop_without_file(tmp_path: Path) -> None:
"""Non-benchmark engagements (no framework_feedback.md) are untouched."""
eng_dir = tmp_path / "eng"
(eng_dir / "state").mkdir(parents=True)
result = CheckResult()
result.add_error("some block")
_log_guard_friction(eng_dir, result, "cmd")
assert not _feedback_file(eng_dir).exists()
def test_log_guard_friction_noop_without_errors(tmp_path: Path) -> None:
eng_dir = tmp_path / "eng"
(eng_dir / "state").mkdir(parents=True)
feedback = _feedback_file(eng_dir)
feedback.write_text("header\n", encoding="utf-8")
result = CheckResult()
result.add_info("all good")
_log_guard_friction(eng_dir, result, "ok-cmd")
assert "Guard" not in feedback.read_text(encoding="utf-8")
def test_log_guard_friction_dedupes_identical_rows(tmp_path: Path) -> None:
eng_dir = tmp_path / "eng"
(eng_dir / "state").mkdir(parents=True)
feedback = _feedback_file(eng_dir)
feedback.write_text(
"| Timestamp | Category | Issue | Impact | Prevention |\n|---|---|---|---|---|\n",
encoding="utf-8",
)
result = CheckResult()
result.add_error("same issue twice")
_log_guard_friction(eng_dir, result, "cmd")
_log_guard_friction(eng_dir, result, "cmd")
assert feedback.read_text(encoding="utf-8").count("same issue twice") == 1
def test_log_guard_friction_escapes_pipes(tmp_path: Path) -> None:
eng_dir = tmp_path / "eng"
(eng_dir / "state").mkdir(parents=True)
feedback = _feedback_file(eng_dir)
feedback.write_text("header\n", encoding="utf-8")
result = CheckResult()
result.add_error("a | b | c")
_log_guard_friction(eng_dir, result, "cmd")
text = feedback.read_text(encoding="utf-8")
# the pipe inside the issue must not split the table row into extra cells
assert text.count("| a \\| b \\| c |") == 1