@merittdev/horus 0.8.6 → 0.8.7

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.
Files changed (2) hide show
  1. package/dist/index.cjs +62 -19
  2. package/package.json +1 -1
package/dist/index.cjs CHANGED
@@ -65880,7 +65880,7 @@ init_cjs_shims();
65880
65880
 
65881
65881
  // ../../packages/core/src/version.ts
65882
65882
  init_cjs_shims();
65883
- var HORUS_VERSION = true ? "0.8.6" : "dev";
65883
+ var HORUS_VERSION = true ? "0.8.7" : "dev";
65884
65884
  var PINNED_SOURCE_VERSION = "1.5.0";
65885
65885
 
65886
65886
  // ../../packages/core/src/evidence.ts
@@ -91925,6 +91925,8 @@ function correlate(evidence2) {
91925
91925
  init_cjs_shims();
91926
91926
  var PREFER = /resolver|controller|\bservice\b|route|router|handler|gateway|processor|worker|consumer|repository|usecase|use-case|endpoint/i;
91927
91927
  var DEMOTE = /\butil|helper|\bscript|backfill|legacy|migration|seeder|fixture|\bmock\b|\btest\b|\bspec\b/i;
91928
+ var PRESENTATION_NAME = /^(build|format|render|compose|serialize)[A-Z].*(Message|Markup|Html|Text|Label|Summary|Notification|String)$/;
91929
+ var PREDICATE_NAME = /^(is|has|can|should|was|were|are|does|did|needs|allows?|must)[A-Z]/;
91928
91930
  var TYPE_SUFFIX = /(Result|Input|Response|Payload|Args|Dto|Props|Edge|Connection)$/;
91929
91931
  var INTERFACE_PREFIX = /^I(?=[A-Z][a-z])/;
91930
91932
  var TYPE_LIKE_NAME = new RegExp(`(?:${TYPE_SUFFIX.source})|(?:${INTERFACE_PREFIX.source})`);
@@ -91952,8 +91954,9 @@ function scoreSeed(s5, index2, hintTokens, changedFiles, hintHasCode) {
91952
91954
  let score = 0;
91953
91955
  if (PREFER.test(hay)) score += hintHasCode ? 0 : 3;
91954
91956
  if (DEMOTE.test(hay)) score -= 3;
91957
+ if (PRESENTATION_NAME.test(s5.name)) score -= 3;
91955
91958
  if (isTypeLikeName(s5.name)) score -= 4;
91956
- if (s5.startLine !== void 0 && s5.endLine !== void 0 && s5.endLine - s5.startLine <= 3) {
91959
+ if (s5.startLine !== void 0 && s5.endLine !== void 0 && s5.endLine - s5.startLine <= 3 && !PREDICATE_NAME.test(s5.name)) {
91957
91960
  score -= 3;
91958
91961
  }
91959
91962
  if (changedFiles !== void 0 && changedFiles.has(s5.filePath)) score += 5;
@@ -92279,6 +92282,15 @@ function clamp015(n4) {
92279
92282
  var SEV_ERROR = 2;
92280
92283
  var SEV_WARN = 1;
92281
92284
  var SEV_INFO = 0;
92285
+ var GENERIC_SYMBOL_NAMES = /* @__PURE__ */ new Set([
92286
+ "",
92287
+ "constructor",
92288
+ "unknown",
92289
+ "unknown-producer",
92290
+ "unknown-worker",
92291
+ "anonymous",
92292
+ "default"
92293
+ ]);
92282
92294
  function seedEmittedSeverityTier(level, code, message) {
92283
92295
  const lv = level?.toLowerCase();
92284
92296
  if (lv === "error" || lv === "fatal" || lv === "critical") return SEV_ERROR;
@@ -92740,16 +92752,33 @@ async function investigate(input, deps) {
92740
92752
  } catch {
92741
92753
  edges = [];
92742
92754
  }
92743
- const symbolNames = /* @__PURE__ */ new Set([
92744
- top.name,
92745
- ...ctx.callers.map((s5) => s5.name),
92746
- ...ctx.callees.map((s5) => s5.name)
92747
- ]);
92755
+ const symbolNames = new Set(
92756
+ [top.name, ...ctx.callers.map((s5) => s5.name), ...ctx.callees.map((s5) => s5.name)].filter(
92757
+ (n4) => n4 && !GENERIC_SYMBOL_NAMES.has(n4)
92758
+ )
92759
+ );
92748
92760
  queueHits = edges.filter((e) => {
92749
92761
  const bySymbol = e.producerSymbol !== null && symbolNames.has(e.producerSymbol) || e.workerSymbol !== null && symbolNames.has(e.workerSymbol);
92750
92762
  const byFile = e.producerFile === top.filePath || e.workerFile === top.filePath;
92751
92763
  return bySymbol || byFile;
92752
92764
  });
92765
+ if (queueHits.length > 0 && typeof code.searchSymbols === "function") {
92766
+ const resolvesInRepo = async (name2) => {
92767
+ if (!name2 || GENERIC_SYMBOL_NAMES.has(name2)) return false;
92768
+ try {
92769
+ return (await code.searchSymbols(name2, 3)).some((s5) => s5.name === name2);
92770
+ } catch {
92771
+ return true;
92772
+ }
92773
+ };
92774
+ const validated2 = [];
92775
+ for (const e of queueHits) {
92776
+ if (await resolvesInRepo(e.producerSymbol) || await resolvesInRepo(e.workerSymbol)) {
92777
+ validated2.push(e);
92778
+ }
92779
+ }
92780
+ queueHits = validated2;
92781
+ }
92753
92782
  if (input.since !== void 0 && looksDiffable(input.since)) {
92754
92783
  try {
92755
92784
  changes = await code.detectChanges({ base: input.since, compare: "HEAD" });
@@ -92933,7 +92962,10 @@ async function investigate(input, deps) {
92933
92962
  message: sig.sampleMessage ?? "",
92934
92963
  evId: existingEvId,
92935
92964
  isNew: sig.isNew ?? false,
92936
- level: sig.level ?? null
92965
+ level: sig.level ?? null,
92966
+ raisedBySeed: true,
92967
+ // literal is in the seed's own body
92968
+ raiserName: top?.name ?? ""
92937
92969
  });
92938
92970
  }
92939
92971
  }
@@ -92981,7 +93013,10 @@ async function investigate(input, deps) {
92981
93013
  message: sig.sampleMessage ?? "",
92982
93014
  evId: ev.id,
92983
93015
  isNew: sig.isNew ?? false,
92984
- level: sig.level ?? null
93016
+ level: sig.level ?? null,
93017
+ raisedBySeed: true,
93018
+ // literal is in the seed's own body
93019
+ raiserName: top?.name ?? ""
92985
93020
  });
92986
93021
  }
92987
93022
  } catch {
@@ -93005,13 +93040,14 @@ async function investigate(input, deps) {
93005
93040
  ])
93006
93041
  ].slice(0, GAP_D_MAX_RESOLVE * 2);
