Skip to content

fix(sheets): never write outside the requested range on positional updates - #941

Open
cathrynlavery wants to merge 2 commits into
openclaw:mainfrom
cathrynlavery:fix/sheets-comma-split
Open

fix(sheets): never write outside the requested range on positional updates#941
cathrynlavery wants to merge 2 commits into
openclaw:mainfrom
cathrynlavery:fix/sheets-comma-split

Conversation

@cathrynlavery

@cathrynlavery cathrynlavery commented Jul 27, 2026

Copy link
Copy Markdown

Problem

gog sheets update <id> "G31" "text, with, commas" parses the positional value as comma-separated rows, so a single-cell write fans out down the column and silently overwrites neighboring cells. We hit this in production against a live tracker sheet.

Fix

  • When the target range resolves to a single cell, the positional value is written literally — commas and pipes are never treated as separators.
  • For finite multi-cell ranges, the parsed matrix is validated against maximum bounds: only payloads whose rows or columns EXCEED the range are rejected (loudly, before the Values API call). Matrices smaller than the range pass through unchanged, preserving the partial-write behavior current main and the Values API support (review round 2 — thanks, the exact-equality check in round 1 was indeed a compatibility regression).
  • Named ranges resolve through the existing range catalog before shape checks. --values-json and append behavior unchanged.
  • links set --cells-json now accepts @file and @- (stdin), matching its sibling flags; docs updated.

Real behavior proof (redacted)

Built from this branch (v0.34.2-0.20260727222104+dirty), run against a disposable test spreadsheet created for this proof; spreadsheet ID redacted:

$ gog sheets update <SHEET_ID> "A1" "text, with, commas"   # single cell, comma-bearing value
Updated 1 cells in 'gog-pr941-proof-disposable'!A1

$ gog sheets get <SHEET_ID> "A1:A3"   # A1 literal, neighbors untouched
text, with, commas

$ gog sheets update <SHEET_ID> "A1:B2" "r1a|r1b,r2a|r2b,r3a|r3b"   # 3 rows into 2-row range -> must reject BEFORE API call
positional values have 3 rows, which exceeds the update range maximum of 2 rows
exit: 2

$ gog sheets update <SHEET_ID> "C1:D2" "only-one-value"   # partial write within larger finite range -> must succeed (P1 compat)
Updated 1 cells in 'gog-pr941-proof-disposable'!C1

$ gog sheets get <SHEET_ID> "C1:D2"
only-one-value

All three review asks demonstrated live: (1) comma-containing single-cell update lands literally in exactly one cell with neighbors untouched, (2) oversize payload rejected before the API call (exit 2), (3) partial positional write within a larger finite range succeeds — the P1 case.

Tests

go test ./internal/sheetsvalues, go test ./internal/cmd -run 'TestSheetsUpdatePositional|TestSheetsLinksSet', and go test ./... all green (42 packages). New coverage: TestSheetsUpdatePositionalPartialMultiCellRangeWritesOneCell (asserts the recorder receives exactly [["one"]]), TestParseArgsForShapeAllowsSmallerMatrix, TestParseArgsForShapeRejectsExceedingRangeBounds, plus the existing single-cell literal and zero-write-on-error assertions.

…dates

- single-cell ranges preserve the positional value literally (commas and
  pipes are no longer treated as row/cell separators), fixing silent
  overwrite of neighboring live cells
- multi-cell positional updates validate parsed shape against the range
  and error loudly on mismatch instead of fanning out past the range
- links set --cells-json now accepts @file and @- like its sibling flags
- command-level HTTP recorder tests prove request bodies and that no
  update call is issued on shape errors
@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. P1 Urgent regression or broken agent/channel workflow affecting real users now. merge-risk: 🚨 compatibility 🚨 Merging this PR could break existing users, config, migrations, defaults, or upgrades. labels Jul 27, 2026
@clawsweeper

clawsweeper Bot commented Jul 27, 2026

Copy link
Copy Markdown
Contributor

Codex review: needs maintainer review before merge. Reviewed July 30, 2026, 7:53 AM ET / 11:53 UTC.

ClawSweeper review

What this changes

The PR makes positional Sheets updates preserve literal single-cell text, rejects positional matrices that exceed finite target-range bounds, resolves named ranges before checking shape, and permits links set --cells-json input from a file or standard input.

Merge readiness

⚠️ Ready for maintainer review - 3 items remain

Keep this PR open for maintainer review: it fixes a source-reproducible Sheets overwrite path, has focused regression coverage and credible redacted live proof, but intentionally changes compatibility for oversized positional payloads targeting finite ranges.

Priority: P1
Reviewed head: 0bee84d15f9fb756a344a558ea7603375cf4fee1
Owner decision: Required. See Decision needed.

Review scores

Measure Result What it means
Overall readiness 🐚 platinum hermit (4/6) A focused, well-tested repair with strong live proof; the remaining question is whether maintainers accept the deliberate finite-range compatibility boundary.
Proof confidence 🦞 diamond lobster (5/6) Sufficient (terminal): The PR body includes a redacted after-fix live CLI transcript from a branch-built binary against a disposable spreadsheet, directly showing all three relevant outcomes.
Patch quality 🐚 platinum hermit (4/6) No actionable review findings were identified.

Verification

Check Result Evidence
Real behavior Verified Sufficient (terminal): The PR body includes a redacted after-fix live CLI transcript from a branch-built binary against a disposable spreadsheet, directly showing all three relevant outcomes.
Evidence reviewed 6 items Current-main behavior: Current main parses positional update arguments with the legacy delimiter-based parser and has no finite-range shape validation on that path, so the reported comma-bearing single-cell input remains source-reproducible there.
Bounded parsing implementation: The PR head adds shape-aware parsing that preserves a one-cell positional value literally and rejects only rows or columns exceeding finite bounds, leaving smaller matrices valid.
Command integration and named ranges: The PR routes positional updates through range-aware parsing and, when necessary, resolves named ranges from the spreadsheet catalog before applying dimensions.
Findings None None.
Security None None.

How this fits together

The Sheets update command parses a user-provided A1 or named range and a positional value matrix before sending it to the Google Sheets Values API. This change adds range-aware validation between command parsing and the API write so a bounded update cannot expand into neighboring cells.

flowchart LR
  A[CLI Sheets update command] --> B[Parse A1 or named range]
  B --> C{Range shape known?}
  C -->|Named range| D[Load spreadsheet range catalog]
  C -->|A1 range| E[Parse positional values]
  D --> E
  E --> F[Check finite range bounds]
  F --> G[Google Sheets Values API]
  G --> H[Requested spreadsheet cells]
Loading

Decision needed

Question Recommendation
Should finite positional Sheets updates fail locally when their matrix exceeds the requested range, rather than preserving the prior API spill behavior? Adopt bounded finite-range writes: Merge the safety fix and accept a clear local error for oversized positional matrices while retaining smaller partial writes.

Why: The patch prevents destructive writes and preserves partial writes, but it deliberately changes behavior for callers that relied on oversized payloads extending beyond a finite target range.

Before merge

  • Resolve merge risk (P1) - Existing scripts that intentionally pass a matrix larger than a finite update range will now fail before the Values API call instead of relying on the prior spill behavior; this is safer but is an intentional compatibility change.
  • Complete next step (P2) - No mechanical repair remains; a maintainer must accept or reject the intentional compatibility change for oversized finite-range positional writes.
Agent review details

Security

None.

Review metrics

Metric Value Why it matters
Patch scope 8 files affected; 393 added, 7 removed Most added lines are focused command and regression-test coverage, plus a small input-parity documentation update.
Behavior cases proved 3 live CLI cases The supplied transcript covers the protected one-cell write, overflow rejection, and compatible partial-write path.

Merge-risk options

Maintainer options:

  1. Accept bounded-write compatibility change (recommended)
    Merge after explicitly accepting that oversized positional payloads against finite ranges now fail locally instead of extending outside the requested range.
  2. Keep legacy spill behind an explicit path
    Pause and redesign the command contract if maintainers need existing oversized positional payloads to remain supported.

Technical review

Best possible solution:

Adopt bounded positional writes if maintainers accept that finite ranges are a hard safety boundary, with the existing partial-write behavior retained and the changed overflow behavior called out in release-facing review context.

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

Yes, at source level: current main still sends positional values through delimiter-based parsing without finite-range dimensions, and the PR supplies a redacted live reproduction against a disposable spreadsheet.

Is this the best way to solve the issue?

Yes, subject to the compatibility decision: range-aware parsing before the Values API is the narrowest way to prevent unintended expansion while the revised patch preserves supported smaller partial writes.

AGENTS.md: found and applied where relevant.

Codex review notes: model internal, reasoning high; reviewed against 1b261244fc26.

Labels

Label justifications:

  • P1: The current command behavior can silently overwrite neighboring spreadsheet cells during an ordinary positional update.
  • merge-risk: 🚨 compatibility: Merging changes existing finite-range callers from permissive spill behavior to a local overflow error.
  • rating: 🐚 platinum hermit: Overall readiness is 🐚 platinum hermit; proof is 🦞 diamond lobster and patch quality is 🐚 platinum hermit.
  • status: 👀 ready for maintainer look: ClawSweeper has no concrete contributor-facing blocker left for this PR. Sufficient (terminal): The PR body includes a redacted after-fix live CLI transcript from a branch-built binary against a disposable spreadsheet, directly showing all three relevant outcomes.
  • proof: sufficient: Contributor real behavior proof is sufficient. The PR body includes a redacted after-fix live CLI transcript from a branch-built binary against a disposable spreadsheet, directly showing all three relevant outcomes.

Evidence

What I checked:

  • Current-main behavior: Current main parses positional update arguments with the legacy delimiter-based parser and has no finite-range shape validation on that path, so the reported comma-bearing single-cell input remains source-reproducible there. (internal/cmd/sheets.go:199, 1b261244fc26)
  • Bounded parsing implementation: The PR head adds shape-aware parsing that preserves a one-cell positional value literally and rejects only rows or columns exceeding finite bounds, leaving smaller matrices valid. (internal/sheetsvalues/values.go:65, 0bee84d15f9f)
  • Command integration and named ranges: The PR routes positional updates through range-aware parsing and, when necessary, resolves named ranges from the spreadsheet catalog before applying dimensions. (internal/cmd/sheets.go:208, 0bee84d15f9f)
  • Regression coverage: Focused tests cover literal single-cell values, finite-range overflow rejection before an update request, partial writes within a larger finite range, and file/stdin batch link input. (internal/cmd/sheets_update_positional_test.go:1, 0bee84d15f9f)
  • Revision provenance: Commit 0bee84d15f9fb756a344a558ea7603375cf4fee1 explicitly revises the first implementation to retain existing partial-write behavior while preserving overflow protection, addressing the prior compatibility finding. (internal/sheetsvalues/values.go:65, 0bee84d15f9f)
  • After-fix live proof: The PR body contains a redacted branch-built transcript against a disposable spreadsheet showing a literal comma-bearing cell write, a pre-API oversized-matrix rejection, and a successful one-cell partial write into a larger finite range. (0bee84d15f9f)

Likely related people:

  • steipete: The repository and Go module namespace identify this as the most likely routing point for an intentional compatibility change; restricted read-only shell access prevented a fuller blame/log attribution pass. (role: likely decision owner; confidence: low; files: internal/cmd/sheets.go, internal/sheetsvalues/values.go)

Rank-up moves

Optional improvements that raise the rating; they are not merge blockers.

  • Record the maintainer decision on finite-range overflow behavior before merging.

Rating scale

Score Internal tier Crab rank Meaning
6/6 S 🦀 challenger crab Exceptional readiness
5/6 A 🦞 diamond lobster Very strong readiness
4/6 B 🐚 platinum hermit Good normal PR; ordinary maintainer review
3/6 C 🦐 gold shrimp Useful, but confidence is limited
2/6 D 🦪 silver shellfish Proof or implementation needs work
1/6 F 🧂 unranked krab Not merge-ready
N/A NA 🌊 off-meta tidepool Rating does not apply

Overall follows the weaker of proof and patch quality.
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.

Workflow

  • 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.

History

Review history (7 earlier review cycles)
  • reviewed 2026-07-27T22:28:13.491Z sha 61e3077 :: needs real behavior proof before merge. :: none
  • reviewed 2026-07-29T16:56:30.920Z sha 61e3077 :: needs real behavior proof before merge. :: [P1] Allow positional payloads smaller than the target range
  • reviewed 2026-07-29T17:27:58.977Z sha 61e3077 :: needs real behavior proof before merge. :: [P1] Allow positional payloads smaller than the target range
  • reviewed 2026-07-29T17:40:00.163Z sha 0bee84d :: needs maintainer review before merge. :: none
  • reviewed 2026-07-29T19:03:54.754Z sha 0bee84d :: needs maintainer review before merge. :: none
  • reviewed 2026-07-29T19:43:46.506Z sha 0bee84d :: needs maintainer review before merge. :: none
  • reviewed 2026-07-30T02:38:25.035Z sha 0bee84d :: needs maintainer review before merge. :: none

… range

Address review: finite-range validation now rejects only matrices that
EXCEED the range's row/column bounds instead of requiring exact shape
equality. Partial positional updates (e.g. one value into Sheet1!A1:B2),
which current main and the Values API support, pass through unchanged.
Single-cell literal preservation and the pre-API oversize rejection are
unchanged. Regression tests added for the partial-write case and for
row/column overflow.
@cathrynlavery

Copy link
Copy Markdown
Author

@clawsweeper re-review

Both blockers addressed in 0bee84d: finite-range validation is now max-bounds (partial writes within a larger finite range pass; only genuine overflow rejects), and the PR body now carries a redacted live-Sheets transcript from a branch-built binary covering the protected, rejected, and partial-write cases. Full suite green.

@clawsweeper

clawsweeper Bot commented Jul 29, 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: when the review finishes, ClawSweeper will create the durable review comment if needed or update the existing comment in place.

Re-review progress:

@clawsweeper clawsweeper Bot added proof: sufficient Contributor real behavior proof is sufficient. 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. merge-risk: 🚨 compatibility 🚨 Merging this PR could break existing users, config, migrations, defaults, or upgrades. 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. merge-risk: 🚨 compatibility 🚨 Merging this PR could break existing users, config, migrations, defaults, or upgrades. labels Jul 29, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

merge-risk: 🚨 compatibility 🚨 Merging this PR could break existing users, config, migrations, defaults, or upgrades. P1 Urgent regression or broken agent/channel workflow affecting real users now. proof: sufficient Contributor real behavior proof is sufficient. 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.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant