refactor(ai-judge): group src modules into domain directories

- move evidence.ts and conversation.ts into evidence/ as bash.ts and conversation.ts
- move prompt.ts and model.ts into judge/
- move highrisk.ts and judge.ts into authority/, renaming judge.ts to enforce.ts to avoid clashing with the judge/ directory
- move review.ts and audit.ts into telemetry/
- move config.ts and catalog.ts into config/ as judge.ts and catalog.ts
- rewrite static and dynamic imports across src, tools, and tests to the new paths
- fix the models-catalog.json relative URL broken by the move (caught by fallow unresolved-import)
- update the PIEXTENSIO-12 module map in the ADR to the new paths
- add editorconfig for 4-space ts indentation
This commit is contained in:
2026-08-22 01:34:29 +08:00
parent c479f51469
commit 99e953664d
26 changed files with 48 additions and 44 deletions
+4
View File
@@ -0,0 +1,4 @@
[*\.ts]
indent_style = space
indent_size = 4
tab_width = 4
+6 -6
View File
@@ -21,12 +21,12 @@ owning decision.
| Module | File | Deterministic tests | Status | | Module | File | Deterministic tests | Status |
|---|---|---|---| |---|---|---|---|
| index | `src/index.ts` | `test/lifecycle.test.ts` | present | | index | `src/index.ts` | `test/lifecycle.test.ts` | present |
| config | `src/config.ts` | `test/config.test.ts` | present | | config | `src/config/judge.ts` | `test/config.test.ts` | present |
| evidence | `src/evidence.ts`, `src/conversation.ts` | `test/evidence.test.ts`, `test/conversation.test.ts` | present | | evidence | `src/evidence/bash.ts`, `src/evidence/conversation.ts` | `test/evidence.test.ts`, `test/conversation.test.ts` | present |
| prompt | `src/prompt.ts` | `test/prompt.test.ts` | present | | prompt | `src/judge/prompt.ts` | `test/prompt.test.ts` | present |
| model | `src/model.ts` | `test/model.test.ts` | present | | model | `src/judge/model.ts` | `test/model.test.ts` | present |
| review | `src/review.ts` | `test/review.test.ts` | present | | review | `src/telemetry/review.ts` | `test/review.test.ts` | present |
| judge | `src/judge.ts` | `test/judge.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 | | analyzer (separate governance consumer) | `src/analyzer/` | `test/analyzer/analyze.test.ts` | present |
No eighth live module was invented. No eighth live module was invented.
@@ -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). * Enforce truth table (PIEXTENSIO-3 cat.4 / M5; ADR 0008 / PIEXTENSIO-23).
@@ -267,5 +267,5 @@ export function classifyModel(
/** Package-root catalog path (data, not source; beside reports/). */ /** Package-root catalog path (data, not source; beside reports/). */
export const DEFAULT_CATALOG_PATH: string = fileURLToPath( export const DEFAULT_CATALOG_PATH: string = fileURLToPath(
new URL("../models-catalog.json", import.meta.url), new URL("../../models-catalog.json", import.meta.url),
); );
@@ -1,6 +1,6 @@
import { readFileSync } from "node:fs"; import { readFileSync } from "node:fs";
import { join } from "node:path"; 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 * Judge configuration (PIEXTENSIO-3 Config acceptance, PIEXTENSIO-11
+10 -10
View File
@@ -11,31 +11,31 @@ import {
type AuthorizerLog, type AuthorizerLog,
type AuthorizerVerdict, type AuthorizerVerdict,
} from "@gotgenes/pi-permission-system"; } from "@gotgenes/pi-permission-system";
import { buildBashJudgmentEvidence, type BashJudgmentEvidence } from "./evidence"; import { buildBashJudgmentEvidence, type BashJudgmentEvidence } from "./evidence/bash";
import { import {
createModelAvailability, createModelAvailability,
requestStructuredVerdict, requestStructuredVerdict,
type ModelAvailability, type ModelAvailability,
type ModelAttempt, type ModelAttempt,
} from "./model"; } from "./judge/model";
import { PROMPT_VERSION, TOOL_SCHEMA_VERSION } from "./prompt"; import { PROMPT_VERSION, TOOL_SCHEMA_VERSION } from "./judge/prompt";
import { loadJudgeConfig, type EffectiveJudgeConfig } from "./config"; import { loadJudgeConfig, type EffectiveJudgeConfig } from "./config/judge";
import { createReviewSink, type ReviewSink } from "./review"; import { createReviewSink, type ReviewSink } from "./telemetry/review";
import { createAuditLog, type AuditLog } from "./audit"; import { createAuditLog, type AuditLog } from "./telemetry/audit";
import { import {
buildConversationEvidence, buildConversationEvidence,
conversationProbeFromSession, conversationProbeFromSession,
type ConversationEvidence, type ConversationEvidence,
} from "./conversation"; } from "./evidence/conversation";
import { classifyHighRisk, type HighRiskMatch } from "./highrisk"; import { classifyHighRisk, type HighRiskMatch } from "./authority/highrisk";
import { evaluateEnforceAuthority, type EnforceGateState } from "./judge"; import { evaluateEnforceAuthority, type EnforceGateState } from "./authority/enforce";
import { import {
classifyModel, classifyModel,
loadModelCatalog, loadModelCatalog,
DEFAULT_CATALOG_PATH, DEFAULT_CATALOG_PATH,
type ModelCatalogClassification, type ModelCatalogClassification,
type LoadedModelCatalog, type LoadedModelCatalog,
} from "./catalog"; } from "./config/catalog";
const LINK_NAME = "ai-bash-judge"; const LINK_NAME = "ai-bash-judge";
const REVIEW_SCHEMA_VERSION = 1; const REVIEW_SCHEMA_VERSION = 1;
@@ -5,8 +5,8 @@ import type {
} from "@earendil-works/pi-ai"; } from "@earendil-works/pi-ai";
import type { ModelRegistry } from "@earendil-works/pi-coding-agent"; import type { ModelRegistry } from "@earendil-works/pi-coding-agent";
import { buildJudgeContext, MAX_REASON_CODE_POINTS, REPORT_VERDICT_TOOL_NAME } from "./prompt"; import { buildJudgeContext, MAX_REASON_CODE_POINTS, REPORT_VERDICT_TOOL_NAME } from "./prompt";
import type { BashJudgmentEvidence } from "./evidence"; import type { BashJudgmentEvidence } from "../evidence/bash";
import type { ConversationEvidence } from "./conversation"; import type { ConversationEvidence } from "../evidence/conversation";
// 15s is the PIEXTENSIO-11 calibrated default (canonical resolution c0b0028d): // 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, // 15,000 ms total wall-clock deadline, accepted config range 5,000–30,000 ms,
@@ -1,6 +1,6 @@
import { Type, type AssistantMessage, type Context, type Tool, type UserMessage } from "@earendil-works/pi-ai"; import { Type, type AssistantMessage, type Context, type Tool, type UserMessage } from "@earendil-works/pi-ai";
import type { BashJudgmentEvidence } from "./evidence"; import type { BashJudgmentEvidence } from "../evidence/bash";
import type { ConversationEvidence } from "./conversation"; import type { ConversationEvidence } from "../evidence/conversation";
export const PROMPT_VERSION = "bash-shadow-v4"; export const PROMPT_VERSION = "bash-shadow-v4";
export const TOOL_SCHEMA_VERSION = "report-verdict-v1"; export const TOOL_SCHEMA_VERSION = "report-verdict-v1";
@@ -2,7 +2,7 @@ import { mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs";
import { tmpdir } from "node:os"; import { tmpdir } from "node:os";
import { join } from "node:path"; import { join } from "node:path";
import { afterEach, describe, expect, it } from "vitest"; import { afterEach, describe, expect, it } from "vitest";
import { createAuditLog } from "../src/audit"; import { createAuditLog } from "../src/telemetry/audit";
const dirs: string[] = []; const dirs: string[] = [];
@@ -3,7 +3,7 @@ import {
classifyModel, classifyModel,
loadModelCatalog, loadModelCatalog,
type CatalogDeps, type CatalogDeps,
} from "../src/catalog"; } from "../src/config/catalog";
/** /**
* PIEXTENSIO-24: the advisory model catalog shipped with the package. * PIEXTENSIO-24: the advisory model catalog shipped with the package.
@@ -1,5 +1,5 @@
import { describe, expect, it } from "vitest"; 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<string, string> = {}): ConfigLoadDeps { function deps(files: Record<string, string> = {}): ConfigLoadDeps {
return { return {
@@ -2,7 +2,7 @@ import { describe, expect, it } from "vitest";
import { import {
buildConversationEvidence, buildConversationEvidence,
type ConversationProbe, type ConversationProbe,
} from "../src/conversation"; } from "../src/evidence/conversation";
function entry(text: string): unknown { function entry(text: string): unknown {
return { return {
@@ -5,8 +5,8 @@ import {
DEFAULT_TIMEOUT_MS, DEFAULT_TIMEOUT_MS,
MIN_TIMEOUT_MS, MIN_TIMEOUT_MS,
MAX_TIMEOUT_MS, MAX_TIMEOUT_MS,
} from "../src/model"; } from "../src/judge/model";
import { createModelAvailability } from "../src/model"; import { createModelAvailability } from "../src/judge/model";
import { import {
applyTimeoutOption, applyTimeoutOption,
replayCorpus, replayCorpus,
@@ -1,6 +1,6 @@
import { describe, expect, it } from "vitest"; import { describe, expect, it } from "vitest";
import type { PromptPermissionDetails } from "@gotgenes/pi-permission-system"; import type { PromptPermissionDetails } from "@gotgenes/pi-permission-system";
import { buildBashJudgmentEvidence } from "../src/evidence"; import { buildBashJudgmentEvidence } from "../src/evidence/bash";
function details( function details(
unit: string, unit: string,
@@ -1,5 +1,5 @@
import { describe, expect, it } from "vitest"; import { describe, expect, it } from "vitest";
import { classifyHighRisk } from "../src/highrisk"; import { classifyHighRisk } from "../src/authority/highrisk";
describe("classifyHighRisk — data_loss", () => { describe("classifyHighRisk — data_loss", () => {
it.each([ it.each([
@@ -2,7 +2,7 @@ import { describe, expect, it } from "vitest";
import { import {
evaluateEnforceAuthority, evaluateEnforceAuthority,
type EnforceGateState, type EnforceGateState,
} from "../src/judge"; } from "../src/authority/enforce";
const ALL_OPEN: EnforceGateState = { const ALL_OPEN: EnforceGateState = {
auditHealthy: true, auditHealthy: true,
@@ -41,8 +41,8 @@ const { mockCatalog } = vi.hoisted(() => ({
diagnostics: [] as Array<Record<string, unknown>>, diagnostics: [] as Array<Record<string, unknown>>,
}, },
})); }));
vi.mock("../src/catalog", async (importOriginal) => { vi.mock("../src/config/catalog", async (importOriginal) => {
const actual = await importOriginal<typeof import("../src/catalog")>(); const actual = await importOriginal<typeof import("../src/config/catalog")>();
return { return {
...actual, ...actual,
loadModelCatalog: () => ({ loadModelCatalog: () => ({
@@ -69,8 +69,8 @@ import {
unpublishPermissionsService, unpublishPermissionsService,
} from "@gotgenes/pi-permission-system"; } from "@gotgenes/pi-permission-system";
import extension from "../src/index"; import extension from "../src/index";
import type { ModelCatalogEntry } from "../src/catalog"; import type { ModelCatalogEntry } from "../src/config/catalog";
import { PROMPT_VERSION, TOOL_SCHEMA_VERSION } from "../src/prompt"; import { PROMPT_VERSION, TOOL_SCHEMA_VERSION } from "../src/judge/prompt";
function createFakePi(): { function createFakePi(): {
pi: ExtensionAPI; pi: ExtensionAPI;
@@ -5,7 +5,7 @@ import {
createModelAvailability, createModelAvailability,
requestStructuredVerdict, requestStructuredVerdict,
type ModelAvailability, type ModelAvailability,
} from "../src/model"; } from "../src/judge/model";
const metadata = { const metadata = {
provider: "test-provider", provider: "test-provider",
@@ -4,7 +4,7 @@ import {
MAX_REASON_CODE_POINTS, MAX_REASON_CODE_POINTS,
PROMPT_VERSION, PROMPT_VERSION,
REPORT_VERDICT_TOOL_NAME, REPORT_VERDICT_TOOL_NAME,
} from "../src/prompt"; } from "../src/judge/prompt";
import type { Context } from "@earendil-works/pi-ai"; import type { Context } from "@earendil-works/pi-ai";
describe("buildJudgeContext", () => { describe("buildJudgeContext", () => {
@@ -1,5 +1,5 @@
import { describe, expect, it } from "vitest"; 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"; import type { AuthorizerLog } from "@gotgenes/pi-permission-system";
function fakeLog(): AuthorizerLog & { function fakeLog(): AuthorizerLog & {
@@ -29,9 +29,9 @@ import {
MIN_TIMEOUT_MS, MIN_TIMEOUT_MS,
MAX_TIMEOUT_MS, MAX_TIMEOUT_MS,
type ModelAvailability, type ModelAvailability,
} from "../src/model"; } from "../src/judge/model";
import type { BashJudgmentEvidence } from "../src/evidence"; import type { BashJudgmentEvidence } from "../src/evidence/bash";
import type { ConversationEvidence } from "../src/conversation"; import type { ConversationEvidence } from "../src/evidence/conversation";
interface CorpusCase { interface CorpusCase {
readonly id: string; readonly id: string;
@@ -491,7 +491,7 @@ async function resolveReplayModel(
); );
return 1; return 1;
} }
const { createModelAvailability } = await import("../src/model"); const { createModelAvailability } = await import("../src/judge/model");
const availability: ModelAvailability = createModelAvailability(found, registry); const availability: ModelAvailability = createModelAvailability(found, registry);
if (availability.kind !== "ready") { if (availability.kind !== "ready") {
process.stderr.write( process.stderr.write(
@@ -599,7 +599,7 @@ async function main(): Promise<number> {
asOf: new Date().toISOString(), asOf: new Date().toISOString(),
provider: parsed.provider, provider: parsed.provider,
model: parsed.model, model: parsed.model,
promptVersion: (await import("../src/prompt")).PROMPT_VERSION, promptVersion: (await import("../src/judge/prompt")).PROMPT_VERSION,
corpusVersion: CORPUS_VERSION, corpusVersion: CORPUS_VERSION,
timeoutMs: parsed.timeoutMs, timeoutMs: parsed.timeoutMs,
strict: parsed.strict, strict: parsed.strict,