Add /sd:port workflow, Check 8 contract-lint, and e2e harness - #26
Merged
Conversation
…declarations and fix contract mismatches
The engine's shell was heavily verified; its product - the command prompts, agents and skills - had zero automated verification. Every relationship between those files was asserted in prose and checked by human review, and that gap had already shipped statically-detectable defects. Check 7 closed the inventory drift class. This closes the contract drift class: 17 rules across CL0xx reference resolution, CL3xx gate integrity and CL9xx suppression hygiene, as twin pure-file-ops scripts that emit TSV and nothing else. Severity lives only in the manifest registry, so a BLOCK/WARN divergence between the two implementations is structurally impossible, and a registry parity guard in each linter exits 2 when the rules it dispatches and the registry disagree. Gate counts become published claims: the manifest seeds Check 7 quantities, giving README <- manifest there and manifest <- disk in CL302, hence transitively README == disk with no gate parser duplicated into validate. Two real violations were fixed before the linter landed, so the first green run is distinguishable from a linter that never fires: architecture.md listed four items against a count of three, and a setup gate had no literal STOP. Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Makes SW-25's Inputs (required|optional) declarations load-bearing: five new rules (CL100-CL104) cross-check every commands/*.md agent invocation against the target agent's declared mode in agents/*.md, in both linter implementations, with matching fixtures and docs. Also fixes two real drifted invocations found while building this (commands/refactor.md missing INVARIANTS, agents/code-explorer.md missing GITNEXUS_AVAILABLE), and suppresses two intentional scoped-re-plan exceptions with cited reasons. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Four rules over the agent role contract: CL200 (WARN, promotes to BLOCK later) an agent with no write tool is instructed to write/append/create; CL201 (BLOCK) an agent declared read-only in contractLint.readOnlyAgents grows a write tool anyway; CL202 (WARN) an mcp__* name is absent from contractLint.knownMcpTools; CL203 (WARN) an agent's own frontmatter declares a tool its own body never mentions. A write tool is exactly Write/Edit/MultiEdit - Bash deliberately does not count. Adds a per-agent tools: frontmatter index and an mcp__* token scan to both linters, five new fixtures (one per rule plus a false-positive guard for CL200's verb scan), and fixes a latent CL203 gap in six existing fixtures' copies of the demo agent. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Four new contract-lint rules: CL400/CL401 (hardcoded stack command/language tokens outside a placeholder, fenced example, or suppression comment), CL402 (hardcoded absolute filesystem path), and CL306 (HARD gate prose describing an escape hatch with no contract-lint: allow comment) - the prose half of CL305 that wave 1 deferred. CL306 deliberately excludes whatever CL305 already governs so the two rules cover disjoint territory. The MSSQL/C#/TypeScript violations the ticket described were already fixed in an earlier commit; the real hits this wave found in the current tree were legitimate multi-stack heuristics and forbidden-example prose, so those got contract-lint: allow annotations rather than rewrites. Nine new fixture cases, docs/contract-lint.md updates, and manifest vocabulary (stackTokens, gateProseEscapeTokens) mirroring the overrideOptionTokens precedent. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Adds CL500 (WARN, permanent): a file exceeding contractLint.budgets.<area>Bytes, ratcheted at today's largest file per scan-scope area. The byte count is normalized (per-line byte sum, not a raw disk read) so the rule agrees with itself across a CRLF Windows checkout and an LF Linux CI runner. Two new fixture cases, a registry-parity fix across 7 older fixture overlays that had not picked up the new rule id, and a bash 'set -e' fix in the byte-budget lookup helper that was silently killing the linter on any unbudgeted file.
All three shipped WARN with an explicit "promotes to BLOCK in a follow-up commit once it has run clean for a release" clause. The engine tree now has zero findings for all three under both linter implementations, so the promotion is live. Severity is registry-driven (specwright.manifest.json), so no rule logic changed; nine fixture overlays and three expected.json goldens updated to match, plus docs and CHANGELOG corrected to reflect BLOCK severity. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Adds a tiny, dependency-free Node.js todo-list library as the first non-.NET project run through specwright end-to-end: pre-scaffolded CLAUDE.md, constitution, and project-config, plus a real .specs/FEAT-todo-priority/ (spec through verify) driven live through the actual sd-spec-architect, sd-code-explorer, sd-implementer, and sd-reviewer subagents with real gate approvals, not hand-authored. Reconciles examples/README.md, docs/walkthrough.md, and root README.md (Quickstart, compatibility matrix, docs list) to point at it instead of promising a fixture that didn't exist. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Drives real claude -p sessions against a throwaway fixture copy and asserts on produced artifacts, not transcript wording - the first mechanism proving the engine behaves correctly end-to-end rather than just that its assets reference each other correctly. Verified live: self-test genuinely detects a neutered spec-gate guard; full-suite run found 4/5 scenarios green plus a real, documented product gap (Rule 1 stalls /sd:feature's own status transitions under an enforcing permission mode) - measured cost and the finding are recorded in tests/e2e/README.md. Reproducible-3x and the Rule 1 fix are tracked as follow-up rather than folded into this scope. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Check 7's entire vocabulary (docClaims/claimPhrases) is count-based, so a stale version string had nothing to trip it - ROADMAP.md said 1.3.0 since before the 1.4.0 release, unnoticed through every green run, and its Planned section claimed an empty queue while [Unreleased] carried eight real entries. A new versionClaims array in specwright.manifest.json closes this: entries compare a captured x.y.z string against the newest dated CHANGELOG heading rather than a disk-derived quantity. validate.sh/.ps1 gained a matching check, deliberately independent of Check 6's existing next_header/$nextHeader (those resolve to whatever line sits directly below [Unreleased], which is a bullet rather than a heading in the normal state, so reusing them would have passed on bash and silently done nothing on PowerShell). selftest-docs grows from 6 scenarios to 7. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Installers now resolve the engine version from CHANGELOG.md and write a specwright-version.txt stamp into every installed area via the existing copy machinery, so no engine artifact exists without a way to tell which version wrote it. Check 5/7 validators, install/README.md, and the CI round-trip account for the stamp with derived (never hardcoded) counts. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Phase 0 now reads the installed specwright-version.txt stamp; Phase 1.5 compares it against project-config.json's version and generalizes the missing-field check into a full template diff, with version as the one field Apply may write outside the project-specific preserve-list. Fresh scaffolds stamp the real installed version instead of the template's literal 1.0.0. Also removes the template's dead $schema URL (no schema was ever published, and the org name didn't match the real repo) - the drift-check now flags any leftover key for removal instead of rewrite. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Gate Complexity trips were never recorded as metrics and this repo's real corpus is n=1 closed spec, not the "n=1 risk" the ticket assumed - so this lands the measurement machinery (a new gate:"complexity"/split event inferred from index.md, /sd:status --calibration, judgement-call caveats on the other five thresholds) and an ADR recording the honest verdict at this corpus size, rather than manufacturing a calibrated number from one spec. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Cross-project port policy promoted into a skill because two agents need the same rule body: sd-spec-architect authors the deviation table and the port task blocks, sd-reviewer judges whether a diff hunk is justified. Defines structural mirror as the default posture, the four-group deviation allowlist with a required citation per group, five anti-simplification rules that reach the implementer through task Acceptance rather than through the skill, completeness conditions for the three gate tables phrased as counting and matching predicates a gate can evaluate without judgement, and the closed four-class hunk vocabulary. Fidelity findings anchor to the port spec's mandatory fidelity acceptance criterion, already a legal code anchor - sd-severity-taxonomy's Anchors table is deliberately left untouched, since its rows are keyed by target and a new row would relax every reviewer task type. agents/spec-architect.md was the CL500 ratchet-setter and sat at the ceiling exactly, so budgets.agentsBytes moves 14454 -> 14671 to admit the two-line wiring. Reviewed growth, not a reflex to a red run. Consumers land later: SW-38 template, SW-39 extraction, SW-40 diff and adjudication, SW-41 pipeline. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…yout Adds the authoring half of the port workflow: a PORT-<slug>-<YYYYMMDD> spec prefix wired through the registry, a port.template.md whose three fidelity tables reuse sd-port-fidelity's (SW-37) schemas rather than the ticket's stale prose precedent, a frozen donor-snapshot layout under 04-artifacts/source/ with a MANIFEST.md format, and SL080-SL083 validate rules. Freezing enumerates literal paths.protected entries since neither spec-gate hook supports globs, and PORT-prefix hook recognition is deliberately deferred to the future port pipeline - both documented as known limitations rather than worked around. No .ps1/.sh file touched. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
New TASK = port-extract mode on sd-code-explorer produces a fixed eight-section donor-side contract (Entry surface, Output surface, Member closure, Complement set, Collaborators, Non-obvious invariants, Dead paths on this entry point, Precedent conventions), replacing the prior free-form /sd:explore prose contract whose gaps a host implementer filled by invention. /sd:explore gains a --port flag that invokes it and, being the main-thread caller, owns source_commit capture (dirty-tree aware) and - under --snapshot contract+source - donor file copying/hashing into a MANIFEST.md matching sd-port-fidelity's format, keeping the explorer agent itself read-only. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Enforcement half of the port epic: a main-thread-generated parity diff (04-artifacts/parity/) plus a new port-parity TASK_TYPE on sd-reviewer that classifies every hunk with sd-port-fidelity's vocabulary, now five classes (adds overreached - a deviation row exists but the hunk exceeds what it licenses), and two whole-artifact checks (member completeness, path conformance). A justified hunk is a PASS and is not written up, so a real BLOCK cannot drown in accepted diffs. sd-reviewer gains no Bash and no write tool - the diff must already exist when it is invoked. The /sd:verify overlap was decided before any checking logic was written: both new checks stay with the reviewer since neither can be decided from 00-spec.md/02-tasks.md alone. Rationale in docs/architecture.md. Adds examples/port-parity-fixture/ (clean + broken port trees) as the regression guard, following spec-lint-fixture's run-by-hand convention. contractLint.budgets.skillsBytes raised 10656 -> 12377 for the skill's growth; agentsBytes needed no change. Diff generation and the /sd:port pipeline itself are SW-41, not yet built - contract-lint reports one new CL101 WARN for the unhosted mode, documented in docs/troubleshooting.md. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Wires the port epic (SW-37 skill, SW-38 template/snapshot layout, SW-39 extraction mode, SW-40 parity gate) into one command: bridge/ extract -> freeze -> host survey -> fidelity tables -> pin behavior -> plan -> execute batched -> justified-diff parity -> close-out. - New commands/port.md; WORKFLOW_TYPE = port added to sd-implementer (neither feature nor refactor was the right constraint set). - port keyword registered in the prompt-router map (both hook implementations) and project-config.template.json. - Manifest gates.commands/port.md + workflowCommands + docClaims wired; skillsBytes ratchet raised 12377 -> 12412. - Docs: README/CLAUDE/CONTRIBUTING/install counts re-derived (14 commands, 47 install files); usage.md phase table; architecture.md routing line + gate table; 4 new troubleshooting.md entries. - Fixed stale "port pipeline lands in a later story" cross-references in spec-architect.md, sd-port-fidelity/sd-spec-templates/ sd-retro-lessons skills, port.template.md, port-parity fixture. Verified: contract-lint 0 block/12 warn (bash+PowerShell agree), scripts/validate.sh 8/8, contract-lint fixture self-test 31/31, sandbox install/uninstall round-trip clean. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Follow-up work discovered mid-spec had nowhere to land except prose, where it evaporated. Adds the RCA template's reserved-ID table (Reserved ID | Type | Title | Owner) to the other four spec types, a close-out prompt (not a gate) in each corresponding command, the first SUGGEST-severity /sd:spec validate rule (SL090) for a done spec that names deferred work with an empty table, and documents that a reserved ID is a placeholder, not a registry entry. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
The page opened with a feature count and asked the reader to take 330 lines of tables on trust before showing a single line of output. - Add `## What it looks like` at the top: the real Gate 1 spec-approval STOP and the real Gate 3 reviewer verdict (0 BLOCK / 0 WARN / 5 SUGGEST / 7 PASS, 18/18 tests), both transcribed from the committed FEAT-todo-priority run in examples/fixture-project/. - Add `## How this differs from prompt-level discipline`, naming what enforces the discipline: gates halt the phase, spec-gate denies Edit/Write at the PreToolUse layer, the reviewer has no write tools, and specs are subagent inputs rather than write-ups. - Merge the two install sections. Quickstart carries the commands inline plus a requirements line; the old section becomes `## Install options and uninstall` and keeps only the advanced path. - Shrink the agent and skill tables to a summary plus a link. Tool allowlists, the routing map, and the skill catalogue already live in docs/architecture.md verbatim. - Fix the BMAD acknowledgement (it pointed at a placeholder https://github.com/), a seven-month-stale compatibility date, and a roadmap bullet reading "nothing queued" against a repo shipping v1.5.0. - Replace the unsourced "~$2-3 per feature run" with a pointer to /sd:status, which reports the reader's own cost from their metrics log. - Surface examples/port-parity-fixture/ and examples/spec-lint-fixture/, previously unmentioned anywhere in the README. The two new prose counts tripped Check 7's undeclared-claim scan, as intended; both get docClaims entries so they derive from disk rather than an exclusion. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The previous commit fixed the order of the page but not its volume. The redundancy was concentrated in four places, not scattered. - Delete `## Architecture highlights`. Three of its four bullets restated hard gates, the cost model and stack-agnosticism verbatim from `## Why spec-driven?`; its 18-line ASCII diagram already lives in docs/architecture.md. The one distinct idea, the three layers, becomes a sentence. - Drop the fifteen `---` rules, ~30 lines spent drawing a line GitHub already draws under every h2. - Stop printing the command and agent names twice. The Features table was a table of contents for the two tables directly beneath it; its rows stay (they anchor docClaims) but the duplicated cells become pointers. - Collapse the spec-folder tree to one expanded spec plus a note, merge the two install blocks into one, and drop the YAML frontmatter snippet that duplicates docs/architecture.md. No published claim is dropped, so specwright.manifest.json is untouched: Check 7 still reports 79 claims and Check 8 still reports 0 BLOCK. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Merging each platform pair into one fenced block saved lines and broke three things: - `./install/install.sh --dry-run && ./install/install.sh` ran the preview and then installed immediately, so the dry-run output scrolled past and was never read. The uninstall block had the same shape, where the real run deletes directories. A dry run you cannot read is not a dry run. - PowerShell sat inside a ```bash fence, so a Windows reader copying the block got bash errors and no syntax highlighting. - The reader had to parse a trailing comment on each line to work out which one was theirs. Now four blocks - bash and powershell, install and uninstall - each with the preview and the real command on separate lines. Costs ~19 lines against the previous commit; correctness wins. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
/sd:portfidelity-first port pipeline (10 phases, 6 gates) plus its supporting pieces:sd-port-fidelityskill,port-extractexplorer mode, port spec template/snapshot layout, and the port-parity adjudication gate onsd-reviewer.scripts/contract-lint.sh/.ps1) with a large fixture suite proving parity between the bash and PowerShell implementations.tests/e2e/) and CI workflows (ci.yml,e2e-nightly.yml).## Spawned specssection to feature/bug/refactor/perf spec templates so deferred follow-up work has a place to land.Test plan
bash scripts/contract-lint.sh --root .and.\scripts\contract-lint.ps1 -Root .(exit 0).\tests\contract-lint\run-selftest.ps1(bash/PowerShell parity fixture suite).\install\install.ps1 -DryRun/ sandbox install round-trip🤖 Generated with Claude Code