reploid 0.0.0-stage → 0.1.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.
Files changed (233) hide show
  1. package/apps/poolday/config/chat-files.json +27 -0
  2. package/apps/poolday/config/partition-generation.js +21 -0
  3. package/apps/poolday/config/partition-policy.json +74 -0
  4. package/apps/poolday/config/partition-releases.json +3 -0
  5. package/apps/poolday/config/work-profile.json +122 -0
  6. package/apps/poolday/host/chat-view.js +47 -0
  7. package/apps/poolday/host/earning/client.js +199 -0
  8. package/apps/poolday/host/earning/contribution.js +168 -0
  9. package/apps/poolday/host/partition-release.js +33 -0
  10. package/apps/poolday/host/work-partition-artifact-source.js +37 -0
  11. package/apps/poolday/host/work-partition-capsule.js +39 -0
  12. package/apps/poolday/host/work-partition-plan.js +167 -0
  13. package/apps/poolday/host/work-partition-tokenizer-guard.js +21 -0
  14. package/apps/poolday/infrastructure/model-storage-lock.js +22 -0
  15. package/apps/poolday/infrastructure/pack-release-storage.js +52 -0
  16. package/apps/poolday/pool/pack-operation.js +161 -0
  17. package/apps/poolday/pool/pack-release-policy.js +44 -0
  18. package/apps/poolday/pool/peer-pack-data-channel.js +217 -0
  19. package/apps/poolday/providers/work-adapter.js +67 -0
  20. package/apps/poolday/providers/work-device.js +33 -0
  21. package/apps/poolday/providers/work-generation-completion.js +55 -0
  22. package/apps/poolday/providers/work-provider.js +209 -0
  23. package/apps/poolday/providers/work-resident-provider.js +113 -0
  24. package/deploy/artifacts/doppler-gpu-0.7.1.tgz +0 -0
  25. package/docs/fleet-service.md +214 -0
  26. package/docs/native-participant.md +534 -0
  27. package/native-delivery.json +1174 -0
  28. package/package.json +29 -4
  29. package/packages/reploid/src/artifacts/binary.js +25 -0
  30. package/packages/reploid/src/artifacts/canonical-json.js +23 -0
  31. package/packages/reploid/src/artifacts/custody/exchange.js +402 -0
  32. package/packages/reploid/src/artifacts/custody/piece-acquisition.js +70 -0
  33. package/packages/reploid/src/artifacts/custody/runtime.js +404 -0
  34. package/packages/reploid/src/artifacts/custody/supply-budget.js +19 -0
  35. package/packages/reploid/src/artifacts/custody-certificate.js +123 -0
  36. package/packages/reploid/src/artifacts/delivery-attestation.js +64 -0
  37. package/packages/reploid/src/artifacts/generation-terminal.js +36 -0
  38. package/packages/reploid/src/artifacts/identity.js +91 -0
  39. package/packages/reploid/src/artifacts/participant-proofs.js +159 -0
  40. package/packages/reploid/src/artifacts/receipt.js +131 -0
  41. package/packages/reploid/src/artifacts/signatures.js +94 -0
  42. package/packages/reploid/src/artifacts/whole-model-receipt.js +42 -0
  43. package/packages/reploid/src/cancellation.js +44 -0
  44. package/packages/reploid/src/config/defaults.json +110 -0
  45. package/packages/reploid/src/config/index.js +209 -0
  46. package/packages/reploid/src/config/request-overrides.json +9 -0
  47. package/packages/reploid/src/config/transport-defaults.json +7 -0
  48. package/packages/reploid/src/hashing.js +30 -0
  49. package/packages/reploid/src/measurement/capacity-utilization.js +321 -0
  50. package/packages/reploid/src/measurement/index.js +5 -0
  51. package/packages/reploid/src/measurement/readiness-records.js +310 -0
  52. package/packages/reploid/src/mesh/computer-identity.js +50 -0
  53. package/packages/reploid/src/mesh/computer-identity.policy.json +8 -0
  54. package/packages/reploid/src/mesh/contribution.js +141 -0
  55. package/packages/reploid/src/mesh/generation-recovery.js +58 -0
  56. package/packages/reploid/src/mesh/gpu-signature-shader.js +27 -0
  57. package/packages/reploid/src/mesh/gpu-signature.js +136 -0
  58. package/packages/reploid/src/mesh/gpu-signature.policy.json +11 -0
  59. package/packages/reploid/src/mesh/index.js +66 -0
  60. package/packages/reploid/src/mesh/partitions/automatic-ordered-partitions.js +540 -0
  61. package/packages/reploid/src/mesh/partitions/automatic-partitions.js +298 -0
  62. package/packages/reploid/src/mesh/partitions/partition-attempt-evidence.js +282 -0
  63. package/packages/reploid/src/mesh/partitions/partition-attempt-queue-policy.json +6 -0
  64. package/packages/reploid/src/mesh/partitions/partition-attempt-queue.js +112 -0
  65. package/packages/reploid/src/mesh/partitions/partition-canonical-contract.js +167 -0
  66. package/packages/reploid/src/mesh/partitions/partition-canonical-execution.js +168 -0
  67. package/packages/reploid/src/mesh/partitions/partition-chat-canonical.js +49 -0
  68. package/packages/reploid/src/mesh/partitions/partition-chat.js +125 -0
  69. package/packages/reploid/src/mesh/partitions/partition-contract.js +192 -0
  70. package/packages/reploid/src/mesh/partitions/partition-device-admission.js +96 -0
  71. package/packages/reploid/src/mesh/partitions/partition-discovery.js +96 -0
  72. package/packages/reploid/src/mesh/partitions/partition-entry-publication.js +183 -0
  73. package/packages/reploid/src/mesh/partitions/partition-entry.js +434 -0
  74. package/packages/reploid/src/mesh/partitions/partition-generation-request.js +33 -0
  75. package/packages/reploid/src/mesh/partitions/partition-grants.js +277 -0
  76. package/packages/reploid/src/mesh/partitions/partition-link.js +103 -0
  77. package/packages/reploid/src/mesh/partitions/partition-network.js +109 -0
  78. package/packages/reploid/src/mesh/partitions/partition-ordered-chat.js +290 -0
  79. package/packages/reploid/src/mesh/partitions/partition-ordered-peer.js +415 -0
  80. package/packages/reploid/src/mesh/partitions/partition-ordered-publication.js +100 -0
  81. package/packages/reploid/src/mesh/partitions/partition-peer.js +314 -0
  82. package/packages/reploid/src/mesh/partitions/partition-placement.js +143 -0
  83. package/packages/reploid/src/mesh/partitions/partition-preparation-progress.js +25 -0
  84. package/packages/reploid/src/mesh/partitions/partition-receiver-policy.json +7 -0
  85. package/packages/reploid/src/mesh/partitions/partition-reservations.js +75 -0
  86. package/packages/reploid/src/mesh/partitions/partition-route-envelope-policy.json +16 -0
  87. package/packages/reploid/src/mesh/partitions/partition-route-envelope.js +74 -0
  88. package/packages/reploid/src/mesh/partitions/partition-route-execution.js +409 -0
  89. package/packages/reploid/src/mesh/partitions/partition-route-network.js +179 -0
  90. package/packages/reploid/src/mesh/partitions/partition-route-ranking.js +268 -0
  91. package/packages/reploid/src/mesh/partitions/partition-runner.js +319 -0
  92. package/packages/reploid/src/mesh/partitions/partition-stage-assignment.js +109 -0
  93. package/packages/reploid/src/mesh/partitions/partition-stage-commit.js +103 -0
  94. package/packages/reploid/src/mesh/partitions/partition-step-receiver.js +291 -0
  95. package/packages/reploid/src/mesh/partitions/partition-summary.js +122 -0
  96. package/packages/reploid/src/mesh/partitions/preparation-owner.js +40 -0
  97. package/packages/reploid/src/mesh/partitions/resident-error-codes.json +10 -0
  98. package/packages/reploid/src/mesh/partitions/resident-partition.js +333 -0
  99. package/packages/reploid/src/mesh/partitions/resident-route.js +46 -0
  100. package/packages/reploid/src/mesh/partitions/signed-resident-factory.js +59 -0
  101. package/packages/reploid/src/mesh/peer-generation.js +896 -0
  102. package/packages/reploid/src/mesh/peer-identity.js +87 -0
  103. package/packages/reploid/src/mesh/placement-beliefs.js +107 -0
  104. package/packages/reploid/src/mesh/preparation-progress.js +46 -0
  105. package/packages/reploid/src/mesh/provider-hardware.js +11 -0
  106. package/packages/reploid/src/mesh/remote-generation-requests.js +53 -0
  107. package/packages/reploid/src/mesh/swarm-coordination.js +140 -0
  108. package/packages/reploid/src/mesh/web-access-network.js +112 -0
  109. package/packages/reploid/src/mesh/web-access-policy.json +17 -0
  110. package/packages/reploid/src/retrieval/citations.js +156 -0
  111. package/packages/reploid/src/retrieval/claim-support.js +113 -0
  112. package/packages/reploid/src/retrieval/costs.js +101 -0
  113. package/packages/reploid/src/retrieval/fixed-provider.js +34 -0
  114. package/packages/reploid/src/retrieval/index.js +20 -0
  115. package/packages/reploid/src/retrieval/lexical-support.js +27 -0
  116. package/packages/reploid/src/retrieval/model-reviewer.js +67 -0
  117. package/packages/reploid/src/retrieval/page-fetch.json +10 -0
  118. package/packages/reploid/src/retrieval/page-text.js +182 -0
  119. package/packages/reploid/src/retrieval/passage.js +37 -0
  120. package/packages/reploid/src/retrieval/policy.json +14 -0
  121. package/packages/reploid/src/retrieval/retrieval.js +23 -0
  122. package/packages/reploid/src/retrieval/review-queue.js +76 -0
  123. package/packages/reploid/src/retrieval/sources.js +263 -0
  124. package/packages/reploid/src/retrieval/support-review.js +155 -0
  125. package/packages/reploid/src/retrieval/text.js +21 -0
  126. package/packages/reploid/src/rules/contribution.rules.json +8 -0
  127. package/packages/reploid/src/rules/routing.rules.json +24 -0
  128. package/packages/reploid/src/transport/assignment.js +571 -0
  129. package/packages/reploid/src/transport/bounded-channel-writer.js +46 -0
  130. package/packages/reploid/src/transport/index.js +11 -0
  131. package/packages/reploid/src/transport/introduction-admission.js +24 -0
  132. package/packages/reploid/src/transport/introduction-bootstrap.js +112 -0
  133. package/packages/reploid/src/transport/introduction-policy.json +12 -0
  134. package/packages/reploid/src/transport/introduction-records.js +90 -0
  135. package/packages/reploid/src/transport/introductions.js +209 -0
  136. package/packages/reploid/src/transport/partition-data-channel.js +421 -0
  137. package/packages/reploid/src/transport/partition-errors.json +16 -0
  138. package/packages/reploid/src/transport/retry-policy.js +36 -0
  139. package/packages/reploid/src/transport/room.js +502 -0
  140. package/packages/reploid/src/transport/sdp-fingerprint.js +5 -0
  141. package/packages/reploid/src/transport/signaling.js +571 -0
  142. package/packages/reploid/src/transport/swarm.js +1247 -0
  143. package/packages/reploid/src/transport/tool-offer-channel.js +137 -0
  144. package/server/browser-roots.js +42 -0
  145. package/server/browser-web-worker.js +94 -0
  146. package/server/chat-completions.js +45 -0
  147. package/server/fleet/browser-bridge.js +145 -0
  148. package/server/fleet/contract.js +42 -0
  149. package/server/fleet/credit-evidence.js +103 -0
  150. package/server/fleet/credit-recovery.js +175 -0
  151. package/server/fleet/credits.js +178 -0
  152. package/server/fleet/execution-admission.js +32 -0
  153. package/server/fleet/native-host.js +817 -0
  154. package/server/fleet/placement.js +132 -0
  155. package/server/fleet/requester.js +346 -0
  156. package/server/fleet/service.js +311 -0
  157. package/server/fleet/terminal-policy.js +83 -0
  158. package/server/fleet/text-api.js +94 -0
  159. package/server/hashing.js +35 -0
  160. package/server/http-request-owner.js +49 -0
  161. package/server/messages.js +57 -0
  162. package/server/native-canonical-epochs.js +90 -0
  163. package/server/native-change-log.js +40 -0
  164. package/server/native-earning.js +203 -0
  165. package/server/native-generation-journal.js +46 -0
  166. package/server/native-model-config.js +57 -0
  167. package/server/native-model-files.js +382 -0
  168. package/server/native-model-origin.js +54 -0
  169. package/server/native-model-origins.json +12 -0
  170. package/server/native-node.js +83 -0
  171. package/server/native-owner/controls.js +162 -0
  172. package/server/native-owner/monitor.js +251 -0
  173. package/server/native-owner/policy.js +273 -0
  174. package/server/native-owner/rate.js +92 -0
  175. package/server/native-participant.js +866 -0
  176. package/server/native-readiness-log.js +30 -0
  177. package/server/native-release-storage.js +64 -0
  178. package/server/native-shader-cache.js +369 -0
  179. package/server/native-supply-budget.js +66 -0
  180. package/server/native-whole-earning.js +67 -0
  181. package/server/native-whole-model-fill.js +182 -0
  182. package/server/native-whole-model.js +130 -0
  183. package/server/public-web-worker.js +66 -0
  184. package/server/responses.js +92 -0
  185. package/server/search/errors.js +47 -0
  186. package/server/search/page-fetch.js +185 -0
  187. package/server/text-api.js +83 -0
  188. package/server/text-recovery.js +45 -0
  189. package/server/text-request-options.js +23 -0
  190. package/server/text-requester.js +231 -0
  191. package/server/token-auth.js +9 -0
  192. package/server/whole-model-requester.js +99 -0
  193. package/shared/config/chat-models.json +4685 -0
  194. package/shared/config/doppler-execution-contracts.js +32 -0
  195. package/shared/config/doppler-execution-contracts.json +43 -0
  196. package/shared/config/doppler-generation-contract.js +223 -0
  197. package/shared/config/doppler-local-models.js +79 -0
  198. package/shared/config/doppler-package.json +7 -0
  199. package/shared/config/model-manifests/a0dc69e917133a82780823d17fc771c0f6b882d7c86c571deeaef45be2ff108b.json +6434 -0
  200. package/shared/config/model-manifests/e985e3cdad60d0cb57d84b436161e66ab5b3f6589a168de6f00b4610e5f1fb59.json +16534 -0
  201. package/shared/config/model-manifests/fa6eb7bbc3ba63571f8cede780b877d9272bde948697af93dd3d33837cb46137.json +7175 -0
  202. package/shared/config/model-pieces/qwen-0-8b-pieces.json +1506 -0
  203. package/shared/config/model-pieces/qwen-2b-pieces.json +4800 -0
  204. package/shared/config/model-pieces/qwen35b-q4_0-pieces.json +28880 -0
  205. package/shared/config/reploid-library.json +49 -0
  206. package/shared/config/swarm-bootstrap.json +21 -0
  207. package/shared/infrastructure/doppler-runtime-service.js +261 -0
  208. package/shared/pool/executable-pack.js +87 -0
  209. package/shared/pool/pack-operation-adapters.js +124 -0
  210. package/shared/pool/pack-operation-policy.js +75 -0
  211. package/shared/pool/pool-config.json +2280 -0
  212. package/shared/vendor/reploid/adapters/doppler-session.js +372 -0
  213. package/shared/vendor/reploid/artifacts/binary.js +25 -0
  214. package/shared/vendor/reploid/artifacts/canonical-json.js +23 -0
  215. package/shared/vendor/reploid/artifacts/delivery-attestation.js +64 -0
  216. package/shared/vendor/reploid/artifacts/identity.js +91 -0
  217. package/shared/vendor/reploid/artifacts/manifest-identity.js +17 -0
  218. package/shared/vendor/reploid/artifacts/participant-proofs.js +159 -0
  219. package/shared/vendor/reploid/artifacts/signatures.js +94 -0
  220. package/shared/vendor/reploid/config/defaults.json +110 -0
  221. package/shared/vendor/reploid/config/index.js +209 -0
  222. package/shared/vendor/reploid/config/request-overrides.json +9 -0
  223. package/shared/vendor/reploid/hashing.js +30 -0
  224. package/shared/vendor/reploid/mesh/generation-context-cache.js +97 -0
  225. package/shared/vendor/reploid/mesh/partitions/partition-attempt-evidence.js +282 -0
  226. package/shared/vendor/reploid/mesh/partitions/partition-contract.js +192 -0
  227. package/shared/vendor/reploid/mesh/partitions/partition-receiver-policy.json +7 -0
  228. package/shared/vendor/reploid/mesh/partitions/partition-route-ranking.js +268 -0
  229. package/shared/vendor/reploid/mesh/preparation-progress.js +46 -0
  230. package/shared/vendor/reploid/mesh/provider-hardware.js +11 -0
  231. package/shared/vendor/reploid/rules/routing.rules.json +24 -0
  232. package/shared/vendor/reploid/transport/partition-errors.json +16 -0
  233. package/README.md +0 -3
