Skip to content

fix(cli): preserve numeric config set record keys#83769

Merged
altaywtf merged 4 commits into
openclaw:mainfrom
TurboTheTurtle:fix/config-set-numeric-record-keys-83331
May 21, 2026
Merged

fix(cli): preserve numeric config set record keys#83769
altaywtf merged 4 commits into
openclaw:mainfrom
TurboTheTurtle:fix/config-set-numeric-record-keys-83331

Conversation

@TurboTheTurtle

@TurboTheTurtle TurboTheTurtle commented May 18, 2026

Copy link
Copy Markdown
Contributor

Fixes #83331.

Behavior or issue addressed:

  • openclaw config set channels.discord.guilds.<snowflake>.requireMention true could create guilds as an array because the next path segment was all digits.
  • Discord guild IDs and other channel IDs are numeric-looking strings for record/object fields, so the path writer now consults the runtime config schema before choosing an object vs array container for missing parents.
  • This preserves numeric array-index behavior for schema-backed lists such as agents.list.0.*, while keeping schema-backed records such as channels.discord.guilds.<id> and channels.telegram.groups.<id> as object keys.

Real behavior proof

Behavior or issue addressed: config set now preserves numeric-looking record keys under schema-backed object fields instead of materializing those parents as arrays, while still creating arrays for schema-backed list paths.

Real environment tested: Local OpenClaw checkout on macOS using the real source CLI entrypoint (node --import tsx src/entry.ts) with OPENCLAW_CONFIG_PATH and OPENCLAW_STATE_DIR pointed at a mktemp directory. The command wrote an actual temp openclaw.json; no production user config was modified.

Exact steps or command run after this patch:

tmp=$(mktemp -d)
config=$tmp/openclaw.json
printf '{"channels":{"discord":{"enabled":true}},"agents":{}}\n' > "$config"
export PATH=/Users/andy/.cache/codex-runtimes/codex-primary-runtime/dependencies/node/bin:$PATH
export OPENCLAW_CONFIG_PATH="$config"
export OPENCLAW_STATE_DIR="$tmp/state"
echo "OPENCLAW_CONFIG_PATH=$OPENCLAW_CONFIG_PATH"
node --import tsx src/entry.ts config set channels.discord.guilds.1495587801394184362.requireMention true --strict-json
node --import tsx src/entry.ts config set channels.telegram.groups.1495587801394184362.requireMention true --strict-json
node --import tsx src/entry.ts config set agents.list.0.id '"tech"' --strict-json
python3 - <<'PY' "$config" "$tmp"
import json,sys
cfg=json.load(open(sys.argv[1]))
dguilds=cfg['channels']['discord']['guilds']
tgroups=cfg['channels']['telegram']['groups']
print('config_path=', sys.argv[1])
print('config_under_mktemp=', sys.argv[1].startswith(sys.argv[2]+'/'))
print('discord_guilds_is_array=', isinstance(dguilds, list))
print('discord_guild_keys=', list(dguilds.keys()))
print('discord_requireMention=', dguilds['1495587801394184362']['requireMention'])
print('telegram_groups_is_array=', isinstance(tgroups, list))
print('telegram_group_keys=', list(tgroups.keys()))
print('telegram_requireMention=', tgroups['1495587801394184362']['requireMention'])
print('agents_list_is_array=', isinstance(cfg['agents']['list'], list))
print('agents_list=', cfg['agents']['list'])
PY

Evidence after fix:

OPENCLAW_CONFIG_PATH=/var/folders/65/9nwck85148n01vx6sgp1mn3w0000gn/T/tmp.fJnfT3x1ed/openclaw.json
Updated channels.discord.guilds.1495587801394184362.requireMention. Restart the gateway to apply.
Updated channels.telegram.groups.1495587801394184362.requireMention. Restart the gateway to apply.
Updated agents.list.0.id. Restart the gateway to apply.
config_path= /var/folders/65/9nwck85148n01vx6sgp1mn3w0000gn/T/tmp.fJnfT3x1ed/openclaw.json
config_under_mktemp= True
discord_guilds_is_array= False
discord_guild_keys= ['1495587801394184362']
discord_requireMention= True
telegram_groups_is_array= False
telegram_group_keys= ['1495587801394184362']
telegram_requireMention= True
agents_list_is_array= True
agents_list= [{'id': 'tech'}]
Config write anomaly: /var/folders/65/9nwck85148n01vx6sgp1mn3w0000gn/T/tmp.fJnfT3x1ed/openclaw.json (missing-meta-before-write)

