From 7de603f47b65f69a4084fb843d67ed0d8ea736e3 Mon Sep 17 00:00:00 2001 From: Edgar Arakelyan Date: Fri, 9 Oct 2026 00:16:13 -0700 Subject: [PATCH 1/2] fix(env_state): changelog triggers skip a service's internal tables _install_changelog_triggers put a row trigger on every table in the schema except _changelog itself. A service's internal tables, named with the same leading underscore, hold no domain rows: the file-bytes table a server keeps next to its rows would log whole blobs into changed_fields on every upload. Skip every underscore-prefixed table, as _changelog already was. Co-Authored-By: Claude Fable 5.1 --- src/agent_env/providers/env_state/env_state_provider.py | 4 +++- tst/unit/providers/env_state/test_env_state_provider.py | 4 ++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/agent_env/providers/env_state/env_state_provider.py b/src/agent_env/providers/env_state/env_state_provider.py index f0e1ff93..a82b1c68 100644 --- a/src/agent_env/providers/env_state/env_state_provider.py +++ b/src/agent_env/providers/env_state/env_state_provider.py @@ -377,7 +377,9 @@ def get_init_script(environment_names: list[str]) -> str: SELECT schemaname, tablename FROM pg_tables WHERE schemaname = _schema_name - AND tablename != '_changelog' + -- Names starting with an underscore are a service's internal tables + -- (file bytes, caches), not domain rows; _changelog itself is one. + AND tablename NOT LIKE '\\_%' LOOP EXECUTE format( 'DROP TRIGGER IF EXISTS _changelog_trigger ON %I.%I', diff --git a/tst/unit/providers/env_state/test_env_state_provider.py b/tst/unit/providers/env_state/test_env_state_provider.py index bac759bf..741e1579 100644 --- a/tst/unit/providers/env_state/test_env_state_provider.py +++ b/tst/unit/providers/env_state/test_env_state_provider.py @@ -180,6 +180,10 @@ def test_get_init_script_changelog_components(): for op in ("TG_OP = 'INSERT'", "TG_OP = 'DELETE'", "TG_OP = 'UPDATE'"): assert op in script assert "_install_changelog_triggers(_schema_name TEXT)" in script + # Internal tables (a leading underscore, like _changelog itself) carry no + # domain rows and get no trigger. + assert "tablename NOT LIKE '\\_%'" in script + assert "tablename != '_changelog'" not in script assert "WHERE schemaname = _schema_name" in script From 10593a6b7b7ffb2c9ad3c9242ebe81fa787ca7a2 Mon Sep 17 00:00:00 2001 From: Edgar Arakelyan Date: Fri, 9 Oct 2026 00:57:15 -0700 Subject: [PATCH 2/2] test: an underscore-prefixed service table gets no changelog trigger (Postgres) Co-Authored-By: Claude Fable 5.1 --- .../env/envs/service_db_changelog_test.py | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/tst/integration/env/envs/service_db_changelog_test.py b/tst/integration/env/envs/service_db_changelog_test.py index 8ab477ad..337696cc 100644 --- a/tst/integration/env/envs/service_db_changelog_test.py +++ b/tst/integration/env/envs/service_db_changelog_test.py @@ -128,3 +128,30 @@ def test_changelog_row_id_composite_pk(pg_conn): f"WHERE schema_name='{schema}' AND table_name='daily' ORDER BY id DESC LIMIT 1", )[0][0] assert json.loads(row_id) == {"user_id": "u_jin", "day": "2025-11-05"} + + +def test_internal_tables_get_no_changelog_trigger(pg_conn): + """A service's internal tables (a leading underscore, like _changelog) hold no + domain rows: the installer skips them, so a blob written there is not copied + into changed_fields while the domain table beside it is still audited.""" + schema = "files_svc" + _exec(pg_conn, LocalPostgresStateProvider.get_init_script([schema])) + _exec(pg_conn, f'CREATE TABLE "{schema}".documents (id text PRIMARY KEY, title text)') + _exec(pg_conn, f'CREATE TABLE "{schema}"._files (path text PRIMARY KEY, content bytea)') + _exec(pg_conn, f"SELECT public._install_changelog_triggers('{schema}')") + + _exec(pg_conn, f"INSERT INTO \"{schema}\".documents VALUES ('d1', 'brief')") + _exec(pg_conn, f"INSERT INTO \"{schema}\"._files VALUES ('a/brief.pdf', '\\x255044462d')") + + rows = _rows( + pg_conn, + "SELECT table_name, operation FROM public._changelog " + f"WHERE schema_name='{schema}' ORDER BY id", + ) + assert rows == [("documents", "INSERT")] + triggers = _rows( + pg_conn, + "SELECT event_object_table FROM information_schema.triggers " + f"WHERE trigger_schema='{schema}' AND trigger_name='_changelog_trigger'", + ) + assert {t[0] for t in triggers} == {"documents"}