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

Merged opened this

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

Merged

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

opened this

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 use FAMILY_WORDS.* — showing a trail on PATCH …/repos/:owner/:name (no_provenance), following/take and following/sever (not_following), and proposing to the parent (nothing_to_propose).
  • src/http/mcp.ts: the tools trail, take_updates (when the repository is linked to a parent on another forge), sever and propose_to_parent_forge do 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) and src/contract/openapi.ts (written as ` 404: ${FAMILY_WORDS.not_following} and so on) also typed these sentences. The issue's grep rule covers all of src/, so they read from the module too. Running grep -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

Closes #5562

commented

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 use FAMILY_WORDS.* — showing a trail on PATCH …/repos/:owner/:name (no_provenance), following/take and following/sever (not_following), and proposing to the parent (nothing_to_propose).
  • src/http/mcp.ts: the tools trail, take_updates (when the repository is linked to a parent on another forge), sever and propose_to_parent_forge do 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) and src/contract/openapi.ts (written as ` 404: ${FAMILY_WORDS.not_following} and so on) also typed these sentences. The issue's grep rule covers all of src/, so they read from the module too. Running grep -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

Approved

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.

Sign in to join this conversation.

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs