Skip to content

fix(msteams): default alwaysFetchGraphMessage=true on the Boon fork#39

Merged
insomnius merged 5 commits into
boonfrom
eng/msteams-alwaysFetchGraphMessage-default-on
Jul 7, 2026
Merged

fix(msteams): default alwaysFetchGraphMessage=true on the Boon fork#39
insomnius merged 5 commits into
boonfrom
eng/msteams-alwaysFetchGraphMessage-default-on

Conversation

@insomnius

@insomnius insomnius commented Jul 6, 2026

Copy link
Copy Markdown

What Problem This Solves

Every Teams tenant in the Boon fleet observed the ENG-14349 Bot Framework stub-stripping regression: inbound activities arrive without the <attachment id=...> HTML stub AND without reference-typed entries even with RSC consent granted, so attachments silently vanish unless the Graph re-fetch path fires. arguijo hit this on 2026-07-06 shortly after the fleet moved to 2026.6.11-boon.1 — Teams broke while Slack kept working.

Historically the fleet worked around this with a host-local msteams SP-PATCH baked in via gandalf-manager scripts/fleet-msteams5.22-bump.sh — a Python edit of the compiled bundle on every Teams host — with ENG-14431 will retire this in the patch comment. This PR is that retirement.

Why This Change Was Made

Upstream 6.11 already ships the fix as an opt-in config: channels.msteams.alwaysFetchGraphMessage (default off). Upstream keeps it off because tenants where Bot Framework delivers the <attachment> stub correctly should not pay per-channel-message Graph latency.

The Boon fork does not have such tenants — every Teams host in the fleet was already carrying the SP-PATCH, i.e. was already paying the round-trip. Flipping the fork default from undefinedtrue gives the same behavior as SP-PATCH without host-local bundle edits, and centralizes future changes to the flag in the fork rather than in a shell script.

The change is scoped to the fork consume-site (extensions/msteams/src/monitor-handler/message-handler.ts) via a small resolver — the upstream schema/type/inbound-media contracts are unchanged. Operators can still set channels.msteams.alwaysFetchGraphMessage: false per host to opt out.

User Impact

  • Teams hosts (arguijo, marathon, veracity, jaynes, kevin-sullivan, badger-construction, macc, salmon, trial-instance, …): attachments in channel/group messages resolve reliably even when Bot Framework strips the stub — no per-host bundle patching, survives openclaw upgrades, no drift.
  • Operator opt-out: explicit alwaysFetchGraphMessage: false still honored.
  • Non-Teams hosts: no impact.
  • Version bump: 2026.6.11-boon.12026.6.11-boon.2.

Evidence

  • SP-PATCH source of truth: getboon/gandalf-manager scripts/fleet-msteams5.22-bump.sh — the two edits it applied on every Teams host.
  • SP-PATCH 2026.5.18-boon.1 — session-takeover hardening #2 (aadGroupId preference): already merged upstream at extensions/msteams/src/attachments/graph.ts:85 — no fork work needed.
  • SP-PATCH fix(googlechat): scope agent sessions per thread in threaded spaces #1 (gate-relax): upstream's alwaysFetchGraphMessage opt-in config is the same code path; this PR flips the default only.
  • Regression reproduced on Boon Teams host: arguijo, 2026-07-06 (Slack thread #project-rohan/p1783349412), agreed with Victor + team.
  • Unit test: extensions/msteams/src/monitor-handler/graph-fallback-default.test.ts — asserts fork default is true, explicit false opts out, explicit true still-on.
  • Fleet baseline: 29/29 Boon EC2 boon-agent hosts on 2026.6.11-boon.1 (807986a) (SSM probe 2026-07-06).

Rollout after merge: 2026.6.11-boon.2 fork release → fleet-sweep Teams hosts to pick up the tarball → per-host changedoc entry stating the SP-PATCH bump script is retired.

🤖 Generated with Claude Code


Summary by cubic

Default channels.msteams.alwaysFetchGraphMessage to true on the Boon fork so Teams channel attachments resolve reliably without per-host bundle patches. Retires the SP-PATCH workaround while keeping a per-host opt‑out.

  • Bug Fixes

    • Mitigates the Bot Framework stub‑stripping regression by enabling Graph re‑fetch by default (ENG-14349).
    • Adds resolveMSTeamsAlwaysFetchGraphMessage in the @openclaw/msteams message handler; honors explicit true/false and leaves callee contracts unchanged; tests added.
    • Aligns config types/schema and docs (upstream default=false, fork default=true), removes plugin‑private paths from core JSDoc to satisfy guardrails, and bumps to 2026.6.11-boon.2 with refreshed npm-shrinkwrap.json.
  • Migration

    • No action needed for existing Boon Teams hosts; the fleet stops relying on the SP-PATCH.
    • To opt out, set channels.msteams.alwaysFetchGraphMessage: false on a host.

Written for commit e528f64. Summary will update on new commits.

Review in cubic

Every Teams tenant in the Boon fleet observed the ENG-14349 Bot Framework
stub-stripping regression - inbound activities arrive without the
`<attachment id=...>` HTML stub and without `reference`-typed entries
even with RSC consent granted, so attachments silently vanish unless the
Graph re-fetch path fires.

Upstream 6.11 already ships the fix as opt-in config
`channels.msteams.alwaysFetchGraphMessage` (default off, kept off upstream
so tenants where Bot Framework delivers the stub correctly don't pay
per-message Graph latency). The Boon fleet does not have such tenants -
every Teams host was previously relying on a host-local msteams SP-PATCH
baked in via gandalf-manager `scripts/fleet-msteams5.22-bump.sh`.

Flip the fork default via a small resolver so an explicit `false` still
opts out per host, and the change is unit-testable without wiring through
the full message-handler.

Version bump: 2026.6.11-boon.1 -> 2026.6.11-boon.2.
@insomnius

Copy link
Copy Markdown
Author

/cr

@github-actions

github-actions Bot commented Jul 6, 2026

Copy link
Copy Markdown

Dependency Guard

This PR changes dependency-related files. Maintainers should confirm these changes are intentional.

Changed files:

  • npm-shrinkwrap.json
  • package.json

Maintainer follow-up:

  • Review whether the dependency changes are intentional.
  • Inspect resolved package deltas when lockfile, shrinkwrap, or workspace dependency policy changes are present.
  • Treat package-lock.json and npm-shrinkwrap.json diffs as security-review surfaces.
  • Run pnpm deps:changes:report -- --base-ref origin/main --markdown /tmp/dependency-changes.md --json /tmp/dependency-changes.json locally for detailed release-style evidence.

@github-actions

github-actions Bot commented Jul 6, 2026

Copy link
Copy Markdown

Dependency graph changes noted

This PR includes dependency graph changes. The dependency guard is informational because the PR author is a repository admin or a member of @openclaw/openclaw-secops.

  • Current SHA: e528f64c04896edcfc7cd93c86207fd14b578d47
  • Trusted actor: @insomnius
  • Trusted role: pull request author; repository admin

Security review is still recommended before merge when the dependency graph change is intentional.

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No issues found across 5 files

Re-trigger cubic

insomnius added 2 commits July 6, 2026 22:46
Round-1 review findings on PR #39:

- `npm-shrinkwrap.json` still pinned `2026.6.11-boon.1`; regen via
  `scripts/generate-npm-shrinkwrap.mjs` so release-check version parity
  (`scripts/check-openclaw-package-tarball.mjs:243`) passes.
- Config-contract docs at `src/config/types.msteams.ts:164` and
  `src/config/zod-schema.providers-core.ts:1651` still asserted
  "Default false." — now note upstream=false / fork=true so the schema/type
  peer stays aligned with the runtime resolver, per root `CLAUDE.md`
  "Config contract: exported types, schema/help, metadata, baselines, docs
  aligned."
…JSDoc

Round-2 review findings on PR #39:

- `extensions/msteams/src/monitor-handler/inbound-media.ts:37` — the
  sibling JSDoc on `resolveMSTeamsInboundMedia`'s param still said
  "Default false (upstream behavior)." and is what editors surface at the
  message-handler call site. Note that the caller resolves the fork default
  before calling in.
- `docs/channels/msteams.md` — `alwaysFetchGraphMessage` was never
  listed in the user-facing Configuration section even upstream; add it so
  the flag is discoverable and the CHANGELOG's opt-out (`false`) is
  findable via docs. Doc source publishes to the openclaw/docs upstream
  mirror, so the entry stays upstream-neutral and describes upstream
  behavior; the fork-specific default is called out only in the fork
  `CHANGELOG.md` and in the internal-facing schema/type JSDoc.

@cubic-dev-ai cubic-dev-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1 issue found across 2 files (changes from recent commits).

Tip: Review your code locally with the cubic CLI to iterate faster.

Fix all with cubic | Re-trigger cubic

Comment thread docs/channels/msteams.md Outdated
insomnius added 2 commits July 6, 2026 23:33
…lee-level test

Round-3 review findings on PR #39:

- `docs/channels/msteams.md` "Set to \`false\` explicitly on any
  deployment that overrides this default and wants to opt out." leaked the
  existence of a fork override to the upstream docs mirror while sitting
  next to "Default: false.". Drop the trailer; the default sentence is
  enough for upstream readers, and the fork `CHANGELOG.md` still
  documents the fork override + opt-out.
- `extensions/msteams/src/monitor-handler/inbound-media.test.ts:231`
  test title said "(upstream default)", but the assertion is at the
  callee boundary and stays valid regardless of the caller's default. The
  message handler applies the resolver upstream, so this test proves the
  callee contract, not the caller default. Retitle + rewrite the leading
  comment to describe the contract, not the (now-misleading) upstream
  behavior.

Round-3 finding #3 (PLAUSIBLE, not filed): no message-handler-level
end-to-end test that exercises the fork default. Accepted as-is —
resolver unit tests + explicit callee-level tests + comment coverage give
enough confidence for a 1-line default flip. Full message-handler test
scaffolding is heavy and out of scope for this PR.
CI `checks-fast-contracts-channels-a` failure: the round-1 doc updates
inserted the plugin-private path
`extensions/msteams/src/monitor-handler/graph-fallback-default.ts` into
core `src/config/types.msteams.ts` and `src/config/zod-schema.providers-core.ts`
JSDoc, which triggered
`src/channels/plugins/contracts/channel-import-guardrails.test.ts`
("keeps core production files off plugin-private src imports").

Reword the doc so it names the fork consume-site by plugin
(`@openclaw/msteams`) and describes the runtime seam (resolver applied
before `resolveMSTeamsInboundMedia`), rather than pointing at a
plugin-private source path. Verified locally:
- `channel-import-guardrails.test.ts`: 148 tests passing.
- `graph-fallback-default.test.ts` + `inbound-media.test.ts`: 16 tests
  passing.

@gandalfboon gandalfboon Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed — approving. No blocking issues.

Logic. resolveMSTeamsAlwaysFetchGraphMessage(configured) returns configured ?? BOON_FORK_ALWAYS_FETCH_GRAPH_MESSAGE_DEFAULT. The nullish-coalesce is the right call: an explicit false opts out per host, and only an unset (undefined) flag falls through to the fork default true. A || here would have silently clobbered the opt-out — it doesn't. Correct.

Seam. The default is resolved in message-handler.ts before calling resolveMSTeamsInboundMedia, and the callee still treats undefined as off. That keeps the callee contract upstream-neutral, and the retitled inbound-media.test.ts:231 now asserts the callee boundary rather than a (misleading) "upstream default" — good catch in round 3.

Fork hygiene. Upstream-mirrored docs/channels/msteams.md documents only the upstream false default with no fork-override leak; the fork default + opt-out live in CHANGELOG.md and internal JSDoc. Config-contract peers (types.msteams.ts, zod-schema.providers-core.ts) are aligned. Zero upstream schema changes. Version bump + npm-shrinkwrap.json are in sync at 2026.6.11-boon.2.

Verification (pulled from source, not the description):

  • Test: graph-fallback-default.test.ts covers all three branches (unset→true, explicit true, explicit false→false). CI checks-fast-contracts-channels-a + channel-runtime-boundary green.
  • Checks: 120 pass / 0 fail / 0 pending. The channel-import-guardrails regression from the round-1 JSDoc is resolved (final commit reworded to reference the plugin publicly).
  • Review threads: 1, resolved + outdated (cubic-dev-ai P2 — correctly rejected; upstream docs shouldn't carry the fork override).
  • Commits: all 5 verified-signed. mergeStateStatus: CLEAN.

Ships. Retiring the host-local SP-PATCH in favor of a fork default is the right structural move.

@insomnius
insomnius merged commit 568a1bb into boon Jul 7, 2026
155 checks passed
@insomnius
insomnius deleted the eng/msteams-alwaysFetchGraphMessage-default-on branch July 7, 2026 10:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants