Skip to content

Commit 72ab370

Browse files
++
1 parent 8c5c222 commit 72ab370

8 files changed

+332
-3
lines changed

.tasks/backlog/TASK-074-cross-impl-compat-expanded.md

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,18 +18,22 @@ high
1818
- C sync helper reference: `core/src/crsqlite.test.c` (syncLeftToRight)
1919
- Feature matrix: `research/zig-cr/90-feature-matrix.md`
2020
- Gap backlog: `research/zig-cr/92-gap-backlog.md`
21+
- Pack columns reference: `core/rs/core/src/pack_columns.rs`
2122

2223
## Description
2324
A real system will often have heterogeneous peers (mobile, server, browser) and long-lived on-disk databases.
2425

25-
We already have a Zig↔Rust/C compatibility script, but its easy for it to be effectively "green" because:
26-
- it can SKIP if the Rust/C extension isnt built
26+
We already have a Zig↔Rust/C compatibility script, but it's easy for it to be effectively "green" because:
27+
- it can SKIP if the Rust/C extension isn't built
2728
- it may not cover important edge cases (deletes, PK updates, schema evolution, numeric/text encoding edge cases)
2829

2930
This task strengthens the compatibility proof by expanding the scenario set and making sure CI/local runs cannot silently skip the Rust/C side.
3031

32+
**Oracle-based testing strategy**: Treat Rust/C as the "Golden Master" oracle. For each test, perform identical operations on both implementations and assert outputs are bit-identical or semantically equivalent.
33+
3134
## Files to Modify
3235
- `zig/harness/test-cross-platform-compat.sh`
36+
- `zig/harness/test-oracle-parity.sh` (new — oracle-based parity tests)
3337
- `core/Makefile` (only if needed to provide a reproducible build target for the Rust/C loadable extension)
3438
- `.github/workflows/zig-tests.yaml` (optional: ensure Rust/C artifact exists for compat test)
3539
- `research/zig-cr/92-gap-backlog.md`
@@ -43,9 +47,15 @@ This task strengthens the compatibility proof by expanding the scenario set and
4347
- float edge cases (sci notation), blobs, NULLs
4448
- schema evolution (add/remove columns with `crsql_commit_alter`/equivalent)
4549
- [ ] Both directions tested: Zig→Rust/C and Rust/C→Zig.
50+
- [ ] **Oracle parity tests** (Rust/C as golden master):
51+
- [ ] `test_wire_format_pack_columns_compatibility`: `crsql_pack_columns(...)` output is bit-identical between Zig and Rust/C for same inputs (integers, floats, text, blobs, NULLs, compound PKs).
52+
- [ ] `test_clock_table_schema_compatibility`: `__crsql_clock` and `__crsql_pks` table schemas match exactly (column names, types, constraints).
53+
- [ ] `test_merge_resolution_value_parity`: Given identical conflict scenarios (same col_version, db_version, site_id tie-breakers), both implementations select the same winner.
54+
- [ ] `test_site_id_storage_format_parity`: Site IDs are stored as 16-byte blobs; cross-opening a DB created by Rust/C in Zig (and vice versa) preserves the site_id value.
4655

4756
## Progress Log
4857
### 2025-12-18
4958
- Task created during "update tasks" to invalidate "zig is done".
59+
- Updated to include oracle-based parity tests (wire format, schema, merge resolution, site_id).
5060

