Skip to content

fix(change-window): preserve LF in managed Git scripts - #8598

Merged
huangruiteng merged 1 commit into
loopx-project:mainfrom
xiaobaifly7:fix/change-window-windows-hook-newlines
Nov 11, 2026
Merged

huangruiteng merged 1 commit into
loopx-project:mainfrom
xiaobaifly7:fix/change-window-windows-hook-newlines

Conversation

@xiaobaifly7

Copy link
Copy Markdown
Contributor

Goal And Delivered Outcome

  • Outcome basis / optional anchor: reproduced Windows defect in repository-change-window installation.
  • Goal/source and gap: a fresh install writes platform-translated CRLF scripts, while the provider stores SHA-256 digests of LF text and verifies the actual file bytes.
  • Observable before → after: on Windows, install exits 0 but immediate verify exits 1 with status=drifted and enabled=false; after this change, the same fresh-repository journey returns status=ready, verified=true, and enabled=true. Both enforcement levels have regression coverage.
  • Issue/task and intended base: self-contained bug fix against main, reproduced at 23bc2e0ed8dc8233620b3e349d686a55941dfc41.

Author Declaration

  • Written by: model_agent — OpenAI Codex (GPT-6).

Implemented against

  • Specification and revision: no written specification; the reproduced defect and request in this PR are the basis. Existing provider behavior is documented in loopx/capabilities/repository_change_window/README.md at the base revision above.
  • Criteria:
Criterion (spec clause) Disposition Symbol / path Test or command
Fresh installation verifies clean on Windows without platform-dependent newline translation implemented git_hook.py::_write_provider_files test_cli_install_verify_round_trip_preserves_lf_scripts
Keep the existing LF digest format and exact-byte drift detection implemented git_hook.py::_provider_checks remains unchanged The regression checks LF bytes, then modifies a script and confirms verify fails
Cover both hook-only and reference-guard managed scripts implemented Hook writer and SSH-command writer in git_hook.py The regression is parameterized over both EnforcementLevel values
  • Self-check before submission: reviewed the writer's caller, CLI install/verify handlers, digest creation and on-disk verification; ran the red/green regression, focused policy checks, real console install/verify and Ruff. No additional abstraction or refactor is needed at this serialization boundary.

Scope And Continuation

  • Completed scope and remaining work: complete within this scope. The existing Python Git IO provider now explicitly writes LF for hooks and the reference-guard SSH script.
  • Slice boundary / successor: no new capability, settings, schema or TypeScript decision owner is introduced; no successor is needed for this defect. Previously drifted installations retain the existing reviewed install --replace recovery path.

Validation

  • Tested revision: 40b9210490106c61e3d6d3da14c7f31f6334efee.
  • Run state: finished.
  • Input classes: synthetic.
Check kind Result Public-safe evidence / limitation
regression_parity passed Before changing production code, uv run --extra test python -m pytest -q tests/capabilities/test_repository_change_window.py -k test_cli_install_verify_round_trip_preserves_lf_scripts failed both enforcement cases at immediate verify. After the fix, both passed.
unit passed uv run --extra test python -m pytest -q tests/capabilities/test_repository_change_window.py tests/capabilities/test_repository_change_window_negative.py -k 'test_cli_install_verify_round_trip_preserves_lf_scripts or policy': 5 passed, 23 deselected on Windows / Python 3.12.13. Includes script-tampering rejection and existing policy cases.
real_entrypoint passed Ran the checkout's uv run --extra test loopx console against a fresh synthetic Git repository. Install succeeded and verify returned ready/enabled/verified after the fix; the same console journey reproduced drift on the unchanged base.
static passed uv run --extra test python -m ruff check loopx/capabilities/repository_change_window/git_hook.py tests/capabilities/test_repository_change_window.py; git diff --check.
  • Coverage and gaps: native Windows source-checkout validation only; POSIX execution, installed-runtime validation and the full suite were not run. The regression asserts platform-independent LF bytes and exact-byte tamper detection. An initial attempt to reuse the older repository helper failed before installation because its text-mode git mktree stdin adds CRLF on Windows; the new regression uses a fresh empty commit instead, leaving that unrelated fixture unchanged. The focused selection is not a claim that the full existing module passes on Windows.

Frontend / Visual Evidence

  • UI impact: none. This changes generated provider file bytes, not presentation or navigation.
  • Before / after / first viewport and preview / states and viewports shown: N/A.
  • Source data: synthetic.
  • Attention review / craft review: N/A; no UI change.

Type of Change

  • Bug fix
  • Test update

LoopX Area

  • Capability or extension (providers, adapters, skills)
  • Host or runtime integration

