PranitInitial commit439f83c3 months agoHistory
786 lines · 27.5 KB · Zig
RawDownload
const std = @import("std");const background_store = @import("../background/background_store.zig");const debug_trace = @import("../shared/debug_trace.zig");const io_mod = @import("../shared/io.zig");const session = @import("session.zig");const session_codec = @import("session_codec.zig");const session_child_store = @import("session_child_store.zig");const session_json = @import("session_json.zig");const session_log = @import("session_log.zig");const session_projection = @import("session_projection.zig");const session_display_metadata = @import("session_display_metadata.zig");const subagent_control_store = @import("../subagent/control_store.zig");const Allocator = std.mem.Allocator; const authority = @import("session_authority.zig");const paths = @import("session_store_paths.zig");const types = @import("session_store_types.zig"); const classifyAuthority = authority.classifyAuthority;const entryExistsRelative = authority.entryExistsRelative;const eventFileStat = authority.eventFileStat;const loadAuthorityMarkerOptional = authority.loadAuthorityMarkerOptional;const loadAuthorityTransitionOptional = authority.loadAuthorityTransitionOptional;const manifestSchemaVersion = authority.manifestSchemaVersion;const openSessionFile = authority.openSessionFile;const readOptionalSessionFile = authority.readOptionalSessionFile;const requireAuthorityFenceAbsent = authority.requireAuthorityFenceAbsent;const sessionDirPath = paths.sessionDirPath;const CandidateStorage = types.CandidateStorage;const DiscoveryCause = types.DiscoveryCause;const DoctorDiagnostic = types.DoctorDiagnostic;const DoctorInspectionOptions = types.DoctorInspectionOptions;const DoctorIssueKind = types.DoctorIssueKind;const ProjectionState = types.ProjectionState;const SessionSummary = types.SessionSummary;const StorageFormat = types.StorageFormat;const automatic_legacy_max_bytes = types.automatic_legacy_max_bytes;const StoreContext = types.StoreContext; pub const DiscoveryMode = enum {    read_only_list,    global_read_only_last,    workspace_writable_last,}; const DiscoveryOutcome = enum {    selected,    retained,    excluded,    skipped,}; pub const DiscoveryCandidateMetadata = struct {    id: []const u8,    storage: CandidateStorage,    projection_state: ProjectionState,}; pub const ReadOnlyCandidate = struct {    summary: SessionSummary,    storage: CandidateStorage,    projection_state: ProjectionState,     pub fn deinit(self: *ReadOnlyCandidate, alloc: Allocator) void {        self.summary.deinit(alloc);        self.* = undefined;    }}; pub const WritableCandidate = struct {    id: []u8,    workspace_root: []u8,    updated_at_ms: i64,    storage: CandidateStorage,    projection_state: ProjectionState,     pub fn deinit(self: *WritableCandidate, alloc: Allocator) void {        alloc.free(self.id);        alloc.free(self.workspace_root);        self.* = undefined;    }}; const LegacyCandidateSummary = struct {    id: []u8,    workspace_root: ?[]u8 = null,    created_at_ms: i64,    updated_at_ms: i64,    conversation_language: session.ConversationLanguage,    history_len: usize,    schema_version: session_json.LegacySchemaVersion = .v1,     fn intoSessionSummary(self: *LegacyCandidateSummary) SessionSummary {        const summary = SessionSummary{            .id = self.id,            .workspace_root = self.workspace_root,            .created_at_ms = self.created_at_ms,            .updated_at_ms = self.updated_at_ms,            .conversation_language = self.conversation_language,            .history_len = self.history_len,        };        self.id = undefined;        self.workspace_root = null;        return summary;    }     fn deinit(self: *LegacyCandidateSummary, alloc: Allocator) void {        alloc.free(self.id);        if (self.workspace_root) |root| alloc.free(root);        self.* = undefined;    }}; /// Frees every diagnostic in the list and the list itself. Call once on the/// slice returned by `Store.inspectForDoctor`.pub fn freeDoctorDiagnostics(    alloc: Allocator,    diagnostics: *std.ArrayList(DoctorDiagnostic),) void {    for (diagnostics.items) |*diagnostic| diagnostic.deinit(alloc);    diagnostics.deinit(alloc);} /// Appends one diagnostic for `session_id`; dupes the id so the caller keeps/// ownership of its slice. `bytes` carries an optional size for size-based kinds.pub fn appendDoctorDiagnostic(    diagnostics: *std.ArrayList(DoctorDiagnostic),    alloc: Allocator,    session_id: []const u8,    kind: DoctorIssueKind,    bytes: ?u64,) !void {    const owned_id = try alloc.dupe(u8, session_id);    errdefer alloc.free(owned_id);    try diagnostics.append(alloc, .{        .session_id = owned_id,        .kind = kind,        .bytes = bytes,    });} fn appendDoctorGrowthDiagnostic(    diagnostics: *std.ArrayList(DoctorDiagnostic),    alloc: Allocator,    session_id: []const u8,    kind: DoctorIssueKind,    bytes: u64,    growth_bytes: u64,    growth_frames: u64,) !void {    const owned_id = try alloc.dupe(u8, session_id);    errdefer alloc.free(owned_id);    try diagnostics.append(alloc, .{        .session_id = owned_id,        .kind = kind,        .bytes = bytes,        .growth_bytes = growth_bytes,        .growth_frames = growth_frames,    });} /// Inspects one session directory and appends a diagnostic for the first/// integrity problem it finds, dispatching to the authority-state it detects./// Owns only sequencing: the actual checks live in the three inspect* helpers/// below. Fails only on `error.OutOfMemory` from diagnostic allocation; all/// inspection errors are converted into diagnostics, never propagated.pub fn inspectDoctorSession(    ctx: StoreContext,    alloc: Allocator,    diagnostics: *std.ArrayList(DoctorDiagnostic),    session_dir: *io_mod.VerifiedDir,    session_id: []const u8,    options: DoctorInspectionOptions,) !void {    const transition = loadAuthorityTransitionOptional(alloc, session_dir) catch |err| {        try appendDoctorDiagnostic(            diagnostics,            alloc,            session_id,            if (err == error.SessionPathUnsafe) .unsafe_path else .invalid_authority_transition,            null,        );        return;    };    if (transition) |transition_value| {        var owned = transition_value;        defer owned.deinit(alloc);        try appendDoctorDiagnostic(diagnostics, alloc, session_id, .authority_transition_pending, null);        return;    }     const marker = loadAuthorityMarkerOptional(alloc, session_dir) catch |err| {        try appendDoctorDiagnostic(            diagnostics,            alloc,            session_id,            if (err == error.SessionPathUnsafe) .unsafe_path else .invalid_authority,            null,        );        return;    };    if (marker == null) {        return inspectAuthoritylessSession(ctx, alloc, diagnostics, session_dir, session_id);    }     var owned_marker = marker.?;    defer owned_marker.deinit(alloc);    if (!std.mem.eql(u8, owned_marker.session_id, session_id)) {        try appendDoctorDiagnostic(diagnostics, alloc, session_id, .invalid_authority, null);        return;    }     return inspectSchemaV3Session(ctx, alloc, diagnostics, session_dir, session_id, options);} /// Diagnoses a session that carries no authority marker: either an in-flight/// schema-v3 creation orphan, an oversized legacy snapshot, or a missing/// authority record. Terminal: appends exactly one classification and returns.fn inspectAuthoritylessSession(    ctx: StoreContext,    alloc: Allocator,    diagnostics: *std.ArrayList(DoctorDiagnostic),    session_dir: *io_mod.VerifiedDir,    session_id: []const u8,) !void {    const manifest_bytes = try readOptionalSessionFile(        alloc,        session_dir,        "session.json",        session_projection.manifest_max_bytes,    );    if (manifest_bytes) |bytes| {        defer alloc.free(bytes);        const schema_version = manifestSchemaVersion(alloc, bytes) catch {            try appendDoctorDiagnostic(diagnostics, alloc, session_id, .missing_authority, null);            return;        };        if (schema_version == 3) {            var manifest = session_projection.decodeManifest(alloc, bytes) catch {                try appendDoctorDiagnostic(diagnostics, alloc, session_id, .missing_authority, null);                return;            };            defer manifest.deinit(alloc);            try appendDoctorDiagnostic(                diagnostics,                alloc,                session_id,                if (std.mem.eql(u8, manifest.id, session_id))                    .authority_less_creation_orphan                else                    .missing_authority,                null,            );            return;        }         var legacy_file = try openSessionFile(session_dir, "session.json", .read_only);        defer legacy_file.close(io_mod.getIo());        const legacy_stat = try legacy_file.stat(io_mod.getIo());        if (legacy_stat.size > automatic_legacy_max_bytes) {            try appendDoctorDiagnostic(diagnostics, alloc, session_id, .oversized_legacy_snapshot, legacy_stat.size);        }        try inspectDoctorManagedChildren(ctx, alloc, diagnostics, session_dir, session_id);        return;    }     const has_prepared_log = entryExistsRelative(session_dir, "events.jsonl") catch false;    try appendDoctorDiagnostic(        diagnostics,        alloc,        session_id,        if (has_prepared_log) .authority_less_creation_orphan else .missing_authority,        null,    );} /// Diagnoses a session that owns a valid authority marker: validates the/// projection manifest, event log size, commit watermark, compaction growth,/// stale/cleanup artifacts, managed children, and finally a canonical replay./// Terminal: stops at the first disqualifying problem.fn inspectSchemaV3Session(    ctx: StoreContext,    alloc: Allocator,    diagnostics: *std.ArrayList(DoctorDiagnostic),    session_dir: *io_mod.VerifiedDir,    session_id: []const u8,    options: DoctorInspectionOptions,) !void {    const manifest_bytes = try readOptionalSessionFile(        alloc,        session_dir,        "session.json",        session_projection.manifest_max_bytes,    );    if (manifest_bytes == null) {        try appendDoctorDiagnostic(diagnostics, alloc, session_id, .projection_missing, null);    }     var manifest: ?session_projection.Manifest = null;    defer if (manifest) |*value| value.deinit(alloc);    if (manifest_bytes) |bytes| {        defer alloc.free(bytes);        manifest = session_projection.decodeManifest(alloc, bytes) catch {            try appendDoctorDiagnostic(diagnostics, alloc, session_id, .projection_invalid, null);            return;        };    }     const event_stat = eventFileStat(session_dir, "events.jsonl") catch |err| {        try appendDoctorDiagnostic(            diagnostics,            alloc,            session_id,            if (err == error.SessionPathUnsafe) .unsafe_path else .canonical_state_invalid,            null,        );        return;    };    if (event_stat.size >= 128 * 1024 * 1024) {        try appendDoctorDiagnostic(diagnostics, alloc, session_id, .canonical_log_large, event_stat.size);        return;    }     const watermark = session_log.inspectCommitWatermark(alloc, session_dir, session_id) catch |err| {        try appendDoctorDiagnostic(            diagnostics,            alloc,            session_id,            if (err == error.SessionPathUnsafe) .unsafe_path else .canonical_state_invalid,            null,        );        return;    };    switch (watermark.status) {        .missing, .invalid, .mismatched => {            try appendDoctorDiagnostic(                diagnostics,                alloc,                session_id,                switch (watermark.status) {                    .missing => .commit_watermark_missing,                    .invalid => .commit_watermark_invalid,                    .mismatched => .commit_watermark_mismatched,                    .valid => unreachable,                },                null,            );            return;        },        .valid => {},    }     const committed_position = watermark.position.?;    const has_failed_compaction = try session_log.hasValidatedCompactionTemp(alloc, session_dir, session_id);    if (manifest) |value| {        try appendCompactionGrowthIfNeeded(            diagnostics,            alloc,            session_id,            value,            committed_position,            has_failed_compaction,            options,        );    }    if (manifest) |value| {        if (session_projection.isManifestStale(value, event_stat)) {            try appendDoctorDiagnostic(diagnostics, alloc, session_id, .projection_stale, null);        }        try appendCleanupCandidateIfPresent(diagnostics, alloc, session_id, session_dir, value);    }     try inspectDoctorManagedChildren(ctx, alloc, diagnostics, session_dir, session_id);     const has_commit_intent = entryExistsRelative(session_dir, "commit.pending.json") catch |err| {        try appendDoctorDiagnostic(            diagnostics,            alloc,            session_id,            if (err == error.SessionPathUnsafe) .unsafe_path else .invalid_commit_intent,            null,        );        return;    };     var root = ctx.canonical_root;    var state = root.loadReadOnly(alloc, session_id, .{}) catch |err| {        try appendDoctorDiagnostic(            diagnostics,            alloc,            session_id,            if (has_commit_intent and err == error.SessionCommitBoundaryUnavailable)                .commit_intent_pending            else if (has_commit_intent)                .invalid_commit_intent            else if (err == error.SessionPathUnsafe)                .unsafe_path            else                .canonical_state_invalid,            null,        );        return;    };    state.deinit(alloc);} /// Appends a compaction diagnostic when the committed log has grown past the/// configured byte/frame thresholds within the manifest's current generation./// No-op when the generation differs or growth is under threshold.fn appendCompactionGrowthIfNeeded(    diagnostics: *std.ArrayList(DoctorDiagnostic),    alloc: Allocator,    session_id: []const u8,    manifest: session_projection.Manifest,    committed_position: session_log.CommitPosition,    has_failed_compaction: bool,    options: DoctorInspectionOptions,) !void {    const same_generation = std.mem.eql(u8, &manifest.log_generation, &committed_position.log_generation);    if (!same_generation) return;    const growth_bytes = committed_position.through_event_log_bytes -        @min(committed_position.through_event_log_bytes, manifest.generation_base_bytes);    const growth_frames = committed_position.through_seq -        @min(committed_position.through_seq, manifest.generation_base_seq);    if (growth_bytes >= options.compaction_byte_threshold or        growth_frames >= options.compaction_frame_threshold)    {        try appendDoctorGrowthDiagnostic(            diagnostics,            alloc,            session_id,            if (has_failed_compaction)                .canonical_log_compaction_failed            else                .canonical_log_compaction_overdue,            committed_position.through_event_log_bytes,            growth_bytes,            growth_frames,        );    }} /// Appends a single cleanup-candidate diagnostic if the directory contains a/// compaction artifact from a generation other than the manifest's current one.fn appendCleanupCandidateIfPresent(    diagnostics: *std.ArrayList(DoctorDiagnostic),    alloc: Allocator,    session_id: []const u8,    session_dir: *io_mod.VerifiedDir,    manifest: session_projection.Manifest,) !void {    var entries = session_dir.dir.iterate();    while (try entries.next(io_mod.getIo())) |entry| {        const generation = session_log.cleanupCandidateGeneration(entry.name) orelse continue;        if (std.mem.eql(u8, &generation, &manifest.log_generation)) continue;        try appendDoctorDiagnostic(diagnostics, alloc, session_id, .cleanup_candidate, null);        break;    }} fn inspectDoctorManagedChildren(    ctx: StoreContext,    alloc: Allocator,    diagnostics: *std.ArrayList(DoctorDiagnostic),    session_dir: *io_mod.VerifiedDir,    session_id: []const u8,) !void {    const display_path = try sessionDirPath(alloc, ctx.sessions_dir, session_id);    defer alloc.free(display_path);    var capability = session_child_store.SessionChildCapability.init(        alloc,        session_dir.dir,        display_path,        .read_only,    ) catch |err| {        if (err == error.OutOfMemory) return err;        try appendDoctorDiagnostic(diagnostics, alloc, session_id, .unsafe_path, null);        return;    };    defer capability.deinit();     const child_kinds = [_]session_child_store.ManagedChildKind{        .background_records,        .background_logs,        .command_artifacts,        .browser_artifacts,        .tool_results,        .subagent_control,    };    for (child_kinds) |kind| {        var entries = capability.iterate(alloc, kind) catch |err| {            if (err == error.OutOfMemory) return err;            try appendDoctorDiagnostic(diagnostics, alloc, session_id, .unsafe_path, null);            return;        };        entries.deinit();    }    background_store.validateAllManagedRecords(alloc, &capability) catch |err| {        if (err == error.OutOfMemory) return err;        try appendDoctorDiagnostic(diagnostics, alloc, session_id, .canonical_state_invalid, null);

Lines 1–500 of 786.