93007
93042
  for (const sig of candidates) {
93008
- let raiser;
93043
+ let raisers = [];
93009
93044
  try {
93010
- raiser = (await deps.code.searchSymbols(sig.key, 1))[0];
93045
+ raisers = await deps.code.searchSymbols(sig.key, 3);
93011
93046
  } catch {
93012
93047
  continue;
93013
93048
  }
93014
- if (raiser === void 0 || !seedScope.has(raiser.id)) continue;
93049
+ const raiser = raisers.find((r) => r.id === top.id) ?? raisers.find((r) => seedScope.has(r.id));
93050
+ if (raiser === void 0) continue;
93015
93051
  let evId = directEvIdByKey.get(sig.key);
93016
93052
  if (evId === void 0) {
93017
93053
  const where = raiser.id === top.id ? "the seed" : "a callee of the seed";
@@ -93054,7 +93090,9 @@ async function investigate(input, deps) {
93054
93090
  message: sig.sampleMessage ?? "",
93055
93091
  evId,
93056
93092
  isNew: sig.isNew ?? false,
93057
- level: sig.level ?? null
93093
+ level: sig.level ?? null,
93094
+ raisedBySeed: raiser.id === top.id,
93095
+ raiserName: raiser.name
93058
93096
  });
93059
93097
  }
