qfai 0.7.2 → 0.8.0

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/dist/index.mjs CHANGED
@@ -1179,8 +1179,8 @@ import { readFile as readFile4 } from "fs/promises";
1179
1179
  import path7 from "path";
1180
1180
  import { fileURLToPath } from "url";
1181
1181
  async function resolveToolVersion() {
1182
- if ("0.7.2".length > 0) {
1183
- return "0.7.2";
1182
+ if ("0.8.0".length > 0) {
1183
+ return "0.8.0";
1184
1184
  }
1185
1185
  try {
1186
1186
  const packagePath = resolvePackageJsonPath();
@@ -1551,7 +1551,7 @@ async function validateDeltas(root, config) {
1551
1551
  issues.push(
1552
1552
  issue2(
1553
1553
  "QFAI-DELTA-002",
1554
- "delta.md \u306E\u5909\u66F4\u533A\u5206\u304C\u4E0D\u8DB3\u3057\u3066\u3044\u307E\u3059\u3002",
1554
+ "delta.md \u306E\u5909\u66F4\u533A\u5206\u304C\u4E0D\u8DB3\u3057\u3066\u3044\u307E\u3059\u3002`## \u5909\u66F4\u533A\u5206` \u3068\u30C1\u30A7\u30C3\u30AF\u30DC\u30C3\u30AF\u30B9\uFF08Compatibility / Change/Improvement\uFF09\u3092\u8FFD\u52A0\u3057\u3066\u304F\u3060\u3055\u3044\u3002",
1555
1555
  "error",
1556
1556
  deltaPath,
1557
1557
  "delta.section"
@@ -2094,7 +2094,7 @@ async function validateTraceability(root, config) {
2094
2094
  issues.push(
2095
2095
  issue6(
2096
2096
  "QFAI-TRACE-020",
2097
- "Spec \u306B QFAI-CONTRACT-REF \u304C\u3042\u308A\u307E\u305B\u3093\u3002",
2097
+ "Spec \u306B QFAI-CONTRACT-REF \u304C\u3042\u308A\u307E\u305B\u3093\u3002\u4F8B: `QFAI-CONTRACT-REF: none` \u307E\u305F\u306F `QFAI-CONTRACT-REF: UI-0001`",
2098
2098
  "error",
2099
2099
  file,
2100
2100
  "traceability.specContractRefRequired"
@@ -2105,7 +2105,7 @@ async function validateTraceability(root, config) {
2105
2105
  issues.push(
2106
2106
  issue6(
2107
2107
  "QFAI-TRACE-023",
2108
- "Spec \u306E QFAI-CONTRACT-REF \u306B none \u3068\u5951\u7D04 ID \u304C\u6DF7\u5728\u3057\u3066\u3044\u307E\u3059\u3002",
2108
+ "Spec \u306E QFAI-CONTRACT-REF \u306B none \u3068\u5951\u7D04 ID \u304C\u6DF7\u5728\u3057\u3066\u3044\u307E\u3059\u3002none \u304B \u5951\u7D04ID \u306E\u3069\u3061\u3089\u304B\u4E00\u65B9\u3060\u3051\u306B\u3057\u3066\u304F\u3060\u3055\u3044\u3002",
2109
2109
  "error",
2110
2110
  file,
2111
2111
  "traceability.specContractRefFormat"
@@ -2118,7 +2118,7 @@ async function validateTraceability(root, config) {
2118
2118
  "QFAI-TRACE-021",
2119
2119
  `Spec \u306E\u5951\u7D04 ID \u304C\u4E0D\u6B63\u3067\u3059: ${contractRefs.invalidTokens.join(
2120
2120
  ", "
2121
- )}`,
2121
+ )} (\u4F8B: UI-0001 / API-0001 / DB-0001)`,
2122
2122
  "error",
2123
2123
  file,
2124
2124
  "traceability.specContractRefFormat",
@@ -2158,7 +2158,7 @@ async function validateTraceability(root, config) {
2158
2158
  issues.push(
2159
2159
  issue6(
2160
2160
  "QFAI-TRACE-031",
2161
- "Scenario \u306B QFAI-CONTRACT-REF \u304C\u3042\u308A\u307E\u305B\u3093\u3002",
2161
+ "Scenario \u306B QFAI-CONTRACT-REF \u304C\u3042\u308A\u307E\u305B\u3093\u3002\u4F8B: `# QFAI-CONTRACT-REF: none` \u307E\u305F\u306F `# QFAI-CONTRACT-REF: UI-0001`",
2162
2162
  "error",
2163
2163
  file,
2164
2164
  "traceability.scenarioContractRefRequired"
@@ -2169,7 +2169,7 @@ async function validateTraceability(root, config) {
2169
2169
  issues.push(
2170
2170
  issue6(
2171
2171
  "QFAI-TRACE-033",
2172
- "Scenario \u306E QFAI-CONTRACT-REF \u306B none \u3068\u5951\u7D04 ID \u304C\u6DF7\u5728\u3057\u3066\u3044\u307E\u3059\u3002",
2172
+ "Scenario \u306E QFAI-CONTRACT-REF \u306B none \u3068\u5951\u7D04 ID \u304C\u6DF7\u5728\u3057\u3066\u3044\u307E\u3059\u3002none \u304B \u5951\u7D04ID \u306E\u3069\u3061\u3089\u304B\u4E00\u65B9\u3060\u3051\u306B\u3057\u3066\u304F\u3060\u3055\u3044\u3002",
2173
2173
  "error",
2174
2174
  file,
2175
2175
  "traceability.scenarioContractRefFormat"
@@ -2182,7 +2182,7 @@ async function validateTraceability(root, config) {
2182
2182
  "QFAI-TRACE-032",
2183
2183
  `Scenario \u306E\u5951\u7D04 ID \u304C\u4E0D\u6B63\u3067\u3059: ${scenarioContractRefs.invalidTokens.join(
2184
2184
  ", "
2185
- )}`,
2185
+ )} (\u4F8B: UI-0001 / API-0001 / DB-0001)`,
2186
2186
  "error",
2187
2187
  file,
2188
2188
  "traceability.scenarioContractRefFormat",
@@ -2680,7 +2680,7 @@ function formatReportMarkdown(data) {
2680
2680
  lines.push(`- \u8A2D\u5B9A: ${data.configPath}`);
2681
2681
  lines.push(`- \u7248: ${data.version}`);
2682
2682
  lines.push("");
2683
- lines.push("## \u6982\u8981");
2683
+ lines.push("## Summary");
2684
2684
  lines.push("");
2685
2685
  lines.push(`- specs: ${data.summary.specs}`);
2686
2686
  lines.push(`- scenarios: ${data.summary.scenarios}`);
@@ -2690,8 +2690,79 @@ function formatReportMarkdown(data) {
2690
2690
  lines.push(
2691
2691
  `- issues: info ${data.summary.counts.info} / warning ${data.summary.counts.warning} / error ${data.summary.counts.error}`
2692
2692
  );
2693
+ lines.push(
2694
+ `- fail-on=error: ${data.summary.counts.error > 0 ? "FAIL" : "PASS"}`
2695
+ );
2696
+ lines.push(
2697
+ `- fail-on=warning: ${data.summary.counts.error + data.summary.counts.warning > 0 ? "FAIL" : "PASS"}`
2698
+ );
2693
2699
  lines.push("");
2694
- lines.push("## ID\u96C6\u8A08");
2700
+ lines.push("## Findings");
2701
+ lines.push("");
2702
+ lines.push("### Issues (by code)");
2703
+ lines.push("");
2704
+ const severityOrder = {
2705
+ error: 0,
2706
+ warning: 1,
2707
+ info: 2
2708
+ };
2709
+ const issueKeyToCount = /* @__PURE__ */ new Map();
2710
+ for (const issue7 of data.issues) {
2711
+ const key = `${issue7.severity}|${issue7.code}`;
2712
+ const current = issueKeyToCount.get(key);
2713
+ if (current) {
2714
+ current.count += 1;
2715
+ continue;
2716
+ }
2717
+ issueKeyToCount.set(key, {
2718
+ severity: issue7.severity,
2719
+ code: issue7.code,
2720
+ count: 1
2721
+ });
2722
+ }
2723
+ const issueSummaryRows = Array.from(issueKeyToCount.values()).sort((a, b) => {
2724
+ const sa = severityOrder[a.severity] ?? 999;
2725
+ const sb = severityOrder[b.severity] ?? 999;
2726
+ if (sa !== sb) return sa - sb;
2727
+ return a.code.localeCompare(b.code);
2728
+ }).map((x) => [x.severity, x.code, String(x.count)]);
2729
+ if (issueSummaryRows.length === 0) {
2730
+ lines.push("- (none)");
2731
+ } else {
2732
+ lines.push(
2733
+ ...formatMarkdownTable(["Severity", "Code", "Count"], issueSummaryRows)
2734
+ );
2735
+ }
2736
+ lines.push("");
2737
+ lines.push("### Issues (list)");
2738
+ lines.push("");
2739
+ if (data.issues.length === 0) {
2740
+ lines.push("- (none)");
2741
+ } else {
2742
+ const sortedIssues = [...data.issues].sort((a, b) => {
2743
+ const sa = severityOrder[a.severity] ?? 999;
2744
+ const sb = severityOrder[b.severity] ?? 999;
2745
+ if (sa !== sb) return sa - sb;
2746
+ const code = a.code.localeCompare(b.code);
2747
+ if (code !== 0) return code;
2748
+ const fileA = a.file ?? "";
2749
+ const fileB = b.file ?? "";
2750
+ const file = fileA.localeCompare(fileB);
2751
+ if (file !== 0) return file;
2752
+ const lineA = a.loc?.line ?? 0;
2753
+ const lineB = b.loc?.line ?? 0;
2754
+ return lineA - lineB;
2755
+ });
2756
+ for (const item of sortedIssues) {
2757
+ const location = item.file ? ` (${item.file})` : "";
2758
+ const refs = item.refs && item.refs.length > 0 ? ` refs=${item.refs.join(",")}` : "";
2759
+ lines.push(
2760
+ `- ${item.severity.toUpperCase()} [${item.code}] ${item.message}${location}${refs}`
2761
+ );
2762
+ }
2763
+ }
2764
+ lines.push("");
2765
+ lines.push("### IDs");
2695
2766
  lines.push("");
2696
2767
  lines.push(formatIdLine("SPEC", data.ids.spec));
2697
2768
  lines.push(formatIdLine("BR", data.ids.br));
@@ -2700,14 +2771,14 @@ function formatReportMarkdown(data) {
2700
2771
  lines.push(formatIdLine("API", data.ids.api));
2701
2772
  lines.push(formatIdLine("DB", data.ids.db));
2702
2773
  lines.push("");
2703
- lines.push("## \u30C8\u30EC\u30FC\u30B5\u30D3\u30EA\u30C6\u30A3");
2774
+ lines.push("### Traceability");
2704
2775
  lines.push("");
2705
2776
  lines.push(`- \u4E0A\u6D41ID\u691C\u51FA\u6570: ${data.traceability.upstreamIdsFound}`);
2706
2777
  lines.push(
2707
2778
  `- \u30B3\u30FC\u30C9/\u30C6\u30B9\u30C8\u53C2\u7167: ${data.traceability.referencedInCodeOrTests ? "\u3042\u308A" : "\u306A\u3057"}`
2708
2779
  );
2709
2780
  lines.push("");
2710
- lines.push("## \u5951\u7D04\u30AB\u30D0\u30EC\u30C3\u30B8");
2781
+ lines.push("### Contract Coverage");
2711
2782
  lines.push("");
2712
2783
  lines.push(`- total: ${data.traceability.contracts.total}`);
2713
2784
  lines.push(`- referenced: ${data.traceability.contracts.referenced}`);
@@ -2716,7 +2787,7 @@ function formatReportMarkdown(data) {
2716
2787
  `- specContractRefMissing: ${data.traceability.specs.contractRefMissing}`
2717
2788
  );
2718
2789
  lines.push("");
2719
- lines.push("## \u5951\u7D04\u2192Spec");
2790
+ lines.push("### Contract \u2192 Spec");
2720
2791
  lines.push("");
2721
2792
  const contractToSpecs = data.traceability.contracts.idToSpecs;
2722
2793
  const contractIds = Object.keys(contractToSpecs).sort(
@@ -2735,7 +2806,7 @@ function formatReportMarkdown(data) {
2735
2806
  }
2736
2807
  }
2737
2808
  lines.push("");
2738
- lines.push("## Spec\u2192\u5951\u7D04");
2809
+ lines.push("### Spec \u2192 Contracts");
2739
2810
  lines.push("");
2740
2811
  const specToContracts = data.traceability.specs.specToContracts;
2741
2812
  const specIds = Object.keys(specToContracts).sort(
@@ -2753,7 +2824,7 @@ function formatReportMarkdown(data) {
2753
2824
  lines.push(...formatMarkdownTable(["Spec", "Status", "Contracts"], rows));
2754
2825
  }
2755
2826
  lines.push("");
2756
- lines.push("## Spec\u3067 contract-ref \u672A\u5BA3\u8A00");
2827
+ lines.push("### Specs missing contract-ref");
2757
2828
  lines.push("");
2758
2829
  const missingRefSpecs = data.traceability.specs.missingRefSpecs;
2759
2830
  if (missingRefSpecs.length === 0) {
@@ -2764,7 +2835,7 @@ function formatReportMarkdown(data) {
2764
2835
  }
2765
2836
  }
2766
2837
  lines.push("");
2767
- lines.push("## SC\u30AB\u30D0\u30EC\u30C3\u30B8");
2838
+ lines.push("### SC coverage");
2768
2839
  lines.push("");
2769
2840
  lines.push(`- total: ${data.traceability.sc.total}`);
2770
2841
  lines.push(`- covered: ${data.traceability.sc.covered}`);
@@ -2794,7 +2865,7 @@ function formatReportMarkdown(data) {
2794
2865
  lines.push(`- missingIds: ${missingWithSources.join(", ")}`);
2795
2866
  }
2796
2867
  lines.push("");
2797
- lines.push("## SC\u2192\u53C2\u7167\u30C6\u30B9\u30C8");
2868
+ lines.push("### SC \u2192 referenced tests");
2798
2869
  lines.push("");
2799
2870
  const scRefs = data.traceability.sc.refs;
2800
2871
  const scIds = Object.keys(scRefs).sort((a, b) => a.localeCompare(b));
@@ -2811,7 +2882,7 @@ function formatReportMarkdown(data) {
2811
2882
  }
2812
2883
  }
2813
2884
  lines.push("");
2814
- lines.push("## Spec:SC=1:1 \u9055\u53CD");
2885
+ lines.push("### Spec:SC=1:1 violations");
2815
2886
  lines.push("");
2816
2887
  const specScIssues = data.issues.filter(
2817
2888
  (item) => item.code === "QFAI-TRACE-012"
@@ -2826,7 +2897,7 @@ function formatReportMarkdown(data) {
2826
2897
  }
2827
2898
  }
2828
2899
  lines.push("");
2829
- lines.push("## Hotspots");
2900
+ lines.push("### Hotspots");
2830
2901
  lines.push("");
2831
2902
  const hotspots = buildHotspots(data.issues);
2832
2903
  if (hotspots.length === 0) {
@@ -2839,35 +2910,28 @@ function formatReportMarkdown(data) {
2839
2910
  }
2840
2911
  }
2841
2912
  lines.push("");
2842
- lines.push("## \u30C8\u30EC\u30FC\u30B5\u30D3\u30EA\u30C6\u30A3\uFF08\u691C\u8A3C\uFF09");
2913
+ lines.push("## Guidance");
2843
2914
  lines.push("");
2844
- const traceIssues = data.issues.filter(
2845
- (item) => item.rule?.startsWith("traceability.") || item.code.startsWith("QFAI_TRACE") || item.code.startsWith("QFAI-TRACE-")
2915
+ lines.push(
2916
+ "- \u6B21\u306E\u624B\u9806: `qfai doctor --fail-on error` \u2192 `qfai validate --fail-on error` \u2192 `qfai report`"
2846
2917
  );
2847
- if (traceIssues.length === 0) {
2848
- lines.push("- (none)");
2849
- } else {
2850
- for (const item of traceIssues) {
2851
- const location = item.file ? ` (${item.file})` : "";
2852
- lines.push(
2853
- `- ${item.severity.toUpperCase()} [${item.code}] ${item.message}${location}`
2854
- );
2855
- }
2856
- }
2857
- lines.push("");
2858
- lines.push("## \u691C\u8A3C\u7D50\u679C");
2859
- lines.push("");
2860
- if (data.issues.length === 0) {
2861
- lines.push("- (none)");
2918
+ if (data.summary.counts.error > 0) {
2919
+ lines.push("- error \u304C\u3042\u308B\u305F\u3081\u3001\u307E\u305A error \u304B\u3089\u4FEE\u6B63\u3057\u3066\u304F\u3060\u3055\u3044\u3002");
2920
+ } else if (data.summary.counts.warning > 0) {
2921
+ lines.push(
2922
+ "- warning \u306E\u6271\u3044\uFF08Hard Gate \u306B\u3059\u308B\u304B\uFF09\u306F\u904B\u7528\u3067\u6C7A\u3081\u3066\u304F\u3060\u3055\u3044\u3002"
2923
+ );
2862
2924
  } else {
2863
- for (const item of data.issues) {
2864
- const location = item.file ? ` (${item.file})` : "";
2865
- const refs = item.refs && item.refs.length > 0 ? ` refs=${item.refs.join(",")}` : "";
2866
- lines.push(
2867
- `- ${item.severity.toUpperCase()} [${item.code}] ${item.message}${location}${refs}`
2868
- );
2869
- }
2925
+ lines.push(
2926
+ "- issue \u306F\u691C\u51FA\u3055\u308C\u307E\u305B\u3093\u3067\u3057\u305F\u3002\u904B\u7528\u30C6\u30F3\u30D7\u30EC\u306B\u6CBF\u3063\u3066\u7D99\u7D9A\u3057\u3066\u304F\u3060\u3055\u3044\u3002"
2927
+ );
2870
2928
  }
2929
+ lines.push(
2930
+ "- \u5909\u66F4\u533A\u5206\uFF08Compatibility / Change/Improvement\uFF09\u306F `.qfai/specs/*/delta.md` \u306B\u8A18\u9332\u3057\u307E\u3059\u3002"
2931
+ );
2932
+ lines.push(
2933
+ "- \u53C2\u7167\u30EB\u30FC\u30EB\u306E\u6B63\u672C: `.qfai/promptpack/steering/traceability.md` / `.qfai/promptpack/steering/compatibility-vs-change.md`"
2934
+ );
2871
2935
  return lines.join("\n");
2872
2936
  }
2873
2937
  function formatReportJson(data) {