fix(periodic-report): bind approved delivery to Goal Channel Bot - #3755
Conversation
Signed-off-by: huangruiteng <huangrt01@163.com>
Signed-off-by: huangruiteng <huangrt01@163.com>
Signed-off-by: huangruiteng <huangrt01@163.com>
Signed-off-by: huangruiteng <huangrt01@163.com>
FindingsNo blocking findings remain on the current head ( Open questions / assumptions
Product / architecture judgmentThe problem was not merely a bad sender option: approval produced no executable delivery successor, while provider routing was still caller-controlled. This PR fixes both owning boundaries. The capability consumer persists the frozen generation bundle and creates a blocked typed successor before the gate; approval resumes only that successor. The Lark extension then owns sender and destination resolution from the Goal Channel binding, forbids caller overrides, and verifies native App sender plus exact chat on readback. This solves the operator-visible failure mode without placing Lark policy in generic quota code. The bounded companion refactor on the final commit isolates request normalization, Bot transport effects, and CLI routing, reducing cognitive complexity and keeping the next provider change localized. A broader generic delivery framework was considered unnecessary for this single shipped path. Main residual risk is runtime configuration drift, which is fail-closed: no matching Bot profile means no send, and no environment-default or user-auth fallback is permitted. Validation
Merge decisionSelf-merge approved under explicit owner authorization. The change is single-purpose, public-safe, covered across capability lifecycle and provider boundaries, and performs no external report delivery during validation. |
Summary
periodic-report deliver-goal-channel, which resolves destination and sender only from the enabled Goal Channelproject_botbindingRoot cause
The governed consumer stopped at an approval Todo. Approval had no linked executable successor, so quota could legitimately return a quiet terminal or monitor state after the user approved the frozen payload. Separately, the Lark adapter treated message existence plus profile re-authentication as delivery proof; it did not prove that the message was in the Goal Channel or that the provider-native sender App matched the bound Bot.
Product and architecture judgment
This fixes the reusable capability boundary rather than special-casing one Goal. The periodic-report capability owns the frozen generation and approval-to-successor lifecycle; the bundled Lark extension owns provider identity, transport, and native readback. Destination and sender authority remain local-private Goal Channel configuration, not request fields. The two-message requirement is now typed execution input rather than Todo prose.
The main risk is external delivery and identity correctness. The command therefore previews without effects and executes only after extension activation, live Bot/chat/membership preflight, then exact readback for both messages. No user OAuth fallback, environment-default Bot, or caller-selected chat is permitted.
Future-facing pass: the change reuses the existing Goal Channel binding/target/transport helpers and the existing periodic-report sink adapter. No broader provider framework was added; further abstraction would be speculative until another provider needs the same native-sender proof contract.
Validation
git diff --check: passedloopx canary premerge --from-git-diff: passed, 17/17 selected checks, no holdsnpm run typecheck:control-planecould not run becausetscis not installed in this checkout (sh: tsc: command not found). The TypeScript runtime test suite passed.An earlier broad run without
LOOPX_PYTHONselected macOS Python 3.9 in subprocess CLI tests; rerunning with the repository-supported Python 3.13 produced the 777-pass result above.Boundaries and merge decision
Merge decision: self-merge after required GitHub checks pass. The external resend remains separately fail-closed until the exact Goal-bound Bot credential exists locally.