/** * ProjectionSnapshotQuery - Read-model snapshot query service interface. * * Exposes the current orchestration projection snapshot for read-only API * access. * * @module ProjectionSnapshotQuery */import type { AgentSessionImportSource, ApprovalRequestId, CheckpointRef, MessageId, OrchestrationCheckpointSummary, OrchestrationMessage, OrchestrationProject, OrchestrationProjectShell, OrchestrationReadModel, OrchestrationSearchThreadsInput, OrchestrationSearchThreadsResult, OrchestrationShellSnapshot, OrchestrationThread, OrchestrationThreadActivity, OrchestrationThreadDetailSnapshot, OrchestrationThreadDetailWindow, OrchestrationThreadShell, ProjectId, ThreadId,} from "@t3tools/contracts";import * as Context from "effect/Context";import type * as Option from "effect/Option";import type * as Effect from "effect/Effect"; import type { ProjectionRepositoryError } from "../../persistence/Errors.ts"; export interface ProjectionSnapshotCounts { readonly projectCount: number; readonly threadCount: number;} export interface ProjectionSnapshotSequence { readonly snapshotSequence: number;} export interface ProjectionEventReplayStats { readonly eventCount: number; readonly payloadBytes: number;} export interface ProjectionThreadCheckpointContext { readonly threadId: ThreadId; readonly projectId: ProjectId; readonly workspaceRoot: string; readonly worktreePath: string | null; readonly checkpoints: ReadonlyArray<OrchestrationCheckpointSummary>;} export interface ProjectionFullThreadDiffContext { readonly threadId: ThreadId; readonly projectId: ProjectId; readonly workspaceRoot: string; readonly worktreePath: string | null; readonly latestCheckpointTurnCount: number; readonly toCheckpointRef: CheckpointRef | null;} export interface ProjectionThreadDetailQuery { /** * Limit activities before SQLite returns and decodes their payloads. * Any explicit filter omits pinned-request reads. An empty list also skips * the activity query. Omit this option to preserve the full detail response. */ readonly activityKinds?: ReadonlyArray<string>;} /** * ProjectionSnapshotQueryShape - Service API for read-model snapshots. */export interface ProjectionSnapshotQueryShape { /** Read the latest request or resolution without loading the thread history. */ readonly getUserInputActivity: (input: { readonly threadId: ThreadId; readonly requestId: ApprovalRequestId; }) => Effect.Effect<Option.Option<OrchestrationThreadActivity>, ProjectionRepositoryError>; /** * Read the lightweight command snapshot used to bootstrap the in-memory * orchestration engine without hydrating message/activity/checkpoint bodies. */ readonly getCommandReadModel: () => Effect.Effect< OrchestrationReadModel, ProjectionRepositoryError >; /** * Read the latest orchestration projection snapshot. * * Rehydrates from projection tables and derives snapshot sequence from * projector cursor state. */ readonly getSnapshot: () => Effect.Effect<OrchestrationReadModel, ProjectionRepositoryError>; /** * Read the latest orchestration shell snapshot. * * Returns only projects and thread shell summaries so clients can bootstrap * lightweight navigation state without hydrating every thread body. */ readonly getShellSnapshot: () => Effect.Effect< OrchestrationShellSnapshot, ProjectionRepositoryError >; /** * Read archived thread shell summaries for the archive page. * * This query is separate from the main shell snapshot so archived threads * are never bootstrapped into normal navigation state. */ readonly getArchivedShellSnapshot: () => Effect.Effect< OrchestrationShellSnapshot, ProjectionRepositoryError >; /** * Search active thread navigation metadata, user messages, and canonical * assistant outputs without hydrating thread detail snapshots. */ readonly searchThreads: ( input: OrchestrationSearchThreadsInput, ) => Effect.Effect<OrchestrationSearchThreadsResult, ProjectionRepositoryError>; /** * Read the latest projection snapshot sequence without hydrating read-model * entities. */ readonly getSnapshotSequence: () => Effect.Effect< ProjectionSnapshotSequence, ProjectionRepositoryError >; /** * Read aggregate projection counts without hydrating the full read model. */ readonly getCounts: () => Effect.Effect<ProjectionSnapshotCounts, ProjectionRepositoryError>; /** * Measure a persisted event range without decoding its payload bodies. */ readonly getEventReplayStats: (input: { readonly fromSequenceExclusive: number; readonly toSequenceInclusive: number; }) => Effect.Effect<ProjectionEventReplayStats, ProjectionRepositoryError>; /** * Read the active project for an exact workspace root match. */ readonly getActiveProjectByWorkspaceRoot: ( workspaceRoot: string, ) => Effect.Effect<Option.Option<OrchestrationProject>, ProjectionRepositoryError>; /** * Read a single active project shell row by id. */ readonly getProjectShellById: ( projectId: ProjectId, ) => Effect.Effect<Option.Option<OrchestrationProjectShell>, ProjectionRepositoryError>; /** * Read the earliest active thread for a project. */ readonly getFirstActiveThreadIdByProjectId: ( projectId: ProjectId, ) => Effect.Effect<Option.Option<ThreadId>, ProjectionRepositoryError>; /** Read completed import sources without loading thread history. */ readonly getImportedAgentSessionSources: (projectId: ProjectId) => Effect.Effect< ReadonlyArray<{ readonly threadId: ThreadId; readonly source: AgentSessionImportSource; }>, ProjectionRepositoryError >; /** * Read the checkpoint context needed to resolve a single thread diff. */ readonly getThreadCheckpointContext: ( threadId: ThreadId, ) => Effect.Effect<Option.Option<ProjectionThreadCheckpointContext>, ProjectionRepositoryError>; /** * Read only the narrow context needed to compute a full-thread diff from * checkpoint 0 to a specific turn count. */ readonly getFullThreadDiffContext: ( threadId: ThreadId, toTurnCount: number, ) => Effect.Effect<Option.Option<ProjectionFullThreadDiffContext>, ProjectionRepositoryError>; /** * Read a single active thread shell row by id. */ readonly getThreadShellById: ( threadId: ThreadId, ) => Effect.Effect<Option.Option<OrchestrationThreadShell>, ProjectionRepositoryError>; /** Read the active thread and session facts used to ingest provider events. */ readonly getThreadRuntimeContext: ( threadId: ThreadId, ) => Effect.Effect< Option.Option<Pick<OrchestrationThreadShell, "id" | "title" | "session">>, ProjectionRepositoryError >; /** * Read one requested message and whether another non-compaction user message exists. * Newer queued messages count too, preserving first-turn title eligibility. */ readonly getTurnStartMessage: (input: { readonly threadId: ThreadId; readonly messageId: MessageId; }) => Effect.Effect< Option.Option<{ readonly message: OrchestrationMessage; readonly hasOtherUserMessages: boolean; }>, ProjectionRepositoryError >; /** * Read a single active thread detail snapshot by id. */ readonly getThreadDetailById: ( threadId: ThreadId, query?: ProjectionThreadDetailQuery, ) => Effect.Effect<Option.Option<OrchestrationThread>, ProjectionRepositoryError>; /** * Read a single active thread detail together with the projection snapshot * sequence in one consistent transaction, so the returned `snapshotSequence` * exactly matches the state reflected in `thread` (no interleaving projector * update between the two reads). * * When `window` is provided, the thread's messages, activities, proposed * plans, and checkpoints are bounded to a page of recent turns and the * response carries `page` metadata (see `OrchestrationThreadDetailWindow`). * Without a window the full thread is returned with no `page` field — * pagination is strictly opt-in. * * Activity payloads are projected for clients as they are read in small * sequential batches. Callers still apply the full snapshot projector for * collection-level activity pruning. */ readonly getThreadDetailSnapshot: ( threadId: ThreadId, window?: OrchestrationThreadDetailWindow, ) => Effect.Effect<Option.Option<OrchestrationThreadDetailSnapshot>, ProjectionRepositoryError>;} /** * ProjectionSnapshotQuery - Service tag for projection snapshot queries. */export class ProjectionSnapshotQuery extends Context.Service< ProjectionSnapshotQuery, ProjectionSnapshotQueryShape>()("t3/orchestration/Services/ProjectionSnapshotQuery") {}
/**
* ProjectionSnapshotQuery - Read-model snapshot query service interface.
*
* Exposes the current orchestration projection snapshot for read-only API
* access.
*
* @module ProjectionSnapshotQuery
*/
import type {
AgentSessionImportSource,
ApprovalRequestId,
CheckpointRef,
MessageId,
OrchestrationCheckpointSummary,
OrchestrationMessage,
OrchestrationProject,
OrchestrationProjectShell,
OrchestrationReadModel,
OrchestrationSearchThreadsInput,
OrchestrationSearchThreadsResult,
OrchestrationShellSnapshot,
OrchestrationThread,
OrchestrationThreadActivity,
OrchestrationThreadDetailSnapshot,
OrchestrationThreadDetailWindow,
OrchestrationThreadShell,
ProjectId,
ThreadId,
} from "@t3tools/contracts";
import * as Context from "effect/Context";
import type * as Option from "effect/Option";
import type * as Effect from "effect/Effect";
import type { ProjectionRepositoryError } from "../../persistence/Errors.ts";
export interface ProjectionSnapshotCounts {
readonly projectCount: number;
readonly threadCount: number;
}
export interface ProjectionSnapshotSequence {
readonly snapshotSequence: number;
}
export interface ProjectionEventReplayStats {
readonly eventCount: number;
readonly payloadBytes: number;
}
export interface ProjectionThreadCheckpointContext {
readonly threadId: ThreadId;
readonly projectId: ProjectId;
readonly workspaceRoot: string;
readonly worktreePath: string | null;
readonly checkpoints: ReadonlyArray<OrchestrationCheckpointSummary>;
}
export interface ProjectionFullThreadDiffContext {
readonly threadId: ThreadId;
readonly projectId: ProjectId;
readonly workspaceRoot: string;
readonly worktreePath: string | null;
readonly latestCheckpointTurnCount: number;
readonly toCheckpointRef: CheckpointRef | null;
}
export interface ProjectionThreadDetailQuery {
/**
* Limit activities before SQLite returns and decodes their payloads.
* Any explicit filter omits pinned-request reads. An empty list also skips
* the activity query. Omit this option to preserve the full detail response.
*/
readonly activityKinds?: ReadonlyArray<string>;
}
/**
* ProjectionSnapshotQueryShape - Service API for read-model snapshots.
*/
export interface ProjectionSnapshotQueryShape {
/** Read the latest request or resolution without loading the thread history. */
readonly getUserInputActivity: (input: {
readonly threadId: ThreadId;
readonly requestId: ApprovalRequestId;
}) => Effect.Effect<Option.Option<OrchestrationThreadActivity>, ProjectionRepositoryError>;
/**
* Read the lightweight command snapshot used to bootstrap the in-memory
* orchestration engine without hydrating message/activity/checkpoint bodies.
*/
readonly getCommandReadModel: () => Effect.Effect<
OrchestrationReadModel,
ProjectionRepositoryError
>;
/**
* Read the latest orchestration projection snapshot.
*
* Rehydrates from projection tables and derives snapshot sequence from
* projector cursor state.
*/
readonly getSnapshot: () => Effect.Effect<OrchestrationReadModel, ProjectionRepositoryError>;
/**
* Read the latest orchestration shell snapshot.
*
* Returns only projects and thread shell summaries so clients can bootstrap
* lightweight navigation state without hydrating every thread body.
*/
readonly getShellSnapshot: () => Effect.Effect<
OrchestrationShellSnapshot,
ProjectionRepositoryError
>;
/**
* Read archived thread shell summaries for the archive page.
*
* This query is separate from the main shell snapshot so archived threads
* are never bootstrapped into normal navigation state.
*/
readonly getArchivedShellSnapshot: () => Effect.Effect<
OrchestrationShellSnapshot,
ProjectionRepositoryError
>;
/**
* Search active thread navigation metadata, user messages, and canonical
* assistant outputs without hydrating thread detail snapshots.
*/
readonly searchThreads: (
input: OrchestrationSearchThreadsInput,
) => Effect.Effect<OrchestrationSearchThreadsResult, ProjectionRepositoryError>;
/**
* Read the latest projection snapshot sequence without hydrating read-model
* entities.
*/
readonly getSnapshotSequence: () => Effect.Effect<
ProjectionSnapshotSequence,
ProjectionRepositoryError
>;
/**
* Read aggregate projection counts without hydrating the full read model.
*/
readonly getCounts: () => Effect.Effect<ProjectionSnapshotCounts, ProjectionRepositoryError>;
/**
* Measure a persisted event range without decoding its payload bodies.
*/
readonly getEventReplayStats: (input: {
readonly fromSequenceExclusive: number;
readonly toSequenceInclusive: number;
}) => Effect.Effect<ProjectionEventReplayStats, ProjectionRepositoryError>;
/**
* Read the active project for an exact workspace root match.
*/
readonly getActiveProjectByWorkspaceRoot: (
workspaceRoot: string,
) => Effect.Effect<Option.Option<OrchestrationProject>, ProjectionRepositoryError>;
/**
* Read a single active project shell row by id.
*/
readonly getProjectShellById: (
projectId: ProjectId,
) => Effect.Effect<Option.Option<OrchestrationProjectShell>, ProjectionRepositoryError>;
/**
* Read the earliest active thread for a project.
*/
readonly getFirstActiveThreadIdByProjectId: (
projectId: ProjectId,
) => Effect.Effect<Option.Option<ThreadId>, ProjectionRepositoryError>;
/** Read completed import sources without loading thread history. */
readonly getImportedAgentSessionSources: (projectId: ProjectId) => Effect.Effect<
ReadonlyArray<{
readonly threadId: ThreadId;
readonly source: AgentSessionImportSource;
}>,
ProjectionRepositoryError
>;
/**
* Read the checkpoint context needed to resolve a single thread diff.
*/
readonly getThreadCheckpointContext: (
threadId: ThreadId,
) => Effect.Effect<Option.Option<ProjectionThreadCheckpointContext>, ProjectionRepositoryError>;
/**
* Read only the narrow context needed to compute a full-thread diff from
* checkpoint 0 to a specific turn count.
*/
readonly getFullThreadDiffContext: (
threadId: ThreadId,
toTurnCount: number,
) => Effect.Effect<Option.Option<ProjectionFullThreadDiffContext>, ProjectionRepositoryError>;
/**
* Read a single active thread shell row by id.
*/
readonly getThreadShellById: (
threadId: ThreadId,
) => Effect.Effect<Option.Option<OrchestrationThreadShell>, ProjectionRepositoryError>;
/** Read the active thread and session facts used to ingest provider events. */
readonly getThreadRuntimeContext: (
threadId: ThreadId,
) => Effect.Effect<
Option.Option<Pick<OrchestrationThreadShell, "id" | "title" | "session">>,
ProjectionRepositoryError
>;
/**
* Read one requested message and whether another non-compaction user message exists.
* Newer queued messages count too, preserving first-turn title eligibility.
*/
readonly getTurnStartMessage: (input: {
readonly threadId: ThreadId;
readonly messageId: MessageId;
}) => Effect.Effect<
Option.Option<{
readonly message: OrchestrationMessage;
readonly hasOtherUserMessages: boolean;
}>,
ProjectionRepositoryError
>;
/**
* Read a single active thread detail snapshot by id.
*/
readonly getThreadDetailById: (
threadId: ThreadId,
query?: ProjectionThreadDetailQuery,
) => Effect.Effect<Option.Option<OrchestrationThread>, ProjectionRepositoryError>;
/**
* Read a single active thread detail together with the projection snapshot
* sequence in one consistent transaction, so the returned `snapshotSequence`
* exactly matches the state reflected in `thread` (no interleaving projector
* update between the two reads).
*
* When `window` is provided, the thread's messages, activities, proposed
* plans, and checkpoints are bounded to a page of recent turns and the
* response carries `page` metadata (see `OrchestrationThreadDetailWindow`).
* Without a window the full thread is returned with no `page` field —
* pagination is strictly opt-in.
*
* Activity payloads are projected for clients as they are read in small
* sequential batches. Callers still apply the full snapshot projector for
* collection-level activity pruning.
*/
readonly getThreadDetailSnapshot: (
threadId: ThreadId,
window?: OrchestrationThreadDetailWindow,
) => Effect.Effect<Option.Option<OrchestrationThreadDetailSnapshot>, ProjectionRepositoryError>;
}
/**
* ProjectionSnapshotQuery - Service tag for projection snapshot queries.
*/
export class ProjectionSnapshotQuery extends Context.Service<
ProjectionSnapshotQuery,
ProjectionSnapshotQueryShape
>()("t3/orchestration/Services/ProjectionSnapshotQuery") {}