diff --git a/src/driver/definition.ts b/src/driver/definition.ts index a27ca0a..3343588 100644 --- a/src/driver/definition.ts +++ b/src/driver/definition.ts @@ -1,5 +1,11 @@ import { z } from "zod"; +/** Compile-time assertion that fails when a boolean type is not `true`. */ +type AssertTrue = T; + +/** Bidirectional assignability check used to catch schema/type drift. */ +type IsEquivalent = [A] extends [B] ? ([B] extends [A] ? true : false) : false; + import type { DriverMetricsType } from "../metrics.ts"; import { DriverKindSchema, @@ -77,10 +83,15 @@ export type ActionKindType = * choices, and unsupported routes without parsing prose. */ export const ProblemSchema = z.object({ + /** Stable machine-readable problem code. */ code: z.string().min(1), + /** Layer that identified the problem. */ layer: ProblemLayerSchema, + /** Severity used by diagnostics and policy. */ severity: ProblemSeveritySchema, + /** Human-readable summary of the problem. */ message: z.string().min(1), + /** Related limit when the problem comes from a specific ceiling or budget. */ limit: LimitSchema.optional(), }).strict(); @@ -98,6 +109,8 @@ export interface ProblemType { readonly limit?: LimitType | undefined; } +type _ProblemTypeMatchesSchema = AssertTrue>>; + /** * One structured action available to the caller after planning. * @@ -106,8 +119,11 @@ export interface ProblemType { * orchestration policy. */ export const ActionSchema = z.object({ + /** Coarse-grained next step the caller can take. */ kind: ActionKindSchema, + /** Optional machine-readable qualifier for UI or policy routing. */ code: z.string().min(1).optional(), + /** Optional human-readable action detail. */ detail: z.string().min(1).optional(), }).strict(); @@ -121,6 +137,8 @@ export interface ActionType { readonly detail?: string | undefined; } +type _ActionTypeMatchesSchema = AssertTrue>>; + /** * Operations that a backend driver can preflight without performing I/O. * @@ -140,13 +158,21 @@ export type DriverOperationType = "stat" | "read" | "write" | "list" | "copy" | * input before an adapter calls a driver, and direct driver callers must supply canonical paths. `size` can be omitted for an unknown-length stream. */ export const DriverPlanInputSchema = z.object({ + /** Backend-native operation being preflighted. */ operation: DriverOperationSchema, + /** Canonical source path when the operation targets one path. */ path: PathSchema.optional(), + /** Canonical destination path for copy and move operations. */ destination: PathSchema.optional(), + /** Caller-known logical byte size when available. */ size: z.number().int().nonnegative().optional(), + /** Caller-known already-buffered byte count for streamed work. */ inputBytes: z.number().int().nonnegative().optional(), + /** Physical input source form for write operations. */ source: z.enum(["bytes", "stream"]).optional(), + /** Requested write semantics for write operations. */ mode: WriteModeSchema.optional(), + /** Whether a read request targets a byte range instead of the full file. */ range: z.boolean().optional(), }).strict(); @@ -170,6 +196,10 @@ export interface DriverPlanInputType { readonly range?: boolean | undefined; } +type _DriverPlanInputTypeMatchesSchema = AssertTrue< + IsEquivalent> +>; + /** * Serializable result returned by a backend driver planner. * @@ -179,12 +209,19 @@ export interface DriverPlanInputType { * into the adapter and filesystem plan. */ export const DriverPlanSchema = z.object({ + /** Backend-native operation that was planned. */ operation: DriverOperationSchema, + /** Whether the request can proceed under current facts and policy. */ supported: z.boolean(), + /** Effective support mode for the backend-native route. */ support: SupportModeSchema, + /** Physical part or block size when partitioning is involved. */ partBytes: z.number().int().positive().optional(), + /** Physical part or block count when partitioning is involved. */ parts: z.number().int().positive().optional(), + /** Structured problems reported by driver planning. */ problems: z.array(ProblemSchema).readonly(), + /** Structured actions the caller can take next. */ actions: z.array(ActionSchema).readonly(), }).strict(); @@ -206,6 +243,10 @@ export interface DriverPlanType { readonly actions: readonly ActionType[]; } +type _DriverPlanTypeMatchesSchema = AssertTrue< + IsEquivalent> +>; + /** * Serializable configured-driver report exposed through filesystem inspection. * @@ -213,12 +254,19 @@ export interface DriverPlanType { * surface in diagnostics before any storage work starts. */ export const DriverInspectionSchema = z.object({ + /** Stable configured driver name. */ name: z.string().min(1), + /** Backend family implemented by this driver. */ kind: DriverKindSchema, + /** Stable backend-native operations and capabilities. */ provides: z.array(z.string().min(1)).readonly(), + /** Ownership of any long-lived backend resource. */ ownership: DriverOwnershipSchema, + /** Requirements already known for this configured instance. */ requirements: z.array(RequirementSchema).readonly(), + /** Limits with provider, policy, or probe provenance. */ limits: z.array(LimitSchema).readonly(), + /** Independently visible driver optimization switches. */ optimizations: z.array(DriverOptimizationSchema).readonly(), }).strict(); @@ -240,6 +288,10 @@ export interface DriverInspectionType { readonly optimizations: readonly DriverOptimizationType[]; } +type _DriverInspectionTypeMatchesSchema = AssertTrue< + IsEquivalent> +>; + /** * Common behavior implemented by every configured storage driver. * diff --git a/src/driver/file.ts b/src/driver/file.ts index 7c5cb59..7fe00b4 100644 --- a/src/driver/file.ts +++ b/src/driver/file.ts @@ -6,14 +6,23 @@ import type { DriverType } from "./definition.ts"; /** Native operations implemented by a file-shaped backend driver. */ export const FileDriverCapabilitiesSchema = z.object({ + /** Backend can materialize file bytes through `readFile()`. */ read: z.boolean(), + /** Backend can commit materialized file bytes through `writeFile()`. */ write: z.boolean(), + /** Backend can open a native read stream. */ streamRead: z.boolean(), + /** Write modes that `writeStream()` can perform natively. */ streamWriteModes: z.array(WriteModeSchema).readonly(), + /** Backend can satisfy byte ranges without whole-file materialization. */ rangeRead: z.boolean(), + /** Backend can copy one entry through a native route. */ copy: z.boolean(), + /** Backend can move or rename one entry through a native route. */ move: z.boolean(), + /** Backend exposes a long-lived asynchronous positional writer. */ positionalWrite: z.boolean(), + /** Backend exposes a synchronous random-access file resource. */ syncAccess: z.boolean(), }).strict(); diff --git a/src/plan.ts b/src/plan.ts index e8462f3..6c6cd75 100644 --- a/src/plan.ts +++ b/src/plan.ts @@ -1,5 +1,11 @@ import { z } from "zod"; +/** Compile-time assertion that fails when a boolean type is not `true`. */ +type AssertTrue = T; + +/** Bidirectional assignability check used to catch schema/type drift. */ +type IsEquivalent = [A] extends [B] ? ([B] extends [A] ? true : false) : false; + import type { AdapterType } from "./adapter/definition.ts"; import { getSupport } from "./capability.ts"; import { @@ -135,35 +141,67 @@ export interface MovePlanInputType { */ export const PlanInputSchema = z.discriminatedUnion("operation", [ z.object({ + /** Selects a read preflight request. */ operation: z.literal("read"), + /** Path the caller plans to read. */ path: z.string().optional(), + /** Caller-known logical size when available. */ size: z.number().int().nonnegative().optional(), + /** Whether the read plans a byte range instead of the full file. */ range: z.boolean().default(false), }).strict(), z.object({ + /** Selects a write preflight request. */ operation: z.literal("write"), + /** Path the caller plans to write. */ path: z.string().optional(), + /** Caller-known logical size when available. */ size: z.number().int().nonnegative().optional(), + /** Caller-known already-buffered byte count when streaming. */ inputBytes: z.number().int().nonnegative().optional(), + /** Physical source form for the write request. */ source: WriteSourceSchema, + /** Requested write semantics. */ mode: WriteModeSchema.default("replace"), }).strict(), z.object({ + /** Selects a copy preflight request. */ operation: z.literal("copy"), + /** Source path the caller plans to copy. */ path: z.string().optional(), + /** Destination path for the copy request. */ destination: z.string().optional(), + /** Caller-known logical size when available. */ size: z.number().int().nonnegative().optional(), }).strict(), z.object({ + /** Selects a move preflight request. */ operation: z.literal("move"), + /** Source path the caller plans to move. */ path: z.string().optional(), + /** Destination path for the move request. */ destination: z.string().optional(), + /** Caller-known logical size when available. */ size: z.number().int().nonnegative().optional(), }).strict(), ]); /** Input accepted by filesystem preflight before defaults and path normalization. */ export type PlanInputType = ReadPlanInputType | WritePlanInputType | CopyPlanInputType | MovePlanInputType; +type _ReadPlanInputTypeMatchesSchema = AssertTrue< + IsEquivalent> +>; +type _WritePlanInputTypeMatchesSchema = AssertTrue< + IsEquivalent> +>; +type _CopyPlanInputTypeMatchesSchema = AssertTrue< + IsEquivalent> +>; +type _MovePlanInputTypeMatchesSchema = AssertTrue< + IsEquivalent> +>; +type _PlanInputTypeMatchesSchema = AssertTrue>>; + /** * Structured preflight result for the complete driver -> adapter -> filesystem stack. * @@ -172,14 +210,23 @@ export type PlanInputType = ReadPlanInputType | WritePlanInputType | CopyPlanInp * filesystem policy. */ export const PlanSchema = z.object({ + /** Filesystem operation that was planned. */ operation: PlanOperationSchema, + /** Whether the complete storage stack can perform the request safely. */ supported: z.boolean(), + /** Effective support mode after driver, adapter, and facade policy are combined. */ support: SupportModeSchema, + /** Backend-native planning result preserved inside the full plan. */ driver: DriverPlanSchema, + /** Facade-owned buffering required before the request can proceed. */ bufferBytes: z.number().int().nonnegative().optional(), + /** Physical part or block size when partitioning is involved. */ partBytes: z.number().int().positive().optional(), + /** Physical part or block count when partitioning is involved. */ parts: z.number().int().positive().optional(), + /** Structured problems found across the complete storage stack. */ problems: z.array(ProblemSchema).readonly(), + /** Structured actions the caller can take next. */ actions: z.array(ActionSchema).readonly(), }).strict(); /** Validated complete-stack preflight result. */ @@ -204,6 +251,8 @@ export interface PlanType { readonly actions: readonly ActionType[]; } +type _PlanTypeMatchesSchema = AssertTrue>>; + /** * Internal facade state required to combine adapter and driver preflight. * diff --git a/src/schema.ts b/src/schema.ts index 7bf87dc..cc98994 100644 --- a/src/schema.ts +++ b/src/schema.ts @@ -1,5 +1,11 @@ import { z } from "zod"; +/** Compile-time assertion that fails when a boolean type is not `true`. */ +type AssertTrue = T; + +/** Bidirectional assignability check used to catch schema/type drift. */ +type IsEquivalent = [A] extends [B] ? ([B] extends [A] ? true : false) : false; + /** * Canonical virtual path stored and exchanged by adapters. * @@ -133,11 +139,17 @@ export type PartitionModeType = "never" | "auto" | "always"; * facade memory growth. */ export const AdapterPartitionSchema = z.object({ + /** Partitioning policy selected for this adapter. */ mode: PartitionModeSchema, + /** Physical part or block size used by the layout. */ partBytes: z.number().int().positive(), + /** Logical size where `auto` starts partitioning when the adapter knows it. */ thresholdBytes: z.number().int().positive().optional(), + /** Whether streamed writes already use the partitioned layout. */ stream: z.boolean().optional(), + /** Maximum physical part or block count when the adapter knows it. */ maxParts: z.number().int().positive().optional(), + /** Stable name of the physical layout strategy. */ layout: z.string().min(1), }).strict(); @@ -157,6 +169,10 @@ export interface AdapterPartitionType { readonly layout: string; } +type _AdapterPartitionTypeMatchesSchema = AssertTrue< + IsEquivalent> +>; + /** * Optional backend limits that can be inspected before work begins. * @@ -203,6 +219,10 @@ export interface AdapterLimitsType { readonly maxBatchBytes?: number | undefined; } +type _AdapterLimitsTypeMatchesSchema = AssertTrue< + IsEquivalent> +>; + /** * Performance routes that the filesystem facade can deliberately bypass. * @@ -237,6 +257,10 @@ export interface OptimizationType { readonly nativeMove: boolean; } +type _OptimizationTypeMatchesSchema = AssertTrue< + IsEquivalent> +>; + /** * Stable adapter capability description. * @@ -290,6 +314,10 @@ export interface AdapterCapabilitiesType { readonly syncAccess: boolean; } +type _AdapterCapabilitiesTypeMatchesSchema = AssertTrue< + IsEquivalent> +>; + /** * Stable error categories exposed by the package. * @@ -329,6 +357,8 @@ export type ErrorCodeType = | "too-large" | "unknown"; +type _ErrorCodeTypeMatchesSchema = AssertTrue>>; + /** Version stored with record-backed filesystem entries. */ export const RecordVersionSchema = z.literal(1); @@ -409,24 +439,34 @@ export const DriverKindSchema = z.enum(["file", "record", "object"]); /** A validated backend driver family. */ export type DriverKindType = "file" | "record" | "object"; +type _DriverKindTypeMatchesSchema = AssertTrue>>; + /** Why one driver limit exists. */ export const LimitKindSchema = z.enum(["hard", "policy", "dynamic"]); /** A validated limit kind. */ export type LimitKindType = "hard" | "policy" | "dynamic"; +type _LimitKindTypeMatchesSchema = AssertTrue>>; + /** Layer that supplied one limit value. */ export const LimitSourceSchema = z.enum(["provider", "implementation", "user", "probe"]); /** A validated limit source. */ export type LimitSourceType = "provider" | "implementation" | "user" | "probe"; +type _LimitSourceTypeMatchesSchema = AssertTrue< + IsEquivalent> +>; + /** Unit used by one numeric limit. */ export const LimitUnitSchema = z.enum(["bytes", "count", "milliseconds", "operations"]); /** A validated limit unit. */ export type LimitUnitType = "bytes" | "count" | "milliseconds" | "operations"; +type _LimitUnitTypeMatchesSchema = AssertTrue>>; + /** * One inspectable storage limit with explicit provenance. * @@ -435,11 +475,17 @@ export type LimitUnitType = "bytes" | "count" | "milliseconds" | "operations"; * current value has not been probed. */ export const LimitSchema = z.object({ + /** Stable machine-readable limit code. */ code: z.string().min(1), + /** Whether the limit is hard, policy-driven, or dynamic. */ kind: LimitKindSchema, + /** Layer that supplied the limit value. */ source: LimitSourceSchema, + /** Unit used by the numeric value. */ unit: LimitUnitSchema, + /** Current numeric limit when known. */ value: z.number().nonnegative().optional(), + /** Human-readable context for diagnostics. */ detail: z.string().min(1).optional(), }).strict().superRefine((value, ctx) => { if (value.value === undefined && value.kind !== "dynamic") { @@ -463,12 +509,18 @@ export interface LimitType { readonly detail?: string | undefined; } +type _LimitTypeMatchesSchema = AssertTrue>>; + /** Current state of one driver requirement. */ export const RequirementStateSchema = z.enum(["available", "missing", "unknown"]); /** A validated requirement state. */ export type RequirementStateType = "available" | "missing" | "unknown"; +type _RequirementStateTypeMatchesSchema = AssertTrue< + IsEquivalent> +>; + /** * One runtime, provider, permission, or configuration requirement. * @@ -476,8 +528,11 @@ export type RequirementStateType = "available" | "missing" | "unknown"; * prefer `available` or `missing` when the state is already known. */ export const RequirementSchema = z.object({ + /** Stable machine-readable requirement code. */ code: z.string().min(1), + /** Current known availability state. */ state: RequirementStateSchema, + /** Concrete reason when the requirement is missing. */ reason: z.string().min(1).optional(), }).strict().superRefine((value, ctx) => { if (value.state === "missing" && value.reason === undefined) { @@ -495,12 +550,18 @@ export interface RequirementType { readonly reason?: string | undefined; } +type _RequirementTypeMatchesSchema = AssertTrue>>; + /** Ownership state for one configured driver backend resource. */ export const DriverOwnershipSchema = z.enum(["none", "borrowed", "owned"]); /** A validated configured-driver backend ownership state. */ export type DriverOwnershipType = "none" | "borrowed" | "owned"; +type _DriverOwnershipTypeMatchesSchema = AssertTrue< + IsEquivalent> +>; + /** * One independently controllable driver optimization. * @@ -509,10 +570,15 @@ export type DriverOwnershipType = "none" | "borrowed" | "owned"; * optimization is enabled. Such optimizations must be disableable. */ export const DriverOptimizationSchema = z.object({ + /** Stable machine-readable optimization code. */ code: z.string().min(1), + /** Current enabled state. */ enabled: z.boolean(), + /** Whether this optimization changes observable behavior. */ changesBehavior: z.boolean(), + /** Whether callers can turn this optimization off. */ disableable: z.boolean(), + /** Human-readable detail for diagnostics or documentation. */ detail: z.string().min(1).optional(), }).strict().superRefine((value, ctx) => { if (value.changesBehavior && !value.disableable) { @@ -533,3 +599,7 @@ export interface DriverOptimizationType { /** Human-readable detail for diagnostics or documentation. */ readonly detail?: string | undefined; } + +type _DriverOptimizationTypeMatchesSchema = AssertTrue< + IsEquivalent> +>;