Prevent, attribute, and recover unknown task files written into the control checkout #913

Open
opened 2026-07-25 16:29:29 -05:00 by jcwalker3 · 1 comment
Owner

Problem statement

A conforming client session running the canonical work-issue workflow stopped before task selection because the stable control checkout held an untracked task file it did not create and could not attribute. Stopping was correct. What is defective is that the system (a) allowed a supported session to put that file there, (b) reports the control checkout as clean in its own authoritative runtime state while the file is present, (c) has no way to say which session, issue, branch, or worktree owns it, and (d) offers no sanctioned operation that preserves it and restores a clean checkout. The only exit is operator guesswork, and operator cleanup destroyed the evidence before it could be claimed.

Supported workflow that was attempted

  • Canonical workflow: skills/llm-project-workflow/workflows/work-issue.md
  • Workflow hash at incident time: 14e515cdaa6a7f0ff9f02951c9c9cb1f0f6fcaddf7732bbc263c4df96d16eec9
  • Verified unchanged: the same file at master 76f293eb hashes to the identical value, so this is not a stale-workflow artifact.
  • Requested task: continue working on permissible tasks for this project — i.e. normal allocator-driven task selection.

Chronological reproduction using authoritative state

  1. 2026-07-25 ~17:13:44 −0400 — an author session working issue #666 wrote tests/test_mcp_restart_governance.py into the control checkout at /Users/jasonwalker/Development/Gitea-Tools/tests/, size 17,770 bytes, 488 lines. The file was never tracked, never staged, never committed there.
  2. ~17:14 — the same work landed correctly in the registered worktree branches/feat-issue-666-concurrent-mcp-restart-tests as a different revision: 17,252 bytes, 478 lines, committed as 59aab06fe17f80b5d0b87a31c76f761b195d8425 and published as PR #910. The control-checkout copy is therefore an earlier, divergent draft, not a duplicate of the committed file — it is unique content with no other copy.
  3. Later — a fresh session loaded work-issue at hash 14e515cd…, observed the control checkout on master @ 76f293eb288fa6cbb3134e093fc960ac01517e75 with the untracked file present, applied work-issue.md §3 (dirty control checkout → stop immediately) and §4 ("If the main checkout is dirty before selection, stop and produce a recovery handoff"), and stopped before task selection. It preserved the file and performed no Git, repository, issue, branch, commit, push, or PR mutation. This behaviour was correct.
  4. Verified in the current session (read-only) — the control checkout is on master @ 76f293eb288fa6cbb3134e093fc960ac01517e75, git status --porcelain --untracked-files=all is empty, and tests/test_mcp_restart_governance.py no longer exists at the control-checkout path. The only surviving copy is the committed one in the #666 worktree, which is a different revision. The 488-line draft was removed with no audit record, no attribution, and no preservation — the recovery failure mode this issue exists to close.

First proven divergence from canonical behaviour

The divergence is the write itself, upstream of every gate that later observed it.

Issue #274 (closed) defines the control checkout as read-only for task work, lists "creating files" as a mutation, and states the acceptance criterion: "Any attempted mutation outside branches/ fails before the command runs." In the implementation, that guarantee exists only inside the MCP mutation preflight chain — gitea_mcp_server.py:1537 and :1577 call _enforce_root_checkout_guard (gitea_mcp_server.py:1872-1889) on the way to a Gitea/Git mutation. A client-side file write into the control checkout never enters that chain, so nothing intercepts it. The first divergence is that a supported session could create the file at all.

The second, compounding divergence is that once created, the file is invisible to the enforced guard:

  • root_checkout_guard.assess_root_checkout_guard (root_checkout_guard.py:52-111) derives dirtiness at line 82 from reviewer_worktree.parse_dirty_tracked_files.
  • parse_dirty_tracked_files (reviewer_worktree.py:44-62) discards every ?? line by design, documented as "Untracked entries (??) are ignored."
  • gitea_mcp_server._parse_porcelain_entries (gitea_mcp_server.py:579-590) applies the same line.startswith("??") exclusion, and it is the source of dirty_files in gitea_get_runtime_context (gitea_mcp_server.py:688-701) and of _new_tracked_changes_since (:593-601).

Consequence: with an untracked task file sitting in the control checkout, gitea_get_runtime_context reports dirty_files: [] with dirty_scope: "control checkout", and assess_root_checkout_guard returns proven: true. Authoritative runtime state cannot distinguish a genuinely clean control checkout from one holding another session's uncommitted work. This session confirmed the shape: the post-cleanup output is byte-for-byte the same output the tooling would have produced while the file was present.

A third inconsistency sits alongside it: stable_control_runtime.observe_dirty_files (stable_control_runtime.py:600-611) does not filter ??, so two dirty definitions coexist in one codebase and can disagree about the same checkout.

Correct fail-closed stop vs. the condition that made the stop necessary

  • Correct, keep it: refusing to select a task, refusing to touch the unknown file, and refusing to mutate anything while the control checkout was contaminated. work-issue.md §3/§4 is right and must not be relaxed.
  • Defective, fix it: that the contaminated state was reachable by a supported session; that the enforced guard reported it clean; that no record existed naming its owner; that no sanctioned operation could preserve it and restore a clean checkout; and that the stop therefore terminated the whole queue rather than routing to a recovery.

Additionally, the stop was applied by the model reading the workflow prose against its own git status — not by a code gate. A safety invariant that #274 required to "fail before the command runs" is currently enforced only by prompt text.

No authoritative owner attribution exists

