qfai 0.7.1 → 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.cjs CHANGED
@@ -1232,8 +1232,8 @@ var import_promises7 = require("fs/promises");
1232
1232
  var import_node_path7 = __toESM(require("path"), 1);
1233
1233
  var import_node_url = require("url");
1234
1234
  async function resolveToolVersion() {
1235
- if ("0.7.1".length > 0) {
1236
- return "0.7.1";
1235
+ if ("0.8.0".length > 0) {
1236
+ return "0.8.0";
1237
1237
  }
1238
1238
  try {
1239
1239
  const packagePath = resolvePackageJsonPath();
@@ -1604,7 +1604,7 @@ async function validateDeltas(root, config) {
1604
1604
  issues.push(
1605
1605
  issue2(
1606
1606
  "QFAI-DELTA-002",
1607
- "delta.md \u306E\u5909\u66F4\u533A\u5206\u304C\u4E0D\u8DB3\u3057\u3066\u3044\u307E\u3059\u3002",
1607
+ "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",
1608
1608
  "error",
1609
1609
  deltaPath,
1610
1610
  "delta.section"
@@ -2147,7 +2147,7 @@ async function validateTraceability(root, config) {
2147
2147
  issues.push(
2148
2148
  issue6(
2149
2149
  "QFAI-TRACE-020",
2150
- "Spec \u306B QFAI-CONTRACT-REF \u304C\u3042\u308A\u307E\u305B\u3093\u3002",
2150
+ "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`",
2151
2151
  "error",
2152
2152
  file,
2153
2153
  "traceability.specContractRefRequired"
@@ -2158,7 +2158,7 @@ async function validateTraceability(root, config) {
2158
2158
  issues.push(
2159
2159
  issue6(
2160
2160
  "QFAI-TRACE-023",
2161
- "Spec \u306E QFAI-CONTRACT-REF \u306B none \u3068\u5951\u7D04 ID \u304C\u6DF7\u5728\u3057\u3066\u3044\u307E\u3059\u3002",
2161
+ "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",
2162
2162
  "error",
2163
2163
  file,
2164
2164
  "traceability.specContractRefFormat"
@@ -2171,7 +2171,7 @@ async function validateTraceability(root, config) {
2171
2171
  "QFAI-TRACE-021",
2172
2172
  `Spec \u306E\u5951\u7D04 ID \u304C\u4E0D\u6B63\u3067\u3059: ${contractRefs.invalidTokens.join(
2173
2173
  ", "
2174
- )}`,
2174
+ )} (\u4F8B: UI-0001 / API-0001 / DB-0001)`,
2175
2175
  "error",
2176
2176
  file,
2177
2177
  "traceability.specContractRefFormat",
@@ -2211,7 +2211,7 @@ async function validateTraceability(root, config) {
2211
2211
  issues.push(
2212
2212
  issue6(
2213
2213
  "QFAI-TRACE-031",
2214
- "Scenario \u306B QFAI-CONTRACT-REF \u304C\u3042\u308A\u307E\u305B\u3093\u3002",
2214
+ "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`",
2215
2215
  "error",
2216
2216
  file,
2217
2217
  "traceability.scenarioContractRefRequired"
@@ -2222,7 +2222,7 @@ async function validateTraceability(root, config) {
2222
2222
  issues.push(
2223
2223
  issue6(
2224
2224
  "QFAI-TRACE-033",
2225
- "Scenario \u306E QFAI-CONTRACT-REF \u306B none \u3068\u5951\u7D04 ID \u304C\u6DF7\u5728\u3057\u3066\u3044\u307E\u3059\u3002",
2225
+ "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",
2226
2226
  "error",
2227
2227
  file,
2228
2228
  "traceability.scenarioContractRefFormat"
@@ -2235,7 +2235,7 @@ async function validateTraceability(root, config) {
2235
2235
  "QFAI-TRACE-032",
2236
2236
  `Scenario \u306E\u5951\u7D04 ID \u304C\u4E0D\u6B63\u3067\u3059: ${scenarioContractRefs.invalidTokens.join(
2237
2237
  ", "
2238
- )}`,
2238
+ )} (\u4F8B: UI-0001 / API-0001 / DB-0001)`,
2239
2239
  "error",
2240
2240
  file,
2241
2241
  "traceability.scenarioContractRefFormat",
@@ -2733,7 +2733,7 @@ function formatReportMarkdown(data) {
2733
2733
  lines.push(`- \u8A2D\u5B9A: ${data.configPath}`);
2734
2734
  lines.push(`- \u7248: ${data.version}`);
2735
2735
  lines.push("");
2736
- lines.push("## \u6982\u8981");
2736
+ lines.push("## Summary");
2737
2737
  lines.push("");
2738
2738
  lines.push(`- specs: ${data.summary.specs}`);
2739
2739
  lines.push(`- scenarios: ${data.summary.scenarios}`);
@@ -2743,8 +2743,79 @@ function formatReportMarkdown(data) {
2743
2743
  lines.push(
2744
2744
  `- issues: info ${data.summary.counts.info} / warning ${data.summary.counts.warning} / error ${data.summary.counts.error}`
2745
2745
  );
2746
+ lines.push(
2747
+ `- fail-on=error: ${data.summary.counts.error > 0 ? "FAIL" : "PASS"}`
2748
+ );
2749
+ lines.push(
2750
+ `- fail-on=warning: ${data.summary.counts.error + data.summary.counts.warning > 0 ? "FAIL" : "PASS"}`
2751
+ );
2746
2752
  lines.push("");
2747
- lines.push("## ID\u96C6\u8A08");
2753
+ lines.push("## Findings");
2754
+ lines.push("");
2755
+ lines.push("### Issues (by code)");
2756
+ lines.push("");
2757
+ const severityOrder = {
2758
+ error: 0,
2759
+ warning: 1,
2760
+ info: 2
2761
+ };
2762
+ const issueKeyToCount = /* @__PURE__ */ new Map();
2763
+ for (const issue7 of data.issues) {
2764
+ const key = `${issue7.severity}|${issue7.code}`;
2765
+ const current = issueKeyToCount.get(key);
2766
+ if (current) {
2767
+ current.count += 1;
2768
+ continue;
2769
+ }
2770
+ issueKeyToCount.set(key, {
2771
+ severity: issue7.severity,
2772
+ code: issue7.code,
2773
+ count: 1
2774
+ });
2775
+ }
2776
+ const issueSummaryRows = Array.from(issueKeyToCount.values()).sort((a, b) => {
2777
+ const sa = severityOrder[a.severity] ?? 999;
2778
+ const sb = severityOrder[b.severity] ?? 999;
2779
+ if (sa !== sb) return sa - sb;
2780
+ return a.code.localeCompare(b.code);
2781
+ }).map((x) => [x.severity, x.code, String(x.count)]);
2782
+ if (issueSummaryRows.length === 0) {
2783
+ lines.push("- (none)");
2784
+ } else {
2785
+ lines.push(
2786
+ ...formatMarkdownTable(["Severity", "Code", "Count"], issueSummaryRows)
2787
+ );
2788
+ }
2789
+ lines.push("");
2790
+ lines.push("### Issues (list)");
2791
+ lines.push("");
2792
+ if (data.issues.length === 0) {
2793
+ lines.push("- (none)");
2794
+ } else {
2795
+ const sortedIssues = [...data.issues].sort((a, b) => {
2796
+ const sa = severityOrder[a.severity] ?? 999;
2797
+ const sb = severityOrder[b.severity] ?? 999;
2798
+ if (sa !== sb) return sa - sb;
2799
+ const code = a.code.localeCompare(b.code);
2800
+ if (code !== 0) return code;
2801
+ const fileA = a.file ?? "";
2802
+ const fileB = b.file ?? "";
2803
+ const file = fileA.localeCompare(fileB);
2804
+ if (file !== 0) return file;
2805
+ const lineA = a.loc?.line ?? 0;
2806
+ const lineB = b.loc?.line ?? 0;
2807
+ return lineA - lineB;
2808
+ });
2809
+ for (const item of sortedIssues) {
2810
+ const location = item.file ? ` (${item.file})` : "";
2811
+ const refs = item.refs && item.refs.length > 0 ? ` refs=${item.refs.join(",")}` : "";
2812
+ lines.push(
2813
+ `- ${item.severity.toUpperCase()} [${item.code}] ${item.message}${location}${refs}`
2814
+ );
2815
+ }
2816
+ }
2817
+ lines.push("");
2818
+ lines.push("### IDs");
2748
2819
  lines.push("");
2749
2820
  lines.push(formatIdLine("SPEC", data.ids.spec));
2750
2821
  lines.push(formatIdLine("BR", data.ids.br));
@@ -2753,14 +2824,14 @@ function formatReportMarkdown(data) {
2753
2824
  lines.push(formatIdLine("API", data.ids.api));
2754
2825
  lines.push(formatIdLine("DB", data.ids.db));
2755
2826
  lines.push("");
2756
- lines.push("## \u30C8\u30EC\u30FC\u30B5\u30D3\u30EA\u30C6\u30A3");
2827
+ lines.push("### Traceability");
2757
2828
  lines.push("");
2758
2829
  lines.push(`- \u4E0A\u6D41ID\u691C\u51FA\u6570: ${data.traceability.upstreamIdsFound}`);
2759
2830
  lines.push(
2760
2831
  `- \u30B3\u30FC\u30C9/\u30C6\u30B9\u30C8\u53C2\u7167: ${data.traceability.referencedInCodeOrTests ? "\u3042\u308A" : "\u306A\u3057"}`
2761
2832
  );
2762
2833
  lines.push("");
2763
- lines.push("## \u5951\u7D04\u30AB\u30D0\u30EC\u30C3\u30B8");
2834
+ lines.push("### Contract Coverage");
2764
2835
  lines.push("");
2765
2836
  lines.push(`- total: ${data.traceability.contracts.total}`);
2766
2837
  lines.push(`- referenced: ${data.traceability.contracts.referenced}`);
@@ -2769,7 +2840,7 @@ function formatReportMarkdown(data) {
2769
2840
  `- specContractRefMissing: ${data.traceability.specs.contractRefMissing}`
2770
2841
  );
2771
2842
  lines.push("");
2772
- lines.push("## \u5951\u7D04\u2192Spec");
2843
+ lines.push("### Contract \u2192 Spec");
2773
2844
  lines.push("");
2774
2845
  const contractToSpecs = data.traceability.contracts.idToSpecs;
2775
2846
  const contractIds = Object.keys(contractToSpecs).sort(
@@ -2788,7 +2859,7 @@ function formatReportMarkdown(data) {
2788
2859
  }
2789
2860
  }
2790
2861
  lines.push("");
2791
- lines.push("## Spec\u2192\u5951\u7D04");
2862
+ lines.push("### Spec \u2192 Contracts");
2792
2863
  lines.push("");
2793
2864
  const specToContracts = data.traceability.specs.specToContracts;
2794
2865
  const specIds = Object.keys(specToContracts).sort(
@@ -2806,7 +2877,7 @@ function formatReportMarkdown(data) {
2806
2877
  lines.push(...formatMarkdownTable(["Spec", "Status", "Contracts"], rows));
2807
2878
  }
2808
2879
  lines.push("");
2809
- lines.push("## Spec\u3067 contract-ref \u672A\u5BA3\u8A00");
2880
+ lines.push("### Specs missing contract-ref");
2810
2881
  lines.push("");
2811
2882
  const missingRefSpecs = data.traceability.specs.missingRefSpecs;
2812
2883
  if (missingRefSpecs.length === 0) {
@@ -2817,7 +2888,7 @@ function formatReportMarkdown(data) {
2817
2888
  }
2818
2889
  }
2819
2890
  lines.push("");
2820
- lines.push("## SC\u30AB\u30D0\u30EC\u30C3\u30B8");
2891
+ lines.push("### SC coverage");
2821
2892
  lines.push("");
2822
2893
  lines.push(`- total: ${data.traceability.sc.total}`);
2823
2894
  lines.push(`- covered: ${data.traceability.sc.covered}`);
@@ -2847,7 +2918,7 @@ function formatReportMarkdown(data) {
2847
2918
  lines.push(`- missingIds: ${missingWithSources.join(", ")}`);
2848
2919
  }
2849
2920
  lines.push("");
2850
- lines.push("## SC\u2192\u53C2\u7167\u30C6\u30B9\u30C8");
2921
+ lines.push("### SC \u2192 referenced tests");
2851
2922
  lines.push("");
2852
2923
  const scRefs = data.traceability.sc.refs;
2853
2924
  const scIds = Object.keys(scRefs).sort((a, b) => a.localeCompare(b));
@@ -2864,7 +2935,7 @@ function formatReportMarkdown(data) {
2864
2935
  }
2865
2936
  }
2866
2937
  lines.push("");
2867
- lines.push("## Spec:SC=1:1 \u9055\u53CD");
2938
+ lines.push("### Spec:SC=1:1 violations");
2868
2939
  lines.push("");
2869
2940
  const specScIssues = data.issues.filter(
2870
2941
  (item) => item.code === "QFAI-TRACE-012"
@@ -2879,7 +2950,7 @@ function formatReportMarkdown(data) {
2879
2950
  }
2880
2951
  }
2881
2952
  lines.push("");
2882
- lines.push("## Hotspots");
2953
+ lines.push("### Hotspots");
2883
2954
  lines.push("");
2884
2955
  const hotspots = buildHotspots(data.issues);
2885
2956
  if (hotspots.length === 0) {
@@ -2892,35 +2963,28 @@ function formatReportMarkdown(data) {
2892
2963
  }
2893
2964
  }
2894
2965
  lines.push("");
2895
- lines.push("## \u30C8\u30EC\u30FC\u30B5\u30D3\u30EA\u30C6\u30A3\uFF08\u691C\u8A3C\uFF09");
2966
+ lines.push("## Guidance");
2896
2967
  lines.push("");
2897
- const traceIssues = data.issues.filter(
2898
- (item) => item.rule?.startsWith("traceability.") || item.code.startsWith("QFAI_TRACE") || item.code.startsWith("QFAI-TRACE-")
2968
+ lines.push(
2969
+ "- \u6B21\u306E\u624B\u9806: `qfai doctor --fail-on error` \u2192 `qfai validate --fail-on error` \u2192 `qfai report`"
2899
2970
  );
2900
- if (traceIssues.length === 0) {
2901
- lines.push("- (none)");
2902
- } else {
2903
- for (const item of traceIssues) {
2904
- const location = item.file ? ` (${item.file})` : "";
2905
- lines.push(
2906
- `- ${item.severity.toUpperCase()} [${item.code}] ${item.message}${location}`
2907
- );
2908
- }
2909
- }
2910
- lines.push("");
2911
- lines.push("## \u691C\u8A3C\u7D50\u679C");
2912
- lines.push("");
2913
- if (data.issues.length === 0) {
2914
- lines.push("- (none)");
2971
+ if (data.summary.counts.error > 0) {
2972
+ lines.push("- error \u304C\u3042\u308B\u305F\u3081\u3001\u307E\u305A error \u304B\u3089\u4FEE\u6B63\u3057\u3066\u304F\u3060\u3055\u3044\u3002");
2973
+ } else if (data.summary.counts.warning > 0) {
2974
+ lines.push(
2975
+ "- warning \u306E\u6271\u3044\uFF08Hard Gate \u306B\u3059\u308B\u304B\uFF09\u306F\u904B\u7528\u3067\u6C7A\u3081\u3066\u304F\u3060\u3055\u3044\u3002"
2976
+ );
2915
2977
  } else {
2916
- for (const item of data.issues) {
2917
- const location = item.file ? ` (${item.file})` : "";
2918
- const refs = item.refs && item.refs.length > 0 ? ` refs=${item.refs.join(",")}` : "";
2919
- lines.push(
2920
- `- ${item.severity.toUpperCase()} [${item.code}] ${item.message}${location}${refs}`
2921
- );
2922
- }
2978
+ lines.push(
2979
+ "- 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"
2980
+ );
2923
2981
  }
2982
+ lines.push(
2983
+ "- \u5909\u66F4\u533A\u5206\uFF08Compatibility / Change/Improvement\uFF09\u306F `.qfai/specs/*/delta.md` \u306B\u8A18\u9332\u3057\u307E\u3059\u3002"
2984
+ );
2985
+ lines.push(
2986
+ "- \u53C2\u7167\u30EB\u30FC\u30EB\u306E\u6B63\u672C: `.qfai/promptpack/steering/traceability.md` / `.qfai/promptpack/steering/compatibility-vs-change.md`"
2987
+ );
2924
2988
  return lines.join("\n");
2925
2989
  }
2926
2990
  function formatReportJson(data) {