@duckcodeailabs/dql-agent 1.10.0 → 1.10.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (86) hide show
  1. package/dist/agent-run-engine.d.ts.map +1 -1
  2. package/dist/agent-run-engine.js +6 -1
  3. package/dist/agent-run-engine.js.map +1 -1
  4. package/dist/analytical-compatibility.d.ts +61 -0
  5. package/dist/analytical-compatibility.d.ts.map +1 -0
  6. package/dist/analytical-compatibility.js +515 -0
  7. package/dist/analytical-compatibility.js.map +1 -0
  8. package/dist/analytical-execution-graph.d.ts +174 -0
  9. package/dist/analytical-execution-graph.d.ts.map +1 -0
  10. package/dist/analytical-execution-graph.js +599 -0
  11. package/dist/analytical-execution-graph.js.map +1 -0
  12. package/dist/analytical-failure-repair.d.ts +91 -0
  13. package/dist/analytical-failure-repair.d.ts.map +1 -0
  14. package/dist/analytical-failure-repair.js +325 -0
  15. package/dist/analytical-failure-repair.js.map +1 -0
  16. package/dist/analytical-frame.d.ts +19 -0
  17. package/dist/analytical-frame.d.ts.map +1 -0
  18. package/dist/analytical-frame.js +299 -0
  19. package/dist/analytical-frame.js.map +1 -0
  20. package/dist/analytical-period-resolution.d.ts +53 -0
  21. package/dist/analytical-period-resolution.d.ts.map +1 -0
  22. package/dist/analytical-period-resolution.js +218 -0
  23. package/dist/analytical-period-resolution.js.map +1 -0
  24. package/dist/analytical-readiness.d.ts +17 -0
  25. package/dist/analytical-readiness.d.ts.map +1 -0
  26. package/dist/analytical-readiness.js +95 -0
  27. package/dist/analytical-readiness.js.map +1 -0
  28. package/dist/analytical-result-facts.d.ts +79 -0
  29. package/dist/analytical-result-facts.d.ts.map +1 -0
  30. package/dist/analytical-result-facts.js +301 -0
  31. package/dist/analytical-result-facts.js.map +1 -0
  32. package/dist/answer-loop.d.ts +51 -4
  33. package/dist/answer-loop.d.ts.map +1 -1
  34. package/dist/answer-loop.js +866 -35
  35. package/dist/answer-loop.js.map +1 -1
  36. package/dist/governed-relational-compiler.d.ts +51 -0
  37. package/dist/governed-relational-compiler.d.ts.map +1 -1
  38. package/dist/governed-relational-compiler.js +144 -1
  39. package/dist/governed-relational-compiler.js.map +1 -1
  40. package/dist/index.d.ts +16 -4
  41. package/dist/index.d.ts.map +1 -1
  42. package/dist/index.js +9 -2
  43. package/dist/index.js.map +1 -1
  44. package/dist/kg/build.d.ts +2 -2
  45. package/dist/kg/build.d.ts.map +1 -1
  46. package/dist/kg/build.js +270 -13
  47. package/dist/kg/build.js.map +1 -1
  48. package/dist/meaning-resolution.d.ts +13 -0
  49. package/dist/meaning-resolution.d.ts.map +1 -1
  50. package/dist/meaning-resolution.js +69 -0
  51. package/dist/meaning-resolution.js.map +1 -1
  52. package/dist/metadata/analysis-planner.js +3 -1
  53. package/dist/metadata/analysis-planner.js.map +1 -1
  54. package/dist/metadata/catalog.d.ts +4 -2
  55. package/dist/metadata/catalog.d.ts.map +1 -1
  56. package/dist/metadata/catalog.js +264 -9
  57. package/dist/metadata/catalog.js.map +1 -1
  58. package/dist/metadata/meaning-evidence.d.ts +9 -2
  59. package/dist/metadata/meaning-evidence.d.ts.map +1 -1
  60. package/dist/metadata/meaning-evidence.js +105 -7
  61. package/dist/metadata/meaning-evidence.js.map +1 -1
  62. package/dist/plan-execution-adapter.d.ts +72 -1
  63. package/dist/plan-execution-adapter.d.ts.map +1 -1
  64. package/dist/plan-execution-adapter.js +208 -0
  65. package/dist/plan-execution-adapter.js.map +1 -1
  66. package/dist/resolved-analytical-plan.d.ts +14 -3
  67. package/dist/resolved-analytical-plan.d.ts.map +1 -1
  68. package/dist/resolved-analytical-plan.js +74 -20
  69. package/dist/resolved-analytical-plan.js.map +1 -1
  70. package/dist/router.d.ts +1 -1
  71. package/dist/router.d.ts.map +1 -1
  72. package/dist/router.js +167 -21
  73. package/dist/router.js.map +1 -1
  74. package/dist/semantic-bridge/compose.d.ts +1 -1
  75. package/dist/semantic-bridge/compose.d.ts.map +1 -1
  76. package/dist/semantic-bridge/compose.js +27 -5
  77. package/dist/semantic-bridge/compose.js.map +1 -1
  78. package/dist/semantic-bridge/member-select.d.ts +1 -1
  79. package/dist/semantic-bridge/member-select.d.ts.map +1 -1
  80. package/dist/semantic-bridge/member-select.js +32 -12
  81. package/dist/semantic-bridge/member-select.js.map +1 -1
  82. package/dist/skills/loader.d.ts +17 -0
  83. package/dist/skills/loader.d.ts.map +1 -1
  84. package/dist/skills/loader.js +62 -4
  85. package/dist/skills/loader.js.map +1 -1
  86. package/package.json +4 -4
