instar 1.3.1674 → 1.3.1676

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.
Files changed (142) hide show
  1. package/dist/commands/server.d.ts.map +1 -1
  2. package/dist/commands/server.js +55 -6
  3. package/dist/commands/server.js.map +1 -1
  4. package/dist/core/CodexLifecycleProductionComposition.d.ts +1 -1
  5. package/dist/core/CodexLifecycleProductionComposition.d.ts.map +1 -1
  6. package/dist/core/EvolutionArchive.d.ts +79 -0
  7. package/dist/core/EvolutionArchive.d.ts.map +1 -0
  8. package/dist/core/EvolutionArchive.js +309 -0
  9. package/dist/core/EvolutionArchive.js.map +1 -0
  10. package/dist/core/EvolutionArchiveSync.d.ts +26 -0
  11. package/dist/core/EvolutionArchiveSync.d.ts.map +1 -0
  12. package/dist/core/EvolutionArchiveSync.js +109 -0
  13. package/dist/core/EvolutionArchiveSync.js.map +1 -0
  14. package/dist/core/EvolutionManager.d.ts +37 -6
  15. package/dist/core/EvolutionManager.d.ts.map +1 -1
  16. package/dist/core/EvolutionManager.js +210 -149
  17. package/dist/core/EvolutionManager.js.map +1 -1
  18. package/dist/core/FileClassifier.d.ts.map +1 -1
  19. package/dist/core/FileClassifier.js +3 -0
  20. package/dist/core/FileClassifier.js.map +1 -1
  21. package/dist/core/JobCoverage.d.ts +53 -0
  22. package/dist/core/JobCoverage.d.ts.map +1 -0
  23. package/dist/core/JobCoverage.js +194 -0
  24. package/dist/core/JobCoverage.js.map +1 -0
  25. package/dist/core/JobCoverageMonitor.d.ts +84 -0
  26. package/dist/core/JobCoverageMonitor.d.ts.map +1 -0
  27. package/dist/core/JobCoverageMonitor.js +364 -0
  28. package/dist/core/JobCoverageMonitor.js.map +1 -0
  29. package/dist/core/JobDependency.d.ts +4 -0
  30. package/dist/core/JobDependency.d.ts.map +1 -0
  31. package/dist/core/JobDependency.js +30 -0
  32. package/dist/core/JobDependency.js.map +1 -0
  33. package/dist/core/JobPortableBundle.d.ts +61 -0
  34. package/dist/core/JobPortableBundle.d.ts.map +1 -0
  35. package/dist/core/JobPortableBundle.js +302 -0
  36. package/dist/core/JobPortableBundle.js.map +1 -0
  37. package/dist/core/JobPortableFs.d.ts +18 -0
  38. package/dist/core/JobPortableFs.d.ts.map +1 -0
  39. package/dist/core/JobPortableFs.js +65 -0
  40. package/dist/core/JobPortableFs.js.map +1 -0
  41. package/dist/core/JobPortableIntegrity.d.ts +4 -0
  42. package/dist/core/JobPortableIntegrity.d.ts.map +1 -0
  43. package/dist/core/JobPortableIntegrity.js +86 -0
  44. package/dist/core/JobPortableIntegrity.js.map +1 -0
  45. package/dist/core/JobPortableSync.d.ts +79 -0
  46. package/dist/core/JobPortableSync.d.ts.map +1 -0
  47. package/dist/core/JobPortableSync.js +513 -0
  48. package/dist/core/JobPortableSync.js.map +1 -0
  49. package/dist/core/LeaseCoordinator.d.ts.map +1 -1
  50. package/dist/core/LeaseCoordinator.js +4 -3
  51. package/dist/core/LeaseCoordinator.js.map +1 -1
  52. package/dist/core/PostUpdateMigrator.d.ts.map +1 -1
  53. package/dist/core/PostUpdateMigrator.js +38 -3
  54. package/dist/core/PostUpdateMigrator.js.map +1 -1
  55. package/dist/core/ReplicatedStoreReconcilerWiring.d.ts +2 -0
  56. package/dist/core/ReplicatedStoreReconcilerWiring.d.ts.map +1 -1
  57. package/dist/core/ReplicatedStoreReconcilerWiring.js +4 -4
  58. package/dist/core/ReplicatedStoreReconcilerWiring.js.map +1 -1
  59. package/dist/core/WriteDomainRegistry.d.ts.map +1 -1
  60. package/dist/core/WriteDomainRegistry.js +13 -0
  61. package/dist/core/WriteDomainRegistry.js.map +1 -1
  62. package/dist/core/jobMeshAwareness.d.ts +12 -0
  63. package/dist/core/jobMeshAwareness.d.ts.map +1 -0
  64. package/dist/core/jobMeshAwareness.js +37 -0
  65. package/dist/core/jobMeshAwareness.js.map +1 -0
  66. package/dist/core/roleFollowRestart.d.ts +16 -0
  67. package/dist/core/roleFollowRestart.d.ts.map +1 -1
  68. package/dist/core/roleFollowRestart.js +32 -1
  69. package/dist/core/roleFollowRestart.js.map +1 -1
  70. package/dist/core/types.d.ts +24 -4
  71. package/dist/core/types.d.ts.map +1 -1
  72. package/dist/core/types.js.map +1 -1
  73. package/dist/data/standards-guard-index.json +1 -1
  74. package/dist/data/standards-guard-index.meta.json +2 -2
  75. package/dist/data/standards-registry.meta.json +1 -1
  76. package/dist/localVerify/FailedFileDiagnosisPeerService.d.ts.map +1 -1
  77. package/dist/localVerify/FailedFileDiagnosisPeerService.js +3 -1
  78. package/dist/localVerify/FailedFileDiagnosisPeerService.js.map +1 -1
  79. package/dist/messaging/TelegramAdapter.d.ts +4 -0
  80. package/dist/messaging/TelegramAdapter.d.ts.map +1 -1
  81. package/dist/messaging/TelegramAdapter.js +24 -0
  82. package/dist/messaging/TelegramAdapter.js.map +1 -1
  83. package/dist/monitoring/guardManifest.d.ts.map +1 -1
  84. package/dist/monitoring/guardManifest.js +6 -0
  85. package/dist/monitoring/guardManifest.js.map +1 -1
  86. package/dist/native/InstarWedgeCanary.app/Contents/MacOS/InstarWedgeCanary +0 -0
  87. package/dist/native/instar-desktop-host +0 -0
  88. package/dist/scaffold/templates.d.ts.map +1 -1
  89. package/dist/scaffold/templates.js +11 -0
  90. package/dist/scaffold/templates.js.map +1 -1
  91. package/dist/scheduler/AgentMdJobLoader.d.ts +4 -15
  92. package/dist/scheduler/AgentMdJobLoader.d.ts.map +1 -1
  93. package/dist/scheduler/AgentMdJobLoader.js +69 -1
  94. package/dist/scheduler/AgentMdJobLoader.js.map +1 -1
  95. package/dist/scheduler/JobCatalogReconcile.d.ts +2 -0
  96. package/dist/scheduler/JobCatalogReconcile.d.ts.map +1 -0
  97. package/dist/scheduler/JobCatalogReconcile.js +27 -0
  98. package/dist/scheduler/JobCatalogReconcile.js.map +1 -0
  99. package/dist/scheduler/JobLoader.d.ts.map +1 -1
  100. package/dist/scheduler/JobLoader.js +26 -1
  101. package/dist/scheduler/JobLoader.js.map +1 -1
  102. package/dist/scheduler/JobScheduler.d.ts +14 -9
  103. package/dist/scheduler/JobScheduler.d.ts.map +1 -1
  104. package/dist/scheduler/JobScheduler.js +182 -9
  105. package/dist/scheduler/JobScheduler.js.map +1 -1
  106. package/dist/scheduler/PromotionCatchUpStore.d.ts +20 -0
  107. package/dist/scheduler/PromotionCatchUpStore.d.ts.map +1 -0
  108. package/dist/scheduler/PromotionCatchUpStore.js +60 -0
  109. package/dist/scheduler/PromotionCatchUpStore.js.map +1 -0
  110. package/dist/server/AgentServer.d.ts.map +1 -1
  111. package/dist/server/AgentServer.js +1 -0
  112. package/dist/server/AgentServer.js.map +1 -1
  113. package/dist/server/CapabilityIndex.d.ts.map +1 -1
  114. package/dist/server/CapabilityIndex.js +2 -1
  115. package/dist/server/CapabilityIndex.js.map +1 -1
  116. package/dist/server/leaseRenewalDependencies.d.ts +4 -0
  117. package/dist/server/leaseRenewalDependencies.d.ts.map +1 -1
  118. package/dist/server/leaseRenewalDependencies.js +2 -0
  119. package/dist/server/leaseRenewalDependencies.js.map +1 -1
  120. package/dist/server/routes.d.ts +2 -0
  121. package/dist/server/routes.d.ts.map +1 -1
  122. package/dist/server/routes.js +265 -0
  123. package/dist/server/routes.js.map +1 -1
  124. package/dist/testing/selfActionRegistry.d.ts.map +1 -1
  125. package/dist/testing/selfActionRegistry.js +92 -0
  126. package/dist/testing/selfActionRegistry.js.map +1 -1
  127. package/package.json +1 -1
  128. package/scripts/job-portable-fs.py +254 -0
  129. package/scripts/job-portable-sync-rollback.mjs +66 -0
  130. package/src/data/builtin-manifest.json +66 -66
  131. package/src/data/feature-ladders.json +2 -0
  132. package/src/data/standards-guard-index.json +1 -1
  133. package/src/data/standards-guard-index.meta.json +2 -2
  134. package/src/data/standards-registry.meta.json +1 -1
  135. package/src/scaffold/templates.ts +11 -0
  136. package/upgrades/1.3.1675.md +48 -0
  137. package/upgrades/1.3.1676.md +18 -0
  138. package/upgrades/side-effects/evolution-retention-cap-saturation.md +172 -0
  139. package/upgrades/side-effects/lease-job-coverage-and-catchup.md +86 -0
  140. package/upgrades/side-effects/lease-job-definition-replication.md +94 -0
  141. package/upgrades/side-effects/takeover-keeps-lease.md +17 -0
  142. package/upgrades/takeover-keeps-lease.eli16.md +22 -0
