Skip to content

fix(ci): pin comm to LC_ALL=C in reborn crate discovery - #6992

Merged
ilblackdragon merged 4 commits into
mainfrom
fix/ci-comm-locale-pin
Aug 2, 2026
Merged

ilblackdragon merged 4 commits into
mainfrom
fix/ci-comm-locale-pin

Conversation

@ilblackdragon

Copy link
Copy Markdown
Member

Summary

scripts/ci/discover-reborn-package-crates.sh sorts both comm inputs with LC_ALL=C but ran comm itself in the ambient locale. Under a UTF-8 collation — which orders ironclaw_events before ironclaw_event_streams, the opposite of C order (_ 0x5f < s 0x73) — comm rejects the C-sorted input with comm: input is not in sorted order, killing the pre-push coverage ratchet for any contributor whose shell has a UTF-8 locale. Hit in practice while pushing #6991 (noted in that PR's body).

Fix: one line — LC_ALL=C comm -12 so comm's collation matches its inputs.

Regression test

scripts/ci/test-ci-comm-locale-pin.sh (wired into the code_style static-check self-tests):

  1. Asserts every comm invocation in scripts/ci/ and .githooks/ is LC_ALL=C-pinned — fails on the pre-fix tree pointing at the exact line.
  2. Exercises the real-world fixture pair (ironclaw_event_streams / ironclaw_events) under an available UTF-8 locale with the pinned form.

Verified red-then-green: test fails with the fix stashed, passes with it applied; discover-reborn-package-crates.sh now runs end-to-end under en_US.UTF-8 and emits the crate closure (previously exit 1).

🤖 Generated with Claude Code

discover-reborn-package-crates.sh sorts both comm inputs with LC_ALL=C
but ran comm itself in the ambient locale. Under a UTF-8 collation
(which orders ironclaw_events before ironclaw_event_streams, unlike C)
comm rejected the C-sorted input with "comm: input is not in sorted
order", killing the pre-push coverage ratchet for any contributor with
a UTF-8 locale.

Regression test scripts/ci/test-ci-comm-locale-pin.sh asserts every
comm invocation in scripts/ci and .githooks is LC_ALL=C-pinned and
exercises the failing fixture pair under a UTF-8 locale; wired into the
code_style static-check self-tests.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings August 1, 2026 02:43
@gemini-code-assist

Copy link
Copy Markdown
Contributor

Caution

The consumer version of Gemini Code Assist on GitHub has been sunset. All code review activity has officially ceased.

@railway-app

railway-app Bot commented Aug 1, 2026 •

Copy link
Copy Markdown

🚅 Deployed to the ironclaw-pr-6992 environment in ironclaw-ci-preview

Service Status Web Updated (UTC)
ironclaw ✅ Success (View Logs) Web Aug 2, 2026 at 3:46 am

@railway-app
railway-app Bot temporarily deployed to ironclaw-ci-preview / ironclaw-pr-6992 August 1, 2026 02:43 Destroyed
@github-actions github-actions Bot added scope: ci CI/CD workflows size: M 50-199 changed lines risk: medium Business logic, config, or moderate-risk modules labels Aug 1, 2026
@coderabbitai

coderabbitai Bot commented Aug 1, 2026 •

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Summary by CodeRabbit

  • Bug Fixes

    • Improved dependency discovery consistency across different system locales by ensuring sorting comparisons behave deterministically.
  • Tests

    • Added automated checks that detect locale-sensitive CI commands and verify reliable behavior across compatible locale settings.
  • Chores

    • Integrated locale validation into routine fast checks, helping identify portability issues earlier in the development workflow.

Walkthrough

The change pins the dependency-closure comm invocation to LC_ALL=C. It adds a Bash regression test for CI and tracked-hook comm calls, then runs that test in the fast-checks workflow.

Changes

CI locale determinism

Layer / File(s) Summary
Locale pin for dependency closure
scripts/ci/discover-reborn-package-crates.sh
The dependency-closure comm invocation now uses LC_ALL=C.
Locale-pin regression test and workflow wiring
scripts/ci/test-ci-comm-locale-pin.sh, .github/workflows/code_style.yml
The Bash test scans comm invocations, validates collation-sensitive input, reports failures, and runs from the fast-checks job.

Estimated code review effort: 2 (Simple) | ~10 minutes

Possibly related PRs

Suggested reviewers: copilot

