Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a55e93763b |
@@ -10,3 +10,8 @@ gitea-mcp*.json
|
||||
.vscode/
|
||||
graphify-out/
|
||||
branches/
|
||||
# Throwaway agent payload/encoding helpers (#261): delete after the MCP
|
||||
# commit completes or aborts; ignored here so strays cannot block issue locks.
|
||||
_encode_*.py
|
||||
_emit_*.py
|
||||
_inline_*.py
|
||||
|
||||
@@ -459,6 +459,33 @@ touching anything.
|
||||
files, detected secret, or any production/deploy behavior — **stop, report the
|
||||
blocker, and take no mutating action.** Fail closed; never work around a gate.
|
||||
|
||||
## Agent temp artifact cleanup (#261)
|
||||
|
||||
Failed or aborted subagent runs have left throwaway helper scripts in the
|
||||
shared working tree — for example `_encode_commit_payload.py` and
|
||||
`_emit_payload.py` from the #152 commit-recovery attempt. These artifacts are
|
||||
never part of any issue scope. They pollute `git status`, which trips
|
||||
fail-closed gates: `gitea_lock_issue` refuses to lock over tracked edits, and
|
||||
the pre-flight purity checks attribute the dirt to the current session.
|
||||
|
||||
Rules:
|
||||
|
||||
- **Delete throwaway helpers as soon as the MCP commit completes or aborts.**
|
||||
Any file matching `_encode_*`, `_emit_*`, or `_inline_*` created as a
|
||||
scratch payload/encoding helper must be removed in the same session that
|
||||
created it — success and failure paths alike.
|
||||
- **Prefer the scratchpad.** Payload preparation belongs in the session
|
||||
scratchpad or a temp directory, never inside the repository worktree
|
||||
(see the shell-free commit payload work in #263).
|
||||
- **`.gitignore` backstop.** The patterns `_encode_*.py`, `_emit_*.py`, and
|
||||
`_inline_*.py` are ignored so a leftover helper cannot show up as an
|
||||
untracked file and block issue locks for later sessions. Ignoring them is a
|
||||
safety net, not permission to leave them behind.
|
||||
- **Cleanup checklist before ending any author session:** run
|
||||
`git status --porcelain` in the worktree you mutated; remove any
|
||||
`_encode_*` / `_emit_*` / `_inline_*` files you created; report the removal
|
||||
in the final run report like any other local mutation.
|
||||
|
||||
## Task/role alignment (#167)
|
||||
|
||||
The **requested task** decides what a session may do — not the credential it
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
"""Docs checks for agent temp-artifact cleanup guidance (#261).
|
||||
|
||||
Failed subagent runs left throwaway helper scripts (e.g.
|
||||
``_encode_commit_payload.py``, ``_emit_payload.py``) in the shared working
|
||||
tree, polluting ``git status`` and tripping issue-lock / preflight gates.
|
||||
These tests keep the cleanup runbook guidance present and the ignore
|
||||
patterns in place so stray helpers can never dirty a worktree again.
|
||||
"""
|
||||
from pathlib import Path
|
||||
|
||||
REPO_ROOT = Path(__file__).resolve().parent.parent
|
||||
RUNBOOK = REPO_ROOT / "docs" / "llm-workflow-runbooks.md"
|
||||
GITIGNORE = REPO_ROOT / ".gitignore"
|
||||
|
||||
ARTIFACT_PATTERNS = ("_encode_*.py", "_emit_*.py", "_inline_*.py")
|
||||
|
||||
|
||||
def _runbook_text():
|
||||
assert RUNBOOK.is_file(), "missing docs/llm-workflow-runbooks.md"
|
||||
return RUNBOOK.read_text(encoding="utf-8")
|
||||
|
||||
|
||||
def _gitignore_text():
|
||||
assert GITIGNORE.is_file(), "missing .gitignore"
|
||||
return GITIGNORE.read_text(encoding="utf-8")
|
||||
|
||||
|
||||
def test_runbook_has_agent_temp_artifact_cleanup_section():
|
||||
text = _runbook_text()
|
||||
assert "## Agent temp artifact cleanup" in text, (
|
||||
"runbook lacks an 'Agent temp artifact cleanup' section")
|
||||
assert "#261" in text, "cleanup guidance does not reference issue #261"
|
||||
|
||||
|
||||
def test_runbook_names_known_stray_artifacts():
|
||||
text = _runbook_text()
|
||||
for name in ("_encode_commit_payload.py", "_emit_payload.py"):
|
||||
assert name in text, f"runbook does not name stray artifact {name!r}"
|
||||
|
||||
|
||||
def test_runbook_covers_all_artifact_patterns():
|
||||
text = _runbook_text()
|
||||
for pattern in ("_encode_*", "_emit_*", "_inline_*"):
|
||||
assert pattern in text, f"runbook does not cover pattern {pattern!r}"
|
||||
|
||||
|
||||
def test_runbook_requires_cleanup_after_commit_or_abort():
|
||||
text = _runbook_text().lower()
|
||||
assert "delete" in text or "remove" in text
|
||||
for phase in ("completes", "aborts"):
|
||||
assert phase in text, (
|
||||
f"runbook does not require cleanup when the MCP commit {phase}")
|
||||
|
||||
|
||||
def test_runbook_explains_lock_and_preflight_impact():
|
||||
text = _runbook_text().lower()
|
||||
assert "gitea_lock_issue" in text
|
||||
assert "preflight" in text or "pre-flight" in text
|
||||
|
||||
|
||||
def test_gitignore_blocks_agent_helper_patterns():
|
||||
lines = [
|
||||
ln.strip() for ln in _gitignore_text().splitlines()
|
||||
if ln.strip() and not ln.strip().startswith("#")
|
||||
]
|
||||
for pattern in ARTIFACT_PATTERNS:
|
||||
assert pattern in lines, f".gitignore lacks pattern {pattern!r}"
|
||||
|
||||
|
||||
def test_no_stray_agent_helpers_in_repo_root():
|
||||
"""Acceptance: artifacts stay removed from default worktrees."""
|
||||
stray = [
|
||||
p.name for pattern in ARTIFACT_PATTERNS
|
||||
for p in REPO_ROOT.glob(pattern)
|
||||
]
|
||||
assert not stray, f"stray agent helper artifacts present: {stray}"
|
||||
Reference in New Issue
Block a user