diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..0421d03 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,4 @@ +[*\.ts] +indent_style = space +indent_size = 4 +tab_width = 4 diff --git a/docs/adr/piextensio-12-acceptance.md b/docs/adr/piextensio-12-acceptance.md index 0cd3208..f23f9fc 100644 --- a/docs/adr/piextensio-12-acceptance.md +++ b/docs/adr/piextensio-12-acceptance.md @@ -21,12 +21,12 @@ owning decision. | Module | File | Deterministic tests | Status | |---|---|---|---| | index | `src/index.ts` | `test/lifecycle.test.ts` | present | -| config | `src/config.ts` | `test/config.test.ts` | present | -| evidence | `src/evidence.ts`, `src/conversation.ts` | `test/evidence.test.ts`, `test/conversation.test.ts` | present | -| prompt | `src/prompt.ts` | `test/prompt.test.ts` | present | -| model | `src/model.ts` | `test/model.test.ts` | present | -| review | `src/review.ts` | `test/review.test.ts` | present | -| judge | `src/judge.ts` | `test/judge.test.ts` | present | +| config | `src/config/judge.ts` | `test/config.test.ts` | present | +| evidence | `src/evidence/bash.ts`, `src/evidence/conversation.ts` | `test/evidence.test.ts`, `test/conversation.test.ts` | present | +| prompt | `src/judge/prompt.ts` | `test/prompt.test.ts` | present | +| model | `src/judge/model.ts` | `test/model.test.ts` | present | +| review | `src/telemetry/review.ts` | `test/review.test.ts` | present | +| judge | `src/authority/enforce.ts` | `test/judge.test.ts` | present | | analyzer (separate governance consumer) | `src/analyzer/` | `test/analyzer/analyze.test.ts` | present | No eighth live module was invented. diff --git a/packages/pi-permission-ai-judge/src/judge.ts b/packages/pi-permission-ai-judge/src/authority/enforce.ts similarity index 97% rename from packages/pi-permission-ai-judge/src/judge.ts rename to packages/pi-permission-ai-judge/src/authority/enforce.ts index 1b1afe9..6e290b2 100644 --- a/packages/pi-permission-ai-judge/src/judge.ts +++ b/packages/pi-permission-ai-judge/src/authority/enforce.ts @@ -1,4 +1,4 @@ -import type { TelemetryHealth } from "./review"; +import type { TelemetryHealth } from "../telemetry/review"; /** * Enforce truth table (PIEXTENSIO-3 cat.4 / M5; ADR 0008 / PIEXTENSIO-23). diff --git a/packages/pi-permission-ai-judge/src/highrisk.ts b/packages/pi-permission-ai-judge/src/authority/highrisk.ts similarity index 100% rename from packages/pi-permission-ai-judge/src/highrisk.ts rename to packages/pi-permission-ai-judge/src/authority/highrisk.ts diff --git a/packages/pi-permission-ai-judge/src/catalog.ts b/packages/pi-permission-ai-judge/src/config/catalog.ts similarity index 99% rename from packages/pi-permission-ai-judge/src/catalog.ts rename to packages/pi-permission-ai-judge/src/config/catalog.ts index a739959..1bee7b9 100644 --- a/packages/pi-permission-ai-judge/src/catalog.ts +++ b/packages/pi-permission-ai-judge/src/config/catalog.ts @@ -267,5 +267,5 @@ export function classifyModel( /** Package-root catalog path (data, not source; beside reports/). */ export const DEFAULT_CATALOG_PATH: string = fileURLToPath( - new URL("../models-catalog.json", import.meta.url), + new URL("../../models-catalog.json", import.meta.url), ); diff --git a/packages/pi-permission-ai-judge/src/config.ts b/packages/pi-permission-ai-judge/src/config/judge.ts similarity index 99% rename from packages/pi-permission-ai-judge/src/config.ts rename to packages/pi-permission-ai-judge/src/config/judge.ts index 2574a9d..2482904 100644 --- a/packages/pi-permission-ai-judge/src/config.ts +++ b/packages/pi-permission-ai-judge/src/config/judge.ts @@ -1,6 +1,6 @@ import { readFileSync } from "node:fs"; import { join } from "node:path"; -import { DEFAULT_TIMEOUT_MS, MAX_TIMEOUT_MS, MIN_TIMEOUT_MS } from "./model"; +import { DEFAULT_TIMEOUT_MS, MAX_TIMEOUT_MS, MIN_TIMEOUT_MS } from "../judge/model"; /** * Judge configuration (PIEXTENSIO-3 Config acceptance, PIEXTENSIO-11 diff --git a/packages/pi-permission-ai-judge/src/evidence.ts b/packages/pi-permission-ai-judge/src/evidence/bash.ts similarity index 100% rename from packages/pi-permission-ai-judge/src/evidence.ts rename to packages/pi-permission-ai-judge/src/evidence/bash.ts diff --git a/packages/pi-permission-ai-judge/src/conversation.ts b/packages/pi-permission-ai-judge/src/evidence/conversation.ts similarity index 100% rename from packages/pi-permission-ai-judge/src/conversation.ts rename to packages/pi-permission-ai-judge/src/evidence/conversation.ts diff --git a/packages/pi-permission-ai-judge/src/index.ts b/packages/pi-permission-ai-judge/src/index.ts index 0c4d1a0..f9ac751 100644 --- a/packages/pi-permission-ai-judge/src/index.ts +++ b/packages/pi-permission-ai-judge/src/index.ts @@ -11,31 +11,31 @@ import { type AuthorizerLog, type AuthorizerVerdict, } from "@gotgenes/pi-permission-system"; -import { buildBashJudgmentEvidence, type BashJudgmentEvidence } from "./evidence"; +import { buildBashJudgmentEvidence, type BashJudgmentEvidence } from "./evidence/bash"; import { createModelAvailability, requestStructuredVerdict, type ModelAvailability, type ModelAttempt, -} from "./model"; -import { PROMPT_VERSION, TOOL_SCHEMA_VERSION } from "./prompt"; -import { loadJudgeConfig, type EffectiveJudgeConfig } from "./config"; -import { createReviewSink, type ReviewSink } from "./review"; -import { createAuditLog, type AuditLog } from "./audit"; +} from "./judge/model"; +import { PROMPT_VERSION, TOOL_SCHEMA_VERSION } from "./judge/prompt"; +import { loadJudgeConfig, type EffectiveJudgeConfig } from "./config/judge"; +import { createReviewSink, type ReviewSink } from "./telemetry/review"; +import { createAuditLog, type AuditLog } from "./telemetry/audit"; import { buildConversationEvidence, conversationProbeFromSession, type ConversationEvidence, -} from "./conversation"; -import { classifyHighRisk, type HighRiskMatch } from "./highrisk"; -import { evaluateEnforceAuthority, type EnforceGateState } from "./judge"; +} from "./evidence/conversation"; +import { classifyHighRisk, type HighRiskMatch } from "./authority/highrisk"; +import { evaluateEnforceAuthority, type EnforceGateState } from "./authority/enforce"; import { classifyModel, loadModelCatalog, DEFAULT_CATALOG_PATH, type ModelCatalogClassification, type LoadedModelCatalog, -} from "./catalog"; +} from "./config/catalog"; const LINK_NAME = "ai-bash-judge"; const REVIEW_SCHEMA_VERSION = 1; diff --git a/packages/pi-permission-ai-judge/src/model.ts b/packages/pi-permission-ai-judge/src/judge/model.ts similarity index 98% rename from packages/pi-permission-ai-judge/src/model.ts rename to packages/pi-permission-ai-judge/src/judge/model.ts index db96fc3..9d42582 100644 --- a/packages/pi-permission-ai-judge/src/model.ts +++ b/packages/pi-permission-ai-judge/src/judge/model.ts @@ -5,8 +5,8 @@ import type { } from "@earendil-works/pi-ai"; import type { ModelRegistry } from "@earendil-works/pi-coding-agent"; import { buildJudgeContext, MAX_REASON_CODE_POINTS, REPORT_VERDICT_TOOL_NAME } from "./prompt"; -import type { BashJudgmentEvidence } from "./evidence"; -import type { ConversationEvidence } from "./conversation"; +import type { BashJudgmentEvidence } from "../evidence/bash"; +import type { ConversationEvidence } from "../evidence/conversation"; // 15s is the PIEXTENSIO-11 calibrated default (canonical resolution c0b0028d): // 15,000 ms total wall-clock deadline, accepted config range 5,000–30,000 ms, diff --git a/packages/pi-permission-ai-judge/src/prompt.ts b/packages/pi-permission-ai-judge/src/judge/prompt.ts similarity index 98% rename from packages/pi-permission-ai-judge/src/prompt.ts rename to packages/pi-permission-ai-judge/src/judge/prompt.ts index 4faedbc..082f0a7 100644 --- a/packages/pi-permission-ai-judge/src/prompt.ts +++ b/packages/pi-permission-ai-judge/src/judge/prompt.ts @@ -1,6 +1,6 @@ import { Type, type AssistantMessage, type Context, type Tool, type UserMessage } from "@earendil-works/pi-ai"; -import type { BashJudgmentEvidence } from "./evidence"; -import type { ConversationEvidence } from "./conversation"; +import type { BashJudgmentEvidence } from "../evidence/bash"; +import type { ConversationEvidence } from "../evidence/conversation"; export const PROMPT_VERSION = "bash-shadow-v4"; export const TOOL_SCHEMA_VERSION = "report-verdict-v1"; diff --git a/packages/pi-permission-ai-judge/src/audit.ts b/packages/pi-permission-ai-judge/src/telemetry/audit.ts similarity index 100% rename from packages/pi-permission-ai-judge/src/audit.ts rename to packages/pi-permission-ai-judge/src/telemetry/audit.ts diff --git a/packages/pi-permission-ai-judge/src/review.ts b/packages/pi-permission-ai-judge/src/telemetry/review.ts similarity index 100% rename from packages/pi-permission-ai-judge/src/review.ts rename to packages/pi-permission-ai-judge/src/telemetry/review.ts diff --git a/packages/pi-permission-ai-judge/test/audit.test.ts b/packages/pi-permission-ai-judge/test/audit.test.ts index 44694b7..a583e8c 100644 --- a/packages/pi-permission-ai-judge/test/audit.test.ts +++ b/packages/pi-permission-ai-judge/test/audit.test.ts @@ -2,7 +2,7 @@ import { mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs"; import { tmpdir } from "node:os"; import { join } from "node:path"; import { afterEach, describe, expect, it } from "vitest"; -import { createAuditLog } from "../src/audit"; +import { createAuditLog } from "../src/telemetry/audit"; const dirs: string[] = []; diff --git a/packages/pi-permission-ai-judge/test/catalog.test.ts b/packages/pi-permission-ai-judge/test/catalog.test.ts index 9ae5905..d7a5434 100644 --- a/packages/pi-permission-ai-judge/test/catalog.test.ts +++ b/packages/pi-permission-ai-judge/test/catalog.test.ts @@ -3,7 +3,7 @@ import { classifyModel, loadModelCatalog, type CatalogDeps, -} from "../src/catalog"; +} from "../src/config/catalog"; /** * PIEXTENSIO-24: the advisory model catalog shipped with the package. diff --git a/packages/pi-permission-ai-judge/test/config.test.ts b/packages/pi-permission-ai-judge/test/config.test.ts index 4523474..331b31d 100644 --- a/packages/pi-permission-ai-judge/test/config.test.ts +++ b/packages/pi-permission-ai-judge/test/config.test.ts @@ -1,5 +1,5 @@ import { describe, expect, it } from "vitest"; -import { loadJudgeConfig, type ConfigLoadDeps } from "../src/config"; +import { loadJudgeConfig, type ConfigLoadDeps } from "../src/config/judge"; function deps(files: Record = {}): ConfigLoadDeps { return { diff --git a/packages/pi-permission-ai-judge/test/conversation.test.ts b/packages/pi-permission-ai-judge/test/conversation.test.ts index bf9dc89..1d8e0e4 100644 --- a/packages/pi-permission-ai-judge/test/conversation.test.ts +++ b/packages/pi-permission-ai-judge/test/conversation.test.ts @@ -2,7 +2,7 @@ import { describe, expect, it } from "vitest"; import { buildConversationEvidence, type ConversationProbe, -} from "../src/conversation"; +} from "../src/evidence/conversation"; function entry(text: string): unknown { return { diff --git a/packages/pi-permission-ai-judge/test/corpus-replay-harness.test.ts b/packages/pi-permission-ai-judge/test/corpus-replay-harness.test.ts index ccc24ef..1b9ad4a 100644 --- a/packages/pi-permission-ai-judge/test/corpus-replay-harness.test.ts +++ b/packages/pi-permission-ai-judge/test/corpus-replay-harness.test.ts @@ -5,8 +5,8 @@ import { DEFAULT_TIMEOUT_MS, MIN_TIMEOUT_MS, MAX_TIMEOUT_MS, -} from "../src/model"; -import { createModelAvailability } from "../src/model"; +} from "../src/judge/model"; +import { createModelAvailability } from "../src/judge/model"; import { applyTimeoutOption, replayCorpus, diff --git a/packages/pi-permission-ai-judge/test/evidence.test.ts b/packages/pi-permission-ai-judge/test/evidence.test.ts index 4dbdc37..2f3deff 100644 --- a/packages/pi-permission-ai-judge/test/evidence.test.ts +++ b/packages/pi-permission-ai-judge/test/evidence.test.ts @@ -1,6 +1,6 @@ import { describe, expect, it } from "vitest"; import type { PromptPermissionDetails } from "@gotgenes/pi-permission-system"; -import { buildBashJudgmentEvidence } from "../src/evidence"; +import { buildBashJudgmentEvidence } from "../src/evidence/bash"; function details( unit: string, diff --git a/packages/pi-permission-ai-judge/test/highrisk.test.ts b/packages/pi-permission-ai-judge/test/highrisk.test.ts index 245ab99..4c1c2bf 100644 --- a/packages/pi-permission-ai-judge/test/highrisk.test.ts +++ b/packages/pi-permission-ai-judge/test/highrisk.test.ts @@ -1,5 +1,5 @@ import { describe, expect, it } from "vitest"; -import { classifyHighRisk } from "../src/highrisk"; +import { classifyHighRisk } from "../src/authority/highrisk"; describe("classifyHighRisk — data_loss", () => { it.each([ diff --git a/packages/pi-permission-ai-judge/test/judge.test.ts b/packages/pi-permission-ai-judge/test/judge.test.ts index 0940ac2..0e99ddc 100644 --- a/packages/pi-permission-ai-judge/test/judge.test.ts +++ b/packages/pi-permission-ai-judge/test/judge.test.ts @@ -2,7 +2,7 @@ import { describe, expect, it } from "vitest"; import { evaluateEnforceAuthority, type EnforceGateState, -} from "../src/judge"; +} from "../src/authority/enforce"; const ALL_OPEN: EnforceGateState = { auditHealthy: true, diff --git a/packages/pi-permission-ai-judge/test/lifecycle.test.ts b/packages/pi-permission-ai-judge/test/lifecycle.test.ts index 4ff7e59..b010966 100644 --- a/packages/pi-permission-ai-judge/test/lifecycle.test.ts +++ b/packages/pi-permission-ai-judge/test/lifecycle.test.ts @@ -41,8 +41,8 @@ const { mockCatalog } = vi.hoisted(() => ({ diagnostics: [] as Array>, }, })); -vi.mock("../src/catalog", async (importOriginal) => { - const actual = await importOriginal(); +vi.mock("../src/config/catalog", async (importOriginal) => { + const actual = await importOriginal(); return { ...actual, loadModelCatalog: () => ({ @@ -69,8 +69,8 @@ import { unpublishPermissionsService, } from "@gotgenes/pi-permission-system"; import extension from "../src/index"; -import type { ModelCatalogEntry } from "../src/catalog"; -import { PROMPT_VERSION, TOOL_SCHEMA_VERSION } from "../src/prompt"; +import type { ModelCatalogEntry } from "../src/config/catalog"; +import { PROMPT_VERSION, TOOL_SCHEMA_VERSION } from "../src/judge/prompt"; function createFakePi(): { pi: ExtensionAPI; diff --git a/packages/pi-permission-ai-judge/test/model.test.ts b/packages/pi-permission-ai-judge/test/model.test.ts index 6e9c515..01fbd89 100644 --- a/packages/pi-permission-ai-judge/test/model.test.ts +++ b/packages/pi-permission-ai-judge/test/model.test.ts @@ -5,7 +5,7 @@ import { createModelAvailability, requestStructuredVerdict, type ModelAvailability, -} from "../src/model"; +} from "../src/judge/model"; const metadata = { provider: "test-provider", diff --git a/packages/pi-permission-ai-judge/test/prompt.test.ts b/packages/pi-permission-ai-judge/test/prompt.test.ts index 87a97b2..bc20d11 100644 --- a/packages/pi-permission-ai-judge/test/prompt.test.ts +++ b/packages/pi-permission-ai-judge/test/prompt.test.ts @@ -4,7 +4,7 @@ import { MAX_REASON_CODE_POINTS, PROMPT_VERSION, REPORT_VERDICT_TOOL_NAME, -} from "../src/prompt"; +} from "../src/judge/prompt"; import type { Context } from "@earendil-works/pi-ai"; describe("buildJudgeContext", () => { diff --git a/packages/pi-permission-ai-judge/test/review.test.ts b/packages/pi-permission-ai-judge/test/review.test.ts index 2620f0b..2b4cf46 100644 --- a/packages/pi-permission-ai-judge/test/review.test.ts +++ b/packages/pi-permission-ai-judge/test/review.test.ts @@ -1,5 +1,5 @@ import { describe, expect, it } from "vitest"; -import { createReviewSink, type ReviewSinkDeps } from "../src/review"; +import { createReviewSink, type ReviewSinkDeps } from "../src/telemetry/review"; import type { AuthorizerLog } from "@gotgenes/pi-permission-system"; function fakeLog(): AuthorizerLog & { diff --git a/packages/pi-permission-ai-judge/tools/corpus-replay.ts b/packages/pi-permission-ai-judge/tools/corpus-replay.ts index cba3f7b..25f0df0 100644 --- a/packages/pi-permission-ai-judge/tools/corpus-replay.ts +++ b/packages/pi-permission-ai-judge/tools/corpus-replay.ts @@ -29,9 +29,9 @@ import { MIN_TIMEOUT_MS, MAX_TIMEOUT_MS, type ModelAvailability, -} from "../src/model"; -import type { BashJudgmentEvidence } from "../src/evidence"; -import type { ConversationEvidence } from "../src/conversation"; +} from "../src/judge/model"; +import type { BashJudgmentEvidence } from "../src/evidence/bash"; +import type { ConversationEvidence } from "../src/evidence/conversation"; interface CorpusCase { readonly id: string; @@ -491,7 +491,7 @@ async function resolveReplayModel( ); return 1; } - const { createModelAvailability } = await import("../src/model"); + const { createModelAvailability } = await import("../src/judge/model"); const availability: ModelAvailability = createModelAvailability(found, registry); if (availability.kind !== "ready") { process.stderr.write( @@ -599,7 +599,7 @@ async function main(): Promise { asOf: new Date().toISOString(), provider: parsed.provider, model: parsed.model, - promptVersion: (await import("../src/prompt")).PROMPT_VERSION, + promptVersion: (await import("../src/judge/prompt")).PROMPT_VERSION, corpusVersion: CORPUS_VERSION, timeoutMs: parsed.timeoutMs, strict: parsed.strict,