Skip to content

Add scrum-master scenario: Scrum Master autopilot using Node.js SDK - #334

Open
keshav Keshari (keshavk-msft) wants to merge 37 commits into
microsoft:mainfrom
keshavk-msft:scenario/scrum-master
Open

keshav Keshari (keshavk-msft) wants to merge 37 commits into
microsoft:mainfrom
keshavk-msft:scenario/scrum-master

Conversation

@keshavk-msft

Copy link
Copy Markdown

Add scrum-master scenario: Scrum Master autopilot using Node.js SDK

What this adds

A scenario extension under scenarios/scrum-master/ — an autonomous Scrum Master built on the Microsoft Agent 365 SDK + OpenAI Agents SDK that runs a scrum team's ceremonies end-to-end: daily standups, board reconciliation, blocker chase, mid-sprint risk warnings, grounded Q&A, and the sprint close report. Complements the existing Chief-of-Staff scenario (#333) by covering the delivery-team side of leader / squad workflows.

Capabilities

Seven flows, each a handler in src/handlers/:

  • Standup — proactive Adaptive Card DMs → summary card to configured channel
  • Reconcile — deterministic phrase classifier → safe auto-transitions on Jira, ambiguous ones go through an SM approval card
  • Chase — blocker → helper matched from SMA_HelperRoster → MCP calendar tool books an unblock meeting on the agent's mailbox
  • Warn — sprint risk alert when progress vs points-to-do thresholds trip
  • Answer — grounded Q&A over live Jira with per-user rolling history (follow-ups like "provide more details" work)
  • Mid-sprint RAG — T-2 red/amber/green table to channel
  • Sprint close — management-ready markdown report on sprint end

Full per-flow mermaid sequence diagrams: scenarios/scrum-master/docs/design.md.

Design principles

Verbatim from docs/design.md:

  1. Deterministic-first. LLM is gated to only the two paths that genuinely need language understanding (free-text Q&A, MCP calendar tool loop).
  2. Card actions never double-fire. Every submit acks in <200 ms and defers heavy work via setImmediate.
  3. Graceful degradation, never a crash. Process-level safety nets keep scheduler alive on connector failures.
  4. One path to Graph. Delegated device-code + MSAL cache — no application-permission client secret required.
  5. Durable state in SharePoint. Seven SMA_* lists survive restarts.
  6. Jira is the source of truth for issue state. Every LLM reply is grounded through a Jira tool call.

What's included

scenarios/scrum-master/
├─ README.md                    — Setup, quick-start (mock), full-setup (live), first-proof, troubleshooting, deploy-to-Azure
├─ docs/
│  ├─ design.md                 — 12 sections: principles, sequence diagrams, auth model, extension points
│  └─ sharepoint-schema.md      — Full column reference for every SMA_* list
├─ src/                         — Handlers, cards, services, cron, mock, utils
├─ scripts/
│  ├─ setup-sharepoint.ts       — Idempotent list provisioning via delegated Graph
│  ├─ seed-team.ts              — SMA_TeamMembers from team.sample.json
│  ├─ seed-helper-roster.ts     — SMA_HelperRoster
│  ├─ seed-jira-sample.ts       — Optional Jira story/sub-task/sprint seed
│  ├─ team.sample.json          — 4 placeholder personas (Alice/Bob/Charlie/Dana)
│  └─ sprint.sample.json        — 2 stories + 5 sub-tasks topology
├─ manifest/                    — Teams app + agentic-user templates (placeholder GUIDs)
├─ azure-functions/             — Sibling package: nightly + mid-sprint timers
├─ package.json                 — Scripts: dev, build, test-tool, setup:sharepoint, seed, seed:helpers, seed:jira
├─ tsconfig.json
├─ .env.template                — Every env var with WHY comments
└─ .gitignore

Runs offline

JIRA_MODE=mock (the default) drives the sample against a mutable in-memory Jira sprint in src/mock/jira-mock.ts. Contributors can clone, npm install, npm run dev, npm run test-tool and try /standup in the Agents Playground without an Atlassian account, without a SharePoint site, and without a Teams tenant.

Live mode (JIRA_MODE=live) requires:

  • Atlassian Cloud (free tier is fine)
  • SharePoint site the developer can write to (delegated Graph, no admin consent)
  • Azure OpenAI or OpenAI API key

Auth model — delegated only

All Microsoft Graph calls use MSAL device-code + delegated scopes (Sites.ReadWrite.All, Sites.Manage.All, Files.ReadWrite.All). Onboarding is a single interactive sign-in. No application-permission client credentials, no admin consent, no Teams policies to provision.

Verification

  • Set up on fresh M365 dev tenant + fresh Jira Cloud trial per README.
  • All 7 flows exercised end-to-end.
  • Secret scan clean — no tenant IDs, no client secrets, no PATs, no persona bleed. All placeholders are 00000000-…, <your-org>.atlassian.net, alice@contoso.com etc.
  • All source has MIT copyright headers.
  • TypeScript compiles clean; no lint errors.
  • CLA signed.

Placement — why scenarios/

Placed at the repo root under scenarios/scrum-master/ rather than under a language tier (e.g. nodejs/openai/) because a scrum-master workflow doesn't map cleanly to a single SDK — it composes Agent 365 SDK, OpenAI Agents SDK, MCP Calendar, and multiple external services. This mirrors how the Chief-of-Staff sample (#333) is placed. Happy to relocate to nodejs/openai/scenarios/scrum-master/ if reviewers prefer a language-tier scoping.

Not included / future work

  • Multi-team support. Sample is single-team by design; the roadmap for SMA_Teams list + TeamId column + per-team Jira credentials in Key Vault is documented in docs/design.md.
  • Production Key Vault-backed MSAL cache. Local dev uses a file cache (.mstoken-cache.json, gitignored). Production swap-in is called out in docs/design.md.
  • E2E test suite under tests/e2e/. Recommend follow-up PR once initial review lands.

Commits

  1. d33aecc — initial import of the scenario code (57 files)
  2. feb98d9 — Jira sample-data seed script + SharePoint schema doc
  3. 1c5a4af — README rewrite (intro-features-prereqs-setup structure)
  4. 62b0cad — observability + docs polish (logger, http-logger, startup banner, process safety nets, design.md, TOC, troubleshooting, deploy-to-Azure)

Related

Scenario extension on top of the OpenAI + Agent 365 base sample: an
autonomous Scrum Master that runs standups, reconciles the Jira board,
chases blockers via MCP Calendar, warns on sprint risk, answers grounded
Q&A, and posts a management-ready sprint close report.

Runs out of the box with JIRA_MODE=mock (no Atlassian account required).
Live mode uses Jira Cloud REST + delegated Microsoft Graph
(Sites.ReadWrite.All + Sites.Manage.All) via device-code flow.

* nodejs / Microsoft Agent 365 SDK + OpenAI Agents SDK + MCP tools
* Adaptive Card DMs, per-user rolling context, deterministic classifier
* Sibling azure-functions/ package hosts the nightly/weekly timers
Enables reviewers to try live mode (JIRA_MODE=live) without hand-crafting
issues:

