Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .agents/skills/validate-sas-release/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,5 @@ Use `npm run check:project -- --security` with the existing Supabase publishable
`npm run lint` and `npm run lint:strict` both block every ESLint error, including every explicit `any`. No baseline exceptions are permitted. Validate the SDK with `npm run check:types:sdk` as well. Use generated database contracts and validated JSON boundaries; never replace removed types with unchecked assertions or inferred `any`.

Check version-specific trust evidence, query-preserving auth redirects and MCP outcome semantics when those flows change. No model evaluations, signup creation, agent requests, provisioning, paid operations or production writes are part of this batch. Inspect and validate any additive SQL separately. Publish only after checks pass and publication is user-authorized; verify that Lovable's commit matches the validated code before using direct deployment. Preserve approval, signature and evidence gates.

After the version bot updates the repository, rerun the code/artifact checks on that commit. The version generator must format TypeScript with the repository Prettier settings; a bot-generated formatting error blocks publication just like a handwritten one.
6 changes: 4 additions & 2 deletions docs/testing/TYPE-SAFETY-RELEASE.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,14 @@ The security checks use the existing Supabase publishable environment. The UI ch

Actual local evidence:

- 198 tests pass, including eight new boundary/regression tests.
- 199 tests pass, including eight new boundary/regression tests and an isolated version-generator regression test.
- Application and SDK TypeScript checks pass.
- Strict ESLint reports zero errors and zero explicit-any violations across 636 files; existing development warnings remain advisory.
- Strict ESLint reports zero errors and zero explicit-any violations across 637 files; existing development warnings remain advisory.
- Production build and dependency audit pass.
- Content, skills mirror, and Agent Plugin artifact checks pass.
- RLS and anonymous-access probes pass across 85 public tables, preserving existing allowlists.
- Signup checks pass at 390px and 1440px; screenshots were visually reviewed.

The batch writes logs, exact exit codes and aggregate results to `artifacts/validation/`. Jev's advisory review is retained there separately; deterministic checks and code inspection decide release readiness. Publication must use the validated Git commit after CI passes and source synchronization is confirmed.

The automatic `0.5.7` version update exposed a Prettier violation in generated changelog metadata. The generator now formats TypeScript using the repository configuration. Its isolated Git fixture runs the real bump command, checks formatting, and verifies matching versions and changelog content. The post-bump app/SDK, build, lint and artifact batch passes without a lint exception.
6 changes: 5 additions & 1 deletion scripts/bump-version.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
*/

import { execSync } from "node:child_process";
import { format, resolveConfig } from "prettier";
import { readFileSync, writeFileSync } from "node:fs";
import { resolve, dirname } from "node:path";
import { fileURLToPath } from "node:url";
Expand Down Expand Up @@ -179,7 +180,10 @@ newVersionSrc = newVersionSrc.replace(
(m) => m + entry,
);

writeFileSync(VERSION_FILE, newVersionSrc);
writeFileSync(
VERSION_FILE,
await format(newVersionSrc, { ...(await resolveConfig(VERSION_FILE)), filepath: VERSION_FILE }),
);

// ---------- rewrite package.json ----------
const pkg = JSON.parse(readFileSync(PKG_FILE, "utf8"));
Expand Down
4 changes: 1 addition & 3 deletions src/lib/version.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,7 @@ export const CHANGELOG: ChangelogEntry[] = [
date: "2026-10-23",
kind: "patch",
title: "Maintenance release",
highlights: [
"eliminate legacy explicit any and enforce strict type gates (#61)",
],
highlights: ["eliminate legacy explicit any and enforce strict type gates (#61)"],
},
{
version: "0.5.6",
Expand Down
59 changes: 59 additions & 0 deletions tests/version-bump.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import { test } from "node:test";
import assert from "node:assert/strict";
import { mkdtempSync, mkdirSync, copyFileSync, writeFileSync, readFileSync, rmSync } from "node:fs";
import { resolve } from "node:path";
import { spawnSync } from "node:child_process";
import { check, resolveConfig } from "prettier";

test("version generator produces lint-compatible TypeScript and consistent release metadata", async () => {
const root = resolve(import.meta.dirname, "..");
mkdirSync(resolve(root, "artifacts/validation"), { recursive: true });
const fixture = mkdtempSync(resolve(root, "artifacts/validation/bump-fixture-"));
const run = (command: string, args: string[]) => {
const result = spawnSync(command, args, { cwd: fixture, encoding: "utf8" });
assert.equal(result.status, 0, result.stderr || result.stdout);
return result.stdout;
};
try {
mkdirSync(resolve(fixture, "scripts"));
mkdirSync(resolve(fixture, "src/lib"), { recursive: true });
for (const file of [
"scripts/bump-version.ts",
"src/lib/version.ts",
"package.json",
"CHANGELOG.md",
".prettierrc",
])
copyFileSync(resolve(root, file), resolve(fixture, file));
run("git", ["init", "-q"]);
run("git", ["config", "user.name", "Release fixture"]);
run("git", ["config", "user.email", "fixture@example.test"]);
run("git", ["add", "."]);
run("git", ["commit", "-qm", "fixture baseline"]);
const current = JSON.parse(readFileSync(resolve(fixture, "package.json"), "utf8")).version;
run("git", ["tag", `v${current}`]);
writeFileSync(resolve(fixture, "fixture.txt"), "Release validation fixture\n");
run("git", ["add", "fixture.txt"]);
run("git", ["commit", "-qm", "fix: preserve typed release contract"]);
const output = run(process.execPath, ["--experimental-strip-types", "scripts/bump-version.ts"]);
assert.ok(output.includes("Bumped"));
const sourcePath = resolve(fixture, "src/lib/version.ts");
const source = readFileSync(sourcePath, "utf8");
assert.equal(
await check(source, { ...(await resolveConfig(sourcePath)), filepath: sourcePath }),
true,
);
const next = current.split(".").map(Number);
next[2]++;
const version = next.join(".");
assert.equal(
JSON.parse(readFileSync(resolve(fixture, "package.json"), "utf8")).version,
version,
);
assert.ok(source.includes(`PLATFORM_VERSION = "${version}"`));
assert.ok(source.includes("preserve typed release contract"));
assert.ok(readFileSync(resolve(fixture, "CHANGELOG.md"), "utf8").includes(`## [${version}]`));
} finally {
rmSync(fixture, { recursive: true, force: true });
}
});
Loading