Skip to content

fix(config): preserve unknown JSON fields during config updates - #1508

Merged
lizhengfeng101 merged 3 commits into
alibaba:mainfrom
dvd233:fix/config-preserve-unknown-keys-1485
Sep 22, 2026
Merged

lizhengfeng101 merged 3 commits into
alibaba:mainfrom
dvd233:fix/config-preserve-unknown-keys-1485

Conversation

@dvd233

@dvd233 dvd233 commented Sep 20, 2026

Copy link
Copy Markdown
Contributor

Description

ocr config set loads config.json into typed structs and writes the whole file back. Fields introduced by a newer binary, hand-added integrations, or nested provider/MCP sections were silently discarded when an older binary performed an unrelated config update.

This change preserves unknown JSON fields at the top level and in provider, LLM, telemetry, and MCP server sections while keeping known-field validation and config unset behavior unchanged. Provider TUI rollback cloning also deep-copies the preserved raw fields.

Type of Change

  • Bug fix (non-breaking change that fixes an issue)
  • New feature (non-breaking change that adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)
  • Refactoring (no functional changes)
  • Documentation update
  • CI / Build / Tooling

How Has This Been Tested?

  • go test ./cmd/opencodereview -count=1
  • Full Makefile package set with go test -count=1 (all passed; extensions excluded as Makefile does)
  • go vet on the same package set
  • go build ./cmd/opencodereview
  • go run scripts/verify-english-only.go
  • bash scripts/verify-license.sh
  • git diff --check
  • Regression coverage exercises unknown fields at top-level, provider, LLM, telemetry, and MCP nesting.

GNU Make is not installed in the Windows environment, so the Makefile-equivalent commands were run directly. The race suite was not runnable because the available Windows Go toolchain has cgo disabled. The repository ocr review --audience agent self-review command was attempted but could not resolve an LLM endpoint because no test credentials/endpoint are configured.

Checklist

  • My code follows the project's coding style (gofmt, go vet)
  • I have performed a self-review of my code
  • I have added tests that prove my fix is effective or my feature works
  • New and existing unit tests pass locally with my changes
  • I have updated the documentation accordingly (not applicable; no user-facing command syntax changed)
  • I have signed the CLA
  • I used AI/LLM assistance and disclosed it below; I reviewed the output, added no AI attribution to commits, and will answer maintainer questions myself.

AI/LLM disclosure: OpenAI Codex (GPT-5) in the Codex desktop environment assisted with repository inspection and drafting. The submitted code and tests were manually reviewed.

Related Issues

Fixes #1485

@github-actions

github-actions Bot commented Sep 20, 2026

Copy link
Copy Markdown
Contributor

🔍 OpenCodeReview found 1 issue(s) in this PR.

  • ✅ Successfully posted inline: 1 comment(s)

Comment thread cmd/opencodereview/config_cmd.go Outdated
Comment on lines +396 to +405
var (
providerEntryJSONFields = []string{
"api_key", "api_key_cmd", "url", "protocol", "model", "models", "auth_header",
"timeout_sec", "extra_body", "extra_headers", "retry_codes", "aws_profile", "aws_region",
}
mcpServerConfigJSONFields = []string{"type", "command", "args", "env", "url", "headers", "tools", "setup"}
configJSONFields = []string{"provider", "model", "max_tokens", "effort", "providers", "custom_providers", "llm", "language", "telemetry", "mcp_servers"}
llmConfigJSONFields = []string{"url", "auth_token", "auth_token_cmd", "auth_header", "model", "protocol", "use_anthropic", "timeout_sec", "extra_body", "extra_headers", "retry_codes"}
telemetryConfigJSONFields = []string{"enabled", "exporter", "otlp_endpoint", "content_logging"}
)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maintainability · medium
Bug-prone design: the known-field lists (configJSONFields, providerEntryJSONFields, etc.) are maintained separately from the struct definitions. If a developer adds a new field to a struct but forgets to update the corresponding list, the new field will be silently captured as "unknown". While mergeUnknownJSONFields prevents duplication when the struct field has a non-zero value, if the field is later cleared (zero value → omitted via omitempty), the stale unknown copy will resurrect it on the next marshal, producing incorrect config output.

Consider deriving the known-field list from the struct at init time using reflection (iterating over struct fields and reading their json tags). This eliminates the synchronization risk entirely:

func jsonFieldNames(v any) []string {
    t := reflect.TypeOf(v)
    var names []string
    for i := 0; i < t.NumField(); i++ {
        tag := t.Field(i).Tag.Get("json")
        if tag == "" || tag == "-" { continue }
        name, _, _ := strings.Cut(tag, ",")
        names = append(names, name)
    }
    return names
}

Alternatively, add a test that uses reflection to verify each list matches its struct.

@chaojixinren

Copy link
Copy Markdown
Contributor

Thanks for the contribution. The unknown-field round-trip looks correct, and deriving known JSON fields directly from struct tags addresses the maintenance concern from the previous review.

Could you please squash the two commits into a single commit before merging? Since both commits are part of the same fix, keeping the PR as one atomic commit would make the history cleaner.

@wu21-web

wu21-web commented Sep 21, 2026

Copy link
Copy Markdown
Contributor

Isn't this expected behavior @dvd233 ? What is the point of preserving a key that is never going to be used? (Please answer without AI/LLM)
cc @chaojixinren

@chaojixinren

Copy link
Copy Markdown
Contributor

I think the chance of hitting this in practice is relatively low, but I still see value in it as a defensive fix.

One concrete case is a temporary downgrade. Suppose a newer OCR version introduces a new config field, e.g. telemetry.sample_rate, and writes it to config.json. If the user later downgrades to an older version that does not know this field and runs an unrelated command such as:

ocr config set language zh

the older binary will unmarshal the config into its typed struct and write the whole file back, silently dropping sample_rate. When the user upgrades again, that configuration is already lost.

So the point is not that the older binary needs to use the unknown key; it is that changing an unrelated setting should ideally not destroy configuration owned by a newer version.

@wu21-web

wu21-web commented Sep 22, 2026

Copy link
Copy Markdown
Contributor

But older versions were archived and they overwrites jsons anyway because your fix cannot change the behavior of older releases .....
It is good that older versions overwrites unrelated fields.

  • Nobody will downgrade.
  • It is good for the older ones to overwrite new configs values so no useless junk stays in the config.

How are these related?

@chaojixinren

Copy link
Copy Markdown
Contributor

But older versions were archived and they overwrites jsons anyway because your fix cannot change the behavior of older releases .....但旧版本被归档了,而且它们还是会覆盖 json,因为你的修复无法改变旧版本的行为..... It is good that older versions overwrites unrelated fields.旧版本覆盖无关字段是件好事。

  • Nobody will downgrade.  没人会降级。
  • It is good for the older ones to overwrite new configs values so no useless junk stays in the config.旧的配置可以覆盖新配置值,这样配置里就不会留下无用的垃圾。

How are these related?这些有什么关系?

Yeah, I think you're right.

My downgrade example doesn't really justify this, since the fix can't change already released versions anyway. And if config.json is supposed to follow the current OCR schema, dropping unknown fields is reasonable.

The aws_profile / aws_region case was more about the structs being out of sync with fields OCR actually uses.

So I don't think we need a generic unknown-field preservation layer here.

Comment thread cmd/opencodereview/config_cmd.go

@lizhengfeng101 lizhengfeng101 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@lizhengfeng101
lizhengfeng101 merged commit 6d17aa4 into alibaba:main Sep 22, 2026
12 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

ocr config set silently drops config.json keys it does not know

4 participants