test(types/agent): pin SessionMode strict-variant deserialization (audit-disputed)#5416
Conversation
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: e982a7851d
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| @@ -1,39 +0,0 @@ | |||
| # `SessionMode` deserialization silently falls back on unknown values; typos cause semantic drift | |||
There was a problem hiding this comment.
Keep issue index consistent with deleted audit file
Deleting this file leaves a dangling link in docs/issues/INDEX.md (the session-mode-deserialize-fallback entry at line 182 still points to session-mode-deserialize-fallback.md). That breaks documentation navigation and any tooling that expects every indexed issue slug to resolve to an existing markdown file; either keep the file as a disputed record or remove/update the index entry in the same change.
Useful? React with 👍 / 👎.
…oses #5415) audit: session-mode-deserialize-fallback (Severity: Medium, audit status: **DISPUTED** in the re-audit 2026-05-18). The audit doc's framing — `session_mode = "New"` silently collapses to `Persistent` — contradicts serde semantics. serde's standard `#[derive(Deserialize)] enum` errors hard on unknown variants when there's no `#[serde(other)]` arm, and `#[default]` only kicks in for `#[serde(default)]` container/field initialisation on a missing key — not as a fallback for unknown variant strings. The bug as described does not currently exist. But: the boundary that makes the audit's framing wrong is also the boundary that a refactor could quietly remove (adding `#[serde(other)]` to silence "unknown variant" errors looks like a reasonable forward-compat tweak). If that ever happens, operators who type `"New"` instead of `"new"` would land on CLAUDE.md's "concurrent writes to a single persistent session are undefined" warning. So this PR is a documentation-and-regression-test patch: * Comment block on `SessionMode` records the strict-variant contract and points at the tests so a future refactor knows what it's about to break. * Four new tests in `agent::tests`: - `session_mode_deserializes_lowercase_persistent_and_new` — happy path. - `session_mode_rejects_capitalised_variant_strings` — `"New"` / `"PERSISTENT"` must error with "unknown variant". - `session_mode_rejects_empty_string_and_typos` — `""`, `"presistent"`, `"none"`, `"default"` all hit the same path. - `optional_session_mode_default_fires_on_missing_key_not_unknown_string` — `#[serde(default)] Option<SessionMode>` is the per-cron-job / per-trigger override shape. Pins that `default` only fires when the key is MISSING; an explicit `"New"` still errors. cargo clippy -p librefang-types --all-targets clean. 4/4 tests pass. Out of scope (audit's secondary recommendation): extend the existing `debug!(session_mode=resolved, …)` in `cron_tick.rs:198-206` to the manifest-load path so operators see the resolved value at boot. That's a separate observability PR — the load sites span boot.rs, agent_state.rs, agent_control.rs and need consistent log targets. Bundling it here would expand scope beyond "pin the boundary the dispute relies on."
e982a78 to
380cff5
Compare
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
# Conflicts: # openapi.json # sdk/go/librefang.go # sdk/javascript/index.js # sdk/python/librefang/librefang_client.py # sdk/rust/src/lib.rs
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
# Conflicts: # xtask/baselines/openapi.sha256
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 0339d20f73
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| @@ -1,39 +0,0 @@ | |||
| # `SessionMode` deserialization silently falls back on unknown values; typos cause semantic drift | |||
There was a problem hiding this comment.
Remove stale issue-index entry for deleted audit doc
Deleting this file leaves a dangling link in docs/issues/INDEX.md (session-mode-deserialize-fallback at line 182 still points to session-mode-deserialize-fallback.md). That breaks issue navigation and any tooling that expects every indexed slug to resolve to an existing markdown file; update the index entry in the same change when removing this document.
Useful? React with 👍 / 👎.
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
Closes #5415.
Audit
docs/issues/session-mode-deserialize-fallback.md(Severity: Medium, audit status: DISPUTED in re-audit 2026-05-18).The audit doc's original framing was that
session_mode = "New"(capitalised typo) silently collapses toPersistentbecause#[serde(rename_all = "snake_case")] #[default] Persistentlacks#[serde(other)]. That framing contradicts serde semantics: the standard#[derive(Deserialize)] enumerrors hard on unknown variants when there's no#[serde(other)]arm, and#[default]only fires for#[serde(default)]container/field init on a missing key — not as a fallback for unknown variant strings.The bug as described does not currently exist.
Why a PR anyway
The boundary that makes the audit's framing wrong is also the boundary that a refactor could quietly remove. Adding
#[serde(other)]to silence "unknown variant" errors looks like a reasonable forward-compat tweak. If that ever happens, operators who type"New"instead of"new"would land on CLAUDE.md's "concurrent writes to a single persistent session are undefined" warning.So this is a documentation-and-regression-test patch that pins the boundary.
Change
crates/librefang-types/src/agent.rs:SessionModerecords the strict-variant contract and points at the tests so a future refactor knows what it's about to break.agent::tests:session_mode_deserializes_lowercase_persistent_and_new— happy path.session_mode_rejects_capitalised_variant_strings—"New"/"PERSISTENT"must error withunknown variant.session_mode_rejects_empty_string_and_typos—"","presistent","none","default"all hit the same path.optional_session_mode_default_fires_on_missing_key_not_unknown_string—#[serde(default)] Option<SessionMode>is the per-cron-job / per-trigger override shape. Pins thatdefaultonly fires when the key is MISSING; an explicit"New"still errors.cargo test -p librefang-types --lib session_mode→ 4/4 pass.cargo clippy -p librefang-types --all-targets -- -D warningsclean.Out of scope
The audit's secondary recommendation — extend the existing
debug!(session_mode=resolved, …)incron_tick.rs:198-206to the manifest-load path so operators see the resolved value at boot — is a separate observability PR. The load sites spanboot.rs,agent_state.rs,agent_control.rsand need consistent log targets / structured fields. Bundling it here would expand scope beyond "pin the boundary the dispute relies on."