Skip to content

fix(deps): let a Monty fork dependency move ahead of upstream when marked - #2876

Merged
chaliy merged 3 commits into
mainfrom
eve/clever-mccarthy-gwhehq
Nov 7, 2026
Merged

chaliy merged 3 commits into
mainfrom
eve/clever-mccarthy-gwhehq

Conversation

@chaliy

@chaliy chaliy commented Nov 7, 2026 •

Copy link
Copy Markdown
Contributor

What changed

A dependency's version in a Monty fork Cargo.toml may now diverge from upstream when its line carries a bashkit fork: <why> marker — the same mechanism source edits already use. Adding or dropping a dependency stays unmarkable, and a marker on a dependency that already matches upstream is itself an error.

With that unblocked, this takes the content of dependabot #2860: fancy-regex 0.20 and getrandom 0.4 in bashkit-monty.

Why

Two rules on main contradicted each other, and the contradiction produced an unmergeable PR every week.

Nine crates are declared both in a fork and in bashkit's own crates (chrono, fancy-regex, getrandom, indexmap, num-bigint, num-traits, serde, sha1, sha2). A Dependabot proposal for one of those edits the fork manifest too, which the drift check then rejects — #2860 is exactly that shape, and it would have come back on every weekly run.

Closing the gap by ignoring those names instead was not an option: it would freeze serde, chrono and sha2 for bashkit as well, which are the ones advisories matter most for.

Holding the fork at upstream's version was not free either — it put two majors of fancy-regex in the graph.

Before / After

Drift check, fork moved to the workspace's fancy-regex:

# Before
bashkit-monty/Cargo.toml: [dependencies] `fancy-regex` differs from upstream {'version': '0.17.0'}
bashkit-monty/Cargo.toml: [dependencies] `getrandom` differs from upstream {'version': '0.3'}
2 fork drift error(s); mark source edits with `// bashkit fork: <why>`

# After
Monty forks match upstream 1.4.0 outside `bashkit fork:` markers

Duplicate major gone from the graph (777 → 776 crates), and the now-unused vet exemption retired:

# Before
fancy-regex: version = "0.17.0"  version = "0.20.0"
# After
fancy-regex: version = "0.20.0"

getrandom 0.3 stays in the lock via ahash, fastbloom and rand_core, so that bump aligns the declaration rather than shrinking the graph — the win there is that Dependabot stops re-proposing it.

re behavior is pinned, not assumed

re is reachable from untrusted Python, and fancy-regex 0.20 changed two things that reach it. Each case below was run through bashkit and through real CPython 3.11; all five agree, and they are now regression tests (python_integration_tests::regex_semantics):

case bashkit CPython
re.match('\xff', '\xff') — codepoint, not raw byte True True
re.search('[\xe0-\xff]', 'z\xe9z') True True
re.search(r'\b(?:foo|bar|baz)\b', 'a bar b') True True
re.sub(r'(\w)\1', 'X', 'aabb') XX XX
re.search(r'(?<=ab)c', 'abc') True True

fancy-regex 0.20 also adds max_prog_size to bound compile-time inlining of subroutine calls. Those are not in the fork's default feature set — Regex::new("(a(?1)?)") fails with Unknown group flag: (?1 — so no new compile-time blowup is reachable and nothing needs wiring up. TM-PY-033 still covers runtime backtracking.

Risk

  • Medium. A regex-engine major under untrusted input, plus a loosened supply-chain invariant.
  • What can break: a re behavior change 0.20 made that the five pinned cases miss. The 312 python_* tests and python_fuzz/python_diff_fuzz are the rest of the net.
  • The loosening is bounded on purpose: versions only, markers required, add/drop still rejected, stale markers rejected, and no few-plain-lines fallback so one note cannot cover neighbouring entries (that last one was caught by a test before it shipped).

Checklist

  • Tests added or updated — 7 new drift-check cases (3 negative), 5 re parity cases
  • Backward compatibility considered — internal tooling and a fork manifest; no public surface
  • check_monty_fork.py clean, cargo clippy -D warnings clean, cargo fmt --check clean
  • 252 repo-script tests, 49 bashkit-monty lib tests, 312 python_* integration tests green
  • CI green — required before merge

Supersedes #2860.


<a href="https://backend.blacksmith.sh/track/enable-autofix?expires=1796648328&installation_model_id=447267&pr_number=2876&ref=codesmith_pr_footer&repository=everruns%2Fbashkit&return_to=https%3A%2F%2Fgithub.com%2Feverruns%2Fbashkit%2Fpull%2F2876&signature=b1007db579d1a6caa1ab163eaae59a0060eab386834bc5948fb71b675dde3964"&gt;&lt;picture&gt;&lt;source media="(prefers-color-scheme: dark)" srcset="https://pr-comments-assets.blacksmith.sh/codesmith/autofix-with-codesmith-dark.svg"&gt;&lt;source media="(prefers-color-scheme: light)" srcset="https://pr-comments-assets.blacksmith.sh/codesmith/autofix-with-codesmith-light.svg"&gt;&lt;img alt="Autofix with [code]smith" src="https://pr-comments-assets.blacksmith.sh/codesmith/autofix-with-codesmith-dark-3x.png" width="190" height="28"&gt;
Open in [code]smith · Need help on this PR? Tag @codesmith-bot with what you need.


Generated by Claude Code

…rked

The forks must match upstream Monty 1.4.0, and the drift check reads that
strictly for `Cargo.toml` dependencies. But nine crates are declared both in a
fork and in bashkit's own crates, and Dependabot deliberately does not ignore
those: bashkit has to be able to move them and to receive their advisories. A
proposal for one edits the fork manifest too, so every such bump was
unmergeable — #2860 (fancy-regex 0.17 -> 0.20, getrandom 0.3 -> 0.4) is the
shape, and it would have returned every week. Holding the fork at upstream's
version was not free either: two majors of fancy-regex sat in the graph.

A fork dependency's version may now diverge when its line carries a
`bashkit fork:` marker, the same mechanism source edits use. Adding or dropping
a dependency stays unmarkable, since re-sync cannot reconcile a crate upstream
does not have, and a marker on a dependency that already matches upstream is an
error so a note left behind by a re-sync cannot excuse the next bump. The
marker window is the comment block above the line plus the line itself, with no
few-lines fallback: a dependency table is one entry per line, and the fallback
let one note cover its neighbours.

With that, this takes #2860's content: fancy-regex 0.20 and getrandom 0.4 in
`bashkit-monty`, which drops fancy-regex 0.17 and its regex tree from the graph
(777 -> 776 crates) and retires the now-unused vet exemption. fancy-regex 0.20
made `Captures` generic over the haystack type, so two marked
`Captures<'_, str>` edits come with it.

`re` is reachable from untrusted Python, so the behavior 0.20 changed is pinned
rather than assumed: `regex_semantics` asserts `\xHH` above 0x7F matches the
codepoint and word-boundary alternation still matches, both against what
CPython prints. fancy-regex's subroutine calls are not in the fork's feature
set, so 0.20's `max_prog_size` guards a blowup that is not reachable here.

Claude-Session: https://claude.ai/code/session_01Wy7MByvAMwapenBYpmq9HN
@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Nov 7, 2026 •

Copy link
Copy Markdown

Deploying with  Cloudflare Workers  Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

Status Name Latest Commit Preview URL Updated (UTC)
✅ Deployment successful!
View logs
bashkit 43c7520 Commit Preview URL

Branch Preview URL
Nov 07 2026, 01:18 PM

@bashkit-pr-reviewer bashkit-pr-reviewer Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Review of the Monty fix-forward: the version-divergence policy, its lint, tests, and the 0.20 adaptation look correct. Two precision gaps in the new marker logic, both P2 — no blockers.

Comment thread scripts/check_monty_fork.py Resolved
Comment thread scripts/check_monty_fork.py Resolved
@bashkit-pr-reviewer

bashkit-pr-reviewer Bot commented Nov 7, 2026 •

Copy link
Copy Markdown

Review verdict, push 43c7520: all findings resolved, no new ones

