Skip to content

fix(builtins): track uucore quoting-style rename in printf shim - #2738

Merged
chaliy merged 1 commit into
mainfrom
eve/clever-mccarthy-2d54fa
Oct 16, 2026
Merged

chaliy merged 1 commit into
mainfrom
eve/clever-mccarthy-2d54fa

Conversation

@chaliy

@chaliy chaliy commented Oct 16, 2026

Copy link
Copy Markdown
Contributor

What changed

The weekly Coreutils Args Drift workflow runs again. It has failed every
scheduled run since 2026-10-05, so bashkit has silently stopped tracking
upstream uutils for two cycles.

The handwritten format_support shim now provides both spellings of two
uucore symbols that upstream renamed, so the vendored format module
compiles whether it is regenerated against the current pin or against
upstream HEAD. No runtime behavior changes.

Separately, the style printf uses to recover a rejected numeric argument
is now named once and enforced by a test, closing a silent-failure path the
drift PR could not have fixed itself.

Why

The drift job re-ports vendored uucore modules against upstream HEAD, then
builds. Upstream renamed QuotingStyle::C_NO_QUOTES to an Escape variant
and extracted locale_aware_shell_escape as a %q shorthand, so the
regenerated code referenced symbols the shim did not have:

error[E0432]: unresolved import `...::format_support::locale_aware_shell_escape`
error[E0599]: no variant or associated item named `Escape` found for enum `QuotingStyle`
error: could not compile `bashkit` (lib) due to 2 previous errors

Both are pure renames. Escape and C_NO_QUOTES both select uucore's
CQuoter with CQuotesEnforce::None, and both are what
--quoting-style=escape resolves to; locale_aware_shell_escape(x) is
locale_aware_escape_name(x, SHELL_ESCAPE) returning String.

The failure is invisible by construction: the job only runs Mondays, and it
dies at Verify build still passes — after regeneration, before the patch
upload — so no PR ever opens and nothing reports the breakage.

Carrying both spellings is deliberate. The pinned generated/format/ still
says C_NO_QUOTES while the regeneration says Escape, and the shim has to
satisfy both at once or the drift run cannot reach its own build step. The
old spelling is dropped once the pin moves past the rename; the condition is
written down in the knowledge entry.

The coupling the drift PR could not repair

printf's numeric_argument_diagnostics recovers a rejected argument by
re-quoting each candidate with the same QuotingStyle the vendored module
used, then prefix-matching the diagnostic. The open-pr job enforces a
generated-only diff, so it can never update printf.rs — a style mismatch
would have dropped printf: <arg>: invalid number silently, and only for
arguments the two styles escape differently. Plain abc escapes to itself
under every style, so printf_invalid_number_stderr could not catch it.

The style is now format_support::DIAGNOSTIC_QUOTING_STYLE, and a test
scans generated/format/argument.rs for the styles it actually names,
failing if any escapes differently.

Before / After

Re-running the workflow's own steps locally against upstream HEAD
781b4991d (pin is 6579cc2), on this branch vs. its parent:

Step Before After
port-module format + 11 arg surfaces regenerates regenerates
cargo build -p bashkit E0432 + E0599, exit 101 passes
cargo test --test integration -- spec_tests::bash_spec_tests never reached 1 passed
cargo test --test integration -- coreutils_differential_tests:: never reached 22 passed

The differential run used a coreutils multicall built from that same
upstream tree, matching how the workflow builds it. That is the last step of
the regenerate job, so the whole job now passes end to end.

Regenerated code confirmed to use the new names:

format/argument.rs:173:  locale_aware_escape_name(OsStr::new(input), QuotingStyle::Escape)
format/spec.rs:354:      let s = locale_aware_shell_escape(args.next_string(*position));

The coupling guard passes in both states — against the pinned tree
(C_NO_QUOTES) and against the regenerated tree (Escape) — which is the
property that makes the upcoming drift PR safe to merge.

No user-visible behavior change: printf reports the raw argument, as bash
does, and the escaped form is only ever a matching key. The new printf test
pins the control-character case against bash 5.2.21:

$ printf '%d' $'a\tb'
bash: printf: a<TAB>b: invalid number

Risk

  • Low. Additive shim surface plus one constant; no generated files and no
    resource limits touched. The two upstream changes are renames verified
    against uutils source at both revisions, not semantic changes.
  • The dual spelling is transitional cruft by design. If it were dropped too
    early the drift run breaks again — which is why the removal condition is
    recorded in knowledge/runtimes/coreutils-args-port.md rather than left to
    memory.
  • This unblocks the drift automation; it does not itself bump the pin. The
    next run opens the regeneration PR for review, as designed.

Checklist

  • Tests added or updated
  • Backward compatibility considered

https://claude.ai/code/session_0112F7oWpuuyUKiXHbhqRGc1


Generated by Claude Code

The weekly Coreutils Args Drift run has failed since 2026-10-05. It
re-ports vendored uucore modules against upstream HEAD, and the
regenerated `format/` no longer compiles against our handwritten shim:
upstream renamed `QuotingStyle::C_NO_QUOTES` to an `Escape` variant and
extracted `locale_aware_shell_escape` as a shorthand for `%q`.

Both are pure renames. `Escape` and the old `C_NO_QUOTES` both select
uucore's `CQuoter` with `CQuotesEnforce::None` and both are what
`--quoting-style=escape` resolves to; `locale_aware_shell_escape(x)` is
`locale_aware_escape_name(x, SHELL_ESCAPE)` returning `String`. The shim
carries both spellings so it builds against the current pin and against
upstream HEAD, which is what unblocks the drift run.

`printf` reverse-matches the vendored module's numeric diagnostics by
re-quoting candidate arguments with the same style, and a drift PR may
only touch generated files, so it cannot keep `printf.rs` in step. The
style is now named once as `DIAGNOSTIC_QUOTING_STYLE`, and a test scans
the generated module for the style it actually uses and fails if that
style escapes differently.

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

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 7eeb5e4 Commit Preview URL

Branch Preview URL
Oct 16 2026, 09:31 AM

@chaliy
chaliy merged commit 76834b9 into main Oct 16, 2026
46 checks passed
@chaliy
chaliy deleted the eve/clever-mccarthy-2d54fa branch October 16, 2026 09:59
chaliy added a commit that referenced this pull request Oct 17, 2026
… modules (#2746)

Regenerated by `bashkit-coreutils-port` against uutils/coreutils@8613dffab
(was 6579cc2). Utilities: cat ls mktemp od readlink realpath shuf stat tac
tee truncate. Vendored module: format.

The vendored `format` module is inert in bashkit:

- `parse_escape_only`/`parse_escape_code` take upstream's new `EscapeSet`.
  Both vendored call sites pass `WithUnicodeAndQuote`, which is what the code
  did unconditionally before, so `%b` and format-string escapes keep treating
  `\"`, `\u` and `\U` as escapes.
- `%q` moves to upstream's `locale_aware_shell_escape` shorthand; the shim
  routes it and the old spelling to the same `shell_quote`.
- `QuotingStyle::C_NO_QUOTES` becomes `QuotingStyle::Escape` (the rename the
  shim pre-absorbed in #2738); both map to the same no-op escaping.
- `set_exit_code` calls move into the per-error match arms; it is a no-op in
  bashkit, which reports status through `ExecResult`.
- `format_float_decimal`/`format_float_scientific` gain bounded zero-padding:
  fractional digits capped at `u16::MAX`, integer zero-extension refused past
  the existing `MAX_FORMAT_WIDTH` (1M).

Two argument surfaces widen slightly, matching upstream: `od` gains `-B` as a
short alias for `--skip-bytes`, and `ls` drops the mutual `overrides_with`
between `--dired` and `--hyperlink` while `--hyperlink=c-maybe` becomes its own
possible value. bashkit's `ls` reads neither flag.

Verified by running 20 printf cases against real bash 5.2.21 with the tree
before and after: identical results both ways (17 match, 3 pre-existing
coreutils-vs-bash divergences in `%b \u`/`\U` and `%q`).
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