🚥 Pre-merge checks | ✅ 3 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Description check ⚠️ Warning The description explains the fix and regression test, but omits most required template sections, including change type, linked issue, security, blast radius, rollback, and review track. Complete the required template sections, mark CI/Infrastructure and review track C, and document validation, impact, rollback, and issue linkage.
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title follows Conventional Commits style and clearly describes the CI locale pinning fix.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Copilot AI left a comment

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.

Pull request overview

Fixes a locale-dependent CI failure in Reborn crate discovery by ensuring comm uses the same collation (LC_ALL=C) as its already-LC_ALL=C-sorted inputs, and adds a self-test to prevent regressions.

Changes:

  • Pin comm to LC_ALL=C in scripts/ci/discover-reborn-package-crates.sh to avoid “input is not in sorted order” under UTF-8 collations.
  • Add a regression test (scripts/ci/test-ci-comm-locale-pin.sh) that (a) enforces locale-pinned comm usage in CI scripts/hooks and (b) reproduces the historical ordering case under a UTF-8 locale.
  • Wire the new regression test into the code_style workflow static-check self-tests.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated no comments.

File Description
scripts/ci/discover-reborn-package-crates.sh Pins comm collation to match LC_ALL=C-sorted inputs, fixing locale-sensitive failures.
scripts/ci/test-ci-comm-locale-pin.sh Adds a regression guard for locale-pinned comm usage and a UTF-8-locale fixture check.
.github/workflows/code_style.yml Runs the new regression script as part of static-check self-tests in CI.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@coderabbitai coderabbitai 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.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@scripts/ci/test-ci-comm-locale-pin.sh`:
- Around line 27-31: Update the regression test around unpinned to normalize
multiline shell commands before inspection, then detect complete comm
invocations with or without options while allowing the valid LC_ALL=C
continuation form. Change the dynamic locale check to select only a non-C locale
whose unpinned comm rejects the C-sorted fixture, and remove any silent fallback
to C.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 495d405f-1d3f-4a98-9cd4-26d534063b4e

📥 Commits

Reviewing files that changed from the base of the PR and between fe8f5c2 and 6cf311d.

📒 Files selected for processing (3)
  • .github/workflows/code_style.yml
  • scripts/ci/discover-reborn-package-crates.sh
  • scripts/ci/test-ci-comm-locale-pin.sh

Comment thread scripts/ci/test-ci-comm-locale-pin.sh Outdated
@ironloopai

ironloopai Bot commented Aug 1, 2026 •

Copy link
Copy Markdown
Contributor

🔎 Review · PR #6992

🟢 Completed · Review submitted

Submitted review →

The locale pin is correct and consistently matches the existing C-sorted inputs. The regression test is appropriately wired into fast checks and covers both repository-wide pinning and the collation-sensitive fixture. No actionable findings.

Automatic · PR opened · attempt 1 of 3 · completed in 58s

Run details
  • Repository: nearai/ironclaw
  • Base: main at fe8f5c2
  • Head: fix/ci-comm-locale-pin at 6cf311d
  • Created: Aug 1, 2026, 2:48 AM UTC
  • Updated: Aug 1, 2026, 2:49 AM UTC
  • Run: ca956fe4-1983-426e-ba3f-1bdd4533ae00
  • Latest attempt: 1 · Completed · df81b567-bc37-4148-8475-22d325929d67

@ironloopai ironloopai Bot left a comment

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.

🔍 Review complete · PR #6992

✅ No actionable findings

The locale pin is correct and consistently matches the existing C-sorted inputs. The regression test is appropriately wired into fast checks and covers both repository-wide pinning and the collation-sensitive fixture. No actionable findings.

Validation and technical details
  • Verified trusted base fe8f5c2 and head 6cf311d.
  • Inspected the complete base-to-head diff and surrounding workflow and crate-discovery code.
  • bash -n passed for both changed shell scripts.
  • scripts/ci/test-ci-comm-locale-pin.sh passed: 2 passed, 0 failed.
  • Confirmed the new test script is executable and invoked by the code-style fast-check job.
  • The end-to-end crate-discovery script could not run in this review environment because cargo is unavailable.
  • Base: main
  • Head: fix/ci-comm-locale-pin at 6cf311d
  • Run: ca956fe4-1983-426e-ba3f-1bdd4533ae00

Address CodeRabbit review on #6992:
- Join backslash-newline continuations before inspection so multiline
  comm invocations are caught and the valid "LC_ALL=C \" + "comm"
  continuation form is not false-flagged; match comm with or without
  options; prune __pycache__ and follow .githooks symlinks.
- Select the case-2 locale by proving the mismatch (unpinned comm must
  reject the C-sorted fixture under it) instead of silently falling
  back to a C-compatible collation like C.UTF-8; skip explicitly when
  no installed locale disagrees. A "zzz" sentinel second file forces
  comm's order check, which never fires on two identical files.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings August 1, 2026 04:42
@railway-app
railway-app Bot temporarily deployed to ironclaw-ci-preview / ironclaw-pr-6992 August 1, 2026 04:42 Destroyed

@coderabbitai coderabbitai 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.

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@scripts/ci/test-ci-comm-locale-pin.sh`:
- Around line 35-45: Update the `hits` detection in `test-ci-comm-locale-pin.sh`
to inspect each `comm` invocation independently rather than excluding an entire
logical line when any invocation is pinned, including commands separated by `;`
or `&&`. Preserve multiline command handling, and add a negative regression test
covering a pinned `comm` followed by an unpinned `comm` in a compound command.
- Around line 52-83: Update the locale-selection loop around mismatch_locale to
first verify that the sentinel “zzz” sorts after both fixture entries under each
candidate locale, and only select a candidate that passes this ordering check
and rejects the C-sorted fixture. Preserve the existing skip behavior when no
qualifying locale is found, and keep the pinned LC_ALL=C assertion for the
selected locale.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: a83a2f19-5e2a-4979-9170-1c7ccf4304d7

📥 Commits

Reviewing files that changed from the base of the PR and between 6cf311d and 38ed9c8.

📒 Files selected for processing (1)
  • scripts/ci/test-ci-comm-locale-pin.sh

Comment thread scripts/ci/test-ci-comm-locale-pin.sh Outdated
Comment thread scripts/ci/test-ci-comm-locale-pin.sh

Copilot AI left a comment

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.

Pull request overview

Copilot reviewed 3 out of 3 changed files in this pull request and generated no new comments.

Suppressed comments (1)

scripts/ci/test-ci-comm-locale-pin.sh:66

  • Temporary files created with mktemp are only removed at the end of the script, so a failure/early exit (due to set -e) will leak /tmp files. Add an EXIT trap immediately after creating them so cleanup runs even when a case fails.
fixture="$(mktemp "${TMPDIR:-/tmp}/comm-locale.XXXXXX")"
sentinel="$(mktemp "${TMPDIR:-/tmp}/comm-locale.XXXXXX")"
printf 'ironclaw_event_streams\nironclaw_events\n' > "$fixture"
printf 'zzz\n' > "$sentinel"

ilblackdragon and others added 2 commits August 2, 2026 02:41
…n test

The regression-test enforcement gate recognizes shell regression tests by
their assertion idiom (assert_success/assert_failure among them); the custom
report-only form was invisible to it. Restructure the fixture case into
explicit assert_failure (unpinned comm rejects the C-sorted fixture) and
assert_success (pinned comm accepts it), which also states the red side of
the regression explicitly.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Two review findings on the locale-pin regression test:

- The scan excluded a whole joined logical line once it contained one
  pinned comm, so 'LC_ALL=C comm a b; comm c d' passed with the second
  invocation unpinned. Compound commands are now split at ;, &, and |
  before the pin check, and scanner self-checks pin the compound,
  multiline-continuation, and pinned-clean cases.

- The mismatch-locale selection now verifies the zzz sentinel still
  sorts after both fixture entries under the candidate locale; without
  that, a locale ordering the sentinel early would never exercise the
  fixture-order path comm is being tested on.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@abbyshekit

Copy link
Copy Markdown
Contributor

Reviewed this alongside #6997, #7001 and #5981. The production fix is correct and minimal, and the sweep is clean — repo-wide there's exactly one other comm (this one) and no join. My comments are all on the regression test, which I think guards less than the description claims. Everything below I reproduced locally.

1. The guard checks comm but not the sort pipes feeding it.

The invariant is comm's collation must match its inputs', but Case 1 only audits one side of it. I removed LC_ALL=C from one of the two sort -u pipes at discover-reborn-package-crates.sh:46 — which reintroduces the identical comm: input is not in sorted order failure under a UTF-8 collation — and the guard was happy:

PASS: all comm invocations are LC_ALL=C-pinned
SKIP: no installed UTF-8 locale rejects the C-sorted fixture; collation mismatch not reproducible here
1 passed, 0 failed   (exit 0)

Worth extending Case 1 to assert that any sort feeding a comm is pinned too, otherwise the next regression in this class lands green.

2. Case 2 doesn't execute on dev machines or in CI.

  • macOS: BSD comm doesn't detect sort disorder at all. I ran the fixture pair under C, en_US.UTF-8 and C.UTF-8 — rc=0 in all three, with 83 UTF-8 locales installed. So mismatch_locale stays empty and it prints SKIP. That's the machine the pre-push hook actually runs on.
  • CI: LANG: "C.UTF-8" is pinned in code_style.yml:35, reborn-tests.yml:66, reborn-e2e.yml:78 and platform-and-compat.yml:59. C.UTF-8 is C-collation, so no candidate locale rejects the fixture there either → SKIP.

SKIP contributes neither PASS nor FAIL and the script still exits 0, so in practice only the static grep from (1) ever runs. Since the script under test is never invoked either, consider running discover-reborn-package-crates.sh end-to-end under a forced collation instead of testing a hard-coded comm.

3. The failure message points at the wrong line.

The description says it fails "pointing at the exact line". I stashed the fix and ran it — it reported line 31 for the violation at line 43. The sed continuation-join renumbers the stream before grep -n sees it, so the offset grows with the number of continuations earlier in the file.

Minor: a line containing both a pinned and an unpinned comm is dropped whole by the grep -av exclusion; and env LC_ALL=C comm / a file-level export LC_ALL=C are flagged as violations despite being correct.

None of this blocks the fix itself — it's a one-line change that's clearly right.

@railway-app
railway-app Bot temporarily deployed to ironclaw-ci-preview / ironclaw-pr-6992 August 2, 2026 03:35 Destroyed

@coderabbitai coderabbitai 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.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@scripts/ci/test-ci-comm-locale-pin.sh`:
- Around line 45-76: Update scan_unpinned_comm so each shell command, including
nested process substitutions, is evaluated independently rather than allowing an
outer LC_ALL=C comm match to exempt an inner invocation. If nested constructs
cannot be parsed safely, reject them explicitly; add the specified
process-substitution fixture to the scanner self-checks and assert it fails.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 3992d46d-fce8-4d0b-bda8-f63cf16120ea

📥 Commits

Reviewing files that changed from the base of the PR and between 38ed9c8 and ce3e4bb.

📒 Files selected for processing (1)
  • scripts/ci/test-ci-comm-locale-pin.sh

Comment on lines +45 to +76
# Case 1: every comm invocation in CI scripts and tracked hooks must pin
# LC_ALL=C so its collation matches the LC_ALL=C-sorted inputs. Backslash-
# newline continuations are joined first so multiline invocations — both the
# offending `comm \` form and a valid `LC_ALL=C \` + `comm` form — are
# inspected as whole commands; comment lines are then dropped, and compound
# commands are split at `;`, `&`, and `|` so each invocation is inspected
# independently (a pinned comm must not excuse an unpinned one on the same
# logical line). `find -L` follows the .githooks symlinks to their tracked
# targets; build caches are pruned. This file is excluded: it deliberately
# runs unpinned comm to prove the failure mode.
scan_unpinned_comm() {
sed -e ':a' -e '/\\$/{N; s/\\\n[[:space:]]*/ /; ba' -e '}' "$1" \
| grep -av '^[[:space:]]*#' \
| tr ';&|' '\n\n\n' \
| grep -anE '(^|[^-=[:alnum:]_.])comm([[:space:]]|$)' \
| grep -avE 'LC_ALL=C[[:space:]]+comm([[:space:]]|$)' \
|| true
}

# Scanner self-checks: each invocation in a compound command is judged on its
# own, and the pinned forms (single, compound, multiline continuation) stay
# clean.
scanner_fixture="$(mktemp "${TMPDIR:-/tmp}/comm-locale.XXXXXX")"
printf 'LC_ALL=C comm -12 a b; comm -12 c d\n' > "$scanner_fixture"
assert_failure "scanner flags an unpinned comm after a pinned one in a compound command" \
test -z "$(scan_unpinned_comm "$scanner_fixture")"
printf 'comm \\\n -12 a b\n' > "$scanner_fixture"
assert_failure "scanner flags an unpinned multiline comm continuation" \
test -z "$(scan_unpinned_comm "$scanner_fixture")"
printf 'LC_ALL=C comm -12 a b && LC_ALL=C \\\n comm -12 c d\n' > "$scanner_fixture"
assert_success "scanner accepts pinned comm in compound and multiline forms" \
test -z "$(scan_unpinned_comm "$scanner_fixture")"

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

input='LC_ALL=C comm -12 a b < <(comm -12 c d)'
hits="$(
  printf '%s\n' "$input" \
    | grep -av '^[[:space:]]*#' \
    | tr ';&|' '\n\n\n' \
    | grep -anE '(^|[^-=[:alnum:]_.])comm([[:space:]]|$)' \
    | grep -avE 'LC_ALL=C[[:space:]]+comm([[:space:]]|$)' \
    || true
)"

test -n "$hits"

Repository: nearai/ironclaw

Length of output: 153


🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

echo "== file =="
fd -a 'test-ci-comm-locale-pin\.sh' . || true

echo "== relevant source =="
file="$(fd 'test-ci-comm-locale-pin\.sh' . | head -n 1)"
if [ -n "${file:-}" ]; then
  wc -l "$file"
  sed -n '1,120p' "$file" | cat -n
fi

echo "== invariant docs references =="
for f in CLAUде.md AGENTS.md .claude/rules/* .claude/rules 2>/dev/null; do
  [ -e "$f" ] || continue
  name="$(printf '%s' "$f" | sed 's#^\./##')"
  echo "--- $name ---"
  sed -n '1,220p' "$name" 2>/dev/null | rg -n "Guardrails|hooks|regression|multiline|commit|secrets|migration|docs/documentation" | head -n 40 || true
done

echo "== deterministic scanner on nested case =="
python3 - <<'PY'
from pathlib import Path
import re

# Reproduce scanner lines 45-76 exactly as comments describe.
def scan_unpinned_comm(text):
    # Simulate sed continuation join without line numbers.
    joined=[]
    for line in text.splitlines():
        if joined and joined[-1].endswith('\\'):
            joined[-1]=joined[-1]+' '+line.lstrip() if len(line)>0 else joined[-1]
        else:
            joined.append(line)
    # Simulate grep -av regex line filter and tr.
    step='\n'.join(l for l in joined if not re.match(r'^[[:space:]]*#', l))
    compound_lines=step.replace(';', '\n').replace('&', '\n').replace('|', '\n').splitlines()
    hits=[]
    for i,line in enumerate(compound_lines,1):
        if re.search(r'(^|[^-=[:alnum:]_.])comm([[:space:]]|$)', line):
            hits.append((i,line))
    return [(i,line) for i,line in hits if not re.search(r'LC_ALL=C[[:space:]]+comm([[:space:]]|$)', line)]

case='LC_ALL=C comm -12 a b < <(comm -12 c d)'
print(scan_unpinned_comm(case))

cases=[
    'LC_ALL=C comm -12 a b < <(comm -12 c d)',
    'LC_ALL=C comm -12 a b && comm -12 c d',
    'comm \\\n  -12 a b',
    'LC_ALL=C comm -12 a b && LC_ALL=C \\\n  comm -12 c d',
]
for case in cases:
    print(repr(case), scan_unpinned_comm(case))
PY

Repository: nearai/ironclaw

Length of output: 6048


🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

echo "== invariant docs references =="
for f in CLAUDE.md AGENTS.md; do
  if [ -e "$f" ]; then
    name="$(printf '%s' "$f" | sed 's#^\./##')"
    echo "--- $name ---"
    sed -n '1,220p' "$name" | rg -n "Guardrails|hooks|regression|multiline|commit|secrets|migration|documentation" | head -n 40 || true
  fi
done
if [ -d .claude/rules ]; then
  for f in .claude/rules/*; do
    [ -e "$f" ] || continue
    echo "--- $f ---"
    sed -n '1,220p' "$f" | rg -n "Guardrails|hooks|regression|multiline|commit|secrets|migration|documentation" | head -n 40 || true
  done
fi

echo "== deterministic scanner-like behavior on nested case =="
python3 - <<'PY'
import subprocess

input='LC_ALL=C comm -12 a b < <(comm -12 c d)'
scanner_fixture='/tmp/coderabbit-comm-scanner-fixture'
with open(scanner_fixture, 'w') as f:
    f.write(input + '\n')

hits = subprocess.run(
    ['sed', '-e', ':a', '-e', '/\\$/{N; s/\\\n[[:space:]]*/ /; ba', '-e', '}', scanner_fixture],
    stdout=subprocess.PIPE,
    text=True,
    check=True,
).stdout | subprocess.run(['grep', '-av', '^[[:space:]]*#'], input=subprocess.STDOUT, text=True, check=True).stdout | subprocess.run(['tr', ';&|', '\n\n\n'], input=subprocess.STDOUT, text=True, check=True).stdout | subprocess.run(['grep', '-anE', '(^|[^-=[:alnum:]_.])comm([[:space:]]|$)'], input=subprocess.STDOUT, text=True) or '' | subprocess.run(['grep', '-avE', 'LC_ALL=C[[:space:]]+comm([[:space:]]|$)'], input=hits.stdout, text=True) or ''

print(repr(input))
print('hits', repr(hits))
print('empty', hits == '')

cases = [
    'LC_ALL=C comm -12 a b < <(comm -12 c d)',
    'LC_ALL=C comm -12 a b && comm -12 c d',
    'comm \\\n  -12 a b',
    'LC_ALL=C comm -12 a b && LC_ALL=C \\\n  comm -12 c d',
]
PY

echo "== targeted command to emulate grep chain =="
test_file="$(mktemp)"
printf '%s\n' 'LC_ALL=C comm -12 a b < <(comm -12 c d)' > "$test_file"
tmp1="$(sed -e ':a' -e '/\\$/{N; s/\\\n[[:space:]]*/ /; ba' -e '}' "$test_file")"
echo "sed_output:"
printf '%s\n' "$tmp1"
tmp2="$(printf '%s\n' "$tmp1" | grep -av '^[[:space:]]*#')"
echo "comment_filter:"
printf '%s\n' "$tmp2"
tmp3="$(printf '%s\n' "$tmp2" | tr ';&|' '\n\n\n')"
echo "compound_split:"
printf '%s\n' "$tmp3"
tmp4="$(printf '%s\n' "$tmp3" | grep -anE '(^|[^-=[:alnum:]_.])comm([[:space:]]|$)' || true)"
echo "comm_hits:"
printf '%s\n' "$tmp4"
tmp5="$(printf '%s\n' "$tmp4" | grep -avE 'LC_ALL=C[[:space:]]+comm([[:space:]]|$)' || true)"
echo "final_hits:"
printf '%s\n' "$tmp5"
rm -f "$test_file"

Repository: nearai/ironclaw

Length of output: 6327


🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

echo "== deterministic scanner-like behavior on nested case =="
input='LC_ALL=C comm -12 a b < <(comm -12 c d)'
test_file="$(mktemp)"
printf '%s\n' "$input" > "$test_file"

step1="$(sed -e ':a' -e '/\\$/{N; s/\\\n[[:space:]]*/ /; ba' -e '}' "$test_file")"
echo "sed/output:"
printf '%s\n' "$step1"

step2="$(printf '%s\n' "$step1" | grep -av '^[[:space:]]*#')"
echo "after comment filter:"
printf '%s\n' "$step2"

step3="$(printf '%s\n' "$step2" | tr ';&|' '\n\n\n')"
echo "after compound split:"
printf '%s\n' "${step3:-<empty>}"

step4="$(printf '%s\n' "$step3" | grep -anE '(^|[^-=[:alnum:]_.])comm([[:space:]]|$)' || true)"
echo "after comm matcher:"
printf '%s\n' "${step4:-<empty>}"

final="$(printf '%s\n' "$step4" | grep -avE 'LC_ALL=C[[:space:]]+comm([[:space:]]|$)' || true)"
echo "final hits:"
printf '%s\n' "${final:-<empty>}"
echo "non-empty? $([ -n "$final" ] && echo yes || echo no)"

rm -f "$test_file"

echo "== minimal grep regex behavior =="
python3 - <<'PY'
import re
line = 'LC_ALL=C comm -12 a b < <(comm -12 c d)'
for pat in ['LC_ALL=C[[:space:]]+comm([[:space:]]|$)', r'(?:^|(?<=[^-=[:alnum:]_.]))comm(?=[[:space:]]|$)']:
    print(pat, re.search(pat, line))
PY

Repository: nearai/ironclaw

Length of output: 797


Reject nested comm inside a pinned logical line.

The scanner treats pinning at the LC_ALL=C[[:space:]]+comm line filter as a line-level exemption, while the invariant at .claude/rules/review-discipline.md:136 requires checks/hooks to handle multiline syntax and keep guarantees aligned with tests. Handle nested shell command forms independently, or reject unsupported nested constructs outright, and add LC_ALL=C comm -12 a b < <(comm -12 c d) as a failing self-check.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@scripts/ci/test-ci-comm-locale-pin.sh` around lines 45 - 76, Update
scan_unpinned_comm so each shell command, including nested process
substitutions, is evaluated independently rather than allowing an outer LC_ALL=C
comm match to exempt an inner invocation. If nested constructs cannot be parsed
safely, reject them explicitly; add the specified process-substitution fixture
to the scanner self-checks and assert it fails.

