@tomismeta/paperclip-aperture 0.3.1 → 0.3.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/worker.js CHANGED
@@ -6378,7 +6378,7 @@ var paperclipConfigSchema = external_exports.object({
6378
6378
  }
6379
6379
  });
6380
6380
 
6381
- // node_modules/.pnpm/@tomismeta+aperture-core@0.4.0/node_modules/@tomismeta/aperture-core/public-dist/index.js
6381
+ // node_modules/.pnpm/@tomismeta+aperture-core@0.4.2/node_modules/@tomismeta/aperture-core/public-dist/index.js
6382
6382
  import { join, dirname } from "path";
6383
6383
  import { readFile, mkdir, writeFile, rename } from "fs/promises";
6384
6384
  function scoreCandidate(candidate) {
@@ -6802,7 +6802,8 @@ var JUDGMENT_DEFAULTS = {
6802
6802
  stackingBoost: 1,
6803
6803
  relationRepeatBoost: 1,
6804
6804
  relationEscalationBoost: 2,
6805
- actionableThreshold: 4
6805
+ actionableThreshold: 4,
6806
+ staleAfterMs: 15 * 6e4
6806
6807
  }
6807
6808
  };
6808
6809
  function deriveAttentionBurden(summary, pressure, attentionState, operatorPresence = "present", now) {
@@ -7032,12 +7033,14 @@ var baseAttentionSurfaceCapabilities = {
7032
7033
  }
7033
7034
  };
