Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 21 additions & 7 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,12 @@ branches.
- Start new work with `pnpm fork:stack start <branch>` and open the PR against `fork/changes`.
Ordinary feature/import PRs are not added to `.github/pr-stack.json`; they enter the runnable fork
only after being reviewed and merged into `fork/changes`.
- **Never open implementation PRs against `main`.** `main` is the upstream mirror; GitHub will
report conflicts and a huge unrelated diff. Always base and retarget feature PRs on `fork/changes`.
- Before handoff (and whenever a PR is CONFLICTING / behind), run
`pnpm fork:stack update --push` (or `pnpm fork:stack update --push <pr-number>`). That rebases or
replays the feature commits onto latest `origin/fork/changes`, retargets a wrong PR base, and
force-with-lease pushes so the PR stays mergeable.
- Independent features use parallel PRs based on `fork/changes`. Chain PRs only when one change
genuinely depends on another, and merge that chain bottom-up.
- Treat external forks and open upstream PRs as selective import sources. Tim Smart imports land as
Expand Down Expand Up @@ -53,13 +59,21 @@ branches.

When implementation work for a user request is done (code, docs, config — not pure Q&A):

1. **Commit** the changes on a feature branch.
2. **Open or update a PR** against the parent required by the private fork stack before handing off.
Use `main` only before cutover or when the work intentionally changes the upstream mirror.
3. **Before pushing follow-ups or saying “updated the PR”**, verify PR state with `gh pr view` (or equivalent):
- If the PR is **open** → push to that branch and update the PR.
- If the PR is **merged** or **closed** → do **not** keep committing on that branch. `git fetch origin main`, create a **new branch from `origin/main`**, re-apply unmerged work, and open a **new PR**.
4. Never assume an earlier PR in the session is still open.
1. **Commit** the changes on a feature branch created with `pnpm fork:stack start <branch>` (from
`fork/changes`).
2. **Open or update a PR against `fork/changes`** before handing off. Do not target `main` unless
the change is intentionally an upstream-mirror / promote projection.
3. **Keep the PR mergeable** before saying “updated the PR” or finishing:
- `pnpm fork:stack update --push` (current branch) or `pnpm fork:stack update --push <pr>`
- Confirm with `gh pr view <n> --json baseRefName,mergeable,mergeStateStatus,url`
- `baseRefName` must be `fork/changes` and `mergeable` should be `MERGEABLE` (CI may still be
`UNSTABLE` while checks run).
4. **Before pushing follow-ups**, verify PR state with `gh pr view` (or equivalent):
- If the PR is **open** → update that branch (prefer `fork:stack update --push`) and push.
- If the PR is **merged** or **closed** → do **not** keep committing on that branch.
`pnpm fork:stack start <new-branch>`, re-apply unmerged work, and open a **new PR** against
`fork/changes`.
5. Never assume an earlier PR in the session is still open.

## Discord-originated pull requests

Expand Down
103 changes: 103 additions & 0 deletions apps/discord-bot/src/features/ResponseBridge.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,8 @@ import {
resolveTemporaryDiscordThreadTitleBadge,
resolveThreadChangeRequestLookupCwds,
mergeStickyTitlePr,
nextMirroredThreadTitleAfterApply,
planDiscordThreadTitleApply,
shouldApplyDiscordThreadPrBadge,
shouldApplyDiscordThreadTitleBadge,
shouldConvertWorkingTipsToWakeUp,
Expand Down Expand Up @@ -2035,6 +2037,107 @@ describe("resolveSettledDiscordThreadTitleUpgrade", () => {
});
});

describe("planDiscordThreadTitleApply", () => {
it("applies a freshly computed title that Discord does not have yet", () => {
expect(
planDiscordThreadTitleApply({
mirroredThreadTitle: "🔀 Empasa pickup carrier rollout",
pendingDesiredThreadTitle: null,
computedDesiredTitle: "🔀 ⏳ Empasa pickup carrier rollout",
}),
).toEqual({
pendingDesiredThreadTitle: "🔀 ⏳ Empasa pickup carrier rollout",
applyTitle: "🔀 ⏳ Empasa pickup carrier rollout",
});
});

it("clears pending when compute says Discord already matches", () => {
expect(
planDiscordThreadTitleApply({
mirroredThreadTitle: "🔀 Empasa pickup carrier rollout",
pendingDesiredThreadTitle: "🔀 ⏳ Empasa pickup carrier rollout",
computedDesiredTitle: "🔀 Empasa pickup carrier rollout",
}),
).toEqual({
pendingDesiredThreadTitle: null,
applyTitle: null,
});
});

it("retries a prior failed rename when compute has nothing new", () => {
// Turn settled, secondary timed out mid-rename — heartbeat must re-apply settle.
expect(
planDiscordThreadTitleApply({
mirroredThreadTitle: "🔀 ⏳ Empasa pickup carrier rollout",
pendingDesiredThreadTitle: "🔀 Empasa pickup carrier rollout",
computedDesiredTitle: null,
}),
).toEqual({
pendingDesiredThreadTitle: "🔀 Empasa pickup carrier rollout",
applyTitle: "🔀 Empasa pickup carrier rollout",
});
});

it("does not re-apply when mirrored already matches pending", () => {
expect(
planDiscordThreadTitleApply({
mirroredThreadTitle: "🔀 Empasa pickup carrier rollout",
pendingDesiredThreadTitle: "🔀 Empasa pickup carrier rollout",
computedDesiredTitle: null,
}),
).toEqual({
pendingDesiredThreadTitle: null,
applyTitle: null,
});
});

it("prefers a newer computed settle over a stale pending busy title", () => {
// VCS raced with settle: pending still wants ⏳, compute now wants settled.
expect(
planDiscordThreadTitleApply({
mirroredThreadTitle: "🔀 ⏳ Empasa pickup carrier rollout",
pendingDesiredThreadTitle: "🔀 ⏳ Empasa pickup carrier rollout",
computedDesiredTitle: "🔀 Empasa pickup carrier rollout",
}),
).toEqual({
pendingDesiredThreadTitle: "🔀 Empasa pickup carrier rollout",
applyTitle: "🔀 Empasa pickup carrier rollout",
});
});
});

describe("nextMirroredThreadTitleAfterApply", () => {
it("keeps pending and leaves mirrored unchanged on REST failure", () => {
expect(
nextMirroredThreadTitleAfterApply({
mirroredThreadTitle: "🔀 Empasa pickup carrier rollout",
pendingDesiredThreadTitle: "🔀 ⏳ Empasa pickup carrier rollout",
appliedTitle: "🔀 ⏳ Empasa pickup carrier rollout",
success: false,
}),
).toEqual({
mirroredThreadTitle: "🔀 Empasa pickup carrier rollout",
pendingDesiredThreadTitle: "🔀 ⏳ Empasa pickup carrier rollout",
attemptedThreadTitle: null,
});
});

it("updates mirrored and clears matching pending on success", () => {
expect(
nextMirroredThreadTitleAfterApply({
mirroredThreadTitle: "🔀 ⏳ Empasa pickup carrier rollout",
pendingDesiredThreadTitle: "🔀 Empasa pickup carrier rollout",
appliedTitle: "🔀 Empasa pickup carrier rollout",
success: true,
}),
).toEqual({
mirroredThreadTitle: "🔀 Empasa pickup carrier rollout",
pendingDesiredThreadTitle: null,
attemptedThreadTitle: "🔀 Empasa pickup carrier rollout",
});
});
});

describe("resolveTemporaryDiscordThreadTitleBadge", () => {
it("returns busy while a turn is Working", () => {
expect(
Expand Down
Loading
Loading