@@ -11,10 +11,10 @@ import { existsSync, mkdirSync, readFileSync, renameSync, rmSync, writeFileSync
11
11
  import { createRequire } from 'node:module';
12
12
  import { dirname, join } from 'node:path';
13
13
  import { brotliCompressSync, brotliDecompressSync, constants as zlibConstants } from 'node:zlib';
14
- import { buildManifest, buildManifestKnowledgeGraph, loadDomainPackageRegistry, loadManifestKnowledgeSkills, loadProjectConfig, parseContractRef, resolveDataLexManifestPath, resolveDbtManifestPath, resolveSemanticLayerWithDiagnostics, extractColumnLineage, normalizeDqlArtifactReference, composeEffectiveTrust, } from '@duckcodeailabs/dql-core';
15
- import { buildKGFromManifest, buildKGFromSemanticLayer } from '../kg/build.js';
16
- import { domainContextSearchDomains } from '../domain-context.js';
17
- import { buildBlockBusinessFingerprint, buildBlockSqlFingerprints } from './block-fingerprints.js';
14
+ import { buildManifest, buildManifestKnowledgeGraph, loadDomainPackageRegistry, loadManifestKnowledgeSkills, loadProjectConfig, parseContractRef, resolveDataLexManifestPath, resolveDbtManifestPath, resolveSemanticLayerWithDiagnostics, extractColumnLineage, normalizeDqlArtifactReference, composeEffectiveTrust, normalizeMetricCapabilityContract, } from "@duckcodeailabs/dql-core";
15
+ import { buildKGFromManifest, buildKGFromSemanticLayer } from "../kg/build.js";
16
+ import { domainContextSearchDomains, } from "../domain-context.js";
17
+ import { buildBlockBusinessFingerprint, buildBlockSqlFingerprints, } from "./block-fingerprints.js";
18
18
  import { buildAnalysisQuestionPlan, certifiedApplicabilityForObject, scoreAllowedSqlRelationWithAnalysisPlan, scoreMetadataObjectWithAnalysisPlan, sortAllowedSqlContextForAnalysisPlan, } from './analysis-planner.js';
19
19
  import { extractSimpleSelectShape, sourceSqlShapeColumns } from './sql-shape.js';
20
20
  import { grainMatches, requestedGrainFromPlan, } from './grain-gate.js';
@@ -835,6 +835,7 @@ export function buildMetadataSnapshot(projectRoot, manifest, semanticLayer, skil
835
835
  addRawDbtManifestCatalogObjects(projectRoot, manifest, objects, edges, diagnostics);
836
836
  addBlockDependencyEdges(manifest, edges);
837
837
  addBlockOutputLineageObjects(manifest, objects, edges);
838
+ addCertifiedBlockAnalyticalCapabilities(objects);
838
839
  // Manifest v3 is the unified DQL runtime. DataLex is migration input only;
839
840
  // retaining it here would reintroduce a second analytical source of truth.
840
841
  if (manifest.manifestVersion !== 3) {
@@ -878,6 +879,205 @@ export function buildMetadataSnapshot(projectRoot, manifest, semanticLayer, skil
878
879
  snapshot.fingerprint = fingerprintSnapshot(snapshot);
879
880
  return snapshot;
880
881
  }
882
+ /**
883
+ * Upgrade only fully declared certified blocks into RFC 0005 capabilities.
884
+ * Local/display-name matching is intentionally insufficient: every reusable
885
+ * metric, grain, dimension/filter, and output role must bind exactly to the
886
+ * already-normalized semantic capability in this immutable snapshot.
887
+ *
888
+ * Acceptance: CONTRACT-002, AGT-018.
889
+ */
890
+ function addCertifiedBlockAnalyticalCapabilities(objects) {
891
+ // Existing certified blocks can carry the pre-ID-001 domain-scoped member
892
+ // identities. Canonicalize those aliases only when exactly one semantic
893
+ // object owns them; repeated leaf aliases intentionally fail closed.
894
+ const semanticIdentityTargets = new Map();
895
+ for (const object of objects.values()) {
896
+ if (!object.objectType.startsWith('semantic_'))
897
+ continue;
898
+ const payload = object.payload ?? {};
899
+ const canonicalIdentity = object.fullName ?? object.name;
900
+ for (const identity of uniqueNonBlank([
901
+ canonicalIdentity,
902
+ stringValue(payload.qualifiedId),
903
+ stringValue(payload.registryQualifiedId),
904
+ stringValue(payload.sourceNativeId),
905
+ ...metadataStringArray(payload.aliases),
906
+ ])) {
907
+ const targets = semanticIdentityTargets.get(identity) ?? new Set();
908
+ targets.add(canonicalIdentity);
909
+ semanticIdentityTargets.set(identity, targets);
910
+ }
911
+ }
912
+ const canonicalizeSemanticRef = (identity) => {
913
+ const targets = semanticIdentityTargets.get(identity);
914
+ if (!targets)
915
+ return identity;
916
+ return targets.size === 1 ? [...targets][0] : undefined;
917
+ };
918
+ const semanticCapabilities = [...objects.values()].flatMap((object) => {
919
+ if (object.objectType !== "semantic_metric")
920
+ return [];
921
+ const capability = normalizeMetricCapabilityContract(object.payload?.analyticalCapability);
922
+ if (!capability)
923
+ return [];
924
+ const payload = object.payload ?? {};
925
+ return [
926
+ {
927
+ object,
928
+ capability,
929
+ exactRefs: new Set(uniqueNonBlank([
930
+ capability.metricId,
931
+ object.objectKey,
932
+ object.fullName,
933
+ stringValue(payload.qualifiedId),
934
+ stringValue(payload.sourceNativeId),
935
+ ...metadataStringArray(payload.aliases),
936
+ ])),
937
+ },
938
+ ];
939
+ });
940
+ for (const block of objects.values()) {
941
+ if (block.objectType !== "dql_block" || block.status !== "certified")
942
+ continue;
943
+ const payload = block.payload ?? {};
944
+ const metricRefs = uniqueNonBlank([
945
+ ...metadataStringArray(payload.metricRefs),
946
+ ]);
947
+ if (metricRefs.length !== 1)
948
+ continue;
949
+ const metrics = semanticCapabilities.filter((candidate) => candidate.exactRefs.has(metricRefs[0]));
950
+ if (metrics.length !== 1)
951
+ continue;
952
+ const semantic = metrics[0];
953
+ const authoredGrain = stringValue(payload.grain);
954
+ const grain = authoredGrain ? canonicalizeSemanticRef(authoredGrain) : undefined;
955
+ if (!grain || !semantic.capability.resultGrainIds.includes(grain))
956
+ continue;
957
+ const authoredGroupedRefs = uniqueNonBlank([
958
+ ...metadataStringArray(payload.dimensions),
959
+ ...metadataStringArray(payload.dimensionsRef),
960
+ ]);
961
+ const authoredFilterRefs = uniqueNonBlank(metadataStringArray(payload.allowedFilters));
962
+ const groupedRefs = authoredGroupedRefs.map(canonicalizeSemanticRef);
963
+ const filterRefs = authoredFilterRefs.map(canonicalizeSemanticRef);
964
+ if (groupedRefs.some((ref) => !ref) || filterRefs.some((ref) => !ref))
965
+ continue;
966
+ const canonicalGroupedRefs = groupedRefs.filter((ref) => Boolean(ref));
967
+ const canonicalFilterRefs = filterRefs.filter((ref) => Boolean(ref));
968
+ const declaredRefs = new Set([...canonicalGroupedRefs, ...canonicalFilterRefs]);
969
+ const capabilityDimensionIds = new Set(semantic.capability.dimensions.map((item) => item.dimensionId));
970
+ const capabilityTimeIds = new Set(semantic.capability.timeDimensions.map((item) => item.dimensionId));
971
+ if ([...declaredRefs].some((id) => !capabilityDimensionIds.has(id) && !capabilityTimeIds.has(id)))
972
+ continue;
973
+ const dimensions = semantic.capability.dimensions.flatMap((dimension) => {
974
+ if (!declaredRefs.has(dimension.dimensionId))
975
+ return [];
976
+ const roles = dimension.supportedRoles.filter((role) => (role === "filter" && canonicalFilterRefs.includes(dimension.dimensionId)) ||
977
+ (role === "group_by" &&
978
+ canonicalGroupedRefs.includes(dimension.dimensionId)) ||
979
+ (role === "display" &&
980
+ canonicalGroupedRefs.includes(dimension.dimensionId)) ||
981
+ (role === "rank_entity" &&
982
+ payload.pattern === "ranking" &&
983
+ canonicalGroupedRefs.includes(dimension.dimensionId)));
984
+ return roles.length > 0
985
+ ? [{ ...dimension, supportedRoles: roles }]
986
+ : [];
987
+ });
988
+ if ([...declaredRefs].some((id) => capabilityDimensionIds.has(id) &&
989
+ !dimensions.some((dimension) => dimension.dimensionId === id)))
990
+ continue;
991
+ const timeDimensions = semantic.capability.timeDimensions.filter((dimension) => declaredRefs.has(dimension.dimensionId));
992
+ const outputs = analyticalBlockOutputs(payload.outputContract);
993
+ if (!outputs ||
994
+ outputs.ids.length === 0 ||
995
+ !outputs.kinds.includes("metric_value"))
996
+ continue;
997
+ const operations = [];
998
+ if (canonicalFilterRefs.length > 0)
999
+ operations.push("filter");
1000
+ if (canonicalGroupedRefs.some((id) => capabilityDimensionIds.has(id)))
1001
+ operations.push("group");
1002
+ if (payload.pattern === "trend")
1003
+ operations.push("trend");
1004
+ if (payload.pattern === "ranking" && outputs.kinds.includes("rank"))
1005
+ operations.push("rank");
1006
+ if (outputs.kinds.includes("delta") ||
1007
+ outputs.kinds.includes("percent_delta"))
1008
+ operations.push("compare");
1009
+ const blockId = stringValue(payload.qualifiedId) ?? block.objectKey;
1010
+ const fingerprint = stringValue(recordPayload(payload.businessFingerprint)?.hash) ??
1011
+ sha256(stableStringify({
1012
+ blockId,
1013
+ metricRefs,
1014
+ grain,
1015
+ groupedRefs: canonicalGroupedRefs,
1016
+ filterRefs: canonicalFilterRefs,
1017
+ outputs,
1018
+ }));
1019
+ const capability = {
1020
+ ...semantic.capability,
1021
+ defaultResultGrainId: grain,
1022
+ resultGrainIds: uniqueNonBlank([
1023
+ grain,
1024
+ ...dimensions.map((dimension) => dimension.entityId),
1025
+ ]),
1026
+ dimensions,
1027
+ timeDimensions,
1028
+ operations: [...new Set(operations)],
1029
+ supportedOutputKinds: outputs.kinds,
1030
+ declaredOutputIds: outputs.ids,
1031
+ executionCapabilities: [
1032
+ { route: "certified", adapterId: block.objectKey },
1033
+ ],
1034
+ sourceFingerprint: fingerprint.startsWith("sha256:")
1035
+ ? fingerprint
1036
+ : `sha256:${fingerprint}`,
1037
+ };
1038
+ const normalized = normalizeMetricCapabilityContract(capability);
1039
+ if (!normalized)
1040
+ continue;
1041
+ objects.set(block.objectKey, {
1042
+ ...block,
1043
+ payload: { ...payload, analyticalCapability: normalized },
1044
+ });
1045
+ }
1046
+ }
1047
+ function analyticalBlockOutputs(value) {
1048
+ if (!Array.isArray(value) || value.length === 0)
1049
+ return undefined;
1050
+ const ids = [];
1051
+ const kinds = [];
1052
+ for (const item of value) {
1053
+ const output = recordPayload(item);
1054
+ const id = stringValue(output?.name);
1055
+ const role = stringValue(output?.role)?.toLowerCase();
1056
+ if (!id || !role)
1057
+ return undefined;
1058
+ const kind = role === "metric" || role === "measure" || role === "value"
1059
+ ? "metric_value"
1060
+ : role === "dimension" || role === "grain"
1061
+ ? "dimension"
1062
+ : role === "rank"
1063
+ ? "rank"
1064
+ : role === "delta"
1065
+ ? "delta"
1066
+ : role === "percent_delta"
1067
+ ? "percent_delta"
1068
+ : undefined;
1069
+ if (!kind)
1070
+ return undefined;
1071
+ ids.push(id);
1072
+ kinds.push(kind);
1073
+ }
1074
+ return { ids: uniqueNonBlank(ids), kinds: [...new Set(kinds)] };
1075
+ }
1076
+ function recordPayload(value) {
1077
+ return value && typeof value === "object" && !Array.isArray(value)
1078
+ ? value
1079
+ : undefined;
1080
+ }
881
1081
  /**
882
1082
  * Manifest graph v2 intentionally omits verbose objects and edges. Snapshot
883
1083
  * construction rematerializes that compiler graph once, then persists the
@@ -982,8 +1182,16 @@ function addManifestKnowledgeGraph(manifest, objects, edges) {
982
1182
  sourceSystem: 'DQL compiled cross-domain policy',
983
1183
  payload: compactObject(route),
984
1184
  });
985
- addMetadataEdge(edges, 'cross_domain_route', keyByGraphId.get(`domain::${route.providerDomainId}`) ?? `domain:${route.providerDomainId}`, objectKey, { state: route.state, reasonCodes: route.reasonCodes });
986
- addMetadataEdge(edges, 'cross_domain_route', objectKey, keyByGraphId.get(`domain::${route.consumerDomainId}`) ?? `domain:${route.consumerDomainId}`, { state: route.state, reasonCodes: route.reasonCodes });
1185
+ addMetadataEdge(edges, "cross_domain_route", keyByGraphId.get(`domain::${route.providerDomainId}`) ??
1186
+ `domain:${route.providerDomainId}`, objectKey, {
1187
+ state: route.state,
1188
+ reasonCodes: route.reasonCodes,
1189
+ });
1190
+ addMetadataEdge(edges, "cross_domain_route", objectKey, keyByGraphId.get(`domain::${route.consumerDomainId}`) ??
1191
+ `domain:${route.consumerDomainId}`, {
1192
+ state: route.state,
1193
+ reasonCodes: route.reasonCodes,
1194
+ });
987
1195
  }
988
1196
  for (const edge of graph.edges ?? []) {
989
1197
  const fromKey = keyByGraphId.get(edge.from) ?? edge.from;
@@ -2356,6 +2564,9 @@ function isQualifiedDqlModelingNode(node) {
2356
2564
  }
2357
2565
  function qualifiedIdentityFromKGNode(node) {
2358
2566
  const payload = node.payload ?? {};
2567
+ const registryIdentity = stringValue(payload.registryQualifiedId);
2568
+ if (registryIdentity)
2569
+ return registryIdentity;
2359
2570
  const explicit = stringValue(payload.qualifiedId);
2360
2571
  if (explicit)
2361
2572
  return explicit;
@@ -2407,7 +2618,8 @@ function addSkillObjects(skills, objects, edges) {
2407
2618
  domain: skill.domain,
2408
2619
  domains: skill.domains ?? [],
2409
2620
  modelAreaRefs: skill.modelAreaRefs ?? [],
2410
- status: skill.status ?? 'active',
2621
+ status: skill.status ?? "active",
2622
+ analyticalPolicy: skill.analyticalPolicy,
2411
2623
  bodyHash,
2412
2624
  }));
2413
2625
  const objectKey = `skill:${identity}`;
@@ -2442,6 +2654,7 @@ function addSkillObjects(skills, objects, edges) {
2442
2654
  examples: skill.examples ?? [],
2443
2655
  sourceRefs: skill.sourceRefs ?? [],
2444
2656
  vocabulary: skill.vocabulary,
2657
+ analyticalPolicy: skill.analyticalPolicy,
2445
2658
  bodyHash,
2446
2659
  sourceFingerprint,
2447
2660
  isStarter: skill.isStarter,
@@ -6260,13 +6473,22 @@ function skillFromMetadataObject(object) {
6260
6473
  examples: stringArrayPayload(payload.examples),
6261
6474
  sourceRefs: stringArrayPayload(payload.sourceRefs),
6262
6475
  vocabulary: stringRecordPayload(payload.vocabulary),
6263
- body: '',
6264
- sourcePath: object.sourcePath ?? '',
6476
+ analyticalPolicy: skillAnalyticalPolicyPayload(payload.analyticalPolicy),
6477
+ body: "",
6478
+ sourcePath: object.sourcePath ?? "",
6265
6479
  isStarter: payload.isStarter === true,
6266
6480
  };
6267
6481
  }
6268
6482
  function localContextSkillFromParsed(skill, object) {
6269
6483
  const guidance = skill.body.slice(0, 4_000);
6484
+ const sourceHash = stringPayload(object.payload?.sourceFingerprint);
6485
+ const policy = skill.analyticalPolicy && sourceHash
6486
+ ? {
6487
+ policyId: `${skill.qualifiedId ?? skill.id}#analytical`,
6488
+ sourceHash,
6489
+ ...skill.analyticalPolicy,
6490
+ }
6491
+ : undefined;
6270
6492
  return {
6271
6493
  objectKey: object.objectKey,
6272
6494
  id: skill.id,
@@ -6286,6 +6508,7 @@ function localContextSkillFromParsed(skill, object) {
6286
6508
  requiredFilters: [...(skill.requiredFilters ?? [])],
6287
6509
  clarifyWhen: [...(skill.clarifyWhen ?? [])],
6288
6510
  vocabulary: { ...skill.vocabulary },
6511
+ ...(policy ? { analyticalPolicy: policy } : {}),
6289
6512
  guidance,
6290
6513
  guidanceTruncated: guidance.length < skill.body.length,
6291
6514
  sourceRefs: [...(skill.sourceRefs ?? [])],
@@ -6293,6 +6516,38 @@ function localContextSkillFromParsed(skill, object) {
6293
6516
  sourcePath: object.sourcePath,
6294
6517
  };
6295
6518
  }
6519
+ function skillAnalyticalPolicyPayload(value) {
6520
+ if (!value || typeof value !== "object" || Array.isArray(value))
6521
+ return undefined;
6522
+ const record = value;
6523
+ const completenessPolicy = stringPayload(record.completenessPolicy);
6524
+ const comparisonAlignment = stringPayload(record.comparisonAlignment);
6525
+ const defaultRankingPeriod = stringPayload(record.defaultRankingPeriod);
6526
+ const policy = {
6527
+ metricIds: stringArrayPayload(record.metricIds),
6528
+ timeRole: stringPayload(record.timeRole),
6529
+ calendarId: stringPayload(record.calendarId),
6530
+ timezone: stringPayload(record.timezone),
6531
+ completenessPolicy: completenessPolicy === "partial_current" ||
6532
+ completenessPolicy === "latest_complete" ||
6533
+ completenessPolicy === "closed_period"
6534
+ ? completenessPolicy
6535
+ : undefined,
6536
+ comparisonAlignment: comparisonAlignment === "elapsed_period" ||
6537
+ comparisonAlignment === "calendar_period" ||
6538
+ comparisonAlignment === "fiscal_period"
6539
+ ? comparisonAlignment
6540
+ : undefined,
6541
+ defaultRankingPeriod: defaultRankingPeriod === "current" ||
6542
+ defaultRankingPeriod === "comparison"
6543
+ ? defaultRankingPeriod
6544
+ : undefined,
6545
+ narrativeGuidance: stringArrayPayload(record.narrativeGuidance),
6546
+ };
6547
+ return Object.values(policy).some((item) => Array.isArray(item) ? item.length > 0 : Boolean(item))
6548
+ ? policy
6549
+ : undefined;
6550
+ }
6296
6551
  function stringPayload(value) {
6297
6552
  return typeof value === 'string' && value.trim() ? value : undefined;
6298
6553
  }