Observed result after fix:

  • Real CLI writes against a mktemp config kept channels.discord.guilds.1495587801394184362 as an object key (discord_guilds_is_array=False).
  • The same schema-backed logic also kept channels.telegram.groups.1495587801394184362 as an object key (telegram_groups_is_array=False).
  • A schema-backed list path still created an array for agents.list.0.id (agents_list_is_array=True, agents_list=[{'id': 'tech'}]).

What was not tested: A globally installed packaged openclaw binary. The patched source CLI entrypoint was tested with a real temp config file, and the normal test harness covers the same mutation path without touching user config.

Validation

Focused regression:

PATH=/Users/andy/.cache/codex-runtimes/codex-primary-runtime/dependencies/node/bin:$PATH node scripts/run-vitest.mjs src/cli/config-cli.test.ts -t "numeric config set path segments|schema-backed numeric list indexes"

Test Files  1 passed (1)
Tests  3 passed | 95 skipped (98)

Full validation:

PATH=/Users/andy/.cache/codex-runtimes/codex-primary-runtime/dependencies/node/bin:$PATH pnpm tsgo:test:src
PATH=/Users/andy/.cache/codex-runtimes/codex-primary-runtime/dependencies/node/bin:$PATH node scripts/run-vitest.mjs src/cli/config-cli.test.ts
PATH=/Users/andy/.cache/codex-runtimes/codex-primary-runtime/dependencies/node/bin:$PATH node_modules/.bin/oxfmt --check --threads=1 src/cli/config-cli.ts src/cli/config-cli.test.ts
PATH=/Users/andy/.cache/codex-runtimes/codex-primary-runtime/dependencies/node/bin:$PATH node_modules/.bin/oxlint src/cli/config-cli.ts src/cli/config-cli.test.ts
git diff --check

Test Files  1 passed (1)
Tests  98 passed (98)
All matched files use the correct format.
Found 0 warnings and 0 errors.

Commit author verification:

b46046b8e6 Andy Ye <35905412+TurboTheTurtle@users.noreply.github.com> fix(cli): use schema for numeric config path containers
6fb04b8643 Andy Ye <35905412+TurboTheTurtle@users.noreply.github.com> fix(cli): preserve numeric config set record keys

@openclaw-barnacle openclaw-barnacle Bot added cli CLI command changes size: S triage: needs-real-behavior-proof Candidate: external PR needs after-fix proof from a real setup. labels May 18, 2026
@clawsweeper

clawsweeper Bot commented May 18, 2026

Copy link
Copy Markdown
Contributor

Codex review: needs maintainer review before merge.

Workflow note: Future ClawSweeper reviews update this same comment in place.

How this review workflow works
  • ClawSweeper keeps one durable marker-backed review comment per issue or PR.
  • Re-runs edit this comment so the latest verdict, findings, and automation markers stay together instead of adding duplicate bot comments.
  • A fresh review can be triggered by eligible @clawsweeper re-review comments, exact-item GitHub events, scheduled/background review runs, or manual workflow dispatch.
  • PR/issue authors and users with repository write access can comment @clawsweeper re-review or @clawsweeper re-run on an open PR or issue to request a fresh review only.
  • Maintainers can also comment @clawsweeper review to request a fresh review only.
  • Fresh-review commands do not start repair, autofix, rebase, CI repair, or automerge.
  • Maintainer-only repair and merge flows require explicit commands such as @clawsweeper autofix, @clawsweeper automerge, @clawsweeper fix ci, or @clawsweeper address review.
  • Maintainers can comment @clawsweeper explain to ask for more context, or @clawsweeper stop to stop active automation.

