58def load_octrc(project_root: Path) -> tuple[dict, list[str]]:
59 """Load the project's OCT RC config (``.octrc.json`` / ``octrc.json``).
61 FS-539: prefers ``.option_c/octrc.json`` when present, falls back to
62 the legacy ``<project_root>/.octrc.json`` otherwise. The concrete
63 path is resolved via :func:`oct.core.option_c_dir.resolve_octrc`.
67 (config, errors) : tuple[dict, list[str]]
68 ``config`` is the parsed JSON object, or an empty dict if the file
69 is missing / unreadable / malformed / not a JSON object.
70 ``errors`` is a list of human-readable error strings; empty when
71 the file was absent or loaded successfully.
74 _dbg(
"OCT-CORE", func, f
"loading octrc for {project_root}", 3)
75 octrc_path = resolve_octrc(project_root)
76 label = octrc_path.name
77 if not octrc_path.is_file():
81 raw = octrc_path.read_text(encoding=
"utf-8")
82 except OSError
as exc:
83 return {}, [f
"{label} unreadable: {exc}"]
86 data = json.loads(raw)
87 except json.JSONDecodeError
as exc:
88 return {}, [f
"{label} has invalid JSON: {exc}"]
90 if not isinstance(data, dict):
92 f
"{label} must be a JSON object, got "
93 f
"{type(data).__name__}"