5161
## Completion Notes
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
# TASK-089: Oracle Parity — API surface completeness
2+
3+
## Status
4+
- [ ] Planned
5+
- [ ] Assigned
6+
- [ ] In Progress
7+
- [ ] Blocked (reason: ...)
8+
- [ ] Complete
9+
10+
## Priority
11+
high
12+
13+
## Assigned To
14+
(unassigned)
15+
16+
## Parent Docs / Cross-links
17+
- Rust extension entry: `core/rs/core/src/lib.rs`
18+
- Zig extension entry: `zig/src/crsqlite.zig`
19+
- Gap backlog: `research/zig-cr/92-gap-backlog.md`
20+
21+
## Description
22+
Verify that Zig exposes the same SQL API surface as Rust/C. Use `pragma_function_list` and `pragma_module_list` to enumerate all registered functions and virtual table modules, then compare.
23+
24+
This is an **oracle test**: Rust/C is the golden master. Any function or module present in Rust/C but missing from Zig is a gap.
25+
26+
## Files to Modify
27+
- `zig/harness/test-api-surface.sh` (new)
28+
- `zig/harness/test-parity.sh` (wire into suite)
29+
- `research/zig-cr/92-gap-backlog.md`
30+
31+
## Acceptance Criteria
32+
- [ ] Test extracts function list from Rust/C extension: `SELECT name FROM pragma_function_list WHERE name LIKE 'crsql%' ORDER BY name`
33+
- [ ] Test extracts function list from Zig extension using same query.
34+
- [ ] Test extracts module list from both: `SELECT name FROM pragma_module_list WHERE name LIKE 'crsql%' OR name = 'clset' ORDER BY name`
35+
- [ ] Test fails if Rust/C has functions/modules not present in Zig.
36+
- [ ] Test documents which functions are intentionally excluded (if any) with rationale.
37+
- [ ] Functions to verify include (at minimum):
38+
- `crsql_as_crr`, `crsql_as_table`
39+
- `crsql_begin_alter`, `crsql_commit_alter`
40+
- `crsql_changes`, `crsql_tracked_peers`
41+
- `crsql_db_version`, `crsql_next_db_version`
42+
- `crsql_site_id`, `crsql_siteid` (alias)
43+
- `crsql_finalize`
44+
- `crsql_fract_key_between`
45+
- `crsql_pack_columns`, `crsql_rows_impacted`
46+
- `crsql_automigrate` (if implemented)
47+
- `crsql_config_get`, `crsql_config_set` (if implemented)
48+
49+
## Progress Log
50+
### 2025-12-18
51+
- Task created from oracle-based parity test suite.
52+
53+
## Completion Notes
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
# TASK-090: Oracle Parity — Trigger/clock logic equivalence
2+
3+
## Status
4+
- [ ] Planned
5+
- [ ] Assigned
6+
- [ ] In Progress
7+
- [ ] Blocked (reason: ...)
8+
- [ ] Complete
9+
10+
## Priority
11+
high
12+
13+
## Assigned To
14+
(unassigned)
15+
16+
## Parent Docs / Cross-links
17+
- Rust trigger gen: `core/rs/core/src/trigger_fns.rs`
18+
- Zig trigger gen: `zig/src/triggers.zig`
19+
- Clock table logic: `zig/src/changes_vtab_read.zig`
20+
- Gap backlog: `research/zig-cr/92-gap-backlog.md`
21+
22+
## Description
23+
Verify that INSERT/UPDATE/DELETE triggers produce identical `__crsql_clock` entries in both implementations.
24+
25+
This is an **oracle test**: Given the same sequence of DML operations on identical schemas, the resulting clock table contents must match exactly (col_version, db_version, seq values).
26+
27+
## Files to Modify
28+
- `zig/harness/test-trigger-parity.sh` (new)
29+
- `zig/harness/test-parity.sh` (wire into suite)
30+
- `research/zig-cr/92-gap-backlog.md`
31+
32+
## Acceptance Criteria
33+
- [ ] Test creates identical CRR table in both Rust/C and Zig DBs.
34+
- [ ] Test performs identical DML sequence:
35+
1. INSERT row
36+
2. UPDATE single column
37+
3. UPDATE multiple columns
38+
4. DELETE row
39+
5. Re-INSERT same PK (resurrection)
40+
- [ ] After each step, compare `__crsql_clock` contents:
41+
- `col_version` matches
42+
- `db_version` matches
43+
- `seq` matches
44+
- [ ] Test fails if any clock entry differs.
45+
- [ ] Test covers:
46+
- Single-column primary key
47+
- Compound primary key
48+
- Tables with nullable columns
49+
- Tables with DEFAULT values
50+
51+
## Progress Log
52+
### 2025-12-18
53+
- Task created from oracle-based parity test suite.
54+
55+
## Completion Notes
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
# TASK-091: Oracle Parity — Fractional index algorithm
2+
3+
## Status
4+
- [ ] Planned
5+
- [ ] Assigned
6+
- [ ] In Progress
7+
- [ ] Blocked (reason: ...)
8+
- [ ] Complete
9+
10+
## Priority
11+
medium
12+
13+
## Assigned To
14+
(unassigned)
15+
16+
## Parent Docs / Cross-links
17+
- Rust fract implementation: `core/rs/core/src/fractindex.rs`
18+
- Zig fract implementation: `zig/src/fract.zig`
19+
- Existing fract tests: `zig/harness/test-fract.sh`
20+
- Gap backlog: `research/zig-cr/92-gap-backlog.md`
21+
22+
## Description
23+
Verify that `crsql_fract_key_between(a, b)` produces identical output in both Rust/C and Zig for the same inputs.
24+
25+
This is an **oracle test**: The fractional index algorithm must be deterministic and produce the same lexicographically-sortable string in both implementations.
26+
27+
## Files to Modify
28+
- `zig/harness/test-fract-parity.sh` (new or extend `test-fract.sh`)
29+
- `zig/harness/test-parity.sh` (wire into suite)
30+
- `research/zig-cr/92-gap-backlog.md`
31+
32+
## Acceptance Criteria
33+
- [ ] Test calls `crsql_fract_key_between(a, b)` with identical inputs on both implementations.
34+
- [ ] Test cases include:
35+
- `(NULL, NULL)` — first key
36+
- `('a', NULL)` — key after 'a'
37+
- `(NULL, 'z')` — key before 'z'
38+
- `('a', 'b')` — key between 'a' and 'b'
39+
- `('aaa', 'aab')` — key between close values
40+
- `('', 'a')` — edge case with empty string
41+
- Long strings (100+ chars) to test truncation/overflow behavior
42+
- [ ] Outputs are **byte-identical** (not just semantically equivalent).
43+
- [ ] Test fails if any output differs.
44+
- [ ] Results maintain lexicographic ordering: `a < result < b` when both are non-NULL.
45+
46+
## Progress Log
47+
### 2025-12-18
48+
- Task created from oracle-based parity test suite.
49+
50+
## Completion Notes
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
# TASK-092: Oracle Parity — db_version advancement timing
2+
3+
## Status
4+
- [ ] Planned
5+
- [ ] Assigned
6+
- [ ] In Progress
7+
- [ ] Blocked (reason: ...)
8+
- [ ] Complete
9+
10+
## Priority
11+
high
12+
13+
## Assigned To
14+
(unassigned)
15+
16+
## Parent Docs / Cross-links
17+
- Rust db_version logic: `core/rs/core/src/db_version.rs`
18+
- Zig db_version logic: `zig/src/crsqlite.zig` (crsql_db_version, crsql_next_db_version)
19+
- Gap backlog: `research/zig-cr/92-gap-backlog.md`
20+
21+
## Description
22+
Verify that `crsql_db_version()` and `crsql_next_db_version()` increment at exactly the same moments in both implementations.
23+
24+
This is an **oracle test**: The db_version is critical for sync protocols. If Zig and Rust/C increment it at different times (e.g., per-statement vs per-transaction), sync will break.
25+
26+
## Files to Modify
27+
- `zig/harness/test-db-version-parity.sh` (new)
28+
- `zig/harness/test-parity.sh` (wire into suite)
29+
- `research/zig-cr/92-gap-backlog.md`
30+
31+
## Acceptance Criteria
32+
- [ ] Test performs identical operations in both implementations and records db_version after each.
33+
- [ ] Operations tested:
34+
1. Initial state (should be 0 or 1)
35+
2. Single INSERT → record db_version
36+
3. Single UPDATE → record db_version
37+
4. Multiple INSERTs in one transaction → record db_version at COMMIT
38+
5. DELETE → record db_version
39+
6. No-op UPDATE (same value) → db_version should NOT change
40+
7. Merge from remote (crsql_changes INSERT) → record db_version
41+
- [ ] All db_version values match exactly between implementations.
42+
- [ ] `crsql_next_db_version()` returns `db_version + 1` in both.
43+
- [ ] Test fails if any db_version diverges.
44+
45+
## Progress Log
46+
### 2025-12-18
47+
- Task created from oracle-based parity test suite.
48+
49+
## Completion Notes
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
# TASK-093: Oracle Parity — rows_impacted counter reset timing
2+
3+
## Status
4+
- [ ] Planned
5+
- [ ] Assigned
6+
- [ ] In Progress
7+
- [ ] Blocked (reason: ...)
8+
- [ ] Complete
9+
10+
## Priority
11+
medium
12+
13+
## Assigned To
14+
(unassigned)
15+
16+
## Parent Docs / Cross-links
17+
- Rust rows_impacted: `core/rs/core/src/rows_impacted.rs`
18+
- Zig rows_impacted: `zig/src/crsqlite.zig`
19+
- Existing tests: `zig/harness/test-rows-impacted.sh`
20+
- Gap backlog: `research/zig-cr/92-gap-backlog.md`
21+
22+
## Description
23+
Verify that `crsql_rows_impacted()` resets at the same moments in both implementations.
24+
25+
This is an **oracle test**: The counter reset timing matters for sync clients that batch changes. If Zig resets on COMMIT but Rust/C resets on statement completion (or vice versa), clients will get wrong counts.
26+
27+
## Files to Modify
28+
- `zig/harness/test-rows-impacted-parity.sh` (new or extend existing)
29+
- `zig/harness/test-parity.sh` (wire into suite)
30+
- `research/zig-cr/92-gap-backlog.md`
31+
32+
## Acceptance Criteria
33+
- [ ] Test performs identical merge sequences and checks `crsql_rows_impacted()` at each checkpoint.
34+
- [ ] Scenarios tested:
35+
1. Insert one change via `crsql_changes` → check count (should be 1)
36+
2. Insert two more changes → check count (should be 3 total, or 2 if reset after first)
37+
3. COMMIT transaction → check count (should be 0 after reset, or preserved)
38+
4. New transaction, insert change → check count
39+
5. ROLLBACK transaction → check count behavior
40+
- [ ] Counter values match exactly between implementations at each checkpoint.
41+
- [ ] Document the expected reset semantics (per-statement, per-transaction, or manual).
42+
- [ ] Test fails if any counter value diverges.
43+
44+
## Progress Log
45+
### 2025-12-18
46+
- Task created from oracle-based parity test suite.
47+
48+
## Completion Notes
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
# TASK-094: Oracle Parity — ALTER TABLE preserves clock history
2+
3+
## Status
4+
- [ ] Planned
5+
- [ ] Assigned
6+
- [ ] In Progress
7+
- [ ] Blocked (reason: ...)
8+
- [ ] Complete
9+
10+
## Priority
11+
high
12+
13+
## Assigned To
14+
(unassigned)
15+
16+
## Parent Docs / Cross-links
17+
- Rust alter logic: `core/rs/core/src/alter.rs`
18+
- Zig alter logic: `zig/src/schema_alter.zig`
19+
- Existing alter tests: `zig/harness/test-alter.sh`
20+
- Gap backlog: `research/zig-cr/92-gap-backlog.md`
21+
22+
## Description
23+
Verify that `crsql_begin_alter` / `crsql_commit_alter` preserves existing clock history and correctly backfills new columns.
24+
25+
This is an **oracle test**: Schema evolution is critical for long-lived databases. If Zig loses clock history during ALTER or fails to backfill new columns, data will be lost or sync will break.
26+
27+
## Files to Modify
28+
- `zig/harness/test-alter-parity.sh` (new or extend `test-alter.sh`)
29+
- `zig/harness/test-parity.sh` (wire into suite)
30+
- `research/zig-cr/92-gap-backlog.md`
31+
32+
## Acceptance Criteria
33+
- [ ] Test creates CRR table, inserts data, records clock state.
34+
- [ ] Test performs ALTER operations via `crsql_begin_alter`/`crsql_commit_alter`:
35+
1. ADD COLUMN (nullable)
36+
2. ADD COLUMN with DEFAULT
37+
3. DROP COLUMN
38+
4. ADD INDEX
39+
5. DROP INDEX
40+
- [ ] After each ALTER:
41+
- Existing clock entries are preserved (same col_version, db_version for unchanged columns)
42+
- New columns have clock entries backfilled (col_version = 1, current db_version)
43+
- Dropped columns have clock entries removed
44+
- [ ] Clock state matches exactly between implementations.
45+
- [ ] Test covers edge cases:
46+
- ALTER on empty table
47+
- ALTER on table with 1000+ rows (batching behavior)
48+
- Multiple ALTERs in sequence
49+
- ALTER that adds column then immediately updates it
50+
- [ ] Test fails if clock history diverges.
51+
52+
## Progress Log
53+
### 2025-12-18
54+
- Task created from oracle-based parity test suite.
55+
56+
## Completion Notes

research/zig-cr/92-gap-backlog.md

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# 92-gap-backlog
22

3-
> Last updated: 2025-12-18 (new test-gap backlog)
3+
> Last updated: 2025-12-18 (added oracle-based parity tests TASK-089 through TASK-094)
44
55
## Status
66

@@ -34,6 +34,14 @@ Missing-feature RGRTDD tracks (spec then impl):
3434
- [ ] **TASK-087** — Spec merge atomicity for batch apply → `.tasks/backlog/TASK-087-spec-merge-atomicity.md`
3535
- [ ] **TASK-088** — Implement savepoint-backed merge atomicity → `.tasks/backlog/TASK-088-impl-merge-atomicity.md`
3636

37+
Oracle-based parity tests (Rust/C as golden master):
38+
- [ ] **TASK-089** — API surface completeness: pragma_function_list/module_list comparison → `.tasks/backlog/TASK-089-api-surface-completeness.md`
39+
- [ ] **TASK-090** — Trigger/clock logic equivalence: col_version/db_version/seq match → `.tasks/backlog/TASK-090-trigger-clock-logic-equivalence.md`
40+
- [ ] **TASK-091** — Fract index algorithm parity: crsql_fract_key_between output match → `.tasks/backlog/TASK-091-fract-index-algorithm-parity.md`
41+
- [ ] **TASK-092** — db_version advancement parity: version increments at same moments → `.tasks/backlog/TASK-092-db-version-advancement-parity.md`
42+
- [ ] **TASK-093** — rows_impacted counter timing: reset timing match → `.tasks/backlog/TASK-093-rows-impacted-counter-timing.md`
43+
- [ ] **TASK-094** — ALTER TABLE history preservation: clock history + backfill match → `.tasks/backlog/TASK-094-alter-table-history-preservation.md`
44+
3745
## Context / Evidence
3846

3947
- C reference runner lists suites in `core/src/tests.c`:

0 commit comments

Comments
 (0)