Skip to content

fix(presets): return None for an unreadable layer in resolve_content - #3959

Open
marcelsafin wants to merge 2 commits into
github:mainfrom
marcelsafin:fix/resolve-content-decode
Open

fix(presets): return None for an unreadable layer in resolve_content#3959
marcelsafin wants to merge 2 commits into
github:mainfrom
marcelsafin:fix/resolve-content-decode

Conversation

@marcelsafin

Copy link
Copy Markdown
Contributor

Description

PresetResolver.resolve_content() reads the winning layer (and each composition layer) with a bare read_text(), so a layer file that cannot be read or decoded crashes command registration with a raw OSError/UnicodeDecodeError. The docstring already promises "Composed content string, or None if not found" — and since #3896, collect_all_layers() deliberately keeps a non-UTF-8 legacy layer (with its replace default) so unrelated commands still resolve, which moves the crash here, where both callers (_register_commands and _reconcile_composed_commands) are unguarded.

Fix: return None when the winning/base layer or a composition layer cannot be read, treating an unreadable layer like a missing one per the documented contract. _read_layer_content becomes Optional[str] accordingly.

Testing

  • Tested locally with uv run specify --help
  • Ran existing tests with uv sync && uv run pytest (6,310 passed, 176 skipped)
  • New regression test test_resolve_content_unreadable_winning_layer_returns_none (fails on main, passes with fix)
  • ruff check src tests clean

AI Disclosure

  • I did not use AI assistance for this contribution
  • I did use AI assistance (describe below)

Implemented autonomously by GitHub Copilot CLI (model: Claude Fable 5) under human direction; TDD (failing test first), full suite and lint verified locally. Commit includes Assisted-by/Co-authored-by trailers.

PresetResolver.resolve_content() reads the winning layer (and each
composition layer) with a bare read_text(), so a layer file that cannot
be read or decoded crashed command registration with a raw
OSError/UnicodeDecodeError. The docstring already promises 'Composed
content string, or None if not found', and since github#3896
collect_all_layers() deliberately tolerates a non-UTF-8 legacy layer —
moving the crash here, where both callers (_register_commands and
_reconcile_composed_commands) are unguarded.

Return None when the winning or base layer cannot be read, treating an
unreadable layer like a missing one per the documented contract.

Assisted-by: GitHub Copilot (model: claude-fable-5, autonomous)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings August 3, 2026 19:56
@marcelsafin
marcelsafin requested a review from mnriem as a code owner August 3, 2026 19:56

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

Updates preset content resolution to tolerate unreadable or invalidly encoded layers.

Changes:

  • Returns None when base, winning, or composition layers cannot be read.
  • Adds regression coverage for an undecodable winning layer.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

File Description
src/specify_cli/presets/__init__.py Handles layer read and decoding failures.
tests/test_presets.py Tests an undecodable winning layer.

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

Comment thread tests/test_presets.py
Review follow-up: add an unreadable replace base beneath a valid
composing layer, and a mocked-PermissionError composing layer over a
valid base, so every new boundary and both exception types are covered.

Assisted-by: GitHub Copilot (model: claude-fable-5, autonomous)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings August 3, 2026 20:13

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 2 out of 2 changed files in this pull request and generated no new comments.

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.

2 participants