v0.7.0
Added
-
Canonical distribution identity. The product and Claude/Codex/Gemini
plugins remainprd-spec-generator, while the official MCP Registry entry
and primary portable bundle becomeai-architect-mcp-specat version 0.7.0.
Repository-facing branding and URLs move to AI Architect MCP Spec at
cdeust/ai-architect-mcp-spec.
Releases retainprd-spec-generator.mcpbas a byte-identical compatibility
asset, and the existingprd-genserver/tool namespace remains unchanged.
The release procedure deprecates all versions of the former Registry entry
only after the new canonical entry is active. -
Portable Spec Verifier for Codex and Gemini CLI. Both host manifests now
launch the same opt-inverifierprofile, which advertises and accepts only
validate_prd_sectionandvalidate_prd_document. The sharedaudit-prd
andvalidate-specskills preserve the boundary between deterministic
structural conformance and semantic or factual correctness. The existing
Claude manifest still selects no profile, so its default 17-toolfull
surface is unchanged. Distribution tests pin manifest versions, launch
arguments, supported skill frontmatter, and that Claude compatibility
invariant.
Fixed
-
Registry checksum guard now validates the field consumers actually read.
Release automation and verification use the schema-definedfileSha256
property rather than agreeing circularly on an unusedfile_sha256field.
The checksum is omitted until the artifact exists, and both identity and
digest guards explicitly reject the former all-zero placeholder. -
Codex and Gemini verifier startup from immutable plugin installs. Their
host manifests now execute the bundled server directly instead of running a
first-launchnpm ciinside the installed plugin directory, which Codex
mounts read-only. Ajv is statically imported so esbuild carries it in the
bundle, and the portable-host smoke test makes the staged plugin root
read-only before exercising MCP initialize, tool discovery, and validation.
Claude Code remains the primary full-profile interface: its.mcp.json
launch path and 17-tool surface are unchanged and covered by regression
tests. The obsolete verifier-only dependency branch was removed from the
remaining Claude launcher after the portable hosts stopped invoking it. -
The server advertised the wrong version to every host that connected.
serverInfo.versionwas the literal0.4.0inpackages/mcp-server/src/index.ts
while package.json,.claude-plugin/plugin.json, manifest.json and server.json
all carried0.6.1— three releases of drift, read by every MCP client at
handshake and by the registry entry built from it. The number is no longer
written down twice:server-version.tsresolves it at startup from the
package.json that ships beside the running bundle (the plugin tree and the
staged .mcpb both carrymcp-server/package.json), falling back to the root
package.json for workspace runs, and returning an obviously-unresolved
sentinel rather than a plausible-looking number if neither can be read.
pnpm bundlestampsmcp-server/package.jsonfrom the root version
(scripts/stamp-bundle-version.mjs), and CI's bundle-freshness check now
diffs all ofmcp-server/, so an unstamped commit fails.The gate that should have caught this is fixed too:
smoke-mcpb.shprinted
serverInfo.versionin its OK line while asserting only that a serverInfo
existed, so the wrong version passed CI in green for three releases. It now
asserts the advertised version equals the one manifest.json declares — two
independent mirrors of the release, so the check can actually fail.
Added
- MCP prompts capability (#28):
prompts/list+prompts/getpublish the
pipeline ordering as enumerable protocol —run_prd_pipeline(context, request)
(coordinate_context_budget → start_pipeline → get_pipeline_state →
submit_action_result → plan_document_verification → conclude_verification) and
verify_prd_document(run_id). Each step's one-line summary is pulled from the
live registered-tool description (the same schematools/listadvertises), so
the ordering is not hand-copied a third time —packages/mcp-server/src/mcp-prompts.ts. - MCP tool profiles (#28):
full/agentprofiles (tool-profiles.ts)
selected by--profile/PRD_GEN_PROFILE.agentadvertises the 12
agent-facing generation/verification tools;fullexposes all 17 including the
internal diagnostics (get_config, read_skill_config, check_health,
get_quality_history, get_strategy_effectiveness). Per-profileinitialize
instructions. - resources/list interop shim (#28): the server now answers
resources/list
andresources/templates/listwith empty arrays and declares the resources
capability, so clients that probe resources regardless of declared capabilities
do not surface-32601as a failed connection (CBM upstream #958). Rationale
recorded at the use site inindex.tsper §8.
Security
-
Every known-vulnerable dependency is gone, and the audit ignore list is now
empty (#36, ScorecardVulnerabilitiesID). The tree carried 39 advisories
(1 critical, 12 high) andpnpm.auditConfig.ignoreGhsassuppressed 8 of them.
Both are now zero:pnpm auditreports{critical:0, high:0, moderate:0, low:0}with nothing suppressed. Floors come from each advisory's
first_patched_version, not from guesswork —vitest(critical
GHSA-5xrq-8626-4rwp,packages/benchmarkwas pinned at^2.0.0while the
rest of the repo ran^4),vite8.1.5,postcss8.5.23,hono4.12.32,
@hono/node-server2.0.5,fast-uri3.1.4,ip-address10.3.1,qs6.15.3,
body-parser2.3.0,js-yaml4.3.0,esbuild0.28.1,mathjs15.2.0.
Transitive floors are pinned viapnpm.overrides, each satisfying its
declaring parent's own range (@modelcontextprotocol/sdkis already at its
latest 1.29.0, so there was no upstream release to wait for).
The previous deferral said mathjs was "absent from the shipped .mcpb"; that
was false —grep -c mathjs mcp-server/index.jsreturns 730 on the bundle it
described — so the two-major bump was owed rather than optional. -
The plugin's runtime provisioning now verifies integrity hashes
(#36, ScorecardPinnedDependenciesID).bin/ensure-deps.shrannpm install --no-package-lockon the user's machine at first launch, so the shipped
plugin re-resolved^8.17.1to whatever it meant that day, unverified. It now
runsnpm ciagainst a committedmcp-server/package-lock.json(44 of 45
entries carry anintegrityhash). Scorecard's shell checker accepts exactly
this one form:isNpmUnpinnedDownloadtreats a command as pinned only when it
containsci, so pinning versions insidenpm install pkg@1.2.3satisfies
neither the checker nor the actual threat. -
Least-privilege
GITHUB_TOKENacross CI (#36, Scorecard
TokenPermissionsID):ci.ymldeclared no top-levelpermissions:block.
Per Scorecard's ownchecks/evaluation/permissions.go, that undeclared
top-level is what zeroed the check;release.yml's job-levelcontents: write— which creating a GitHub Release genuinely requires — costs nothing
because that file already declarescontents: readat top level.
Added
-
Property-based tests for
validateSection(#36, ScorecardFuzzingID):
six contract invariants underfast-check— never throws, score stays in
[0,1],rulesPassed/violations partitionrulesChecked,
hasCriticalViolationsagrees with the violation set, determinism, and
section-type echo. The function is fed LLM output, so its input space is "any
string a model might emit"; the two defectsregex-hardening.test.tsrecords
([:<≤<=]never matching<=, andtest_foomatching insidemytest_foo)
were both reachable by ordinary inputs nobody had written down. -
Dependabot (#36, Scorecard
DependencyUpdateToolID) fornpmand
github-actions. The second ecosystem matters as much as the first: every
uses:is pinned by commit SHA, and a SHA pin never ages out on its own, so
without it the repo trades a supply-chain risk for an unpatched-action risk.
Fixed
-
The
.mcpbbundle could not start.manifest.jsondeclares
server.mcp_config=node ${__dirname}/mcp-server/index.js, and the staged
tree carried nonode_modules: launching it exited immediately with
Cannot find module 'ajv'.bin/ensure-deps.shshipped inside the bundle but
nothing in the.mcpbever invoked it — that launcher belongs to the plugin
path (.mcp.json), which passes it explicitly. The.mcpbnow ships with its
runtime dependencies already provisioned from the committed lockfile
(--omit=optionalleaves out the platform-specificbetter-sqlite3, whose
absence is the already-declared Beta(7,3) prior fallback).The reason this survived a green suite is that the suite exercises the
workspace sources; nothing ever started the artifact users install. So
staging moved out ofrelease.ymlintoscripts/release/stage-mcpb.sh, and
scripts/release/smoke-mcpb.shstages the bundle and speaks MCP to it over
stdio, assertinginitializereturns aserverInfoandtools/listreturns
17 tools. It runs as themcpb smokeCI job on every push and as a gate
inrelease.ymlbefore packing. Verified to fail on the defect it exists to
catch: with provisioning removed it reportsSMOKE FAIL: no response to initialize — the server did not start.Both channels are now verified end-to-end from a clean tree: the plugin path
(ensure-deps.sh→npm ci→ 44 packages) and the.mcpbpath both reach
initialize OK → prd-gen 0.4.0, 17 tools. -
The ReDoS growth-ratio assertion no longer fails on an unchanged tree.
expectSubQuadratictimed everysmallsample and then everylargeone, so
ambient-load drift between the two blocks landed entirely in the numerator —
on a 90-file parallel suite that is routine, andmainproduced ratio 3.42
against a 2.5 ceiling on one run while passing the next two. The pair is now
timed back-to-back and the median is taken over per-pair ratios, so the load
term is common to numerator and denominator and cancels. The assertion keeps
its 2.5 ceiling and its power: measured against an injected O(n²) worker it
still reports 4.00 idle and 3.81 under eight competing CPU spinners, versus
0.03/0.05 for a linear one. -
The external-judge harness no longer reads any file on the path to the
network (js/file-access-to-http, the last CodeQL alert open onmain).
Both inputs used to be paths chosen at run time —prompt_sourcenamed a
file inside the claim data, andjudge.mjs --prompt-filenamed one on the
command line — so the corpus was substitutable: point either at another file
and its bytes are posted to a third-party LLM API. #37 guarded the first with
a traversal check; this removes both reads instead. The corpus is now bound
by a staticimport … with { type: "json" }, AC-008's historical text is
inline in the fixture (its file recorded inevidence_sourceas provenance,
pinned byte-for-byte by a test), andjudge.mjsreads stdin —< prompt.txt
is the same invocation with the shell doing the open. Verified with the
CodeQL CLI against the query's own model: 1 result before, 0 after, and 0 new
alerts across the fullsecurity-and-qualitysuite. -
Three polynomial-ReDoS patterns closed in the hard-output rules
(js/polynomial-redos, the two CodeQL alerts that survived #37). All three
were reported at the sharedfindPatternViolationscall site but lived in the
patterns handed to it:sp_not_in_fr_table's cell scan, and
no_placeholder_tests' TODO-body and matrix-row patterns. Each measured
3.9x–4.0x per doubling before the fix — 2.6 s on a 176 KB single-line input —
and is now linear. Pinned by growth-ratio tests (not wall-clock thresholds) in
packages/validation/src/__tests__/regex-hardening.test.ts, each of which
fails on the pre-fix code. -
Internal diagnostics tools are gated, not merely hidden under the
agent
profile (#28 criterion 5): an excluded tool is absent fromtools/listAND
rejected on call (RegisteredTool.disable()→-32602 "Tool … disabled").
Hiding from the list while still executing would be a hole, not an
optimization. Asserted bypackages/mcp-server/src/__tests__/mcp-prompts.test.ts.
Removed
-
judge.mjs --prompt-file— prompt text now comes from stdin only.
node judge.mjs … < prompt.txtis byte-for-byte the same invocation with the
shell performing the open, so no capability is lost; what goes is a second
way to do one thing that happened to be the exfiltration primitive above. No
caller in the repo used the flag. -
prompt_sourceinfixtures/ground-truth.json, replaced by the inline
evidencefield every other claim already used, plus anevidence_source
provenance pointer that nothing reads.resolveClaimEvidencetherefore no
longer touches the filesystem, and theresolveInsideFixturescontainment
helper added in #37 is gone with the read it guarded.
Changed
-
sp_not_in_fr_tableis now row-scoped (consequence of the ReDoS fix
above; the old pattern had no linear equivalent).\sand[^|]both match
\n, so the old greedy cell loop ran to the LAST Story-Points cell in the
section and emitted ONE violation whose evidence spanned every row in
between. Two offending rows now produce two violations, each carrying its own
row asoffendingContent— so a section with N offending rows scores N
penalties where it previously scored one. -
no_placeholder_testsmatrix-row detection is line-scoped. For the same
reason (\smatching\n), a// TODOon the line after a matrix row was
read as that row's third cell. A markdown row cannot wrap, so this removes a
false positive rather than a detection. -
The default MCP tool profile is
full(behaviour preserved). This diverges
from #28 criterion 3's "default to the agent-facing set": shrinking the
default advertised surface is a breaking change (a client that called a
now-hidden tool would break), so — mirroring automatised-pipeline's
ToolProfileand this parity wave's decision across all three repos —full
stays the default andagentis opt-in. No default behaviour change ships, so
manifest.json/server.jsonneed no default update; the opt-in env
(PRD_GEN_PROFILE) is documented here. -
Public-readiness baseline: LICENSE (MIT, sole independent author),
CONTRIBUTING.md, CODE_OF_CONDUCT.md, SECURITY.md. -
GitHub issue templates (bug / feature / audit-finding) and PR template
with audit-cycle checklist. -
GitHub Actions release workflow (
release.yml): tag-triggered build +
test + bundle-freshness gate + CHANGELOG-driven release notes. -
assets/banner.svg— ANSI Shadow project banner matching the ai-architect
ecosystem's visual contract. -
README cross-links to companion projects (Cortex, zetetic-team-subagents,
automatised-pipeline). -
.claude-plugin/marketplace.jsonand rewrittenplugin.json— marketplace
distribution viaclaude plugin marketplace add cdeust/prd-spec-generator. -
mcp-server/index.js— reproducible ESM bundle (esbuild;better-sqlite3
stays external);pnpm bundlescript; CI bundle-freshness gate. -
pnpm verifyend-to-end chain: install → build → bundle → test.
Note (2026-07-17, #22 backfill): these bullets predate the
[0.2.1]
boundary below — they shipped alongside the## [0.2.0]version-bump
commit (6c41cb7) whose own dedicated section further down this file
already describes a different set of changes (Phase 4 strategy-wiring).
Reconciling[0.2.0]'s content with what6c41cb7actually shipped is a
separate,[0.2.0]-scoped correction outside #22's 0.2.1–0.5.0 backfill
range, so this residual is left in place rather than reattributed on
unverified inference.
Canonical .mcpb bundle
Artifact: ai-architect-mcp-spec.mcpb (legacy alias: prd-spec-generator.mcpb)
SHA-256: 6dcf5096089e80dadaeec78743f562ecc6d3a3a5349e7e377275ffa50f20dec7