@shapeshift-labs/frontier-lang-compiler 0.2.66 → 0.2.68

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 (48) hide show
  1. package/README.md +6 -2
  2. package/bench/smoke.mjs +15 -1
  3. package/bench/universal-fixture-suite.mjs +183 -0
  4. package/dist/declarations/native-project-admission.d.ts +115 -0
  5. package/dist/declarations/roundtrip-audit.d.ts +186 -0
  6. package/dist/declarations/roundtrip.d.ts +2 -53
  7. package/dist/declarations/runtime.d.ts +0 -11
  8. package/dist/declarations/semantic-history-records.d.ts +277 -0
  9. package/dist/declarations/semantic-history.d.ts +45 -92
  10. package/dist/declarations/semantic-slice-admission.d.ts +111 -0
  11. package/dist/declarations/semantic-slice.d.ts +36 -1
  12. package/dist/declarations/universal-conversion-plan.d.ts +59 -0
  13. package/dist/declarations/universal-runtime-capabilities.d.ts +171 -0
  14. package/dist/index.d.ts +1 -0
  15. package/dist/index.js +1 -0
  16. package/dist/internal/index-impl/createNativeRoundtripEvidence.js +54 -49
  17. package/dist/internal/index-impl/createSemanticSlice.js +1 -1
  18. package/dist/internal/index-impl/createSemanticSliceAdmissionRecord.js +10 -1
  19. package/dist/internal/index-impl/expandSemanticSliceSelection.js +0 -1
  20. package/dist/internal/index-impl/nativeRoundtripAudit.js +217 -0
  21. package/dist/internal/index-impl/projectImportAdmissionImportEvidence.js +160 -0
  22. package/dist/internal/index-impl/projectImportAdmissionLanguageSummaries.js +247 -0
  23. package/dist/internal/index-impl/projectImportAdmissionRanks.js +52 -0
  24. package/dist/internal/index-impl/projectImportAdmissionSummaries.js +46 -111
  25. package/dist/internal/index-impl/projectImportAdmissionTasks.js +239 -0
  26. package/dist/internal/index-impl/semanticHistoryRecordNormalizers.js +151 -0
  27. package/dist/internal/index-impl/semanticHistoryRecordOverlaps.js +113 -0
  28. package/dist/internal/index-impl/semanticHistoryRecords.js +210 -149
  29. package/dist/internal/index-impl/semanticSliceAdmissionSurface.js +142 -0
  30. package/dist/internal/index-impl/semanticSliceExpectationAssertions.js +100 -0
  31. package/dist/internal/index-impl/semanticSliceExpectationRecords.js +75 -0
  32. package/dist/internal/index-impl/semanticSliceExpectedAssertions.js +5 -2
  33. package/dist/internal/index-impl/testSemanticSlice.js +4 -1
  34. package/dist/language-adapter-package-contracts.js +12 -57
  35. package/dist/language-adapter-package-rows.js +116 -0
  36. package/dist/universal-conversion-plan-summary.js +42 -0
  37. package/dist/universal-conversion-plan.js +46 -40
  38. package/dist/universal-runtime-capabilities.js +92 -0
  39. package/dist/universal-runtime-host-selectors.js +192 -0
  40. package/dist/universal-runtime-profiles.js +109 -0
  41. package/dist/universal-runtime-route-records.js +162 -0
  42. package/examples/js-frontier-rust-workbench-client.mjs +58 -1
  43. package/examples/js-frontier-rust-workbench-convert.mjs +161 -0
  44. package/examples/js-frontier-rust-workbench-route-styles.mjs +126 -0
  45. package/examples/js-frontier-rust-workbench-route.mjs +190 -0
  46. package/examples/js-frontier-rust-workbench-styles.mjs +3 -38
  47. package/examples/js-frontier-rust-workbench.mjs +22 -128
  48. package/package.json +1 -1