* src/scripts/seed-jira-sample.ts — creates 2 stories + 5 sub-tasks and a
  future sprint on a pre-existing Jira Scrum project. Idempotent by
  summary. Reuses accountIds from team.sample.json so a single edit
  propagates through the whole seed.
* src/scripts/sprint.sample.json — topology (edit to customise).
* docs/sharepoint-schema.md — human-readable reference for every
  SMA_* list column, matching LIST_SCHEMAS in services/sharepoint.ts.
* package.json — new npm script: seed:jira
Consolidates a single top-level H1 (was two) and reorders content for a
first-time reader: intro paragraph -> features (7 MVPs) -> architecture
diagram -> prerequisites -> quick start in mock mode -> full setup in
live mode -> capability try-it table -> reference sections.

Adds:
* Mermaid architecture diagram
* Quick start (mock mode, no external deps) as the fast path
* Full configuration reference table with defaults and required-for
* Try-each-capability table with trigger + expected + handler link
* Link to docs/sharepoint-schema.md

Drops:
* Duplicated base-sample content (identity, install, typing, multi-message)
  now referenced via a link at the top
* Redundant POC-flavoured framing
Additive-only improvements ported from patterns in the Chief-of-Staff sample
(PR microsoft#333). Zero behaviour change to existing
handlers.

* src/util/logger.ts (new) — level-based logger with LOG_LEVEL, timestamped
  scope tags, and automatic secret redaction. Available for future use;
  existing console.log calls left in place.
* src/util/httpLogger.ts (new) — global axios interceptor for outbound
  Jira / Graph / MCP tracing. Off by default, gated behind LOG_HTTP=true.
* src/startup-check.ts (new) — one-shot boot banner printing every relevant
  env var with [MISSING] markers so misconfig surfaces before the first
  handler runs.
* src/index.ts — wire installHttpLogging + printStartupBanner immediately
  after configDotenv(); add unhandledRejection and uncaughtException
  handlers so a stray connector 502 no longer tears down the scheduler.
* docs/design.md — replace stub with full design doc: 12 numbered sections
  including per-flow mermaid sequence diagrams, determinism boundary,
  concurrency guarantees, and extension points.
* README.md — trim architecture / reconcile rules / warn thresholds /
  calendar path (moved to design.md); add TOC, First live proof smoke
  test, Troubleshooting matrix, and Deploy to Azure sections.
* .env.template — document LOG_LEVEL and LOG_HTTP toggles.
Copilot AI review requested due to automatic review settings July 24, 2026 09:04
@keshavk-msft
keshav Keshari (keshavk-msft) requested a review from a team as a code owner July 24, 2026 09:04

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Adds a new Scrum Master autonomous scenario under scenarios/scrum-master/, built on the Microsoft Agent 365 SDK + OpenAI Agents SDK, with integrations for Jira (live + mock), SharePoint Lists state, proactive Teams messaging via Adaptive Cards, and optional Azure Functions timers to drive scheduled ceremonies.

Changes:

  • Introduces the Scrum Master scenario agent (message routing, slash commands, standup/reconcile/chase/warn/sprint-summary flows) plus supporting services (Jira, SharePoint, Graph delegated auth, MCP Calendar).
  • Adds provisioning + seed scripts for SharePoint lists, helper roster, and optional Jira sample data.
  • Adds scenario packaging/config (ToolingManifest, env template, manifests, Azure Functions sibling project, build tooling).

Reviewed changes

Copilot reviewed 59 out of 63 changed files in this pull request and generated 8 comments.

Show a summary per file
File Description
scenarios/scrum-master/tsconfig.json TypeScript compiler configuration for the scenario package.
scenarios/scrum-master/ToolingManifest.json Declares MCP servers (Mail/Calendar) used by the scenario.
scenarios/scrum-master/src/util/logger.ts Scenario-level log helper with redaction/truncation.
scenarios/scrum-master/src/util/httpLogger.ts Optional global axios request/response tracing.
scenarios/scrum-master/src/token-cache.ts In-memory token cache + token resolver for observability export.
scenarios/scrum-master/src/startup-check.ts Startup banner summarizing key env configuration.
scenarios/scrum-master/src/services/team-roster.ts SharePoint-backed team roster with cached ConversationReferences.
scenarios/scrum-master/src/services/sharepoint.ts Graph CRUD wrapper for SharePoint lists + report upload helper.
scenarios/scrum-master/src/services/session-store.ts In-memory standup session tracking for fan-in/cutoffs.
scenarios/scrum-master/src/services/proactive.ts Proactive messaging helper (continueConversation wrapper).
scenarios/scrum-master/src/services/jira.ts Jira client abstraction (live REST + mock implementation).
scenarios/scrum-master/src/services/jira-tool.ts OpenAI Agents function-tools for grounded Jira Q&A.
scenarios/scrum-master/src/services/issue-labels.ts Helpers to map Jira keys to “Task-N” labels and clean titles.
scenarios/scrum-master/src/services/helperMatcher.ts Keyword-based helper matching for blocker chase flow.
scenarios/scrum-master/src/services/graph.ts Delegated Graph auth via MSAL device-code + file token cache.
scenarios/scrum-master/src/services/calendar.ts Calendar ops via MCP CalendarTools using a scenario-specific agent.
scenarios/scrum-master/src/scripts/team.sample.json Sample team roster seed data (placeholder identities).
scenarios/scrum-master/src/scripts/sprint.sample.json Sample sprint topology for optional Jira seeding.
scenarios/scrum-master/src/scripts/setup-sharepoint.ts Idempotent SharePoint list + library provisioning script.
scenarios/scrum-master/src/scripts/seed-team.ts Seeds TeamMembers list (optionally patches current user AAD id).
scenarios/scrum-master/src/scripts/seed-jira-sample.ts Optional live Jira sample data seeding (stories/subtasks/sprint).
scenarios/scrum-master/src/scripts/seed-helper-roster.ts Seeds HelperRoster list rows used by blocker chase.
scenarios/scrum-master/src/openai-config.ts OpenAI/Azure OpenAI client configuration wiring for agents SDK.
scenarios/scrum-master/src/mock/jira-mock.ts In-memory mutable mock sprint for offline demo mode.
scenarios/scrum-master/src/index.ts Express host + internal endpoints + scheduler kickoff.
scenarios/scrum-master/src/handlers/warn.ts Nightly sprint risk detection + SM DM.
scenarios/scrum-master/src/handlers/sprint-summary.ts T-2 mid-sprint markdown summary report builder + delivery.
scenarios/scrum-master/src/handlers/reconcile.ts Deterministic status classifier + safe Jira transitions + SM approval card.
scenarios/scrum-master/src/handlers/config.ts /config channel capture of channel ConversationReference.
scenarios/scrum-master/src/handlers/commands.ts Slash-command router for scenario commands.
scenarios/scrum-master/src/handlers/answer.ts Grounded Jira Q&A agent with per-user rolling history.
scenarios/scrum-master/src/cron/local-scheduler.ts In-process node-cron scheduler for dev mode.
scenarios/scrum-master/src/config.ts Central env-var parsing for scenario configuration.
scenarios/scrum-master/src/client.ts OpenAI Agents + MCP tool registration + observability scope wrapper.
scenarios/scrum-master/src/cards/transition-confirm.card.ts Adaptive Card for SM approval of non-safe Jira transitions.
scenarios/scrum-master/src/cards/standup-summary.card.ts Adaptive Card for consolidated standup summary posting.
scenarios/scrum-master/src/cards/standup-request.card.ts Adaptive Card DM for standup collection + “submitted” confirmation.
scenarios/scrum-master/src/cards/meeting-propose.card.ts Adaptive Card for SM meeting-slot selection and booking.
scenarios/scrum-master/src/cards/blocker-escalation.card.ts Adaptive Card DM escalating a blocker to the SM.
scenarios/scrum-master/src/agent.ts AgentApplication wiring: message routing, card submits, notifications, token preload.
scenarios/scrum-master/package.json Scenario package metadata, dependencies, and scripts.
scenarios/scrum-master/manifest/manifest.json Teams manifest template for the scenario.
scenarios/scrum-master/manifest/agenticUserTemplateManifest.json Agentic user template manifest for the scenario.
scenarios/scrum-master/docs/sharepoint-schema.md Human-readable SharePoint list schema reference.
scenarios/scrum-master/azure-functions/tsconfig.json TS config for the Azure Functions sibling project.
scenarios/scrum-master/azure-functions/src/index.ts Azure Functions timers that POST to agent internal endpoints.
scenarios/scrum-master/azure-functions/README.md Azure Functions setup/run/deploy documentation.
scenarios/scrum-master/azure-functions/package.json Azure Functions package metadata and deps.
scenarios/scrum-master/azure-functions/local.settings.sample.json Local settings template for Functions (callback URL + token).
scenarios/scrum-master/azure-functions/host.json Azure Functions host configuration.
scenarios/scrum-master/azure-functions/.gitignore Ignores dist, node_modules, and local.settings.json secrets.
scenarios/scrum-master/.gitignore Ignores build output, env files, MSAL cache, and logs.
scenarios/scrum-master/.env.template Comprehensive env template covering OpenAI, Agent 365, Jira, SharePoint, scheduling.
Comments suppressed due to low confidence (2)

scenarios/scrum-master/src/util/httpLogger.ts:50

  • The response log line includes res.config.url verbatim, which may contain query strings. Strip ?… / #… before logging.
    scenarios/scrum-master/src/util/httpLogger.ts:60
  • The error log line includes cfg?.url verbatim, which may contain query strings. Strip ?… / #… before logging.

Comment thread scenarios/scrum-master/src/config.ts Resolved
Comment thread scenarios/scrum-master/src/index.ts Resolved
Comment thread scenarios/scrum-master/src/index.ts Resolved
Comment thread scenarios/scrum-master/src/client.ts Resolved
Comment thread scenarios/scrum-master/src/client.ts Resolved
Comment thread scenarios/scrum-master/src/client.ts Resolved
Applies 7 of the 8 review comments; the 8th (client.ts:140 MCP transport
close-in-finally) is deferred because it changes runtime behaviour on a
codepath inherited from the base sample.

* config.ts — default JIRA_MODE to 'mock' (was 'live') so a fresh clone
  runs offline in mock mode as the README documents, instead of throwing
  on missing Jira credentials.
* index.ts — remove duplicate unhandledRejection/uncaughtException
  handlers (kept the more-detailed pair at top of file).
* index.ts — emit a one-shot boot warning when INTERNAL_TRIGGER_TOKEN is
  empty so production deployments notice open /api/internal/* endpoints.
* token-cache.ts — replace 'All rights reserved' header with the
  repo-standard MIT license header.
* client.ts — rename observability service from 'TypeScript Claude
  Sample Agent' to 'Scrum Master Sample Agent'.
* client.ts — fix fallback agentId/agentName (was
  'typescript-compliance-agent' / 'TypeScript Compliance Agent').
* util/httpLogger.ts — add safePath() helper and strip query strings +
  URL fragments from request/response/error log lines so credentials in
  ?token=… never leak.
* AGENT-CODE-WALKTHROUGH.md — sync doc snippet to new agentId strings.
Copilot AI review requested due to automatic review settings July 24, 2026 09:17
@keshavk-msft

Copy link
Copy Markdown
Author

Thanks copilot-pull-request-reviewer for the thorough pass. Pushed ca578fa addressing 7 of the 8 comments:

# File Fix
1 src/config.ts:36 getJiraMode() now defaults to mock so a fresh clone with no .env runs offline (matches README).
2 src/index.ts:170 Removed the duplicate unhandledRejection/uncaughtException handlers (kept the more-detailed pair at the top of the file).
3 src/index.ts:79 One-shot boot warning when INTERNAL_TRIGGER_TOKEN is empty so open /api/internal/* endpoints don't slip into production silently.
4 src/token-cache.ts:1 Replaced "All rights reserved" header with the standard MIT header.
5 src/client.ts:45 Observability service name → Scrum Master Sample Agent.
6 src/client.ts:158 Fallback agentId / agentName → scrum-master-sample-agent / Scrum Master Sample Agent.
8 src/util/httpLogger.ts Added safePath() helper and stripped ?… / #… from request, response, and error log lines. Credentials in ?token=… no longer leak into logs.

Deferred: comment #7 (src/client.ts:140 — server.close() in finally)

Valid observation and the same behaviour we already worked around in services/calendar.ts (removed the close() there and added a session-lost retry). Keeping client.ts unchanged in this PR because:

  1. invokeAgent() in client.ts is an inherited codepath from the base OpenAI sample-agent and isn't on any hot path in the Scrum Master flows — our Q&A goes through handlers/answer.ts, which builds its own Agent per turn. So the flaky-tool-reuse risk is theoretical for this scenario.
  2. Aligning client.ts with the calendar.ts pattern touches MCP transport lifecycle, which is a runtime-behaviour change I'd rather land as its own PR (with a smoke test) than fold into this initial contribution.

Happy to open a follow-up if reviewers prefer.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 59 out of 63 changed files in this pull request and generated 8 comments.

Comments suppressed due to low confidence (4)

scenarios/scrum-master/src/services/sharepoint.ts:127

  • findByField() has the same issue as findByTitle(): URL-encoding the value inside the OData literal can break matches (e.g., spaces become %20). Encode the entire $filter expression and keep escapeODataString limited to OData single-quote escaping.
    scenarios/scrum-master/src/client.ts:139
  • invokeAgent() always closes MCP servers in finally. In this same scenario, calendar.ts documents that closing Streamable-HTTP MCP transports can break subsequent calls with "Session not found" because McpToolRegistrationService can reuse an already-closed transport. Consider not closing MCP servers here (or only closing on process shutdown) to avoid intermittent MCP failures across turns.
      await this.closeServers();

scenarios/scrum-master/azure-functions/README.md:24

  • This second link to ../openai/sample-agent is also incorrect for this scenario (the agent is ..). Updating it avoids sending readers to a non-existent path.
- The agent already running somewhere reachable — either a dev tunnel URL, App Service, or Container Apps endpoint that exposes `/api/internal/*` from [`../openai/sample-agent`](../openai/sample-agent).

scenarios/scrum-master/src/index.ts:94

  • When INTERNAL_TRIGGER_TOKEN is empty, /api/internal/* endpoints become unauthenticated even if the server is bound to 0.0.0.0 (non-development). Logging a warning is easy to miss in deployment logs; it's safer to reject requests unless you're explicitly in development mode.

Comment thread scenarios/scrum-master/src/config.ts Resolved
Comment thread scenarios/scrum-master/src/agent.ts Resolved
Comment thread scenarios/scrum-master/src/agent.ts Resolved
Comment thread scenarios/scrum-master/package.json Resolved
Copilot AI review requested due to automatic review settings July 27, 2026 06:07

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 59 out of 63 changed files in this pull request and generated 3 comments.

Comments suppressed due to low confidence (2)

scenarios/scrum-master/src/agent.ts:238

  • The prompt Please follow any instructions in it makes the agent treat email content as executable instructions, which is a classic prompt-injection vector. Even with general safety guidance elsewhere, it’s better to frame email content as untrusted data and ask for summarization + a drafted response.
      // Then process the email
      const response = await client.invokeAgentWithScope(
        `You have received the following email. Please follow any instructions in it. ${emailContent}`
      );

scenarios/scrum-master/src/client.ts:199

  • closeServers() closes every MCP server after each agent invocation. This conflicts with the calendar MCP guidance in services/calendar.ts / README troubleshooting: streamable HTTP MCP sessions are intended to be long-lived, and closing can lead to -32001 Session not found on subsequent turns when the registration service reuses a closed transport.
  private async closeServers(): Promise<void> {
    if (this.agent.mcpServers && this.agent.mcpServers.length > 0) {
      for (const server of this.agent.mcpServers) {
        await server.close();
      }
    }
  }

Comment thread scenarios/scrum-master/src/index.ts Resolved
Copilot AI review requested due to automatic review settings July 27, 2026 06:13

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 59 out of 63 changed files in this pull request and generated 2 comments.

Comments suppressed due to low confidence (6)

scenarios/scrum-master/src/agent.ts:191

  • Logging even a token prefix can leak credentials via console logs (often shipped to centralized log stores). Avoid printing any part of the observability token; log only metadata like agentId/tenantId.
      console.log(`Preloaded Observability token for agentId=${agentId}, tenantId=${tenantId} token=${aauToken?.token?.substring(0, 10)}...`);

scenarios/scrum-master/src/agent.ts:238

  • This prompt tells the model to "follow any instructions" inside an email, which is a direct prompt-injection vector (email content is untrusted). Ask the model to summarize/extract action items instead, without executing instructions from the email body.
      const response = await client.invokeAgentWithScope(
        `You have received the following email. Please follow any instructions in it. ${emailContent}`
      );

scenarios/scrum-master/src/client.ts:140

  • This closes MCP server sessions after every run(). In this same scenario (see calendar.ts), closing Streamable-HTTP MCP transports can break subsequent tool calls with "Session not found" because McpToolRegistrationService may reuse the underlying transport across agents. Consider keeping MCP sessions long-lived here as well.
    } finally {
      await this.closeServers();
    }

scenarios/scrum-master/src/index.ts:94

  • If INTERNAL_TRIGGER_TOKEN is empty, /api/internal/* becomes unauthenticated for all environments (including production misconfig). It would be safer to only allow the "open" behavior in development and fail closed otherwise.
    scenarios/scrum-master/azure-functions/README.md:3
  • This README links to ../openai/sample-agent, but the agent process for this scenario is the parent scenarios/scrum-master package (and its README). The current link is broken/misleading in this repo layout.
Two timer-triggered functions that drive the SMA scheduled ceremonies. The agent process (in [`../openai/sample-agent`](../openai/sample-agent)) owns all state, tokens, and Adaptive Card logic — these functions only *nudge* it via HTTP.

scenarios/scrum-master/azure-functions/README.md:24

  • Same as above: this link points at ../openai/sample-agent, but the internal endpoints live in the parent scenario package. Update the reference so readers can find the right code/docs.
- The agent already running somewhere reachable — either a dev tunnel URL, App Service, or Container Apps endpoint that exposes `/api/internal/*` from [`../openai/sample-agent`](../openai/sample-agent).

Comment thread scenarios/scrum-master/src/client.ts Resolved
The MCP calendar tool loop occasionally succeeds at creating the event but
the LLM returns a garbled response (e.g. webLink="onlineMeetingUrl" as a
literal string, or id="errorEvent verification failed..." from a mis-formed
rule-microsoft#6 error path). The existing !out.webLink check misses this because
the values are truthy strings that pass Zod validation.

* services/calendar.ts — after the existing empty-webLink guard, check that
  webLink is actually a URL (^https?://) and that id doesn't start with
  "error". On mismatch, throw a distinct CALENDAR_VERIFY_FAILED: error
  with an actionable "verify in Outlook" message.
* handlers/chase.ts — catch the CALENDAR_VERIFY_FAILED: prefix separately;
  mark the blocker as booked (event was almost certainly created) and DM
  the SM a warning that asks them to verify in Outlook, instead of the
  scary "couldn't book the meeting" error.

Tested in the POC with real MCP calendar output that reproduced the shape
described.
Copilot AI review requested due to automatic review settings July 29, 2026 08:04

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 59 out of 63 changed files in this pull request and generated 1 comment.

Comments suppressed due to low confidence (7)

scenarios/scrum-master/src/agent.ts:191

  • This log line prints a prefix of the exchanged observability token. Even partial token material can be used for correlation/attacks and shouldn’t be emitted to logs.
      console.log(`Preloaded Observability token for agentId=${agentId}, tenantId=${tenantId} token=${aauToken?.token?.substring(0, 10)}...`);

scenarios/scrum-master/src/agent.ts:238

  • The email-notification flow explicitly instructs the model to “follow any instructions” found in the email content. That creates a prompt-injection path where untrusted email content can drive unintended tool use or actions. The agent should treat email as untrusted data: summarize it, extract requests, and ask for user confirmation before acting.
      // Then process the email
      const response = await client.invokeAgentWithScope(
        `You have received the following email. Please follow any instructions in it. ${emailContent}`
      );

scenarios/scrum-master/src/token-cache.ts:37

  • The comments describe “expiration handling” and “store a token with expiration”, but the implementation is a plain Map with no TTL/expiry logic. This is misleading for readers and for anyone reusing the sample code.
    scenarios/scrum-master/src/client.ts:199
  • This closes all MCP server transports after every agent invocation. In this scenario, calendar.ts documents that closing a Streamable-HTTP MCP transport can break subsequent tool calls with “Session not found” when McpToolRegistrationService reuses the closed transport across turns. To avoid intermittent failures, consider not closing MCP servers here (or ensure each agent gets a non-shared transport instance).
  private async closeServers(): Promise<void> {
    if (this.agent.mcpServers && this.agent.mcpServers.length > 0) {
      for (const server of this.agent.mcpServers) {
        await server.close();
      }
    }
  }

scenarios/scrum-master/src/handlers/report.ts:268

  • The action-items table hardcodes the target sprint as "Sprint 2". That will be incorrect for most real sprint names; use a neutral label like "Next sprint" (or derive it from sprint metadata if available).
    scenarios/scrum-master/src/handlers/chase.ts:17
  • The header comment describes the blocker-chase flow as using direct Graph calls (/me/findMeetingTimes, POST /events). The implementation now drives mcp_CalendarTools via services/calendar.ts, so this comment is outdated/misleading.
    scenarios/scrum-master/src/handlers/report.ts:260
  • The action-items table hardcodes the target sprint as "Sprint 2". That will be incorrect for most real sprint names (and even for mock data) and can confuse readers; consider using a neutral label like "Next sprint".

This issue also appears on line 268 of the same file.

Comment thread scenarios/scrum-master/src/index.ts Resolved
Ports the observability pattern from PR microsoft#333 (Chief-of-Staff) so both
scenarios share the same MAC Activity wiring convention. Also addresses
the five outstanding Copilot review comments from Jul 27 and Jul 29.

Observability:
* src/observability.ts (new) — shared module: getAgentId (agentic
  instance), getAgentBlueprintId (metadata only), getTenantId,
  buildAgentDetails, buildRequest, ensureObservabilityToken (both
  identities), runWithObservabilityContext. Runtime agent id comes from
  activity.recipient.agenticAppId — not the blueprint id — which is what
  the exporter needs for spans to bind to MAC Activity.
* src/agent.ts — call ensureObservabilityToken at the top of
  handleAgentMessageActivity so per-turn spans have identity.
* src/services/proactive.ts — wrap continueConversation in
  runWithObservabilityContext so proactive DMs and channel posts carry
  the same tenant+agent baggage as inbound /api/messages turns.
* .env.template — add agent365Observability__agentInstanceId with
  guidance distinguishing runtime instance vs blueprint id.

Review-comment fixes:
* src/index.ts — fail-shut on empty INTERNAL_TRIGGER_TOKEN when
  NODE_ENV=production (was warn-only). Keeps dev convention intact.
* src/services/proactive.ts — getBotAppId throws with a clear message
  when connections__service_connection__settings__clientId is unset
  instead of letting continueConversation fail with an opaque error.
* src/cards/transition-confirm.card.ts — approval toggles default to
  'false' so risky/non-whitelisted transitions require explicit opt-in.
* src/client.ts — remove hard-coded 45 / 78 input/output token counts
  that were leaking into telemetry. Instrumentor populates real values.
* src/openai-config.ts — mask AZURE_OPENAI_ENDPOINT to scheme+host
  and log only [set]/(unset) for the deployment so internal resource
  names never appear in logs.
@keshavk-msft

Copy link
Copy Markdown
Author

Updated in 2335201. Two-part update:

1. Wired A365 observability (matches PR #333 pattern)

Ran the instrument-observability skill (equivalent) — same wiring convention as the Chief-of-Staff scenario in #333 (f71e0e6).

  • New: src/observability.ts — single source of truth for identity resolution, token cache warming, and OTEL baggage.
  • Runtime agent identity now comes from activity.recipient.agenticAppId (the agentic instance) — not the blueprint id. The exporter binds spans only when token principal == /agents/{agentId} == gen_ai.agent.id; blueprint-tagged spans and instance-tagged spans land in separate identity groups and only one has a cached token. Warming both means neither gets silently dropped.
  • src/agent.ts: ensureObservabilityToken at the top of handleAgentMessageActivity so inbound turns bind cleanly.
  • src/services/proactive.ts: every continueConversation call wrapped in runWithObservabilityContext so proactive DMs (standup fan-out, blocker cards, meeting picker, etc.) carry the same tenant+agent baggage as inbound /api/messages turns. Without this, all our scheduled and card-driven work silently drops spans.
  • .env.template: new agent365Observability__agentInstanceId with a clear comment distinguishing runtime instance vs blueprint id.

2. Addressed the 5 open review comments

Comment Fix
index.ts:100 — open /api/internal/* when token empty (flagged twice, Jul 27 + 29) Fail-shut when NODE_ENV=production. Warn-and-continue kept for dev convenience.
proactive.ts:33 — opaque error when clientId unset getBotAppId now throws with a clear message pointing at .env.template.
transition-confirm.card.ts:46 — toggles default to true Now default to false; risky transitions require explicit SM opt-in.
client.ts:170 — hard-coded 45/78 token counts Removed. Instrumentor now populates real values.
openai-config.ts:55 — leaking full endpoint Endpoint masked to scheme+host; deployment logged as [set] / (unset).

Not yet in this commit

  • buildUserDetails UPN resolution from PR Add chief-of-staff scenario: Chief of Staff autopilot using Node.js SDK #333's refactor — that path uses Chief-of-Staff's graph/peopleTools.ts which we don't have. Adding it here would mean also porting the Graph people lookup helper. Happy to do it as a follow-up if reviewers want the "real UPN in MAC Activity" column populated on Teams-channel activities.
  • DESIGN.md observability section — will add in the next commit alongside a matching README troubleshooting row for the "empty MAC Activity tab" scenario.

Verification pending on our tenant — will run the agent locally and confirm the boot log shows both identities being warmed.

Two things landed after live-tenant verification with the a365-skills
'a365-code-validator' + 'instrument-observability' flow:

Observability (from running the instrument-observability skill against
the sample):
* src/observability.ts — add withInvokeAgentScope() and
  withExecuteToolScope() helpers plus a per-turn AsyncLocalStorage so
  tool definitions can pick up the current TurnContext without threading
  it through every signature. buildUserDetails / buildCallerDetails
  populate user.id / userName / userEmail (UPN only when the from.id
  actually carries one). runWithTurnBaggage() replaces the old
  runWithObservabilityContext export.
* src/agent.ts — hoist ensureObservabilityToken +
  preloadObservabilityToken above the dispatch decision so cards,
  slash commands, Answer, and the generic LLM path all run inside one
  identity-tagged baggage scope. Same treatment for the
  agent-notification (email) branch.
* src/client.ts — bind AgentDetails / Request via buildAgentDetails() /
  buildRequest() from the shared module, so gen_ai.agent.id gets the
  runtime agentic instance id rather than the blueprint id. Drops the
  hard-coded conversationId literal.
* src/handlers/answer.ts — wrap the Q&A turn in withInvokeAgentScope so
  MAC Activity gets an invoke_agent parent above the auto-instrumented
  chat inference span.
* src/services/jira-tool.ts — wrap jira_get_issue,
  jira_list_sprint_issues, jira_get_issue_comments in
  withExecuteToolScope so tool calls become named execute_tool spans
  bound to the agent identity.
* .env.template — small doc tweak clarifying the exporter default.

Bug fix (found while live-testing the Q&A path):
* src/services/issue-labels.ts — toJiraKey() checked the canonical
  ^PROJ-N regex before the taskish ^task-N regex, so 'Task-9' matched
  the canonical branch and returned 'TASK-9' (a made-up project). Only
  bare numbers reached the correct branch. Reorder so the task/# prefix
  match runs first; canonical falls through only for real project keys
  like 'DEMO-14' or 'EDP-10'.

Ignore hygiene:
* .gitignore — exclude TS compile artefacts under src/**/*.{js,d.ts,
  js.map}, azure-functions/src/**/*.{js,d.ts,js.map}, and the workspace-
  local skill install directories (.agents/, .claude/,
  .github/copilot-instructions.md) so those don't accidentally join the
  next commit.

Live-tenant verification highlights (agentId f5a59964-... on tenant
1fe41f4b-...):
* Boot: Agent365Exporter enabled: true, both blueprint + agentic-
  instance identity tokens cached.
* MVP 1 standup: sentTo=4, per-card submit round-trip succeeded; span
  export-group succeeded in ~1.3s (9/10 spans bound on Answer turn,
  6/10 on standup fan-out).
* MVP 3 chase: end-to-end unblock meeting booked; 4/4 spans bound on
  the calendar tool loop.
* MVP 4 warn / MVP 6 mid-sprint RAG / MVP 7 sprint close: all fired
  through HTTP triggers, all export-group succeeded.
* MVP 5 Q&A: withInvokeAgentScope + withExecuteToolScope both fire and
  bind. Task-9 lookup succeeds after the label fix.
* M365 admin center Agents view now shows the Scrum Master Blueprint
  with a MarioR@... session on today's date.
@keshavk-msft

Copy link
Copy Markdown
Author

Live-tenant verification complete. Ran the a365-code-validator and instrument-observability skills from microsoft/agent365-skills, then exercised every MVP end-to-end. Pushed 5e8a957.

Observability instrumentation is now in place

The skill flow surfaced 5 gaps in what we had before, all fixed in this commit:

  1. Baggage scope wasn't wrapping every dispatch branch — the default free-text turn returned before the baggage scope was applied, so spans exported with no identity. Hoisted ensureObservabilityToken + preloadObservabilityToken above the router in src/agent.ts.
  2. gen_ai.agent.id was the blueprint id — src/client.ts now uses buildAgentDetails(turnContext) from the shared module, so the runtime agentic instance id (activity.recipient.agenticAppId) wins.
  3. Custom token resolver couldn't serve the span's identity — resolved by fix Added CODEOWNERS and .gitignore files #2; the cache key now matches the exported span's agentId.
  4. No invoke_agent span — new withInvokeAgentScope in src/observability.ts wraps the Q&A turn in answer.ts and the generic LLM path in agent.ts.
  5. No execute_tool spans on Jira function-tools — new withExecuteToolScope wraps jira_get_issue, jira_list_sprint_issues, jira_get_issue_comments in services/jira-tool.ts.

Bug fix caught during live testing

src/services/issue-labels.ts — toJiraKey("Task-9") was returning TASK-9 instead of EDP-9. The canonical ^PROJ-N regex matched Task-9 before the taskish branch got a chance. Reordered so the task/# prefix runs first; canonical is a fallthrough for real project keys (EDP-10, SCRUM-14).

Live-tenant verification results

Tenant 1fe41f4b-... · runtime agent f5a59964-743e-4a3c-8947-a768e7a68d8f · Scrum Master Blueprint. Every batch below was acknowledged by agent365.svc.cloud.microsoft.

MVP Verified Span export
1 · Standup trigger + fan-out ✅ sentTo: 4, skipped: 0 4 batches, all succeeded
1a · Standup card submit round-trip ✅ Mario POST /api/messages → Jira comment on EDP-5 6/10 → export ok
3 · Chase blocker → helper → book ✅ EDP-10 unblock sync booked, 2 attendees invited 4/4 bound, ~1.3s
4 · Warn (forced) ✅ atRisk: false, forceAlert delivered 3/10 → export ok
5 · Q&A + Task-N mapping ✅ Task-9 returns "Done, assigned to Quinn, 8 pts" (after fix) 9/10 bound, ~1.6s
5 · Rolling history follow-up ✅ Provide more details resolves against Task-9 inherits scope
5 · jira_get_issue_comments tool ✅ Cites Quinn's Jul 29 comment paraphrased execute_tool span fires
6 · Mid-sprint RAG ✅ 18 tasks classified, 10 RED, posted inline 3/6 → export ok
7 · Sprint close ✅ 5 stories, 8 tasks done, 1 bug closed, posted inline 3/7 → export ok

M365 admin center Agents view now shows the Scrum Master Blueprint with MarioR@M365CPI69584317.OnMicrosoft.com at 1 total session, last activity Aug 11, 2026 — confirming the end-to-end pipeline (agent → OTEL → A365 exporter → tenant admin center) is closed.

Known cosmetic warnings (not from this change, pre-existing)

  • Zod field ... .optional() without .nullable() on jira_get_issue_comments.limit and calendar tool's attendeeCount — future-version OpenAI SDK warning
  • Operation attempted on ended Span from OpenAIAgentsTraceProcessor — interop bug between @openai/agents-core and @microsoft/agents-a365-observability-extensions-openai. Non-fatal — spans still export correctly.

Worth filing as follow-up issues on the samples repo but neither blocks this PR.

Not verified in this session (deferred, not blocking)

  • MVP 2 reconcile with a move-triggering language submit (needs 3 more persona submits)
  • Full standup summarize path (needs all 4 responders)
  • Cron scheduler auto-fire (HTTP path already validated)
  • Reconcile approval card for ambiguous transitions (needs backwards move to trigger)
  • CALENDAR_VERIFY_FAILED guard (chase happy path succeeded — guard dormant)
  • Production INTERNAL_TRIGGER_TOKEN fail-shut (dev-mode warning verified at boot)

Drain accepted submissions before finalization, keep roster failures retryable, skip context-free mock timers, retain epic-backed Story subtask expansion, and correct design review helper routing. Upgrade only the affected OTLP protobuf branch and verify span serialization plus lifecycle regressions.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Regenerate with npm 10 and verify clean npm ci, build, and all 68 regressions. Preserve public tarball integrity and the approved immutable redirect release.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Remove vulnerable nested Zod 3 copies through the shared patched runtime. Validate real SDK messages, Adaptive Card actions, semantic records and feedback rejection paths, plus all 72 scenario regressions and clean npm 10 installation.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Claim new standup runs atomically using a provisioned unique RunKey, find unreported ended sprints, preserve delivery failure details, return existing bookings and use retry delays longer than callback timeouts. Document paused-worker schema migration; validate both builds and all 84 offline regressions. Keep roster lookup before finalization as the newer review requires.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Split path segments before resolving the fixture module so the required Ubuntu Node 22 job runs the same regressions as Windows.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

The runtime and the contracts operators are asked to follow are not yet aligned closely enough to merge.

Five things to address before this merges; details inline.

Since my last review:

  • Fixed: Keep roster lookup failures from permanently locking standup finalization (scenarios/scrum-master/src/handlers/standup.ts)
  • Fixed: Do not route mock timer standups through the live proactive adapter (scenarios/scrum-master/src/handlers/standup.ts)
  • Fixed: Stop the generic review keyword from shadowing design review (scenarios/scrum-master/src/scripts/seed-helper-roster.ts)
  • Fixed: Distinguish epic parents from subtask parents (scenarios/scrum-master/src/services/jira.ts)
  • Fixed: Coordinate cutoff finalization with in-flight submissions (scenarios/scrum-master/src/handlers/standup.ts)
  • Still open: Do not interpret negated completion statements as Done (scenarios/scrum-master/src/handlers/reconcile.ts). The negation guard in scenarios/scrum-master/src/handlers/reconcile.ts:88 still omits "aren't" and "weren't". 'We aren't done yet' reaches the Done classifier and can still automatically advance an In

Comment thread scenarios/scrum-master/src/agent.ts Resolved
Isolate inbound email drafting from tools, block timer redirects, redact token diagnostics, preserve blocker follow-up after completion write failures, and resolve Jira subtask types by ID. Add regression tests and build timer dependencies in CI.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

The handler split and offline path are a solid shape for this sample, and the latest email and timer changes move those paths in the right direction. I would not merge this head until the published install path and the operator contracts match the runtime.

Three minor comments inline.

Since my last review:

  • Fixed: Inbound email is executed by an agent that still has Mail, Calendar, and Jira tools (scenarios/scrum-master/src/agent.ts)
  • Fixed: Function timers can forward the internal trigger token on a redirect (scenarios/scrum-master/azure-functions/src/index.ts)
  • Fixed: Remove tenant and agent identifiers from token-cache diagnostics (scenarios/scrum-master/src/token-cache.ts)
  • Fixed: Keep a failed completion write from skipping blocker follow-up (scenarios/scrum-master/src/handlers/standup.ts)
  • Fixed: Resolve the project's subtask type instead of hard-coding its name (scenarios/scrum-master/src/scripts/seed-jira-sample.ts)
  • Still open: Do not interpret negated completion statements as Done (scenarios/scrum-master/src/handlers/reconcile.ts). scenarios/scrum-master/src/handlers/reconcile.ts:88 still omits aren't and weren't. 'We aren't done yet' matches the Done rule and can pass the In Review-to-Done automatic transition check at :144. |

Comment thread scenarios/scrum-master/docs/design.md Resolved
Validate parent projects only for subtasks, retain cutoff timers until summary delivery succeeds, and clarify the separate delegated Graph identities. Cover foreign-project epics and automatic deadline retry with regression tests.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Please fix the following three P1 authorization issues before merging. This review is deliberately limited to these three high-priority findings.

Validate open sessions and responder assignments before standup writes; authorize blocker and meeting actions with single-use server-side slot proposals; restrict reporting destination configuration to SMs in the deployment allowed team. Document the fail-closed configuration and add authorization regression coverage.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Keep the emitted dismissal payload aligned with server-side blocker authorization and test both escalation actions.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

The handler/service separation and deterministic ceremony logic make this complex scenario reasonably easy to follow. The implementation needs more consistent enforcement of runtime contracts and failure recovery before it is ready to merge.

Three things to address before this merges; details inline.

Since my last review:

  • Fixed: Do not drop allowed stories because their epic is in another project (scenarios/scrum-master/src/services/jira.ts)
  • Fixed: Auth model still says every Graph call uses the device-code cache (scenarios/scrum-master/docs/design.md)
  • Still open: Do not interpret negated completion statements as Done (scenarios/scrum-master/src/handlers/reconcile.ts). The negation guard in scenarios/scrum-master/src/handlers/reconcile.ts:88 still omits aren't and weren't. An In Review issue updated with We aren't done yet is classified as Done and remains eli
  • Still open: Restore the cutoff timer after an early finalization failure (scenarios/scrum-master/src/services/session-store.ts). Partially fixed: services/session-store.ts:81-84 now preserves the future timer, but a deadline-straddling failure still loses automatic recovery. In handlers/standup.ts:257-265 the one-shot cutoff ca

Comment thread scenarios/scrum-master/.env.template Resolved
Compare the allowed team GUID with aadGroupId while retaining connector routing IDs. Serialize responder submissions, enforce unique durable ResponseKeys with a safe existing-list migration, and acknowledge replays without repeating side effects. Also handle plural negation and retain bounded automatic summary recovery across cutoff failures.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

The handler boundaries and deterministic ceremony flow are a readable, workable shape for this sample. I would not merge this head as it stands.

Three minor comments inline.

Since my last review:

  • Fixed: Compare the allowed team GUID with the team's AAD group ID (scenarios/scrum-master/src/handlers/config.ts)
  • Fixed: Deduplicate standup submissions before repeating durable writes and comments (scenarios/scrum-master/src/handlers/standup.ts)
  • Fixed: SMA_ALLOWED_TEAM_ID is documented as a team GUID, but the gate compares channelData.team.id (scenarios/scrum-master/.env.template)
  • Still open: Do not interpret negated completion statements as Done (scenarios/scrum-master/src/handlers/reconcile.ts). The original examples and aren't/weren't contractions are guarded, but scenarios/scrum-master/src/handlers/reconcile.ts:88 still omits couldn't. 'I couldn't get it done' matches only the Done rule at
  • Still open: Restore the cutoff timer after an early finalization failure (scenarios/scrum-master/src/services/session-store.ts). scenarios/scrum-master/src/services/session-store.ts:86-89 no longer cancels the cutoff when claiming finalization. handlers/standup.ts:297-318 reschedules when a finalizer is in flight and provides b

Copilot AI added 4 commits November 9, 2026 09:28
…unding

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@keshavk-msft

Copy link
Copy Markdown
Author

Addressed the November 6 review in 05201a4 and b6e7cce:

  • Failed blocker lookups are no longer treated as no blockers. Pending chase can be retried independently of the already-delivered summary, with successful notification progress retained in process.
  • Sprint report highlights/improvements quote actual completed Jira summaries; keyword-based metrics count related tasks rather than claiming compliance, releases or test executions.
  • Standup submits acknowledge recording before deferring Graph work and send submitted cards only after recording succeeds. Documentation no longer claims universal sub-200 ms acknowledgements.
  • Straight/curly couldn't negations now prevent Done inference.
  • Existing early-finalization cutoff recovery remains intact; added a regression for a roster failure spanning cutoff, alongside future-cutoff, in-flight-finalizer and bounded retry/exhaustion tests.

Validation: TypeScript build passed; full 107-test suite passed for the submission/chase/cutoff fixes. After the metric-label follow-up, the build and all 21 focused report/core tests passed. The three inline threads have been replied to and resolved.

Mergeability is still blocked on GitHub: the upstream-main merge and CI-orchestrator conflict resolution are prepared locally, preserving both Scrum Master and Chief of Staff jobs and all 13 aggregate CI dependencies. GitHub rejected that workflow-changing push because the active OAuth token lacks workflow scope. Only code/docs/test commits were pushed; the prepared merge requires a workflow-authorized push. No fresh PR checks are currently reported while the remote branch remains conflicting.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

The ceremony handlers are clearly separated, and the mock path is a reasonable way to exercise them offline. The failure handling is careful in places, but the package is not yet consistent enough end to end to merge.

Two minor comments inline.

Since my last review:

  • Fixed: Restore the cutoff timer after an early finalization failure (scenarios/scrum-master/src/services/session-store.ts)
  • Fixed: Do not report a failed blocker lookup as an empty chase (scenarios/scrum-master/src/handlers/chase.ts)
  • Fixed: Do not turn task keywords into compliance or deployment claims (scenarios/scrum-master/src/handlers/report.ts)
  • Still open: Do not interpret negated completion statements as Done (scenarios/scrum-master/src/handlers/reconcile.ts). The added contraction guards help, but 'Nothing is done yet' still bypasses the word-boundary negation regex in scenarios/scrum-master/src/handlers/reconcile.ts:88 and produces the sole Done match at
  • Still open: Standup submit still does Graph work before the first ack (scenarios/scrum-master/src/handlers/standup.ts). The submit handler now acknowledges before deferred response persistence at scenarios/scrum-master/src/handlers/standup.ts:426. However, agent.ts:98 awaits upsertConversationReference before dispatchi

Fix empty/error calendar lookups, document Functions Node minimum, and guard negative completion updates. Validate agent entry acknowledgement with blocked token and roster calls.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@keshavk-msft

keshav Keshari (keshavk-msft) commented Nov 10, 2026 •

Copy link
Copy Markdown
Author

Krishnadheeraj (@DheerajPannala) Rick Brighenti (@rbrighenti) — the latest review feedback is addressed in 1a48d1e. Please re-review and, if the changes look good and required checks pass, approve and merge this PR.

Changes:

  • Preserve empty calendar availability; remove synthetic bookable fallback times. Lookup/registration/malformed-output failures now propagate and produce an explicit retry notice, not fabricated slots.
  • Functions docs now require Node.js 20+ and recommend/select Node.js 22 to match CI.
  • Guard negative completion statements including “Nothing is done yet”, “None … completed”, “Nobody … finished”, and “Neither … done”.
  • Fix the remaining standup entry-path delay: token warmup and conversation-reference Graph refresh are deferred for standup submits. Baggage wrapping and SDK authentication remain in place. Regression tests exercise the real agent dispatch with token/reference calls held pending and prove the recording acknowledgement returns independently.

Validation: agent TypeScript build passed, Functions TypeScript build passed, and 111/111 regression tests passed. Both new inline comments have been replied to and resolved. Your review summary's two still-open concerns are also covered above.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

The scenario is organized around clear handlers, and the recent changes fit that structure. It is not yet consistent enough with its own contracts to merge.

Two minor comments inline.

Since my last review:

  • Fixed: Standup submit still does Graph work before the first ack (scenarios/scrum-master/src/handlers/standup.ts)
  • Fixed: Preserve an empty availability result instead of inventing bookable slots (scenarios/scrum-master/src/services/calendar.ts)
  • Fixed: Raise the documented Functions Node.js minimum (scenarios/scrum-master/azure-functions/README.md)
  • Still open: Do not interpret negated completion statements as Done (scenarios/scrum-master/src/handlers/reconcile.ts). The newly listed negations are guarded, but 'Unable to get this done' with hasBlocker=false still matches only the Done rule: scenarios/scrum-master/src/handlers/reconcile.ts:61,88-92. For an In Revie

Comment thread scenarios/scrum-master/README.md Resolved
Reject elapsed meeting slots through booking, require live Jira board configuration, and restrict completion inference to explicit assertions using fresh Jira state. Repair mixed-hierarchy RAG reporting, sprint-specific blocker metrics, cutoff scheduling and WARN thresholds with regression coverage.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@keshavk-msft

Copy link
Copy Markdown
Author

Krishnadheeraj (@DheerajPannala) Rick Brighenti (@rbrighenti) — pushed b7c76c1 with both inline fixes and a broader sample-contract pass to reduce the repeated review churn. Please re-review when the new checks complete.

Latest review:

  • Elapsed meeting slots are rejected at submission and through booking's asynchronous boundaries; unused claims are released and the SM is asked for fresh availability.
  • Live JIRA_BOARD_ID is required and validated as a positive safe integer; mock defaults are preserved.
  • Addressed the remaining negated-completion concern at the root rather than adding one more negative word. Done inference now requires a finite, whole-statement assertion (e.g. Done, I'm done, I have completed it). Arbitrary prose, questions, conditional/partial completion and Unable to get this done leave Jira unchanged. This intentionally favors missed automation over an incorrect completion transition. The safe-step decision also refreshes Jira state rather than trusting the standup-start snapshot.

Additional reproduced and fixed issues from the broader pass:

  • Mixed Story/Task/Sub-task T-2 reports omitted standalone overdue work and inflated Story counts.
  • Sprint-close reports counted blocker history from unrelated sprints.
  • Valid multi-day cutoffs silently had no timer; positive supported delays now schedule, while invalid explicit settings fail validation.
  • WARN thresholds now validate finite fractions in [0,1], rather than silently accepting values such as 40.

Validation: 124/124 tests passed, agent and Functions TypeScript builds passed, source headers/legacy-reference checks and patch whitespace checks passed. Added regression coverage for timing boundaries, inference polarity/fresh state, configuration limits and reporting scope. Directly related documentation is updated; both new inline threads are replied to and resolved.

Scope was the Scrum Master sample and its core ceremony/service contracts, not an assurance that every repository path is defect-free. No live SharePoint migration or calendar invitation was performed, and the normal dirty checkout/recovery stash remain untouched. Existing documented process-local restart/scale-out limits still apply.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

The ceremony handlers are a clear deterministic shape, and the latest contract hardening is careful. I would not merge this head until the published runtime and the code are the same system.

Six minor comments inline.

Since my last review:

  • Fixed: Do not interpret negated completion statements as Done (scenarios/scrum-master/src/handlers/reconcile.ts)
  • Fixed: Reject meeting slots that have already started (scenarios/scrum-master/src/handlers/chase.ts)
  • Fixed: Config table says JIRA_BOARD_ID has no default, but live mode silently falls back to board 1 (scenarios/scrum-master/README.md)

Comment thread scenarios/scrum-master/src/index.ts Resolved
Comment thread scenarios/scrum-master/README.md Resolved
Validate configuration before listening, guard moved Jira aliases on writes, refresh no-op summary status, preserve blank blocker flags and allow explicit prior-day retained-session recovery. Add bootstrap and deferred-write regression tests.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@keshavk-msft

Copy link
Copy Markdown
Author

Krishnadheeraj (@DheerajPannala) Rick Brighenti (@rbrighenti) — addressed all six comments from review 5843503634 in e88d769 and replied to/resolved each thread.

  • Jira writes revalidate the resolved project and use the canonical allowed key, including deferred standup comments and approved transitions.
  • Fresh Jira status is retained in the summary even when reconciliation needs no transition.
  • /standup retry <sprintId>#<yyyy-mm-dd> recovers retained previous-day/sprint sessions without creating today's run; logs and docs give the exact command.
  • Blank optional blocker descriptions remain visible and preserve the SM mention.
  • Schedule bounds and required live Jira settings now fail fast before listening; startup docs and actual boot behavior agree. Tests use the real validation boundary, not just getter-unit-test proxies.

Validation: 146/146 regression tests passed, agent and Functions TypeScript builds passed, and patch/source checks passed. Added integration coverage for side-effect write boundaries, bootstrap behavior, rendered summary text and retained-run command recovery. No live SharePoint migration/calendar operation was performed, and the normal dirty checkout/recovery stash remain unchanged.

Please re-review when fresh CI completes. This validates the addressed contracts; it is not a claim that every possible deployment/runtime path is defect-free.

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.

5 participants