Summary
The PR makes config set choose missing containers from the runtime config schema so numeric-looking record keys stay object keys while schema-backed list indexes still create arrays, with regression tests and a changelog entry.

Reproducibility: yes. source-reproducible: current main chooses array containers for all-digit next path segments in config set, while Discord guilds and Telegram groups are schema-backed object records. I did not execute the CLI in this read-only review.

PR rating
Overall: 🐚 platinum hermit
Proof: 🦞 diamond lobster
Patch quality: 🐚 platinum hermit
Summary: Good normal PR: the proof is strong, the patch is focused, and no concrete correctness or security blocker surfaced in read-only review.

Rank-up moves:

  • none
What the crustacean ranks mean
  • 🦀 challenger crab: rare, exceptional readiness with strong proof, clean implementation, and convincing validation.
  • 🦞 diamond lobster: very strong readiness with only minor maintainer review expected.
  • 🐚 platinum hermit: good normal PR, likely mergeable with ordinary maintainer review.
  • 🦐 gold shrimp: useful signal, but proof or patch confidence is still limited.
  • 🦪 silver shellfish: thin signal; proof, validation, or implementation needs work.
  • 🧂 unranked krab: not merge-ready because proof is missing/unusable or there are serious correctness or safety concerns.
  • 🌊 off-meta tidepool: rating does not apply to this item.

Shiny media proof means a screenshot, video, or linked artifact directly shows the changed behavior. Runtime, network, CSP, and security claims still need visible diagnostics.

Real behavior proof
Sufficient (terminal): The PR body supplies terminal proof from the real source CLI writing a temporary config file and showing the corrected object-key behavior plus preserved array creation.

Next step before merge
No ClawSweeper repair lane is needed; the PR is ready for ordinary maintainer review and required merge checks.

Security
Cleared: The diff only changes local CLI config path materialization, tests, and changelog text; it adds no dependency, workflow, package-script, secret-handling, or remote code-execution surface.

Review details

Best possible solution:

Land the schema-aware config writer fix after normal maintainer review so #83331 can close through this PR.

Do we have a high-confidence way to reproduce the issue?

Yes, source-reproducible: current main chooses array containers for all-digit next path segments in config set, while Discord guilds and Telegram groups are schema-backed object records. I did not execute the CLI in this read-only review.

Is this the best way to solve the issue?

Yes. Consulting the runtime config schema at the missing-parent path is narrower and more maintainable than hard-coding channel-specific numeric ID paths, and the tests cover both record and list behavior.

Label changes:

  • add proof: sufficient: Contributor real behavior proof is sufficient. The PR body supplies terminal proof from the real source CLI writing a temporary config file and showing the corrected object-key behavior plus preserved array creation.

Label justifications:

  • P2: This is a normal-priority CLI config correctness fix with limited blast radius and focused regression coverage.
  • rating: 🐚 platinum hermit: Current PR rating is 🐚 platinum hermit because proof is 🦞 diamond lobster, patch quality is 🐚 platinum hermit, and Good normal PR: the proof is strong, the patch is focused, and no concrete correctness or security blocker surfaced in read-only review.
  • status: 👀 ready for maintainer look: ClawSweeper has no concrete contributor-facing blocker left for this PR. Sufficient (terminal): The PR body supplies terminal proof from the real source CLI writing a temporary config file and showing the corrected object-key behavior plus preserved array creation.
  • proof: sufficient: Contributor real behavior proof is sufficient. The PR body supplies terminal proof from the real source CLI writing a temporary config file and showing the corrected object-key behavior plus preserved array creation.