7034
7035
  function createAttentionEvidenceContext(input = {}) {
7036
+ const taskSignalSummary = input.taskSignalSummary ?? emptyAttentionSignalSummary();
7035
7037
  return {
7036
7038
  currentFrame: input.currentFrame ?? null,
7037
7039
  currentTaskView: input.currentTaskView ?? emptyTaskView(),
7038
7040
  currentEpisode: input.currentEpisode ?? null,
7039
7041
  attentionView: input.attentionView ?? emptyAttentionView(),
7040
- taskSignalSummary: input.taskSignalSummary ?? emptyAttentionSignalSummary(),
7042
+ taskSignalSummary,
7043
+ continuitySignalSummary: input.continuitySignalSummary ?? taskSignalSummary,
7041
7044
  globalSignalSummary: input.globalSignalSummary ?? emptyAttentionSignalSummary(),
7042
7045
  taskAttentionState: input.taskAttentionState ?? "monitoring",
7043
7046
  globalAttentionState: input.globalAttentionState ?? "monitoring",
@@ -7060,6 +7063,7 @@ function buildAttentionEvidenceInput(input = {}) {
7060
7063
  ...input.currentEpisode !== void 0 ? { currentEpisode: input.currentEpisode } : {},
7061
7064
  ...input.attentionView !== void 0 ? { attentionView: input.attentionView } : {},
7062
7065
  ...input.taskSignalSummary !== void 0 ? { taskSignalSummary: input.taskSignalSummary } : {},
7066
+ ...input.continuitySignalSummary !== void 0 ? { continuitySignalSummary: input.continuitySignalSummary } : {},
7063
7067
  ...input.globalSignalSummary !== void 0 ? { globalSignalSummary: input.globalSignalSummary } : {},
7064
7068
  ...input.taskAttentionState !== void 0 ? { taskAttentionState: input.taskAttentionState } : {},
7065
7069
  ...input.globalAttentionState !== void 0 ? { globalAttentionState: input.globalAttentionState } : {},
@@ -7099,7 +7103,7 @@ function resolveAttentionEvidenceContext(currentFrame, input = {}, referenceTime
7099
7103
  });
7100
7104
  }
7101
7105
  function isAttentionEvidenceContext(input) {
7102
- return "currentFrame" in input && "currentTaskView" in input && "currentEpisode" in input && "attentionView" in input && "taskSignalSummary" in input && "globalSignalSummary" in input && "taskAttentionState" in input && "globalAttentionState" in input && "pressureForecast" in input && "attentionBurden" in input && "surfaceCapabilities" in input && "operatorPresence" in input && input.currentFrame !== void 0 && input.currentTaskView !== void 0 && input.currentEpisode !== void 0 && input.attentionView !== void 0 && input.taskSignalSummary !== void 0 && input.globalSignalSummary !== void 0 && input.taskAttentionState !== void 0 && input.globalAttentionState !== void 0 && input.pressureForecast !== void 0 && input.attentionBurden !== void 0 && input.surfaceCapabilities !== void 0 && input.operatorPresence !== void 0;
7106
+ return "currentFrame" in input && "currentTaskView" in input && "currentEpisode" in input && "attentionView" in input && "taskSignalSummary" in input && "continuitySignalSummary" in input && "globalSignalSummary" in input && "taskAttentionState" in input && "globalAttentionState" in input && "pressureForecast" in input && "attentionBurden" in input && "surfaceCapabilities" in input && "operatorPresence" in input && input.currentFrame !== void 0 && input.currentTaskView !== void 0 && input.currentEpisode !== void 0 && input.attentionView !== void 0 && input.taskSignalSummary !== void 0 && input.continuitySignalSummary !== void 0 && input.globalSignalSummary !== void 0 && input.taskAttentionState !== void 0 && input.globalAttentionState !== void 0 && input.pressureForecast !== void 0 && input.attentionBurden !== void 0 && input.surfaceCapabilities !== void 0 && input.operatorPresence !== void 0;
7103
7107
  }
7104
7108
  function emptyTaskView() {
7105
7109
  return {
@@ -7155,11 +7159,15 @@ function readSemanticRelationTarget(relationHints) {
7155
7159
  var DEFAULTS = JUDGMENT_DEFAULTS.episodeEvidence;
7156
7160
  var EpisodeTracker = class {
7157
7161
  byKey = /* @__PURE__ */ new Map();
7162
+ byId = /* @__PURE__ */ new Map();
7158
7163
  byInteractionId = /* @__PURE__ */ new Map();
7164
+ nextSequenceByKey = /* @__PURE__ */ new Map();
7159
7165
  assign(candidate) {
7160
7166
  const key = buildEpisodeKey(candidate);
7161
7167
  const existingId = this.byInteractionId.get(candidate.interactionId);
7162
- const record = (existingId ? this.findById(existingId) : void 0) ?? this.byKey.get(key) ?? this.createRecord(key, candidate);
7168
+ const boundRecord = existingId ? this.byId.get(existingId) : void 0;
7169
+ const keyedRecord = boundRecord ? null : this.byKey.get(key);
7170
+ const record = boundRecord ?? this.resolveAssignableRecord(key, keyedRecord, candidate);
7163
7171
  record.interactions.add(candidate.interactionId);
7164
7172
  record.lastInteractionId = candidate.interactionId;
7165
7173
  record.updatedAt = candidate.timestamp;
@@ -7176,6 +7184,7 @@ var EpisodeTracker = class {
7176
7184
  record.evidenceReasons = evidence.reasons;
7177
7185
  record.state = nextEpisodeState(record.state, candidate, record, evidence.score);
7178
7186
  this.byKey.set(record.key, record);
7187
+ this.byId.set(record.id, record);
7179
7188
  this.byInteractionId.set(candidate.interactionId, record.id);
7180
7189
  return {
7181
7190
  ...candidate,
@@ -7192,12 +7201,17 @@ var EpisodeTracker = class {
7192
7201
  if (!episodeId) {
7193
7202
  return;
7194
7203
  }
7195
- const record = this.findById(episodeId);
7204
+ const record = this.byId.get(episodeId);
7196
7205
  if (!record) {
7197
7206
  return;
7198
7207
  }
7199
- record.state = "resolved";
7200
- this.byKey.set(record.key, record);
7208
+ if (this.byKey.get(record.key)?.id === record.id) {
7209
+ this.byKey.delete(record.key);
7210
+ }
7211
+ this.byId.delete(record.id);
7212
+ for (const relatedInteractionId of record.interactions) {
7213
+ this.byInteractionId.delete(relatedInteractionId);
7214
+ }
7201
7215
  }
7202
7216
  readFrameEpisode(frame) {
7203
7217
  if (!frame) {
@@ -7221,8 +7235,10 @@ var EpisodeTracker = class {
7221
7235
  return { id, key, state, size, evidenceScore, evidenceReasons, lastInteractionId, updatedAt };
7222
7236
  }
7223
7237
  createRecord(key, candidate) {
7238
+ const nextSequence = (this.nextSequenceByKey.get(key) ?? 0) + 1;
7239
+ this.nextSequenceByKey.set(key, nextSequence);
7224
7240
  return {
7225
- id: `episode:${key}`,
7241
+ id: `episode:${key}:${nextSequence}`,
7226
7242
  key,
7227
7243
  state: candidate.blocking ? "actionable" : "emerging",
7228
7244
  size: 0,
@@ -7237,13 +7253,26 @@ var EpisodeTracker = class {
7237
7253
  relationKinds: new Set((candidate.relationHints ?? []).map((hint) => hint.kind))
7238
7254
  };
7239
7255
  }
7240
- findById(id) {
7241
- for (const record of this.byKey.values()) {
7242
- if (record.id === id) {
7243
- return record;
7244
- }
7256
+ resolveAssignableRecord(key, current, candidate) {
7257
+ if (!current) {
7258
+ return this.createRecord(key, candidate);
7245
7259
  }
7246
- return void 0;
7260
+ if (this.shouldRollEpisode(current, candidate.timestamp)) {
7261
+ current.state = "stale";
7262
+ return this.createRecord(key, candidate);
7263
+ }
7264
+ return current;
7265
+ }
7266
+ shouldRollEpisode(record, nextTimestamp) {
7267
+ if (isDormantEpisodeState(record.state)) {
7268
+ return true;
7269
+ }
7270
+ const previousMs = Date.parse(record.updatedAt);
7271
+ const nextMs = Date.parse(nextTimestamp);
7272
+ if (Number.isNaN(previousMs) || Number.isNaN(nextMs)) {
7273
+ return false;
7274
+ }
7275
+ return nextMs - previousMs >= DEFAULTS.staleAfterMs;
7247
7276
  }
7248
7277
  };
7249
7278
  function buildEpisodeKey(candidate) {
@@ -7255,6 +7284,12 @@ function buildEpisodeKey(candidate) {
7255
7284
  function readFrameEpisodeId(frame) {
7256
7285
  return frame ? readString(frame.metadata?.episode, "id") : null;
7257
7286
  }
7287
+ function readFrameEpisodeState(frame) {
7288
+ return frame ? readState(frame.metadata?.episode, "state") : null;
7289
+ }
7290
+ function isDormantEpisodeState(state) {
7291
+ return state === "stale" || state === "resolved";
7292
+ }
7258
7293
  function episodeAnchor(candidate) {
7259
7294
  const relationAnchor = readSemanticRelationTarget(candidate.relationHints);
7260
7295
  if (relationAnchor) {
@@ -7485,10 +7520,13 @@ function detectSemanticRelationHints(text) {
7485
7520
  return dedupeRelationHints(hints);
7486
7521
  }
7487
7522
  function inferConsequenceFromSemanticText(text, fallback, toolFamily) {
7523
+ if (isRoutineSuccessObservation(text)) {
7524
+ return fallback;
7525
+ }
7488
7526
  if (toolFamily === "read" || toolFamily === "search") {
7489
7527
  return fallback;
7490
7528
  }
7491
- if (containsAnySemanticPhrase(text, HIGH_RISK_PHRASES)) {
7529
+ if (containsAnySemanticRiskPhrase(text, HIGH_RISK_PHRASES)) {
7492
7530
  return "high";
7493
7531
  }
7494
7532
  if (toolFamily === "write" || toolFamily === "edit" || toolFamily === "bash") {
@@ -7496,9 +7534,82 @@ function inferConsequenceFromSemanticText(text, fallback, toolFamily) {
7496
7534
  }
7497
7535
  return fallback;
7498
7536
  }
7537
+ function detectObservationalFailureStatus(text, toolFamily) {
7538
+ if (toolFamily !== "edit" && toolFamily !== "read") {
7539
+ return false;
7540
+ }
7541
+ return containsAnySemanticPhrase(text, OBSERVATIONAL_READBACK_PHRASES) || looksLikeTaggedFileObservation(text) || looksLikeReadObservationPayload(text);
7542
+ }
7543
+ function detectRoutineObservationalFailureLowConsequence(text, toolFamily) {
7544
+ if (toolFamily === "search") {
7545
+ return looksLikeSearchResultOutput(text);
7546
+ }
7547
+ if (toolFamily === "read") {
7548
+ if (looksLikeSearchResultOutput(text)) {
7549
+ return true;
7550
+ }
7551
+ if (!looksLikeTaggedFileObservation(text) && !looksLikeReadObservationPayload(text)) {
7552
+ return false;
7553
+ }
7554
+ if (looksLikeSourceCodeObservation(text)) {
7555
+ return false;
7556
+ }
7557
+ return looksLikeLogObservation(text) || looksLikeBuildMetadataObservation(text);
7558
+ }
7559
+ return false;
7560
+ }
7561
+ function detectExpectedDiagnosticFailure(text, toolFamily) {
7562
+ if (toolFamily !== "bash") {
7563
+ return false;
7564
+ }
7565
+ return containsAnySemanticPhrase(text, EXPECTED_DIAGNOSTIC_FAILURE_PHRASES) && !containsAnySemanticPhrase(text, TERMINAL_FAILURE_PHRASES);
7566
+ }
7499
7567
  function containsAnySemanticPhrase(value, phrases) {
7500
7568
  return phrases.some((phrase) => value.includes(phrase));
7501
7569
  }
7570
+ function containsAnySemanticRiskPhrase(value, phrases) {
7571
+ return phrases.some((phrase) => containsSemanticRiskPhrase(value, phrase));
7572
+ }
7573
+ function containsSemanticRiskPhrase(value, phrase) {
7574
+ const normalizedPhrase = normalizeSemanticText(phrase);
7575
+ if (!normalizedPhrase) {
7576
+ return false;
7577
+ }
7578
+ if (!normalizedPhrase.includes(" ")) {
7579
+ return hasWord(value, normalizedPhrase);
7580
+ }
7581
+ return new RegExp(`(?:^|\\s)${escapeRegExp(normalizedPhrase)}(?:\\s|$)`).test(value);
7582
+ }
7583
+ function looksLikeReadObservationPayload(text) {
7584
+ if (!containsPathLikeToken(text)) {
7585
+ return false;
7586
+ }
7587
+ return containsAnySemanticPhrase(text, OBSERVATIONAL_PAYLOAD_PHRASES) || containsCodeLikeContent(text) || containsLineNumberedCodeContent(text);
7588
+ }
7589
+ function looksLikeTaggedFileObservation(text) {
7590
+ return containsAnySemanticPhrase(text, TAGGED_FILE_OBSERVATION_PHRASES) && containsPathLikeToken(text);
7591
+ }
7592
+ function looksLikeSearchResultOutput(text) {
7593
+ return SEARCH_RESULT_OUTPUT_PATTERN.test(text) || containsPathLikeToken(text) && /\bmatch(?:es)?\b/.test(text);
7594
+ }
7595
+ function containsPathLikeToken(text) {
7596
+ return PATH_LIKE_TOKEN_PATTERN.test(text);
7597
+ }
7598
+ function containsCodeLikeContent(text) {
7599
+ return CODE_CONTENT_PATTERN.test(text);
7600
+ }
7601
+ function containsLineNumberedCodeContent(text) {
7602
+ return LINE_NUMBERED_CODE_PATTERN.test(text);
7603
+ }
7604
+ function looksLikeSourceCodeObservation(text) {
7605
+ return SOURCE_CODE_PATH_PATTERN.test(text) || SOURCE_CODE_FILENAME_PATTERN.test(text) || SOURCE_CODE_CONTENT_PATTERN.test(text) || LINE_NUMBERED_SOURCE_CODE_PATTERN.test(text);
7606
+ }
7607
+ function looksLikeLogObservation(text) {
7608
+ return LOG_OUTPUT_PATTERN.test(text) || containsAnySemanticPhrase(text, LOG_LIKE_OBSERVATION_PHRASES);
7609
+ }
7610
+ function looksLikeBuildMetadataObservation(text) {
7611
+ return BUILD_METADATA_PATTERN.test(text) || containsAnySemanticPhrase(text, BUILD_METADATA_PHRASES);
7612
+ }
7502
7613
  function readMetadataToolFamily(metadata) {
7503
7614
  const value = metadata?.toolFamily;
7504
7615
  return typeof value === "string" ? value : null;
@@ -7574,6 +7685,70 @@ var HIGH_RISK_PHRASES = [
7574
7685
  "kill process",
7575
7686
  "migrate"
7576
7687
  ];
7688
+ var OBSERVATIONAL_READBACK_PHRASES = [
7689
+ "result of running cat -n",
7690
+ "result of running sed -n",
7691
+ "result of running grep",
7692
+ "result of running ls",
7693
+ "result of running find",
7694
+ "here s the result of running cat -n",
7695
+ "here s the result of running sed -n"
7696
+ ];
7697
+ var OBSERVATIONAL_PAYLOAD_PHRASES = [
7698
+ "observation",
7699
+ "contents of",
7700
+ "showing first",
7701
+ "showing top",
7702
+ "found"
7703
+ ];
7704
+ var TAGGED_FILE_OBSERVATION_PHRASES = [
7705
+ "path",
7706
+ "type file",
7707
+ "content"
7708
+ ];
7709
+ var ROUTINE_SUCCESS_PHRASES = [
7710
+ "ran successfully and did not produce any output",
7711
+ "command ran successfully and did not produce any output",
7712
+ "completed successfully and did not produce any output"
7713
+ ];
7714
+ var LOG_LIKE_OBSERVATION_PHRASES = [
7715
+ "tool-output",
7716
+ "dmesg"
7717
+ ];
7718
+ var BUILD_METADATA_PHRASES = [
7719
+ "makefile",
7720
+ "spdx-license-identifier",
7721
+ "patchlevel",
7722
+ "sublevel",
7723
+ "extraversion"
7724
+ ];
7725
+ var PATH_LIKE_TOKEN_PATTERN = /(?:^|\s)\/[a-z0-9._-]+(?:\/[a-z0-9._-]+)+(?:\s|$)/;
7726
+ var SEARCH_RESULT_OUTPUT_PATTERN = /\bfound\s+\d+\s+match(?:es)?\b|\bshowing\s+(?:first|top)\s+\d+\b|\bmatch(?:es)?\s+in\s+\d+\s+files?\b/;
7727
+ var CODE_CONTENT_PATTERN = /\b(import|from|export|class|def|function|const|let|var|return)\b/;
7728
+ var LINE_NUMBERED_CODE_PATTERN = /\b\d+\s+(?:import|from|export|class|def|function|const|let|var|return)\b/;
7729
+ var SOURCE_CODE_PATH_PATTERN = /\/[a-z0-9._/-]+\.(?:c|cc|cpp|cxx|h|hpp|ts|tsx|js|jsx|py|rb|go|rs|java|kt|swift)(?:\b|\/)/;
7730
+ var SOURCE_CODE_FILENAME_PATTERN = /\b[a-z0-9.-]+\.(?:c|cc|cpp|cxx|h|hpp|ts|tsx|js|jsx|py|rb|go|rs|java|kt|swift)\b/;
7731
+ var SOURCE_CODE_CONTENT_PATTERN = /\b(static|struct|enum|typedef|void|int|char|bool|return)\b/;
7732
+ var LINE_NUMBERED_SOURCE_CODE_PATTERN = /\b\d+\s+(?:static|struct|enum|typedef|void|int|char|bool|return)\b/;
7733
+ var LOG_OUTPUT_PATTERN = /\b\d+\s+\[\s*\d+\.\d+\]\s+[a-z0-9_.:-]+/;
7734
+ var BUILD_METADATA_PATTERN = /\b(?:version|patchlevel|sublevel|extraversion)\b/;
7735
+ var EXPECTED_DIAGNOSTIC_FAILURE_PHRASES = [
7736
+ "form is valid false",
7737
+ "form without instance is valid false",
7738
+ "form errors",
7739
+ "errorlist",
7740
+ "decompress result"
7741
+ ];
7742
+ var TERMINAL_FAILURE_PHRASES = [
7743
+ "traceback",
7744
+ "exception",
7745
+ "permission denied",
7746
+ "command not found",
7747
+ "segmentation fault"
7748
+ ];
7749
+ function isRoutineSuccessObservation(text) {
7750
+ return containsAnySemanticPhrase(text, ROUTINE_SUCCESS_PHRASES);
7751
+ }
7577
7752
  var REPEAT_PHRASES = [
7578
7753
  "still",
7579
7754
  "again",
@@ -7732,11 +7907,12 @@ var EventEvaluator = class {
7732
7907
  evaluateHumanInput(event) {
7733
7908
  const actions = this.createActions(event);
7734
7909
  const responseSpec = this.createResponseSpec(event, actions);
7910
+ const toolFamily = event.request.kind === "approval" ? event.toolFamily : void 0;
7735
7911
  return {
7736
7912
  taskId: event.taskId,
7737
7913
  interactionId: event.interactionId,
7738
7914
  ...event.source !== void 0 ? { source: event.source } : {},
7739
- ...event.toolFamily !== void 0 ? { toolFamily: event.toolFamily } : {},
7915
+ ...toolFamily !== void 0 ? { toolFamily } : {},
7740
7916
  ...event.activityClass !== void 0 ? { activityClass: event.activityClass } : {},
7741
7917
  mode: event.request.kind,
7742
7918
  tone: event.tone ?? "focused",
@@ -8000,11 +8176,11 @@ function readBoundedToolFamily(input) {
8000
8176
  if (input.mode === "status") {
8001
8177
  return readExplicitToolFamily(input);
8002
8178
  }
8003
- if (input.activityClass !== void 0 && input.activityClass !== "permission_request") {
8004
- return readExplicitToolFamily(input);
8005
- }
8006
8179
  if (input.mode !== "approval") {
8007
- return readExplicitToolFamily(input);
8180
+ return null;
8181
+ }
8182
+ if (input.activityClass !== void 0 && input.activityClass !== "permission_request") {
8183
+ return null;
8008
8184
  }
8009
8185
  return inferToolFamily(input);
8010
8186
  }
@@ -8283,7 +8459,9 @@ var evaluateNoActiveFrameCriterionRule = (input) => {
8283
8459
  evidence.attentionView.active,
8284
8460
  ...evidence.attentionView.queued,
8285
8461
  ...evidence.attentionView.ambient
8286
- ].filter((frame) => frame !== null).some((frame) => frame.interactionId !== candidate.interactionId && readFrameEpisodeId(frame) === candidate.episodeId)) {
8462
+ ].filter((frame) => frame !== null).some(
8463
+ (frame) => frame.interactionId !== candidate.interactionId && readFrameEpisodeId(frame) === candidate.episodeId && !isDormantEpisodeState(readFrameEpisodeState(frame))
8464
+ )) {
8287
8465
  return noopPolicyCriterionRule("no_active_frame");
8288
8466
  }
8289
8467
  if (candidateScore >= criterion.activationThreshold) {
@@ -8781,31 +8959,35 @@ function isSameDecisionStream(activeFrame, candidate) {
8781
8959
  return false;
8782
8960
  }
8783
8961
  var evaluateDeferralEscalationContinuityRule = (input) => {
8784
- const activeFrame = input.evidence.currentFrame;
8785
8962
  const { candidate, context, evidence } = input;
8786
- if (!activeFrame || context.currentScore === null) {
8963
+ const activeFrame = evidence.attentionView.active ?? evidence.currentFrame;
8964
+ if (!activeFrame) {
8965
+ return noopContinuityRule("deferral_escalation");
8966
+ }
8967
+ const currentScore = activeFrame === evidence.currentFrame ? context.currentScore : scoreAttentionFrame(activeFrame, { now: candidate.timestamp });
8968
+ if (currentScore === null) {
8787
8969
  return noopContinuityRule("deferral_escalation");
8788
8970
  }
8789
8971
  if (candidate.blocking || candidate.priority === "background" || isBlockingFrame(activeFrame)) {
8790
8972
  return noopContinuityRule("deferral_escalation");
8791
8973
  }
8792
- const taskSummary = evidence.taskSignalSummary;
8793
- const repeatedlyDeferred = taskSummary.counts.deferred >= JUDGMENT_DEFAULTS.queuePlanner.deferredEscalationThreshold;
8794
- const repeatedlyReturned = taskSummary.counts.returned >= JUDGMENT_DEFAULTS.queuePlanner.returnedEscalationThreshold;
8795
- if (!repeatedlyDeferred && !repeatedlyReturned) {
8974
+ if (!hasResurfacingPressure(evidence.continuitySignalSummary)) {
8796
8975
  return noopContinuityRule("deferral_escalation");
8797
8976
  }
8798
- if (context.candidateScore < context.currentScore - JUDGMENT_DEFAULTS.queuePlanner.escalationScoreSlack) {
8977
+ if (context.candidateScore < currentScore - JUDGMENT_DEFAULTS.queuePlanner.escalationScoreSlack) {
8799
8978
  return noopContinuityRule("deferral_escalation");
8800
8979
  }
8801
8980
  return overrideContinuityRule(
8802
8981
  "deferral_escalation",
8803
8982
  { kind: "activate", candidate },
8804
8983
  priorityForFrame(activeFrame),
8805
- context.currentScore,
8806
- ["repeated deferral makes this task more deserving of current focus"]
8984
+ currentScore,
8985
+ ["repeated deferral or resurfacing makes this task more deserving of current focus"]
8807
8986
  );
8808
8987
  };
8988
+ function hasResurfacingPressure(summary) {
8989
+ return summary.counts.deferred >= JUDGMENT_DEFAULTS.queuePlanner.deferredEscalationThreshold || summary.counts.returned >= JUDGMENT_DEFAULTS.queuePlanner.returnedEscalationThreshold;
8990
+ }
8809
8991
  var evaluateMinimumDwellContinuityRule = (input) => {
8810
8992
  const activeFrame = input.evidence.currentFrame;
8811
8993
  const { candidate, context, evidence, helpers, routed, plannerDefaults } = input;
@@ -8843,7 +9025,7 @@ var evaluateSameEpisodeContinuityRule = (input) => {
8843
9025
  return noopContinuityRule("same_episode");
8844
9026
  }
8845
9027
  const currentEpisodeId = readFrameEpisodeId(activeFrame);
8846
- if (!currentEpisodeId || currentEpisodeId !== candidate.episodeId) {
9028
+ if (!currentEpisodeId || currentEpisodeId !== candidate.episodeId || isDormantEpisodeState(readFrameEpisodeState(activeFrame))) {
8847
9029
  return noopContinuityRule("same_episode");
8848
9030
  }
8849
9031
  if (candidate.blocking && !isBlockingFrame(activeFrame)) {
@@ -8864,6 +9046,9 @@ var evaluateSameEpisodeContinuityRule = (input) => {
8864
9046
  ["the active episode has advanced to a superseding step"]
8865
9047
  );
8866
9048
  }
9049
+ if (hasResurfacingPressure(evidence.continuitySignalSummary)) {
9050
+ return noopContinuityRule("same_episode");
9051
+ }
8867
9052
  return overrideContinuityRule(
8868
9053
  "same_episode",
8869
9054
  helpers.peripheralDecision(candidate, context.policyVerdict, evidence.surfaceCapabilities),
@@ -8897,10 +9082,15 @@ var evaluateVisibleEpisodeContinuityRule = (input) => {
8897
9082
  evidence.attentionView.active,
8898
9083
  ...evidence.attentionView.queued,
8899
9084
  ...evidence.attentionView.ambient
8900
- ].filter((frame) => frame !== null).filter((frame) => frame.interactionId !== candidate.interactionId && readFrameEpisodeId(frame) === candidate.episodeId);
9085
+ ].filter((frame) => frame !== null).filter(
9086
+ (frame) => frame.interactionId !== candidate.interactionId && readFrameEpisodeId(frame) === candidate.episodeId && !isDormantEpisodeState(readFrameEpisodeState(frame))
9087
+ );
8901
9088
  if (visibleRelatedFrames.length === 0 || !(candidate.episodeState === "batched" || (candidate.episodeSize ?? 1) >= 2 || visibleRelatedFrames.length >= 2)) {
8902
9089
  return noopContinuityRule("visible_episode");
8903
9090
  }
9091
+ if (hasResurfacingPressure(evidence.continuitySignalSummary)) {
9092
+ return noopContinuityRule("visible_episode");
9093
+ }
8904
9094
  return overrideContinuityRule(
8905
9095
  "visible_episode",
8906
9096
  helpers.batchedDecision(
@@ -8951,7 +9141,9 @@ var AttentionPlanner = class {
8951
9141
  };
8952
9142
  }
8953
9143
  batchedDecision(candidate, policyVerdict, attentionView, surfaceCapabilities) {
8954
- const episodeIsAlreadyInterruptive = candidate.episodeId !== void 0 && [attentionView?.active, ...attentionView?.queued ?? []].filter((frame) => frame !== null).some((frame) => frame.interactionId !== candidate.interactionId && readFrameEpisodeId(frame) === candidate.episodeId);
9144
+ const episodeIsAlreadyInterruptive = candidate.episodeId !== void 0 && [attentionView?.active, ...attentionView?.queued ?? []].filter((frame) => frame !== null).some(
9145
+ (frame) => frame.interactionId !== candidate.interactionId && readFrameEpisodeId(frame) === candidate.episodeId && !isDormantEpisodeState(readFrameEpisodeState(frame))
9146
+ );
8955
9147
  if (episodeIsAlreadyInterruptive) {
8956
9148
  return { kind: "queue", candidate };
8957
9149
  }
@@ -8973,7 +9165,9 @@ var AttentionPlanner = class {
8973
9165
  if (!attentionView) {
8974
9166
  return false;
8975
9167
  }
8976
- const relatedEpisodeVisible = candidate.episodeId !== void 0 && [attentionView.active, ...attentionView.queued].filter((frame) => frame !== null).some((frame) => frame.interactionId !== candidate.interactionId && readFrameEpisodeId(frame) === candidate.episodeId);
9168
+ const relatedEpisodeVisible = candidate.episodeId !== void 0 && [attentionView.active, ...attentionView.queued].filter((frame) => frame !== null).some(
9169
+ (frame) => frame.interactionId !== candidate.interactionId && readFrameEpisodeId(frame) === candidate.episodeId && !isDormantEpisodeState(readFrameEpisodeState(frame))
9170
+ );
8977
9171
  if (relatedEpisodeVisible) {
8978
9172
  return true;
8979
9173
  }
@@ -9111,6 +9305,15 @@ var AttentionPlanner = class {
9111
9305
  };
9112
9306
  }
9113
9307
  if (currentBlocking && !candidate.blocking) {
9308
+ if (hasResurfacingPressure(evidence.continuitySignalSummary)) {
9309
+ reasons.push("blocking work keeps resurfacing backlog queued so it stays visible until focus can return");
9310
+ return {
9311
+ decision: { kind: "queue", candidate },
9312
+ currentPriority,
9313
+ currentScore,
9314
+ reasons
9315
+ };
9316
+ }
9114
9317
  reasons.push("blocking work keeps non-blocking updates in the periphery");
9115
9318
  return {
9116
9319
  decision: this.peripheralDecision(candidate, context.policyVerdict, evidence.surfaceCapabilities),
@@ -9143,6 +9346,15 @@ var AttentionPlanner = class {
9143
9346
  };
9144
9347
  }
9145
9348
  if (this.shouldSuppressForBacklog(candidate, evidence.attentionView, candidate.timestamp)) {
9349
+ if (hasResurfacingPressure(evidence.continuitySignalSummary)) {
9350
+ reasons.push("existing urgent backlog keeps resurfacing work queued so it remains visible");
9351
+ return {
9352
+ decision: { kind: "queue", candidate },
9353
+ currentPriority,
9354
+ currentScore,
9355
+ reasons
9356
+ };
9357
+ }
9146
9358
  reasons.push(
9147
9359
  context.utility.components.deferralAffinity > 0 ? "existing urgent backlog defers this work, but memory keeps it queued because it usually returns after deferral" : "existing urgent backlog keeps lower-value status work queued"
9148
9360
  );
@@ -9585,85 +9797,7 @@ var AttentionSignalStore = class _AttentionSignalStore {
9585
9797
  return [...this.byTaskId.values()].flat().sort((left, right) => left.timestamp.localeCompare(right.timestamp));
9586
9798
  }
9587
9799
  summarize(taskId) {
9588
- const signals = this.list(taskId);
9589
- const recentSignals = this.recentSignals(signals);
9590
- const counts = {
9591
- presented: 0,
9592
- viewed: 0,
9593
- responded: 0,
9594
- dismissed: 0,
9595
- deferred: 0,
9596
- contextExpanded: 0,
9597
- contextSkipped: 0,
9598
- timedOut: 0,
9599
- returned: 0,
9600
- attentionShifted: 0
9601
- };
9602
- const deferred = {
9603
- queued: 0,
9604
- suppressed: 0,
9605
- manual: 0
9606
- };
9607
- let responseLatencyTotal = 0;
9608
- let responseLatencyCount = 0;
9609
- let dismissalLatencyTotal = 0;
9610
- let dismissalLatencyCount = 0;
9611
- for (const signal of recentSignals) {
9612
- switch (signal.kind) {
9613
- case "presented":
9614
- counts.presented += 1;
9615
- break;
9616
- case "viewed":
9617
- counts.viewed += 1;
9618
- break;
9619
- case "responded":
9620
- counts.responded += 1;
9621
- if (signal.latencyMs !== void 0) {
9622
- responseLatencyTotal += signal.latencyMs;
9623
- responseLatencyCount += 1;
9624
- }
9625
- break;
9626
- case "dismissed":
9627
- counts.dismissed += 1;
9628
- if (signal.latencyMs !== void 0) {
9629
- dismissalLatencyTotal += signal.latencyMs;
9630
- dismissalLatencyCount += 1;
9631
- }
9632
- break;
9633
- case "deferred":
9634
- counts.deferred += 1;
9635
- if (signal.reason !== void 0) {
9636
- deferred[signal.reason] += 1;
9637
- }
9638
- break;
9639
- case "context_expanded":
9640
- counts.contextExpanded += 1;
9641
- break;
9642
- case "context_skipped":
9643
- counts.contextSkipped += 1;
9644
- break;
9645
- case "timed_out":
9646
- counts.timedOut += 1;
9647
- break;
9648
- case "returned":
9649
- counts.returned += 1;
9650
- break;
9651
- case "attention_shifted":
9652
- counts.attentionShifted += 1;
9653
- break;
9654
- }
9655
- }
9656
- return {
9657
- recentSignals: recentSignals.length,
9658
- lifetimeSignals: signals.length,
9659
- counts,
9660
- deferred,
9661
- responseRate: counts.presented > 0 ? counts.responded / counts.presented : 0,
9662
- dismissalRate: counts.presented > 0 ? counts.dismissed / counts.presented : 0,
9663
- averageResponseLatencyMs: responseLatencyCount > 0 ? Math.round(responseLatencyTotal / responseLatencyCount) : null,
9664
- averageDismissalLatencyMs: dismissalLatencyCount > 0 ? Math.round(dismissalLatencyTotal / dismissalLatencyCount) : null,
9665
- lastSignalAt: signals.length > 0 ? signals[signals.length - 1]?.timestamp ?? null : null
9666
- };
9800
+ return summarizeAttentionSignals(this.list(taskId));
9667
9801
  }
9668
9802
  recentSignals(signals) {
9669
9803
  const bounded = signals.slice(-32);
@@ -9685,6 +9819,106 @@ var AttentionSignalStore = class _AttentionSignalStore {
9685
9819
  return recent.length > 0 ? recent : bounded;
9686
9820
  }
9687
9821
  };
9822
+ var RECENT_WINDOW_MS = 30 * 60 * 1e3;
9823
+ function summarizeAttentionSignals(signals) {
9824
+ const recentSignals = recentAttentionSignals(signals);
9825
+ const counts = {
9826
+ presented: 0,
9827
+ viewed: 0,
9828
+ responded: 0,
9829
+ dismissed: 0,
9830
+ deferred: 0,
9831
+ contextExpanded: 0,
9832
+ contextSkipped: 0,
9833
+ timedOut: 0,
9834
+ returned: 0,
9835
+ attentionShifted: 0
9836
+ };
9837
+ const deferred = {
9838
+ queued: 0,
9839
+ suppressed: 0,
9840
+ manual: 0
9841
+ };
9842
+ let responseLatencyTotal = 0;
9843
+ let responseLatencyCount = 0;
9844
+ let dismissalLatencyTotal = 0;
9845
+ let dismissalLatencyCount = 0;
9846
+ for (const signal of recentSignals) {
9847
+ switch (signal.kind) {
9848
+ case "presented":
9849
+ counts.presented += 1;
9850
+ break;
9851
+ case "viewed":
9852
+ counts.viewed += 1;
9853
+ break;
9854
+ case "responded":
9855
+ counts.responded += 1;
9856
+ if (signal.latencyMs !== void 0) {
9857
+ responseLatencyTotal += signal.latencyMs;
9858
+ responseLatencyCount += 1;
9859
+ }
9860
+ break;
9861
+ case "dismissed":
9862
+ counts.dismissed += 1;
9863
+ if (signal.latencyMs !== void 0) {
9864
+ dismissalLatencyTotal += signal.latencyMs;
9865
+ dismissalLatencyCount += 1;
9866
+ }
9867
+ break;
9868
+ case "deferred":
9869
+ counts.deferred += 1;
9870
+ if (signal.reason !== void 0) {
9871
+ deferred[signal.reason] += 1;
9872
+ }
9873
+ break;
9874
+ case "context_expanded":
9875
+ counts.contextExpanded += 1;
9876
+ break;
9877
+ case "context_skipped":
9878
+ counts.contextSkipped += 1;
9879
+ break;
9880
+ case "timed_out":
9881
+ counts.timedOut += 1;
9882
+ break;
9883
+ case "returned":
9884
+ counts.returned += 1;
9885
+ break;
9886
+ case "attention_shifted":
9887
+ counts.attentionShifted += 1;
9888
+ break;
9889
+ }
9890
+ }
9891
+ return {
9892
+ recentSignals: recentSignals.length,
9893
+ lifetimeSignals: signals.length,
9894
+ counts,
9895
+ deferred,
9896
+ responseRate: counts.presented > 0 ? counts.responded / counts.presented : 0,
9897
+ dismissalRate: counts.presented > 0 ? counts.dismissed / counts.presented : 0,
9898
+ averageResponseLatencyMs: responseLatencyCount > 0 ? Math.round(responseLatencyTotal / responseLatencyCount) : null,
9899
+ averageDismissalLatencyMs: dismissalLatencyCount > 0 ? Math.round(dismissalLatencyTotal / dismissalLatencyCount) : null,
9900
+ lastSignalAt: signals.length > 0 ? signals[signals.length - 1]?.timestamp ?? null : null
9901
+ };
9902
+ }
9903
+ function recentAttentionSignals(signals) {
9904
+ const bounded = signals.slice(-32);
9905
+ const latestTimestamp2 = bounded[bounded.length - 1]?.timestamp;
9906
+ if (latestTimestamp2 === void 0) {
9907
+ return bounded;
9908
+ }
9909
+ const latestMs = Date.parse(latestTimestamp2);
9910
+ if (Number.isNaN(latestMs)) {
9911
+ return bounded;
9912
+ }
9913
+ const recent = bounded.filter((signal) => {
9914
+ const signalMs = Date.parse(signal.timestamp);
9915
+ if (Number.isNaN(signalMs)) {
9916
+ return true;
9917
+ }
9918
+ return latestMs - signalMs <= RECENT_WINDOW_MS;
9919
+ });
9920
+ return recent.length > 0 ? recent : bounded;
9921
+ }
9688
9922
  async function readMarkdownFile(path2, fallback, parse) {
9689
9923
  try {
9690
9924
  const content = await readFile(path2, "utf8");
@@ -9880,6 +10114,10 @@ function signalMetadataForFrame(frame) {
9880
10114
  if (key) {
9881
10115
  metadata.sourceKey = key;
9882
10116
  }
10117
+ const episode = frame.metadata?.episode;
10118
+ if (episode && typeof episode === "object" && !Array.isArray(episode)) {
10119
+ metadata.episode = episode;
10120
+ }
9883
10121
  return metadata;
9884
10122
  }
9885
10123
  function signalMetadataForCandidate(candidate) {
@@ -10149,7 +10387,13 @@ function inferSemanticInterpretation(event) {
10149
10387
  factors: ["task.started"],
10150
10388
  relationHints: [],
10151
10389
  confidence: "high",
10152
- reasons: semanticReasonsForLifecycle("task_started")
10390
+ reasons: semanticReasonsForLifecycle("task_started"),
10391
+ provenance: {
10392
+ intentFrame: "inferred",
10393
+ activityClass: "inferred",
10394
+ consequence: "inferred",
10395
+ confidence: "inferred"
10396
+ }
10153
10397
  };
10154
10398
  case "task.updated":
10155
10399
  return inferTaskUpdateSemantics(event);
@@ -10163,7 +10407,13 @@ function inferSemanticInterpretation(event) {
10163
10407
  factors: ["task.completed"],
10164
10408
  relationHints: [],
10165
10409
  confidence: "high",
10166
- reasons: semanticReasonsForLifecycle("completion")
10410
+ reasons: semanticReasonsForLifecycle("completion"),
10411
+ provenance: {
10412
+ intentFrame: "inferred",
10413
+ activityClass: "inferred",
10414
+ consequence: "inferred",
10415
+ confidence: "inferred"
10416
+ }
10167
10417
  };
10168
10418
  case "task.cancelled":
10169
10419
  return {
@@ -10174,7 +10424,14 @@ function inferSemanticInterpretation(event) {
10174
10424
  factors: ["task.cancelled"],
10175
10425
  relationHints: [],
10176
10426
  confidence: "high",
10177
- reasons: semanticReasonsForTaskStatus("completed", { wasCancelled: true })
10427
+ reasons: semanticReasonsForTaskStatus("completed", { wasCancelled: true }),
10428
+ provenance: {
10429
+ intentFrame: "inferred",
10430
+ activityClass: "inferred",
10431
+ consequence: "inferred",
10432
+ ...event.reason ? { whyNow: "inferred" } : {},
10433
+ confidence: "inferred"
10434
+ }
10178
10435
  };
10179
10436
  }
10180
10437
  }
@@ -10183,19 +10440,65 @@ function inferTaskUpdateSemantics(event) {
10183
10440
  const impliedAsk = detectImpliedOperatorAsk(text);
10184
10441
  const relationHints = detectSemanticRelationHints(text);
10185
10442
  const taxonomyInput = buildTaxonomyInput(event.title, event.summary, event.toolFamily);
10186
- const toolFamily = readExplicitSemanticToolFamily(taxonomyInput) ?? inferSemanticToolFamily(taxonomyInput) ?? void 0;
10443
+ const { toolFamily, source: toolFamilySource } = resolveSemanticToolFamily(taxonomyInput, true);
10444
+ const relationProvenance = relationHints.length > 0 ? { relationHints: "inferred" } : {};
10445
+ const observationalFailure = event.status === "failed" && detectObservationalFailureStatus(text, toolFamily);
10446
+ const routineObservationalFailureLowConsequence = event.status === "failed" && detectRoutineObservationalFailureLowConsequence(text, toolFamily);
10447
+ const expectedDiagnosticFailure = event.status === "failed" && detectExpectedDiagnosticFailure(text, toolFamily);
10187
10448
  switch (event.status) {
10188
10449
  case "failed":
10450
+ if (observationalFailure) {
10451
+ return {
10452
+ intentFrame: "status_update",
10453
+ activityClass: "status_update",
10454
+ ...toolFamily ? { toolFamily } : {},
10455
+ consequence: inferConsequenceFromSemanticText(
10456
+ text,
10457
+ routineObservationalFailureLowConsequence ? "low" : "high",
10458
+ toolFamily
10459
+ ),
10460
+ factors: ["task.updated", "failed", "observational_failure"],
10461
+ relationHints,
10462
+ confidence: "high",
10463
+ reasons: [
10464
+ "task status indicates failure but the update reads like observational output"
10465
+ ],
10466
+ provenance: {
10467
+ intentFrame: "inferred",
10468
+ activityClass: "inferred",
10469
+ ...toolFamilySource === "explicit" ? { toolFamily: "source" } : toolFamilySource === "inferred" ? { toolFamily: "inferred" } : {},
10470
+ consequence: "inferred",
10471
+ ...relationProvenance,
10472
+ confidence: "inferred"
10473
+ }
10474
+ };
10475
+ }
10189
10476
  return {
10190
10477
  intentFrame: "failure",
10191
10478
  activityClass: "tool_failure",
10192
10479
  ...toolFamily ? { toolFamily } : {},
10193
- consequence: inferConsequenceFromSemanticText(text, "high", toolFamily),
10480
+ consequence: inferConsequenceFromSemanticText(
10481
+ text,
10482
+ routineObservationalFailureLowConsequence ? "low" : expectedDiagnosticFailure ? "medium" : "high",
10483
+ toolFamily
10484
+ ),
10194
10485
  whyNow: semanticWhyNowForTaskStatus("failed") ?? "Work has failed and should be reviewed.",
10195
10486
  factors: ["task.updated", "failed"],
10196
10487
  relationHints,
10197
10488
  confidence: impliedAsk ? "medium" : "high",
10198
- reasons: semanticReasonsForTaskStatus("failed", { impliedAsk })
10489
+ reasons: expectedDiagnosticFailure ? [
10490
+ ...semanticReasonsForTaskStatus("failed", { impliedAsk }),
10491
+ "failure content looks like expected diagnostic output from repro work"
10492
+ ] : semanticReasonsForTaskStatus("failed", { impliedAsk }),
10493
+ provenance: {
10494
+ intentFrame: "inferred",
10495
+ activityClass: "inferred",
10496
+ ...toolFamilySource === "explicit" ? { toolFamily: "source" } : toolFamilySource === "inferred" ? { toolFamily: "inferred" } : {},
10497
+ consequence: "inferred",
10498
+ whyNow: "inferred",
10499
+ ...relationProvenance,
10500
+ confidence: "inferred"
10501
+ }
10199
10502
  };
10200
10503
  case "blocked":
10201
10504
  return {
@@ -10207,7 +10510,16 @@ function inferTaskUpdateSemantics(event) {
10207
10510
  factors: ["task.updated", "blocked"],
10208
10511
  relationHints,
10209
10512
  confidence: impliedAsk ? "medium" : "high",
10210
- reasons: semanticReasonsForTaskStatus("blocked", { impliedAsk })
10513
+ reasons: semanticReasonsForTaskStatus("blocked", { impliedAsk }),
10514
+ provenance: {
10515
+ intentFrame: "inferred",
10516
+ activityClass: "inferred",
10517
+ ...toolFamilySource === "explicit" ? { toolFamily: "source" } : toolFamilySource === "inferred" ? { toolFamily: "inferred" } : {},
10518
+ consequence: "inferred",
10519
+ whyNow: "inferred",
10520
+ ...relationProvenance,
10521
+ confidence: "inferred"
10522
+ }
10211
10523
  };
10212
10524
  case "running":
10213
10525
  case "waiting":
@@ -10224,17 +10536,31 @@ function inferTaskUpdateSemantics(event) {
10224
10536
  factors: ["task.updated", event.status],
10225
10537
  relationHints,
10226
10538
  confidence: impliedAsk ? "low" : "high",
10227
- reasons: semanticReasonsForTaskStatus(event.status, { impliedAsk })
10539
+ reasons: semanticReasonsForTaskStatus(event.status, { impliedAsk }),
10540
+ provenance: {
10541
+ intentFrame: "inferred",
10542
+ activityClass: "inferred",
10543
+ ...toolFamilySource === "explicit" ? { toolFamily: "source" } : toolFamilySource === "inferred" ? { toolFamily: "inferred" } : {},
10544
+ consequence: "inferred",
10545
+ ...impliedAsk ? { whyNow: "inferred" } : {},
10546
+ ...relationProvenance,
10547
+ confidence: "inferred"
10548
+ }
10228
10549
  };
10229
10550
  }
10230
10551
  }
10231
10552
  function inferHumanInputSemantics(event) {
10232
10553
  const taxonomyInput = buildTaxonomyInput(event.title, event.summary, event.toolFamily, event.context);
10233
- const toolFamily = readExplicitSemanticToolFamily(taxonomyInput) ?? inferSemanticToolFamily(taxonomyInput) ?? void 0;
10554
+ const { toolFamily, source: toolFamilySource } = resolveSemanticToolFamily(
10555
+ taxonomyInput,
10556
+ event.request.kind === "approval"
10557
+ );
10234
10558
  const text = normalizeSemanticText(`${event.title} ${event.summary}`);
10235
10559
  const relationHints = detectSemanticRelationHints(text);
10236
10560
  const baseConsequence = event.riskHint ?? consequenceFromRequestKind(event.request.kind, toolFamily);
10237
10561
  const consequence = inferConsequenceFromSemanticText(text, baseConsequence, toolFamily);
10562
+ const relationProvenance = relationHints.length > 0 ? { relationHints: "inferred" } : {};
10563
+ const toolFamilyProvenance = toolFamilySource === "explicit" ? { toolFamily: "source" } : toolFamilySource === "inferred" ? { toolFamily: "inferred" } : {};
10238
10564
  return {
10239
10565
  intentFrame: semanticIntentFrameForRequestKind(event.request.kind),
10240
10566
  activityClass: semanticActivityClassForRequestKind(event.request.kind),
@@ -10243,13 +10569,36 @@ function inferHumanInputSemantics(event) {
10243
10569
  whyNow: semanticWhyNowForRequestKind(event.request.kind, consequence),
10244
10570
  factors: ["human.input.requested", event.request.kind],
10245
10571
  relationHints,
10246
- confidence: event.riskHint ? "high" : toolFamily ? "medium" : "low",
10572
+ confidence: event.riskHint ? "high" : event.request.kind === "approval" && toolFamily ? "medium" : "low",
10247
10573
  reasons: [
10248
10574
  event.riskHint ? "source provided an explicit risk hint" : "request kind establishes an explicit operator decision point",
10249
- ...toolFamily ? ["tool family was inferred or supplied"] : []
10250
- ]
10575
+ ...toolFamilySource === "explicit" ? ["tool family was supplied by the source or context"] : toolFamilySource === "inferred" ? ["tool family was inferred from approval wording"] : []
10576
+ ],
10577
+ provenance: {
10578
+ intentFrame: "inferred",
10579
+ activityClass: "inferred",
10580
+ ...toolFamilyProvenance,
10581
+ consequence: event.riskHint ? "source" : "inferred",
10582
+ whyNow: "inferred",
10583
+ ...relationProvenance,
10584
+ confidence: event.riskHint ? "source" : "inferred"
10585
+ }
10251
10586
  };
10252
10587
  }
10588
+ function resolveSemanticToolFamily(input, allowTextInference) {
10589
+ const explicit = readExplicitSemanticToolFamily(input);
10590
+ if (explicit) {
10591
+ return { toolFamily: explicit, source: "explicit" };
10592
+ }
10593
+ if (!allowTextInference) {
10594
+ return { source: "none" };
10595
+ }
10596
+ const inferred = inferSemanticToolFamily(input);
10597
+ if (inferred) {
10598
+ return { toolFamily: inferred, source: "inferred" };
10599
+ }
10600
+ return { source: "none" };
10601
+ }
10253
10602
  function applySemanticHints(inferred, hints) {
10254
10603
  if (!hints) {
10255
10604
  return inferred;
@@ -10259,7 +10608,23 @@ function applySemanticHints(inferred, hints) {
10259
10608
  ...pickDefined(hints),
10260
10609
  factors: dedupeSemanticStrings([...inferred.factors ?? [], ...hints.factors ?? []]),
10261
10610
  relationHints: [...hints.relationHints ?? inferred.relationHints],
10262
- reasons: dedupeSemanticStrings([...inferred.reasons ?? [], ...hints.reasons ?? []])
10611
+ reasons: dedupeSemanticStrings([...inferred.reasons ?? [], ...hints.reasons ?? []]),
10612
+ provenance: {
10613
+ ...inferred.provenance ?? {},
10614
+ ...hintedSemanticProvenance(hints)
10615
+ }
10616
+ };
10617
+ }
10618
+ function hintedSemanticProvenance(hints) {
10619
+ return {
10620
+ ...hints.intentFrame !== void 0 ? { intentFrame: "hint" } : {},
10621
+ ...hints.activityClass !== void 0 ? { activityClass: "hint" } : {},
10622
+ ...hints.toolFamily !== void 0 ? { toolFamily: "hint" } : {},
10623
+ ...hints.consequence !== void 0 ? { consequence: "hint" } : {},
10624
+ ...hints.whyNow !== void 0 ? { whyNow: "hint" } : {},
10625
+ ...hints.relationHints !== void 0 ? { relationHints: "hint" } : {},
10626
+ ...hints.confidence !== void 0 ? { confidence: "hint" } : {},
10627
+ ...hints.abstained !== void 0 ? { abstained: "hint" } : {}
10263
10628
  };
10264
10629
  }
10265
10630
  function pickDefined(value) {
@@ -10351,6 +10716,7 @@ function normalizeHumanInput(event, semantic) {
10351
10716
  base: event.provenance,
10352
10717
  semantic
10353
10718
  });
10719
+ const toolFamily = event.request.kind === "approval" ? event.toolFamily ?? semantic.toolFamily : void 0;
10354
10720
  return {
10355
10721
  id: event.id,
10356
10722
  type: event.type,
@@ -10358,7 +10724,7 @@ function normalizeHumanInput(event, semantic) {
10358
10724
  interactionId: event.interactionId,
10359
10725
  timestamp: event.timestamp,
10360
10726
  ...event.source !== void 0 ? { source: event.source } : {},
10361
- ...event.toolFamily !== void 0 ? { toolFamily: event.toolFamily } : semantic.toolFamily !== void 0 ? { toolFamily: semantic.toolFamily } : {},
10727
+ ...toolFamily !== void 0 ? { toolFamily } : {},
10362
10728
  ...event.activityClass !== void 0 ? { activityClass: event.activityClass } : semantic.activityClass !== void 0 ? { activityClass: semantic.activityClass } : {},
10363
10729
  semantic,
10364
10730
  title: event.title,
@@ -10720,6 +11086,7 @@ var TraceRecorder = class {
10720
11086
  }
10721
11087
  recordCandidate(snapshot, input) {
10722
11088
  const { original, adjusted, explanation, result } = input;
11089
+ const semantic = buildSemanticSummary(snapshot.event, adjusted);
10723
11090
  return {
10724
11091
  ...snapshot,
10725
11092
  evaluation: {
@@ -10731,6 +11098,7 @@ var TraceRecorder = class {
10731
11098
  scoreOffset: adjusted.attentionScoreOffset ?? 0,
10732
11099
  rationale: adjusted.attentionRationale ?? []
10733
11100
  },
11101
+ ...semantic !== void 0 ? { semantic } : {},
10734
11102
  episode: buildEpisodeSummary(adjusted),
10735
11103
  policy: explanation.policy,
10736
11104
  policyRules: {
@@ -10780,6 +11148,149 @@ function buildEpisodeSummary(candidate) {
10780
11148
  updatedAt: candidate.timestamp
10781
11149
  };
10782
11150
  }
11151
+ function buildSemanticSummary(event, adjusted) {
11152
+ const semantic = event.semantic;
11153
+ if (!semantic) {
11154
+ return void 0;
11155
+ }
11156
+ return {
11157
+ intentFrame: semantic.intentFrame,
11158
+ ...semantic.activityClass !== void 0 ? { activityClass: semantic.activityClass } : {},
11159
+ ...semantic.toolFamily !== void 0 ? { toolFamily: semantic.toolFamily } : {},
11160
+ ...semantic.consequence !== void 0 ? { consequence: semantic.consequence } : {},
11161
+ ...semantic.confidence !== void 0 ? { confidence: semantic.confidence } : {},
11162
+ ...semantic.abstained === true ? { abstained: true } : {},
11163
+ ...semantic.whyNow !== void 0 ? { whyNow: semantic.whyNow } : {},
11164
+ relationHints: semantic.relationHints,
11165
+ factors: semantic.factors,
11166
+ reasons: semantic.reasons,
11167
+ influence: buildSemanticInfluence(event, adjusted),
11168
+ impact: buildSemanticImpact(event, adjusted),
11169
+ ...semantic.provenance !== void 0 ? { provenance: semantic.provenance } : {}
11170
+ };
11171
+ }
11172
+ function buildSemanticInfluence(event, adjusted) {
11173
+ const semantic = event.semantic;
11174
+ if (!semantic) {
11175
+ return [];
11176
+ }
11177
+ const influence = [];
11178
+ if (event.type === "task.updated") {
11179
+ influence.push("task status remained authoritative; semantic details stayed bounded to explanation, continuity, and ambiguity handling");
11180
+ if (event.toolFamily === semantic.toolFamily && semantic.toolFamily !== void 0) {
11181
+ influence.push("tool family enriched the canonical status event without changing status routing");
11182
+ }
11183
+ if (semantic.relationHints.length > 0) {
11184
+ influence.push("relation hints were available to continuity handling");
11185
+ }
11186
+ if (semantic.abstained === true) {
11187
+ influence.push("semantic abstention can keep non-blocking status work peripheral until clearer evidence arrives");
11188
+ } else if (semantic.confidence === "low") {
11189
+ influence.push("low semantic confidence can keep non-blocking status work peripheral until the signal is clearer");
11190
+ }
11191
+ return influence;
11192
+ }
11193
+ if (event.type === "human.input.requested") {
11194
+ if (event.consequence === semantic.consequence && semantic.consequence !== void 0) {
11195
+ influence.push("semantic consequence shaped the canonical human-input consequence");
11196
+ }
11197
+ if (semantic.toolFamily !== void 0) {
11198
+ if (event.request.kind === "approval") {
11199
+ influence.push("tool family remained decision-bearing on the approval path");
11200
+ } else {
11201
+ influence.push("tool family stayed explanatory on the question/form path");
11202
+ }
11203
+ }
11204
+ if (semantic.relationHints.length > 0) {
11205
+ influence.push("relation hints were available to continuity handling");
11206
+ }
11207
+ if (semantic.abstained === true) {
11208
+ influence.push(
11209
+ adjusted.blocking ? "semantic abstention stayed visible but did not downgrade blocking work" : "semantic abstention constrained non-blocking routing"
11210
+ );
11211
+ } else if (semantic.confidence === "low") {
11212
+ influence.push(
11213
+ adjusted.blocking ? "semantic low confidence stayed visible but did not downgrade blocking work" : "low semantic confidence constrained non-blocking routing"
11214
+ );
11215
+ }
11216
+ if (influence.length === 0) {
11217
+ influence.push("semantic interpretation mainly stayed explanatory beyond the explicit request");
11218
+ }
11219
+ return influence;
11220
+ }
11221
+ influence.push("semantic interpretation was recorded for explanation only");
11222
+ return influence;
11223
+ }
11224
+ function buildSemanticImpact(event, adjusted) {
11225
+ const semantic = event.semantic;
11226
+ const decisionBearing = /* @__PURE__ */ new Set();
11227
+ const explanatory = /* @__PURE__ */ new Set();
11228
+ if (!semantic) {
11229
+ return {
11230
+ decisionBearing: [],
11231
+ explanatory: []
11232
+ };
11233
+ }
11234
+ explanatory.add("intent");
11235
+ if (semantic.toolFamily !== void 0) {
11236
+ explanatory.add("tool");
11237
+ }
11238
+ if (semantic.consequence !== void 0) {
11239
+ explanatory.add("consequence");
11240
+ }
11241
+ if (semantic.whyNow !== void 0) {
11242
+ explanatory.add("why now");
11243
+ }
11244
+ if (semantic.relationHints.length > 0) {
11245
+ explanatory.add("relations");
11246
+ }
11247
+ if (semantic.confidence !== void 0) {
11248
+ explanatory.add("confidence");
11249
+ }
11250
+ if (semantic.abstained === true) {
11251
+ explanatory.add("abstention");
11252
+ }
11253
+ switch (event.type) {
11254
+ case "task.updated":
11255
+ if (semantic.toolFamily !== void 0 && event.toolFamily === semantic.toolFamily) {
11256
+ promoteSemanticField(explanatory, decisionBearing, "tool", "tool (bounded)");
11257
+ }
11258
+ if (semantic.relationHints.length > 0) {
11259
+ promoteSemanticField(explanatory, decisionBearing, "relations", "relations (continuity)");
11260
+ }
11261
+ break;
11262
+ case "human.input.requested":
11263
+ if (semantic.consequence !== void 0 && event.consequence === semantic.consequence) {
11264
+ promoteSemanticField(explanatory, decisionBearing, "consequence", "consequence (canonical)");
11265
+ }
11266
+ if (semantic.toolFamily !== void 0 && event.request.kind === "approval") {
11267
+ promoteSemanticField(explanatory, decisionBearing, "tool", "tool (approval path)");
11268
+ }
11269
+ if (semantic.relationHints.length > 0) {
11270
+ promoteSemanticField(explanatory, decisionBearing, "relations", "relations (continuity)");
11271
+ }
11272
+ break;
11273
+ default:
11274
+ if (semantic.relationHints.length > 0) {
11275
+ promoteSemanticField(explanatory, decisionBearing, "relations", "relations (continuity)");
11276
+ }
11277
+ break;
11278
+ }
11279
+ if (!adjusted.blocking && semantic.confidence === "low") {
11280
+ promoteSemanticField(explanatory, decisionBearing, "confidence", "confidence (ambiguity)");
11281
+ }
11282
+ if (!adjusted.blocking && semantic.abstained === true) {
11283
+ promoteSemanticField(explanatory, decisionBearing, "abstention", "abstention (ambiguity)");
11284
+ }
11285
+ return {
11286
+ decisionBearing: [...decisionBearing],
11287
+ explanatory: [...explanatory]
11288
+ };
11289
+ }
11290
+ function promoteSemanticField(explanatory, decisionBearing, fieldLabel, decisionLabel) {
11291
+ explanatory.delete(fieldLabel);
11292
+ decisionBearing.add(decisionLabel);
11293
+ }
10783
11294
  function findResultBucket(attentionView, taskId, interactionId, decisionKind) {
10784
11295
  if (decisionKind === "auto_approve" || decisionKind === "clear") {
10785
11296
  return "none";
@@ -10969,7 +11480,8 @@ var ApertureCore = class _ApertureCore {
10969
11480
  taskSummary,
10970
11481
  globalSummary
10971
11482
  ));
10972
- const explanation = this.coordinator.explain(evidence.currentFrame, candidate, evidence);
11483
+ const candidateEvidence = this.augmentContinuitySignalSummary(event.taskId, candidate, evidence);
11484
+ const explanation = this.coordinator.explain(evidence.currentFrame, candidate, candidateEvidence);
10973
11485
  let result;
10974
11486
  switch (explanation.decision.kind) {
10975
11487
  case "auto_approve":
@@ -10996,17 +11508,39 @@ var ApertureCore = class _ApertureCore {
10996
11508
  );
10997
11509
  break;
10998
11510
  case "activate":
10999
- result = explanation.decision.candidate.episodeId && this.findPeripheralEpisodeFrame(explanation.decision.candidate.episodeId, preAttentionView) ? this.materializePeripheralFrame(
11511
+ result = this.shouldRetireSupersededEpisodeFrames(
11000
11512
  explanation.decision.candidate,
11001
- selectPeripheralBucket(
11002
- explanation.decision.candidate,
11003
- explanation.policy,
11004
- evidence.surfaceCapabilities
11005
- ),
11006
11513
  preAttentionView
11007
- ) : this.commitFrame(this.applyResponseExpiry(
11008
- this.planner.plan(explanation.decision.candidate, evidence.currentFrame)
11009
- ));
11514
+ ) ? this.commitFrame(
11515
+ this.applyResponseExpiry(
11516
+ this.planner.plan(explanation.decision.candidate, evidence.currentFrame)
11517
+ ),
11518
+ this.findSupersededEpisodeFrames(
11519
+ explanation.decision.candidate,
11520
+ preAttentionView
11521
+ )
11522
+ ) : (() => {
11523
+ const existingPeripheralFrame = explanation.decision.candidate.episodeId ? this.findPeripheralEpisodeFrame(explanation.decision.candidate.episodeId, preAttentionView) : null;
11524
+ if (existingPeripheralFrame && this.shouldPromotePeripheralEpisodeFrame(explanation)) {
11525
+ return this.promotePeripheralEpisodeFrame(
11526
+ explanation.decision.candidate,
11527
+ existingPeripheralFrame.frame
11528
+ );
11529
+ }
11530
+ return existingPeripheralFrame ? this.materializePeripheralFrame(
11531
+ explanation.decision.candidate,
11532
+ selectPeripheralBucket(
11533
+ explanation.decision.candidate,
11534
+ explanation.policy,
11535
+ evidence.surfaceCapabilities
11536
+ ),
11537
+ preAttentionView
11538
+ ) : this.commitFrame(
11539
+ this.applyResponseExpiry(
11540
+ this.planner.plan(explanation.decision.candidate, evidence.currentFrame)
11541
+ )
11542
+ );
11543
+ })();
11010
11544
  break;
11011
11545
  }
11012
11546
  const postAttentionView = this.getAttentionView();
@@ -11096,15 +11630,15 @@ var ApertureCore = class _ApertureCore {
11096
11630
  `response for interaction ${response.interactionId} expired at ${expiredAt} and must be revalidated before submission`
11097
11631
  );
11098
11632
  }
11633
+ const previousAttentionView = this.getAttentionView();
11099
11634
  const timestamp = this.nowIso();
11100
11635
  this.recordSignal(this.signalForResponse(current, response, timestamp));
11101
11636
  this.episodes.resolveInteraction(response.interactionId);
11102
- const previousTaskView = this.taskViews.get(response.taskId);
11103
11637
  const taskView = this.taskViews.resolve(response.taskId, response.interactionId);
11104
11638
  const newPrimary = taskView.active;
11639
+ const nextAttentionView = this.getAttentionView();
11640
+ this.recordAttentionTransition(previousAttentionView, nextAttentionView, timestamp);
11105
11641
  if (newPrimary) {
11106
- this.recordAttentionShift(previousTaskView.active, newPrimary, timestamp);
11107
- this.recordReturnSignal(previousTaskView, newPrimary, timestamp);
11108
11642
  this.notifyFrame(response.taskId, newPrimary);
11109
11643
  } else {
11110
11644
  this.notifyFrame(response.taskId, null);
@@ -11196,12 +11730,27 @@ var ApertureCore = class _ApertureCore {
11196
11730
  listener(signal);
11197
11731
  }
11198
11732
  }
11199
- commitFrame(frame) {
11200
- const previousTaskView = this.taskViews.get(frame.taskId);
11201
- const previousActive = previousTaskView.active;
11733
+ commitFrame(frame, retiredFrames = []) {
11734
+ const previousAttentionView = this.getAttentionView();
11735
+ const retiredKeys = /* @__PURE__ */ new Set();
11736
+ for (const retiredFrame of retiredFrames) {
11737
+ const key = `${retiredFrame.taskId}::${retiredFrame.interactionId}`;
11738
+ if (retiredKeys.has(key)) {
11739
+ continue;
11740
+ }
11741
+ retiredKeys.add(key);
11742
+ const retiredTaskView = this.taskViews.discard(
11743
+ retiredFrame.taskId,
11744
+ retiredFrame.interactionId
11745
+ );
11746
+ if (retiredFrame.taskId !== frame.taskId) {
11747
+ this.notifyFrame(retiredFrame.taskId, retiredTaskView.active);
11748
+ this.notifyTaskView(retiredFrame.taskId, retiredTaskView);
11749
+ }
11750
+ }
11202
11751
  const taskView = this.taskViews.setActive(frame.taskId, frame);
11203
- this.recordAttentionShift(previousActive, frame, frame.timing.updatedAt);
11204
- this.recordReturnSignal(previousTaskView, frame, frame.timing.updatedAt);
11752
+ const nextAttentionView = this.getAttentionView();
11753
+ this.recordAttentionTransition(previousAttentionView, nextAttentionView, frame.timing.updatedAt);
11205
11754
  this.recordSignal({
11206
11755
  kind: "presented",
11207
11756
  taskId: frame.taskId,
@@ -11230,6 +11779,7 @@ var ApertureCore = class _ApertureCore {
11230
11779
  currentEpisode: this.episodes.readFrameEpisode(currentFrame),
11231
11780
  attentionView,
11232
11781
  taskSignalSummary,
11782
+ continuitySignalSummary: taskSignalSummary,
11233
11783
  globalSignalSummary,
11234
11784
  taskAttentionState,
11235
11785
  globalAttentionState,
@@ -11238,12 +11788,21 @@ var ApertureCore = class _ApertureCore {
11238
11788
  }), this.timeSource());
11239
11789
  }
11240
11790
  applyClear(taskId) {
11791
+ const previousAttentionView = this.getAttentionView();
11241
11792
  const existingTaskView = this.taskViews.get(taskId);
11242
11793
  const hadAnyVisibleState = existingTaskView.active !== null || existingTaskView.queued.length > 0 || existingTaskView.ambient.length > 0;
11243
11794
  if (!hadAnyVisibleState) {
11244
11795
  return null;
11245
11796
  }
11797
+ for (const frame of [existingTaskView.active, ...existingTaskView.queued, ...existingTaskView.ambient]) {
11798
+ if (!frame) {
11799
+ continue;
11800
+ }
11801
+ this.episodes.resolveInteraction(frame.interactionId);
11802
+ }
11246
11803
  const taskView = this.taskViews.clear(taskId);
11804
+ const nextAttentionView = this.getAttentionView();
11805
+ this.recordAttentionTransition(previousAttentionView, nextAttentionView, this.nowIso());
11247
11806
  this.notifyFrame(taskId, null);
11248
11807
  this.notifyTaskView(taskId, taskView);
11249
11808
  this.notifyAttentionView();
@@ -11283,9 +11842,32 @@ var ApertureCore = class _ApertureCore {
11283
11842
  this.notifyAttentionView();
11284
11843
  return merged;
11285
11844
  }
11845
+ promotePeripheralEpisodeFrame(candidate, existingFrame) {
11846
+ const planned = this.applyResponseExpiry(this.planner.plan(candidate, existingFrame));
11847
+ const promoted = {
11848
+ ...planned,
11849
+ id: existingFrame.id
11850
+ };
11851
+ return this.commitFrame(promoted, [existingFrame]);
11852
+ }
11286
11853
  findFrameByInteractionId(taskId, interactionId) {
11287
11854
  return this.findFrame(taskId, interactionId);
11288
11855
  }
11856
+ shouldRetireSupersededEpisodeFrames(candidate, attentionView) {
11857
+ return this.findSupersededEpisodeFrames(candidate, attentionView).length > 0;
11858
+ }
11859
+ findSupersededEpisodeFrames(candidate, attentionView) {
11860
+ if (!candidate.episodeId || !hasSemanticRelationKind(candidate.relationHints, "supersedes")) {
11861
+ return [];
11862
+ }
11863
+ return [
11864
+ attentionView.active,
11865
+ ...attentionView.queued,
11866
+ ...attentionView.ambient
11867
+ ].filter(
11868
+ (frame) => frame !== null && frame.interactionId !== candidate.interactionId && readFrameEpisodeId(frame) === candidate.episodeId && !isDormantEpisodeState(readFrameEpisodeState(frame))
11869
+ );
11870
+ }
11289
11871
  applyResponseExpiry(frame) {
11290
11872
  if (this.responseExpiryMs === void 0 || frame.responseSpec?.kind === "none") {
11291
11873
  return frame;
@@ -11315,16 +11897,52 @@ var ApertureCore = class _ApertureCore {
11315
11897
  return expiresAt;
11316
11898
  }
11317
11899
  findPeripheralEpisodeFrame(episodeId, attentionView) {
11318
- const queued = attentionView.queued.find((frame) => readFrameEpisodeId(frame) === episodeId);
11900
+ const queued = attentionView.queued.find(
11901
+ (frame) => readFrameEpisodeId(frame) === episodeId && !isDormantEpisodeState(readFrameEpisodeState(frame))
11902
+ );
11319
11903
  if (queued) {
11320
11904
  return { frame: queued, bucket: "queue" };
11321
11905
  }
11322
- const ambient = attentionView.ambient.find((frame) => readFrameEpisodeId(frame) === episodeId);
11906
+ const ambient = attentionView.ambient.find(
11907
+ (frame) => readFrameEpisodeId(frame) === episodeId && !isDormantEpisodeState(readFrameEpisodeState(frame))
11908
+ );
11323
11909
  if (ambient) {
11324
11910
  return { frame: ambient, bucket: "ambient" };
11325
11911
  }
11326
11912
  return null;
11327
11913
  }
11914
+ augmentContinuitySignalSummary(taskId, candidate, evidence) {
11915
+ const continuitySignalSummary = this.resolveContinuitySignalSummary(taskId, candidate, evidence.taskSignalSummary);
11916
+ if (continuitySignalSummary === evidence.taskSignalSummary) {
11917
+ return evidence;
11918
+ }
11919
+ return {
11920
+ ...evidence,
11921
+ continuitySignalSummary
11922
+ };
11923
+ }
11924
+ resolveContinuitySignalSummary(taskId, candidate, taskSignalSummary) {
11925
+ if (!candidate.episodeId) {
11926
+ return taskSignalSummary;
11927
+ }
11928
+ const taskSignals = this.signals.list(taskId);
11929
+ const relatedEpisodeSignals = this.signals.list().filter(
11930
+ (signal) => signal.taskId !== taskId && readSignalEpisodeId(signal) === candidate.episodeId
11931
+ );
11932
+ if (relatedEpisodeSignals.length === 0) {
11933
+ return taskSignalSummary;
11934
+ }
11935
+ return summarizeAttentionSignals(
11936
+ [...taskSignals, ...relatedEpisodeSignals].sort(
11937
+ (left, right) => left.timestamp.localeCompare(right.timestamp)
11938
+ )
11939
+ );
11940
+ }
11941
+ shouldPromotePeripheralEpisodeFrame(explanation) {
11942
+ return explanation.continuityEvaluations?.some(
11943
+ (evaluation) => evaluation.rule === "deferral_escalation" && evaluation.kind === "override" && evaluation.decision?.kind === "activate"
11944
+ ) ?? false;
11945
+ }
11328
11946
  recordDeferredSignal(frame, reason, sourceFrame = frame) {
11329
11947
  this.recordSignal({
11330
11948
  kind: "deferred",
@@ -11410,8 +12028,17 @@ var ApertureCore = class _ApertureCore {
11410
12028
  }
11411
12029
  return Math.max(0, completedAt - startedAt);
11412
12030
  }
12031
+ recordAttentionTransition(previousAttentionView, nextAttentionView, timestamp) {
12032
+ const previous = previousAttentionView.active;
12033
+ const next = nextAttentionView.active;
12034
+ if (!next) {
12035
+ return;
12036
+ }
12037
+ this.recordAttentionShift(previous, next, timestamp);
12038
+ this.recordReturnSignal(previousAttentionView, next, timestamp);
12039
+ }
11413
12040
  recordAttentionShift(previous, next, timestamp) {
11414
- if (!previous || previous.interactionId === next.interactionId) {
12041
+ if (!previous || sameFrame(previous, next)) {
11415
12042
  return;
11416
12043
  }
11417
12044
  const destinationSignal = {
@@ -11438,8 +12065,8 @@ var ApertureCore = class _ApertureCore {
11438
12065
  });
11439
12066
  }
11440
12067
  }
11441
- recordReturnSignal(previousTaskView, next, timestamp) {
11442
- const from = previousTaskView.queued.some((frame) => frame.interactionId === next.interactionId) ? "queued" : previousTaskView.ambient.some((frame) => frame.interactionId === next.interactionId) ? "ambient" : null;
12068
+ recordReturnSignal(previousAttentionView, next, timestamp) {
12069
+ const from = previousAttentionView.queued.some((frame) => sameFrame(frame, next)) ? "queued" : previousAttentionView.ambient.some((frame) => sameFrame(frame, next)) ? "ambient" : null;
11443
12070
  if (!from) {
11444
12071
  return;
11445
12072
  }
@@ -11450,7 +12077,8 @@ var ApertureCore = class _ApertureCore {
11450
12077
  timestamp,
11451
12078
  frameId: next.id,
11452
12079
  ...next.source !== void 0 ? { source: next.source } : {},
11453
- from
12080
+ from,
12081
+ metadata: signalMetadataForFrame(next)
11454
12082
  });
11455
12083
  }
11456
12084
  observationSignal(kind, taskId, interactionId, frame, options) {
@@ -11606,6 +12234,17 @@ var ApertureCore = class _ApertureCore {
11606
12234
  }
11607
12235
  }
11608
12236
  };
12237
+ function readSignalEpisodeId(signal) {
12238
+ const episode = signal.metadata?.episode;
12239
+ if (!episode || typeof episode !== "object" || Array.isArray(episode)) {
12240
+ return null;
12241
+ }
12242
+ const id = episode.id;
12243
+ return typeof id === "string" && id.length > 0 ? id : null;
12244
+ }
12245
+ function sameFrame(left, right) {
12246
+ return left.id === right.id || left.taskId === right.taskId && left.interactionId === right.interactionId;
12247
+ }
11609
12248
 
11610
12249
  // src/aperture/types.ts
11611
12250
  function toStoredFrame(frame) {
@@ -13043,7 +13682,7 @@ function registerDataHandlers(ctx, store) {
13043
13682
  });
13044
13683
  }
13045
13684
 
13046
- // node_modules/.pnpm/@tomismeta+aperture-core@0.4.0/node_modules/@tomismeta/aperture-core/public-dist/semantic.js
13685
+ // node_modules/.pnpm/@tomismeta+aperture-core@0.4.2/node_modules/@tomismeta/aperture-core/public-dist/semantic.js
13047
13686
  function normalizeSemanticText2(value) {
13048
13687
  return value.toLowerCase().replace(/[^a-z0-9/.-]+/g, " ").trim();
13049
13688
  }
@@ -13091,10 +13730,13 @@ function detectSemanticRelationHints2(text) {
13091
13730
  return dedupeRelationHints2(hints);
13092
13731
  }
13093
13732
  function inferConsequenceFromSemanticText2(text, fallback, toolFamily) {
13733
+ if (isRoutineSuccessObservation2(text)) {
13734
+ return fallback;
13735
+ }
13094
13736
  if (toolFamily === "read" || toolFamily === "search") {
13095
13737
  return fallback;
13096
13738
  }
13097
- if (containsAnySemanticPhrase2(text, HIGH_RISK_PHRASES2)) {
13739
+ if (containsAnySemanticRiskPhrase2(text, HIGH_RISK_PHRASES2)) {
13098
13740
  return "high";
13099
13741
  }
13100
13742
  if (toolFamily === "write" || toolFamily === "edit" || toolFamily === "bash") {
@@ -13102,9 +13744,82 @@ function inferConsequenceFromSemanticText2(text, fallback, toolFamily) {
13102
13744
  }
13103
13745
  return fallback;
13104
13746
  }
13747
+ function detectObservationalFailureStatus2(text, toolFamily) {
13748
+ if (toolFamily !== "edit" && toolFamily !== "read") {
13749
+ return false;
13750
+ }
13751
+ return containsAnySemanticPhrase2(text, OBSERVATIONAL_READBACK_PHRASES2) || looksLikeTaggedFileObservation2(text) || looksLikeReadObservationPayload2(text);
13752
+ }
13753
+ function detectRoutineObservationalFailureLowConsequence2(text, toolFamily) {
13754
+ if (toolFamily === "search") {
13755
+ return looksLikeSearchResultOutput2(text);
13756
+ }
13757
+ if (toolFamily === "read") {
13758
+ if (looksLikeSearchResultOutput2(text)) {
13759
+ return true;
13760
+ }
13761
+ if (!looksLikeTaggedFileObservation2(text) && !looksLikeReadObservationPayload2(text)) {
13762
+ return false;
13763
+ }
13764
+ if (looksLikeSourceCodeObservation2(text)) {
13765
+ return false;
13766
+ }
13767
+ return looksLikeLogObservation2(text) || looksLikeBuildMetadataObservation2(text);
13768
+ }
13769
+ return false;
13770
+ }
13771
+ function detectExpectedDiagnosticFailure2(text, toolFamily) {
13772
+ if (toolFamily !== "bash") {
13773
+ return false;
13774
+ }
13775
+ return containsAnySemanticPhrase2(text, EXPECTED_DIAGNOSTIC_FAILURE_PHRASES2) && !containsAnySemanticPhrase2(text, TERMINAL_FAILURE_PHRASES2);
13776
+ }
13105
13777
  function containsAnySemanticPhrase2(value, phrases) {
13106
13778
  return phrases.some((phrase) => value.includes(phrase));
13107
13779
  }
13780
+ function containsAnySemanticRiskPhrase2(value, phrases) {
13781
+ return phrases.some((phrase) => containsSemanticRiskPhrase2(value, phrase));
13782
+ }
13783
+ function containsSemanticRiskPhrase2(value, phrase) {
13784
+ const normalizedPhrase = normalizeSemanticText2(phrase);
13785
+ if (!normalizedPhrase) {
13786
+ return false;
13787
+ }
13788
+ if (!normalizedPhrase.includes(" ")) {
13789
+ return hasWord2(value, normalizedPhrase);
13790
+ }
13791
+ return new RegExp(`(?:^|\\s)${escapeRegExp2(normalizedPhrase)}(?:\\s|$)`).test(value);
13792
+ }
13793
+ function looksLikeReadObservationPayload2(text) {
13794
+ if (!containsPathLikeToken2(text)) {
13795
+ return false;
13796
+ }
13797
+ return containsAnySemanticPhrase2(text, OBSERVATIONAL_PAYLOAD_PHRASES2) || containsCodeLikeContent2(text) || containsLineNumberedCodeContent2(text);
13798
+ }
13799
+ function looksLikeTaggedFileObservation2(text) {
13800
+ return containsAnySemanticPhrase2(text, TAGGED_FILE_OBSERVATION_PHRASES2) && containsPathLikeToken2(text);
13801
+ }
13802
+ function looksLikeSearchResultOutput2(text) {
13803
+ return SEARCH_RESULT_OUTPUT_PATTERN2.test(text) || containsPathLikeToken2(text) && /\bmatch(?:es)?\b/.test(text);
13804
+ }
13805
+ function containsPathLikeToken2(text) {
13806
+ return PATH_LIKE_TOKEN_PATTERN2.test(text);
13807
+ }
13808
+ function containsCodeLikeContent2(text) {
13809
+ return CODE_CONTENT_PATTERN2.test(text);
13810
+ }
13811
+ function containsLineNumberedCodeContent2(text) {
13812
+ return LINE_NUMBERED_CODE_PATTERN2.test(text);
13813
+ }
13814
+ function looksLikeSourceCodeObservation2(text) {
13815
+ return SOURCE_CODE_PATH_PATTERN2.test(text) || SOURCE_CODE_FILENAME_PATTERN2.test(text) || SOURCE_CODE_CONTENT_PATTERN2.test(text) || LINE_NUMBERED_SOURCE_CODE_PATTERN2.test(text);
13816
+ }
13817
+ function looksLikeLogObservation2(text) {
13818
+ return LOG_OUTPUT_PATTERN2.test(text) || containsAnySemanticPhrase2(text, LOG_LIKE_OBSERVATION_PHRASES2);
13819
+ }
13820
+ function looksLikeBuildMetadataObservation2(text) {
13821
+ return BUILD_METADATA_PATTERN2.test(text) || containsAnySemanticPhrase2(text, BUILD_METADATA_PHRASES2);
13822
+ }
13108
13823
  function readMetadataToolFamily2(metadata) {
13109
13824
  const value = metadata?.toolFamily;
13110
13825
  return typeof value === "string" ? value : null;
@@ -13180,6 +13895,70 @@ var HIGH_RISK_PHRASES2 = [
13180
13895
  "kill process",
13181
13896
  "migrate"
13182
13897
  ];
13898
+ var OBSERVATIONAL_READBACK_PHRASES2 = [
13899
+ "result of running cat -n",
13900
+ "result of running sed -n",
13901
+ "result of running grep",
13902
+ "result of running ls",
13903
+ "result of running find",
13904
+ "here s the result of running cat -n",
13905
+ "here s the result of running sed -n"
13906
+ ];
13907
+ var OBSERVATIONAL_PAYLOAD_PHRASES2 = [
13908
+ "observation",
13909
+ "contents of",
13910
+ "showing first",
13911
+ "showing top",
13912
+ "found"
13913
+ ];
13914
+ var TAGGED_FILE_OBSERVATION_PHRASES2 = [
13915
+ "path",
13916
+ "type file",
13917
+ "content"
13918
+ ];
13919
+ var ROUTINE_SUCCESS_PHRASES2 = [
13920
+ "ran successfully and did not produce any output",
13921
+ "command ran successfully and did not produce any output",
13922
+ "completed successfully and did not produce any output"
13923
+ ];
13924
+ var LOG_LIKE_OBSERVATION_PHRASES2 = [
13925
+ "tool-output",
13926
+ "dmesg"
13927
+ ];
13928
+ var BUILD_METADATA_PHRASES2 = [
13929
+ "makefile",
13930
+ "spdx-license-identifier",
13931
+ "patchlevel",
13932
+ "sublevel",
13933
+ "extraversion"
13934
+ ];
13935
+ var PATH_LIKE_TOKEN_PATTERN2 = /(?:^|\s)\/[a-z0-9._-]+(?:\/[a-z0-9._-]+)+(?:\s|$)/;
13936
+ var SEARCH_RESULT_OUTPUT_PATTERN2 = /\bfound\s+\d+\s+match(?:es)?\b|\bshowing\s+(?:first|top)\s+\d+\b|\bmatch(?:es)?\s+in\s+\d+\s+files?\b/;
13937
+ var CODE_CONTENT_PATTERN2 = /\b(import|from|export|class|def|function|const|let|var|return)\b/;
13938
+ var LINE_NUMBERED_CODE_PATTERN2 = /\b\d+\s+(?:import|from|export|class|def|function|const|let|var|return)\b/;
13939
+ var SOURCE_CODE_PATH_PATTERN2 = /\/[a-z0-9._/-]+\.(?:c|cc|cpp|cxx|h|hpp|ts|tsx|js|jsx|py|rb|go|rs|java|kt|swift)(?:\b|\/)/;
13940
+ var SOURCE_CODE_FILENAME_PATTERN2 = /\b[a-z0-9.-]+\.(?:c|cc|cpp|cxx|h|hpp|ts|tsx|js|jsx|py|rb|go|rs|java|kt|swift)\b/;
13941
+ var SOURCE_CODE_CONTENT_PATTERN2 = /\b(static|struct|enum|typedef|void|int|char|bool|return)\b/;
13942
+ var LINE_NUMBERED_SOURCE_CODE_PATTERN2 = /\b\d+\s+(?:static|struct|enum|typedef|void|int|char|bool|return)\b/;
13943
+ var LOG_OUTPUT_PATTERN2 = /\b\d+\s+\[\s*\d+\.\d+\]\s+[a-z0-9_.:-]+/;
13944
+ var BUILD_METADATA_PATTERN2 = /\b(?:version|patchlevel|sublevel|extraversion)\b/;
13945
+ var EXPECTED_DIAGNOSTIC_FAILURE_PHRASES2 = [
13946
+ "form is valid false",
13947
+ "form without instance is valid false",
13948
+ "form errors",
13949
+ "errorlist",
13950
+ "decompress result"
13951
+ ];
13952
+ var TERMINAL_FAILURE_PHRASES2 = [
13953
+ "traceback",
13954
+ "exception",
13955
+ "permission denied",
13956
+ "command not found",
13957
+ "segmentation fault"
13958
+ ];
13959
+ function isRoutineSuccessObservation2(text) {
13960
+ return containsAnySemanticPhrase2(text, ROUTINE_SUCCESS_PHRASES2);
13961
+ }
13183
13962
  var REPEAT_PHRASES2 = [
13184
13963
  "still",
13185
13964
  "again",
@@ -13328,7 +14107,13 @@ function inferSemanticInterpretation2(event) {
13328
14107
  factors: ["task.started"],
13329
14108
  relationHints: [],
13330
14109
  confidence: "high",
13331
- reasons: semanticReasonsForLifecycle2("task_started")
14110
+ reasons: semanticReasonsForLifecycle2("task_started"),
14111
+ provenance: {
14112
+ intentFrame: "inferred",
14113
+ activityClass: "inferred",
14114
+ consequence: "inferred",
14115
+ confidence: "inferred"
14116
+ }
13332
14117
  };
13333
14118
  case "task.updated":
13334
14119
  return inferTaskUpdateSemantics2(event);
@@ -13342,7 +14127,13 @@ function inferSemanticInterpretation2(event) {
13342
14127
  factors: ["task.completed"],
13343
14128
  relationHints: [],
13344
14129
  confidence: "high",
13345
- reasons: semanticReasonsForLifecycle2("completion")
14130
+ reasons: semanticReasonsForLifecycle2("completion"),
14131
+ provenance: {
14132
+ intentFrame: "inferred",
14133
+ activityClass: "inferred",
14134
+ consequence: "inferred",
14135
+ confidence: "inferred"
14136
+ }
13346
14137
  };
13347
14138
  case "task.cancelled":
13348
14139
  return {
@@ -13353,7 +14144,14 @@ function inferSemanticInterpretation2(event) {
13353
14144
  factors: ["task.cancelled"],
13354
14145
  relationHints: [],
13355
14146
  confidence: "high",
13356
- reasons: semanticReasonsForTaskStatus2("completed", { wasCancelled: true })
14147
+ reasons: semanticReasonsForTaskStatus2("completed", { wasCancelled: true }),
14148
+ provenance: {
14149
+ intentFrame: "inferred",
14150
+ activityClass: "inferred",
14151
+ consequence: "inferred",
14152
+ ...event.reason ? { whyNow: "inferred" } : {},
14153
+ confidence: "inferred"
14154
+ }
13357
14155
  };
13358
14156
  }
13359
14157
  }
@@ -13362,19 +14160,65 @@ function inferTaskUpdateSemantics2(event) {
13362
14160
  const impliedAsk = detectImpliedOperatorAsk2(text);
13363
14161
  const relationHints = detectSemanticRelationHints2(text);
13364
14162
  const taxonomyInput = buildTaxonomyInput2(event.title, event.summary, event.toolFamily);
13365
- const toolFamily = readExplicitSemanticToolFamily2(taxonomyInput) ?? inferSemanticToolFamily2(taxonomyInput) ?? void 0;
14163
+ const { toolFamily, source: toolFamilySource } = resolveSemanticToolFamily2(taxonomyInput, true);
14164
+ const relationProvenance = relationHints.length > 0 ? { relationHints: "inferred" } : {};
14165
+ const observationalFailure = event.status === "failed" && detectObservationalFailureStatus2(text, toolFamily);
14166
+ const routineObservationalFailureLowConsequence = event.status === "failed" && detectRoutineObservationalFailureLowConsequence2(text, toolFamily);
14167
+ const expectedDiagnosticFailure = event.status === "failed" && detectExpectedDiagnosticFailure2(text, toolFamily);
13366
14168
  switch (event.status) {
13367
14169
  case "failed":
14170
+ if (observationalFailure) {
14171
+ return {
14172
+ intentFrame: "status_update",
14173
+ activityClass: "status_update",
14174
+ ...toolFamily ? { toolFamily } : {},
14175
+ consequence: inferConsequenceFromSemanticText2(
14176
+ text,
14177
+ routineObservationalFailureLowConsequence ? "low" : "high",
14178
+ toolFamily
14179
+ ),
14180
+ factors: ["task.updated", "failed", "observational_failure"],
14181
+ relationHints,
14182
+ confidence: "high",
14183
+ reasons: [
14184
+ "task status indicates failure but the update reads like observational output"
14185
+ ],
14186
+ provenance: {
14187
+ intentFrame: "inferred",
14188
+ activityClass: "inferred",
14189
+ ...toolFamilySource === "explicit" ? { toolFamily: "source" } : toolFamilySource === "inferred" ? { toolFamily: "inferred" } : {},
14190
+ consequence: "inferred",
14191
+ ...relationProvenance,
14192
+ confidence: "inferred"
14193
+ }
14194
+ };
14195
+ }
13368
14196
  return {
13369
14197
  intentFrame: "failure",
13370
14198
  activityClass: "tool_failure",
13371
14199
  ...toolFamily ? { toolFamily } : {},
13372
- consequence: inferConsequenceFromSemanticText2(text, "high", toolFamily),
14200
+ consequence: inferConsequenceFromSemanticText2(
14201
+ text,
14202
+ routineObservationalFailureLowConsequence ? "low" : expectedDiagnosticFailure ? "medium" : "high",
14203
+ toolFamily
14204
+ ),
13373
14205
  whyNow: semanticWhyNowForTaskStatus2("failed") ?? "Work has failed and should be reviewed.",
13374
14206
  factors: ["task.updated", "failed"],
13375
14207
  relationHints,
13376
14208
  confidence: impliedAsk ? "medium" : "high",
13377
- reasons: semanticReasonsForTaskStatus2("failed", { impliedAsk })
14209
+ reasons: expectedDiagnosticFailure ? [
14210
+ ...semanticReasonsForTaskStatus2("failed", { impliedAsk }),
14211
+ "failure content looks like expected diagnostic output from repro work"
14212
+ ] : semanticReasonsForTaskStatus2("failed", { impliedAsk }),
14213
+ provenance: {
14214
+ intentFrame: "inferred",
14215
+ activityClass: "inferred",
14216
+ ...toolFamilySource === "explicit" ? { toolFamily: "source" } : toolFamilySource === "inferred" ? { toolFamily: "inferred" } : {},
14217
+ consequence: "inferred",
14218
+ whyNow: "inferred",
14219
+ ...relationProvenance,
14220
+ confidence: "inferred"
14221
+ }
13378
14222
  };
13379
14223
  case "blocked":
13380
14224
  return {
@@ -13386,7 +14230,16 @@ function inferTaskUpdateSemantics2(event) {
13386
14230
  factors: ["task.updated", "blocked"],
13387
14231
  relationHints,
13388
14232
  confidence: impliedAsk ? "medium" : "high",
13389
- reasons: semanticReasonsForTaskStatus2("blocked", { impliedAsk })
14233
+ reasons: semanticReasonsForTaskStatus2("blocked", { impliedAsk }),
14234
+ provenance: {
14235
+ intentFrame: "inferred",
14236
+ activityClass: "inferred",
14237
+ ...toolFamilySource === "explicit" ? { toolFamily: "source" } : toolFamilySource === "inferred" ? { toolFamily: "inferred" } : {},
14238
+ consequence: "inferred",
14239
+ whyNow: "inferred",
14240
+ ...relationProvenance,
14241
+ confidence: "inferred"
14242
+ }
13390
14243
  };
13391
14244
  case "running":
13392
14245
  case "waiting":
@@ -13403,17 +14256,31 @@ function inferTaskUpdateSemantics2(event) {
13403
14256
  factors: ["task.updated", event.status],
13404
14257
  relationHints,
13405
14258
  confidence: impliedAsk ? "low" : "high",
13406
- reasons: semanticReasonsForTaskStatus2(event.status, { impliedAsk })
14259
+ reasons: semanticReasonsForTaskStatus2(event.status, { impliedAsk }),
14260
+ provenance: {
14261
+ intentFrame: "inferred",
14262
+ activityClass: "inferred",
14263
+ ...toolFamilySource === "explicit" ? { toolFamily: "source" } : toolFamilySource === "inferred" ? { toolFamily: "inferred" } : {},
14264
+ consequence: "inferred",
14265
+ ...impliedAsk ? { whyNow: "inferred" } : {},
14266
+ ...relationProvenance,
14267
+ confidence: "inferred"
14268
+ }
13407
14269
  };
13408
14270
  }
13409
14271
  }
13410
14272
  function inferHumanInputSemantics2(event) {
13411
14273
  const taxonomyInput = buildTaxonomyInput2(event.title, event.summary, event.toolFamily, event.context);
13412
- const toolFamily = readExplicitSemanticToolFamily2(taxonomyInput) ?? inferSemanticToolFamily2(taxonomyInput) ?? void 0;
14274
+ const { toolFamily, source: toolFamilySource } = resolveSemanticToolFamily2(
14275
+ taxonomyInput,
14276
+ event.request.kind === "approval"
14277
+ );
13413
14278
  const text = normalizeSemanticText2(`${event.title} ${event.summary}`);
13414
14279
  const relationHints = detectSemanticRelationHints2(text);
13415
14280
  const baseConsequence = event.riskHint ?? consequenceFromRequestKind2(event.request.kind, toolFamily);
13416
14281
  const consequence = inferConsequenceFromSemanticText2(text, baseConsequence, toolFamily);
14282
+ const relationProvenance = relationHints.length > 0 ? { relationHints: "inferred" } : {};
14283
+ const toolFamilyProvenance = toolFamilySource === "explicit" ? { toolFamily: "source" } : toolFamilySource === "inferred" ? { toolFamily: "inferred" } : {};
13417
14284
  return {
13418
14285
  intentFrame: semanticIntentFrameForRequestKind2(event.request.kind),
13419
14286
  activityClass: semanticActivityClassForRequestKind2(event.request.kind),
@@ -13422,13 +14289,36 @@ function inferHumanInputSemantics2(event) {
13422
14289
  whyNow: semanticWhyNowForRequestKind2(event.request.kind, consequence),
13423
14290
  factors: ["human.input.requested", event.request.kind],
13424
14291
  relationHints,
13425
- confidence: event.riskHint ? "high" : toolFamily ? "medium" : "low",
14292
+ confidence: event.riskHint ? "high" : event.request.kind === "approval" && toolFamily ? "medium" : "low",
13426
14293
  reasons: [
13427
14294
  event.riskHint ? "source provided an explicit risk hint" : "request kind establishes an explicit operator decision point",
13428
- ...toolFamily ? ["tool family was inferred or supplied"] : []
13429
- ]
14295
+ ...toolFamilySource === "explicit" ? ["tool family was supplied by the source or context"] : toolFamilySource === "inferred" ? ["tool family was inferred from approval wording"] : []
14296
+ ],
14297
+ provenance: {
14298
+ intentFrame: "inferred",
14299
+ activityClass: "inferred",
14300
+ ...toolFamilyProvenance,
14301
+ consequence: event.riskHint ? "source" : "inferred",
14302
+ whyNow: "inferred",
14303
+ ...relationProvenance,
14304
+ confidence: event.riskHint ? "source" : "inferred"
14305
+ }
13430
14306
  };
13431
14307
  }
14308
+ function resolveSemanticToolFamily2(input, allowTextInference) {
14309
+ const explicit = readExplicitSemanticToolFamily2(input);
14310
+ if (explicit) {
14311
+ return { toolFamily: explicit, source: "explicit" };
14312
+ }
14313
+ if (!allowTextInference) {
14314
+ return { source: "none" };
14315
+ }
14316
+ const inferred = inferSemanticToolFamily2(input);
14317
+ if (inferred) {
14318
+ return { toolFamily: inferred, source: "inferred" };
14319
+ }
14320
+ return { source: "none" };
14321
+ }
13432
14322
  function applySemanticHints2(inferred, hints) {
13433
14323
  if (!hints) {
13434
14324
  return inferred;
@@ -13438,7 +14328,23 @@ function applySemanticHints2(inferred, hints) {
13438
14328
  ...pickDefined2(hints),
13439
14329
  factors: dedupeSemanticStrings2([...inferred.factors ?? [], ...hints.factors ?? []]),
13440
14330
  relationHints: [...hints.relationHints ?? inferred.relationHints],
13441
- reasons: dedupeSemanticStrings2([...inferred.reasons ?? [], ...hints.reasons ?? []])
14331
+ reasons: dedupeSemanticStrings2([...inferred.reasons ?? [], ...hints.reasons ?? []]),
14332
+ provenance: {
14333
+ ...inferred.provenance ?? {},
14334
+ ...hintedSemanticProvenance2(hints)
14335
+ }
14336
+ };
14337
+ }
14338
+ function hintedSemanticProvenance2(hints) {
14339
+ return {
14340
+ ...hints.intentFrame !== void 0 ? { intentFrame: "hint" } : {},
14341
+ ...hints.activityClass !== void 0 ? { activityClass: "hint" } : {},
14342
+ ...hints.toolFamily !== void 0 ? { toolFamily: "hint" } : {},
14343
+ ...hints.consequence !== void 0 ? { consequence: "hint" } : {},
14344
+ ...hints.whyNow !== void 0 ? { whyNow: "hint" } : {},
14345
+ ...hints.relationHints !== void 0 ? { relationHints: "hint" } : {},
14346
+ ...hints.confidence !== void 0 ? { confidence: "hint" } : {},
14347
+ ...hints.abstained !== void 0 ? { abstained: "hint" } : {}
13442
14348
  };
13443
14349
  }
13444
14350
  function pickDefined2(value) {