Skip to content

Commit c219975

Browse files
authored
Merge pull request #3523 from huangruiteng/codex/goal-channel-default-notify
feat(goal-channel): default human-gate auto-notify on for new goal channels
2 parents e2902df + b3dc717 commit c219975

2 files changed

Lines changed: 82 additions & 2 deletions

File tree

‎loopx/extensions/lark/goal_channel_setup.py‎

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,16 +10,20 @@
1010

1111
from ...control_plane.runtime.public_safety import public_safe_compact_text
1212
from .goal_channel_contracts import (
13+
HUMAN_GATE_AUTO_NOTIFY_SETTING,
1314
binding_for_goal,
15+
clear_human_gate_auto_notify_marker,
1416
control_message,
1517
goal_from_registry,
1618
goal_objective,
19+
human_gate_auto_notify_marker_path,
1720
now_iso,
1821
operation_packet,
1922
provider_idempotency_key,
2023
read_goal_channel_binding,
2124
save_goal_binding,
2225
semantic_key,
26+
write_human_gate_auto_notify_marker,
2327
)
2428
from .goal_channel_transport import (
2529
APP_ID_PATTERN,
@@ -51,6 +55,15 @@ def _mapping(value: Any) -> dict[str, Any]:
5155
return dict(value) if isinstance(value, Mapping) else {}
5256

5357

58+
def _default_goal_channel_automation(
59+
raw_binding: Mapping[str, Any],
60+
) -> dict[str, Any]:
61+
"""Human-gate auto-notify is on by default for newly configured channels."""
62+
automation = _mapping(raw_binding.get("automation"))
63+
automation.setdefault(HUMAN_GATE_AUTO_NOTIFY_SETTING, True)
64+
return automation
65+
66+
5467
def _base_url_from_payload(payload: Mapping[str, Any]) -> str:
5568
data = payload.get("data")
5669
data = data if isinstance(data, Mapping) else {}
@@ -758,6 +771,7 @@ def setup_lark_goal_channel(
758771
"bot_display_name": effective_bot_name,
759772
"cli_bin": effective_cli_bin,
760773
}
774+
automation = _default_goal_channel_automation(raw_existing)
761775
saved_binding: dict[str, Any] = {
762776
"goal_id": goal_id,
763777
"provider": "lark",
@@ -770,7 +784,7 @@ def setup_lark_goal_channel(
770784
"base_url": kanban_url,
771785
},
772786
"identity": saved_identity,
773-
"automation": _mapping(raw_existing.get("automation")),
787+
"automation": automation,
774788
"receipts": mutable_receipts,
775789
}
776790
if effective_target_name:
@@ -781,6 +795,11 @@ def setup_lark_goal_channel(
781795
goal_id=goal_id,
782796
binding=saved_binding,
783797
)
798+
marker_path = human_gate_auto_notify_marker_path(binding_path, goal_id)
799+
if automation.get(HUMAN_GATE_AUTO_NOTIFY_SETTING) is True:
800+
write_human_gate_auto_notify_marker(marker_path)
801+
else:
802+
clear_human_gate_auto_notify_marker(marker_path)
784803
return operation_packet(
785804
ok=True,
786805
goal_id=goal_id,

‎tests/extensions/test_lark_goal_channel.py‎

Lines changed: 62 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -476,6 +476,64 @@ def test_setup_execute_persists_private_binding_after_verified_pin(
476476
_assert_public_packet(payload)
477477

478478

479+
def test_setup_execute_defaults_human_gate_auto_notify_on(tmp_path: Path) -> None:
480+
registry_path = tmp_path / ".loopx" / "registry.json"
481+
binding_path = tmp_path / ".loopx" / "goal-channel.json"
482+
kanban_path = tmp_path / ".loopx" / "lark-kanban.json"
483+
calls: list[list[str]] = []
484+
485+
payload = setup_lark_goal_channel(
486+
registry=_registry(tmp_path),
487+
registry_path=registry_path,
488+
goal_id=GOAL_ID,
489+
binding_path=binding_path,
490+
kanban_config_path=kanban_path,
491+
bot_app_id="cli_public_fixture",
492+
execute=True,
493+
runner=_fake_runner(calls),
494+
)
495+
assert payload["ok"] is True
496+
assert payload["status"] == "configured"
497+
persisted = read_goal_channel_binding(binding_path)["bindings"][GOAL_ID]
498+
assert persisted["automation"]["human_gate_auto_notify_enabled"] is True
499+
marker_path = goal_channel_contracts.human_gate_auto_notify_marker_path(
500+
binding_path, GOAL_ID
501+
)
502+
assert goal_channel_contracts.human_gate_auto_notify_marker_enabled(marker_path)
503+
504+
505+
def test_setup_execute_preserves_explicit_auto_notify_opt_out(tmp_path: Path) -> None:
506+
binding_path = tmp_path / ".loopx" / "goal-channel.json"
507+
binding_path.parent.mkdir(parents=True)
508+
kanban_path = tmp_path / ".loopx" / "lark-kanban.json"
509+
_write_binding(binding_path, kanban_path)
510+
payload = read_goal_channel_binding(binding_path)
511+
payload["bindings"][GOAL_ID]["automation"] = {
512+
"human_gate_auto_notify_enabled": False
513+
}
514+
write_goal_channel_binding(binding_path, payload)
515+
calls: list[list[str]] = []
516+
517+
result = setup_lark_goal_channel(
518+
registry=_registry(tmp_path),
519+
registry_path=tmp_path / ".loopx" / "registry.json",
520+
goal_id=GOAL_ID,
521+
binding_path=binding_path,
522+
kanban_config_path=kanban_path,
523+
bot_app_id="cli_public_fixture",
524+
execute=True,
525+
runner=_fake_runner(calls),
526+
)
527+
assert result["ok"] is True
528+
assert result["status"] == "configured"
529+
persisted = read_goal_channel_binding(binding_path)["bindings"][GOAL_ID]
530+
assert persisted["automation"]["human_gate_auto_notify_enabled"] is False
531+
marker_path = goal_channel_contracts.human_gate_auto_notify_marker_path(
532+
binding_path, GOAL_ID
533+
)
534+
assert not goal_channel_contracts.human_gate_auto_notify_marker_enabled(marker_path)
535+
536+
479537
def test_configure_auto_notify_is_preview_first_and_persists_private_opt_in(
480538
tmp_path: Path,
481539
) -> None:
@@ -556,9 +614,12 @@ def test_configure_can_disable_auto_notify_for_incomplete_binding(
556614
_assert_public_packet(payload)
557615

558616

559-
def test_auto_notify_gate_is_disabled_by_default_and_suppressible(
617+
def test_auto_notify_gate_is_disabled_when_unconfigured_and_suppressible(
560618
tmp_path: Path,
561619
) -> None:
620+
# A raw binding with no automation setting is unconfigured (disabled); the
621+
# setup path now defaults human-gate auto-notify to on (see
622+
# test_setup_execute_defaults_human_gate_auto_notify_on).
562623
binding_path = tmp_path / ".loopx" / "goal-channel.json"
563624
binding_path.parent.mkdir(parents=True)
564625
kanban_path = tmp_path / ".loopx" / "lark-kanban.json"

0 commit comments

Comments
 (0)