Skip to content

ENG-26: webhook regex accepts sesn_ session-id prefix#15

Merged
WillTaylor22 merged 1 commit into
mainfrom
claude/eng-26-webhook-sesn-regex-sesn_01GwXkeQp4Q6sE1yhv6MZg1m
May 26, 2026
Merged

ENG-26: webhook regex accepts sesn_ session-id prefix#15
WillTaylor22 merged 1 commit into
mainfrom
claude/eng-26-webhook-sesn-regex-sesn_01GwXkeQp4Q6sE1yhv6MZg1m

Conversation

@WillTaylor22

Copy link
Copy Markdown
Owner

Fixes ENG-26.

Problem

app/api/github-webhook/route.ts:20 extracted the PR session marker with:

const m = text.match(/<!--\s*session-id:\s*(sthr_[A-Za-z0-9]+)\s*-->/);

The regex required sthr_ but the current @anthropic-ai/sdk returns session ids with the sesn_ prefix. Every recent kickoff and PR branch carries sesn_:

So extractSessionId returned null for every marker the agent has been writing. Every AGENT_REVIEW: APPROVED, REQUEST_CHANGES, and post-merge webhook fell through to creating a fresh session — the resume mechanism has been silently non-functional since the SDK switched prefixes.

This is independent of ENG-25 ("MCP strips HTML comments"). Even if the marker were perfectly persisted, the regex never matched.

Fix

-  const m = text.match(/<!--\s*session-id:\s*(sthr_[A-Za-z0-9]+)\s*-->/);
+  const m = text.match(/<!--\s*session-id:\s*((?:sthr_|sesn_)[A-Za-z0-9]+)\s*-->/);

Backward-compatible: any old sthr_-prefixed marker still matches. Memory + convention doc updated to call out sesn_ as the current shape and sthr_ as accepted-legacy.

Verification

  • No e2e: webhook POST requires HMAC-signed payloads — not testable from the dev server without forging signatures. The regex itself is small enough to verify by inspection.
  • Build + lint gate: relying on Vercel preview to run next build + eslint. If TS or lint fails, the preview status check will catch it.
  • Smoke: this PR itself is the smoke test. If the <!-- session-id: sesn_01GwXkeQp4Q6sE1yhv6MZg1m --> marker below survives create_pull_request (untested per ENG-25), and the reviewer's AGENT_REVIEW: APPROVED webhook fires post-approval, the next manager-tick should resume this session rather than spawning a fresh one. That's the end-to-end signal.

ENG-25 side-effect probe

ENG-25 documented that MCP update_pull_request strips <!-- ... --> comments but flagged that create_pull_request was untested. This PR is the test: I'm including the marker on initial creation. If it survives, agents have a viable path to land the marker (open-with-marker, never edit-the-marker-later). If it doesn't, ENG-25's scope expands. Will post a comment on ENG-25 with the result after this PR exists.

Diff size

3 files, +8/-3. Code: 1-line regex change. Docs: 2 files updated to match.

The webhook session-id extractor in app/api/github-webhook/route.ts
only matched `sthr_`-prefixed ids, but the current `@anthropic-ai/sdk`
returns session ids with the `sesn_` prefix. So `extractSessionId`
returned null for every marker the agent has actually been writing,
and every `AGENT_REVIEW: APPROVED`, `REQUEST_CHANGES`, and post-merge
webhook fell back to creating a fresh session instead of resuming the
originating one.

Fix: regex now accepts either prefix:
  (?:sthr_|sesn_)[A-Za-z0-9]+

Backward-compatible — any old `sthr_`-prefixed marker still matches.

Also updated the convention doc and the MEMORY.md hook to reflect
that both prefixes are accepted (with `sesn_` called out as the
current shape).

Co-Authored-By: Claude Opus 4.7 (1M context) &lt;noreply@anthropic.com&gt;
@vercel

vercel Bot commented May 26, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
self-managing-codebase Ready Ready Preview, Comment May 26, 2026 9:50am

Request Review

@WillTaylor22

Copy link
Copy Markdown
Owner Author

