Merge pull request #961 from getagentseal/fix/pr-cwd-time-bound

fix(pr-attribution): time-bound the working-directory correlation
This commit is contained in:
Resham Joshi 2026-08-10 14:17:19 -07:00 committed by GitHub
commit 9703e35e4e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 53 additions and 4 deletions

View file

@ -3595,13 +3595,31 @@ export function correlateCrossProviderPrSessions(projects: ProjectSummary[]): vo
// Prompt-linked sessions become valid cwd anchors too. Attribute only when an
// exact cwd maps to one PR set; a main checkout used for multiple PRs remains
// intentionally ambiguous.
const refsByCwd = new Map<string, Map<string, string[]>>()
//
// Time-bounded (the eywa#160 lesson): cwd evidence also carries the evidence
// sessions' own activity window, and only sessions OVERLAPPING that window
// (plus a pad) inherit the PR. Without the bound, a repo whose only captured
// PR link was pasted once became a black hole — every session ever run in
// that checkout, a month of unrelated work included, was attributed to it
// (129 of 131 sessions, ~$7.4K direct, observed on real data). The rule's
// charter is "a tool session launched around PR work in this checkout",
// which is inherently a same-working-stretch claim.
const CWD_WINDOW_PAD_MS = 6 * 60 * 60 * 1000
type CwdAnchor = { refs: string[]; startMs: number; endMs: number }
const refsByCwd = new Map<string, Map<string, CwdAnchor>>()
for (const [session, evidenceRefs] of evidence) {
const cwd = normalizedWorkingDirectory(session.workingDirectory)
if (!cwd || evidenceRefs.length !== 1) continue
const startMs = Date.parse(session.firstTimestamp)
const endMs = Date.parse(session.lastTimestamp)
if (!Number.isFinite(startMs) || !Number.isFinite(endMs)) continue
const refs = evidenceRefs.slice().sort()
const sets = refsByCwd.get(cwd) ?? new Map<string, string[]>()
sets.set(refs.join('\0'), refs)
const key = refs.join('\0')
const sets = refsByCwd.get(cwd) ?? new Map<string, CwdAnchor>()
const existing = sets.get(key)
sets.set(key, existing
? { refs, startMs: Math.min(existing.startMs, startMs), endMs: Math.max(existing.endMs, endMs) }
: { refs, startMs, endMs })
refsByCwd.set(cwd, sets)
}
for (const session of sessions) {
@ -3609,7 +3627,13 @@ export function correlateCrossProviderPrSessions(projects: ProjectSummary[]): vo
const cwd = normalizedWorkingDirectory(session.workingDirectory)
if (!cwd) continue
const sets = refsByCwd.get(cwd)
if (sets?.size === 1) assignCorrelatedPrs(session, [...sets.values()][0]!, 'working-directory')
if (sets?.size !== 1) continue
const anchor = [...sets.values()][0]!
const sessionStart = Date.parse(session.firstTimestamp)
const sessionEnd = Date.parse(session.lastTimestamp)
if (!Number.isFinite(sessionStart) || !Number.isFinite(sessionEnd)) continue
if (sessionEnd < anchor.startMs - CWD_WINDOW_PAD_MS || sessionStart > anchor.endMs + CWD_WINDOW_PAD_MS) continue
assignCorrelatedPrs(session, anchor.refs, 'working-directory')
}
}

View file

@ -106,3 +106,28 @@ describe('cross-provider PR correlation', () => {
expect(codex.prAttributionSource).toBe('launcher-prompt')
})
})
describe('working-directory correlation is time-bounded (eywa#160 regression)', () => {
it('attributes a same-cwd session inside the evidence window, never one weeks later', () => {
// One session in the repo genuinely produced the PR link. A tool session
// an hour later in the same checkout is PR work; a session three weeks
// later in the same checkout is just... work. Before the bound, the
// later session (and 128 real siblings) inherited the PR, attributing a
// month of unrelated spend ($7.4K observed) to a single PR row.
const linked = session({ id: 'anchor', provider: 'claude', timestamp: '2026-07-11T10:00:00Z', message: 'open the PR', refs: [A], cwd: '/repo/eywa' })
const nearby = session({ id: 'nearby', provider: 'codex', timestamp: '2026-07-11T11:30:00Z', message: 'run the review suite for the change', cwd: '/repo/eywa' })
const weeksLater = session({ id: 'later', provider: 'codex', timestamp: '2026-08-02T09:00:00Z', message: 'completely unrelated feature work', cwd: '/repo/eywa' })
correlateCrossProviderPrSessions([project([linked, nearby, weeksLater])])
expect(nearby.prLinks).toEqual([A])
expect(nearby.prAttributionSource).toBe('working-directory')
expect(weeksLater.prLinks).toBeUndefined()
})
it('widens the window across multiple evidence sessions for the same PR', () => {
const early = session({ id: 'e1', provider: 'claude', timestamp: '2026-07-11T10:00:00Z', message: 'open', refs: [A], cwd: '/repo/eywa' })
const late = session({ id: 'e2', provider: 'claude', timestamp: '2026-07-14T10:00:00Z', message: 'follow-up', refs: [A], cwd: '/repo/eywa' })
const between = session({ id: 'mid', provider: 'codex', timestamp: '2026-07-12T12:00:00Z', message: 'work in between the two linked sessions', cwd: '/repo/eywa' })
correlateCrossProviderPrSessions([project([early, late, between])])
expect(between.prLinks).toEqual([A])
})
})