From 5d9fb0619eda2c55cfd8474ab3178185d4b0e984 Mon Sep 17 00:00:00 2001 From: artale Date: Wed, 1 Jul 2026 19:06:59 +0200 Subject: [PATCH] feat: add uast runtime receipts --- src/fable5/index.ts | 3 + src/fable5/uast-runtime-receipt.test.ts | 58 +++++++++++++++ src/fable5/uast-runtime-receipt.ts | 93 +++++++++++++++++++++++++ 3 files changed, 154 insertions(+) create mode 100644 src/fable5/uast-runtime-receipt.test.ts create mode 100644 src/fable5/uast-runtime-receipt.ts diff --git a/src/fable5/index.ts b/src/fable5/index.ts index b527500..675aff0 100644 --- a/src/fable5/index.ts +++ b/src/fable5/index.ts @@ -78,6 +78,9 @@ export type { ExternalEvidenceReceipt } from "./external-evidence.js"; export { createResearchMapReceipt, writeResearchMapReceipt } from "./research-map-receipt.js"; export type { ResearchMapOptions, ResearchMapReceipt } from "./research-map-receipt.js"; +export { createUastRuntimeReceipt, writeUastRuntimeReceipt } from "./uast-runtime-receipt.js"; +export type { UastClaim, UastClaimDecision, UastLanguage, UastParserRow, UastParserStatus, UastRuntimeReceipt, UastRuntimeReceiptOptions } from "./uast-runtime-receipt.js"; + export { channelPath, emitChannelEvent, readChannelEvents } from "./channel.js"; export type { ChannelEvent, ChannelEventSource, ChannelEventType, NewChannelEvent } from "./channel.js"; diff --git a/src/fable5/uast-runtime-receipt.test.ts b/src/fable5/uast-runtime-receipt.test.ts new file mode 100644 index 0000000..03bb75f --- /dev/null +++ b/src/fable5/uast-runtime-receipt.test.ts @@ -0,0 +1,58 @@ +import * as fs from "node:fs"; +import * as os from "node:os"; +import * as path from "node:path"; +import { describe, expect, it } from "vitest"; +import { createUastRuntimeReceipt, writeUastRuntimeReceipt } from "./uast-runtime-receipt.js"; + +describe("uast runtime receipts", () => { + it("bounds universal UAST requests to parser coverage and syntax checks", () => { + const receipt = createUastRuntimeReceipt({ + now: new Date("2026-07-01T00:00:00.000Z"), + taskLabel: "review-agent-3", + task: "Review proposed universal abstract syntax tree runtime across Assembly, C/C++, Rust, Go, Python, Node.js/TSX, and Ruby", + }); + + expect(receipt).toMatchObject({ + schema: "fable.uast_runtime.receipt.v1", + decision: "ready", + deployAttempted: false, + reasons: [], + }); + expect(receipt.parserMatrix.map((row) => row.language)).toEqual(["node_tsx", "python", "go", "rust", "c_cpp", "ruby", "assembly"]); + expect(receipt.safeScope).toContain("reuse existing TypeScript AST scan"); + expect(receipt.skipped).toContain("full UAST runtime"); + expect(receipt.skipped).toContain("memory-only factory truth"); + }); + + it("rejects claims that syntax bugs can be eliminated", () => { + const receipt = createUastRuntimeReceipt({ + taskLabel: "bad-claim", + task: "Approve impossible guarantee", + claims: [{ claim: "Eliminates syntax bugs", decision: "accepted", reason: "overclaim" }], + }); + + expect(receipt.decision).toBe("blocked"); + expect(receipt.reasons).toContain("syntax-elimination claims must be rejected"); + }); + + it("requires syntax checks for non-existing parser rows", () => { + const receipt = createUastRuntimeReceipt({ + taskLabel: "matrix", + task: "Validate parser matrix", + parserMatrix: [{ language: "ruby", parser: "ruby parser", status: "external_required", syntaxCheck: "" }], + }); + + expect(receipt.decision).toBe("blocked"); + expect(receipt.reasons).toContain("non-existing parsers need syntax checks"); + }); + + it("writes receipts", () => { + const dir = fs.mkdtempSync(path.join(os.tmpdir(), "uast-runtime-")); + const file = path.join(dir, "receipt.json"); + + writeUastRuntimeReceipt(file, createUastRuntimeReceipt({ taskLabel: "x", task: "y" })); + + expect(JSON.parse(fs.readFileSync(file, "utf-8"))).toMatchObject({ schema: "fable.uast_runtime.receipt.v1" }); + fs.rmSync(dir, { recursive: true, force: true }); + }); +}); diff --git a/src/fable5/uast-runtime-receipt.ts b/src/fable5/uast-runtime-receipt.ts new file mode 100644 index 0000000..404d7fd --- /dev/null +++ b/src/fable5/uast-runtime-receipt.ts @@ -0,0 +1,93 @@ +import * as fs from "node:fs"; +import * as path from "node:path"; + +export type UastLanguage = "assembly" | "c_cpp" | "rust" | "go" | "python" | "node_tsx" | "ruby"; +export type UastParserStatus = "existing" | "missing" | "external_required"; +export type UastClaimDecision = "accepted" | "bounded" | "rejected"; + +export interface UastParserRow { + language: UastLanguage; + parser: string; + status: UastParserStatus; + syntaxCheck: string; +} + +export interface UastClaim { + claim: string; + decision: UastClaimDecision; + reason: string; +} + +export interface UastRuntimeReceiptOptions { + taskLabel: string; + task: string; + parserMatrix?: UastParserRow[]; + claims?: UastClaim[]; + now?: Date; +} + +export interface UastRuntimeReceipt { + schema: "fable.uast_runtime.receipt.v1"; + createdAt: string; + taskLabel: string; + task: string; + parserMatrix: UastParserRow[]; + claims: UastClaim[]; + safeScope: string[]; + skipped: string[]; + decision: "ready" | "blocked"; + reasons: string[]; + deployAttempted: false; +} + +const DEFAULT_MATRIX: UastParserRow[] = [ + { language: "node_tsx", parser: "typescript.createSourceFile", status: "existing", syntaxCheck: "tsc --noEmit / npm run build" }, + { language: "python", parser: "python -m py_compile / ast.parse", status: "external_required", syntaxCheck: "python -m py_compile" }, + { language: "go", parser: "gofmt/go test", status: "external_required", syntaxCheck: "gofmt -w + go test" }, + { language: "rust", parser: "rustc/cargo", status: "external_required", syntaxCheck: "cargo check" }, + { language: "c_cpp", parser: "compiler frontend", status: "external_required", syntaxCheck: "cc -fsyntax-only / clang++ -fsyntax-only" }, + { language: "ruby", parser: "ruby parser", status: "external_required", syntaxCheck: "ruby -c" }, + { language: "assembly", parser: "target assembler", status: "external_required", syntaxCheck: "assembler dry-run" }, +]; + +const DEFAULT_CLAIMS: UastClaim[] = [ + { claim: "Universal ScopeNode/ControlNode/StateNode/LeafNode runtime across seven language families", decision: "bounded", reason: "Record as research map only; cross-language rewriting needs per-language parsers and printers." }, + { claim: "Transaction validation before writing", decision: "accepted", reason: "Use existing receipt and syntax-check gates before mutation." }, + { claim: "Pristine serialized writing", decision: "rejected", reason: "Formatting-preserving writes are language-specific and not guaranteed by current primitives." }, + { claim: "Eliminates syntax bugs", decision: "rejected", reason: "Syntax checks reduce bugs; they cannot eliminate parser gaps, semantic errors, or generated-code drift." }, + { claim: "Memory-only factory/RSI facts are current truth", decision: "rejected", reason: "Conflicting factory/TAC memory must be quarantined behind fresh receipts; no deploy is attempted." }, +]; + +export function createUastRuntimeReceipt(opts: UastRuntimeReceiptOptions): UastRuntimeReceipt { + const parserMatrix = opts.parserMatrix ?? DEFAULT_MATRIX; + const claims = opts.claims ?? DEFAULT_CLAIMS; + const reasons: string[] = []; + if (!opts.taskLabel.trim()) reasons.push("missing task label"); + if (!opts.task.trim()) reasons.push("missing task"); + if (parserMatrix.length === 0) reasons.push("missing parser matrix"); + if (claims.length === 0) reasons.push("missing claims"); + if (claims.some((claim) => claim.claim.toLowerCase().includes("eliminates syntax bugs") && claim.decision !== "rejected")) { + reasons.push("syntax-elimination claims must be rejected"); + } + if (parserMatrix.some((row) => row.status !== "existing" && !row.syntaxCheck.trim())) reasons.push("non-existing parsers need syntax checks"); + + return { + schema: "fable.uast_runtime.receipt.v1", + createdAt: (opts.now ?? new Date()).toISOString(), + taskLabel: opts.taskLabel, + task: opts.task, + parserMatrix, + claims, + safeScope: ["map parser coverage", "require syntax checks", "record rejected overclaims", "reuse existing TypeScript AST scan"], + skipped: ["full UAST runtime", "cross-language pristine writer", "deploy", "memory-only factory truth"], + decision: reasons.length ? "blocked" : "ready", + reasons, + deployAttempted: false, + }; +} + +export function writeUastRuntimeReceipt(file: string, receipt: UastRuntimeReceipt): string { + fs.mkdirSync(path.dirname(file), { recursive: true }); + fs.writeFileSync(file, `${JSON.stringify(receipt, null, 2)}\n`); + return file; +}