Technical Direction

  • Direction / acceptance reference: existing built-in repository-change-window capability, bundled git-hook provider. This bounded Python IO fix retains the existing owner and public contracts.

Shared-authority RFC fixture impact

N/A; no shared-authority routing, persistence or migration behavior changes.

Boundary Checklist

  • Neither the diff nor this PR draft discloses private state, credentials, raw traces, verifier logs, internal links or local machine paths.
  • No maintainer-owned benchmark work is duplicated.
  • The change is scoped to the reproduced newline defect.
  • No paired RFC changed.
  • UI impact is marked none.
  • The single commit includes a DCO Signed-off-by trailer (git commit -s).

🤖 Generated with Claude Code

Signed-off-by: xiaobaifly7 <196511160+xiaobaifly7@users.noreply.github.com>

@loopx-agent loopx-agent left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Reviewer: model_agent · gpt-6.1-sol · OpenAI · runtime_reported · max

本次评审对应提交 40b9210490106c61e3d6d3da14c7f31f6334efee。

动机 / Motivation

明确为本地 Git 仓库启用 change-window 的操作员,需要在安装后确认提交和传输保护已经可用。文本写入采用平台换行。当默认换行为 CRLF 时,install 成功后 verify 将未修改的脚本标为 drifted。模拟默认 CRLF 时,两种模式的安装从 verify=drifted 变为 ready,已安装的 CRLF fixture 可通过 --replace 恢复。模拟默认 CRLF 时,两种模式的安装从 verify=drifted 变为 ready,已安装的 CRLF fixture 可通过 --replace 恢复。独立验证用 macOS Git,并在两个文本写点模拟 Windows 默认 CRLF。Windows 原机结果来自作者,已安装版本和托管 CI 未纳入验证。

改动思路 / Approach

LF 是现有脚本模板和摘要的共同字节约定,写入时明确编码即可。代码保留在现有 Python Git IO provider。策略决定和 typed CLI 状态沿用当前结构。 现有模板以 LF 构造,旧 writer 在默认 CRLF 环境会把 LF 转换成 CRLF。verify 按真实磁盘字节做摘要并判漂移。在两个写点指定 newline,让字节与既有摘要协议对齐。

具体改动 / Changes

关键代码讲解

  • 在两种模式逐个检查受管脚本的原始字节、可执行位和保存的 SHA-256。模拟默认 CRLF 时基线 install 成功但 verify 漂移,当前提交生成 LF 且立即 ready。 文件写入
  • macOS 临时仓库使用真实 Git hook。允许时转交原 hook,受限窗口拒绝提交前 hook,reference_guard 的 SSH wrapper 将读取请求实参交给原有本地命令。 校验
  • 两种模式的篡改均被拒绝。把基线生成的两套 CRLF 安装交给新提交,保留旧窗口执行 --replace 后恢复 ready。卸载恢复原有 hooksPath 与 sshCommand。 回归

适用协议 loopx/capabilities/repository_change_window/README.md,按基线 23bc2e0 核对。对应检查为 portable_script_bytes、exact_byte_drift 和 existing_recovery_route。 协议

对主干的风险 / Risks

作用范围限于明确启用 provider 的仓库和生成的 Git shell 脚本。预览与默认关闭在两版均没有写 provider 文件。历史 CRLF 安装会继续报告漂移,显式按原窗口执行 --replace 后可恢复。我在 macOS 使用真实 Git,并在文件写入处模拟 Windows 默认换行。Windows 原机验收为作者报告,已安装版与托管 CI 未复验。

语义与 CI 对齐

28 项相关测试通过,Ruff、DCO、RFC 双语差异与 git diff --check 通过。两版在 macOS 上普通安装、受管 hook、原命令转交和卸载的观测一致,两种模式模拟 CRLF 都有红绿结果。

我的整体评价 / Verdict

两种安装模式现在都能落盘 LF 并通过原有校验。实际字节篡改、默认关闭、已有配置和修复路径均有独立证据。改动集中在现有文件 writer,可以通过评审。本次评审覆盖现有宿主与 CLI 行为。独立验证用 macOS Git,并在两个文本写点模拟 Windows 默认 CRLF。Windows 原机结果来自作者,已安装版本和托管 CI 未纳入验证。

English verdict: APPROVE. Both enforcement levels now write stable LF bytes, which the existing exact-byte verification accepts. Matched macOS Git execution and CRLF translation simulation confirm install, drift, replacement, and restoration. The author supplied the native Windows run.

@huangruiteng
huangruiteng merged commit 661ff60 into loopx-project:main Nov 11, 2026
35 of 45 checks passed
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.

3 participants