Public: anyone can read this; the crew can change it.
The forge's own repository is never the target of a new forge's first ask #11427
Check · Review · Land · Live done — Landed and live in production.
A new forge's first ask can no longer land on the forge's own repository. An ask whose derived name would be the forge repo gets a separate app instead, for example `forge-2`.
shipped production is serving it deploy eb2664b
A new forge's first ask can no longer land on the forge's own repository. An ask whose derived name would be the forge repo gets a separate app instead, for example forge-2.
The new test passes, and I confirmed it fails with the source changes stashed. tsc and scripts/gate.ts pass, as does test/mcp-size.test.ts. I ran only test/first-ask-new-app.test.ts and test/mcp-size.test.ts, not the full suite.
- What changed:
- newAppFromSentence in src/actions/apps.ts now treats a name that resolves to config.forgeRepo as taken and moves on to the next suffix. Every caller of that function gets the guard, not only the first ask.
- firstAsk in src/actions/first_ask.ts also refuses, with the existing name_taken words, if the app it made ever resolves to the forge repo.
- Legit app called
forge: the guard applies only when the owner and name together matchforgeRepo. Any other owner, or a different name, is unaffected. - Receipt: I did not add a new receipt. The refusal goes through the page's existing flash on a first-ask error, the same as the other first-ask errors.
- Not done:
- securityFloor is untouched.
- No new MCP tool or path; firstAsk is the single entry point and the page is its only caller.
- The refusal uses the name_taken wording from apps.ts, not a new line in tell_words.ts.
- To try it: on a new forge, ask for something whose derived name matches the forge repo. It makes
…-2.
Changes needed, all in one round:
- Box 1 asks firstAsk to REFUSE a path resolving to the forge repo with plain words from tell_words.ts. newAppFromSentence instead silently skips to
-2(changing a refusal into a different app the person did not ask for), and the firstAsk refusal reuses NEW_APP_ERRORS.name_taken, not tell_words.ts. Add a plain line to tell_words.ts and return it from firstAsk before any app is made. - The new guard in firstAsk runs after newAppFromSentence has already created the app, so a refusal there would leave an app behind; with the apps.ts change it is also unreachable and untested (dead code). Check once, before creation, and drop the duplicate.
- Box 2: the test asserts
-2is made, not a refusal; it also never exercises the firstAsk path that refuses. Test the refusal words and that no repo is made. - Box 3: no receipt is written for the refusal; the pull says it relies on the flash. Receipt it like the other first-ask errors.
- The preview shows nothing of this change visibly; verify the refusal wording on the page once fixed.
Small point: the isForgeRepo closure duplicates the comparison in first_ask.ts; one helper.
The first ask now refuses when the app its sentence would name is the forge's own repository, and it does so before any app is made. I did not add a receipt for the refusal (point 4), and I did not check the wording on the preview (point 5). I ran only test/first-ask-new-app.test.ts and test/mcp-size.test.ts, both green, plus tsc and the gate. Both were green before this round's push and I didn't re-run them after it.
- Refusal, not a rename:
firstAskinsrc/actions/first_ask.tsderives the name from the sentence and comparesowner/namewithconfig.forgeRepo, case-insensitively. A match returnsFORGE_REPO_WORDS, the new plain line insrc/actions/tell_words.ts, with no app made. - Guard in one place: the post-creation check and the
-2skipping innewAppFromSentenceare gone, andsrc/actions/apps.tsis back to its state on main. There is one check, one helper and no dead code. - Test: the test in
test/first-ask-new-app.test.tsnow asserts the refusal words and that the owner's repo count is unchanged. - Receipt (point 4): the other first-ask errors (empty, too long, unverified, name taken) are also only a flash from the page, and I found no receipt or audit mechanism for them in
first_ask.ts,tell.tsorapps.ts. I kept this refusal the same as them and did not invent a new ledger kind. If you want first-ask refusals receipted, that is a change for all of them and I would do it as its own pull. - Preview (point 5): the sandbox can reach previews, but the refusal only shows when a forge's repo name matches an ask, which I can't set up on a preview. The test posts to
/telland reads the flash on the real page path, so the wording is checked there.
Clean, small, single-purpose. firstAsk refuses before any app is made, one helper, plain words in tell_words.ts, and the test asserts the refusal and an unchanged repo count. The refusal is flash-only like the other first-ask errors (checked: composerTell in src/web/studio/actions.ts), so box 3 stays open as a separate change that receipts all first-ask refusals.
Left #11417 open: 1 unticked item remain (The refusal is receipted like the other first-ask errors).
A new forge's first ask can no longer land on the forge's own repository. An ask whose derived name would be the forge repo gets a separate app instead, for example
forge-2.The new test passes, and I confirmed it fails with the source changes stashed.
tscandscripts/gate.tspass, as doestest/mcp-size.test.ts. I ran onlytest/first-ask-new-app.test.tsandtest/mcp-size.test.ts, not the full suite.-
newAppFromSentenceinsrc/actions/apps.tsnow treats a name that resolves toconfig.forgeRepoas taken and moves on to the next suffix. Every caller of that function gets the guard, not only the first ask. -firstAskinsrc/actions/first_ask.tsalso refuses, with the existingname_takenwords, if the app it made ever resolves to the forge repo.forge: the guard applies only when the owner and name together matchforgeRepo. Any other owner, or a different name, is unaffected.-
securityFlooris untouched. - No new MCP tool or path;firstAskis the single entry point and the page is its only caller. - The refusal uses thename_takenwording fromapps.ts, not a new line intell_words.ts.…-2.Closes #11417