@devrouter/cli 0.6.7 → 0.6.8
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.
- package/dist/devrouter-lifecycle-worker.js +20 -9
- package/dist/devrouter.js +69 -21
- package/package.json +1 -1
- package/upgrade-prompts/0.6.8.md +53 -0
|
@@ -5592,7 +5592,7 @@ function loadRepoConfig(repoPath, read2 = (file) => import_node_fs16.default.rea
|
|
|
5592
5592
|
const config = parseRepoConfigSource(raw, configPath);
|
|
5593
5593
|
const requiredVersion = config.devrouter?.version;
|
|
5594
5594
|
if (requiredVersion && !hasWarnedVersionMismatch) {
|
|
5595
|
-
const cliVersion = true ? "0.6.
|
|
5595
|
+
const cliVersion = true ? "0.6.8" : "0.0.0-dev";
|
|
5596
5596
|
if (cliVersion !== "0.0.0-dev" && compareSemver2(requiredVersion, cliVersion) > 0) {
|
|
5597
5597
|
hasWarnedVersionMismatch = true;
|
|
5598
5598
|
process.stderr.write(
|
|
@@ -7979,7 +7979,7 @@ function advanceAppReplacementAttempt(identity2, authority, stage, newPrimaryId)
|
|
|
7979
7979
|
});
|
|
7980
7980
|
}
|
|
7981
7981
|
function installedCliVersion() {
|
|
7982
|
-
return true ? "0.6.
|
|
7982
|
+
return true ? "0.6.8" : "0.0.0-dev";
|
|
7983
7983
|
}
|
|
7984
7984
|
function compareCliVersions(left, right) {
|
|
7985
7985
|
const parts = (value) => value.split(".").map((part) => Number.parseInt(part, 10) || 0);
|
|
@@ -14468,7 +14468,9 @@ function reliabilityRecovery(reason2, repoPath, variant) {
|
|
|
14468
14468
|
`Run: devrouter ensure ${checkout}${variantOption} (still queued until capacity frees up)`
|
|
14469
14469
|
];
|
|
14470
14470
|
default:
|
|
14471
|
-
return [
|
|
14471
|
+
return [
|
|
14472
|
+
`Inspect: devrouter status --repo ${checkout} --json; wait for the current lifecycle owner to finish or cancel it before retrying.`
|
|
14473
|
+
];
|
|
14472
14474
|
}
|
|
14473
14475
|
}
|
|
14474
14476
|
function refusedManagedStart(result) {
|
|
@@ -14493,7 +14495,10 @@ function readReliabilityStatus(options) {
|
|
|
14493
14495
|
workspace: options.workspace ?? null,
|
|
14494
14496
|
provider
|
|
14495
14497
|
});
|
|
14496
|
-
} catch {
|
|
14498
|
+
} catch (error) {
|
|
14499
|
+
options.drift.push(
|
|
14500
|
+
error instanceof ReliabilityJournalError ? error.cause : "journal-unreadable"
|
|
14501
|
+
);
|
|
14497
14502
|
return void 0;
|
|
14498
14503
|
}
|
|
14499
14504
|
if (!record5) return void 0;
|
|
@@ -14913,6 +14918,12 @@ function collectManagedRuntimeStatus(options) {
|
|
|
14913
14918
|
if (inspection.activeProcesses.some((process2) => !desiredProcesses.includes(process2))) {
|
|
14914
14919
|
drift.push("one or more active processes are outside the selected profile");
|
|
14915
14920
|
}
|
|
14921
|
+
const reliability = readReliabilityStatus({
|
|
14922
|
+
repoPath: options.repoPath,
|
|
14923
|
+
variant: state?.variant,
|
|
14924
|
+
drift,
|
|
14925
|
+
...options.workspace !== void 0 ? { workspace: options.workspace } : {}
|
|
14926
|
+
});
|
|
14916
14927
|
const positivelyStopped = !inspection.primaryActive && Object.values(inspection.baseStatuses).every(isStoppedOrMissingResourceStatus) && Object.values(inspection.serviceStatuses).every(isStoppedOrMissingResourceStatus) && activeApps.length === 0;
|
|
14917
14928
|
const onlyDegradedIncident = state?.status === "degraded" && drift.length === 1;
|
|
14918
14929
|
const requiredServicesReady = desiredServices.every(
|
|
@@ -14930,11 +14941,11 @@ function collectManagedRuntimeStatus(options) {
|
|
|
14930
14941
|
services: inspection.activeServices,
|
|
14931
14942
|
processes: inspection.activeProcesses
|
|
14932
14943
|
};
|
|
14933
|
-
|
|
14934
|
-
|
|
14935
|
-
|
|
14936
|
-
|
|
14937
|
-
}
|
|
14944
|
+
if (status === "failed-transition" && reliability?.attention) {
|
|
14945
|
+
reliability.attention.recovery = [
|
|
14946
|
+
`Inspect: devrouter status --repo ${recoveryPath(options.repoPath)}; resolve the reported drift before retrying ensure.`
|
|
14947
|
+
];
|
|
14948
|
+
}
|
|
14938
14949
|
return {
|
|
14939
14950
|
mode: "managed",
|
|
14940
14951
|
status,
|
package/dist/devrouter.js
CHANGED
|
@@ -4944,7 +4944,7 @@ function loadRepoConfig(repoPath, read2 = (file) => import_node_fs8.default.read
|
|
|
4944
4944
|
const config = parseRepoConfigSource(raw, configPath);
|
|
4945
4945
|
const requiredVersion = config.devrouter?.version;
|
|
4946
4946
|
if (requiredVersion && !hasWarnedVersionMismatch) {
|
|
4947
|
-
const cliVersion = true ? "0.6.
|
|
4947
|
+
const cliVersion = true ? "0.6.8" : "0.0.0-dev";
|
|
4948
4948
|
if (cliVersion !== "0.0.0-dev" && compareSemver(requiredVersion, cliVersion) > 0) {
|
|
4949
4949
|
hasWarnedVersionMismatch = true;
|
|
4950
4950
|
process.stderr.write(
|
|
@@ -7266,7 +7266,7 @@ function validateAppReplacementAttempt(value, identity2) {
|
|
|
7266
7266
|
return attempt;
|
|
7267
7267
|
}
|
|
7268
7268
|
function installedCliVersion() {
|
|
7269
|
-
return true ? "0.6.
|
|
7269
|
+
return true ? "0.6.8" : "0.0.0-dev";
|
|
7270
7270
|
}
|
|
7271
7271
|
function compareCliVersions(left, right) {
|
|
7272
7272
|
const parts = (value) => value.split(".").map((part) => Number.parseInt(part, 10) || 0);
|
|
@@ -17876,6 +17876,29 @@ function recoveryPath(repoPath) {
|
|
|
17876
17876
|
if (/^[A-Za-z0-9_@%+=:,./-]+$/.test(repoPath)) return repoPath;
|
|
17877
17877
|
return `'${repoPath.replaceAll("'", "'\\''")}'`;
|
|
17878
17878
|
}
|
|
17879
|
+
function managedRuntimeRecovery(runtime, repoPath) {
|
|
17880
|
+
const checkout = recoveryPath(repoPath);
|
|
17881
|
+
const historyCause = runtime.drift.find((entry) => Object.hasOwn(HISTORY_CAUSES, entry));
|
|
17882
|
+
if (historyCause) {
|
|
17883
|
+
return [
|
|
17884
|
+
historyCause === "journal-writer-newer" ? "Preserve lifecycle history and use a matching or newer devrouter CLI before retrying lifecycle commands." : "Preserve lifecycle history and inspect its unreadable or unsafe evidence before retrying lifecycle commands.",
|
|
17885
|
+
`Inspect: devrouter status --repo ${checkout} --json`
|
|
17886
|
+
];
|
|
17887
|
+
}
|
|
17888
|
+
if (runtime.status === "failed-transition") {
|
|
17889
|
+
return [
|
|
17890
|
+
`Inspect: devrouter status --repo ${checkout}; resolve the reported drift before retrying ensure.`
|
|
17891
|
+
];
|
|
17892
|
+
}
|
|
17893
|
+
const attention = runtime.reliability?.attention;
|
|
17894
|
+
if (attention?.recovery.length) return attention.recovery;
|
|
17895
|
+
if (attention || runtime.reliability?.operation?.drained === false) {
|
|
17896
|
+
return [
|
|
17897
|
+
`Inspect: devrouter status --repo ${checkout} --json; wait for the current lifecycle owner to finish or cancel it before retrying.`
|
|
17898
|
+
];
|
|
17899
|
+
}
|
|
17900
|
+
return void 0;
|
|
17901
|
+
}
|
|
17879
17902
|
function reliabilityRecovery(reason2, repoPath, variant) {
|
|
17880
17903
|
const checkout = recoveryPath(repoPath);
|
|
17881
17904
|
const variantOption = variant && variant !== "default" ? ` --variant ${variant}` : "";
|
|
@@ -17908,7 +17931,9 @@ function reliabilityRecovery(reason2, repoPath, variant) {
|
|
|
17908
17931
|
`Run: devrouter ensure ${checkout}${variantOption} (still queued until capacity frees up)`
|
|
17909
17932
|
];
|
|
17910
17933
|
default:
|
|
17911
|
-
return [
|
|
17934
|
+
return [
|
|
17935
|
+
`Inspect: devrouter status --repo ${checkout} --json; wait for the current lifecycle owner to finish or cancel it before retrying.`
|
|
17936
|
+
];
|
|
17912
17937
|
}
|
|
17913
17938
|
}
|
|
17914
17939
|
function refusedManagedStart(result) {
|
|
@@ -17933,7 +17958,10 @@ function readReliabilityStatus(options) {
|
|
|
17933
17958
|
workspace: options.workspace ?? null,
|
|
17934
17959
|
provider
|
|
17935
17960
|
});
|
|
17936
|
-
} catch {
|
|
17961
|
+
} catch (error) {
|
|
17962
|
+
options.drift.push(
|
|
17963
|
+
error instanceof ReliabilityJournalError ? error.cause : "journal-unreadable"
|
|
17964
|
+
);
|
|
17937
17965
|
return void 0;
|
|
17938
17966
|
}
|
|
17939
17967
|
if (!record6) return void 0;
|
|
@@ -18348,6 +18376,12 @@ function collectManagedRuntimeStatus(options) {
|
|
|
18348
18376
|
if (inspection.activeProcesses.some((process2) => !desiredProcesses.includes(process2))) {
|
|
18349
18377
|
drift.push("one or more active processes are outside the selected profile");
|
|
18350
18378
|
}
|
|
18379
|
+
const reliability = readReliabilityStatus({
|
|
18380
|
+
repoPath: options.repoPath,
|
|
18381
|
+
variant: state?.variant,
|
|
18382
|
+
drift,
|
|
18383
|
+
...options.workspace !== void 0 ? { workspace: options.workspace } : {}
|
|
18384
|
+
});
|
|
18351
18385
|
const positivelyStopped = !inspection.primaryActive && Object.values(inspection.baseStatuses).every(isStoppedOrMissingResourceStatus) && Object.values(inspection.serviceStatuses).every(isStoppedOrMissingResourceStatus) && activeApps.length === 0;
|
|
18352
18386
|
const onlyDegradedIncident = state?.status === "degraded" && drift.length === 1;
|
|
18353
18387
|
const requiredServicesReady = desiredServices.every(
|
|
@@ -18365,11 +18399,11 @@ function collectManagedRuntimeStatus(options) {
|
|
|
18365
18399
|
services: inspection.activeServices,
|
|
18366
18400
|
processes: inspection.activeProcesses
|
|
18367
18401
|
};
|
|
18368
|
-
|
|
18369
|
-
|
|
18370
|
-
|
|
18371
|
-
|
|
18372
|
-
}
|
|
18402
|
+
if (status === "failed-transition" && reliability?.attention) {
|
|
18403
|
+
reliability.attention.recovery = [
|
|
18404
|
+
`Inspect: devrouter status --repo ${recoveryPath(options.repoPath)}; resolve the reported drift before retrying ensure.`
|
|
18405
|
+
];
|
|
18406
|
+
}
|
|
18373
18407
|
return {
|
|
18374
18408
|
mode: "managed",
|
|
18375
18409
|
status,
|
|
@@ -18397,7 +18431,7 @@ function collectManagedRuntimeStatus(options) {
|
|
|
18397
18431
|
...state?.transitionPhase ? { transitionPhase: state.transitionPhase } : {}
|
|
18398
18432
|
};
|
|
18399
18433
|
}
|
|
18400
|
-
var EMPTY_RESOURCES;
|
|
18434
|
+
var HISTORY_CAUSES, EMPTY_RESOURCES;
|
|
18401
18435
|
var init_managed_runtime_status = __esm({
|
|
18402
18436
|
"src/core/managed-runtime-status.ts"() {
|
|
18403
18437
|
"use strict";
|
|
@@ -18413,6 +18447,20 @@ var init_managed_runtime_status = __esm({
|
|
|
18413
18447
|
init_reliability_output();
|
|
18414
18448
|
init_workspace();
|
|
18415
18449
|
init_workspace_runtime();
|
|
18450
|
+
HISTORY_CAUSES = {
|
|
18451
|
+
"journal-directory-unreadable": true,
|
|
18452
|
+
"journal-directory-unsafe": true,
|
|
18453
|
+
"journal-entry-unsupported": true,
|
|
18454
|
+
"journal-enumeration-limit": true,
|
|
18455
|
+
"journal-enumeration-timeout": true,
|
|
18456
|
+
"journal-unreadable": true,
|
|
18457
|
+
"journal-entry-unsafe": true,
|
|
18458
|
+
"journal-invalid": true,
|
|
18459
|
+
"journal-writer-newer": true,
|
|
18460
|
+
"journal-identity-mismatch": true,
|
|
18461
|
+
"journal-unstable": true,
|
|
18462
|
+
"journal-enumeration-failed": true
|
|
18463
|
+
};
|
|
18416
18464
|
EMPTY_RESOURCES = {
|
|
18417
18465
|
apps: [],
|
|
18418
18466
|
services: [],
|
|
@@ -25492,17 +25540,15 @@ async function collectRouterStatus(repoPath) {
|
|
|
25492
25540
|
);
|
|
25493
25541
|
} else if (repo?.valid) {
|
|
25494
25542
|
const repoArgument = `'${repo.path.replaceAll("'", `'\\''`)}'`;
|
|
25495
|
-
const
|
|
25543
|
+
const recovery = repo.managedRuntime ? managedRuntimeRecovery(repo.managedRuntime, repo.path) : void 0;
|
|
25496
25544
|
if (repo.managedRuntime?.mode === "managed") {
|
|
25497
|
-
nextSteps.push(
|
|
25498
|
-
failedTransition ? `Inspect: devrouter status --repo ${repoArgument}; resolve the reported drift before retrying ensure.` : `Run: devrouter ensure ${repoArgument}`
|
|
25499
|
-
);
|
|
25545
|
+
nextSteps.push(...recovery ?? [`Run: devrouter ensure ${repoArgument}`]);
|
|
25500
25546
|
} else {
|
|
25501
25547
|
nextSteps.push(`Run: dev app ls --repo ${repo.path}`);
|
|
25502
25548
|
nextSteps.push("Run: dev app run <name> --repo <path> --yes");
|
|
25503
25549
|
}
|
|
25504
25550
|
nextSteps.push("Run: dev ls");
|
|
25505
|
-
if (!
|
|
25551
|
+
if (!recovery && repo.managedRuntime?.mountNesting?.status === "unwound") {
|
|
25506
25552
|
nextSteps.push(
|
|
25507
25553
|
`Run: devrouter stop ${repoArgument} and then devrouter ensure ${repoArgument} to re-apply the unwound nested mount`
|
|
25508
25554
|
);
|
|
@@ -25946,7 +25992,7 @@ function probeInstalledCliVersion(executable) {
|
|
|
25946
25992
|
}
|
|
25947
25993
|
function buildCliPathCheck(options = {}) {
|
|
25948
25994
|
const id5 = "global.cli-path";
|
|
25949
|
-
const runningVersion = options.runningVersion ?? (true ? "0.6.
|
|
25995
|
+
const runningVersion = options.runningVersion ?? (true ? "0.6.8" : "0.0.0-dev");
|
|
25950
25996
|
if (runningVersion === "0.0.0-dev") {
|
|
25951
25997
|
return {
|
|
25952
25998
|
id: id5,
|
|
@@ -26768,6 +26814,7 @@ async function buildDoctorReport(options = {}) {
|
|
|
26768
26814
|
});
|
|
26769
26815
|
if (repo.managedRuntime) {
|
|
26770
26816
|
const managedRuntime = repo.managedRuntime;
|
|
26817
|
+
const recovery = managedRuntimeRecovery(managedRuntime, repo.path);
|
|
26771
26818
|
const repoArgument = `'${repo.path.replaceAll("'", `'\\''`)}'`;
|
|
26772
26819
|
const variantOption = managedRuntime.activeVariant && managedRuntime.activeVariant !== "default" ? ` --variant ${managedRuntime.activeVariant}` : "";
|
|
26773
26820
|
const level = managedRuntime.mode === "legacy" || managedRuntime.status === "ready" ? "ok" : managedRuntime.status === "starting" || managedRuntime.status === "stopped" ? "warn" : "error";
|
|
@@ -26782,7 +26829,7 @@ async function buildDoctorReport(options = {}) {
|
|
|
26782
26829
|
level,
|
|
26783
26830
|
summary: summary2,
|
|
26784
26831
|
...details ? { details } : {},
|
|
26785
|
-
suggestion: managedRuntime.mode === "legacy" ? void 0 :
|
|
26832
|
+
suggestion: managedRuntime.mode === "legacy" ? void 0 : recovery ? recovery.join(" ") : managedRuntime.status === "ready" ? void 0 : `Run: devrouter ensure ${repoArgument}${variantOption}`
|
|
26786
26833
|
});
|
|
26787
26834
|
const mountNesting = managedRuntime.mountNesting;
|
|
26788
26835
|
if (mountNesting && mountNesting.status !== "not-applicable") {
|
|
@@ -26800,7 +26847,7 @@ async function buildDoctorReport(options = {}) {
|
|
|
26800
26847
|
(entry) => `unwound=${entry.destination} (source ${entry.source} inside ${entry.nestedWithin})`
|
|
26801
26848
|
)
|
|
26802
26849
|
].join("; "),
|
|
26803
|
-
suggestion:
|
|
26850
|
+
suggestion: recovery ? void 0 : `Run: devrouter stop ${repoArgument} and then devrouter ensure ${repoArgument}${variantOption} to restart the exact container, which re-applies the nested mount.`
|
|
26804
26851
|
});
|
|
26805
26852
|
} else if (mountNesting.status === "unverified") {
|
|
26806
26853
|
addCheck(checks, {
|
|
@@ -26811,7 +26858,7 @@ async function buildDoctorReport(options = {}) {
|
|
|
26811
26858
|
`container=${container}`,
|
|
26812
26859
|
`reason=${mountNesting.reason ?? "unknown"}`
|
|
26813
26860
|
].join("; "),
|
|
26814
|
-
suggestion: `Run: devrouter exec ${repoArgument} -- cat /proc/self/mountinfo to read the container's own mount table.`
|
|
26861
|
+
suggestion: recovery ? void 0 : `Run: devrouter exec ${repoArgument} -- cat /proc/self/mountinfo to read the container's own mount table.`
|
|
26815
26862
|
});
|
|
26816
26863
|
} else {
|
|
26817
26864
|
addCheck(checks, {
|
|
@@ -26845,7 +26892,7 @@ async function buildDoctorReport(options = {}) {
|
|
|
26845
26892
|
suggestion: `Remedy ${expansionNotice.remedy.code}: set a named default profile other than '${expansionNotice.profile}'${remedyCandidates}.`
|
|
26846
26893
|
});
|
|
26847
26894
|
}
|
|
26848
|
-
const cliVersion = true ? "0.6.
|
|
26895
|
+
const cliVersion = true ? "0.6.8" : "0.0.0-dev";
|
|
26849
26896
|
const configVersion = config.devrouter?.version;
|
|
26850
26897
|
const installedKnown = cliVersion !== "0.0.0-dev";
|
|
26851
26898
|
const versionComparison = installedKnown && configVersion ? compareSemver(configVersion, cliVersion) : void 0;
|
|
@@ -27081,6 +27128,7 @@ var init_doctor = __esm({
|
|
|
27081
27128
|
init_capacity_store();
|
|
27082
27129
|
init_docker();
|
|
27083
27130
|
init_host_routes();
|
|
27131
|
+
init_managed_runtime_status();
|
|
27084
27132
|
init_reliability_operation_store();
|
|
27085
27133
|
init_repo_config();
|
|
27086
27134
|
init_devcontainer_diagnostics();
|
|
@@ -42524,7 +42572,7 @@ var init_version = __esm({
|
|
|
42524
42572
|
|
|
42525
42573
|
// src/cli.ts
|
|
42526
42574
|
var import_commander = require("commander");
|
|
42527
|
-
var CLI_VERSION = true ? "0.6.
|
|
42575
|
+
var CLI_VERSION = true ? "0.6.8" : "0.0.0-dev";
|
|
42528
42576
|
var VERSION_FLAGS = /* @__PURE__ */ new Set(["-V", "--version"]);
|
|
42529
42577
|
function withErrorHandling(action2) {
|
|
42530
42578
|
return async (...args) => {
|
package/package.json
CHANGED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# Upgrade to devrouter 0.6.8
|
|
2
|
+
|
|
3
|
+
Managed status reports unreadable lifecycle history as drift. Newer-writer history
|
|
4
|
+
requires a matching or newer reader while preserving the journal; other unreadable
|
|
5
|
+
history requires inspection. Status and doctor prioritize that remedy, failed
|
|
6
|
+
transition inspection, durable operation attention and live-owner guidance before
|
|
7
|
+
ordinary startup or nested-mount restart advice. Ordinary readable-history drift
|
|
8
|
+
retains normal ensure guidance. No configuration schema, command surface,
|
|
9
|
+
dependency, ownership or admission guard changes are introduced.
|
|
10
|
+
|
|
11
|
+
## Task
|
|
12
|
+
|
|
13
|
+
Within approved installation/adaptation scope, select the integrity-verified exact
|
|
14
|
+
package, update `devrouter.version` in `.devrouter.yml` and refresh existing agent
|
|
15
|
+
guidance through `devrouter repo agents`. Verify selected/PATH executables and
|
|
16
|
+
concrete package, source, harness and controller pins sharing the affected journal
|
|
17
|
+
namespace or mixed caller chain. Owners confirm compatible adoption or explicit
|
|
18
|
+
non-use; a PATH listing alone does not prove participation. Independent remote
|
|
19
|
+
state is a separate adoption boundary. Unknown affected participation holds
|
|
20
|
+
activation. Do not alter dormant harness checks or replay consumed attempts.
|
|
21
|
+
|
|
22
|
+
A new reader accepts older supported history. Older 0.6.7 readers refuse actual
|
|
23
|
+
0.6.8-written journals through direct read, update, enumeration and admission even
|
|
24
|
+
without a schema change. Installing alone writes no lifecycle journal. Before
|
|
25
|
+
any separately authorized new lifecycle write, coordinate affected clients; keep
|
|
26
|
+
inactive older pins unused until compatibility is established. After newer writes,
|
|
27
|
+
use a matching or newer CLI and preserve all journal bytes and durable
|
|
28
|
+
initialization/replacement receipts. Never erase, downgrade or replay history to
|
|
29
|
+
bypass refusal or rearm an attempt.
|
|
30
|
+
|
|
31
|
+
Publication, installation and notices authorize no consumer startup, repair,
|
|
32
|
+
replacement, initialization, reset or extra attempt. Inspection is read-only
|
|
33
|
+
and does not establish application readiness. A live owner must finish or be
|
|
34
|
+
explicitly cancelled within its own authority before another operation.
|
|
35
|
+
|
|
36
|
+
## Validation
|
|
37
|
+
|
|
38
|
+
1. Verify registry integrity, selected package/member bytes and executable
|
|
39
|
+
versions. Run native checks for actual consumer edits; preserve journals and
|
|
40
|
+
receipts when only selecting a CLI.
|
|
41
|
+
2. Use `devrouter status --repo <checkout> --json` and existing diagnostic evidence
|
|
42
|
+
within authorized inspection scope. Check the reported reason and actual
|
|
43
|
+
next-command preconditions; do not infer permission from generic advice.
|
|
44
|
+
3. Any separately authorized runtime work ends with canonical stop and exact
|
|
45
|
+
worker, provider, container and route proof unless the user keeps it running.
|
|
46
|
+
|
|
47
|
+
## Report
|
|
48
|
+
|
|
49
|
+
Report selected package/executable identities, affected-client adoption or holds,
|
|
50
|
+
remaining unknowns and relevant checks. Any consumer recovery claim needs its
|
|
51
|
+
actual useful-work, retained-data, neighbour and stopped-terminal evidence.
|
|
52
|
+
Synthetic qualification and package identity alone do not prove receiving-host
|
|
53
|
+
adoption, consumer recovery or retained-maintenance acceptance.
|