mirror of
https://github.com/AgentSeal/codeburn.git
synced 2026-08-21 06:24:32 +00:00
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:
commit
9703e35e4e
2 changed files with 53 additions and 4 deletions
|
|
@ -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')
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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])
|
||||
})
|
||||
})
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue