@hardkas/core 0.7.1-alpha → 0.7.4-alpha
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/dist/index.d.ts +2 -1
- package/dist/index.js +141 -43
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -654,6 +654,7 @@ interface RuntimeContext {
|
|
|
654
654
|
random: DeterministicRandom;
|
|
655
655
|
ids: IdProvider;
|
|
656
656
|
telemetry: TelemetryManager;
|
|
657
|
+
workflowId?: string;
|
|
657
658
|
}
|
|
658
659
|
/**
|
|
659
660
|
* A default system runtime context (for non-deterministic contexts like dev server or CLI entry points)
|
|
@@ -786,7 +787,7 @@ declare class AppendCoordinator {
|
|
|
786
787
|
};
|
|
787
788
|
}
|
|
788
789
|
|
|
789
|
-
declare const CURRENT_RUNTIME_VERSION = "0.7.
|
|
790
|
+
declare const CURRENT_RUNTIME_VERSION = "0.7.4-alpha";
|
|
790
791
|
declare const MIN_SUPPORTED_VERSION = "0.5.0-alpha";
|
|
791
792
|
interface MigrationStatus {
|
|
792
793
|
needsMigration: boolean;
|
package/dist/index.js
CHANGED
|
@@ -93,7 +93,13 @@ function getTelemetry() {
|
|
|
93
93
|
}
|
|
94
94
|
var TelemetryProxy = class {
|
|
95
95
|
logAnomaly(anomalyType, severity, subsystem, details, sandboxOverride) {
|
|
96
|
-
return getTelemetry().logAnomaly(
|
|
96
|
+
return getTelemetry().logAnomaly(
|
|
97
|
+
anomalyType,
|
|
98
|
+
severity,
|
|
99
|
+
subsystem,
|
|
100
|
+
details,
|
|
101
|
+
sandboxOverride
|
|
102
|
+
);
|
|
97
103
|
}
|
|
98
104
|
init(rootDir) {
|
|
99
105
|
return getTelemetry().init(rootDir);
|
|
@@ -142,7 +148,9 @@ var AppendCoordinator = class _AppendCoordinator {
|
|
|
142
148
|
} catch (e) {
|
|
143
149
|
if (e.code === "EEXIST") {
|
|
144
150
|
if (Date.now() - start > timeoutMs) {
|
|
145
|
-
throw new Error(
|
|
151
|
+
throw new Error(
|
|
152
|
+
`[AppendCoordinator] Timeout waiting for lock on ${lockPath}`
|
|
153
|
+
);
|
|
146
154
|
}
|
|
147
155
|
const sleepMs = 5 + Math.floor(Math.random() * 15);
|
|
148
156
|
const sharedBuf = new Int32Array(new SharedArrayBuffer(4));
|
|
@@ -152,7 +160,10 @@ var AppendCoordinator = class _AppendCoordinator {
|
|
|
152
160
|
throw e;
|
|
153
161
|
}
|
|
154
162
|
}
|
|
155
|
-
fs.writeSync(
|
|
163
|
+
fs.writeSync(
|
|
164
|
+
fd,
|
|
165
|
+
JSON.stringify({ pid: process.pid, time: (/* @__PURE__ */ new Date()).toISOString() })
|
|
166
|
+
);
|
|
156
167
|
const recovery = _AppendCoordinator.recoverCorruptedTail(filePath);
|
|
157
168
|
if (recovery.repaired) {
|
|
158
169
|
repaired = true;
|
|
@@ -311,7 +322,7 @@ var CoreEventBus = class {
|
|
|
311
322
|
}
|
|
312
323
|
}
|
|
313
324
|
/**
|
|
314
|
-
* Normalizes and emits an event.
|
|
325
|
+
* Normalizes and emits an event.
|
|
315
326
|
* Useful for incremental migration from raw events.
|
|
316
327
|
*/
|
|
317
328
|
normalizeAndEmit(event) {
|
|
@@ -396,7 +407,10 @@ function maskSecrets(data) {
|
|
|
396
407
|
let redacted = data.replace(/\b[0-9a-fA-F]{64}\b/g, (match) => {
|
|
397
408
|
return `${match.slice(0, 6)}...${match.slice(-4)} [REDACTED]`;
|
|
398
409
|
});
|
|
399
|
-
redacted = redacted.replace(
|
|
410
|
+
redacted = redacted.replace(
|
|
411
|
+
/\b([a-z]{3,10}\s+){11,23}[a-z]{3,10}\b/g,
|
|
412
|
+
"[MNEMONIC REDACTED]"
|
|
413
|
+
);
|
|
400
414
|
return redacted;
|
|
401
415
|
}
|
|
402
416
|
if (Array.isArray(data)) {
|
|
@@ -452,7 +466,12 @@ async function writeFileAtomic(targetPath, data, options = {}) {
|
|
|
452
466
|
attempts++;
|
|
453
467
|
if (attempts >= maxAttempts) throw e;
|
|
454
468
|
if (e.code === "EPERM" || e.code === "EBUSY") {
|
|
455
|
-
EnvironmentTelemetry.logAnomaly(
|
|
469
|
+
EnvironmentTelemetry.logAnomaly(
|
|
470
|
+
"FS_RETRY",
|
|
471
|
+
"low",
|
|
472
|
+
"fs",
|
|
473
|
+
`Retrying rename of ${targetPath} due to ${e.code}`
|
|
474
|
+
);
|
|
456
475
|
await new Promise((resolve) => setTimeout(resolve, 10 * attempts));
|
|
457
476
|
continue;
|
|
458
477
|
}
|
|
@@ -470,11 +489,9 @@ async function writeFileAtomic(targetPath, data, options = {}) {
|
|
|
470
489
|
}
|
|
471
490
|
}
|
|
472
491
|
} catch (err) {
|
|
473
|
-
throw new HardkasError(
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
{ cause: err }
|
|
477
|
-
);
|
|
492
|
+
throw new HardkasError("IO_ERROR", `Failed to write file atomically: ${targetPath}`, {
|
|
493
|
+
cause: err
|
|
494
|
+
});
|
|
478
495
|
} finally {
|
|
479
496
|
if (fs2.existsSync(tempPath)) {
|
|
480
497
|
try {
|
|
@@ -515,7 +532,12 @@ function writeFileAtomicSync(targetPath, data, options = {}) {
|
|
|
515
532
|
attempts++;
|
|
516
533
|
if (attempts >= maxAttempts) throw e;
|
|
517
534
|
if (e.code === "EPERM" || e.code === "EBUSY") {
|
|
518
|
-
EnvironmentTelemetry.logAnomaly(
|
|
535
|
+
EnvironmentTelemetry.logAnomaly(
|
|
536
|
+
"FS_RETRY",
|
|
537
|
+
"low",
|
|
538
|
+
"fs",
|
|
539
|
+
`Retrying rename sync of ${targetPath} due to ${e.code}`
|
|
540
|
+
);
|
|
519
541
|
continue;
|
|
520
542
|
}
|
|
521
543
|
throw e;
|
|
@@ -614,7 +636,9 @@ async function acquireLock(args) {
|
|
|
614
636
|
release: async () => {
|
|
615
637
|
if (fs3.existsSync(lockPath)) {
|
|
616
638
|
try {
|
|
617
|
-
const current = JSON.parse(
|
|
639
|
+
const current = JSON.parse(
|
|
640
|
+
fs3.readFileSync(lockPath, "utf-8")
|
|
641
|
+
);
|
|
618
642
|
if (current.pid === process.pid) {
|
|
619
643
|
fs3.unlinkSync(lockPath);
|
|
620
644
|
}
|
|
@@ -645,13 +669,27 @@ async function acquireLock(args) {
|
|
|
645
669
|
staleRecoveryAttempted = true;
|
|
646
670
|
try {
|
|
647
671
|
fs3.unlinkSync(lockPath);
|
|
648
|
-
EnvironmentTelemetry.logAnomaly(
|
|
672
|
+
EnvironmentTelemetry.logAnomaly(
|
|
673
|
+
"STALE_LOCK_RECOVERY",
|
|
674
|
+
"medium",
|
|
675
|
+
"lock",
|
|
676
|
+
`Recovered corrupted lock file at ${lockPath} (Age: ${ageMs}ms)`,
|
|
677
|
+
args.rootDir
|
|
678
|
+
);
|
|
649
679
|
continue;
|
|
650
680
|
} catch {
|
|
651
|
-
throw new HardkasError(
|
|
681
|
+
throw new HardkasError(
|
|
682
|
+
"LOCK_METADATA_INVALID",
|
|
683
|
+
`Lock file at ${lockPath} is corrupted and cannot be recovered.`,
|
|
684
|
+
{ cause: err }
|
|
685
|
+
);
|
|
652
686
|
}
|
|
653
687
|
}
|
|
654
|
-
throw new HardkasError(
|
|
688
|
+
throw new HardkasError(
|
|
689
|
+
"LOCK_METADATA_INVALID",
|
|
690
|
+
`Lock file at ${lockPath} is corrupted.`,
|
|
691
|
+
{ cause: err }
|
|
692
|
+
);
|
|
655
693
|
}
|
|
656
694
|
if (existingMetadata) {
|
|
657
695
|
const isLocal = existingMetadata.hostname === os.hostname();
|
|
@@ -660,7 +698,13 @@ async function acquireLock(args) {
|
|
|
660
698
|
staleRecoveryAttempted = true;
|
|
661
699
|
try {
|
|
662
700
|
fs3.unlinkSync(lockPath);
|
|
663
|
-
EnvironmentTelemetry.logAnomaly(
|
|
701
|
+
EnvironmentTelemetry.logAnomaly(
|
|
702
|
+
"STALE_LOCK_RECOVERY",
|
|
703
|
+
"medium",
|
|
704
|
+
"lock",
|
|
705
|
+
`Recovered lock held by dead process (PID: ${existingMetadata.pid})`,
|
|
706
|
+
args.rootDir
|
|
707
|
+
);
|
|
664
708
|
continue;
|
|
665
709
|
} catch (unlinkErr) {
|
|
666
710
|
throw new HardkasError(
|
|
@@ -678,7 +722,13 @@ async function acquireLock(args) {
|
|
|
678
722
|
);
|
|
679
723
|
}
|
|
680
724
|
if (args.wait && Date.now() - start < timeoutMs) {
|
|
681
|
-
EnvironmentTelemetry.logAnomaly(
|
|
725
|
+
EnvironmentTelemetry.logAnomaly(
|
|
726
|
+
"LOCK_CONTENTION",
|
|
727
|
+
"low",
|
|
728
|
+
"lock",
|
|
729
|
+
`Waiting for lock ${args.name} held by PID ${existingMetadata.pid}`,
|
|
730
|
+
args.rootDir
|
|
731
|
+
);
|
|
682
732
|
await new Promise((resolve) => setTimeout(resolve, pollMs));
|
|
683
733
|
continue;
|
|
684
734
|
}
|
|
@@ -767,10 +817,18 @@ function clearLock(rootDir, name, options = {}) {
|
|
|
767
817
|
const isLocal = metadata.hostname === os.hostname();
|
|
768
818
|
const isAlive = isLocal ? isProcessAlive(metadata.pid) : true;
|
|
769
819
|
if (options.ifDead) {
|
|
770
|
-
if (!isLocal)
|
|
771
|
-
|
|
820
|
+
if (!isLocal)
|
|
821
|
+
return {
|
|
822
|
+
cleared: false,
|
|
823
|
+
reason: "Cannot verify liveness of remote lock (host: " + metadata.hostname + ")"
|
|
824
|
+
};
|
|
825
|
+
if (isAlive)
|
|
826
|
+
return { cleared: false, reason: `Process (PID: ${metadata.pid}) is still alive` };
|
|
772
827
|
} else if (!options.force) {
|
|
773
|
-
return {
|
|
828
|
+
return {
|
|
829
|
+
cleared: false,
|
|
830
|
+
reason: "Lock is potentially active. Use --force or --if-dead."
|
|
831
|
+
};
|
|
774
832
|
}
|
|
775
833
|
fs3.unlinkSync(lockPath);
|
|
776
834
|
return { cleared: true };
|
|
@@ -823,7 +881,10 @@ function diffReplays(replayA, replayB) {
|
|
|
823
881
|
const timeA = new Date(tsA).getTime();
|
|
824
882
|
const timeB = new Date(tsB).getTime();
|
|
825
883
|
if (timeA !== timeB) {
|
|
826
|
-
diff.observational.timestampShifts.push({
|
|
884
|
+
diff.observational.timestampShifts.push({
|
|
885
|
+
path: "timestamp",
|
|
886
|
+
shiftMs: Math.abs(timeA - timeB)
|
|
887
|
+
});
|
|
827
888
|
}
|
|
828
889
|
}
|
|
829
890
|
return diff;
|
|
@@ -879,7 +940,7 @@ async function createSnapshot(options) {
|
|
|
879
940
|
const manifest = {
|
|
880
941
|
snapshotVersion: 1,
|
|
881
942
|
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
882
|
-
hardkasVersion: "0.7.
|
|
943
|
+
hardkasVersion: "0.7.4-alpha",
|
|
883
944
|
stateAuthority: "filesystem",
|
|
884
945
|
projectionAuthority: "sqlite",
|
|
885
946
|
deterministicScope,
|
|
@@ -924,7 +985,10 @@ var TelemetryRotator = class {
|
|
|
924
985
|
}
|
|
925
986
|
const stats = fs5.statSync(activeFile);
|
|
926
987
|
if (stats.size < maxSizeBytes) {
|
|
927
|
-
return {
|
|
988
|
+
return {
|
|
989
|
+
rotated: false,
|
|
990
|
+
reason: `File size (${stats.size}) is below threshold (${maxSizeBytes})`
|
|
991
|
+
};
|
|
928
992
|
}
|
|
929
993
|
return this.forceRotate(rootDir);
|
|
930
994
|
}
|
|
@@ -1019,7 +1083,9 @@ function verifyArtifactIntegrity(identity, computedHash) {
|
|
|
1019
1083
|
}
|
|
1020
1084
|
function verifyReplay(identity, replayCtx) {
|
|
1021
1085
|
if (identity.semanticHash !== replayCtx.semanticHash) {
|
|
1022
|
-
throw new Error(
|
|
1086
|
+
throw new Error(
|
|
1087
|
+
`[CRITICAL SEMANTIC ERROR] Replay semantic hash divergence: expected ${identity.semanticHash}, got ${replayCtx.semanticHash}`
|
|
1088
|
+
);
|
|
1023
1089
|
}
|
|
1024
1090
|
validateStatusTransition(identity.status, "REPLAY_VERIFIED");
|
|
1025
1091
|
return "REPLAY_VERIFIED";
|
|
@@ -1042,10 +1108,14 @@ function verifyCapabilityBoundary(identity, capability) {
|
|
|
1042
1108
|
// src/semantics/migration.ts
|
|
1043
1109
|
function verifyMigrationIntegrity(preMigration, postMigration) {
|
|
1044
1110
|
if (preMigration.artifactId !== postMigration.artifactId) {
|
|
1045
|
-
throw new Error(
|
|
1111
|
+
throw new Error(
|
|
1112
|
+
`[CRITICAL SEMANTIC ERROR] Migration unexpectedly altered canonical artifact ID: ${preMigration.artifactId} -> ${postMigration.artifactId}`
|
|
1113
|
+
);
|
|
1046
1114
|
}
|
|
1047
1115
|
if (postMigration.schemaVersion < preMigration.schemaVersion) {
|
|
1048
|
-
throw new Error(
|
|
1116
|
+
throw new Error(
|
|
1117
|
+
`[CRITICAL SEMANTIC ERROR] Invalid migration: schema downgraded from ${preMigration.schemaVersion} to ${postMigration.schemaVersion}`
|
|
1118
|
+
);
|
|
1049
1119
|
}
|
|
1050
1120
|
}
|
|
1051
1121
|
function migrateArtifact(identity, targetVersion) {
|
|
@@ -1060,7 +1130,9 @@ function migrateArtifact(identity, targetVersion) {
|
|
|
1060
1130
|
}
|
|
1061
1131
|
function comparePrePostMigrationLineage(preLineageId, postLineageId) {
|
|
1062
1132
|
if (preLineageId !== postLineageId) {
|
|
1063
|
-
throw new Error(
|
|
1133
|
+
throw new Error(
|
|
1134
|
+
`[CRITICAL SEMANTIC ERROR] Lineage broken across schema migration: ${preLineageId} -> ${postLineageId}`
|
|
1135
|
+
);
|
|
1064
1136
|
}
|
|
1065
1137
|
}
|
|
1066
1138
|
|
|
@@ -1098,7 +1170,12 @@ function detectSemanticDrift(dashboardView, queryStoreView, replayView, filesyst
|
|
|
1098
1170
|
return { hasDrift: false, severity: "NONE" };
|
|
1099
1171
|
}
|
|
1100
1172
|
function assertNoSemanticDrift(dashboardView, queryStoreView, replayView, filesystemView) {
|
|
1101
|
-
const report = detectSemanticDrift(
|
|
1173
|
+
const report = detectSemanticDrift(
|
|
1174
|
+
dashboardView,
|
|
1175
|
+
queryStoreView,
|
|
1176
|
+
replayView,
|
|
1177
|
+
filesystemView
|
|
1178
|
+
);
|
|
1102
1179
|
if (report.hasDrift) {
|
|
1103
1180
|
throw new Error(
|
|
1104
1181
|
`[CRITICAL SEMANTIC DRIFT] Subsystem disagreement detected.
|
|
@@ -1112,14 +1189,18 @@ Resolution Command: ${report.exactReplayCommand}`
|
|
|
1112
1189
|
// src/migrations.ts
|
|
1113
1190
|
import fs6 from "fs";
|
|
1114
1191
|
import path8 from "path";
|
|
1115
|
-
var CURRENT_RUNTIME_VERSION = "0.7.
|
|
1192
|
+
var CURRENT_RUNTIME_VERSION = "0.7.4-alpha";
|
|
1116
1193
|
var MIN_SUPPORTED_VERSION = "0.5.0-alpha";
|
|
1117
1194
|
var MigrationManager = class {
|
|
1118
1195
|
static checkVersion(rootDir) {
|
|
1119
1196
|
const versionFile = path8.join(rootDir, ".hardkas", "version.json");
|
|
1120
1197
|
if (!fs6.existsSync(versionFile)) {
|
|
1121
1198
|
this.writeVersion(rootDir, CURRENT_RUNTIME_VERSION);
|
|
1122
|
-
return {
|
|
1199
|
+
return {
|
|
1200
|
+
needsMigration: false,
|
|
1201
|
+
canDowngrade: true,
|
|
1202
|
+
currentVersion: CURRENT_RUNTIME_VERSION
|
|
1203
|
+
};
|
|
1123
1204
|
}
|
|
1124
1205
|
try {
|
|
1125
1206
|
const data = JSON.parse(fs6.readFileSync(versionFile, "utf-8"));
|
|
@@ -1131,30 +1212,49 @@ var MigrationManager = class {
|
|
|
1131
1212
|
return { needsMigration: false, canDowngrade: false, currentVersion: wsVersion };
|
|
1132
1213
|
}
|
|
1133
1214
|
if (this.compareSemver(wsVersion, MIN_SUPPORTED_VERSION) < 0) {
|
|
1134
|
-
throw new HardkasError(
|
|
1215
|
+
throw new HardkasError(
|
|
1216
|
+
"MIGRATION_UNSUPPORTED",
|
|
1217
|
+
`Workspace version ${wsVersion} is too old to migrate to ${CURRENT_RUNTIME_VERSION}`
|
|
1218
|
+
);
|
|
1135
1219
|
}
|
|
1136
1220
|
return { needsMigration: true, canDowngrade: true, currentVersion: wsVersion };
|
|
1137
1221
|
} catch (err) {
|
|
1138
1222
|
if (err instanceof HardkasError) throw err;
|
|
1139
|
-
throw new HardkasError(
|
|
1223
|
+
throw new HardkasError(
|
|
1224
|
+
"MIGRATION_ERROR",
|
|
1225
|
+
`Failed to parse version.json: ${err.message}`
|
|
1226
|
+
);
|
|
1140
1227
|
}
|
|
1141
1228
|
}
|
|
1142
1229
|
static migrate(rootDir, dryRun = false) {
|
|
1143
1230
|
const status = this.checkVersion(rootDir);
|
|
1144
1231
|
if (!status.canDowngrade) {
|
|
1145
|
-
throw new HardkasError(
|
|
1232
|
+
throw new HardkasError(
|
|
1233
|
+
"DOWNGRADE_REFUSED",
|
|
1234
|
+
`Cannot safely downgrade from workspace version ${status.currentVersion} to runtime version ${CURRENT_RUNTIME_VERSION}.`
|
|
1235
|
+
);
|
|
1146
1236
|
}
|
|
1147
1237
|
if (!status.needsMigration) return;
|
|
1148
1238
|
if (dryRun) {
|
|
1149
|
-
console.log(
|
|
1239
|
+
console.log(
|
|
1240
|
+
`[DRY-RUN] Would migrate workspace from ${status.currentVersion} to ${CURRENT_RUNTIME_VERSION}`
|
|
1241
|
+
);
|
|
1150
1242
|
return;
|
|
1151
1243
|
}
|
|
1152
1244
|
this.backupWorkspace(rootDir);
|
|
1153
1245
|
try {
|
|
1154
1246
|
this.writeVersion(rootDir, CURRENT_RUNTIME_VERSION);
|
|
1155
1247
|
} catch (err) {
|
|
1156
|
-
getTelemetry().logAnomaly(
|
|
1157
|
-
|
|
1248
|
+
getTelemetry().logAnomaly(
|
|
1249
|
+
"EXTERNAL_MUTATION",
|
|
1250
|
+
"critical",
|
|
1251
|
+
"projection",
|
|
1252
|
+
`Migration failed: ${err.message}`
|
|
1253
|
+
);
|
|
1254
|
+
throw new HardkasError(
|
|
1255
|
+
"MIGRATION_FAILED",
|
|
1256
|
+
`Migration failed, workspace might be corrupted: ${err.message}`
|
|
1257
|
+
);
|
|
1158
1258
|
}
|
|
1159
1259
|
}
|
|
1160
1260
|
static writeVersion(rootDir, version) {
|
|
@@ -1195,11 +1295,7 @@ var kaspaNetworkIdSchema = z.enum([
|
|
|
1195
1295
|
"devnet",
|
|
1196
1296
|
"simulated"
|
|
1197
1297
|
]);
|
|
1198
|
-
var executionModeSchema = z.enum([
|
|
1199
|
-
"simulated",
|
|
1200
|
-
"real",
|
|
1201
|
-
"readonly"
|
|
1202
|
-
]);
|
|
1298
|
+
var executionModeSchema = z.enum(["simulated", "real", "readonly"]);
|
|
1203
1299
|
var artifactTypeSchema = z.enum([
|
|
1204
1300
|
"txPlan",
|
|
1205
1301
|
"signedTx",
|
|
@@ -1239,7 +1335,9 @@ var InvariantViolationError = class extends HardkasError {
|
|
|
1239
1335
|
domain;
|
|
1240
1336
|
severity;
|
|
1241
1337
|
constructor(domain, message, options) {
|
|
1242
|
-
super(`INVARIANT_VIOLATION_${domain.toUpperCase()}`, message, {
|
|
1338
|
+
super(`INVARIANT_VIOLATION_${domain.toUpperCase()}`, message, {
|
|
1339
|
+
cause: options?.cause
|
|
1340
|
+
});
|
|
1243
1341
|
this.name = "InvariantViolationError";
|
|
1244
1342
|
this.domain = domain;
|
|
1245
1343
|
this.severity = options?.severity || "fatal";
|