Dashboard › cli › Distillation
9cfb43c2-4999-484a-9d61-10e9acb8086e["lore_tm_v1_Sghw2RRKRvzyvG4gT-JHDS9R2xizlN_TaxLdMeByydw"]
SourceStrategy with PatchCache, applyPatchChainInMemory, SHA-256 verification, and progress events; product-specific concerns such as version, telemetry, logging, and cache location are injected.SourceStrategy.resolveChain(currentVersion, targetVersion, signal?, report?): Promise<PatchChain | null>, where the returned PatchChain is ordered oldest hop first and includes the expected final SHA-256.SourceStrategy returning null always falls back to a full download; UnavailableReporter classification is telemetry-only and never changes control flow.DeltaSource as "cache" | "network" | "offline_miss".DeltaUnavailableReason as "no_patches" | "malformed_chain" | "too_long" | "over_budget" | "network": no_patches means no patch tags/assets in the range; malformed_chain means published patches form a broken or unusable chain, including a missing <binaryName> layer, invalid from-version back-pointer, missing target SHA-256 annotation, or other validation failure; too_long exceeds maximum depth; over_budget exceeds the patch-size ratio gate; and network is a transient resolution failure.malformed_chain telemetry is intended to distinguish a poisoned published manifest from benign no_patches, allowing immediate alerting instead of silently degrading every spanning upgrade to a full download.UnavailableReporter = (reason: DeltaUnavailableReason) => void and DeltaTelemetry hooks onResolved?: (info: { source: DeltaSource; chain: PatchChain }) => void, onOfflineMiss?: () => void, and onUnavailable?: (reason: DeltaUnavailableReason) => void; the library remains telemetry-agnostic.ResolveAndApplyOpts with source, currentVersion, targetVersion, oldPath, destPath, optional cache, optional offline, optional onProgress, optional telemetry, and optional signal.ResolveAndApplyOpts.offline means βnever touch the network β cache hit or bust.βResolveAndApplyOpts.onProgress are βNever rendered by the library.βresolveAndApply(opts): Promise<DeltaResult | null> as cache-first: it calls tryLoadCachedChain(cache, currentVersion, targetVersion) and, on a hit, emits telemetry?.onResolved?.({ source: "cache", chain: cached }) before applying the cached chain.tryLoadCachedChain() swallowing any cache.load(currentVersion, targetVersion) error and returning null, allowing normal fallback behavior.resolveAndApply() in offline mode emitting telemetry?.onOfflineMiss?.() and returning null after a cache miss, without calling source.resolveChain() or touching the network.{ type: "phase", phase: "resolve" }, defaulting unavailableReason to "no_patches", and passing a report callback to source.resolveChain() so the source can replace that default with a more specific DeltaUnavailableReason.source.resolveChain() returns null, resolveAndApply() calls telemetry?.onUnavailable?.(unavailableReason) and returns null, preserving full-download fallback regardless of the reported reason.cache.save(chain, chain.steps).catch(() => {}) when cache and chain.steps are present; save failures are ignored, then telemetry?.onResolved?.({ source: "network", chain }) is emitted before application.resolveAndApply() throws only for genuine patch application or verification failures, such as a corrupt patch or SHA-256 mismatch; callers treat such throws as a signal to fall back to a full download.applyChain() computing apply-phase progress total as the sum of parsePatchHeader(patch.data).newSize across every patch hop because byte callbacks include both in-memory intermediate outputs and the final disk write; using only the final hop size would make a multi-hop progress bar hit 100% after the first hop and then freeze.parsePatchHeader() call throws, total becomes null, while the corrupt header remains subject to proper rejection later during patch application.applyChain() emitting apply-phase events in this order: { type: "phase", phase: "apply" }; cumulative { type: "bytes", phase: "apply", written, total } updates from applyPatchChainInMemory(); then { type: "done", phase: "apply" }.applyChain() calling applyPatchChainInMemory(oldPath, chain.patches.map((p) => p.data), destPath, onBytes) and accumulating every callbackβs bytes into written.{ type: "phase", phase: "verify" } followed, on success, by { type: "done", phase: "verify" }; if the produced hash differs from chain.expectedSha256, it throws SHA-256 mismatch after patching: got ${sha256}, expected ${chain.expectedSha256}.applyChain() returning { sha256, patchBytes: chain.totalSize, chainLength: chain.patches.length }.