@fortemi/core 2026.6.4 → 2026.6.6

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.
@@ -53,8 +53,10 @@ interface AiwgFortemiChunkPartRef {
53
53
  }
54
54
  declare const AIWG_SCAN_REQUIRED_FIELDS: Array<keyof AiwgFortemiRecord>;
55
55
  type AiwgFortemiProjectedRecord = Pick<AiwgFortemiRecord, 'schema_version' | 'id' | 'type' | 'title' | 'text' | 'facets' | 'tags' | 'concepts' | 'privacy'> & Partial<AiwgFortemiRecord>;
56
+ type AiwgDetailIdEncoding = 'uri' | 'base64url';
56
57
  interface AiwgFortemiChunkDetailRef {
57
58
  href: string;
59
+ encoding?: AiwgDetailIdEncoding;
58
60
  }
59
61
  interface AiwgFortemiChunkManifest {
60
62
  schema_version: 'aiwg.fortemi.index.chunk-manifest.v1';
@@ -125,6 +127,7 @@ interface AiwgChunkedIndexLoadOptions {
125
127
  maxCachedParts?: number;
126
128
  detailLoader?: AiwgChunkedIndexDetailLoader;
127
129
  maxCachedDetails?: number;
130
+ maxCachedMatches?: number;
128
131
  }
129
132
  type AiwgChunkedIndexProgressPhase = 'part' | 'query';
130
133
  interface AiwgChunkedIndexProgress {
@@ -200,12 +203,15 @@ declare function assertAiwgFortemiChunkManifest(value: unknown): AiwgFortemiChun
200
203
  declare function validateAiwgFortemiChunkPart(value: unknown, partRef?: AiwgFortemiChunkPartRef, manifest?: AiwgFortemiChunkManifest): AiwgChunkedIndexValidationResult;
201
204
  declare function assertAiwgFortemiChunkPart(value: unknown, partRef?: AiwgFortemiChunkPartRef, manifest?: AiwgFortemiChunkManifest): AiwgFortemiChunkPart;
202
205
  declare function createAiwgFetchChunkLoader(baseUrl?: string | URL): AiwgChunkedIndexLoader;
206
+ declare function encodeAiwgDetailId(id: string, encoding?: AiwgDetailIdEncoding): string;
207
+ declare function aiwgDetailHrefForId(detail: AiwgFortemiChunkDetailRef, id: string): string;
203
208
  declare function createAiwgFetchDetailLoader(baseUrl?: string | URL): AiwgChunkedIndexDetailLoader;
204
209
  declare function getAiwgFortemiFacets(items: AiwgFortemiRecord[]): Record<string, Record<string, number>>;
205
210
  interface AiwgChunkedIndexBuildOptions {
206
211
  partSize?: number;
207
212
  projection?: Array<keyof AiwgFortemiRecord>;
208
213
  detailHref?: string;
214
+ idEncoding?: AiwgDetailIdEncoding;
209
215
  generatedAt?: string;
210
216
  }
211
217
  interface AiwgChunkedIndexBuildResult {
@@ -216,12 +222,13 @@ interface AiwgChunkedIndexBuildResult {
216
222
  }>;
217
223
  details: Array<{
218
224
  id: string;
225
+ href: string;
219
226
  record: AiwgFortemiRecord;
220
227
  }>;
221
228
  }
222
229
  declare function buildAiwgChunkedIndex(index: AiwgFortemiIndexExport, options?: AiwgChunkedIndexBuildOptions): AiwgChunkedIndexBuildResult;
223
230
  declare function queryAiwgFortemiIndex(index: AiwgFortemiIndexExport, query?: string, options?: AiwgIndexQueryOptions): AiwgIndexQueryResult;
224
- declare function createAiwgReviewDecisionExport(source: AiwgFortemiIndexExport, decisions: AiwgReviewDecision[], generatedAt?: string): AiwgReviewDecisionExport;
231
+ declare function createAiwgReviewDecisionExport(source: Pick<AiwgFortemiIndexExport, 'schema_version'>, decisions: AiwgReviewDecision[], generatedAt?: string): AiwgReviewDecisionExport;
225
232
  declare function createAiwgIndexController(initialIndex?: AiwgFortemiIndexExport): AiwgIndexController;
226
233
  declare function aiwgFortemiIndexToCommunityGraph(index: AiwgFortemiIndexExport, options?: AiwgIndexGraphOptions): {
227
234
  nodes: {
@@ -239,4 +246,4 @@ declare function aiwgFortemiIndexToCommunityGraph(index: AiwgFortemiIndexExport,
239
246
  }[];
240
247
  };
241
248
 
242
- export { AIWG_SCAN_REQUIRED_FIELDS, type AiwgChunkedIndexBuildOptions, type AiwgChunkedIndexBuildResult, type AiwgChunkedIndexDetailLoader, type AiwgChunkedIndexLoadOptions, type AiwgChunkedIndexLoader, type AiwgChunkedIndexProgress, type AiwgChunkedIndexProgressPhase, type AiwgChunkedIndexQueryOptions, type AiwgChunkedIndexQueryResult, type AiwgChunkedIndexValidationResult, type AiwgFortemiChunkDetailRef, type AiwgFortemiChunkManifest, type AiwgFortemiChunkPart, type AiwgFortemiChunkPartRef, type AiwgFortemiIndexExport, type AiwgFortemiProjectedRecord, type AiwgFortemiProvenance, type AiwgFortemiRecord, type AiwgFortemiRecordSource, type AiwgFortemiRecordType, type AiwgFortemiRelationship, type AiwgIndexController, type AiwgIndexControllerListener, type AiwgIndexControllerSnapshot, type AiwgIndexGraphOptions, type AiwgIndexQueryMatch, type AiwgIndexQueryOptions, type AiwgIndexQueryRankedItem, type AiwgIndexQueryResult, type AiwgIndexQueryWeights, type AiwgIndexValidationResult, type AiwgPrivacyClassification, type AiwgProvenanceConfidence, type AiwgReviewAction, type AiwgReviewDecision, type AiwgReviewDecisionExport, type AiwgReviewInput, aiwgFortemiIndexToCommunityGraph, assertAiwgFortemiChunkManifest, assertAiwgFortemiChunkPart, assertAiwgFortemiIndexExport, buildAiwgChunkedIndex, createAiwgFetchChunkLoader, createAiwgFetchDetailLoader, createAiwgIndexController, createAiwgReviewDecisionExport, getAiwgFortemiFacets, queryAiwgFortemiIndex, validateAiwgFortemiChunkManifest, validateAiwgFortemiChunkPart, validateAiwgFortemiIndexExport };
249
+ export { AIWG_SCAN_REQUIRED_FIELDS, type AiwgChunkedIndexBuildOptions, type AiwgChunkedIndexBuildResult, type AiwgChunkedIndexDetailLoader, type AiwgChunkedIndexLoadOptions, type AiwgChunkedIndexLoader, type AiwgChunkedIndexProgress, type AiwgChunkedIndexProgressPhase, type AiwgChunkedIndexQueryOptions, type AiwgChunkedIndexQueryResult, type AiwgChunkedIndexValidationResult, type AiwgDetailIdEncoding, type AiwgFortemiChunkDetailRef, type AiwgFortemiChunkManifest, type AiwgFortemiChunkPart, type AiwgFortemiChunkPartRef, type AiwgFortemiIndexExport, type AiwgFortemiProjectedRecord, type AiwgFortemiProvenance, type AiwgFortemiRecord, type AiwgFortemiRecordSource, type AiwgFortemiRecordType, type AiwgFortemiRelationship, type AiwgIndexController, type AiwgIndexControllerListener, type AiwgIndexControllerSnapshot, type AiwgIndexGraphOptions, type AiwgIndexQueryMatch, type AiwgIndexQueryOptions, type AiwgIndexQueryRankedItem, type AiwgIndexQueryResult, type AiwgIndexQueryWeights, type AiwgIndexValidationResult, type AiwgPrivacyClassification, type AiwgProvenanceConfidence, type AiwgReviewAction, type AiwgReviewDecision, type AiwgReviewDecisionExport, type AiwgReviewInput, aiwgDetailHrefForId, aiwgFortemiIndexToCommunityGraph, assertAiwgFortemiChunkManifest, assertAiwgFortemiChunkPart, assertAiwgFortemiIndexExport, buildAiwgChunkedIndex, createAiwgFetchChunkLoader, createAiwgFetchDetailLoader, createAiwgIndexController, createAiwgReviewDecisionExport, encodeAiwgDetailId, getAiwgFortemiFacets, queryAiwgFortemiIndex, validateAiwgFortemiChunkManifest, validateAiwgFortemiChunkPart, validateAiwgFortemiIndexExport };
@@ -134,6 +134,9 @@ function validateAiwgFortemiChunkManifest(value) {
134
134
  if (data.detail !== void 0) {
135
135
  if (!hasString(data.detail.href)) errors.push("detail.href is required");
136
136
  else if (!data.detail.href.includes("{id}")) errors.push("detail.href must contain the {id} placeholder");
137
+ if (data.detail.encoding !== void 0 && data.detail.encoding !== "uri" && data.detail.encoding !== "base64url") {
138
+ errors.push("detail.encoding must be 'uri' or 'base64url'");
139
+ }
137
140
  }
138
141
  if (!Array.isArray(data?.parts)) errors.push("parts must be an array");
139
142
  let expectedOffset = 0;
@@ -235,10 +238,20 @@ function createAiwgFetchChunkLoader(baseUrl) {
235
238
  return response.json();
236
239
  };
237
240
  }
241
+ function encodeAiwgDetailId(id, encoding = "base64url") {
242
+ if (encoding === "uri") return encodeURIComponent(id);
243
+ const bytes = new TextEncoder().encode(id);
244
+ let binary = "";
245
+ for (const byte of bytes) binary += String.fromCharCode(byte);
246
+ return btoa(binary).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
247
+ }
248
+ function aiwgDetailHrefForId(detail, id) {
249
+ return detail.href.replace("{id}", encodeAiwgDetailId(id, detail.encoding ?? "uri"));
250
+ }
238
251
  function createAiwgFetchDetailLoader(baseUrl) {
239
252
  return async (id, manifest) => {
240
253
  if (!manifest.detail?.href) throw new Error("Manifest has no detail.href for record resolution");
241
- const relative = manifest.detail.href.replace("{id}", encodeURIComponent(id));
254
+ const relative = aiwgDetailHrefForId(manifest.detail, id);
242
255
  const href = baseUrl ? new URL(relative, baseUrl).toString() : relative;
243
256
  const response = await fetch(href);
244
257
  if (!response.ok) throw new Error("Failed to fetch AIWG index detail " + href + ": " + response.status);
@@ -261,6 +274,8 @@ function getAiwgFortemiFacets(items) {
261
274
  function buildAiwgChunkedIndex(index, options = {}) {
262
275
  const partSize = hasPositiveInteger(options.partSize) ? options.partSize : 500;
263
276
  const projection = options.projection;
277
+ const idEncoding = options.idEncoding ?? "base64url";
278
+ const detailHref = options.detailHref ?? "detail/{id}.json";
264
279
  const items = index.items;
265
280
  const pad = (value) => String(value).padStart(4, "0");
266
281
  const project = (record) => {
@@ -293,12 +308,16 @@ function buildAiwgChunkedIndex(index, options = {}) {
293
308
  part_size: partSize,
294
309
  facets: getAiwgFortemiFacets(items),
295
310
  parts: partRefs,
296
- ...projection ? { projection, detail: { href: options.detailHref ?? "detail/{id}.json" } } : {}
311
+ ...projection ? { projection, detail: { href: detailHref, encoding: idEncoding } } : {}
297
312
  };
298
313
  return {
299
314
  manifest,
300
315
  parts,
301
- details: projection ? items.map((record) => ({ id: record.id, record })) : []
316
+ details: projection ? items.map((record) => ({
317
+ id: record.id,
318
+ href: aiwgDetailHrefForId({ href: detailHref, encoding: idEncoding }, record.id),
319
+ record
320
+ })) : []
302
321
  };
303
322
  }
304
323
  function includesAll(actual, expected) {
@@ -408,6 +427,34 @@ function clampMaxCachedDetails(value) {
408
427
  if (!hasPositiveInteger(value)) return 32;
409
428
  return value;
410
429
  }
430
+ function clampMaxCachedMatches(value) {
431
+ if (!hasPositiveInteger(value)) return 5e3;
432
+ return value;
433
+ }
434
+ function matchSetCacheKey(q, options) {
435
+ return JSON.stringify({
436
+ q,
437
+ types: options.types ?? null,
438
+ facets: options.facets ?? null,
439
+ tags: options.tags ?? null,
440
+ concepts: options.concepts ?? null,
441
+ privacy: options.privacy ?? null,
442
+ rel: options.relationshipTargetId ?? null,
443
+ weights: { ...DEFAULT_QUERY_WEIGHTS, ...options.weights }
444
+ });
445
+ }
446
+ function cacheMatchEntries(runtime, key, entries) {
447
+ runtime.matchCache.delete(key);
448
+ runtime.matchCache.set(key, entries);
449
+ let total = 0;
450
+ for (const set of runtime.matchCache.values()) total += set.length;
451
+ while (total > runtime.maxCachedMatches && runtime.matchCache.size > 1) {
452
+ const oldest = runtime.matchCache.keys().next().value;
453
+ if (oldest === void 0 || oldest === key) break;
454
+ total -= runtime.matchCache.get(oldest)?.length ?? 0;
455
+ runtime.matchCache.delete(oldest);
456
+ }
457
+ }
411
458
  function isDirectChunkBrowse(query, options) {
412
459
  return query.trim() === "" && !options.rank && !options.snippets && !options.includeMatches && !options.types && !options.facets && !options.tags && !options.concepts && !options.privacy && !options.relationshipTargetId;
413
460
  }
@@ -494,6 +541,19 @@ async function queryChunkedAiwgFortemiIndex(runtime, query = "", options = {}) {
494
541
  complete: true
495
542
  };
496
543
  }
544
+ const matchKey = matchSetCacheKey(q, options);
545
+ const cached = runtime.matchCache.get(matchKey);
546
+ if (cached) {
547
+ runtime.matchCache.delete(matchKey);
548
+ runtime.matchCache.set(matchKey, cached);
549
+ return {
550
+ ...createQueryResultFromRankedEntries(cached, q, options),
551
+ manifestTotal: runtime.manifest.total,
552
+ scannedParts: 0,
553
+ fetchedParts: 0,
554
+ complete: true
555
+ };
556
+ }
497
557
  const entries = [];
498
558
  for (const partRef of runtime.manifest.parts) {
499
559
  const loaded = await loadChunkPart(runtime, partRef);
@@ -503,6 +563,7 @@ async function queryChunkedAiwgFortemiIndex(runtime, query = "", options = {}) {
503
563
  entries.push(...createRankedEntries(loaded.part.items, q, options, partRef.offset));
504
564
  options.onProgress?.({ phase: "query", done: scannedParts, total: runtime.manifest.parts.length, href: partRef.href });
505
565
  }
566
+ cacheMatchEntries(runtime, matchKey, entries);
506
567
  return {
507
568
  ...createQueryResultFromRankedEntries(entries, q, options),
508
569
  manifestTotal: runtime.manifest.total,
@@ -573,7 +634,9 @@ function createAiwgIndexController(initialIndex) {
573
634
  partCache: /* @__PURE__ */ new Map(),
574
635
  detailLoader: options.detailLoader,
575
636
  maxCachedDetails: clampMaxCachedDetails(options.maxCachedDetails),
576
- detailCache: /* @__PURE__ */ new Map()
637
+ detailCache: /* @__PURE__ */ new Map(),
638
+ maxCachedMatches: clampMaxCachedMatches(options.maxCachedMatches),
639
+ matchCache: /* @__PURE__ */ new Map()
577
640
  };
578
641
  data = null;
579
642
  reviewDecisions = [];
@@ -633,6 +696,7 @@ function createAiwgIndexController(initialIndex) {
633
696
  clearChunkCache() {
634
697
  chunked?.partCache.clear();
635
698
  chunked?.detailCache.clear();
699
+ chunked?.matchCache.clear();
636
700
  error = null;
637
701
  notify();
638
702
  },
@@ -658,7 +722,9 @@ function createAiwgIndexController(initialIndex) {
658
722
  notify();
659
723
  },
660
724
  createReviewDecisionExport(generatedAt) {
661
- return createAiwgReviewDecisionExport(requireIndex(), reviewDecisions, generatedAt);
725
+ const source = index ?? (chunked ? { schema_version: "aiwg.fortemi.index.export.v1" } : null);
726
+ if (!source) throw new Error("No AIWG index export or chunked manifest loaded");
727
+ return createAiwgReviewDecisionExport(source, reviewDecisions, generatedAt);
662
728
  },
663
729
  subscribe(listener) {
664
730
  listeners.add(listener);
@@ -712,6 +778,6 @@ function communityIdsFor(item, options) {
712
778
  return [`type:${item.type}`];
713
779
  }
714
780
 
715
- export { AIWG_SCAN_REQUIRED_FIELDS, aiwgFortemiIndexToCommunityGraph, assertAiwgFortemiChunkManifest, assertAiwgFortemiChunkPart, assertAiwgFortemiIndexExport, buildAiwgChunkedIndex, createAiwgFetchChunkLoader, createAiwgFetchDetailLoader, createAiwgIndexController, createAiwgReviewDecisionExport, getAiwgFortemiFacets, queryAiwgFortemiIndex, validateAiwgFortemiChunkManifest, validateAiwgFortemiChunkPart, validateAiwgFortemiIndexExport };
781
+ export { AIWG_SCAN_REQUIRED_FIELDS, aiwgDetailHrefForId, aiwgFortemiIndexToCommunityGraph, assertAiwgFortemiChunkManifest, assertAiwgFortemiChunkPart, assertAiwgFortemiIndexExport, buildAiwgChunkedIndex, createAiwgFetchChunkLoader, createAiwgFetchDetailLoader, createAiwgIndexController, createAiwgReviewDecisionExport, encodeAiwgDetailId, getAiwgFortemiFacets, queryAiwgFortemiIndex, validateAiwgFortemiChunkManifest, validateAiwgFortemiChunkPart, validateAiwgFortemiIndexExport };
716
782
  //# sourceMappingURL=aiwg-index.js.map
717
783
  //# sourceMappingURL=aiwg-index.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/aiwg-index.ts"],"names":[],"mappings":"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","file":"aiwg-index.js","sourcesContent":["export type AiwgFortemiRecordType =\n | 'crm.contact'\n | 'crm.organization'\n | 'crm.event'\n | 'crm.interaction'\n | 'aiwg.artifact'\n | 'docs.page'\n\nexport type AiwgPrivacyClassification = 'private' | 'sanitized' | 'public'\nexport type AiwgProvenanceConfidence = 'source' | 'candidate' | 'reviewed' | 'rejected'\nexport type AiwgReviewAction = 'accept' | 'reject' | 'defer'\n\nexport interface AiwgFortemiRecordSource {\n path: string\n repo_relative_path: string\n locator: string\n}\n\nexport interface AiwgFortemiRelationship {\n type: string\n target_id: string\n source_path?: string\n}\n\nexport interface AiwgFortemiProvenance {\n field: string\n source: string\n path: string\n confidence: AiwgProvenanceConfidence\n privacy: AiwgPrivacyClassification\n}\n\nexport interface AiwgFortemiRecord {\n schema_version: 'aiwg.fortemi.index.record.v1'\n id: string\n type: AiwgFortemiRecordType\n source: AiwgFortemiRecordSource\n title: string\n text: string\n facets: Record<string, string[]>\n tags: string[]\n concepts: string[]\n relationships: AiwgFortemiRelationship[]\n provenance: AiwgFortemiProvenance[]\n privacy: {\n classification: AiwgPrivacyClassification\n pii: boolean\n }\n updated_at: string\n}\n\nexport interface AiwgFortemiIndexExport {\n schema_version: 'aiwg.fortemi.index.export.v1'\n generated_at: string\n source: {\n repo: string\n privacy: AiwgPrivacyClassification\n }\n items: AiwgFortemiRecord[]\n}\n\nexport interface AiwgFortemiChunkPartRef {\n href: string\n offset: number\n count: number\n}\n\n// Fields a scan part must retain for query/browse/rank/facet to work. The rest\n// (source, provenance, relationships, updated_at) are detail-only and may be\n// dropped from scan parts via `projection`, then resolved on demand by id.\nexport const AIWG_SCAN_REQUIRED_FIELDS: Array<keyof AiwgFortemiRecord> = [\n 'schema_version',\n 'id',\n 'type',\n 'title',\n 'text',\n 'facets',\n 'tags',\n 'concepts',\n 'privacy',\n]\n\n// A record as it appears in a scan part. With no manifest `projection`, this is a\n// full AiwgFortemiRecord. With a projection, detail-only fields are absent — read\n// them via the controller's getRecord(). Typed as the full record for ergonomics;\n// query/browse code guards the projectable fields.\nexport type AiwgFortemiProjectedRecord =\n Pick<AiwgFortemiRecord, 'schema_version' | 'id' | 'type' | 'title' | 'text' | 'facets' | 'tags' | 'concepts' | 'privacy'>\n & Partial<AiwgFortemiRecord>\n\n// How the controller resolves a full record by id when scan parts are projected.\nexport interface AiwgFortemiChunkDetailRef {\n // href template containing `{id}` (URL-encoded at substitution), relative to the\n // manifest base — e.g. \"detail/{id}.json\".\n href: string\n}\n\nexport interface AiwgFortemiChunkManifest {\n schema_version: 'aiwg.fortemi.index.chunk-manifest.v1'\n generated_at: string\n source: AiwgFortemiIndexExport['source']\n total: number\n part_size: number\n facets?: Record<string, Record<string, number>>\n // Field names present in scan-part items. Absent → scan parts carry whole records.\n // When set, must include AIWG_SCAN_REQUIRED_FIELDS.\n projection?: Array<keyof AiwgFortemiRecord>\n // Resolver for full records by id (used with `projection` to lazy-load detail).\n detail?: AiwgFortemiChunkDetailRef\n parts: AiwgFortemiChunkPartRef[]\n}\n\nexport interface AiwgFortemiChunkPart {\n schema_version: 'aiwg.fortemi.index.chunk.v1'\n manifest_schema_version: 'aiwg.fortemi.index.chunk-manifest.v1'\n offset: number\n items: AiwgFortemiRecord[]\n}\n\nexport interface AiwgIndexValidationResult {\n valid: boolean\n errors: string[]\n counts: Partial<Record<AiwgFortemiRecordType, number>>\n}\n\nexport interface AiwgChunkedIndexValidationResult {\n valid: boolean\n errors: string[]\n}\n\nexport interface AiwgIndexQueryOptions {\n types?: AiwgFortemiRecordType[]\n facets?: Record<string, string[]>\n tags?: string[]\n concepts?: string[]\n privacy?: AiwgPrivacyClassification[]\n relationshipTargetId?: string\n limit?: number\n offset?: number\n rank?: boolean\n snippets?: boolean\n snippetLength?: number\n weights?: Partial<AiwgIndexQueryWeights>\n includeMatches?: boolean\n}\n\nexport interface AiwgIndexQueryWeights {\n title: number\n text: number\n tag: number\n concept: number\n}\n\nexport interface AiwgIndexQueryMatch {\n field: 'title' | 'text' | 'tag' | 'concept'\n value: string\n}\n\nexport interface AiwgIndexQueryRankedItem {\n item: AiwgFortemiRecord\n rank: number\n snippet?: string\n matches?: AiwgIndexQueryMatch[]\n}\n\nexport interface AiwgIndexQueryResult {\n items: AiwgFortemiRecord[]\n total: number\n facets: Record<string, Record<string, number>>\n rankedItems?: AiwgIndexQueryRankedItem[]\n}\n\nexport type AiwgChunkedIndexLoader = (\n part: AiwgFortemiChunkPartRef,\n manifest: AiwgFortemiChunkManifest,\n) => Promise<unknown>\n\n// Resolves a full record by id (used with projected scan parts). Returns the\n// parsed record JSON; validated by the controller before use.\nexport type AiwgChunkedIndexDetailLoader = (\n id: string,\n manifest: AiwgFortemiChunkManifest,\n) => Promise<unknown>\n\nexport interface AiwgChunkedIndexLoadOptions {\n maxCachedParts?: number\n // Required to resolve detail for projected indexes via getRecord(); ignored otherwise.\n detailLoader?: AiwgChunkedIndexDetailLoader\n maxCachedDetails?: number\n}\n\nexport type AiwgChunkedIndexProgressPhase = 'part' | 'query'\n\nexport interface AiwgChunkedIndexProgress {\n phase: AiwgChunkedIndexProgressPhase\n done: number\n total: number\n href?: string\n}\n\nexport interface AiwgChunkedIndexQueryOptions extends AiwgIndexQueryOptions {\n onProgress?: (progress: AiwgChunkedIndexProgress) => void\n}\n\nexport interface AiwgChunkedIndexQueryResult extends AiwgIndexQueryResult {\n manifestTotal: number\n scannedParts: number\n fetchedParts: number\n complete: boolean\n}\n\nexport interface AiwgReviewDecision {\n item_id: string\n action: AiwgReviewAction\n reason?: string\n updated_at: string\n}\n\nexport interface AiwgReviewDecisionExport {\n schema_version: 'aiwg.fortemi.review-decisions.v1'\n generated_at: string\n source_export_schema_version: string\n decisions: AiwgReviewDecision[]\n}\n\nexport interface AiwgIndexGraphOptions {\n communityFacet?: string\n communityTagPrefix?: string\n relationshipWeights?: Record<string, number>\n includeDanglingRelationships?: boolean\n}\n\nexport interface AiwgReviewInput {\n item_id: string\n action: AiwgReviewAction\n reason?: string\n}\n\nexport interface AiwgIndexControllerSnapshot {\n index: AiwgFortemiIndexExport | null\n chunked: {\n manifest: AiwgFortemiChunkManifest\n cachedParts: number\n maxCachedParts: number\n } | null\n data: AiwgIndexQueryResult | null\n error: Error | null\n reviewDecisions: AiwgReviewDecision[]\n}\n\nexport type AiwgIndexControllerListener = (snapshot: AiwgIndexControllerSnapshot) => void\n\nexport interface AiwgIndexController {\n loadIndex(value: unknown): AiwgFortemiIndexExport\n loadChunkedIndex(\n manifest: unknown,\n loader: AiwgChunkedIndexLoader,\n options?: AiwgChunkedIndexLoadOptions,\n ): AiwgFortemiChunkManifest\n getIndex(): AiwgFortemiIndexExport | null\n getChunkedManifest(): AiwgFortemiChunkManifest | null\n getSnapshot(): AiwgIndexControllerSnapshot\n query(query?: string, options?: AiwgIndexQueryOptions): AiwgIndexQueryResult\n queryChunked(query?: string, options?: AiwgChunkedIndexQueryOptions): Promise<AiwgChunkedIndexQueryResult>\n // Resolve a full record by id. For a projected chunked index, fetches detail via\n // the detailLoader (bounded cache); for a whole-record index/parts, returns the\n // record from loaded data. Rejects if detail is unavailable.\n getRecord(id: string): Promise<AiwgFortemiRecord>\n clearChunkCache(): void\n toCommunityGraph(options?: AiwgIndexGraphOptions): ReturnType<typeof aiwgFortemiIndexToCommunityGraph>\n setReviewDecision(input: AiwgReviewInput): AiwgReviewDecision\n clearReviewDecision(itemId: string): void\n createReviewDecisionExport(generatedAt?: string): AiwgReviewDecisionExport\n subscribe(listener: AiwgIndexControllerListener): () => void\n}\n\nconst REQUIRED_RECORD_FIELDS: Array<keyof AiwgFortemiRecord> = [\n 'schema_version',\n 'id',\n 'type',\n 'source',\n 'title',\n 'text',\n 'facets',\n 'tags',\n 'concepts',\n 'relationships',\n 'provenance',\n 'privacy',\n 'updated_at',\n]\n\nconst VALID_TYPES = new Set<AiwgFortemiRecordType>([\n 'crm.contact',\n 'crm.organization',\n 'crm.event',\n 'crm.interaction',\n 'aiwg.artifact',\n 'docs.page',\n])\n\nconst DEFAULT_QUERY_WEIGHTS: AiwgIndexQueryWeights = {\n title: 4,\n tag: 3,\n concept: 2,\n text: 1,\n}\n\nfunction hasString(value: unknown): value is string {\n return typeof value === 'string' && value.length > 0\n}\n\nfunction pushFacet(counts: Record<string, Record<string, number>>, name: string, value: string) {\n counts[name] ??= {}\n counts[name][value] = (counts[name][value] ?? 0) + 1\n}\n\nfunction hasNonNegativeInteger(value: unknown): value is number {\n return Number.isInteger(value) && typeof value === 'number' && value >= 0\n}\n\nfunction hasPositiveInteger(value: unknown): value is number {\n return Number.isInteger(value) && typeof value === 'number' && value > 0\n}\n\nfunction isFacetCounts(value: unknown): value is Record<string, Record<string, number>> {\n if (!value || typeof value !== 'object' || Array.isArray(value)) return false\n return Object.values(value).every((counts) => (\n !!counts\n && typeof counts === 'object'\n && !Array.isArray(counts)\n && Object.values(counts).every((count) => hasNonNegativeInteger(count))\n ))\n}\n\nexport function validateAiwgFortemiIndexExport(value: unknown): AiwgIndexValidationResult {\n const errors: string[] = []\n const counts: Partial<Record<AiwgFortemiRecordType, number>> = {}\n const data = value as Partial<AiwgFortemiIndexExport>\n\n if (data?.schema_version !== 'aiwg.fortemi.index.export.v1') {\n errors.push('schema_version must be aiwg.fortemi.index.export.v1')\n }\n if (!hasString(data?.generated_at)) errors.push('generated_at is required')\n if (!hasString(data?.source?.repo)) errors.push('source.repo is required')\n if (!hasString(data?.source?.privacy)) errors.push('source.privacy is required')\n if (!Array.isArray(data?.items)) errors.push('items must be an array')\n\n const ids = new Set<string>()\n let previousId = ''\n for (const [index, item] of (data.items ?? []).entries()) {\n for (const field of REQUIRED_RECORD_FIELDS) {\n if (!(field in item)) errors.push('items[' + index + '].' + field + ' is required')\n }\n if (item.schema_version !== 'aiwg.fortemi.index.record.v1') {\n errors.push('items[' + index + '].schema_version must be aiwg.fortemi.index.record.v1')\n }\n if (!hasString(item.id)) errors.push('items[' + index + '].id is required')\n if (hasString(item.id) && ids.has(item.id)) errors.push('duplicate id: ' + item.id)\n if (hasString(item.id)) ids.add(item.id)\n if (previousId && hasString(item.id) && previousId.localeCompare(item.id) > 0) {\n errors.push('items must be sorted by id: ' + previousId + ' before ' + item.id)\n }\n if (hasString(item.id)) previousId = item.id\n if (!VALID_TYPES.has(item.type)) errors.push('items[' + index + '].type is invalid')\n else counts[item.type] = (counts[item.type] ?? 0) + 1\n if (!hasString(item.source?.path)) errors.push('items[' + index + '].source.path is required')\n if (!hasString(item.source?.repo_relative_path)) errors.push('items[' + index + '].source.repo_relative_path is required')\n if (!hasString(item.source?.locator)) errors.push('items[' + index + '].source.locator is required')\n if (!Array.isArray(item.tags)) errors.push('items[' + index + '].tags must be an array')\n if (!Array.isArray(item.concepts)) errors.push('items[' + index + '].concepts must be an array')\n if (!Array.isArray(item.relationships)) errors.push('items[' + index + '].relationships must be an array')\n if (!Array.isArray(item.provenance) || item.provenance.length === 0) {\n errors.push('items[' + index + '].provenance must be a non-empty array')\n }\n if (!item.privacy || typeof item.privacy.pii !== 'boolean' || !hasString(item.privacy.classification)) {\n errors.push('items[' + index + '].privacy requires classification and pii')\n }\n }\n\n return { valid: errors.length === 0, errors, counts }\n}\n\nexport function assertAiwgFortemiIndexExport(value: unknown): AiwgFortemiIndexExport {\n const result = validateAiwgFortemiIndexExport(value)\n if (!result.valid) {\n throw new Error('Invalid AIWG Fortemi index export:\\n' + result.errors.join('\\n'))\n }\n return value as AiwgFortemiIndexExport\n}\n\nexport function validateAiwgFortemiChunkManifest(value: unknown): AiwgChunkedIndexValidationResult {\n const errors: string[] = []\n const data = value as Partial<AiwgFortemiChunkManifest>\n\n if (data?.schema_version !== 'aiwg.fortemi.index.chunk-manifest.v1') {\n errors.push('schema_version must be aiwg.fortemi.index.chunk-manifest.v1')\n }\n if (!hasString(data?.generated_at)) errors.push('generated_at is required')\n if (!hasString(data?.source?.repo)) errors.push('source.repo is required')\n if (!hasString(data?.source?.privacy)) errors.push('source.privacy is required')\n if (!hasNonNegativeInteger(data?.total)) errors.push('total must be a non-negative integer')\n if (!hasPositiveInteger(data?.part_size)) errors.push('part_size must be a positive integer')\n if (data.facets !== undefined && !isFacetCounts(data.facets)) {\n errors.push('facets must be a nested string-to-number count object')\n }\n if (data.projection !== undefined) {\n if (!Array.isArray(data.projection) || !data.projection.every((field) => typeof field === 'string')) {\n errors.push('projection must be an array of field names')\n } else {\n const present = new Set(data.projection)\n for (const field of AIWG_SCAN_REQUIRED_FIELDS) {\n if (!present.has(field)) errors.push('projection must include scan-required field ' + field)\n }\n }\n }\n if (data.detail !== undefined) {\n if (!hasString(data.detail.href)) errors.push('detail.href is required')\n else if (!data.detail.href.includes('{id}')) errors.push('detail.href must contain the {id} placeholder')\n }\n if (!Array.isArray(data?.parts)) errors.push('parts must be an array')\n\n let expectedOffset = 0\n const parts = Array.isArray(data?.parts) ? data.parts : []\n for (const [index, part] of parts.entries()) {\n if (!hasString(part.href)) errors.push('parts[' + index + '].href is required')\n if (!hasNonNegativeInteger(part.offset)) errors.push('parts[' + index + '].offset must be a non-negative integer')\n if (!hasNonNegativeInteger(part.count)) errors.push('parts[' + index + '].count must be a non-negative integer')\n if (hasNonNegativeInteger(part.offset) && part.offset !== expectedOffset) {\n errors.push('parts[' + index + '].offset must be ' + expectedOffset)\n }\n if (hasNonNegativeInteger(part.count)) expectedOffset += part.count\n }\n if (hasNonNegativeInteger(data?.total) && expectedOffset !== data.total) {\n errors.push('parts counts must add up to total')\n }\n\n return { valid: errors.length === 0, errors }\n}\n\nexport function assertAiwgFortemiChunkManifest(value: unknown): AiwgFortemiChunkManifest {\n const result = validateAiwgFortemiChunkManifest(value)\n if (!result.valid) {\n throw new Error('Invalid AIWG Fortemi chunk manifest:\\n' + result.errors.join('\\n'))\n }\n return value as AiwgFortemiChunkManifest\n}\n\n// Validate projected (slim) scan-part items: scan-required fields only, ids unique + sorted.\nfunction validateProjectedRecords(items: Array<Partial<AiwgFortemiRecord>>): string[] {\n const errors: string[] = []\n const ids = new Set<string>()\n let previousId = ''\n for (const [index, item] of items.entries()) {\n if (item.schema_version !== 'aiwg.fortemi.index.record.v1') {\n errors.push('items[' + index + '].schema_version must be aiwg.fortemi.index.record.v1')\n }\n if (!hasString(item.id)) errors.push('items[' + index + '].id is required')\n if (hasString(item.id) && ids.has(item.id)) errors.push('duplicate id: ' + item.id)\n if (hasString(item.id)) ids.add(item.id)\n if (previousId && hasString(item.id) && previousId.localeCompare(item.id) > 0) {\n errors.push('items must be sorted by id: ' + previousId + ' before ' + item.id)\n }\n if (hasString(item.id)) previousId = item.id\n if (!item.type || !VALID_TYPES.has(item.type)) errors.push('items[' + index + '].type is invalid')\n if (!hasString(item.title)) errors.push('items[' + index + '].title is required')\n if (typeof item.text !== 'string') errors.push('items[' + index + '].text is required')\n if (!item.facets || typeof item.facets !== 'object' || Array.isArray(item.facets)) {\n errors.push('items[' + index + '].facets must be an object')\n }\n if (!Array.isArray(item.tags)) errors.push('items[' + index + '].tags must be an array')\n if (!Array.isArray(item.concepts)) errors.push('items[' + index + '].concepts must be an array')\n if (!item.privacy || !hasString(item.privacy.classification)) {\n errors.push('items[' + index + '].privacy.classification is required')\n }\n }\n return errors\n}\n\nexport function validateAiwgFortemiChunkPart(\n value: unknown,\n partRef?: AiwgFortemiChunkPartRef,\n manifest?: AiwgFortemiChunkManifest,\n): AiwgChunkedIndexValidationResult {\n const errors: string[] = []\n const data = value as Partial<AiwgFortemiChunkPart>\n\n if (data?.schema_version !== 'aiwg.fortemi.index.chunk.v1') {\n errors.push('schema_version must be aiwg.fortemi.index.chunk.v1')\n }\n if (data?.manifest_schema_version !== 'aiwg.fortemi.index.chunk-manifest.v1') {\n errors.push('manifest_schema_version must be aiwg.fortemi.index.chunk-manifest.v1')\n }\n if (!hasNonNegativeInteger(data?.offset)) errors.push('offset must be a non-negative integer')\n if (!Array.isArray(data?.items)) errors.push('items must be an array')\n\n if (partRef && hasNonNegativeInteger(data?.offset) && data.offset !== partRef.offset) {\n errors.push('offset must match manifest part offset ' + partRef.offset)\n }\n if (partRef && Array.isArray(data?.items) && data.items.length !== partRef.count) {\n errors.push('items length must match manifest part count ' + partRef.count)\n }\n\n if (Array.isArray(data?.items)) {\n if (manifest?.projection) {\n errors.push(...validateProjectedRecords(data.items).map((error) => 'items.' + error))\n } else {\n const validation = validateAiwgFortemiIndexExport({\n schema_version: 'aiwg.fortemi.index.export.v1',\n generated_at: manifest?.generated_at ?? '1970-01-01T00:00:00.000Z',\n source: manifest?.source ?? { repo: 'chunk', privacy: 'public' },\n items: data.items,\n })\n errors.push(...validation.errors.map((error) => 'items.' + error))\n }\n }\n\n return { valid: errors.length === 0, errors }\n}\n\nexport function assertAiwgFortemiChunkPart(\n value: unknown,\n partRef?: AiwgFortemiChunkPartRef,\n manifest?: AiwgFortemiChunkManifest,\n): AiwgFortemiChunkPart {\n const result = validateAiwgFortemiChunkPart(value, partRef, manifest)\n if (!result.valid) {\n throw new Error('Invalid AIWG Fortemi chunk part:\\n' + result.errors.join('\\n'))\n }\n return value as AiwgFortemiChunkPart\n}\n\nexport function createAiwgFetchChunkLoader(baseUrl?: string | URL): AiwgChunkedIndexLoader {\n return async (part) => {\n const href = baseUrl ? new URL(part.href, baseUrl).toString() : part.href\n const response = await fetch(href)\n if (!response.ok) throw new Error('Failed to fetch AIWG index chunk ' + href + ': ' + response.status)\n return response.json()\n }\n}\n\n// Detail loader for projected indexes: resolves the manifest's detail.href {id}\n// template (id URL-encoded) against baseUrl and fetches the full record.\nexport function createAiwgFetchDetailLoader(baseUrl?: string | URL): AiwgChunkedIndexDetailLoader {\n return async (id, manifest) => {\n if (!manifest.detail?.href) throw new Error('Manifest has no detail.href for record resolution')\n const relative = manifest.detail.href.replace('{id}', encodeURIComponent(id))\n const href = baseUrl ? new URL(relative, baseUrl).toString() : relative\n const response = await fetch(href)\n if (!response.ok) throw new Error('Failed to fetch AIWG index detail ' + href + ': ' + response.status)\n return response.json()\n }\n}\n\nexport function getAiwgFortemiFacets(items: AiwgFortemiRecord[]): Record<string, Record<string, number>> {\n const result: Record<string, Record<string, number>> = {}\n for (const item of items) {\n pushFacet(result, 'type', item.type)\n pushFacet(result, 'privacy', item.privacy.classification)\n for (const tag of item.tags) pushFacet(result, 'tag', tag)\n for (const concept of item.concepts) pushFacet(result, 'concept', concept)\n for (const [name, values] of Object.entries(item.facets)) {\n for (const value of values) pushFacet(result, name, value)\n }\n }\n return result\n}\n\nexport interface AiwgChunkedIndexBuildOptions {\n partSize?: number\n // When set, scan parts carry only these fields; full records go to `details`.\n projection?: Array<keyof AiwgFortemiRecord>\n // Detail href template (with {id}); defaults to \"detail/{id}.json\" when projecting.\n detailHref?: string\n generatedAt?: string\n}\n\nexport interface AiwgChunkedIndexBuildResult {\n manifest: AiwgFortemiChunkManifest\n parts: Array<{ href: string; part: AiwgFortemiChunkPart }>\n // Empty unless projecting. Each entry is a full record to host at the detail href.\n details: Array<{ id: string; record: AiwgFortemiRecord }>\n}\n\n// Pure builder (no I/O): project an index export into the chunked manifest + parts\n// (+ detail records when projecting). The caller writes the returned objects to disk.\n// Manifest facets are computed from the full records, so global counts are exact even\n// when scan parts are slim.\nexport function buildAiwgChunkedIndex(\n index: AiwgFortemiIndexExport,\n options: AiwgChunkedIndexBuildOptions = {},\n): AiwgChunkedIndexBuildResult {\n const partSize = hasPositiveInteger(options.partSize) ? options.partSize : 500\n const projection = options.projection\n const items = index.items\n const pad = (value: number): string => String(value).padStart(4, '0')\n const project = (record: AiwgFortemiRecord): AiwgFortemiRecord => {\n if (!projection) return record\n const slim: Record<string, unknown> = {}\n for (const field of projection) slim[field] = record[field]\n return slim as unknown as AiwgFortemiRecord\n }\n\n const parts: Array<{ href: string; part: AiwgFortemiChunkPart }> = []\n const partRefs: AiwgFortemiChunkPartRef[] = []\n for (let offset = 0, partIndex = 0; offset < items.length; offset += partSize, partIndex += 1) {\n const slice = items.slice(offset, offset + partSize)\n const href = 'part-' + pad(partIndex) + '.json'\n parts.push({\n href,\n part: {\n schema_version: 'aiwg.fortemi.index.chunk.v1',\n manifest_schema_version: 'aiwg.fortemi.index.chunk-manifest.v1',\n offset,\n items: slice.map(project),\n },\n })\n partRefs.push({ href, offset, count: slice.length })\n }\n\n const manifest: AiwgFortemiChunkManifest = {\n schema_version: 'aiwg.fortemi.index.chunk-manifest.v1',\n generated_at: options.generatedAt ?? index.generated_at,\n source: index.source,\n total: items.length,\n part_size: partSize,\n facets: getAiwgFortemiFacets(items),\n parts: partRefs,\n ...(projection ? { projection, detail: { href: options.detailHref ?? 'detail/{id}.json' } } : {}),\n }\n\n return {\n manifest,\n parts,\n details: projection ? items.map((record) => ({ id: record.id, record })) : [],\n }\n}\n\nfunction includesAll(actual: string[], expected: string[] | undefined): boolean {\n if (!expected || expected.length === 0) return true\n const actualSet = new Set(actual)\n return expected.every((value) => actualSet.has(value))\n}\n\nfunction matchesFacetFilters(item: AiwgFortemiRecord, filters: Record<string, string[]> | undefined): boolean {\n if (!filters) return true\n return Object.entries(filters).every(([name, expected]) => includesAll(item.facets[name] ?? [], expected))\n}\n\nfunction queryMatches(item: AiwgFortemiRecord, q: string): AiwgIndexQueryMatch[] {\n if (!q) return []\n const matches: AiwgIndexQueryMatch[] = []\n if (item.title.toLowerCase().includes(q)) matches.push({ field: 'title', value: item.title })\n if (item.text.toLowerCase().includes(q)) matches.push({ field: 'text', value: item.text })\n for (const tag of item.tags) {\n if (tag.toLowerCase().includes(q)) matches.push({ field: 'tag', value: tag })\n }\n for (const concept of item.concepts) {\n if (concept.toLowerCase().includes(q)) matches.push({ field: 'concept', value: concept })\n }\n return matches\n}\n\nfunction rankMatches(matches: AiwgIndexQueryMatch[], weights: AiwgIndexQueryWeights): number {\n return matches.reduce((total, match) => total + weights[match.field], 0)\n}\n\nfunction clipSnippet(value: string, q: string, maxLength: number): string {\n const normalizedLength = Math.max(20, maxLength)\n if (!value) return ''\n if (!q) return value.length > normalizedLength ? `${value.slice(0, normalizedLength).trimEnd()}...` : value\n\n const lower = value.toLowerCase()\n const index = lower.indexOf(q)\n if (index < 0) return value.length > normalizedLength ? `${value.slice(0, normalizedLength).trimEnd()}...` : value\n\n const context = Math.max(0, Math.floor((normalizedLength - q.length) / 2))\n const start = Math.max(0, index - context)\n const end = Math.min(value.length, start + normalizedLength)\n const prefix = start > 0 ? '...' : ''\n const suffix = end < value.length ? '...' : ''\n return `${prefix}${value.slice(start, end).trim()}${suffix}`\n}\n\nfunction createSnippet(item: AiwgFortemiRecord, matches: AiwgIndexQueryMatch[], q: string, maxLength: number): string {\n const textMatch = matches.find((match) => match.field === 'text')\n const titleMatch = matches.find((match) => match.field === 'title')\n const firstMatch = textMatch ?? titleMatch ?? matches[0]\n return clipSnippet(firstMatch?.value ?? item.text, q, maxLength)\n}\n\ninterface AiwgRankedEntry {\n item: AiwgFortemiRecord\n ordinal: number\n rank: number\n matches: AiwgIndexQueryMatch[]\n}\n\nfunction createRankedEntries(\n items: AiwgFortemiRecord[],\n q: string,\n options: AiwgIndexQueryOptions,\n ordinalBase = 0,\n): AiwgRankedEntry[] {\n const weights = { ...DEFAULT_QUERY_WEIGHTS, ...options.weights }\n return items.map((item, ordinal) => ({ item, ordinal: ordinalBase + ordinal, matches: queryMatches(item, q) }))\n .filter(({ item, matches }) => {\n if (q && matches.length === 0) return false\n if (options.types && !options.types.includes(item.type)) return false\n if (options.privacy && !options.privacy.includes(item.privacy.classification)) return false\n if (!includesAll(item.tags, options.tags)) return false\n if (!includesAll(item.concepts, options.concepts)) return false\n if (!matchesFacetFilters(item, options.facets)) return false\n if (options.relationshipTargetId && !(item.relationships ?? []).some((rel) => rel.target_id === options.relationshipTargetId)) {\n return false\n }\n return true\n })\n .map(({ item, ordinal, matches }) => ({\n item,\n ordinal,\n rank: rankMatches(matches, weights),\n matches,\n }))\n}\n\nfunction sortRankedEntries(entries: AiwgRankedEntry[], rank?: boolean): AiwgRankedEntry[] {\n return [...entries].sort((left, right) => {\n if (rank) return right.rank - left.rank || left.ordinal - right.ordinal\n return left.ordinal - right.ordinal\n })\n}\n\nfunction createQueryResultFromRankedEntries(\n entries: AiwgRankedEntry[],\n query: string,\n options: AiwgIndexQueryOptions,\n): AiwgIndexQueryResult {\n const ranked = sortRankedEntries(entries, options.rank)\n const offset = options.offset ?? 0\n const limit = options.limit ?? ranked.length\n const page = ranked.slice(offset, offset + limit)\n const result: AiwgIndexQueryResult = {\n items: page.map((entry) => entry.item),\n total: ranked.length,\n facets: getAiwgFortemiFacets(ranked.map((entry) => entry.item)),\n }\n if (options.rank || options.snippets || options.includeMatches) {\n const snippetLength = options.snippetLength ?? 160\n result.rankedItems = page.map((entry) => ({\n item: entry.item,\n rank: entry.rank,\n ...(options.snippets ? { snippet: createSnippet(entry.item, entry.matches, query, snippetLength) } : {}),\n ...(options.includeMatches ? { matches: entry.matches } : {}),\n }))\n }\n return result\n}\n\nexport function queryAiwgFortemiIndex(\n index: AiwgFortemiIndexExport,\n query = '',\n options: AiwgIndexQueryOptions = {},\n): AiwgIndexQueryResult {\n const q = query.trim().toLowerCase()\n return createQueryResultFromRankedEntries(createRankedEntries(index.items, q, options), q, options)\n}\n\ninterface AiwgChunkedIndexRuntime {\n manifest: AiwgFortemiChunkManifest\n loader: AiwgChunkedIndexLoader\n maxCachedParts: number\n partCache: Map<string, AiwgFortemiChunkPart>\n detailLoader?: AiwgChunkedIndexDetailLoader\n maxCachedDetails: number\n detailCache: Map<string, AiwgFortemiRecord>\n}\n\nfunction chunkPartCacheKey(part: AiwgFortemiChunkPartRef): string {\n return `${part.offset}:${part.href}`\n}\n\nfunction clampMaxCachedParts(value: number | undefined): number {\n if (!hasPositiveInteger(value)) return 3\n return value\n}\n\nfunction clampMaxCachedDetails(value: number | undefined): number {\n if (!hasPositiveInteger(value)) return 32\n return value\n}\n\nfunction isDirectChunkBrowse(query: string, options: AiwgIndexQueryOptions): boolean {\n return query.trim() === ''\n && !options.rank\n && !options.snippets\n && !options.includeMatches\n && !options.types\n && !options.facets\n && !options.tags\n && !options.concepts\n && !options.privacy\n && !options.relationshipTargetId\n}\n\nfunction getPartsForRange(\n manifest: AiwgFortemiChunkManifest,\n offset: number,\n limit: number,\n): AiwgFortemiChunkPartRef[] {\n const end = offset + limit\n return manifest.parts.filter((part) => part.count > 0 && part.offset < end && part.offset + part.count > offset)\n}\n\nasync function loadChunkPart(\n runtime: AiwgChunkedIndexRuntime,\n part: AiwgFortemiChunkPartRef,\n): Promise<{ part: AiwgFortemiChunkPart; fetched: boolean }> {\n const key = chunkPartCacheKey(part)\n const cached = runtime.partCache.get(key)\n if (cached) {\n runtime.partCache.delete(key)\n runtime.partCache.set(key, cached)\n return { part: cached, fetched: false }\n }\n\n const parsed = assertAiwgFortemiChunkPart(await runtime.loader(part, runtime.manifest), part, runtime.manifest)\n runtime.partCache.set(key, parsed)\n while (runtime.partCache.size > runtime.maxCachedParts) {\n const oldest = runtime.partCache.keys().next().value\n if (oldest === undefined) break\n runtime.partCache.delete(oldest)\n }\n return { part: parsed, fetched: true }\n}\n\nasync function getChunkRecord(runtime: AiwgChunkedIndexRuntime, id: string): Promise<AiwgFortemiRecord> {\n const cached = runtime.detailCache.get(id)\n if (cached) {\n runtime.detailCache.delete(id)\n runtime.detailCache.set(id, cached)\n return cached\n }\n // Whole-record parts already in cache: serve without a detail fetch.\n if (!runtime.manifest.projection) {\n for (const part of runtime.partCache.values()) {\n const found = part.items.find((item) => item.id === id)\n if (found) return found\n }\n }\n if (!runtime.detailLoader) {\n throw new Error('No detailLoader configured to resolve record ' + id)\n }\n const raw = await runtime.detailLoader(id, runtime.manifest)\n const record = assertAiwgFortemiIndexExport({\n schema_version: 'aiwg.fortemi.index.export.v1',\n generated_at: runtime.manifest.generated_at,\n source: runtime.manifest.source,\n items: [raw],\n }).items[0]\n if (record.id !== id) {\n throw new Error('Detail record id mismatch: expected ' + id + ', got ' + record.id)\n }\n runtime.detailCache.set(id, record)\n while (runtime.detailCache.size > runtime.maxCachedDetails) {\n const oldest = runtime.detailCache.keys().next().value\n if (oldest === undefined) break\n runtime.detailCache.delete(oldest)\n }\n return record\n}\n\nasync function queryChunkedAiwgFortemiIndex(\n runtime: AiwgChunkedIndexRuntime,\n query = '',\n options: AiwgChunkedIndexQueryOptions = {},\n): Promise<AiwgChunkedIndexQueryResult> {\n const q = query.trim().toLowerCase()\n let scannedParts = 0\n let fetchedParts = 0\n\n if (isDirectChunkBrowse(query, options)) {\n const offset = options.offset ?? 0\n const limit = options.limit ?? runtime.manifest.total\n const parts = getPartsForRange(runtime.manifest, offset, limit)\n const items: AiwgFortemiRecord[] = []\n for (const partRef of parts) {\n const loaded = await loadChunkPart(runtime, partRef)\n if (loaded.fetched) fetchedParts += 1\n scannedParts += 1\n options.onProgress?.({ phase: 'part', done: scannedParts, total: parts.length, href: partRef.href })\n const start = Math.max(0, offset - partRef.offset)\n const end = Math.min(loaded.part.items.length, offset + limit - partRef.offset)\n items.push(...loaded.part.items.slice(start, end))\n }\n return {\n items,\n total: runtime.manifest.total,\n facets: runtime.manifest.facets ?? {},\n manifestTotal: runtime.manifest.total,\n scannedParts,\n fetchedParts,\n complete: true,\n }\n }\n\n const entries: AiwgRankedEntry[] = []\n for (const partRef of runtime.manifest.parts) {\n const loaded = await loadChunkPart(runtime, partRef)\n if (loaded.fetched) fetchedParts += 1\n scannedParts += 1\n options.onProgress?.({ phase: 'part', done: scannedParts, total: runtime.manifest.parts.length, href: partRef.href })\n entries.push(...createRankedEntries(loaded.part.items, q, options, partRef.offset))\n options.onProgress?.({ phase: 'query', done: scannedParts, total: runtime.manifest.parts.length, href: partRef.href })\n }\n\n return {\n ...createQueryResultFromRankedEntries(entries, q, options),\n manifestTotal: runtime.manifest.total,\n scannedParts,\n fetchedParts,\n complete: true,\n }\n}\n\nexport function createAiwgReviewDecisionExport(\n source: AiwgFortemiIndexExport,\n decisions: AiwgReviewDecision[],\n generatedAt = new Date().toISOString(),\n): AiwgReviewDecisionExport {\n return {\n schema_version: 'aiwg.fortemi.review-decisions.v1',\n generated_at: generatedAt,\n source_export_schema_version: source.schema_version,\n decisions: [...decisions].sort((left, right) => left.item_id.localeCompare(right.item_id)),\n }\n}\n\nexport function createAiwgIndexController(initialIndex?: AiwgFortemiIndexExport): AiwgIndexController {\n let index: AiwgFortemiIndexExport | null = initialIndex ?? null\n let chunked: AiwgChunkedIndexRuntime | null = null\n let data: AiwgIndexQueryResult | null = null\n let error: Error | null = null\n let reviewDecisions: AiwgReviewDecision[] = []\n const listeners = new Set<AiwgIndexControllerListener>()\n\n const snapshot = (): AiwgIndexControllerSnapshot => ({\n index,\n chunked: chunked\n ? {\n manifest: chunked.manifest,\n cachedParts: chunked.partCache.size,\n maxCachedParts: chunked.maxCachedParts,\n }\n : null,\n data,\n error,\n reviewDecisions: [...reviewDecisions],\n })\n const notify = () => {\n const current = snapshot()\n for (const listener of listeners) listener(current)\n }\n const requireIndex = (): AiwgFortemiIndexExport => {\n if (!index) throw new Error('No AIWG index export loaded')\n return index\n }\n\n return {\n loadIndex(value: unknown): AiwgFortemiIndexExport {\n try {\n const parsed = assertAiwgFortemiIndexExport(value)\n index = parsed\n chunked = null\n data = null\n reviewDecisions = []\n error = null\n notify()\n return parsed\n } catch (err) {\n error = err instanceof Error ? err : new Error(String(err))\n notify()\n throw error\n }\n },\n loadChunkedIndex(\n manifest: unknown,\n loader: AiwgChunkedIndexLoader,\n options: AiwgChunkedIndexLoadOptions = {},\n ): AiwgFortemiChunkManifest {\n try {\n const parsed = assertAiwgFortemiChunkManifest(manifest)\n index = null\n chunked = {\n manifest: parsed,\n loader,\n maxCachedParts: clampMaxCachedParts(options.maxCachedParts),\n partCache: new Map(),\n detailLoader: options.detailLoader,\n maxCachedDetails: clampMaxCachedDetails(options.maxCachedDetails),\n detailCache: new Map(),\n }\n data = null\n reviewDecisions = []\n error = null\n notify()\n return parsed\n } catch (err) {\n error = err instanceof Error ? err : new Error(String(err))\n notify()\n throw error\n }\n },\n getIndex(): AiwgFortemiIndexExport | null {\n return index\n },\n getChunkedManifest(): AiwgFortemiChunkManifest | null {\n return chunked?.manifest ?? null\n },\n getSnapshot(): AiwgIndexControllerSnapshot {\n return snapshot()\n },\n query(query = '', options?: AiwgIndexQueryOptions): AiwgIndexQueryResult {\n const result = queryAiwgFortemiIndex(requireIndex(), query, options)\n data = result\n error = null\n notify()\n return result\n },\n async queryChunked(query = '', options?: AiwgChunkedIndexQueryOptions): Promise<AiwgChunkedIndexQueryResult> {\n if (!chunked) throw new Error('No AIWG chunked index manifest loaded')\n try {\n const result = await queryChunkedAiwgFortemiIndex(chunked, query, options)\n data = result\n error = null\n notify()\n return result\n } catch (err) {\n error = err instanceof Error ? err : new Error(String(err))\n notify()\n throw error\n }\n },\n async getRecord(id: string): Promise<AiwgFortemiRecord> {\n if (chunked) {\n try {\n return await getChunkRecord(chunked, id)\n } catch (err) {\n error = err instanceof Error ? err : new Error(String(err))\n notify()\n throw error\n }\n }\n const found = requireIndex().items.find((item) => item.id === id)\n if (!found) throw new Error('Record not found: ' + id)\n return found\n },\n clearChunkCache(): void {\n chunked?.partCache.clear()\n chunked?.detailCache.clear()\n error = null\n notify()\n },\n toCommunityGraph(options?: AiwgIndexGraphOptions) {\n return aiwgFortemiIndexToCommunityGraph(requireIndex(), options)\n },\n setReviewDecision(input: AiwgReviewInput): AiwgReviewDecision {\n const decision: AiwgReviewDecision = {\n ...input,\n updated_at: new Date().toISOString(),\n }\n reviewDecisions = [\n ...reviewDecisions.filter((item) => item.item_id !== decision.item_id),\n decision,\n ].sort((left, right) => left.item_id.localeCompare(right.item_id))\n error = null\n notify()\n return decision\n },\n clearReviewDecision(itemId: string): void {\n reviewDecisions = reviewDecisions.filter((item) => item.item_id !== itemId)\n error = null\n notify()\n },\n createReviewDecisionExport(generatedAt?: string): AiwgReviewDecisionExport {\n return createAiwgReviewDecisionExport(requireIndex(), reviewDecisions, generatedAt)\n },\n subscribe(listener: AiwgIndexControllerListener): () => void {\n listeners.add(listener)\n return () => {\n listeners.delete(listener)\n }\n },\n }\n}\n\nexport function aiwgFortemiIndexToCommunityGraph(\n index: AiwgFortemiIndexExport,\n options: AiwgIndexGraphOptions = {},\n) {\n const ids = new Set(index.items.map((item) => item.id))\n const relationshipWeights = options.relationshipWeights ?? {}\n const edgeCounts = new Map<string, { source: string; target: string; kind: string; weight: number }>()\n\n for (const item of index.items) {\n for (const relationship of item.relationships) {\n if (!ids.has(relationship.target_id) && !options.includeDanglingRelationships) continue\n const kind = relationship.type\n const baseWeight = relationshipWeights[kind] ?? 1\n const key = `${item.id}\\u0000${relationship.target_id}\\u0000${kind}`\n const existing = edgeCounts.get(key)\n if (existing) existing.weight += baseWeight\n else edgeCounts.set(key, { source: item.id, target: relationship.target_id, kind, weight: baseWeight })\n }\n }\n\n const communities = new Map<string, string[]>()\n for (const item of index.items) {\n const communityIds = communityIdsFor(item, options)\n for (const communityId of communityIds) {\n const nodes = communities.get(communityId) ?? []\n nodes.push(item.id)\n communities.set(communityId, nodes)\n }\n }\n\n return {\n nodes: index.items.map((item) => ({ id: item.id })),\n edges: Array.from(edgeCounts.values()).sort((left, right) => (\n left.source.localeCompare(right.source)\n || left.target.localeCompare(right.target)\n || left.kind.localeCompare(right.kind)\n )),\n communities: Array.from(communities.entries())\n .map(([id, nodes]) => ({ id, nodes: [...new Set(nodes)].sort() }))\n .sort((left, right) => left.id.localeCompare(right.id)),\n }\n}\n\nfunction communityIdsFor(item: AiwgFortemiRecord, options: AiwgIndexGraphOptions): string[] {\n if (options.communityFacet) {\n const values = item.facets[options.communityFacet] ?? []\n if (values.length > 0) return values.map((value) => `${options.communityFacet}:${value}`)\n }\n if (options.communityTagPrefix) {\n const prefix = options.communityTagPrefix\n const tags = item.tags.filter((tag) => tag.startsWith(prefix))\n if (tags.length > 0) return tags\n }\n if (item.concepts.length > 0) return item.concepts.map((concept) => `concept:${concept}`)\n return [`type:${item.type}`]\n}\n"]}
1
+ {"version":3,"sources":["../src/aiwg-index.ts"],"names":[],"mappings":"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","file":"aiwg-index.js","sourcesContent":["export type AiwgFortemiRecordType =\n | 'crm.contact'\n | 'crm.organization'\n | 'crm.event'\n | 'crm.interaction'\n | 'aiwg.artifact'\n | 'docs.page'\n\nexport type AiwgPrivacyClassification = 'private' | 'sanitized' | 'public'\nexport type AiwgProvenanceConfidence = 'source' | 'candidate' | 'reviewed' | 'rejected'\nexport type AiwgReviewAction = 'accept' | 'reject' | 'defer'\n\nexport interface AiwgFortemiRecordSource {\n path: string\n repo_relative_path: string\n locator: string\n}\n\nexport interface AiwgFortemiRelationship {\n type: string\n target_id: string\n source_path?: string\n}\n\nexport interface AiwgFortemiProvenance {\n field: string\n source: string\n path: string\n confidence: AiwgProvenanceConfidence\n privacy: AiwgPrivacyClassification\n}\n\nexport interface AiwgFortemiRecord {\n schema_version: 'aiwg.fortemi.index.record.v1'\n id: string\n type: AiwgFortemiRecordType\n source: AiwgFortemiRecordSource\n title: string\n text: string\n facets: Record<string, string[]>\n tags: string[]\n concepts: string[]\n relationships: AiwgFortemiRelationship[]\n provenance: AiwgFortemiProvenance[]\n privacy: {\n classification: AiwgPrivacyClassification\n pii: boolean\n }\n updated_at: string\n}\n\nexport interface AiwgFortemiIndexExport {\n schema_version: 'aiwg.fortemi.index.export.v1'\n generated_at: string\n source: {\n repo: string\n privacy: AiwgPrivacyClassification\n }\n items: AiwgFortemiRecord[]\n}\n\nexport interface AiwgFortemiChunkPartRef {\n href: string\n offset: number\n count: number\n}\n\n// Fields a scan part must retain for query/browse/rank/facet to work. The rest\n// (source, provenance, relationships, updated_at) are detail-only and may be\n// dropped from scan parts via `projection`, then resolved on demand by id.\nexport const AIWG_SCAN_REQUIRED_FIELDS: Array<keyof AiwgFortemiRecord> = [\n 'schema_version',\n 'id',\n 'type',\n 'title',\n 'text',\n 'facets',\n 'tags',\n 'concepts',\n 'privacy',\n]\n\n// A record as it appears in a scan part. With no manifest `projection`, this is a\n// full AiwgFortemiRecord. With a projection, detail-only fields are absent — read\n// them via the controller's getRecord(). Typed as the full record for ergonomics;\n// query/browse code guards the projectable fields.\nexport type AiwgFortemiProjectedRecord =\n Pick<AiwgFortemiRecord, 'schema_version' | 'id' | 'type' | 'title' | 'text' | 'facets' | 'tags' | 'concepts' | 'privacy'>\n & Partial<AiwgFortemiRecord>\n\n// How a record id is encoded into a detail filename/path segment.\n// - 'base64url': path-safe, single segment, no '%' — works on every static host,\n// including ids containing '/' (default for new builds; see #177).\n// - 'uri': encodeURIComponent — legacy. Breaks for ids containing '/' on static\n// servers that reject %2F (path-traversal protection → 404).\nexport type AiwgDetailIdEncoding = 'uri' | 'base64url'\n\n// How the controller resolves a full record by id when scan parts are projected.\nexport interface AiwgFortemiChunkDetailRef {\n // href template containing `{id}`, relative to the manifest base — e.g.\n // \"detail/{id}.json\". The `{id}` is encoded per `encoding` at substitution.\n href: string\n // id→segment encoding. Absent is treated as 'uri' for backward compatibility\n // with manifests built before #177; new builds default to 'base64url'.\n encoding?: AiwgDetailIdEncoding\n}\n\nexport interface AiwgFortemiChunkManifest {\n schema_version: 'aiwg.fortemi.index.chunk-manifest.v1'\n generated_at: string\n source: AiwgFortemiIndexExport['source']\n total: number\n part_size: number\n facets?: Record<string, Record<string, number>>\n // Field names present in scan-part items. Absent → scan parts carry whole records.\n // When set, must include AIWG_SCAN_REQUIRED_FIELDS.\n projection?: Array<keyof AiwgFortemiRecord>\n // Resolver for full records by id (used with `projection` to lazy-load detail).\n detail?: AiwgFortemiChunkDetailRef\n parts: AiwgFortemiChunkPartRef[]\n}\n\nexport interface AiwgFortemiChunkPart {\n schema_version: 'aiwg.fortemi.index.chunk.v1'\n manifest_schema_version: 'aiwg.fortemi.index.chunk-manifest.v1'\n offset: number\n items: AiwgFortemiRecord[]\n}\n\nexport interface AiwgIndexValidationResult {\n valid: boolean\n errors: string[]\n counts: Partial<Record<AiwgFortemiRecordType, number>>\n}\n\nexport interface AiwgChunkedIndexValidationResult {\n valid: boolean\n errors: string[]\n}\n\nexport interface AiwgIndexQueryOptions {\n types?: AiwgFortemiRecordType[]\n facets?: Record<string, string[]>\n tags?: string[]\n concepts?: string[]\n privacy?: AiwgPrivacyClassification[]\n relationshipTargetId?: string\n limit?: number\n offset?: number\n rank?: boolean\n snippets?: boolean\n snippetLength?: number\n weights?: Partial<AiwgIndexQueryWeights>\n includeMatches?: boolean\n}\n\nexport interface AiwgIndexQueryWeights {\n title: number\n text: number\n tag: number\n concept: number\n}\n\nexport interface AiwgIndexQueryMatch {\n field: 'title' | 'text' | 'tag' | 'concept'\n value: string\n}\n\nexport interface AiwgIndexQueryRankedItem {\n item: AiwgFortemiRecord\n rank: number\n snippet?: string\n matches?: AiwgIndexQueryMatch[]\n}\n\nexport interface AiwgIndexQueryResult {\n items: AiwgFortemiRecord[]\n total: number\n facets: Record<string, Record<string, number>>\n rankedItems?: AiwgIndexQueryRankedItem[]\n}\n\nexport type AiwgChunkedIndexLoader = (\n part: AiwgFortemiChunkPartRef,\n manifest: AiwgFortemiChunkManifest,\n) => Promise<unknown>\n\n// Resolves a full record by id (used with projected scan parts). Returns the\n// parsed record JSON; validated by the controller before use.\nexport type AiwgChunkedIndexDetailLoader = (\n id: string,\n manifest: AiwgFortemiChunkManifest,\n) => Promise<unknown>\n\nexport interface AiwgChunkedIndexLoadOptions {\n maxCachedParts?: number\n // Required to resolve detail for projected indexes via getRecord(); ignored otherwise.\n detailLoader?: AiwgChunkedIndexDetailLoader\n maxCachedDetails?: number\n // Bounds the filtered/ranked match-set cache used to page a query without\n // re-scanning every part. Counts total cached entries across all queries\n // (LRU-evicted). Defaults to 5000. The cache is keyed on query + filters +\n // weights, so paging the same query (varying only offset/limit/sort/snippets)\n // reuses the scan; see queryChunked.\n maxCachedMatches?: number\n}\n\nexport type AiwgChunkedIndexProgressPhase = 'part' | 'query'\n\nexport interface AiwgChunkedIndexProgress {\n phase: AiwgChunkedIndexProgressPhase\n done: number\n total: number\n href?: string\n}\n\nexport interface AiwgChunkedIndexQueryOptions extends AiwgIndexQueryOptions {\n onProgress?: (progress: AiwgChunkedIndexProgress) => void\n}\n\nexport interface AiwgChunkedIndexQueryResult extends AiwgIndexQueryResult {\n manifestTotal: number\n scannedParts: number\n fetchedParts: number\n complete: boolean\n}\n\nexport interface AiwgReviewDecision {\n item_id: string\n action: AiwgReviewAction\n reason?: string\n updated_at: string\n}\n\nexport interface AiwgReviewDecisionExport {\n schema_version: 'aiwg.fortemi.review-decisions.v1'\n generated_at: string\n source_export_schema_version: string\n decisions: AiwgReviewDecision[]\n}\n\nexport interface AiwgIndexGraphOptions {\n communityFacet?: string\n communityTagPrefix?: string\n relationshipWeights?: Record<string, number>\n includeDanglingRelationships?: boolean\n}\n\nexport interface AiwgReviewInput {\n item_id: string\n action: AiwgReviewAction\n reason?: string\n}\n\nexport interface AiwgIndexControllerSnapshot {\n index: AiwgFortemiIndexExport | null\n chunked: {\n manifest: AiwgFortemiChunkManifest\n cachedParts: number\n maxCachedParts: number\n } | null\n data: AiwgIndexQueryResult | null\n error: Error | null\n reviewDecisions: AiwgReviewDecision[]\n}\n\nexport type AiwgIndexControllerListener = (snapshot: AiwgIndexControllerSnapshot) => void\n\nexport interface AiwgIndexController {\n loadIndex(value: unknown): AiwgFortemiIndexExport\n loadChunkedIndex(\n manifest: unknown,\n loader: AiwgChunkedIndexLoader,\n options?: AiwgChunkedIndexLoadOptions,\n ): AiwgFortemiChunkManifest\n getIndex(): AiwgFortemiIndexExport | null\n getChunkedManifest(): AiwgFortemiChunkManifest | null\n getSnapshot(): AiwgIndexControllerSnapshot\n query(query?: string, options?: AiwgIndexQueryOptions): AiwgIndexQueryResult\n queryChunked(query?: string, options?: AiwgChunkedIndexQueryOptions): Promise<AiwgChunkedIndexQueryResult>\n // Resolve a full record by id. For a projected chunked index, fetches detail via\n // the detailLoader (bounded cache); for a whole-record index/parts, returns the\n // record from loaded data. Rejects if detail is unavailable.\n getRecord(id: string): Promise<AiwgFortemiRecord>\n clearChunkCache(): void\n toCommunityGraph(options?: AiwgIndexGraphOptions): ReturnType<typeof aiwgFortemiIndexToCommunityGraph>\n setReviewDecision(input: AiwgReviewInput): AiwgReviewDecision\n clearReviewDecision(itemId: string): void\n createReviewDecisionExport(generatedAt?: string): AiwgReviewDecisionExport\n subscribe(listener: AiwgIndexControllerListener): () => void\n}\n\nconst REQUIRED_RECORD_FIELDS: Array<keyof AiwgFortemiRecord> = [\n 'schema_version',\n 'id',\n 'type',\n 'source',\n 'title',\n 'text',\n 'facets',\n 'tags',\n 'concepts',\n 'relationships',\n 'provenance',\n 'privacy',\n 'updated_at',\n]\n\nconst VALID_TYPES = new Set<AiwgFortemiRecordType>([\n 'crm.contact',\n 'crm.organization',\n 'crm.event',\n 'crm.interaction',\n 'aiwg.artifact',\n 'docs.page',\n])\n\nconst DEFAULT_QUERY_WEIGHTS: AiwgIndexQueryWeights = {\n title: 4,\n tag: 3,\n concept: 2,\n text: 1,\n}\n\nfunction hasString(value: unknown): value is string {\n return typeof value === 'string' && value.length > 0\n}\n\nfunction pushFacet(counts: Record<string, Record<string, number>>, name: string, value: string) {\n counts[name] ??= {}\n counts[name][value] = (counts[name][value] ?? 0) + 1\n}\n\nfunction hasNonNegativeInteger(value: unknown): value is number {\n return Number.isInteger(value) && typeof value === 'number' && value >= 0\n}\n\nfunction hasPositiveInteger(value: unknown): value is number {\n return Number.isInteger(value) && typeof value === 'number' && value > 0\n}\n\nfunction isFacetCounts(value: unknown): value is Record<string, Record<string, number>> {\n if (!value || typeof value !== 'object' || Array.isArray(value)) return false\n return Object.values(value).every((counts) => (\n !!counts\n && typeof counts === 'object'\n && !Array.isArray(counts)\n && Object.values(counts).every((count) => hasNonNegativeInteger(count))\n ))\n}\n\nexport function validateAiwgFortemiIndexExport(value: unknown): AiwgIndexValidationResult {\n const errors: string[] = []\n const counts: Partial<Record<AiwgFortemiRecordType, number>> = {}\n const data = value as Partial<AiwgFortemiIndexExport>\n\n if (data?.schema_version !== 'aiwg.fortemi.index.export.v1') {\n errors.push('schema_version must be aiwg.fortemi.index.export.v1')\n }\n if (!hasString(data?.generated_at)) errors.push('generated_at is required')\n if (!hasString(data?.source?.repo)) errors.push('source.repo is required')\n if (!hasString(data?.source?.privacy)) errors.push('source.privacy is required')\n if (!Array.isArray(data?.items)) errors.push('items must be an array')\n\n const ids = new Set<string>()\n let previousId = ''\n for (const [index, item] of (data.items ?? []).entries()) {\n for (const field of REQUIRED_RECORD_FIELDS) {\n if (!(field in item)) errors.push('items[' + index + '].' + field + ' is required')\n }\n if (item.schema_version !== 'aiwg.fortemi.index.record.v1') {\n errors.push('items[' + index + '].schema_version must be aiwg.fortemi.index.record.v1')\n }\n if (!hasString(item.id)) errors.push('items[' + index + '].id is required')\n if (hasString(item.id) && ids.has(item.id)) errors.push('duplicate id: ' + item.id)\n if (hasString(item.id)) ids.add(item.id)\n if (previousId && hasString(item.id) && previousId.localeCompare(item.id) > 0) {\n errors.push('items must be sorted by id: ' + previousId + ' before ' + item.id)\n }\n if (hasString(item.id)) previousId = item.id\n if (!VALID_TYPES.has(item.type)) errors.push('items[' + index + '].type is invalid')\n else counts[item.type] = (counts[item.type] ?? 0) + 1\n if (!hasString(item.source?.path)) errors.push('items[' + index + '].source.path is required')\n if (!hasString(item.source?.repo_relative_path)) errors.push('items[' + index + '].source.repo_relative_path is required')\n if (!hasString(item.source?.locator)) errors.push('items[' + index + '].source.locator is required')\n if (!Array.isArray(item.tags)) errors.push('items[' + index + '].tags must be an array')\n if (!Array.isArray(item.concepts)) errors.push('items[' + index + '].concepts must be an array')\n if (!Array.isArray(item.relationships)) errors.push('items[' + index + '].relationships must be an array')\n if (!Array.isArray(item.provenance) || item.provenance.length === 0) {\n errors.push('items[' + index + '].provenance must be a non-empty array')\n }\n if (!item.privacy || typeof item.privacy.pii !== 'boolean' || !hasString(item.privacy.classification)) {\n errors.push('items[' + index + '].privacy requires classification and pii')\n }\n }\n\n return { valid: errors.length === 0, errors, counts }\n}\n\nexport function assertAiwgFortemiIndexExport(value: unknown): AiwgFortemiIndexExport {\n const result = validateAiwgFortemiIndexExport(value)\n if (!result.valid) {\n throw new Error('Invalid AIWG Fortemi index export:\\n' + result.errors.join('\\n'))\n }\n return value as AiwgFortemiIndexExport\n}\n\nexport function validateAiwgFortemiChunkManifest(value: unknown): AiwgChunkedIndexValidationResult {\n const errors: string[] = []\n const data = value as Partial<AiwgFortemiChunkManifest>\n\n if (data?.schema_version !== 'aiwg.fortemi.index.chunk-manifest.v1') {\n errors.push('schema_version must be aiwg.fortemi.index.chunk-manifest.v1')\n }\n if (!hasString(data?.generated_at)) errors.push('generated_at is required')\n if (!hasString(data?.source?.repo)) errors.push('source.repo is required')\n if (!hasString(data?.source?.privacy)) errors.push('source.privacy is required')\n if (!hasNonNegativeInteger(data?.total)) errors.push('total must be a non-negative integer')\n if (!hasPositiveInteger(data?.part_size)) errors.push('part_size must be a positive integer')\n if (data.facets !== undefined && !isFacetCounts(data.facets)) {\n errors.push('facets must be a nested string-to-number count object')\n }\n if (data.projection !== undefined) {\n if (!Array.isArray(data.projection) || !data.projection.every((field) => typeof field === 'string')) {\n errors.push('projection must be an array of field names')\n } else {\n const present = new Set(data.projection)\n for (const field of AIWG_SCAN_REQUIRED_FIELDS) {\n if (!present.has(field)) errors.push('projection must include scan-required field ' + field)\n }\n }\n }\n if (data.detail !== undefined) {\n if (!hasString(data.detail.href)) errors.push('detail.href is required')\n else if (!data.detail.href.includes('{id}')) errors.push('detail.href must contain the {id} placeholder')\n if (\n data.detail.encoding !== undefined &&\n data.detail.encoding !== 'uri' &&\n data.detail.encoding !== 'base64url'\n ) {\n errors.push(\"detail.encoding must be 'uri' or 'base64url'\")\n }\n }\n if (!Array.isArray(data?.parts)) errors.push('parts must be an array')\n\n let expectedOffset = 0\n const parts = Array.isArray(data?.parts) ? data.parts : []\n for (const [index, part] of parts.entries()) {\n if (!hasString(part.href)) errors.push('parts[' + index + '].href is required')\n if (!hasNonNegativeInteger(part.offset)) errors.push('parts[' + index + '].offset must be a non-negative integer')\n if (!hasNonNegativeInteger(part.count)) errors.push('parts[' + index + '].count must be a non-negative integer')\n if (hasNonNegativeInteger(part.offset) && part.offset !== expectedOffset) {\n errors.push('parts[' + index + '].offset must be ' + expectedOffset)\n }\n if (hasNonNegativeInteger(part.count)) expectedOffset += part.count\n }\n if (hasNonNegativeInteger(data?.total) && expectedOffset !== data.total) {\n errors.push('parts counts must add up to total')\n }\n\n return { valid: errors.length === 0, errors }\n}\n\nexport function assertAiwgFortemiChunkManifest(value: unknown): AiwgFortemiChunkManifest {\n const result = validateAiwgFortemiChunkManifest(value)\n if (!result.valid) {\n throw new Error('Invalid AIWG Fortemi chunk manifest:\\n' + result.errors.join('\\n'))\n }\n return value as AiwgFortemiChunkManifest\n}\n\n// Validate projected (slim) scan-part items: scan-required fields only, ids unique + sorted.\nfunction validateProjectedRecords(items: Array<Partial<AiwgFortemiRecord>>): string[] {\n const errors: string[] = []\n const ids = new Set<string>()\n let previousId = ''\n for (const [index, item] of items.entries()) {\n if (item.schema_version !== 'aiwg.fortemi.index.record.v1') {\n errors.push('items[' + index + '].schema_version must be aiwg.fortemi.index.record.v1')\n }\n if (!hasString(item.id)) errors.push('items[' + index + '].id is required')\n if (hasString(item.id) && ids.has(item.id)) errors.push('duplicate id: ' + item.id)\n if (hasString(item.id)) ids.add(item.id)\n if (previousId && hasString(item.id) && previousId.localeCompare(item.id) > 0) {\n errors.push('items must be sorted by id: ' + previousId + ' before ' + item.id)\n }\n if (hasString(item.id)) previousId = item.id\n if (!item.type || !VALID_TYPES.has(item.type)) errors.push('items[' + index + '].type is invalid')\n if (!hasString(item.title)) errors.push('items[' + index + '].title is required')\n if (typeof item.text !== 'string') errors.push('items[' + index + '].text is required')\n if (!item.facets || typeof item.facets !== 'object' || Array.isArray(item.facets)) {\n errors.push('items[' + index + '].facets must be an object')\n }\n if (!Array.isArray(item.tags)) errors.push('items[' + index + '].tags must be an array')\n if (!Array.isArray(item.concepts)) errors.push('items[' + index + '].concepts must be an array')\n if (!item.privacy || !hasString(item.privacy.classification)) {\n errors.push('items[' + index + '].privacy.classification is required')\n }\n }\n return errors\n}\n\nexport function validateAiwgFortemiChunkPart(\n value: unknown,\n partRef?: AiwgFortemiChunkPartRef,\n manifest?: AiwgFortemiChunkManifest,\n): AiwgChunkedIndexValidationResult {\n const errors: string[] = []\n const data = value as Partial<AiwgFortemiChunkPart>\n\n if (data?.schema_version !== 'aiwg.fortemi.index.chunk.v1') {\n errors.push('schema_version must be aiwg.fortemi.index.chunk.v1')\n }\n if (data?.manifest_schema_version !== 'aiwg.fortemi.index.chunk-manifest.v1') {\n errors.push('manifest_schema_version must be aiwg.fortemi.index.chunk-manifest.v1')\n }\n if (!hasNonNegativeInteger(data?.offset)) errors.push('offset must be a non-negative integer')\n if (!Array.isArray(data?.items)) errors.push('items must be an array')\n\n if (partRef && hasNonNegativeInteger(data?.offset) && data.offset !== partRef.offset) {\n errors.push('offset must match manifest part offset ' + partRef.offset)\n }\n if (partRef && Array.isArray(data?.items) && data.items.length !== partRef.count) {\n errors.push('items length must match manifest part count ' + partRef.count)\n }\n\n if (Array.isArray(data?.items)) {\n if (manifest?.projection) {\n errors.push(...validateProjectedRecords(data.items).map((error) => 'items.' + error))\n } else {\n const validation = validateAiwgFortemiIndexExport({\n schema_version: 'aiwg.fortemi.index.export.v1',\n generated_at: manifest?.generated_at ?? '1970-01-01T00:00:00.000Z',\n source: manifest?.source ?? { repo: 'chunk', privacy: 'public' },\n items: data.items,\n })\n errors.push(...validation.errors.map((error) => 'items.' + error))\n }\n }\n\n return { valid: errors.length === 0, errors }\n}\n\nexport function assertAiwgFortemiChunkPart(\n value: unknown,\n partRef?: AiwgFortemiChunkPartRef,\n manifest?: AiwgFortemiChunkManifest,\n): AiwgFortemiChunkPart {\n const result = validateAiwgFortemiChunkPart(value, partRef, manifest)\n if (!result.valid) {\n throw new Error('Invalid AIWG Fortemi chunk part:\\n' + result.errors.join('\\n'))\n }\n return value as AiwgFortemiChunkPart\n}\n\nexport function createAiwgFetchChunkLoader(baseUrl?: string | URL): AiwgChunkedIndexLoader {\n return async (part) => {\n const href = baseUrl ? new URL(part.href, baseUrl).toString() : part.href\n const response = await fetch(href)\n if (!response.ok) throw new Error('Failed to fetch AIWG index chunk ' + href + ': ' + response.status)\n return response.json()\n }\n}\n\n// Encode a record id into a single, path-safe detail filename segment.\n// - 'base64url' (default): UTF-8 → base64url (no '+', '/', '=', '%'). Safe for ids\n// containing '/' on static hosts that reject %2F (#177).\n// - 'uri': encodeURIComponent (legacy).\nexport function encodeAiwgDetailId(id: string, encoding: AiwgDetailIdEncoding = 'base64url'): string {\n if (encoding === 'uri') return encodeURIComponent(id)\n const bytes = new TextEncoder().encode(id)\n let binary = ''\n for (const byte of bytes) binary += String.fromCharCode(byte)\n // btoa is available in browsers and Node ≥16.\n return btoa(binary).replace(/\\+/g, '-').replace(/\\//g, '_').replace(/=+$/, '')\n}\n\n// Resolve a manifest detail.href template for a given id, honoring detail.encoding\n// (absent → 'uri' for backward compatibility). The writer and the loader both go\n// through this so emitted filenames and fetched paths always agree.\nexport function aiwgDetailHrefForId(detail: AiwgFortemiChunkDetailRef, id: string): string {\n return detail.href.replace('{id}', encodeAiwgDetailId(id, detail.encoding ?? 'uri'))\n}\n\n// Detail loader for projected indexes: resolves the manifest's detail.href {id}\n// template (encoded per detail.encoding) against baseUrl and fetches the full record.\nexport function createAiwgFetchDetailLoader(baseUrl?: string | URL): AiwgChunkedIndexDetailLoader {\n return async (id, manifest) => {\n if (!manifest.detail?.href) throw new Error('Manifest has no detail.href for record resolution')\n const relative = aiwgDetailHrefForId(manifest.detail, id)\n const href = baseUrl ? new URL(relative, baseUrl).toString() : relative\n const response = await fetch(href)\n if (!response.ok) throw new Error('Failed to fetch AIWG index detail ' + href + ': ' + response.status)\n return response.json()\n }\n}\n\nexport function getAiwgFortemiFacets(items: AiwgFortemiRecord[]): Record<string, Record<string, number>> {\n const result: Record<string, Record<string, number>> = {}\n for (const item of items) {\n pushFacet(result, 'type', item.type)\n pushFacet(result, 'privacy', item.privacy.classification)\n for (const tag of item.tags) pushFacet(result, 'tag', tag)\n for (const concept of item.concepts) pushFacet(result, 'concept', concept)\n for (const [name, values] of Object.entries(item.facets)) {\n for (const value of values) pushFacet(result, name, value)\n }\n }\n return result\n}\n\nexport interface AiwgChunkedIndexBuildOptions {\n partSize?: number\n // When set, scan parts carry only these fields; full records go to `details`.\n projection?: Array<keyof AiwgFortemiRecord>\n // Detail href template (with {id}); defaults to \"detail/{id}.json\" when projecting.\n detailHref?: string\n // id→filename encoding for detail files; defaults to 'base64url' (path-safe,\n // works for ids containing '/'; see #177).\n idEncoding?: AiwgDetailIdEncoding\n generatedAt?: string\n}\n\nexport interface AiwgChunkedIndexBuildResult {\n manifest: AiwgFortemiChunkManifest\n parts: Array<{ href: string; part: AiwgFortemiChunkPart }>\n // Empty unless projecting. Each entry carries the full record plus the resolved,\n // encoding-correct `href` to host it at — write the record to that path so the\n // detail loader (which uses the same encoding) can fetch it back.\n details: Array<{ id: string; href: string; record: AiwgFortemiRecord }>\n}\n\n// Pure builder (no I/O): project an index export into the chunked manifest + parts\n// (+ detail records when projecting). The caller writes the returned objects to disk.\n// Manifest facets are computed from the full records, so global counts are exact even\n// when scan parts are slim.\nexport function buildAiwgChunkedIndex(\n index: AiwgFortemiIndexExport,\n options: AiwgChunkedIndexBuildOptions = {},\n): AiwgChunkedIndexBuildResult {\n const partSize = hasPositiveInteger(options.partSize) ? options.partSize : 500\n const projection = options.projection\n const idEncoding = options.idEncoding ?? 'base64url'\n const detailHref = options.detailHref ?? 'detail/{id}.json'\n const items = index.items\n const pad = (value: number): string => String(value).padStart(4, '0')\n const project = (record: AiwgFortemiRecord): AiwgFortemiRecord => {\n if (!projection) return record\n const slim: Record<string, unknown> = {}\n for (const field of projection) slim[field] = record[field]\n return slim as unknown as AiwgFortemiRecord\n }\n\n const parts: Array<{ href: string; part: AiwgFortemiChunkPart }> = []\n const partRefs: AiwgFortemiChunkPartRef[] = []\n for (let offset = 0, partIndex = 0; offset < items.length; offset += partSize, partIndex += 1) {\n const slice = items.slice(offset, offset + partSize)\n const href = 'part-' + pad(partIndex) + '.json'\n parts.push({\n href,\n part: {\n schema_version: 'aiwg.fortemi.index.chunk.v1',\n manifest_schema_version: 'aiwg.fortemi.index.chunk-manifest.v1',\n offset,\n items: slice.map(project),\n },\n })\n partRefs.push({ href, offset, count: slice.length })\n }\n\n const manifest: AiwgFortemiChunkManifest = {\n schema_version: 'aiwg.fortemi.index.chunk-manifest.v1',\n generated_at: options.generatedAt ?? index.generated_at,\n source: index.source,\n total: items.length,\n part_size: partSize,\n facets: getAiwgFortemiFacets(items),\n parts: partRefs,\n ...(projection ? { projection, detail: { href: detailHref, encoding: idEncoding } } : {}),\n }\n\n return {\n manifest,\n parts,\n details: projection\n ? items.map((record) => ({\n id: record.id,\n href: aiwgDetailHrefForId({ href: detailHref, encoding: idEncoding }, record.id),\n record,\n }))\n : [],\n }\n}\n\nfunction includesAll(actual: string[], expected: string[] | undefined): boolean {\n if (!expected || expected.length === 0) return true\n const actualSet = new Set(actual)\n return expected.every((value) => actualSet.has(value))\n}\n\nfunction matchesFacetFilters(item: AiwgFortemiRecord, filters: Record<string, string[]> | undefined): boolean {\n if (!filters) return true\n return Object.entries(filters).every(([name, expected]) => includesAll(item.facets[name] ?? [], expected))\n}\n\nfunction queryMatches(item: AiwgFortemiRecord, q: string): AiwgIndexQueryMatch[] {\n if (!q) return []\n const matches: AiwgIndexQueryMatch[] = []\n if (item.title.toLowerCase().includes(q)) matches.push({ field: 'title', value: item.title })\n if (item.text.toLowerCase().includes(q)) matches.push({ field: 'text', value: item.text })\n for (const tag of item.tags) {\n if (tag.toLowerCase().includes(q)) matches.push({ field: 'tag', value: tag })\n }\n for (const concept of item.concepts) {\n if (concept.toLowerCase().includes(q)) matches.push({ field: 'concept', value: concept })\n }\n return matches\n}\n\nfunction rankMatches(matches: AiwgIndexQueryMatch[], weights: AiwgIndexQueryWeights): number {\n return matches.reduce((total, match) => total + weights[match.field], 0)\n}\n\nfunction clipSnippet(value: string, q: string, maxLength: number): string {\n const normalizedLength = Math.max(20, maxLength)\n if (!value) return ''\n if (!q) return value.length > normalizedLength ? `${value.slice(0, normalizedLength).trimEnd()}...` : value\n\n const lower = value.toLowerCase()\n const index = lower.indexOf(q)\n if (index < 0) return value.length > normalizedLength ? `${value.slice(0, normalizedLength).trimEnd()}...` : value\n\n const context = Math.max(0, Math.floor((normalizedLength - q.length) / 2))\n const start = Math.max(0, index - context)\n const end = Math.min(value.length, start + normalizedLength)\n const prefix = start > 0 ? '...' : ''\n const suffix = end < value.length ? '...' : ''\n return `${prefix}${value.slice(start, end).trim()}${suffix}`\n}\n\nfunction createSnippet(item: AiwgFortemiRecord, matches: AiwgIndexQueryMatch[], q: string, maxLength: number): string {\n const textMatch = matches.find((match) => match.field === 'text')\n const titleMatch = matches.find((match) => match.field === 'title')\n const firstMatch = textMatch ?? titleMatch ?? matches[0]\n return clipSnippet(firstMatch?.value ?? item.text, q, maxLength)\n}\n\ninterface AiwgRankedEntry {\n item: AiwgFortemiRecord\n ordinal: number\n rank: number\n matches: AiwgIndexQueryMatch[]\n}\n\nfunction createRankedEntries(\n items: AiwgFortemiRecord[],\n q: string,\n options: AiwgIndexQueryOptions,\n ordinalBase = 0,\n): AiwgRankedEntry[] {\n const weights = { ...DEFAULT_QUERY_WEIGHTS, ...options.weights }\n return items.map((item, ordinal) => ({ item, ordinal: ordinalBase + ordinal, matches: queryMatches(item, q) }))\n .filter(({ item, matches }) => {\n if (q && matches.length === 0) return false\n if (options.types && !options.types.includes(item.type)) return false\n if (options.privacy && !options.privacy.includes(item.privacy.classification)) return false\n if (!includesAll(item.tags, options.tags)) return false\n if (!includesAll(item.concepts, options.concepts)) return false\n if (!matchesFacetFilters(item, options.facets)) return false\n if (options.relationshipTargetId && !(item.relationships ?? []).some((rel) => rel.target_id === options.relationshipTargetId)) {\n return false\n }\n return true\n })\n .map(({ item, ordinal, matches }) => ({\n item,\n ordinal,\n rank: rankMatches(matches, weights),\n matches,\n }))\n}\n\nfunction sortRankedEntries(entries: AiwgRankedEntry[], rank?: boolean): AiwgRankedEntry[] {\n return [...entries].sort((left, right) => {\n if (rank) return right.rank - left.rank || left.ordinal - right.ordinal\n return left.ordinal - right.ordinal\n })\n}\n\nfunction createQueryResultFromRankedEntries(\n entries: AiwgRankedEntry[],\n query: string,\n options: AiwgIndexQueryOptions,\n): AiwgIndexQueryResult {\n const ranked = sortRankedEntries(entries, options.rank)\n const offset = options.offset ?? 0\n const limit = options.limit ?? ranked.length\n const page = ranked.slice(offset, offset + limit)\n const result: AiwgIndexQueryResult = {\n items: page.map((entry) => entry.item),\n total: ranked.length,\n facets: getAiwgFortemiFacets(ranked.map((entry) => entry.item)),\n }\n if (options.rank || options.snippets || options.includeMatches) {\n const snippetLength = options.snippetLength ?? 160\n result.rankedItems = page.map((entry) => ({\n item: entry.item,\n rank: entry.rank,\n ...(options.snippets ? { snippet: createSnippet(entry.item, entry.matches, query, snippetLength) } : {}),\n ...(options.includeMatches ? { matches: entry.matches } : {}),\n }))\n }\n return result\n}\n\nexport function queryAiwgFortemiIndex(\n index: AiwgFortemiIndexExport,\n query = '',\n options: AiwgIndexQueryOptions = {},\n): AiwgIndexQueryResult {\n const q = query.trim().toLowerCase()\n return createQueryResultFromRankedEntries(createRankedEntries(index.items, q, options), q, options)\n}\n\ninterface AiwgChunkedIndexRuntime {\n manifest: AiwgFortemiChunkManifest\n loader: AiwgChunkedIndexLoader\n maxCachedParts: number\n partCache: Map<string, AiwgFortemiChunkPart>\n detailLoader?: AiwgChunkedIndexDetailLoader\n maxCachedDetails: number\n detailCache: Map<string, AiwgFortemiRecord>\n maxCachedMatches: number\n // query+filter+weights key -> the full filtered/ranked entry set for that\n // query (offset/limit/sort/snippets independent). LRU-ordered; bounded by\n // maxCachedMatches (total entries). Lets pagination reuse a single scan.\n matchCache: Map<string, AiwgRankedEntry[]>\n}\n\nfunction chunkPartCacheKey(part: AiwgFortemiChunkPartRef): string {\n return `${part.offset}:${part.href}`\n}\n\nfunction clampMaxCachedParts(value: number | undefined): number {\n if (!hasPositiveInteger(value)) return 3\n return value\n}\n\nfunction clampMaxCachedDetails(value: number | undefined): number {\n if (!hasPositiveInteger(value)) return 32\n return value\n}\n\nfunction clampMaxCachedMatches(value: number | undefined): number {\n if (!hasPositiveInteger(value)) return 5000\n return value\n}\n\n// Stable key over the inputs that determine the filtered/ranked entry SET and\n// each entry's rank value — but not offset/limit/sort/snippets, which only shape\n// the page projected from a cached set. Caller-stable option objects (same field\n// order each page) hit the cache; a reordered object simply misses (still correct).\nfunction matchSetCacheKey(q: string, options: AiwgIndexQueryOptions): string {\n return JSON.stringify({\n q,\n types: options.types ?? null,\n facets: options.facets ?? null,\n tags: options.tags ?? null,\n concepts: options.concepts ?? null,\n privacy: options.privacy ?? null,\n rel: options.relationshipTargetId ?? null,\n weights: { ...DEFAULT_QUERY_WEIGHTS, ...options.weights },\n })\n}\n\nfunction cacheMatchEntries(runtime: AiwgChunkedIndexRuntime, key: string, entries: AiwgRankedEntry[]): void {\n runtime.matchCache.delete(key)\n runtime.matchCache.set(key, entries)\n let total = 0\n for (const set of runtime.matchCache.values()) total += set.length\n // Evict oldest sets until within budget, but always keep the just-inserted set\n // so paging a large result still benefits from the single scan.\n while (total > runtime.maxCachedMatches && runtime.matchCache.size > 1) {\n const oldest = runtime.matchCache.keys().next().value\n if (oldest === undefined || oldest === key) break\n total -= runtime.matchCache.get(oldest)?.length ?? 0\n runtime.matchCache.delete(oldest)\n }\n}\n\nfunction isDirectChunkBrowse(query: string, options: AiwgIndexQueryOptions): boolean {\n return query.trim() === ''\n && !options.rank\n && !options.snippets\n && !options.includeMatches\n && !options.types\n && !options.facets\n && !options.tags\n && !options.concepts\n && !options.privacy\n && !options.relationshipTargetId\n}\n\nfunction getPartsForRange(\n manifest: AiwgFortemiChunkManifest,\n offset: number,\n limit: number,\n): AiwgFortemiChunkPartRef[] {\n const end = offset + limit\n return manifest.parts.filter((part) => part.count > 0 && part.offset < end && part.offset + part.count > offset)\n}\n\nasync function loadChunkPart(\n runtime: AiwgChunkedIndexRuntime,\n part: AiwgFortemiChunkPartRef,\n): Promise<{ part: AiwgFortemiChunkPart; fetched: boolean }> {\n const key = chunkPartCacheKey(part)\n const cached = runtime.partCache.get(key)\n if (cached) {\n runtime.partCache.delete(key)\n runtime.partCache.set(key, cached)\n return { part: cached, fetched: false }\n }\n\n const parsed = assertAiwgFortemiChunkPart(await runtime.loader(part, runtime.manifest), part, runtime.manifest)\n runtime.partCache.set(key, parsed)\n while (runtime.partCache.size > runtime.maxCachedParts) {\n const oldest = runtime.partCache.keys().next().value\n if (oldest === undefined) break\n runtime.partCache.delete(oldest)\n }\n return { part: parsed, fetched: true }\n}\n\nasync function getChunkRecord(runtime: AiwgChunkedIndexRuntime, id: string): Promise<AiwgFortemiRecord> {\n const cached = runtime.detailCache.get(id)\n if (cached) {\n runtime.detailCache.delete(id)\n runtime.detailCache.set(id, cached)\n return cached\n }\n // Whole-record parts already in cache: serve without a detail fetch.\n if (!runtime.manifest.projection) {\n for (const part of runtime.partCache.values()) {\n const found = part.items.find((item) => item.id === id)\n if (found) return found\n }\n }\n if (!runtime.detailLoader) {\n throw new Error('No detailLoader configured to resolve record ' + id)\n }\n const raw = await runtime.detailLoader(id, runtime.manifest)\n const record = assertAiwgFortemiIndexExport({\n schema_version: 'aiwg.fortemi.index.export.v1',\n generated_at: runtime.manifest.generated_at,\n source: runtime.manifest.source,\n items: [raw],\n }).items[0]\n if (record.id !== id) {\n throw new Error('Detail record id mismatch: expected ' + id + ', got ' + record.id)\n }\n runtime.detailCache.set(id, record)\n while (runtime.detailCache.size > runtime.maxCachedDetails) {\n const oldest = runtime.detailCache.keys().next().value\n if (oldest === undefined) break\n runtime.detailCache.delete(oldest)\n }\n return record\n}\n\nasync function queryChunkedAiwgFortemiIndex(\n runtime: AiwgChunkedIndexRuntime,\n query = '',\n options: AiwgChunkedIndexQueryOptions = {},\n): Promise<AiwgChunkedIndexQueryResult> {\n const q = query.trim().toLowerCase()\n let scannedParts = 0\n let fetchedParts = 0\n\n if (isDirectChunkBrowse(query, options)) {\n const offset = options.offset ?? 0\n const limit = options.limit ?? runtime.manifest.total\n const parts = getPartsForRange(runtime.manifest, offset, limit)\n const items: AiwgFortemiRecord[] = []\n for (const partRef of parts) {\n const loaded = await loadChunkPart(runtime, partRef)\n if (loaded.fetched) fetchedParts += 1\n scannedParts += 1\n options.onProgress?.({ phase: 'part', done: scannedParts, total: parts.length, href: partRef.href })\n const start = Math.max(0, offset - partRef.offset)\n const end = Math.min(loaded.part.items.length, offset + limit - partRef.offset)\n items.push(...loaded.part.items.slice(start, end))\n }\n return {\n items,\n total: runtime.manifest.total,\n facets: runtime.manifest.facets ?? {},\n manifestTotal: runtime.manifest.total,\n scannedParts,\n fetchedParts,\n complete: true,\n }\n }\n\n // Reuse the filtered/ranked entry set across pages of the same query: the\n // expensive part scan is offset/limit/sort/snippet independent. A hit projects\n // a new page from cached entries without touching parts (scanned/fetched = 0).\n const matchKey = matchSetCacheKey(q, options)\n const cached = runtime.matchCache.get(matchKey)\n if (cached) {\n runtime.matchCache.delete(matchKey)\n runtime.matchCache.set(matchKey, cached)\n return {\n ...createQueryResultFromRankedEntries(cached, q, options),\n manifestTotal: runtime.manifest.total,\n scannedParts: 0,\n fetchedParts: 0,\n complete: true,\n }\n }\n\n const entries: AiwgRankedEntry[] = []\n for (const partRef of runtime.manifest.parts) {\n const loaded = await loadChunkPart(runtime, partRef)\n if (loaded.fetched) fetchedParts += 1\n scannedParts += 1\n options.onProgress?.({ phase: 'part', done: scannedParts, total: runtime.manifest.parts.length, href: partRef.href })\n entries.push(...createRankedEntries(loaded.part.items, q, options, partRef.offset))\n options.onProgress?.({ phase: 'query', done: scannedParts, total: runtime.manifest.parts.length, href: partRef.href })\n }\n cacheMatchEntries(runtime, matchKey, entries)\n\n return {\n ...createQueryResultFromRankedEntries(entries, q, options),\n manifestTotal: runtime.manifest.total,\n scannedParts,\n fetchedParts,\n complete: true,\n }\n}\n\nexport function createAiwgReviewDecisionExport(\n // Only the export schema_version is needed — so this works in chunked mode\n // (where no whole index is loaded) by passing a minimal source. See #178.\n source: Pick<AiwgFortemiIndexExport, 'schema_version'>,\n decisions: AiwgReviewDecision[],\n generatedAt = new Date().toISOString(),\n): AiwgReviewDecisionExport {\n return {\n schema_version: 'aiwg.fortemi.review-decisions.v1',\n generated_at: generatedAt,\n source_export_schema_version: source.schema_version,\n decisions: [...decisions].sort((left, right) => left.item_id.localeCompare(right.item_id)),\n }\n}\n\nexport function createAiwgIndexController(initialIndex?: AiwgFortemiIndexExport): AiwgIndexController {\n let index: AiwgFortemiIndexExport | null = initialIndex ?? null\n let chunked: AiwgChunkedIndexRuntime | null = null\n let data: AiwgIndexQueryResult | null = null\n let error: Error | null = null\n let reviewDecisions: AiwgReviewDecision[] = []\n const listeners = new Set<AiwgIndexControllerListener>()\n\n const snapshot = (): AiwgIndexControllerSnapshot => ({\n index,\n chunked: chunked\n ? {\n manifest: chunked.manifest,\n cachedParts: chunked.partCache.size,\n maxCachedParts: chunked.maxCachedParts,\n }\n : null,\n data,\n error,\n reviewDecisions: [...reviewDecisions],\n })\n const notify = () => {\n const current = snapshot()\n for (const listener of listeners) listener(current)\n }\n const requireIndex = (): AiwgFortemiIndexExport => {\n if (!index) throw new Error('No AIWG index export loaded')\n return index\n }\n\n return {\n loadIndex(value: unknown): AiwgFortemiIndexExport {\n try {\n const parsed = assertAiwgFortemiIndexExport(value)\n index = parsed\n chunked = null\n data = null\n reviewDecisions = []\n error = null\n notify()\n return parsed\n } catch (err) {\n error = err instanceof Error ? err : new Error(String(err))\n notify()\n throw error\n }\n },\n loadChunkedIndex(\n manifest: unknown,\n loader: AiwgChunkedIndexLoader,\n options: AiwgChunkedIndexLoadOptions = {},\n ): AiwgFortemiChunkManifest {\n try {\n const parsed = assertAiwgFortemiChunkManifest(manifest)\n index = null\n chunked = {\n manifest: parsed,\n loader,\n maxCachedParts: clampMaxCachedParts(options.maxCachedParts),\n partCache: new Map(),\n detailLoader: options.detailLoader,\n maxCachedDetails: clampMaxCachedDetails(options.maxCachedDetails),\n detailCache: new Map(),\n maxCachedMatches: clampMaxCachedMatches(options.maxCachedMatches),\n matchCache: new Map(),\n }\n data = null\n reviewDecisions = []\n error = null\n notify()\n return parsed\n } catch (err) {\n error = err instanceof Error ? err : new Error(String(err))\n notify()\n throw error\n }\n },\n getIndex(): AiwgFortemiIndexExport | null {\n return index\n },\n getChunkedManifest(): AiwgFortemiChunkManifest | null {\n return chunked?.manifest ?? null\n },\n getSnapshot(): AiwgIndexControllerSnapshot {\n return snapshot()\n },\n query(query = '', options?: AiwgIndexQueryOptions): AiwgIndexQueryResult {\n const result = queryAiwgFortemiIndex(requireIndex(), query, options)\n data = result\n error = null\n notify()\n return result\n },\n async queryChunked(query = '', options?: AiwgChunkedIndexQueryOptions): Promise<AiwgChunkedIndexQueryResult> {\n if (!chunked) throw new Error('No AIWG chunked index manifest loaded')\n try {\n const result = await queryChunkedAiwgFortemiIndex(chunked, query, options)\n data = result\n error = null\n notify()\n return result\n } catch (err) {\n error = err instanceof Error ? err : new Error(String(err))\n notify()\n throw error\n }\n },\n async getRecord(id: string): Promise<AiwgFortemiRecord> {\n if (chunked) {\n try {\n return await getChunkRecord(chunked, id)\n } catch (err) {\n error = err instanceof Error ? err : new Error(String(err))\n notify()\n throw error\n }\n }\n const found = requireIndex().items.find((item) => item.id === id)\n if (!found) throw new Error('Record not found: ' + id)\n return found\n },\n clearChunkCache(): void {\n chunked?.partCache.clear()\n chunked?.detailCache.clear()\n chunked?.matchCache.clear()\n error = null\n notify()\n },\n toCommunityGraph(options?: AiwgIndexGraphOptions) {\n return aiwgFortemiIndexToCommunityGraph(requireIndex(), options)\n },\n setReviewDecision(input: AiwgReviewInput): AiwgReviewDecision {\n const decision: AiwgReviewDecision = {\n ...input,\n updated_at: new Date().toISOString(),\n }\n reviewDecisions = [\n ...reviewDecisions.filter((item) => item.item_id !== decision.item_id),\n decision,\n ].sort((left, right) => left.item_id.localeCompare(right.item_id))\n error = null\n notify()\n return decision\n },\n clearReviewDecision(itemId: string): void {\n reviewDecisions = reviewDecisions.filter((item) => item.item_id !== itemId)\n error = null\n notify()\n },\n createReviewDecisionExport(generatedAt?: string): AiwgReviewDecisionExport {\n // The review-decisions export only needs the export schema_version, not the\n // items — so it works in chunked mode by synthesizing a minimal source (#178).\n const source: Pick<AiwgFortemiIndexExport, 'schema_version'> | null =\n index ?? (chunked ? { schema_version: 'aiwg.fortemi.index.export.v1' } : null)\n if (!source) throw new Error('No AIWG index export or chunked manifest loaded')\n return createAiwgReviewDecisionExport(source, reviewDecisions, generatedAt)\n },\n subscribe(listener: AiwgIndexControllerListener): () => void {\n listeners.add(listener)\n return () => {\n listeners.delete(listener)\n }\n },\n }\n}\n\nexport function aiwgFortemiIndexToCommunityGraph(\n index: AiwgFortemiIndexExport,\n options: AiwgIndexGraphOptions = {},\n) {\n const ids = new Set(index.items.map((item) => item.id))\n const relationshipWeights = options.relationshipWeights ?? {}\n const edgeCounts = new Map<string, { source: string; target: string; kind: string; weight: number }>()\n\n for (const item of index.items) {\n for (const relationship of item.relationships) {\n if (!ids.has(relationship.target_id) && !options.includeDanglingRelationships) continue\n const kind = relationship.type\n const baseWeight = relationshipWeights[kind] ?? 1\n const key = `${item.id}\\u0000${relationship.target_id}\\u0000${kind}`\n const existing = edgeCounts.get(key)\n if (existing) existing.weight += baseWeight\n else edgeCounts.set(key, { source: item.id, target: relationship.target_id, kind, weight: baseWeight })\n }\n }\n\n const communities = new Map<string, string[]>()\n for (const item of index.items) {\n const communityIds = communityIdsFor(item, options)\n for (const communityId of communityIds) {\n const nodes = communities.get(communityId) ?? []\n nodes.push(item.id)\n communities.set(communityId, nodes)\n }\n }\n\n return {\n nodes: index.items.map((item) => ({ id: item.id })),\n edges: Array.from(edgeCounts.values()).sort((left, right) => (\n left.source.localeCompare(right.source)\n || left.target.localeCompare(right.target)\n || left.kind.localeCompare(right.kind)\n )),\n communities: Array.from(communities.entries())\n .map(([id, nodes]) => ({ id, nodes: [...new Set(nodes)].sort() }))\n .sort((left, right) => left.id.localeCompare(right.id)),\n }\n}\n\nfunction communityIdsFor(item: AiwgFortemiRecord, options: AiwgIndexGraphOptions): string[] {\n if (options.communityFacet) {\n const values = item.facets[options.communityFacet] ?? []\n if (values.length > 0) return values.map((value) => `${options.communityFacet}:${value}`)\n }\n if (options.communityTagPrefix) {\n const prefix = options.communityTagPrefix\n const tags = item.tags.filter((tag) => tag.startsWith(prefix))\n if (tags.length > 0) return tags\n }\n if (item.concepts.length > 0) return item.concepts.map((concept) => `concept:${concept}`)\n return [`type:${item.type}`]\n}\n"]}