Keep the reset control out of production

c32e86bd05a0 · AtlantisPleb · · parent 50b882b8d909

Keep the reset control out of production

The one-click reset deletes every message, memory, and voice session an
account has, behind one confirmation and no undo. Its docstring has always
said development and staging only, but the only gate was a feature flag —
so a production deployment that set the flag got the control on the page
and the delete route behind it.

The environment now decides last. Setting the flag against production is
inert rather than destructive, and the controller asks the same question
before it deletes anything, so the route closes with the control.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016o8HwTaqLKEWCHTjsjFtrB
Co-Authored-By
Claude Opus 5 (1M context) <noreply@anthropic.com>

Deploy story

What this commit did to the running system — joined from the forge receipt chain, the part a commit page elsewhere cannot show.

Not deployed through the forge lane

No push, promotion, build, or deploy receipt references this commit (receipts are scanned over a bounded recent window). Changes shipped by full node replacement carry their proof in the release gate receipt instead.

Changed files

  • modified lib/openagents/data_rights.ex
  • added test/openagents/data_rights/reset_gate_test.exs

Diff

2 files changed, +57 -2

lib/openagents/data_rights.ex modified +12 -2

@@ -22,10 +22,20 @@ defmodule OpenAgents.DataRights do

22 22
  @maximum_export_voice_sessions 2_000
23 23
  @maximum_export_tool_steps 10_000
24 24
25
  @doc "Whether the one-click full reset control is enabled (development and staging only)."
25
  @doc """
26
  Whether the one-click full reset control is enabled.
27
28
  Development and staging only. The control deletes every message, memory, and
29
  voice session an account has, with one confirmation and no undo — reasonable
30
  to hand someone exercising a build, never something to leave on a page a
31
  customer is using. The flag alone was the gate, so a production deployment
32
  that set it got the control; the environment now decides last, and enabling
33
  the flag against production is inert rather than destructive.
34
  """
26 35
  @spec reset_enabled?() :: boolean()
27 36
  def reset_enabled? do
28
    Application.get_env(:openagents, :conversation_reset_enabled, false) == true
37
    Application.get_env(:openagents, :conversation_reset_enabled, false) == true and
38
      Application.get_env(:openagents, :runtime_environment) != :production
29 39
  end
30 40
31 41
  @spec export(User.t(), Visitor.t(), Conversation.t()) :: {:ok, map()} | {:error, term()}
test/openagents/data_rights/reset_gate_test.exs added +45

@@ -0,0 +1,45 @@

1
defmodule OpenAgents.DataRights.ResetGateTest do
2
  use ExUnit.Case, async: false
3
4
  alias OpenAgents.DataRights
5
6
  setup do
7
    previous_flag = Application.get_env(:openagents, :conversation_reset_enabled, false)
8
    previous_environment = Application.get_env(:openagents, :runtime_environment)
9
10
    on_exit(fn ->
11
      Application.put_env(:openagents, :conversation_reset_enabled, previous_flag)
12
      Application.put_env(:openagents, :runtime_environment, previous_environment)
13
    end)
14
15
    :ok
16
  end
17
18
  test "the flag enables the reset control outside production" do
19
    Application.put_env(:openagents, :conversation_reset_enabled, true)
20
21
    for environment <- [:development, :test, :staging] do
22
      Application.put_env(:openagents, :runtime_environment, environment)
23
      assert DataRights.reset_enabled?()
24
    end
25
  end
26
27
  # The environment decides last. A production deployment that sets the flag
28
  # gets nothing: no control on the page, and no route behind it, because the
29
  # controller asks this same question before it deletes anything.
30
  test "production refuses the reset control even with the flag set" do
31
    Application.put_env(:openagents, :conversation_reset_enabled, true)
32
    Application.put_env(:openagents, :runtime_environment, :production)
33
34
    refute DataRights.reset_enabled?()
35
  end
36
37
  test "the control stays off wherever the flag is unset" do
38
    Application.put_env(:openagents, :conversation_reset_enabled, false)
39
40
    for environment <- [:development, :test, :staging, :production] do
41
      Application.put_env(:openagents, :runtime_environment, environment)
42
      refute DataRights.reset_enabled?()
43
    end
44
  end
45
end

This page updates live while a promote is in flight · changelog