Skip to content

Consider opt-in force_destroy for kernel_browser_pool (architecture amendment) #24

Description

@IlyaasK

Summary

Evaluate adding an opt-in force_destroy (default false) attribute to kernel_browser_pool, so terraform destroy can tear down a pool that has live/leased browser sessions instead of failing with pool_in_use.

Raised during PR #3 review: DeleteBrowserPool hardcodes Force: kernel.Bool(false) (client.go:223).

Why this is deferred, not just a missing knob

Force: false implements a deliberate non-goal, not an arbitrary default. docs/architecture.md lists "force-release/recovery operations" as out of scope (line 52) and bars internal/kernelclient from exposing SDK runtime methods like force-release (line 85), enforced as a compile-time boundary.

The reasoning: Terraform converges on durable state. A pool is durable infra; the browser sessions leased from it are runtime, owned by whoever is actively driving them. A force=true destroy reaches across and terminates that live work — exactly the runtime control the declarative model is meant to keep out. The pool_in_use error is the intended recoverable path: drain/release, then retry (resource.go:271).

So enabling force_destroy is an architecture amendment, requiring:

  • docs/architecture.md updated to carve out the opt-in delete exception
  • docs/release.md security-checklist line "Delete uses force=false" reworded
  • reviewer sign-off (the boundary was an explicit decision)

Recommendation

Hold for v0. The failure is already safe and recoverable, the blast radius is other actors' live sessions (and default-false doesn't protect an operator who sets it once and forgets), and it's easy to add later but painful to remove once shipped (Hyrum's law). No demonstrated demand yet.

Revisit when a concrete workflow needs it — most likely ephemeral pools in CI hitting repeated stuck destroys. That use case also pins down the exact semantics (hard-kill vs drain-then-delete, polling, timeout) that we'd otherwise be guessing at.

Scope if approved (~80–150 lines across ~7 files, not a one-liner)

  • model.go: add ForceDestroy types.Bool
  • schema.go: Optional + Computed bool, default false (booldefault.StaticBool), description
  • client.go:223: add force bool param to DeleteBrowserPool — ripples through two consumer interfaces that redeclare it (resource.go:28, acctest.go:92) plus both call sites
  • resource.go delete handler: read state.ForceDestroy, thread it through, update the pool_in_use diagnostic
  • Design wrinkle: force_destroy is a client-only attribute the API never stores or returns (same class as project_id). Read can't populate it, so it must be preserved from prior state or it shows perpetual drift — handle like the AWS provider's force_destroy.
  • Rewrite TestDeleteBrowserPoolDoesNotForceRuntimeCleanup into default-false + true-when-set cases
  • Update schema_test.go expected-attributes map + bool-attribute assertion
  • Regenerate Terraform docs (scripts/check-docs.sh gate)
  • Acceptance test for the force path
  • Land as a new PR on top of the stack (the vertical slice is coherent at the tip), not threaded into existing stack commits

Precedent: AWS provider force_destroy on S3 buckets / IAM users (opt-in, default false).

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions