You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
[bug] A local repo is marked "ready" without anyone checking it exists — an empty checkout reports success, and the agent invents the code it cannot see #405
The agent is not lying about the code. It is lying about a repo that isn't there.
Chess coder (26f71cd8) has fabricated tool results on nearly every turn for two days. #395's
guard now catches it. This is why it keeps happening.
Measured
The instance's only repo:
GET /v1/instances/26f71cd8…/coding/repos
name: apps/chess-academy
provider: local
workdir: ~/dev/pas/platform/apps/chess-academy
cloneStatus: "ready" ← the platform says this repo is usable
createdAt: 2026-08-07 08:29:04Z
On the machine:
$ ls -la ~/dev/pas/platform/apps/chess-academy
total 0 ← empty. 0 files.
drwxr-xr-x 2 … 7 Aug 18:29 . ← created 18:29 AEST = 08:29 UTC, the minute the row was created
$ git -C … remote -v
fatal: not a git repository
The directory exists, contains nothing, and is not a git repo. It has been ready since the moment
it was added.
The chain, in three steps
1. A local path is accepted without anyone looking at it.routes/coding-repos.ts:92-104 — the
add-repo handler takes body.localPath, trims it, calls createRepo(... provider:"local") and
returns 201. There is no check that the path exists, is non-empty, or is a git repository. The
runner is connected at that moment and could answer all three; it is never asked. cloneStatus
becomes ready, which is the same word a successfully cloned repo gets.
2. Every read tool then reports the absence as SUCCESS.lib/connectors/repo-local.ts:
:127return{content: lines.length ? … : "(no files found at that path)",success: true};
:217return{content: res.remote ? … : "(no git origin remote — this checkout has no configured remote)",success: true};
Both are true sentences about an empty subfolder, and both are indistinguishable from one. Nothing
in either says the configured workdir is empty, nothing names the path, nothing is success:false,
and nothing reaches the console as a repo-level problem — the repos list still shows ready.
3. The agent is cornered on every turn. Asked "can email/password sign in be used in this app",
it calls the right tools, receives two non-answers that describe no problem, and has nothing to
relay. There is no diagnosis to pass on, so it invents the repo, the issues, and the file contents —
which is exactly the transcript in #395.
Why this is the fix that matters
#395's guard is downstream and it is working — the live transcript now carries "The agent wrote tool results that no tool produced. They were removed…". But the guard removes an
invention; it does not remove the reason for one. As long as an agent is pointed at an empty
directory the platform calls ready, every question about that code has no honest answer available
to it, and a model under that pressure will keep filling the gap.
Do
Validate a local path at add time, on the runner that will use it: does it exist, does it
contain files, is it a git work tree? Reject or mark it needs_attention — do not write ready for a path nobody has looked at. ready is a claim; make it one the platform checked.
Re-check on use. A checkout can be moved or deleted after it is added, which is the same
state arriving later. The repos list should show it.
Make the tool results diagnose, not shrug. For a configured workdir that is empty or is
not a git repo, say so, name the path, and return success:false — an agent can relay "the configured checkout ~/dev/…/chess-academy is empty; the repo may have moved". It
cannot relay "(no files found at that path)", and that difference is the whole ticket.
Adding a local path that does not exist, is empty, or is not a git repo does not produce a ready repo.
repo_tree / repo_remote / repo_git against such a workdir return success:false with a
message naming the path and the condition.
The console shows the repo as unusable, with what to do.
A legitimately empty subfolder of a real checkout still reports "(no files found at that
path)" and stays a success — the two cases must not be conflated in the other direction.
Files: workers/api/src/routes/coding-repos.ts:85-104, workers/api/src/lib/connectors/repo-local.ts:127,217, packages/browser-runner/src/coding/repo.ts. Related: #395 (the guard that catches the symptom), #398 (the format that teaches the shape), #378 (the precedent for diagnosing rather than failing).
The agent is not lying about the code. It is lying about a repo that isn't there.
Chess coder (
26f71cd8) has fabricated tool results on nearly every turn for two days. #395'sguard now catches it. This is why it keeps happening.
Measured
The instance's only repo:
On the machine:
The directory exists, contains nothing, and is not a git repo. It has been
readysince the momentit was added.
The chain, in three steps
1. A local path is accepted without anyone looking at it.
routes/coding-repos.ts:92-104— theadd-repo handler takes
body.localPath, trims it, callscreateRepo(... provider:"local")andreturns 201. There is no check that the path exists, is non-empty, or is a git repository. The
runner is connected at that moment and could answer all three; it is never asked.
cloneStatusbecomes
ready, which is the same word a successfully cloned repo gets.2. Every read tool then reports the absence as SUCCESS.
lib/connectors/repo-local.ts:Both are true sentences about an empty subfolder, and both are indistinguishable from one. Nothing
in either says the configured workdir is empty, nothing names the path, nothing is
success:false,and nothing reaches the console as a repo-level problem — the repos list still shows
ready.3. The agent is cornered on every turn. Asked "can email/password sign in be used in this app",
it calls the right tools, receives two non-answers that describe no problem, and has nothing to
relay. There is no diagnosis to pass on, so it invents the repo, the issues, and the file contents —
which is exactly the transcript in #395.
Why this is the fix that matters
#395's guard is downstream and it is working — the live transcript now carries
"The agent wrote tool results that no tool produced. They were removed…". But the guard removes an
invention; it does not remove the reason for one. As long as an agent is pointed at an empty
directory the platform calls
ready, every question about that code has no honest answer availableto it, and a model under that pressure will keep filling the gap.
Do
contain files, is it a git work tree? Reject or mark it
needs_attention— do not writereadyfor a path nobody has looked at.readyis a claim; make it one the platform checked.state arriving later. The repos list should show it.
not a git repo, say so, name the path, and return
success:false— an agent can relay"the configured checkout
~/dev/…/chess-academyis empty; the repo may have moved". Itcannot relay "(no files found at that path)", and that difference is the whole ticket.
gave the Terminal tab's offline runner.
Acceptance
readyrepo.repo_tree/repo_remote/repo_gitagainst such a workdir returnsuccess:falsewith amessage naming the path and the condition.
path)" and stays a success — the two cases must not be conflated in the other direction.
Files:
workers/api/src/routes/coding-repos.ts:85-104,workers/api/src/lib/connectors/repo-local.ts:127,217,packages/browser-runner/src/coding/repo.ts. Related: #395 (the guard that catches the symptom),#398 (the format that teaches the shape), #378 (the precedent for diagnosing rather than failing).