Source: Coding guidelines

Copilot AI left a comment

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.

Pull request overview

Copilot reviewed 3 out of 3 changed files in this pull request and generated no new comments.

@ilblackdragon
ilblackdragon added this pull request to the merge queue Aug 2, 2026
Merged via the queue into main with commit 5a1d812 Aug 2, 2026
42 of 44 checks passed
@ilblackdragon
ilblackdragon deleted the fix/ci-comm-locale-pin branch August 2, 2026 05:24
l3ocifer pushed a commit to l3ocifer/frick-ironclaw that referenced this pull request Sep 3, 2026
* fix(ci): pin comm to LC_ALL=C in reborn crate discovery

discover-reborn-package-crates.sh sorts both comm inputs with LC_ALL=C
but ran comm itself in the ambient locale. Under a UTF-8 collation
(which orders ironclaw_events before ironclaw_event_streams, unlike C)
comm rejected the C-sorted input with "comm: input is not in sorted
order", killing the pre-push coverage ratchet for any contributor with
a UTF-8 locale.

Regression test scripts/ci/test-ci-comm-locale-pin.sh asserts every
comm invocation in scripts/ci and .githooks is LC_ALL=C-pinned and
exercises the failing fixture pair under a UTF-8 locale; wired into the
code_style static-check self-tests.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* test(ci): harden comm locale-pin regression test per review

Address CodeRabbit review on nearai#6992:
- Join backslash-newline continuations before inspection so multiline
  comm invocations are caught and the valid "LC_ALL=C \" + "comm"
  continuation form is not false-flagged; match comm with or without
  options; prune __pycache__ and follow .githooks symlinks.
- Select the case-2 locale by proving the mismatch (unpinned comm must
  reject the C-sorted fixture under it) instead of silently falling
  back to a C-compatible collation like C.UTF-8; skip explicitly when
  no installed locale disagrees. A "zzz" sentinel second file forces
  comm's order check, which never fires on two identical files.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* test(ci): use assert_success/assert_failure helpers in comm locale-pin test

The regression-test enforcement gate recognizes shell regression tests by
their assertion idiom (assert_success/assert_failure among them); the custom
report-only form was invisible to it. Restructure the fixture case into
explicit assert_failure (unpinned comm rejects the C-sorted fixture) and
assert_success (pinned comm accepts it), which also states the red side of
the regression explicitly.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

* test(ci): per-invocation comm scan and sentinel-order guard per review

Two review findings on the locale-pin regression test:

- The scan excluded a whole joined logical line once it contained one
  pinned comm, so 'LC_ALL=C comm a b; comm c d' passed with the second
  invocation unpinned. Compound commands are now split at ;, &, and |
  before the pin check, and scanner self-checks pin the compound,
  multiline-continuation, and pinned-clean cases.

- The mismatch-locale selection now verifies the zzz sentinel still
  sorts after both fixture entries under the candidate locale; without
  that, a locale ordering the sentinel early would never exercise the
  fixture-order path comm is being tested on.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>

This branch was successfully deployed

No deployments
ironclaw-ci-preview / ironclaw-pr-6992 — ce3e4bb2 Deployed Aug 2, 2026 by railway-app[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

contributor: core 20+ merged PRs risk: medium Business logic, config, or moderate-risk modules scope: ci CI/CD workflows size: M 50-199 changed lines

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants