@@ -1630,6 +1630,38 @@ describe("sendJobConclusionSpan", () => {
16301630 expect ( span . name ) . toBe ( "gh-aw.job.conclusion" ) ;
16311631 } ) ;
16321632
1633+ it ( "emits a dedicated agent span on timed_out when agent_output mtime is unavailable" , async ( ) => {
1634+ const mockFetch = vi . fn ( ) . mockResolvedValue ( { ok : true , status : 200 , statusText : "OK" } ) ;
1635+ vi . stubGlobal ( "fetch" , mockFetch ) ;
1636+
1637+ process . env . OTEL_EXPORTER_OTLP_ENDPOINT = "https://traces.example.com" ;
1638+ process . env . INPUT_JOB_NAME = "agent" ;
1639+ process . env . GH_AW_AGENT_CONCLUSION = "timed_out" ;
1640+
1641+ const startMs = 1_700_000_000_000 ;
1642+ const statSpy = vi . spyOn ( fs , "statSync" ) . mockImplementation ( ( ) => {
1643+ throw Object . assign ( new Error ( "ENOENT" ) , { code : "ENOENT" } ) ;
1644+ } ) ;
1645+
1646+ await sendJobConclusionSpan ( "gh-aw.agent.conclusion" , { startMs } ) ;
1647+
1648+ statSpy . mockRestore ( ) ;
1649+ expect ( mockFetch ) . toHaveBeenCalledTimes ( 2 ) ;
1650+
1651+ const agentBody = JSON . parse ( mockFetch . mock . calls [ 0 ] [ 1 ] . body ) ;
1652+ const agentSpan = agentBody . resourceSpans [ 0 ] . scopeSpans [ 0 ] . spans [ 0 ] ;
1653+ expect ( agentSpan . name ) . toBe ( "gh-aw.agent.agent" ) ;
1654+ expect ( agentSpan . startTimeUnixNano ) . toBe ( toNanoString ( startMs ) ) ;
1655+ expect ( BigInt ( agentSpan . endTimeUnixNano ) ) . toBeGreaterThan ( BigInt ( toNanoString ( startMs ) ) ) ;
1656+
1657+ const conclusionBody = JSON . parse ( mockFetch . mock . calls [ 1 ] [ 1 ] . body ) ;
1658+ const conclusionSpan = conclusionBody . resourceSpans [ 0 ] . scopeSpans [ 0 ] . spans [ 0 ] ;
1659+ expect ( conclusionSpan . name ) . toBe ( "gh-aw.agent.conclusion" ) ;
1660+ expect ( agentSpan . parentSpanId ) . toBe ( conclusionSpan . spanId ) ;
1661+ expect ( conclusionSpan . status . code ) . toBe ( 2 ) ;
1662+ expect ( conclusionSpan . status . message ) . toContain ( "agent timed_out" ) ;
1663+ } ) ;
1664+
16331665 it ( "does not emit a dedicated agent span for non-agent jobs" , async ( ) => {
16341666 const mockFetch = vi . fn ( ) . mockResolvedValue ( { ok : true , status : 200 , statusText : "OK" } ) ;
16351667 vi . stubGlobal ( "fetch" , mockFetch ) ;
0 commit comments