Skip to content

extensions: add Azure DevOps Team load canvas 🤖🤖🤖 - #6323

Open
anarchitect wants to merge 1 commit into
github:mainfrom
anarchitect:feature/ado-personal-team-load
Open

anarchitect wants to merge 1 commit into
github:mainfrom
anarchitect:feature/ado-personal-team-load

Conversation

@anarchitect

Copy link
Copy Markdown

What this adds

A reusable Copilot canvas for Azure DevOps Services team open work. It reads Azure Boards ownership and Azure Repos pull requests through supported REST APIs using the existing Azure CLI identity.

  1. Organisation, project, repository and people pickers, with unique identity GUIDs rather than display-name matching.
  2. Owned open work items, authored active PRs and outstanding individual reviews, counted once per person and record.
  3. Expandable records, reviewer votes, unassigned work, a configurable count threshold, manual refresh and visible-page auto refresh.
  4. Private profiles that survive workspace changes and provider restarts, with revision-checked atomic saves.
  5. Explicit authentication, access, partial-coverage and stale-data messages.

The shared UI and SDK actions use the same dispatcher. Tokens remain server-side. The canvas makes no remote writes and does not estimate hours or Teams availability.

Why it is different

The interaction pattern is inspired by the pinned TinyClips Team load investigation. This contribution implements an Azure DevOps adapter and identity/state model; it has no TinyClips workspace assumption or preconfigured organisation, project or people.

Project-specific work item type/state categories determine which work is open. Work assigned to untracked people remains owned. Active drafts count, completed review votes and group requests do not count as outstanding individual reviews, and PR roles are deduplicated.

WIQL reads omit $top because permission filtering can leave a short or empty truncated page before later readable records. Queries exceeding the 20,000-result limit split disjoint ID ranges, and detail batches use ASOF snapshots. Coverage is limited to the selected API-visible resources; hidden resources cannot be quantified.

Validation

  1. npm run plugin:validate passed for all 111 plugins, including this one.
  2. npm run build passed and generated the marketplace entry and plugin README row.
  3. bash eng/fix-line-endings.sh completed.
  4. node --test extensions/ado-personal-team-load/tests.mjs passed all 21 tests. Module syntax checks and git diff --cached --check passed.
  5. The installed personal extension was verified in a Copilot host through capabilities, open_canvas, SDK actions, provider restart and reopening the same instance/profile.
  6. Actual isolated Google Chrome checks passed for saved scope before catalog discovery, threshold save without losing selections, manual refresh, visible auto refresh, polling focus, reload and responsive widths of 320, 768, 1024 and 1440 pixels.
  7. Independent authorised source reads matched 245 open work items, 86 unassigned items and two displayed identity totals of 2 and 1. No private organisation, identity or work content is included in this PR.
  8. The 1280 by 720 preview is a genuine unconfigured canvas. Staged-file allowlist and private-content checks passed.

The live verification scope had no active PRs. Nonempty PR roles, reviewer votes and PR paging are covered by isolated tests, while the live empty PR API reads were authorised.

Boundaries

This first version is read-only and supports Azure DevOps Services, not Azure DevOps Server. It intentionally omits remote editing, momentum charts, agent handoff and execution markers. PR/reviewer endpoints do not provide a shared transaction snapshot.

The extension adds no npm dependencies. The repository dependency restore reported existing audit advisories; this PR does not change package manifests or its lockfile.

Source, installation commands, API references and the independent verification command are documented in extensions/ado-personal-team-load/README.md. The matching curated manifest is in plugins/ado-personal-team-load/plugin.json.

AI-assisted implementation and validation, submitted at the user's request.

Show API-visible Azure Boards ownership and Azure Repos review work through shared canvas actions. Keep profiles independent of workspaces, use process state categories and expose coverage failures.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@anarchitect
anarchitect requested review from a team as code owners November 9, 2026 10:54
Copilot AI auto review requested due to automatic review settings November 9, 2026 10:54
@github-actions github-actions Bot added canvas-extension PR touches canvas extensions new-submission PR adds at least one new contribution plugin PR touches plugins labels Nov 9, 2026
@github-actions

github-actions Bot commented Nov 9, 2026

Copy link
Copy Markdown
Contributor

🔒 PR Risk Scan Results

Scanned 15 changed file(s).

Severity Count
🔴 High 0
🟠 Medium 0
ℹ️ Info 0

✅ No matching risk patterns were detected in changed files.

Skipped non-text or missing files
  • extensions/ado-personal-team-load/assets/preview.png

This is an automated soft-gate report. Findings indicate review targets and do not block merge by themselves.

@github-actions

github-actions Bot commented Nov 9, 2026 •

Copy link
Copy Markdown
Contributor

🚦 Submission status: 👀 Ready for review

Risk tier: merge-risk:high — Privileged execution, automation, or review-policy change
Required to merge: passing submission-gate checks plus 1 approval from reviewers with write access, including a maintainer with admin or maintain permission.

Why this tier
  • Spawns processes or evaluates code in extensions/ado-personal-team-load/adapter.mjs
  • Spawns processes or evaluates code in extensions/ado-personal-team-load/tests.mjs

Automated checks

Check Status Details
Line endings ✅ Passed Passed · logs
Spelling ✅ Passed Passed · logs
Generated README consistency ✅ Passed Passed · logs
Plugin and extension validation ✅ Passed Passed · logs
Canvas extension validation ✅ Passed Passed · logs
Plugin structure ✅ Passed Passed · logs
Risk scan ✅ Passed Passed · logs
Contributor reputation ✅ Passed Passed · logs
Duplicate resource scan ✅ Passed Passed · logs
PR quality signal ⏭️ Skipped Skipped by its workflow · logs
Canvas/plugin smoke test ✅ Passed Passed · logs

Review

  • Approvals: 0/1
  • Assigned reviewer: not assigned yet — comment /request-review to ask for one
  • Review target date: not set
  • Still needed: 1 more approval(s); an approval from a maintainer with admin or maintain permission
  • The core-maintainers pool is not staffed yet; an approver with admin or maintain permission is required instead.

Commands

Command Who What it does
/rerun-checks PR author, maintainers Re-runs failed or incomplete checks and re-evaluates this gate
/request-review PR author, maintainers Asks the review rotation to assign a reviewer (adds needs-reviewer)

Updated for 617cadb · gate run · This comment is maintained automatically — see submission gate docs.

@github-actions

github-actions Bot commented Nov 9, 2026

Copy link
Copy Markdown
Contributor

🟡 Contributor Reputation Check: MEDIUM risk

Check Risk
Profile MEDIUM
Credential audit NONE

Maintainers: please review this contributor before merging.
See the workflow run for full details.
Automated check powered by AGT.

@github-actions

github-actions Bot commented Nov 9, 2026

Copy link
Copy Markdown
Contributor

🧩 Canvas smoke test

✅ Passed · 0 error(s), 1 warning(s)

Check Result
Syntax, imports, file safety ✅
Preview image (≥ 400×160 PNG) ✅
Plugin manifests ✅
Materialize ✅
Install (Copilot CLI) ✅

Plugin ado-personal-team-load v1.0.0

Field Value
Description Read-only Azure DevOps team open work canvas with scope pickers, ownership, PR reviews and explicit coverage.
Author anarchitect — https://github.com/anarchitect
License MIT
Keywords azure-devops, azure-boards, azure-repos, team-load, work-item-ownership, pull-request-reviews, canvas
Extensions ado-personal-team-load
Materialize ✅
Install ✅
Changed plugin files
  • plugins/ado-personal-team-load/README.md
  • plugins/ado-personal-team-load/plugin.json

Extension ado-personal-team-load

ado-personal-team-load preview

Field Value
Registered by ado-personal-team-load
Package —
Preview 1280×720, 42.7 KB
Modules 9 (6 reachable from extension.mjs)
Files 13

Permissions and capabilities (static analysis of modules reachable from extension.mjs)

  • Spawns processes (node:child_process)
  • File system access (node:fs)
  • Network sockets / local server (node:http, node:net, ...)
  • Host information (node:os)
  • Reads environment variables (process.env)

Warnings

  • tests.mjs: import "node:test" is not a Node.js builtin, host-provided package, or declared dependency (module is not reachable from extension.mjs)
Changed extension files
  • extensions/ado-personal-team-load/README.md
  • extensions/ado-personal-team-load/adapter.mjs
  • extensions/ado-personal-team-load/assets/app.mjs
  • extensions/ado-personal-team-load/assets/index.html
  • extensions/ado-personal-team-load/assets/preview.png
  • extensions/ado-personal-team-load/assets/styles.css
  • extensions/ado-personal-team-load/extension.mjs
  • extensions/ado-personal-team-load/hub.mjs
  • extensions/ado-personal-team-load/model.mjs
  • extensions/ado-personal-team-load/schemas.mjs
  • extensions/ado-personal-team-load/server.mjs
  • extensions/ado-personal-team-load/tests.mjs
  • extensions/ado-personal-team-load/verify-live.mjs

Static checks compile modules without executing them. Minimum preview size is configurable with CANVAS_PREVIEW_MIN_WIDTH/CANVAS_PREVIEW_MIN_HEIGHT. Workflow run

@github-actions github-actions Bot added needs-review:MEDIUM Contributor reputation check flagged MEDIUM risk ready-for-review Submission passed intake validation and is ready for maintainer review and removed awaiting-automation labels Nov 9, 2026

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.

🟡 Changes recommended

Unresolved critical issues expose private work data to other local accounts and can silently clear saved scope selections or freeze workload counts after partial refresh failures.

14 open issues
What changed in this PR

Adds a reusable, read-only Azure DevOps canvas to the extension catalog for inspecting work ownership and PR review workload across selected projects.

Changes:

  • Adds Azure CLI authentication, resource discovery and identity-based work counting.
  • Provides scope pickers, expandable records, refresh controls, coverage reporting and persistent private profiles.
  • Adds tests, live verification tooling, documentation and plugin registration.
