@jphutchins/code-review 0.1.0-alpha.57 → 0.1.0-alpha.59

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/index.js CHANGED
@@ -63,7 +63,9 @@ var Confidence = t.refinement(t.number, (n) => n >= 0 && n <= 1, "Confidence");
63
63
  var Likelihood = t.refinement(t.number, (n) => n >= 0 && n <= 1, "Likelihood");
64
64
  var FiniteNumber = t.refinement(t.number, (n) => Number.isFinite(n), "FiniteNumber");
65
65
  var NonNegativePrice = t.refinement(t.number, (n) => n >= 0, "NonNegativePrice");
66
- var SCHEMA_VERSION_RE = /^(0|[1-9]\d*)\.(\d+)\.(\d+)(?:-[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?(?:\+[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?$/;
66
+ var SEMVER_SUFFIX = "(?:-[0-9A-Za-z-]+(?:\\.[0-9A-Za-z-]+)*)?(?:\\+[0-9A-Za-z-]+(?:\\.[0-9A-Za-z-]+)*)?";
67
+ var SCHEMA_VERSION_RE = new RegExp(`^(0|[1-9]\\d*)\\.(\\d+)\\.(\\d+)${SEMVER_SUFFIX}$`);
68
+ var anchoredSchemaVersionPattern = (version) => `^${version.split(".").slice(0, 2).join("\\.")}\\.[0-9]+${SEMVER_SUFFIX}$`;
67
69
  var SchemaVersion = t.refinement(
68
70
  t.string,
69
71
  (s) => SCHEMA_VERSION_RE.test(s),
@@ -74,11 +76,16 @@ var UriString = t.refinement(
74
76
  (s) => !/\s/.test(s) && URL.canParse(s),
75
77
  "UriString"
76
78
  );
79
+ var strictExact = (name, shape, members) => {
80
+ const keys = new Set(members.flatMap((m) => Object.keys(m.props)));
81
+ return t.exact(
82
+ t.refinement(shape, (x) => Object.keys(x).every((k) => keys.has(k)), name)
83
+ );
84
+ };
77
85
  var RuleUrlCodec = t.partial({
78
86
  code_url: UriString
79
87
  });
80
- var FindingRequired = t.type({
81
- id: t.string,
88
+ var FindingCoreRequired = t.type({
82
89
  path: t.string,
83
90
  start_line: LineNumber,
84
91
  end_line: LineNumber,
@@ -89,28 +96,25 @@ var FindingRequired = t.type({
89
96
  confidence: Confidence,
90
97
  likelihood: Likelihood
91
98
  });
99
+ var FindingIdRequired = t.type({ id: t.string });
92
100
  var FindingOptional = t.partial({
93
101
  side: SideCodec,
94
102
  recommendation: t.string,
95
103
  patch: t.string
96
104
  });
97
- var FindingShape = t.intersection([FindingRequired, RuleUrlCodec, FindingOptional]);
98
- var EndGeStart = t.refinement(
99
- FindingShape,
100
- (f) => f.end_line >= f.start_line,
101
- "EndGeStart"
102
- );
103
- var FINDING_KEYS = /* @__PURE__ */ new Set([
104
- ...Object.keys(FindingRequired.props),
105
- ...Object.keys(RuleUrlCodec.props),
106
- ...Object.keys(FindingOptional.props)
105
+ var EndGeStart = (shape) => t.refinement(shape, (f) => f.end_line >= f.start_line, "EndGeStart");
106
+ var FindingShape = t.intersection([
107
+ FindingCoreRequired,
108
+ FindingIdRequired,
109
+ RuleUrlCodec,
110
+ FindingOptional
111
+ ]);
112
+ var FindingCodec = strictExact("FindingStrict", EndGeStart(FindingShape), [
113
+ FindingCoreRequired,
114
+ FindingIdRequired,
115
+ RuleUrlCodec,
116
+ FindingOptional
107
117
  ]);
108
- var FindingStrict = t.refinement(
109
- EndGeStart,
110
- (f) => Object.keys(f).every((k) => FINDING_KEYS.has(k)),
111
- "FindingStrict"
112
- );
113
- var FindingCodec = t.exact(FindingStrict);
114
118
  var SystemicRequired = t.type({
115
119
  title: t.string,
116
120
  description: t.string,
@@ -125,47 +129,34 @@ var SystemicOptional = t.partial({
125
129
  paths: t.array(t.string)
126
130
  });
127
131
  var SystemicProblemShape = t.intersection([SystemicRequired, RuleUrlCodec, SystemicOptional]);
128
- var SYSTEMIC_KEYS = /* @__PURE__ */ new Set([
129
- ...Object.keys(SystemicRequired.props),
130
- ...Object.keys(RuleUrlCodec.props),
131
- ...Object.keys(SystemicOptional.props)
132
+ var SystemicProblemCodec = strictExact("SystemicProblemStrict", SystemicProblemShape, [
133
+ SystemicRequired,
134
+ RuleUrlCodec,
135
+ SystemicOptional
132
136
  ]);
133
- var SystemicProblemStrict = t.refinement(
134
- SystemicProblemShape,
135
- (s) => Object.keys(s).every((k) => SYSTEMIC_KEYS.has(k)),
136
- "SystemicProblemStrict"
137
+ var ConsecutiveRounds = t.refinement(
138
+ t.number,
139
+ (n) => Number.isSafeInteger(n) && n >= 1,
140
+ "ConsecutiveRounds"
141
+ );
142
+ var StartRound = t.refinement(
143
+ t.number,
144
+ (n) => Number.isSafeInteger(n) && n >= 1,
145
+ "StartRound"
137
146
  );
138
- var SystemicProblemCodec = t.exact(SystemicProblemStrict);
139
147
  var RecurringShape = t.type({
140
148
  id: t.string,
141
- consecutive_rounds: t.refinement(
142
- t.number,
143
- (n) => Number.isSafeInteger(n) && n >= 1,
144
- "ConsecutiveRounds"
145
- ),
146
- start_round: t.refinement(
147
- t.number,
148
- (n) => Number.isSafeInteger(n) && n >= 1,
149
- "StartRound"
150
- )
149
+ consecutive_rounds: ConsecutiveRounds,
150
+ start_round: StartRound
151
151
  });
152
- var RECURRING_KEYS = new Set(Object.keys(RecurringShape.props));
153
- var RecurringCodec = t.refinement(
154
- RecurringShape,
155
- (r) => Object.keys(r).every((k) => RECURRING_KEYS.has(k)),
156
- "RecurringStrict"
157
- );
152
+ var RecurringCodec = strictExact("RecurringStrict", RecurringShape, [RecurringShape]);
158
153
  var ScopeMetastasisShape = t.type({
159
154
  decision_prompt: t.string,
160
155
  recurring: t.array(RecurringCodec)
161
156
  });
162
- var SCOPE_METASTASIS_KEYS = new Set(Object.keys(ScopeMetastasisShape.props));
163
- var ScopeMetastasisStrict = t.refinement(
164
- ScopeMetastasisShape,
165
- (s) => Object.keys(s).every((k) => SCOPE_METASTASIS_KEYS.has(k)),
166
- "ScopeMetastasisStrict"
167
- );
168
- var ScopeMetastasisCodec = t.exact(ScopeMetastasisStrict);
157
+ var ScopeMetastasisCodec = strictExact("ScopeMetastasisStrict", ScopeMetastasisShape, [
158
+ ScopeMetastasisShape
159
+ ]);
169
160
  var RoundNumber = t.refinement(
170
161
  t.number,
171
162
  (n) => Number.isSafeInteger(n) && n >= 1,
@@ -179,6 +170,7 @@ var idFrequencyCodec = (name) => new t.Type(
179
170
  const entries = [];
180
171
  for (const [k, v] of Object.entries(u)) {
181
172
  if (typeof v !== "number" || !Number.isSafeInteger(v) || v < 0) return t.failure(v, c);
173
+ if (v === 0) continue;
182
174
  entries.push([k, v]);
183
175
  }
184
176
  return t.success(Object.fromEntries(entries));
@@ -193,16 +185,10 @@ var ConvergenceRoundOptional = t.partial({
193
185
  sha: t.string
194
186
  });
195
187
  var ConvergenceRoundShape = t.intersection([ConvergenceRoundRequired, ConvergenceRoundOptional]);
196
- var CONVERGENCE_ROUND_KEYS = /* @__PURE__ */ new Set([
197
- ...Object.keys(ConvergenceRoundRequired.props),
198
- ...Object.keys(ConvergenceRoundOptional.props)
188
+ var ConvergenceRoundCodec = strictExact("ConvergenceRoundStrict", ConvergenceRoundShape, [
189
+ ConvergenceRoundRequired,
190
+ ConvergenceRoundOptional
199
191
  ]);
200
- var ConvergenceRoundStrict = t.refinement(
201
- ConvergenceRoundShape,
202
- (r) => Object.keys(r).every((k) => CONVERGENCE_ROUND_KEYS.has(k)),
203
- "ConvergenceRoundStrict"
204
- );
205
- var ConvergenceRoundCodec = t.exact(ConvergenceRoundStrict);
206
192
  var ConvergenceCoreShape = t.type({
207
193
  score: FiniteNumber,
208
194
  threshold: FiniteNumber,
@@ -210,16 +196,10 @@ var ConvergenceCoreShape = t.type({
210
196
  });
211
197
  var ConvergenceOptional = t.partial({ rounds: t.array(ConvergenceRoundCodec) });
212
198
  var ConvergenceShape = t.intersection([ConvergenceCoreShape, ConvergenceOptional]);
213
- var CONVERGENCE_KEYS = /* @__PURE__ */ new Set([
214
- ...Object.keys(ConvergenceCoreShape.props),
215
- ...Object.keys(ConvergenceOptional.props)
199
+ var ConvergenceCodec = strictExact("ConvergenceStrict", ConvergenceShape, [
200
+ ConvergenceCoreShape,
201
+ ConvergenceOptional
216
202
  ]);
217
- var ConvergenceStrict = t.refinement(
218
- ConvergenceShape,
219
- (c) => Object.keys(c).every((k) => CONVERGENCE_KEYS.has(k)),
220
- "ConvergenceStrict"
221
- );
222
- var ConvergenceCodec = t.exact(ConvergenceStrict);
223
203
  var LineDelta = t.refinement(
224
204
  t.number,
225
205
  (n) => Number.isInteger(n) && n >= 0,
@@ -269,102 +249,66 @@ var usableCountsMap = (v) => {
269
249
  );
270
250
  return entries.length === 0 ? void 0 : Object.fromEntries(entries);
271
251
  };
252
+ var mergedCountsMaps = (ids, codes) => {
253
+ const idsMap = usableCountsMap(ids);
254
+ const codesMap = usableCountsMap(codes);
255
+ if (idsMap === void 0) return codesMap;
256
+ if (codesMap === void 0) return idsMap;
257
+ return { ...codesMap, ...idsMap };
258
+ };
272
259
  var LegacyRuleCodec = t.partial({
273
260
  code: t.string,
274
261
  id: t.string,
275
262
  code_url: UriString
276
263
  });
277
- var FindingShapeV09 = t.intersection([
278
- t.type({
279
- path: t.string,
280
- start_line: LineNumber,
281
- end_line: LineNumber,
282
- severity: SeverityCodec,
283
- title: t.string,
284
- description: t.string,
285
- reasoning: t.string,
286
- confidence: Confidence,
287
- likelihood: Likelihood
288
- }),
289
- LegacyRuleCodec,
290
- t.partial({
291
- side: SideCodec,
292
- recommendation: t.string,
293
- patch: t.string
294
- })
295
- ]);
296
- var EndGeStartV09 = t.refinement(
297
- FindingShapeV09,
298
- (f) => f.end_line >= f.start_line,
299
- "EndGeStartV09"
300
- );
301
- var FindingCodecV09 = t.exact(EndGeStartV09);
264
+ var FindingShapeV09 = t.intersection([FindingCoreRequired, LegacyRuleCodec, FindingOptional]);
265
+ var FindingCodecV09 = t.exact(EndGeStart(FindingShapeV09));
302
266
  var SystemicV09Optional = t.partial({
303
267
  finding_codes: t.array(t.string),
304
268
  finding_ids: t.array(t.string),
305
269
  paths: t.array(t.string)
306
270
  });
307
271
  var SystemicV09Shape = t.intersection([SystemicRequired, LegacyRuleCodec, SystemicV09Optional]);
308
- var SYSTEMIC_V09_KEYS = /* @__PURE__ */ new Set([
309
- ...Object.keys(SystemicRequired.props),
310
- ...Object.keys(LegacyRuleCodec.props),
311
- ...Object.keys(SystemicV09Optional.props)
312
- ]);
313
- var SystemicV09Strict = t.refinement(
314
- SystemicV09Shape,
315
- (s) => Object.keys(s).every((k) => SYSTEMIC_V09_KEYS.has(k)),
316
- "SystemicV09Strict"
317
- );
318
- var SystemicProblemCodecV09 = t.exact(SystemicV09Strict);
319
- var RecurringV09Shape = t.intersection([
320
- t.partial({ code: t.string, id: t.string }),
321
- t.type({
322
- consecutive_rounds: t.refinement(
323
- t.number,
324
- (n) => Number.isSafeInteger(n) && n >= 1,
325
- "ConsecutiveRoundsV09"
326
- ),
327
- start_round: t.refinement(
328
- t.number,
329
- (n) => Number.isSafeInteger(n) && n >= 1,
330
- "StartRoundV09"
331
- )
332
- })
272
+ var SystemicProblemCodecV09 = strictExact("SystemicV09Strict", SystemicV09Shape, [
273
+ SystemicRequired,
274
+ LegacyRuleCodec,
275
+ SystemicV09Optional
333
276
  ]);
277
+ var RecurringV09Identity = t.partial({ code: t.string, id: t.string });
278
+ var RecurringV09Counts = t.type({
279
+ consecutive_rounds: ConsecutiveRounds,
280
+ start_round: StartRound
281
+ });
282
+ var RecurringV09Shape = t.intersection([RecurringV09Identity, RecurringV09Counts]);
334
283
  var ScopeMetastasisV09Shape = t.type({
335
284
  decision_prompt: t.string,
336
285
  recurring: t.array(RecurringV09Shape)
337
286
  });
338
- var SCOPE_METASTASIS_V09_KEYS = new Set(Object.keys(ScopeMetastasisV09Shape.props));
339
- var ScopeMetastasisV09Strict = t.refinement(
340
- ScopeMetastasisV09Shape,
341
- (s) => Object.keys(s).every((k) => SCOPE_METASTASIS_V09_KEYS.has(k)),
342
- "ScopeMetastasisV09Strict"
343
- );
344
- var ScopeMetastasisCodecV09 = t.exact(ScopeMetastasisV09Strict);
287
+ var ScopeMetastasisCodecV09 = strictExact("ScopeMetastasisV09Strict", ScopeMetastasisV09Shape, [
288
+ ScopeMetastasisV09Shape
289
+ ]);
345
290
  var CodeFrequencyV09 = idFrequencyCodec("CodeFrequencyV09");
291
+ var ConvergenceRoundV09Optional = t.partial({
292
+ score: FiniteNumber,
293
+ codes: CodeFrequencyV09,
294
+ ids: CodeFrequencyV09,
295
+ sha: t.string
296
+ });
346
297
  var ConvergenceRoundV09Shape = t.intersection([
347
- t.type({ round: RoundNumber }),
348
- t.partial({ score: FiniteNumber, codes: CodeFrequencyV09, ids: CodeFrequencyV09, sha: t.string })
298
+ ConvergenceRoundRequired,
299
+ ConvergenceRoundV09Optional
349
300
  ]);
350
- var CONVERGENCE_ROUND_V09_KEYS = /* @__PURE__ */ new Set(["round", "score", "codes", "ids", "sha"]);
351
- var ConvergenceRoundV09Strict = t.refinement(
301
+ var ConvergenceRoundCodecV09 = strictExact(
302
+ "ConvergenceRoundV09Strict",
352
303
  ConvergenceRoundV09Shape,
353
- (r) => Object.keys(r).every((k) => CONVERGENCE_ROUND_V09_KEYS.has(k)),
354
- "ConvergenceRoundV09Strict"
304
+ [ConvergenceRoundRequired, ConvergenceRoundV09Optional]
355
305
  );
356
- var ConvergenceRoundCodecV09 = t.exact(ConvergenceRoundV09Strict);
357
- var ConvergenceV09Shape = t.intersection([
306
+ var ConvergenceV09Optional = t.partial({ rounds: t.array(ConvergenceRoundCodecV09) });
307
+ var ConvergenceV09Shape = t.intersection([ConvergenceCoreShape, ConvergenceV09Optional]);
308
+ var ConvergenceCodecV09 = strictExact("ConvergenceV09Strict", ConvergenceV09Shape, [
358
309
  ConvergenceCoreShape,
359
- t.partial({ rounds: t.array(ConvergenceRoundCodecV09) })
310
+ ConvergenceV09Optional
360
311
  ]);
361
- var CONVERGENCE_V09_KEYS = /* @__PURE__ */ new Set([...Object.keys(ConvergenceCoreShape.props), "rounds"]);
362
- var ConvergenceV09Strict = t.refinement(
363
- ConvergenceV09Shape,
364
- (c) => Object.keys(c).every((k) => CONVERGENCE_V09_KEYS.has(k)),
365
- "ConvergenceV09Strict"
366
- );
367
- var ConvergenceCodecV09 = t.exact(ConvergenceV09Strict);
368
312
  var FindingsV09Shape = t.intersection([
369
313
  t.type({
370
314
  // Any pre-0.10 minor — the registry dispatches on major.minor before decoding, so the codec
@@ -417,7 +361,7 @@ var normalizeV09 = (doc) => {
417
361
  converged: doc.convergence.converged,
418
362
  ...doc.convergence.rounds !== void 0 ? {
419
363
  rounds: doc.convergence.rounds.map((r) => {
420
- const ids = usableCountsMap(r.ids) ?? usableCountsMap(r.codes);
364
+ const ids = mergedCountsMaps(r.ids, r.codes);
421
365
  return {
422
366
  round: r.round,
423
367
  ...r.score !== void 0 ? { score: r.score } : {},
@@ -488,26 +432,17 @@ var FlatModelPricesShape = t.type({
488
432
  cache_read: NonNegativePrice,
489
433
  cache_write: NonNegativePrice
490
434
  });
491
- var FLAT_PRICE_KEYS = new Set(Object.keys(FlatModelPricesShape.props));
492
- var FlatModelPricesStrict = t.refinement(
493
- FlatModelPricesShape,
494
- (p) => Object.keys(p).every((k) => FLAT_PRICE_KEYS.has(k)),
495
- "FlatModelPricesStrict"
496
- );
497
- var FlatModelPricesCodec = t.exact(FlatModelPricesStrict);
435
+ var FlatModelPricesCodec = strictExact("FlatModelPricesStrict", FlatModelPricesShape, [
436
+ FlatModelPricesShape
437
+ ]);
498
438
  var UTC_HHMM_RE = /^([01][0-9]|2[0-3]):[0-5][0-9]$/;
499
439
  var UtcHHMM = t.refinement(t.string, (s) => UTC_HHMM_RE.test(s), "UtcHHMM");
500
- var PriceSlotShape = t.intersection([
501
- t.type({ utc_from: UtcHHMM, utc_to: UtcHHMM }),
440
+ var PriceSlotAnchor = t.type({ utc_from: UtcHHMM, utc_to: UtcHHMM });
441
+ var PriceSlotShape = t.intersection([PriceSlotAnchor, FlatModelPricesShape]);
442
+ var PriceSlotCodec = strictExact("PriceSlotStrict", PriceSlotShape, [
443
+ PriceSlotAnchor,
502
444
  FlatModelPricesShape
503
445
  ]);
504
- var PRICE_SLOT_KEYS = /* @__PURE__ */ new Set(["utc_from", "utc_to", ...Object.keys(FlatModelPricesShape.props)]);
505
- var PriceSlotStrict = t.refinement(
506
- PriceSlotShape,
507
- (s) => Object.keys(s).every((k) => PRICE_SLOT_KEYS.has(k)),
508
- "PriceSlotStrict"
509
- );
510
- var PriceSlotCodec = t.exact(PriceSlotStrict);
511
446
  var NonEmptyPriceSlots = t.refinement(
512
447
  t.array(PriceSlotCodec),
513
448
  (a) => a.length >= 1,
@@ -516,16 +451,10 @@ var NonEmptyPriceSlots = t.refinement(
516
451
  var SlottedRequired = t.type({ slots: NonEmptyPriceSlots });
517
452
  var SlottedOptional = t.partial({ weekend_slots: NonEmptyPriceSlots });
518
453
  var SlottedShape = t.intersection([SlottedRequired, SlottedOptional]);
519
- var SLOTTED_KEYS = /* @__PURE__ */ new Set([
520
- ...Object.keys(SlottedRequired.props),
521
- ...Object.keys(SlottedOptional.props)
454
+ var SlottedModelPricesCodec = strictExact("SlottedModelPricesStrict", SlottedShape, [
455
+ SlottedRequired,
456
+ SlottedOptional
522
457
  ]);
523
- var SlottedModelPricesStrict = t.refinement(
524
- SlottedShape,
525
- (s) => Object.keys(s).every((k) => SLOTTED_KEYS.has(k)),
526
- "SlottedModelPricesStrict"
527
- );
528
- var SlottedModelPricesCodec = t.exact(SlottedModelPricesStrict);
529
458
  var ModelPricesCodec = t.union([FlatModelPricesCodec, SlottedModelPricesCodec]);
530
459
  var PriceMapCodec = t.type({
531
460
  _updated: t.string,
@@ -828,10 +757,13 @@ var isSeverityCounts = (u) => typeof u === "object" && u !== null && SEVERITIES.
828
757
  var MAX_IDS_PER_ROUND = 8;
829
758
  var hasId = (ids, code) => ids !== void 0 && Object.prototype.hasOwnProperty.call(ids, code);
830
759
  var escapeCodeBackticks = (code) => code.replace(/`/g, "-").replace(/\r?\n/g, " ");
831
- var normalizeIdCounts = (ids, priorCodes) => {
832
- const entries = Object.entries(usableCountsMap(ids) ?? {});
760
+ var normalizeIdCounts = (ids, priorCodes, preferredKeys, preValidated = false) => {
761
+ const entries = Object.entries((preValidated ? ids : usableCountsMap(ids)) ?? {});
833
762
  if (entries.length === 0) return void 0;
834
763
  const sorted = entries.sort((a, b) => {
764
+ const aPreferred = preferredKeys?.has(a[0]) === true ? 1 : 0;
765
+ const bPreferred = preferredKeys?.has(b[0]) === true ? 1 : 0;
766
+ if (aPreferred !== bPreferred) return bPreferred - aPreferred;
835
767
  if (b[1] !== a[1]) return b[1] - a[1];
836
768
  const aPrior = hasId(priorCodes, a[0]) ? 1 : 0;
837
769
  const bPrior = hasId(priorCodes, b[0]) ? 1 : 0;
@@ -851,7 +783,12 @@ var parseRounds = (body) => {
851
783
  let priorCodes;
852
784
  for (const u of decoded.filter(isSeverityCounts)) {
853
785
  const rec = u;
854
- const codes = normalizeIdCounts(rec["ids"], priorCodes) ?? normalizeIdCounts(rec["codes"], priorCodes);
786
+ const codes = normalizeIdCounts(
787
+ mergedCountsMaps(rec["ids"], rec["codes"]),
788
+ priorCodes,
789
+ new Set(Object.keys(usableCountsMap(rec["ids"]) ?? {})),
790
+ true
791
+ );
855
792
  priorCodes = codes;
856
793
  const sha = rec["sha"];
857
794
  const shaStr = typeof sha === "string" && sha !== "" ? sha : void 0;
@@ -1084,7 +1021,7 @@ var withLegacyConvergenceIds = (raw) => {
1084
1021
  const mapped = rounds.map((r) => {
1085
1022
  if (typeof r !== "object" || r === null) return r;
1086
1023
  const round = r;
1087
- const ids = usableCountsMap(round["ids"]) ?? usableCountsMap(round["codes"]);
1024
+ const ids = mergedCountsMaps(round["ids"], round["codes"]);
1088
1025
  if (ids === void 0) {
1089
1026
  return round["ids"] !== void 0 || round["codes"] !== void 0 ? Object.fromEntries(Object.entries(round).filter(([k]) => k !== "ids" && k !== "codes")) : round;
1090
1027
  }
@@ -1446,10 +1383,29 @@ var answeredRegistryFrom = (comments, botLogin) => {
1446
1383
  }
1447
1384
  return [...byKey.values()];
1448
1385
  };
1449
- var matches = (f, e) => e.code === resolveFindingId(f) || isSynthesizedFindingId(e.code) && e.title === f.title;
1450
- var isVerbatimReRaise = (f, e) => f.title === e.title && f.description === e.description && f.reasoning === e.reasoning && f.severity === e.severity && f.path === e.path && (f.patch ?? null) === e.patch;
1451
- var isAnsweredDrop = (f, e) => matches(f, e) && isVerbatimReRaise(f, e) && f.severity !== "critical";
1386
+ var isSynthesizedTitleMatch = (f, e) => isSynthesizedFindingId(e.code) && e.title === f.title;
1387
+ var matches = (resolvedId, f, e) => e.code === resolvedId || isSynthesizedTitleMatch(f, e);
1388
+ var VERBATIM_FIELDS = ["title", "description", "reasoning", "severity", "path", "patch"];
1389
+ var verbatimFieldEqual = (f, e, field) => field === "patch" ? (f.patch ?? null) === e.patch : f[field] === e[field];
1390
+ var isVerbatimReRaise = (f, e) => VERBATIM_FIELDS.every((field) => verbatimFieldEqual(f, e, field));
1391
+ var isAnsweredDrop = (resolvedId, f, e) => matches(resolvedId, f, e) && isVerbatimReRaise(f, e) && f.severity !== "critical";
1392
+ var verbatimMatchCount = (f, e) => VERBATIM_FIELDS.reduce((count, field) => count + (verbatimFieldEqual(f, e, field) ? 1 : 0), 0);
1452
1393
  var answeredNoteKey = (f) => f.id !== "" ? f.id : `title:${f.title}`;
1394
+ var NO_TITLE_MATCH = { entry: void 0, score: -1 };
1395
+ var bestTitleMatch = (f, registry) => {
1396
+ let best;
1397
+ let bestScore = -1;
1398
+ for (const e of registry) {
1399
+ if (!isSynthesizedTitleMatch(f, e)) continue;
1400
+ const score = verbatimMatchCount(f, e);
1401
+ if (score > bestScore) {
1402
+ best = e;
1403
+ bestScore = score;
1404
+ if (score === VERBATIM_FIELDS.length) break;
1405
+ }
1406
+ }
1407
+ return { entry: best, score: bestScore };
1408
+ };
1453
1409
  var answeredNote = (e) => `Re-raised; prior answer at ${e.replyUrl} by ${e.replyAuthor} \u2014 cite the new evidence that invalidates it.`;
1454
1410
  var applyAnswered = (findings, registry) => {
1455
1411
  const kept = [];
@@ -1458,14 +1414,18 @@ var applyAnswered = (findings, registry) => {
1458
1414
  const droppedFindingIds = [];
1459
1415
  let droppedCount = 0;
1460
1416
  for (const f of findings) {
1461
- const entry = registry.find((e) => e.code === resolveFindingId(f)) ?? registry.find((e) => isSynthesizedFindingId(e.code) && e.title === f.title);
1417
+ const resolvedId = resolveFindingId(f);
1418
+ const idMatch = registry.find((e) => e.code === resolvedId);
1419
+ const { entry: titleMatch, score: titleScore } = idMatch === void 0 ? bestTitleMatch(f, registry) : NO_TITLE_MATCH;
1420
+ const entry = idMatch ?? titleMatch;
1462
1421
  if (entry === void 0) {
1463
1422
  kept.push(f);
1464
1423
  continue;
1465
1424
  }
1466
- if (isAnsweredDrop(f, entry)) {
1425
+ const dropped = (idMatch !== void 0 ? isVerbatimReRaise(f, entry) : titleScore === VERBATIM_FIELDS.length) && f.severity !== "critical";
1426
+ if (dropped) {
1467
1427
  droppedByEntry.set(entry.replyId, entry);
1468
- droppedFindingIds.push(resolveFindingId(f));
1428
+ droppedFindingIds.push(resolvedId);
1469
1429
  droppedCount += 1;
1470
1430
  } else {
1471
1431
  kept.push(f);
@@ -3179,30 +3139,44 @@ var priorIdsFrom = (doc) => {
3179
3139
  });
3180
3140
  return [...idsOf("findings", false), ...idsOf("systemic_problems", true)];
3181
3141
  };
3142
+ var appendBestEffort = (path, label, body) => {
3143
+ if (path === void 0 || path === "") return;
3144
+ try {
3145
+ appendFileSync(path, body);
3146
+ } catch (err) {
3147
+ process.stderr.write(`Warning: could not write ${label}: ${errMsg(err)}
3148
+ `);
3149
+ }
3150
+ };
3151
+ var writePostedSignal = (value) => {
3152
+ appendBestEffort(
3153
+ process.env["GITHUB_OUTPUT"],
3154
+ "the posted signal to GITHUB_OUTPUT",
3155
+ `posted=${value ? "true" : "false"}
3156
+ `
3157
+ );
3158
+ };
3182
3159
  var appendRunSummary = (summaryPath, body) => {
3183
3160
  if (summaryPath === void 0 || summaryPath === "") return;
3184
3161
  const rendered = body();
3185
- try {
3186
- appendFileSync(summaryPath, `
3162
+ appendBestEffort(summaryPath, "the run summary", `
3187
3163
  ${rendered}
3188
3164
  `);
3189
- } catch (err) {
3190
- process.stderr.write(`Warning: could not write the run summary: ${errMsg(err)}
3191
- `);
3192
- }
3193
3165
  };
3194
- var upsertSticky = async (repo, prNumber, existing, body, ghApi) => {
3166
+ var upsertSticky = async (repo, prNumber, existing, body, ghApi, signal = false) => {
3195
3167
  if (existing !== null) {
3196
3168
  const patched = await patchComment(repo, existing.id, body, ghApi);
3197
3169
  process.stderr.write(
3198
3170
  `Updated sticky comment #${String(existing.id)} on PR #${String(prNumber)}
3199
3171
  `
3200
3172
  );
3173
+ if (signal) writePostedSignal(true);
3201
3174
  return { id: existing.id, url: patched?.html_url };
3202
3175
  }
3203
3176
  const posted = await postComment(repo, prNumber, body, ghApi);
3204
3177
  process.stderr.write(`Posted new sticky comment on PR #${String(prNumber)}
3205
3178
  `);
3179
+ if (signal && posted !== null) writePostedSignal(true);
3206
3180
  return posted ? { id: posted.id, url: posted.html_url } : null;
3207
3181
  };
3208
3182
  var isBotReview = (r) => typeof r === "object" && r !== null && typeof r.id === "number" && typeof r.state === "string" && typeof r.user?.login === "string";
@@ -3325,6 +3299,7 @@ var post = async (input, ghApi = runGhApi, readArtifact = ghArtifactReader) => {
3325
3299
  if (resolution.kind === "none") {
3326
3300
  process.stderr.write(`No open PR for ${input.headSha} \u2014 nothing to post
3327
3301
  `);
3302
+ writePostedSignal(false);
3328
3303
  process.exit(0);
3329
3304
  }
3330
3305
  if (resolution.kind === "not-open") {
@@ -3332,6 +3307,7 @@ var post = async (input, ghApi = runGhApi, readArtifact = ghArtifactReader) => {
3332
3307
  `PR #${String(resolution.prNumber)} for ${input.headSha} is not open (state: ${resolution.state}) \u2014 nothing to post
3333
3308
  `
3334
3309
  );
3310
+ writePostedSignal(false);
3335
3311
  process.exit(0);
3336
3312
  }
3337
3313
  const prNumber = resolution.prNumber;
@@ -3372,6 +3348,7 @@ var post = async (input, ghApi = runGhApi, readArtifact = ghArtifactReader) => {
3372
3348
  process.stderr.write(
3373
3349
  message ?? "Review did not complete and the sticky already reflects a completed review \u2014 leaving it in place\n"
3374
3350
  );
3351
+ writePostedSignal(true);
3375
3352
  process.exit(0);
3376
3353
  };
3377
3354
  const logAnsweredDrops = () => {
@@ -3399,7 +3376,7 @@ ${dropNote}` : ""}`,
3399
3376
  sticky.body
3400
3377
  )
3401
3378
  );
3402
- await upsertSticky(input.repo, prNumber, sticky, body, ghApi);
3379
+ await upsertSticky(input.repo, prNumber, sticky, body, ghApi, true);
3403
3380
  process.exit(0);
3404
3381
  };
3405
3382
  const prices = JSON.parse(readFileSync(input.pricesPath, "utf-8"));
@@ -3477,7 +3454,8 @@ ${dropNote}` : ""}`,
3477
3454
  prNumber,
3478
3455
  existingSticky,
3479
3456
  renderNotice("The diff for this PR is empty \u2014 nothing to review.", discussion),
3480
- ghApi
3457
+ ghApi,
3458
+ true
3481
3459
  );
3482
3460
  process.exit(0);
3483
3461
  }
@@ -3490,7 +3468,8 @@ ${dropNote}` : ""}`,
3490
3468
  prNumber,
3491
3469
  existingSticky,
3492
3470
  renderNotice(noticeMessageFor(findingsResult), discussion),
3493
- ghApi
3471
+ ghApi,
3472
+ true
3494
3473
  );
3495
3474
  process.exit(0);
3496
3475
  }
@@ -3615,7 +3594,7 @@ ${dropNote}` : ""}`,
3615
3594
  orphanedUnresolvable: orphanResolveFailed
3616
3595
  })
3617
3596
  );
3618
- await upsertSticky(input.repo, prNumber, existingSticky, body, ghApi);
3597
+ await upsertSticky(input.repo, prNumber, existingSticky, body, ghApi, true);
3619
3598
  appendRunSummary(process.env["GITHUB_STEP_SUMMARY"], () => body);
3620
3599
  if (inlineRequested) {
3621
3600
  process.stderr.write(
@@ -3741,7 +3720,8 @@ ${dropNote}` : ""}`,
3741
3720
  prNumber,
3742
3721
  existingSticky,
3743
3722
  renderBody(initialDisposition),
3744
- ghApi
3723
+ ghApi,
3724
+ true
3745
3725
  );
3746
3726
  const priorInlineComments = await listPriorBotCommentIds(
3747
3727
  input.repo,
@@ -5489,11 +5469,20 @@ var deadlineCmd = defineCommand({
5489
5469
  }
5490
5470
  });
5491
5471
  var derivedSchemaVersion = (kind, raw) => kind === "findings" ? declaredVersion(raw) : void 0;
5492
- var printableSchema = (schemaPath) => {
5472
+ var printableSchema = (schemaPath, pinVersion) => {
5493
5473
  const schema = JSON.parse(readFileSync(schemaPath, "utf-8"));
5494
5474
  const enforcementSchema = Object.fromEntries(
5495
5475
  Object.entries(schema).filter(([key2]) => key2 !== "$schema")
5496
5476
  );
5477
+ if (!pinVersion) return JSON.stringify(enforcementSchema, null, 2);
5478
+ const properties = enforcementSchema["properties"];
5479
+ const schemaVersion = typeof properties === "object" && properties !== null ? properties["schema_version"] : void 0;
5480
+ if (typeof schemaVersion === "object" && schemaVersion !== null) {
5481
+ properties["schema_version"] = {
5482
+ ...schemaVersion,
5483
+ pattern: anchoredSchemaVersionPattern(DEFAULT_SCHEMA_VERSION)
5484
+ };
5485
+ }
5497
5486
  return JSON.stringify(enforcementSchema, null, 2);
5498
5487
  };
5499
5488
  var validateCmd = defineCommand({
@@ -5539,7 +5528,7 @@ var validateCmd = defineCommand({
5539
5528
  process.stderr.write(
5540
5529
  `
5541
5530
  The ${kind} document must conform to this schema (the field descriptions are the authoritative spec \u2014 match the property names exactly):
5542
- ${printableSchema(schemaPath)}
5531
+ ${printableSchema(schemaPath, kind === "findings" && schemaPath === schemaPathFor(kind))}
5543
5532
  `
5544
5533
  );
5545
5534
  }
@@ -5672,9 +5661,10 @@ var seedDraftCmd = defineCommand({
5672
5661
  const resolved = resolvedPriorValue(strippedPrior);
5673
5662
  const doc = resolved === null ? strippedPrior : {
5674
5663
  ...resolved,
5675
- findings: answeredRegistry !== null && answeredRegistry.length > 0 ? resolved.findings.filter(
5676
- (f) => !answeredRegistry.some((e) => isAnsweredDrop(f, e))
5677
- ) : resolved.findings
5664
+ findings: answeredRegistry !== null && answeredRegistry.length > 0 ? resolved.findings.filter((f) => {
5665
+ const resolvedId = resolveFindingId(f);
5666
+ return !answeredRegistry.some((e) => isAnsweredDrop(resolvedId, f, e));
5667
+ }) : resolved.findings
5678
5668
  };
5679
5669
  const carried = doc["scope_metastasis"];
5680
5670
  if (ScopeMetastasisCodec.decode(carried)._tag === "Right") return doc;
@@ -6008,7 +5998,26 @@ var printSchemaCmd = defineCommand({
6008
5998
  run: async ({ args }) => {
6009
5999
  const schemaKind = requireSchemaKind(args.name);
6010
6000
  const schemaPath = requireSchemaPath(schemaKind, args["schema-version"]);
6011
- process.stdout.write(`${printableSchema(schemaPath)}
6001
+ process.stdout.write(
6002
+ `${printableSchema(schemaPath, schemaKind === "findings" && schemaPath === schemaPathFor(schemaKind))}
6003
+ `
6004
+ );
6005
+ }
6006
+ });
6007
+ var defaultVersionCmd = defineCommand({
6008
+ meta: {
6009
+ name: "default-version",
6010
+ description: "Print the in-force schema version the installed registry resolves by default \u2014 the value a draft should stamp as schema_version"
6011
+ },
6012
+ args: {
6013
+ kind: {
6014
+ type: "string",
6015
+ description: "Schema kind (findings | triage | prices); default: findings"
6016
+ }
6017
+ },
6018
+ run: async ({ args }) => {
6019
+ const kind = requireSchemaKind(args.kind || "findings");
6020
+ process.stdout.write(`${defaultVersion(kind)}
6012
6021
  `);
6013
6022
  }
6014
6023
  });
@@ -6679,6 +6688,7 @@ var main = defineCommand({
6679
6688
  extract: extractCmd,
6680
6689
  "validate-patches": validatePatchesCmd,
6681
6690
  "print-schema": printSchemaCmd,
6691
+ "default-version": defaultVersionCmd,
6682
6692
  "stop-gate": stopGateCmd,
6683
6693
  "budget-hook": budgetHookCmd,
6684
6694
  "print-settings": printSettingsCmd,
@@ -6690,6 +6700,6 @@ if (!process.env["VITEST"]) {
6690
6700
  await runMain(main);
6691
6701
  }
6692
6702
 
6693
- export { main, snapshotIfValid };
6703
+ export { main, printableSchema, snapshotIfValid };
6694
6704
  //# sourceMappingURL=index.js.map
6695
6705
  //# sourceMappingURL=index.js.map