Merge remote-tracking branch 'origin/main' into feat/pulse-hourly-mean-complete

This commit is contained in:
Marc-André Bombeck committed 2026-10-04 14:54:53 +02:00
commit 13b8920dd5
88 files changed
+5627 -772

No files matched your search

@@ -0,0 +1,124 @@
/**
* Structural guard (#1126): `reasoning_effort` reaches a model only through
* the setting the resolver bound to the provider instance.
*
* Default must send nothing, so the key may not appear on any wire except as
* the bound value, and only the two clients whose endpoint a person chose may
* carry it. Pinned here:
*
* 1. the key appears in exactly the Local client and the OpenAI client,
* once each, and only as `reasoning_effort: this.reasoningEffort`;
* 2. nothing but the binder assigns `.reasoningEffort`;
* 3. every exported resolver in `provider.ts` calls `bindReasoningEffort`.
*
* That clients are constructed only in `provider.ts` (so a resolver always
* binds them) is frozen by `ai-call-timeout-guard.test.ts`.
*
* Its limit: it reads source text. A body built under a computed key, or a
* resolver that binds through an alias, would slip it.
* `reasoning-effort.test.ts` and `provider-reasoning-effort.test.ts` prove
* the behaviour on the wire.
*
* Mutation check: hard-code `reasoning_effort: "none"` into either client,
* set `client.reasoningEffort = ...` in a route, or drop `bindReasoningEffort`
* from `resolveProviderForTest`: each one goes red here.
*/
import { readFileSync } from "node:fs";
import { join } from "node:path";
import { describe, expect, it } from "vitest";
import { walkSourceFiles } from "./helpers/source-files";
const SRC = join(process.cwd(), "src");
function stripComments(source: string): string {
return source
.replace(/\/\*[\s\S]*?\*\//g, "")
.replace(/(^|[^:])\/\/.*$/gm, "$1");
}
function code(rel: string): string {
return stripComments(readFileSync(join(SRC, rel), "utf8"));
}
const files = walkSourceFiles(SRC, { floor: 3000 })
.filter((p) => !p.startsWith("generated/"))
.filter((p) => !p.includes("__tests__"))
.filter((p) => !p.endsWith(".test.ts") && !p.endsWith(".test.tsx"));
describe("reasoning_effort on the wire", () => {
// As an object key: the published descriptions name the field in prose.
const KEY = /\breasoning_effort["']?\s*:/g;
const sites = files.filter((rel) => new RegExp(KEY).test(code(rel)));
it("appears in the Local and the OpenAI client only", () => {
expect(sites.sort()).toEqual([
"lib/ai/local-client.ts",
"lib/ai/openai-client.ts",
]);
});
it.each(["lib/ai/local-client.ts", "lib/ai/openai-client.ts"])(
"%s sends it once, as the bound value",
(rel) => {
const source = code(rel);
expect(source.match(new RegExp(KEY))?.length).toBe(1);
expect(source).toMatch(
/\breasoning_effort\s*:\s*this\s*\.\s*reasoningEffort\b/,
);
},
);
});
/** Where `.reasoningEffort` may be assigned, and why. */
const ASSIGNMENT_SITES: Record<string, string> = {
"lib/ai/reasoning-effort.ts":
"The binder, the one place a provider instance gets its value.",
"lib/ai/provider-chain.ts":
"Writes the stored chain entry, not a provider instance.",
};
describe("only the binder assigns it to a provider", () => {
it("names every assignment site, with a reason", () => {
const sites = files.filter((rel) =>
/\.\s*reasoningEffort\s*=(?!=)/.test(code(rel)),
);
expect(sites.sort()).toEqual(Object.keys(ASSIGNMENT_SITES).sort());
});
});
describe("every exported resolver binds it", () => {
const source = code("lib/ai/provider.ts");
const resolvers = source
.split(/\nexport\s+/)
.map((chunk) => {
const m = /^async\s+function\s+(\w+)\s*\(/.exec(chunk);
if (!m) return null;
const header = chunk.slice(0, chunk.indexOf("{\n"));
if (
!/Promise<\s*(?:AIProvider|ProviderChainResolved\[\])\s*>/.test(header)
) {
return null;
}
const end = chunk.indexOf("\n}\n");
return { name: m[1], body: chunk.slice(header.length, end) };
})
.filter((r): r is { name: string; body: string } => r !== null);
it("finds the resolvers (an empty set is a failure, not a pass)", () => {
expect(resolvers.map((r) => r.name).sort()).toEqual([
"resolveProvider",
"resolveProviderChain",
"resolveProviderForTest",
]);
});
it.each(resolvers.map((r) => r.name))(
"%s calls bindReasoningEffort",
(name) => {
const resolver = resolvers.find((r) => r.name === name);
expect(resolver?.body ?? "").toMatch(/\bbindReasoningEffort\s*\(/);
},
);
});
@@ -0,0 +1,65 @@
/**
* Structural guard: the runtime image puts the @napi-rs/canvas native binary
* of the version the app pins next to that version's loader.
*
* ## The failure this freezes (GitHub #1124)
*
* The pnpm store holds two canvas versions: the one in package.json and an
* older one that pdf-parse's own pdfjs-dist pulls in. The runner stage picked
* the musl binary with `find | head -1`, got the old one, and copied it into
* the new loader's directory, where the loader looks first. PDF rendering
* still worked, so nothing looked wrong; `loadImage` called an
* `Image.decode` the old binary lacks, and every preview thumbnail failed
* with "image.decode is not a function" on both architectures.
*
* ## What it proves and what it does not
*
* The builder records the resolved canvas version, the runner hoists by that
* name, and the build stops when the copied binary's package is a different
* version. Whether the binary loads is proved when the image runs; this file
* reads the Dockerfile only.
*/
import { readFileSync } from "node:fs";
import { join } from "node:path";
import { describe, expect, it } from "vitest";
const DOCKERFILE = readFileSync(join(process.cwd(), "Dockerfile"), "utf8");
function stage(name: string): string {
const start = DOCKERFILE.search(new RegExp(`^FROM .* AS ${name}$`, "m"));
expect(start, `the Dockerfile has a ${name} stage`).toBeGreaterThan(0);
const next = DOCKERFILE.slice(start + 1).search(/^FROM /m);
return next < 0
? DOCKERFILE.slice(start)
: DOCKERFILE.slice(start, start + 1 + next);
}
describe("canvas binary hoist", () => {
it("records the resolved canvas version in the builder", () => {
expect(stage("builder")).toMatch(
/require\('\/app\/node_modules\/@napi-rs\/canvas\/package\.json'\)\.version"[\s\\]*>\s*\/app\/\.canvas-version/,
);
});
it("hoists the loader and the musl binary of that version only", () => {
const runner = stage("runner");
expect(runner).toContain(
"COPY --from=builder /app/.canvas-version /tmp/.canvas-version",
);
expect(runner).toContain(
'CANVAS_DIR="/app/node_modules/.pnpm/@napi-rs+canvas@${CANVAS_VERSION}/',
);
expect(runner).toContain("canvas-linux-*-musl@${CANVAS_VERSION}/");
// A version-blind pick is the defect: any `canvas…@*` glob decides by
// readdir order which of the store's copies wins.
expect(runner).not.toMatch(/@napi-rs\+canvas[^"'\s]*@\*/);
});
it("fails the build when the copied binary is another version", () => {
const runner = stage("runner");
expect(runner).toMatch(
/\[ "\$BIN_VERSION" = "\$CANVAS_VERSION" \] \|\| \{[^}]*exit 1; \}/,
);
});
});