diff --git a/DOCS-add-photo.md b/DOCS-add-photo.md index ef4293f..1cf447c 100644 --- a/DOCS-add-photo.md +++ b/DOCS-add-photo.md @@ -1,5 +1,9 @@ # Adding a photo from the chat: `!add_photo` +> **Unwired since 2026-09-04.** `!dodaj` is not a command until photos land +> in an approval queue instead of straight in the album. Everything below +> describes the ingest path as it was wired, and as the queue will reuse it. + How a member of an album's group puts a photo into it by sending one, and what keeps that path from leaking anything. The album itself — where it lives, what its manifests look like, how several albums coexist — is diff --git a/DOCS-commands.md b/DOCS-commands.md index 85d7ec9..2871dcf 100644 --- a/DOCS-commands.md +++ b/DOCS-commands.md @@ -30,7 +30,6 @@ This file is the trigger reference — every spelling that resolves, which | stats_me | `!ja` `!moje` `!mnie` | | command_stats | `!analityka` `!command_stats` `!commandstats` `!analytics` `!uzycie` `!użycie` `!ranking` | | help | `!pomoc` `!pomocy` `!help` `!komendy` `!commands` | -| add_photo | `!dodaj` `!dodaj_zdjecie` `!dodajzdjecie` `!add_photo` `!addphoto` | | random | `!losowe` `!losuj` `!random` `!rand` | | suggest | `!zaproponuj` `!propozycja` `!sugestia` `!suggest` `!pomysl` | @@ -66,11 +65,16 @@ group — the album's, whose triggers are real people's names — is neither answered nor recorded, because a refusal would announce that the album exists. -`add_photo` and `random` exist **only in the photo album's own groups**, and -only on an installation that has an album at all — everywhere else they are -not commands, not refused and never logged. Both take arguments, and those +`random` exists **only in the photo album's own groups**, and only on an +installation that has an album at all — everywhere else it is not a command, +not refused and never logged. It takes arguments, and those arguments are resolved to pseudonym keys by the registry before any handler, -log line or `command_uses` row sees them. See `DOCS-photo-pack.md` and `DOCS-add-photo.md`. +log line or `command_uses` row sees them. See `DOCS-photo-pack.md`. + +`add_photo` (`!dodaj`) is **unwired since 2026-09-04**: a photo posted to a +group must not reach the album without somebody approving it, and no approval +queue exists yet. It comes back when one does; `DOCS-add-photo.md` describes +the path as it was. ## Why `!pomoc` shows the first alias and not a trigger diff --git a/fake_signal/scenarios/pack_add_disabled.yaml b/fake_signal/scenarios/pack_add_disabled.yaml new file mode 100644 index 0000000..506feb1 --- /dev/null +++ b/fake_signal/scenarios/pack_add_disabled.yaml @@ -0,0 +1,13 @@ +# Adding a photo from the chat is switched off until an approval queue +# exists (2026-09-04): a photo somebody posts must not reach the album +# unreviewed. Unwired rather than gated, so !dodaj is an unknown word like +# any other -- answered, and never storing anything. The eight scenarios +# that proved the ingest path are at 64852ae, for the queue to bring back. +name: "!dodaj is not a command while photos cannot be approved" +inject: + - { + text: "!dodaj alfa", uuid: uuid-add-off, name: AddOff, + attachment: att-off, + } +expect: + - { kind: text, to: reply, contains: "Nie znam !dodaj" } diff --git a/scripts/e2e.sh b/scripts/e2e.sh index bd019b1..c5d5897 100755 --- a/scripts/e2e.sh +++ b/scripts/e2e.sh @@ -158,9 +158,6 @@ main() { wait_for_url "http://127.0.0.1:${BOT_PORT}/healthz" "bot" wait_for_subscription - echo "== generating media for !add_photo (real exif, never committed)" - "$PYTHON" "$REPO_ROOT/tool/e2e_media.py" --upload "$FAKE_URL" - echo "== replaying scenarios" "$PYTHON" -m fake_signal.cli \ "$REPO_ROOT"/fake_signal/scenarios/*.yaml \ @@ -176,7 +173,9 @@ main() { --group "fourth_reply=${FOURTH_GROUP}" \ --group "other=${OTHER_GROUP}" - prove_the_add_photo_invariants + # !dodaj is unwired until photos land in an approval queue instead of + # the album (2026-09-04). Its scenarios, the media generation step and + # prove_the_add_photo_invariants left with it; git has them at 64852ae. prove_the_deafness_gate enforce_the_time_budget "$STARTED_AT" } diff --git a/scripts/e2e_proofs.sh b/scripts/e2e_proofs.sh index 989bdd3..86e40c4 100755 --- a/scripts/e2e_proofs.sh +++ b/scripts/e2e_proofs.sh @@ -8,45 +8,6 @@ # and the same bot process the scenarios used. # ============================================================================ -prove_the_add_photo_invariants() { - local pack="${TEMP_DIR}/pack" - - echo "== checking every stored file was actually stripped" - "$PYTHON" "$REPO_ROOT/tool/e2e_media.py" --verify-pack "$pack" - - echo "== checking a typed label never reached custom.json as a key" - if grep -qE '"(wakacje|piesek)"[[:space:]]*:' "${pack}/custom.json"; then - echo "Error: a typed label became a key in custom.json" >&2 - exit 1 - fi - - echo "== checking !dodaj with no attachment minted nothing" - if grep -q "piesek" "${pack}/custom.json"; then - echo "Error: a mint survived a message that carried no attachment" >&2 - exit 1 - fi - - echo "== checking the refused uploads were not stored" - if grep -q "att-junk" "${pack}/tags.json"; then - echo "Error: a refused file reached tags.json" >&2 - exit 1 - fi - - echo "== checking signal-cli's own copies were deleted" - local left - left="$(curl -sf "${FAKE_URL}/_control/attachments")" - if [[ "$left" == *"att-person"* || "$left" == *"att-custom"* ]]; then - echo "Error: an ingested attachment is still in the container store: ${left}" >&2 - exit 1 - fi - - echo "== checking the adder was recorded for a future !undo_photo" - if [[ ! -s "${pack}/adds.json" ]]; then - echo "Error: adds.json was never written" >&2 - exit 1 - fi -} - # The gate that did not exist on 2026-08-29, proven against the real process: # with signal-cli unable to reach Signal, /healthz must go red rather than # keep answering 200 while nothing arrives. diff --git a/signal_bot/aliases.json b/signal_bot/aliases.json index 18892b3..e1fb217 100644 --- a/signal_bot/aliases.json +++ b/signal_bot/aliases.json @@ -145,13 +145,6 @@ "!komendy", "!commands" ], - "add_photo": [ - "!dodaj", - "!dodaj_zdjecie", - "!dodajzdjecie", - "!add_photo", - "!addphoto" - ], "random": [ "!losowe", "!losuj", diff --git a/signal_bot/bot.py b/signal_bot/bot.py index fc3d01f..73d9249 100644 --- a/signal_bot/bot.py +++ b/signal_bot/bot.py @@ -23,8 +23,6 @@ from signal_bot.decorators import cooldown from signal_bot.dispatcher import Dispatcher from signal_bot.help_command import register_help_command from signal_bot.http_client import ImageFetcher -from signal_bot.media_strip import ExiftoolStripper -from signal_bot.pack_add import register_add_command from signal_bot.pack_command import register_pack_commands from signal_bot.pack_holder import PackHolder from signal_bot.pack_load import load as load_pack @@ -178,7 +176,6 @@ def _register_album(registry: CommandRegistry, directory: Path, rate_limit: Deco holder = PackHolder(load_pack(directory)) register_pack_commands(registry, holder, decorate=rate_limit) register_random_command(registry, holder, tuple(aliases["random"]), decorate=rate_limit) - register_add_command(registry, holder, ExiftoolStripper(), tuple(aliases["add_photo"])) def build_bot( diff --git a/tests/test_multiple_albums.py b/tests/test_multiple_albums.py index 20e3bb4..030e553 100644 --- a/tests/test_multiple_albums.py +++ b/tests/test_multiple_albums.py @@ -109,21 +109,26 @@ def test_two_albums_may_share_a_trigger_when_their_groups_do_not_overlap( assert first is not second -def test_add_photo_and_random_exist_separately_in_each_album( +def test_random_exists_separately_in_each_album( tmp_path: Path, config: Config, store: Store, transport: FakeTransport, directory: GroupDirectory, ) -> None: - """!dodaj and !losowe carry the same triggers in both, by construction.""" + """!losowe carries the same triggers in both, by construction. + + !dodaj used to be asserted here too. It is unwired until an approval + queue exists (2026-09-04), and a word nothing registers is the same in + every group: the scoping this test guards is the album's, not its. + """ real = _album(tmp_path / "real", WATCHED_GROUP) test = _album(tmp_path / "test", SECOND_GROUP, key="p9", trigger="!zeta") registry = _registry(config, store, transport, directory, (real, test)) for group in (WATCHED_GROUP, SECOND_GROUP): - assert _claim(registry, "!dodaj alfa", group) is not None assert _claim(registry, "!losowe", group) is not None + assert _claim(registry, "!dodaj alfa", group) is None def test_two_albums_sharing_a_group_are_refused_at_startup( diff --git a/tests/test_personal_data_sources.py b/tests/test_personal_data_sources.py index 1a9035f..b343329 100644 --- a/tests/test_personal_data_sources.py +++ b/tests/test_personal_data_sources.py @@ -88,7 +88,7 @@ def test_a_label_that_is_a_command_word_is_not_forbidden( assert "ciocia_hania" in words -@pytest.mark.parametrize("label", ["losowe", "papiez", "add_photo", "staty"]) +@pytest.mark.parametrize("label", ["losowe", "papiez", "komendy", "staty"]) def test_no_command_word_can_be_outlawed_by_a_label( sources: ModuleType, tmp_path: Path, monkeypatch: pytest.MonkeyPatch, label: str ) -> None: