Files
skills/docs/api-stack/api/api-lifecycle/src/reinstall-criteria/reinstall-criteria.md
2026-05-29 08:20:56 +01:00

2.6 KiB

reinstall-criteria

(no submodules)

Purpose

Decides whether a manifest update from prev to next requires a full reinstall path (uninstalled → installing → installed → starting → started) versus a hot-reload (stopped → starting). The criteria mirror design §4 exactly: a schemaVersion bump, new scopes/events/jobs/secrets, or any dependsOn diff force the full path; a strict version downgrade throws LIFECYCLE.REINSTALL_REQUIRED_VERSION_DOWNGRADE because the ledger would then point at a higher schemaVersion than the running code can satisfy.

Features

  • Pure requiresReinstall(prev, next): boolean — no I/O, no global state, no clock dependency.
  • Per-field detection of added items only (removals are intentionally not a reinstall trigger — the host can drop them in hot-reload).
  • Embedded compareSemver(a, b) implementing loose semver compare (X.Y.Z form, prerelease/build metadata ignored). The manifest validator in api-manifest already rejects non-semver values, so this is the only consumer.
  • Throws LIFECYCLE.REINSTALL_REQUIRED_VERSION_DOWNGRADE with prev / next versions in error.context for downgrade attempts.

Usage: Basic

import { requiresReinstall } from "@suaveplan/api-lifecycle/reinstall-criteria";

if (requiresReinstall(prev, next)) {
    // walk the full install path
} else {
    // hot reload via stopped → starting
}

Usage: Advanced

Wrapping the call in admin tooling that wants to surface the specific trigger reason:

import { compareSemver, requiresReinstall } from "@suaveplan/api-lifecycle/reinstall-criteria";

function explain(prev: PluginManifest, next: PluginManifest): string {
    if (compareSemver(next.version, prev.version) < 0) return "version downgrade";
    if ((next.database?.schemaVersion ?? 0) > (prev.database?.schemaVersion ?? 0)) {
        return "schemaVersion bumped";
    }
    return requiresReinstall(prev, next) ? "manifest changed materially" : "hot reload OK";
}

API Reference

  • requiresReinstall(prev: PluginManifest, next: PluginManifest): boolean
  • compareSemver(a: string, b: string): -1 | 0 | 1

Implementation Notes

The "added-items" detection uses Sets built from prev so the comparison is O(n) per field. dependsOn is compared via a key-union walk so a removed-but-then-readded dep with a different version is still caught. Removing items intentionally does not trigger a reinstall — design §4 defines this as a hot-reload-safe operation; the host driver drops the corresponding capability registrations in the installed → starting side-effect chain.