What I checked:

  • Current main root cause: Current main still creates a missing parent as an array whenever the next path segment is all digits unless patch mode forces numeric object keys, which explains config set materializing guilds as an array for numeric-looking record keys. (src/cli/config-cli.ts:474, de5f1fa99a09)
  • Existing patch-mode coverage: Current main already has coverage for config patch preserving numeric object keys, so the unique remaining fix in this PR is the config set missing-container path. (src/cli/config-cli.test.ts:1997, de5f1fa99a09)
  • Schema contract for record fields: The channel config schemas model Telegram groups and Discord guilds as z.record(...) object maps, which supports using schema metadata to keep numeric-looking IDs as object keys. (src/config/zod-schema.providers-core.ts:270, de5f1fa99a09)
  • Schema contract for Discord guild records: Discord account config declares guilds as a record keyed by string IDs, not a list, while nested channel maps are also records. (src/config/zod-schema.providers-core.ts:688, de5f1fa99a09)
  • PR implementation shape: The PR diff adds JSON-schema traversal helpers, loads the best-effort runtime config schema for config mutations, and passes that schema into setAtPath/mergeAtPath so missing containers are chosen from the config contract instead of only from digit heuristics. (src/cli/config-cli.ts:459, 6d87faf97a67)
  • PR regression coverage: The PR adds focused tests for Discord numeric guild IDs, Telegram numeric group IDs, and schema-backed array creation for agents.list.0.id. (src/cli/config-cli.test.ts:1319, 6d87faf97a67)

Likely related people:

  • @steipete: Peter Steinberger introduced the original config get/set/unset helper surface and recently touched the generated baseline snapshot containing the current file. (role: introduced behavior and recent area contributor; confidence: high; commits: 2b16a87f043f, 1b1580cbc3f5; files: src/cli/config-cli.ts, src/cli/config-cli.test.ts)
  • @joshavant: Josh Avant expanded config set with builder, SecretRef, provider, and dry-run behavior in the same CLI mutation path. (role: feature-area contributor; confidence: high; commits: e99963100d22, ab5aec137c9e; files: src/cli/config-cli.ts, src/cli/config-cli.test.ts)
  • @vincentkoc: Vincent Koc recently maintained config dry-run/schema validation performance around this CLI surface. (role: recent adjacent contributor; confidence: medium; commits: 3792a39fd65c, 25a2ea448095; files: src/cli/config-cli.ts)
  • @mbelinky: Mikhail Beliakov added the runtime config schema CLI path that this PR now uses to decide object-vs-array materialization. (role: schema surface contributor; confidence: medium; commits: fd934a566bd8; files: src/cli/config-cli.ts, src/config/runtime-schema.ts)

Codex review notes: model gpt-5.5, reasoning high; reviewed against de5f1fa99a09.

@TurboTheTurtle TurboTheTurtle force-pushed the fix/config-set-numeric-record-keys-83331 branch from 376e731 to 6fb04b8 Compare May 18, 2026 21:40
@openclaw-barnacle openclaw-barnacle Bot added proof: supplied External PR includes structured after-fix real behavior proof. and removed triage: needs-real-behavior-proof Candidate: external PR needs after-fix proof from a real setup. labels May 18, 2026
@clawsweeper clawsweeper Bot added rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. P2 Normal backlog priority with limited blast radius. labels May 18, 2026
@clawsweeper clawsweeper Bot added proof: sufficient ClawSweeper judged the real behavior proof convincing. rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR. and removed rating: 🧂 unranked krab Not merge-ready due to missing proof or serious correctness/safety concerns. status: 📣 needs proof The PR needs real behavior proof before ClawSweeper can clear the contributor ask. labels May 18, 2026
@TurboTheTurtle

Copy link
Copy Markdown
Contributor Author

@clawsweeper re-review

@clawsweeper

clawsweeper Bot commented May 18, 2026

Copy link
Copy Markdown
Contributor

🦞🧹
ClawSweeper re-review requested.

I asked ClawSweeper to review this item again.
Action: item re-review queued (workflow sweep.yml, event repository_dispatch).
Result: the existing ClawSweeper review comment will be edited in place when the review finishes.

Re-review progress:

@giodl73-repo giodl73-repo 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.

Looks good. The fix uses the runtime config schema to choose object versus array containers for missing config-set path parents, which addresses numeric-looking record keys without regressing schema-backed array paths. The PR has focused real CLI proof plus full relevant validation and green CI.

@altaywtf altaywtf self-assigned this May 21, 2026
@altaywtf altaywtf force-pushed the fix/config-set-numeric-record-keys-83331 branch from b46046b to 15b06e1 Compare May 21, 2026 20:40
@openclaw-barnacle openclaw-barnacle Bot removed the proof: sufficient ClawSweeper judged the real behavior proof convincing. label May 21, 2026
@clawsweeper clawsweeper Bot added the proof: sufficient ClawSweeper judged the real behavior proof convincing. label May 21, 2026
@clawsweeper