@@ -0,0 +1,113 @@
1
+ import{uniqueStrings as uniqueRawStrings}from'../../native-import-utils.js';
2
+
3
+ export function querySemanticHistoryRecordOverlaps(records,options={}){
4
+ const list=array(records).filter(Boolean);
5
+ const overlaps=[];
6
+ for(let leftIndex=0;leftIndex<list.length;leftIndex+=1){
7
+ for(let rightIndex=leftIndex+1;rightIndex<list.length;rightIndex+=1){
8
+ const overlap=semanticHistoryOverlap(list[leftIndex],list[rightIndex],options);
9
+ if(overlap.overlapKinds.length||overlap.conflictReasons.length)overlaps.push(overlap);
10
+ }
11
+ }
12
+ return overlaps.sort((left,right)=>Number(right.conflict)-Number(left.conflict)||left.leftId.localeCompare(right.leftId)||left.rightId.localeCompare(right.rightId));
13
+ }
14
+
15
+ export function semanticHistoryRecordsOverlap(left,right,options={}){
16
+ return semanticHistoryOverlap(left,right,options).overlapKinds.length>0;
17
+ }
18
+
19
+ export function semanticHistoryRecordsConflict(left,right,options={}){
20
+ return semanticHistoryOverlap(left,right,options).conflict;
21
+ }
22
+
23
+ function semanticHistoryOverlap(left,right,options){
24
+ const leftIndex=historyIndex(left);
25
+ const rightIndex=historyIndex(right);
26
+ const overlap=compactRecord({
27
+ ownership:intersect(leftIndex.ownershipKeys,rightIndex.ownershipKeys),
28
+ 'conflict-key':intersect(leftIndex.conflictKeys,rightIndex.conflictKeys),
29
+ source:intersect(leftIndex.sourceIds,rightIndex.sourceIds),
30
+ 'source-path':options.includeSourcePaths===false?[]:intersect(leftIndex.sourcePaths,rightIndex.sourcePaths),
31
+ import:intersect(leftIndex.importIds,rightIndex.importIds),
32
+ 'semantic-candidate':intersect(leftIndex.semanticCandidateIds,rightIndex.semanticCandidateIds),
33
+ 'semantic-claim':options.includeClaims?intersect(leftIndex.semanticClaimIds,rightIndex.semanticClaimIds):[],
34
+ 'claim-hash':options.includeClaims?intersect(leftIndex.semanticClaimHashes,rightIndex.semanticClaimHashes):[],
35
+ evidence:options.includeEvidence?intersect(leftIndex.evidenceIds,rightIndex.evidenceIds):[],
36
+ proof:options.includeProofs?intersect(leftIndex.proofIds,rightIndex.proofIds):[],
37
+ replay:options.includeReplay?intersect(leftIndex.replayIds,rightIndex.replayIds):[],
38
+ patch:options.includePatches?intersect(leftIndex.patchIds,rightIndex.patchIds):[],
39
+ 'merge-decision':options.includeMergeDecisions?intersect(leftIndex.mergeDecisionIds,rightIndex.mergeDecisionIds):[],
40
+ actor:options.includeActors?intersect(leftIndex.actorIds,rightIndex.actorIds):[],
41
+ 'record-source':options.includeRecordSources?intersect(leftIndex.recordSourceIds,rightIndex.recordSourceIds):[],
42
+ 'base-hash':options.includeBaseHashes?intersect(leftIndex.baseHashes,rightIndex.baseHashes):[],
43
+ 'target-hash':options.includeTargetHashes?intersect(leftIndex.targetHashes,rightIndex.targetHashes):[]
44
+ });
45
+ const overlapKinds=Object.keys(overlap);
46
+ const semanticOverlap=Boolean(overlap.ownership?.length||overlap['conflict-key']?.length||overlap.source?.length||overlap['source-path']?.length||overlap.import?.length);
47
+ const conflictReasons=uniqueStrings([
48
+ overlap.ownership?.length?'ownership-overlap':undefined,
49
+ overlap['conflict-key']?.length?'semantic-conflict-key-overlap':undefined,
50
+ semanticOverlap&&disjointNonEmpty(leftIndex.baseHashes,rightIndex.baseHashes)?'base-hash-mismatch':undefined,
51
+ (overlap.ownership?.length||overlap['conflict-key']?.length)&&disjointNonEmpty(leftIndex.targetHashes,rightIndex.targetHashes)?'target-hash-mismatch':undefined,
52
+ semanticOverlap&&(blockedAdmission(left)||blockedAdmission(right))?'admission-blocked':undefined,
53
+ semanticOverlap&&(rejectedReview(left)||rejectedReview(right))?'reviewer-rejected':undefined,
54
+ options.conflictOnSourcePath&&overlap['source-path']?.length?'source-path-overlap':undefined
55
+ ]);
56
+ return{
57
+ schema:'frontier.lang.semanticHistoryOverlap.v1',
58
+ leftId:String(left?.id??'left'),
59
+ rightId:String(right?.id??'right'),
60
+ overlap,
61
+ overlapKinds,
62
+ conflict:conflictReasons.length>0,
63
+ conflictReasons,
64
+ admission:{left:left?.admission?.status,right:right?.admission?.status},
65
+ reviewer:{left:left?.reviewer?.status,right:right?.reviewer?.status}
66
+ };
67
+ }
68
+
69
+ function historyIndex(record){
70
+ const acceptedFacts=record?.acceptedFacts??[];
71
+ const rejectedTheories=record?.rejectedTheories??[];
72
+ const importedParserEvidence=record?.importedParserEvidence??[];
73
+ const proofAttempts=record?.proofAttempts??[];
74
+ const patchAncestry=record?.patchAncestry??[];
75
+ const mergeDecisions=record?.mergeDecisions??[];
76
+ return record?.index??{
77
+ baseHashes:uniqueStrings([record?.baseHash]),
78
+ targetHashes:uniqueStrings([record?.targetHash]),
79
+ sourceIds:uniqueStrings(record?.sourceIds),
80
+ importIds:uniqueStrings(record?.importIds),
81
+ sourcePaths:uniqueStrings([record?.sourcePath,...(record?.sources??[]).map((source)=>source.sourcePath)]),
82
+ sourceHashes:uniqueStrings((record?.sources??[]).map((source)=>source.sourceHash)),
83
+ actorIds:uniqueStrings([record?.actor?.id,...acceptedFacts.map((claim)=>claim.actor?.id),...rejectedTheories.map((claim)=>claim.actor?.id),...importedParserEvidence.map((entry)=>entry.actor?.id),...proofAttempts.map((entry)=>entry.actor?.id),...patchAncestry.map((entry)=>entry.actor?.id),...mergeDecisions.map((entry)=>entry.actor?.id)]),
84
+ recordSourceIds:uniqueStrings([record?.recordSource?.id,record?.recordSource?.sourceId,...acceptedFacts.flatMap((claim)=>[claim.recordSource?.id,claim.recordSource?.sourceId]),...rejectedTheories.flatMap((claim)=>[claim.recordSource?.id,claim.recordSource?.sourceId]),...importedParserEvidence.flatMap((entry)=>[entry.recordSource?.id,entry.recordSource?.sourceId]),...proofAttempts.flatMap((entry)=>[entry.recordSource?.id,entry.recordSource?.sourceId]),...patchAncestry.flatMap((entry)=>[entry.recordSource?.id,entry.recordSource?.sourceId]),...mergeDecisions.flatMap((entry)=>[entry.recordSource?.id,entry.recordSource?.sourceId])]),
85
+ ownershipKeys:uniqueStrings((record?.ownershipRegions??[]).map((region)=>region.key)),
86
+ semanticCandidateIds:uniqueStrings((record?.semanticCandidates??[]).map((candidate)=>candidate.id)),
87
+ semanticClaimIds:uniqueStrings([...acceptedFacts.map((claim)=>claim.id),...rejectedTheories.map((claim)=>claim.id)]),
88
+ semanticClaimHashes:uniqueStrings([...acceptedFacts.map((claim)=>claim.hash),...rejectedTheories.map((claim)=>claim.hash)]),
89
+ acceptedFactIds:uniqueStrings(acceptedFacts.map((claim)=>claim.id)),
90
+ rejectedTheoryIds:uniqueStrings(rejectedTheories.map((claim)=>claim.id)),
91
+ conflictKeys:uniqueStrings([...(record?.semanticCandidates??[]).flatMap((candidate)=>candidate.conflictKeys??[]),...acceptedFacts.flatMap((claim)=>claim.conflictKeys??[]),...rejectedTheories.flatMap((claim)=>claim.conflictKeys??[]),...patchAncestry.flatMap((patch)=>patch.conflictKeys??[]),...mergeDecisions.flatMap((decision)=>decision.conflictKeys??[])]),
92
+ evidenceIds:uniqueStrings([...(record?.evidenceIds??[]),...acceptedFacts.flatMap((claim)=>claim.evidenceIds??[]),...rejectedTheories.flatMap((claim)=>claim.evidenceIds??[]),...importedParserEvidence.flatMap((entry)=>[entry.evidenceId,...(entry.evidenceIds??[])]),...proofAttempts.flatMap((entry)=>entry.evidenceIds??[]),...mergeDecisions.flatMap((entry)=>entry.evidenceIds??[])]),
93
+ importedParserEvidenceIds:uniqueStrings(importedParserEvidence.map((entry)=>entry.id)),
94
+ importedParserEvidenceHashes:uniqueStrings(importedParserEvidence.map((entry)=>entry.hash)),
95
+ proofIds:uniqueStrings([...(record?.proofIds??[]),...acceptedFacts.flatMap((claim)=>claim.proofIds??[]),...rejectedTheories.flatMap((claim)=>claim.proofIds??[]),...proofAttempts.flatMap((entry)=>[entry.proofId,...(entry.proofIds??[])]),...mergeDecisions.flatMap((entry)=>entry.proofIds??[])]),
96
+ proofAttemptIds:uniqueStrings(proofAttempts.map((entry)=>entry.id)),
97
+ proofAttemptHashes:uniqueStrings(proofAttempts.map((entry)=>entry.hash)),
98
+ replayIds:uniqueStrings([...(record?.replayLinks??[]).map((link)=>link.id),...(record?.semanticCandidates??[]).flatMap((candidate)=>candidate.replayIds??[]),...acceptedFacts.flatMap((claim)=>claim.replayIds??[]),...rejectedTheories.flatMap((claim)=>claim.replayIds??[]),...proofAttempts.flatMap((entry)=>entry.replayIds??[])]),
99
+ patchIds:uniqueStrings([...(record?.semanticCandidates??[]).map((candidate)=>candidate.patchId),...patchAncestry.flatMap((entry)=>[entry.patchId,...(entry.parentPatchIds??[]),...(entry.ancestorPatchIds??[])]),...mergeDecisions.flatMap((entry)=>entry.patchIds??[])]),
100
+ patchHashes:uniqueStrings(patchAncestry.flatMap((entry)=>[entry.hash,...(entry.parentHashes??[]),...(entry.ancestorHashes??[])])),
101
+ mergeDecisionIds:uniqueStrings(mergeDecisions.map((entry)=>entry.id)),
102
+ mergeDecisionHashes:uniqueStrings(mergeDecisions.map((entry)=>entry.hash))
103
+ };
104
+ }
105
+
106
+ function blockedAdmission(record){return ['blocked','rejected'].includes(String(record?.admission?.status??''));}
107
+ function rejectedReview(record){return ['rejected','changes-requested'].includes(String(record?.reviewer?.status??''));}
108
+ function intersect(left,right){const rightSet=new Set(right??[]);return uniqueStrings((left??[]).filter((value)=>rightSet.has(value)));}
109
+ function disjointNonEmpty(left,right){return Boolean(left?.length&&right?.length&&intersect(left,right).length===0);}
110
+
111
+ function array(value){if(value===undefined||value===null)return[];return Array.isArray(value)?value:[value];}
112
+ function uniqueStrings(values){return uniqueRawStrings((values??[]).filter((entry)=>entry!==undefined&&entry!==null&&String(entry)!==''));}
113
+ function compactRecord(value){return Object.fromEntries(Object.entries(value??{}).filter(([,entry])=>entry!==undefined&&(!Array.isArray(entry)||entry.length>0)));}
@@ -1,182 +1,263 @@
1
+ import{hashSemanticValue}from'@shapeshift-labs/frontier-lang-kernel';
1
2
  import{ idFragment, maxSemanticMergeReadiness, normalizeSemanticMergeReadiness, uniqueStrings as uniqueRawStrings }from'../../native-import-utils.js';
3
+ import{normalizeOwnershipRegions,normalizeSemanticCandidates,normalizeSemanticClaims,normalizeSources,semanticClaimsByStatus}from'./semanticHistoryRecordNormalizers.js';
2
4
 
3
5
  export const SemanticHistoryAdmissionStatuses=Object.freeze(['proposed','queued','admitted','needs-review','blocked','rejected']);
4
6
  export const SemanticHistoryReviewerStatuses=Object.freeze(['unreviewed','approved','changes-requested','reviewed','rejected']);
5
- export const SemanticHistoryOverlapKinds=Object.freeze(['ownership','conflict-key','source','source-path','import','semantic-candidate','evidence','proof','replay','base-hash','target-hash']);
7
+ export const SemanticHistoryOverlapKinds=Object.freeze(['ownership','conflict-key','source','source-path','import','semantic-candidate','semantic-claim','claim-hash','evidence','proof','replay','patch','merge-decision','actor','record-source','base-hash','target-hash']);
6
8
  export const SemanticHistoryConflictReasons=Object.freeze(['ownership-overlap','semantic-conflict-key-overlap','base-hash-mismatch','target-hash-mismatch','admission-blocked','reviewer-rejected','source-path-overlap']);
7
9
 
8
10
  export function createSemanticHistoryRecord(input={},options={}){
9
11
  const imported=input.importResult??input.imported;
12
+ const actor=normalizeActor(input.actor??options.actor??compactRecord({id:input.actorId??options.actorId,kind:input.actorKind??options.actorKind,role:input.actorRole??options.actorRole,runId:input.runId??options.runId,lane:input.lane??options.lane,taskId:input.taskId??options.taskId}));
13
+ const recordSource=normalizeRecordSource(input.recordSource??input.historySource??options.recordSource??options.historySource,compactRecord({...input,...options}));
10
14
  const sources=normalizeSources(input,imported);
11
15
  const ownershipRegions=normalizeOwnershipRegions([...(array(input.ownershipRegions)),...(array(input.changedRegions)),...(array(input.changeSet?.changedRegions)),...(array(imported?.ownershipRegions))]);
12
16
  const semanticCandidates=normalizeSemanticCandidates([...(array(input.semanticCandidates)),...(array(input.mergeCandidates)),...(array(input.mergeCandidate)),...(array(input.changeSet?.mergeCandidate)),...(array(imported?.mergeCandidates))]);
13
17
  const replayLinks=normalizeReplayLinks(input.replayLinks??input.replay);
14
18
  const baseHash=firstString(input.baseHash,input.beforeHash,...sources.map((source)=>source.baseHash),...semanticCandidates.map((candidate)=>candidate.baseHash));
15
19
  const targetHash=firstString(input.targetHash,input.afterHash,...sources.map((source)=>source.targetHash),...semanticCandidates.map((candidate)=>candidate.targetHash));
16
- const evidenceIds=uniqueStrings([...(strings(input.evidenceIds)),...(array(input.evidence)).map((record)=>record?.id),...(array(imported?.evidence)).map((record)=>record?.id),...semanticCandidates.flatMap((candidate)=>candidate.evidenceIds),...(strings(input.reviewer?.evidenceIds)),...(strings(input.admission?.evidenceIds))]);
17
- const proofIds=uniqueStrings([...(strings(input.proofIds)),...(array(input.proofs)).map((record)=>record?.id),...semanticCandidates.flatMap((candidate)=>candidate.proofIds)]);
20
+ const sourceContext={actor,recordSource,language:input.language??imported?.language??sources.find((source)=>source.language)?.language,sourcePath:input.sourcePath??imported?.sourcePath??sources.find((source)=>source.sourcePath)?.sourcePath,sourceHash:input.sourceHash??imported?.sourceHash??sources.find((source)=>source.sourceHash)?.sourceHash,baseHash,targetHash};
21
+ const acceptedFacts=normalizeSemanticClaims([
22
+ ...(array(input.acceptedFacts)),
23
+ ...(array(input.acceptedSemanticClaims)),
24
+ ...semanticClaimsByStatus(input,'accepted')
25
+ ],{...sourceContext,status:'accepted',claimKind:'fact',prefix:'semantic_fact'});
26
+ const rejectedTheories=normalizeSemanticClaims([
27
+ ...(array(input.rejectedTheories)),
28
+ ...(array(input.rejectedSemanticClaims)),
29
+ ...semanticClaimsByStatus(input,'rejected')
30
+ ],{...sourceContext,status:'rejected',claimKind:'theory',prefix:'semantic_theory'});
31
+ const importedParserEvidence=normalizeImportedParserEvidence([
32
+ ...(array(input.importedParserEvidence)),
33
+ ...(array(input.parserEvidence)),
34
+ ...(array(imported?.parserEvidence))
35
+ ],sourceContext);
36
+ const proofAttempts=normalizeProofAttempts([...(array(input.proofAttempts)),...(array(input.proofs))],sourceContext);
37
+ const patchAncestry=normalizePatchAncestry(input.patchAncestry??input.patchAncestors??input.ancestry,sourceContext);
38
+ const mergeDecisions=normalizeMergeDecisions(input.mergeDecisions??input.decisions,sourceContext);
39
+ const semanticClaimIds=uniqueStrings([...acceptedFacts.map((claim)=>claim.id),...rejectedTheories.map((claim)=>claim.id)]);
40
+ const semanticClaimHashes=uniqueStrings([...acceptedFacts.map((claim)=>claim.hash),...rejectedTheories.map((claim)=>claim.hash)]);
41
+ const evidenceIds=uniqueStrings([...(strings(input.evidenceIds)),...(array(input.evidence)).map((record)=>record?.id),...(array(imported?.evidence)).map((record)=>record?.id),...semanticCandidates.flatMap((candidate)=>candidate.evidenceIds),...acceptedFacts.flatMap((claim)=>claim.evidenceIds),...rejectedTheories.flatMap((claim)=>claim.evidenceIds),...importedParserEvidence.flatMap((record)=>[record.evidenceId,...array(record.evidenceIds)]),...proofAttempts.flatMap((record)=>record.evidenceIds),...mergeDecisions.flatMap((decision)=>decision.evidenceIds),...(strings(input.reviewer?.evidenceIds)),...(strings(input.admission?.evidenceIds))]);
42
+ const proofIds=uniqueStrings([...(strings(input.proofIds)),...(array(input.proofs)).map((record)=>record?.id),...semanticCandidates.flatMap((candidate)=>candidate.proofIds),...acceptedFacts.flatMap((claim)=>claim.proofIds),...rejectedTheories.flatMap((claim)=>claim.proofIds),...proofAttempts.flatMap((record)=>[record.proofId,...array(record.proofIds)]),...mergeDecisions.flatMap((decision)=>decision.proofIds)]);
18
43
  const sourceIds=uniqueStrings([input.sourceId,...strings(input.sourceIds),...sources.map((source)=>source.id)]);
19
44
  const importIds=uniqueStrings([input.importId,input.importResultId,imported?.id,...strings(input.importIds),...sources.map((source)=>source.importId),...semanticCandidates.map((candidate)=>candidate.importResultId)]);
20
45
  const sourcePaths=uniqueStrings([input.sourcePath,imported?.sourcePath,...sources.map((source)=>source.sourcePath),...ownershipRegions.map((region)=>region.sourcePath),...semanticCandidates.map((candidate)=>candidate.sourcePath)]);
21
46
  const sourceHashes=uniqueStrings([input.sourceHash,imported?.sourceHash,...sources.map((source)=>source.sourceHash),...ownershipRegions.map((region)=>region.sourceHash)]);
22
- const conflictKeys=uniqueStrings([...(strings(input.conflictKeys)),...semanticCandidates.flatMap((candidate)=>candidate.conflictKeys)]);
47
+ const conflictKeys=uniqueStrings([...(strings(input.conflictKeys)),...semanticCandidates.flatMap((candidate)=>candidate.conflictKeys),...acceptedFacts.flatMap((claim)=>claim.conflictKeys),...rejectedTheories.flatMap((claim)=>claim.conflictKeys),...patchAncestry.flatMap((patch)=>patch.conflictKeys),...mergeDecisions.flatMap((decision)=>decision.conflictKeys)]);
23
48
  const reviewer=normalizeReviewer(input.reviewer);
24
49
  const admission=normalizeAdmission(input.admission,semanticCandidates,reviewer);
25
- return{
50
+ const actorIds=uniqueStrings([actor?.id,actor?.actorId,...acceptedFacts.map((claim)=>claim.actor?.id),...rejectedTheories.map((claim)=>claim.actor?.id),...importedParserEvidence.map((record)=>record.actor?.id),...proofAttempts.map((record)=>record.actor?.id),...patchAncestry.map((record)=>record.actor?.id),...mergeDecisions.map((record)=>record.actor?.id)]);
51
+ const recordSourceIds=uniqueStrings([recordSource?.id,recordSource?.sourceId,...acceptedFacts.flatMap((claim)=>[claim.recordSource?.id,claim.recordSource?.sourceId]),...rejectedTheories.flatMap((claim)=>[claim.recordSource?.id,claim.recordSource?.sourceId]),...importedParserEvidence.flatMap((record)=>[record.recordSource?.id,record.recordSource?.sourceId]),...proofAttempts.flatMap((record)=>[record.recordSource?.id,record.recordSource?.sourceId]),...patchAncestry.flatMap((record)=>[record.recordSource?.id,record.recordSource?.sourceId]),...mergeDecisions.flatMap((record)=>[record.recordSource?.id,record.recordSource?.sourceId])]);
52
+ const patchIds=uniqueStrings([...semanticCandidates.map((candidate)=>candidate.patchId),...patchAncestry.flatMap((patch)=>[patch.patchId,...array(patch.parentPatchIds),...array(patch.ancestorPatchIds)]),...mergeDecisions.flatMap((decision)=>decision.patchIds)]);
53
+ const mergeDecisionIds=uniqueStrings(mergeDecisions.map((decision)=>decision.id));
54
+ const index={
55
+ baseHashes:uniqueStrings([baseHash,...sources.map((source)=>source.baseHash),...semanticCandidates.map((candidate)=>candidate.baseHash),...patchAncestry.map((patch)=>patch.baseHash)]),
56
+ targetHashes:uniqueStrings([targetHash,...sources.map((source)=>source.targetHash),...semanticCandidates.map((candidate)=>candidate.targetHash),...patchAncestry.map((patch)=>patch.targetHash)]),
57
+ sourceIds,
58
+ importIds,
59
+ sourcePaths,
60
+ sourceHashes,
61
+ actorIds,
62
+ recordSourceIds,
63
+ ownershipKeys:uniqueStrings([...ownershipRegions.map((region)=>region.key),...semanticCandidates.flatMap((candidate)=>candidate.ownershipKeys)]),
64
+ semanticCandidateIds:uniqueStrings(semanticCandidates.map((candidate)=>candidate.id)),
65
+ semanticClaimIds,
66
+ semanticClaimHashes,
67
+ acceptedFactIds:uniqueStrings(acceptedFacts.map((claim)=>claim.id)),
68
+ rejectedTheoryIds:uniqueStrings(rejectedTheories.map((claim)=>claim.id)),
69
+ conflictKeys,
70
+ evidenceIds,
71
+ importedParserEvidenceIds:uniqueStrings(importedParserEvidence.map((record)=>record.id)),
72
+ importedParserEvidenceHashes:uniqueStrings(importedParserEvidence.map((record)=>record.hash)),
73
+ proofIds,
74
+ proofAttemptIds:uniqueStrings(proofAttempts.map((record)=>record.id)),
75
+ proofAttemptHashes:uniqueStrings(proofAttempts.map((record)=>record.hash)),
76
+ replayIds:uniqueStrings([...replayLinks.map((link)=>link.id),...semanticCandidates.flatMap((candidate)=>candidate.replayIds),...acceptedFacts.flatMap((claim)=>claim.replayIds),...rejectedTheories.flatMap((claim)=>claim.replayIds),...proofAttempts.flatMap((record)=>record.replayIds)]),
77
+ patchIds,
78
+ patchHashes:uniqueStrings(patchAncestry.flatMap((patch)=>[patch.hash,...array(patch.parentHashes),...array(patch.ancestorHashes)])),
79
+ mergeDecisionIds,
80
+ mergeDecisionHashes:uniqueStrings(mergeDecisions.map((decision)=>decision.hash))
81
+ };
82
+ const recordCore={
26
83
  kind:'frontier.lang.semanticHistoryRecord',
27
84
  version:1,
28
- id:input.id??options.id??`semantic_history_${idFragment(firstString(sourcePaths[0],importIds[0],sourceIds[0],'record'))}`,
29
- createdAt:input.createdAt??options.createdAt??Date.now(),
30
85
  baseHash,
31
86
  targetHash,
32
- language:input.language??imported?.language??sources.find((source)=>source.language)?.language,
33
- sourcePath:input.sourcePath??imported?.sourcePath??sourcePaths[0],
87
+ language:sourceContext.language,
88
+ sourcePath:sourceContext.sourcePath??sourcePaths[0],
89
+ actor,
90
+ recordSource,
34
91
  sourceIds,
35
92
  importIds,
36
93
  sources,
37
94
  ownershipRegions,
38
95
  semanticCandidates,
96
+ acceptedFacts,
97
+ rejectedTheories,
98
+ importedParserEvidence,
99
+ proofAttempts,
100
+ patchAncestry,
101
+ mergeDecisions,
39
102
  evidenceIds,
40
103
  proofIds,
41
104
  reviewer,
42
105
  admission,
43
106
  replayLinks,
44
- index:{
45
- baseHashes:uniqueStrings([baseHash,...sources.map((source)=>source.baseHash),...semanticCandidates.map((candidate)=>candidate.baseHash)]),
46
- targetHashes:uniqueStrings([targetHash,...sources.map((source)=>source.targetHash),...semanticCandidates.map((candidate)=>candidate.targetHash)]),
47
- sourceIds,
48
- importIds,
49
- sourcePaths,
50
- sourceHashes,
51
- ownershipKeys:uniqueStrings([...ownershipRegions.map((region)=>region.key),...semanticCandidates.flatMap((candidate)=>candidate.ownershipKeys)]),
52
- semanticCandidateIds:uniqueStrings(semanticCandidates.map((candidate)=>candidate.id)),
53
- conflictKeys,
54
- evidenceIds,
55
- proofIds,
56
- replayIds:uniqueStrings(replayLinks.map((link)=>link.id))
57
- },
107
+ index,
58
108
  metadata:compactRecord(input.metadata)
59
109
  };
110
+ const hash=hashSemanticValue(recordCore);
111
+ const stableId=`semantic_history_${idFragment(hash)}`;
112
+ return{
113
+ ...recordCore,
114
+ id:input.id??options.id??stableId,
115
+ stableId,
116
+ hash,
117
+ createdAt:input.createdAt??options.createdAt??Date.now()
118
+ };
60
119
  }
61
120
 
62
- export function querySemanticHistoryRecordOverlaps(records,options={}){
63
- const list=array(records).filter(Boolean);
64
- const overlaps=[];
65
- for(let leftIndex=0;leftIndex<list.length;leftIndex+=1){
66
- for(let rightIndex=leftIndex+1;rightIndex<list.length;rightIndex+=1){
67
- const overlap=semanticHistoryOverlap(list[leftIndex],list[rightIndex],options);
68
- if(overlap.overlapKinds.length||overlap.conflictReasons.length)overlaps.push(overlap);
69
- }
70
- }
71
- return overlaps.sort((left,right)=>Number(right.conflict)-Number(left.conflict)||left.leftId.localeCompare(right.leftId)||left.rightId.localeCompare(right.rightId));
121
+ export{querySemanticHistoryRecordOverlaps,semanticHistoryRecordsConflict,semanticHistoryRecordsOverlap}from'./semanticHistoryRecordOverlaps.js';
122
+
123
+ function normalizeImportedParserEvidence(records,defaults){
124
+ return records.filter(Boolean).map((record,index)=>{
125
+ const source=typeof record==='string'?{evidenceId:record}:record;
126
+ const normalized=compactRecord({
127
+ kind:'frontier.lang.semanticHistoryImportedParserEvidence',
128
+ version:1,
129
+ evidenceId:firstString(source.evidenceId,source.id),
130
+ importId:source.importId??source.importResultId??defaults.importId,
131
+ parserId:source.parserId??source.parser??source.adapterId,
132
+ parserKind:source.parserKind??source.kind,
133
+ language:source.language??defaults.language,
134
+ sourcePath:source.sourcePath??defaults.sourcePath,
135
+ sourceHash:source.sourceHash??source.hash??defaults.sourceHash,
136
+ astHash:source.astHash??source.nativeAstHash,
137
+ semanticIndexHash:source.semanticIndexHash,
138
+ status:source.status??'unknown',
139
+ evidenceIds:uniqueStrings([source.evidenceId,source.id,...strings(source.evidenceIds)]),
140
+ replayIds:uniqueStrings(source.replayIds),
141
+ actor:normalizeActor(source.actor)??defaults.actor,
142
+ recordSource:normalizeRecordSource(source.recordSource??source.historySource??defaults.recordSource,defaults),
143
+ metadata:source.metadata
144
+ });
145
+ return withStableSubrecordIdentity('imported_parser_evidence',normalized,source,index);
146
+ });
72
147
  }
73
148
 
74
- export function semanticHistoryRecordsOverlap(left,right,options={}){
75
- return semanticHistoryOverlap(left,right,options).overlapKinds.length>0;
149
+ function normalizeProofAttempts(records,defaults){
150
+ return records.filter(Boolean).map((record,index)=>{
151
+ const source=typeof record==='string'?{proofId:record}:record;
152
+ const normalized=compactRecord({
153
+ kind:'frontier.lang.semanticHistoryProofAttempt',
154
+ version:1,
155
+ proofId:firstString(source.proofId,source.id),
156
+ proofKind:source.proofKind??source.kind,
157
+ status:source.status??'unknown',
158
+ proverId:source.proverId??source.prover,
159
+ claimIds:uniqueStrings(source.claimIds),
160
+ evidenceIds:uniqueStrings(source.evidenceIds),
161
+ proofIds:uniqueStrings(source.proofIds),
162
+ replayIds:uniqueStrings(source.replayIds),
163
+ command:source.command,
164
+ resultHash:source.resultHash??source.proofHash,
165
+ actor:normalizeActor(source.actor)??defaults.actor,
166
+ recordSource:normalizeRecordSource(source.recordSource??source.historySource??defaults.recordSource,defaults),
167
+ metadata:source.metadata
168
+ });
169
+ return withStableSubrecordIdentity('proof_attempt',normalized,source,index);
170
+ });
76
171
  }
77
172
 
78
- export function semanticHistoryRecordsConflict(left,right,options={}){
79
- return semanticHistoryOverlap(left,right,options).conflict;
173
+ function normalizePatchAncestry(records,defaults){
174
+ return array(records).filter(Boolean).map((record,index)=>{
175
+ const source=typeof record==='string'?{patchId:record}:record;
176
+ const normalized=compactRecord({
177
+ kind:'frontier.lang.semanticHistoryPatchAncestry',
178
+ version:1,
179
+ patchId:firstString(source.patchId,source.id),
180
+ parentPatchIds:uniqueStrings([...(strings(source.parentPatchIds)),...(strings(source.parents))]),
181
+ ancestorPatchIds:uniqueStrings([...(strings(source.ancestorPatchIds)),...(strings(source.ancestors))]),
182
+ baseHash:source.baseHash??defaults.baseHash,
183
+ targetHash:source.targetHash??defaults.targetHash,
184
+ parentHashes:uniqueStrings(source.parentHashes),
185
+ ancestorHashes:uniqueStrings(source.ancestorHashes),
186
+ conflictKeys:uniqueStrings(source.conflictKeys),
187
+ actor:normalizeActor(source.actor)??defaults.actor,
188
+ recordSource:normalizeRecordSource(source.recordSource??source.historySource??defaults.recordSource,defaults),
189
+ metadata:source.metadata
190
+ });
191
+ return withStableSubrecordIdentity('patch_ancestry',normalized,source,index);
192
+ });
80
193
  }
81
194
 
82
- function semanticHistoryOverlap(left,right,options){
83
- const leftIndex=historyIndex(left);
84
- const rightIndex=historyIndex(right);
85
- const overlap=compactRecord({
86
- ownership:intersect(leftIndex.ownershipKeys,rightIndex.ownershipKeys),
87
- 'conflict-key':intersect(leftIndex.conflictKeys,rightIndex.conflictKeys),
88
- source:intersect(leftIndex.sourceIds,rightIndex.sourceIds),
89
- 'source-path':options.includeSourcePaths===false?[]:intersect(leftIndex.sourcePaths,rightIndex.sourcePaths),
90
- import:intersect(leftIndex.importIds,rightIndex.importIds),
91
- 'semantic-candidate':intersect(leftIndex.semanticCandidateIds,rightIndex.semanticCandidateIds),
92
- evidence:options.includeEvidence?intersect(leftIndex.evidenceIds,rightIndex.evidenceIds):[],
93
- proof:options.includeProofs?intersect(leftIndex.proofIds,rightIndex.proofIds):[],
94
- replay:options.includeReplay?intersect(leftIndex.replayIds,rightIndex.replayIds):[],
95
- 'base-hash':options.includeBaseHashes?intersect(leftIndex.baseHashes,rightIndex.baseHashes):[],
96
- 'target-hash':options.includeTargetHashes?intersect(leftIndex.targetHashes,rightIndex.targetHashes):[]
195
+ function normalizeMergeDecisions(records,defaults){
196
+ return array(records).filter(Boolean).map((record,index)=>{
197
+ const source=typeof record==='string'?{decision:record}:record;
198
+ const normalized=compactRecord({
199
+ kind:'frontier.lang.semanticHistoryMergeDecision',
200
+ version:1,
201
+ decision:source.decision??source.status,
202
+ status:source.status??source.decision,
203
+ decidedAt:source.decidedAt,
204
+ claimIds:uniqueStrings(source.claimIds),
205
+ acceptedClaimIds:uniqueStrings(source.acceptedClaimIds),
206
+ rejectedClaimIds:uniqueStrings(source.rejectedClaimIds),
207
+ patchIds:uniqueStrings([...(strings(source.patchIds)),source.patchId]),
208
+ conflictKeys:uniqueStrings(source.conflictKeys),
209
+ evidenceIds:uniqueStrings(source.evidenceIds),
210
+ proofIds:uniqueStrings(source.proofIds),
211
+ reasonCodes:uniqueStrings(source.reasonCodes),
212
+ actor:normalizeActor(source.actor)??defaults.actor,
213
+ recordSource:normalizeRecordSource(source.recordSource??source.historySource??defaults.recordSource,defaults),
214
+ metadata:source.metadata
215
+ });
216
+ return withStableSubrecordIdentity('merge_decision',normalized,source,index);
97
217
  });
98
- const overlapKinds=Object.keys(overlap);
99
- const semanticOverlap=Boolean(overlap.ownership?.length||overlap['conflict-key']?.length||overlap.source?.length||overlap['source-path']?.length||overlap.import?.length);
100
- const conflictReasons=uniqueStrings([
101
- overlap.ownership?.length?'ownership-overlap':undefined,
102
- overlap['conflict-key']?.length?'semantic-conflict-key-overlap':undefined,
103
- semanticOverlap&&disjointNonEmpty(leftIndex.baseHashes,rightIndex.baseHashes)?'base-hash-mismatch':undefined,
104
- (overlap.ownership?.length||overlap['conflict-key']?.length)&&disjointNonEmpty(leftIndex.targetHashes,rightIndex.targetHashes)?'target-hash-mismatch':undefined,
105
- semanticOverlap&&(blockedAdmission(left)||blockedAdmission(right))?'admission-blocked':undefined,
106
- semanticOverlap&&(rejectedReview(left)||rejectedReview(right))?'reviewer-rejected':undefined,
107
- options.conflictOnSourcePath&&overlap['source-path']?.length?'source-path-overlap':undefined
108
- ]);
109
- return{
110
- schema:'frontier.lang.semanticHistoryOverlap.v1',
111
- leftId:String(left?.id??'left'),
112
- rightId:String(right?.id??'right'),
113
- overlap,
114
- overlapKinds,
115
- conflict:conflictReasons.length>0,
116
- conflictReasons,
117
- admission:{left:left?.admission?.status,right:right?.admission?.status},
118
- reviewer:{left:left?.reviewer?.status,right:right?.reviewer?.status}
119
- };
120
218
  }
121
219
 
122
- function normalizeSources(input,imported){
123
- const entries=[...(array(input.sources)),...(array(input.sourceRefs)),...(array(input.source)),...(array(imported))];
124
- if(entries.length===0&&(input.sourcePath||input.sourceHash||input.baseHash||input.targetHash||input.sourceId||input.importId)){
125
- entries.push(input);
126
- }
127
- return entries.map((source,index)=>compactRecord({
128
- id:source?.id??source?.sourceId,
129
- importId:source?.importId??source?.importResultId??(source?.kind==='frontier.lang.importResult'?source.id:undefined),
130
- language:source?.language??input.language,
131
- sourcePath:source?.sourcePath??source?.path??input.sourcePath,
132
- sourceHash:source?.sourceHash??source?.hash,
133
- baseHash:source?.baseHash??source?.beforeHash??input.baseHash??input.beforeHash,
134
- targetHash:source?.targetHash??source?.afterHash??input.targetHash??input.afterHash,
135
- metadata:source?.metadata,
136
- ordinal:index
137
- })).filter((source)=>source.id||source.importId||source.sourcePath||source.sourceHash||source.baseHash||source.targetHash);
220
+ function withStableSubrecordIdentity(prefix,record,source,index){
221
+ const hash=source.hash??hashSemanticValue(record);
222
+ return{
223
+ ...record,
224
+ id:source.id??`${prefix}_${idFragment(firstString(record.subject,record.evidenceId,record.proofId,record.patchId,record.decision,hash,index+1))}`,
225
+ hash
226
+ };
138
227
  }
139
228
 
140
- function normalizeOwnershipRegions(regions){
141
- const seen=new Set();
142
- const normalized=[];
143
- for(const region of regions){
144
- const key=firstString(region?.key,region?.ownershipKey,region?.conflictKey,region?.id);
145
- if(!key||seen.has(key))continue;
146
- seen.add(key);
147
- normalized.push(compactRecord({
148
- id:region?.id,
149
- key,
150
- regionKind:region?.regionKind??region?.ownershipRegionKind,
151
- granularity:region?.granularity??'semantic',
152
- language:region?.language,
153
- sourcePath:region?.sourcePath,
154
- sourceHash:region?.sourceHash,
155
- symbolId:region?.symbolId,
156
- symbolName:region?.symbolName??region?.name,
157
- sourceSpan:region?.sourceSpan??region?.span,
158
- metadata:region?.metadata
159
- }));
160
- }
161
- return normalized;
229
+ function normalizeActor(value){
230
+ const actor=typeof value==='string'?{id:value}:value;
231
+ const normalized=compactRecord({
232
+ id:actor?.id??actor?.actorId,
233
+ kind:actor?.kind??actor?.actorKind??actor?.type,
234
+ role:actor?.role,
235
+ displayName:actor?.displayName??actor?.name,
236
+ runId:actor?.runId,
237
+ lane:actor?.lane,
238
+ taskId:actor?.taskId,
239
+ metadata:actor?.metadata
240
+ });
241
+ return nonEmptyRecord(normalized);
162
242
  }
163
243
 
164
- function normalizeSemanticCandidates(candidates){
165
- return candidates.filter(Boolean).map((candidate,index)=>compactRecord({
166
- id:candidate.id??candidate.candidateId??`semantic_candidate_${index+1}`,
167
- importResultId:candidate.importResultId,
168
- patchId:candidate.patchId,
169
- sourcePath:candidate.sourcePath,
170
- baseHash:candidate.baseHash,
171
- targetHash:candidate.targetHash,
172
- readiness:normalizeSemanticMergeReadiness(candidate.readiness)??candidate.readiness,
173
- conflictKeys:uniqueStrings([...(strings(candidate.conflictKeys)),...(array(candidate.touchedSymbols)).map((entry)=>entry?.conflictKey),...(array(candidate.touchedSemanticNodes)).map((entry)=>entry?.conflictKey),...(array(candidate.nativeSpans)).map((entry)=>entry?.conflictKey),...(array(candidate.conflictClasses??candidate.metadata?.conflictClasses)).flatMap((entry)=>entry?.conflictKeys??[]),...(candidate.conflictSummary?.conflictKeys??candidate.metadata?.conflictSummary?.conflictKeys??[])]),
174
- ownershipKeys:uniqueStrings([...(strings(candidate.ownershipKeys)),...(strings(candidate.regionKeys))]),
175
- evidenceIds:uniqueStrings([...(strings(candidate.evidenceIds)),...(array(candidate.evidence)).map((record)=>record?.id),...(array(candidate.conflictClasses??candidate.metadata?.conflictClasses)).flatMap((entry)=>entry?.evidenceIds??[])]),
176
- proofIds:uniqueStrings([...(strings(candidate.proofIds)),...(array(candidate.evidence)).filter((record)=>record?.kind==='proof').map((record)=>record?.id)]),
177
- replayIds:uniqueStrings([...(strings(candidate.replayIds)),...(array(candidate.evidence)).filter((record)=>record?.kind==='replay').map((record)=>record?.id)]),
178
- metadata:compactRecord({risk:candidate.risk,reasons:candidate.reasons,...candidate.metadata})
179
- }));
244
+ function normalizeRecordSource(value,context={}){
245
+ const source=typeof value==='string'?{id:value}:value;
246
+ const normalized=compactRecord({
247
+ id:source?.id??source?.sourceId??context.recordSourceId??context.historySourceId,
248
+ sourceId:source?.sourceId??source?.id??context.recordSourceId??context.historySourceId,
249
+ sourceKind:source?.sourceKind??source?.kind??source?.type,
250
+ sourcePath:source?.sourcePath??source?.path,
251
+ sourceHash:source?.sourceHash??source?.hash,
252
+ href:source?.href??source?.url,
253
+ importId:source?.importId??context.importId??context.importResultId,
254
+ runId:source?.runId??context.runId,
255
+ jobId:source?.jobId??context.jobId,
256
+ lane:source?.lane??context.lane,
257
+ taskId:source?.taskId??context.taskId,
258
+ metadata:source?.metadata
259
+ });
260
+ return nonEmptyRecord(normalized);
180
261
  }
181
262
 
182
263
  function normalizeReplayLinks(value){
@@ -205,29 +286,9 @@ function normalizeAdmission(admission,candidates,reviewer){
205
286
  return compactRecord({status:admission?.status??'proposed',readiness,admittedAt:admission?.admittedAt,reviewerId:admission?.reviewerId??reviewer.reviewerId,reasonCodes:uniqueStrings(admission?.reasonCodes),evidenceIds:uniqueStrings(admission?.evidenceIds),metadata:admission?.metadata});
206
287
  }
207
288
 
208
- function historyIndex(record){
209
- return record?.index??{
210
- baseHashes:uniqueStrings([record?.baseHash]),
211
- targetHashes:uniqueStrings([record?.targetHash]),
212
- sourceIds:uniqueStrings(record?.sourceIds),
213
- importIds:uniqueStrings(record?.importIds),
214
- sourcePaths:uniqueStrings([record?.sourcePath,...(record?.sources??[]).map((source)=>source.sourcePath)]),
215
- sourceHashes:uniqueStrings((record?.sources??[]).map((source)=>source.sourceHash)),
216
- ownershipKeys:uniqueStrings((record?.ownershipRegions??[]).map((region)=>region.key)),
217
- semanticCandidateIds:uniqueStrings((record?.semanticCandidates??[]).map((candidate)=>candidate.id)),
218
- conflictKeys:uniqueStrings((record?.semanticCandidates??[]).flatMap((candidate)=>candidate.conflictKeys??[])),
219
- evidenceIds:uniqueStrings(record?.evidenceIds),
220
- proofIds:uniqueStrings(record?.proofIds),
221
- replayIds:uniqueStrings((record?.replayLinks??[]).map((link)=>link.id))
222
- };
223
- }
224
-
225
- function blockedAdmission(record){return ['blocked','rejected'].includes(String(record?.admission?.status??''));}
226
- function rejectedReview(record){return ['rejected','changes-requested'].includes(String(record?.reviewer?.status??''));}
227
- function intersect(left,right){const rightSet=new Set(right??[]);return uniqueStrings((left??[]).filter((value)=>rightSet.has(value)));}
228
- function disjointNonEmpty(left,right){return Boolean(left?.length&&right?.length&&intersect(left,right).length===0);}
229
289
  function array(value){if(value===undefined||value===null)return[];return Array.isArray(value)?value:[value];}
230
290
  function strings(value){return array(value).map((entry)=>String(entry??'')).filter(Boolean);}
231
291
  function uniqueStrings(values){return uniqueRawStrings((values??[]).filter((entry)=>entry!==undefined&&entry!==null&&String(entry)!==''));}
232
292
  function firstString(...values){return values.map((value)=>value===undefined||value===null?'':String(value)).find(Boolean);}
233
293
  function compactRecord(value){return Object.fromEntries(Object.entries(value??{}).filter(([,entry])=>entry!==undefined&&(!Array.isArray(entry)||entry.length>0)));}
294
+ function nonEmptyRecord(value){return Object.keys(value??{}).length?value:undefined;}