Setting the file. One moment.
Merge Signals · Vercel Optimize · vercel-labs/agent-skills · Skills Docs
ContentsBack to the top of the page function formatRouteSignal
— line 130
This file
Number 7.70
Position 70 of 155
Type JavaScript
Size 6 KB
Lines 192 scripts/ merge-signals.mjs
JavaScript · 192 lines · 6 KB
{ routePathMatchScore }
from
'../lib/investigation-brief.mjs'
;
11 import { canonicalizeRoute } from '../lib/route-normalize.mjs' ;
12
13 const log = ( ... args ) => console. error ( '[merge-signals]' , ... args);
14
15 async function main () {
16 const args = parseArgs (process.argv. slice ( 2 ));
17 if ( ! args.signalsPath || ! args.codebasePath) {
18 console. error ( 'usage: node scripts/merge-signals.mjs <signals.json> <codebase.json> [--out merged.json] [--force]' );
19 process. exit ( 1 );
20 }
21
22 const [ signals , codebase ] = await Promise . all ([
23 readJson (args.signalsPath, 'signals' ),
24 readJson (args.codebasePath, 'codebase scan' ),
25 ]);
26
27 const merged = mergeSignals (signals, codebase);
28 const body = JSON . stringify (merged, null , 2 ) + ' \n ' ;
29 if (args.outPath) {
30 await writeOutput (args.outPath, body, { force: args.force });
31 log ( `wrote ${ args . outPath }` );
32 } else {
33 process.stdout. write (body);
34 }
35 }
36
37 export function mergeSignals ( signals , codebase ) {
38 assertObject (signals, 'signals' );
39 assertObject (codebase, 'codebase scan' );
40
41 if ( ! signals.schemaVersion) {
42 throw new Error ( 'signals.json is missing schemaVersion; pass collect-signals output as the first file.' );
43 }
44 if ( ! Array. isArray (codebase.routes) || ! Array. isArray (codebase.findings) || ! codebase.stack) {
45 throw new Error ( 'codebase.json must be scan-codebase output with stack, routes[], and findings[].' );
46 }
47
48 return {
49 ... signals,
50 codebase: annotateCodebaseScan (signals, codebase),
51 };
52 }
53
54 export function annotateCodebaseScan ( signals , codebase ) {
55 const index = buildRouteMetricIndex (signals);
56 return {
57 ... codebase,
58 findings: (codebase.findings ?? []). map (( finding ) => annotateFinding (finding, index)),
59 };
60 }
61
62 function annotateFinding ( finding , index ) {
63 if ( ! finding || typeof finding !== 'object' ) return finding;
64 if (finding.trafficIndependent) return finding;
65 if ( ! finding.route) return { ... finding, o11ySignal: 'NO-ROUTE-MAPPING' };
66
67 const summary = bestRouteSummary (finding.route, index);
68 if ( ! summary || ! hasTraffic (summary)) return { ... finding, o11ySignal: 'COLD-PATH' };
69 return { ... finding, o11ySignal: formatRouteSignal (summary) };
70 }
71
72 function buildRouteMetricIndex ( signals ) {
73 const out = new Map ();
74 const ensure = ( route ) => {
75 const canonical = canonicalizeRoute (route);
76 const existing = out. get (canonical) ?? { route: canonical };
77 out. set (canonical, existing);
78 return existing;
79 };
80
81 for ( const row of rows (signals, 'fnStatusByRoute' )) {
82 if ( ! row.route) continue ;
83 const summary = ensure (row.route);
84 summary.functionRuns = (summary.functionRuns ?? 0 ) + numeric (row.value);
85 }
86 for ( const row of rows (signals, 'fnDurationP95ByRoute' )) {
87 if ( ! row.route) continue ;
88 ensure (row.route).p95Ms = numeric (row.value);
89 }
90 for ( const row of rows (signals, 'requestsByRouteCache' )) {
91 if ( ! row.route) continue ;
92 const summary = ensure (row.route);
93 const count = numeric (row.value);
94 summary.requests = (summary.requests ?? 0 ) + count;
95 if ( String (row.cache_result). toUpperCase () === 'HIT' ) {
96 summary.cacheHits = (summary.cacheHits ?? 0 ) + count;
97 }
98 }
99 return out;
100 }
101
102 function rows ( signals , metricId ) {
103 const rows = signals?.metrics?.[metricId]?.rows;
104 return Array. isArray (rows) ? rows : [];
105 }
106
107 function numeric ( value ) {
108 const n = Number (value);
109 return Number. isFinite (n) ? n : 0 ;
110 }
111
112 function bestRouteSummary ( route , index ) {
113 const canonical = canonicalizeRoute (route);
114 const exact = index. get (canonical);
115 if (exact) return exact;
116
117 let best = null ;
118 for ( const summary of index. values ()) {
119 const score = routePathMatchScore (canonical, summary.route);
120 if (score <= 0 ) continue ;
121 if ( ! best || score > best.score) best = { score, summary };
122 }
123 return best?.summary ?? null ;
124 }
125
126 function hasTraffic ( summary ) {
127 return (summary.functionRuns ?? 0 ) > 0 || (summary.requests ?? 0 ) > 0 ;
128 }
129
130 function formatRouteSignal ( summary ) {
131 const parts = [];
132 if ((summary.functionRuns ?? 0 ) > 0 ) parts. push ( `inv=${ Math . round ( summary . functionRuns ) }` );
133 else if ((summary.requests ?? 0 ) > 0 ) parts. push ( `requests=${ Math . round ( summary . requests ) }` );
134 if ((summary.p95Ms ?? 0 ) > 0 ) parts. push ( `p95=${ Math . round ( summary . p95Ms ) }ms` );
135 if ((summary.requests ?? 0 ) > 0 && summary.cacheHits != null ) {
136 const hitRate = Math. round ((summary.cacheHits / summary.requests) * 100 );
137 parts. push ( `cache=${ hitRate }%` );
138 }
139 return parts. join ( ',' ) || 'COLD-PATH' ;
140 }
141
142 function parseArgs ( argv ) {
143 const out = { positional: [], force: false };
144 for ( let i = 0 ; i < argv. length ; i ++ ) {
145 const a = argv[i];
146 if (a === '--out' ) out.outPath = argv[ ++ i];
147 else if (a. startsWith ( '--out=' )) out.outPath = a. slice ( '--out=' . length );
148 else if (a === '--force' ) out.force = true ;
149 else out.positional. push (a);
150 }
151 out.signalsPath = out.positional[ 0 ];
152 out.codebasePath = out.positional[ 1 ];
153 return out;
154 }
155
156 async function readJson ( path , label ) {
157 try {
158 return JSON . parse ( await readFile (path, 'utf-8' ));
159 } catch (err) {
160 throw new Error ( `Could not read ${ label } JSON at ${ path }: ${ err . message }` );
161 }
162 }
163
164 function assertObject ( value , label ) {
165 if ( ! value || typeof value !== 'object' || Array. isArray (value)) {
166 throw new Error ( `${ label } must be a JSON object.` );
167 }
168 }
169
170 async function writeOutput ( path , body , { force }) {
171 if ( ! force && await exists (path)) {
172 throw new Error ( `output file already exists: ${ path }. Use a fresh run directory or pass --force to overwrite.` );
173 }
174 await mkdir ( dirname (path), { recursive: true });
175 await writeFile (path, body);
176 }
177
178 async function exists ( path ) {
179 try {
180 await access (path);
181 return true ;
182 } catch {
183 return false ;
184 }
185 }
186
187 if (process.argv[ 1 ] && realpathSync (process.argv[ 1 ]) === realpathSync ( fileURLToPath ( import . meta .url))) {
188 main (). catch (( err ) => {
189 console. error ( '[merge-signals] FAILED:' , err.message);
190 process. exit ( 1 );
191 });
192 }