Make Swift and Rust peer implementation lanes - #15
Conversation
The Rust crate arrived as crates/ beside the Swift Sources/, which read as a primary implementation with an attachment. It is not one: the two lanes implement the same session-reading semantics for different hosts, and neither is generated from the other. Sources/ and Tests/ move to implementations/swift/, crates/ moves to implementations/rust/. Both manifests stay at the repository root and reach in with explicit paths, so no consumer of either language changes anything. Peers that are not generated from each other need somewhere to agree, so contracts/ arrives with the first fact that qualifies: the session index DDL and its user_version, which until now existed only inside the Swift writer while the Rust reader asserted a matching number by hand. Each lane now has a test that reads that file -- Swift checks it creates exactly those objects, Rust builds a database from it and opens it -- so a schema change on one side alone fails CI instead of silently diverging. The move also caught a real break: AgentSessionKitInfoTests walked three directories up from #filePath to find CHANGELOG.md, which is five now. It had been failing as an XCTest case while the swift-testing summary line still said everything passed. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 8bbef3314a
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
Two findings from review, both real. release.yml read the version constant from Sources/AgentSessionKit/, which the move emptied. Tagging 0.7.0 would have failed at the version check -- the one job that must not break on the commit that renames things. RELEASING.md named the same stale path. The contract test compared only created object names, so a changed column type, constraint, index expression, FTS tokenizer, or trigger body passed while the two lanes silently disagreed. It now compares whole normalised CREATE statements; only whitespace and IF NOT EXISTS are normalised away, since those differ between a file run once and a writer that re-runs on every open. Verified by flipping the FTS tokenizer in the contract alone: the old comparison missed it, this one fails. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 285098c280
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| echo "Tag: ${TAG}" | ||
|
|
||
| INFO="Sources/AgentSessionKit/AgentSessionKitInfo.swift" | ||
| INFO="implementations/swift/Sources/AgentSessionKit/AgentSessionKitInfo.swift" |
There was a problem hiding this comment.
Verify the Rust crate version before publishing
When a later shared release updates the Swift constant and changelog but accidentally leaves the Rust manifest behind, this job still publishes because it validates only AgentSessionKitInfo.version and runs only Swift commands. Rust consumers fetching that tag then receive a crate whose package version disagrees with the release, so the release check should also compare implementations/rust/crates/agent-session-core/Cargo.toml with TAG before publishing.
AGENTS.md reference: AGENTS.md:L74-L79
Useful? React with 👍 / 👎.
| searchable index, and a local MCP transport. | ||
|
|
||
| No third-party dependencies. Foundation, Darwin, and the system SQLite. | ||
| No third-party dependencies in either lane beyond the system SQLite. |
There was a problem hiding this comment.
Correct the dependency-free claim
This claim is false for the newly documented Rust lane: its manifest depends on rusqlite, serde, serde_json, and thiserror, while rusqlite enables bundled SQLite rather than using only the system library. This can mislead consumers assessing binary size, licensing, or supply-chain exposure; scope the statement to Swift or document the Rust dependencies accurately.
Useful? React with 👍 / 👎.
Summary
The Rust crate landed as
crates/beside the SwiftSources/, which reads as a primary implementation with an attachment. It is not one — the two lanes implement the same session-reading semantics for different hosts, and neither is generated from the other. This makes the layout say that.No consumer changes anything. Both manifests stay at the repository root and reach into
implementations/with explicit paths, so the git URL, theexact:pin,import AgentSessionKit, and both product names are unaffected. Verified against the two dependents (vibe-bar,auspex). The one real move is for anyone depending on the Rust crate by path rather than by git:crates/→implementations/rust/crates/.contracts/
Peers that are not generated from each other need somewhere to agree. The first fact that qualifies is the session index schema, which until now lived only inside the Swift writer while the Rust reader asserted a matching version number by hand — exactly the shape that drifts silently.
contracts/storage/session-index-v5.sqlis now the canonical DDL, and each lane has a test that reads it:SessionIndexContractTests(Swift) — the writer creates exactly the objects the contract names, compared as sorted object names so formatting differences do not fail the build but a real addition or removal does.index::contract_tests(Rust) — builds a database straight from the file, opens it with the reader, and checks the enforceduser_versionequals the one the contract declares.Verified by deliberately adding a table to the contract: Swift fails, revert makes it pass.
I did not create the empty
schemas/,fixtures/,vectors/, ortools/directories from the sketch, or a secondagent-session-contractcrate. There is nothing to put in them yet, and an empty abstraction is the thing this change is trying to remove.A real break the move caught
AgentSessionKitInfoTestsresolved the repository root by walking three directories up from#filePath; it is five now. It had been failing as an XCTest case while the swift-testing summary still reported everything green — worth knowing independently of this refactor.Version
0.7.0 — structural change plus the new contract lane.
AgentSessionKitInfo.versionand the Rust crate version both track it, asAgentSessionKitInfoTestsrequires.Test plan
swift test: 618 swift-testing + all XCTest cases green, including the two new contract tests.cargo test --workspace: 73 green (71 + 2 new contract tests).cargo clippy --workspace --all-targets -- -D warningsandcargo fmt --check: clean.contracts/, so a contract change runs both.🤖 Generated with Claude Code