clawsweeper Bot commented May 21, 2026

Copy link
Copy Markdown
Contributor

ClawSweeper PR egg

✨ Hatched: 🌱 uncommon Clockwork Test Hopper

Hatch command

Comment @clawsweeper hatch when this PR is hatchable.

Hatchability rules:

  • Merged PRs are hatchable.
  • Open PRs are hatchable when they are status: 👀 ready for maintainer look, status: 🚀 automerge armed, or labeled clawsweeper:automerge.
  • Closed unmerged PRs are hatchable only when one of those hatchable labels is still present in the durable record.

Rarity: 🌱 uncommon.
Trait: sniffs out flaky tests.
Image traits: location CI tidepool; accessory review stamp; palette violet, aqua, and starlight; mood patient; pose stepping out of a freshly hatched shell; shell soft velvet shell; lighting calm overcast light; background subtle branch markers.
Share on X: post this hatch
Copy: My PR egg hatched a 🌱 uncommon Clockwork Test Hopper in ClawSweeper.

What is this egg doing here?
  • Eggs appear after the PR passes real-behavior proof. It is here for vibes, not verdicts: it does not change labels, ratings, merge decisions, or automation.
  • The shell reacts to review momentum: open follow-up work warms it up, re-review makes it wobble, and a clean final review lets it hatch.
  • Hatchability usually comes from sufficient real-behavior proof, no blocking P0/P1/P2 findings, no security attention needed, and clean correctness. A merged PR is already final, so merge makes the egg hatchable independently.
  • The hatch is seeded from this repository and PR number, so the same PR keeps the same creature; the reviewed head SHA can only change safe visual details.
  • Rarity is just collectible sparkle: 🥚 common, 🌱 uncommon, 💎 rare, ✨ glimmer, and 🌈 legendary.

@openclaw-barnacle openclaw-barnacle Bot removed the proof: sufficient ClawSweeper judged the real behavior proof convincing. label May 21, 2026
@altaywtf altaywtf force-pushed the fix/config-set-numeric-record-keys-83331 branch from cb1e6aa to 6d87faf Compare May 21, 2026 21:28
@clawsweeper clawsweeper Bot added the proof: sufficient ClawSweeper judged the real behavior proof convincing. label May 21, 2026
@altaywtf altaywtf force-pushed the fix/config-set-numeric-record-keys-83331 branch from 6d87faf to 7121fdb Compare May 21, 2026 22:02
@openclaw-barnacle openclaw-barnacle Bot removed the proof: sufficient ClawSweeper judged the real behavior proof convincing. label May 21, 2026
@openclaw-barnacle openclaw-barnacle Bot added agents Agent runtime and tooling extensions: codex size: XL and removed size: M labels May 21, 2026
@altaywtf altaywtf force-pushed the fix/config-set-numeric-record-keys-83331 branch from aa67857 to cb55b4a Compare May 21, 2026 22:08
@openclaw-barnacle openclaw-barnacle Bot added size: M and removed agents Agent runtime and tooling extensions: codex size: XL labels May 21, 2026
@altaywtf altaywtf merged commit 6b5eba1 into openclaw:main May 21, 2026
52 of 110 checks passed
@altaywtf

Copy link
Copy Markdown
Member

Merged via squash.

Thanks @TurboTheTurtle!

@TurboTheTurtle TurboTheTurtle deleted the fix/config-set-numeric-record-keys-83331 branch May 21, 2026 23:21
SebTardif pushed a commit to SebTardif/openclaw that referenced this pull request May 24, 2026
Merged via squash.

Prepared head SHA: cb55b4a
Co-authored-by: TurboTheTurtle <35905412+TurboTheTurtle@users.noreply.github.com>
Co-authored-by: altaywtf <9790196+altaywtf@users.noreply.github.com>
Reviewed-by: @altaywtf
SebTardif pushed a commit to SebTardif/openclaw that referenced this pull request May 24, 2026
Merged via squash.