Control-plane ownership is keyed on issues, branches, worktrees, and leases — never on filesystem paths inside the control checkout:

  • worktree_cleanup_audit.audit_branches_directory classifies only entries under branches/ (worktree_cleanup_audit.py:621-640); the control checkout is explicitly excluded as "protected" (:317, :332).
  • agent_temp_artifacts.find_agent_temp_artifacts_from_porcelain (#261) matches untracked repo-root files against three fixed basename globs (_encode_*.py, _emit_*.py, _inline_*.py) and skips anything containing a path separator — so tests/test_mcp_restart_governance.py is out of scope twice over, and it attributes nothing.
  • dirty_orphan_worktree_recovery (#860) requires a registered branches/ worktree plus a durable issue lock naming the claimant; neither exists for the control checkout.

The only attribution available in this incident was forensic inference from file mtime and content diff against PR #910 — exactly the operator guesswork this issue must eliminate.

No sanctioned recovery path exists

gitea_recover_dirty_orphaned_issue_worktree, gitea_rebind_dirty_same_claimant_author_session, and the #812 preserve/prepare/restore model all require a known issue and a known claimant and operate on branches/ worktrees only. For an unattributable artifact in the control checkout there is no preserve step, no quarantine step, and no clean-checkout verification. Deletion is forbidden by work-issue.md §4 and by #274; retention blocks every workflow. That is an unrecoverable state, and it silently resolved into data loss.

Gate boundary is wrong for issue intake

create-issue.md §3 and §4 make a dirty control checkout blocking for issue creation too, and §18a requires gitea_create_issue to run from that clean control checkout. So a contaminated control checkout blocks not only author implementation but also the issue-first intake that would file the incident. The intake path is a pure remote mutation with no local tree write; a control checkout holding foreign untracked content is not a safety reason to refuse it, provided intake cannot slide into author work.

Model-agnostic impact

Nothing in the failing path is client-specific. The contract is the shared canonical workflow plus the MCP gate layer: the same work-issue.md hash, the same _parse_porcelain_entries filter, the same root_checkout_guard, the same absent attribution and absent recovery. Codex, Claude, Gemini, Grok, and any other conforming client reach the identical stop with the identical lack of a next action. A fix that keys on a client name, a model name, or a User-Agent does not fix this.

Relevant source, workflow, and test locations

Source

  • root_checkout_guard.py:52-111assess_root_checkout_guard, dirtiness derived at :82
  • reviewer_worktree.py:44-62parse_dirty_tracked_files, ?? exclusion
  • gitea_mcp_server.py:555-573_get_workspace_porcelain (git status --porcelain, no -uall)
  • gitea_mcp_server.py:579-590_parse_porcelain_entries, ?? exclusion
  • gitea_mcp_server.py:593-601_new_tracked_changes_since
  • gitea_mcp_server.py:688-701gitea_get_runtime_context dirty_files
  • gitea_mcp_server.py:1537, :1577, :1872-1889 — guard enforcement sites
  • stable_control_runtime.py:600-611observe_dirty_files (does not filter ??)
  • worktree_cleanup_audit.py:317, :332, :621-640 — control checkout excluded from classification
  • agent_temp_artifacts.py — repo-root basename-glob detection only
  • dirty_orphan_worktree_recovery.py, dirty_same_claimant_session_rebind.pybranches/-only recovery
  • anti_stomp_preflight.py:547 — second guard call site

Workflow

  • skills/llm-project-workflow/workflows/work-issue.md §3, §4
  • skills/llm-project-workflow/workflows/create-issue.md §3, §4, §18a

Tests

  • tests/test_root_checkout_guard.py
  • tests/test_workspace_guard_alignment.py
  • tests/test_stable_control_runtime.py
  • tests/test_create_issue_workspace_guard.py
  • tests/test_issue_618_author_worktree_resolution.py
  • tests/test_anti_stomp_preflight.py
  • tests/test_namespace_workspace_binding.py

Verified architectural boundary responsible

The control checkout / branches/ worktree isolation boundary (#274, #475, #618, #713). It is responsible for prevention (nothing task-related may be created in the control checkout), attribution (every artifact under repository control must trace to an owning session, issue, branch, or worktree), and recovery (unknown work must be preservable without destroying it and without an operator deciding by hand). Today it enforces only a subset of prevention, and only for tracked paths reached through the MCP mutation preflight.

Scope

  • Detect any unexpected artifact in the control checkout, including untracked paths, and make one dirty definition authoritative across root_checkout_guard, _parse_porcelain_entries, and observe_dirty_files.
  • Prevent or immediately reject task-related writes to the control checkout.
  • Record provenance for artifacts created under repository control so ownership is queryable, not inferred.
  • Add a sanctioned, auditable recovery that preserves unknown work byte-for-byte and returns the control checkout to verified clean.
  • Keep issue-first intake reachable while the control checkout is contaminated, without permitting author implementation.
  • Make every blocked result carry an actionable, satisfiable next action.

Non-goals

  • Weakening the clean-control-checkout invariant or the branches-only rule.
  • Re-owning branches/ worktree recovery (#812, #860, #864) — consume those primitives, do not restate them.
  • Re-owning MCP session-state residue relocation (#716).
  • Re-owning out-of-band shell mutation auditing (#867).
  • Re-owning transient/staged dirty-observation stability (#893).
  • Changing issue #666, its branch, its worktree, or PR #910 in any way.
  • Adding .gitignore or local-exclude entries to hide artifacts from the guard.

Acceptance criteria

AC1 — One authoritative dirty definition. A single classifier decides control-checkout cleanliness, covers modified, staged, deleted, renamed, and untracked paths, and is used by assess_root_checkout_guard, gitea_get_runtime_context, and stable_control_runtime. Any two of these reporting different cleanliness for the same checkout is itself a test failure.

AC2 — Untracked contamination is visible. With an untracked non-ignored file present in the control checkout, gitea_get_runtime_context reports it in dirty_files with dirty_scope: "control checkout", and the root-checkout guard reports proven: false with that path named. Ignored files are excluded and the exclusion is reported, not silent.

AC3 — Prevention or immediate rejection. A task-related write to the control checkout is prevented, or is detected and rejected at the next gate boundary with the exact path named — before any task selection, claim, lease, branch, or commit occurs. The rejection is produced by a code gate, not by workflow prose alone.

AC4 — Provenance is recorded, not inferred. Artifacts created under repository control carry a durable provenance record naming the session identity, profile, role kind, issue, branch, and bound worktree. A read-only query maps an unexpected control-checkout path to its owner, or returns an explicit owner_unknown verdict with the evidence it consulted. Inference from mtime or content similarity is never presented as attribution.

AC5 — Preservation without data loss. A sanctioned MCP operation preserves unknown control-checkout content — tracked modifications and untracked files — byte-for-byte into a durable addressable checkpoint outside the working tree, with per-file content hashes, before anything is moved or removed. The operation is non-destructive and idempotent on unchanged content. It reuses the #812 preserve/restore primitives where they exist rather than duplicating them.

AC6 — Deterministic sanctioned recovery. A single sanctioned operation carries the control checkout from contaminated to verified-clean: classify → attribute (or record owner_unknown) → preserve → restore the checkout → verify. It has a read-only assessor whose verdict and evidence match the mutating path, and a dry-run that mutates nothing. It never deletes, stashes, resets, cleans, or silently relocates unknown work, and it fails closed on any content-loss risk, ambiguous ownership, or a live competing owner.

AC7 — Clean-checkout verification after recovery. After recovery the control checkout passes the canonical clean-checkout preflight under the AC1 definition, no tracked file and no Git ref changed, no unrelated content was removed, and a durable audit record names the checkpoint id, per-file hashes, acting identity and profile, and the disposition of every path.

AC8 — Issue intake stays reachable. With the control checkout contaminated, gitea_create_issue remains available (it performs no local tree write), while work_issue, lock_issue, commit_files, create_pr, and every other author implementation mutation stay fail-closed. Intake cannot silently become author work: no assignment, no issue lock, no lease, no branch, and no worktree is created by the intake path.

AC9 — Actionable blocked results. Any blocked result from this class names: the exact failed gate; the exact conflicting artifact path(s); the known owner and owning task, or an explicit statement that the owner is unknown; whether recovery is automatic or requires an operator; and the exact sanctioned next action, satisfiable at the phase it is emitted in.

AC10 — Restart honesty. No message in this path reports an MCP restart or reconnect as necessary unless authoritative runtime state (master parity / namespace health) actually requires it.

AC11 — No regression in guard strictness. Dirty, drifted, detached, and non-canonical control checkouts still fail closed for every caller that has not gone through the sanctioned recovery operation. Recovery is an explicit operation, never a general exemption or a bypass flag.

Regression requirements

  1. Prevention / immediate rejection — a task write into the control checkout is prevented or rejected before task selection, with the exact path named (AC3).
  2. Concurrent sessions and issue-specific worktrees — two concurrent author sessions on different issues, each with its own registered branches/ worktree, both complete normally; neither can claim, quarantine, or destroy the other's work, and neither is blocked by the other's worktree state.
  3. Ownership / provenance of unexpected artifacts — an unexpected untracked path resolves to its owning session/issue/branch/worktree when a provenance record exists, and to an explicit owner_unknown verdict with consulted evidence when it does not.
  4. Preservation of unknown work — preserve captures tracked-modified, untracked, staged, and mixed content; hashes verify equal before and after; the source is byte-identical after preserve; a hash mismatch, a missing file, and a restore collision each fail closed with the specific paths named.
  5. Deterministic sanctioned recovery — the full classify→attribute→preserve→restore→verify path runs end to end from a synthetic contaminated checkout; assessor and mutator agree; dry-run mutates nothing.
  6. Clean-checkout verification after recovery — post-recovery the canonical preflight passes under the AC1 definition, and no tracked file or Git ref changed.
  7. Issue intake without entering author implementationgitea_create_issue succeeds against a contaminated control checkout while work_issue / lock_issue / commit_files / create_pr fail closed, and the intake path creates no assignment, lock, lease, branch, or worktree.
  8. Accurate actionable diagnostics — the blocked payload asserts every AC9 field, and asserts no restart/reconnect claim is emitted when parity is green (AC10).
  9. Ordinary clean-checkout workflows — a clean control checkout on master at live master proceeds through allocation, claim, worktree creation, implementation, and PR creation with no new gate, no new prompt, and no measurable added latency.
  10. Existing unaffected behaviour — author, reviewer, merger, reconciler, and controller flows keep their current semantics. Named coverage must include: the #475 root-checkout guard cases; the #540 reconciler exemption via actual_role; the #618 author worktree resolution; the #713 registered-worktree proof; the #749 / §18a create-issue bootstrap exemption and its non-generalization; and the #860 / #864 dirty-worktree recovery and rebind semantics.

Prohibited

  • Prompt-only fixes. Adding or rewording workflow text without a code gate does not satisfy AC3.
  • Client-specific checks. No Codex-specific, Claude-specific, Gemini-specific, or Grok-specific branches; no LLM-name, model-name, or User-Agent exceptions.
  • Special-casing this incident. No rule keyed on tests/test_mcp_restart_governance.py, on issue #666, on PR #910, or on the tests/ prefix.
  • Deleting or silently relocating unknown work, including git stash, git clean, git reset, git checkout --, or moving files to a temp path without a durable audit record and verified hashes.
  • Weakening the clean-control-checkout invariant or the branches-only rule, including .gitignore / local-exclude entries that hide artifacts from the guard, or a bypass flag that makes contamination non-blocking.
  • Treating operator cleanup as the durable solution. "The operator removes the file" is not an acceptance criterion.
  • Allowing one session to claim or destroy another session's work, whether by ownership assumption, TTL expiry alone, or a dead-PID inference that is not corroborated by authoritative control-plane evidence.
  • Reporting restart or reconnect as necessary unless authoritative runtime state requires it.

Duplicate search

Searched open (96 issues, limit 400, complete) and closed (407 issues, limit 500, complete) issues, and open PRs (10, is_final_page: true, inventory_complete: true, total_count: 10). Terms: the proposed title; control checkout, main checkout, untracked, dirty, contamination, orphan, provenance, ownership, worktree, branches-only, recovery, preserve, artifact, intake, issue-first, task selection, allocation; plus tests/test_mcp_restart_governance.py, #666, #274.

Issue State Verified root cause / scope Why not a duplicate
#274 closed Branches-only worktrees for all LLM task mutations; ACs demand mutation outside branches/ "fails before the command runs" This incident proves the regression / incomplete implementation: the enforced guard runs only in the MCP mutation preflight and ignores untracked paths entirely, so the file was created and then read as clean. #274 has no attribution, no preservation, no recovery, and no intake-boundary criteria, and its scope is global policy rather than this defect. This issue claims only the uncovered remainder and cites #274 as the invariant to restore.
#666 open Deliver tests/test_mcp_restart_governance.py (PR #910) The source of the leaked artifact, not the defect. Its ACs are about test coverage of restart governance. Read-only evidence here.
#681 closed Instance cleanup of three specific tracked WIP files left in the control checkout by PR #680's reviewer session Same class, prior occurrence — evidence that the class was never systemically closed. Its ACs are instance-scoped ("#604 author path never touches these three files"). It fixed one occurrence, added no prevention, attribution, or recovery machinery, and its files were tracked, so the guard could at least see them.
#697 open _parse_porcelain_entries ignores ??, so gitea_get_runtime_context preflight misses untracked files Closest partial overlap — it owns one sub-part of AC1/AC2 and remains unfixed on master (gitea_mcp_server.py:583 still excludes ??). It has no acceptance criteria, does not cover root_checkout_guard/parse_dirty_tracked_files or observe_dirty_files, and covers none of prevention, attribution, preservation, recovery, or intake. Tightening detection alone would not have prevented this incident — detection is the part that (via prose) already stopped the run. This issue must consume #697's fix rather than restate it.
#716 open MCP session-state residue (.mcp_session_*) written into the control checkout; inventory, migration, quarantine of that state class Different artifact class with known provenance recorded inside the state itself. Its AC19 covers session artifacts, not task implementation content, and its discovery/quarantine ops are keyed to session-state directory structure, not arbitrary untracked repository paths. It also presumes the clean-checkout preflight already fails on untracked content — the assumption this incident disproves.
#812 closed Sanctioned preserve/prepare/restore/publish for a registered branches/ author worktree with a known issue and known claimant (entry points A and B) Nearest prior art for the preserve/restore primitive, and this issue must reuse it. It never covers the control checkout, and every operation takes a known issue=N and derives ownership from a recorded claimant. Unknown-owner artifacts in the control checkout are outside its entire evidence model.
#867 open Detect and audit out-of-band shell mutations (direct commits, branch resets, wildcard rm -f) Trigger class is unsanctioned shell tooling. This incident involved a supported session's ordinary file write and no shell git mutation. Its AC3 provenance is about state-modifying Git operations carrying MCP provenance, not about attributing arbitrary repository paths to a session.
#893 open Transient dirty observation latching a run into a permanent block; staged-dirty reading clean Opposite direction (over-detection latching / staged blind spot), and its own body records a NOT a duplicate verdict against #697 for the under-detection direction. Its ACs explicitly preserve protection for genuinely dirty control checkouts rather than defining it.
#890 open Unify seven competing author ownership stores; fenced recover_author_ownership Ownership of issues, locks, and leases — not of filesystem artifacts. No path-level provenance and no control-checkout scope.
#860 / #864 / #868 closed Dirty-preserving recovery and rebind for a registered dirty worktree under a same-claimant durable lock Require a registered branches/ worktree plus a durable lock naming the claimant. Neither exists for the control checkout, and the owner here is unknown by construction.
#261 closed Document cleanup for agent temp artifacts (_encode_*.py, _emit_*.py, _inline_*.py) Repo-root basename globs only, path separators explicitly skipped, and it attributes nothing. tests/test_mcp_restart_governance.py is out of scope twice over.

Verdict: no open or closed issue covers the verified root cause and full acceptance boundary. Coverage is fragmented across prevention (#274, regressed), detection (#697, partial and unfixed), a different residue class (#716), a known-owner recovery primitive (#812/#860), shell-mutation auditing (#867), and a one-off instance cleanup (#681). No new PR addresses it.

Related

  • Restores the invariant of #274 (closed) — regression proven by this incident.
  • Consumes #697 (detection), #812 / #860 / #864 (preserve/restore primitives), #713 (registered-worktree proof), #618 (author worktree resolution).
  • Adjacent, not merged into this scope: #716, #867, #893, #890.
  • Evidence only, must not be modified: #666, PR #910, branches/feat-issue-666-concurrent-mcp-restart-tests.
  • Prior occurrence of the same class: #681 (closed).

Canonical issue state

STATE: ready-for-author
WHO_IS_NEXT: author
NEXT_ACTION: Implement AC1-AC11 with the ten regression requirements, against synthetic fixtures only
NEXT_PROMPT: Author the control-checkout artifact prevention, provenance, and sanctioned recovery capability per AC1-AC11; reuse #697, #812, #860, #713 rather than restating them; never read or modify branches/feat-issue-666-concurrent-mcp-restart-tests, issue #666, or PR #910; PR; stop
## Problem statement A conforming client session running the canonical `work-issue` workflow stopped before task selection because the stable control checkout held an untracked task file it did not create and could not attribute. Stopping was correct. What is defective is that the system (a) allowed a supported session to put that file there, (b) reports the control checkout as **clean** in its own authoritative runtime state while the file is present, (c) has no way to say which session, issue, branch, or worktree owns it, and (d) offers no sanctioned operation that preserves it and restores a clean checkout. The only exit is operator guesswork, and operator cleanup destroyed the evidence before it could be claimed. ## Supported workflow that was attempted * Canonical workflow: `skills/llm-project-workflow/workflows/work-issue.md` * Workflow hash at incident time: `14e515cdaa6a7f0ff9f02951c9c9cb1f0f6fcaddf7732bbc263c4df96d16eec9` * Verified unchanged: the same file at master `76f293eb` hashes to the identical value, so this is not a stale-workflow artifact. * Requested task: *continue working on permissible tasks for this project* — i.e. normal allocator-driven task selection. ## Chronological reproduction using authoritative state 1. **2026-07-25 ~17:13:44 −0400** — an author session working issue #666 wrote `tests/test_mcp_restart_governance.py` into the **control checkout** at `/Users/jasonwalker/Development/Gitea-Tools/tests/`, size 17,770 bytes, 488 lines. The file was never tracked, never staged, never committed there. 2. **~17:14** — the same work landed correctly in the registered worktree `branches/feat-issue-666-concurrent-mcp-restart-tests` as a **different** revision: 17,252 bytes, 478 lines, committed as `59aab06fe17f80b5d0b87a31c76f761b195d8425` and published as PR #910. The control-checkout copy is therefore an **earlier, divergent draft**, not a duplicate of the committed file — it is unique content with no other copy. 3. **Later** — a fresh session loaded `work-issue` at hash `14e515cd…`, observed the control checkout on `master` @ `76f293eb288fa6cbb3134e093fc960ac01517e75` with the untracked file present, applied `work-issue.md` §3 (`dirty control checkout` → stop immediately) and §4 (*"If the main checkout is dirty before selection, stop and produce a recovery handoff"*), and stopped **before task selection**. It preserved the file and performed no Git, repository, issue, branch, commit, push, or PR mutation. This behaviour was correct. 4. **Verified in the current session (read-only)** — the control checkout is on `master` @ `76f293eb288fa6cbb3134e093fc960ac01517e75`, `git status --porcelain --untracked-files=all` is empty, and `tests/test_mcp_restart_governance.py` no longer exists at the control-checkout path. The only surviving copy is the committed one in the #666 worktree, which is a different revision. The 488-line draft was removed with **no audit record, no attribution, and no preservation** — the recovery failure mode this issue exists to close. ## First proven divergence from canonical behaviour The divergence is **the write itself**, upstream of every gate that later observed it. Issue #274 (closed) defines the control checkout as read-only for task work, lists *"creating files"* as a mutation, and states the acceptance criterion: *"Any attempted mutation outside `branches/` fails before the command runs."* In the implementation, that guarantee exists only inside the MCP **mutation preflight** chain — `gitea_mcp_server.py:1537` and `:1577` call `_enforce_root_checkout_guard` (`gitea_mcp_server.py:1872-1889`) on the way to a Gitea/Git mutation. A client-side file write into the control checkout never enters that chain, so nothing intercepts it. The first divergence is that a supported session could create the file at all. The second, compounding divergence is that once created, the file is **invisible to the enforced guard**: * `root_checkout_guard.assess_root_checkout_guard` (`root_checkout_guard.py:52-111`) derives dirtiness at line 82 from `reviewer_worktree.parse_dirty_tracked_files`. * `parse_dirty_tracked_files` (`reviewer_worktree.py:44-62`) discards every `??` line by design, documented as *"Untracked entries (`??`) are ignored."* * `gitea_mcp_server._parse_porcelain_entries` (`gitea_mcp_server.py:579-590`) applies the same `line.startswith("??")` exclusion, and it is the source of `dirty_files` in `gitea_get_runtime_context` (`gitea_mcp_server.py:688-701`) and of `_new_tracked_changes_since` (`:593-601`). Consequence: with an untracked task file sitting in the control checkout, `gitea_get_runtime_context` reports `dirty_files: []` with `dirty_scope: "control checkout"`, and `assess_root_checkout_guard` returns `proven: true`. **Authoritative runtime state cannot distinguish a genuinely clean control checkout from one holding another session's uncommitted work.** This session confirmed the shape: the post-cleanup output is byte-for-byte the same output the tooling would have produced while the file was present. A third inconsistency sits alongside it: `stable_control_runtime.observe_dirty_files` (`stable_control_runtime.py:600-611`) does **not** filter `??`, so two dirty definitions coexist in one codebase and can disagree about the same checkout. ## Correct fail-closed stop vs. the condition that made the stop necessary * **Correct, keep it:** refusing to select a task, refusing to touch the unknown file, and refusing to mutate anything while the control checkout was contaminated. `work-issue.md` §3/§4 is right and must not be relaxed. * **Defective, fix it:** that the contaminated state was reachable by a supported session; that the enforced guard reported it clean; that no record existed naming its owner; that no sanctioned operation could preserve it and restore a clean checkout; and that the stop therefore terminated the whole queue rather than routing to a recovery. Additionally, the stop was applied by the model reading the workflow prose against its own `git status` — not by a code gate. A safety invariant that #274 required to *"fail before the command runs"* is currently enforced only by prompt text. ## No authoritative owner attribution exists Control-plane ownership is keyed on issues, branches, worktrees, and leases — never on filesystem paths inside the control checkout: * `worktree_cleanup_audit.audit_branches_directory` classifies only entries under `branches/` (`worktree_cleanup_audit.py:621-640`); the control checkout is explicitly excluded as *"protected"* (`:317`, `:332`). * `agent_temp_artifacts.find_agent_temp_artifacts_from_porcelain` (#261) matches untracked **repo-root** files against three fixed basename globs (`_encode_*.py`, `_emit_*.py`, `_inline_*.py`) and skips anything containing a path separator — so `tests/test_mcp_restart_governance.py` is out of scope twice over, and it attributes nothing. * `dirty_orphan_worktree_recovery` (#860) requires a **registered `branches/` worktree** plus a **durable issue lock** naming the claimant; neither exists for the control checkout. The only attribution available in this incident was forensic inference from file mtime and content diff against PR #910 — exactly the operator guesswork this issue must eliminate. ## No sanctioned recovery path exists `gitea_recover_dirty_orphaned_issue_worktree`, `gitea_rebind_dirty_same_claimant_author_session`, and the #812 preserve/prepare/restore model all require a **known issue and a known claimant** and operate on `branches/` worktrees only. For an unattributable artifact in the control checkout there is no preserve step, no quarantine step, and no clean-checkout verification. Deletion is forbidden by `work-issue.md` §4 and by #274; retention blocks every workflow. That is an unrecoverable state, and it silently resolved into data loss. ## Gate boundary is wrong for issue intake `create-issue.md` §3 and §4 make a dirty control checkout blocking for issue creation too, and §18a requires `gitea_create_issue` to run *from that clean control checkout*. So a contaminated control checkout blocks not only author implementation but also the **issue-first intake** that would file the incident. The intake path is a pure remote mutation with no local tree write; a control checkout holding foreign untracked content is not a safety reason to refuse it, provided intake cannot slide into author work. ## Model-agnostic impact Nothing in the failing path is client-specific. The contract is the shared canonical workflow plus the MCP gate layer: the same `work-issue.md` hash, the same `_parse_porcelain_entries` filter, the same `root_checkout_guard`, the same absent attribution and absent recovery. Codex, Claude, Gemini, Grok, and any other conforming client reach the identical stop with the identical lack of a next action. A fix that keys on a client name, a model name, or a User-Agent does not fix this. ## Relevant source, workflow, and test locations **Source** * `root_checkout_guard.py:52-111` — `assess_root_checkout_guard`, dirtiness derived at `:82` * `reviewer_worktree.py:44-62` — `parse_dirty_tracked_files`, `??` exclusion * `gitea_mcp_server.py:555-573` — `_get_workspace_porcelain` (`git status --porcelain`, no `-uall`) * `gitea_mcp_server.py:579-590` — `_parse_porcelain_entries`, `??` exclusion * `gitea_mcp_server.py:593-601` — `_new_tracked_changes_since` * `gitea_mcp_server.py:688-701` — `gitea_get_runtime_context` `dirty_files` * `gitea_mcp_server.py:1537`, `:1577`, `:1872-1889` — guard enforcement sites * `stable_control_runtime.py:600-611` — `observe_dirty_files` (does not filter `??`) * `worktree_cleanup_audit.py:317`, `:332`, `:621-640` — control checkout excluded from classification * `agent_temp_artifacts.py` — repo-root basename-glob detection only * `dirty_orphan_worktree_recovery.py`, `dirty_same_claimant_session_rebind.py` — `branches/`-only recovery * `anti_stomp_preflight.py:547` — second guard call site **Workflow** * `skills/llm-project-workflow/workflows/work-issue.md` §3, §4 * `skills/llm-project-workflow/workflows/create-issue.md` §3, §4, §18a **Tests** * `tests/test_root_checkout_guard.py` * `tests/test_workspace_guard_alignment.py` * `tests/test_stable_control_runtime.py` * `tests/test_create_issue_workspace_guard.py` * `tests/test_issue_618_author_worktree_resolution.py` * `tests/test_anti_stomp_preflight.py` * `tests/test_namespace_workspace_binding.py` ## Verified architectural boundary responsible The **control checkout / `branches/` worktree isolation boundary** (#274, #475, #618, #713). It is responsible for prevention (nothing task-related may be created in the control checkout), attribution (every artifact under repository control must trace to an owning session, issue, branch, or worktree), and recovery (unknown work must be preservable without destroying it and without an operator deciding by hand). Today it enforces only a subset of prevention, and only for tracked paths reached through the MCP mutation preflight. ## Scope * Detect any unexpected artifact in the control checkout, **including untracked paths**, and make one dirty definition authoritative across `root_checkout_guard`, `_parse_porcelain_entries`, and `observe_dirty_files`. * Prevent or immediately reject task-related writes to the control checkout. * Record provenance for artifacts created under repository control so ownership is queryable, not inferred. * Add a sanctioned, auditable recovery that preserves unknown work byte-for-byte and returns the control checkout to verified clean. * Keep issue-first intake reachable while the control checkout is contaminated, without permitting author implementation. * Make every blocked result carry an actionable, satisfiable next action. ## Non-goals * Weakening the clean-control-checkout invariant or the branches-only rule. * Re-owning `branches/` worktree recovery (#812, #860, #864) — consume those primitives, do not restate them. * Re-owning MCP session-state residue relocation (#716). * Re-owning out-of-band shell mutation auditing (#867). * Re-owning transient/staged dirty-observation stability (#893). * Changing issue #666, its branch, its worktree, or PR #910 in any way. * Adding `.gitignore` or local-exclude entries to hide artifacts from the guard. ## Acceptance criteria **AC1 — One authoritative dirty definition.** A single classifier decides control-checkout cleanliness, covers modified, staged, deleted, renamed, **and untracked** paths, and is used by `assess_root_checkout_guard`, `gitea_get_runtime_context`, and `stable_control_runtime`. Any two of these reporting different cleanliness for the same checkout is itself a test failure. **AC2 — Untracked contamination is visible.** With an untracked non-ignored file present in the control checkout, `gitea_get_runtime_context` reports it in `dirty_files` with `dirty_scope: "control checkout"`, and the root-checkout guard reports `proven: false` with that path named. Ignored files are excluded and the exclusion is reported, not silent. **AC3 — Prevention or immediate rejection.** A task-related write to the control checkout is prevented, or is detected and rejected at the next gate boundary with the exact path named — before any task selection, claim, lease, branch, or commit occurs. The rejection is produced by a code gate, not by workflow prose alone. **AC4 — Provenance is recorded, not inferred.** Artifacts created under repository control carry a durable provenance record naming the session identity, profile, role kind, issue, branch, and bound worktree. A read-only query maps an unexpected control-checkout path to its owner, or returns an explicit `owner_unknown` verdict with the evidence it consulted. Inference from mtime or content similarity is never presented as attribution. **AC5 — Preservation without data loss.** A sanctioned MCP operation preserves unknown control-checkout content — tracked modifications and untracked files — byte-for-byte into a durable addressable checkpoint outside the working tree, with per-file content hashes, before anything is moved or removed. The operation is non-destructive and idempotent on unchanged content. It reuses the #812 preserve/restore primitives where they exist rather than duplicating them. **AC6 — Deterministic sanctioned recovery.** A single sanctioned operation carries the control checkout from contaminated to verified-clean: classify → attribute (or record `owner_unknown`) → preserve → restore the checkout → verify. It has a read-only assessor whose verdict and evidence match the mutating path, and a dry-run that mutates nothing. It never deletes, stashes, resets, cleans, or silently relocates unknown work, and it fails closed on any content-loss risk, ambiguous ownership, or a live competing owner. **AC7 — Clean-checkout verification after recovery.** After recovery the control checkout passes the canonical clean-checkout preflight under the AC1 definition, no tracked file and no Git ref changed, no unrelated content was removed, and a durable audit record names the checkpoint id, per-file hashes, acting identity and profile, and the disposition of every path. **AC8 — Issue intake stays reachable.** With the control checkout contaminated, `gitea_create_issue` remains available (it performs no local tree write), while `work_issue`, `lock_issue`, `commit_files`, `create_pr`, and every other author implementation mutation stay fail-closed. Intake cannot silently become author work: no assignment, no issue lock, no lease, no branch, and no worktree is created by the intake path. **AC9 — Actionable blocked results.** Any blocked result from this class names: the exact failed gate; the exact conflicting artifact path(s); the known owner and owning task, or an explicit statement that the owner is unknown; whether recovery is automatic or requires an operator; and the exact sanctioned next action, satisfiable at the phase it is emitted in. **AC10 — Restart honesty.** No message in this path reports an MCP restart or reconnect as necessary unless authoritative runtime state (master parity / namespace health) actually requires it. **AC11 — No regression in guard strictness.** Dirty, drifted, detached, and non-canonical control checkouts still fail closed for every caller that has not gone through the sanctioned recovery operation. Recovery is an explicit operation, never a general exemption or a bypass flag. ## Regression requirements 1. **Prevention / immediate rejection** — a task write into the control checkout is prevented or rejected before task selection, with the exact path named (AC3). 2. **Concurrent sessions and issue-specific worktrees** — two concurrent author sessions on different issues, each with its own registered `branches/` worktree, both complete normally; neither can claim, quarantine, or destroy the other's work, and neither is blocked by the other's worktree state. 3. **Ownership / provenance of unexpected artifacts** — an unexpected untracked path resolves to its owning session/issue/branch/worktree when a provenance record exists, and to an explicit `owner_unknown` verdict with consulted evidence when it does not. 4. **Preservation of unknown work** — preserve captures tracked-modified, untracked, staged, and mixed content; hashes verify equal before and after; the source is byte-identical after preserve; a hash mismatch, a missing file, and a restore collision each fail closed with the specific paths named. 5. **Deterministic sanctioned recovery** — the full classify→attribute→preserve→restore→verify path runs end to end from a synthetic contaminated checkout; assessor and mutator agree; dry-run mutates nothing. 6. **Clean-checkout verification after recovery** — post-recovery the canonical preflight passes under the AC1 definition, and no tracked file or Git ref changed. 7. **Issue intake without entering author implementation** — `gitea_create_issue` succeeds against a contaminated control checkout while `work_issue` / `lock_issue` / `commit_files` / `create_pr` fail closed, and the intake path creates no assignment, lock, lease, branch, or worktree. 8. **Accurate actionable diagnostics** — the blocked payload asserts every AC9 field, and asserts no restart/reconnect claim is emitted when parity is green (AC10). 9. **Ordinary clean-checkout workflows** — a clean control checkout on `master` at live master proceeds through allocation, claim, worktree creation, implementation, and PR creation with no new gate, no new prompt, and no measurable added latency. 10. **Existing unaffected behaviour** — author, reviewer, merger, reconciler, and controller flows keep their current semantics. Named coverage must include: the #475 root-checkout guard cases; the #540 reconciler exemption via `actual_role`; the #618 author worktree resolution; the #713 registered-worktree proof; the #749 / §18a create-issue bootstrap exemption and its non-generalization; and the #860 / #864 dirty-worktree recovery and rebind semantics. ## Prohibited * **Prompt-only fixes.** Adding or rewording workflow text without a code gate does not satisfy AC3. * **Client-specific checks.** No Codex-specific, Claude-specific, Gemini-specific, or Grok-specific branches; no LLM-name, model-name, or User-Agent exceptions. * **Special-casing this incident.** No rule keyed on `tests/test_mcp_restart_governance.py`, on issue #666, on PR #910, or on the `tests/` prefix. * **Deleting or silently relocating unknown work**, including `git stash`, `git clean`, `git reset`, `git checkout --`, or moving files to a temp path without a durable audit record and verified hashes. * **Weakening the clean-control-checkout invariant** or the branches-only rule, including `.gitignore` / local-exclude entries that hide artifacts from the guard, or a bypass flag that makes contamination non-blocking. * **Treating operator cleanup as the durable solution.** "The operator removes the file" is not an acceptance criterion. * **Allowing one session to claim or destroy another session's work**, whether by ownership assumption, TTL expiry alone, or a dead-PID inference that is not corroborated by authoritative control-plane evidence. * **Reporting restart or reconnect as necessary** unless authoritative runtime state requires it. ## Duplicate search Searched open (96 issues, limit 400, complete) and closed (407 issues, limit 500, complete) issues, and open PRs (10, `is_final_page: true`, `inventory_complete: true`, `total_count: 10`). Terms: the proposed title; *control checkout*, *main checkout*, *untracked*, *dirty*, *contamination*, *orphan*, *provenance*, *ownership*, *worktree*, *branches-only*, *recovery*, *preserve*, *artifact*, *intake*, *issue-first*, *task selection*, *allocation*; plus `tests/test_mcp_restart_governance.py`, `#666`, `#274`. | Issue | State | Verified root cause / scope | Why not a duplicate | |---|---|---|---| | **#274** | closed | Branches-only worktrees for all LLM task mutations; ACs demand mutation outside `branches/` *"fails before the command runs"* | This incident **proves the regression / incomplete implementation**: the enforced guard runs only in the MCP mutation preflight and ignores untracked paths entirely, so the file was created and then read as clean. #274 has no attribution, no preservation, no recovery, and no intake-boundary criteria, and its scope is global policy rather than this defect. This issue claims only the uncovered remainder and cites #274 as the invariant to restore. | | **#666** | open | Deliver `tests/test_mcp_restart_governance.py` (PR #910) | The *source* of the leaked artifact, not the defect. Its ACs are about test coverage of restart governance. Read-only evidence here. | | **#681** | closed | Instance cleanup of three specific **tracked** WIP files left in the control checkout by PR #680's reviewer session | Same class, prior occurrence — evidence that the class was never systemically closed. Its ACs are instance-scoped (*"#604 author path never touches these three files"*). It fixed one occurrence, added no prevention, attribution, or recovery machinery, and its files were tracked, so the guard could at least see them. | | **#697** | open | `_parse_porcelain_entries` ignores `??`, so `gitea_get_runtime_context` preflight misses untracked files | **Closest partial overlap** — it owns one sub-part of AC1/AC2 and remains unfixed on master (`gitea_mcp_server.py:583` still excludes `??`). It has no acceptance criteria, does not cover `root_checkout_guard`/`parse_dirty_tracked_files` or `observe_dirty_files`, and covers none of prevention, attribution, preservation, recovery, or intake. Tightening detection alone would not have prevented this incident — detection is the part that (via prose) already stopped the run. This issue must consume #697's fix rather than restate it. | | **#716** | open | MCP **session-state** residue (`.mcp_session_*`) written into the control checkout; inventory, migration, quarantine of that state class | Different artifact class with *known* provenance recorded inside the state itself. Its AC19 covers *session artifacts*, not task implementation content, and its discovery/quarantine ops are keyed to session-state directory structure, not arbitrary untracked repository paths. It also presumes the clean-checkout preflight already fails on untracked content — the assumption this incident disproves. | | **#812** | closed | Sanctioned preserve/prepare/restore/publish for a **registered `branches/` author worktree** with a known issue and known claimant (entry points A and B) | Nearest prior art for the preserve/restore primitive, and this issue must reuse it. It never covers the control checkout, and every operation takes a known `issue=N` and derives ownership from a recorded claimant. Unknown-owner artifacts in the control checkout are outside its entire evidence model. | | **#867** | open | Detect and audit **out-of-band shell** mutations (direct commits, branch resets, wildcard `rm -f`) | Trigger class is unsanctioned shell tooling. This incident involved a *supported* session's ordinary file write and no shell git mutation. Its AC3 provenance is about state-modifying Git operations carrying MCP provenance, not about attributing arbitrary repository paths to a session. | | **#893** | open | Transient dirty observation latching a run into a permanent block; staged-dirty reading clean | Opposite direction (over-detection latching / staged blind spot), and its own body records a `NOT a duplicate` verdict against #697 for the under-detection direction. Its ACs explicitly preserve protection for genuinely dirty control checkouts rather than defining it. | | **#890** | open | Unify seven competing author **ownership** stores; fenced `recover_author_ownership` | Ownership of issues, locks, and leases — not of filesystem artifacts. No path-level provenance and no control-checkout scope. | | **#860 / #864 / #868** | closed | Dirty-preserving recovery and rebind for a **registered** dirty worktree under a same-claimant durable lock | Require a registered `branches/` worktree plus a durable lock naming the claimant. Neither exists for the control checkout, and the owner here is unknown by construction. | | **#261** | closed | Document cleanup for agent temp artifacts (`_encode_*.py`, `_emit_*.py`, `_inline_*.py`) | Repo-root basename globs only, path separators explicitly skipped, and it attributes nothing. `tests/test_mcp_restart_governance.py` is out of scope twice over. | **Verdict:** no open or closed issue covers the verified root cause and full acceptance boundary. Coverage is fragmented across prevention (#274, regressed), detection (#697, partial and unfixed), a different residue class (#716), a known-owner recovery primitive (#812/#860), shell-mutation auditing (#867), and a one-off instance cleanup (#681). No new PR addresses it. ## Related * Restores the invariant of **#274** (closed) — regression proven by this incident. * Consumes **#697** (detection), **#812** / **#860** / **#864** (preserve/restore primitives), **#713** (registered-worktree proof), **#618** (author worktree resolution). * Adjacent, not merged into this scope: **#716**, **#867**, **#893**, **#890**. * Evidence only, must not be modified: **#666**, PR **#910**, `branches/feat-issue-666-concurrent-mcp-restart-tests`. * Prior occurrence of the same class: **#681** (closed). ## Canonical issue state ```text STATE: ready-for-author WHO_IS_NEXT: author NEXT_ACTION: Implement AC1-AC11 with the ten regression requirements, against synthetic fixtures only NEXT_PROMPT: Author the control-checkout artifact prevention, provenance, and sanctioned recovery capability per AC1-AC11; reuse #697, #812, #860, #713 rather than restating them; never read or modify branches/feat-issue-666-concurrent-mcp-restart-tests, issue #666, or PR #910; PR; stop ```
Owner

Current reproduction: ignored control-checkout artifact is silently reported clean

A second concrete reproduction now exercises AC1/AC2 with a different artifact class:

  • /Users/jasonwalker/Development/Gitea-Tools/AGENTS.md still exists (177 bytes).
  • git check-ignore -v AGENTS.md reports .git/info/exclude:29:AGENTS.md.
  • Normal git status --untracked-files=all reports a clean branch, while git status --ignored --short --untracked-files=all AGENTS.md reports !! AGENTS.md.
  • gitea_get_runtime_context(remote="prgs") simultaneously reports dirty_files: [], workspace_healthy: true, preflight_ready: true, and master parity at 26f54851d1d20eff92c339e778125f31c09fa95f.

This session did not add the exclude entry and cannot attribute who did. The state changed externally during read-only investigation: earlier Git status exposed AGENTS.md as untracked; later it became hidden by .git/info/exclude while remaining on disk.

This directly strengthens AC2: ignored-file exclusion is currently silent in authoritative runtime output. It also supplies a current AC4 attribution case: owner is explicitly unknown, and neither runtime output nor Git metadata records the responsible session/task.

The comment is the only durable mutation from this investigation.

Canonical Issue State

STATE: ready-for-author
WHO_IS_NEXT: author
NEXT_ACTION: Implement #913 AC1-AC11 and regression requirements from a verified clean registered issue worktree, including explicit reporting of ignored exclusions.
NEXT_PROMPT:

In Scaled-Tech-Consulting/Gitea-Tools, claim issue #913 from a verified clean control checkout, bootstrap a registered branches/ worktree, implement AC1-AC11 including the ignored-file reproduction in this comment, validate, open a PR closing #913, and stop.

WHAT_HAPPENED: Reproduced silent ignored-artifact invisibility using AGENTS.md and recorded exact Git/runtime evidence.
WHY: The current runtime reports a checkout containing an ignored artifact as clean and provides no provenance for the exclusion or file.
RELATED_PRS: none
BLOCKERS: none for an independent author session using a verified clean registered issue worktree.
VALIDATION: git check-ignore identified .git/info/exclude:29; git status --ignored reported !! AGENTS.md; gitea_get_runtime_context reported dirty_files [], workspace_healthy true, preflight_ready true, and master parity true.
LAST_UPDATED_BY: sysadmin (prgs-controller)

Canonical Handoff

REPOSITORY: Scaled-Tech-Consulting/Gitea-Tools
ISSUE: 913
PR: none
WORKFLOW_STATE: needs-author
HEAD_SHA: none
BASE_BRANCH: master
BASE_OR_MERGE_SHA: 26f54851d1d20eff92c339e778125f31c09fa95f
ACTING_ROLE: controller
ACTING_IDENTITY: sysadmin (prgs-controller)
COMPLETED_ACTIONS: Reproduced and documented silent ignored-artifact invisibility against AC1, AC2, and AC4.
VALIDATION_EVIDENCE: git check-ignore -v AGENTS.md => .git/info/exclude:29; git status --ignored => !! AGENTS.md; gitea_get_runtime_context => dirty_files [], workspace_healthy true, preflight_ready true, master parity true.
MUTATION_LEDGER: Posted this evidence and canonical handoff as one issue comment on #913.
BLOCKERS: none for an independent author session using a verified clean registered issue worktree.
NEXT_ACTOR: author
NEXT_ACTION: Implement #913 AC1-AC11 and regression requirements from a verified clean registered issue worktree, including explicit reporting of ignored exclusions.
PROHIBITED_ACTIONS: Do not delete, silently relocate, or hide AGENTS.md; do not weaken clean-checkout or branches-only guards; do not special-case a client or filename.
NEXT_PROMPT: In Scaled-Tech-Consulting/Gitea-Tools, claim issue #913 from a verified clean control checkout, bootstrap a registered branches/ worktree, implement AC1-AC11 including the ignored-file reproduction in this comment, validate, open a PR closing #913, and stop.
WORKFLOW_FAILURE_ISSUES: #913
LAST_UPDATED: 2026-07-25T22:25:46Z
## Current reproduction: ignored control-checkout artifact is silently reported clean A second concrete reproduction now exercises AC1/AC2 with a different artifact class: - `/Users/jasonwalker/Development/Gitea-Tools/AGENTS.md` still exists (177 bytes). - `git check-ignore -v AGENTS.md` reports `.git/info/exclude:29:AGENTS.md`. - Normal `git status --untracked-files=all` reports a clean branch, while `git status --ignored --short --untracked-files=all AGENTS.md` reports `!! AGENTS.md`. - `gitea_get_runtime_context(remote="prgs")` simultaneously reports `dirty_files: []`, `workspace_healthy: true`, `preflight_ready: true`, and master parity at `26f54851d1d20eff92c339e778125f31c09fa95f`. This session did not add the exclude entry and cannot attribute who did. The state changed externally during read-only investigation: earlier Git status exposed `AGENTS.md` as untracked; later it became hidden by `.git/info/exclude` while remaining on disk. This directly strengthens AC2: ignored-file exclusion is currently silent in authoritative runtime output. It also supplies a current AC4 attribution case: owner is explicitly unknown, and neither runtime output nor Git metadata records the responsible session/task. The comment is the only durable mutation from this investigation. ## Canonical Issue State STATE: ready-for-author WHO_IS_NEXT: author NEXT_ACTION: Implement #913 AC1-AC11 and regression requirements from a verified clean registered issue worktree, including explicit reporting of ignored exclusions. NEXT_PROMPT: ```text In Scaled-Tech-Consulting/Gitea-Tools, claim issue #913 from a verified clean control checkout, bootstrap a registered branches/ worktree, implement AC1-AC11 including the ignored-file reproduction in this comment, validate, open a PR closing #913, and stop. ``` WHAT_HAPPENED: Reproduced silent ignored-artifact invisibility using AGENTS.md and recorded exact Git/runtime evidence. WHY: The current runtime reports a checkout containing an ignored artifact as clean and provides no provenance for the exclusion or file. RELATED_PRS: none BLOCKERS: none for an independent author session using a verified clean registered issue worktree. VALIDATION: git check-ignore identified .git/info/exclude:29; git status --ignored reported !! AGENTS.md; gitea_get_runtime_context reported dirty_files [], workspace_healthy true, preflight_ready true, and master parity true. LAST_UPDATED_BY: sysadmin (prgs-controller) <!-- sph:v1 --> ## Canonical Handoff ```text REPOSITORY: Scaled-Tech-Consulting/Gitea-Tools ISSUE: 913 PR: none WORKFLOW_STATE: needs-author HEAD_SHA: none BASE_BRANCH: master BASE_OR_MERGE_SHA: 26f54851d1d20eff92c339e778125f31c09fa95f ACTING_ROLE: controller ACTING_IDENTITY: sysadmin (prgs-controller) COMPLETED_ACTIONS: Reproduced and documented silent ignored-artifact invisibility against AC1, AC2, and AC4. VALIDATION_EVIDENCE: git check-ignore -v AGENTS.md => .git/info/exclude:29; git status --ignored => !! AGENTS.md; gitea_get_runtime_context => dirty_files [], workspace_healthy true, preflight_ready true, master parity true. MUTATION_LEDGER: Posted this evidence and canonical handoff as one issue comment on #913. BLOCKERS: none for an independent author session using a verified clean registered issue worktree. NEXT_ACTOR: author NEXT_ACTION: Implement #913 AC1-AC11 and regression requirements from a verified clean registered issue worktree, including explicit reporting of ignored exclusions. PROHIBITED_ACTIONS: Do not delete, silently relocate, or hide AGENTS.md; do not weaken clean-checkout or branches-only guards; do not special-case a client or filename. NEXT_PROMPT: In Scaled-Tech-Consulting/Gitea-Tools, claim issue #913 from a verified clean control checkout, bootstrap a registered branches/ worktree, implement AC1-AC11 including the ignored-file reproduction in this comment, validate, open a PR closing #913, and stop. WORKFLOW_FAILURE_ISSUES: #913 LAST_UPDATED: 2026-07-25T22:25:46Z ```
Sign in to join this conversation.
2 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: Scaled-Tech-Consulting/Gitea-Tools#913