diff --git a/apps/upi_core/lib/upi_core/application.ex b/apps/upi_core/lib/upi_core/application.ex
index 47d9a36..19f56c2 100644
--- a/apps/upi_core/lib/upi_core/application.ex
+++ b/apps/upi_core/lib/upi_core/application.ex
@@ -5,6 +5,9 @@ defmodule UpiCore.Application do
 
   @impl true
   def start(_type, _args) do
+    # [RespValQr Payee.Ac] ADDED: stop at startup (clear message, no error code) when the Indian settlement account is not configured
+    validate_settlement_account!()
+
     # Initialize ETS cache for RespChkTxn ref_data
     unless :ets.whereis(:ref_data_cache) do
       :ets.new(:ref_data_cache, [:set, :public, :named_table])
@@ -18,10 +21,32 @@ defmodule UpiCore.Application do
       {Cachex, name: :rate_limiter, limit: 50_000},
       # UpiCore.Settlements.SettlementScheduler removed — superseded by UpiSettlement.Scheduler
       UpiCore.Logging.LogRotationService,
-      UpiCore.Telemetry.MetricsCollector
+      # [ChkTxn TimeoutSimulationHandler] ADDED: the controllers of upi_dynamic and upi_static call UpiCore.SpecialHandlers.TimeoutSimulationHandler, whose Agent was never started (ReqChkTxn exited).
+      # Started once here, in the supervision tree both apps depend on, so there is exactly one instance and no name clash when both apps run in one VM.
+      # OLD:       UpiCore.Telemetry.MetricsCollector
+      UpiCore.Telemetry.MetricsCollector,
+      UpiCore.SpecialHandlers.TimeoutSimulationHandler
     ]
 
     opts = [strategy: :one_for_one, name: UpiCore.Supervisor]
     Supervisor.start_link(children, opts)
   end
+
+  # [RespValQr Payee.Ac] ADDED: ACNUM / ACTYPE / IFSC are Mandatory in RespValQr (TSD Table 2; FAQ 10: the Indian settlement bank account of the IP)
+  # [RespValQr Payee.Ac] CHANGED: defp -> def (@doc false) so the startup check can be unit-tested
+  # OLD:   defp validate_settlement_account! do
+  @doc false
+  def validate_settlement_account! do
+    account = Map.new(Application.get_env(:upi_core, :psp_settlement_account, []))
+
+    missing =
+      for {key, env} <- [ac_type: "PSP_SETTLEMENT_AC_TYPE", ac_num: "PSP_SETTLEMENT_AC_NUM", ifsc: "PSP_SETTLEMENT_IFSC"],
+          Map.get(account, key) in [nil, ""],
+          do: env
+
+    if missing != [] do
+      raise "Cannot start: the Indian settlement account is not configured. Missing environment variable(s): " <>
+              Enum.join(missing, ", ") <> " (RespValQr Payee/Ac ACTYPE, ACNUM, IFSC are mandatory, TSD Table 2)"
+    end
+  end
 end
diff --git a/apps/upi_core/lib/upi_core/upi_xml_schema.ex b/apps/upi_core/lib/upi_core/upi_xml_schema.ex
index d963d22..6126046 100644
--- a/apps/upi_core/lib/upi_core/upi_xml_schema.ex
+++ b/apps/upi_core/lib/upi_core/upi_xml_schema.ex
@@ -392,10 +392,16 @@ defmodule UpiCore.UpiXmlSchema do
     ac_num = Map.get(settlement_ac, :ac_num)
     ac_ifsc = Map.get(settlement_ac, :ifsc)
 
+    # [RespValQr Payee.Ac] CHANGED: ACNUM / ACTYPE / IFSC are Mandatory (TSD Table 2, FAQ 10: the Indian settlement bank account of the IP) and are never sent empty.
+    # UpiCore.Application refuses to start without them; this raise only guards a direct call when the config was removed at runtime.
+    # OLD:     if Enum.any?([ac_type, ac_num, ac_ifsc], &(&1 in [nil, ""])) do
+    # OLD:       Logger.error(
+    # OLD:         "[RespValQr Payee.Ac] :psp_settlement_account is not fully configured (PSP_SETTLEMENT_AC_TYPE / PSP_SETTLEMENT_AC_NUM / PSP_SETTLEMENT_IFSC) - sending empty Ac values"
+    # OLD:       )
+    # OLD:     end
     if Enum.any?([ac_type, ac_num, ac_ifsc], &(&1 in [nil, ""])) do