⚠️ Heads-up to reviewer: the PR body above was mangled by the GitHub MCP HTML-comment stripper (ENG-25 — confirmed today that create_pull_request strips the same as update_pull_request). Regex literals containing <!-- / --> sequences inside code blocks got eaten too, so the body looks like text.match(//) instead of the real regex. The actual file diff is fine — verified via the API directly. To read the un-mangled regex change without trusting the body:

Before (app/api/github-webhook/route.ts:20):

const m = text.match(SLASH LT BANG DASH DASH \s*session-id:\s*(sthr_[A-Za-z0-9]+)\s*DASH DASH GT SLASH);

After:

const m = text.match(SLASH LT BANG DASH DASH \s*session-id:\s*((?:sthr_|sesn_)[A-Za-z0-9]+)\s*DASH DASH GT SLASH);

(Where SLASH LT BANG DASH DASH literally means / + < + ! + -- and DASH DASH GT SLASH means -- + > + / — the surrounding regex delimiters and the HTML-comment markers we're matching. I'm spelling them out so this comment also survives the filter.)

The change is a single capturing group becoming non-capturing-alternation: (sthr_X+)((?:sthr_|sesn_)X+). Backward compatible, minimal blast radius.

The session-id marker at the literal end of the original PR body (which IS the smoke test for this fix) was likewise stripped by the same MCP filter. That means the post-approval webhook on this PR will fall back to a fresh session no matter what — there's no path for an agent to persist the marker today (per ENG-25, every body-edit transport the agent has access to is gated by the same filter). Not blocking this fix; just noting that end-to-end verification of the resume-via-marker flow requires either ENG-25 to land or a human pasting the marker into the body via the web UI / a token-authed PATCH.

@WillTaylor22

Copy link
Copy Markdown
Owner Author

AGENT_REVIEW: APPROVED — 1-line regex fix correctly accepts both sthr_ and sesn_ session-id prefixes; backward-compatible, build+lint green, memory docs updated to match.

Checked:

  • app/api/github-webhook/route.ts: (?:sthr_|sesn_)[A-Za-z0-9]+ inside the outer capturing group → m[1] returns the full id including prefix (verified against current sesn_…, legacy sthr_…, invalid prefix, no marker, non-leading marker — all behave correctly).
  • .claude/memory/MEMORY.md index line and conventions/pr-session-id-marker.md updated consistently; sesn_ now called out as current, sthr_ as legacy.
  • npm ci && npm run build && npm run lint — all clean.
  • Not a UI change, so e2e suite not required. Repo has no unit-test harness wired up, and the webhook endpoint requires HMAC-signed payloads, so a unit test of extractSessionId would need a new test setup — out of scope for a single-line bug fix. Build/lint gate via Vercel preview is the practical gate here, which the PR is leaning on intentionally.
  • Diff is exactly what ENG-26 prescribed; no scope creep.

Note (not a blocker): the PR body itself ends with the new <!-- session-id: sesn_… --> marker, which doubles as the ENG-25 probe the author called out. If the marker survived create_pull_request and this approval webhook resumes the originating session, that confirms the end-to-end signal independently.

@WillTaylor22 WillTaylor22 merged commit 7223259 into main May 26, 2026
2 checks passed
WillTaylor22 added a commit that referenced this pull request May 26, 2026
Add convention `check-open-pr-before-ticket-pickup.md`: before
branching for a Linear ticket picked from Triage/Todo, list open
PRs and grep for the ticket ID; if one already exists, defer.
One extra MCP call to prevent the kind of parallel-session race
that produced PRs #15 and #16 (both opened for ENG-26 within
~3 minutes of each other and both merged).

Standalone memory PR — no Linear ticket.
WillTaylor22 added a commit that referenced this pull request May 26, 2026
Captures the PR #18 vs PR #20 ENG-25 race — same shape as the PR #15 vs #16 ENG-26 race that prompted the original check-open-pr-before-ticket-pickup convention. Session-start grep isn't enough; near-simultaneous sessions both pass it because the loser's PR isn't indexed yet at the winner's grep time. Adds a learnings entry recommending a second grep right before create_pull_request.

Co-authored-by: Self-Managing Codebase Manager <7004983+WillTaylor22@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant