fix(desktop): read SQLite state despite metadata name collisions

Resolve exported SQLite metadata through built-in PRAGMAs on the private connection. Preserve application tables/views, source encoding, nullable rows and the existing resource limits.

Validated with 93 focused tests, current-main RED controls, and actual CLI exports of the public Chinook dataset with native/shipped-reader parity and unchanged source hashes. No live GUI, container or installed agentenv qualification is claimed.

Full technical CI 42247722923 (all eight shards and final aggregate) passed; Greptile review scored 5/5 on the merged head. The original human readiness declarations remain unfilled; the explicitly authorized maintainer readiness exception applies without adding a human-review attestation.

Assisted-by: Reimu (gensokyo-skills:reimu-incident-triage)
This commit is contained in:
Nianze Wu authored and GitHub committed 2026-11-06 16:21:02 +00:00
1 parent 98c589e420
commit 93ce13e76f
2 files changed
+127 -2

No files matched your search

+2 -2
View File
@@ -184,11 +184,11 @@ def _table(db, name: str, primary_key: list, encoding: str) -> dict:
def _sqlite(path: Path) -> dict:
"""The database's ordinary tables, in schema order, up to REA's table and row limits."""
with contextlib.closing(sqlite3.connect(path.resolve().as_uri() + "?mode=ro", uri=True, timeout=SQLITE_BUSY_S)) as db:
kinds = dict(db.execute("select name, type from pragma_table_list where schema = 'main'"))
kinds = dict(db.execute("select name, type from temp.pragma_table_list where schema = 'main'"))
names = [name for (name,) in db.execute("select name from sqlite_schema where type = 'table'")
if kinds.get(name) == "table"]
keys = {name: [key for (key,) in db.execute(
"select name from pragma_table_info(?, 'main') where pk > 0 order by pk", (name,))]
"select name from temp.pragma_table_info(?, 'main') where pk > 0 order by pk", (name,))]
for name in names[:MAX_TABLES]}
encoding = {"UTF-8": "utf-8", "UTF-16le": "utf-16-le", "UTF-16be": "utf-16-be"}[
db.execute("PRAGMA encoding").fetchone()[0]]
@@ -0,0 +1,125 @@
import { execFileSync } from "node:child_process";
import { readFile, writeFile } from "node:fs/promises";
import { join } from "node:path";
import { DatabaseSync } from "node:sqlite";
import { expect, it } from "vitest";
import {
PYTHON_HELPERS,
PYTHON_IMPORTS,
} from "../../../src/domain/desktop/appExportPython.js";
import { PYTHON_TASK_EVALUATOR } from "../../../src/domain/desktop/appTaskPython.js";
import { inspectSqliteDatabaseSnapshot } from "../../../src/sqlite/SqliteDatabaseInspection.js";
import { createTestTempDirectory } from "../../fixtures/temporaryDirectory.js";
const collisions = [
["table", "pragma_table_list"],
["table", "pragma_table_info"],
["view", "pragma_table_list"],
["view", "pragma_table_info"],
] as const;
it.each(
(["UTF-8", "UTF-16le", "UTF-16be"] as const).flatMap((encoding) =>
collisions.map(([kind, name]) => [encoding, kind, name] as const),
),
)(
"reads exported %s SQLite state when a %s shadows %s",
async (encoding, kind, name) => {
const root = await createTestTempDirectory("desktop-sqlite-metadata-");
const path = join(root, "state.db");
const db = new DatabaseSync(path);
try {
db.exec(`
PRAGMA encoding = '${encoding}';
CREATE TABLE notes(id INTEGER, part TEXT, "body "" text" TEXT, PRIMARY KEY(part, id));
INSERT INTO notes VALUES(7, 'a', 'retained');
${
kind === "table"
? `CREATE TABLE ${name}(name TEXT, type TEXT, schema TEXT);
INSERT INTO ${name} VALUES('notes', 'view', 'main');`
: `CREATE VIEW ${name} AS SELECT missing_function() AS name, 'table' AS type, 'main' AS schema;`
}
`);
db.prepare("INSERT INTO notes VALUES(NULL, ?, ?)").run(
"a",
"\ufeffretained 😀\ufeff",
);
} finally {
db.close();
}
const before = await readFile(path);
const imports = PYTHON_IMPORTS.split("\n")
.filter((line) => !line.includes("agentenv_protocol"))
.join("\n");
const program = join(root, "read.py");
await writeFile(
program,
`${imports}${PYTHON_HELPERS}${PYTHON_TASK_EVALUATOR}
views = _views(Path(sys.argv[1]), ["state.db"])
checks = [{"id": "row", "kind": "row_present", "file": "state.db", "table": "notes", "where": {"id": 7}}]
missing = [{**checks[0], "where": {"id": 8}}]
print(json.dumps({"views": views, "results": evaluate(checks + missing, views)}))
`,
);
const output = JSON.parse(
execFileSync(
process.platform === "win32" ? "python" : "python3",
["-I", "-B", program, root],
{ encoding: "utf8" },
),
) as {
views: Record<string, { format: string; view: { tables: unknown } }>;
results: { result: boolean }[];
};
expect(output.views["state.db"]).toMatchObject({
format: "sqlite",
truncated: false,
view: {
tables_truncated: false,
},
});
expect(output.results.map(({ result }) => result)).toEqual([true, false]);
expect(output.views["state.db"]?.view.tables).toEqual({
notes: {
columns: ["id", "part", 'body " text'],
primary_key: ["part", "id"],
rows: [
[7, "a", "retained"],
[null, "a", "\ufeffretained 😀\ufeff"],
],
truncated: false,
},
...(kind === "table"
? {
[name]: {
columns: ["name", "type", "schema"],
primary_key: [],
rows: [["notes", "view", "main"]],
truncated: false,
},
}
: {}),
});
expect(
inspectSqliteDatabaseSnapshot(path, { path, table: "notes" }).rows,
).toMatchObject({
columns: ["id", "part", 'body " text'],
values: [
[
{ type: "integer", value: "7" },
{ type: "text", value: "a" },
{ type: "text", value: "retained" },
],
[
{ type: "null" },
{ type: "text", value: "a" },
{ type: "text", value: "\ufeffretained 😀\ufeff" },
],
],
});
expect((await readFile(path)).equals(before)).toBe(true);
},
);