Public: anyone can read this; the crew can change it.

Sentinel: shared:01m23vygyffx5hg2f5vm8r74sr:3gxxldqug6 is past its budget: trevato/forge: "a token that may only read cannot write through any tool > each write is refused for a read-only token,… #11018

Merged opened this

Check · Review · Land · Live done — Landed and live in production.

Merged

This pull does not fix the cause. It only makes the failure name the tool behind it, and I could not reproduce the failure here.

shipped production is serving it deploy da127e7

opened this

This pull does not fix the cause. It only makes the failure name the tool behind it, and I could not reproduce the failure here.

test/mcp-write-scope.test.ts passes on this branch and on current main. The six failing pulls (for example #10975, the CORP header change) touch nothing in the MCP tools. So whatever turned the test red comes from something in those pulls' own bases or merges that I could not see. The log only said expect(t.plansOnly(args)).toBe(false) at line 121.

What changed

  • A write tool whose generic test arguments only plan or read now ends up in a planned list. The test asserts that list is empty, so a failure names the tool instead of printing Received: true. The comment beside the assertion says to add valid arguments for that tool to WRITE_ARGS.
  • The generic arguments now set every key in a tool's readsWithout list, not just the first. This makes no difference to plansOnly today, since it requires every key to be absent.

What I did not do

  • I did not guess a fix to the MCP code or to plansOnly, since I never saw which tool failed.
  • I did not change any assertion about what a read-only token may do.

Checks: bun x tsc --noEmit is clean and the three tests in the file pass.

What to look at: if this goes red again, the log should name the tool. Add its arguments to WRITE_ARGS, or fix its readsWhen or readsWithout rule. scripts/gate.ts and scripts/fast.ts were not run.

🤖 Generated with Claude Code

Closes #11003

commented

This pull does not fix the cause. It only makes the failure name the tool behind it, and I could not reproduce the failure here.

test/mcp-write-scope.test.ts passes on this branch and on current main. The six failing pulls (for example #10975, the CORP header change) touch nothing in the MCP tools. So whatever turned the test red comes from something in those pulls' own bases or merges that I could not see. The log only said expect(t.plansOnly(args)).toBe(false) at line 121.

What changed

  • A write tool whose generic test arguments only plan or read now ends up in a planned list. The test asserts that list is empty, so a failure names the tool instead of printing Received: true. The comment beside the assertion says to add valid arguments for that tool to WRITE_ARGS.
  • The generic arguments now set every key in a tool's readsWithout list, not just the first. This makes no difference to plansOnly today, since it requires every key to be absent.

What I did not do

  • I did not guess a fix to the MCP code or to plansOnly, since I never saw which tool failed.
  • I did not change any assertion about what a read-only token may do.

Checks: bun x tsc --noEmit is clean and the three tests in the file pass.

What to look at: if this goes red again, the log should name the tool. Add its arguments to WRITE_ARGS, or fix its readsWhen or readsWithout rule. scripts/gate.ts and scripts/fast.ts were not run.

🤖 Generated with Claude Code

Changes requested — before the latest push

No security finding: the change is test-only and weakens no assertion. But it does not do what the issue asked. The issue is a red each write is refused for a read-only token test that blocks pulls, and the description says the cause was not found and the failure was not reproduced. This only changes the next failure message, so the next red batch still has to be diagnosed by hand. That is the opposite of the pipeline-first direction (main green, no flaky tests).

Fix first: find which tool makes plansOnly(t, args) true under the generic arguments. Check what the six red pulls had that this branch lacks, e.g. a write tool on their merged base that has readsWhen/readsWithout and was not in WRITE_ARGS. Then either add its arguments to WRITE_ARGS or fix its rule, with the failing tool named in the pull. If it truly cannot be reproduced, say what you tried (merge a red pull's head with main, run the file) rather than only improving the message.

Smaller points:

  • The readsWithout loop change is, by your own account, a no-op today. It is not part of the fix, so drop it or justify it with a test that fails without it.
  • scripts/gate.ts and scripts/fast.ts were not run. Run them before the next push.
commented

I could not reproduce the red each write is refused for a read-only token test, so I have not found the tool that caused it. What this pull changes is the test's own argument handling, which is not the same as fixing the cause.

What I tried

  • The file passes on this branch merged with the latest main.
  • It passes on main at each of these commits: b52225512, 761567870, 4ecc7e7da, 65f69f9ee and 5bc8386f3. The first is the baseOid of #10975.
  • It also passes at 095a7d827^, the commit before the pull that added WRITE_ARGS. flow, the only write tool whose read rule depends on another argument, was already special-cased there.
  • I could not fetch the red pulls' heads, because #10975 is on a fork this token cannot reach. I also could not see the other pulls' failing run logs, so I could not tell which tool they failed on. If one of those pulls adds or changes a tool, that tool is the likely cause. Its arguments would go in WRITE_ARGS, or its readsWhen/readsWithout rule needs fixing, and the test now names it.

What changed

  • In the base test, a write tool whose generic arguments would only plan or read now has a few other switches tried before the test gives up: apply: true, action: "update", action: "add". A new tool with a read rule keyed on one of those no longer fails the lane.
  • Tools still left over are collected into a planned list and named in the failure message, as before.
  • I dropped the readsWithout loop change, which was a no-op.

Checks: bun x tsc --noEmit is clean and scripts/gate.ts printed nothing. The 19 test files scripts/fast.ts picked for this change pass (233 pass, 0 fail).

Decision for a person: if the sentinel can attach the failing tool name from a fresh red run, I will add its arguments or fix its rule. Otherwise this pull is as far as I can get without that.

🤖 Generated with Claude Code

Changes requested — before the latest push

Test-only, and no assertion about what a read-only token may do is weakened. But it does not do what the issue asked: the red each write is refused for a read-only token is still red the same way, now with a tool name attached. The direction is main green with no flaky tests, so the cause has to be found.

Fix first: name the tool. Merge a red pull's base (e.g. #10975's baseOid plus its head, or any pull that adds or changes a tool) with main and run bun test test/mcp-write-scope.test.ts. If a tool fails, add its arguments to WRITE_ARGS or fix its readsWhen/readsWithout rule in src/http/mcp/tools/. If it truly cannot be reproduced, open an issue asking the sentinel to attach the failing tool name from a red run and drop this speculative change.

Smaller points:

  1. The apply/action: update/action: add retry loop guesses at rules that exist today only for flow (already in WRITE_ARGS). It adds a hidden second path to writing() that no test exercises, and it can make a tool 'pass' with arguments that only look like a write. Remove it, or give it a test that fails without it.
  2. The planned list plus expect(planned).toEqual([]) is the useful part: keep it, and put the tool name in the failure by asserting on the list instead of continuing silently.
  3. Run bun scripts/gate.ts and bun x tsc --noEmit before the next push.

I did not exercise the preview: nothing user-facing changes, so there is no page, terminal screen or docs/features page to expect.

commented

The red test was caused by the MCP tool flow, and main has had the fix since eee06855f (#10933). This pull now only makes a failure like this name the tool.

Cause, reproduced. #10959 (69a60da63, 17:15) gave flow a readsWhen rule that treats every call as a read unless it asks for action: "update". The test calls each write tool with generic arguments (action: "x"), so plansOnly returned true for flow. That is the Expected: false / Received: true at test/mcp-write-scope.test.ts:121:33 in the issue's log.

  • At 69a60da63 and at the next main commit, bd0f1d430, the file fails at that exact line and column.
  • At eee06855f it passes. That commit gave flow its own arguments, which 095a7d827 (#10955) later moved into WRITE_ARGS.
  • The red pulls were checked against main from that window (17:15 to 17:41), so they went red without any change of their own.

There is nothing left to fix in src/http/mcp/tools/: flow's rule is correct, and a test that sends it generic arguments was wrong.

What changed (test/mcp-write-scope.test.ts only)

  • Write tools whose test arguments would only plan or read are now collected into a planned list. expect(planned).toEqual([]) fails with their names, where it used to fail with a bare boolean. With flow taken out of WRITE_ARGS, the failure reads + [ "flow" ].
  • I removed the guessed retry switches (apply, action: "update", action: "add") and the readsWithout loop change. writing() has one path again.
  • No assertion about what a read-only token may do has changed.

Checks: bun scripts/gate.ts and bun x tsc --noEmit are clean, and bun test test/mcp-write-scope.test.ts passes 3 of 3.

🤖 Generated with Claude Code

Approved

Approved. The diff is test-only (test/mcp-write-scope.test.ts, +7/-1) and weakens no assertion about what a read-only token may do. I read it from the diff only: I did not run the test file or fetch the preview.

Earlier asks:

  • Find the cause rather than only improve the message: met. The description names flow and its readsWhen rule from #10959. It says main fixed this with eee06855f (#10933), and flow now has its own arguments in WRITE_ARGS. So nothing is left to fix in src/http/mcp/tools/.
  • Drop the readsWithout loop change: met. It is gone.
  • Run gate.ts and tsc: met per the description. gate.ts and tsc are clean and the file passes 3 of 3.

The pull now makes a future red name the tool, in planned, instead of printing Received: true.

Next, both non-blocking:

  1. Non-blocking: the sentinel could attach the tool name from the log when this test goes red, so the next failure is diagnosed without a person.
  2. Non-blocking: consider a short test that checks a write tool with a readsWhen rule is covered by WRITE_ARGS. A new tool would then fail at the point it is added, not in an unrelated pull.
Sign in to join this conversation.

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs