Skip to content

feat(teams): add operator cron delivery - #1504

Draft
NeoHsu wants to merge 18 commits into
openabdev:mainfrom
NeoHsu:stack/teams-12-operator-cron
Draft

feat(teams): add operator cron delivery#1504
NeoHsu wants to merge 18 commits into
openabdev:mainfrom
NeoHsu:stack/teams-12-operator-cron

Conversation

@NeoHsu

@NeoHsu NeoHsu commented Aug 20, 2026

Copy link
Copy Markdown

Important

Stacked draft: logical base stack/teams-11-conversation-registry is PR #1503. GitHub requires an upstream PR base to exist in openabdev/openab, so this draft temporarily targets main and may show preceding stack layers. Do not merge it until #1503 is merged and this branch is rebased onto current main; then review only its single incremental commit.

What problem does this solve?

Allow an operator-authored baseline cron job to send a scheduled prompt and its
agent response into one exact active, non-expired PR 11 Teams conversation in
Unified or Standalone mode, with required delivery outcomes, Gateway-local
reference resolution, lifecycle reconciliation, no synthetic Teams thread, and
no persistent reference or serviceUrl exposure to Core or ACP.

Discord Discussion URL: https://discord.com/channels/1491295327620169908/1491365158868619404/1531339032527765655
Microsoft Teams roadmap discussion.

Review Contract

This is the proposed PR-body contract. It is not frozen until the owner or a
maintainer approves it and records the reviewed head plus an immutable contract
revision or hash.

Goal

Allow an operator-authored baseline cron job to send a scheduled prompt and its
agent response into one exact active, non-expired PR 11 Teams conversation in
Unified or Standalone mode, with required delivery outcomes, Gateway-local
reference resolution, lifecycle reconciliation, no synthetic Teams thread, and
no persistent reference or serviceUrl exposure to Core or ACP.

Non-goals

Agent-writable Teams usercron, /remind or any user-created schedule, proactive
app installation or conversation creation, Graph/RSC/delegated permissions,
registry CRUD or discovery, target aliases, catch-up after missed ticks,
automatic retry/backoff, durable outbound queues, new cron expression semantics,
new Teams thread creation, media/card cron payloads, restart-persistent activity
ownership, multi-Gateway coordination, cross-process locking, or sovereign-cloud
expansion are outside PR 12.

Accepted Residual Risks

Operator config contains the non-secret Teams tenant and conversation IDs plus
the scheduled prompt; filesystem and config access remain the operator's
responsibility. Scheduled activities are intentionally unprompted and PR 12 has
no user opt-out UI. A stale or removed installation can consume one failed
scheduled attempt, and the two-result disable threshold can allow one additional
explicit blocked/not-in-roster attempt before stopping future use. Clock shifts,
timezone changes, process downtime, and hello timing can skip a tick; there is
no catch-up. A Gateway disconnect after an accepted frame can leave delivery
Unknown, which suppresses retry but may omit that occurrence. Registry
reconciliation can fail after an authoritative platform outcome, leaving prior
state until later evidence. The registry and topology retain PR 11's
single-writer/single-consumer and filesystem-confidentiality limits.

Acceptance Criteria

Default and non-Teams cron behavior remains backward compatible; only
operator-owned baseline config can target Teams and agent-writable usercron is
rejected before lookup; Teams config supplies a bounded tenant plus conversation
identity and forbids synthetic thread selection; Core emits an additive
persistent target only after the exact capability and supported topology are
available; old peers and registry-off deployments fail closed before wire, HTTP,
session, or ACP work; Gateway reconstructs and validates the complete
app/tenant/Bot-Framework-channel/conversation key, current tenant allowlist, and
active non-expired record without exposing its stored reference or serviceUrl;
one real-ID trigger delivery precedes ACP and all later writes preserve the same
target; Teams creates no scheduler thread; Standalone reconnects through one
stable proxy without a second consumer; Unified and Standalone are semantically
equivalent; Delivered, exact consecutive blocked outcomes, other Rejected
outcomes, and Unknown update or preserve registry state exactly as declared
and never blind-retry; and target, prompt, response body, identifier, credential,
and endpoint logging guards hold.

Follow-ups

A separate user-reminder contract may bind the initiating user and trusted scope
and revalidate both at execution. Later work may add operator aliases and
registry audit/CRUD, opt-out controls, external-scheduler ingress, catch-up or a
durable outbox, media/card scheduled payloads, persistent bot-owned activity
reconciliation, encrypted/shared transactional storage, multi-replica
coordination, or sovereign-cloud profiles.

At a Glance

Authenticated Teams activity / operator target
                    │
                    ▼
            [this PR’s bounded layer]
                    │
                    ▼
          explicit outcome or fail-closed stop

Prior Art & Industry Research

OpenClaw: its Microsoft Teams extension separates access checks, Bot Framework route context, and outbound operations. For this slice the relevant comparison is proactive Teams sends from previously trusted conversation context.

Hermes Agent: its Teams platform adapter keeps Teams-specific transport and message shaping behind a platform adapter. It does not provide OpenAB’s negotiated Core/Gateway outcome contract, so this PR keeps the useful adapter boundary but adds explicit fail-closed semantics.

Proposed Solution

  • Allow only operator-owned baseline [[cron.jobs]] to target one exact trusted Teams conversation.
  • Require a real-ID trigger delivery before session or ACP work.
  • Reconcile authoritative delivery outcomes into registry lifecycle state and reject Teams usercron.

Why this approach?

Restricting authority to operator baseline jobs prevents agent-writable schedules from turning an old route into an ambient send capability.

Alternatives Considered

Allow usercron or /remind to reuse persistent routes (rejected: missing user/scope revalidation) or retry Unknown sends (rejected: duplicates).

Validation

  • cargo test -p openab-core cron::tests (79 passed)
  • cargo test -p openab-gateway --features teams adapters::teams_registry::tests (14 passed)
  • Core/Gateway compilation and Helm renders

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant