pi-radar 0.5.1 → 0.7.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/README.md +76 -2
- package/dist/extension/baseline.js +45 -13
- package/dist/extension/radar-client.js +37 -10
- package/dist/extension/radar-execution.js +10 -4
- package/dist/extension/radar-publication.js +9 -3
- package/dist/index.js +47 -14
- package/extension/generated-contracts.ts +115 -8
- package/extension/radar-client.ts +42 -15
- package/extension/radar-execution.ts +5 -5
- package/extension/radar-publication.ts +11 -4
- package/package.json +1 -1
- package/schema/public/v1/handoff-receipt.deserialize.schema.json +2 -9
- package/schema/public/v1/handoff-receipt.serialize.schema.json +2 -9
- package/schema/public/v1/handoff.deserialize.schema.json +2 -9
- package/schema/public/v1/handoff.serialize.schema.json +2 -9
- package/schema/public/v1/observation-get-response.deserialize.schema.json +18 -6
- package/schema/public/v1/observation-get-response.serialize.schema.json +19 -7
- package/schema/public/v1/observation-snapshot.deserialize.schema.json +18 -6
- package/schema/public/v1/observation-snapshot.serialize.schema.json +19 -7
- package/schema/public/v1/presence-answer.deserialize.schema.json +1 -0
- package/schema/public/v1/presence-answer.serialize.schema.json +1 -0
- package/schema/public/v1/presence-report.deserialize.schema.json +0 -7
- package/schema/public/v1/presence-report.serialize.schema.json +0 -8
- package/schema/public/v1/spawn-list-page.deserialize.schema.json +291 -0
- package/schema/public/v1/spawn-list-page.serialize.schema.json +296 -0
- package/schema/public/v1/spawn-list-params.deserialize.schema.json +33 -0
- package/schema/public/v1/spawn-list-params.serialize.schema.json +38 -0
|
@@ -11,7 +11,6 @@ export interface PresenceReportDeserialize {
|
|
|
11
11
|
run?: string | null;
|
|
12
12
|
session_id: string;
|
|
13
13
|
source: string;
|
|
14
|
-
spawn_token?: string | null;
|
|
15
14
|
subject_id?: string | null;
|
|
16
15
|
}
|
|
17
16
|
/**
|
|
@@ -54,7 +53,7 @@ export interface PresenceReportProcessIdentity {
|
|
|
54
53
|
start_ticks: number;
|
|
55
54
|
[k: string]: unknown;
|
|
56
55
|
}
|
|
57
|
-
export type PresenceAnswerStanding = "pending" | "granted" | "duplicate" | "released";
|
|
56
|
+
export type PresenceAnswerStanding = "reserved" | "pending" | "granted" | "duplicate" | "released";
|
|
58
57
|
|
|
59
58
|
/**
|
|
60
59
|
* The small public receipt; session/location context stays inside Radar.
|
|
@@ -151,8 +150,7 @@ export interface HandoffSerialize {
|
|
|
151
150
|
* generation identify the exact execution that took the action.
|
|
152
151
|
*/
|
|
153
152
|
export interface HandoffIdentity {
|
|
154
|
-
|
|
155
|
-
execution_id: string;
|
|
153
|
+
claim_id: string;
|
|
156
154
|
registration_id: string;
|
|
157
155
|
session_id: string;
|
|
158
156
|
subject_id: string;
|
|
@@ -172,8 +170,7 @@ export interface HandoffReceiptSerialize {
|
|
|
172
170
|
* generation identify the exact execution that took the action.
|
|
173
171
|
*/
|
|
174
172
|
export interface HandoffIdentity {
|
|
175
|
-
|
|
176
|
-
execution_id: string;
|
|
173
|
+
claim_id: string;
|
|
177
174
|
registration_id: string;
|
|
178
175
|
session_id: string;
|
|
179
176
|
subject_id: string;
|
|
@@ -286,7 +283,7 @@ export type Freshness = "fresh" | "stale";
|
|
|
286
283
|
* refused rather than silently dropped.
|
|
287
284
|
*/
|
|
288
285
|
export type Report = Snapshot | AssignmentSnapshot | FactsSnapshot;
|
|
289
|
-
export type Standing = "pending" | "granted" | "duplicate" | "released";
|
|
286
|
+
export type Standing = "reserved" | "pending" | "granted" | "duplicate" | "released";
|
|
290
287
|
/**
|
|
291
288
|
* How a registration relates to the live panes.
|
|
292
289
|
*/
|
|
@@ -677,6 +674,11 @@ export interface RegistryAgent {
|
|
|
677
674
|
facts: PublicChannelFacts | null;
|
|
678
675
|
process: ProcessEvidence;
|
|
679
676
|
registration: PublicRegistration;
|
|
677
|
+
/**
|
|
678
|
+
* Whether this process runs inside a Radar-established execution scope. A
|
|
679
|
+
* process started outside the managed launch path has none and is observed.
|
|
680
|
+
*/
|
|
681
|
+
scoped?: boolean | null;
|
|
680
682
|
}
|
|
681
683
|
/**
|
|
682
684
|
* A channel read for a reader that is not its writer: the same identity,
|
|
@@ -902,6 +904,7 @@ export interface RegistryLocation {
|
|
|
902
904
|
*/
|
|
903
905
|
export interface ManagedSubject {
|
|
904
906
|
child_close: ChildCloseTarget | null;
|
|
907
|
+
claim_id: string;
|
|
905
908
|
identity_unresolved: boolean;
|
|
906
909
|
metadata: ManagedMetadata;
|
|
907
910
|
process: ProcessIdentity;
|
|
@@ -938,10 +941,10 @@ export interface ManagedMetadata {
|
|
|
938
941
|
export interface SpawnBinding {
|
|
939
942
|
child_incarnation: string | null;
|
|
940
943
|
child_source: string | null;
|
|
944
|
+
claim_id: string | null;
|
|
941
945
|
parent: string;
|
|
942
946
|
request_id: string;
|
|
943
947
|
state: SpawnState;
|
|
944
|
-
subject_id: string | null;
|
|
945
948
|
}
|
|
946
949
|
/**
|
|
947
950
|
* What this machine knows about that process. Filled by the collector
|
|
@@ -1385,3 +1388,107 @@ export interface ObservationTooLarge {
|
|
|
1385
1388
|
limit_bytes: number;
|
|
1386
1389
|
revision: number;
|
|
1387
1390
|
}
|
|
1391
|
+
/**
|
|
1392
|
+
* Input accepted by `spawn.list`.
|
|
1393
|
+
*
|
|
1394
|
+
* A caller presents itself; the parent whose launches it reads is derived from
|
|
1395
|
+
* the claim it holds. There is deliberately no parent parameter: naming another
|
|
1396
|
+
* subject would let any client read its launches.
|
|
1397
|
+
*/
|
|
1398
|
+
export interface SpawnListParamsDeserialize {
|
|
1399
|
+
after?: string | null;
|
|
1400
|
+
limit?: number | null;
|
|
1401
|
+
registration_id?: string | null;
|
|
1402
|
+
}
|
|
1403
|
+
/**
|
|
1404
|
+
* What a completed request did.
|
|
1405
|
+
*/
|
|
1406
|
+
export type SpawnListPageSerializeRequestOutcome = "completed" | "refused" | "unknown";
|
|
1407
|
+
/**
|
|
1408
|
+
* What a spawn topology read can say about a child's process exit.
|
|
1409
|
+
*/
|
|
1410
|
+
export type SpawnListPageSerializePublicSpawnExitObservation =
|
|
1411
|
+
| {
|
|
1412
|
+
state: "unknown";
|
|
1413
|
+
}
|
|
1414
|
+
| {
|
|
1415
|
+
code: number | null;
|
|
1416
|
+
observed_at: string;
|
|
1417
|
+
signal: number | null;
|
|
1418
|
+
state: "exited";
|
|
1419
|
+
};
|
|
1420
|
+
/**
|
|
1421
|
+
* Freshness is independent of process identity or completion.
|
|
1422
|
+
*/
|
|
1423
|
+
export type SpawnListPageSerializeFreshness = "fresh" | "stale";
|
|
1424
|
+
/**
|
|
1425
|
+
* The state of one edge in the recorded topology: the strongest statement a
|
|
1426
|
+
* read can make about it, and nothing beyond the records and this read's own
|
|
1427
|
+
* evidence.
|
|
1428
|
+
*/
|
|
1429
|
+
export type SpawnListPageSerializeSpawnState = "unbound" | "bound" | "unresolved";
|
|
1430
|
+
|
|
1431
|
+
/**
|
|
1432
|
+
* One page of spawn edges. `next` names the request id the page ended on.
|
|
1433
|
+
*/
|
|
1434
|
+
export interface SpawnListPageSerialize {
|
|
1435
|
+
next?: string | null;
|
|
1436
|
+
spawns: SpawnListPageSerializePublicSpawnTopology[];
|
|
1437
|
+
}
|
|
1438
|
+
/**
|
|
1439
|
+
* One edge as a topology read reports it: the stored facts, plus the two things
|
|
1440
|
+
* a read derives instead of inferring.
|
|
1441
|
+
*/
|
|
1442
|
+
export interface SpawnListPageSerializePublicSpawnTopology {
|
|
1443
|
+
bound?: SpawnListPageSerializeBoundChild | null;
|
|
1444
|
+
claim_id?: string | null;
|
|
1445
|
+
created: SpawnListPageSerializeRequestOutcome;
|
|
1446
|
+
exit_observation?: SpawnListPageSerializePublicSpawnExitObservation | null;
|
|
1447
|
+
/**
|
|
1448
|
+
* Freshness of the recorded location against this read's evidence, in the
|
|
1449
|
+
* registry's one freshness vocabulary: `fresh` when the backend reports the
|
|
1450
|
+
* location now, `stale` when it does not — which is never evidence that the
|
|
1451
|
+
* child stopped. Absent when the edge recorded no location, because there is
|
|
1452
|
+
* nothing to verify.
|
|
1453
|
+
*/
|
|
1454
|
+
freshness?: SpawnListPageSerializeFreshness | null;
|
|
1455
|
+
launched: SpawnListPageSerializeRequestOutcome;
|
|
1456
|
+
location?: SpawnListPageSerializeRegistryLocation | null;
|
|
1457
|
+
parent: string;
|
|
1458
|
+
parent_session_id?: string | null;
|
|
1459
|
+
parent_subject_id?: string | null;
|
|
1460
|
+
recorded_at: string;
|
|
1461
|
+
request_id: string;
|
|
1462
|
+
state: SpawnListPageSerializeSpawnState;
|
|
1463
|
+
version: number;
|
|
1464
|
+
}
|
|
1465
|
+
/**
|
|
1466
|
+
* The child a token bound: the registering incarnation's own registry identity.
|
|
1467
|
+
*/
|
|
1468
|
+
export interface SpawnListPageSerializeBoundChild {
|
|
1469
|
+
/**
|
|
1470
|
+
* When the edge bound to this incarnation.
|
|
1471
|
+
*/
|
|
1472
|
+
bound_at: string;
|
|
1473
|
+
incarnation: string;
|
|
1474
|
+
/**
|
|
1475
|
+
* Exact registry identity returned to the registering child. Absent in legacy records.
|
|
1476
|
+
*/
|
|
1477
|
+
registration_id?: string | null;
|
|
1478
|
+
source: string;
|
|
1479
|
+
}
|
|
1480
|
+
/**
|
|
1481
|
+
* Where an agent's incarnation lives on one backend, in that backend's own
|
|
1482
|
+
* coordinates.
|
|
1483
|
+
*
|
|
1484
|
+
* The backend name is free-form so a source Radar does not ship yet is
|
|
1485
|
+
* preserved rather than rejected; the rest are the coordinates as reported, and
|
|
1486
|
+
* each is optional because a backend need not name every level.
|
|
1487
|
+
*/
|
|
1488
|
+
export interface SpawnListPageSerializeRegistryLocation {
|
|
1489
|
+
backend: string;
|
|
1490
|
+
instance?: string | null;
|
|
1491
|
+
pane?: string | null;
|
|
1492
|
+
tab?: string | null;
|
|
1493
|
+
workspace?: string | null;
|
|
1494
|
+
}
|
|
@@ -11,6 +11,8 @@ import type {
|
|
|
11
11
|
HandoffSerialize,
|
|
12
12
|
ManagedLaunchMetadataDeserialize,
|
|
13
13
|
SpawnExitObservationSerialize,
|
|
14
|
+
SpawnListParamsDeserialize,
|
|
15
|
+
SpawnListPageSerialize,
|
|
14
16
|
} from "./generated-contracts.ts";
|
|
15
17
|
|
|
16
18
|
/**
|
|
@@ -31,16 +33,15 @@ import type {
|
|
|
31
33
|
*/
|
|
32
34
|
export const RADAR_PROTOCOL_VERSION = 2;
|
|
33
35
|
/**
|
|
34
|
-
*
|
|
35
|
-
*
|
|
36
|
-
* this handshake and then refuse every presence report, leaving a Pi session
|
|
37
|
-
* silently unmanaged instead of telling the operator to restart the daemon.
|
|
36
|
+
* Revision 5 names attempts by claim_id and requires exact-claim controls.
|
|
37
|
+
* Earlier daemons expose different identity fields; require a coordinated update.
|
|
38
38
|
*/
|
|
39
|
-
export const RADAR_MINIMUM_REVISION =
|
|
39
|
+
export const RADAR_MINIMUM_REVISION = 6;
|
|
40
40
|
/** Public daemon contracts this client may preflight. */
|
|
41
41
|
export const RADAR_REGISTRY_CONTRACT = "registry.v1";
|
|
42
42
|
export const RADAR_REGISTRY_FACTS_CONTRACT = "registry.facts.v1";
|
|
43
43
|
export const RADAR_SPAWN_CONTRACT = "spawn.v1";
|
|
44
|
+
export const RADAR_SPAWN_LIST_CONTRACT = "spawn.list.v1";
|
|
44
45
|
export const RADAR_SPAWN_CLOSE_CONTRACT = "spawn.close.v1";
|
|
45
46
|
export const RADAR_SPAWN_LAUNCH_CONTEXT_CONTRACT = "spawn.launch_context.v1";
|
|
46
47
|
export const RADAR_EVENTS_CONTRACT = "events.v1";
|
|
@@ -516,7 +517,7 @@ function decodePresenceAnswer(value: unknown): RadarResult<RadarPresenceAnswer>
|
|
|
516
517
|
if (
|
|
517
518
|
!isUuid(registrationId) ||
|
|
518
519
|
!isUuid(claimId) ||
|
|
519
|
-
!["pending", "granted", "duplicate", "released"].includes(String(standing)) ||
|
|
520
|
+
!["reserved", "pending", "granted", "duplicate", "released"].includes(String(standing)) ||
|
|
520
521
|
(subjectId !== undefined && !isUuid(subjectId)) ||
|
|
521
522
|
(standing === "granted" && !isUuid(subjectId))
|
|
522
523
|
)
|
|
@@ -563,7 +564,6 @@ function handoffAt(value: unknown): HandoffSerialize | undefined {
|
|
|
563
564
|
const version = numberAt(value, "version");
|
|
564
565
|
const id = stringAt(value, "id");
|
|
565
566
|
const sender = recordAt(value, "sender");
|
|
566
|
-
const senderGeneration = numberAt(sender, "execution_generation");
|
|
567
567
|
const target = stringAt(value, "recipient_subject_id");
|
|
568
568
|
const summary = stringAt(value, "summary");
|
|
569
569
|
const content = stringAt(value, "content");
|
|
@@ -574,8 +574,7 @@ function handoffAt(value: unknown): HandoffSerialize | undefined {
|
|
|
574
574
|
if (
|
|
575
575
|
version !== 1 || !isUuid(id) || !isUuid(stringAt(sender, "registration_id")) ||
|
|
576
576
|
!isUuid(stringAt(sender, "session_id")) || !isUuid(stringAt(sender, "subject_id")) ||
|
|
577
|
-
!isUuid(stringAt(sender, "
|
|
578
|
-
(senderGeneration ?? 0) < 1 || !isUuid(target) || summary === undefined || content === undefined ||
|
|
577
|
+
!isUuid(stringAt(sender, "claim_id")) || !isUuid(target) || summary === undefined || content === undefined ||
|
|
579
578
|
published === undefined || !Number.isSafeInteger(published) || published < 0 ||
|
|
580
579
|
(correlation !== undefined && correlation !== null &&
|
|
581
580
|
(typeof correlation !== "string" || correlation.length === 0 ||
|
|
@@ -588,13 +587,11 @@ function handoffReceiptAt(value: unknown): HandoffReceiptSerialize | undefined {
|
|
|
588
587
|
const version = numberAt(value, "version");
|
|
589
588
|
const handoffId = stringAt(value, "handoff_id");
|
|
590
589
|
const recipient = recordAt(value, "recipient");
|
|
591
|
-
const generation = numberAt(recipient, "execution_generation");
|
|
592
590
|
const received = numberAt(value, "received_at_unix_ms");
|
|
593
591
|
if (
|
|
594
592
|
version !== 1 || !isUuid(handoffId) || !isUuid(stringAt(recipient, "registration_id")) ||
|
|
595
593
|
!isUuid(stringAt(recipient, "session_id")) || !isUuid(stringAt(recipient, "subject_id")) ||
|
|
596
|
-
!isUuid(stringAt(recipient, "
|
|
597
|
-
(generation ?? 0) < 1 || received === undefined || !Number.isSafeInteger(received) || received < 0
|
|
594
|
+
!isUuid(stringAt(recipient, "claim_id")) || received === undefined || !Number.isSafeInteger(received) || received < 0
|
|
598
595
|
) return undefined;
|
|
599
596
|
return value as HandoffReceiptSerialize;
|
|
600
597
|
}
|
|
@@ -748,7 +745,7 @@ function unresolvedOperation(requestId: string, detail: string): RadarResult<nev
|
|
|
748
745
|
};
|
|
749
746
|
}
|
|
750
747
|
|
|
751
|
-
export const
|
|
748
|
+
export const RADAR_REGISTRATION_ENV = "PI_RADAR_REGISTRATION_ID";
|
|
752
749
|
const RADAR_MANAGED_IDENTITY_ENV = new Set([
|
|
753
750
|
"PI_RADAR_MANAGED_SUBJECT_ID",
|
|
754
751
|
"PI_RADAR_MANAGED_LAUNCH_ID",
|
|
@@ -978,8 +975,8 @@ function spawnRequestShape(request: {
|
|
|
978
975
|
const env = Object.entries(request.env ?? {});
|
|
979
976
|
if (env.length > 256) return "spawn env names more than 256 entries";
|
|
980
977
|
for (const [name, value] of env) {
|
|
981
|
-
if (name ===
|
|
982
|
-
return `spawn env cannot set the reserved ${
|
|
978
|
+
if (name === RADAR_REGISTRATION_ENV)
|
|
979
|
+
return `spawn env cannot set the reserved ${RADAR_REGISTRATION_ENV}`;
|
|
983
980
|
if (RADAR_MANAGED_IDENTITY_ENV.has(name))
|
|
984
981
|
return `spawn env cannot set Radar-issued identity variable ${name}`;
|
|
985
982
|
if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(name) || /\p{Cc}/u.test(value))
|
|
@@ -1104,6 +1101,8 @@ export type RadarClient = {
|
|
|
1104
1101
|
env?: Record<string, string>;
|
|
1105
1102
|
managed?: RadarManagedLaunchMetadata;
|
|
1106
1103
|
}): Promise<RadarResult<RadarSpawnEdge>>;
|
|
1104
|
+
/** List launches owned by this client's registered process. */
|
|
1105
|
+
spawnList(request: Pick<SpawnListParamsDeserialize, "after" | "limit">): Promise<RadarResult<SpawnListPageSerialize>>;
|
|
1107
1106
|
spawnGet(request_id: string): Promise<RadarResult<RadarSpawnTopology>>;
|
|
1108
1107
|
/** The registered child's process verdict, read from its immutable claim. */
|
|
1109
1108
|
agentGet(registration_id: string): Promise<RadarResult<RadarAgentProcess>>;
|
|
@@ -1447,6 +1446,7 @@ export function createRadarClient(options: RadarClientOptions = {}): RadarClient
|
|
|
1447
1446
|
};
|
|
1448
1447
|
return answer;
|
|
1449
1448
|
};
|
|
1449
|
+
let processRegistrationId: string | undefined;
|
|
1450
1450
|
let handshake: Promise<RadarResult<RadarHandshake>> | undefined;
|
|
1451
1451
|
const negotiated = async (): Promise<RadarResult<RadarHandshake>> => {
|
|
1452
1452
|
handshake ??= probe();
|
|
@@ -1552,6 +1552,7 @@ export function createRadarClient(options: RadarClientOptions = {}): RadarClient
|
|
|
1552
1552
|
const record = (answer.value as { registration?: unknown }).registration;
|
|
1553
1553
|
const agentId = stringAt(record, "registration_id");
|
|
1554
1554
|
if (!isUuid(agentId)) return protocol("registration reply carries no registration_id");
|
|
1555
|
+
processRegistrationId = agentId;
|
|
1555
1556
|
return { ok: true, value: { registration_id: agentId } };
|
|
1556
1557
|
});
|
|
1557
1558
|
},
|
|
@@ -1705,6 +1706,32 @@ export function createRadarClient(options: RadarClientOptions = {}): RadarClient
|
|
|
1705
1706
|
},
|
|
1706
1707
|
);
|
|
1707
1708
|
},
|
|
1709
|
+
async spawnList(request) {
|
|
1710
|
+
const registrationId = processRegistrationId;
|
|
1711
|
+
if (registrationId === undefined)
|
|
1712
|
+
return { ok: false, code: "refused", message: "spawn.list requires this client's process registration" };
|
|
1713
|
+
return withContract(RADAR_SPAWN_LIST_CONTRACT, async () => {
|
|
1714
|
+
const params: SpawnListParamsDeserialize = {
|
|
1715
|
+
registration_id: registrationId,
|
|
1716
|
+
...(request.after !== undefined ? { after: request.after } : {}),
|
|
1717
|
+
...(request.limit !== undefined ? { limit: request.limit } : {}),
|
|
1718
|
+
};
|
|
1719
|
+
const answer = await call("spawn.list", { ...params });
|
|
1720
|
+
if (answer.ok === false) return answer;
|
|
1721
|
+
const spawns = recordAt(answer.value, "spawns");
|
|
1722
|
+
const next = recordAt(answer.value, "next");
|
|
1723
|
+
if (!Array.isArray(spawns) || (next != null && !isUuid(next)))
|
|
1724
|
+
return protocol("spawn.list reply carries no valid page");
|
|
1725
|
+
for (const spawn of spawns) {
|
|
1726
|
+
const decoded = spawnTopology(spawn);
|
|
1727
|
+
if (decoded.ok === false) return decoded;
|
|
1728
|
+
if (typeof recordAt(spawn, "version") !== "number" || typeof recordAt(spawn, "recorded_at") !== "string" ||
|
|
1729
|
+
!["unbound", "bound", "unresolved"].includes(String(recordAt(spawn, "state"))))
|
|
1730
|
+
return protocol("spawn.list reply carries an incomplete topology");
|
|
1731
|
+
}
|
|
1732
|
+
return { ok: true, value: answer.value as SpawnListPageSerialize };
|
|
1733
|
+
});
|
|
1734
|
+
},
|
|
1708
1735
|
async spawnGet(requestId) {
|
|
1709
1736
|
if (!isUuid(requestId))
|
|
1710
1737
|
return {
|
|
@@ -51,10 +51,10 @@ export type RadarExecutionOptions = {
|
|
|
51
51
|
*/
|
|
52
52
|
location?: () => Promise<RadarLocationResolution>;
|
|
53
53
|
/**
|
|
54
|
-
*
|
|
55
|
-
*
|
|
54
|
+
* Registration allocated by Radar before this process launched. Normally
|
|
55
|
+
* captured from the launch environment by the process-local publication.
|
|
56
56
|
*/
|
|
57
|
-
|
|
57
|
+
launchRegistrationId?: string;
|
|
58
58
|
/** Only a real fixed managed assignment is part of immutable registration. */
|
|
59
59
|
managedBinding?: { key: string; run: string; owner: string; label: string };
|
|
60
60
|
/**
|
|
@@ -207,8 +207,8 @@ export function createRadarExecutionAdapter(
|
|
|
207
207
|
? { location: options.location }
|
|
208
208
|
: {}),
|
|
209
209
|
...(managed !== undefined ? { binding: managed } : {}),
|
|
210
|
-
...(options.
|
|
211
|
-
? {
|
|
210
|
+
...(options.launchRegistrationId !== undefined
|
|
211
|
+
? { launchRegistrationId: options.launchRegistrationId }
|
|
212
212
|
: {}),
|
|
213
213
|
});
|
|
214
214
|
} catch {
|
|
@@ -269,6 +269,7 @@ export function createPublicationStore(root: string): PublicationStore {
|
|
|
269
269
|
*/
|
|
270
270
|
export type RadarProcessSlot = {
|
|
271
271
|
incarnation?: string;
|
|
272
|
+
launchRegistrationId?: string;
|
|
272
273
|
publications: Map<string, RadarPublication>;
|
|
273
274
|
};
|
|
274
275
|
|
|
@@ -280,7 +281,13 @@ export function radarProcessSlot(): RadarProcessSlot {
|
|
|
280
281
|
const host = globalThis as typeof globalThis & {
|
|
281
282
|
[PROCESS_SLOT]?: RadarProcessSlot;
|
|
282
283
|
};
|
|
283
|
-
|
|
284
|
+
if (!host[PROCESS_SLOT]) {
|
|
285
|
+
const slot = createRadarProcessSlot();
|
|
286
|
+
slot.launchRegistrationId = process.env.PI_RADAR_REGISTRATION_ID;
|
|
287
|
+
delete process.env.PI_RADAR_REGISTRATION_ID;
|
|
288
|
+
host[PROCESS_SLOT] = slot;
|
|
289
|
+
}
|
|
290
|
+
return host[PROCESS_SLOT];
|
|
284
291
|
}
|
|
285
292
|
|
|
286
293
|
/** The process incarnation, created on first use and kept for the process. */
|
|
@@ -1151,7 +1158,7 @@ export type RadarPublicationOptions = {
|
|
|
1151
1158
|
/** Set on a managed child: the sidecar its owner correlates the subject with. */
|
|
1152
1159
|
binding?: { key: string; run: string; owner: string; label: string };
|
|
1153
1160
|
/** A daemon-spawned child's one-use launch token; sent privately, never stored in the process record. */
|
|
1154
|
-
|
|
1161
|
+
launchRegistrationId?: string;
|
|
1155
1162
|
leaseMs?: number;
|
|
1156
1163
|
heartbeatMs?: number;
|
|
1157
1164
|
};
|
|
@@ -1226,8 +1233,8 @@ function createRadarPublicationInner(
|
|
|
1226
1233
|
const store = options.store ?? createPublicationStore(dataRoot);
|
|
1227
1234
|
const scheduler = options.scheduler ?? systemScheduler;
|
|
1228
1235
|
const client = options.client;
|
|
1229
|
-
const spawnToken = options.spawnToken;
|
|
1230
1236
|
const slot = options.slot ?? radarProcessSlot();
|
|
1237
|
+
const launchRegistrationId = options.launchRegistrationId ?? slot.launchRegistrationId;
|
|
1231
1238
|
const incarnation = options.incarnation ?? radarProcessIncarnation(slot);
|
|
1232
1239
|
|
|
1233
1240
|
const cacheKey = `${
|
|
@@ -1416,7 +1423,7 @@ function createRadarPublicationInner(
|
|
|
1416
1423
|
const { location: _initialLocation, ...identity } = record.registration;
|
|
1417
1424
|
return { ...identity,
|
|
1418
1425
|
...(location?.state === "resolved" ? { location: location.location } : {}),
|
|
1419
|
-
...(
|
|
1426
|
+
...(launchRegistrationId ? { registration_id: launchRegistrationId } : {}),
|
|
1420
1427
|
};
|
|
1421
1428
|
},
|
|
1422
1429
|
heartbeatMs: options.heartbeatMs ?? RADAR_HEARTBEAT_MS,
|
package/package.json
CHANGED
|
@@ -4,13 +4,7 @@
|
|
|
4
4
|
"additionalProperties": false,
|
|
5
5
|
"description": "The current managed Pi execution that published or received a handoff.\n`subject_id` is stable across verified successors; `execution_id` and\ngeneration identify the exact execution that took the action.",
|
|
6
6
|
"properties": {
|
|
7
|
-
"
|
|
8
|
-
"format": "uint32",
|
|
9
|
-
"maximum": 4294967295,
|
|
10
|
-
"minimum": 1,
|
|
11
|
-
"type": "integer"
|
|
12
|
-
},
|
|
13
|
-
"execution_id": {
|
|
7
|
+
"claim_id": {
|
|
14
8
|
"type": "string"
|
|
15
9
|
},
|
|
16
10
|
"registration_id": {
|
|
@@ -27,8 +21,7 @@
|
|
|
27
21
|
"registration_id",
|
|
28
22
|
"session_id",
|
|
29
23
|
"subject_id",
|
|
30
|
-
"
|
|
31
|
-
"execution_generation"
|
|
24
|
+
"claim_id"
|
|
32
25
|
],
|
|
33
26
|
"type": "object"
|
|
34
27
|
}
|
|
@@ -4,13 +4,7 @@
|
|
|
4
4
|
"additionalProperties": false,
|
|
5
5
|
"description": "The current managed Pi execution that published or received a handoff.\n`subject_id` is stable across verified successors; `execution_id` and\ngeneration identify the exact execution that took the action.",
|
|
6
6
|
"properties": {
|
|
7
|
-
"
|
|
8
|
-
"format": "uint32",
|
|
9
|
-
"maximum": 4294967295,
|
|
10
|
-
"minimum": 1,
|
|
11
|
-
"type": "integer"
|
|
12
|
-
},
|
|
13
|
-
"execution_id": {
|
|
7
|
+
"claim_id": {
|
|
14
8
|
"type": "string"
|
|
15
9
|
},
|
|
16
10
|
"registration_id": {
|
|
@@ -27,8 +21,7 @@
|
|
|
27
21
|
"registration_id",
|
|
28
22
|
"session_id",
|
|
29
23
|
"subject_id",
|
|
30
|
-
"
|
|
31
|
-
"execution_generation"
|
|
24
|
+
"claim_id"
|
|
32
25
|
],
|
|
33
26
|
"type": "object"
|
|
34
27
|
}
|
|
@@ -4,13 +4,7 @@
|
|
|
4
4
|
"additionalProperties": false,
|
|
5
5
|
"description": "The current managed Pi execution that published or received a handoff.\n`subject_id` is stable across verified successors; `execution_id` and\ngeneration identify the exact execution that took the action.",
|
|
6
6
|
"properties": {
|
|
7
|
-
"
|
|
8
|
-
"format": "uint32",
|
|
9
|
-
"maximum": 4294967295,
|
|
10
|
-
"minimum": 1,
|
|
11
|
-
"type": "integer"
|
|
12
|
-
},
|
|
13
|
-
"execution_id": {
|
|
7
|
+
"claim_id": {
|
|
14
8
|
"type": "string"
|
|
15
9
|
},
|
|
16
10
|
"registration_id": {
|
|
@@ -27,8 +21,7 @@
|
|
|
27
21
|
"registration_id",
|
|
28
22
|
"session_id",
|
|
29
23
|
"subject_id",
|
|
30
|
-
"
|
|
31
|
-
"execution_generation"
|
|
24
|
+
"claim_id"
|
|
32
25
|
],
|
|
33
26
|
"type": "object"
|
|
34
27
|
}
|
|
@@ -4,13 +4,7 @@
|
|
|
4
4
|
"additionalProperties": false,
|
|
5
5
|
"description": "The current managed Pi execution that published or received a handoff.\n`subject_id` is stable across verified successors; `execution_id` and\ngeneration identify the exact execution that took the action.",
|
|
6
6
|
"properties": {
|
|
7
|
-
"
|
|
8
|
-
"format": "uint32",
|
|
9
|
-
"maximum": 4294967295,
|
|
10
|
-
"minimum": 1,
|
|
11
|
-
"type": "integer"
|
|
12
|
-
},
|
|
13
|
-
"execution_id": {
|
|
7
|
+
"claim_id": {
|
|
14
8
|
"type": "string"
|
|
15
9
|
},
|
|
16
10
|
"registration_id": {
|
|
@@ -27,8 +21,7 @@
|
|
|
27
21
|
"registration_id",
|
|
28
22
|
"session_id",
|
|
29
23
|
"subject_id",
|
|
30
|
-
"
|
|
31
|
-
"execution_generation"
|
|
24
|
+
"claim_id"
|
|
32
25
|
],
|
|
33
26
|
"type": "object"
|
|
34
27
|
}
|
|
@@ -1037,6 +1037,9 @@
|
|
|
1037
1037
|
}
|
|
1038
1038
|
]
|
|
1039
1039
|
},
|
|
1040
|
+
"claim_id": {
|
|
1041
|
+
"type": "string"
|
|
1042
|
+
},
|
|
1040
1043
|
"identity_unresolved": {
|
|
1041
1044
|
"type": "boolean"
|
|
1042
1045
|
},
|
|
@@ -1067,6 +1070,7 @@
|
|
|
1067
1070
|
},
|
|
1068
1071
|
"required": [
|
|
1069
1072
|
"subject_id",
|
|
1073
|
+
"claim_id",
|
|
1070
1074
|
"process",
|
|
1071
1075
|
"identity_unresolved",
|
|
1072
1076
|
"metadata",
|
|
@@ -2094,6 +2098,13 @@
|
|
|
2094
2098
|
},
|
|
2095
2099
|
"registration": {
|
|
2096
2100
|
"$ref": "#/$defs/PublicRegistration"
|
|
2101
|
+
},
|
|
2102
|
+
"scoped": {
|
|
2103
|
+
"description": "Whether this process runs inside a Radar-established execution scope. A\nprocess started outside the managed launch path has none and is observed.",
|
|
2104
|
+
"type": [
|
|
2105
|
+
"boolean",
|
|
2106
|
+
"null"
|
|
2107
|
+
]
|
|
2097
2108
|
}
|
|
2098
2109
|
},
|
|
2099
2110
|
"required": [
|
|
@@ -2375,6 +2386,12 @@
|
|
|
2375
2386
|
"null"
|
|
2376
2387
|
]
|
|
2377
2388
|
},
|
|
2389
|
+
"claim_id": {
|
|
2390
|
+
"type": [
|
|
2391
|
+
"string",
|
|
2392
|
+
"null"
|
|
2393
|
+
]
|
|
2394
|
+
},
|
|
2378
2395
|
"parent": {
|
|
2379
2396
|
"type": "string"
|
|
2380
2397
|
},
|
|
@@ -2383,12 +2400,6 @@
|
|
|
2383
2400
|
},
|
|
2384
2401
|
"state": {
|
|
2385
2402
|
"$ref": "#/$defs/SpawnState"
|
|
2386
|
-
},
|
|
2387
|
-
"subject_id": {
|
|
2388
|
-
"type": [
|
|
2389
|
-
"string",
|
|
2390
|
-
"null"
|
|
2391
|
-
]
|
|
2392
2403
|
}
|
|
2393
2404
|
},
|
|
2394
2405
|
"required": [
|
|
@@ -2420,6 +2431,7 @@
|
|
|
2420
2431
|
},
|
|
2421
2432
|
"Standing": {
|
|
2422
2433
|
"enum": [
|
|
2434
|
+
"reserved",
|
|
2423
2435
|
"pending",
|
|
2424
2436
|
"granted",
|
|
2425
2437
|
"duplicate",
|
|
@@ -1096,6 +1096,9 @@
|
|
|
1096
1096
|
}
|
|
1097
1097
|
]
|
|
1098
1098
|
},
|
|
1099
|
+
"claim_id": {
|
|
1100
|
+
"type": "string"
|
|
1101
|
+
},
|
|
1099
1102
|
"identity_unresolved": {
|
|
1100
1103
|
"type": "boolean"
|
|
1101
1104
|
},
|
|
@@ -1126,6 +1129,7 @@
|
|
|
1126
1129
|
},
|
|
1127
1130
|
"required": [
|
|
1128
1131
|
"subject_id",
|
|
1132
|
+
"claim_id",
|
|
1129
1133
|
"process",
|
|
1130
1134
|
"identity_unresolved",
|
|
1131
1135
|
"metadata",
|
|
@@ -2197,6 +2201,13 @@
|
|
|
2197
2201
|
},
|
|
2198
2202
|
"registration": {
|
|
2199
2203
|
"$ref": "#/$defs/PublicRegistration"
|
|
2204
|
+
},
|
|
2205
|
+
"scoped": {
|
|
2206
|
+
"description": "Whether this process runs inside a Radar-established execution scope. A\nprocess started outside the managed launch path has none and is observed.",
|
|
2207
|
+
"type": [
|
|
2208
|
+
"boolean",
|
|
2209
|
+
"null"
|
|
2210
|
+
]
|
|
2200
2211
|
}
|
|
2201
2212
|
},
|
|
2202
2213
|
"required": [
|
|
@@ -2491,6 +2502,12 @@
|
|
|
2491
2502
|
"null"
|
|
2492
2503
|
]
|
|
2493
2504
|
},
|
|
2505
|
+
"claim_id": {
|
|
2506
|
+
"type": [
|
|
2507
|
+
"string",
|
|
2508
|
+
"null"
|
|
2509
|
+
]
|
|
2510
|
+
},
|
|
2494
2511
|
"parent": {
|
|
2495
2512
|
"type": "string"
|
|
2496
2513
|
},
|
|
@@ -2499,18 +2516,12 @@
|
|
|
2499
2516
|
},
|
|
2500
2517
|
"state": {
|
|
2501
2518
|
"$ref": "#/$defs/SpawnState"
|
|
2502
|
-
},
|
|
2503
|
-
"subject_id": {
|
|
2504
|
-
"type": [
|
|
2505
|
-
"string",
|
|
2506
|
-
"null"
|
|
2507
|
-
]
|
|
2508
2519
|
}
|
|
2509
2520
|
},
|
|
2510
2521
|
"required": [
|
|
2511
2522
|
"parent",
|
|
2512
2523
|
"request_id",
|
|
2513
|
-
"
|
|
2524
|
+
"claim_id",
|
|
2514
2525
|
"child_source",
|
|
2515
2526
|
"child_incarnation",
|
|
2516
2527
|
"state"
|
|
@@ -2539,6 +2550,7 @@
|
|
|
2539
2550
|
},
|
|
2540
2551
|
"Standing": {
|
|
2541
2552
|
"enum": [
|
|
2553
|
+
"reserved",
|
|
2542
2554
|
"pending",
|
|
2543
2555
|
"granted",
|
|
2544
2556
|
"duplicate",
|