Repository navigation
fix(config): accept null skill sections when updating the blocklist - #914
Conversation
The loader accepts a null skillForge section, but block/unblock either crashed or created a second section under the other spelling. Treat null as an empty section for a write, retain the existing spelling, and refuse other invalid section types without overwriting them.
gloryfromca
left a comment
There was a problem hiding this comment.
No blockers; this can merge as far as I am concerned.
Reviewed the full github/main...HEAD diff, the set_skill_blocked callers, Raven/base loader behavior, the prior key-spelling fix and relevant history, backward compatibility across camelCase and snake_case inputs, and the added tests for signs of weakened coverage. I also checked the applicable AGENTS.md rules and CONTEXT-MAP.md architecture routing; no project-rule or architecture conflict was found.
Verification:
uv run --all-extras pytest tests/test_config_update.py tests/test_cli_skill_commands.py -x-> 93 passeduv run --all-extras pytest tests/test_config_raven_sections.py -x-> 38 passedgit diff --check github/main...HEAD-> clean
The first run without --all-extras stopped in autouse fixture setup because raven_everos was unavailable (4 setup errors); rerunning with the project extras reached and passed all focused tests.
|
Windows compatibility review: no new issue found in the inspected scope. Reviewed head Native Windows / Python 3.13.12, in a detached temporary checkout with uv run pytest tests/test_config_update.py tests/test_cli_skill_commands.py -k 'skill_block or skill_unblock' -n 0 -x --tb=short --basetemp "$reviewRunDir/pr914/tests"Result: 18 passed, 75 deselected. The remaining configuration/CLI tests and concurrent readers holding files open were not exercised. This scoped review does not establish full Windows compatibility. |
|
No blockers in the reviewed scope. Scope: I reviewed the full PR diff (3 changed files), including tests and documentation, and traced affected callers and contracts at Checked camelCase and snake_case selection, null and absent sections, malformed-section preservation, case-insensitive idempotence, atomic no-op writes, CLI behavior, and load_raven_config readback. An absent unblock does not rewrite a null section; an invalid non-object section is refused without overwriting it. Verification (native Windows, Python 3.12, isolated source snapshots; local JUnit-output options omitted below):
The four failing IDs are unchanged Windows permission-mode tests and reproduce at the merge base. The null-section, spelling, invalid-section, and no-op cases passed. No new finding was identified. I also read the Python 3.13 Windows review. Its conclusions are consistent; the measurements here record a separate Python 3.12 run.
|
58cbcb4 to
986cc6e
Compare
gloryfromca
left a comment
There was a problem hiding this comment.
No blockers; this can merge as far as I am concerned.
The source tree is byte-identical to the previously reviewed clean revision: both commits have tree d30bf2d514d63f523977c4d0f82cb23e6d91c2a5 and parent 4acc63cebd0752652194f9e4989628da29a8a25d. The only change is removal of the Co-authored-by: Codex trailer. The rewritten commit remains English, ASCII-only, conventionally formatted, and within the repository's commit rules.
I did not rerun tests because no source or test byte changed; the prior 93 focused and 38 surrounding-config passing results apply to this exact tree. git diff --check github/main...HEAD remains clean.
|
Windows compatibility re-review: no new issue found in the inspected scope. Reviewed the complete 3-file PR diff at Git checks: source tree identical to previously reviewed Native Windows / Python 3.13.12, detached checkout, PR head: uv run pytest 'tests/test_config_update.py' 'tests/test_cli_skill_commands.py' -k 'skill_block or skill_unblock' -n 0 -x --tb=short --basetemp 'C:\Users\livxu\AppData\Local\Temp\raven-windows-review\fa39f19b3fcb4d7daa4ad3b9472340f8\pr914\unit-pytest'
# 18 passed, 75 deselected in 8.81s; exit 0Limits: The remaining configuration/CLI tests, concurrent readers holding files open and the full repository suite were not exercised. This scoped result does not establish full Windows compatibility. |
|
Not a blocker -- board acceptance of #914 at head 986cc6e merged onto main 829eb28: graded A. There are two small follow-ups. I reproduced both on that merged tree. Severity of this one finding, not a verdict on the pull request. The blocking findings from this pass are review threads on the changed files; GitHub renders those collapsed, as a file name with no text. 1. The null-section rule lives in one of the two writers of
Object and absent sections succeed through both writers. Both refused this file on main, so nothing regressed, but the two writers now disagree about the same file. 2. The new ValueError on the unblock path is untested. I made the raise conditional on @pytest.mark.parametrize("blocked", [True, False])
@pytest.mark.parametrize("spelling", ["skillForge", "skill_forge"])
@pytest.mark.parametrize("invalid", [[], 1, "invalid"])
def test_skill_block_preserves_an_invalid_section(cfg_path, spelling, invalid, blocked):
cfg_path.write_text(json.dumps({spelling: invalid}), encoding="utf-8")
before = cfg_path.read_bytes()
with pytest.raises(ValueError, match="object or null"):
set_skill_blocked("alpha", blocked, config_path=cfg_path)
assert cfg_path.read_bytes() == before |
## Summary A config containing `skillForge: null` beside a populated `skill_forge` loaded successfully, but saving a setting could fill the null alias and leave two active blocks. The next settings read or runtime startup then failed validation. The same problem affected session-title and skill-gate role pins. Use one key-spelling selector for `settings.set`, raw self-configuration reads and writes, and skill block/unblock. It prefers an existing non-null value, then preserves an existing null spelling, and creates a section only when appropriate. Invalid sections such as `false`, `0`, arrays and strings still reach validation and leave the original file unchanged on refusal. Both dotted writes and whole-block pin merges return the actual previous value. This consolidates the settings writer change from #925 and retains the block/unblock guards and same-turn Manifest grouping regressions following #913 and #914. No settings keys or RPC fields are added. ## Type - [x] Fix - [ ] Feature - [ ] Docs - [ ] CI / tooling - [ ] Refactor - [ ] Other ## Verification Native Windows, Python 3.12.13, with an isolated user profile and Raven home. Imports were checked to resolve from the reviewed checkout. The real user's configuration was hash-checked before and after each command. ```text uv run --frozen --no-sync pytest tests/test_rpc_settings.py tests/test_config_update.py tests/test_config_self_surface.py -k 'non_null_alias or two_null_aliases or invalid_alias_beside_null' -q -n 0 --tb=short ``` 35 passed. Before the implementation change, the initial regression selection had 19 failures and 8 passing controls. Replacing the non-null predicate with a truthiness check produces 15 failures and 5 passing controls; the mutation ran in a separate process without modifying source files. The broader test selection was: ```text uv run --frozen --no-sync pytest tests/test_rpc_settings.py tests/test_rpc_console.py tests/test_config_update.py tests/test_config_self_surface.py tests/test_raven_config_tool.py tests/test_rpc_contract_shapes.py tests/test_cli_skill_commands.py tests/test_curator_context_engine.py tests/test_history_trimmer.py -q -n 0 --tb=short ``` The final run additionally emitted JUnit and coverage XML outside the checkout and measured `--cov=raven.config.keys`: 740 passed and 8 failed; the shared selector has 100% line and branch coverage. The same selection on unmodified current main yielded 673 passed and the identical 8 failing test IDs, with zero introduced failures. Those failures concern native Windows path spelling, state-home isolation, CRLF output, four POSIX file-mode assertions, and session usage. The full repository suite was not run locally. ```text uv run --frozen --no-sync pre-commit run --files raven/config/keys.py raven/config/self_surface.py raven/config/update.py raven/rpc/methods/console.py tests/test_config_self_surface.py tests/test_config_update.py tests/test_rpc_settings.py tests/test_curator_context_engine.py uv run --frozen --no-sync ty check raven/config/keys.py raven/config/self_surface.py raven/config/update.py raven/rpc/methods/console.py uv run --frozen --no-sync lint-imports uv run --frozen --no-sync python scripts/check_source_language.py origin/main uv run --frozen --no-sync python scripts/check_large_files.py origin/main git diff --check origin/main ``` Applicable hooks, type checks, all ten import contracts, source-language and repository-file gates passed. - [x] Relevant tests pass locally - [x] Relevant lint / type checks pass locally - [ ] User-facing docs or screenshots are updated when needed The focused regressions pass; the broader native Windows baseline failures are disclosed above. The writer's code contract is updated. No user-facing controls require documentation changes. ## Risk - [x] Security impact considered - [x] Backward compatibility considered - [x] Rollback path is clear for risky changes When one spelling is null and another holds a value, writes and raw reads now follow the non-null spelling. Invalid non-object sections remain invalid, including when a null alias is present. Existing spelling, unrelated fields, the settings allowlist, validation and locked atomic writes are preserved. A null base section such as `tools` can become loadable when the requested setting initializes it. No migration is required; revert this PR to roll back. ## Related Issues #913, #914. Supersedes #925. --------- Co-authored-by: Codex <noreply@openai.com>
Summary
The loader accepts a null skillForge section, but block/unblock either crashed or created a second section under the other spelling. Treat null as an empty section for a write, retain the existing spelling, and refuse other invalid section types without overwriting them.
The CLI regression checks block/unblock, case-insensitive idempotence, a loadable result and an absent unblock that leaves the original bytes unchanged. The unblock output must not name a key the write did not use.
Type
Verification
Native Windows, Python 3.12. PYTHONUTF8=1; the existing environment was selected through UV_PROJECT_ENVIRONMENT, and PYTHONPATH pointed at this checkout.
Result: 10 passed in the targeted selection. The broader two-file selection previously produced 89 passed and 4 failed at the pre-existing POSIX permission assertions in config-update tests. Those failures were reproduced in the main audit; the affected permission-writing code is unchanged. The relevant-tests box remains unchecked for the broader selection.
Whole-branch gates:
All listed gates passed. The whole-branch review covered callers, ownership, guard boundaries, failure paths, regression strength, architecture and compatibility. No screenshot change applies; directly affected code documentation is updated where needed. The full repository suite and Linux/macOS execution were not run locally; the local Docker Linux engine was unavailable.
Risk
Only an absent or null selected section is initialized. Other invalid types fail without rewriting the file. Existing dictionaries, spelling precedence and no-op behavior remain intact. Revert the squash commit to roll back.
Related Issues
#500