- attempt_ledger.ensure: relax gap-3 outcome NOT NULL on Postgres (ALTER COLUMN outcome DROP NOT NULL, probe-gated); without it every resume write on a gap-3-migrated PG table fails with NotNullViolation. SQLite keeps NOT NULL (no such ALTER). - db.PgCursor: PRAGMA table_info fake rows had the notnull flag inverted (NO -> 0); now matches sqlite semantics (1 = NOT NULL). No caller read row[3] before, so this was latent. - ledger_onboarding: stale 'PG path unverified' notes updated to point at the real-PG proof. - tests: pragma_info notnull pin (fake driver) + _column_notnull probe pins (fresh + gap-3 SQLite). Proof: 28/28 checks on real Postgres 16.15 (see verification/ codex-task-attempts-pg-proof-20261106.md).
This commit is contained in:
1 parent
698398dafb
commit
2fcde375a4
5 files changed
+104
-16
No files matched your search
@@ -30,6 +30,7 @@ from cloud.attempt_ledger import ( # noqa: E402
|
||||
SQLITE_DDL,
|
||||
TASK_ATTEMPTS_DDL,
|
||||
UNIFIED_COLUMNS,
|
||||
_column_notnull,
|
||||
aggregate_attempts,
|
||||
ensure_task_attempts_table,
|
||||
read_attempt_rows,
|
||||
@@ -133,6 +134,31 @@ class TestFreshAndMigrations(unittest.TestCase):
|
||||
self.assertEqual(self.conn.execute(
|
||||
"SELECT COUNT(*) FROM task_attempts").fetchone()[0], 1)
|
||||
|
||||
def test_column_notnull_probe(self):
|
||||
# PG 实证(2026-11-06):ensure 的 outcome 放宽依赖
|
||||
# PRAGMA row[3] 的 notnull 语义;SQLite 侧钉住探针本身。
|
||||
ensure_task_attempts_table(self.conn)
|
||||
flags = _column_notnull(self.conn, "task_attempts")
|
||||
self.assertFalse(flags["outcome"])
|
||||
self.assertTrue(flags["task_id"])
|
||||
self.assertTrue(flags["attempt_no"])
|
||||
self.assertTrue(flags["is_defect"])
|
||||
|
||||
def test_column_notnull_probe_sees_gap3_outcome(self):
|
||||
# gap-3 形态的 outcome 是 NOT NULL;探针必须报 True,
|
||||
# 否则 PG 上的放宽不会触发,恢复写路仍会炸。
|
||||
self.conn.execute(GAP3_DDL)
|
||||
flags = _column_notnull(self.conn, "task_attempts")
|
||||
self.assertTrue(flags["outcome"])
|
||||
# SQLite 上放宽语句不合法、被 ensure 吞掉:迁移本身
|
||||
# 不抛错、列集仍齐,但 outcome 保持 NOT NULL(需重建
|
||||
# 表才能改,见批总结诚实边界;本批只修 PG 路径)。
|
||||
ensure_task_attempts_table(self.conn)
|
||||
self.assertEqual(set(_columns(self.conn)),
|
||||
set(UNIFIED_COLUMNS))
|
||||
self.assertTrue(
|
||||
_column_notnull(self.conn, "task_attempts")["outcome"])
|
||||
|
||||
def test_old_shape_migrates_with_rows_intact(self):
|
||||
self.conn.execute(OLD_DDL)
|
||||
self.conn.execute(
|
||||
|
||||
Reference in new issue
Block a user