fix(db,topics): time.Time params for TIMESTAMP + comment-aware SQL split
Two fixes surfaced by sim e2e test (which otherwise passed full
lifecycle: created → signup_open → 3 signups → allocator → debating
→ arguments → verdict gate (409 early, 201 after debate_end_at) →
completed).
1) MySQL TIMESTAMP rejects RFC3339-with-Z strings — passing those as
sqlx parameters fails with "Incorrect datetime value". Changed
CreateTopicInput lifecycle fields from string to time.Time; the
handler parses+UTCs in validateLifecycleTimes (which now returns
the parsed array along with the validation result) and passes
time.Time to the store. The mysql driver formats correctly.
2) splitSQL was naive `strings.Split(s, ";")` which split inside
comments — the 001 migration had a few `--` lines containing `;`
("signup_close_at; immutable", etc) which broke. Migration text
tidied to not use `;` inside comments, AND splitSQL upgraded to
skip both `-- ...` and `/* ... */` comment regions before splitting.
Sim verified — clean apply on fresh MySQL.
This commit is contained in:
@@ -105,10 +105,33 @@ func RunMigrations(ctx context.Context, d *sqlx.DB) error {
|
||||
}
|
||||
|
||||
func splitSQL(s string) []string {
|
||||
// Crude but adequate for our migrations (no string-literal semicolons).
|
||||
// If we ever need to embed semicolons inside strings, switch to a
|
||||
// proper SQL tokenizer.
|
||||
return strings.Split(s, ";")
|
||||
// Comment-aware splitter: skip `;` inside `-- ...` line comments
|
||||
// and `/* ... */` block comments. Doesn't handle string-literal
|
||||
// semicolons (we don't put any) — if we ever need that, swap in a
|
||||
// real SQL tokenizer.
|
||||
var b strings.Builder
|
||||
i := 0
|
||||
for i < len(s) {
|
||||
if i+1 < len(s) && s[i] == '-' && s[i+1] == '-' {
|
||||
// single-line comment — strip through end of line
|
||||
for i < len(s) && s[i] != '\n' {
|
||||
i++
|
||||
}
|
||||
continue
|
||||
}
|
||||
if i+1 < len(s) && s[i] == '/' && s[i+1] == '*' {
|
||||
// block comment — strip through `*/`
|
||||
i += 2
|
||||
for i+1 < len(s) && !(s[i] == '*' && s[i+1] == '/') {
|
||||
i++
|
||||
}
|
||||
i += 2
|
||||
continue
|
||||
}
|
||||
b.WriteByte(s[i])
|
||||
i++
|
||||
}
|
||||
return strings.Split(b.String(), ";")
|
||||
}
|
||||
|
||||
func firstLine(s string) string {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
-- 001_init.sql — Dialectic v2 schema (greenfield, replaces Python v1).
|
||||
-- See /home/hzhang/arch/DIALECTIC-V2-DESIGN.md for the design.
|
||||
|
||||
-- Verdict schemas — declared at topic-creation time; judge produces output matching.
|
||||
-- Verdict schemas — declared at topic-creation time, judge produces output matching.
|
||||
CREATE TABLE verdict_schemas (
|
||||
id VARCHAR(64) NOT NULL PRIMARY KEY,
|
||||
description TEXT NOT NULL,
|
||||
@@ -60,7 +60,7 @@ CREATE TABLE signups (
|
||||
|
||||
-- Camps: the post-allocation assignment. One row per (topic, camp) with
|
||||
-- the locked-in agent. Written by camp-allocation algorithm at
|
||||
-- signup_close_at; immutable afterwards (no drop-out / replacement in v1).
|
||||
-- signup_close_at — immutable afterwards (no drop-out / replacement in v1).
|
||||
CREATE TABLE camps (
|
||||
id CHAR(36) NOT NULL PRIMARY KEY,
|
||||
topic_id CHAR(36) NOT NULL,
|
||||
@@ -73,7 +73,7 @@ CREATE TABLE camps (
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
|
||||
-- Rounds: chronological partition of arguments. Each topic has N rounds
|
||||
-- (typically 3-5); round 0 is the opening. Round transitions are driven
|
||||
-- (typically 3-5), round 0 is the opening. Round transitions are driven
|
||||
-- by the orchestrator on a schedule (or all-participants-posted).
|
||||
CREATE TABLE rounds (
|
||||
id CHAR(36) NOT NULL PRIMARY KEY,
|
||||
@@ -86,7 +86,7 @@ CREATE TABLE rounds (
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
|
||||
-- Arguments: an individual contribution within a round by a camp's agent.
|
||||
-- For pro/con these are claims/rebuttals; for judge these are clarifying
|
||||
-- For pro/con these are claims/rebuttals — for judge these are clarifying
|
||||
-- questions (judge is silent observer in v1 except for clarifications).
|
||||
CREATE TABLE arguments (
|
||||
id CHAR(36) NOT NULL PRIMARY KEY,
|
||||
@@ -118,7 +118,7 @@ CREATE TABLE verdicts (
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
|
||||
|
||||
-- Agent API keys: provisioned per agent at recruitment time. Stored as
|
||||
-- sha256(pepper || raw); pepper rotation invalidates all keys.
|
||||
-- sha256(pepper || raw) — pepper rotation invalidates all keys.
|
||||
CREATE TABLE agent_keys (
|
||||
agent_id VARCHAR(64) NOT NULL PRIMARY KEY,
|
||||
key_hash CHAR(64) NOT NULL UNIQUE,
|
||||
|
||||
Reference in New Issue
Block a user