@@ -0,0 +1,268 @@
1
+ import { assertPartition as assert } from './partition-contract.js';
2
+
3
+ /** Expected-cost ranking of eligible prepared routes (DR-6; Launch 3, opt-in). It ranks complete
4
+ * assignments of distinct prepared stages by expected cost per completed answer under an explicit,
5
+ * versioned `reploid.route-cost-policy/v1`; nothing here grants, reserves or moves an attempt.
6
+ * Peer identity is the deterministic tie-breaker, never the placement criterion.
7
+ *
8
+ * For a route, with workload P prompt tokens and T expected tokens, per stage i:
9
+ * latency = prefill_i * P + decode_i * T (stage execution; prices.latencyPerMs)
10
+ * transfer = transfer_i * T (inbound activation transfer; prices.transferPerMs)
11
+ * queueing = (active_i + queued_i) * (latency_i + transfer_i) (advertised capacity; prices.queueingPerMs)
12
+ * opening = 0 for a route already open or the local stage, else its measured channel opening
13
+ * (prices.preparationPerMs). Stage residents are always prepared: unprepared offers are
14
+ * not eligible, so routing never waits on stage preparation.
15
+ * refusal r_i = (refusals_i + readiness.priorRefusals) / (admissions_i + readiness.priorAttempts)
16
+ * reserve = max(0, reserve.spareSlots - (availableSlots_i - 1)) slots below the spare reserve
17
+ * and per route f = (failures + failure.priorFailures) / (executions + failure.priorAttempts).
18
+ * With a = prod(1 - r_i), retries on the same route give N = 1 / (a * (1 - f)) attempts per
19
+ * completed answer, service S = latency + queueing + transfer costs and penalty F = refund + retry:
20
+ * readiness = N * (1 - a) * F failure = N * a * f * (S + F)
21
+ * total = S + preparation + readiness + failure + reserve
22
+ * Unmeasured or stale latency/opening use the policy's declared priors and are labeled as such;
23
+ * outcome probabilities always include the declared prior counts. Totals are compared in units of
24
+ * `resolution`, so routes equal within it tie and fall back to participant ids. Answer quality is
25
+ * route-independent under one model, plan and numerical tolerance and is not a ranking input. */
26
+ export const ROUTE_COST_POLICY_SCHEMA = 'reploid.route-cost-policy/v1';
27
+ export const ROUTE_SELECTION_SCHEMA = 'reploid.route-selection/v1';
28
+ export const ROUTE_RANKING_WORK_LIMIT = 'Route ranking work limit exceeded';
29
+ const RUNTIME = 'executionMs';
30
+ const POLICY_GROUPS = Object.freeze({
31
+ prices: ['latencyPerMs', 'queueingPerMs', 'transferPerMs', 'preparationPerMs', 'refundPerFailure', 'retryPerFailure'],
32
+ unknown: ['prefillMsPerToken', 'decodeMsPerToken', 'transferMsPerToken', 'openingMs', 'maxObservationAgeMs'],
33
+ readiness: ['priorAttempts', 'priorRefusals'],
34
+ failure: ['priorAttempts', 'priorFailures'],
35
+ reserve: ['spareSlots', 'perMissingSlot']
36
+ });
37
+ const COMPONENTS = Object.freeze(['latency', 'queueing', 'transfer', 'preparation', 'readiness', 'failure', 'reserve']);
38
+ const finite = value => typeof value === 'number' && Number.isFinite(value) && value >= 0;
39
+ const count = value => Number.isSafeInteger(value) && value >= 0;
40
+ const mean = row => row && row.count > 0 && finite(row.total) ? row.total / row.count : null;
41
+ const exact = (value, keys) => !!value && typeof value === 'object' && !Array.isArray(value)
42
+ && Object.keys(value).length === keys.length && keys.every(key => Object.hasOwn(value, key));
43
+ const freeze = value => { if (value && typeof value === 'object') { Object.values(value).forEach(freeze); Object.freeze(value); } return value; };
44
+ const stageKey = stages => JSON.stringify(stages.map(({ participantId, transportId, residentId, executionId }) =>
45
+ [participantId, transportId ?? null, residentId ?? null, executionId ?? null]));
46
+
47
+ /** Validates one complete cost policy and returns a frozen copy; a missing or unknown member fails. */
48
+ export function validateRouteCostPolicy(policy) {
49
+ const fail = path => { throw new Error('Explicit route cost policy required: ' + path); };
50
+ if (!exact(policy, ['schema', 'id', 'unit', 'resolution', ...Object.keys(POLICY_GROUPS)])) fail('members');
51
+ if (policy.schema !== ROUTE_COST_POLICY_SCHEMA) fail('schema');
52
+ for (const key of ['id', 'unit']) if (typeof policy[key] !== 'string' || !policy[key].length || policy[key].length > 128) fail(key);
53
+ if (!finite(policy.resolution) || policy.resolution <= 0) fail('resolution');
54
+ for (const [group, keys] of Object.entries(POLICY_GROUPS)) {
55
+ if (!exact(policy[group], keys)) fail(group);
56
+ for (const key of keys) if (!finite(policy[group][key])) fail(group + '.' + key);
57
+ }
58
+ const { unknown, readiness, failure, reserve } = policy;
59
+ // Unmeasured computation is never free; transfer and opening priors may be zero only by declaration.
60
+ if (unknown.prefillMsPerToken <= 0) fail('unknown.prefillMsPerToken');
61
+ if (unknown.decodeMsPerToken <= 0) fail('unknown.decodeMsPerToken');
62
+ if (!Number.isSafeInteger(unknown.maxObservationAgeMs) || unknown.maxObservationAgeMs <= 0) fail('unknown.maxObservationAgeMs');
63
+ if (readiness.priorAttempts <= 0 || readiness.priorRefusals >= readiness.priorAttempts) fail('readiness');
64
+ if (failure.priorAttempts <= 0 || failure.priorFailures >= failure.priorAttempts) fail('failure');
65
+ if (!count(reserve.spareSlots)) fail('reserve.spareSlots');
66
+ return freeze(structuredClone(policy));
67
+ }
68
+
69
+ /** Bounded per (plan, participant, stage) estimates and per-route execution outcomes, measured by this
70
+ * coordinator. Latency and opening fold by exponential smoothing so a recovered or slowed contributor is
71
+ * reflected without unbounded history; admission and execution outcomes are counts of distinct attempts. */
72
+ export function createRouteObservations({ maxEntries, smoothing }) {
73
+ assert(Number.isSafeInteger(maxEntries) && maxEntries > 0 && finite(smoothing) && smoothing > 0 && smoothing <= 1,
74
+ 'Explicit observation limits required');
75
+ const rows = new Map(), routes = new Map();
76
+ const key = (planId, participantId, index) => JSON.stringify([planId, participantId, index]);
77
+ const routeKey = (planId, participants) => JSON.stringify([planId, ...participants]);
78
+ const fold = (previous, value) => value === null ? previous ?? null : previous == null ? value : previous + smoothing * (value - previous);
79
+ const touch = (map, id, value) => { map.delete(id); map.set(id, value); while (map.size > maxEntries) map.delete(map.keys().next().value); };
80
+ const row = (planId, stage) => rows.get(key(planId, stage.participantId, stage.index)) ?? { planId, participantId: stage.participantId,
81
+ index: stage.index, at: null, samples: 0, decodeMs: null, transferMs: null, prefillMsPerToken: null,
82
+ openingMs: null, openedAt: null, admissions: 0, refusals: 0 };
83
+ const bound = (planId, route, at) => assert(typeof planId === 'string' && Array.isArray(route?.stages) && route.stages.length > 0
84
+ && route.stages.every((stage, index) => stage?.index === index && typeof stage.participantId === 'string')
85
+ && Number.isSafeInteger(at), 'Observation binding required');
86
+ return Object.freeze({
87
+ /** Folds one completed attempt's ordered phases (partition-summary.js) into per-stage latency. */
88
+ record({ planId, route, phases, at }) {
89
+ bound(planId, route, at);
90
+ if (!phases?.prompt || !phases.decode) return 0;
91
+ let recorded = 0;
92
+ for (const stage of route.stages) {
93
+ const prompt = phases.prompt.stages?.find(item => item.partitionIndex === stage.index);
94
+ const decode = phases.decode.stages?.find(item => item.partitionIndex === stage.index);
95
+ const decodeMs = mean(decode?.elapsedMs), executionMs = mean(decode?.runtime?.[RUNTIME]);
96
+ const tokens = phases.prompt.inputTokens;
97
+ const prefillMsPerToken = finite(prompt?.elapsedMs) && Number.isSafeInteger(tokens) && tokens > 0 ? prompt.elapsedMs / tokens : null;
98
+ if (decodeMs === null && prefillMsPerToken === null) continue;
99
+ const previous = row(planId, stage);
100
+ touch(rows, key(planId, stage.participantId, stage.index), { ...previous, at, samples: previous.samples + 1,
101
+ decodeMs: fold(previous.decodeMs, decodeMs),
102
+ transferMs: fold(previous.transferMs, decodeMs !== null && executionMs !== null ? Math.max(decodeMs - executionMs, 0) : null),
103
+ prefillMsPerToken: fold(previous.prefillMsPerToken, prefillMsPerToken) });
104
+ recorded++;
105
+ }
106
+ return recorded;
107
+ },
108
+ /** One finished attempt: stages [0, admitted) admitted it; with `refused`, stage `admitted` refused it
109
+ * (readiness). `execution` is the outcome after complete admission, or null when cancelled or never
110
+ * fully admitted. Cancellation is never a refusal or failure. */
111
+ recordOutcome({ planId, route, admitted, refused, execution, at }) {
112
+ bound(planId, route, at);
113
+ const all = route.stages.length;
114
+ assert(Number.isSafeInteger(admitted) && admitted >= 0 && admitted <= all && typeof refused === 'boolean'
115
+ && (!refused || admitted < all) && [null, 'completed', 'failed'].includes(execution)
116
+ && (execution === null || admitted === all), 'Route outcome binding required');
117
+ route.stages.slice(0, admitted + (refused ? 1 : 0)).forEach((stage, position) => {
118
+ const previous = row(planId, stage);
119
+ touch(rows, key(planId, stage.participantId, stage.index), { ...previous, admissions: previous.admissions + 1,
120
+ refusals: previous.refusals + (position === admitted ? 1 : 0) });
121
+ });
122
+ if (execution === null) return;
123
+ const participants = route.stages.map(stage => stage.participantId), id = routeKey(planId, participants);
124
+ const previous = routes.get(id) ?? { planId, participants, at: null, executions: 0, failures: 0 };
125
+ touch(routes, id, { ...previous, at, executions: previous.executions + 1, failures: previous.failures + (execution === 'failed' ? 1 : 0) });
126
+ },
127
+ /** Measured time to open this coordinator's channel to a stage for a new route. */
128
+ recordOpening({ planId, stage, openingMs, at }) {
129
+ assert(typeof planId === 'string' && typeof stage?.participantId === 'string' && Number.isSafeInteger(stage.index)
130
+ && stage.index >= 0 && finite(openingMs) && Number.isSafeInteger(at), 'Opening observation required');
131
+ const previous = row(planId, stage);
132
+ touch(rows, key(planId, stage.participantId, stage.index), { ...previous, openingMs: fold(previous.openingMs, openingMs), openedAt: at });
133
+ },
134
+ get: (planId, participantId, index) => structuredClone(rows.get(key(planId, participantId, index)) ?? null),
135
+ getRoute: (planId, participants) => structuredClone(routes.get(routeKey(planId, participants)) ?? null),
136
+ snapshot: () => structuredClone([...rows.values()]),
137
+ snapshotRoutes: () => structuredClone([...routes.values()])
138
+ });
139
+ }
140
+
141
+ const fresh = (at, now, maxAge) => Number.isSafeInteger(at) && now - at <= maxAge;
142
+
143
+ /** Expected per-stage cost inputs for a new attempt on this candidate, each with its provenance. */
144
+ function stageInputs(candidate, observation, policy, workload, now) {
145
+ const { unknown, readiness, reserve } = policy, maxAge = unknown.maxObservationAgeMs;
146
+ const measuredLatency = observation?.samples > 0 && observation.decodeMs !== null && observation.prefillMsPerToken !== null;
147
+ const latencySource = !measuredLatency ? 'prior' : fresh(observation.at, now, maxAge) ? 'measured' : 'stale';
148
+ const measured = latencySource === 'measured';
149
+ // Measured decode includes the stage's inbound transfer; split only where its execution time was reported.
150
+ const split = measured && observation.transferMs !== null;
151
+ const prefillMsPerToken = measured ? observation.prefillMsPerToken : unknown.prefillMsPerToken;
152
+ const decodeMsPerToken = !measured ? unknown.decodeMsPerToken : split ? Math.max(observation.decodeMs - observation.transferMs, 0) : observation.decodeMs;
153
+ const transferMsPerToken = !measured ? unknown.transferMsPerToken : split ? observation.transferMs : null;
154
+ const latencyMs = prefillMsPerToken * workload.promptTokens + decodeMsPerToken * workload.expectedTokens;
155
+ const transferMs = (transferMsPerToken ?? 0) * workload.expectedTokens;
156
+ const { active, availableSlots } = candidate.capacity, queued = candidate.capacity.queued ?? 0;
157
+ const openingSource = candidate.local ? 'local' : observation?.openingMs == null ? 'prior'
158
+ : fresh(observation.openedAt, now, maxAge) ? 'measured' : 'stale';
159
+ const openingMs = candidate.local ? 0 : openingSource === 'measured' ? observation.openingMs : unknown.openingMs;
160
+ const admissions = observation?.admissions ?? 0, refusals = observation?.refusals ?? 0;
161
+ return { latencyMs, transferMs, queueingMs: (active + queued) * (latencyMs + transferMs), openingMs,
162
+ refusalProbability: (refusals + readiness.priorRefusals) / (admissions + readiness.priorAttempts),
163
+ missingSlots: Math.max(0, reserve.spareSlots - (availableSlots - 1)),
164
+ inputs: { index: candidate.index, participantId: candidate.participantId,
165
+ latency: { source: latencySource, samples: observation?.samples ?? 0, observedAt: observation?.at ?? null,
166
+ prefillMsPerToken, decodeMsPerToken, transfer: split ? 'measured' : measured ? 'within-decode' : latencySource, transferMsPerToken },
167
+ capacity: { active, queued, availableSlots }, opening: { source: openingSource, ms: openingMs },
168
+ admission: { admissions, refusals } } };
169
+ }
170
+
171
+ /** Ranks complete assignments of distinct participants to every stage by expected cost (see above).
172
+ * Full, closed or memory-short candidates are inadmissible; a stage without an admissible candidate
173
+ * yields no route, so a slow device is avoided only by another complete route, never by leaving
174
+ * layers uncovered. `open` lists stage identities of routes this coordinator already opened. */
175
+ export function rankPartitionRoutes({ planId, candidates, observations, workload, limits, policy, now, open = [] }) {
176
+ assert(typeof planId === 'string' && Array.isArray(candidates) && candidates.length > 0 && candidates.every(Array.isArray)
177
+ && typeof observations?.get === 'function' && typeof observations.getRoute === 'function' && Array.isArray(open), 'Route ranking input required');
178
+ const costs = validateRouteCostPolicy(policy);
179
+ assert(Number.isSafeInteger(now) && now >= 0, 'Route ranking clock required');
180
+ assert(Number.isSafeInteger(workload?.promptTokens) && workload.promptTokens > 0
181
+ && Number.isSafeInteger(workload.expectedTokens) && workload.expectedTokens > 0
182
+ && Number.isSafeInteger(workload.allocationBytes) && workload.allocationBytes >= 0, 'Explicit ranking workload required');
183
+ assert(Number.isSafeInteger(limits?.maxParticipants) && Number.isSafeInteger(limits.maxRoutes) && limits.maxRoutes > 0
184
+ && Number.isSafeInteger(limits.maxSelectionSteps) && limits.maxSelectionSteps > 0, 'Explicit ranking limits required');
185
+ const admitted = candidate => candidate.capacity.availableSlots !== 0 && candidate.capacity.closed !== true
186
+ && (candidate.memory == null || finite(candidate.memory.availableBytes) && candidate.memory.availableBytes >= workload.allocationBytes);
187
+ const rows = candidates.map((stage, index) => stage.map(candidate => {
188
+ assert(candidate.index === index && typeof candidate.participantId === 'string', 'Candidate stage mismatch');
189
+ assert(count(candidate.capacity?.active) && count(candidate.capacity.availableSlots)
190
+ && (candidate.capacity.queued === undefined || count(candidate.capacity.queued)), 'Candidate capacity required');
191
+ return structuredClone(candidate);
192
+ }).filter(admitted).map(candidate => ({ candidate, ...stageInputs(candidate, observations.get(planId, candidate.participantId, index), costs, workload, now) }))
193
+ .sort((a, b) => a.candidate.participantId < b.candidate.participantId ? -1 : a.candidate.participantId > b.candidate.participantId ? 1 : 0));
194
+ const participants = [...new Set(rows.flat().map(row => row.candidate.participantId))].sort();
195
+ assert(participants.length <= limits.maxParticipants && participants.length <= 30, 'Route ranking participant limit exceeded');
196
+ const bit = new Map(participants.map((id, index) => [id, 1 << index]));
197
+ const opened = new Set(open.map(stageKey));
198
+ const { prices } = costs, penalty = prices.refundPerFailure + prices.retryPerFailure;
199
+ function price(chosen) {
200
+ const stages = chosen.map(row => row.candidate), ids = stages.map(stage => stage.participantId);
201
+ const prepared = opened.has(stageKey(stages));
202
+ const sum = name => chosen.reduce((total, row) => total + row[name], 0);
203
+ const latencyMs = sum('latencyMs'), queueingMs = sum('queueingMs'), transferMs = sum('transferMs');
204
+ const preparationMs = prepared ? 0 : sum('openingMs'), reserveSlots = sum('missingSlots');
205
+ const admit = chosen.reduce((product, row) => product * (1 - row.refusalProbability), 1);
206
+ const outcome = observations.getRoute(planId, ids), executions = outcome?.executions ?? 0, failures = outcome?.failures ?? 0;
207
+ const failureProbability = (failures + costs.failure.priorFailures) / (executions + costs.failure.priorAttempts);
208
+ const attempts = 1 / (admit * (1 - failureProbability));
209
+ const service = latencyMs * prices.latencyPerMs + queueingMs * prices.queueingPerMs + transferMs * prices.transferPerMs;
210
+ const components = { latency: latencyMs * prices.latencyPerMs, queueing: queueingMs * prices.queueingPerMs,
211
+ transfer: transferMs * prices.transferPerMs, preparation: preparationMs * prices.preparationPerMs,
212
+ readiness: attempts * (1 - admit) * penalty, failure: attempts * admit * failureProbability * (service + penalty),
213
+ reserve: reserveSlots * costs.reserve.perMissingSlot };
214
+ const cost = COMPONENTS.reduce((total, name) => total + components[name], 0);
215
+ return { stages, participants: ids, cost, units: Math.round(cost / costs.resolution), prepared,
216
+ measured: chosen.every(row => row.inputs.latency.source === 'measured'), components,
217
+ expected: { latencyMs, queueingMs, transferMs, preparationMs, reserveSlots, refusalProbability: 1 - admit,
218
+ failureProbability, attemptsPerAnswer: attempts },
219
+ inputs: { stages: chosen.map(row => row.inputs), execution: { executions, failures } } };
220
+ }
221
+ // Enumerate distinct assignments stage by stage in participant order; the bound keeps work explicit.
222
+ const routes = [];
223
+ let steps = 0;
224
+ const walk = (index, used, chosen) => {
225
+ assert(++steps <= limits.maxSelectionSteps, ROUTE_RANKING_WORK_LIMIT);
226
+ if (index === rows.length) { routes.push(price(chosen)); return; }
227
+ for (const row of rows[index]) {
228
+ const mask = bit.get(row.candidate.participantId);
229
+ if (used & mask) continue;
230
+ walk(index + 1, used | mask, [...chosen, row]);
231
+ }
232
+ };
233
+ walk(0, 0, []);
234
+ // Ties compare participant ids stage by stage in code-unit order, like first-valid matching;
235
+ // locale collation would ignore separators and differ between hosts.
236
+ const byIds = (a, b) => { for (let i = 0; i < a.participants.length; i++) {
237
+ const x = a.participants[i], y = b.participants[i];
238
+ if (x !== y) return x < y ? -1 : 1;
239
+ } return 0; };
240
+ return freeze(routes.sort((a, b) => a.units - b.units || byIds(a, b)).slice(0, limits.maxRoutes));
241
+ }
242
+
243
+ /** New attempts move to a better-ranked route only when its expected cost is lower by the margin;
244
+ * attempts already running are never moved, and the current route is kept while any attempt on it is
245
+ * active. A current route that is no longer admissible (a full, closed or memory-short stage) takes no
246
+ * new attempts, so they go to the best admissible route; its active attempts stay where they are. */
247
+ export function preferRoute({ current, ranked, active, margin }) {
248
+ assert(finite(margin) && margin < 1 && Array.isArray(ranked), 'Explicit route preference margin required');
249
+ const best = ranked[0] ?? null;
250
+ if (!current || !best) return best ?? current ?? null;
251
+ const ids = route => JSON.stringify(route.stages.map(stage => stage.participantId));
252
+ const mine = ranked.find(route => ids(route) === ids(current));
253
+ if (!mine) return best;
254
+ if (active || ids(best) === ids(current)) return current;
255
+ return best.cost <= mine.cost * (1 - margin) ? best : current;
256
+ }
257
+
258
+ /** The auditable record of one ranking decision: the full policy, workload, the chosen route's inputs
259
+ * and cost breakdown, and the best `maxRoutes` alternatives. Unsigned coordinator observations. */
260
+ export function routeSelectionRecord({ policy, workload, ranked, chosen, reason, decidedAt, maxRoutes }) {
261
+ assert(typeof reason === 'string' && Number.isSafeInteger(decidedAt) && Number.isSafeInteger(maxRoutes) && maxRoutes > 0
262
+ && Array.isArray(ranked), 'Route selection record input required');
263
+ const summary = route => ({ participants: [...route.participants], cost: route.cost, units: route.units, measured: route.measured,
264
+ prepared: route.prepared, components: { ...route.components }, expected: { ...route.expected } });
265
+ return freeze(structuredClone({ schema: ROUTE_SELECTION_SCHEMA, policy: validateRouteCostPolicy(policy), reason, decidedAt,
266
+ workload: { promptTokens: workload.promptTokens, expectedTokens: workload.expectedTokens }, considered: ranked.length,
267
+ chosen: chosen ? { ...summary(chosen), inputs: chosen.inputs } : null, alternatives: ranked.slice(0, maxRoutes).map(summary) }));
268
+ }
@@ -0,0 +1,46 @@
1
+ /** Bounded public loading telemetry. Never publish file paths, prompts or raw errors. */
2
+ export function publicPreparationProgress(progress) {
3
+ if (!progress || typeof progress !== 'object') return null;
4
+ let kind = progress.kind;
5
+ if (!['downloading', 'receiving', 'cached', 'pipelines', 'loading'].includes(kind)) {
6
+ if (progress.stage === 'acquiring') kind = /^Downloading/.test(progress.message) ? 'downloading'
7
+ : /^Receiving/.test(progress.message) ? 'receiving' : /^Reusing/.test(progress.message) ? 'cached' : 'loading';
8
+ else kind = progress.phase === 'pipelines' || progress.stage === 'preparing' && Number.isSafeInteger(progress.prepared)
9
+ ? 'pipelines' : 'loading';
10
+ }
11
+ const result = { kind };
12
+ if (typeof progress.workId === 'string' && progress.workId.length <= 96) result.workId = progress.workId;
13
+ if (Number.isSafeInteger(progress.sequence) && progress.sequence >= 0) result.sequence = progress.sequence;
14
+ if (['preparing', 'prepared', 'cancelling', 'cancelled', 'timed-out', 'failed'].includes(progress.status)) result.status = progress.status;
15
+ if (typeof progress.outstanding === 'boolean') result.outstanding = progress.outstanding;
16
+ if (Number.isSafeInteger(progress.receivedBytes) && Number.isSafeInteger(progress.totalBytes)
17
+ && progress.totalBytes > 0 && progress.receivedBytes >= 0 && progress.receivedBytes <= progress.totalBytes) {
18
+ result.receivedBytes = progress.receivedBytes; result.totalBytes = progress.totalBytes;
19
+ }
20
+ if (kind === 'pipelines' && Number.isSafeInteger(progress.prepared) && Number.isSafeInteger(progress.total)
21
+ && progress.total > 0 && progress.prepared >= 0 && progress.prepared <= progress.total) {
22
+ result.prepared = progress.prepared; result.total = progress.total;
23
+ }
24
+ return result;
25
+ }
26
+
27
+
28
+ /** Observation-only high-water counters per preparation and file/pipeline work item.
29
+ * Paths stay local; opaque work IDs distinguish a new file from regressing progress.
30
+ */
31
+ export function createPreparationProgressObserver() {
32
+ const operation = crypto.randomUUID(), work = new Map();
33
+ let sequence = 0;
34
+ return value => {
35
+ const step = publicPreparationProgress(value);
36
+ if (!step) return value;
37
+ const key = JSON.stringify([step.kind, value.path || '', step.totalBytes ?? step.total ?? null]);
38
+ const previous = work.get(key);
39
+ const next = { ...value, ...step, workId: previous?.workId || `${operation}:${work.size}`, sequence: ++sequence };
40
+ for (const field of ['receivedBytes', 'prepared']) if (previous?.[field] !== undefined) {
41
+ next[field] = Math.max(previous[field], next[field] ?? 0);
42
+ }
43
+ work.set(key, next);
44
+ return next;
45
+ };
46
+ }
@@ -0,0 +1,11 @@
1
+ /** Bounded, self-reported GPU metadata. Never an identity or an admission input. */
2
+ export function publicProviderHardware(value) {
3
+ if (!value || typeof value !== 'object' || Array.isArray(value)) return null;
4
+ const result = {};
5
+ for (const key of ['vendor', 'architecture', 'device', 'description']) {
6
+ if (typeof value[key] !== 'string') continue;
7
+ const text = value[key].replace(/[\u0000-\u001f\u007f]/g, '').trim().slice(0, 160);
8
+ if (text) result[key] = text;
9
+ }
10
+ return Object.keys(result).length ? result : null;
11
+ }
@@ -0,0 +1,24 @@
1
+ {
2
+ "schema": "reploid.rules/v1",
3
+ "rules": [
4
+ {
5
+ "id": "local-only",
6
+ "order": [
7
+ "local"
8
+ ]
9
+ },
10
+ {
11
+ "id": "local-first",
12
+ "order": [
13
+ "local",
14
+ "remote"
15
+ ]
16
+ },
17
+ {
18
+ "id": "remote-only",
19
+ "order": [
20
+ "remote"
21
+ ]
22
+ }
23
+ ]
24
+ }
@@ -0,0 +1,16 @@
1
+ {
2
+ "RESULT_EXPIRED": "The retained canonical result expired. Start a new authorized attempt.",
3
+ "RESOURCE_EXHAUSTED": "A contributor exhausted its resource allowance. Retry with prepared capacity or a shorter conversation.",
4
+ "AUTHORIZATION_DENIED": "A contributor declined authorization for this request.",
5
+ "EXECUTION_FAILED": "Partition peer declined or failed request",
6
+ "OUTPUT_LIMIT_EXCEEDED": "A contributor exceeded the answer length allowance. The attempt failed; its partial answer is incomplete.",
7
+ "GENERATION_OUTPUT_INVALID": "A contributor did not produce a valid final answer. The attempt failed; its partial answer is incomplete.",
8
+ "CAPACITY_UNAVAILABLE": "A contributor has no available prepared capacity for this attempt. Select available capacity and retry.",
9
+ "CAPACITY_QUEUE_FULL": "Prepared capacity for this route is busy and its queue is full. The attempt was not run; retry later.",
10
+ "CAPACITY_QUEUE_TIMEOUT": "No prepared capacity for this route became free before this attempt's queue limit or permission window ended. The attempt was not run; retry starts a new attempt.",
11
+ "CONNECTION_LOST": "A contributor disconnected. The attempt was interrupted; remote cleanup is not confirmed.",
12
+ "REQUEST_TIMEOUT": "The contributor request timed out. Remote completion and cleanup are not confirmed.",
13
+ "CLEANUP_FAILED": "Partition attempt settlement failed. Contributor cleanup is not confirmed; its capacity remains unavailable.",
14
+ "ANSWER_DEADLINE_EXCEEDED": "Response timed out. Retry starts a new attempt.",
15
+ "WORKLOAD_OUTSIDE_ENVELOPE": "This route does not support a request of this prompt length, answer length or number of concurrent requests. Nothing was sent to its other contributors."
16
+ }
package/README.md DELETED
@@ -1,3 +0,0 @@
1
- # Temporary Holding Version
2
-
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.