chainlesschain 0.66.0 → 0.132.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/bin/chainlesschain.js +0 -0
- package/package.json +1 -1
- package/src/commands/a2a.js +380 -0
- package/src/commands/agent-network.js +254 -1
- package/src/commands/audit.js +302 -0
- package/src/commands/automation.js +271 -1
- package/src/commands/bi.js +348 -0
- package/src/commands/codegen.js +224 -0
- package/src/commands/collab.js +341 -0
- package/src/commands/compliance.js +1035 -0
- package/src/commands/cowork.js +221 -0
- package/src/commands/crosschain.js +218 -0
- package/src/commands/dbevo.js +284 -0
- package/src/commands/dev.js +252 -0
- package/src/commands/did.js +358 -0
- package/src/commands/dlp.js +341 -0
- package/src/commands/encrypt.js +341 -0
- package/src/commands/evomap.js +394 -0
- package/src/commands/export.js +256 -1
- package/src/commands/federation.js +283 -0
- package/src/commands/fusion.js +258 -0
- package/src/commands/governance.js +325 -0
- package/src/commands/hardening.js +411 -0
- package/src/commands/hook.js +148 -0
- package/src/commands/import.js +252 -0
- package/src/commands/incentive.js +322 -0
- package/src/commands/inference.js +318 -0
- package/src/commands/infra.js +244 -0
- package/src/commands/instinct.js +260 -0
- package/src/commands/ipfs.js +318 -0
- package/src/commands/kg.js +387 -0
- package/src/commands/llm.js +263 -0
- package/src/commands/lowcode.js +356 -0
- package/src/commands/marketplace.js +256 -0
- package/src/commands/mcp.js +221 -0
- package/src/commands/memory.js +248 -0
- package/src/commands/multimodal.js +296 -0
- package/src/commands/nlprog.js +356 -0
- package/src/commands/note.js +244 -0
- package/src/commands/ops.js +354 -0
- package/src/commands/orchestrate.js +166 -0
- package/src/commands/org.js +277 -0
- package/src/commands/p2p.js +390 -0
- package/src/commands/perception.js +290 -0
- package/src/commands/permmem.js +251 -0
- package/src/commands/plugin-ecosystem.js +273 -0
- package/src/commands/pqc.js +393 -0
- package/src/commands/privacy.js +321 -0
- package/src/commands/quantization.js +351 -0
- package/src/commands/rcache.js +271 -0
- package/src/commands/recommend.js +340 -0
- package/src/commands/reputation.js +261 -0
- package/src/commands/runtime.js +307 -0
- package/src/commands/scim.js +262 -0
- package/src/commands/session.js +258 -0
- package/src/commands/siem.js +246 -0
- package/src/commands/skill.js +267 -1
- package/src/commands/sla.js +259 -0
- package/src/commands/social.js +256 -0
- package/src/commands/sso.js +186 -1
- package/src/commands/stress.js +230 -0
- package/src/commands/sync.js +256 -0
- package/src/commands/tech.js +338 -0
- package/src/commands/tenant.js +351 -0
- package/src/commands/terraform.js +245 -0
- package/src/commands/tokens.js +269 -0
- package/src/commands/trust.js +249 -0
- package/src/commands/wallet.js +277 -0
- package/src/commands/workflow.js +171 -0
- package/src/commands/zkp.js +335 -0
- package/src/index.js +4 -0
- package/src/lib/a2a-protocol.js +451 -0
- package/src/lib/agent-coordinator.js +325 -0
- package/src/lib/agent-network.js +387 -0
- package/src/lib/agent-router.js +395 -0
- package/src/lib/aiops.js +478 -0
- package/src/lib/app-builder.js +239 -0
- package/src/lib/audit-logger.js +379 -0
- package/src/lib/automation-engine.js +330 -0
- package/src/lib/autonomous-developer.js +350 -0
- package/src/lib/bi-engine.js +338 -0
- package/src/lib/code-agent.js +323 -0
- package/src/lib/collaboration-governance.js +364 -0
- package/src/lib/community-governance.js +436 -0
- package/src/lib/compliance-manager.js +434 -0
- package/src/lib/content-recommendation.js +469 -0
- package/src/lib/cross-chain.js +345 -0
- package/src/lib/crypto-manager.js +350 -0
- package/src/lib/dbevo.js +338 -0
- package/src/lib/decentral-infra.js +340 -0
- package/src/lib/did-manager.js +367 -0
- package/src/lib/dlp-engine.js +389 -0
- package/src/lib/evomap-federation.js +177 -0
- package/src/lib/evomap-governance.js +276 -0
- package/src/lib/federation-hardening.js +259 -0
- package/src/lib/hardening-manager.js +348 -0
- package/src/lib/hook-manager.js +380 -0
- package/src/lib/inference-network.js +330 -0
- package/src/lib/instinct-manager.js +332 -0
- package/src/lib/ipfs-storage.js +334 -0
- package/src/lib/knowledge-exporter.js +381 -0
- package/src/lib/knowledge-graph.js +432 -0
- package/src/lib/knowledge-importer.js +379 -0
- package/src/lib/llm-providers.js +391 -0
- package/src/lib/mcp-registry.js +333 -0
- package/src/lib/memory-manager.js +330 -0
- package/src/lib/multimodal.js +346 -0
- package/src/lib/nl-programming.js +343 -0
- package/src/lib/note-versioning.js +327 -0
- package/src/lib/org-manager.js +323 -0
- package/src/lib/p2p-manager.js +387 -0
- package/src/lib/perception.js +346 -0
- package/src/lib/perf-tuning.js +4 -1
- package/src/lib/permanent-memory.js +320 -0
- package/src/lib/plugin-ecosystem.js +377 -0
- package/src/lib/pqc-manager.js +368 -0
- package/src/lib/privacy-computing.js +427 -0
- package/src/lib/protocol-fusion.js +417 -0
- package/src/lib/quantization.js +325 -0
- package/src/lib/reputation-optimizer.js +299 -0
- package/src/lib/response-cache.js +327 -0
- package/src/lib/scim-manager.js +329 -0
- package/src/lib/session-manager.js +329 -0
- package/src/lib/siem-exporter.js +333 -0
- package/src/lib/skill-loader.js +377 -0
- package/src/lib/skill-marketplace.js +325 -0
- package/src/lib/sla-manager.js +275 -0
- package/src/lib/social-manager.js +326 -0
- package/src/lib/sso-manager.js +332 -0
- package/src/lib/stress-tester.js +330 -0
- package/src/lib/sync-manager.js +326 -0
- package/src/lib/tech-learning-engine.js +369 -0
- package/src/lib/tenant-saas.js +460 -0
- package/src/lib/terraform-manager.js +363 -0
- package/src/lib/threat-intel.js +335 -0
- package/src/lib/token-incentive.js +293 -0
- package/src/lib/token-tracker.js +329 -0
- package/src/lib/trust-security.js +390 -0
- package/src/lib/ueba.js +389 -0
- package/src/lib/universal-runtime.js +325 -0
- package/src/lib/wallet-manager.js +326 -0
- package/src/lib/workflow-engine.js +322 -0
- package/src/lib/zkp-engine.js +274 -0
package/src/lib/quantization.js
CHANGED
|
@@ -360,3 +360,328 @@ export function getQuantizationStats(db) {
|
|
|
360
360
|
export function _resetState() {
|
|
361
361
|
_jobs.clear();
|
|
362
362
|
}
|
|
363
|
+
|
|
364
|
+
/* ═════════════════════════════════════════════════════════ *
|
|
365
|
+
* Phase 20 V2 — Model Maturity + Job Ticket Lifecycle
|
|
366
|
+
* ═════════════════════════════════════════════════════════ */
|
|
367
|
+
|
|
368
|
+
export const MODEL_MATURITY_V2 = Object.freeze({
|
|
369
|
+
ONBOARDING: "onboarding",
|
|
370
|
+
ACTIVE: "active",
|
|
371
|
+
DEPRECATED: "deprecated",
|
|
372
|
+
RETIRED: "retired",
|
|
373
|
+
});
|
|
374
|
+
|
|
375
|
+
export const JOB_TICKET_V2 = Object.freeze({
|
|
376
|
+
QUEUED: "queued",
|
|
377
|
+
RUNNING: "running",
|
|
378
|
+
COMPLETED: "completed",
|
|
379
|
+
FAILED: "failed",
|
|
380
|
+
CANCELED: "canceled",
|
|
381
|
+
});
|
|
382
|
+
|
|
383
|
+
const MODEL_TRANSITIONS_V2 = new Map([
|
|
384
|
+
["onboarding", new Set(["active", "retired"])],
|
|
385
|
+
["active", new Set(["deprecated", "retired"])],
|
|
386
|
+
["deprecated", new Set(["active", "retired"])],
|
|
387
|
+
]);
|
|
388
|
+
const MODEL_TERMINALS_V2 = new Set(["retired"]);
|
|
389
|
+
|
|
390
|
+
const JOB_TRANSITIONS_V2 = new Map([
|
|
391
|
+
["queued", new Set(["running", "canceled", "failed"])],
|
|
392
|
+
["running", new Set(["completed", "failed", "canceled"])],
|
|
393
|
+
]);
|
|
394
|
+
const JOB_TERMINALS_V2 = new Set(["completed", "failed", "canceled"]);
|
|
395
|
+
|
|
396
|
+
export const QUANT_DEFAULT_MAX_ACTIVE_MODELS_PER_OWNER = 50;
|
|
397
|
+
export const QUANT_DEFAULT_MAX_RUNNING_JOBS_PER_OWNER = 3;
|
|
398
|
+
export const QUANT_DEFAULT_MODEL_IDLE_MS = 120 * 86400000; // 120d
|
|
399
|
+
export const QUANT_DEFAULT_JOB_STUCK_MS = 6 * 3600000; // 6h
|
|
400
|
+
|
|
401
|
+
let _maxActiveModelsPerOwnerV2 = QUANT_DEFAULT_MAX_ACTIVE_MODELS_PER_OWNER;
|
|
402
|
+
let _maxRunningJobsPerOwnerV2 = QUANT_DEFAULT_MAX_RUNNING_JOBS_PER_OWNER;
|
|
403
|
+
let _modelIdleMsV2 = QUANT_DEFAULT_MODEL_IDLE_MS;
|
|
404
|
+
let _jobStuckMsV2 = QUANT_DEFAULT_JOB_STUCK_MS;
|
|
405
|
+
|
|
406
|
+
function _positiveIntV2(n, label) {
|
|
407
|
+
const v = Math.floor(Number(n));
|
|
408
|
+
if (!Number.isFinite(v) || v <= 0)
|
|
409
|
+
throw new Error(`${label} must be a positive integer`);
|
|
410
|
+
return v;
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
export function getDefaultMaxActiveModelsPerOwnerV2() {
|
|
414
|
+
return QUANT_DEFAULT_MAX_ACTIVE_MODELS_PER_OWNER;
|
|
415
|
+
}
|
|
416
|
+
export function getMaxActiveModelsPerOwnerV2() {
|
|
417
|
+
return _maxActiveModelsPerOwnerV2;
|
|
418
|
+
}
|
|
419
|
+
export function setMaxActiveModelsPerOwnerV2(n) {
|
|
420
|
+
return (_maxActiveModelsPerOwnerV2 = _positiveIntV2(
|
|
421
|
+
n,
|
|
422
|
+
"maxActiveModelsPerOwner",
|
|
423
|
+
));
|
|
424
|
+
}
|
|
425
|
+
export function getDefaultMaxRunningJobsPerOwnerV2() {
|
|
426
|
+
return QUANT_DEFAULT_MAX_RUNNING_JOBS_PER_OWNER;
|
|
427
|
+
}
|
|
428
|
+
export function getMaxRunningJobsPerOwnerV2() {
|
|
429
|
+
return _maxRunningJobsPerOwnerV2;
|
|
430
|
+
}
|
|
431
|
+
export function setMaxRunningJobsPerOwnerV2(n) {
|
|
432
|
+
return (_maxRunningJobsPerOwnerV2 = _positiveIntV2(
|
|
433
|
+
n,
|
|
434
|
+
"maxRunningJobsPerOwner",
|
|
435
|
+
));
|
|
436
|
+
}
|
|
437
|
+
export function getDefaultModelIdleMsV2() {
|
|
438
|
+
return QUANT_DEFAULT_MODEL_IDLE_MS;
|
|
439
|
+
}
|
|
440
|
+
export function getModelIdleMsV2() {
|
|
441
|
+
return _modelIdleMsV2;
|
|
442
|
+
}
|
|
443
|
+
export function setModelIdleMsV2(ms) {
|
|
444
|
+
return (_modelIdleMsV2 = _positiveIntV2(ms, "modelIdleMs"));
|
|
445
|
+
}
|
|
446
|
+
export function getDefaultJobStuckMsV2() {
|
|
447
|
+
return QUANT_DEFAULT_JOB_STUCK_MS;
|
|
448
|
+
}
|
|
449
|
+
export function getJobStuckMsV2() {
|
|
450
|
+
return _jobStuckMsV2;
|
|
451
|
+
}
|
|
452
|
+
export function setJobStuckMsV2(ms) {
|
|
453
|
+
return (_jobStuckMsV2 = _positiveIntV2(ms, "jobStuckMs"));
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
const _modelsV2 = new Map();
|
|
457
|
+
const _jobTicketsV2 = new Map();
|
|
458
|
+
|
|
459
|
+
export function registerModelV2(
|
|
460
|
+
_db,
|
|
461
|
+
{ modelId, ownerId, family, initialStatus, metadata } = {},
|
|
462
|
+
) {
|
|
463
|
+
if (!modelId) throw new Error("modelId is required");
|
|
464
|
+
if (!ownerId) throw new Error("ownerId is required");
|
|
465
|
+
if (_modelsV2.has(modelId))
|
|
466
|
+
throw new Error(`Model ${modelId} already exists`);
|
|
467
|
+
const status = initialStatus || MODEL_MATURITY_V2.ONBOARDING;
|
|
468
|
+
if (!Object.values(MODEL_MATURITY_V2).includes(status))
|
|
469
|
+
throw new Error(`Invalid initial status: ${status}`);
|
|
470
|
+
if (MODEL_TERMINALS_V2.has(status))
|
|
471
|
+
throw new Error(`Cannot register in terminal status: ${status}`);
|
|
472
|
+
if (status === MODEL_MATURITY_V2.ACTIVE) {
|
|
473
|
+
if (getActiveModelCount(ownerId) >= _maxActiveModelsPerOwnerV2)
|
|
474
|
+
throw new Error(
|
|
475
|
+
`Owner ${ownerId} reached active-model cap (${_maxActiveModelsPerOwnerV2})`,
|
|
476
|
+
);
|
|
477
|
+
}
|
|
478
|
+
const now = Date.now();
|
|
479
|
+
const record = {
|
|
480
|
+
modelId,
|
|
481
|
+
ownerId,
|
|
482
|
+
family: family || "",
|
|
483
|
+
status,
|
|
484
|
+
metadata: metadata || {},
|
|
485
|
+
createdAt: now,
|
|
486
|
+
updatedAt: now,
|
|
487
|
+
lastUsedAt: now,
|
|
488
|
+
};
|
|
489
|
+
_modelsV2.set(modelId, record);
|
|
490
|
+
return { ...record, metadata: { ...record.metadata } };
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
export function getModelV2(modelId) {
|
|
494
|
+
const r = _modelsV2.get(modelId);
|
|
495
|
+
return r ? { ...r, metadata: { ...r.metadata } } : null;
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
export function setModelMaturityV2(_db, modelId, newStatus, patch = {}) {
|
|
499
|
+
const record = _modelsV2.get(modelId);
|
|
500
|
+
if (!record) throw new Error(`Unknown model: ${modelId}`);
|
|
501
|
+
if (!Object.values(MODEL_MATURITY_V2).includes(newStatus))
|
|
502
|
+
throw new Error(`Invalid status: ${newStatus}`);
|
|
503
|
+
const allowed = MODEL_TRANSITIONS_V2.get(record.status) || new Set();
|
|
504
|
+
if (!allowed.has(newStatus))
|
|
505
|
+
throw new Error(`Invalid transition: ${record.status} -> ${newStatus}`);
|
|
506
|
+
if (newStatus === MODEL_MATURITY_V2.ACTIVE) {
|
|
507
|
+
if (getActiveModelCount(record.ownerId) >= _maxActiveModelsPerOwnerV2)
|
|
508
|
+
throw new Error(
|
|
509
|
+
`Owner ${record.ownerId} reached active-model cap (${_maxActiveModelsPerOwnerV2})`,
|
|
510
|
+
);
|
|
511
|
+
}
|
|
512
|
+
record.status = newStatus;
|
|
513
|
+
record.updatedAt = Date.now();
|
|
514
|
+
if (patch.reason !== undefined) record.lastReason = patch.reason;
|
|
515
|
+
if (patch.metadata)
|
|
516
|
+
record.metadata = { ...record.metadata, ...patch.metadata };
|
|
517
|
+
return { ...record, metadata: { ...record.metadata } };
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
export function activateModel(db, id, reason) {
|
|
521
|
+
return setModelMaturityV2(db, id, MODEL_MATURITY_V2.ACTIVE, { reason });
|
|
522
|
+
}
|
|
523
|
+
export function deprecateModel(db, id, reason) {
|
|
524
|
+
return setModelMaturityV2(db, id, MODEL_MATURITY_V2.DEPRECATED, { reason });
|
|
525
|
+
}
|
|
526
|
+
export function retireModel(db, id, reason) {
|
|
527
|
+
return setModelMaturityV2(db, id, MODEL_MATURITY_V2.RETIRED, { reason });
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
export function touchModelUsage(modelId) {
|
|
531
|
+
const record = _modelsV2.get(modelId);
|
|
532
|
+
if (!record) throw new Error(`Unknown model: ${modelId}`);
|
|
533
|
+
record.lastUsedAt = Date.now();
|
|
534
|
+
record.updatedAt = record.lastUsedAt;
|
|
535
|
+
return { ...record, metadata: { ...record.metadata } };
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
export function enqueueJobTicketV2(
|
|
539
|
+
_db,
|
|
540
|
+
{ ticketId, ownerId, modelId, quantType, level, metadata } = {},
|
|
541
|
+
) {
|
|
542
|
+
if (!ticketId) throw new Error("ticketId is required");
|
|
543
|
+
if (!ownerId) throw new Error("ownerId is required");
|
|
544
|
+
if (!modelId) throw new Error("modelId is required");
|
|
545
|
+
if (!quantType) throw new Error("quantType is required");
|
|
546
|
+
if (_jobTicketsV2.has(ticketId))
|
|
547
|
+
throw new Error(`Ticket ${ticketId} already exists`);
|
|
548
|
+
const now = Date.now();
|
|
549
|
+
const record = {
|
|
550
|
+
ticketId,
|
|
551
|
+
ownerId,
|
|
552
|
+
modelId,
|
|
553
|
+
quantType,
|
|
554
|
+
level: level || null,
|
|
555
|
+
status: JOB_TICKET_V2.QUEUED,
|
|
556
|
+
metadata: metadata || {},
|
|
557
|
+
createdAt: now,
|
|
558
|
+
updatedAt: now,
|
|
559
|
+
};
|
|
560
|
+
_jobTicketsV2.set(ticketId, record);
|
|
561
|
+
return { ...record, metadata: { ...record.metadata } };
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
export function getJobTicketV2(ticketId) {
|
|
565
|
+
const r = _jobTicketsV2.get(ticketId);
|
|
566
|
+
return r ? { ...r, metadata: { ...r.metadata } } : null;
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
export function setJobTicketStatusV2(_db, ticketId, newStatus, patch = {}) {
|
|
570
|
+
const record = _jobTicketsV2.get(ticketId);
|
|
571
|
+
if (!record) throw new Error(`Unknown ticket: ${ticketId}`);
|
|
572
|
+
if (!Object.values(JOB_TICKET_V2).includes(newStatus))
|
|
573
|
+
throw new Error(`Invalid status: ${newStatus}`);
|
|
574
|
+
const allowed = JOB_TRANSITIONS_V2.get(record.status) || new Set();
|
|
575
|
+
if (!allowed.has(newStatus))
|
|
576
|
+
throw new Error(`Invalid transition: ${record.status} -> ${newStatus}`);
|
|
577
|
+
if (newStatus === JOB_TICKET_V2.RUNNING) {
|
|
578
|
+
if (getRunningJobCount(record.ownerId) >= _maxRunningJobsPerOwnerV2)
|
|
579
|
+
throw new Error(
|
|
580
|
+
`Owner ${record.ownerId} reached running-job cap (${_maxRunningJobsPerOwnerV2})`,
|
|
581
|
+
);
|
|
582
|
+
record.startedAt = Date.now();
|
|
583
|
+
}
|
|
584
|
+
record.status = newStatus;
|
|
585
|
+
record.updatedAt = Date.now();
|
|
586
|
+
if (patch.reason !== undefined) record.lastReason = patch.reason;
|
|
587
|
+
if (patch.metadata)
|
|
588
|
+
record.metadata = { ...record.metadata, ...patch.metadata };
|
|
589
|
+
return { ...record, metadata: { ...record.metadata } };
|
|
590
|
+
}
|
|
591
|
+
|
|
592
|
+
export function startJobTicket(db, id, reason) {
|
|
593
|
+
return setJobTicketStatusV2(db, id, JOB_TICKET_V2.RUNNING, { reason });
|
|
594
|
+
}
|
|
595
|
+
export function completeJobTicket(db, id, reason) {
|
|
596
|
+
return setJobTicketStatusV2(db, id, JOB_TICKET_V2.COMPLETED, { reason });
|
|
597
|
+
}
|
|
598
|
+
export function failJobTicket(db, id, reason) {
|
|
599
|
+
return setJobTicketStatusV2(db, id, JOB_TICKET_V2.FAILED, { reason });
|
|
600
|
+
}
|
|
601
|
+
export function cancelJobTicket(db, id, reason) {
|
|
602
|
+
return setJobTicketStatusV2(db, id, JOB_TICKET_V2.CANCELED, { reason });
|
|
603
|
+
}
|
|
604
|
+
|
|
605
|
+
export function getActiveModelCount(ownerId) {
|
|
606
|
+
let n = 0;
|
|
607
|
+
for (const r of _modelsV2.values()) {
|
|
608
|
+
if (r.status !== MODEL_MATURITY_V2.ACTIVE) continue;
|
|
609
|
+
if (ownerId && r.ownerId !== ownerId) continue;
|
|
610
|
+
n++;
|
|
611
|
+
}
|
|
612
|
+
return n;
|
|
613
|
+
}
|
|
614
|
+
|
|
615
|
+
export function getRunningJobCount(ownerId) {
|
|
616
|
+
let n = 0;
|
|
617
|
+
for (const r of _jobTicketsV2.values()) {
|
|
618
|
+
if (r.status !== JOB_TICKET_V2.RUNNING) continue;
|
|
619
|
+
if (ownerId && r.ownerId !== ownerId) continue;
|
|
620
|
+
n++;
|
|
621
|
+
}
|
|
622
|
+
return n;
|
|
623
|
+
}
|
|
624
|
+
|
|
625
|
+
export function autoRetireIdleModels(_db, nowMs) {
|
|
626
|
+
const now = nowMs ?? Date.now();
|
|
627
|
+
const flipped = [];
|
|
628
|
+
for (const r of _modelsV2.values()) {
|
|
629
|
+
if (
|
|
630
|
+
r.status === MODEL_MATURITY_V2.ACTIVE ||
|
|
631
|
+
r.status === MODEL_MATURITY_V2.DEPRECATED
|
|
632
|
+
) {
|
|
633
|
+
if (now - r.lastUsedAt > _modelIdleMsV2) {
|
|
634
|
+
r.status = MODEL_MATURITY_V2.RETIRED;
|
|
635
|
+
r.updatedAt = now;
|
|
636
|
+
r.lastReason = "idle";
|
|
637
|
+
flipped.push(r.modelId);
|
|
638
|
+
}
|
|
639
|
+
}
|
|
640
|
+
}
|
|
641
|
+
return { flipped, count: flipped.length };
|
|
642
|
+
}
|
|
643
|
+
|
|
644
|
+
export function autoFailStuckJobTickets(_db, nowMs) {
|
|
645
|
+
const now = nowMs ?? Date.now();
|
|
646
|
+
const flipped = [];
|
|
647
|
+
for (const r of _jobTicketsV2.values()) {
|
|
648
|
+
if (r.status === JOB_TICKET_V2.RUNNING) {
|
|
649
|
+
const anchor = r.startedAt || r.createdAt;
|
|
650
|
+
if (now - anchor > _jobStuckMsV2) {
|
|
651
|
+
r.status = JOB_TICKET_V2.FAILED;
|
|
652
|
+
r.updatedAt = now;
|
|
653
|
+
r.lastReason = "stuck_timeout";
|
|
654
|
+
flipped.push(r.ticketId);
|
|
655
|
+
}
|
|
656
|
+
}
|
|
657
|
+
}
|
|
658
|
+
return { flipped, count: flipped.length };
|
|
659
|
+
}
|
|
660
|
+
|
|
661
|
+
export function getQuantizationStatsV2() {
|
|
662
|
+
const modelsByStatus = {};
|
|
663
|
+
for (const s of Object.values(MODEL_MATURITY_V2)) modelsByStatus[s] = 0;
|
|
664
|
+
const ticketsByStatus = {};
|
|
665
|
+
for (const s of Object.values(JOB_TICKET_V2)) ticketsByStatus[s] = 0;
|
|
666
|
+
for (const r of _modelsV2.values()) modelsByStatus[r.status]++;
|
|
667
|
+
for (const r of _jobTicketsV2.values()) ticketsByStatus[r.status]++;
|
|
668
|
+
return {
|
|
669
|
+
totalModelsV2: _modelsV2.size,
|
|
670
|
+
totalTicketsV2: _jobTicketsV2.size,
|
|
671
|
+
maxActiveModelsPerOwner: _maxActiveModelsPerOwnerV2,
|
|
672
|
+
maxRunningJobsPerOwner: _maxRunningJobsPerOwnerV2,
|
|
673
|
+
modelIdleMs: _modelIdleMsV2,
|
|
674
|
+
jobStuckMs: _jobStuckMsV2,
|
|
675
|
+
modelsByStatus,
|
|
676
|
+
ticketsByStatus,
|
|
677
|
+
};
|
|
678
|
+
}
|
|
679
|
+
|
|
680
|
+
export function _resetStateV2() {
|
|
681
|
+
_maxActiveModelsPerOwnerV2 = QUANT_DEFAULT_MAX_ACTIVE_MODELS_PER_OWNER;
|
|
682
|
+
_maxRunningJobsPerOwnerV2 = QUANT_DEFAULT_MAX_RUNNING_JOBS_PER_OWNER;
|
|
683
|
+
_modelIdleMsV2 = QUANT_DEFAULT_MODEL_IDLE_MS;
|
|
684
|
+
_jobStuckMsV2 = QUANT_DEFAULT_JOB_STUCK_MS;
|
|
685
|
+
_modelsV2.clear();
|
|
686
|
+
_jobTicketsV2.clear();
|
|
687
|
+
}
|
|
@@ -506,4 +506,303 @@ export function _resetState() {
|
|
|
506
506
|
_runs.clear();
|
|
507
507
|
_analytics.clear();
|
|
508
508
|
_seq = 0;
|
|
509
|
+
_maxConcurrentOptimizations = DEFAULT_MAX_CONCURRENT_OPTIMIZATIONS;
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
/* ═══════════════════════════════════════════════════════════════
|
|
513
|
+
* V2 (Phase 60) — Frozen enums + async optimization lifecycle +
|
|
514
|
+
* concurrency limiter + patch-merged setRunStatus + stats-v2.
|
|
515
|
+
* Strictly additive on top of the legacy surface above.
|
|
516
|
+
* ═══════════════════════════════════════════════════════════════ */
|
|
517
|
+
|
|
518
|
+
export const RUN_STATUS_V2 = Object.freeze({
|
|
519
|
+
RUNNING: "running",
|
|
520
|
+
COMPLETE: "complete",
|
|
521
|
+
APPLIED: "applied",
|
|
522
|
+
FAILED: "failed",
|
|
523
|
+
CANCELLED: "cancelled",
|
|
524
|
+
});
|
|
525
|
+
|
|
526
|
+
export const OBJECTIVE_V2 = Object.freeze({
|
|
527
|
+
ACCURACY: "accuracy",
|
|
528
|
+
FAIRNESS: "fairness",
|
|
529
|
+
RESILIENCE: "resilience",
|
|
530
|
+
CONVERGENCE_SPEED: "convergence_speed",
|
|
531
|
+
});
|
|
532
|
+
|
|
533
|
+
export const DECAY_MODEL_V2 = Object.freeze({
|
|
534
|
+
EXPONENTIAL: "exponential",
|
|
535
|
+
LINEAR: "linear",
|
|
536
|
+
STEP: "step",
|
|
537
|
+
NONE: "none",
|
|
538
|
+
});
|
|
539
|
+
|
|
540
|
+
export const ANOMALY_METHOD_V2 = Object.freeze({
|
|
541
|
+
IQR: "iqr",
|
|
542
|
+
Z_SCORE: "z_score",
|
|
543
|
+
});
|
|
544
|
+
|
|
545
|
+
const DEFAULT_MAX_CONCURRENT_OPTIMIZATIONS = 2;
|
|
546
|
+
let _maxConcurrentOptimizations = DEFAULT_MAX_CONCURRENT_OPTIMIZATIONS;
|
|
547
|
+
export const REPUTATION_DEFAULT_MAX_CONCURRENT =
|
|
548
|
+
DEFAULT_MAX_CONCURRENT_OPTIMIZATIONS;
|
|
549
|
+
|
|
550
|
+
export function setMaxConcurrentOptimizations(n) {
|
|
551
|
+
if (typeof n !== "number" || !Number.isFinite(n) || n < 1) {
|
|
552
|
+
throw new Error("maxConcurrentOptimizations must be a positive integer");
|
|
553
|
+
}
|
|
554
|
+
_maxConcurrentOptimizations = Math.floor(n);
|
|
555
|
+
return _maxConcurrentOptimizations;
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
export function getMaxConcurrentOptimizations() {
|
|
559
|
+
return _maxConcurrentOptimizations;
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
// Run state machine:
|
|
563
|
+
// running → { complete, failed, cancelled }
|
|
564
|
+
// complete → { applied }
|
|
565
|
+
// applied/failed/cancelled are terminal.
|
|
566
|
+
const _runTerminal = new Set([
|
|
567
|
+
RUN_STATUS_V2.APPLIED,
|
|
568
|
+
RUN_STATUS_V2.FAILED,
|
|
569
|
+
RUN_STATUS_V2.CANCELLED,
|
|
570
|
+
]);
|
|
571
|
+
const _runAllowed = new Map([
|
|
572
|
+
[
|
|
573
|
+
RUN_STATUS_V2.RUNNING,
|
|
574
|
+
new Set([
|
|
575
|
+
RUN_STATUS_V2.COMPLETE,
|
|
576
|
+
RUN_STATUS_V2.FAILED,
|
|
577
|
+
RUN_STATUS_V2.CANCELLED,
|
|
578
|
+
]),
|
|
579
|
+
],
|
|
580
|
+
[RUN_STATUS_V2.COMPLETE, new Set([RUN_STATUS_V2.APPLIED])],
|
|
581
|
+
[RUN_STATUS_V2.APPLIED, new Set([])],
|
|
582
|
+
[RUN_STATUS_V2.FAILED, new Set([])],
|
|
583
|
+
[RUN_STATUS_V2.CANCELLED, new Set([])],
|
|
584
|
+
]);
|
|
585
|
+
|
|
586
|
+
export function getActiveOptimizationCount() {
|
|
587
|
+
let count = 0;
|
|
588
|
+
for (const r of _runs.values()) {
|
|
589
|
+
if (r.status === RUN_STATUS_V2.RUNNING) count++;
|
|
590
|
+
}
|
|
591
|
+
return count;
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
/**
|
|
595
|
+
* startOptimizationV2 — creates a RUNNING row without computing iterations.
|
|
596
|
+
* Caller drives the transition via completeOptimization or
|
|
597
|
+
* cancelOptimization / failOptimization, or the generic setRunStatus.
|
|
598
|
+
*/
|
|
599
|
+
export function startOptimizationV2(db, opts = {}) {
|
|
600
|
+
const objective = opts.objective || OBJECTIVE_V2.ACCURACY;
|
|
601
|
+
if (!Object.values(OBJECTIVE_V2).includes(objective)) {
|
|
602
|
+
throw new Error(`Unknown objective: ${objective}`);
|
|
603
|
+
}
|
|
604
|
+
const rawIter = opts.iterations == null ? 50 : Number(opts.iterations);
|
|
605
|
+
const iterations = Math.max(
|
|
606
|
+
1,
|
|
607
|
+
Math.min(1000, Number.isFinite(rawIter) ? rawIter : 50),
|
|
608
|
+
);
|
|
609
|
+
|
|
610
|
+
const activeCount = getActiveOptimizationCount();
|
|
611
|
+
if (activeCount >= _maxConcurrentOptimizations) {
|
|
612
|
+
throw new Error(
|
|
613
|
+
`Max concurrent optimizations reached: ${activeCount}/${_maxConcurrentOptimizations}`,
|
|
614
|
+
);
|
|
615
|
+
}
|
|
616
|
+
|
|
617
|
+
const runId = crypto.randomUUID();
|
|
618
|
+
const now = Date.now();
|
|
619
|
+
const paramSpace = {
|
|
620
|
+
lambda: [0.01, 0.5],
|
|
621
|
+
kappa: [0.5, 3.0],
|
|
622
|
+
contamination: [0.01, 0.2],
|
|
623
|
+
};
|
|
624
|
+
|
|
625
|
+
const run = {
|
|
626
|
+
runId,
|
|
627
|
+
objective,
|
|
628
|
+
iterations,
|
|
629
|
+
paramSpace,
|
|
630
|
+
bestParams: null,
|
|
631
|
+
bestScore: null,
|
|
632
|
+
errorMessage: null,
|
|
633
|
+
status: RUN_STATUS_V2.RUNNING,
|
|
634
|
+
createdAt: now,
|
|
635
|
+
completedAt: null,
|
|
636
|
+
_seq: ++_seq,
|
|
637
|
+
};
|
|
638
|
+
_runs.set(runId, run);
|
|
639
|
+
|
|
640
|
+
db.prepare(
|
|
641
|
+
`INSERT INTO reputation_optimization_runs (run_id, objective, iterations, param_space, best_params, best_score, status, created_at, completed_at)
|
|
642
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`,
|
|
643
|
+
).run(
|
|
644
|
+
runId,
|
|
645
|
+
objective,
|
|
646
|
+
iterations,
|
|
647
|
+
JSON.stringify(paramSpace),
|
|
648
|
+
null,
|
|
649
|
+
null,
|
|
650
|
+
run.status,
|
|
651
|
+
now,
|
|
652
|
+
null,
|
|
653
|
+
);
|
|
654
|
+
|
|
655
|
+
const { _seq: _omit, ...rest } = run;
|
|
656
|
+
void _omit;
|
|
657
|
+
return rest;
|
|
658
|
+
}
|
|
659
|
+
|
|
660
|
+
/**
|
|
661
|
+
* completeOptimization — advances RUNNING → COMPLETE, runs the iteration
|
|
662
|
+
* loop, writes analytics, and returns the same { ...run, analytics }
|
|
663
|
+
* shape as legacy startOptimization.
|
|
664
|
+
*/
|
|
665
|
+
export function completeOptimization(db, runId) {
|
|
666
|
+
const run = _runs.get(runId);
|
|
667
|
+
if (!run) throw new Error(`Optimization run not found: ${runId}`);
|
|
668
|
+
|
|
669
|
+
const allowed = _runAllowed.get(run.status);
|
|
670
|
+
if (!allowed || !allowed.has(RUN_STATUS_V2.COMPLETE)) {
|
|
671
|
+
throw new Error(`Invalid run status transition: ${run.status} → complete`);
|
|
672
|
+
}
|
|
673
|
+
|
|
674
|
+
let bestParams = null;
|
|
675
|
+
let bestScore = -Infinity;
|
|
676
|
+
const history = [];
|
|
677
|
+
|
|
678
|
+
for (let i = 0; i < run.iterations; i++) {
|
|
679
|
+
const params = _sampleParams(run._seq * 101 + i * 17 + 1);
|
|
680
|
+
const score = _evaluateParams(params, run.objective, i);
|
|
681
|
+
history.push({ iteration: i, params, score });
|
|
682
|
+
if (score > bestScore) {
|
|
683
|
+
bestScore = score;
|
|
684
|
+
bestParams = params;
|
|
685
|
+
}
|
|
686
|
+
}
|
|
687
|
+
|
|
688
|
+
const now = Date.now();
|
|
689
|
+
run.status = RUN_STATUS_V2.COMPLETE;
|
|
690
|
+
run.bestParams = bestParams;
|
|
691
|
+
run.bestScore = Number(bestScore.toFixed(6));
|
|
692
|
+
run.completedAt = now;
|
|
693
|
+
run.history = history;
|
|
694
|
+
|
|
695
|
+
db.prepare(
|
|
696
|
+
`UPDATE reputation_optimization_runs SET status = ?, best_params = ?, best_score = ?, completed_at = ? WHERE run_id = ?`,
|
|
697
|
+
).run(run.status, JSON.stringify(bestParams), run.bestScore, now, runId);
|
|
698
|
+
|
|
699
|
+
const distribution = _buildDistribution(listScores({ decay: "none" }));
|
|
700
|
+
const anomalies = detectAnomalies({ method: "z_score" });
|
|
701
|
+
const recommendations = _buildRecommendations(run.objective, bestParams);
|
|
702
|
+
const analyticsId = crypto.randomUUID();
|
|
703
|
+
const analytics = {
|
|
704
|
+
analyticsId,
|
|
705
|
+
runId,
|
|
706
|
+
reputationDistribution: distribution,
|
|
707
|
+
anomalies,
|
|
708
|
+
recommendations,
|
|
709
|
+
createdAt: now,
|
|
710
|
+
};
|
|
711
|
+
_analytics.set(runId, analytics);
|
|
712
|
+
db.prepare(
|
|
713
|
+
`INSERT INTO reputation_analytics (analytics_id, run_id, reputation_distribution, anomalies, recommendations, created_at)
|
|
714
|
+
VALUES (?, ?, ?, ?, ?, ?)`,
|
|
715
|
+
).run(
|
|
716
|
+
analyticsId,
|
|
717
|
+
runId,
|
|
718
|
+
JSON.stringify(distribution),
|
|
719
|
+
JSON.stringify(anomalies),
|
|
720
|
+
JSON.stringify(recommendations),
|
|
721
|
+
now,
|
|
722
|
+
);
|
|
723
|
+
|
|
724
|
+
const { _seq: _omit, ...rest } = run;
|
|
725
|
+
void _omit;
|
|
726
|
+
return { ...rest, analytics };
|
|
727
|
+
}
|
|
728
|
+
|
|
729
|
+
export function cancelOptimization(db, runId) {
|
|
730
|
+
return setRunStatus(db, runId, RUN_STATUS_V2.CANCELLED);
|
|
731
|
+
}
|
|
732
|
+
|
|
733
|
+
export function failOptimization(db, runId, errorMessage) {
|
|
734
|
+
return setRunStatus(db, runId, RUN_STATUS_V2.FAILED, { errorMessage });
|
|
735
|
+
}
|
|
736
|
+
|
|
737
|
+
export function applyOptimization(db, runId) {
|
|
738
|
+
return setRunStatus(db, runId, RUN_STATUS_V2.APPLIED);
|
|
739
|
+
}
|
|
740
|
+
|
|
741
|
+
export function setRunStatus(db, runId, newStatus, patch = {}) {
|
|
742
|
+
const run = _runs.get(runId);
|
|
743
|
+
if (!run) throw new Error(`Optimization run not found: ${runId}`);
|
|
744
|
+
|
|
745
|
+
if (!Object.values(RUN_STATUS_V2).includes(newStatus)) {
|
|
746
|
+
throw new Error(`Unknown run status: ${newStatus}`);
|
|
747
|
+
}
|
|
748
|
+
|
|
749
|
+
const allowed = _runAllowed.get(run.status);
|
|
750
|
+
if (!allowed || !allowed.has(newStatus)) {
|
|
751
|
+
throw new Error(
|
|
752
|
+
`Invalid run status transition: ${run.status} → ${newStatus}`,
|
|
753
|
+
);
|
|
754
|
+
}
|
|
755
|
+
|
|
756
|
+
run.status = newStatus;
|
|
757
|
+
if (typeof patch.errorMessage === "string") {
|
|
758
|
+
run.errorMessage = patch.errorMessage;
|
|
759
|
+
}
|
|
760
|
+
if (_runTerminal.has(newStatus) && run.completedAt == null) {
|
|
761
|
+
run.completedAt = Date.now();
|
|
762
|
+
}
|
|
763
|
+
|
|
764
|
+
db.prepare(
|
|
765
|
+
`UPDATE reputation_optimization_runs SET status = ?, completed_at = ? WHERE run_id = ?`,
|
|
766
|
+
).run(newStatus, run.completedAt, runId);
|
|
767
|
+
|
|
768
|
+
const { _seq: _omit, ...rest } = run;
|
|
769
|
+
void _omit;
|
|
770
|
+
return rest;
|
|
771
|
+
}
|
|
772
|
+
|
|
773
|
+
export function getReputationStatsV2() {
|
|
774
|
+
const runs = [..._runs.values()];
|
|
775
|
+
const observations = [];
|
|
776
|
+
for (const arr of _observations.values()) observations.push(...arr);
|
|
777
|
+
|
|
778
|
+
const byStatus = {};
|
|
779
|
+
for (const s of Object.values(RUN_STATUS_V2)) byStatus[s] = 0;
|
|
780
|
+
for (const r of runs) byStatus[r.status] = (byStatus[r.status] || 0) + 1;
|
|
781
|
+
|
|
782
|
+
const byObjective = {};
|
|
783
|
+
for (const o of Object.values(OBJECTIVE_V2)) byObjective[o] = 0;
|
|
784
|
+
for (const r of runs)
|
|
785
|
+
byObjective[r.objective] = (byObjective[r.objective] || 0) + 1;
|
|
786
|
+
|
|
787
|
+
let totalObservations = observations.length;
|
|
788
|
+
let totalDids = _observations.size;
|
|
789
|
+
let bestScore = null;
|
|
790
|
+
for (const r of runs) {
|
|
791
|
+
if (r.bestScore != null && (bestScore == null || r.bestScore > bestScore)) {
|
|
792
|
+
bestScore = r.bestScore;
|
|
793
|
+
}
|
|
794
|
+
}
|
|
795
|
+
|
|
796
|
+
return {
|
|
797
|
+
totalRuns: runs.length,
|
|
798
|
+
activeRuns: getActiveOptimizationCount(),
|
|
799
|
+
maxConcurrentOptimizations: _maxConcurrentOptimizations,
|
|
800
|
+
byStatus,
|
|
801
|
+
byObjective,
|
|
802
|
+
observations: {
|
|
803
|
+
totalDids,
|
|
804
|
+
totalObservations,
|
|
805
|
+
},
|
|
806
|
+
bestScoreEver: bestScore,
|
|
807
|
+
};
|
|
509
808
|
}
|