@akagilnc/pi-workflow-roles 0.1.2517 → 0.1.2525
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/public-cli/main.js
CHANGED
|
@@ -16111,14 +16111,19 @@ async function createWriterLease(lockPath, runDirectory, reportCleanupFailure) {
|
|
|
16111
16111
|
};
|
|
16112
16112
|
}
|
|
16113
16113
|
async function acquireRunWriterLease(runDirectory, onCleanupFailure) {
|
|
16114
|
-
const
|
|
16114
|
+
const reportDiagnostic = (diagnostic) => {
|
|
16115
|
+
const line2 = diagnostic.endsWith("\n") ? diagnostic : `${diagnostic}
|
|
16116
|
+
`;
|
|
16115
16117
|
try {
|
|
16116
|
-
onCleanupFailure?.(
|
|
16117
|
-
`writer lease lock cleanup failed (best-effort continue; stale lock is reclaimed by the next acquire's holder autopsy) at ${join7(runDirectory, WRITER_LOCK_FILE)}: ${describeErrorIdentity(error)}`
|
|
16118
|
-
);
|
|
16118
|
+
onCleanupFailure?.(line2);
|
|
16119
16119
|
} catch {
|
|
16120
16120
|
}
|
|
16121
16121
|
};
|
|
16122
|
+
const reportCleanupFailure = (error) => {
|
|
16123
|
+
reportDiagnostic(
|
|
16124
|
+
`writer lease lock cleanup failed (best-effort continue; stale lock is reclaimed by the next acquire's holder autopsy) at ${join7(runDirectory, WRITER_LOCK_FILE)}: ${describeErrorIdentity(error)}`
|
|
16125
|
+
);
|
|
16126
|
+
};
|
|
16122
16127
|
const lockPath = join7(runDirectory, WRITER_LOCK_FILE);
|
|
16123
16128
|
let lastAutopsy = { verdict: "absent" };
|
|
16124
16129
|
for (let reclaimsLeft = WRITER_LEASE_RECLAIM_ROUNDS; ; reclaimsLeft -= 1) {
|
|
@@ -16149,6 +16154,9 @@ async function acquireRunWriterLease(runDirectory, onCleanupFailure) {
|
|
|
16149
16154
|
`stale writer lease reclaim failed at ${lockPath} (autopsy: ${describeAutopsy(lastAutopsy)}): ${describeErrorIdentity(reclaimError)}`
|
|
16150
16155
|
);
|
|
16151
16156
|
}
|
|
16157
|
+
reportDiagnostic(
|
|
16158
|
+
`stale writer lease reclaimed at ${lockPath} (holder pid ${lastAutopsy.pid} verified dead): the killed holder may have left an orphaned pi child still writing this run \u2014 check for a surviving pi process on this run before continuing`
|
|
16159
|
+
);
|
|
16152
16160
|
}
|
|
16153
16161
|
throw new RunWriterLeaseHeldError(
|
|
16154
16162
|
`role run writer lease stayed contested at ${lockPath} after ${WRITER_LEASE_RECLAIM_ROUNDS} reclaims (last autopsy: ${describeAutopsy(lastAutopsy)})`
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@akagilnc/pi-workflow-roles",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2525",
|
|
4
4
|
"description": "Soul-bound workflow roles for Pi",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -42,11 +42,11 @@
|
|
|
42
42
|
"scripts": {
|
|
43
43
|
"build": "tsx scripts/generate-tool-execution-observation-schema.ts && tsc -p tsconfig.build.json && node scripts/build-package.mjs",
|
|
44
44
|
"prepack": "npm run build",
|
|
45
|
-
"test": "node --import tsx --test test/unit/**/*.test.ts test/contract/**/*.test.ts",
|
|
46
|
-
"test:fast": "node --import tsx --test test/unit/**/*.test.ts test/contract/**/*.test.ts",
|
|
47
|
-
"test:integration": "node --import tsx --test test/unit/**/*.test.ts test/contract/**/*.test.ts test/integration/**/*.test.ts",
|
|
45
|
+
"test": "node --import tsx --import ./scripts/test-process-env-preload.mjs --test test/unit/**/*.test.ts test/contract/**/*.test.ts",
|
|
46
|
+
"test:fast": "node --import tsx --import ./scripts/test-process-env-preload.mjs --test test/unit/**/*.test.ts test/contract/**/*.test.ts",
|
|
47
|
+
"test:integration": "node --import tsx --import ./scripts/test-process-env-preload.mjs --test test/unit/**/*.test.ts test/contract/**/*.test.ts test/integration/**/*.test.ts",
|
|
48
48
|
"test:all": "node scripts/run-test-all.mjs",
|
|
49
|
-
"test:adjudication": "node --import tsx --test test/adjudication/**/*.test.ts",
|
|
49
|
+
"test:adjudication": "node --import tsx --import ./scripts/test-process-env-preload.mjs --test test/adjudication/**/*.test.ts",
|
|
50
50
|
"typecheck": "tsc --noEmit"
|
|
51
51
|
},
|
|
52
52
|
"pi": {
|
|
@@ -523,7 +523,8 @@ const WRITER_LEASE_RECLAIM_ROUNDS = 3;
|
|
|
523
523
|
* race repeatedly lost) surfaces the same typed error instead of spinning.
|
|
524
524
|
*
|
|
525
525
|
* `onCleanupFailure` receives a non-terminal diagnostic line when release-time
|
|
526
|
-
* lock cleanup fails
|
|
526
|
+
* lock cleanup fails, a contested lock cannot be read, or a stale lock is
|
|
527
|
+
* reclaimed (the #556 orphan-pi residual declaration). Release stays
|
|
527
528
|
* best-effort (a stale lock is reclaimed by the next acquire's autopsy), but
|
|
528
529
|
* the true error identity must still land somewhere observable — silent
|
|
529
530
|
* swallowing is forbidden.
|
|
@@ -532,18 +533,24 @@ export async function acquireRunWriterLease(
|
|
|
532
533
|
runDirectory: string,
|
|
533
534
|
onCleanupFailure?: (diagnostic: string) => void,
|
|
534
535
|
): Promise<RunWriterLease> {
|
|
535
|
-
const
|
|
536
|
-
//
|
|
537
|
-
//
|
|
538
|
-
//
|
|
536
|
+
const reportDiagnostic = (diagnostic: string): void => {
|
|
537
|
+
// Single sink exit for every non-terminal writer-lease diagnostic (#556):
|
|
538
|
+
// a throwing onCleanupFailure must not propagate through release() or
|
|
539
|
+
// acquire() — both are best-effort by contract. Template wording stays at
|
|
540
|
+
// the call sites, never inside this wrapper. The default io.stderr writes
|
|
541
|
+
// raw, so this exit guarantees the line delimiter.
|
|
542
|
+
const line = diagnostic.endsWith("\n") ? diagnostic : `${diagnostic}\n`;
|
|
539
543
|
try {
|
|
540
|
-
onCleanupFailure?.(
|
|
541
|
-
`writer lease lock cleanup failed (best-effort continue; stale lock is reclaimed by the next acquire's holder autopsy) at ${join(runDirectory, WRITER_LOCK_FILE)}: ${describeErrorIdentity(error)}`,
|
|
542
|
-
);
|
|
544
|
+
onCleanupFailure?.(line);
|
|
543
545
|
} catch {
|
|
544
|
-
// diagnostic-sink failure is itself best-effort; never break release().
|
|
546
|
+
// diagnostic-sink failure is itself best-effort; never break acquire()/release().
|
|
545
547
|
}
|
|
546
548
|
};
|
|
549
|
+
const reportCleanupFailure = (error: unknown): void => {
|
|
550
|
+
reportDiagnostic(
|
|
551
|
+
`writer lease lock cleanup failed (best-effort continue; stale lock is reclaimed by the next acquire's holder autopsy) at ${join(runDirectory, WRITER_LOCK_FILE)}: ${describeErrorIdentity(error)}`,
|
|
552
|
+
);
|
|
553
|
+
};
|
|
547
554
|
const lockPath = join(runDirectory, WRITER_LOCK_FILE);
|
|
548
555
|
let lastAutopsy: WriterLockAutopsy = { verdict: "absent" };
|
|
549
556
|
// The reclaim budget: every successful reclaim is immediately followed by a
|
|
@@ -585,6 +592,12 @@ export async function acquireRunWriterLease(
|
|
|
585
592
|
`stale writer lease reclaim failed at ${lockPath} (autopsy: ${describeAutopsy(lastAutopsy)}): ${describeErrorIdentity(reclaimError)}`,
|
|
586
593
|
);
|
|
587
594
|
}
|
|
595
|
+
// #556 residual declaration, facts only: the pid-only autopsy proves the
|
|
596
|
+
// CLI holder died; its pi child may outlive it and keep writing this run.
|
|
597
|
+
// Declare — do not guard.
|
|
598
|
+
reportDiagnostic(
|
|
599
|
+
`stale writer lease reclaimed at ${lockPath} (holder pid ${lastAutopsy.pid} verified dead): the killed holder may have left an orphaned pi child still writing this run — check for a surviving pi process on this run before continuing`,
|
|
600
|
+
);
|
|
588
601
|
}
|
|
589
602
|
throw new RunWriterLeaseHeldError(
|
|
590
603
|
`role run writer lease stayed contested at ${lockPath} after ${WRITER_LEASE_RECLAIM_ROUNDS} reclaims (last autopsy: ${describeAutopsy(lastAutopsy)})`,
|