Prepared head SHA: cb55b4a
Co-authored-by: TurboTheTurtle <35905412+TurboTheTurtle@users.noreply.github.com>
Co-authored-by: altaywtf <9790196+altaywtf@users.noreply.github.com>
Reviewed-by: @altaywtf
SebTardif pushed a commit to SebTardif/openclaw that referenced this pull request May 24, 2026
Merged via squash.

Prepared head SHA: cb55b4a
Co-authored-by: TurboTheTurtle <35905412+TurboTheTurtle@users.noreply.github.com>
Co-authored-by: altaywtf <9790196+altaywtf@users.noreply.github.com>
Reviewed-by: @altaywtf
github-actions Bot pushed a commit to Desicool/openclaw that referenced this pull request May 24, 2026
Merged via squash.

Prepared head SHA: cb55b4a
Co-authored-by: TurboTheTurtle <35905412+TurboTheTurtle@users.noreply.github.com>
Co-authored-by: altaywtf <9790196+altaywtf@users.noreply.github.com>
Reviewed-by: @altaywtf
galiniliev pushed a commit to galiniliev/openclaw that referenced this pull request May 25, 2026
Merged via squash.

Prepared head SHA: cb55b4a
Co-authored-by: TurboTheTurtle <35905412+TurboTheTurtle@users.noreply.github.com>
Co-authored-by: altaywtf <9790196+altaywtf@users.noreply.github.com>
Reviewed-by: @altaywtf
SebTardif pushed a commit to SebTardif/openclaw that referenced this pull request May 26, 2026
Merged via squash.

Prepared head SHA: cb55b4a
Co-authored-by: TurboTheTurtle <35905412+TurboTheTurtle@users.noreply.github.com>
Co-authored-by: altaywtf <9790196+altaywtf@users.noreply.github.com>
Reviewed-by: @altaywtf
SebTardif pushed a commit to SebTardif/openclaw that referenced this pull request May 26, 2026
Merged via squash.

Prepared head SHA: cb55b4a
Co-authored-by: TurboTheTurtle <35905412+TurboTheTurtle@users.noreply.github.com>
Co-authored-by: altaywtf <9790196+altaywtf@users.noreply.github.com>
Reviewed-by: @altaywtf
SebTardif pushed a commit to SebTardif/openclaw that referenced this pull request May 26, 2026
Merged via squash.

Prepared head SHA: cb55b4a
Co-authored-by: TurboTheTurtle <35905412+TurboTheTurtle@users.noreply.github.com>
Co-authored-by: altaywtf <9790196+altaywtf@users.noreply.github.com>
Reviewed-by: @altaywtf
jameslcowan pushed a commit to jameslcowan/openclaw that referenced this pull request Jun 2, 2026
Merged via squash.

Prepared head SHA: cb55b4a
Co-authored-by: TurboTheTurtle <35905412+TurboTheTurtle@users.noreply.github.com>
Co-authored-by: altaywtf <9790196+altaywtf@users.noreply.github.com>
Reviewed-by: @altaywtf
SYU8384 pushed a commit to SYU8384/openclaw that referenced this pull request Jun 3, 2026
Merged via squash.

Prepared head SHA: cb55b4a
Co-authored-by: TurboTheTurtle <35905412+TurboTheTurtle@users.noreply.github.com>
Co-authored-by: altaywtf <9790196+altaywtf@users.noreply.github.com>
Reviewed-by: @altaywtf
sablehead pushed a commit to sablehead/openclaw that referenced this pull request Jun 10, 2026
Merged via squash.

Prepared head SHA: cb55b4a
Co-authored-by: TurboTheTurtle <35905412+TurboTheTurtle@users.noreply.github.com>
Co-authored-by: altaywtf <9790196+altaywtf@users.noreply.github.com>
Reviewed-by: @altaywtf
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

cli CLI command changes P2 Normal backlog priority with limited blast radius. proof: supplied External PR includes structured after-fix real behavior proof. rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. size: M status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

config patch/set coerce numeric-string object keys into array indices

3 participants