|
| 1 | +# Markdown Artifact Review |
| 2 | + |
| 3 | +The existing Wizard and SDD canvases share a Markdown reader inside their |
| 4 | +existing artifact previews. This is an enhancement to those canvases, not a |
| 5 | +new plugin, canvas, workflow, or installation method. |
| 6 | + |
| 7 | +## Reading Artifacts |
| 8 | + |
| 9 | +Open an existing artifact using the canvas's **View** control. Markdown |
| 10 | +previews include GitHub-flavored tables, lists, task lists, code blocks, |
| 11 | +footnotes, and a heading outline. The outline uses a side rail when the |
| 12 | +preview has room and a keyboard-accessible drawer in narrower containers. |
| 13 | + |
| 14 | +The artifact selector includes the selected feature's supporting documents, |
| 15 | +contracts, checklists, and available project constitution. Wizard also |
| 16 | +supports command and template sources already known to its composition. |
| 17 | +Relative Markdown links open scoped documents in the same reader. Back and |
| 18 | +forward arrows select the previous or next available Markdown document in the |
| 19 | +current folder, in natural filename order, without requiring prior visits. |
| 20 | +They skip unavailable files, do not cross into subfolders, and stop at the first |
| 21 | +and last document. Returning to a visited document preserves its reading position |
| 22 | +when its revision is unchanged. |
| 23 | +Returning to the canvas restores the invoking control and current workflow |
| 24 | +state, including progress received while reading. |
| 25 | + |
| 26 | +The source label identifies working-tree content. Existing canvas change |
| 27 | +notifications refresh artifact membership and mark changed content; **Refresh** |
| 28 | +loads the current revision. Missing, unavailable, oversized, or invalid text |
| 29 | +produces an in-preview state without closing the canvas. |
| 30 | +If a review context expires, explicit **Refresh** revalidates its scope and |
| 31 | +selected document in a new context. Context-bound history starts afresh, and |
| 32 | +old clarification bindings are not reused. A document that is no longer in |
| 33 | +the authorized scope remains unavailable. |
| 34 | + |
| 35 | +## Existing Workflows |
| 36 | + |
| 37 | +- Canvas identities, agent actions, stage commands, setup, Run/Rerun, |
| 38 | + overwrite confirmation, and prerequisite ordering are retained. |
| 39 | +- Wizard catalogs, composition, pipeline customization, folder browsing, |
| 40 | + and non-Markdown source previews retain their existing entry points. |
| 41 | +- SDD feature targeting, constitution, progress, optional quality gates, |
| 42 | + new-feature flow, and artifact deep links are retained. |
| 43 | +- Existing artifacts, including normalized extension pipeline entries, can be |
| 44 | + viewed even when setup or execution is gated. This intentionally makes SDD |
| 45 | + feature cards and Wizard artifact navigation available earlier; it does not |
| 46 | + enable execution or perform setup. Non-Markdown previews also keep |
| 47 | + clarification and Apply/Run controls gated, with setup rechecked on submission. |
| 48 | +- Reading, changing documents, following local links, and returning do not |
| 49 | + dispatch a workflow, install dependencies, or write project files. The |
| 50 | + Wizard startup still bootstraps missing runtime dependencies; development |
| 51 | + and test dependencies are omitted from that installation and recovery retry. |
| 52 | + |
| 53 | +Clarification controls remain explicit workflow actions. SDD still confirms |
| 54 | +and submits a targeted answer; Wizard retains queued answers and its |
| 55 | +apply-and-rerun flow. Reader answers are additionally bound to the current |
| 56 | +context, artifact, revision, question, and owning command. When stages share an |
| 57 | +output file, the selected stage's command takes precedence over artifact-path |
| 58 | +matches. Changed questions must be refreshed and reconfirmed. Code examples and |
| 59 | +HTML comments do not become actionable clarification markers. Existing callers |
| 60 | +without reader metadata retain their original action contracts. |
| 61 | +Answers accept normal textarea whitespace (line breaks and tabs) while retaining |
| 62 | +the character and aggregate UTF-8 byte limits. Identifier validation remains strict. |
| 63 | +Questions may contain inline code, emphasis, URLs, and email addresses. Their raw |
| 64 | +source spans determine bindings; markers inside code examples, links, images, |
| 65 | +headings, comments, or escaped/entity-encoded prefixes remain inert. |
| 66 | + |
| 67 | +## Read Boundary |
| 68 | + |
| 69 | +The server derives membership from the existing canvas workspace and selected |
| 70 | +feature or composition, not from a browser-supplied absolute path. Additive |
| 71 | +`/api/review/*` endpoints use the existing canvas capability plus Host/Origin |
| 72 | +checks; legacy endpoint response shapes remain unchanged. Context, artifact, |
| 73 | +and pagination identifiers are opaque and instance-bound, not credentials. |
| 74 | + |
| 75 | +Files must be ordinary, bounded, UTF-8 Markdown inside the authorized |
| 76 | +workspace. Path traversal, `.git`, symbolic links and junctions, Windows |
| 77 | +device aliases and alternate streams are rejected. Revisions hash exact |
| 78 | +file bytes; display-only BOM removal never rewrites the source. Errors shown |
| 79 | +by the reader are bounded and do not expose file contents or private paths. |
| 80 | + |
| 81 | +Raw HTML is disabled, images are inert placeholders, and task checkboxes |
| 82 | +cannot edit documents. Local and external link decisions go through the |
| 83 | +host adapter. Unsafe schemes, protocol-relative URLs, and URLs containing |
| 84 | +credentials are inert; reading never passively fetches external content. |
| 85 | + |
| 86 | +Limits are 5 MiB per artifact, 200 items per page, 10,000 inspected entries |
| 87 | +per discovery pass, and 50 history entries. Reaching the discovery limit |
| 88 | +returns a terminal partial result. This reader has no editing, remote |
| 89 | +repository discovery, authentication, or cloning feature. |
| 90 | + |
| 91 | +## Maintainer Layout |
| 92 | + |
| 93 | +The build-only package is |
| 94 | +[ui/markdown-reader](../plugins/spec-kit-copilot-wizard/extensions/speckit-wizard-canvas/ui/markdown-reader/package.json) |
| 95 | +under Wizard. It owns rendering, outline, focus, and trusted clarification |
| 96 | +presentation. Each canvas keeps its own workflow state and server lifecycle. |
| 97 | + |
| 98 | +Wizard's [review service](../plugins/spec-kit-copilot-wizard/extensions/speckit-wizard-canvas/server/artifact-review.mjs) |
| 99 | +and browser adapter are canonical. The |
| 100 | +[synchronizer](../scripts/canvas-reader/sync-domain.mjs) copies the shared |
| 101 | +domain and adapter into SDD, and bundles the clarification parser for Node. |
| 102 | +[Asset synchronization](../scripts/canvas-reader/sync-assets.mjs) packages |
| 103 | +the reader, dependency notices, and provenance in each plugin independently. |
| 104 | +Neither installed plugin requires the sibling checkout or reader build |
| 105 | +dependencies. Generated payloads are marked in the repository attributes; |
| 106 | +edit their canonical sources and rebuild, not the copies. |
| 107 | + |
| 108 | +## Build And Test |
| 109 | + |
| 110 | +Use Node 24.19.0, npm 11.17.0, and the locked dependencies. From the repository |
| 111 | +root in PowerShell: |
| 112 | + |
| 113 | +```powershell |
| 114 | +$wizard = "plugins/spec-kit-copilot-wizard/extensions/speckit-wizard-canvas" |
| 115 | +$reader = "$wizard/ui/markdown-reader" |
| 116 | +npm ci --prefix $wizard --ignore-scripts |
| 117 | +npm ci --prefix $reader --ignore-scripts |
| 118 | +npm --prefix $reader run typecheck |
| 119 | +npm --prefix $reader run lint |
| 120 | +npm --prefix $reader test |
| 121 | +npm --prefix $reader run build |
| 122 | +npm --prefix $reader run verify:package |
| 123 | +node --test "$wizard/test/*.test.mjs" "plugins/spec-kit-copilot-sdd/extensions/sdd-canvas/tests/*.test.mjs" |
| 124 | +npm --prefix $reader run test:tools |
| 125 | +npm --prefix $reader run test:browser |
| 126 | +npm --prefix $reader audit --audit-level=low --ignore-scripts |
| 127 | +``` |
| 128 | + |
| 129 | +Both package lockfiles must use public `registry.npmjs.org` HTTPS tarball URLs |
| 130 | +and SHA-512 integrity for every dependency. Regenerate against that registry, |
| 131 | +not a user- or organization-configured mirror, and retain the package-contract |
| 132 | +checks. The reader temporarily overrides `minimatch` to 11.0.1 to address |
| 133 | +GHSA-g3hv-75wg-m249 until its lint dependencies accept the patched major; do not |
| 134 | +replace this with an audit exemption or an ESLint downgrade. |
| 135 | + |
| 136 | +After dependency or lockfile updates, rebuild and verify both packaged payloads |
| 137 | +with this toolchain. The source fingerprint includes the lockfile, so tooling-only |
| 138 | +updates still require regenerated provenance manifests even if the bundled |
| 139 | +JavaScript and CSS remain unchanged. |
| 140 | + |
| 141 | +The [validation workflow](../.github/workflows/canvas-reader-validation.yml) |
| 142 | +runs Windows and Linux checks. CI builds without synchronizing first, so |
| 143 | +stale committed payloads fail verification rather than being silently fixed. |
| 144 | +Browser tests use Edge on Windows and isolated Chromium on Linux, actual |
| 145 | +canvas shells, owned synthetic files, and mocked host sessions. They cover |
| 146 | +navigation, responsive layout, clarification, freshness, source preservation, |
| 147 | +and independent packaging without executing real workflows. They do not |
| 148 | +replace native Copilot App acceptance or real workflow acceptance. |
0 commit comments