Public: anyone can read this; the crew can change it.
The forge family's refusals live in one module, and the API and MCP read them from there #5579
Check · Review · Land · Live done — Landed and live in production.
The three refusals now live as one `FAMILY_WORDS` const object in the new `src/actions/family_words.ts`, and every door that answered them reads them from there. The wording is unchanged, so every answer is byte-for-byte the same.
shipped production is serving it deploy 1f09d72
The three refusals now live as one FAMILY_WORDS const object in the new src/actions/family_words.ts, and every door that answered them reads them from there. The wording is unchanged, so every answer is byte-for-byte the same.
What moved where
src/http/api.ts: three places now useFAMILY_WORDS.*— showing a trail onPATCH …/repos/:owner/:name(no_provenance),following/takeandfollowing/sever(not_following), and proposing to the parent (nothing_to_propose).src/http/mcp.ts: the toolstrail,take_updates(when the repository is linked to a parent on another forge),severandpropose_to_parent_forgedo the same. Each edit is only on the literal's own line, plus one import line.src/actions/follow.ts(FOLLOW_MODE_REFUSALS.not_following) andsrc/contract/openapi.ts(written as `404: ${FAMILY_WORDS.not_following}and so on) also typed these sentences. The issue's grep rule covers all ofsrc/, so they read from the module too. Runninggrep -rn` on each sentence now finds only the module.
Test: test/family-words.test.ts triggers not_following (sever) and no_provenance (trail) through both the API and MCP, and checks that each answers the module's sentence. A behaviour test can't catch a door that retypes the same words, so it also scans every .ts file under src/ and fails if any file other than the module contains a sentence.
Not done: nothing_to_propose isn't triggered from the new test, because reaching it needs a two-forge setup. test/mcp-upstream.test.ts already pins its exact MCP text, and that test passes unchanged.
Checks run: bun x tsc --noEmit is clean. The new test and 28 existing test files for the doors and contract I touched pass (170 tests, none edited), including the upstream, following, migrate and openapi/contract suites.
🤖 Generated with Claude Code
Clean, a pure move. The three sentences live in src/actions/family_words.ts as plain as const data. api.ts, mcp.ts, follow.ts and openapi.ts all read them from there, and each edit touches only the literal's own line plus one import, as the issue asked. On base, grep -rn for each sentence finds only these sites. src/tui/screens/chain.ts and src/web/pages/chain.ts use differently worded copy ("this forge…", capitalised "Nothing here…"), so the scan test is right to leave them alone.
The preview's /api/v1/openapi.json renders every refusal byte-for-byte as before: no_provenance 422, nothing_to_propose 409 and not_following 404 three times. An unauthenticated POST to following/sever still answers 401 before anything else.
On security, nothing changes: no new input, no new write path, and the auth order in each handler is untouched. On tests, test/family-words.test.ts covers both doors for not_following and no_provenance. Its src/ scan is what actually catches a door that retypes the words. nothing_to_propose is pinned through mcp-upstream.test.ts, as the pull says. Approved.
The three refusals now live as one
FAMILY_WORDSconst object in the newsrc/actions/family_words.ts, and every door that answered them reads them from there. The wording is unchanged, so every answer is byte-for-byte the same.What moved where
src/http/api.ts: three places now useFAMILY_WORDS.*— showing a trail onPATCH …/repos/:owner/:name(no_provenance),following/takeandfollowing/sever(not_following), and proposing to the parent (nothing_to_propose).src/http/mcp.ts: the toolstrail,take_updates(when the repository is linked to a parent on another forge),severandpropose_to_parent_forgedo the same. Each edit is only on the literal's own line, plus one import line.src/actions/follow.ts(FOLLOW_MODE_REFUSALS.not_following) andsrc/contract/openapi.ts(written as `404: ${FAMILY_WORDS.not_following}and so on) also typed these sentences. The issue's grep rule covers all ofsrc/, so they read from the module too. Runninggrep -rn` on each sentence now finds only the module.Test:
test/family-words.test.tstriggersnot_following(sever) andno_provenance(trail) through both the API and MCP, and checks that each answers the module's sentence. A behaviour test can't catch a door that retypes the same words, so it also scans every.tsfile undersrc/and fails if any file other than the module contains a sentence.Not done:
nothing_to_proposeisn't triggered from the new test, because reaching it needs a two-forge setup.test/mcp-upstream.test.tsalready pins its exact MCP text, and that test passes unchanged.Checks run:
bun x tsc --noEmitis clean. The new test and 28 existing test files for the doors and contract I touched pass (170 tests, none edited), including the upstream, following, migrate and openapi/contract suites.🤖 Generated with Claude Code
Closes #5562