File Description
plugins/​ado-personal-team-load/​README.md Introduces the plugin and links its usage guide.
plugins/​ado-personal-team-load/​plugin.json Defines plugin metadata and extension composition.
extensions/​ado-personal-team-load/​verify-live.mjs Compares displayed counts with independent API reads.
extensions/​ado-personal-team-load/​tests.mjs Covers counting, paging, persistence, actions and UI behavior.
extensions/​ado-personal-team-load/​server.mjs Serves canvas assets and routes local actions.
extensions/​ado-personal-team-load/​schemas.mjs Defines shared action schemas and validation.
extensions/​ado-personal-team-load/​README.md Documents installation, authentication, counting and verification.
extensions/​ado-personal-team-load/​model.mjs Computes identity-based totals and threshold labels.
extensions/​ado-personal-team-load/​hub.mjs Manages profiles, discovery, refreshes and coverage state.
extensions/​ado-personal-team-load/​extension.mjs Registers SDK actions and canvas lifecycle handlers.
extensions/​ado-personal-team-load/​assets/​styles.css Adds responsive layouts, themes and focus styling.
extensions/​ado-personal-team-load/​assets/​index.html Defines scope controls, workload panels and coverage details.
extensions/​ado-personal-team-load/​assets/​app.mjs Implements selections, rendering, actions and refresh polling.
extensions/​ado-personal-team-load/​adapter.mjs Handles CLI tokens, Azure DevOps APIs, state mappings and paging.
docs/​README.plugins.md Adds the generated plugin catalog entry.
.github/​plugin/​marketplace.json Registers the plugin in the marketplace.

Review effort: Max (auto)

Comment on lines +142 to +143
$("organisation").addEventListener("change", () => { $("organisation-url").value = ""; chosenProjects.clear(); chosenRepositories.clear(); chosenPeople.clear(); });
$("organisation-url").addEventListener("change", () => { chosenProjects.clear(); chosenRepositories.clear(); chosenPeople.clear(); });
if (record.revision !== revision) throw new AdoError("conflict", "Scope changed during refresh. Refresh the new scope.");
refreshErrors = errors;
// Keep an earlier complete snapshot on failure, with an explicit stale marker.
if (!errors.length || !snapshot) {
Comment on lines +17 to +19
config: object({ ...scopeProperties, repositories: ids(30), people: ids(100),
threshold: { type: "integer", minimum: 1, maximum: 1000 },
refreshSeconds: { type: "integer", minimum: 60, maximum: 86400 } }),
Comment on lines +19 to +22
if (req.method === "GET" && (path === "/" || assets.has(path))) {
const name = path === "/" ? "/index.html" : path;
res.setHeader("Content-Type", name.endsWith(".html") ? "text/html; charset=utf-8" : name.endsWith(".css") ? "text/css" : "text/javascript");
res.end(assets.get(name).replace("{{CANVAS_KEY}}", key)); return;
Comment on lines +66 to +67
throw new AdoError(response.status === 401 ? "authentication" : response.status === 403 ? "access" : "api",
`Azure DevOps returned HTTP ${response.status} for ${parsed.pathname}. No data from this request is counted.`);
Comment on lines +68 to +71
for (const p of identities) if (p.id && p.descriptor && chosenPeople.has(p.id)) { chosenPeople.delete(p.id); chosenPeople.add(p.descriptor); }
const matches = identities.filter(p => `${p.displayName} ${p.uniqueName} ${p.id || p.descriptor}`.toLowerCase().includes(search));
choices($("people"), matches.slice(0, 100),
chosenPeople, p => p.descriptor || p.id, p => p.displayName || p.id);
return known ? { ...row, displayName: known.displayName, uniqueName: known.uniqueName } : row;
});
const stale = Boolean(snapshot && (Date.now() - Date.parse(snapshot.at) > c.refreshSeconds * 1000 || snapshot.retained));
return { profile, config: c, revision: record.revision, catalog, ...result, people,
const observed = org === c.organisation ? (snapshot?.result.identities || []) : [];
let people = observed;
try {
people = await adapter.people(org, tenant);
Comment on lines +142 to +143
catalog.repositories = knownRepos;
for (const p of result.identities) if (!catalog.people.some(x => x.id === p.id || (x.descriptor && x.descriptor === p.descriptor))) catalog.people.push(p);
identities.set(id, { id, displayName: p.displayName || id, uniqueName: p.uniqueName || "", descriptor: p.descriptor || "" });
}
for (const w of workItems) addIdentity(w.owner);
for (const p of prs) { addIdentity(p.author); p.reviewers.forEach(addIdentity); }

This branch has not been deployed

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

Labels

canvas-extension PR touches canvas extensions merge-risk:high needs-review:MEDIUM Contributor reputation check flagged MEDIUM risk new-submission PR adds at least one new contribution plugin PR touches plugins ready-for-review Submission passed intake validation and is ready for maintainer review

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants