@agenr/skeln-plugin 3.3.0 → 2026.6.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.
Files changed (34) hide show
  1. package/dist/build-before-turn-artifact-NPUHVWFE.js +71 -0
  2. package/dist/build-recall-artifact-F3LS3PZX.js +62 -0
  3. package/dist/chunk-5AXMFBHR.js +14 -0
  4. package/dist/chunk-5AYIXQRF.js +4452 -0
  5. package/dist/{chunk-Z5X7T4QZ.js → chunk-5TIP2EPP.js} +1519 -2565
  6. package/dist/{chunk-5LADPJ4C.js → chunk-GAERET5Q.js} +138 -504
  7. package/dist/chunk-GF3PX3VM.js +41 -0
  8. package/dist/chunk-GKZQ5AG5.js +44 -0
  9. package/dist/chunk-LDJN7CVU.js +3231 -0
  10. package/dist/{chunk-ZYADFKX3.js → chunk-MC3C2XM5.js} +34 -1
  11. package/dist/chunk-NBS62ES5.js +3012 -0
  12. package/dist/chunk-NSLTJBUC.js +270 -0
  13. package/dist/chunk-OJSIZDZD.js +9 -0
  14. package/dist/chunk-OWGQWQUP.js +45 -0
  15. package/dist/chunk-Q5UTJXHZ.js +1069 -0
  16. package/dist/{chunk-M5M65AYP.js → chunk-SOQW7356.js} +271 -1934
  17. package/dist/chunk-VBPYU7GO.js +597 -0
  18. package/dist/chunk-VTHBPXDQ.js +1750 -0
  19. package/dist/{chunk-KH52KJSJ.js → chunk-XFJ4S4G2.js} +844 -39
  20. package/dist/chunk-Y5NB3FTH.js +106 -0
  21. package/dist/{chunk-RYMSM3OS.js → chunk-ZX55JBV2.js} +1710 -322
  22. package/dist/claim-slot-policy-CdrW_1l4.d.ts +13 -0
  23. package/dist/index.d.ts +630 -51
  24. package/dist/index.js +881 -4682
  25. package/dist/lifecycle-checkpoint-IAC5FCQU.js +154 -0
  26. package/dist/{claim-slot-policy-CQ-h0GaV.d.ts → ports-C4QkwDBS.d.ts} +168 -78
  27. package/dist/scan-6JKPOQHD.js +6 -0
  28. package/dist/service-EKFACEN6.js +15 -0
  29. package/dist/service-RHNB5AEQ.js +861 -0
  30. package/dist/sink-AUAAWC5O.js +8 -0
  31. package/package.json +1 -1
  32. package/dist/cli.d.ts +0 -1
  33. package/dist/internal-eval-server.d.ts +0 -1
  34. package/dist/internal-recall-eval-server.d.ts +0 -1
@@ -1,3 +1,11 @@
1
+ import {
2
+ isCurrentlyValidMemory,
3
+ isStaleMemory,
4
+ isWithinValidityWindow,
5
+ normalizeClaimKey,
6
+ resolveKeyedDurableLifecycleStatus
7
+ } from "./chunk-VBPYU7GO.js";
8
+
1
9
  // src/core/recall/cross-encoder.ts
2
10
  var DEFAULT_CROSS_ENCODER_TOP_K = 10;
3
11
  var DEFAULT_CROSS_ENCODER_ALPHA = 0.6;
@@ -125,6 +133,41 @@ function elapsedMs(startedAt) {
125
133
  return Math.max(0, Date.now() - startedAt);
126
134
  }
127
135
 
136
+ // src/core/recall/entry-lineage.ts
137
+ function describeDurableLineageState(entry, nowMs) {
138
+ if (entry.superseded_by) {
139
+ return "superseded";
140
+ }
141
+ if (!isCurrentlyValidMemory(entry, nowMs)) {
142
+ return "historical";
143
+ }
144
+ return "current";
145
+ }
146
+ function formatDurableClaimLifecycle(entry) {
147
+ const status = resolveKeyedDurableLifecycleStatus(entry);
148
+ return status === "no_key" ? "no-key" : status;
149
+ }
150
+ function summarizeClaimFamilyTransition(entries, nowMs) {
151
+ const current = entries.find((entry) => isCurrentlyValidMemory(entry, nowMs));
152
+ const prior = [...entries].reverse().find((entry) => entry.id !== current?.id && isHistoricalFamilyMember(entry, nowMs));
153
+ if (current && prior) {
154
+ return `${prior.id} -> ${current.id}`;
155
+ }
156
+ if (prior) {
157
+ return `${prior.id} is historical with no current sibling in the traced family`;
158
+ }
159
+ if (current) {
160
+ return `${current.id} is the only current sibling in the traced family`;
161
+ }
162
+ return void 0;
163
+ }
164
+ function isHistoricalFamilyMember(entry, nowMs) {
165
+ if (entry.superseded_by) {
166
+ return true;
167
+ }
168
+ return !isCurrentlyValidMemory(entry, nowMs);
169
+ }
170
+
128
171
  // src/core/recall/fusion.ts
129
172
  var DEFAULT_RRF_RANK_CONSTANT = 60;
130
173
  var DEFAULT_RRF_SMALL_POOL_RANK_CONSTANT = 8;
@@ -268,9 +311,10 @@ var STOP_WORDS = /* @__PURE__ */ new Set([
268
311
  ]);
269
312
  var FTS_OPERATOR_TOKENS = /* @__PURE__ */ new Set(["or", "not", "near"]);
270
313
  var LEXICAL_TOKEN_PATTERN = /[\p{L}\p{N}][\p{L}\p{N}._-]*/gu;
314
+ var TOKEN_EDGE_PUNCTUATION_PATTERN = /^[._-]+|[._-]+$/gu;
271
315
  function tokenize(text) {
272
316
  const matches = normalizeLexicalText(text).match(LEXICAL_TOKEN_PATTERN) ?? [];
273
- return matches.filter((token) => token.length >= 2 && !STOP_WORDS.has(token));
317
+ return matches.map((token) => token.replace(TOKEN_EDGE_PUNCTUATION_PATTERN, "")).filter((token) => token.length >= 2 && !STOP_WORDS.has(token));
274
318
  }
275
319
  function buildLexicalPlan(text) {
276
320
  const trimmed = text.trim();
@@ -696,468 +740,6 @@ function sanitizeInteger(value, fallback) {
696
740
  return Math.floor(value);
697
741
  }
698
742
 
699
- // src/core/claim-key.ts
700
- var UNKNOWN_SEGMENT = "unknown";
701
- var SELF_REFERENTIAL_ENTITIES = /* @__PURE__ */ new Set(["i", "me", "myself", "the_user", "user", "we", "our_team", "the_project", "this_project"]);
702
- var GENERIC_ENTITIES = /* @__PURE__ */ new Set([
703
- "app",
704
- "company",
705
- "config",
706
- "data",
707
- "device",
708
- "entity",
709
- "environment",
710
- "item",
711
- "organization",
712
- "person",
713
- "place",
714
- "project",
715
- "service",
716
- "setting",
717
- "system",
718
- "team",
719
- "thing",
720
- "user",
721
- "workspace"
722
- ]);
723
- var GENERIC_ATTRIBUTES = /* @__PURE__ */ new Set(["info", "details", "config", "stuff", "thing", "data"]);
724
- var COMPACTION_RELATION_TOKENS = /* @__PURE__ */ new Set([
725
- "after",
726
- "before",
727
- "depend",
728
- "depends",
729
- "follows",
730
- "follow",
731
- "keep",
732
- "keeps",
733
- "maintain",
734
- "maintains",
735
- "need",
736
- "needs",
737
- "precede",
738
- "precedes",
739
- "preserve",
740
- "preserves",
741
- "require",
742
- "required",
743
- "requires",
744
- "retain",
745
- "retains"
746
- ]);
747
- var COMPACTION_BREAK_TOKENS = /* @__PURE__ */ new Set(["about", "across", "and", "between", "during", "for", "from", "into", "onto", "or", "to", "with"]);
748
- var COMPACTION_WEAK_LEADING_TOKENS = /* @__PURE__ */ new Set(["actual", "authoritative", "canonical", "concrete", "current", "durable", "existing", "real"]);
749
- var ACTION_CONDITION_TOKENS = /* @__PURE__ */ new Set(["activate", "activation", "apply", "fire", "launch", "run", "start", "trigger"]);
750
- var TRAILING_OBJECT_COMPACTION_PREPOSITIONS = /* @__PURE__ */ new Set(["about", "for", "from", "into", "onto", "to", "with"]);
751
- var TRAILING_OBJECT_TRANSFER_HEADS = /* @__PURE__ */ new Set([
752
- "access",
753
- "boundary",
754
- "condition",
755
- "contract",
756
- "guide",
757
- "path",
758
- "policy",
759
- "preference",
760
- "process",
761
- "rule",
762
- "schedule",
763
- "support",
764
- "surface",
765
- "window",
766
- "workflow"
767
- ]);
768
- var STABLE_ATTRIBUTE_HEADS = /* @__PURE__ */ new Set([
769
- "access",
770
- "boundary",
771
- "condition",
772
- "contract",
773
- "default",
774
- "dependency",
775
- "guide",
776
- "mode",
777
- "order",
778
- "path",
779
- "policy",
780
- "preference",
781
- "preservation",
782
- "process",
783
- "requirement",
784
- "rule",
785
- "schedule",
786
- "setting",
787
- "status",
788
- "strategy",
789
- "support",
790
- "surface",
791
- "timezone",
792
- "truth",
793
- "version",
794
- "window",
795
- "workflow"
796
- ]);
797
- function normalizeClaimKeySegment(value) {
798
- return value.trim().toLowerCase().replace(/[^a-z0-9]+/g, "_").replace(/_+/g, "_").replace(/^_+|_+$/g, "");
799
- }
800
- function normalizeClaimKey(value) {
801
- const trimmed = value.trim();
802
- if (trimmed.length === 0) {
803
- return { ok: false, reason: "empty" };
804
- }
805
- const slashCount = Array.from(trimmed).filter((character) => character === "/").length;
806
- if (slashCount === 0) {
807
- return { ok: false, reason: "missing_separator" };
808
- }
809
- if (slashCount !== 1) {
810
- return { ok: false, reason: "too_many_segments" };
811
- }
812
- const [rawEntity = "", rawAttribute = ""] = trimmed.split("/");
813
- const entity = normalizeClaimKeySegment(rawEntity);
814
- if (entity.length === 0) {
815
- return { ok: false, reason: "empty_entity" };
816
- }
817
- const attribute = normalizeClaimKeySegment(rawAttribute);
818
- if (attribute.length === 0) {
819
- return { ok: false, reason: "empty_attribute" };
820
- }
821
- if (entity === UNKNOWN_SEGMENT && attribute === UNKNOWN_SEGMENT) {
822
- return { ok: false, reason: "unknown_pair" };
823
- }
824
- return {
825
- ok: true,
826
- value: {
827
- claimKey: `${entity}/${attribute}`,
828
- entity,
829
- attribute
830
- }
831
- };
832
- }
833
- function compactClaimKey(claimKey) {
834
- const normalized = normalizeClaimKey(claimKey);
835
- if (!normalized.ok) {
836
- return null;
837
- }
838
- let attributeTokens = normalized.value.attribute.split("_").filter((token) => token.length > 0);
839
- const entityTokens = normalized.value.entity.split("_").filter((token) => token.length > 0);
840
- const reasons = [];
841
- if (entityTokens.length > 0 && startsWithTokens(attributeTokens, entityTokens) && attributeTokens.length > entityTokens.length) {
842
- attributeTokens = attributeTokens.slice(entityTokens.length);
843
- reasons.push("removed duplicated entity prefix from attribute");
844
- }
845
- if (entityTokens.length > 0 && attributeTokens.length > entityTokens.length + 1 && endsWithTokens(attributeTokens, entityTokens) && TRAILING_OBJECT_COMPACTION_PREPOSITIONS.has(attributeTokens[attributeTokens.length - entityTokens.length - 1] ?? "")) {
846
- attributeTokens = attributeTokens.slice(0, attributeTokens.length - entityTokens.length - 1);
847
- reasons.push("removed duplicated entity suffix from attribute");
848
- }
849
- const sourceOfTruthCompaction = compactSourceOfTruthAttribute(attributeTokens);
850
- if (sourceOfTruthCompaction) {
851
- attributeTokens = sourceOfTruthCompaction.attributeTokens;
852
- reasons.push(sourceOfTruthCompaction.reason);
853
- } else {
854
- const relationCompaction = compactRelationAttribute(attributeTokens);
855
- if (relationCompaction) {
856
- attributeTokens = relationCompaction.attributeTokens;
857
- reasons.push(relationCompaction.reason);
858
- } else {
859
- const trailingObjectCompaction = compactTrailingObjectAttribute(attributeTokens);
860
- if (trailingObjectCompaction) {
861
- attributeTokens = trailingObjectCompaction.attributeTokens;
862
- reasons.push(trailingObjectCompaction.reason);
863
- }
864
- }
865
- }
866
- const attribute = attributeTokens.join("_");
867
- if (attribute.length === 0) {
868
- return {
869
- claimKey: normalized.value.claimKey,
870
- entity: normalized.value.entity,
871
- attribute: normalized.value.attribute,
872
- compactedFrom: null,
873
- reason: null
874
- };
875
- }
876
- const compactedClaimKey = `${normalized.value.entity}/${attribute}`;
877
- return {
878
- claimKey: compactedClaimKey,
879
- entity: normalized.value.entity,
880
- attribute,
881
- compactedFrom: compactedClaimKey !== normalized.value.claimKey ? normalized.value.claimKey : null,
882
- reason: reasons.length > 0 ? joinCompactionReasons(reasons) : null
883
- };
884
- }
885
- function validateExtractedClaimKey(claimKey) {
886
- if (SELF_REFERENTIAL_ENTITIES.has(claimKey.entity)) {
887
- return {
888
- ok: false,
889
- reason: "self_referential_entity",
890
- value: claimKey
891
- };
892
- }
893
- if (GENERIC_ATTRIBUTES.has(claimKey.attribute)) {
894
- return {
895
- ok: false,
896
- reason: "generic_attribute",
897
- value: claimKey
898
- };
899
- }
900
- if (isValueShapedAttribute(claimKey.attribute)) {
901
- return {
902
- ok: false,
903
- reason: "value_shaped_attribute",
904
- value: claimKey
905
- };
906
- }
907
- return {
908
- ok: true,
909
- value: claimKey
910
- };
911
- }
912
- function inspectClaimKey(value) {
913
- const rawClaimKey = value.trim();
914
- const normalized = normalizeClaimKey(rawClaimKey);
915
- if (!normalized.ok) {
916
- return {
917
- rawClaimKey,
918
- canonical: false,
919
- normalizationFailure: normalized.reason,
920
- suspectReasons: []
921
- };
922
- }
923
- const suspectReasons = /* @__PURE__ */ new Set();
924
- const validation = validateExtractedClaimKey(normalized.value);
925
- if (!validation.ok) {
926
- suspectReasons.add(validation.reason);
927
- }
928
- if (GENERIC_ENTITIES.has(normalized.value.entity)) {
929
- suspectReasons.add("generic_entity");
930
- }
931
- return {
932
- rawClaimKey,
933
- canonical: normalized.value.claimKey === rawClaimKey,
934
- normalized: normalized.value,
935
- suspectReasons: [...suspectReasons]
936
- };
937
- }
938
- function isTrustedClaimKeyForCleanup(value) {
939
- const inspection = inspectClaimKey(value);
940
- return Boolean(inspection.canonical && inspection.normalized && inspection.suspectReasons.length === 0);
941
- }
942
- function describeClaimKeyNormalizationFailure(reason) {
943
- switch (reason) {
944
- case "empty":
945
- return "claim key was empty";
946
- case "missing_separator":
947
- return "claim key must contain exactly one '/'";
948
- case "too_many_segments":
949
- return "claim key must contain exactly one '/'";
950
- case "empty_entity":
951
- return "claim key entity was empty after normalization";
952
- case "empty_attribute":
953
- return "claim key attribute was empty after normalization";
954
- case "unknown_pair":
955
- return 'claim key "unknown/unknown" is not allowed';
956
- }
957
- }
958
- function describeExtractedClaimKeyRejection(reason, claimKey) {
959
- switch (reason) {
960
- case "self_referential_entity":
961
- return `entity "${claimKey.entity}" is self-referential`;
962
- case "generic_attribute":
963
- return `attribute "${claimKey.attribute}" is too generic`;
964
- case "value_shaped_attribute":
965
- return `attribute "${claimKey.attribute}" looks value-shaped`;
966
- }
967
- }
968
- function describeClaimKeySuspicion(reason, claimKey) {
969
- switch (reason) {
970
- case "generic_entity":
971
- return `entity "${claimKey.entity}" is too generic`;
972
- case "self_referential_entity":
973
- case "generic_attribute":
974
- case "value_shaped_attribute":
975
- return describeExtractedClaimKeyRejection(reason, claimKey);
976
- }
977
- }
978
- function isValueShapedAttribute(attribute) {
979
- return /^\d+(?:_\d+)*$/u.test(attribute) || /^v\d+(?:_\d+)*$/u.test(attribute);
980
- }
981
- function compactSourceOfTruthAttribute(attributeTokens) {
982
- const sourceOfTruthIndex = findSourceOfTruthPhraseIndex(attributeTokens);
983
- if (sourceOfTruthIndex === -1) {
984
- return null;
985
- }
986
- const normalizedPhrase = ["source", "of", "truth"];
987
- if (attributeTokens.length === normalizedPhrase.length && startsWithTokens(attributeTokens, normalizedPhrase)) {
988
- return null;
989
- }
990
- const before = attributeTokens.slice(0, sourceOfTruthIndex);
991
- const after = attributeTokens.slice(sourceOfTruthIndex + normalizedPhrase.length);
992
- const leadingAllowed = before.every((token) => COMPACTION_WEAK_LEADING_TOKENS.has(token));
993
- const hasMixedStableFamily = before.some((token) => STABLE_ATTRIBUTE_HEADS.has(token)) || after.some((token) => STABLE_ATTRIBUTE_HEADS.has(token));
994
- const hasConjunctionNoise = before.includes("and") || before.includes("or") || after.includes("and") || after.includes("or");
995
- if (!leadingAllowed || hasMixedStableFamily || hasConjunctionNoise) {
996
- return null;
997
- }
998
- return {
999
- attributeTokens: normalizedPhrase,
1000
- reason: "collapsed source-of-truth phrasing into the stable canonical slot"
1001
- };
1002
- }
1003
- function compactRelationAttribute(attributeTokens) {
1004
- const relationIndex = attributeTokens.findIndex((token) => COMPACTION_RELATION_TOKENS.has(token));
1005
- if (relationIndex === -1) {
1006
- return null;
1007
- }
1008
- const relation = attributeTokens[relationIndex] ?? "";
1009
- const left = attributeTokens.slice(0, relationIndex);
1010
- const right = attributeTokens.slice(relationIndex + 1);
1011
- if (left.length === 0 && right.length === 0) {
1012
- return null;
1013
- }
1014
- if (isRequirementRelation(relation)) {
1015
- const conditionAction = extractConditionAction(right);
1016
- if (conditionAction) {
1017
- return {
1018
- attributeTokens: [conditionAction, "condition"],
1019
- reason: `collapsed a sentence-like ${conditionAction} requirement into a stable condition slot`
1020
- };
1021
- }
1022
- const requirementFocus = extractCompactionFocus(right, 2) ?? extractCompactionFocus(left, 2);
1023
- if (!requirementFocus) {
1024
- return null;
1025
- }
1026
- return {
1027
- attributeTokens: [...requirementFocus, "requirement"],
1028
- reason: "collapsed a sentence-like requirement phrase into a stable requirement slot"
1029
- };
1030
- }
1031
- if (isOrderingRelation(relation)) {
1032
- const orderingFocus = extractCompactionFocus(right, 2) ?? extractCompactionFocus(left, 2);
1033
- if (!orderingFocus) {
1034
- return null;
1035
- }
1036
- return {
1037
- attributeTokens: [...orderingFocus, "order"],
1038
- reason: "collapsed a sentence-like ordering phrase into a stable order slot"
1039
- };
1040
- }
1041
- if (isPreservationRelation(relation)) {
1042
- const preservationFocus = extractCompactionFocus(right, 2) ?? extractCompactionFocus(left, 2);
1043
- if (!preservationFocus) {
1044
- return null;
1045
- }
1046
- return {
1047
- attributeTokens: [...preservationFocus, "preservation"],
1048
- reason: "collapsed a sentence-like preservation phrase into a stable preservation slot"
1049
- };
1050
- }
1051
- return null;
1052
- }
1053
- function compactTrailingObjectAttribute(attributeTokens) {
1054
- const prepositionIndex = attributeTokens.findIndex((token) => TRAILING_OBJECT_COMPACTION_PREPOSITIONS.has(token));
1055
- if (prepositionIndex <= 0 || prepositionIndex >= attributeTokens.length - 1) {
1056
- return null;
1057
- }
1058
- const left = trimWeakLeadingTokens(attributeTokens.slice(0, prepositionIndex));
1059
- const right = attributeTokens.slice(prepositionIndex + 1);
1060
- if (left.length === 0 || left.length > 3 || left.includes("and") || left.includes("or") || left.some((token) => COMPACTION_RELATION_TOKENS.has(token))) {
1061
- return null;
1062
- }
1063
- const head = left[left.length - 1];
1064
- if (!head || !TRAILING_OBJECT_TRANSFER_HEADS.has(head)) {
1065
- return null;
1066
- }
1067
- const objectFocus = extractCompactionFocus(right, 2);
1068
- if (!objectFocus) {
1069
- return null;
1070
- }
1071
- const headCore = extractStableHeadCore(left, 2);
1072
- if (!headCore) {
1073
- return null;
1074
- }
1075
- return {
1076
- attributeTokens: [...objectFocus, ...headCore],
1077
- reason: "collapsed a trailing object phrase into a compact stable slot name"
1078
- };
1079
- }
1080
- function findSourceOfTruthPhraseIndex(tokens) {
1081
- for (let index = 0; index <= tokens.length - 3; index += 1) {
1082
- if (tokens[index] === "source" && tokens[index + 1] === "of" && tokens[index + 2] === "truth") {
1083
- return index;
1084
- }
1085
- }
1086
- return -1;
1087
- }
1088
- function extractConditionAction(tokens) {
1089
- for (let index = tokens.length - 1; index >= 0; index -= 1) {
1090
- const token = tokens[index];
1091
- if (token && ACTION_CONDITION_TOKENS.has(token)) {
1092
- return token;
1093
- }
1094
- }
1095
- return null;
1096
- }
1097
- function extractCompactionFocus(tokens, limit) {
1098
- const compactable = trimWeakLeadingTokens(tokens).filter((token) => token.length > 0);
1099
- const segments = splitTokensOnBreaks(compactable).filter((segment) => segment.length > 0);
1100
- const preferredSegment = segments[0];
1101
- if (!preferredSegment || preferredSegment.length === 0) {
1102
- return null;
1103
- }
1104
- return preferredSegment.slice(0, limit);
1105
- }
1106
- function extractStableHeadCore(tokens, limit) {
1107
- const compactable = trimWeakLeadingTokens(tokens).filter((token) => token.length > 0);
1108
- const head = compactable[compactable.length - 1];
1109
- if (!head || !STABLE_ATTRIBUTE_HEADS.has(head)) {
1110
- return null;
1111
- }
1112
- return compactable.slice(Math.max(0, compactable.length - limit));
1113
- }
1114
- function splitTokensOnBreaks(tokens) {
1115
- const segments = [];
1116
- let current = [];
1117
- for (const token of tokens) {
1118
- if (COMPACTION_BREAK_TOKENS.has(token)) {
1119
- if (current.length > 0) {
1120
- segments.push(current);
1121
- current = [];
1122
- }
1123
- continue;
1124
- }
1125
- current.push(token);
1126
- }
1127
- if (current.length > 0) {
1128
- segments.push(current);
1129
- }
1130
- return segments;
1131
- }
1132
- function trimWeakLeadingTokens(tokens) {
1133
- let start = 0;
1134
- while (start < tokens.length && COMPACTION_WEAK_LEADING_TOKENS.has(tokens[start] ?? "")) {
1135
- start += 1;
1136
- }
1137
- return tokens.slice(start);
1138
- }
1139
- function joinCompactionReasons(reasons) {
1140
- if (reasons.length <= 1) {
1141
- return reasons[0] ?? "";
1142
- }
1143
- return `${reasons.slice(0, -1).join(", ")} and ${reasons[reasons.length - 1]}`;
1144
- }
1145
- function isRequirementRelation(token) {
1146
- return token === "depend" || token === "depends" || token === "need" || token === "needs" || token === "required" || token === "require" || token === "requires";
1147
- }
1148
- function isOrderingRelation(token) {
1149
- return token === "after" || token === "before" || token === "follow" || token === "follows" || token === "precede" || token === "precedes";
1150
- }
1151
- function isPreservationRelation(token) {
1152
- return token === "keep" || token === "keeps" || token === "maintain" || token === "maintains" || token === "preserve" || token === "preserves" || token === "retain" || token === "retains";
1153
- }
1154
- function startsWithTokens(tokens, prefix) {
1155
- return prefix.every((token, index) => tokens[index] === token);
1156
- }
1157
- function endsWithTokens(tokens, suffix) {
1158
- return suffix.every((token, index) => tokens[tokens.length - suffix.length + index] === token);
1159
- }
1160
-
1161
743
  // src/core/claim-slot-policy.ts
1162
744
  var MULTIVALUED_ATTRIBUTE_HEADS = /* @__PURE__ */ new Set(["access", "dependency", "guide", "integration", "preference", "requirement", "support"]);
1163
745
  function resolveClaimSlotPolicy(claimKey, config) {
@@ -1294,6 +876,38 @@ var inferMonthAnchor = (monthName, now) => {
1294
876
  return new Date(Date.UTC(year, monthIndex, 15));
1295
877
  };
1296
878
 
879
+ // src/core/recall/as-of-validity.ts
880
+ function resolveRecallValidAsOf(params) {
881
+ if (params.rankingProfile === "historical_state") {
882
+ return null;
883
+ }
884
+ return new Date(params.asOfDate ? params.asOfDate.getTime() : params.nowMs);
885
+ }
886
+ function applyAsOfValidityFilter(mergeOutcome, summary, params) {
887
+ const asOf = resolveRecallValidAsOf(params);
888
+ if (asOf === null) {
889
+ return;
890
+ }
891
+ const asOfMs = asOf.getTime();
892
+ const removed = /* @__PURE__ */ new Set();
893
+ for (const [id, candidate] of mergeOutcome.merged) {
894
+ if (!isWithinValidityWindow(candidate.entry.valid_from, candidate.entry.valid_to, asOfMs)) {
895
+ mergeOutcome.merged.delete(id);
896
+ removed.add(id);
897
+ }
898
+ }
899
+ if (removed.size > 0) {
900
+ mergeOutcome.vectorRanks = mergeOutcome.vectorRanks.filter((id) => !removed.has(id));
901
+ mergeOutcome.ftsRanks = mergeOutcome.ftsRanks.filter((id) => !removed.has(id));
902
+ }
903
+ summary.filtering.asOfValidity = {
904
+ applied: true,
905
+ anchor: new Date(asOfMs).toISOString(),
906
+ source: params.asOfDate ? "explicit_as_of" : "now",
907
+ excludedCount: removed.size
908
+ };
909
+ }
910
+
1297
911
  // src/core/recall/trace.ts
1298
912
  var NOOP_RECALL_TRACE_SINK = {
1299
913
  reportSummary() {
@@ -1308,7 +922,7 @@ var HISTORICAL_NEIGHBORHOOD_FAMILIES = ["supersession_chain", "claim_key_sibling
1308
922
  var MIN_VECTOR_ONLY_EVIDENCE = 0.3;
1309
923
  var HISTORICAL_STATE_FLAT_RECENCY = 0.5;
1310
924
  var HISTORICAL_PREDECESSOR_BOOST = 0.08;
1311
- var HISTORICAL_RETIRED_PREDECESSOR_BOOST = 0.06;
925
+ var HISTORICAL_STALE_PREDECESSOR_BOOST = 0.06;
1312
926
  var HISTORICAL_OLDER_STATE_BOOST = 0.08;
1313
927
  var HISTORICAL_LINEAGE_GAP_MARGIN = 0.02;
1314
928
  var HISTORICAL_LINEAGE_MAX_BONUS = 0.45;
@@ -1343,14 +957,20 @@ var MIN_VECTOR_WITHOUT_GROUNDED_LEXICAL_SUPPORT = 0.45;
1343
957
  var GROUNDING_SORT_MAX_SCORE_GAP = 0.03;
1344
958
  async function recall(query, ports, options = {}) {
1345
959
  const text = query.text.trim();
960
+ const now = options.now ?? /* @__PURE__ */ new Date();
961
+ const nowMs = now.getTime();
1346
962
  const limit = normalizeLimit(query.limit);
1347
963
  const threshold = normalizeThreshold(query.threshold);
1348
964
  const budget = normalizeBudget(query.budget);
1349
- const asOfDate = query.asOf ? parseAroundDate(query.asOf) : null;
1350
- const aroundDate = query.around !== void 0 ? parseAroundDate(query.around) : inferAroundDate(text);
1351
- const since = query.since ? parseRelativeDate(query.since) : null;
1352
- const until = query.until ? parseRelativeDate(query.until) : null;
1353
- const filters = buildEntryFilters(query.types, query.tags, since, until);
965
+ const asOfDate = query.asOf ? parseAroundDate(query.asOf, now) : null;
966
+ const aroundDate = query.around !== void 0 ? parseAroundDate(query.around, now) : inferAroundDate(text, now);
967
+ const since = query.since ? parseRelativeDate(query.since, now) : null;
968
+ const until = query.until ? parseRelativeDate(query.until, now) : null;
969
+ const filters = buildDurableFilters(query.types, query.tags, since, until, {
970
+ asOfDate,
971
+ nowMs,
972
+ rankingProfile: query.rankingProfile
973
+ });
1354
974
  const trace = options.trace ?? createNoopRecallTraceSink();
1355
975
  const slotPolicyConfig = options.slotPolicyConfig;
1356
976
  const summary = buildRecallTraceSummary({
@@ -1413,6 +1033,11 @@ async function recall(query, ports, options = {}) {
1413
1033
  summary.degraded.lexicalOnly = summary.degraded.active && queryEmbedding.length === 0;
1414
1034
  const mergeStartedAt = Date.now();
1415
1035
  const mergeOutcome = mergeCandidates(vectorCandidates, ftsCandidates);
1036
+ applyAsOfValidityFilter(mergeOutcome, summary, {
1037
+ rankingProfile: query.rankingProfile,
1038
+ asOfDate,
1039
+ nowMs
1040
+ });
1416
1041
  const neighborhoodEnabled = options.rankingPolicy?.neighborhood !== "disabled";
1417
1042
  const expansionRanks = neighborhoodEnabled ? await expandEntryNeighborhood(mergeOutcome.merged, queryEmbedding, ports, {
1418
1043
  rankingProfile: query.rankingProfile,
@@ -1434,18 +1059,20 @@ async function recall(query, ports, options = {}) {
1434
1059
  asOfDate,
1435
1060
  aroundDate,
1436
1061
  aroundRadius: query.aroundRadius,
1437
- rankingProfile: query.rankingProfile
1062
+ rankingProfile: query.rankingProfile,
1063
+ now
1438
1064
  })
1439
1065
  ),
1440
1066
  {
1441
1067
  aroundDate,
1442
- rankingProfile: query.rankingProfile
1068
+ rankingProfile: query.rankingProfile,
1069
+ nowMs
1443
1070
  },
1444
1071
  summary.claimKey,
1445
1072
  slotPolicyConfig
1446
1073
  );
1447
1074
  const rerankedCandidates = neighborhoodEnabled ? applySeededEntryRerank(historicallyBoosted, summary.neighborhood) : historicallyBoosted;
1448
- const shaped = applyClaimKeyResultShaping(rerankedCandidates, summary.claimKey, slotPolicyConfig).sort((left, right) => right.score - left.score);
1075
+ const shaped = applyClaimKeyResultShaping(rerankedCandidates, summary.claimKey, nowMs, slotPolicyConfig).sort((left, right) => right.score - left.score);
1449
1076
  const diversified = applyMmrDiversification(shaped, queryEmbedding, options.rankingPolicy, summary.mmr);
1450
1077
  const scored = await applyEntryCrossEncoderRerank(diversified, text, ports.crossEncoder, options.rankingPolicy, summary.crossEncoder);
1451
1078
  summary.timings.scoreCandidatesMs = elapsedMs2(scoreStartedAt);
@@ -1550,7 +1177,7 @@ function buildRecallTraceSummary(params) {
1550
1177
  expansionRequested: false,
1551
1178
  expansionAvailable: false,
1552
1179
  familiesRequested: [],
1553
- includeRetired: false,
1180
+ includeHistorical: false,
1554
1181
  seedIds: [],
1555
1182
  expansionCandidates: 0,
1556
1183
  strongSeedIds: [],
@@ -1696,17 +1323,17 @@ async function expandEntryNeighborhood(mergedCandidates, queryEmbedding, ports,
1696
1323
  return [];
1697
1324
  }
1698
1325
  const families = HISTORICAL_NEIGHBORHOOD_FAMILIES;
1699
- const includeRetired = true;
1326
+ const includeHistorical = true;
1700
1327
  const seedIds = Array.from(mergedCandidates.keys());
1701
1328
  trace.expansionRequested = true;
1702
1329
  trace.familiesRequested = [...families];
1703
- trace.includeRetired = includeRetired;
1330
+ trace.includeHistorical = includeHistorical;
1704
1331
  trace.seedIds = seedIds;
1705
1332
  const expanded = await ports.expandNeighborhood({
1706
1333
  seedIds,
1707
1334
  budget: DEFAULT_NEIGHBORHOOD_BUDGET,
1708
1335
  families,
1709
- includeRetired
1336
+ includeHistorical
1710
1337
  });
1711
1338
  const ranked = expanded.filter((entry) => !mergedCandidates.has(entry.id)).map((entry) => ({
1712
1339
  entry,
@@ -1772,7 +1399,7 @@ function resolveRecencyScore(entry, params) {
1772
1399
  if (params.rankingProfile === "historical_state") {
1773
1400
  return HISTORICAL_STATE_FLAT_RECENCY;
1774
1401
  }
1775
- return recencyScore(entry.created_at, entry.expiry);
1402
+ return recencyScore(entry.created_at, entry.expiry, params.now);
1776
1403
  }
1777
1404
  function resolveAsOfScore(entry, asOfDate) {
1778
1405
  const validFrom = parseTimestamp(entry.valid_from);
@@ -1808,7 +1435,7 @@ function applyHistoricalLineageBoosts(candidates, params, claimKeyTrace, slotPol
1808
1435
  const entries = candidates.map((candidate) => candidate.entry);
1809
1436
  const scoresById = new Map(candidates.map((candidate) => [candidate.entry.id, candidate.score]));
1810
1437
  return candidates.map((candidate) => {
1811
- const decision = resolveHistoricalLineageBonus(candidate.entry, entries, scoresById, candidate.score, params.aroundDate, slotPolicyConfig);
1438
+ const decision = resolveHistoricalLineageBonus(candidate.entry, entries, scoresById, candidate.score, params.aroundDate, params.nowMs, slotPolicyConfig);
1812
1439
  if (decision.tentativeLineageSuppressed) {
1813
1440
  claimKeyTrace.tentativeLineageSuppressed += 1;
1814
1441
  }
@@ -1827,7 +1454,7 @@ function applyHistoricalLineageBoosts(candidates, params, claimKeyTrace, slotPol
1827
1454
  };
1828
1455
  });
1829
1456
  }
1830
- function resolveHistoricalLineageBonus(entry, entries, scoresById, candidateScore, aroundDate, slotPolicyConfig) {
1457
+ function resolveHistoricalLineageBonus(entry, entries, scoresById, candidateScore, aroundDate, nowMs, slotPolicyConfig) {
1831
1458
  const directSuccessor = entries.find((peer) => peer.id !== entry.id && entry.superseded_by === peer.id);
1832
1459
  if (directSuccessor) {
1833
1460
  const successorScore = scoresById.get(directSuccessor.id) ?? 0;
@@ -1846,7 +1473,7 @@ function resolveHistoricalLineageBonus(entry, entries, scoresById, candidateScor
1846
1473
  let bestPeerScore = 0;
1847
1474
  let peerMatched = false;
1848
1475
  for (const peer of entries) {
1849
- if (peer.id === entry.id || !isPotentialCurrentPeer(peer) || createdAtMs(entry.created_at) >= createdAtMs(peer.created_at)) {
1476
+ if (peer.id === entry.id || !isPotentialCurrentPeer(peer, nowMs) || createdAtMs(entry.created_at) >= createdAtMs(peer.created_at)) {
1850
1477
  continue;
1851
1478
  }
1852
1479
  const relation = resolveHistoricalPeerRelation(entry, peer, entries, slotPolicyConfig);
@@ -1869,7 +1496,7 @@ function resolveHistoricalLineageBonus(entry, entries, scoresById, candidateScor
1869
1496
  tentativeLineageSuppressed
1870
1497
  };
1871
1498
  }
1872
- const base = entry.retired ? HISTORICAL_RETIRED_PREDECESSOR_BOOST : HISTORICAL_OLDER_STATE_BOOST;
1499
+ const base = isStalePredecessor(entry, nowMs) ? HISTORICAL_STALE_PREDECESSOR_BOOST : HISTORICAL_OLDER_STATE_BOOST;
1873
1500
  return {
1874
1501
  bonus: shapeHistoricalLineageBonus(base, candidateScore, bestPeerScore),
1875
1502
  tentativeLineageSuppressed
@@ -1880,8 +1507,11 @@ function shapeHistoricalLineageBonus(base, candidateScore, successorScore) {
1880
1507
  const needed = gap > 0 ? gap + HISTORICAL_LINEAGE_GAP_MARGIN : 0;
1881
1508
  return Math.min(HISTORICAL_LINEAGE_MAX_BONUS, Math.max(base, needed));
1882
1509
  }
1883
- function isPotentialCurrentPeer(entry) {
1884
- return !entry.retired && entry.superseded_by === void 0;
1510
+ function isPotentialCurrentPeer(entry, nowMs) {
1511
+ return isCurrentlyValidMemory(entry, nowMs);
1512
+ }
1513
+ function isStalePredecessor(entry, nowMs) {
1514
+ return isStaleMemory(entry, nowMs);
1885
1515
  }
1886
1516
  function resolveHistoricalPeerRelation(left, right, entries, slotPolicyConfig) {
1887
1517
  if (left.claim_key && right.claim_key && left.claim_key === right.claim_key) {
@@ -2034,18 +1664,18 @@ function resolveMmrMinPoolSize(policy) {
2034
1664
  }
2035
1665
  return Math.floor(raw);
2036
1666
  }
2037
- function applyClaimKeyResultShaping(candidates, claimKeyTrace, slotPolicyConfig) {
1667
+ function applyClaimKeyResultShaping(candidates, claimKeyTrace, nowMs, slotPolicyConfig) {
2038
1668
  if (candidates.length === 0) {
2039
1669
  return candidates;
2040
1670
  }
2041
1671
  const trustedActiveClaimKeys = new Set(
2042
1672
  candidates.map((candidate) => candidate.entry).filter(
2043
- (entry) => isPotentialCurrentPeer(entry) && entry.claim_key && entry.claim_key_status === "trusted" && resolveClaimSlotPolicy(entry.claim_key, slotPolicyConfig).policy === "exclusive"
1673
+ (entry) => isPotentialCurrentPeer(entry, nowMs) && entry.claim_key && entry.claim_key_status === "trusted" && resolveClaimSlotPolicy(entry.claim_key, slotPolicyConfig).policy === "exclusive"
2044
1674
  ).map((entry) => entry.claim_key)
2045
1675
  );
2046
- const trustedSlotRankById = rankTrustedSlotSiblings(candidates, slotPolicyConfig);
1676
+ const trustedSlotRankById = rankTrustedSlotSiblings(candidates, nowMs, slotPolicyConfig);
2047
1677
  return candidates.map((candidate) => {
2048
- const trustPenalty = shouldPenalizeTentativeCurrentSibling(candidate.entry, trustedActiveClaimKeys) ? CLAIM_KEY_TENTATIVE_CURRENT_PENALTY : 0;
1678
+ const trustPenalty = shouldPenalizeTentativeCurrentSibling(candidate.entry, trustedActiveClaimKeys, nowMs) ? CLAIM_KEY_TENTATIVE_CURRENT_PENALTY : 0;
2049
1679
  const redundancyPenalty = resolveTrustedSlotRedundancyPenalty(candidate.entry.id, trustedSlotRankById);
2050
1680
  if (trustPenalty <= 0 && redundancyPenalty <= 0) {
2051
1681
  return candidate;
@@ -2067,12 +1697,12 @@ function applyClaimKeyResultShaping(candidates, claimKeyTrace, slotPolicyConfig)
2067
1697
  };
2068
1698
  });
2069
1699
  }
2070
- function rankTrustedSlotSiblings(candidates, slotPolicyConfig) {
1700
+ function rankTrustedSlotSiblings(candidates, nowMs, slotPolicyConfig) {
2071
1701
  const candidatesById = new Map(candidates.map((candidate) => [candidate.entry.id, candidate]));
2072
1702
  const trustedByClaimKey = /* @__PURE__ */ new Map();
2073
1703
  for (const candidate of candidates) {
2074
1704
  const claimKey = candidate.entry.claim_key;
2075
- if (!claimKey || candidate.entry.claim_key_status !== "trusted" || !isPotentialCurrentPeer(candidate.entry) || resolveClaimSlotPolicy(claimKey, slotPolicyConfig).policy !== "exclusive") {
1705
+ if (!claimKey || candidate.entry.claim_key_status !== "trusted" || !isPotentialCurrentPeer(candidate.entry, nowMs) || resolveClaimSlotPolicy(claimKey, slotPolicyConfig).policy !== "exclusive") {
2076
1706
  continue;
2077
1707
  }
2078
1708
  const siblings = trustedByClaimKey.get(claimKey) ?? [];
@@ -2092,8 +1722,8 @@ function rankTrustedSlotSiblings(candidates, slotPolicyConfig) {
2092
1722
  function compareCandidatesForTrustedSlotRank(left, right) {
2093
1723
  return right.score - left.score || createdAtMs(right.entry.created_at) - createdAtMs(left.entry.created_at) || left.entry.id.localeCompare(right.entry.id);
2094
1724
  }
2095
- function shouldPenalizeTentativeCurrentSibling(entry, trustedActiveClaimKeys) {
2096
- return isPotentialCurrentPeer(entry) && entry.claim_key !== void 0 && entry.claim_key_status !== "trusted" && trustedActiveClaimKeys.has(entry.claim_key);
1725
+ function shouldPenalizeTentativeCurrentSibling(entry, trustedActiveClaimKeys, nowMs) {
1726
+ return isPotentialCurrentPeer(entry, nowMs) && entry.claim_key !== void 0 && entry.claim_key_status !== "trusted" && trustedActiveClaimKeys.has(entry.claim_key);
2097
1727
  }
2098
1728
  function resolveTrustedSlotRedundancyPenalty(entryId, trustedSlotRankById) {
2099
1729
  const rank = trustedSlotRankById.get(entryId) ?? 0;
@@ -2199,7 +1829,7 @@ function mergeCandidates(vectorCandidates, ftsCandidates) {
2199
1829
  ftsRanks
2200
1830
  };
2201
1831
  }
2202
- function buildEntryFilters(types, tags, since, until) {
1832
+ function buildDurableFilters(types, tags, since, until, options) {
2203
1833
  const filters = {};
2204
1834
  if (types && types.length > 0) {
2205
1835
  filters.types = types;
@@ -2213,6 +1843,16 @@ function buildEntryFilters(types, tags, since, until) {
2213
1843
  if (until) {
2214
1844
  filters.until = until;
2215
1845
  }
1846
+ if (options) {
1847
+ const validAsOf = resolveRecallValidAsOf({
1848
+ rankingProfile: options.rankingProfile,
1849
+ asOfDate: options.asOfDate,
1850
+ nowMs: options.nowMs
1851
+ });
1852
+ if (validAsOf) {
1853
+ filters.validAsOf = validAsOf;
1854
+ }
1855
+ }
2216
1856
  return Object.keys(filters).length > 0 ? filters : void 0;
2217
1857
  }
2218
1858
  function applyBudget(results, budget) {
@@ -2362,8 +2002,8 @@ function hasCanonicalConsecutivePhrase(haystack, needle) {
2362
2002
  function estimateTokens(entry) {
2363
2003
  return (entry.subject.length + entry.content.length) / 4;
2364
2004
  }
2365
- function parseAroundDate(value) {
2366
- return parseRelativeDate(value) ?? inferAroundDate(value);
2005
+ function parseAroundDate(value, now) {
2006
+ return parseRelativeDate(value, now) ?? inferAroundDate(value, now);
2367
2007
  }
2368
2008
  function normalizeLimit(value) {
2369
2009
  if (typeof value !== "number" || !Number.isFinite(value)) {
@@ -2399,15 +2039,6 @@ export {
2399
2039
  importanceScore,
2400
2040
  scoreCandidate,
2401
2041
  cosineSimilarity,
2402
- normalizeClaimKeySegment,
2403
- normalizeClaimKey,
2404
- compactClaimKey,
2405
- validateExtractedClaimKey,
2406
- inspectClaimKey,
2407
- isTrustedClaimKeyForCleanup,
2408
- describeClaimKeyNormalizationFailure,
2409
- describeExtractedClaimKeyRejection,
2410
- describeClaimKeySuspicion,
2411
2042
  tokenize,
2412
2043
  buildLexicalPlan,
2413
2044
  computeLexicalScore,
@@ -2432,5 +2063,8 @@ export {
2432
2063
  sharesEntryLineage,
2433
2064
  sharesEpisodeLineage,
2434
2065
  sharesProcedureLineage,
2435
- recall
2066
+ recall,
2067
+ describeDurableLineageState,
2068
+ formatDurableClaimLifecycle,
2069
+ summarizeClaimFamilyTransition
2436
2070
  };