fix: headless EXIT_RELOAD case + notification dedup boundary

- src/headless-events.ts: add case "reload" → EXIT_RELOAD (12).
  EXIT_RELOAD sentinel was defined but unused — "reload" status fell
  through to EXIT_ERROR (1).
- src/resources/extensions/sf/notification-store.ts:109: use <= for
  dedup window so a second identical notification at exactly
  DEDUP_WINDOW_MS still gets suppressed (was off-by-one at boundary).
- src/resources/extensions/sf/definition-loader.ts: pending docstring
  tweaks from autonomous sweep.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Mikael Hugo 2026-05-02 01:52:29 +02:00
parent 7824cb527c
commit 038938f2ac
3 changed files with 10 additions and 2 deletions

View file

@ -43,6 +43,8 @@ export function mapStatusToExitCode(status: string): number {
return EXIT_BLOCKED;
case "cancelled":
return EXIT_CANCELLED;
case "reload":
return EXIT_RELOAD;
default:
return EXIT_ERROR;
}

View file

@ -19,6 +19,9 @@ import { parse } from "yaml";
// ─── Public TypeScript Types (camelCase) ─────────────────────────────────
/**
* Step verification policy: content-heuristic, shell-command, prompt-verify, or human-review.
*/
export type VerifyPolicy =
| { policy: "content-heuristic"; minSize?: number; pattern?: string }
| { policy: "shell-command"; command: string }
@ -32,6 +35,9 @@ export interface IterateConfig {
pattern: string;
}
/**
* Workflow step definition with prompt, dependencies, produced artifacts, and optional verification.
*/
export interface StepDefinition {
/** Unique step identifier within the workflow. */
id: string;

View file

@ -106,7 +106,7 @@ export function appendNotification(
: `${_basePath}:${severity}:${source}:${persistedMessage}`;
const now = Date.now();
const lastSeen = _recentMessageTimestamps.get(dedupKey);
if (lastSeen !== undefined && now - lastSeen < DEDUP_WINDOW_MS) return;
if (lastSeen !== undefined && now - lastSeen <= DEDUP_WINDOW_MS) return;
_recentMessageTimestamps.set(dedupKey, now);
if (_recentMessageTimestamps.size > DEDUP_PRUNE_THRESHOLD) {
for (const [key, ts] of _recentMessageTimestamps) {
@ -347,7 +347,7 @@ function _withLock<T>(basePath: string, fn: () => T): T {
try {
const stat = readFileSync(lockPath, "utf-8");
const lockTime = parseInt(stat, 10);
if (Date.now() - lockTime > 5000) {
if (Number.isFinite(lockTime) && Date.now() - lockTime > 5000) {
try {
unlinkSync(lockPath);
} catch {