Skip to content

migrate-embedded-sqlite-to-pure-go-modernc - #786

Merged
jeffreyaven merged 9 commits into
mainfrom
feat/gosqlite-migration
Sep 21, 2026
Merged

jeffreyaven merged 9 commits into
mainfrom
feat/gosqlite-migration

Conversation

@jeffreyaven

Copy link
Copy Markdown
Member

Description

Migrates the embedded SQLite backend from cgo to pure Go. The embedded
relational engine now uses modernc.org/sqlite v1.59.0 (SQLite 3.53.4),
consumed via any-sdk v0.5.6-alpha01-pure-go-sqlite-migration ->
v0.5.6-alpha02-pure-go-sqlite-migration, which owns the driver seam
(public/sqlengine, driver name stackql-sqlite) and the six StackQL
extension functions ported to pure Go (public/sqlfuncs: split_part,
regexp_like, regexp_substr, regexp_replace, json_equal,
aws_policy_equal). All builds are CGO_ENABLED=0; the
stackql-go-sqlite3 cgo fork, its go.mod replace directive, the
sqlite_stackql build tag, and all C toolchain CI steps are removed.

History. The original work order halted on a stop condition (the driver
seam lives in any-sdk, not this repo - see the first revision of this PR
description). The migration was executed upstream (any-sdk PR #144, defect
fixes in PR #145), then resumed here against the released alpha tags. The
robot suite surfaced three real behavior differences on first run; all
three were root-caused and resolved:

Finding Description Resolution
A aws_policy_equal missing two fork-only behaviors (Tags unordered; top-level array-vs-array unordered) - the cgo fork had drifted from sqlite-ext-functions, the port's source Fixed upstream (any-sdk #145, alpha02); golden vectors added upstream
B Declared-boolean columns rendered 0/1 (modernc lacks mattn's decltype bool conversion) Fixed upstream (any-sdk #145, alpha02): engine-layer mattn-parity conversion; the 3 boolean fixtures untouched
C sqlite_version() 3.45.1 -> 3.53.4 Fixture pinned to 3.53.4 (exact-match comparison; pattern matching not supported by the fixture format) - the ONLY fixture modified in this PR

Result: robot suite 651/651 PASS on
v0.5.6-alpha02-pure-go-sqlite-migration, zero tests skipped, weakened, or
deleted.

User-visible behavior changes (documented in any-sdk
public/sqlfuncs/DIVERGENCES.md, to be reflected in release notes):
regexp functions now use standard RE2 syntax (the retired tiny-regex-c
engine treated (, ), | as literals and silently failed on patterns
over ~30 nodes - groups, alternation, and inverted classes now work);
JSON parsing is strict RFC 8259 (trailing content and lax number forms
rejected); external loadable SQLite extensions (.load) are no longer
supported; library embedders inherit the modernc dependency tree.

Follow-up before release: bump go.mod to any-sdk v0.5.6-beta01 once
any-sdk feat/go-sqlite-migration is promoted to main and tagged.

Six commits in the three work-order groups: 8c36181, 2f1cb75,
e4d2d0a, 9085b5b, f811bd5, 6e87bbf (final commit deletes the
executed work order per burn order).

Type of change

  • Bug fix (non-breaking change to fix a bug).
  • Feature (non-breaking change to add functionality).
  • Breaking change. Please explain: regexp pattern metacharacters
    ( ) | are now interpreted (previously literal under the retired
    engine); strict JSON parsing rejects previously tolerated malformed
    input; .load-able extensions unsupported. All documented in any-sdk
    DIVERGENCES.md.

Issues referenced.

Resolves the unblocking request from this PR's original halt report via
any-sdk #144 and #145.

Evidence

  • Robot suite: 651/651 PASS locally against the exact consumed alpha02
    module; the 5 previously-failing tests (findings A/B/C) all green.
  • Function golden vectors, 7/7 fuzz targets (10s smoke, zero crashers),
    startup pragma assertions, concurrency stress, and timestamp round-trip
    all pass against alpha02 (upstream suites plus in-repo smoke).
  • go mod graph | grep "mattn/go-sqlite3" empty; repo-wide grep for
    mattn / stackql-go-sqlite3 / sqlite_stackql /
    SQLITE_ENABLE_STACKQL clean outside docs/changelog; internal/sqlfuncs
    removed (superseded by any-sdk public/sqlfuncs).
  • Every CI target confirmed CGO_ENABLED=0; C toolchain steps removed.
  • CodeQL 0 alerts; automated code review no comments.
  • Rollback anchors: v0.11.707-final-cgo (this repo, commit 7013bd6)
    and any-sdk's final cgo release.

Performance - cgo baseline from the last 10 successful build.yml
runs on main (runs 673-707, 2026-09-09 -> 2026-09-20). Migrated columns
pending maintainer approval of the gated workflow runs on this PR; red-flag
rule: >25% over median AND outside the baseline range on any platform.

Job (platform/arch) n Baseline median Baseline range Migrated Delta %
Linux Build (amd64) 10 8m25s 4m52s-10m27s pending CI approval -
Linux arm64 Build 10 29m08s 25m28s-29m57s pending CI approval -
MacOS Build (intel) 10 29m31s 21m16s-41m56s pending CI approval -
MacOS ARM Build 10 3m15s 1m17s-4m37s pending CI approval -
Windows Build 10 33m29s 28m42s-36m45s pending CI approval -
WSL Test 10 19m43s 16m58s-20m39s pending CI approval -
Linux Test (registry-mocked) 10 27m13s 21m32s-28m22s pending CI approval -
Linux Test (registry) 10 3m56s 3m12s-4m22s pending CI approval -
Docker Build (linux/amd64) 10 9m02s 6m37s-9m47s pending CI approval -
Docker Build (linux/arm64) 10 7m07s 6m54s-7m26s pending CI approval -
Docker Test (amd64, sqlite) 10 13m23s 12m06s-14m35s pending CI approval -
Docker Test (amd64, postgres_tcp) 10 36m40s 30m58s-37m13s pending CI approval -
Docker Test (arm64, sqlite) 10 2m49s 2m41s-3m21s pending CI approval -
Docker Test (arm64, postgres_tcp) 10 2m50s 2m38s-2m59s pending CI approval -

Checklist:

  • A full round of testing has been completed, and there are no test
    failures as a result of these changes. (Local; cross-platform CI pending
    run approval.)
  • The changes are covered with functional and/or integration robot
    testing.
  • The changes work on all supported platforms. (Pending approval of the
    gated CI runs on this PR.)
  • Unit tests pass locally, as per the developer guide.
  • Robot tests pass locally, as per the developer guide (651/651).
  • Linter passes locally, as per the developer guide.

Variations

The only test fixture modified is the sqlite_version pin (finding C).
The three declared-boolean fixtures are deliberately untouched: rendering
parity is preserved upstream (finding B).

Tech Debt

Retired in this change set: the stackql-go-sqlite3 fork dependency and its
replace directive, the sqlite-ext-functions C build coupling, the
sqlite_stackql build tag, and the cgo cross-compile toolchain matrix.
Remaining (tracked outside this PR): archive stackql-go-sqlite3 and
sqlite-ext-functions post-merge; bump to any-sdk v0.5.6-beta01;
omni-sdk adopts the same backend later.

jeffreyaven and others added 3 commits September 21, 2026 05:17
* docs(sqlfuncs): mirror CLAUDE.md as AGENTS.md for all agent sessions

Co-authored-by: jeffreyaven <5146499+jeffreyaven@users.noreply.github.com>

* deps: adopt any-sdk pure-Go sqlite backend, drop mattn/cgo fork replace

Co-authored-by: jeffreyaven <5146499+jeffreyaven@users.noreply.github.com>

* ci: retire cgo - CGO_ENABLED=0, drop C toolchains and sqlite_stackql tag, add per-artifact function smoke

Co-authored-by: jeffreyaven <5146499+jeffreyaven@users.noreply.github.com>

* docs+test: modernc backend invariants, release notes draft, robot ext-function smoke scenario

Co-authored-by: jeffreyaven <5146499+jeffreyaven@users.noreply.github.com>

* deps: bump any-sdk to alpha02 (aws_policy_equal tags parity, boolean decltype); pin sqlite_version fixture to 3.53.4

Co-authored-by: jeffreyaven <5146499+jeffreyaven@users.noreply.github.com>

* burn: remove executed migration work order

Co-authored-by: jeffreyaven <5146499+jeffreyaven@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: jeffreyaven <5146499+jeffreyaven@users.noreply.github.com>
* retire remaining cgo configuration and stale migration artifacts

Co-authored-by: jeffreyaven <5146499+jeffreyaven@users.noreply.github.com>

* preserve migration smoke-test documentation

Co-authored-by: jeffreyaven <5146499+jeffreyaven@users.noreply.github.com>

---------

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: jeffreyaven <5146499+jeffreyaven@users.noreply.github.com>
@jeffreyaven jeffreyaven self-assigned this Sep 21, 2026
Co-authored-by: jeffreyaven <5146499+jeffreyaven@users.noreply.github.com>
@jeffreyaven
jeffreyaven added this pull request to stack #789 September 21, 2026 04:25
Co-authored-by: jeffreyaven <5146499+jeffreyaven@users.noreply.github.com>

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

filename should not have spaces ideally please change to stackql_release_process.md

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Renamed to docs/stackql_release_process.md in 625b20a.

Also updated the three references to the old name so nothing is left dangling: the header comments in mcp-packaging.yml and mcp-registry-publish.yml, and packaging/mcpb/CLAUDE.md.

Comment thread .github/workflows/build.yml Outdated

build\stackql.exe --help

- name: Extension function smoke test

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Move this to robot

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done in 27f1c4d. The step is removed; the check is the robot scenario Sqlite Extension Functions Smoke Working in stackql_mocked_from_cmd_line.robot, which this job already runs via build.py --robot-test.

The scenario previously used a weaker aws_policy_equal comparison than this step did, so I moved the step's arguments (Version plus scalar-vs-array Resource) into the scenario so nothing is lost in the move. I ran the scenario's exact SQL against a CGO_ENABLED=0 build of this branch and the output matches the expected table.

Comment thread .github/workflows/build.yml Outdated
Write-Host $execOut
if ($execOut -notmatch 'StackQL') { throw "exec did not return 'StackQL'" }

# Extension function smoke: proves the pure Go sqlite function registration

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

move this to robot

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed in 27f1c4d, with one thing to flag.

This job has no robot harness: no checkout and no Python, it only downloads the amd64 exe from winbuild and runs it under x64 emulation. So after this change the extension functions are no longer exercised under emulation. The same binary is covered by the robot scenario in winbuild.

If you want emulation coverage kept, the options are wiring a minimal robot run into this job, or keeping a workflow-level check in this job only. Let me know which you prefer and I will add it.

I also dropped the stale "cgo" wording from the comment just above, since this PR makes it incorrect.

Comment thread .github/workflows/build.yml Outdated
run: |
python cicd/python/build.py --verbose --build-mcp-client

- name: Extension function smoke test

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

move this to robot

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed in 27f1c4d. linuxbuild does not run robot itself, but linuxtest needs it and runs the functional suite against this job's artifact, so the robot scenario Sqlite Extension Functions Smoke Working covers the linux amd64 binary there.

Comment thread .github/workflows/build.yml Outdated
run: |
python cicd/python/build.py --verbose --build-mcp-client

- name: Extension function smoke test

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

move this to robot

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed in 27f1c4d. This job runs the functional suite in-job, so the robot scenario Sqlite Extension Functions Smoke Working covers the native linux arm64 binary.

Comment thread .github/workflows/build.yml Outdated
python cicd/python/build.py --verbose --build
python cicd/python/build.py --verbose --build-mcp-client

- name: Extension function smoke test

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

move this to robot

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed in 27f1c4d. This job runs the functional suite in-job, so the robot scenario Sqlite Extension Functions Smoke Working covers the darwin intel binary.

Comment thread .github/workflows/build.yml Outdated
python cicd/python/build.py --verbose --build
python cicd/python/build.py --verbose --build-mcp-client

- name: Extension function smoke test

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

move this to robot

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed in 27f1c4d, with the same flag as on the winarmsmoke thread.

This job builds and uploads the darwin arm64 binary but does not run robot, so after this change the extension functions are not exercised on darwin arm64. macOS coverage comes from macosbuild (intel).

Adding a full robot run here would take this job from roughly 3 minutes to something like the 30 minutes of the intel job, so I have not done that unprompted. Let me know if you want it.

db_backend:
- sqlite
- postgres_tcp
include:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This requires an assertion, at the conclusion of all shards, that every single test is run on each db and platform. Failure to verify both the total count and the presence of any expected line item must fail

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added in c645a2b as a new dockertestverify job. It needs dockertest, so it runs once every shard has concluded. dockermerge now needs it as well, so an image cannot be pushed past a failed verification.

How it works:

  • Every robot-running dockertest leg uploads its output.xml. The unsharded sqlite leg uploads as shard 1 of 1, so both db backends go through the same check.
  • The verifier lives in robot_shard.py next to the shard modifier. It parses test/robot/functional with no modifier applied to get the expected tests, then compares that as a multiset against the union of the shard reports for each (platform, db) group. The total count and each line item are checked independently.
  • Failure to verify fails the job: an absent shard, an absent output.xml, inconsistent shard counts, a NOT RUN test, an expected group with no reports, or reports from a group that is not in the expected list. That last one means a new robot-running leg cannot be added without also being verified.

Testing: run locally against real output.xml files produced by dry-run shards (146 + 159 + 170 + 176 = 651, matching the unsharded 651). 13 mutated cases all exit 1. One of them renames a test so the count is still 651 but a line item is wrong, which shows the two checks are independent. actionlint 1.6.23 with shellcheck passes.

Scoping notes:

  • The linux/arm64 docker leg is not an expected group because it has never run the robot suite. The matrix.platform == 'linux/amd64' condition is on main and predates this PR. Native linux arm64 robot coverage is in linuxarmbuild.
  • Only the docker postgres leg is sharded. The other platforms run the suite unsharded through build.py --robot-test with no modifier, so there is nothing to reassemble there.
  • The job skips verification under the same conditions where dockertest skips robot (fork and Dependabot PRs, build-elide refs, express tags). That condition is duplicated rather than shared. If the two drift, this job expects reports that do not exist and fails, which is the safe direction.

This has not run in CI yet. The artifact upload and download directory layout is the one part I could not exercise locally, so the first run on this push is the real test of it.

jeffreyaven and others added 4 commits September 21, 2026 18:42
Rename `docs/stackql release process.md` to
`docs/stackql_release_process.md` per review, and update the three
references to it (two workflow header comments and the mcpb packaging
notes) so nothing points at the old name.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Remove the six workflow-level extension function smoke steps from
build.yml per review. The check lives in the robot scenario
`Sqlite Extension Functions Smoke Working`, which now carries the
stronger aws_policy_equal comparison the workflow steps used (Version
plus scalar-vs-array Resource), so nothing is lost in the move.

The scenario runs wherever the functional suite runs: winbuild,
linuxtest, linuxarmbuild, macosbuild, wsltest and the docker sqlite leg.
winarmsmoke and macosarmbuild have no robot harness, so the check is no
longer exercised in those two jobs.

Also drop the stale "cgo" wording from the winarmsmoke comment.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Sharding splits one robot run across several dockertest legs, so no
single leg can attest that the whole suite ran. Add a dockertestverify
job that runs once all legs conclude and fails unless, for each
(platform, db backend) group, the shards together account for every
functional test exactly once.

- Each robot-running dockertest leg uploads its output.xml; unsharded
  legs upload as shard 1 of 1.
- robot_shard.py gains a verifier. The expected tests are parsed from
  test/robot/functional with no shard modifier applied, then compared
  as a multiset against the union of the shard reports, so the total
  count and each individual test are checked independently.
- Anything that prevents verification fails it: absent shard, absent
  output.xml, inconsistent shard counts, a NOT RUN test, an expected
  group with no reports, or reports from a group that is not listed.
- dockermerge now needs dockertestverify, so an image cannot be pushed
  past a failed verification.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Per review: now that GitHub hosts arm64 macOS and Windows runners, run
the robot functional suite on both rather than leaving the extension
function check unexercised there.

- macosarmbuild: mirror the macosbuild robot harness (libpq, python
  deps, registry rewrite, certificates, robot run, report upload). The
  libpq path is resolved with `brew --prefix` because homebrew's prefix
  differs on Apple Silicon.
- winarmsmoke: mirror the winbuild robot harness against the amd64
  binary under x64 emulation. Python is x64 because psycopg2-binary,
  psycopg-binary and cryptography publish no win_arm64 wheels. The job
  now checks out the repo (before the artifact downloads, since checkout
  cleans the workspace) and moves from the short to the standard job
  timeout.
- winbuild: upload the MCP client as an artifact so the MCP scenarios
  run in winarmsmoke rather than being skipped.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@jeffreyaven
jeffreyaven merged commit b56c507 into main Sep 21, 2026
57 checks passed
@jeffreyaven
jeffreyaven deleted the feat/gosqlite-migration branch September 21, 2026 10:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants