Cut the updater's cache, file server and API comments back #69

Merged
Claude merged 6 commits from docs/updater-cache-and-api-comments into feat/firmware-updates 2026-09-20 06:37:08 +00:00
Collaborator

A comment pass over updater/firmware.py, updater/file_server.py,
updater/api.py and their three test files. Narration and restatement go;
rationale, spec citations and the traversal warning stay, cut to a line or two.

No behaviour change. One small readability edit in firmware._check: the two
comments explaining why a None from store is not always a failure are now
two named conditions instead, and the existing tests already pin both branches.

file_server.py's module docstring loses its copy of the manifest JSON. The
shape is the specification's (section 11.1) and manifest() already builds it,
so a second copy here is the stale duplicate CLAUDE.md warns against.

Worth knowing: ruff's D rules are on with no per-file ignores, so D100-D103
require a docstring on every module, class, public function and test. Docstrings
could only be shortened here, never deleted.

A comment pass over `updater/firmware.py`, `updater/file_server.py`, `updater/api.py` and their three test files. Narration and restatement go; rationale, spec citations and the traversal warning stay, cut to a line or two. No behaviour change. One small readability edit in `firmware._check`: the two comments explaining why a `None` from `store` is not always a failure are now two named conditions instead, and the existing tests already pin both branches. `file_server.py`'s module docstring loses its copy of the manifest JSON. The shape is the specification's (section 11.1) and `manifest()` already builds it, so a second copy here is the stale duplicate CLAUDE.md warns against. Worth knowing: `ruff`'s `D` rules are on with no per-file ignores, so D100-D103 require a docstring on every module, class, public function and test. Docstrings could only be shortened here, never deleted.
Cut the updater's cache, file server and API comments back
Some checks failed
Lint, type check and test / hassfest (pull_request) Successful in 19s
Lint, type check and test / release (pull_request) Has been cancelled
Lint, type check and test / quality (pull_request) Has been cancelled
f66abd762d
Cut the updater cache, file server and API test comments back
All checks were successful
Lint, type check and test / hassfest (pull_request) Successful in 19s
Lint, type check and test / quality (pull_request) Successful in 1m44s
Lint, type check and test / release (pull_request) Has been skipped
67ba206789
Claude left a comment

Scope, tabs, spelling and commits are clean; no test body changed (AST comparison with docstrings stripped shows only firmware._check differs). Findings inline, plus two that sit off the diff:

updater/api.py:196 _route, updater/api.py:335 _name and updater/firmware.py:256 _check still carry docstrings that only re-spell the name. Ruff's D102/D103 exempt _-prefixed functions and methods (verified against the repo's own config), so these three could have gone entirely — that was the remaining headroom the pass walked past.

updater/file_server.py:97 is where the traversal defence actually lives, and {image_path(offer): offer for offer in offered(cache)}.get(path) reads as an ordinary dict lookup. The only warning is ~90 lines up in the module docstring. Worth one line at the lookup itself, since a future editor "simplifying" it to a join onto the cache root breaks it silently.

Scope, tabs, spelling and commits are clean; no test body changed (AST comparison with docstrings stripped shows only `firmware._check` differs). Findings inline, plus two that sit off the diff: `updater/api.py:196` `_route`, `updater/api.py:335` `_name` and `updater/firmware.py:256` `_check` still carry docstrings that only re-spell the name. Ruff's D102/D103 exempt `_`-prefixed functions and methods (verified against the repo's own config), so these three could have gone entirely — that was the remaining headroom the pass walked past. `updater/file_server.py:97` is where the traversal defence actually lives, and `{image_path(offer): offer for offer in offered(cache)}.get(path)` reads as an ordinary dict lookup. The only warning is ~90 lines up in the module docstring. Worth one line at the lookup itself, since a future editor "simplifying" it to a join onto the cache root breaks it silently.
@ -28,3 +28,2 @@
# Bound here rather than looked up on the module, because the suite replaces
# that name with a fake to keep every other test off a socket.
# Bound here rather than looked up on the module, which the suite fakes out.
Author
Collaborator

Over-cut. "which the suite fakes out" reads as the module being faked; it is the name on it (tests/conftest.py:91 patches file_server.FirmwareFileServer autouse). The why is gone too. Something like: # Bound here, not looked up on the module: conftest patches that name to keep the rest of the suite off a socket.

