Skip to content

Land browser pool update boundaries on main - #116

Merged
IlyaasK merged 2 commits into
mainfrom
hypeship/land-pr115-on-main
Aug 5, 2026
Merged

Land browser pool update boundaries on main#116
IlyaasK merged 2 commits into
mainfrom
hypeship/land-pr115-on-main

Conversation

@IlyaasK

@IlyaasK IlyaasK commented Aug 5, 2026

Copy link
Copy Markdown
Collaborator

Summary

Why

#115 was still based on the merged #114 branch. Merging it therefore advanced that stale branch rather than the canonical main branch. This PR replays the resulting reviewed commit onto current main without changing its file-level behavior.

How

The #115 squash result was cherry-picked onto current main. It applied cleanly, so the resulting diff is the reviewed #115 change while retaining the project ID update fix already present on main through #113.

Verification

  • gofmt -l cmd internal
  • go test -short -timeout=2m ./...
  • go vet ./...
  • bash scripts/check-docs.sh
  • bash scripts/check-markdown-links.sh
  • bash scripts/check-examples.sh (all five configurations validated with the locally built provider)
  • git diff --check origin/main...HEAD

The five sequential review gates and Cursor Bugbot completed clean on #115. This bridge contains the same reviewed implementation applied to current main.

Intentionally unsupported

No browser-pool data source, runtime browser operations, force deletion, leased-browser state, or other session behavior is added.


Note

Medium Risk
Changes Terraform plan/apply semantics (replacement on name/viewport clear, in-place profile clear, computed defaults), which can surprise operators or trigger destructive pool replacement; scope is limited to the browser pool resource with broad test coverage.

Overview
This PR tightens kernel_browser_pool planning and updates so behavior matches Kernel API limits and avoids noisy or incorrect diffs.

Clear vs replace: Clearing profile_id is now an in-place update (empty profile in the patch) instead of a hard error. Clearing name or viewport plans resource replacement via schema plan modifiers, with ModifyPlan warnings that the pool and its browsers will be deleted (and leased browsers can block apply). Diagnostics that rejected unsupported clears for those fields are removed.

Planning stability: chrome_policy gets a plan modifier so semantically equivalent JSON does not force updates. extension_ids is optional+computed with create-time default [], state preservation on omit, and flattening that reflects API empty lists. Other computed fields (headless, timeouts, viewport refresh rate, etc.) use UseStateForUnknown / related modifiers so unrelated edits do not churn unknown computed values.

Tests and docs: Regression tests cover replacement planning, profile clear patches, chrome policy equivalence, and extension list behavior; generated browser_pool resource docs describe omit/clear/replace rules.

Reviewed by Cursor Bugbot for commit 9587351. Bugbot is set up for automated code reviews on this repo. Configure here.

* Tighten browser pool update boundaries

* Prevent no-op browser pool updates

* Normalize imported empty extension lists

* Fix browser pool planning after restack

Adapt tests to the updated base, preserve unknown nested refresh defaults, follow organization-specific fill-rate limits, and clear profiles in place through the SDK-documented payload.

* Warn before browser pool replacement

* Close browser pool planning test gaps
@IlyaasK

IlyaasK commented Aug 5, 2026

Copy link
Copy Markdown
Collaborator Author

Closing because #115 still requires human review before its changes can land on main.

@IlyaasK IlyaasK closed this Aug 5, 2026
@IlyaasK IlyaasK reopened this Aug 5, 2026
@IlyaasK
IlyaasK requested a review from Sayan- August 5, 2026 13:26

@Sayan- Sayan- left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Checked the four API-contract claims against packages/api and they all hold: profile clears via {"id": ""} per poolProfileClearsRef, extensions clear on empty array and preserve on omission, fill_rate_per_minute is correctly lower-bound-only since the cap is per-organization, and name/viewport genuinely cannot be cleared in place. The schema descriptions match the OpenAPI wording closely.

RequiresReplace on a name/viewport clear is the right call over the previous plan-time error, since an error leaves the user with a config Terraform can never converge on. The blast radius is also bounded in a way worth noting: non-forceful delete is blocked while any browser is leased, so replacing a busy pool fails at destroy rather than discarding in-flight work. The warning text states that accurately.

Two cleanups:

  1. validateSupportedUpdateClears still carries the name and viewport branches, but they can no longer surface as errors — those are exactly the conditions the new schema modifiers turn into a replacement, so Update is never reached for them. They do still run inside idleBrowserRebuildWarningRequired, where they suppress the idle-rebuild warning on the stale premise that the clear blocks the update. The net behavior is harmless (replacement supersedes the idle warning), but the code now reads as if clearing a name blocks an update when it actually recreates the pool. Worth picking one mechanism and deleting the other so the next reader isn't guessing.

  2. browserPoolReplacementRequired recomputes what the attribute plan modifiers already decided. Resource-level ModifyPlan runs after schema plan modification, so resp.RequiresReplace is already populated by the time you get there — checking that directly would drop the third "keep these aligned" comment in this package and the drift risk with it.

Minor: the extension_ids seed in ImportState looks redundant, since extension_ids is required on the read response and Read runs immediately after import. Drop it if it isn't load-bearing.

@IlyaasK
IlyaasK requested a review from Sayan- August 5, 2026 16:16
@IlyaasK

IlyaasK commented Aug 5, 2026

Copy link
Copy Markdown
Collaborator Author

Follow-up on the replacement predicate: I kept browserPoolReplacementRequired intentionally. Terraform Plugin Framework runs resource-level ModifyPlan before it appends attribute-level RequiresReplace paths to the final plan response, so resp.RequiresReplace is still empty while this resource computes its replacement warning. The local predicate is therefore necessary for the warning to appear during the same plan. I added a comment at the helper documenting that ordering constraint; the predicate mirrors only the two replacement cases (name and viewport clears), while the obsolete update-clear validation branches were removed.

@Sayan- Sayan- left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Deleting validateSupportedUpdateClears is the right resolution — name and viewport clears now have exactly one mechanism.

You're right about RequiresReplace and I was wrong. I checked server_planresourcechange.go in framework v1.19: the schema-level paths are appended to the server's own response at line 297, but the resource-level ModifyPlanResponse is constructed with RequiresReplace: path.Paths{} at line 331 and only appended back afterward. So there's nothing to read from inside ModifyPlan and mirroring the conditions is the only option. The comment explaining that is more useful than the "keep aligned" note it replaced.

Coupling the extension_ids change to dropping the import seed was the right call and went further than I suggested. Since the API always returns extension_ids, removing the omittedExtensionIDs fallback makes flatten report the resolved value instead of depending on what happened to be in the base model, which is what let the import seed be deleted safely. Suppressing the idle-rebuild warning when a replacement is already planned is also a good touch, since the replacement warning supersedes it.

@IlyaasK
IlyaasK merged commit 5f8e644 into main Aug 5, 2026
2 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.

2 participants