Skip to content

fix: pin .claude markdown to LF so the pr-review parity gate compares equal bytes - #466

Open
thomasluizon wants to merge 1 commit into
mainfrom
fix/gitattributes-skill-md-eol
Open

fix: pin .claude markdown to LF so the pr-review parity gate compares equal bytes#466
thomasluizon wants to merge 1 commit into
mainfrom
fix/gitattributes-skill-md-eol

Conversation

@thomasluizon

Copy link
Copy Markdown
Owner

What this fixes

tools/launch-worker.mjs:99-112 in orbit-ui-mobile hashes the working-tree bytes of .claude/skills/pr-review/{SKILL.md,rubric.md} in both repositories. It refuses to launch the independent reviewer for repo ui or repo api when the two hashes differ.

The committed blobs are already identical in both repositories:

SKILL.md   b374cfd63d3a1257da76870e2da00586f87183cf
rubric.md  308d1c76fedec17cf0a1dae93bc0cc18925d88da

Both repositories set core.autocrlf=true. orbit-ui-mobile pins .claude/skills/**/*.md text eol=lf. This repository pinned only *.mjs and two JSON artifacts. The same blob therefore checked out as LF there and CRLF here.

                       ui bytes   api bytes   delta
SKILL.md               13388      13618       +230   (230 lines)
rubric.md              20247      20536       +289   (289 lines)

git check-attr text eol -- .claude/skills/pr-review/SKILL.md
  ui : text: set          eol: lf
  api: text: unspecified  eol: unspecified

git status was clean in both repositories. That is why nothing looked wrong.

Cost, measured on the overnight run of 2026-08-08: 76 tickets stood down rather than opened unreviewable, and 4 pull requests handed over with no independent review.

What changed

One line in .gitattributes: .claude/**/*.md text eol=lf. That is a superset of the missing .claude/skills/**/*.md line, and it also covers every future mirrored document under .claude.

No blob changes. The committed content was already correct. Only the working tree was wrong, so the working tree is re-materialized from the unchanged blobs.

Proof

Both working trees after the change:

SKILL.md   3fbf6d133b4a7bafbe8da8345ea10d45ff96ac6b83d6c78f348651fa3c830059  13388 B
rubric.md  672f14194f2bc7834828d434babdad152d5b361b2059b75f34f5b0d370be72b6  20247 B

Those are the exact hashes recorded on ORB-215.

Red-capable gate proof. The guard was removed, the failure observed, then the guard restored:

===== GREEN: gate passes with the fix in place =====
--review --repo api requires the configured primary checkout on main; found
fix/gitattributes-skill-md-eol in C:\Users\thoma\Documents\Programming\Projects\orbit-api

===== guard removed: .gitattributes reverted, tree re-materialized =====
api SKILL.md bytes after reverting the fix: 13618

===== RED: gate refuses =====
pr-review parity failed for .claude\skills\pr-review\SKILL.md: UI is canonical and
API must match before an API review can launch

===== guard restored =====
api SKILL.md bytes after restore: 13388

With the fix, the launcher passes the parity check and stops at the next check (the branch check). Without it, the launcher prints the exact refusal that stood 76 tickets down.

Audit of other pinned pairs

Question asked on ORB-215: has any other path pair drifted the same way?

No. Full sweep of every path present in both repositories at HEAD:

Measure Count
Paths present in both repositories 30
Of those, identical committed blob 3
Of those, different working-tree bytes 2 (this pair)

After this change that count is 0. The other 27 shared paths carry different blobs on purpose. .claude/skills/_shared/verification-protocol.md and .claude/skills/second-opinion/SKILL.md differ in real content, not line endings: the API copy of the first carries a mirror header, and the second omits the UI-only unattended-run sentences.

Related

A checkout setting must never be able to fail a contract gate again. The durable half of this fix is in the paired orbit-ui-mobile pull request, which makes the launcher compare committed blobs instead of working-tree bytes. This commit alone holds only on a machine whose .gitattributes is applied; the blob comparison holds on a fresh clone too.

Refs ORB-215

… equal bytes

tools/launch-worker.mjs in orbit-ui-mobile sha256s the working-tree bytes of
.claude/skills/pr-review/{SKILL.md,rubric.md} in both repositories and refuses to
launch an independent reviewer for repo ui or api when they differ.

The committed blobs are already byte-identical:
  SKILL.md  b374cfd
  rubric.md 308d1c7

Both repositories set core.autocrlf=true. orbit-ui-mobile pins
`.claude/skills/**/*.md text eol=lf`; this repository pinned only *.mjs and two
JSON artifacts. The same blob therefore checked out LF there and CRLF here,
+230 bytes on SKILL.md and +289 on rubric.md. `git check-attr text eol` reported
`eol: lf` in the UI repository and `eol: unspecified` here. `git status` was clean
in both, which is why nothing looked wrong.

Cost, measured on the overnight run of 2026-08-08: 76 tickets stood down rather
than opened unreviewable, and 4 pull requests handed over with no independent
review.

This commit changes no blob. It pins `.claude/**/*.md text eol=lf`, a superset of
the missing line that also covers every future mirrored document under .claude,
and re-materializes the working tree from the unchanged blobs.

Proof, both working trees after the change:
  SKILL.md  3fbf6d133b4a7bafbe8da8345ea10d45ff96ac6b83d6c78f348651fa3c830059 13388 B
  rubric.md 672f14194f2bc7834828d434babdad152d5b361b2059b75f34f5b0d370be72b6 20247 B

Gate proof: with .gitattributes reverted and the tree re-materialized, the launcher
prints "pr-review parity failed for .claude\skills\pr-review\SKILL.md". With this
commit applied it passes that check and advances to the next one.

Audit of every other path present in both repositories: 30 shared paths, 3 with an
identical committed blob, and only these 2 drifted. The other 27 differ in content
on purpose.

Refs ORB-215

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 5eca6803ae

ℹ️ 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".

Comment thread .gitattributes
# blob as CRLF here and LF there, +230 bytes on SKILL.md and +289 on rubric.md, so the
# gate compared different bytes for the same content and stood 76 tickets down on
# 2026-08-08. `git status` stayed clean in both repos, which is why nothing looked wrong.
.claude/**/*.md text eol=lf

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Rematerialize the unchanged Markdown files

When this commit is pulled into an existing core.autocrlf=true checkout whose .claude Markdown files already contain CRLF, Git updates .gitattributes but leaves these unchanged blobs untouched, so the launcher continues hashing the 13,618-byte CRLF SKILL.md and the parity gate remains blocked. Reproducing a checkout from the parent to this commit retained all 230 CR bytes despite git check-attr reporting eol: lf; this rollout therefore needs an explicit worktree refresh or the blob-based launcher change to land simultaneously.

Useful? React with 👍 / 👎.

@sonarqubecloud

sonarqubecloud Bot commented Aug 8, 2026

Copy link
Copy Markdown

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