@serve.zone/interfaces 32.16.0 → 32.18.0

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/changelog.md CHANGED
@@ -1,5 +1,65 @@
1
1
  # Changelog
2
2
 
3
+ ## 2026-09-22 - 32.18.0
4
+
5
+ ### Features
6
+
7
+ - Answer a refused Spark legacy-retirement statement on the wire. The observation that carried it
8
+ stays accepted — a node's liveness and census are true whatever its released runtime states, and
9
+ the cluster's target set depends on their freshness — while the accepted receipt answers the
10
+ statement itself through the new optional member `fleetCutoverLegacyRetirement`, a
11
+ `TSparkLegacyRetirementOutcome` that is `accepted` at the generation both node-owned records
12
+ advanced to, `restated` for the replay that renewed nothing, or `refused` by one of the
13
+ contract's own refusal names and never retryable, because resending one exact statement cannot
14
+ change the answer. `validateSparkSwarmObservationResponse` binds answer to statement in both
15
+ directions: a receipt that answers a statement the observation never made, or leaves one it did
16
+ make unanswered, is refused, and a rejected receipt carries no outcome at all.
17
+ `evidence-refused` joins the observation rejection codes as the one non-retryable answer about
18
+ content rather than sequencing — an evidence member a server refuses for this body and every
19
+ resend of it — leaving a server-side condition a later attempt could pass as `acceptance-race`.
20
+ `sparkLegacyConfigurationDispositions` and `TSparkLegacyConfigurationDisposition` are exported
21
+ beside the runtime modes, and the release-version grammar (`IReleaseVersion`,
22
+ `parseReleaseVersion`, `isReleaseVersion`, `compareReleaseVersions`,
23
+ `maximumReleaseVersionLength`) moves from `private/` into `data/`, so a policy that orders two
24
+ released versions reads the package's own comparison instead of splitting strings of its own.
25
+ Every addition is additive; no existing shape narrows.
26
+
27
+ ### Maintenance
28
+
29
+ - Pin pnpm 12.4.2 as the release package manager.
30
+
31
+ ## 2026-09-22 - 32.17.0
32
+
33
+ ### Features
34
+
35
+ - Add generation-bearing cluster relay credential authority, its accepted registration record and
36
+ the legacy shared-credential retirement receipt. Cloudly can mint and rotate a relay credential
37
+ whose exact generation authenticates one socket, answer an accepted registration that names that
38
+ generation and the record it wrote, and accept an explicit retirement of the pre-relay shared
39
+ cluster authority only after a replacement relay has registered under the replacement credential
40
+ and is live. Rotation has no overlap window: a superseded generation ends the relay's custody
41
+ through the new `relay-credential-generation-stale` refusal. The credential authenticates the
42
+ same cluster control-plane session as before; the gain is generation and revocability, not a
43
+ narrower scope. No shape carries bearer, hash or key material; the bearer travels only as an
44
+ immutable encrypted secret version reference. `IRegisterClusterRelayResponse` gains `credential`
45
+ and `acceptedRegistration` as required members, so its one producer, Cloudly, must supply them
46
+ to compile; that break is the intended fail-closed.
47
+ - Add the Spark-owned producers the Coreflow retirement evidence still lacked. A Swarm-era Spark
48
+ states, on the observation it already posts, the verified bundle installed on its host and the
49
+ unit that will boot it, the released owning mode it refuses, and its released configuration
50
+ source by digest, owner generation and disposition. There is no route for it: the evidence
51
+ requires the relay's node observation and the Spark observation to be the identical accepted
52
+ reference, so the facts travel on the census observation itself. Cloudly accepts them into two
53
+ revisioned node-owned records whose references complete `legacy.oldModeRefusal` and
54
+ `legacy.configurationCas`, and whose content it flattens into the evidence's Spark bundle, unit
55
+ and legacy-source members; `IFleetCutoverCoreflowRetirementEvidence` itself is unchanged. The new
56
+ member is optional, names no node, carries no proof boolean and can represent no decoded member
57
+ of the released configuration file, which holds that node's bearer and jump code. An omitted
58
+ member advances nothing, so a retirement is honest through the freshness of the observation its
59
+ records name, not through their existence. Cloudly reads this minor before Spark writes it:
60
+ every observation validator is exact-key, so a server that does not know the member refuses the
61
+ whole observation instead of ignoring it.
62
+
3
63
  ## 2026-09-20 - 32.16.0
4
64
 
5
65
  ### Features
@@ -3,7 +3,7 @@
3
3
  */
4
4
  export const commitinfo = {
5
5
  name: '@serve.zone/interfaces',
6
- version: '32.16.0',
6
+ version: '32.18.0',
7
7
  description: 'Shared TypeScript interfaces and TypedRequest contracts for the serve.zone ecosystem.'
8
8
  };
9
9
  //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiMDBfY29tbWl0aW5mb19kYXRhLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vdHMvMDBfY29tbWl0aW5mb19kYXRhLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOztHQUVHO0FBQ0gsTUFBTSxDQUFDLE1BQU0sVUFBVSxHQUFHO0lBQ3hCLElBQUksRUFBRSx3QkFBd0I7SUFDOUIsT0FBTyxFQUFFLFNBQVM7SUFDbEIsV0FBVyxFQUFFLHVGQUF1RjtDQUNyRyxDQUFBIn0=
@@ -1,5 +1,8 @@
1
1
  import * as plugins from '../plugins.js';
2
2
  import type { IClusterNode } from './clusternode.js';
3
+ import type { IFleetCutoverAcceptedEvidenceReference } from './fleetcutover.js';
4
+ import type { TSha256Digest } from './immutableimage.js';
5
+ import type { IRuntimeAuthorityReference } from './runtimeassignment.js';
3
6
  import { type IProtocolOffer } from '../protocol.js';
4
7
  export interface ICluster {
5
8
  id: string;
@@ -119,6 +122,16 @@ export interface IRegisterClusterRelayResponse {
119
122
  origin: string;
120
123
  /** Cloudly's own offer, so an accepted relay judges the session it just registered into. */
121
124
  protocol: IProtocolOffer;
125
+ /**
126
+ * The relay credential generation Cloudly authenticated this socket as.
127
+ *
128
+ * Read from Cloudly's own record and never from the registration: a relay that stated its own
129
+ * generation would be asserting its own rank. It is how a relay learns the exact generation its
130
+ * readiness is bound to.
131
+ */
132
+ credential: IRuntimeAuthorityReference;
133
+ /** The accepted registration record this answer wrote, as a retirement record later cites it. */
134
+ acceptedRegistration: IFleetCutoverAcceptedEvidenceReference;
122
135
  }
123
136
  /**
124
137
  * The registration refusals that end a relay's custody of its cluster.
@@ -129,7 +142,7 @@ export interface IRegisterClusterRelayResponse {
129
142
  * says it could not verify the relay, a malformed or conflicting registration, an internal error —
130
143
  * state nothing about dispatch and are not listed here.
131
144
  */
132
- export declare const clusterRelayUndispatchedRefusals: readonly ["relay-cluster-not-enabled", "relay-node-foreign", "relay-sequence-not-advancing"];
145
+ export declare const clusterRelayUndispatchedRefusals: readonly ["relay-cluster-not-enabled", "relay-node-foreign", "relay-sequence-not-advancing", "relay-credential-generation-stale"];
133
146
  /** One of the reasons Cloudly states that it does not dispatch to a relay. */
134
147
  export type TClusterRelayUndispatchedRefusal = typeof clusterRelayUndispatchedRefusals[number];
135
148
  /**
@@ -165,14 +178,12 @@ export declare const validateClusterRelayVpnHub: (valueArg: unknown, pathArg?: s
165
178
  */
166
179
  export declare const validateRegisterClusterRelayRequest: (valueArg: unknown, pathArg?: string) => string[];
167
180
  /**
168
- * One cluster's relay as Cloudly serves it to an administrator.
181
+ * What one accepted relay registration states about the relay that sent it.
169
182
  *
170
- * This is the read shape, not the registration a relay sends: `IRegisterClusterRelayRequest` is
171
- * what the relay puts on the wire, and this is what Cloudly answers with after it accepted one.
172
- * `clusterId` names the cluster the relay serves, and `acceptedAt` is Cloudly's own acceptance
173
- * time, which is what orders two registrations of one cluster.
183
+ * The part the served read shape and the accepted record share: no record identity, no digest and
184
+ * no liveness, so neither shape restates the other's fields.
174
185
  */
175
- export interface IClusterRelayRegistration {
186
+ export interface IClusterRelayRegistrationFacts {
176
187
  clusterId: string;
177
188
  nodeId: string;
178
189
  listenAddress: string;
@@ -180,6 +191,16 @@ export interface IClusterRelayRegistration {
180
191
  version: string;
181
192
  registrationSequence: number;
182
193
  acceptedAt: number;
194
+ }
195
+ /**
196
+ * One cluster's relay as Cloudly serves it to an administrator.
197
+ *
198
+ * This is the read shape, not the registration a relay sends: `IRegisterClusterRelayRequest` is
199
+ * what the relay puts on the wire, and this is what Cloudly answers with after it accepted one.
200
+ * `clusterId` names the cluster the relay serves, and `acceptedAt` is Cloudly's own acceptance
201
+ * time, which is what orders two registrations of one cluster.
202
+ */
203
+ export interface IClusterRelayRegistration extends IClusterRelayRegistrationFacts {
183
204
  /**
184
205
  * Whether a verified socket carries this relay at this instant.
185
206
  *
@@ -197,6 +218,28 @@ export interface IClusterRelayRegistration {
197
218
  * that passes here has claimed nothing.
198
219
  */
199
220
  export declare const validateClusterRelayRegistration: (valueArg: unknown, pathArg?: string) => string[];
221
+ /**
222
+ * Cloudly's accepted registration record: the thing an evidence reference names.
223
+ *
224
+ * `credential` is the exact relay credential generation the registering socket authenticated as,
225
+ * so a reader can tell a registration made under the current credential from one made under a
226
+ * superseded one. Liveness is deliberately absent: a live socket is not a fact a record can hold,
227
+ * and a digest that covered it would change without anything having been registered.
228
+ */
229
+ export interface IClusterRelayAcceptedRegistration extends IClusterRelayRegistrationFacts {
230
+ id: string;
231
+ /** Advances by one per accepted registration, so a reference to a superseded one fails closed. */
232
+ generation: number;
233
+ credential: IRuntimeAuthorityReference;
234
+ digest: TSha256Digest;
235
+ }
236
+ export declare const clusterRelayContract: Readonly<{
237
+ readonly acceptedRegistrationDigestDomain: "serve.zone/cluster-relay-accepted-registration";
238
+ }>;
239
+ /** Structural copy only; whether the record is the cluster's current one is Cloudly's to decide. */
240
+ export declare const snapshotClusterRelayAcceptedRegistration: (valueArg: unknown) => IClusterRelayAcceptedRegistration;
241
+ export declare const computeClusterRelayAcceptedRegistrationDigest: (valueArg: unknown) => Promise<TSha256Digest>;
242
+ export declare const validateClusterRelayAcceptedRegistration: (valueArg: unknown) => Promise<string[]>;
200
243
  /**
201
244
  * The name the relay's certificate is issued for, and the A record Cloudly
202
245
  * owns for it. Derived from the origin so every consumer derives it
@@ -4,7 +4,7 @@ import { isPlausibleUnicastIpv4 } from '../private/ipv4.js';
4
4
  import { validateProtocolOfferOn } from '../protocol.js';
5
5
  import { hasExactKeys } from '../private/dataproperties.js';
6
6
  import { isClusterNodeId } from '../private/nodeidentifier.js';
7
- import { networkNoiseKey } from '../private/networkcontract.js';
7
+ import { captureNetwork, networkCounter, networkDigest, networkHash, networkId, networkNoiseKey, networkRecord, networkReference, } from '../private/networkcontract.js';
8
8
  /**
9
9
  * The registration refusals that end a relay's custody of its cluster.
10
10
  *
@@ -21,6 +21,13 @@ export const clusterRelayUndispatchedRefusals = Object.freeze([
21
21
  'relay-node-foreign',
22
22
  /** A registration of this relay identity at the same or a higher sequence is already recorded. */
23
23
  'relay-sequence-not-advancing',
24
+ /**
25
+ * The credential this socket authenticated with is no longer the cluster's current generation.
26
+ *
27
+ * Rotation has no overlap, so another relay may already hold the current one: this relay is not
28
+ * the one Cloudly dispatches to, which `relay-identity-unverified` never states.
29
+ */
30
+ 'relay-credential-generation-stale',
24
31
  ]);
25
32
  const maximumClusterRelayOriginLength = 2048;
26
33
  const maximumClusterRelayVersionLength = 64;
@@ -170,6 +177,20 @@ export const validateRegisterClusterRelayRequest = (valueArg, pathArg = 'cluster
170
177
  errors.push(...validateClusterRelayNonNegativeInteger(valueArg.registrationSequence, `${pathArg} registrationSequence`));
171
178
  return errors;
172
179
  };
180
+ const clusterRelayRegistrationFactKeys = [
181
+ 'clusterId', 'nodeId', 'listenAddress', 'listenPort', 'version', 'registrationSequence',
182
+ 'acceptedAt',
183
+ ];
184
+ /** The one format rule of every registration fact, whichever shape carries it. */
185
+ const validateClusterRelayRegistrationFacts = (valueArg, pathArg) => [
186
+ ...validateClusterRelayIdentifier(valueArg.clusterId, `${pathArg} clusterId`),
187
+ ...validateClusterRelayIdentifier(valueArg.nodeId, `${pathArg} nodeId`),
188
+ ...validateClusterRelayListenAddress(valueArg.listenAddress, `${pathArg} listenAddress`),
189
+ ...validateClusterRelayListenPort(valueArg.listenPort, `${pathArg} listenPort`),
190
+ ...validateClusterRelayVersion(valueArg.version, `${pathArg} version`),
191
+ ...validateClusterRelayNonNegativeInteger(valueArg.registrationSequence, `${pathArg} registrationSequence`),
192
+ ...validateClusterRelayNonNegativeInteger(valueArg.acceptedAt, `${pathArg} acceptedAt`),
193
+ ];
173
194
  /**
174
195
  * Validates one served relay registration and names every reason it is refused.
175
196
  *
@@ -178,21 +199,61 @@ export const validateRegisterClusterRelayRequest = (valueArg, pathArg = 'cluster
178
199
  * that passes here has claimed nothing.
179
200
  */
180
201
  export const validateClusterRelayRegistration = (valueArg, pathArg = 'cluster relay registration') => {
181
- if (!isRecord(valueArg) || !hasExactKeys(valueArg, ['clusterId', 'nodeId', 'listenAddress',
182
- 'listenPort', 'version', 'registrationSequence', 'acceptedAt', 'live'])) {
202
+ if (!isRecord(valueArg)
203
+ || !hasExactKeys(valueArg, [...clusterRelayRegistrationFactKeys, 'live'])) {
183
204
  return [`${pathArg} must use its exact schema`];
184
205
  }
185
206
  return [
186
- ...validateClusterRelayIdentifier(valueArg.clusterId, `${pathArg} clusterId`),
187
- ...validateClusterRelayIdentifier(valueArg.nodeId, `${pathArg} nodeId`),
188
- ...validateClusterRelayListenAddress(valueArg.listenAddress, `${pathArg} listenAddress`),
189
- ...validateClusterRelayListenPort(valueArg.listenPort, `${pathArg} listenPort`),
190
- ...validateClusterRelayVersion(valueArg.version, `${pathArg} version`),
191
- ...validateClusterRelayNonNegativeInteger(valueArg.registrationSequence, `${pathArg} registrationSequence`),
192
- ...validateClusterRelayNonNegativeInteger(valueArg.acceptedAt, `${pathArg} acceptedAt`),
207
+ ...validateClusterRelayRegistrationFacts(valueArg, pathArg),
193
208
  ...(typeof valueArg.live === 'boolean' ? [] : [`${pathArg} live must be a boolean`]),
194
209
  ];
195
210
  };
211
+ export const clusterRelayContract = Object.freeze({
212
+ acceptedRegistrationDigestDomain: 'serve.zone/cluster-relay-accepted-registration',
213
+ });
214
+ const failClusterRelayRecord = () => {
215
+ throw new Error('Cluster relay contract rejected.');
216
+ };
217
+ /** The facts of an already exact-keyed record, refused unless each passes its one format rule. */
218
+ const readClusterRelayRegistrationFacts = (valueArg) => {
219
+ if (validateClusterRelayRegistrationFacts(valueArg, 'cluster relay registration').length > 0) {
220
+ failClusterRelayRecord();
221
+ }
222
+ const { clusterId, nodeId, listenAddress, listenPort, version, registrationSequence, acceptedAt, } = valueArg;
223
+ // Each member passed its format rule above, which is what the assertion states.
224
+ return {
225
+ clusterId, nodeId, listenAddress, listenPort, version, registrationSequence, acceptedAt,
226
+ };
227
+ };
228
+ /** Structural copy only; whether the record is the cluster's current one is Cloudly's to decide. */
229
+ export const snapshotClusterRelayAcceptedRegistration = (valueArg) => {
230
+ try {
231
+ const value = networkRecord(captureNetwork(valueArg), [
232
+ ...clusterRelayRegistrationFactKeys, 'id', 'generation', 'credential', 'digest',
233
+ ]);
234
+ return {
235
+ ...readClusterRelayRegistrationFacts(value),
236
+ id: networkId(value.id),
237
+ generation: networkCounter(value.generation),
238
+ credential: networkReference(value.credential),
239
+ digest: networkDigest(value.digest),
240
+ };
241
+ }
242
+ catch {
243
+ return failClusterRelayRecord();
244
+ }
245
+ };
246
+ export const computeClusterRelayAcceptedRegistrationDigest = async (valueArg) => networkHash(clusterRelayContract.acceptedRegistrationDigestDomain, snapshotClusterRelayAcceptedRegistration(valueArg));
247
+ export const validateClusterRelayAcceptedRegistration = async (valueArg) => {
248
+ try {
249
+ const value = snapshotClusterRelayAcceptedRegistration(valueArg);
250
+ return value.digest === await computeClusterRelayAcceptedRegistrationDigest(value)
251
+ ? [] : ['cluster relay accepted registration digest does not match'];
252
+ }
253
+ catch {
254
+ return ['cluster relay accepted registration must use its exact canonical schema'];
255
+ }
256
+ };
196
257
  /**
197
258
  * The name the relay's certificate is issued for, and the A record Cloudly
198
259
  * owns for it. Derived from the origin so every consumer derives it
@@ -206,4 +267,4 @@ export const clusterRelayCertificateDomainName = (relayArg) => {
206
267
  }
207
268
  return new URL(relayArg.origin).hostname;
208
269
  };
209
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2x1c3Rlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3RzL2RhdGEvY2x1c3Rlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEtBQUssT0FBTyxNQUFNLGVBQWUsQ0FBQztBQUV6QyxPQUFPLEVBQTRCLE1BQU0sbUJBQW1CLENBQUM7QUFFN0QsT0FBTyxFQUFFLHNCQUFzQixFQUFFLE1BQU0sb0JBQW9CLENBQUM7QUFDNUQsT0FBTyxFQUFFLHVCQUF1QixFQUF1QixNQUFNLGdCQUFnQixDQUFDO0FBQzlFLE9BQU8sRUFBRSxZQUFZLEVBQUUsTUFBTSw4QkFBOEIsQ0FBQztBQUM1RCxPQUFPLEVBQUUsZUFBZSxFQUFFLE1BQU0sOEJBQThCLENBQUM7QUFDL0QsT0FBTyxFQUFFLGVBQWUsRUFBRSxNQUFNLCtCQUErQixDQUFDO0FBcUloRTs7Ozs7Ozs7R0FRRztBQUNILE1BQU0sQ0FBQyxNQUFNLGdDQUFnQyxHQUFHLE1BQU0sQ0FBQyxNQUFNLENBQUM7SUFDNUQsK0VBQStFO0lBQy9FLDJCQUEyQjtJQUMzQiwyRkFBMkY7SUFDM0Ysb0JBQW9CO0lBQ3BCLGtHQUFrRztJQUNsRyw4QkFBOEI7Q0FDdEIsQ0FBQyxDQUFDO0FBS1osTUFBTSwrQkFBK0IsR0FBRyxJQUFJLENBQUM7QUFDN0MsTUFBTSxnQ0FBZ0MsR0FBRyxFQUFFLENBQUM7QUFFNUMsTUFBTSxRQUFRLEdBQUcsQ0FBQyxRQUFpQixFQUF1QyxFQUFFLENBQUMsQ0FDM0UsT0FBTyxDQUFDLFFBQVEsQ0FBQztPQUNkLE9BQU8sUUFBUSxLQUFLLFFBQVE7T0FDNUIsQ0FBQyxLQUFLLENBQUMsT0FBTyxDQUFDLFFBQVEsQ0FBQztPQUN4QixDQUFDLE1BQU0sQ0FBQyxjQUFjLENBQUMsUUFBUSxDQUFDLEtBQUssTUFBTSxDQUFDLFNBQVM7V0FDbkQsTUFBTSxDQUFDLGNBQWMsQ0FBQyxRQUFRLENBQUMsS0FBSyxJQUFJLENBQUMsQ0FDL0MsQ0FBQztBQUVGLE1B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
270
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2x1c3Rlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3RzL2RhdGEvY2x1c3Rlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEtBQUssT0FBTyxNQUFNLGVBQWUsQ0FBQztBQUV6QyxPQUFPLEVBQTRCLE1BQU0sbUJBQW1CLENBQUM7QUFLN0QsT0FBTyxFQUFFLHNCQUFzQixFQUFFLE1BQU0sb0JBQW9CLENBQUM7QUFDNUQsT0FBTyxFQUFFLHVCQUF1QixFQUF1QixNQUFNLGdCQUFnQixDQUFDO0FBQzlFLE9BQU8sRUFBRSxZQUFZLEVBQUUsTUFBTSw4QkFBOEIsQ0FBQztBQUM1RCxPQUFPLEVBQUUsZUFBZSxFQUFFLE1BQU0sOEJBQThCLENBQUM7QUFDL0QsT0FBTyxFQUNMLGNBQWMsRUFDZCxjQUFjLEVBQ2QsYUFBYSxFQUNiLFdBQVcsRUFDWCxTQUFTLEVBQ1QsZUFBZSxFQUNmLGFBQWEsRUFDYixnQkFBZ0IsR0FDakIsTUFBTSwrQkFBK0IsQ0FBQztBQStJdkM7Ozs7Ozs7O0dBUUc7QUFDSCxNQUFNLENBQUMsTUFBTSxnQ0FBZ0MsR0FBRyxNQUFNLENBQUMsTUFBTSxDQUFDO0lBQzVELCtFQUErRTtJQUMvRSwyQkFBMkI7SUFDM0IsMkZBQTJGO0lBQzNGLG9CQUFvQjtJQUNwQixrR0FBa0c7SUFDbEcsOEJBQThCO0lBQzlCOzs7OztPQUtHO0lBQ0gsbUNBQW1DO0NBQzNCLENBQUMsQ0FBQztBQUtaLE1BQU0sK0JBQStCLEdBQUcsSUFBSSxDQUFDO0FBQzdDLE1BQU0sZ0NBQWdDLEdBQUcsRUFBRSxDQUFDO0FBRTVDLE1BQU0sUUFBUSxHQUFHLENBQUMsUUFBaUIsRUFBdUMsRUFBRSxDQUFDLENBQzNFLE9BQU8sQ0FBQyxRQUFRLENBQUM7T0FDZCxPQUFPLFFBQVEsS0FBSyxRQUFRO09BQzVCLENBQUMsS0FBSyxDQUFDLE9BQU8sQ0FBQyxRQUFRLENBQUM7T0FDeEIsQ0FBQyxNQUFNLENBQUMsY0FBYyxDQUFD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
@@ -2,6 +2,7 @@ import * as plugins from '../plugins.js';
2
2
  import { type TSha256Digest, type TImmutableContainerPlatform } from './immutableimage.js';
3
3
  import type { ISparkNodeReportRecord } from './sparknodereport.js';
4
4
  import { type IFleetCutoverAcceptedEvidenceReference, type IFleetCutoverHeldVolumeFenceEvidencePage, type IFleetCutoverLocalNodeSnapshot, type IFleetCutoverManagerSnapshot, type IFleetCutoverPreparedVolumeHandoffAggregate, type IFleetCutoverPreparedVolumeHandoffIntent, type IFleetCutoverPreparedVolumeHandoffPage } from './fleetcutover.js';
5
+ import { type ISparkLegacyRuntimeRetirement, type TSparkLegacyRetirementOutcome } from './sparklegacyretirement.js';
5
6
  import { type IProtocolOffer } from '../protocol.js';
6
7
  import { isClusterNodeId } from '../private/nodeidentifier.js';
7
8
  /**
@@ -198,6 +199,8 @@ interface ISparkSwarmObservationBase {
198
199
  observedAt: number;
199
200
  /** Available in every observation state; exact page membership proves an empty node subset. */
200
201
  fleetCutoverHeldVolumeFences?: IFleetCutoverHeldVolumeFenceEvidencePage;
202
+ /** Available in every observation state too: this describes the host, not its Docker daemon. */
203
+ fleetCutoverLegacyRetirement?: ISparkLegacyRuntimeRetirement;
201
204
  }
202
205
  export type TSparkSwarmObservation = (ISparkSwarmObservationBase & {
203
206
  state: 'unknown';
@@ -221,7 +224,17 @@ export type TSparkSwarmObservation = (ISparkSwarmObservationBase & {
221
224
  /** Manager-visible services/tasks only; it never claims remote physical containers. */
222
225
  fleetCutoverManagerSnapshot?: IFleetCutoverManagerSnapshot;
223
226
  });
224
- export type TSparkSwarmObservationRejectionCode = 'sequence-conflict' | 'sequence-stale' | 'sequence-gap' | 'session-sequence-invalid' | 'session-retired' | 'observation-too-old' | 'observation-from-future' | 'observation-time-not-advancing' | 'acceptance-race';
227
+ export type TSparkSwarmObservationRejectionCode = 'sequence-conflict' | 'sequence-stale' | 'sequence-gap' | 'session-sequence-invalid' | 'session-retired' | 'observation-too-old' | 'observation-from-future' | 'observation-time-not-advancing' | 'acceptance-race'
228
+ /**
229
+ * An evidence member of this observation is refused, for this body and every resend of it.
230
+ *
231
+ * The whole observation is rejected because the refused content is what the body states, and a
232
+ * node that keeps resending it would never be recorded. It is the answer for a member whose
233
+ * content this server has decided against; a server-side condition that a later attempt could
234
+ * pass is `acceptance-race` instead, and telling the two apart while accepting evidence is the
235
+ * server's own work.
236
+ */
237
+ | 'evidence-refused';
225
238
  export declare const sparkSwarmObservationContract: Readonly<{
226
239
  readonly digestDomain: "serve.zone/spark-swarm-observation";
227
240
  readonly maximumPastAgeMs: 300000;
@@ -237,6 +250,7 @@ export declare const sparkSwarmObservationContract: Readonly<{
237
250
  'observation-from-future': false;
238
251
  'observation-time-not-advancing': false;
239
252
  'acceptance-race': true;
253
+ 'evidence-refused': false;
240
254
  }>;
241
255
  }>;
242
256
  /** Cloudly derives node and cluster scope from this authenticated Spark request. */
@@ -278,6 +292,15 @@ export interface ISparkSwarmObservationAcceptedReceipt {
278
292
  acceptedAt: number;
279
293
  /** Runtime target generation observed immediately after this acceptance. */
280
294
  targetGenerationAtAcceptance: number;
295
+ /**
296
+ * What the server did with `fleetCutoverLegacyRetirement`, present exactly when it was stated.
297
+ *
298
+ * A statement about the node's own released runtime is judged against records rather than
299
+ * against this message, so its refusal is answered here instead of rejecting an observation
300
+ * whose liveness and census are true either way. Absent on the rejected receipt: an observation
301
+ * that was not accepted never reached the statement.
302
+ */
303
+ fleetCutoverLegacyRetirement?: TSparkLegacyRetirementOutcome;
281
304
  /** The answering server's offer; see `sparkSwarmNodeContracts`. */
282
305
  protocol: IProtocolOffer;
283
306
  }