feat(p7): AI tables + enums + migration + events + InferencePort contract

Task 7.1: 7 AI-proposal-layer tables (IiosAiJob, IiosAiModelRun, IiosAiArtifact,
IiosAiClaim, IiosAiEvidenceLink, IiosAiToolCall, IiosEmbeddingRef) + enums;
migration ai-init. Adds ai.job.created / ai.artifact.proposed / ai.artifact.accepted
events and a standalone InferencePort contract (not part of sealed IiosPlatformPorts).
resetDb truncates the new tables.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-07-01 16:26:21 +05:30
parent 54c47dd133
commit 42bb99c09f
6 changed files with 419 additions and 0 deletions
+3
View File
@@ -43,6 +43,9 @@ export const IIOS_EVENTS = {
callbackRequested: 'com.insignia.iios.support.callback.requested.v1',
routeDecisionPreviewed: 'com.insignia.iios.route.decision.previewed.v1',
routeApproved: 'com.insignia.iios.route.approved.v1',
aiJobCreated: 'com.insignia.iios.ai.job.created.v1',
aiArtifactProposed: 'com.insignia.iios.ai.artifact.proposed.v1',
aiArtifactAccepted: 'com.insignia.iios.ai.artifact.accepted.v1',
notificationQueued: 'com.insignia.iios.notification.queued.v1',
deliveryAttempted: 'com.insignia.iios.delivery.attempted.v1',
} as const;
+1
View File
@@ -2,6 +2,7 @@ export * from './scope';
export * from './enums';
export * from './ingest';
export * from './ports';
export * from './inference';
export * from './events';
export * from './commands';
export * from './errors';
+61
View File
@@ -0,0 +1,61 @@
/**
* The AI inference port (P7). A standalone contract — deliberately NOT part of the
* sealed `IiosPlatformPorts`: AI is an internal "AI Factory" whose model execution
* routes through the Capability Broker in P9. In P7 it is a faked, deterministic,
* golden provider (no network). Every result carries the provenance the critics
* mandate (model/prompt version, tokens, cost, confidence, abstention, evidence).
*/
export type AiJobType = 'CLASSIFY' | 'SUMMARIZE' | 'EXTRACT';
export type AiArtifactType = 'CLASSIFICATION' | 'SUMMARY' | 'TRANSCRIPT' | 'DIGEST' | 'EXTRACTION';
export type AiClaimType = 'MODERATION_FLAG' | 'EVENT' | 'FAQ' | 'INTENT' | 'PRIORITY';
export interface InferenceRequest {
jobType: AiJobType;
text: string;
purpose: string;
scopeId: string;
/** The kernel interaction this inference is about — used as the default evidence source. */
interactionId?: string;
}
export interface InferenceClaim {
claimType: AiClaimType;
claimJson: Record<string, unknown>;
confidence: number;
}
export interface InferenceEvidence {
sourceType: string;
sourceId: string;
spanRef?: string;
relevanceScore?: number;
}
export interface InferenceModelRun {
model: string;
modelVersion: string;
promptVersion: string;
tokensIn: number;
tokensOut: number;
costUnits: number;
latencyMs: number;
}
export interface InferenceResult {
artifactType: AiArtifactType;
content: unknown;
confidence: number;
explanation?: string;
/** Set when the model declines to assert a claim (Scenario 7 abstention). */
abstentionReason?: string;
claims: InferenceClaim[];
evidence: InferenceEvidence[];
modelRun: InferenceModelRun;
}
export interface InferencePort {
infer(req: InferenceRequest): Promise<InferenceResult>;
}
@@ -0,0 +1,173 @@
-- CreateEnum
CREATE TYPE "IiosAiJobType" AS ENUM ('CLASSIFY', 'SUMMARIZE', 'EXTRACT');
-- CreateEnum
CREATE TYPE "IiosAiJobStatus" AS ENUM ('PENDING', 'RUNNING', 'DONE', 'FAILED', 'ABSTAINED');
-- CreateEnum
CREATE TYPE "IiosAiArtifactType" AS ENUM ('CLASSIFICATION', 'SUMMARY', 'TRANSCRIPT', 'DIGEST', 'EXTRACTION');
-- CreateEnum
CREATE TYPE "IiosAiArtifactStatus" AS ENUM ('PROPOSED', 'ACCEPTED', 'REJECTED', 'SUPERSEDED');
-- CreateEnum
CREATE TYPE "IiosAiClaimType" AS ENUM ('MODERATION_FLAG', 'EVENT', 'FAQ', 'INTENT', 'PRIORITY');
-- CreateEnum
CREATE TYPE "IiosAiClaimValidation" AS ENUM ('UNVALIDATED', 'ACCEPTED', 'REJECTED');
-- CreateTable
CREATE TABLE "IiosAiJob" (
"id" TEXT NOT NULL,
"scopeId" TEXT NOT NULL,
"jobType" "IiosAiJobType" NOT NULL,
"interactionId" TEXT,
"inputWindowRef" TEXT NOT NULL,
"purpose" TEXT NOT NULL,
"status" "IiosAiJobStatus" NOT NULL DEFAULT 'PENDING',
"modelPolicyRef" TEXT NOT NULL DEFAULT 'golden-v1',
"policyDecisionRef" TEXT,
"inputScopeHash" TEXT NOT NULL,
"replayVersion" TEXT NOT NULL DEFAULT 'v1',
"abstentionReason" TEXT,
"traceId" TEXT,
"idempotencyKey" TEXT NOT NULL,
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
CONSTRAINT "IiosAiJob_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "IiosAiModelRun" (
"id" TEXT NOT NULL,
"scopeId" TEXT NOT NULL,
"provider" TEXT NOT NULL DEFAULT 'fake',
"model" TEXT NOT NULL,
"modelVersion" TEXT NOT NULL,
"promptVersion" TEXT NOT NULL,
"toolPolicyRef" TEXT,
"tokensIn" INTEGER NOT NULL DEFAULT 0,
"tokensOut" INTEGER NOT NULL DEFAULT 0,
"costUnits" INTEGER NOT NULL DEFAULT 0,
"latencyMs" INTEGER NOT NULL DEFAULT 0,
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
CONSTRAINT "IiosAiModelRun_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "IiosAiArtifact" (
"id" TEXT NOT NULL,
"jobId" TEXT NOT NULL,
"modelRunId" TEXT NOT NULL,
"artifactType" "IiosAiArtifactType" NOT NULL,
"status" "IiosAiArtifactStatus" NOT NULL DEFAULT 'PROPOSED',
"confidence" DOUBLE PRECISION,
"contentRef" JSONB NOT NULL,
"explanationRef" TEXT,
"abstentionReason" TEXT,
"acceptedByActorId" TEXT,
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
CONSTRAINT "IiosAiArtifact_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "IiosAiClaim" (
"id" TEXT NOT NULL,
"artifactId" TEXT NOT NULL,
"claimType" "IiosAiClaimType" NOT NULL,
"claimJson" JSONB NOT NULL,
"confidence" DOUBLE PRECISION,
"validationStatus" "IiosAiClaimValidation" NOT NULL DEFAULT 'UNVALIDATED',
"acceptedByRef" TEXT,
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
CONSTRAINT "IiosAiClaim_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "IiosAiEvidenceLink" (
"id" TEXT NOT NULL,
"artifactId" TEXT NOT NULL,
"sourceType" TEXT NOT NULL,
"sourceId" TEXT NOT NULL,
"spanRef" TEXT,
"relevanceScore" DOUBLE PRECISION,
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
CONSTRAINT "IiosAiEvidenceLink_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "IiosAiToolCall" (
"id" TEXT NOT NULL,
"modelRunId" TEXT NOT NULL,
"toolName" TEXT NOT NULL,
"toolInputHash" TEXT NOT NULL,
"toolOutputRef" TEXT,
"policyRefId" TEXT,
"status" TEXT NOT NULL DEFAULT 'PENDING',
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
CONSTRAINT "IiosAiToolCall_pkey" PRIMARY KEY ("id")
);
-- CreateTable
CREATE TABLE "IiosEmbeddingRef" (
"id" TEXT NOT NULL,
"sourceType" TEXT NOT NULL,
"sourceId" TEXT NOT NULL,
"embeddingModel" TEXT NOT NULL,
"vectorStoreRef" TEXT NOT NULL,
"embeddingHash" TEXT NOT NULL,
"version" TEXT NOT NULL,
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
CONSTRAINT "IiosEmbeddingRef_pkey" PRIMARY KEY ("id")
);
-- CreateIndex
CREATE UNIQUE INDEX "IiosAiJob_idempotencyKey_key" ON "IiosAiJob"("idempotencyKey");
-- CreateIndex
CREATE INDEX "IiosAiJob_scopeId_jobType_idx" ON "IiosAiJob"("scopeId", "jobType");
-- CreateIndex
CREATE INDEX "IiosAiJob_interactionId_idx" ON "IiosAiJob"("interactionId");
-- CreateIndex
CREATE INDEX "IiosAiModelRun_scopeId_idx" ON "IiosAiModelRun"("scopeId");
-- CreateIndex
CREATE INDEX "IiosAiArtifact_jobId_idx" ON "IiosAiArtifact"("jobId");
-- CreateIndex
CREATE INDEX "IiosAiArtifact_status_idx" ON "IiosAiArtifact"("status");
-- CreateIndex
CREATE INDEX "IiosAiClaim_artifactId_idx" ON "IiosAiClaim"("artifactId");
-- CreateIndex
CREATE INDEX "IiosAiEvidenceLink_artifactId_idx" ON "IiosAiEvidenceLink"("artifactId");
-- CreateIndex
CREATE INDEX "IiosAiToolCall_modelRunId_idx" ON "IiosAiToolCall"("modelRunId");
-- CreateIndex
CREATE UNIQUE INDEX "IiosEmbeddingRef_sourceType_sourceId_version_key" ON "IiosEmbeddingRef"("sourceType", "sourceId", "version");
-- AddForeignKey
ALTER TABLE "IiosAiArtifact" ADD CONSTRAINT "IiosAiArtifact_jobId_fkey" FOREIGN KEY ("jobId") REFERENCES "IiosAiJob"("id") ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "IiosAiArtifact" ADD CONSTRAINT "IiosAiArtifact_modelRunId_fkey" FOREIGN KEY ("modelRunId") REFERENCES "IiosAiModelRun"("id") ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "IiosAiClaim" ADD CONSTRAINT "IiosAiClaim_artifactId_fkey" FOREIGN KEY ("artifactId") REFERENCES "IiosAiArtifact"("id") ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "IiosAiEvidenceLink" ADD CONSTRAINT "IiosAiEvidenceLink_artifactId_fkey" FOREIGN KEY ("artifactId") REFERENCES "IiosAiArtifact"("id") ON DELETE CASCADE ON UPDATE CASCADE;
-- AddForeignKey
ALTER TABLE "IiosAiToolCall" ADD CONSTRAINT "IiosAiToolCall_modelRunId_fkey" FOREIGN KEY ("modelRunId") REFERENCES "IiosAiModelRun"("id") ON DELETE CASCADE ON UPDATE CASCADE;
+180
View File
@@ -144,6 +144,51 @@ enum IiosRouteDecisionState {
SIMULATED
}
// ─── AI enums (P7) ────────────────────────────────────────────────
enum IiosAiJobType {
CLASSIFY
SUMMARIZE
EXTRACT
}
enum IiosAiJobStatus {
PENDING
RUNNING
DONE
FAILED
ABSTAINED
}
enum IiosAiArtifactType {
CLASSIFICATION
SUMMARY
TRANSCRIPT
DIGEST
EXTRACTION
}
enum IiosAiArtifactStatus {
PROPOSED
ACCEPTED
REJECTED
SUPERSEDED
}
enum IiosAiClaimType {
MODERATION_FLAG
EVENT
FAQ
INTENT
PRIORITY
}
enum IiosAiClaimValidation {
UNVALIDATED
ACCEPTED
REJECTED
}
// ─── Kernel tables ────────────────────────────────────────────────
/// Frozen six-vector scope. orgId + appId are REQUIRED (no global-by-null).
@@ -663,3 +708,138 @@ model IiosModerationFlag {
@@index([interactionId])
}
// ─── AI Interaction SDK tables (P7) — proposal layer, never decides ─────────
/// A scoped, purposed AI work order (classify / summarize / extract). Carries the
/// provenance the critics mandate (input_scope_hash, policy_decision_id, purpose,
/// replay_version, traceId, idempotencyKey). Idempotent per key.
model IiosAiJob {
id String @id @default(cuid())
scopeId String
jobType IiosAiJobType
interactionId String?
inputWindowRef String
purpose String
status IiosAiJobStatus @default(PENDING)
modelPolicyRef String @default("golden-v1")
policyDecisionRef String?
inputScopeHash String
replayVersion String @default("v1")
abstentionReason String?
traceId String?
idempotencyKey String @unique
createdAt DateTime @default(now())
artifacts IiosAiArtifact[]
@@index([scopeId, jobType])
@@index([interactionId])
}
/// Model/prompt/tool execution metadata + cost. The budget governor (KG-12) sums
/// costUnits per scope. In P7 provider='fake' (deterministic golden model).
model IiosAiModelRun {
id String @id @default(cuid())
scopeId String
provider String @default("fake")
model String
modelVersion String
promptVersion String
toolPolicyRef String?
tokensIn Int @default(0)
tokensOut Int @default(0)
costUnits Int @default(0)
latencyMs Int @default(0)
createdAt DateTime @default(now())
artifacts IiosAiArtifact[]
toolCalls IiosAiToolCall[]
@@index([scopeId])
}
/// A durable AI proposal/output. NEVER committed truth by itself — status starts
/// PROPOSED and only a human accept (or a deterministic gate) advances it.
model IiosAiArtifact {
id String @id @default(cuid())
jobId String
job IiosAiJob @relation(fields: [jobId], references: [id], onDelete: Cascade)
modelRunId String
modelRun IiosAiModelRun @relation(fields: [modelRunId], references: [id], onDelete: Cascade)
artifactType IiosAiArtifactType
status IiosAiArtifactStatus @default(PROPOSED)
confidence Float?
contentRef Json
explanationRef String?
abstentionReason String?
acceptedByActorId String?
createdAt DateTime @default(now())
claims IiosAiClaim[]
evidence IiosAiEvidenceLink[]
@@index([jobId])
@@index([status])
}
/// A structured extracted claim (event date, intent, priority, FAQ, moderation
/// flag). validationStatus stays UNVALIDATED until a human/deterministic accept.
model IiosAiClaim {
id String @id @default(cuid())
artifactId String
artifact IiosAiArtifact @relation(fields: [artifactId], references: [id], onDelete: Cascade)
claimType IiosAiClaimType
claimJson Json
confidence Float?
validationStatus IiosAiClaimValidation @default(UNVALIDATED)
acceptedByRef String?
createdAt DateTime @default(now())
@@index([artifactId])
}
/// Source citation for an AI claim/artifact (message / segment / KB chunk).
model IiosAiEvidenceLink {
id String @id @default(cuid())
artifactId String
artifact IiosAiArtifact @relation(fields: [artifactId], references: [id], onDelete: Cascade)
sourceType String
sourceId String
spanRef String?
relevanceScore Float?
createdAt DateTime @default(now())
@@index([artifactId])
}
/// Tool calls made by an agent under MCP/tool policy. Schema now; exercised when a
/// real provider + tools land in P9.
model IiosAiToolCall {
id String @id @default(cuid())
modelRunId String
modelRun IiosAiModelRun @relation(fields: [modelRunId], references: [id], onDelete: Cascade)
toolName String
toolInputHash String
toolOutputRef String?
policyRefId String?
status String @default("PENDING")
createdAt DateTime @default(now())
@@index([modelRunId])
}
/// Reference to a vector embedding record/index; does not expose text. Schema now;
/// exercised when RAG lands in P9.
model IiosEmbeddingRef {
id String @id @default(cuid())
sourceType String
sourceId String
embeddingModel String
vectorStoreRef String
embeddingHash String
version String
createdAt DateTime @default(now())
@@unique([sourceType, sourceId, version])
}
@@ -8,6 +8,7 @@ import type { PrismaClient } from '@prisma/client';
export async function resetDb(prisma: PrismaClient): Promise<void> {
await prisma.$executeRawUnsafe(
`TRUNCATE TABLE
"IiosAiEvidenceLink","IiosAiClaim","IiosAiToolCall","IiosAiArtifact","IiosAiModelRun","IiosAiJob","IiosEmbeddingRef",
"IiosRouteDecision","IiosRouteBinding","IiosModerationFlag",
"IiosInboundRawEvent","IiosDeliveryAttempt","IiosOutboundCommand","IiosRateLimitBucket",
"IiosTicketStateHistory","IiosTicketThreadLink","IiosCallbackRequest","IiosTicket",