-      Logger.error(
-        "[RespValQr Payee.Ac] :psp_settlement_account is not fully configured (PSP_SETTLEMENT_AC_TYPE / PSP_SETTLEMENT_AC_NUM / PSP_SETTLEMENT_IFSC) - sending empty Ac values"
-      )
+      raise ArgumentError,
+            "[RespValQr Payee.Ac] settlement account is not configured: set PSP_SETTLEMENT_AC_TYPE, PSP_SETTLEMENT_AC_NUM and PSP_SETTLEMENT_IFSC"
     end
 
     # [RespValQr Merchant.Fx] REMOVED: <Fx> inside <Merchant> is not in TSD Table 2 (Fx is only under FxList)
diff --git a/apps/upi_core/test/upi_core/runtime_test.exs b/apps/upi_core/test/upi_core/runtime_test.exs
new file mode 100644
index 0000000..9270122
--- /dev/null
+++ b/apps/upi_core/test/upi_core/runtime_test.exs
@@ -0,0 +1,66 @@
+defmodule UpiCore.RuntimeTest do
+  use ExUnit.Case, async: false
+
+  alias UpiCore.UpiXmlSchema
+
+  @qr "upiGlobal://pay?ver=01&mode=16&pa=a@b&pn=N&mc=5812&bAm=5.00&bCurr=AED&QRexpire=2999-01-01T00:00:00+05:30&sign=X"
+
+  defp with_account(value, fun) do
+    previous = Application.get_env(:upi_core, :psp_settlement_account)
+    Application.put_env(:upi_core, :psp_settlement_account, value)
+    on_exit(fn -> Application.put_env(:upi_core, :psp_settlement_account, previous) end)
+    fun.()
+  end
+
+  describe "settlement account (RespValQr Payee/Ac, TSD Table 2 mandatory)" do
+    test "startup check passes when all three values are set" do
+      with_account([ac_type: "CURRENT", ac_num: "N1", ifsc: "I1"], fn ->
+        UpiCore.Application.validate_settlement_account!()
+      end)
+    end
+
+    test "startup check stops the app and names every missing environment variable" do
+      with_account([ac_type: "CURRENT", ac_num: "", ifsc: nil], fn ->
+        error = assert_raise RuntimeError, fn -> UpiCore.Application.validate_settlement_account!() end
+        assert error.message =~ "PSP_SETTLEMENT_AC_NUM"
+        assert error.message =~ "PSP_SETTLEMENT_IFSC"
+        refute error.message =~ "PSP_SETTLEMENT_AC_TYPE"
+      end)
+
+      with_account([], fn ->
+        assert_raise RuntimeError, ~r/PSP_SETTLEMENT_AC_TYPE, PSP_SETTLEMENT_AC_NUM, PSP_SETTLEMENT_IFSC/, fn ->
+          UpiCore.Application.validate_settlement_account!()
+        end
+      end)
+    end
+
+    test "RespValQr is never built with empty Ac values" do
+      with_account([ac_type: "CURRENT", ac_num: nil, ifsc: "I1"], fn ->
+        assert_raise ArgumentError, ~r/PSP_SETTLEMENT_AC_NUM/, fn ->
+          UpiXmlSchema.generate_resp_val_qr(%{org_id: "MER101", result: "SUCCESS", initiation_mode: "16", qr_payload: @qr})
+        end
+      end)
+    end
+
+    test "no error code is introduced for a missing account" do
+      with_account([], fn ->
+        error = assert_raise RuntimeError, fn -> UpiCore.Application.validate_settlement_account! end
+        refute error.message =~ "U30"
+      end)
+    end
+  end
+
+  describe "TimeoutSimulationHandler wiring" do
+    test "exactly one instance of the handler the controllers call is supervised by UpiCore" do
+      children = Supervisor.which_children(UpiCore.Supervisor)
+      matching = Enum.filter(children, fn {id, _pid, _type, _mods} -> id == UpiCore.SpecialHandlers.TimeoutSimulationHandler end)
+      assert [{_, pid, _, _}] = matching
+      assert pid == Process.whereis(UpiCore.SpecialHandlers.TimeoutSimulationHandler)
+    end
+
+    test "handle_req_chk_txn_timeout/1 answers instead of exiting" do
+      assert :normal ==
+               UpiCore.SpecialHandlers.TimeoutSimulationHandler.handle_req_chk_txn_timeout(%{txn_id: "SOME-TXN", org_txn_id: "SOME-ORG-TXN"})
+    end
+  end
+end
diff --git a/apps/upi_dynamic/test/upi_dynamic/ack_test.exs b/apps/upi_dynamic/test/upi_dynamic/ack_test.exs
index e3414c7..ed2dce5 100644
--- a/apps/upi_dynamic/test/upi_dynamic/ack_test.exs
+++ b/apps/upi_dynamic/test/upi_dynamic/ack_test.exs
@@ -17,7 +17,9 @@ defmodule UpiDynamic.AckTest do
     on_exit(fn -> Ecto.Adapters.SQL.Sandbox.stop_owner(pid) end)
 
     # the controller asks this Agent whether a txn is a timeout simulation (the dynamic app starts its own copy under another name)
-    start_supervised!({UpiCore.SpecialHandlers.TimeoutSimulationHandler, []})
+    # [ChkTxn TimeoutSimulationHandler] UpiCore.Application now starts the Agent the controllers call - nothing to start here
+    # OLD:     start_supervised!({UpiCore.SpecialHandlers.TimeoutSimulationHandler, []})
+    assert is_pid(Process.whereis(UpiCore.SpecialHandlers.TimeoutSimulationHandler))
 
     # never let the async RespValQr / RespChkTxn reach the real NPCI endpoint from a test
     for key <- [:npci_qr_validation_endpoint, :npci_respchktxn_endpoint, :npci_resp_chk_txn_endpoint] do
@@ -81,4 +83,16 @@ defmodule UpiDynamic.AckTest do
 
     assert_ack(call(:check_transaction, "/ReqChkTxn/2.0/urn:txnid:NPCICHK0001", xml), "ReqChkTxn")
   end
+
+  test "ReqChkTxn does not exit (the handler the controller calls is supervised)" do
+    xml = """
+    <ns2:ReqChkTxn xmlns:ns2="http://npci.org/upi/schema/">
+      <Head ver="2.0" ts="2026-07-09T14:46:20+05:30" orgId="NPCI" msgId="#{@msg_id}"/>
+      <Txn id="NPCICHK0009" note="N" refId="R" refUrl="http://x" ts="2026-07-09T14:46:21+05:30" type="ChkTxn" orgTxnId="ORGTXN0009" orgMsgId="NPCIORGMSG9" custRef="CUSTREF09" initiationMode="16" purpose="11" subType="PAY"/>
+    </ns2:ReqChkTxn>
+    """
+
+    conn = call(:check_transaction, "/ReqChkTxn/2.0/urn:txnid:NPCICHK0009", xml)
+    assert conn.status == 200
+  end
 end
diff --git a/apps/upi_static/test/upi_static/ack_test.exs b/apps/upi_static/test/upi_static/ack_test.exs
index ac4c8e7..04d40f1 100644
--- a/apps/upi_static/test/upi_static/ack_test.exs
+++ b/apps/upi_static/test/upi_static/ack_test.exs
@@ -17,7 +17,9 @@ defmodule UpiStatic.AckTest do
     on_exit(fn -> Ecto.Adapters.SQL.Sandbox.stop_owner(pid) end)
 
     # the static controller also asks the UpiCore copy of this Agent (the app only starts its own, differently named one)
-    start_supervised!({UpiCore.SpecialHandlers.TimeoutSimulationHandler, []})
+    # [ChkTxn TimeoutSimulationHandler] UpiCore.Application now starts the Agent the controllers call - nothing to start here
+    # OLD:     start_supervised!({UpiCore.SpecialHandlers.TimeoutSimulationHandler, []})
+    assert is_pid(Process.whereis(UpiCore.SpecialHandlers.TimeoutSimulationHandler))
 
     for key <- [:npci_qr_validation_endpoint, :npci_respchktxn_endpoint, :npci_resp_chk_txn_endpoint] do
       old = Application.get_env(:upi_static, key)
