@ivorycanvas/qamap 0.3.4 → 0.3.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +17 -1
- package/dist/e2e.js +43 -1
- package/dist/e2e.js.map +1 -1
- package/dist/manifest.js +138 -4
- package/dist/manifest.js.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/docs/benchmarking.md +6 -1
- package/docs/e2e-output-examples.md +1 -1
- package/docs/manifest.md +4 -0
- package/docs/release-validation.md +18 -31
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,22 @@
|
|
|
2
2
|
|
|
3
3
|
## Unreleased
|
|
4
4
|
|
|
5
|
+
## 0.3.5 - 2026-07-11
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
|
|
9
|
+
- `manifest init` now creates reusable manual API contract flows for common server route, controller, handler, and framework-backed service modules. Each inferred flow carries API file anchors plus success-contract and invalid-request checks, so a baseline can shape later service changes instead of containing domains only.
|
|
10
|
+
- The public benchmark can generate an external verification manifest from a fixture's base commit and assert manifest matches and manifest-backed QA flows against the head commit. API contract and reverse-import fixtures now protect this feedback loop in CI without executing fixture code.
|
|
11
|
+
|
|
12
|
+
### Changed
|
|
13
|
+
|
|
14
|
+
- A changed file that matches a declared manifest domain but no flow anchor now keeps manifest provenance on the best overlapping inferred flow. QAMap does not invent manifest checks or merge unrelated flows; it preserves the code-derived steps, selectors, and entrypoint while explaining the domain-level evidence.
|
|
15
|
+
- Private repository smoke output is treated as local-only diagnostic data. Public regression coverage uses minimized synthetic fixtures and neutral sample vocabulary.
|
|
16
|
+
|
|
17
|
+
### Fixed
|
|
18
|
+
|
|
19
|
+
- Replaced legacy real-world-derived example vocabulary with neutral synthetic examples in tests and documentation.
|
|
20
|
+
|
|
5
21
|
## 0.3.4 - 2026-07-10
|
|
6
22
|
|
|
7
23
|
### Added
|
|
@@ -19,7 +35,7 @@
|
|
|
19
35
|
|
|
20
36
|
- Reports are colorized when printed to an interactive terminal: headings, the At a Glance keys, status words and stage labels, priority tags, and inline commands get ANSI styling with zero dependencies. Files written with `--output`, pipes, CI logs, and machine formats (`json`, `agent`, `sarif`) are byte-identical to before; the standard `NO_COLOR` and `FORCE_COLOR` environment variables are honored.
|
|
21
37
|
- Mock/fixture file detection now matches whole name tokens instead of substrings, and a bare `handler` filename no longer counts as mock evidence outside mock-style directories. Files like `useSeedlingCatalog.ts` or `errorHandler.ts` stop being misreported as fixtures, which also stops branches from being marked `ready` on the strength of ordinary source files.
|
|
22
|
-
- Fixture guidance now names the concrete thing to do instead of assigning homework. QAMap statically reads the contents of discovered mock/fixture/seed files (up to 24 per plan) and extracts exports, handled routes (MSW, Mirage, express-style, Playwright `route(...)`), and response keys. Next actions
|
|
38
|
+
- Fixture guidance now names the concrete thing to do instead of assigning homework. QAMap statically reads the contents of discovered mock/fixture/seed files (up to 24 per plan) and extracts exports, handled routes (MSW, Mirage, express-style, Playwright `route(...)`), and response keys. Next actions name the reusable fixture and uncovered endpoint; generated Playwright mock bodies reuse observed response keys instead of the `ok: true` placeholder; and fixture action-item titles carry the endpoints so the compact agent format keeps the target. Matched insights are exposed as an optional `mockInsights` array on `fixtureReadiness` in JSON output.
|
|
23
39
|
- `qamap init --agent` gives agent onboarding a single command: it adds a marked `Pre-PR QA (QAMap)` section to `AGENTS.md` (created if missing, appended if present, refreshed in place on re-runs without touching surrounding content), installs the packaged skill to `.claude/skills/qamap-pr-qa/SKILL.md`, and creates a starter `qamap.config.json` when none exists. Every step is idempotent, and a locally modified skill copy is never replaced without `--force`.
|
|
24
40
|
- Korean action labels now qualify for flow and scenario naming: labels like `저장하기` or `신청하기` (36 common action stems, with `~하기/~합니다`-style endings) name the journey the same way English action words do, draft filenames keep Hangul instead of collapsing to an empty slug, and Korean submit-like labels drive `Submit` steps. This closes the known limit noted in 0.3.3.
|
|
25
41
|
|
package/dist/e2e.js
CHANGED
|
@@ -4822,7 +4822,43 @@ async function buildManifestDraftFlows(plan, baseFlows) {
|
|
|
4822
4822
|
.filter((match) => match.kind === "flow")
|
|
4823
4823
|
.slice(0, 4);
|
|
4824
4824
|
const checkMatches = plan.verificationManifestMatches.filter((match) => match.kind === "check");
|
|
4825
|
-
|
|
4825
|
+
const flowDrafts = await Promise.all(flowMatches.map((match) => buildManifestDraftFlow(plan, match, checkMatches, baseFlows)));
|
|
4826
|
+
const flowMatchedFiles = new Set(flowMatches.flatMap((match) => match.matchedFiles));
|
|
4827
|
+
const domainDrafts = await Promise.all(plan.verificationManifestMatches
|
|
4828
|
+
.filter((match) => match.kind === "domain" && match.matchedFiles.some((file) => !flowMatchedFiles.has(file)))
|
|
4829
|
+
.slice(0, 4)
|
|
4830
|
+
.map((match) => buildManifestDomainDraftFlow(plan, match, baseFlows)));
|
|
4831
|
+
return [...flowDrafts, ...domainDrafts.filter((flow) => Boolean(flow))].slice(0, 4);
|
|
4832
|
+
}
|
|
4833
|
+
async function buildManifestDomainDraftFlow(plan, match, baseFlows) {
|
|
4834
|
+
const manifestFiles = normalizeScenarioFilesForRoot(plan, match.matchedFiles);
|
|
4835
|
+
const baseFlow = bestOverlappingBaseFlowForManifestMatch(manifestFiles, baseFlows);
|
|
4836
|
+
if (!baseFlow || isVerificationOnlyFlow(baseFlow)) {
|
|
4837
|
+
return undefined;
|
|
4838
|
+
}
|
|
4839
|
+
// A domain path can cover many independent flows. Preserve manifest
|
|
4840
|
+
// provenance on the best overlapping flow without claiming every matched
|
|
4841
|
+
// domain file belongs to that single draft.
|
|
4842
|
+
const files = baseFlow.files;
|
|
4843
|
+
const flow = {
|
|
4844
|
+
...baseFlow,
|
|
4845
|
+
reason: `${match.reason} ${baseFlow.reason}`,
|
|
4846
|
+
files,
|
|
4847
|
+
entrypoints: uniqueEntrypoints([
|
|
4848
|
+
...baseFlow.entrypoints,
|
|
4849
|
+
...(await inferFlowEntrypoints(plan.root, files, plan.recommendedRunner.name)),
|
|
4850
|
+
]),
|
|
4851
|
+
selectors: uniqueSelectors([
|
|
4852
|
+
...baseFlow.selectors,
|
|
4853
|
+
...(await inferFlowSelectors(plan.root, files, plan.recommendedRunner.name)),
|
|
4854
|
+
]),
|
|
4855
|
+
draftSource: "verification-manifest",
|
|
4856
|
+
manifestMatch: match,
|
|
4857
|
+
};
|
|
4858
|
+
return {
|
|
4859
|
+
...flow,
|
|
4860
|
+
languageBrief: buildFlowLanguageBrief(flow),
|
|
4861
|
+
};
|
|
4826
4862
|
}
|
|
4827
4863
|
async function buildManifestDraftFlow(plan, match, checkMatches, baseFlows) {
|
|
4828
4864
|
const relatedChecks = checkMatches.filter((check) => check.id.startsWith(`${match.id}.`));
|
|
@@ -4879,6 +4915,12 @@ function bestBaseFlowForManifestMatch(files, baseFlows) {
|
|
|
4879
4915
|
}
|
|
4880
4916
|
return best && best.score > 0 ? best.flow : baseFlows[0];
|
|
4881
4917
|
}
|
|
4918
|
+
function bestOverlappingBaseFlowForManifestMatch(files, baseFlows) {
|
|
4919
|
+
const ranked = baseFlows
|
|
4920
|
+
.map((flow) => ({ flow, score: fileOverlapScore(files, flow.files) }))
|
|
4921
|
+
.sort((left, right) => right.score - left.score);
|
|
4922
|
+
return ranked[0]?.score > 0 ? ranked[0].flow : undefined;
|
|
4923
|
+
}
|
|
4882
4924
|
function coreFlowForManifestMatch(plan, match) {
|
|
4883
4925
|
return plan.coreFlows.find((flow) => flow.name === match.name || flow.id === match.id);
|
|
4884
4926
|
}
|