fix(missions): repo-less capture was publishing the agent's own identity files

First live run of `capture_repo_less_phases`: 9 artifacts, of which 2 were the
user's research. The other 7 were AGENTS.md, HEARTBEAT.md, IDENTITY.md,
MEMORY.md, SOUL.md, TOOLS.md and USER.md — the agent runtime's identity
scaffolding, seeded into the workspace root because that root is pinned to the
repository root.

The codebase already knew about these files and already had the list. What it
did not have is a defence that works without a repo: `ignore_agent_scaffolding`
writes them to `.git/info/exclude`, and a mission with no repository has no
`.git`. So the exact files that once got committed into a user's repo and
pushed (the reason that list exists) came back through a new channel.

`AGENT_SCAFFOLDING` is now `pub(crate)` and `mission_outputs` filters on it
directly — one list, two consumers, so the next file the runtime starts seeding
is excluded from both at once rather than from whichever was remembered.

Negative control: replace the filter with `&& true` and
`research_documents_are_kept_and_scaffolding_is_not` fails.

Found by running it against a live mission, not by reading it. The unit tests
passed the whole time — they seeded a tree that did not contain the scaffolding,
because I did not know it would be there.
This commit is contained in:
Omar Sobh
2026-08-07 11:35:00 -07:00
parent ceab28b902
commit 89bc53b53d
2 changed files with 21 additions and 2 deletions
+14 -1
View File
@@ -198,7 +198,16 @@ fn keep_files(root: &Path) -> Vec<PathBuf> {
if !SKIP_DIRS.contains(&name.as_str()) {
stack.push(path);
}
} else if path.is_file() && !name.starts_with('.') {
} else if path.is_file()
&& !name.starts_with('.')
// The agent runtime seeds its own identity files into the
// workspace root, which is pinned to the repo root. In a
// repo-backed mission `.git/info/exclude` hides them; a
// repo-less mission has no `.git`, so without this the user's
// artifact list is 7 files of agent scaffolding and 2 of their
// research. Measured exactly that way on the first live run.
&& !crate::mission_workspace::AGENT_SCAFFOLDING.contains(&name.as_str())
{
out.push(path);
}
}
@@ -272,6 +281,10 @@ mod tests {
touch(&repo.join("research/01_repo_archaeology.md"));
touch(&repo.join("research/02_ecosystem.md"));
touch(&repo.join("notes.txt"));
// The seven the agent runtime seeds into the workspace root.
for f in crate::mission_workspace::AGENT_SCAFFOLDING {
touch(&repo.join(f));
}
touch(&repo.join(".git/HEAD"));
touch(&repo.join("node_modules/left-pad/index.js"));
touch(&repo.join("target/debug/thing"));