@@ -69,4 +71,16 @@ defmodule UpiStatic.AckTest do
     {:ok, ack} = UpiStatic.SpecialHandlers.StaticAccIp05Scenario.handle_req_pay_immediate_ack("<ReqPay/>", %{msg_id: @msg_id})
     assert String.trim(ack) =~ ~r|^<ns2:Ack xmlns:ns2="http://npci.org/upi/schema/" api="ReqPay" reqMsgId="#{@msg_id}" ts="[^"]+"/>$|
   end
+
+  test "ReqChkTxn does not exit (the handler the controller calls is supervised)" do
+    xml = """
+    <ns2:ReqChkTxn xmlns:ns2="http://npci.org/upi/schema/">
+      <Head ver="2.0" ts="2026-07-09T14:46:20+05:30" orgId="NPCI" msgId="#{@msg_id}"/>
+      <Txn id="NPCICHK0009" note="N" refId="R" refUrl="http://x" ts="2026-07-09T14:46:21+05:30" type="ChkTxn" orgTxnId="ORGTXN0009" orgMsgId="NPCIORGMSG9" custRef="CUSTREF09" initiationMode="16" purpose="11" subType="PAY"/>
+    </ns2:ReqChkTxn>
+    """
+
+    conn = call(:check_transaction, "/ReqChkTxn/2.0/urn:txnid:NPCICHK0009", xml)
+    assert conn.status == 200
+  end
 end
diff --git a/config/runtime.exs b/config/runtime.exs
index 457a703..32d1b50 100755
--- a/config/runtime.exs
+++ b/config/runtime.exs
@@ -68,10 +68,17 @@ config :upi_core, :xml_signing_priv_key_path, System.get_env("XML_SIGNING_PRIV_K
 
 # [RespValQr Payee.Ac] ADDED: PSP's Indian settlement account sent as Payee/Ac in RespValQr
 # (TSD Table 2: ACTYPE / ACNUM / IFSC). Real values come from the environment - never hard-coded.
-config :upi_core, :psp_settlement_account,
-  ac_type: System.get_env("PSP_SETTLEMENT_AC_TYPE"),
-  ac_num: System.get_env("PSP_SETTLEMENT_AC_NUM"),
-  ifsc: System.get_env("PSP_SETTLEMENT_IFSC")
+# [RespValQr Payee.Ac] CHANGED: read from the environment in every env except :test (config/test.exs carries fake values); UpiCore.Application stops the app at startup if one is missing (TSD Table 2: Mandatory)
+# OLD: config :upi_core, :psp_settlement_account,
+# OLD:   ac_type: System.get_env("PSP_SETTLEMENT_AC_TYPE"),
+# OLD:   ac_num: System.get_env("PSP_SETTLEMENT_AC_NUM"),
+# OLD:   ifsc: System.get_env("PSP_SETTLEMENT_IFSC")
+if config_env() != :test do
+  config :upi_core, :psp_settlement_account,
+    ac_type: System.get_env("PSP_SETTLEMENT_AC_TYPE"),
+    ac_num: System.get_env("PSP_SETTLEMENT_AC_NUM"),
+    ifsc: System.get_env("PSP_SETTLEMENT_IFSC")
+end
 
 IO.puts("\n[NPCI_MODE] #{npci_mode} -> #{npci_base_url}\n")
 
diff --git a/config/test.exs b/config/test.exs
index 757f573..7e0ade2 100755
--- a/config/test.exs
+++ b/config/test.exs
@@ -24,6 +24,12 @@ config :upi_static, UpiStatic.Endpoint,
   server: false
 
 config :upi_core, UpiCore.Mailer, adapter: Swoosh.Adapters.Test
+
+# [RespValQr Payee.Ac] ADDED: obviously fake settlement account for tests (runtime.exs does not set it in :test)
+config :upi_core, :psp_settlement_account,
+  ac_type: "CURRENT",
+  ac_num: "TESTACNUM001",
+  ifsc: "TEST0000001"
 config :swoosh, :api_client, false
 config :logger, level: :warning
 config :phoenix, :plug_init_mode, :runtime
