import { StringEnum } from "@earendil-works/pi-ai"; import { Type, type Static } from "typebox"; const Id = (prefix: string) => Type.String({ pattern: `^${prefix}[A-Za-z0-9_-]{1,80}$`, maxLength: 96 }); const AnyGraphId = Type.String({ pattern: "^(pl_|tr_|arc_|ref_)[A-Za-z0-9_-]{1,80}$", maxLength: 96 }); const ShortText = Type.String({ minLength: 1, maxLength: 240 }); const LongText = Type.String({ minLength: 1, maxLength: 800 }); const TextList = Type.Array(ShortText, { maxItems: 16 }); const PlanningDependencySchema = Type.Object({ kind: StringEnum(["place_state", "gate_state", "transition_outcome", "evidence_selector"] as const), placeId: Type.Optional(Id("pl_")), state: Type.Optional(StringEnum(["satisfied", "invalidated", "open", "closed", "blocked"] as const)), transitionId: Type.Optional(Id("tr_")), outcome: Type.Optional(StringEnum(["success", "failure"] as const)), selector: Type.Optional(ShortText), }); const TransitionPlanningSchema = Type.Object({ commitment: Type.Optional(StringEnum(["committed", "provisional", "directional"] as const)), dependsOn: Type.Optional(Type.Array(PlanningDependencySchema, { maxItems: 16 })), reconsiderWhen: Type.Optional(LongText), refinementTrigger: Type.Optional(LongText), }); // complexity-note(score=2, seen=pi): This provider-compatible wide object cannot express per-op required fields without emitting fragile union schemas. // refactor-next: Move to discriminated operation schemas after every supported provider accepts the generated anyOf contract; reducers remain authoritative meanwhile. export const GraphPatchOpSchema = Type.Object({ op: StringEnum([ "set_root_intent", "create_place", "create_transition", "connect", "set_place_state", "set_transition_contract", "set_transition_planning", "refine_transition", "supersede_refinement", "activate_transition", "complete_transition", "fail_transition", "retire_transition", "supersede_transition", "attach_evidence", "mark_gate", ] as const), rootIntent: Type.Optional(LongText), placeId: Type.Optional(Id("pl_")), placeType: Type.Optional( StringEnum(["Goal", "Condition", "InformationNeed", "DecisionOutcome", "Gate", "Verified", "Outcome"] as const), ), label: Type.Optional(ShortText), placeState: Type.Optional(StringEnum(["unknown", "satisfied", "invalidated"] as const)), gateState: Type.Optional(StringEnum(["open", "closed", "blocked"] as const)), transitionId: Type.Optional(Id("tr_")), oldTransitionId: Type.Optional(Id("tr_")), newTransitionId: Type.Optional(Id("tr_")), transitionType: Type.Optional( StringEnum(["Investigate", "Decide", "Implement", "Verify", "Recover", "AskHuman", "Branch", "Conclude"] as const), ), intent: Type.Optional(ShortText), planning: Type.Optional(TransitionPlanningSchema), whyNow: Type.Optional(LongText), scope: Type.Optional(LongText), expectedEvidence: Type.Optional(TextList), evidenceSelectors: Type.Optional(TextList), allowedEpisodeKinds: Type.Optional(TextList), exitCondition: Type.Optional(LongText), failureCondition: Type.Optional(LongText), arcId: Type.Optional(Id("arc_")), fromId: Type.Optional(Type.String({ minLength: 3, maxLength: 96 })), toId: Type.Optional(Type.String({ minLength: 3, maxLength: 96 })), arcKind: Type.Optional(StringEnum(["flow", "read", "success", "failure"] as const)), refinementId: Type.Optional(Id("ref_")), oldRefinementId: Type.Optional(Id("ref_")), newRefinementId: Type.Optional(Id("ref_")), nodeIds: Type.Optional(Type.Array(AnyGraphId, { minItems: 1, maxItems: 128 })), arcIds: Type.Optional(Type.Array(Id("arc_"), { maxItems: 128 })), entryPlaceId: Type.Optional(Id("pl_")), successExitPlaceId: Type.Optional(Id("pl_")), failureExitPlaceId: Type.Optional(Id("pl_")), tokenId: Type.Optional(Id("tok_")), reason: Type.Optional(LongText), evidenceIds: Type.Optional(Type.Array(Id("ev_"), { maxItems: 32 })), targetId: Type.Optional(Type.String({ minLength: 3, maxLength: 96 })), evidence: Type.Optional( Type.Object({ evidenceId: Id("ev_"), type: StringEnum([ "agent_declaration", "tool_episode", "test_result", "error_signature", "git_fact", "external_gate", "human_statement", "observer_inference", ] as const), summary: LongText, source: ShortText, selectors: Type.Optional(TextList), observedAt: Type.Optional(Type.String({ maxLength: 64 })), redacted: Type.Optional(Type.Boolean()), }), ), }); export const GraphPatchSchema = Type.Object({ schemaVersion: Type.Literal(2), patchId: Id("patch_"), baseRevision: Type.Integer({ minimum: 0 }), idempotencyKey: Type.String({ minLength: 1, maxLength: 160 }), correlationId: Type.Optional(Type.String({ minLength: 1, maxLength: 160 })), ops: Type.Array(GraphPatchOpSchema, { minItems: 1, maxItems: 64 }), }); export type GraphPatchParams = Static;