The patch-section-not-compared P2 from the last round is fixed: SOURCE_REDIRECT_TABLES = ('patch', 'replace') is rejected outright in manifest_errors, unmarkable, with a Decision comment that even covers the non-root-manifest inert-today/published-crate reasoning. Tests pin it (test_a_patch_table_fails, test_a_replace_table_fails, test_a_marker_does_not_excuse_a_patch_table, plus test_repackaging_a_dependency_fails for the package-swap case), and knowledge/operations/dependencies.md documents the rule in the same change. No new code beyond that hunk, the >= 2 header-parts relaxation (harmless: still gated on parts[-2] in DEP_TABLES), the tests, and the knowledge paragraph — re-scanned the full diff for anything I hadn't seen; nothing else moved.

Finding status: marked-deps-cross-table-bleed ✓, dep-spec-ignores-source-keys ✓, patch-section-not-compared ✓ — all resolved, none reposted, no new review submitted. Still not verifiable in this shell: compile/tests (no toolchain, per workflow).

…urces

Two precision gaps in the marker logic, both found in review of this change.

`marked_deps` keyed markers by bare dependency name while `manifest_errors`
checked per (table, name), so a note on `[dependencies] serde` also silenced a
`[build-dependencies] serde` drift — compile-time code behind a runtime note.
Markers are now keyed by (table, name). Target tables key the same in both
places: `marked_deps` reads raw header text, `dep_tables` keys from parsed
TOML, and `normalize_table` strips quotes so `[target.'cfg(...)'.dependencies]`
agrees with `target.cfg(...).dependencies`.

`dep_spec` compared only version, features, default-features and optional, so
the keys that decide *which* crate is built were invisible: an unmarked edit
keeping version and features identical while adding `path = "../evil"`, a git
source, or a different `package` passed silently. Those keys are now compared
on their own and are never markable — a marker records a reviewed version move,
and re-sync cannot reconcile a different source. The declared renames keep
their `package`/`path`; the existing rename check still validates them.

Pre-existing for the source keys, but this change makes the manifest comparison
the load-bearing control for version policy, so it is closed here.

Claude-Session: https://claude.ai/code/session_01Wy7MByvAMwapenBYpmq9HN

@bashkit-pr-reviewer bashkit-pr-reviewer Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Re-review of the new push: both P2s from the last round are fixed (markers now keyed by (table, name) with normalize_table, and per-dep source keys including package are compared as unmarkable). One leftover gap in the same area below.

Comment thread scripts/check_monty_fork.py Resolved
`[patch.crates-io]` and `[replace]` redirect a crate's source without touching
the dependency line, so the per-dependency source check never sees them: a fork
could point `serde` at a git fork while its `[dependencies]` line stayed
identical to upstream's and the drift check passed clean.

Rejected on sight rather than compared, and no marker covers them. Upstream
Monty 1.4 has neither table and a fork has no reason to, so comparing versions
inside one would be code for a case that should not exist. `[patch]` in a
non-root manifest is inert today, but the forks are published crates and a
consumer may build one as its own workspace root, so this does not rest on
that.

Claude-Session: https://claude.ai/code/session_01Wy7MByvAMwapenBYpmq9HN
@chaliy
chaliy merged commit 38d2c4c into main Nov 7, 2026
51 checks passed
@chaliy
chaliy deleted the eve/clever-mccarthy-gwhehq branch November 7, 2026 13:56
chaliy added a commit that referenced this pull request Nov 7, 2026
The fork-drift check rejected jiter 0.18 in bashkit-monty because upstream
Monty 1.4.0 pins 0.17. #2876 made a marked version divergence legal, so the
line now carries its reason: upstream's 0.17 declares pyo3 ^0.29.2, the Python
binding is on 0.30, and the two collide on links=pyo3-python, so cargo cannot
resolve the workspace at all. jiter 0.18 moves its pyo3 requirement to ^0.30.1
and unifies the graph on one major; 0.19 exists but is not needed.

Cargo.lock now holds a single pyo3 (0.30.1), jiter 0.18.0 and
pyo3-async-runtimes 0.30.0.

Claude-Session: https://claude.ai/code/session_01Wy7MByvAMwapenBYpmq9HN
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.

1 participant