memory: check open PRs before picking up a Linear ticket#17
Merged
WillTaylor22 merged 1 commit intoMay 26, 2026
Conversation
PR #15 and PR #16 were opened in parallel for ENG-26 today by two different sessions (sesn_01GwXk... and sesn_01UTKG...). #15 merged first; #16 had to be closed as redundant. Mitigation: list open PRs and grep for the ticket ID before branching. One extra MCP call, prevents the race. Standalone memory PR — no Linear ticket (this isn't bug work, it's a convention surfaced during the operational loop).
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Owner
Author
|
AGENT_REVIEW: APPROVED — memory-only PR adds a sensible "grep open PRs before branching" convention that addresses a real ENG-26 dup race; format and caps are clean. What I checked:
Nit (not blocking, flagging for the retro agent):
|
This was referenced May 26, 2026
WillTaylor22
added a commit
that referenced
this pull request
May 26, 2026
…#20) * ENG-25: webhook accepts plain-text session-id marker (MCP-survivable) The convention previously required `<!-- session-id: ... -->` as an HTML comment in the PR body. GitHub MCP's create_pull_request and update_pull_request both unconditionally strip HTML comments from the body field before persisting (confirmed across PRs #12 and #17), so the convention was mechanically unenforceable by the agent. Fix (ENG-25 option 2): the canonical marker shape is now a plain-text line: session-id: sesn_xxxxxxxxxxxxxxxx which survives MCP. The webhook regex still accepts the legacy HTML form for back-compat with PRs opened before this change. Changes: - app/api/github-webhook/route.ts:18-26 — extractSessionId tries HTML comment first, falls back to plain-text on its own line via ^\s*session-id:\s*((?:sthr_|sesn_)[A-Za-z0-9]+)\s*$ with the /m flag. Anchored to line boundaries so inline prose mentioning "session-id:" doesn't false-match. - .claude/memory/conventions/pr-session-id-marker.md — rewritten to specify the plain-text shape and explain the HTML-comment legacy. Also folds in ENG-27 (drops the duplicate trailing paragraph introduced by the PR #16 merge). - .claude/memory/learnings/2026-05-26-github-mcp-strips-html-comments.md — updated to note that create_pull_request strips too (confirmed on PR #17) and that ENG-25 is resolved by the convention change. - .claude/memory/MEMORY.md — index entries updated. Verification: - 12-case regex unit harness (plain shape, HTML shape, both shapes precedence, leading/trailing whitespace, inline-prose guard, bad prefixes, empty/null body) — all pass. - npm run lint — clean. - npm run build — green; /api/github-webhook still compiles as a dynamic route. - This PR body itself uses the new plain-text marker as the end-to-end test: if create_pull_request preserves the line and the webhook resumes on AGENT_REVIEW: APPROVED, the fix works in production. * memory: note greedy-strip behavior surfaced during PR #20 creation The MCP doesn't just strip well-formed comments — it strips greedily from any unclosed <!-- opener to end-of-body. Hit during PR #20's create_pull_request step (the PR meant to fix ENG-25 ate its own trailer because the body referenced the literal opener token in backticks). Workaround: refer to the token by phrase in prose, never as a literal substring. * ENG-25 round 2: last-match regex + unit-test guardrails Reviewer (PR #20 round 1) caught that String.match(/.../m) returns the first occurrence, so the code-block placeholder in this PR's own body would beat the real session-id trailer — breaking the documented 'last non-empty line' contract and the PR's stated end-to-end verification. Changes: - lib/extract-session-id.ts: extracted from route.ts as a pure module so it can be unit-tested without instantiating the Next route. Plain shape now uses matchAll(...) and takes the last match. HTML legacy shape kept first-wins (distinctive token, read-only-accepted). - app/api/github-webhook/route.ts: import the helper, drop the inline copy. - tests/unit/extract-session-id.spec.ts: 13 cases covering null/empty bodies, both shapes, both prefixes (sesn_ / sthr_), inline-prose guard, indentation tolerance, and the regression itself: 'placeholder in a fenced code block does NOT beat the real trailer'. - playwright.config.ts: testDir widened to ./tests, testMatch covers both e2e/ and unit/. Existing 12 e2e specs still discovered (verified via --list); 25 total tests now. - Memory: new learning at learnings/2026-05-26-regex-last-match-semantics.md on the /m vs /g + matchAll gotcha; MEMORY.md index updated. Verified: npm run lint, npm run build, npm run e2e -- tests/unit (13/13). --------- Co-authored-by: Self-Managing Codebase Manager <7004983+WillTaylor22@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Memory entry surfaced this session while running the operational loop after PR #15 merged.
Finding
PRs #15 and #16 were both opened today for ENG-26 by two parallel sessions:
sesn_session-id prefix #15 — branchclaude/eng-26-webhook-sesn-regex-sesn_01GwXkeQp4Q6sE1yhv6MZg1m, merged at 09:53:15Z.claude/eng-26-webhook-sesn-regex-sesn_01UTKGQsLg2sQsyGcZcBb9hN, closed as redundant in this session.Identical fix (the same 1-line regex change), identical convention/MEMORY.md edits. Net cost: one wasted session's worth of build, lint, and reviewer-agent attention.
Root cause
Linear's
In Progresstransition isn't atomic across sessions that both pick up at the same wall-clock tick. Step 4 of the manager loop ("Pick up work") doesn't currently say to check for existing PRs before branching, so two sessions that read Triage at the same moment will both branch and both push.Mitigation
One extra
list_pull_requests+ grep for the ticket ID in titles and bodies, beforegit checkout -b. If a PR for this ticket already exists, defer.Change
.claude/memory/conventions/check-open-pr-before-ticket-pickup.md— new (1 paragraph)..claude/memory/MEMORY.md— one-line index entry.Caps
conventions/directory: 2 → 3 files. No cap on conventions.learnings/unchanged at 4 (cap 20).Verification
Memory-only PR, no code paths touched. Skipping build/lint/e2e per the dev-loop convention for memory edits.