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
6 changes: 5 additions & 1 deletion packages/review-kit/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,11 @@ All notable changes to `@agentworkforce/review-kit` will be documented in this f

## [Unreleased]

### Fixed

- Skip non-pull-request events before requesting a gateway expansion, while
continuing to surface expansion failures for genuine pull-request events.

## [4.1.30] - 2026-07-17

### Added
Expand All @@ -17,4 +22,3 @@ All notable changes to `@agentworkforce/review-kit` will be documented in this f
- Add strongly typed review-agent and review-persona factories that encode the
seven silent review plumbing traps from workforce#281.
- Add built-in PR diff and git-history evidence providers.

9 changes: 9 additions & 0 deletions packages/review-kit/src/agent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,15 @@ function createParsedReviewHandler(
event: event.type
});

if (!event.type.startsWith('github.pull_request.')) {
ctx.log?.('info', 'review-kit.skipped', {
lens: parsed.lens,
reason: 'non-pull-request-event',
eventType: event.type
});
return;
}

const payload = (await event.expand('full')).data;
const pullRequest = readPullRequest(payload);
if (!pullRequest) {
Expand Down
79 changes: 74 additions & 5 deletions packages/review-kit/src/review-kit.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,12 @@ import { join } from 'node:path';
import { fileURLToPath, pathToFileURL } from 'node:url';
import test from 'node:test';
import { extractAgentSpec } from '@agentworkforce/deploy';
import type {
HarnessRunArgs,
WorkforceCtx,
WorkforceEvent,
WritebackResult
import {
envelopeToAgentEvent,
type HarnessRunArgs,
type WorkforceCtx,
type WorkforceEvent,
type WritebackResult
} from '@agentworkforce/runtime';
import {
defineReviewAgent,
Expand Down Expand Up @@ -191,6 +192,74 @@ test('trap 6: a missing writeback receipt is logged as unconfirmed and never thr
);
});

test('non-PR events skip before requesting an unavailable expansion', async () => {
const fixture = handlerFixture();
const event = envelopeToAgentEvent({
id: 'evt-manual',
workspace: 'workspace-1',
type: 'cron.tick',
occurredAt: '2026-07-17T15:18:00Z',
name: 'manual',
cron: 'manual'
});
assert.ok(event);

await assert.rejects(
() => event.expand('full'),
/expand\("full"\) is unavailable/u,
'the real cron event shape has no gateway expansion loader'
);
await assert.doesNotReject(() => fixture.handler(fixture.ctx, event));

assert.equal(fixture.harnessRuns(), 0);
assert.equal(fixture.writes.length, 0);
assert.deepEqual(fixture.logs.at(-1), {
level: 'info',
message: 'review-kit.skipped',
fields: {
lens: 'maintainability',
reason: 'non-pull-request-event',
eventType: 'cron.tick'
}
});
});

test('PR expansion failures still surface instead of being mistaken for non-PR events', async () => {
const fixture = handlerFixture();
const expansionFailure = new Error('github gateway expansion failed');
const event = {
type: 'github.pull_request.opened',
expand: async () => {
throw expansionFailure;
}
} as unknown as WorkforceEvent;

await assert.rejects(() => fixture.handler(fixture.ctx, event), expansionFailure);
assert.equal(fixture.logs.some((entry) => entry.message === 'review-kit.skipped'), false);
assert.equal(fixture.harnessRuns(), 0);
assert.equal(fixture.writes.length, 0);
});

test('expanded but malformed PR payloads retain the unreadable-pull-request guard', async () => {
const fixture = handlerFixture();

await assert.doesNotReject(() =>
fixture.handler(fixture.ctx, fixture.eventForData({ malformed: true }))
);

assert.equal(fixture.harnessRuns(), 0);
assert.equal(fixture.writes.length, 0);
assert.deepEqual(fixture.logs.at(-1), {
level: 'info',
message: 'review-kit.skipped',
fields: {
lens: 'maintainability',
reason: 'unreadable-pull-request',
keys: 'malformed'
}
});
});

test('plumbing: repository, label, and draft guards skip before requiring a mount', async () => {
const handler = createReviewHandler({
repo: REPO,
Expand Down
Loading