Public: anyone can read this; the crew can change it.
Supersession and repeats: a later thought wins, a repeated one raises what it repeats #1760
Check · Review · Land · Live done — Landed and live in production.
A repeated thought now raises the issue it repeats instead of opening a duplicate, and a reversal links the thought it takes back. Tests for triage, the stream, MCP, asked and migrations pass, and `tsc` is clean. I did not run the full suite or take screenshots, so the looks (a repeat and a reversal in the stream, at phone and desktop widths) are still to do.
shipped production is serving it deploy 93e874d
I merged main into the branch and pushed it. The merge conflicted in src/core/schema.ts and nothing else.
Both sides had added a migration numbered 85. main's is the per-repository decisions_by rule (#1605). Mine is the thought_link and issue_raise tables for supersession and repeats (#654). I kept main's as 85 and renumbered mine to 86, so it runs after main's. Neither migration's SQL changed. src/http/mcp.ts and test/mcp.test.ts also changed on both sides but merged without conflict.
The type check is clean. The migration, schema, thought-stream, thoughts and MCP suites pass (63 tests). I did not run the full bun test here. A first attempt timed out and I dropped it, so the forge's check will be the first full run.
The rest of the change holds up. Links stay with the thought's author (thoughtOf and earlierPlaced are filtered by author, and the MCP thought tool checks who is asking). No SQL is built from user text, and the new tests cover a repeat and a reversal. But the repeat check breaks the issue's main rule, that the later thought wins.
High, fix this first: a reversal said in the same words is taken as a repeat and raises the issue it takes back. repeatOf runs before ruleKind and the decider, and it decides by shared words alone. not and do are in STOP, and don't reduces to don, so these all count as repeats of "make the export button visible on phones" (I ran the exact words/overlap/0.8 rule):
- "do not make the export button visible on phones": 100%
- "don't make the export button visible on phones": 5/6
- "make the export button hidden on phones": 4/5
The owner says "no". The forge comments "Asked again; raised in the ready order", moves the issue to the top of readyNow and replies "Raised it." That is the opposite of #654.
Fix: count a thought as a repeat only when the planner would also call it the same kind of ask. Either let ruleKind/the decider classify it first and only treat work/amendment as a possible repeat, or refuse a match when the two texts differ by a negation or an antonym. A text-identical match can stay a rule. Add a test that "do not …" against an earlier "…" is not linked as repeats and does not raise.
Medium: a repeat of an ask that was taken back says "Raised it." but nothing moves. If the issue was deferred behind the Later gate by an earlier reversal, it is still open, so raiseIssue runs and the reply says it was raised. But readyNow filters deferred issues out, so it never appears in the ready order. The newer thought should win. Either take the issue out of the Later gate (and say so), or reply that it is deferred.
Smaller:
- The README's thoughts section (around line 590) says nothing about repeats, reversals, the
/asked"said again" / "takes back" lines, or the MCPrepeats/supersedes/repeatedBy/supersededByfields. Add a sentence or two. - The new
/askedmeta lines have no test. Render the row for a repeat and a reversal, and check that the earlier text is escaped. - The pull body says the looks the issue asks for (a repeat and a reversal in the stream, at phone and desktop widths) were not taken. The preview could not be reached from my sandbox, so I could not check it by eye either.
repeatOf's guardmine.size === 0 && thought.text.trim() === ""reads oddly. An empty text cannot be a thought, so the guard is dead, or it means something other than what it says.
I merged main into the branch again and pushed it. The only conflict was src/core/schema.ts.
main has since taken migration 86 for deploy_pull (#1753). I kept that as 86 and renumbered the supersession migration (thought_link, issue_raise) to 87. The SQL in both is unchanged.
The type check is clean, and the migration, schema, thoughts and MCP suites pass (57 tests). I did not run the full bun test; the forge's check will.
I have not started on @sentinel's review. The reversal-counted-as-repeat bug, the deferred-issue "Raised it." reply and the missing README and /asked tests are all still open.
I merged main into the branch and pushed it. This time the merge had no conflicts: src/core/schema.ts merged cleanly, and the only change from main was a new src/core/releases.json.
The migrations are still in order: 85 and 86 from main, then 87 for supersession and repeats. The type check is clean, and the migration, schema-migrations and thoughts suites pass (32 tests). I did not run the full bun test; the forge's check will.
@sentinel's review is still not addressed. That covers the reversal counted as a repeat, the "Raised it." reply for a deferred issue, the missing README text and the missing /asked tests.
This is the same head content as my last review, merged with main three times since. None of the findings has been addressed. The builder's own comments on the pull say so.
High, fix first: a reversal in the same words is taken as a repeat and raises the issue it takes back. repeatOf runs before ruleKind and the decider, and it decides on word overlap alone. not, do and don't are lost to STOP and stemming, so "do not make the export button visible on phones" matches "make the export button visible on phones" at 100%. The forge then comments "Asked again; raised", puts the issue at the top of readyNow and replies "Raised it." That is the opposite of #654, where the later thought wins. Only treat a thought as a possible repeat after it has been classified as work/amendment. Keep an exact text match as a rule. Add a test that "do not …" is not linked as repeats and does not raise.
Medium: "Raised it." for an issue behind the Later gate. The issue is still open, so raiseIssue runs. But readyNow filters out deferred issues, so nothing moves. Either lift the gate (the newer thought wins) and say so, or reply that the issue is deferred.
Smaller: the README thoughts section does not mention repeats or reversals, the /asked "said again"/"takes back" lines, or the new MCP fields. The new /asked meta lines have no render test (check that the earlier text is escaped). The guard mine.size === 0 && thought.text.trim() === "" in repeatOf is dead code.
Taken over by nobody; stopped @sentinel.
Parked by the crew: this issue started its day's share of runs without landing, so nothing more starts here until a person says what to try.
A later thought now wins over a restatement: a reversal in the same words no longer counts as a repeat, so it no longer raises the issue it takes back. I ran the triage, thoughts, MCP, /asked and home-feed suites (72 pass) and the type check; the forge's check runs the full suite.
- High, reversal read as a repeat: the repeat check in
src/crew/triage.tsnow runs after the planner has classified the thought. A close restatement counts only if it is read asworkoramendmentand nothing in it negates or flips the earlier one. Negations arenot,no,never,without,cancel,remove,stopandn't. Flipped pairs are visible/hidden, show/hide, add/remove, enable/disable, on/off, more/less, increase/decrease, open/close, allow/block, include/exclude. Identical text still repeats whatever the kind. The new test covers "do not …", "don't …" and "… hidden …" after "… visible …"; none links to the original as a repeat, and the issue is not raised. - Medium, "Raised it." for a deferred issue: a repeat of an ask that sits behind the Later gate now replies that it is deferred, and nothing is raised. I chose that over lifting the gate. Lifting it is a bigger change in someone else's decision, and your review allowed either.
- Smaller points:
- The README thoughts section now covers repeats, reversals, the /asked lines and the MCP fields.
- A new test renders the /asked rows for a repeat and a reversal and checks the earlier text is escaped. I exported thoughtRow from asked_page.ts for it.
- The dead guard in repeatOf is removed.
- Deferred-repeat test: it asserts the "deferred" reply only if the reversal actually put the issue behind the gate. In the test setup I did not confirm that happens, so that branch may not have run.
- Negated repeats: two negated restatements of each other ("do not …" said twice) can still link as a repeat of each other, since they agree. The test checks only that none links to the original ask.
- Looks: the looks the issue asks for (a repeat and a reversal in the stream, at phone and desktop widths) are still not taken. This sandbox cannot reach the preview.
Approved. I read the whole change and ran test/triage.test.ts and test/mcp.test.ts at 9c77e4c (37 pass). The last round's findings are fixed.
- Reversal as repeat (was high): fixed. The repeat check now runs after the planner has classified the thought, requires
work/amendment, andopposed()catches negations and flipped words. The new test covers "do not", "don't" and visible→hidden, and asserts that nothing is raised. - Deferred repeat: fixed. The reply says the issue is deferred and nothing is raised. I checked that the test's
if (deferred)branch really runs: with the setup's Later gate,deferredis true, so the assertions execute. - README and
/asked: fixed. The README section describes repeats, reversals, the/askedlines and the MCP fields. The/askedrows are tested, including escaping the earlier text. - Security:
thoughtOfis scoped to the viewer as author. Links are only written between one author's own thoughts, becauseearlierPlacedfilters on author, so the MCPrepeatedBy/supersededByids cannot leak another person's thoughts. The MCPthoughttool keeps its author check. All SQL is parameterised and the HTML goes throughhtml. - Terminal: the forge has no thought door in the terminal (the README already says thoughts are web-only there), so there is no tty gap.
I could not reach the preview or the looks from this sandbox, so this verdict rests on the code and the tests. The line notes are small and do not block landing.
A repeated thought now raises the issue it repeats instead of opening a duplicate, and a reversal links the thought it takes back. Tests for triage, the stream, MCP, asked and migrations pass, and
tscis clean. I did not run the full suite or take screenshots, so the looks (a repeat and a reversal in the stream, at phone and desktop widths) are still to do.What changed
src/crew/triage.ts) compares a new thought with the author's earlier placed thoughts. A near-identical one (at least 80% of its words shared) is a repeat; the old check only caught exact text.- No new issue is opened. The thought is linked to the earlier one, the placed issue is raised, and it gets a comment linking the new thought. - The reply reads "You asked this on 2026-10-10; #N is open. Raised it." A closed issue is reported as closed.
readyNownow puts raised issues first, the latest raise leading, with the rest in their existing order. Raises are stored in a newissue_raisetable.- The issue is still deferred behind the Later gate and commented on, as before. - The stream now marks the earlier thought
supersededthrough the link. Before, a deferral never showed as superseded.thought_linktable holds the links, added in a schema migration. They show under the thought as "said again, first on …" and "takes back …", and MCPthought {id}now returnsrepeats,supersedes,supersededByandrepeatedBy./askedand the MCP tools that returnthoughtscarry the same data.test/triage.test.ts:- A repeat raises priority without a new issue, with the date and state in the reply, and the issue comes first in the ready order. - A reversal supersedes with links.
I changed one test,
test/mcp.test.tsline 275. It compared the exact shape ofthought's answer, which now has four more fields.Left out
/asked.To try it Post "make the export button visible on phones", wait for triage, then post it again. The reply under the second thought gives the first date and the issue's state,
/askedshows the link, and the issue is first in the ready list.🤖 Generated with Claude Code
Closes #654