@xera-ai/core 0.4.0 → 0.4.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/artifact/status.d.ts +4 -0
- package/dist/artifact/status.d.ts.map +1 -1
- package/dist/bin/internal.js +593 -72
- package/dist/bin-internal/graph-enrich.d.ts +2 -0
- package/dist/bin-internal/graph-enrich.d.ts.map +1 -0
- package/dist/bin-internal/graph-record.d.ts.map +1 -1
- package/dist/bin-internal/impact-prepare.d.ts +2 -0
- package/dist/bin-internal/impact-prepare.d.ts.map +1 -0
- package/dist/bin-internal/index.d.ts.map +1 -1
- package/dist/bin-internal/report.d.ts.map +1 -1
- package/dist/bin-internal/verify-prompts.d.ts.map +1 -1
- package/dist/classifier/aggregate.d.ts.map +1 -1
- package/dist/config/schema.d.ts +6 -0
- package/dist/config/schema.d.ts.map +1 -1
- package/dist/graph/classify.d.ts +42 -0
- package/dist/graph/classify.d.ts.map +1 -0
- package/dist/graph/enrich.d.ts +10 -0
- package/dist/graph/enrich.d.ts.map +1 -0
- package/dist/graph/impact.d.ts +31 -0
- package/dist/graph/impact.d.ts.map +1 -0
- package/dist/graph/index.d.ts +7 -0
- package/dist/graph/index.d.ts.map +1 -1
- package/dist/graph/schema.d.ts +3 -0
- package/dist/graph/schema.d.ts.map +1 -1
- package/dist/graph/similarity.d.ts +3 -0
- package/dist/graph/similarity.d.ts.map +1 -0
- package/dist/graph/types.d.ts +1 -1
- package/dist/graph/types.d.ts.map +1 -1
- package/dist/src/index.js +15 -1
- package/package.json +1 -1
- package/src/artifact/status.ts +8 -1
- package/src/bin-internal/graph-enrich.ts +28 -0
- package/src/bin-internal/graph-record.ts +45 -1
- package/src/bin-internal/impact-prepare.ts +64 -0
- package/src/bin-internal/index.ts +4 -0
- package/src/bin-internal/report.ts +63 -5
- package/src/bin-internal/verify-prompts.ts +2 -0
- package/src/classifier/aggregate.ts +1 -0
- package/src/config/schema.ts +12 -0
- package/src/graph/classify.ts +126 -0
- package/src/graph/enrich.ts +103 -0
- package/src/graph/impact.ts +262 -0
- package/src/graph/index.ts +26 -0
- package/src/graph/schema.ts +8 -1
- package/src/graph/similarity.ts +43 -0
- package/src/graph/types.ts +7 -2
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"graph-enrich.d.ts","sourceRoot":"","sources":["../../src/bin-internal/graph-enrich.ts"],"names":[],"mappings":"AAEA,wBAAsB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CAyBpE"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"graph-record.d.ts","sourceRoot":"","sources":["../../src/bin-internal/graph-record.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"graph-record.d.ts","sourceRoot":"","sources":["../../src/bin-internal/graph-record.ts"],"names":[],"mappings":"AA2EA,wBAAsB,WAAW,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAqCnF;AAiFD,wBAAsB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CA6FpE"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"impact-prepare.d.ts","sourceRoot":"","sources":["../../src/bin-internal/impact-prepare.ts"],"names":[],"mappings":"AAkBA,wBAAsB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CA6CtE"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/bin-internal/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/bin-internal/index.ts"],"names":[],"mappings":"AAkDA,wBAAsB,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CAczD"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"report.d.ts","sourceRoot":"","sources":["../../src/bin-internal/report.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"report.d.ts","sourceRoot":"","sources":["../../src/bin-internal/report.ts"],"names":[],"mappings":"AAiBA,wBAAsB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CAuF/D"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"verify-prompts.d.ts","sourceRoot":"","sources":["../../src/bin-internal/verify-prompts.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,OAAO,CAAC;IACZ,OAAO,EAAE,MAAM,CAAC;CACjB;
|
|
1
|
+
{"version":3,"file":"verify-prompts.d.ts","sourceRoot":"","sources":["../../src/bin-internal/verify-prompts.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,OAAO,CAAC;IACZ,OAAO,EAAE,MAAM,CAAC;CACjB;AAeD,wBAAgB,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,WAAW,EAAE,CA8B7D;AAED,wBAAsB,gBAAgB,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CAQvE"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"aggregate.d.ts","sourceRoot":"","sources":["../../src/classifier/aggregate.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAc,sBAAsB,EAAE,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"aggregate.d.ts","sourceRoot":"","sources":["../../src/classifier/aggregate.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAc,sBAAsB,EAAE,MAAM,SAAS,CAAC;AAalF,wBAAgB,kBAAkB,CAAC,SAAS,EAAE,sBAAsB,EAAE,GAAG,cAAc,CAoBtF"}
|
package/dist/config/schema.d.ts
CHANGED
|
@@ -60,6 +60,12 @@ export declare const XeraConfigSchema: z.ZodObject<{
|
|
|
60
60
|
local: "local";
|
|
61
61
|
}>>;
|
|
62
62
|
}, z.core.$strip>>;
|
|
63
|
+
run: z.ZodPrefault<z.ZodPrefault<z.ZodObject<{
|
|
64
|
+
autoImpact: z.ZodPrefault<z.ZodObject<{
|
|
65
|
+
enabled: z.ZodDefault<z.ZodBoolean>;
|
|
66
|
+
threshold: z.ZodDefault<z.ZodNumber>;
|
|
67
|
+
}, z.core.$strip>>;
|
|
68
|
+
}, z.core.$strip>>>;
|
|
63
69
|
adapters: z.ZodDefault<z.ZodArray<z.ZodString>>;
|
|
64
70
|
}, z.core.$strip>;
|
|
65
71
|
export type XeraConfig = z.infer<typeof XeraConfigSchema>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../src/config/schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;
|
|
1
|
+
{"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../src/config/schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAkFxB,eAAO,MAAM,gBAAgB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAO3B,CAAC;AAEH,MAAM,MAAM,UAAU,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,gBAAgB,CAAC,CAAC"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import type { Classification, ScenarioNode, Snapshot, TicketNode } from './types';
|
|
2
|
+
export interface ClassifyInput {
|
|
3
|
+
scenarioId: string;
|
|
4
|
+
traceClassification: Classification;
|
|
5
|
+
}
|
|
6
|
+
export interface CandidateEvidence {
|
|
7
|
+
ticketId: string;
|
|
8
|
+
summary: string;
|
|
9
|
+
modifiedArea: string;
|
|
10
|
+
relevantAcRef?: string;
|
|
11
|
+
}
|
|
12
|
+
export interface ClassifyEvidence {
|
|
13
|
+
candidateTickets?: CandidateEvidence[];
|
|
14
|
+
reasoning?: string;
|
|
15
|
+
expectedByTest?: string;
|
|
16
|
+
actualInApp?: string;
|
|
17
|
+
proposedAction?: 'regenerate-scenario' | 'review-and-decide';
|
|
18
|
+
}
|
|
19
|
+
export interface ClassifyOutput {
|
|
20
|
+
classification: Classification;
|
|
21
|
+
confidence: number;
|
|
22
|
+
evidence?: ClassifyEvidence;
|
|
23
|
+
}
|
|
24
|
+
export interface OutdatedDecision {
|
|
25
|
+
classification: 'TEST_OUTDATED' | 'BUG' | 'AMBIGUOUS';
|
|
26
|
+
confidence: number;
|
|
27
|
+
evidence: {
|
|
28
|
+
reasoning: string;
|
|
29
|
+
expectedByTest?: string;
|
|
30
|
+
actualInApp?: string;
|
|
31
|
+
relevantAcRef?: string;
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
export type DecideOutdated = (args: {
|
|
35
|
+
scenario: ScenarioNode;
|
|
36
|
+
candidates: TicketNode[];
|
|
37
|
+
}) => Promise<OutdatedDecision>;
|
|
38
|
+
export declare function findCandidateTickets(graph: Snapshot, scenario: ScenarioNode): TicketNode[];
|
|
39
|
+
export declare function enhanceClassification(input: ClassifyInput, graph: Snapshot, decideOutdated: DecideOutdated, options?: {
|
|
40
|
+
threshold?: number;
|
|
41
|
+
}): Promise<ClassifyOutput>;
|
|
42
|
+
//# sourceMappingURL=classify.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"classify.d.ts","sourceRoot":"","sources":["../../src/graph/classify.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,YAAY,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAElF,MAAM,WAAW,aAAa;IAC5B,UAAU,EAAE,MAAM,CAAC;IACnB,mBAAmB,EAAE,cAAc,CAAC;CACrC;AAED,MAAM,WAAW,iBAAiB;IAChC,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE,MAAM,CAAC;IACrB,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,gBAAgB;IAC/B,gBAAgB,CAAC,EAAE,iBAAiB,EAAE,CAAC;IACvC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,cAAc,CAAC,EAAE,qBAAqB,GAAG,mBAAmB,CAAC;CAC9D;AAED,MAAM,WAAW,cAAc;IAC7B,cAAc,EAAE,cAAc,CAAC;IAC/B,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,gBAAgB,CAAC;CAC7B;AAED,MAAM,WAAW,gBAAgB;IAC/B,cAAc,EAAE,eAAe,GAAG,KAAK,GAAG,WAAW,CAAC;IACtD,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE;QACR,SAAS,EAAE,MAAM,CAAC;QAClB,cAAc,CAAC,EAAE,MAAM,CAAC;QACxB,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,aAAa,CAAC,EAAE,MAAM,CAAC;KACxB,CAAC;CACH;AAED,MAAM,MAAM,cAAc,GAAG,CAAC,IAAI,EAAE;IAClC,QAAQ,EAAE,YAAY,CAAC;IACvB,UAAU,EAAE,UAAU,EAAE,CAAC;CAC1B,KAAK,OAAO,CAAC,gBAAgB,CAAC,CAAC;AAKhC,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,YAAY,GAAG,UAAU,EAAE,CA2B1F;AAED,wBAAsB,qBAAqB,CACzC,KAAK,EAAE,aAAa,EACpB,KAAK,EAAE,QAAQ,EACf,cAAc,EAAE,cAAc,EAC9B,OAAO,GAAE;IAAE,SAAS,CAAC,EAAE,MAAM,CAAA;CAAO,GACnC,OAAO,CAAC,cAAc,CAAC,CA4CzB"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export interface EnrichOptions {
|
|
2
|
+
force?: boolean;
|
|
3
|
+
}
|
|
4
|
+
export interface EnrichResult {
|
|
5
|
+
ticketId: string;
|
|
6
|
+
similarCount: number;
|
|
7
|
+
enrichedAt: string;
|
|
8
|
+
}
|
|
9
|
+
export declare function enrichTicket(repoRoot: string, ticketId: string, opts: EnrichOptions): Promise<EnrichResult>;
|
|
10
|
+
//# sourceMappingURL=enrich.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"enrich.d.ts","sourceRoot":"","sources":["../../src/graph/enrich.ts"],"names":[],"mappings":"AAqBA,MAAM,WAAW,aAAa;IAC5B,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAED,MAAM,WAAW,YAAY;IAC3B,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;CACpB;AAkBD,wBAAsB,YAAY,CAChC,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,aAAa,GAClB,OAAO,CAAC,YAAY,CAAC,CAmDvB"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { EdgeKind, Priority, Snapshot, TicketNode } from './types';
|
|
2
|
+
export interface ImpactEdge {
|
|
3
|
+
kind: EdgeKind;
|
|
4
|
+
from: string;
|
|
5
|
+
to: string;
|
|
6
|
+
confidence?: number;
|
|
7
|
+
source?: string;
|
|
8
|
+
}
|
|
9
|
+
export interface ImpactScenario {
|
|
10
|
+
scenarioId: string;
|
|
11
|
+
ticketId: string;
|
|
12
|
+
name: string;
|
|
13
|
+
priority: Priority;
|
|
14
|
+
edgePath: ImpactEdge[];
|
|
15
|
+
riskScore: number;
|
|
16
|
+
lastPassedAt?: string;
|
|
17
|
+
}
|
|
18
|
+
export interface ImpactOpts {
|
|
19
|
+
depth: 1 | 2 | 3;
|
|
20
|
+
minPriority?: Priority;
|
|
21
|
+
}
|
|
22
|
+
export interface ImpactReport {
|
|
23
|
+
targetTicket: string;
|
|
24
|
+
modifiedAreas: string[];
|
|
25
|
+
scenarios: ImpactScenario[];
|
|
26
|
+
generatedAt: string;
|
|
27
|
+
}
|
|
28
|
+
export declare function riskScore(scenario: ImpactScenario, daysSinceLastPass: number): number;
|
|
29
|
+
export declare function walkImpact(graph: Snapshot, target: TicketNode, opts: ImpactOpts): ImpactScenario[];
|
|
30
|
+
export declare function renderImpactMarkdown(report: ImpactReport): string;
|
|
31
|
+
//# sourceMappingURL=impact.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"impact.d.ts","sourceRoot":"","sources":["../../src/graph/impact.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAExE,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,QAAQ,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;IACX,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,cAAc;IAC7B,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,QAAQ,CAAC;IACnB,QAAQ,EAAE,UAAU,EAAE,CAAC;IACvB,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IACjB,WAAW,CAAC,EAAE,QAAQ,CAAC;CACxB;AAED,MAAM,WAAW,YAAY;IAC3B,YAAY,EAAE,MAAM,CAAC;IACrB,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,SAAS,EAAE,cAAc,EAAE,CAAC;IAC5B,WAAW,EAAE,MAAM,CAAC;CACrB;AA4BD,wBAAgB,SAAS,CAAC,QAAQ,EAAE,cAAc,EAAE,iBAAiB,EAAE,MAAM,GAAG,MAAM,CAOrF;AAUD,wBAAgB,UAAU,CACxB,KAAK,EAAE,QAAQ,EACf,MAAM,EAAE,UAAU,EAClB,IAAI,EAAE,UAAU,GACf,cAAc,EAAE,CAkHlB;AAeD,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,YAAY,GAAG,MAAM,CAqDjE"}
|
package/dist/graph/index.d.ts
CHANGED
|
@@ -1,7 +1,14 @@
|
|
|
1
|
+
export type { CandidateEvidence, ClassifyEvidence, ClassifyInput, ClassifyOutput, DecideOutdated, OutdatedDecision, } from './classify';
|
|
2
|
+
export { enhanceClassification, findCandidateTickets, } from './classify';
|
|
1
3
|
export type { CostSummary, LlmCallLog } from './cost';
|
|
2
4
|
export { logLlmCall, summarizeCost } from './cost';
|
|
5
|
+
export type { EnrichOptions, EnrichResult } from './enrich';
|
|
6
|
+
export { enrichTicket } from './enrich';
|
|
7
|
+
export type { ImpactEdge, ImpactOpts, ImpactReport, ImpactScenario, } from './impact';
|
|
8
|
+
export { renderImpactMarkdown, riskScore, walkImpact, } from './impact';
|
|
3
9
|
export { currentYyyyMm, graphPaths } from './paths';
|
|
4
10
|
export { EventSchema, safeParseEvent } from './schema';
|
|
11
|
+
export { buildSimilarityPrompt } from './similarity';
|
|
5
12
|
export { appendEvents, computeEventsHash, deriveSnapshot, isSnapshotStale, loadAllEvents, loadSnapshot, writeSnapshot, } from './store';
|
|
6
13
|
export * from './types';
|
|
7
14
|
export { ulid } from './ulid';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/graph/index.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAC;AACtD,OAAO,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,QAAQ,CAAC;AACnD,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACpD,OAAO,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AACvD,OAAO,EACL,YAAY,EACZ,iBAAiB,EACjB,cAAc,EACd,eAAe,EACf,aAAa,EACb,YAAY,EACZ,aAAa,GACd,MAAM,SAAS,CAAC;AACjB,cAAc,SAAS,CAAC;AACxB,OAAO,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/graph/index.ts"],"names":[],"mappings":"AAAA,YAAY,EACV,iBAAiB,EACjB,gBAAgB,EAChB,aAAa,EACb,cAAc,EACd,cAAc,EACd,gBAAgB,GACjB,MAAM,YAAY,CAAC;AACpB,OAAO,EACL,qBAAqB,EACrB,oBAAoB,GACrB,MAAM,YAAY,CAAC;AACpB,YAAY,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAC;AACtD,OAAO,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,QAAQ,CAAC;AACnD,YAAY,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAC5D,OAAO,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AACxC,YAAY,EACV,UAAU,EACV,UAAU,EACV,YAAY,EACZ,cAAc,GACf,MAAM,UAAU,CAAC;AAClB,OAAO,EACL,oBAAoB,EACpB,SAAS,EACT,UAAU,GACX,MAAM,UAAU,CAAC;AAClB,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACpD,OAAO,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AACvD,OAAO,EAAE,qBAAqB,EAAE,MAAM,cAAc,CAAC;AACrD,OAAO,EACL,YAAY,EACZ,iBAAiB,EACjB,cAAc,EACd,eAAe,EACf,aAAa,EACb,YAAY,EACZ,aAAa,GACd,MAAM,SAAS,CAAC;AACjB,cAAc,SAAS,CAAC;AACxB,OAAO,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC"}
|
package/dist/graph/schema.d.ts
CHANGED
|
@@ -108,6 +108,7 @@ export declare const EventSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
|
108
108
|
SELECTOR_DRIFT: "SELECTOR_DRIFT";
|
|
109
109
|
FLAKY: "FLAKY";
|
|
110
110
|
TEST_BUG: "TEST_BUG";
|
|
111
|
+
TEST_OUTDATED: "TEST_OUTDATED";
|
|
111
112
|
}>;
|
|
112
113
|
confidence: z.ZodEnum<{
|
|
113
114
|
low: "low";
|
|
@@ -130,6 +131,7 @@ export declare const EventSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
|
130
131
|
SELECTOR_DRIFT: "SELECTOR_DRIFT";
|
|
131
132
|
FLAKY: "FLAKY";
|
|
132
133
|
TEST_BUG: "TEST_BUG";
|
|
134
|
+
TEST_OUTDATED: "TEST_OUTDATED";
|
|
133
135
|
}>;
|
|
134
136
|
disputedTo: z.ZodEnum<{
|
|
135
137
|
PASS: "PASS";
|
|
@@ -137,6 +139,7 @@ export declare const EventSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
|
137
139
|
SELECTOR_DRIFT: "SELECTOR_DRIFT";
|
|
138
140
|
FLAKY: "FLAKY";
|
|
139
141
|
TEST_BUG: "TEST_BUG";
|
|
142
|
+
TEST_OUTDATED: "TEST_OUTDATED";
|
|
140
143
|
}>;
|
|
141
144
|
qaActor: z.ZodString;
|
|
142
145
|
qaReason: z.ZodOptional<z.ZodString>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../src/graph/schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../src/graph/schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAsHrC,eAAO,MAAM,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2BActB,CAAC;AAEH,wBAAgB,cAAc,CAC5B,KAAK,EAAE,OAAO,GACb;IAAE,OAAO,EAAE,IAAI,CAAC;IAAC,IAAI,EAAE,KAAK,CAAA;CAAE,GAAG;IAAE,OAAO,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,CAAC,CAAC,QAAQ,CAAA;CAAE,CAIxE"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"similarity.d.ts","sourceRoot":"","sources":["../../src/graph/similarity.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAI1C,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,UAAU,EAAE,UAAU,EAAE,UAAU,EAAE,GAAG,MAAM,CAsC1F"}
|
package/dist/graph/types.d.ts
CHANGED
|
@@ -2,7 +2,7 @@ export declare const SCHEMA_VERSION: 1;
|
|
|
2
2
|
export type Priority = 'p0' | 'p1' | 'p2';
|
|
3
3
|
export type ScenarioStatus = 'pass' | 'fail';
|
|
4
4
|
export type EdgeKind = 'tests' | 'uses' | 'covers' | 'modifies' | 'jira-linked' | 'similar' | 'ran';
|
|
5
|
-
export type Classification = 'REAL_BUG' | 'TEST_BUG' | 'SELECTOR_DRIFT' | 'FLAKY' | 'PASS';
|
|
5
|
+
export type Classification = 'REAL_BUG' | 'TEST_BUG' | 'SELECTOR_DRIFT' | 'FLAKY' | 'PASS' | 'TEST_OUTDATED';
|
|
6
6
|
export interface TicketFetchedPayload {
|
|
7
7
|
ticketId: string;
|
|
8
8
|
summary: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/graph/types.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,cAAc,EAAG,CAAU,CAAC;AAEzC,MAAM,MAAM,QAAQ,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;AAC1C,MAAM,MAAM,cAAc,GAAG,MAAM,GAAG,MAAM,CAAC;AAC7C,MAAM,MAAM,QAAQ,GAAG,OAAO,GAAG,MAAM,GAAG,QAAQ,GAAG,UAAU,GAAG,aAAa,GAAG,SAAS,GAAG,KAAK,CAAC;AAEpG,MAAM,MAAM,cAAc,
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/graph/types.ts"],"names":[],"mappings":"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"}
|
package/dist/src/index.js
CHANGED
|
@@ -107,7 +107,14 @@ function generateRunId(now = new Date) {
|
|
|
107
107
|
import { existsSync as existsSync3, mkdirSync as mkdirSync2, readFileSync as readFileSync3, writeFileSync as writeFileSync2 } from "fs";
|
|
108
108
|
import { dirname as dirname2 } from "path";
|
|
109
109
|
import { z as z2 } from "zod";
|
|
110
|
-
var ClassificationEnum = z2.enum([
|
|
110
|
+
var ClassificationEnum = z2.enum([
|
|
111
|
+
"PASS",
|
|
112
|
+
"REAL_BUG",
|
|
113
|
+
"SELECTOR_DRIFT",
|
|
114
|
+
"FLAKY",
|
|
115
|
+
"TEST_BUG",
|
|
116
|
+
"TEST_OUTDATED"
|
|
117
|
+
]);
|
|
111
118
|
var ResultEnum = z2.enum(["PASS", "FAIL"]);
|
|
112
119
|
var ConfidenceEnum = z2.enum(["low", "medium", "high"]);
|
|
113
120
|
var HistoryEntrySchema = z2.object({
|
|
@@ -317,11 +324,18 @@ var ReportingSchema = z4.object({
|
|
|
317
324
|
}).prefault({}),
|
|
318
325
|
artifactLinks: z4.enum(["git", "local"]).default("git")
|
|
319
326
|
}).prefault({});
|
|
327
|
+
var RunSchema = z4.object({
|
|
328
|
+
autoImpact: z4.object({
|
|
329
|
+
enabled: z4.boolean().default(true),
|
|
330
|
+
threshold: z4.number().nonnegative().default(6)
|
|
331
|
+
}).prefault({})
|
|
332
|
+
}).prefault({});
|
|
320
333
|
var XeraConfigSchema = z4.object({
|
|
321
334
|
jira: JiraSchema,
|
|
322
335
|
web: WebSchema,
|
|
323
336
|
ai: AISchema,
|
|
324
337
|
reporting: ReportingSchema,
|
|
338
|
+
run: RunSchema.prefault({}),
|
|
325
339
|
adapters: z4.array(z4.string().min(1)).min(1).default(["web"])
|
|
326
340
|
});
|
|
327
341
|
|
package/package.json
CHANGED
package/src/artifact/status.ts
CHANGED
|
@@ -2,7 +2,14 @@ import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
|
|
|
2
2
|
import { dirname } from 'node:path';
|
|
3
3
|
import { z } from 'zod';
|
|
4
4
|
|
|
5
|
-
const ClassificationEnum = z.enum([
|
|
5
|
+
const ClassificationEnum = z.enum([
|
|
6
|
+
'PASS',
|
|
7
|
+
'REAL_BUG',
|
|
8
|
+
'SELECTOR_DRIFT',
|
|
9
|
+
'FLAKY',
|
|
10
|
+
'TEST_BUG',
|
|
11
|
+
'TEST_OUTDATED',
|
|
12
|
+
]);
|
|
6
13
|
const ResultEnum = z.enum(['PASS', 'FAIL']);
|
|
7
14
|
const ConfidenceEnum = z.enum(['low', 'medium', 'high']);
|
|
8
15
|
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { enrichTicket } from '../graph/enrich';
|
|
2
|
+
|
|
3
|
+
export async function graphEnrichCmd(argv: string[]): Promise<number> {
|
|
4
|
+
let ticket: string | undefined;
|
|
5
|
+
let force = false;
|
|
6
|
+
for (let i = 0; i < argv.length; i++) {
|
|
7
|
+
if (argv[i] === '--ticket') ticket = argv[++i];
|
|
8
|
+
else if (argv[i] === '--force') force = true;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
const repoRoot = process.cwd();
|
|
12
|
+
|
|
13
|
+
if (!ticket) {
|
|
14
|
+
console.error('[graph-enrich] usage: graph-enrich --ticket <id> [--force]');
|
|
15
|
+
return 1;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
try {
|
|
19
|
+
const result = await enrichTicket(repoRoot, ticket, { force });
|
|
20
|
+
console.log(
|
|
21
|
+
`[graph-enrich] ${ticket} enriched (${result.similarCount} similar edges, at ${result.enrichedAt})`,
|
|
22
|
+
);
|
|
23
|
+
return 0;
|
|
24
|
+
} catch (e) {
|
|
25
|
+
console.error(`[graph-enrich] ${ticket} failed: ${(e as Error).message}`);
|
|
26
|
+
return 1;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
@@ -4,6 +4,8 @@ import { basename, join } from 'node:path';
|
|
|
4
4
|
import { parse as parseYaml } from 'yaml';
|
|
5
5
|
import { appendEvents } from '../graph/store';
|
|
6
6
|
import type {
|
|
7
|
+
Classification,
|
|
8
|
+
ClassificationDisputedPayload,
|
|
7
9
|
EdgeDiscoveredPayload,
|
|
8
10
|
Event,
|
|
9
11
|
PomPromotedPayload,
|
|
@@ -192,7 +194,9 @@ function parseFlags(args: string[]): Map<string, string> {
|
|
|
192
194
|
export async function graphRecordCmd(argv: string[]): Promise<number> {
|
|
193
195
|
const [action, ...rest] = argv;
|
|
194
196
|
if (!action) {
|
|
195
|
-
console.error(
|
|
197
|
+
console.error(
|
|
198
|
+
`Usage: xera-internal graph-record <fetch|script|exec|classify|promote|dispute> [args]`,
|
|
199
|
+
);
|
|
196
200
|
return 1;
|
|
197
201
|
}
|
|
198
202
|
const repoRoot = process.cwd();
|
|
@@ -236,6 +240,46 @@ export async function graphRecordCmd(argv: string[]): Promise<number> {
|
|
|
236
240
|
case 'promote': {
|
|
237
241
|
return recordPromote(repoRoot, parseFlags(rest));
|
|
238
242
|
}
|
|
243
|
+
case 'dispute': {
|
|
244
|
+
const flags = parseFlags(rest);
|
|
245
|
+
const runId = flags.get('--run-id');
|
|
246
|
+
const scenarioIdArg = flags.get('--scenario-id');
|
|
247
|
+
const from = flags.get('--from');
|
|
248
|
+
const to = flags.get('--to');
|
|
249
|
+
const actor = flags.get('--actor');
|
|
250
|
+
const reason = flags.get('--reason');
|
|
251
|
+
if (!runId || !scenarioIdArg || !from || !to || !actor) {
|
|
252
|
+
console.error(
|
|
253
|
+
'[graph-record dispute] required: --run-id --scenario-id --from --to --actor [--reason]',
|
|
254
|
+
);
|
|
255
|
+
return 1;
|
|
256
|
+
}
|
|
257
|
+
const validClass = [
|
|
258
|
+
'REAL_BUG',
|
|
259
|
+
'TEST_BUG',
|
|
260
|
+
'SELECTOR_DRIFT',
|
|
261
|
+
'FLAKY',
|
|
262
|
+
'PASS',
|
|
263
|
+
'TEST_OUTDATED',
|
|
264
|
+
];
|
|
265
|
+
if (!validClass.includes(from) || !validClass.includes(to)) {
|
|
266
|
+
console.error(
|
|
267
|
+
`[graph-record dispute] --from and --to must be one of: ${validClass.join(', ')}`,
|
|
268
|
+
);
|
|
269
|
+
return 1;
|
|
270
|
+
}
|
|
271
|
+
const payload: ClassificationDisputedPayload = {
|
|
272
|
+
runId,
|
|
273
|
+
scenarioId: scenarioIdArg,
|
|
274
|
+
originalClassification: from as Classification,
|
|
275
|
+
disputedTo: to as Classification,
|
|
276
|
+
qaActor: actor,
|
|
277
|
+
};
|
|
278
|
+
if (reason) payload.qaReason = reason;
|
|
279
|
+
const e = makeEvent('xera-report', 'classification.disputed', payload);
|
|
280
|
+
appendEvents(repoRoot, [e], { skill: 'xera-report', ticketId: scenarioIdArg.slice(0, 12) });
|
|
281
|
+
return 0;
|
|
282
|
+
}
|
|
239
283
|
default:
|
|
240
284
|
console.error(`Unknown action: ${action}`);
|
|
241
285
|
return 1;
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { mkdirSync, writeFileSync } from 'node:fs';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
import type { ImpactOpts, ImpactReport } from '../graph/impact';
|
|
4
|
+
import { renderImpactMarkdown, walkImpact } from '../graph/impact';
|
|
5
|
+
import { deriveSnapshot, loadAllEvents } from '../graph/store';
|
|
6
|
+
import type { Priority } from '../graph/types';
|
|
7
|
+
|
|
8
|
+
function parseDepth(s: string | undefined): 1 | 2 | 3 {
|
|
9
|
+
const n = s ? Number.parseInt(s, 10) : 2;
|
|
10
|
+
if (n === 1 || n === 3) return n;
|
|
11
|
+
return 2;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function parseMinPriority(s: string | undefined): Priority | undefined {
|
|
15
|
+
if (s === 'p0' || s === 'p1' || s === 'p2') return s;
|
|
16
|
+
return undefined;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export async function impactPrepareCmd(argv: string[]): Promise<number> {
|
|
20
|
+
const ticket = argv[0];
|
|
21
|
+
if (!ticket || ticket.startsWith('--')) {
|
|
22
|
+
console.error(
|
|
23
|
+
'[impact-prepare] usage: impact-prepare <TICKET> [--depth 1|2|3] [--min-priority p0|p1|p2] [--quiet]',
|
|
24
|
+
);
|
|
25
|
+
return 1;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
let depth: 1 | 2 | 3 = 2;
|
|
29
|
+
let minPriority: Priority | undefined;
|
|
30
|
+
let quiet = false;
|
|
31
|
+
for (let i = 1; i < argv.length; i++) {
|
|
32
|
+
if (argv[i] === '--depth') depth = parseDepth(argv[++i]);
|
|
33
|
+
else if (argv[i] === '--min-priority') minPriority = parseMinPriority(argv[++i]);
|
|
34
|
+
else if (argv[i] === '--quiet') quiet = true;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const repoRoot = process.cwd();
|
|
38
|
+
const graph = deriveSnapshot(loadAllEvents(repoRoot));
|
|
39
|
+
const target = graph.tickets[ticket];
|
|
40
|
+
if (!target) {
|
|
41
|
+
console.error(`[impact-prepare] ticket ${ticket} not in graph; run /xera-fetch first`);
|
|
42
|
+
return 2;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const opts: ImpactOpts = { depth };
|
|
46
|
+
if (minPriority) opts.minPriority = minPriority;
|
|
47
|
+
|
|
48
|
+
const scenarios = walkImpact(graph, target, opts);
|
|
49
|
+
|
|
50
|
+
const report: ImpactReport = {
|
|
51
|
+
targetTicket: ticket,
|
|
52
|
+
modifiedAreas: target.modifiesAreas,
|
|
53
|
+
scenarios,
|
|
54
|
+
generatedAt: new Date().toISOString(),
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
const impactDir = join(repoRoot, '.xera/impact');
|
|
58
|
+
mkdirSync(impactDir, { recursive: true });
|
|
59
|
+
writeFileSync(join(impactDir, `${ticket}.json`), JSON.stringify(report, null, 2));
|
|
60
|
+
if (!quiet) {
|
|
61
|
+
writeFileSync(join(impactDir, `${ticket}.md`), renderImpactMarkdown(report));
|
|
62
|
+
}
|
|
63
|
+
return 0;
|
|
64
|
+
}
|
|
@@ -5,10 +5,12 @@ import { evalReportCmd } from './eval-report';
|
|
|
5
5
|
import { execCmd } from './exec';
|
|
6
6
|
import { fetchCmd } from './fetch';
|
|
7
7
|
import { graphBackfillCmd } from './graph-backfill';
|
|
8
|
+
import { graphEnrichCmd } from './graph-enrich';
|
|
8
9
|
import { graphQueryCmd } from './graph-query';
|
|
9
10
|
import { graphRecordCmd } from './graph-record';
|
|
10
11
|
import { graphSnapshotCmd } from './graph-snapshot';
|
|
11
12
|
import { healPrepareCmd } from './heal-prepare';
|
|
13
|
+
import { impactPrepareCmd } from './impact-prepare';
|
|
12
14
|
import { lintCmd } from './lint';
|
|
13
15
|
import { normalizeCmd } from './normalize';
|
|
14
16
|
import { postCmd } from './post';
|
|
@@ -28,10 +30,12 @@ const COMMANDS: Record<string, (argv: string[]) => Promise<number>> = {
|
|
|
28
30
|
exec: execCmd,
|
|
29
31
|
fetch: fetchCmd,
|
|
30
32
|
'graph-backfill': graphBackfillCmd,
|
|
33
|
+
'graph-enrich': graphEnrichCmd,
|
|
31
34
|
'graph-query': graphQueryCmd,
|
|
32
35
|
'graph-record': graphRecordCmd,
|
|
33
36
|
'graph-snapshot': graphSnapshotCmd,
|
|
34
37
|
'heal-prepare': healPrepareCmd,
|
|
38
|
+
'impact-prepare': impactPrepareCmd,
|
|
35
39
|
lint: lintCmd,
|
|
36
40
|
normalize: normalizeCmd,
|
|
37
41
|
post: postCmd,
|
|
@@ -1,8 +1,11 @@
|
|
|
1
|
-
import { readFileSync, writeFileSync } from 'node:fs';
|
|
1
|
+
import { existsSync, readFileSync, writeFileSync } from 'node:fs';
|
|
2
2
|
import { join } from 'node:path';
|
|
3
3
|
import { resolveArtifactPaths } from '../artifact/paths';
|
|
4
4
|
import { aggregateScenarios } from '../classifier/aggregate';
|
|
5
5
|
import type { ScenarioClassification } from '../classifier/types';
|
|
6
|
+
import type { OutdatedDecision } from '../graph/classify';
|
|
7
|
+
import { enhanceClassification } from '../graph/classify';
|
|
8
|
+
import { deriveSnapshot, loadAllEvents } from '../graph/store';
|
|
6
9
|
import { buildJiraComment } from '../reporter/jira-comment';
|
|
7
10
|
import { writeStatusFromClassification } from '../reporter/status-writer';
|
|
8
11
|
|
|
@@ -23,20 +26,75 @@ export async function reportCmd(argv: string[]): Promise<number> {
|
|
|
23
26
|
const input = JSON.parse(readFileSync(inputArg.slice('--input='.length), 'utf8')) as ReportInput;
|
|
24
27
|
|
|
25
28
|
const aggregated = aggregateScenarios(input.scenarios);
|
|
29
|
+
|
|
30
|
+
// v0.6.1: TEST_OUTDATED enhancement.
|
|
31
|
+
// The /xera-report skill writes outdated-decisions.json BEFORE invoking this subcommand,
|
|
32
|
+
// containing { [scenarioId]: { classification, confidence, evidence } } for every
|
|
33
|
+
// failing scenario the skill ran the LLM on. We use those decisions directly via
|
|
34
|
+
// an injected resolver — no Claude call here.
|
|
35
|
+
const decisionsPath = join(paths.ticketDir, 'runs', input.runId, 'outdated-decisions.json');
|
|
36
|
+
const decisions: Record<string, OutdatedDecision> = existsSync(decisionsPath)
|
|
37
|
+
? (JSON.parse(readFileSync(decisionsPath, 'utf8')) as Record<string, OutdatedDecision>)
|
|
38
|
+
: {};
|
|
39
|
+
|
|
40
|
+
const graph = deriveSnapshot(loadAllEvents(process.cwd()));
|
|
41
|
+
|
|
42
|
+
// Build a lookup: normalized name → scenarioId (graph node id) for this ticket.
|
|
43
|
+
// This mirrors how graph-record-script.ts stores scenarios using sha1(ticket:name),
|
|
44
|
+
// but here we look up by the stored node id so both sha1-keyed and stub-keyed graphs work.
|
|
45
|
+
const normalizeScenarioName = (name: string) => name.trim().toLowerCase().replace(/\s+/g, ' ');
|
|
46
|
+
|
|
47
|
+
const scenarioIdByName: Record<string, string> = {};
|
|
48
|
+
for (const [id, node] of Object.entries(graph.scenarios)) {
|
|
49
|
+
if (node.ticketId === ticket) {
|
|
50
|
+
scenarioIdByName[normalizeScenarioName(node.name)] = id;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const enhancedScenarios: ScenarioClassification[] = await Promise.all(
|
|
55
|
+
aggregated.scenarios.map(async (s) => {
|
|
56
|
+
if (s.outcome !== 'FAIL') return s;
|
|
57
|
+
const scenarioId = scenarioIdByName[normalizeScenarioName(s.name)];
|
|
58
|
+
if (!scenarioId) return s;
|
|
59
|
+
const decision = decisions[scenarioId];
|
|
60
|
+
const decideOutdated = async (): Promise<OutdatedDecision> =>
|
|
61
|
+
decision ?? {
|
|
62
|
+
classification: 'BUG' as const,
|
|
63
|
+
confidence: 0,
|
|
64
|
+
evidence: { reasoning: 'no LLM decision' },
|
|
65
|
+
};
|
|
66
|
+
const enhanced = await enhanceClassification(
|
|
67
|
+
{ scenarioId, traceClassification: s.class },
|
|
68
|
+
graph,
|
|
69
|
+
decideOutdated,
|
|
70
|
+
);
|
|
71
|
+
if (enhanced.classification !== s.class) {
|
|
72
|
+
return {
|
|
73
|
+
...s,
|
|
74
|
+
class: enhanced.classification,
|
|
75
|
+
rationale: `${s.rationale} | TEST_OUTDATED override (conf ${enhanced.confidence})`,
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
return s;
|
|
79
|
+
}),
|
|
80
|
+
);
|
|
81
|
+
|
|
82
|
+
const reAggregated = aggregateScenarios(enhancedScenarios);
|
|
83
|
+
|
|
26
84
|
const ts = new Date().toISOString();
|
|
27
85
|
writeStatusFromClassification(paths.statusPath, {
|
|
28
86
|
ticket,
|
|
29
87
|
runTs: ts,
|
|
30
|
-
classification:
|
|
88
|
+
classification: reAggregated,
|
|
31
89
|
scenarioCounts: input.scenarioCounts,
|
|
32
90
|
});
|
|
33
91
|
|
|
34
92
|
const md = buildJiraComment({
|
|
35
93
|
ticket,
|
|
36
94
|
runId: input.runId,
|
|
37
|
-
overall:
|
|
38
|
-
overallConfidence:
|
|
39
|
-
scenarios:
|
|
95
|
+
overall: reAggregated.overall,
|
|
96
|
+
overallConfidence: reAggregated.overallConfidence,
|
|
97
|
+
scenarios: reAggregated.scenarios,
|
|
40
98
|
xeraVersion: '0.1.0',
|
|
41
99
|
promptsVersion: '1.0.0',
|
|
42
100
|
});
|
package/src/config/schema.ts
CHANGED
|
@@ -69,11 +69,23 @@ const ReportingSchema = z
|
|
|
69
69
|
})
|
|
70
70
|
.prefault({});
|
|
71
71
|
|
|
72
|
+
const RunSchema = z
|
|
73
|
+
.object({
|
|
74
|
+
autoImpact: z
|
|
75
|
+
.object({
|
|
76
|
+
enabled: z.boolean().default(true),
|
|
77
|
+
threshold: z.number().nonnegative().default(6.0),
|
|
78
|
+
})
|
|
79
|
+
.prefault({}),
|
|
80
|
+
})
|
|
81
|
+
.prefault({});
|
|
82
|
+
|
|
72
83
|
export const XeraConfigSchema = z.object({
|
|
73
84
|
jira: JiraSchema,
|
|
74
85
|
web: WebSchema,
|
|
75
86
|
ai: AISchema,
|
|
76
87
|
reporting: ReportingSchema,
|
|
88
|
+
run: RunSchema.prefault({}),
|
|
77
89
|
adapters: z.array(z.string().min(1)).min(1).default(['web']),
|
|
78
90
|
});
|
|
79
91
|
|