From b269f76b333ebf4ab68de8f4eee324cebce79b38 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B0=8F=E6=A9=98?= Date: Mon, 27 Apr 2026 12:07:22 +0000 Subject: [PATCH] =?UTF-8?q?refactor(daemon):=20rename=20reflex-scheduler?= =?UTF-8?q?=20=E2=86=92=20sense-scheduler?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Rename ReflexScheduler to SenseScheduler, update all file names, imports, comments, test descriptions, and log source values. Fixes #202 --- README.md | 2 +- docs/rfc-001-observation-engine.md | 2 +- docs/rfc-002-workflow-engine.md | 10 ++--- packages/core/src/__tests__/config.test.ts | 2 +- packages/core/src/parse-nerve-config.ts | 1 + packages/core/src/sense.ts | 2 +- packages/daemon/README.md | 8 ++-- .../__tests__/log-store-integration.test.ts | 18 ++++----- ... sense-scheduler-throttle-pending.test.ts} | 10 ++--- ...eduler.test.ts => sense-scheduler.test.ts} | 38 +++++++++---------- packages/daemon/src/kernel.ts | 12 +++--- ...reflex-scheduler.ts => sense-scheduler.ts} | 20 +++++----- packages/daemon/src/signal-bus.ts | 2 +- .../src/__tests__/log-store-archive.test.ts | 8 +++- .../store/src/__tests__/log-store.test.ts | 16 ++++---- packages/store/src/log-store.ts | 4 +- 16 files changed, 81 insertions(+), 74 deletions(-) rename packages/daemon/src/__tests__/{reflex-scheduler-throttle-pending.test.ts => sense-scheduler-throttle-pending.test.ts} (90%) rename packages/daemon/src/__tests__/{reflex-scheduler.test.ts => sense-scheduler.test.ts} (86%) rename packages/daemon/src/{reflex-scheduler.ts => sense-scheduler.ts} (91%) diff --git a/README.md b/README.md index a75cfcd..d8ce67f 100644 --- a/README.md +++ b/README.md @@ -30,7 +30,7 @@ Three extension points for **what / when / multi-step action** — reflexes neve |---------|-------------| | [`@uncaged/nerve-core`](./packages/core) | Shared types, config parser, Sense→workflow routing, daemon IPC protocol | | [`@uncaged/nerve-store`](./packages/store) | Append-only log SQLite, JSONL archive, CAS blob store, workflow run rows | -| [`@uncaged/nerve-daemon`](./packages/daemon) | Kernel, workers, signal bus, reflex scheduler, workflow manager, file watcher, IPC | +| [`@uncaged/nerve-daemon`](./packages/daemon) | Kernel, workers, signal bus, sense scheduler, workflow manager, file watcher, IPC | | [`@uncaged/nerve-cli`](./packages/cli) | CLI (`nerve`) — init, validate, daemon, dev, logs, sense, store, workflow | ## Quick Start diff --git a/docs/rfc-001-observation-engine.md b/docs/rfc-001-observation-engine.md index 77c7d9c..c0d9a96 100644 --- a/docs/rfc-001-observation-engine.md +++ b/docs/rfc-001-observation-engine.md @@ -473,7 +473,7 @@ Sense 的运行时属性(`group`、`throttle`、`timeout`)在 `nerve.yaml` ```sql CREATE TABLE logs ( id INTEGER PRIMARY KEY AUTOINCREMENT, - source TEXT NOT NULL, -- "reflex", "workflow", "system" + source TEXT NOT NULL, -- "sense_scheduler", "sense", "workflow", "system" type TEXT NOT NULL, -- "run_start", "run_complete", "error", "state_change" ref_id TEXT, -- 关联的 reflex name / workflow run_id payload TEXT, -- JSON diff --git a/docs/rfc-002-workflow-engine.md b/docs/rfc-002-workflow-engine.md index 2c97804..3a4ff5d 100644 --- a/docs/rfc-002-workflow-engine.md +++ b/docs/rfc-002-workflow-engine.md @@ -350,12 +350,12 @@ export type WorkflowManager = { }; ``` -### 7.2 Reflex Scheduler 扩展 +### 7.2 Sense Scheduler 扩展 -当前 `ReflexScheduler` 只处理 `kind: "sense"` 的 reflex。扩展为同时处理 `kind: "workflow"`: +当前 `SenseScheduler` 只处理 `kind: "sense"` 的 reflex。扩展为同时处理 `kind: "workflow"`: ```typescript -// reflex-scheduler.ts 扩展 +// sense-scheduler.ts 扩展 if (reflex.kind === "workflow") { const workflowName = reflex.workflow; if (reflex.on !== null && reflex.on.length > 0) { @@ -393,8 +393,8 @@ if (reflex.kind === "workflow") { ### Phase 2:Kernel 集成 - [ ] `packages/daemon/src/kernel.ts` — 集成 WorkflowManager,处理 workflow worker 的生命周期 -- [ ] `packages/daemon/src/reflex-scheduler.ts` — 扩展支持 `kind: "workflow"` 的 reflex -- [ ] 集成测试:Sense signal → Reflex → Workflow 全链路 +- [ ] `packages/daemon/src/sense-scheduler.ts` — 扩展支持 `kind: "workflow"` 的 reflex +- [ ] 集成测试:Sense signal → SenseScheduler → Workflow 全链路 ### Phase 3:崩溃恢复与热更新 diff --git a/packages/core/src/__tests__/config.test.ts b/packages/core/src/__tests__/config.test.ts index 19f0057..ea70226 100644 --- a/packages/core/src/__tests__/config.test.ts +++ b/packages/core/src/__tests__/config.test.ts @@ -203,7 +203,7 @@ api: expect(result.value.api).toEqual({ port: 9800, token: "secret", host: "0.0.0.0" }); }); - it("accepts inline interval and on only (no reflexes key)", () => { + it("accepts per-sense interval and on only (no top-level reflexes key)", () => { const yaml = ` senses: cpu: diff --git a/packages/core/src/parse-nerve-config.ts b/packages/core/src/parse-nerve-config.ts index 276d36b..0ff95de 100644 --- a/packages/core/src/parse-nerve-config.ts +++ b/packages/core/src/parse-nerve-config.ts @@ -301,6 +301,7 @@ export function parseNerveConfig(raw: string): Result { if (!sensesResult.ok) return sensesResult; const { senses } = sensesResult.value; + // Legacy top-level `reflexes` is rejected; each sense carries `interval` / `on` for the sense scheduler. if (Object.hasOwn(obj, "reflexes")) { return err( new Error( diff --git a/packages/core/src/sense.ts b/packages/core/src/sense.ts index f5aecfc..d863733 100644 --- a/packages/core/src/sense.ts +++ b/packages/core/src/sense.ts @@ -11,7 +11,7 @@ export type SenseInfo = { group: string; throttle: number | null; timeout: number | null; - /** Declarative reflex lines that schedule this sense (derived from nerve.yaml). */ + /** Declarative schedule (`interval` / `on`) for this sense (derived from nerve.yaml). */ triggers: string[]; lastSignalTimestamp: number | null; }; diff --git a/packages/daemon/README.md b/packages/daemon/README.md index 997761c..fe35dc5 100644 --- a/packages/daemon/README.md +++ b/packages/daemon/README.md @@ -1,18 +1,18 @@ # @uncaged/nerve-daemon -The observation engine runtime for [nerve](../../README.md) — runs senses, routes signals, schedules reflexes, and manages workflows. +The observation engine runtime for [nerve](../../README.md) — runs senses, routes signals, runs the sense scheduler, and manages workflows. ## Architecture | Module | Source (indicative) | Responsibility | |--------|---------------------|----------------| -| **Kernel** | `kernel.ts` | Orchestrator — worker pool, signal bus, reflex scheduler, workflow manager, optional file watcher and daemon IPC, config reload hooks | +| **Kernel** | `kernel.ts` | Orchestrator — worker pool, signal bus, sense scheduler, workflow manager, optional file watcher and daemon IPC, config reload hooks | | **Worker pool** | `worker-pool.ts` | Fork and supervise one child process per sense group; restart/shutdown; crash cleanup hooks for scheduler state | | **Kernel sense groups** | `kernel-sense-groups.ts` | Derive sense groups from config; list senses per group for scheduling | | **Sense runtime** | sense worker + Drizzle | Per-sense SQLite (`node:sqlite`), migrations, peer DB reads | | **Sense worker** | `sense-worker.ts` (fork target) | Child process entry — runs `compute()` per sense in a group | | **Signal bus** | `signal-bus.ts` | In-memory pub/sub for sense signals | -| **Reflex scheduler** | `reflex-scheduler.ts` | Interval + `on` subscriptions, throttle/coalesce | +| **Sense scheduler** | `sense-scheduler.ts` | Interval + `on` subscriptions, throttle/coalesce | | **Workflow manager** | `workflow-manager.ts` | One worker per workflow name, concurrency (drop/queue), queue caps | | **Workflow worker** | `workflow-worker.ts` | Child process — runs RFC-002 threads (`start-thread`, `resume-thread` IPC) | | **IPC (parent ↔ workers)** | `ipc.ts` | Typed messages for sense and workflow workers (includes `resume-thread` for recovery) | @@ -37,7 +37,7 @@ Hot reload (`drainAndRespawn`) uses a controlled drain: in-flight runs may be ma - **One worker process per sense group** — isolation between groups, shared compute within a group - **`node:sqlite` (DatabaseSync)** — zero native addons, WAL mode, built into Node.js ≥ 22.5 - **Throttle + coalesce** — if compute is in-flight, at most one pending trigger is queued (no unbounded accumulation) -- **Log ≠ Signal** — logs are queryable data assets but cannot trigger reflexes (prevents feedback loops) +- **Log ≠ Signal** — logs are queryable data assets but cannot trigger the sense scheduler or workflows (prevents feedback loops) ## Usage diff --git a/packages/daemon/src/__tests__/log-store-integration.test.ts b/packages/daemon/src/__tests__/log-store-integration.test.ts index 065d6b4..420394d 100644 --- a/packages/daemon/src/__tests__/log-store-integration.test.ts +++ b/packages/daemon/src/__tests__/log-store-integration.test.ts @@ -6,10 +6,10 @@ import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; import type { NerveConfig, Signal } from "@uncaged/nerve-core"; import { createLogStore } from "@uncaged/nerve-store"; import type { LogStore } from "@uncaged/nerve-store"; -import { createReflexScheduler } from "../reflex-scheduler.js"; +import { createSenseScheduler } from "../sense-scheduler.js"; import { createSignalBus } from "../signal-bus.js"; -describe("LogStore + ReflexScheduler integration", () => { +describe("LogStore + SenseScheduler integration", () => { let tmpDir: string; let logStore: LogStore; @@ -42,14 +42,14 @@ describe("LogStore + ReflexScheduler integration", () => { }; const bus = createSignalBus(); const triggered: string[] = []; - const scheduler = createReflexScheduler(config, bus, (name) => triggered.push(name), { + const scheduler = createSenseScheduler(config, bus, (name) => triggered.push(name), { logStore, }); const signal: Signal = { id: 1, senseId: "cpu-usage", payload: 42, timestamp: Date.now() }; bus.emit(signal); - const logs = logStore.query({ source: "reflex", type: "run_start" }); + const logs = logStore.query({ source: "sense_scheduler", type: "run_start" }); expect(logs).toHaveLength(1); expect(logs[0].refId).toBe("cpu-usage"); expect(triggered).toHaveLength(1); @@ -77,8 +77,8 @@ describe("LogStore + ReflexScheduler integration", () => { api: { port: null, token: null, host: "127.0.0.1" }, }; const bus = createSignalBus(); - const ref: { scheduler: ReturnType | null } = { scheduler: null }; - const scheduler = createReflexScheduler( + const ref: { scheduler: ReturnType | null } = { scheduler: null }; + const scheduler = createSenseScheduler( config, bus, (name) => { @@ -90,7 +90,7 @@ describe("LogStore + ReflexScheduler integration", () => { vi.advanceTimersByTime(3000); - const logs = logStore.query({ source: "reflex", type: "run_start" }); + const logs = logStore.query({ source: "sense_scheduler", type: "run_start" }); expect(logs.length).toBeGreaterThanOrEqual(3); expect(logs.every((l) => l.refId === "cpu-usage")).toBe(true); @@ -117,7 +117,7 @@ describe("LogStore + ReflexScheduler integration", () => { }; const bus = createSignalBus(); const triggered: string[] = []; - const scheduler = createReflexScheduler( + const scheduler = createSenseScheduler( config, bus, (name) => { @@ -128,7 +128,7 @@ describe("LogStore + ReflexScheduler integration", () => { ); logStore.append({ - source: "reflex", + source: "sense_scheduler", type: "run_complete", refId: "cpu-usage", payload: '{"v":99}', diff --git a/packages/daemon/src/__tests__/reflex-scheduler-throttle-pending.test.ts b/packages/daemon/src/__tests__/sense-scheduler-throttle-pending.test.ts similarity index 90% rename from packages/daemon/src/__tests__/reflex-scheduler-throttle-pending.test.ts rename to packages/daemon/src/__tests__/sense-scheduler-throttle-pending.test.ts index 17afcce..21e437b 100644 --- a/packages/daemon/src/__tests__/reflex-scheduler-throttle-pending.test.ts +++ b/packages/daemon/src/__tests__/sense-scheduler-throttle-pending.test.ts @@ -1,7 +1,7 @@ import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; import type { NerveConfig, Signal } from "@uncaged/nerve-core"; -import { createReflexScheduler } from "../reflex-scheduler.js"; +import { createSenseScheduler } from "../sense-scheduler.js"; import { createSignalBus } from "../signal-bus.js"; function makeConfig(overrides: Partial = {}): NerveConfig { @@ -28,7 +28,7 @@ function makeSignal(senseId: string, payload: unknown = 1): Signal { return { id: 1, senseId, payload, timestamp: Date.now() }; } -describe("ReflexScheduler — throttle + pending deferred trigger", () => { +describe("SenseScheduler — throttle + pending deferred trigger", () => { beforeEach(() => { vi.useFakeTimers(); }); @@ -53,7 +53,7 @@ describe("ReflexScheduler — throttle + pending deferred trigger", () => { }, }); const bus = createSignalBus(); - const scheduler = createReflexScheduler(config, bus, (name) => triggered.push(name)); + const scheduler = createSenseScheduler(config, bus, (name) => triggered.push(name)); // First trigger fires immediately (outside throttle window) bus.emit(makeSignal("cpu-usage")); @@ -89,7 +89,7 @@ describe("ReflexScheduler — throttle + pending deferred trigger", () => { }, }); const bus = createSignalBus(); - const scheduler = createReflexScheduler(config, bus, (name) => triggered.push(name)); + const scheduler = createSenseScheduler(config, bus, (name) => triggered.push(name)); // First trigger fires bus.emit(makeSignal("cpu-usage")); @@ -129,7 +129,7 @@ describe("ReflexScheduler — throttle + pending deferred trigger", () => { }, }); const bus = createSignalBus(); - const scheduler = createReflexScheduler(config, bus, (name) => triggered.push(name)); + const scheduler = createSenseScheduler(config, bus, (name) => triggered.push(name)); bus.emit(makeSignal("cpu-usage")); scheduler.onComputeComplete("cpu-usage"); diff --git a/packages/daemon/src/__tests__/reflex-scheduler.test.ts b/packages/daemon/src/__tests__/sense-scheduler.test.ts similarity index 86% rename from packages/daemon/src/__tests__/reflex-scheduler.test.ts rename to packages/daemon/src/__tests__/sense-scheduler.test.ts index 410a0f3..c047554 100644 --- a/packages/daemon/src/__tests__/reflex-scheduler.test.ts +++ b/packages/daemon/src/__tests__/sense-scheduler.test.ts @@ -1,7 +1,7 @@ import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; import type { NerveConfig, Signal } from "@uncaged/nerve-core"; -import { createReflexScheduler } from "../reflex-scheduler.js"; +import { createSenseScheduler } from "../sense-scheduler.js"; import { createSignalBus } from "../signal-bus.js"; // --------------------------------------------------------------------------- @@ -54,7 +54,7 @@ function makeSignal(senseId: string, payload: unknown = 1): Signal { // Tests // --------------------------------------------------------------------------- -describe("ReflexScheduler — interval reflex", () => { +describe("SenseScheduler — interval schedule", () => { beforeEach(() => { vi.useFakeTimers(); }); @@ -73,10 +73,10 @@ describe("ReflexScheduler — interval reflex", () => { }); const bus = createSignalBus(); // Use a ref so the triggerFn can call back into the scheduler - const ref: { scheduler: ReturnType | null } = { + const ref: { scheduler: ReturnType | null } = { scheduler: null, }; - const scheduler = createReflexScheduler(config, bus, (name) => { + const scheduler = createSenseScheduler(config, bus, (name) => { triggered.push(name); // Immediately complete compute so the scheduler is not blocked by in-flight state ref.scheduler?.onComputeComplete(name); @@ -101,10 +101,10 @@ describe("ReflexScheduler — interval reflex", () => { }, }); const bus = createSignalBus(); - const ref: { scheduler: ReturnType | null } = { + const ref: { scheduler: ReturnType | null } = { scheduler: null, }; - const scheduler = createReflexScheduler(config, bus, (name) => { + const scheduler = createSenseScheduler(config, bus, (name) => { triggered.push(name); ref.scheduler?.onComputeComplete(name); }); @@ -128,7 +128,7 @@ describe("ReflexScheduler — interval reflex", () => { }, }); const bus = createSignalBus(); - const scheduler = createReflexScheduler(config, bus, (name) => triggered.push(name)); + const scheduler = createSenseScheduler(config, bus, (name) => triggered.push(name)); // Only advance 500ms — should be 0 triggers (not catching up) vi.advanceTimersByTime(500); @@ -138,7 +138,7 @@ describe("ReflexScheduler — interval reflex", () => { }); }); -describe("ReflexScheduler — event (on) reflex", () => { +describe("SenseScheduler — event (on) schedule", () => { it("triggers target sense when watched sense emits a signal", () => { const triggered: string[] = []; const base = makeConfig(); @@ -153,7 +153,7 @@ describe("ReflexScheduler — event (on) reflex", () => { }, }); const bus = createSignalBus(); - const scheduler = createReflexScheduler(config, bus, (name) => triggered.push(name)); + const scheduler = createSenseScheduler(config, bus, (name) => triggered.push(name)); bus.emit(makeSignal("cpu-usage")); scheduler.onComputeComplete("system-health"); @@ -176,7 +176,7 @@ describe("ReflexScheduler — event (on) reflex", () => { }, }); const bus = createSignalBus(); - const scheduler = createReflexScheduler(config, bus, (name) => triggered.push(name)); + const scheduler = createSenseScheduler(config, bus, (name) => triggered.push(name)); bus.emit(makeSignal("disk-usage")); @@ -195,7 +195,7 @@ describe("ReflexScheduler — event (on) reflex", () => { }, }); const bus = createSignalBus(); - const scheduler = createReflexScheduler(config, bus, (name) => triggered.push(name)); + const scheduler = createSenseScheduler(config, bus, (name) => triggered.push(name)); scheduler.stop(); bus.emit(makeSignal("cpu-usage")); @@ -204,7 +204,7 @@ describe("ReflexScheduler — event (on) reflex", () => { }); }); -describe("ReflexScheduler — throttle", () => { +describe("SenseScheduler — throttle", () => { beforeEach(() => { vi.useFakeTimers(); }); @@ -228,7 +228,7 @@ describe("ReflexScheduler — throttle", () => { }, }); const bus = createSignalBus(); - const scheduler = createReflexScheduler(config, bus, (name) => triggered.push(name)); + const scheduler = createSenseScheduler(config, bus, (name) => triggered.push(name)); bus.emit(makeSignal("cpu-usage")); scheduler.onComputeComplete("cpu-usage"); @@ -257,7 +257,7 @@ describe("ReflexScheduler — throttle", () => { }, }); const bus = createSignalBus(); - const scheduler = createReflexScheduler(config, bus, (name) => triggered.push(name)); + const scheduler = createSenseScheduler(config, bus, (name) => triggered.push(name)); bus.emit(makeSignal("cpu-usage")); scheduler.onComputeComplete("cpu-usage"); @@ -272,7 +272,7 @@ describe("ReflexScheduler — throttle", () => { }); }); -describe("ReflexScheduler — merge/coalesce", () => { +describe("SenseScheduler — merge/coalesce", () => { it("concurrent triggers collapse to at most one pending run", () => { const triggered: string[] = []; const base = makeConfig(); @@ -283,7 +283,7 @@ describe("ReflexScheduler — merge/coalesce", () => { }, }); const bus = createSignalBus(); - const scheduler = createReflexScheduler(config, bus, (name) => triggered.push(name)); + const scheduler = createSenseScheduler(config, bus, (name) => triggered.push(name)); // First trigger starts compute bus.emit(makeSignal("cpu-usage")); @@ -316,7 +316,7 @@ describe("ReflexScheduler — merge/coalesce", () => { }, }); const bus = createSignalBus(); - const scheduler = createReflexScheduler(config, bus, (name) => triggered.push(name)); + const scheduler = createSenseScheduler(config, bus, (name) => triggered.push(name)); bus.emit(makeSignal("cpu-usage")); expect(triggered.length).toBe(1); @@ -329,7 +329,7 @@ describe("ReflexScheduler — merge/coalesce", () => { }); }); -describe("ReflexScheduler — interval + on combined", () => { +describe("SenseScheduler — interval + on combined", () => { beforeEach(() => { vi.useFakeTimers(); }); @@ -351,7 +351,7 @@ describe("ReflexScheduler — interval + on combined", () => { }, }); const bus = createSignalBus(); - const scheduler = createReflexScheduler(config, bus, (name) => triggered.push(name)); + const scheduler = createSenseScheduler(config, bus, (name) => triggered.push(name)); // Event trigger bus.emit(makeSignal("cpu-usage")); diff --git a/packages/daemon/src/kernel.ts b/packages/daemon/src/kernel.ts index 6645e81..a2d64f3 100644 --- a/packages/daemon/src/kernel.ts +++ b/packages/daemon/src/kernel.ts @@ -1,5 +1,5 @@ /** - * Kernel — ties sense workers, signal bus, reflex scheduler, workflow manager, + * Kernel — ties sense workers, signal bus, sense scheduler, workflow manager, * optional file watcher, and daemon IPC. */ @@ -34,8 +34,8 @@ import { senseNamesInGroup, senseNamesInGroupAsSet, } from "./kernel-sense-groups.js"; -import { createReflexScheduler } from "./reflex-scheduler.js"; -import type { ReflexScheduler } from "./reflex-scheduler.js"; +import { createSenseScheduler } from "./sense-scheduler.js"; +import type { SenseScheduler } from "./sense-scheduler.js"; import { createSignalBus } from "./signal-bus.js"; import type { SignalBus } from "./signal-bus.js"; import { createSenseWorkerPool, resolveWorkerScript } from "./worker-pool.js"; @@ -142,7 +142,7 @@ export function createKernel( let stopped = false; /** Assigned before workers start; `handleWorkerMessage` only runs after this is set. */ - let scheduler!: ReflexScheduler; + let scheduler!: SenseScheduler; let readyResolve: (() => void) | undefined; const ready = new Promise((resolve) => { @@ -247,7 +247,7 @@ export function createKernel( senseWorkerPool.sendCompute(group, senseName); } - scheduler = createReflexScheduler(config, bus, triggerFn, { + scheduler = createSenseScheduler(config, bus, triggerFn, { logStore, }); @@ -283,7 +283,7 @@ export function createKernel( const oldWorkflows = config.workflows; config = newConfig; scheduler.stop(); - scheduler = createReflexScheduler(config, bus, triggerFn, { + scheduler = createSenseScheduler(config, bus, triggerFn, { logStore, }); workflowManager.updateConfig(newConfig); diff --git a/packages/daemon/src/reflex-scheduler.ts b/packages/daemon/src/sense-scheduler.ts similarity index 91% rename from packages/daemon/src/reflex-scheduler.ts rename to packages/daemon/src/sense-scheduler.ts index 35d233a..29f9ce7 100644 --- a/packages/daemon/src/reflex-scheduler.ts +++ b/packages/daemon/src/sense-scheduler.ts @@ -1,5 +1,5 @@ /** - * Reflex Scheduler — drives sense compute cycles from each sense's `interval` / `on`. + * Sense Scheduler — drives sense compute cycles from each sense's `interval` / `on`. * * Supports: * - interval: periodic setInterval-based triggering @@ -24,8 +24,8 @@ type SenseState = { deferredTimer: ReturnType | null; }; -/** Handle returned by createReflexScheduler — call stop() for graceful shutdown. */ -export type ReflexScheduler = { +/** Handle returned by createSenseScheduler — call stop() for graceful shutdown. */ +export type SenseScheduler = { /** Notify scheduler that a compute cycle finished. Drains the pending flag. */ onComputeComplete: (senseName: string) => void; stop: () => void; @@ -35,25 +35,25 @@ function makeSenseState(): SenseState { return { lastComputeAt: 0, inFlight: false, pending: false, deferredTimer: null }; } -export type ReflexSchedulerOptions = { +export type SenseSchedulerOptions = { logStore?: LogStore; }; /** - * Create and start a reflex scheduler. + * Create and start a sense scheduler. * * @param config Full NerveConfig (senses for schedule + throttle). * @param bus SignalBus to subscribe for event-driven triggers. * @param triggerFn Called with the sense name when a compute should be dispatched. * @param opts Optional: logStore for structured logging. - * @returns ReflexScheduler with stop() and onComputeComplete() methods. + * @returns SenseScheduler with stop() and onComputeComplete() methods. */ -export function createReflexScheduler( +export function createSenseScheduler( config: NerveConfig, bus: SignalBus, triggerFn: TriggerFn, - opts?: ReflexSchedulerOptions, -): ReflexScheduler { + opts?: SenseSchedulerOptions, +): SenseScheduler { const logStore = opts?.logStore; const intervals: ReturnType[] = []; const unsubscribers: Unsubscribe[] = []; @@ -74,7 +74,7 @@ export function createReflexScheduler( state.pending = false; state.lastComputeAt = Date.now(); logStore?.append({ - source: "reflex", + source: "sense_scheduler", type: "run_start", refId: senseName, payload: null, diff --git a/packages/daemon/src/signal-bus.ts b/packages/daemon/src/signal-bus.ts index cf2c216..c8499a3 100644 --- a/packages/daemon/src/signal-bus.ts +++ b/packages/daemon/src/signal-bus.ts @@ -1,5 +1,5 @@ /** - * In-memory signal bus for routing signals between sense workers and reflex subscribers. + * In-memory signal bus for routing signals between sense workers and sense-scheduler subscribers. * Synchronous dispatch — no persistence, no async queuing. * * If a handler throws, the error is logged and remaining handlers still run. diff --git a/packages/store/src/__tests__/log-store-archive.test.ts b/packages/store/src/__tests__/log-store-archive.test.ts index e63d9fd..8f45d0e 100644 --- a/packages/store/src/__tests__/log-store-archive.test.ts +++ b/packages/store/src/__tests__/log-store-archive.test.ts @@ -31,7 +31,13 @@ describe("LogStore — cold archive (RFC-001 §5.4)", () => { it("exports one UTC day to JSONL, deletes rows, advances archived_up_to", () => { const ts = Date.UTC(2026, 1, 1, 10, 0, 0); store.append({ source: "system", type: "x", refId: null, payload: '{"a":1}', timestamp: ts }); - store.append({ source: "reflex", type: "y", refId: "z", payload: null, timestamp: ts + 1 }); + store.append({ + source: "sense_scheduler", + type: "y", + refId: "z", + payload: null, + timestamp: ts + 1, + }); const now = nowForLastArchivableFeb1(); const result = store.archiveLogs({ now, retentionMs: 30 * DAY_MS }); diff --git a/packages/store/src/__tests__/log-store.test.ts b/packages/store/src/__tests__/log-store.test.ts index a8bea69..47d012e 100644 --- a/packages/store/src/__tests__/log-store.test.ts +++ b/packages/store/src/__tests__/log-store.test.ts @@ -63,14 +63,14 @@ describe("LogStore", () => { timestamp: 1000, }); store.append({ - source: "reflex", + source: "sense_scheduler", type: "run_start", refId: "cpu", payload: null, timestamp: 2000, }); store.append({ - source: "reflex", + source: "sense_scheduler", type: "run_complete", refId: "cpu", payload: '{"v":42}', @@ -92,14 +92,14 @@ describe("LogStore", () => { timestamp: 1000, }); store.append({ - source: "reflex", + source: "sense_scheduler", type: "run_start", refId: "cpu", payload: null, timestamp: 2000, }); store.append({ - source: "reflex", + source: "sense_scheduler", type: "run_complete", refId: "cpu", payload: '{"v":42}', @@ -116,9 +116,9 @@ describe("LogStore", () => { }); it("filters by source", () => { - const results = store.query({ source: "reflex" }); + const results = store.query({ source: "sense_scheduler" }); expect(results).toHaveLength(2); - expect(results.every((r) => r.source === "reflex")).toBe(true); + expect(results.every((r) => r.source === "sense_scheduler")).toBe(true); }); it("filters by type", () => { @@ -178,7 +178,7 @@ describe("LogStore", () => { timestamp: 5000, }); store.append({ - source: "reflex", + source: "sense_scheduler", type: "run_start", refId: "a", payload: null, @@ -231,7 +231,7 @@ describe("LogStore", () => { it("preserves JSON payload", () => { const payload = JSON.stringify({ cpu: 95, host: "node-1" }); store.append({ - source: "reflex", + source: "sense_scheduler", type: "run_complete", refId: "cpu", payload, diff --git a/packages/store/src/log-store.ts b/packages/store/src/log-store.ts index 1e36c69..66e2070 100644 --- a/packages/store/src/log-store.ts +++ b/packages/store/src/log-store.ts @@ -1,8 +1,8 @@ /** * Log Store — append-only structured log storage backed by SQLite. * - * Stores system, reflex, and workflow log entries in a single table. - * Logs are data assets for audit/analysis — they MUST NOT trigger reflexes. + * Stores system, sense-scheduler (`sense_scheduler` source), sense, and workflow log entries in a single table. + * Logs are data assets for audit/analysis — they MUST NOT feed back into scheduling or workflows as triggers. * * Also provides a `meta` key-value table for bookkeeping (e.g. archive watermarks). */