@@ -0,0 +1,84 @@
1
+ import type { JobDefinition } from './types.js';
2
+ import type { MachineIdentityManager } from './MachineIdentity.js';
3
+ import { type PeerEndpointKind } from '../server/peerUrlGuard.js';
4
+ import { type PoolPeerTarget, type RopeResultRecorder } from '../server/poolPeerFetch.js';
5
+ import { JobCoverageStore, type JobCoverageEntry } from './JobCoverage.js';
6
+ export interface JobCoverageMonitorOptions {
7
+ stateDir: string;
8
+ jobsFile: string;
9
+ projectDir: string;
10
+ port: number;
11
+ onCatalogRepair?: () => void;
12
+ reconcileDefaults?: (jobsFile: string, port: number) => string[];
13
+ authToken: string;
14
+ identityManager: MachineIdentityManager;
15
+ isAwake: () => boolean;
16
+ peerUrls: () => Array<PoolPeerTarget & {
17
+ kind: PeerEndpointKind;
18
+ }>;
19
+ recordRopeResult?: RopeResultRecorder;
20
+ onPortableCandidate?: (peer: PoolPeerTarget & {
21
+ kind: PeerEndpointKind;
22
+ }, job: JobCoverageEntry, generation: string) => Promise<void>;
23
+ portableGaps?: () => string[];
24
+ alert: (conditionKey: string, title: string, summary: string) => Promise<void>;
25
+ clearAlert?: (conditionKey: string) => void;
26
+ now?: () => number;
27
+ }
28
+ /** Reads only the installed catalog. Scheduler-less standby still has a catalog. */
29
+ export declare function readJobCoverageCatalog(jobsFile: string): {
30
+ jobs: JobDefinition[];
31
+ complete: boolean;
32
+ };
33
+ export declare class JobCoverageMonitor {
34
+ readonly store: JobCoverageStore;
35
+ private readonly options;
36
+ private timer;
37
+ private firstTimer;
38
+ private inFlight;
39
+ private stopped;
40
+ private failures;
41
+ private readonly failureFile;
42
+ private readonly portableCursorFile;
43
+ private portableCursors;
44
+ private readonly auditFile;
45
+ private readonly alertFile;
46
+ private reconciled;
47
+ constructor(options: JobCoverageMonitorOptions);
48
+ localSnapshot(nonce: string): import("./JobCoverage.js").SignedJobCoverage;
49
+ start(): void;
50
+ stop(): void;
51
+ poll(): Promise<void>;
52
+ checkPromotionCoverage(): Promise<void>;
53
+ private markPeerFailure;
54
+ private readFailures;
55
+ private writeFailures;
56
+ private audit;
57
+ private readAlertState;
58
+ private writeAlertState;
59
+ view(): {
60
+ selfMachineId: string;
61
+ localComplete: boolean;
62
+ peers: ({
63
+ machineId: string;
64
+ status: "fresh" | "incomplete" | "stale" | "unavailable";
65
+ observedAt: string;
66
+ ageMs: number;
67
+ jobCount: number;
68
+ complete: boolean;
69
+ failureCount: number;
70
+ reason: string | null;
71
+ } | {
72
+ machineId: string;
73
+ status: string;
74
+ observedAt: null;
75
+ ageMs: null;
76
+ jobCount: null;
77
+ complete: boolean;
78
+ failureCount: number;
79
+ reason: string | null;
80
+ })[];
81
+ differences: import("./JobCoverage.js").JobCoverageDifference[];
82
+ };
83
+ }
84
+ //# sourceMappingURL=JobCoverageMonitor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"JobCoverageMonitor.d.ts","sourceRoot":"","sources":["../../src/core/JobCoverageMonitor.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,364 @@
1
+ /** Peer observation and promotion comparison for scheduler coverage. */
2
+ import { randomBytes, createHash } from 'node:crypto';
3
+ import fs from 'node:fs';
4
+ import path from 'node:path';
5
+ import { isRegistryEntryActive } from './MachineIdentity.js';
6
+ import { isPeerUrlAllowedForCredentials } from '../server/peerUrlGuard.js';
7
+ import { poolPeerFetch } from '../server/poolPeerFetch.js';
8
+ import { loadJobsDetailed } from '../scheduler/JobLoader.js';
9
+ import { reconcileLegacyDefaultJobs } from '../scheduler/JobCatalogReconcile.js';
10
+ import { jobDependencyExists } from './JobDependency.js';
11
+ import { SafeFsExecutor } from './SafeFsExecutor.js';
12
+ import { featureEvidence } from '../monitoring/FeatureEvidenceLog.js';
13
+ import { JobCoverageStore, acceptJobCoverage, assignJobCoverageGeneration, compareJobCoverage, projectJobCoverage, signJobCoverage } from './JobCoverage.js';
14
+ /** Reads only the installed catalog. Scheduler-less standby still has a catalog. */
15
+ export function readJobCoverageCatalog(jobsFile) {
16
+ try {
17
+ if (!fs.existsSync(jobsFile) && !fs.existsSync(path.join(path.dirname(jobsFile), 'jobs', 'schedule'))) {
18
+ return { jobs: [], complete: false };
19
+ }
20
+ const loaded = loadJobsDetailed(jobsFile, { quiet: true });
21
+ return { jobs: loaded.jobs, complete: loaded.problems.length === 0 && loaded.bodyFailures.length === 0
22
+ && !loaded.diagnostics.some(d => d.level === 'error') };
23
+ }
24
+ catch {
25
+ return { jobs: [], complete: false };
26
+ }
27
+ }
28
+ async function readBoundedJson(response, maxBytes = 256 * 1024) {
29
+ const reader = response.body?.getReader();
30
+ if (!reader)
31
+ throw new Error('empty-body');
32
+ const parts = [];
33
+ let length = 0;
34
+ try {
35
+ while (true) {
36
+ const { done, value } = await reader.read();
37
+ if (done)
38
+ break;
39
+ length += value.byteLength;
40
+ if (length > maxBytes)
41
+ throw new Error('oversized-snapshot');
42
+ parts.push(value);
43
+ }
44
+ }
45
+ finally {
46
+ reader.releaseLock();
47
+ }
48
+ const merged = new Uint8Array(length);
49
+ let at = 0;
50
+ for (const part of parts) {
51
+ merged.set(part, at);
52
+ at += part.byteLength;
53
+ }
54
+ return JSON.parse(new TextDecoder().decode(merged));
55
+ }
56
+ export class JobCoverageMonitor {
57
+ store;
58
+ options;
59
+ timer = null;
60
+ firstTimer = null;
61
+ inFlight = false;
62
+ stopped = false;
63
+ failures = new Map();
64
+ failureFile;
65
+ portableCursorFile;
66
+ portableCursors = {};
67
+ auditFile;
68
+ alertFile;
69
+ reconciled = false;
70
+ constructor(options) {
71
+ this.options = options;
72
+ this.store = new JobCoverageStore(options.stateDir);
73
+ this.alertFile = path.join(options.stateDir, 'state', 'job-coverage-alert.json');
74
+ this.failureFile = path.join(options.stateDir, 'state', 'job-coverage-poll.json');
75
+ this.portableCursorFile = path.join(options.stateDir, 'state', 'job-portable-cursors.json');
76
+ try {
77
+ const parsed = JSON.parse(fs.readFileSync(this.portableCursorFile, 'utf8'));
78
+ if (parsed.version === 1 && parsed.cursors && typeof parsed.cursors === 'object')
79
+ this.portableCursors = parsed.cursors;
80
+ }
81
+ catch { /* first observation starts at the first portable job */ }
82
+ this.auditFile = path.join(options.stateDir, 'state', 'job-coverage-audit.jsonl');
83
+ this.failures = this.readFailures();
84
+ }
85
+ localSnapshot(nonce) {
86
+ const identity = this.options.identityManager.loadIdentity();
87
+ const catalog = readJobCoverageCatalog(this.options.jobsFile);
88
+ const payload = assignJobCoverageGeneration(projectJobCoverage(identity.machineId, catalog.jobs, catalog.complete), this.options.stateDir);
89
+ return signJobCoverage(payload, nonce, this.options.identityManager.loadSigningKey());
90
+ }
91
+ start() {
92
+ if (this.timer || this.stopped)
93
+ return;
94
+ const tick = () => {
95
+ void this.poll().then(() => this.checkPromotionCoverage())
96
+ .catch(error => { /* @silent-fallback-ok — the next bounded tick retries; the error is logged */ console.warn('[job-coverage] tick failed:', error); });
97
+ };
98
+ this.firstTimer = setTimeout(tick, 2000);
99
+ this.firstTimer.unref?.();
100
+ this.timer = setInterval(tick, 5 * 60_000);
101
+ this.timer.unref?.();
102
+ }
103
+ stop() {
104
+ this.stopped = true;
105
+ if (this.timer)
106
+ clearInterval(this.timer);
107
+ if (this.firstTimer)
108
+ clearTimeout(this.firstTimer);
109
+ this.timer = null;
110
+ this.firstTimer = null;
111
+ }
112
+ async poll() {
113
+ if (this.inFlight || this.stopped)
114
+ return;
115
+ this.inFlight = true;
116
+ try {
117
+ const identity = this.options.identityManager.loadIdentity();
118
+ const registered = Object.entries(this.options.identityManager.loadRegistry().machines)
119
+ .filter(([id, entry]) => id !== identity.machineId && isRegistryEntryActive(entry));
120
+ const urls = new Map(this.options.peerUrls().map(p => [p.machineId, p]));
121
+ // Two requests at a time, no overlapping ticks.
122
+ for (let i = 0; i < registered.length; i += 2) {
123
+ await Promise.all(registered.slice(i, i + 2).map(async ([id]) => {
124
+ const peer = urls.get(id);
125
+ const now = this.options.now?.() ?? Date.now();
126
+ if (now < (this.failures.get(id)?.nextEligibleAt ?? 0))
127
+ return;
128
+ if (!peer) {
129
+ this.markPeerFailure(id, 'no-reachable-url', now);
130
+ return;
131
+ }
132
+ if (!isPeerUrlAllowedForCredentials({ url: peer.url, kind: peer.kind }).ok) {
133
+ this.markPeerFailure(id, 'url-refused', now);
134
+ return;
135
+ }
136
+ const publicKey = this.options.identityManager.getSigningPublicKeyPem(id);
137
+ if (!publicKey) {
138
+ this.markPeerFailure(id, 'identity-unverifiable', now);
139
+ return;
140
+ }
141
+ let lastError = null;
142
+ for (let attempt = 0; attempt < 2; attempt++) {
143
+ const nonce = randomBytes(32).toString('hex');
144
+ try {
145
+ const response = await poolPeerFetch(this.options.recordRopeResult, peer, `/jobs/coverage-snapshot?nonce=${nonce}`, { headers: { Authorization: `Bearer ${this.options.authToken}` },
146
+ signal: AbortSignal.timeout(3000), redirect: 'manual' });
147
+ if (!response.ok)
148
+ throw new Error(`http-${response.status}`);
149
+ const payload = acceptJobCoverage(await readBoundedJson(response), id, nonce, publicKey);
150
+ if (!payload)
151
+ throw new Error('invalid-signed-snapshot');
152
+ this.store.record(payload, new Date(now));
153
+ if (this.options.onPortableCandidate) {
154
+ // A bounded transfer attempt follows a verified advertisement; failure is
155
+ // logged as a portability gap and never reclassifies signed metadata as bad.
156
+ const candidates = payload.jobs.filter(row => row.portable === true);
157
+ const start = (this.portableCursors[id] ?? 0) % Math.max(1, candidates.length);
158
+ const selected = candidates.length > 20
159
+ ? Array.from({ length: 20 }, (_, n) => candidates[(start + n) % candidates.length])
160
+ : candidates;
161
+ this.portableCursors[id] = candidates.length ? (start + selected.length) % candidates.length : 0;
162
+ fs.mkdirSync(path.dirname(this.portableCursorFile), { recursive: true });
163
+ const cursorTmp = `${this.portableCursorFile}.${process.pid}.tmp`;
164
+ fs.writeFileSync(cursorTmp, JSON.stringify({ version: 1, cursors: this.portableCursors }), { mode: 0o600 });
165
+ fs.renameSync(cursorTmp, this.portableCursorFile);
166
+ for (const job of selected) {
167
+ try {
168
+ await this.options.onPortableCandidate(peer, job, payload.generation);
169
+ }
170
+ catch (error) { // @silent-fallback-ok — evidence and warning report transfer failure; no candidate is admitted by this handler
171
+ featureEvidence.record('multiMachine.jobDefinitionSync', { kind: 'error',
172
+ reason: 'portable transfer unavailable', context: { source: id, slug: job.slug } });
173
+ console.warn(`[job-coverage] portable transfer unavailable for ${job.slug}:`, error);
174
+ }
175
+ }
176
+ }
177
+ this.failures.delete(id);
178
+ this.writeFailures();
179
+ this.audit('peer-observed', id);
180
+ lastError = null;
181
+ break;
182
+ }
183
+ catch (error) {
184
+ lastError = error;
185
+ }
186
+ }
187
+ if (lastError) {
188
+ const message = lastError instanceof Error ? lastError.message : '';
189
+ const failureClass = /^(?:http-[0-9]{3}|invalid-signed-snapshot|oversized-snapshot|empty-body)$/.test(message)
190
+ ? message : 'fetch-failed';
191
+ this.markPeerFailure(id, failureClass, now);
192
+ }
193
+ }));
194
+ }
195
+ }
196
+ catch (error) {
197
+ console.warn('[job-coverage] poll failed:', error);
198
+ }
199
+ finally {
200
+ this.inFlight = false;
201
+ }
202
+ }
203
+ async checkPromotionCoverage() {
204
+ if (!this.options.isAwake() || this.stopped)
205
+ return;
206
+ const identity = this.options.identityManager.loadIdentity();
207
+ if (!this.reconciled) {
208
+ try {
209
+ const installed = (this.options.reconcileDefaults ?? reconcileLegacyDefaultJobs)(this.options.jobsFile, this.options.port);
210
+ if (installed.length > 0) {
211
+ this.options.onCatalogRepair?.();
212
+ this.audit('catalog-repaired', identity.machineId, String(installed.length));
213
+ }
214
+ this.reconciled = true;
215
+ }
216
+ catch (error) {
217
+ console.warn('[job-coverage] safe catalog repair failed:', error);
218
+ }
219
+ }
220
+ const local = readJobCoverageCatalog(this.options.jobsFile);
221
+ const own = projectJobCoverage(identity.machineId, local.jobs, local.complete);
222
+ const observations = this.store.list(this.options.now?.() ?? Date.now());
223
+ const registered = Object.entries(this.options.identityManager.loadRegistry().machines)
224
+ .filter(([id, entry]) => id !== identity.machineId && isRegistryEntryActive(entry));
225
+ const active = Object.fromEntries(Object.entries(observations)
226
+ .filter(([id]) => registered.some(([registeredId]) => registeredId === id)));
227
+ const differences = compareJobCoverage(own.jobs, active, identity.machineId, identity.name);
228
+ for (const job of local.jobs) {
229
+ if (!job.enabled || !job.requiredPaths?.length)
230
+ continue;
231
+ if (job.requiredPaths.some(dependency => !jobDependencyExists(this.options.projectDir, dependency))) {
232
+ differences.push({ slug: job.slug, sourceMachineId: identity.machineId,
233
+ reason: 'dependency', observedAt: new Date().toISOString(), stale: false });
234
+ }
235
+ }
236
+ const unknown = registered.filter(([id]) => !observations[id] || observations[id].status !== 'fresh').map(([id]) => id);
237
+ const portableGaps = this.options.portableGaps?.() ?? [];
238
+ if (differences.length === 0 && unknown.length === 0 && portableGaps.length === 0 && local.complete) {
239
+ if (fs.existsSync(this.alertFile)) {
240
+ try {
241
+ this.options.clearAlert?.('lease-job-coverage');
242
+ SafeFsExecutor.safeRmSync(this.alertFile, { force: true, operation: 'JobCoverageMonitor.closeRecoveredEpisode' });
243
+ this.audit('coverage-recovered', identity.machineId);
244
+ }
245
+ catch (error) {
246
+ console.warn('[job-coverage] could not close recovered alert:', error);
247
+ }
248
+ }
249
+ return;
250
+ }
251
+ const summary = [
252
+ ...(!local.complete ? ['Local job catalog is incomplete; coverage cannot be proven'] : []),
253
+ ...differences.slice(0, 20).map(d => `${d.slug}: ${d.reason} (seen on ${d.sourceMachineId}${d.stale ? ', stale' : ''})`),
254
+ ...portableGaps.slice(0, 20),
255
+ ...(unknown.length ? [`Coverage uncertain for ${unknown.length} peer(s): ${unknown.slice(0, 5).join(', ')}`] : []),
256
+ ].join('\n');
257
+ const conditionKey = 'lease-job-coverage';
258
+ const now = this.options.now?.() ?? Date.now();
259
+ const fingerprint = createHash('sha256').update(summary).digest('hex');
260
+ const prior = this.readAlertState();
261
+ if (prior?.fingerprint === fingerprint) {
262
+ const floor = prior.deliveredAt ? 24 * 60 * 60_000 : 60 * 60_000;
263
+ if (now - prior.at < floor)
264
+ return;
265
+ }
266
+ this.writeAlertState({ fingerprint, at: now, deliveredAt: null });
267
+ try {
268
+ await this.options.alert(conditionKey, 'Scheduled jobs need review after lease handoff', summary);
269
+ this.writeAlertState({ fingerprint, at: now, deliveredAt: now });
270
+ this.audit('coverage-alert-delivered', identity.machineId);
271
+ }
272
+ catch (error) {
273
+ console.warn('[job-coverage] alert delivery failed:', error);
274
+ }
275
+ }
276
+ markPeerFailure(machineId, reason, now) {
277
+ const count = (this.failures.get(machineId)?.count ?? 0) + 1;
278
+ this.failures.set(machineId, { count, nextEligibleAt: now + Math.min(30 * 60_000, count >= 3 ? 15 * 60_000 : 5 * 60_000 * 2 ** (count - 1)) });
279
+ this.writeFailures();
280
+ this.store.markUnavailable(machineId, reason);
281
+ this.audit('peer-unavailable', machineId, reason);
282
+ }
283
+ readFailures() {
284
+ try {
285
+ const raw = fs.readFileSync(this.failureFile, 'utf8');
286
+ if (raw.length > 32 * 1024)
287
+ return new Map();
288
+ const rows = JSON.parse(raw);
289
+ return new Map(Object.entries(rows).filter(([id, row]) => /^[a-zA-Z0-9_-]{1,128}$/.test(id)
290
+ && Number.isSafeInteger(row?.count) && row.count > 0 && row.count <= 100000
291
+ && Number.isFinite(row.nextEligibleAt)));
292
+ }
293
+ catch {
294
+ return new Map();
295
+ }
296
+ }
297
+ writeFailures() {
298
+ fs.mkdirSync(path.dirname(this.failureFile), { recursive: true });
299
+ const tmp = `${this.failureFile}.${process.pid}.tmp`;
300
+ fs.writeFileSync(tmp, JSON.stringify(Object.fromEntries(this.failures)), { mode: 0o600 });
301
+ fs.renameSync(tmp, this.failureFile);
302
+ }
303
+ audit(event, machineId, reason) {
304
+ try {
305
+ fs.mkdirSync(path.dirname(this.auditFile), { recursive: true });
306
+ if (fs.existsSync(this.auditFile) && fs.statSync(this.auditFile).size > 1024 * 1024) {
307
+ const rotated = `${this.auditFile}.1`;
308
+ SafeFsExecutor.safeRmSync(rotated, { force: true, operation: 'JobCoverageMonitor.rotateAudit' });
309
+ fs.renameSync(this.auditFile, rotated);
310
+ }
311
+ fs.appendFileSync(this.auditFile, JSON.stringify({ at: new Date(this.options.now?.() ?? Date.now()).toISOString(),
312
+ event, machineId, ...(reason ? { reason: reason.slice(0, 100) } : {}) }) + '\n', { mode: 0o600 });
313
+ }
314
+ catch (error) { /* @silent-fallback-ok — audit loss is logged; coverage state remains authoritative */
315
+ console.warn('[job-coverage] audit write failed:', error);
316
+ }
317
+ }
318
+ readAlertState() {
319
+ try {
320
+ const raw = JSON.parse(fs.readFileSync(this.alertFile, 'utf8'));
321
+ if (typeof raw.fingerprint === 'string' && typeof raw.at === 'number') {
322
+ return { fingerprint: raw.fingerprint, at: raw.at,
323
+ deliveredAt: typeof raw.deliveredAt === 'number' ? raw.deliveredAt : null };
324
+ }
325
+ }
326
+ catch { /* @silent-fallback-ok — no prior episode is normal */ }
327
+ return null;
328
+ }
329
+ writeAlertState(state) {
330
+ fs.mkdirSync(path.dirname(this.alertFile), { recursive: true });
331
+ const tmp = `${this.alertFile}.${process.pid}.tmp`;
332
+ fs.writeFileSync(tmp, JSON.stringify(state), { mode: 0o600 });
333
+ fs.renameSync(tmp, this.alertFile);
334
+ }
335
+ view() {
336
+ const identity = this.options.identityManager.loadIdentity();
337
+ const local = readJobCoverageCatalog(this.options.jobsFile);
338
+ const observations = this.store.list(this.options.now?.() ?? Date.now());
339
+ const registered = Object.entries(this.options.identityManager.loadRegistry().machines)
340
+ .filter(([id, entry]) => id !== identity.machineId && isRegistryEntryActive(entry));
341
+ const peers = registered.map(([machineId]) => {
342
+ const row = observations[machineId];
343
+ const failureCount = this.failures.get(machineId)?.count ?? 0;
344
+ return row ? { machineId, status: row.status, observedAt: row.observedAt,
345
+ ageMs: Math.max(0, (this.options.now?.() ?? Date.now()) - Date.parse(row.observedAt)),
346
+ jobCount: row.payload.jobs.length, complete: row.payload.complete, failureCount,
347
+ reason: row.error ?? null }
348
+ : { machineId, status: failureCount ? 'unavailable' : 'unknown', observedAt: null,
349
+ ageMs: null, jobCount: null, complete: false, failureCount,
350
+ reason: failureCount ? 'poll-failed' : null };
351
+ });
352
+ const active = Object.fromEntries(Object.entries(observations)
353
+ .filter(([id]) => registered.some(([registeredId]) => registeredId === id)));
354
+ const differences = compareJobCoverage(projectJobCoverage(identity.machineId, local.jobs, local.complete).jobs, active, identity.machineId, identity.name);
355
+ for (const job of local.jobs) {
356
+ if (job.enabled && job.requiredPaths?.some(dependency => !jobDependencyExists(this.options.projectDir, dependency))) {
357
+ differences.push({ slug: job.slug, sourceMachineId: identity.machineId,
358
+ reason: 'dependency', observedAt: new Date().toISOString(), stale: false });
359
+ }
360
+ }
361
+ return { selfMachineId: identity.machineId, localComplete: local.complete, peers, differences };
362
+ }
363
+ }
364
+ //# sourceMappingURL=JobCoverageMonitor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"JobCoverageMonitor.js","sourceRoot":"","sources":["../../src/core/JobCoverageMonitor.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ export declare function validJobDependencyPath(value: unknown): value is string;
2
+ /** Reject symlinks at every component; a dependency is only an existence signal. */
3
+ export declare function jobDependencyExists(projectRoot: string, relativePath: string): boolean;
4
+ //# sourceMappingURL=JobDependency.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"JobDependency.d.ts","sourceRoot":"","sources":["../../src/core/JobDependency.ts"],"names":[],"mappings":"AAKA,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,MAAM,CAKtE;AAED,oFAAoF;AACpF,wBAAgB,mBAAmB,CAAC,WAAW,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,OAAO,CAWtF"}
@@ -0,0 +1,30 @@
1
+ /** Declared local prerequisites for scheduled jobs; paths never leave this machine. */
2
+ import fs from 'node:fs';
3
+ import path from 'node:path';
4
+ const SECRET_SEGMENT = /^(?:\.env(?:\..*)?|config(?:\.json)?|auth|secrets?|tokens?|credentials?|\.instar)$/i;
5
+ export function validJobDependencyPath(value) {
6
+ if (typeof value !== 'string' || value.length < 1 || value.length > 256 || path.isAbsolute(value)
7
+ || value.includes('\\') || value.includes('\0'))
8
+ return false;
9
+ const parts = value.split('/');
10
+ return parts.every(part => part.length > 0 && part !== '.' && part !== '..' && !SECRET_SEGMENT.test(part));
11
+ }
12
+ /** Reject symlinks at every component; a dependency is only an existence signal. */
13
+ export function jobDependencyExists(projectRoot, relativePath) {
14
+ if (!validJobDependencyPath(relativePath))
15
+ return false;
16
+ let cursor = path.resolve(projectRoot);
17
+ for (const part of relativePath.split('/')) {
18
+ cursor = path.join(cursor, part);
19
+ try {
20
+ const stat = fs.lstatSync(cursor);
21
+ if (stat.isSymbolicLink())
22
+ return false;
23
+ }
24
+ catch { /* @silent-fallback-ok — a missing or unreadable dependency refuses this job */
25
+ return false;
26
+ }
27
+ }
28
+ return true;
29
+ }
30
+ //# sourceMappingURL=JobDependency.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"JobDependency.js","sourceRoot":"","sources":["../../src/core/JobDependency.ts"],"names":[],"mappings":"AAAA,uFAAuF;AACvF,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAE7B,MAAM,cAAc,GAAG,qFAAqF,CAAC;AAC7G,MAAM,UAAU,sBAAsB,CAAC,KAAc;IACnD,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,IAAI,KAAK,CAAC,MAAM,GAAG,GAAG,IAAI,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC;WAC5F,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC;QAAE,OAAO,KAAK,CAAC;IAChE,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAC/B,OAAO,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,IAAI,IAAI,KAAK,GAAG,IAAI,IAAI,KAAK,IAAI,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;AAC7G,CAAC;AAED,oFAAoF;AACpF,MAAM,UAAU,mBAAmB,CAAC,WAAmB,EAAE,YAAoB;IAC3E,IAAI,CAAC,sBAAsB,CAAC,YAAY,CAAC;QAAE,OAAO,KAAK,CAAC;IACxD,IAAI,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC;IACvC,KAAK,MAAM,IAAI,IAAI,YAAY,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC;QAC3C,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;QACjC,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,EAAE,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;YAClC,IAAI,IAAI,CAAC,cAAc,EAAE;gBAAE,OAAO,KAAK,CAAC;QAC1C,CAAC;QAAC,MAAM,CAAC,CAAC,+EAA+E;YAAC,OAAO,KAAK,CAAC;QAAC,CAAC;IAC3G,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC"}
@@ -0,0 +1,61 @@
1
+ export interface PortableFile {
2
+ path: string;
3
+ sha256: string;
4
+ content: string;
5
+ }
6
+ export interface PortableJobBundle {
7
+ version: 1;
8
+ slug: string;
9
+ root: string;
10
+ files: PortableFile[];
11
+ }
12
+ /** Read a user manifest and only its declared files. Unknown manifest fields are refused. */
13
+ export declare function collectPortableJob(projectRoot: string, stateDir: string, slug: string): PortableJobBundle;
14
+ /** Validate a decrypted bundle before storing any bytes. */
15
+ export declare function validatePortableBundle(value: unknown): PortableJobBundle;
16
+ import { type EncryptedSecretPayload } from './SecretStore.js';
17
+ export interface PortableBundleRequest {
18
+ version: 1;
19
+ sourceMachineId: string;
20
+ recipientMachineId: string;
21
+ sourceKeyEpoch: number;
22
+ recipientKeyEpoch: number;
23
+ slug: string;
24
+ nonce: string;
25
+ signature: string;
26
+ }
27
+ export interface PortableBundleWire {
28
+ version: 1;
29
+ sourceMachineId: string;
30
+ recipientMachineId: string;
31
+ sourceKeyEpoch: number;
32
+ recipientKeyEpoch: number;
33
+ slug: string;
34
+ nonce: string;
35
+ root: string;
36
+ generation: number;
37
+ encrypted: EncryptedSecretPayload;
38
+ signature: string;
39
+ }
40
+ export declare function makePortableBundleRequest(sourceMachineId: string, recipientMachineId: string, slug: string, nonce: string, privateKey: string, sourceKeyEpoch?: number, recipientKeyEpoch?: number): PortableBundleRequest;
41
+ export declare function acceptPortableBundleRequest(value: unknown, expectedSource: string, publicKey: string): PortableBundleRequest;
42
+ export declare function makePortableBundleWire(bundle: PortableJobBundle, request: PortableBundleRequest, sourcePrivateKey: string, recipientEncryptionPublicKey: string, generation: number): PortableBundleWire;
43
+ export declare function acceptPortableBundleWire(value: unknown, request: PortableBundleRequest, sourcePublicKey: string, recipientPrivateKeyPem: string): PortableJobBundle;
44
+ export declare class PortableApprovalStore {
45
+ private readonly kind;
46
+ private readonly file;
47
+ constructor(stateDir: string, kind: 'export' | 'activate');
48
+ private read;
49
+ isApproved(slug: string, root: string): boolean;
50
+ approve(slug: string, root: string): void;
51
+ revoke(slug: string): void;
52
+ }
53
+ /** Source-owned monotonic content version, advanced only with an exact-root export approval. */
54
+ export declare class PortableGenerationStore {
55
+ private readonly file;
56
+ constructor(stateDir: string);
57
+ private read;
58
+ current(slug: string, root: string): number | null;
59
+ advance(slug: string, root: string): number;
60
+ }
61
+ //# sourceMappingURL=JobPortableBundle.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"JobPortableBundle.d.ts","sourceRoot":"","sources":["../../src/core/JobPortableBundle.ts"],"names":[],"mappings":"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"}