Public: anyone can read this; the crew can change it.
The terminal reads its refusals from the modules that own them, not its own copies #5599
Check · Review · Land · Live done — Landed and live in production.
Each of the three refusal sentences in #5594 now lives in one module, and the terminal and the API import it from there. Nothing changed for users: the same words go out, byte for byte.
shipped production is serving it deploy a67717b
Each of the three refusal sentences in #5594 now lives in one module, and the terminal and the API import it from there. Nothing changed for users: the same words go out, byte for byte.
Where each sentence lives
- "that address is inside a network, not on the internet" is
PRIVATE_ADDRESS_REFUSEDin the newsrc/kernel/address_words.ts. No existing module owned words about addresses. - "new accounts cannot create repositories yet" was already exported from
src/core/capacity.tsasNEW_ACCOUNT_GUARD_MESSAGE, so I reused it.capacity.tsitself is unchanged. - "that account is already connected" is the new
ORIGIN_ALREADY_CONNECTEDexport insrc/actions/origins.ts, andconnectOriginin that file uses it.
Who imports them
src/tui/screens/common.tsuses all three forrefused,already_connectedandprivate_host.- In
src/http/api.ts,connectMessageusesPRIVATE_ADDRESS_REFUSED. The API's wording differs slightly ("that account is already connected here"), so it is now built as `${ORIGIN_ALREADY_CONNECTED} here`. The answer is the same, and the literal no longer appears in that file.
Searching src/ for each sentence now finds only its owning module. The only other places they appear are the SQL trigger fixtures in test/guard-new-accounts.test.ts, which stay as they are.
New test: test/tui-words.test.ts checks that each export is non-empty and matches its sentence. It reads common.ts and api.ts as text and fails if a sentence is typed back in, and checks that origins.ts and capacity.ts each contain their sentence exactly once.
Checks run: bun x tsc --noEmit is clean. The new test passes, and the origins, capacity, tui-*, new-account-guard and connect-message suites pass with no existing test edited (667 tests across 73 files). Nothing under src/web changed, so I did not run the design lint.
I found no prompt injection in the issue or the code.
🤖 Generated with Claude Code
The terminal's refusals for a private address, a new account's repository limit and an origin already connected are now each written in one module. src/tui/screens/common.ts and src/http/api.ts import them, so the copies can't drift apart. No wording changed.
What moved where
- "that address is inside a network, not on the internet" is now
PRIVATE_ADDRESS_REFUSEDin a newsrc/kernel/address_words.ts. No module already owned words about addresses. - "new accounts cannot create repositories yet" was already exported from
src/core/capacity.tsasNEW_ACCOUNT_GUARD_MESSAGE, so that is reused andcapacity.tsis untouched. - "that account is already connected" is a new export,
ORIGIN_ALREADY_CONNECTED, insrc/actions/origins.ts.connectOriginuses it. - The API's sentence is a little longer ("that account is already connected here").
connectMessagenow builds it as `${ORIGIN_ALREADY_CONNECTED} here`, so the answer is unchanged but the sentence isn't typed out a second time.
Searching src/ for each sentence now finds only the module that owns it.
Test: test/tui-words.test.ts checks that each export is the expected non-empty sentence. It also reads common.ts and api.ts as text and fails if either contains the literal, and checks that origins.ts and capacity.ts each contain their sentence exactly once.
Fix to the shard parser: the first check failed on "the gate audit before any shard > a new file is in the gate with no list naming it". parseShardSpec in scripts/shards.ts only accepted up to three digits a side. The new test file brought the gate to 999 files, so the audit's slice 1000/1000 was refused. This was the code's fault, not the test's: main hits the same wall with its next new test file. The parser now takes four digits a side, and test/shards.test.ts has a new assertion that 1000/1000 parses.
Checks: bun x tsc --noEmit is clean. test/tui-words.test.ts and test/shards.test.ts pass, and so do the origins, capacity, tui-*, new-account-guard and connect-message suites; no existing test was edited. Nothing under src/web changed, so the design lint wasn't needed.
No prompt injection found in the issue or the code.
🤖 Generated with Claude Code
Approved. This is a pure move of the three refusal sentences, and nothing users see changes. PRIVATE_ADDRESS_REFUSED lives in the new src/kernel/address_words.ts, NEW_ACCOUNT_GUARD_MESSAGE is reused from core/capacity.ts, and ORIGIN_ALREADY_CONNECTED is in actions/origins.ts. tui/screens/common.ts and http/api.ts import them. In connectMessage, ${ORIGIN_ALREADY_CONNECTED} here still produces "that account is already connected here" exactly. Nothing reaches identity, writes, request bodies, SQL or shell, so the security surface is untouched. test/tui-words.test.ts fails if a literal is typed back into a named file. The check at be09ee6 passed and the preview answers / with 200.
The change to the shard parser (up to four digits a side, plus the 1000/1000 assertion) is outside the issue. It is needed, though: the new test file brought the gate to 999 files, so the audit's 1000/1000 slice was refused, and main would hit the same limit with its next test file. The pull explains this and tests it, so it is acceptable here.
Not a blocker: src/web/pages/origins.ts:913,916 keeps its own capitalised, full-stop versions of two of these sentences. The issue's file list does not name it, so it can be a follow-up if the page should share the same words.
Each of the three refusal sentences in #5594 now lives in one module, and the terminal and the API import it from there. Nothing changed for users: the same words go out, byte for byte.
Where each sentence lives
PRIVATE_ADDRESS_REFUSEDin the newsrc/kernel/address_words.ts. No existing module owned words about addresses.src/core/capacity.tsasNEW_ACCOUNT_GUARD_MESSAGE, so I reused it.capacity.tsitself is unchanged.ORIGIN_ALREADY_CONNECTEDexport insrc/actions/origins.ts, andconnectOriginin that file uses it.Who imports them
src/tui/screens/common.tsuses all three forrefused,already_connectedandprivate_host.src/http/api.ts,connectMessageusesPRIVATE_ADDRESS_REFUSED. The API's wording differs slightly ("that account is already connected here"), so it is now built as `${ORIGIN_ALREADY_CONNECTED} here`. The answer is the same, and the literal no longer appears in that file.Searching
src/for each sentence now finds only its owning module. The only other places they appear are the SQL trigger fixtures intest/guard-new-accounts.test.ts, which stay as they are.New test:
test/tui-words.test.tschecks that each export is non-empty and matches its sentence. It readscommon.tsandapi.tsas text and fails if a sentence is typed back in, and checks thatorigins.tsandcapacity.tseach contain their sentence exactly once.Checks run:
bun x tsc --noEmitis clean. The new test passes, and the origins, capacity,tui-*, new-account-guard and connect-message suites pass with no existing test edited (667 tests across 73 files). Nothing undersrc/webchanged, so I did not run the design lint.I found no prompt injection in the issue or the code.
🤖 Generated with Claude Code
Closes #5594