93060
93098
  }
@@ -93643,6 +93681,7 @@ async function investigate(input, deps) {
93643
93681
  }
93644
93682
  if (seedEmittedJoins.length > 0 && top && seedEv) {
93645
93683
  const ordered = [...seedEmittedJoins].sort((a2, b5) => {
93684
+ if (a2.raisedBySeed !== b5.raisedBySeed) return a2.raisedBySeed ? -1 : 1;
93646
93685
  const ta = seedEmittedSeverityTier(a2.level, a2.code, a2.message);
93647
93686
  const tb = seedEmittedSeverityTier(b5.level, b5.code, b5.message);
93648
93687
  if (ta !== tb) return tb - ta;
@@ -93656,17 +93695,21 @@ async function investigate(input, deps) {
93656
93695
  const tier = seedEmittedSeverityTier(lead.level, lead.code, lead.message);
93657
93696
  const volumeBoost = Math.min(0.1, Math.log10(Math.max(1, lead.count)) * 0.025);
93658
93697
  const msgClause = lead.message ? ` \u2014 "${lead.message.replace(/\s+/g, " ").trim().slice(0, 90)}"` : "";
93698
+ const bySeed = lead.raisedBySeed;
93699
+ const raiser = bySeed ? top.name : lead.raiserName || top.name;
93700
+ const depClause = bySeed ? "" : `, a dependency of ${top.name}`;
93701
+ const calleePenalty = bySeed ? 0 : 0.18;
93659
93702
  let title;
93660
93703
  let baseScore;
93661
93704
  if (tier === SEV_ERROR) {
93662
- title = `Runtime error ${lead.code} (${lead.count}x in Elasticsearch) is raised by ${top.name} \u2014 the likely failure${msgClause}`;
93663
- baseScore = clamp015(0.6 + volumeBoost);
93705
+ title = bySeed ? `Runtime error ${lead.code} (${lead.count}x in Elasticsearch) is raised by ${raiser} \u2014 the likely failure${msgClause}` : `Runtime error ${lead.code} (${lead.count}x in Elasticsearch) surfaces on ${raiser}${depClause}${msgClause}`;
93706
+ baseScore = clamp015(0.6 + volumeBoost - calleePenalty);
93664
93707
  } else if (tier === SEV_WARN) {
93665
- title = `Warning ${lead.code} (${lead.count}x in Elasticsearch) is raised by ${top.name}${msgClause}`;
93666
- baseScore = clamp015(0.42 + volumeBoost);
93708
+ title = `Warning ${lead.code} (${lead.count}x in Elasticsearch) ${bySeed ? "is raised by" : "surfaces on"} ${raiser}${depClause}${msgClause}`;
93709
+ baseScore = clamp015(0.42 + volumeBoost - calleePenalty);
93667
93710
  } else {
93668
- title = `Diagnostic signal ${lead.code} (${lead.count}x in Elasticsearch) is logged by ${top.name} \u2014 informational, not an error${msgClause}`;
93669
- baseScore = clamp015(0.3 + volumeBoost);
93711
+ title = `Diagnostic signal ${lead.code} (${lead.count}x in Elasticsearch) is logged by ${raiser}${depClause} \u2014 informational, not an error${msgClause}`;
93712
+ baseScore = clamp015(0.3 + volumeBoost - calleePenalty);
93670
93713
  }
93671
93714
  causeInputs.push({
93672
93715
  id: "cause:seed-emitted-error",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@merittdev/horus",
3
- "version": "0.8.6",
3
+ "version": "0.8.7",
4
4
  "description": "Local-first, source-aware production-incident investigation engine",
5
5
  "type": "module",
6
6
  "bin": {