/** * **session_manifest mirror writers** — best-effort GLOBAL-scope mirror of the * per-project `tasks_sessions` rows (EP-SESSION-MANIFEST · epic T11638 · task T11639). * * ## What this module does * * The authoritative session row lives per-project in `tasks_sessions` (PROJECT * scope `cleo.db`). These writers copy a compact projection of that row into the * `session_manifest` table in the GLOBAL-scope `cleo.db` so the fleet has a single, * machine-wide index of every session across every project — without ATTACHing N * per-project DB files. The manifest is a MIRROR, never the source of truth. * * ## Three invariants (the ACs of T11639) * * 1. **Shared handle, never closed (AC3).** All writes go through the singleton * GLOBAL `cleo.db` handle returned by {@link openDualScopeDb}('global'). We NEVER * call `.close()` on it — closing the cached handle would pull the rug from under * every other global-scope reader/writer in the process. * 2. **Best-effort — never throw into the caller (AC3).** Every public writer here * swallows ALL errors (log at debug + continue). A failure to mirror MUST NOT * fail the underlying `cleo session start|end` / handoff op. The mirror is an * observability convenience, not a correctness dependency. * 3. **MIRROR, never authoritative (AC4).** {@link reconcileSessionManifestOnStart} * re-reads the AUTHORITATIVE project row and OVERWRITES the manifest row, so a * stale or partially-written manifest entry can never drift into being treated as * truth. Consumers needing exact session state read `tasks_sessions`. * * ## Identity (`project_id`) * * The mirror reuses the CANONICAL `nexus_project_registry.project_id` (12-hex) for * the owning project — resolved via the nexus identity helper — never a freshly * minted id. Nullable: a session started outside any resolvable registered project * still mirrors with `project_id` NULL. * * ## Writer lease (operating rule 5) * * Global-scope writes acquire the writer lease ({@link withWriterLease}) for * `(scope='global', lane='tasks')`, pinned to the global `cleo.db` path, so they * serialize with the cold-open and every other chokepoint write — healing T5158. * * @module * @task T11639 * @epic T11638 * @saga T11242 * @see ../store/schema/cleo-global/session-manifest.ts — the table decl * @see ./index.ts — startSession/endSession call sites */ import type { Session } from '@cleocode/contracts'; import { type DualScopeDbHandle } from '../store/dual-scope-db.js'; import { sessionManifest } from '../store/schema/cleo-global/session-manifest.js'; /** * Ensure the GLOBAL `session_manifest` table exists and return the SHARED global * `cleo.db` handle (AC1). * * This is the named "ensure" entry point referenced by EP-SESSION-MANIFEST. It * opens (or re-uses) the singleton GLOBAL-scope handle via {@link openDualScopeDb}, * whose migrate step runs the `session_manifest` migration idempotently — so the * table is guaranteed present after this resolves. The returned handle is the SHARED * singleton: callers MUST NOT close it. * * @returns The shared GLOBAL-scope {@link DualScopeDbHandle} (table ensured). * @task T11639 */ export declare function ensureGlobalSignaldockDb(): Promise>; /** * Best-effort mirror of a session into the GLOBAL `session_manifest` (AC3). * * Call on session start / end / handoff. Resolves the owning project's canonical * `project_id`, ensures the table + shared handle, and upserts the mirror row. ANY * failure (DB unopenable, write error, identity-resolution failure) is logged at * debug and SWALLOWED — this NEVER throws into the caller, so a mirror failure * cannot fail the underlying session op. * * @param projectRoot - Absolute path to the project whose session is being mirrored * (used to resolve the canonical `project_id` and `project_path`). * @param session - The authoritative {@link Session} (post-mutation) to mirror. * @task T11639 */ export declare function mirrorSessionToManifest(projectRoot: string, session: Session): Promise; /** * Reconcile-on-start: re-read the AUTHORITATIVE project session row and OVERWRITE * its manifest mirror so the manifest can never drift into authority (AC4). * * Called at session start (after the project row is persisted). It reads the * canonical `tasks_sessions` row back from the PROJECT scope and re-projects it into * the GLOBAL manifest — guaranteeing the mirror reflects the source of truth even if * a prior mirror write was partial, stale, or raced. Best-effort: ANY failure is * logged at debug and swallowed. * * @param projectRoot - Absolute path to the owning project. * @param sessionId - The session whose manifest row is reconciled. * @task T11639 */ export declare function reconcileSessionManifestOnStart(projectRoot: string, sessionId: string): Promise; /** * Read a single `session_manifest` mirror row through the SHARED global handle. * * Primarily a test / introspection convenience — production consumers needing exact * session state MUST read the authoritative `tasks_sessions`, not this mirror. * * @param sessionId - The session id to look up in the manifest. * @returns The mirror row, or `null` when absent. * @task T11639 */ export declare function readSessionManifestRow(sessionId: string): Promise; /** * Resolve the absolute on-disk path of the GLOBAL `cleo.db` (the manifest's home). * Thin re-export of the scope→path resolver for callers that want the path without * opening the handle. * * @returns The GLOBAL-scope `cleo.db` absolute path. * @task T11639 */ export declare function resolveGlobalManifestDbPath(): string; //# sourceMappingURL=session-manifest-mirror.d.ts.map