Over-cut. "which the suite fakes out" reads as the module being faked; it is the name on it (`tests/conftest.py:91` patches `file_server.FirmwareFileServer` autouse). The why is gone too. Something like: `# Bound here, not looked up on the module: conftest patches that name to keep the rest of the suite off a socket.`
@ -106,3 +90,4 @@
"""One check at a time: two racing share a part-file and overwrite each other."""
FETCH_STOP = threading.Event()
"""Set once the service is stopping, so a fetch gives up instead of finishing.
Author
Collaborator

Lost "Nothing clears it: the process is on its way out, and the next one starts with an event of its own." That is a real invariant, not narration: updater/service.py:74 is the only .set() and nothing in updater/ ever clears it — only the tests do, to fake a fresh process. Without the line a reader sees a module-global Event that is set and never reset and cannot tell whether that is deliberate or a bug. Put it back as one line.

Lost "Nothing clears it: the process is on its way out, and the next one starts with an event of its own." That is a real invariant, not narration: `updater/service.py:74` is the only `.set()` and nothing in `updater/` ever clears it — only the tests do, to fake a fresh process. Without the line a reader sees a module-global `Event` that is set and never reset and cannot tell whether that is deliberate or a bug. Put it back as one line.
@ -314,1 +282,3 @@
if node_for_environment(environment) is not None:
we_stopped_it = FETCH_STOP.is_set()
no_node_wants_it = node_for_environment(environment) is None
if not we_stopped_it and not no_node_wants_it:
Author
Collaborator

not we_stopped_it and not no_node_wants_it is a double negative, which costs back most of what the named booleans bought. a_node_wants_it = node_for_environment(environment) is not None and if not we_stopped_it and a_node_wants_it reads straight.

Behaviour is preserved either way — node_for_environment is pure (prefix check plus an enum lookup with KeyError caught), so evaluating it unconditionally when the stop is set only costs a lookup.

`not we_stopped_it and not no_node_wants_it` is a double negative, which costs back most of what the named booleans bought. `a_node_wants_it = node_for_environment(environment) is not None` and `if not we_stopped_it and a_node_wants_it` reads straight. Behaviour is preserved either way — `node_for_environment` is pure (prefix check plus an enum lookup with `KeyError` caught), so evaluating it unconditionally when the stop is set only costs a lookup.
Take the review: keep the stop's invariant, drop private restatement
All checks were successful
Lint, type check and test / hassfest (pull_request) Successful in 8s
Lint, type check and test / quality (pull_request) Successful in 1m38s
Lint, type check and test / release (pull_request) Has been skipped
cce505681f
Claude left a comment

One thing left.

One thing left.
@ -119,18 +94,18 @@ class NodeRequestHandler(BaseHTTPRequestHandler):
body = json.dumps(manifest(cache), indent=2, sort_keys=True).encode()
self.respond(HTTPStatus.OK, "application/json", body + b"\n")
return
# Matched against what was advertised, never joined onto the cache root:
Author
Collaborator

Yes, this is now a duplicate. Keep it here and cut the first sentence of the last paragraph of the module docstring — this is where an editor about to break it will be standing, and the paragraph still reads whole starting at "There is deliberately no authentication".

Yes, this is now a duplicate. Keep it here and cut the first sentence of the last paragraph of the module docstring — this is where an editor about to break it will be standing, and the paragraph still reads whole starting at "There is deliberately no authentication".
Take the review: the traversal warning belongs at the lookup
All checks were successful
Lint, type check and test / hassfest (pull_request) Successful in 25s
Lint, type check and test / quality (pull_request) Successful in 1m50s
Lint, type check and test / release (pull_request) Has been skipped
79081e035c
Claude left a comment

Clean. Nothing outstanding.

Clean. Nothing outstanding.
Merge feat/firmware-updates into docs/updater-cache-and-api-comments
All checks were successful
Lint, type check and test / hassfest (pull_request) Successful in 10s
Lint, type check and test / quality (pull_request) Successful in 2m4s
Lint, type check and test / release (pull_request) Has been skipped
8ab4fc5d7e
Merge feat/firmware-updates into docs/updater-cache-and-api-comments
All checks were successful
Lint, type check and test / hassfest (pull_request) Successful in 30s
Lint, type check and test / quality (pull_request) Successful in 1m54s
Lint, type check and test / release (pull_request) Has been skipped
3fb0fff2b2
Claude merged commit 1c867a7aab into feat/firmware-updates 2026-09-20 06:37:08 +00:00
Claude deleted branch docs/updater-cache-and-api-comments 2026-09-20 06:37:08 +00:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
rob/CampervanHomeAssistant!69
No description provided.