Add Spec Kit assess canvas dashboard - #4
Conversation
Add the standard community-health files required by the open-source release checklist (github/open-source-releases#706), aligned with the sibling github/spec-kit repository: - LICENSE (MIT, Copyright GitHub, Inc.) - CODE_OF_CONDUCT.md (Contributor Covenant 1.4) - SECURITY.md - SUPPORT.md - CONTRIBUTING.md (tailored to this skills plugin) - .github/CODEOWNERS (@mnriem) - README.md: add Background, License, Maintainers, Support, and Acknowledgement sections Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Assisted-by: GitHub Copilot (model: Claude Opus 4.8, autonomous) Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 38c901bb-913e-4055-8ed4-fdcda14dc858
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 38c901bb-913e-4055-8ed4-fdcda14dc858
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 38c901bb-913e-4055-8ed4-fdcda14dc858
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 38c901bb-913e-4055-8ed4-fdcda14dc858
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 38c901bb-913e-4055-8ed4-fdcda14dc858
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 38c901bb-913e-4055-8ed4-fdcda14dc858
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 38c901bb-913e-4055-8ed4-fdcda14dc858
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 38c901bb-913e-4055-8ed4-fdcda14dc858
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 38c901bb-913e-4055-8ed4-fdcda14dc858
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 38c901bb-913e-4055-8ed4-fdcda14dc858
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 38c901bb-913e-4055-8ed4-fdcda14dc858
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 38c901bb-913e-4055-8ed4-fdcda14dc858
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 38c901bb-913e-4055-8ed4-fdcda14dc858
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 38c901bb-913e-4055-8ed4-fdcda14dc858
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 38c901bb-913e-4055-8ed4-fdcda14dc858
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 38c901bb-913e-4055-8ed4-fdcda14dc858
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 38c901bb-913e-4055-8ed4-fdcda14dc858
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 38c901bb-913e-4055-8ed4-fdcda14dc858
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 38c901bb-913e-4055-8ed4-fdcda14dc858
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 38c901bb-913e-4055-8ed4-fdcda14dc858
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 38c901bb-913e-4055-8ed4-fdcda14dc858
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 38c901bb-913e-4055-8ed4-fdcda14dc858
There was a problem hiding this comment.
🟡 Not ready to approve
Command dispatch, symlink safety, stale-state handling, and contributor guidance have unresolved correctness issues.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
This review doesn't count toward merge requirements. Sign up for the private preview to control whether Copilot approvals count.
Pull request overview
Adds a Copilot canvas dashboard for the Spec Kit assessment pipeline, alongside generated project setup, assessment fixtures, and community documentation.
Changes:
- Adds assessment scanning, previews, stage execution, reruns, clarifications, and live updates.
- Installs the assess pipeline and generated Copilot skills.
- Adds repository governance and support documentation.
File summaries
| File | Description |
|---|---|
SUPPORT.md |
Adds support guidance. |
SECURITY.md |
Adds vulnerability reporting policy. |
README.md |
Expands project background and policies. |
LICENSE |
Adds MIT license. |
CONTRIBUTING.md |
Adds contribution workflow. |
CODE_OF_CONDUCT.md |
Adds contributor conduct policy. |
.specify/workflows/workflow-registry.json |
Registers the SDD workflow. |
.specify/workflows/speckit/workflow.yml |
Defines the full SDD cycle. |
.specify/templates/tasks-template.md |
Adds the task-generation template. |
.specify/templates/spec-template.md |
Adds the feature-specification template. |
.specify/templates/plan-template.md |
Adds the implementation-plan template. |
.specify/templates/constitution-template.md |
Adds the constitution template. |
.specify/templates/checklist-template.md |
Adds the checklist template. |
.specify/scripts/bash/setup-tasks.sh |
Prepares task-generation inputs. |
.specify/scripts/bash/setup-plan.sh |
Prepares planning inputs. |
.specify/scripts/bash/check-prerequisites.sh |
Validates workflow prerequisites. |
.specify/memory/constitution.md |
Adds the initial constitution placeholder. |
.specify/memory/.constitution-template.json |
Records the constitution template hash. |
.specify/integrations/speckit.manifest.json |
Records installed Spec Kit files. |
.specify/integrations/copilot.manifest.json |
Records generated Copilot skills. |
.specify/integration.json |
Configures Copilot skills mode. |
.specify/init-options.json |
Records initialization options. |
.specify/extensions/assess/README.md |
Documents the assess pipeline. |
.specify/extensions/assess/extension.yml |
Declares assess commands. |
.specify/extensions/assess/commands/speckit.assess.shape.md |
Defines concept shaping. |
.specify/extensions/assess/commands/speckit.assess.research.md |
Defines evidence research. |
.specify/extensions/assess/commands/speckit.assess.intake.md |
Defines idea intake. |
.specify/extensions/assess/commands/speckit.assess.define.md |
Defines problem framing. |
.specify/extensions/assess/commands/speckit.assess.decide.md |
Defines assessment decisions. |
.specify/extensions/.registry |
Registers the assess extension. |
.specify/extensions/.cache/catalog.json |
Caches the extension catalog. |
.specify/extensions/.cache/catalog-metadata.json |
Records catalog cache metadata. |
.specify/extensions/.cache/catalog-ebf165086500aab1-metadata.json |
Records community catalog metadata. |
.specify/extensions.yml |
Enables assess extension settings. |
.specify/assessments/spec-kit-sdd-canvas/research.md |
Captures canvas research. |
.specify/assessments/spec-kit-sdd-canvas/problem.md |
Defines the canvas problem. |
.specify/assessments/spec-kit-sdd-canvas/intake.md |
Captures the original idea. |
.specify/assessments/spec-kit-sdd-canvas/decision.md |
Records the assessment verdict. |
.specify/assessments/spec-kit-sdd-canvas/concept.md |
Compares canvas concepts. |
.github/skills/speckit-taskstoissues/SKILL.md |
Adds task-to-issue guidance. |
.github/skills/speckit-tasks/SKILL.md |
Adds task-generation guidance. |
.github/skills/speckit-plan/SKILL.md |
Adds planning guidance. |
.github/skills/speckit-implement/SKILL.md |
Adds implementation guidance. |
.github/skills/speckit-converge/SKILL.md |
Adds convergence analysis. |
.github/skills/speckit-constitution/SKILL.md |
Adds constitution guidance. |
.github/skills/speckit-clarify/SKILL.md |
Adds clarification guidance. |
.github/skills/speckit-assess-shape/SKILL.md |
Exposes assessment shaping. |
.github/skills/speckit-assess-research/SKILL.md |
Exposes assessment research. |
.github/skills/speckit-assess-intake/SKILL.md |
Exposes assessment intake. |
.github/skills/speckit-assess-define/SKILL.md |
Exposes problem definition. |
.github/skills/speckit-assess-decide/SKILL.md |
Exposes assessment decisions. |
.github/skills/speckit-analyze/SKILL.md |
Adds artifact consistency analysis. |
.github/extensions/assess-canvas/README.md |
Documents the canvas dashboard. |
.github/extensions/assess-canvas/extension.mjs |
Implements canvas actions and HTTP/SSE. |
.github/extensions/assess-canvas/copilot-extension.json |
Declares the canvas extension. |
.github/extensions/assess-canvas/assess.js |
Scans and reads assessment artifacts. |
.github/CODEOWNERS |
Assigns the repository owner. |
Review details
Suppressed comments (5)
.github/extensions/assess-canvas/assess.js:208
- This containment check is lexical, but
statSync/readFileSyncfollow symlinks. A crafted checkout can make an allowed artifact such asintake.mda symlink to an arbitrary same-user file, which/api/artifactwill then expose. Reject symlinks in.specify,assessments, the slug directory, and the artifact withlstat, then verify the real path remains under the real assessments directory before reading.
const assessDir = resolve(join(projectRoot, ".specify", "assessments"));
const filePath = resolve(join(assessDir, cleanSlug, stage.file));
const expected = join(assessDir, cleanSlug, stage.file);
if (filePath !== expected) return { ok: false, error: "path escape" };
if (!filePath.startsWith(assessDir + "/")) return { ok: false, error: "path escape" };
if (!existsSync(filePath)) return { ok: false, error: "not found" };
const content = readIfFile(filePath);
if (content === null) return { ok: false, error: "not a file" };
.github/extensions/assess-canvas/assess.js:147
- The contiguous-chain rule marks every later artifact stale whenever an earlier optional stage is absent. The assess contract explicitly permits
researchwithout intake and makesdefinethe minimum viable stage, so a valid define-only assessment is shown as stale/zero progress and directed back to intake. Compute freshness from each stage's actual required prerequisites and newer existing inputs instead of requiring every preceding artifact.
const stale = exists && (!chainCurrent || (latestMtime > 0 && mtime < latestMtime));
const done = exists && !stale;
.github/extensions/assess-canvas/assess.js:250
- The SSE signature omits prerequisite state. Installing Spec Kit/assess usually leaves the assessments directory absent, so the signature stays
0and no update is broadcast; the open canvas remains stuck on “Setup required” until reloaded. IncludeinitializedandassessInstalled(orsetupRequired) in the signature.
export function stateSignature(state) {
const parts = [state.exists ? "1" : "0"];
.github/extensions/assess-canvas/assess.js:205
- This hard-coded
/makes all valid artifact paths fail the containment check on Windows, wherepath.resolveuses backslashes. The preceding equality check already verifies the normalized slug plus fixed stage filename; remove the platform-specific prefix check (or usepath.relative).
if (filePath !== expected) return { ok: false, error: "path escape" };
if (!filePath.startsWith(assessDir + "/")) return { ok: false, error: "path escape" };
CONTRIBUTING.md:50
- The plugin version is intentionally independent from the installed
specifyCLI version; initialization records whichever current CLI is used. Requiring lockstep versions and a targeted CLI release would incorrectly pin contributors and undo that compatibility model.
- Files reviewed: 62/63 changed files
- Comments generated: 4
- Review effort level: Balanced
We're testing this review assessment. Please use 👍 or 👎 to tell us if it's correct.
…ss-canvas # Conflicts: # CONTRIBUTING.md
Use generated skill invocations, enforce current stage prerequisites, reject symlinked artifacts, and track prerequisite changes in live updates. Remove generated Spec Kit setup and assessment fixtures from the PR. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 38c901bb-913e-4055-8ed4-fdcda14dc858
There was a problem hiding this comment.
🟡 Not ready to approve
Stale-state propagation, prerequisite enforcement, loopback API security, and accessibility issues remain unresolved.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
This review doesn't count toward merge requirements. Sign up for the private preview to control whether Copilot approvals count.
Review details
Suppressed comments (10)
.github/extensions/assess-canvas/index.html:158
- The stage-guidance textarea has no associated label, so assistive technology cannot reliably identify the field after its placeholder disappears. Give it an explicit accessible name.
<textarea id="stageInstructions" placeholder="Optional guidance for this stage"></textarea>
.github/extensions/assess-canvas/index.html:169
- The required clarification-answer textarea has no associated label; relying only on placeholder text leaves the control without a persistent accessible name. Add an explicit accessible name.
<textarea id="clarifyAnswer" placeholder="Required clarification answer"></textarea>
.github/extensions/assess-canvas/index.html:142
- These two inputs have no associated label; placeholder text is not a persistent accessible name and disappears as soon as users type. Add visible
<label>elements, or at minimum explicit accessible names, for the idea and slug fields.
This issue also appears in the following locations of the same file:
- line 158
- line 169
<textarea id="idea" placeholder="Let users work offline and sync when they reconnect"></textarea>
<div class="row" style="margin-top: 8px;">
<input type="text" id="newslug" placeholder="slug (optional, e.g. offline-mode)" style="max-width: 60%;" />
.github/extensions/assess-canvas/assess.js:162
- Staleness is not propagated transitively. After rerunning
intake,researchbecomes stale; ifdefineis then rerun without refreshing research, its newer mtime makes itdoneeven though the define skill reads the still-staleresearch.md. Downstream stages can consequently be reported current while depending on stale content. Treat an existing stale prior stage as stale input in addition to comparing mtimes.
const newerInput = STAGES.slice(0, index).some((input) => {
const inputState = stages[input.key];
return inputState.exists && inputState.mtime > state.mtime;
});
.github/extensions/assess-canvas/index.html:281
- This uses mere existence rather than currentness, so Shape and Decide are presented as available when
problem.mdis stale. The server then rejects the action, contradicting the dashboard's enabled state. Match the server guard by requiringdefine.done.
if (stage === "shape" || stage === "decide") return Boolean(assessment.stages.define.exists);
.github/extensions/assess-canvas/index.html:252
- Existing artifacts bypass the computed
availableflag entirely. Thus an existing Shape or Decide pill remains clickable even when its current-stage prerequisite is unavailable; it opens a rerun dialog that can only fail at the server. Apply availability to reruns too.
if (st.exists) {
p.title = "Run " + s.command + " again";
p.onclick = () => openStageDialog(s.key, a.slug, true, a.title);
.github/extensions/assess-canvas/extension.mjs:118
- Clarification reruns bypass the setup prerequisite enforced by
/api/runandrun_stage. If the assess extension was removed while artifacts remain, this path still sends an unavailable/skill:speckit-assess-*prompt instead of directing the user through setup. Reject clarification runs while setup is required.
const artifact = readArtifact(PROJECT_ROOT, slug, stage.key);
if (!artifact.ok) return { error: artifact.error };
.github/extensions/assess-canvas/extension.mjs:130
- This direct dispatch also bypasses
buildPrompt's current-problem guard. A clarification opened from a staleconcept.md, or a decision whose revisit stage is Shape, can therefore rerun Shape while Define is stale and use an outdated problem. Validate the resolved target's prerequisite before sending.
const prompt = [
.github/extensions/assess-canvas/index.html:392
- The form is cleared immediately, before the request has succeeded. Any network failure or server rejection (for example, a slug collision requiring overwrite) permanently discards the user's idea and slug. Await a success result from
runand clear these fields only whenj.okis true.
run("speckit-assess-intake", slug || null, idea, null, false);
document.getElementById("idea").value = "";
document.getElementById("newslug").value = "";
.github/extensions/assess-canvas/extension.mjs:280
list_assessmentspromises per-stage progress, but each returned assessment omitsstagesand exposes only an aggregate count/next stage. Agent callers therefore cannot determine which artifacts exist or are stale, despite the README documenting that capability. Include the stage-state map in each item.
assessments: state.assessments.map((a) => ({
slug: a.slug,
title: a.title,
completed: a.completed,
total: a.total,
nextStage: a.nextStage,
verdict: a.verdict,
})),
- Files reviewed: 5/5 changed files
- Comments generated: 2
- Review effort level: Balanced
We're testing this review assessment. Please use 👍 or 👎 to tell us if it's correct.
Protect loopback routes with per-instance capabilities and canonical request checks, reject intermediate symlinks, propagate stale inputs, and align UI and clarification guards with current stage state. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 38c901bb-913e-4055-8ed4-fdcda14dc858
There was a problem hiding this comment.
🟡 Not ready to approve
Setup reliability, clarification races, root detection, and unbounded artifact reads need correction.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
This review doesn't count toward merge requirements. Sign up for the private preview to control whether Copilot approvals count.
Review details
Suppressed comments (4)
.github/extensions/assess-canvas/extension.mjs:134
- A clarification is re-read and selected only by its numeric index. Because the artifact can be regenerated while this full-page preview remains open, that index may now identify a different question, causing the submitted answer to rerun a stage for the wrong clarification. Send the displayed question or a content digest with the request and reject submission unless it still matches the current artifact.
const artifact = readArtifact(PROJECT_ROOT, slug, stage.key);
if (!artifact.ok) return { error: artifact.error };
const clarification = extractClarifications(artifact.content)[index];
if (!clarification) return { error: "clarification no longer exists" };
.github/extensions/assess-canvas/assess.js:98
readIfFilesynchronously loads an unbounded repository file.scanAssessmentscalls this for intake and decision artifacts on every 1.5-second poll, so one oversized artifact can repeatedly block the server or exhaust the extension process's memory. Enforce a file-size limit before reading (and use a bounded prefix for title/verdict scans), with a distinct oversized-file result for previews.
function readIfFile(p) {
try {
const stat = lstatSync(p);
if (stat.isSymbolicLink() || !stat.isFile()) return null;
return readFileSync(p, "utf8");
.github/extensions/assess-canvas/assess.js:54
- This recognizes only a
.gitdirectory, but Git worktrees and submodules use a regular.gitfile. When Copilot is launched from a nested directory in either case and.specifyis absent, root discovery falls back to that nested directory and setup initializes the wrong location. Accept a non-symlink regular.gitfile as a Git-root marker too.
if (gitRoot === null && isRealDir(join(dir, ".git"))) gitRoot = dir;
.github/extensions/assess-canvas/extension.mjs:32
- The setup command omits
--script, so the PTY-backed agent shell can stop at the interactive script-type chooser instead of completing setup. This repository requires every agent-runspecify initto pass that flag (skills/speckit-init/SKILL.md:76-79,91-98); use the cross-platformpyoption here.
"If `.specify/` is missing, run `specify init --here --force --integration copilot --integration-options=\"--skills\"`.",
- Files reviewed: 5/5 changed files
- Comments generated: 0 new
- Review effort level: Balanced
We're testing this review assessment. Please use 👍 or 👎 to tell us if it's correct.
Address review feedback for bounded reads, worktree root detection, setup flags, and clarification races. Declare the canvas as a plugin extension component so marketplace installs include it. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 38c901bb-913e-4055-8ed4-fdcda14dc858
There was a problem hiding this comment.
🟡 Not ready to approve
Extension startup, dispatch reliability, project isolation, and filesystem race issues remain unresolved.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
This review doesn't count toward merge requirements. Sign up for the private preview to control whether Copilot approvals count.
Review details
Suppressed comments (9)
.github/extensions/assess-canvas/extension.mjs:234
- Await
session.send()before returning HTTP 200. The SDK returns a promise, so the current endpoint tells the UI setup was sent even when dispatch rejects and leaves the rejection unhandled.
session.send({ prompt: SETUP_PROMPT });
.github/extensions/assess-canvas/extension.mjs:332
- This action reports success before the asynchronous send is accepted. Await the SDK call so dispatch failures propagate through the action instead of becoming unhandled rejections.
session.send({ prompt: SETUP_PROMPT });
.github/extensions/assess-canvas/extension.mjs:401
- This action returns
{ ok: true }without awaiting the asynchronous send. Await it so a rejected dispatch is surfaced to the caller rather than falsely reported as successful.
session.send({ prompt: built.prompt });
.github/extensions/assess-canvas/extension.mjs:264
- Await
session.send()before returning success. Otherwise a failed stage dispatch still produces{ ok: true }and an unhandled promise rejection.
session.send({ prompt: built.prompt });
.github/extensions/assess-canvas/extension.mjs:158
session.send()is asynchronous, but this helper returns{ ok: true }without waiting for it. A rejected send therefore becomes an unhandled rejection while both callers report success. MakeclarificationRunasync, await the send, and await this helper from the HTTP and canvas-action handlers.
This issue also appears in the following locations of the same file:
- line 234
- line 264
- line 332
- line 401
session.send({ prompt });
return {
.github/extensions/assess-canvas/extension.mjs:63
decideis allowed when an existingconcept.mdis stale. After Define is rerun, this lets the Decide skill read an obsolete concept; moreoverscanAssessments()necessarily marks the newly written decision stale because a previous stage remains stale. Block Decide when a concept exists but Shape is not current, or explicitly ignore the stale concept and align the scanner/UI with that policy.
function stagePrerequisiteError(stageKey, assessment) {
if ((stageKey === "shape" || stageKey === "decide") && !assessment?.stages?.define?.done) {
return `${stageKey} requires a current problem.md; rerun define first`;
}
.github/extensions/assess-canvas/assess.js:148
- Directory presence does not prove the assess skills are usable. A disabled assess installation can leave this directory while its registry entry is disabled, and a project initialized without Copilot skills mode can have the extension files but no
speckit-assess-*skills. In both casessetupRequiredbecomes false and every action dispatches a missing skill. Validate the registry's enabled/registered-skills state and the expected generated skills before declaring readiness.
const assessInstalled = initialized && hasRealDirectoryChain(projectRoot, ".specify", "extensions", "assess");
.github/extensions/assess-canvas/index.html:180
- All validation and dispatch feedback is written into this transient toast, but it is not exposed as a live region. Screen-reader users will not be notified when input is rejected or a stage succeeds/fails. Mark it as a polite status region.
<div class="toast" id="toast"></div>
plugin.json:21
- Adding a distributable extension without changing the plugin version leaves both
plugin.jsonand the two marketplace version fields at0.15.0. Marketplace update flows can therefore treat this build as the already-installed release and never deliver the canvas. Bump all three plugin/marketplace versions together for this release.
"extensions": ".github/extensions/"
- Files reviewed: 8/8 changed files
- Comments generated: 4
- Review effort level: Balanced
We're testing this review assessment. Please use 👍 or 👎 to tell us if it's correct.
Make extension modules portable, isolate project-root discovery, verify no-follow file descriptors, await SDK dispatch, validate assess skill readiness, and publish plugin version 0.15.1. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 38c901bb-913e-4055-8ed4-fdcda14dc858
There was a problem hiding this comment.
🟡 Not ready to approve
Registry truncation and missing overwrite confirmation can cause incorrect setup state and unauthorized reruns.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
This review doesn't count toward merge requirements. Sign up for the private preview to control whether Copilot approvals count.
Review details
Suppressed comments (2)
.github/extensions/assess-canvas/assess.mjs:196
readJsonIfFileparses only the first 64 KiB, so any valid extension registry larger than that is truncated and rejected. The registry format has no corresponding 64 KiB limit; once enough extensions/metadata are installed, this makesassessInstalledfalse and permanently routes the canvas back to setup. Read the complete registry through the bounded, descriptor-verified reader instead of the scan prefix.
function readJsonIfFile(p, realRoot) {
const text = readPrefixIfFile(p, realRoot);
if (text === null) return null;
.github/extensions/assess-canvas/extension.mjs:360
- The agent-callable clarification action can overwrite an existing stage artifact without carrying the explicit overwrite confirmation required by
run_stage. Nevertheless,clarificationRuntells the agent that the user explicitly confirmed the overwrite. Require anoverwrite: truefield for this action and reject calls without it; the HTTP path can continue relying on its confirmation dialog.
answer: { type: "string" },
},
required: ["slug", "stage", "index", "question", "answer"],
- Files reviewed: 8/8 changed files
- Comments generated: 0 new
- Review effort level: Balanced
We're testing this review assessment. Please use 👍 or 👎 to tell us if it's correct.
Publish the Idea Assessment canvas independently as spec-kit-copilot-assess, keep the core skills plugin focused, and describe the repository as the Copilot integration hub for Spec Kit. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 38c901bb-913e-4055-8ed4-fdcda14dc858
There was a problem hiding this comment.
🟡 Not ready to approve
The canvas lifecycle has a server-leak race, and input and accessibility validation need correction.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
This review doesn't count toward merge requirements. Sign up for the private preview to control whether Copilot approvals count.
Review details
Suppressed comments (3)
plugins/spec-kit-copilot-assess/extensions/assess-canvas/extension.mjs:413
- Concurrent opens for the same
instanceIdcan both pass this check because the map is not populated untilstartServer()resolves. One entry then overwrites the other, so the first loopback server and polling timer are never closed; a close arriving during startup has the same leak. Store a shared startup promise before awaiting it, and makeonCloseawait and clean that promise.
let entry = servers.get(ctx.instanceId);
if (!entry) {
entry = await startServer(ctx.instanceId);
servers.set(ctx.instanceId, entry);
plugins/spec-kit-copilot-assess/extensions/assess-canvas/assess.mjs:45
- This accepts arbitrarily long normalized slugs. A slug longer than the filesystem's component limit passes the API validation and is sent to the skill, but creating
.specify/assessments/<slug>then fails withENAMETOOLONG; reject oversized slugs before reporting the run as sent.
return SLUG_RE.test(slug) ? slug : "";
plugins/spec-kit-copilot-assess/extensions/assess-canvas/index.html:153
- The symbol-only button's accessible name is “×”, which does not describe its purpose to screen-reader users. Give it meaningful text; the artifact-view code can still replace that text with “← Dashboard”.
<button class="closex" id="closeArt" title="Close">×</button>
- Files reviewed: 9/9 changed files
- Comments generated: 0 new
- Review effort level: Balanced
We're testing this review assessment. Please use 👍 or 👎 to tell us if it's correct.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 38c901bb-913e-4055-8ed4-fdcda14dc858
There was a problem hiding this comment.
🟡 Not ready to approve
Setup-state controls and dialog accessibility need correction before approval.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
This review doesn't count toward merge requirements. Sign up for the private preview to control whether Copilot approvals count.
Review details
Suppressed comments (3)
plugins/spec-kit-copilot-assess/extensions/assess-canvas/index.html:170
- This dialog also lacks an accessible name. Give the heading an ID and reference it with
aria-labelledbyso assistive technology can identify the clarification dialog.
<dialog id="clarifyDialog">
<h2>Resolve clarification</h2>
plugins/spec-kit-copilot-assess/extensions/assess-canvas/index.html:290
- When setup is required, existing assessment cards are still rendered and this helper enables intake/research/define (and possibly downstream stages). Those controls then always fail because
/api/runreturns 409 in the same state. Disable all stage controls whilesetupRequiredis true so the setup action is genuinely the first available step.
function canRunStage(stage, assessment) {
if (stage === "intake" || stage === "research" || stage === "define") return true;
plugins/spec-kit-copilot-assess/extensions/assess-canvas/index.html:158
- The native dialog has no accessible name; descendant headings do not automatically name a
dialog. Associate it with the existing heading so screen readers announce what opened.
This issue also appears on line 169 of the same file.
<dialog id="stageDialog">
- Files reviewed: 9/9 changed files
- Comments generated: 0 new
- Review effort level: Balanced
We're testing this review assessment. Please use 👍 or 👎 to tell us if it's correct.
Summary
spec-kit-copilot-assess, an independently installable Copilot App canvas plugin for the Spec Kit assessment funnelDistribution
The marketplace now exposes two independently versioned plugins:
spec-kit-copilotv0.15.0 — the existing core Spec Kit skillsspec-kit-copilot-assessv0.1.0 — the optional Idea Assessment canvasThe canvas plugin lives under
plugins/spec-kit-copilot-assess/and declares its ownextensions/component path. Installing the core skills plugin does not install or enable the canvas.Validation
Both plugins were installed independently from the repository's marketplace in an isolated
COPILOT_HOME; the core installed nine skills and the assessment plugin installed its canvas extension. The canvas implementation was also exercised through the GitHub Copilot App runtime before the packaging split.