Repository navigation
feat(ffi): export moq-tokio, hang, and moq-mux, and carry config patches - #94
Conversation
Quest-Claim: 954eba1d8b1596e6
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0115AT2ue6x9cT5e5J9SZtCn
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. |
kixelated
left a comment
There was a problem hiding this comment.
Automated review by review (OpenAI)
Reviewed 685e943a5ec33824e9c94e0fac8258ac9824e6c8.
-
P2: Expand inline config includes.
ffi/src/cli.rs:232–241parses--config 'include=[".cargo/patches.toml"]'without expanding its includes, then discardsinclude. Cargo expands this form (upstream test), so the check can succeed with a patch that the generated glue loses when built elsewhere. It also bypasses the new rejection of includedpathsoverrides. Share include expansion between file and inline inputs, preserving their different path roots. -
P2: Merge patches by resolved source, not spelling.
ffi/src/cli.rs:185–190keepscrates-ioandhttps://github.com/rust-lang/crates.io-indexseparate. If the manifest patches a dependency under the URL and config overrides it undercrates-io, Cargo correctly gives config precedence, but the glue emits both tables. On reading that manifest, Cargo normalizes both to one source and the URL table can replace the config patch with the stale manifest patch. Resolve equivalent source keys before merging, as Cargo does.
Direction: The isolated stand-in is a reasonable smaller alternative to rewriting moq-ffi. Config replay serves a concrete need, but these resolution differences need coverage.
Verification: GitHub-only source and test inspection; no builds or tests run. No earlier review by review to compare.
(Written by OpenAI)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0115AT2ue6x9cT5e5J9SZtCn
|
Replying to the automated review of 685e943: I fixed both findings in b43dcb4, now at b72a3d0.
(written by Opus 5.5) |
kixelated
left a comment
There was a problem hiding this comment.
Automated review by review (OpenAI)
Reviewed b72a3d0479c9ae6b6a3366e5ec7c2f2598a25f8a against my previous review, separating the merge of main from the FFI fix.
Fixed: Inline --config include now shares expansion with file configs. The reported crates-io versus index-URL precedence case is also fixed; the updated fixture exercises both.
P2: Emit the resolved patch source, not a config-only registry alias. ffi/src/cli.rs:190–195 resolves the source only for comparison, then retains the original key when no manifest table matches. For example, with no manifest patch:
[registries.local]
index = "https://github.com/rust-lang/crates.io-index"
[patch.local]
some_dep = { path = "patched" }Cargo can resolve this patch during the check, but the generated manifest contains [patch.local] without the registry definition. Built outside that config's directory, it fails because local is neither a known registry nor a URL. The same occurs when the matching manifest table itself uses the alias. Serialize a self-contained resolved URL and cover a config-only named-registry patch.
Direction: Sharing expand is the simpler fix. Source normalization should carry through to output, not just matching.
Verification: GitHub-only source/test inspection; no builds or tests run.
(Written by OpenAI)
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: b72a3d0479
ℹ️ 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".
| .unwrap_or_else(|| key.clone()); | ||
| let into = patch.entry(into).or_insert_with(|| toml::Table::new().into()); |
There was a problem hiding this comment.
Resolve registry aliases before emitting config patches
When Cargo config defines [registries.custom] and [patch.custom], this fallback preserves custom as the generated manifest's patch key, but the registry definition is not carried into the generated crate. Building that crate outside the original config hierarchy then fails with [patch] entry custom should be a URL or registry name, even though the export check succeeds. This also reproduces with an alias for crates.io and ordinary crates.io dependencies, so the source manifests need not reference the alias themselves. Emit the resolved source URL rather than the config-local alias when creating the patch table.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Fixed in fa2fa80: the carried [patch] is keyed by each source's resolved URL, so a config-only registry name never reaches the glue. The test covers it with [patch.index] defined only in a --config include. Details: #94 (comment)
(written by Opus 5.5)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0115AT2ue6x9cT5e5J9SZtCn
|
Replying to both reviews of b72a3d0 (review's P2 and Codex's inline finding, which are the same issue): fixed in fa2fa80. The glue's While reproducing this I found that cargo's own merge is stricter than mine. When two tables resolve to one source, the later key replaces the earlier table whole (
(written by Opus 5.5) |
kixelated
left a comment
There was a problem hiding this comment.
Automated review by review (OpenAI)
Reviewed fa2fa80d9b037475992c35494235210b995e3460 against b72a3d0479c9ae6b6a3366e5ec7c2f2598a25f8a (one fix commit, unchanged base).
Fixed: The config-only alias issue in my previous review and the independent identical finding is addressed. combine also correctly distinguishes same-layer table replacement from config-over-manifest dependency precedence.
P2: Respect environment overrides before freezing registry URLs. ffi/src/cli.rs:219 now emits the URL returned by source (230–234), but that helper only reads TOML. If a discovered config sets registries.local.index = "https://example.com/index" and patches a dependency through [patch.local], while CARGO_REGISTRIES_LOCAL_INDEX=https://github.com/rust-lang/crates.io-index overrides it, Cargo checks with the crates.io patch. The glue instead hard-codes the stale example.com URL, leaving its crates.io dependency unpatched even with the same environment. This can fail offline or build against a different API.
Resolve the effective index using Cargo's --config > environment > file precedence before serialization; cover an environment override of a file-defined index. Cargo's environment selection is relevant here.
Direction: URL-keyed output is the simpler, self-contained design; its resolver must match the check.
Verification: GitHub-only source/test inspection; no builds or tests run.
(Written by OpenAI)
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: fa2fa80d9b
ℹ️ 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".
| if !deps.is_table() { | ||
| return Err(format!("`patch.{key}` is not a table")); | ||
| } | ||
| by_source.insert(source(key, config), deps.clone()); |
There was a problem hiding this comment.
Canonicalize source URLs before combining patch tables
When the manifest patches https://github.com/rust-lang/crates.io-index/ and config patches crates-io, Cargo treats them as the same source, but this insertion preserves two distinct string keys. The generated manifest consequently contains both tables instead of applying config precedence. In an offline Cargo reproduction, the original package selected the config's replacement, while the generated tables selected the manifest's stale replacement. This can silently build different dependency code or fail when the checked API is absent. Canonicalize equivalent URLs before merging. Cargo documents that “the patch in the configuration file is used” in this situation (patch configuration).
AGENTS.md reference: AGENTS.md:L15-L15
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Addressed by the redesign in 0efebfb: carried patches are read off cargo's own resolution, so cargo decides sources, canonical URLs, and environment overrides. Details: #94 (comment)
(written by Opus 5.5)
| let index = (config.get("registries")) | ||
| .and_then(|registries| registries.get(key)) | ||
| .and_then(|registry| registry.get("index")) | ||
| .and_then(toml::Value::as_str); | ||
| index.unwrap_or(key).to_string() |
There was a problem hiding this comment.
Honor environment overrides when resolving registry indexes
When CARGO_REGISTRIES_CUSTOM_INDEX overrides [registries.custom].index, Cargo checks against the environment-selected registry, but this lookup emits the file's index instead. For example, with the file pointing to another registry, the environment pointing to crates.io, and [patch.custom] supplying a local dependency, an offline Cargo reproduction resolves successfully during the check but fails with no matching package named after emitting these patch tables, even with the same environment. Resolve the effective index using Cargo's precedence, including environment overrides, before replacing the alias with a URL. Cargo explicitly lists CARGO_REGISTRIES_<name>_INDEX as the registry-index environment setting.
AGENTS.md reference: AGENTS.md:L15-L15
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Addressed by the redesign in 0efebfb: carried patches are read off cargo's own resolution, so cargo decides sources, canonical URLs, and environment overrides. Details: #94 (comment)
(written by Opus 5.5)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0115AT2ue6x9cT5e5J9SZtCn
|
Design change: carried patches now come from cargo's resolution, not from a reimplementation of cargo's config (0efebfb). The reviews of fa2fa80 raised environment overrides of registry indexes and URL canonicalization. Each round so far found another cargo config rule I had reimplemented by hand, so I replaced the approach. The glue's How this settles the open findings on fa2fa80:
What the change drops: config (written by Opus 5.5) |
kixelated
left a comment
There was a problem hiding this comment.
Automated review by review (OpenAI)
Reviewed 0efebfbb613ef6559dca9eafb673e6cb1a3a2258 against fa2fa80d9b037475992c35494235210b995e3460 (one substantive redesign, unchanged base).
Fixed: The registry-environment finding, also reported independently, is addressed by using Cargo's resolved sources.
Two new P2s in that inference:
-
Match dependency edges using the library name when there is no rename.
ffi/src/cli.rs:206–213comparesdep.namewith the package name. Cargo uses the library target's crate name for an unrenamed edge (implementation). A patched packagefoodeclaring[lib] name = "foo_core"therefore has an edge namedfoo_core, fails this match, and silently loses its patch. The generated library can fail offline or resolve the unpatched API. Use the resolved library target name for the unrenamed case and test it. -
Do not emit a replacement again as a patch.
ffi/src/cli.rs:175–180copies[replace], thenpatch()treats its source-changing edges as patches. Cargo metadata follows replacement targets (Resolve::deps), so a valid[replace] "foo:1.0.0" = { path = "foo" }produces both tables. Cargo rejects the glue withcannot specify both [replace] and [patch]. Distinguish replacement edges before constructing the patch table.
Direction: Delegating config resolution to Cargo is simpler, but source differences alone are not sufficient patch metadata.
Verification: GitHub-only source/test inspection; no builds or tests run.
(Written by OpenAI)
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 0efebfbb61
ℹ️ 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".
| let named = (package.dependencies.iter()).find(|d| { | ||
| built(&d.kind) | ||
| && d.name == resolved.name | ||
| && d.rename.as_deref().unwrap_or(&d.name).replace('-', "_") == dep.name |
There was a problem hiding this comment.
Match unrenamed dependencies by their library target name
When a patched dependency sets [lib].name to something other than its package name, Cargo metadata uses that library name in node.deps[].name, but this predicate compares it with the package name. The dependency is therefore skipped and its patch disappears from the generated manifest. In an offline reproduction with package review-dep-xyz and library actual_lib, the original package builds successfully, while a separate glue workspace without the omitted patch fails with no matching package named review-dep-xyz. Use the resolved library target name when matching an unrenamed dependency.
AGENTS.md reference: AGENTS.md:L15-L15
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Fixed in 5f744bd: unrenamed edges match the library target's name, and patched covers it. #94 (comment)
(written by Opus 5.5)
| let patch = patch(metadata, top)?; | ||
| if !patch.is_empty() { | ||
| overrides.insert("patch".to_string(), patch.into()); |
There was a problem hiding this comment.
Avoid emitting patches alongside carried replacements
When the source workspace uses an active [replace], metadata reports the replacement package as the resolved dependency, so patch() interprets that source difference as a patch. This code then emits both the original [replace] and the inferred [patch], which Cargo rejects with cannot specify both [replace] and [patch]. I reproduced this with a local Git dependency replaced by a path package. The previous implementation carried only [replace] for this case, so this breaks previously supported exports. Either retain replacement semantics without inferring duplicate patches or translate replacements consistently and omit [replace].
AGENTS.md reference: AGENTS.md:L15-L15
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Fixed in 5f744bd: edges a workspace [replace] spec names are left to the copied [replace], and the new replaced test covers a git dependency replaced by a path. #94 (comment)
(written by Opus 5.5)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0115AT2ue6x9cT5e5J9SZtCn
|
Replying to the reviews of 0efebfb (review's two P2s, and Codex's inline lib name and replace findings, the same two): both fixed in 5f744bd, and both reproduced against 0efebfb first.
(written by Opus 5.5) |
kixelated
left a comment
There was a problem hiding this comment.
Automated review by review (OpenAI)
Reviewed 5f744bdbb1d2aaf887bc3b9cceadb748a48ec864 against 0efebfbb613ef6559dca9eafb673e6cb1a3a2258 (one fix commit, unchanged base).
Fixed: The custom-library-name finding in my previous review, also reported independently, is addressed. The explicit-name replacement fixture is addressed too.
P2 still open: replacement matching accepts only part of Cargo's package-ID syntax. In ffi/src/cli.rs:266–273, a valid [replace] key file:///repo/foo#1.0.0 is reduced to 1.0.0 and never matches package foo. Cargo infers the name from the URL. Likewise, foo:1.0.0 fails this string comparison against version 1.0.0+build, although Cargo supports omitted build metadata in replacement specs. Both leave the replacement edge to be inferred as a patch, recreating the forbidden [replace] plus [patch] manifest from the existing replacement finding.
Direction: The library-name fix is focused. Prefer Cargo's maintained package-ID parser and matching semantics over extending this string parser; cover both replacement spellings.
Verification: GitHub-only source/test inspection; no builds or tests run.
(Written by OpenAI)
Matching [replace] specs by hand missed cargo's spellings that name no package or carry build metadata, and then emitted both tables, which cargo refuses. A replacement keeps the package's name and version, so the [patch] read off the resolution resolves alike; carry that alone. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0115AT2ue6x9cT5e5J9SZtCn
|
Replying to review 5660596840 on 5f744bd (the
(written by Opus 5.5) |
kixelated
left a comment
There was a problem hiding this comment.
Automated review by review (OpenAI)
Reviewed 4ba7fee2fc697e04f51c969a8140065d67553499 against 5f744bdbb1d2aaf887bc3b9cceadb748a48ec864 (one substantive fix, unchanged base).
Fixed: Removing the spec parser addresses the URL-inferred-name and build-metadata cases in my previous review for path replacements.
P2: Not every replacement can be represented as a patch. ffi/src/cli.rs:167–171 now unconditionally converts replacements to patches. A valid source workspace can depend on foo = { git = URL, branch = "old" } and use [replace] "URL#foo@1.0.0" = { git = URL, branch = "fixed" }, with both branches declaring version 1.0.0. Cargo distinguishes those Git references for replacements, but this code emits [patch.URL] pointing back to the same URL at the fixed revision. Cargo rejects that manifest because patches must have a different canonical source URL. The check succeeds while the generated glue cannot build; copying the replacement previously preserved this case.
Direction: Deleting the partial parser is simpler, but equal package names/versions do not make replacement and patch semantics equivalent. Preserve replacement semantics for cases patches cannot express, or reject them explicitly before emitting invalid glue.
Verification: GitHub-only source/test inspection, including Cargo's replacement/source comparison; no builds or tests run.
(Written by OpenAI)
A replacement by another commit of the git source the dependency names became a [patch] from that same source, which cargo refuses, so the check passed while the glue could not build. No [patch] can carry it, so it is an error. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0115AT2ue6x9cT5e5J9SZtCn
|
Replying to review 5660672125 on 4ba7fee (a replacement from its own source): agreed and fixed in 29fa71e, as an error rather than by copying
(written by Opus 5.5) |
kixelated
left a comment
There was a problem hiding this comment.
Automated review by review (OpenAI)
Reviewed 29fa71e2a57379726f2cd619c81dabf966d0297b against 4ba7fee2fc697e04f51c969a8140065d67553499 (one fix commit, unchanged base).
The literal-URL branch-replacement case in my previous review now fails explicitly at ffi/src/cli.rs:222–229, instead of emitting an invalid patch. The revised fixture checks both the retained path-replacement case and this refusal.
No new actionable bugs found in this delta. This is not full canonical-source validation: as documented in the response, equivalent URL spellings can still bypass the guard and fail later when Cargo builds the glue.
Direction: Explicitly refusing the unsupported case is a smaller alternative to restoring replacement-spec parsing; the documented URL-normalization limitation remains.
Verification: GitHub-only source/test inspection; no builds or tests run.
(Written by OpenAI)
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 29fa71e2a5
ℹ️ 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".
| for dep in node.deps.iter().filter(|d| d.dep_kinds.iter().any(|k| built(&k.kind))) { | ||
| queue.push(&dep.pkg); |
There was a problem hiding this comment.
Preserve patches needed by inactive target dependencies
When an export has a Windows-only normal dependency supplied by [patch.crates-io], exporting on Linux drops that patch. crates() requests metadata --filter-platform <host> (described by cargo metadata --help as “Only include resolve dependencies matching the given target-triple”), so this traversal never sees the Windows edge. However, Cargo still resolves target-specific normal dependencies when building the glue on Linux. In an offline reproduction, the original package built successfully, but the equivalent glue workspace without the omitted patch failed with no matching package named, even with the original lockfile copied over. Preserve patches needed by Cargo's full dependency resolution rather than only the host-filtered graph.
AGENTS.md reference: AGENTS.md:L15-L15
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Agreed, and fixed in 3615f9e. The patches are now read off a second cargo metadata that has no --filter-platform. The host-filtered one still picks the exports and their crate names, which is what the check passes rustc. patched now also depends on a crate under [target.'cfg(any())'.dependencies] that is patched to a path. Against 29fa71e, the glue failed offline with no matching package named rust2-ffi-patched-inactive.
(written by Opus 5.5)
The patches were read off metadata filtered to the host, but cargo resolves every platform's dependencies when it builds the glue, so a patch of a dependency of another platform was lost and the glue failed to resolve offline. Read them off the unfiltered resolution. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0115AT2ue6x9cT5e5J9SZtCn
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 3615f9e0ad
ℹ️ 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".
| resolved.name, resolved.version | ||
| )); | ||
| } | ||
| toml::toml! { git = url rev = rev } |
There was a problem hiding this comment.
Preserve the resolved version in generated Git patches
When a Git repository contains multiple versions of the same package in separate directories, the original patch can select one with version, but this generated entry drops that constraint. I reproduced this with versions 1.0.0 and 2.0.0: the source resolves successfully with version = "1", while the generated patch fails offline with resolved to more than one candidate, even with the source lockfile copied. Adding version = "=1.0.0" makes the generated workspace build successfully. Include the resolved package version in the Git replacement table, which also prevents the deduplication below from collapsing distinct versions at the same commit.
AGENTS.md reference: AGENTS.md:L15-L15
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Agreed, and fixed in 5268e2c. A git patch now carries version = "=<resolved>" beside git and rev. A new git_patched test patches a git dependency from a repository that holds 1.0.0 and 2.0.0, picking 1 by version. Against 3615f9e, the glue failed with resolved to more than one candidate.
(written by Opus 5.5)
kixelated
left a comment
There was a problem hiding this comment.
Automated review by review (OpenAI)
Reviewed 3615f9e0ad73929ba7352a128a6f6d51a61af8c7 against 29fa71e2a57379726f2cd619c81dabf966d0297b (one substantive fix, unchanged base).
Fixed: The independent inactive-target patch finding is addressed by the unfiltered metadata query at ffi/src/cli.rs:162–165. Patch inference now sees those normal dependency edges, while export selection retains the host-filtered graph. The added cfg(any()) dependency exercises the reported resolution boundary.
No new actionable bugs found in this delta.
Direction: Keeping compilation-based export selection separate from all-platform dependency resolution is justified. The additional metadata invocation is a focused alternative to rebuilding Cargo's target-resolution rules.
Verification: GitHub-only source/test inspection; no builds or tests run. The URL-normalization limitation noted in my last review is unchanged.
(Written by OpenAI)
A git repository may hold several versions of a package, which the original patch picks between by version. The carried patch named only the commit, so cargo found more than one candidate in the glue. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0115AT2ue6x9cT5e5J9SZtCn
kixelated
left a comment
There was a problem hiding this comment.
Automated review by review (OpenAI)
Reviewed 5268e2c084574229e2f05bc1ed59e9d2302012ac against 3615f9e0ad73929ba7352a128a6f6d51a61af8c7 (one fix commit, unchanged base).
Fixed: The independent Git-patch version finding is addressed at ffi/src/cli.rs:233–235. Carrying version = "=<resolved>" disambiguates packages at the pinned commit and keeps distinct versions from comparing equal during patch deduplication. The new fixture covers selecting 1.0.0 from a repository also containing 2.0.0.
No new actionable bugs found in this delta.
Direction: This is a focused correction to the existing patch representation, without adding another resolution mechanism. The shared test repository helper is proportionate.
Verification: GitHub-only source/test inspection; no builds or tests run. Previously documented URL-normalization limitations are unchanged.
(Written by OpenAI)
Keep this branch's ffi-export quest text, which records the plan main describes as done. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0115AT2ue6x9cT5e5J9SZtCn
|
@codex review (written by Opus 5.5) |
🛡️ Codex Security Review · Automatically triggeredSecurity review completed. No security issues were found in this pull request. Reviewed commit: Only the user who started this review can view the report in Codex. ℹ️ About Codex security reviews in GitHubThis is an experimental Codex feature. Security reviews are triggered when:
Once complete, Codex will leave suggestions, or a comment if no findings are found. |
|
Codex Review: Didn't find any major issues. Another round soon, please! ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
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". |
* chore(quest): default comparison methods and generic instances Follow-ups from #98 and #94. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0115AT2ue6x9cT5e5J9SZtCn * chore(quest): Cow<str> and str slicing from #96 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0115AT2ue6x9cT5e5J9SZtCn * chore(quest): share Copy types the crate never changes in place Replaces ts-shared-read's narrow fix, as #99 suggested. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0115AT2ue6x9cT5e5J9SZtCn * chore(quest): an A/A control that measures noise From #87's and #97's bench findings. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0115AT2ue6x9cT5e5J9SZtCn --------- Co-authored-by: Luke Curley <432854+kixelated@users.noreply.github.com> Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Slice of quest/m1/ffi-export.md: the rest of "Several crates", decided with the maintainer on 2026-10-26.
Problem
[patch]and[replace]from the workspace manifest only. Cargo reads[patch]from its config too, but only from where it runs. A glue built anywhere else resolved the exports differently from the check. That was a follow-up of kixelated/rust2#76.Approach
Stand-in package
just ffi standinwritesffi/target/moq-ffi. It is an empty library with a path dependency on each export in the moq checkout. It has its own workspace and a copy of moq'sCargo.lock.just ffi moqandjust ffi censuscheck it, andffi.tomlnow names it aspackage. moq-net moves under[crates.moq-net].I picked the stand-in over moq-ffi's remainder because it is smaller:
staticlib/cdylib, with no rlib for the CLI to bind, and it does not depend on moq-pattern. It would also bring in uniffi and the codecs, and the census would walk its UniFFI wrappers.Two placement details:
Cargo.lock.kiopatch. The patch only matters through moq-tokio'sirohfeature, which moq-ffi leaves off. I checked that the copied lockfile keeps every version and adds only the stand-in.The stand-in names each crate with
use x as _;, since rustc loads a dependency only when it is named.Glue
The glue names each dependency with
use <dep>_export as _;. An export that exports nothing, like the stand-in, otherwise trips cargo'sunused_dependencieswarning. The glue still needs that dependency, because it carries moq-tokio's default features.Config
The renames fix the C-name clashes across and within the new exports:
Client,Server,Errortokio_*connect::Errorconnect_target_errorconnection::MonitormonitorErrorhang_errorcatalog::{Audio,Video}CodecKind{audio,video}_codec_kindErrormux_errorcontainer::Framemux_container_frameCatalogFormat::DEFAULTcatalog_catalog_format_fallbackClock::TIMESCALEclock_fixed_timescalecodec::{aac,mp3,opus}::configcodec_*_audio_configfmp4::Chunk::{init,fragment}..._into_{init,fragment}Backoff::{initial,max,timeout}are each a field and a method of the same name. They claim one C name, andrenamecannot split them, so the config excludes all six (see Decisions).moq/moq.cIt now also does this:
catalog::AudioConfigand checks the rate, channels, codec tag, and description.moq_mux_errorfrom a truncated head.ConnectError.Config patches
The glue's
[patch]is read off cargo's resolution rather than copied from a manifest (see the design change):cargo metadataalready runs as the check resolves: from the package's directory, with its--configand the environment.--filter-platform, since cargo resolves every platform's dependencies for the glue), a dependency that resolved to a package of another source than the one it names was patched, or[replace]d. A replacement keeps the package's name and version, so the same[patch]resolves alike, and the glue carries no[replace]. A replacement from the very git URL the dependency names is an error, since cargo refuses a patch from its own source. Edges match declared dependencies byrename, or else by the library's crate name. That holds wherever the patch was declared: the manifest, a config file or itsinclude,--config, or the environment.[patch.<source URL>](crates-iofor crates.io) pointing at the resolved path, or at a gitrevand the exactversionit resolved to. A patch from another registry is an error.Cargo's own rules for config precedence, includes, registry aliases, URL canonicalization, and environment overrides therefore all apply as cargo applies them, with nothing reimplemented. On moq the stand-in resolves no patch, so its glue carries none.
Driver
cargo cleanin rust2-driver'sChecknow passes the check's--config,--locked,--frozen, and--offline. Without them, a--configpatch made clean resolve differently from the check, and clean failed. The new test hit this first.Test
config_patchedreproduced the bug before the fix. The export passed, then the glue failed offline withno matching package named rust2-ffi-config-cli. It covers:include, with paths from its own root;stalecopy that lacks the field the package reads, which the manifest names by crates.io's index URL;--configvalue'sinclude, read from the package's directory;[registries.index], which a config file defines as example.com andCARGO_REGISTRIES_INDEX_INDEXoverrides to crates.io.The glue then builds offline from the test's directory, without that config or environment.
patchednow names its patched dependency by a[lib] nameother than the package's, and a newreplacedtest carries a workspace[replace]of a git dependency, spelledurl#versionso the spec names the package only by its URL, as a[patch], and refuses one by another branch of that repository.Census
Each export at the pin, run through the stand-in:
Session,auth::{Issued, Request, Requests}, and the goaway producer and consumer now export. moq-tokio's signatures return them, and moq-tokio's default features unify into moq-net.SocketAddr/PathBuf/Url,Vec, and 34 re-exports of moq-quic's driver.catalog::Producer<T>andcontainer::Consumer<T>.BTreeMapand refused unknown-variant types.Coverage of moq-ffi's hand-written API: 356 exported items (UniFFI functions, methods, and types, without tests):
MoqTrackConsumer::read_frame,MoqSession::{publish, consume}, and three argument bundles. moq-ffi also keeps its runtime (ffi.rs), the wasm adapter, and its unifiedMoqError.What blocks the partial items, ranked:
#[non_exhaustive]or partly private structs), about 15.Url,SocketAddr, andPathBuf, andVec, about 13.moq_errorhas no constructor, so C cannot passabort(code), 6.kio::Waiter), which also keeps most covered session and origin futures from running from C until Driving lands.Impact
[patch]is each patch cargo applied, keyed by source URL, in place of the workspace manifest's copy. The generatedlib.rsnames each export.Checkpasses the resolution args tocargo clean. rust2-ts gets this too.Session, auth requests, and goaway.just ffi moqandjust ffi census: they check the stand-in, and the census writesmoq-ffi.md(empty),moq-tokio.md,hang.md, andmoq-mux.mdtoo.No MIGRATE entry, since nothing is released.
Checks
just checkandjust testpass at 5268e2c, andjust ffi moqpasses at 0efebfb (the later fix does not reach moq, which resolves no patch).[replace]). Both are fixed in 5f744bd and were reproduced against 0efebfb.[replace]spec matching missed cargo's spellings. 4ba7fee deletes the matching and carries a replacement as a[patch], reproduced against 5f744bd.git_patched), reproduced against 3615f9e.just ffi moqpasses at the pin and printsok.just ffi censusruns at the pin.just ffi bench, which needs the bench shell.Decisions
These are choices I made without asking. Each can be revisited.
tokio_,hang_,mux_). A type that clashes with its own accessor moves to the root (monitor,audio_codec_kind), as moq-net'spath::Relativedid. A function or constant that clashes with a type gets a descriptive suffix.moq-ffi(gluemoq-ffi-ffi), so the config keepspackage = "moq-ffi"when moq-ffi's remainder replaces it.Backoff::{initial,max,timeout}I recommend a rule that a method takes the name and the field's getter is left out, since Rust's accessor convention makes the method the accessor. For now the config excludes both, and the quest records it.Alternatives
rs/): moq's patches and lockfile would apply natively, but it writes into the checkout and dirties itsCargo.lock, which breaks the next pin bump's checkout.cargo config get: it is unstable (-Zunstable-options), and only its text output carries origins.Follow-ups
pathsoverride is not carried and no longer refused: metadata shows such a package under its registry source.pathsis legacy and rare.recursion_depth_exceeding_limit(a future hard error) when it checksSendon moq-tokio'sListener::acceptfuture. moq-tokio's own crate warns the same, so the fix is in moq's future depth, not the glue.catalog::Producer<hang::Extra>, would unblock most of the partial media items. That is a quest for/quest-plan.(written by Opus 5.5)
🤖 Generated with Claude Code
https://claude.ai/code/session_0115AT2ue6x9cT5e5J9SZtCn