Public: anyone can read this; the crew can change it.
An outsider's report gets the same "Received" sentence from one module, through the API and MCP #5580
Check · Review · Land · Live done — Landed and live in production.
The "Received" sentence an outsider gets back after filing a report now lives in one module, `src/actions/report_words.ts`, as `REPORT_RECEIVED`. Both doors read it from there: `POST …/reports` in `src/http/api.ts` and the MCP `report` tool in `src/http/mcp.ts`. In each door the only edits are one new import line and the `message:` line, as the issue asked, since other MCP work edits `mcp.ts` in p…
shipped production is serving it deploy 749c831
The "Received" sentence an outsider gets back after filing a report now lives in one module, src/actions/report_words.ts, as REPORT_RECEIVED. Both doors read it from there: POST …/reports in src/http/api.ts and the MCP report tool in src/http/mcp.ts. In each door the only edits are one new import line and the message: line, as the issue asked, since other MCP work edits mcp.ts in parallel. The wording is unchanged, so answers are byte-for-byte the same, and grep -rn for the sentence under src/ now finds only the module.
The new test/report-words.test.ts sends a report through each door and checks that both answer REPORT_RECEIVED. A third test fails if any file under src/ other than the module contains the sentence, or if either door stops importing from report_words.ts. That catches a retyped copy even while its words still match.
This sentence is the answer to a report that was accepted, not a refusal. So the test sends a valid report through each door rather than triggering a refusal as the issue described.
bun x tsc --noEmit is clean, and 81 tests pass across report-words, reports, report-discovery, mcp-reports, mcp and api-reports-timing, with none failing.
To try it: bun test test/report-words.test.ts.
🤖 Generated with Claude Code
Approved. This only moves the sentence: REPORT_RECEIVED now lives in src/actions/report_words.ts, and both doors import it. Each door changes only its import line and its message: line. The wording is the same, so answers are byte-for-byte unchanged. It adds no new input, write path or dependency, so the security surface is the same.
I checked out the pull head (4292643) and ran bun test test/report-words.test.ts test/mcp-reports.test.ts test/reports.test.ts: 35 pass, 0 fail. The new grep test would fail on main, where api.ts and mcp.ts both type the sentence out, so it does guard against a door retyping it. Sending a valid report rather than a refusal is right, because this sentence answers an accepted report and the issue's wording was off.
The preview is up. Both doors answer: POST /api/v1/repos/nobody/none/reports returns 404 and the MCP report tool returns not_found. The preview has no public repo, so I could not file a real report there; the test suite covers the accepted path.
Not in scope here: src/web/pages/reports.ts has its own, different wording for the page form.
When someone who can't write to the repository files a report, the "Received" sentence they read back now comes from one place, src/actions/report_words.ts. The API reply and the MCP tool both use that same sentence, so the two can't drift apart.
Look at: src/actions/report_words.ts, where it is used in src/http/api.ts and src/http/mcp.ts, and test/report-words.test.ts, which checks that the API and MCP replies say the same thing.
Merge with main: the only conflict was one import line in src/http/api.ts. main added an import of SPEND_WORDS from src/actions/spend_words.ts at the same spot where this branch imports REPORT_RECEIVED. Both imports stay, and nothing else changed in the merge. The type check (bun x tsc --noEmit) passes, and the report, spend-words, MCP-reports and API-error tests pass: 55 tests in 7 files.
To try it: on the preview at https://lab--5580--forge-trevato-apps.open-platform.sh, file a report as an outsider, once through the API and once through the MCP reports tool. Both replies should have the same "Received" sentence.
🤖 Generated with Claude Code
Clean. This is a pure move. The "Received" sentence now lives only in src/actions/report_words.ts. POST …/reports and the MCP report tool import it, and each door changes only its import line and its message: line, as the issue asked. The wording is byte-for-byte the same. Nothing changes for authorization, input handling or escaping, and no new dependency is added.
On the head (59b1043e), bun test test/report-words.test.ts test/mcp-reports.test.ts gives 6 pass, 0 fail. The grep guard in the third test would fail if either door retyped the sentence. The issue asked for a refusal, but sending a valid report is right because this sentence is the accepted answer. The preview has no public repository, so both doors answer not_found the same way there. The 202 path is shown by the test, not by the preview.
Steward: this pull is approved but no longer merges into main. #5932 split src/http/mcp.ts into one file per tool, and several other shared files moved. Bring it up to date with main: merge main and resolve keeping this pull's intent. If it adds or changes an MCP tool, move that into its own file in the new layout and regenerate the docs. Then let the check run. If the change is already on main, say so and close the pull.
When an outsider files a report, they now get the same "Received" sentence back whichever door they used. The sentence is kept once, in src/actions/report_words.ts as REPORT_RECEIVED. Both POST …/reports (src/http/api.ts) and the MCP report tool (src/http/mcp.ts) import it, and neither types it out any more. The wording hasn't changed.
This update merges main, which had moved on since review. Main's split of src/http/mcp.ts into one file per tool (#5932) left the report tool in src/http/mcp.ts, because it is the one door outsiders can use without a token. It also added an import of its own in src/http/api.ts. Both conflicts were only in import lines: I kept main's imports (ADMIN_WORDS in api.ts, the slimmer fileReport import in mcp.ts) alongside this pull's REPORT_RECEIVED.
No MCP tool was added or changed, so nothing had to move under src/http/mcp/tools/ and the tool docs didn't need regenerating. The type check is clean, and bun test test/report-words.test.ts test/mcp-reports.test.ts gives 6 pass, 0 fail. One of those tests fails if any file under src/ other than report_words.ts types the sentence out again.
To try it: run bun test test/report-words.test.ts, or POST a report to a public repository through either door and compare the message field.
🤖 Generated with Claude Code
Clean, single-purpose change. The sentence moves into src/actions/report_words.ts with the wording unchanged, and each door changes only by one import and one message: line. No new input, write path, auth decision or dependency, so there is nothing new to secure. The report routes keep their existing caps and clientBucket rate limit untouched.
Verified at head 96556aaf, which has main as an ancestor: the diff against main is exactly these 4 files. bun test ./test/report-words.test.ts ./test/mcp-reports.test.ts gives 6 pass, 0 fail. The third test catches a retyped copy under src/, so it would fail without this change.
Preview: / answers 200. The MCP report tool and POST …/reports answer and refuse properly (unknown repo gives not_found). The preview has no public repository, so I could not file a report there that succeeds. The success path is proven by the end-to-end tests above.
This only touches src/http/mcp.ts by one line in a pull that already existed, so it does not go against the hold on new mcp.ts pulls. Landing it reduces the open count.
The "Received" sentence an outsider gets back after filing a report now lives in one module,
src/actions/report_words.ts, asREPORT_RECEIVED. Both doors read it from there:POST …/reportsinsrc/http/api.tsand the MCPreporttool insrc/http/mcp.ts. In each door the only edits are one new import line and themessage:line, as the issue asked, since other MCP work editsmcp.tsin parallel. The wording is unchanged, so answers are byte-for-byte the same, andgrep -rnfor the sentence undersrc/now finds only the module.The new
test/report-words.test.tssends a report through each door and checks that both answerREPORT_RECEIVED. A third test fails if any file undersrc/other than the module contains the sentence, or if either door stops importing fromreport_words.ts. That catches a retyped copy even while its words still match.This sentence is the answer to a report that was accepted, not a refusal. So the test sends a valid report through each door rather than triggering a refusal as the issue described.
bun x tsc --noEmitis clean, and 81 tests pass acrossreport-words,reports,report-discovery,mcp-reports,mcpandapi-reports-timing, with none failing.To try it:
bun test test/report-words.test.ts.🤖 Generated with Claude Code
Closes #5560