/*
RFC-0221 §4.1: the version-compare matrix — the core safety gate of handoff.absorb.
- Do not read the filesystem or git — inputs are already-resolved facts.
- Do not apply migrators — that is the absorb pipeline's job.
- RFC-0221: initial matrix.
*/
import { compareSemver } from "./semver.ts";
import type { VersionComparison } from "./types.ts";
export interface CompareEcosystemInput {
sourceVersion: string;
currentVersion: string;
/** packagesHash from the lock (legacy byte hash). */
sourcePackagesHash: string;
/** packagesHash of the recipient's current packages/ tree (legacy byte hash). */
currentPackagesHash: string;
/** RFC-0364: platformSemanticHash from the lock (preferred drift signal). */
sourcePlatformSemanticHash?: string;
/** RFC-0364: platformSemanticHash of the recipient's current packages/ tree. */
currentPlatformSemanticHash?: string;
}
/**
* RFC-0221 §4.1 normative matrix:
* V_src == V_cur → in-sync (packagesDrift flagged if hashes differ)
* V_src < V_cur → catch-up
* V_src > V_cur → refuse-downgrade ("git pull first"; never downgrade a site)
*/
export function compareEcosystem(input: CompareEcosystemInput): VersionComparison {
const {
sourceVersion,
currentVersion,
sourcePackagesHash,
currentPackagesHash,
sourcePlatformSemanticHash,
currentPlatformSemanticHash,
} = input;
const order = compareSemver(sourceVersion, currentVersion);
if (order > 0) {
return {
verdict: "refuse-downgrade",
sourceVersion,
currentVersion,
packagesDrift: false,
message:
`your ecosystem (${currentVersion}) is older than this bundle (${sourceVersion}) — ` +
`run \`git pull\` and retry. A site is never downgraded.`,
};
}
if (order < 0) {
return {
verdict: "catch-up",
sourceVersion,
currentVersion,
packagesDrift: false,
message: `catch-up: migrating site from ${sourceVersion} to ${currentVersion}.`,
};
}
// RFC-0364: prefer platformSemanticHash when both sides have it; fall back to packagesHash.
const sourceHash = sourcePlatformSemanticHash ?? sourcePackagesHash;
const currentHash = currentPlatformSemanticHash ?? currentPackagesHash;
const packagesDrift = sourceHash !== currentHash;
return {
verdict: "in-sync",
sourceVersion,
currentVersion,
packagesDrift,
message: packagesDrift
? `in sync at ${currentVersion}, but your packages/ differ from the bundle's release ` +
`snapshot (uncommitted ecosystem drift) — proceeding with a warning.`
: `in sync at ${currentVersion}; no migration needed.`,
};
}