fix: 隔离代码代理诊断 trace
This commit is contained in:
@@ -27,6 +27,11 @@ describe("diagnose-code-agent warm-session terminal classification", () => {
|
||||
namespaceSource: "provider-decision",
|
||||
providerDecisionNamespace: "agentrun-v02",
|
||||
ok: true,
|
||||
commandOk: true,
|
||||
resultOk: true,
|
||||
runResultOk: true,
|
||||
eventsOk: true,
|
||||
diagnosticTransportFailed: false,
|
||||
terminalStatus: "completed",
|
||||
terminalEventSeq: 10,
|
||||
eventCount: 2,
|
||||
@@ -42,6 +47,7 @@ describe("diagnose-code-agent warm-session terminal classification", () => {
|
||||
});
|
||||
expect(diagnosis.calls).toContain("-n agentrun-v02 exec deploy/agentrun-mgr");
|
||||
expect(diagnosis.calls).not.toContain("agentrun-v01");
|
||||
assertDiagnosticRequestContract(diagnosis);
|
||||
|
||||
const compact = compactDiagnoseCodeAgentResult(diagnosis.payload);
|
||||
expect((compact.agentrun as Record<string, any>).authority).toMatchObject({
|
||||
@@ -57,6 +63,10 @@ describe("diagnose-code-agent warm-session terminal classification", () => {
|
||||
result: compact,
|
||||
});
|
||||
expect(rendered.renderedText).toContain("authorityQuery namespace=agentrun-v02 source=provider-decision ok=true commandState=completed terminal=completed");
|
||||
expect(rendered.renderedText).toContain("Diagnostic trace:");
|
||||
expect(rendered.renderedText).toContain(`traceId=${diagnosis.payload.diagnosticTrace.traceId}`);
|
||||
expect(rendered.renderedText).toContain("expectedLinkTraceId=de11d47d1bab0ca4d3f6259279f3a332");
|
||||
expect(rendered.renderedText).toContain(`--target NC01 --trace-id ${diagnosis.payload.diagnosticTrace.traceId} --full`);
|
||||
});
|
||||
|
||||
test("reports unknown instead of running when command authority and terminal span are both absent", () => {
|
||||
@@ -73,6 +83,20 @@ describe("diagnose-code-agent warm-session terminal classification", () => {
|
||||
terminalSpanSeen: false,
|
||||
});
|
||||
expect(diagnosis.payload.rootCauseCandidates[0].code).toBe("observability_gap_authority_query_failed");
|
||||
expect(diagnosis.payload.agentrun.authority).toMatchObject({
|
||||
diagnosticTransportFailed: true,
|
||||
diagnosticTransportFailures: ["command-result", "run-result", "events"],
|
||||
attempts: {
|
||||
result: [{ diagnosticContextApplied: true, fallbackDenied: "headerless-service-proxy", error: "diagnostic-transport-failed" }],
|
||||
runResult: [{ diagnosticContextApplied: true, fallbackDenied: "headerless-service-proxy", error: "diagnostic-transport-failed" }],
|
||||
events: [{ diagnosticContextApplied: true, fallbackDenied: "headerless-service-proxy", error: "diagnostic-transport-failed" }],
|
||||
},
|
||||
});
|
||||
expect(diagnosis.payload.agentrun.authority.attempts.command[0].diagnosticContextApplied).toBe(false);
|
||||
expect(diagnosis.payload.agentrun.authority.attempts.result).toHaveLength(1);
|
||||
expect(diagnosis.payload.agentrun.authority.attempts.runResult).toHaveLength(1);
|
||||
expect(diagnosis.payload.agentrun.authority.attempts.events).toHaveLength(1);
|
||||
assertNoHeaderlessDiagnosticFallback(diagnosis.calls);
|
||||
});
|
||||
|
||||
test("keeps a scoped OTel terminal span complete even if the supplemental authority read fails", () => {
|
||||
@@ -90,6 +114,15 @@ describe("diagnose-code-agent warm-session terminal classification", () => {
|
||||
terminalSpanCount: 1,
|
||||
});
|
||||
});
|
||||
|
||||
test("uses a fresh diagnostic trace for each repeated diagnosis without unscoped authority reads", () => {
|
||||
const first = runFixture({ authorityAvailable: true, terminalSpan: false });
|
||||
const second = runFixture({ authorityAvailable: true, terminalSpan: false });
|
||||
assertDiagnosticRequestContract(first);
|
||||
assertDiagnosticRequestContract(second);
|
||||
expect(first.payload.diagnosticTrace.traceId).not.toBe(second.payload.diagnosticTrace.traceId);
|
||||
expect(first.payload.diagnosticTrace.traceparent).not.toBe(second.payload.diagnosticTrace.traceparent);
|
||||
});
|
||||
});
|
||||
|
||||
function runFixture(input: { authorityAvailable: boolean; terminalSpan: boolean }): {
|
||||
@@ -102,6 +135,7 @@ function runFixture(input: { authorityAvailable: boolean; terminalSpan: boolean
|
||||
writeFileSync(join(directory, "trace.json"), JSON.stringify(traceFixture(input.terminalSpan)));
|
||||
writeFileSync(join(directory, "command.json"), JSON.stringify({ id: "cmd_second", state: "completed" }));
|
||||
writeFileSync(join(directory, "result.json"), JSON.stringify({ ok: true, commandId: "cmd_second", status: "completed", commandState: "completed", terminalStatus: "completed" }));
|
||||
writeFileSync(join(directory, "run-result.json"), JSON.stringify({ ok: true, commandId: "cmd_second", commandState: "completed", terminalStatus: "completed" }));
|
||||
writeFileSync(join(directory, "events.json"), JSON.stringify({
|
||||
items: [
|
||||
{ seq: 10, type: "terminal_status", payload: { commandId: "cmd_second", terminalStatus: "completed" } },
|
||||
@@ -121,6 +155,7 @@ if [ "$AUTHORITY_AVAILABLE" != "1" ]; then
|
||||
fi
|
||||
case "$*" in
|
||||
*"-n agentrun-v02 exec deploy/agentrun-mgr"*"/commands/cmd_second/result"*) cat "$FIXTURE_DIR/result.json"; exit 0 ;;
|
||||
*"-n agentrun-v02 exec deploy/agentrun-mgr"*"/runs/run_warm/result?commandId=cmd_second"*) cat "$FIXTURE_DIR/run-result.json"; exit 0 ;;
|
||||
*"-n agentrun-v02 exec deploy/agentrun-mgr"*"/commands/cmd_second"*) cat "$FIXTURE_DIR/command.json"; exit 0 ;;
|
||||
*"-n agentrun-v02 exec deploy/agentrun-mgr"*"/runs/run_warm/events"*) cat "$FIXTURE_DIR/events.json"; exit 0 ;;
|
||||
esac
|
||||
@@ -147,6 +182,59 @@ exit 1
|
||||
};
|
||||
}
|
||||
|
||||
function assertDiagnosticRequestContract(diagnosis: { payload: Record<string, any>; calls: string }): void {
|
||||
const diagnostic = diagnosis.payload.diagnosticTrace;
|
||||
expect(diagnostic).toMatchObject({
|
||||
operation: "unidesk.diagnose-code-agent",
|
||||
targetBusinessTraceId: "trc_warm_second",
|
||||
targetCommandId: "cmd_second",
|
||||
expectedTargetOtelTraceId: "de11d47d1bab0ca4d3f6259279f3a332",
|
||||
contextReady: true,
|
||||
headerReadPaths: ["command-result", "run-result", "events"],
|
||||
ordinaryReadPaths: ["command-detail"],
|
||||
});
|
||||
expect(diagnostic.traceId).toMatch(/^[0-9a-f]{32}$/);
|
||||
expect(diagnostic.parentSpanId).toMatch(/^[0-9a-f]{16}$/);
|
||||
expect(diagnostic.traceparent).toBe(`00-${diagnostic.traceId}-${diagnostic.parentSpanId}-01`);
|
||||
expect(diagnostic.traceCommand).toContain(`--target NC01 --trace-id ${diagnostic.traceId} --full`);
|
||||
expect(diagnostic.targetTraceCommand).toContain("--target NC01 --trace-id de11d47d1bab0ca4d3f6259279f3a332 --full");
|
||||
expect(diagnostic.linkQueryClue).toContain("links for traceId=de11d47d1bab0ca4d3f6259279f3a332");
|
||||
|
||||
const lines = callLines(diagnosis.calls);
|
||||
const diagnosticLines = lines.filter((line) => line.includes("x-agentrun-trace-purpose: diagnostic"));
|
||||
expect(diagnosticLines).toHaveLength(3);
|
||||
for (const path of [
|
||||
"/api/v1/runs/run_warm/commands/cmd_second/result",
|
||||
"/api/v1/runs/run_warm/result?commandId=cmd_second",
|
||||
"/api/v1/runs/run_warm/events?afterSeq=0&limit=1000",
|
||||
]) {
|
||||
const line = diagnosticLines.find((candidate) => candidate.includes(path));
|
||||
expect(line).toBeDefined();
|
||||
expect(line).toContain(`traceparent: ${diagnostic.traceparent}`);
|
||||
expect(line).toContain("x-agentrun-diagnostic-operation: unidesk.diagnose-code-agent");
|
||||
expect(line).toContain("x-agentrun-diagnostic-target-business-trace-id: trc_warm_second");
|
||||
expect(line).toContain("x-agentrun-diagnostic-target-command-id: cmd_second");
|
||||
}
|
||||
const traceparents = new Set(diagnosticLines.flatMap((line) => line.match(/00-[0-9a-f]{32}-[0-9a-f]{16}-01/g) ?? []));
|
||||
expect([...traceparents]).toEqual([diagnostic.traceparent]);
|
||||
|
||||
const commandDetailLines = lines.filter((line) => line.includes("/api/v1/runs/run_warm/commands/cmd_second") && !line.includes("/commands/cmd_second/result"));
|
||||
expect(commandDetailLines).toHaveLength(1);
|
||||
expect(commandDetailLines[0]).not.toContain("x-agentrun-trace-purpose");
|
||||
assertNoHeaderlessDiagnosticFallback(diagnosis.calls);
|
||||
}
|
||||
|
||||
function assertNoHeaderlessDiagnosticFallback(calls: string): void {
|
||||
const proxyLines = callLines(calls).filter((line) => line.includes("services/http:agentrun-mgr"));
|
||||
expect(proxyLines.some((line) => line.includes("/commands/cmd_second/result"))).toBe(false);
|
||||
expect(proxyLines.some((line) => line.includes("/runs/run_warm/result?commandId=cmd_second"))).toBe(false);
|
||||
expect(proxyLines.some((line) => line.includes("/runs/run_warm/events?afterSeq=0&limit=1000"))).toBe(false);
|
||||
}
|
||||
|
||||
function callLines(calls: string): string[] {
|
||||
return calls.split("\n").map((line) => line.trim()).filter(Boolean);
|
||||
}
|
||||
|
||||
function traceFixture(terminalSpan: boolean): Record<string, unknown> {
|
||||
const common = [
|
||||
attribute("traceId", "trc_warm_second"),
|
||||
|
||||
Reference in New Issue
Block a user