From dc453faa0935a9856ed3cab688dd31f8ab45f9e9 Mon Sep 17 00:00:00 2001 From: "mateolafalce3@gmail.com" Date: Fri, 14 Aug 2026 09:49:49 -0300 Subject: [PATCH 1/2] fix(sep-automation): preserve stale action summaries Reuse the original staleness analysis when recording successful actions and wait for summary updates before returning. Co-authored-by: Michael <265398295+lafalce-assistant@users.noreply.github.com> --- tools/sep-automation/src/processor.ts | 27 +++-- .../test/unit/processor.test.ts | 112 ++++++++++++++++++ 2 files changed, 131 insertions(+), 8 deletions(-) create mode 100644 tools/sep-automation/test/unit/processor.test.ts diff --git a/tools/sep-automation/src/processor.ts b/tools/sep-automation/src/processor.ts index 900496744..0657200ea 100644 --- a/tools/sep-automation/src/processor.ts +++ b/tools/sep-automation/src/processor.ts @@ -13,6 +13,7 @@ import { type SEPItem, type ActionResult, type SEPState, + type StaleAnalysis, } from "./types.js"; /** Summary data collected during processing */ @@ -95,10 +96,14 @@ export class SEPProcessor { } // Check staleness - const stalenessResult = await this.checkStaleness(sep); - if (stalenessResult) { - results.push(stalenessResult); - this.updateSummaryFromStaleness(stalenessResult, sep, summaryData); + const stalenessAction = await this.checkStaleness(sep); + if (stalenessAction) { + results.push(stalenessAction.result); + await this.updateSummaryFromStaleness( + stalenessAction.result, + stalenessAction.analysis, + summaryData, + ); } // Check maintainer accountability @@ -155,14 +160,20 @@ export class SEPProcessor { /** * Check for staleness and take appropriate action */ - private async checkStaleness(sep: SEPItem): Promise { + private async checkStaleness( + sep: SEPItem, + ): Promise<{ result: ActionResult; analysis: StaleAnalysis } | null> { const analysis = await this.analyzer.analyze(sep); if (!analysis.shouldPing && !analysis.shouldMarkDormant) { return null; } - return this.pingHandler.executePing(analysis, this.config.dryRun); + const result = await this.pingHandler.executePing( + analysis, + this.config.dryRun, + ); + return { result, analysis }; } /** @@ -218,14 +229,14 @@ export class SEPProcessor { */ private async updateSummaryFromStaleness( result: ActionResult, - sep: SEPItem, + analysis: StaleAnalysis, summary: SummaryData, ): Promise { if (!result.success) { return; } - const analysis = await this.analyzer.analyze(sep); + const { item: sep } = analysis; switch (result.action.type) { case ActionType.NeedsSponsor: diff --git a/tools/sep-automation/test/unit/processor.test.ts b/tools/sep-automation/test/unit/processor.test.ts new file mode 100644 index 000000000..a7dfa5701 --- /dev/null +++ b/tools/sep-automation/test/unit/processor.test.ts @@ -0,0 +1,112 @@ +import { beforeEach, describe, expect, it, vi } from "vitest"; +import { PingHandler } from "../../src/actions/ping.js"; +import type { TransitionHandler } from "../../src/actions/transition.js"; +import type { GitHubComment } from "../../src/github/types.js"; +import { SEPProcessor } from "../../src/processor.js"; +import { SEPAnalyzer } from "../../src/sep/analyzer.js"; +import { ActionType, BOT_COMMENT_MARKER } from "../../src/types.js"; +import { + asGitHubClient, + asLogger, + asMaintainerResolver, + createMockConfig, + createMockGitHubClient, + createMockLogger, + createMockMaintainerResolver, + createMockSEPItem, + type MockGitHubClient, + type MockLogger, + type MockMaintainerResolver, +} from "../mocks.js"; + +const MS_PER_DAY = 24 * 60 * 60 * 1000; + +describe("SEPProcessor", () => { + let github: MockGitHubClient; + let maintainers: MockMaintainerResolver; + let logger: MockLogger; + + beforeEach(() => { + vi.clearAllMocks(); + github = createMockGitHubClient(); + maintainers = createMockMaintainerResolver(); + logger = createMockLogger(); + }); + + function createProcessor(comments: GitHubComment[]): SEPProcessor { + const config = createMockConfig(); + const githubClient = asGitHubClient(github); + const maintainerResolver = asMaintainerResolver(maintainers); + const typedLogger = asLogger(logger); + + github.getComments.mockImplementation(async () => comments); + github.addComment.mockImplementation(async (_number, body: string) => { + comments.push({ + id: comments.length + 1, + body, + created_at: new Date().toISOString(), + updated_at: new Date().toISOString(), + user: { login: "sep-automation-bot" }, + }); + return { url: "https://github.com/comment/1" }; + }); + + return new SEPProcessor( + config, + new SEPAnalyzer(config, githubClient), + maintainerResolver, + { + executeTransition: vi.fn(), + } as unknown as TransitionHandler, + new PingHandler(config, githubClient, maintainerResolver, typedLogger), + typedLogger, + ); + } + + it("includes a successful stale ping in the returned summary", async () => { + const comments: GitHubComment[] = []; + const processor = createProcessor(comments); + const sep = createMockSEPItem({ + assignees: [], + createdAt: new Date(Date.now() - 95 * MS_PER_DAY), + }); + + const result = await processor.process(sep); + + expect(result.results).toHaveLength(1); + expect(result.results[0]?.action.type).toBe(ActionType.PingAuthor); + expect(result.summaryData.pings).toEqual([ + { + item: sep, + pingTarget: "author", + targetUser: sep.author, + daysSinceActivity: 95, + }, + ]); + expect(comments[0]?.body).toContain(BOT_COMMENT_MARKER); + expect(github.getComments).toHaveBeenCalledTimes(1); + }); + + it("preserves the original close decision in the dormant summary", async () => { + const comments: GitHubComment[] = []; + const processor = createProcessor(comments); + const sep = createMockSEPItem({ + assignees: [], + createdAt: new Date(Date.now() - 185 * MS_PER_DAY), + }); + + const result = await processor.process(sep); + + expect(result.results).toHaveLength(1); + expect(result.results[0]?.action.type).toBe(ActionType.MarkDormant); + expect(result.summaryData.dormant).toEqual([ + { + item: sep, + daysSinceActivity: 185, + wasClosed: true, + }, + ]); + expect(github.closeIssue).toHaveBeenCalledWith(sep.number); + expect(github.getComments).toHaveBeenCalledTimes(1); + }); +}); From 05bd52f9d74bf743c50752f24c8c2f9da1ffae65 Mon Sep 17 00:00:00 2001 From: "mateolafalce3@gmail.com" Date: Fri, 14 Aug 2026 11:41:29 -0300 Subject: [PATCH 2/2] fix: sep-automation-staleness-summary --- docs/specification/draft/schema.mdx | 1 - 1 file changed, 1 deletion(-) diff --git a/docs/specification/draft/schema.mdx b/docs/specification/draft/schema.mdx index 159c7be5e..75ac20091 100644 --- a/docs/specification/draft/schema.mdx +++ b/docs/specification/draft/schema.mdx @@ -1536,4 +1536,3 @@ For example, the world of a web search tool is open, whereas that of a memory tool is not.

Default: true

-