mirror of
https://github.com/Jeuners/ECC.git
synced 2026-09-19 11:34:09 +02:00
fix(clv2): align Python _update_registry schema with shell counterpart (#2369)
* fix(clv2): align Python _update_registry schema with shell counterpart The Python `_update_registry` in instinct-cli.py wrote registry entries without the `id` and `created_at` fields, while the shell counterpart in detect-project.sh writes both. A projects.json entry could therefore have a different shape depending on which path (Python CLI or shell hook) last touched it. Emit the same field set and order as the shell version: id, name, root, remote, created_at (preserved from any existing entry), last_seen. Add regression tests asserting field parity and created_at preservation. Fixes #2299 * fix(clv2): guard _update_registry against a non-dict registry entry A malformed projects.json (a non-dict value for the current project id, e.g. null) would make existing.get("created_at", ...) raise and crash the update, losing the old code's ability to self-heal a corrupt per-entry value. Normalize existing to {} when it is not a dict so the entry is healed by the rewrite. Add a regression test for the malformed-entry path. * test(clv2): assert the first-write created_at == last_seen contract The new _update_registry tests only checked both timestamps were truthy. On the initial write both derive from the same `now`, so created_at must equal last_seen; assert that explicitly so a later refactor that breaks the contract is caught. Split the compound assertions into single-expression checks. * fix(clv2): heal a non-dict top-level registry in _update_registry A projects.json that is valid JSON but not a mapping (e.g. `[]` or a string) previously crashed _update_registry on registry.get(), before the per-entry guard could run, so the corrupt file could not be healed. Guard the top-level shape right after the load and fall back to {} so the rewrite repairs the file — matching the per-entry healing already in place. Resolves the remaining CodeRabbit finding on #2299. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
parent
be91f21837
commit
f12b106c3c
2 changed files with 85 additions and 1 deletions
|
|
@ -430,12 +430,32 @@ def _update_registry(pid: str, pname: str, proot: str, premote: str) -> None:
|
|||
registry = json.load(f)
|
||||
except (FileNotFoundError, json.JSONDecodeError):
|
||||
registry = {}
|
||||
# A registry that is valid JSON but not a mapping (e.g. a list from a
|
||||
# corrupt projects.json) must not crash the update before the per-entry
|
||||
# guard below: fall back to an empty dict so the whole file is healed.
|
||||
if not isinstance(registry, dict):
|
||||
registry = {}
|
||||
|
||||
# Mirror the shell counterpart in detect-project.sh: the entry carries
|
||||
# "id" and "created_at" alongside the other fields so a projects.json
|
||||
# record has the same shape regardless of which path (Python CLI or
|
||||
# shell hook) last wrote it. "created_at" is preserved from any
|
||||
# existing entry; only "last_seen" advances on update.
|
||||
now = datetime.now(timezone.utc).isoformat().replace("+00:00", "Z")
|
||||
existing = registry.get(pid, {})
|
||||
# A malformed registry (e.g. a non-dict value for this id) must not
|
||||
# crash the update: fall back to an empty dict so the corrupt entry is
|
||||
# healed by the rewrite, matching the old unconditional-overwrite
|
||||
# behavior.
|
||||
if not isinstance(existing, dict):
|
||||
existing = {}
|
||||
registry[pid] = {
|
||||
"id": pid,
|
||||
"name": pname,
|
||||
"root": proot,
|
||||
"remote": premote,
|
||||
"last_seen": datetime.now(timezone.utc).isoformat().replace("+00:00", "Z"),
|
||||
"created_at": existing.get("created_at", now),
|
||||
"last_seen": now,
|
||||
}
|
||||
|
||||
tmp_file = REGISTRY_FILE.parent / f".{REGISTRY_FILE.name}.tmp.{os.getpid()}"
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue