delivery-friction-analyzer 0.22.0 → 0.22.1
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.
|
@@ -28,7 +28,7 @@ The command reads local `friction-metrics.v1` JSON and writes deterministic `fri
|
|
|
28
28
|
- `source`: optional source-bundle provenance copied into live-generated report
|
|
29
29
|
artifacts, including `kind` and a human-readable label.
|
|
30
30
|
- `targetRepository`: analyzed repository identity; live analysis sample size is encoded as `targetRepository.analysisPullRequestLimit` from collection metadata.
|
|
31
|
-
- `analysisFilter`: optional metadata for explicit filters applied before metrics computation, including excluded PR classes and before/after PR counts.
|
|
31
|
+
- `analysisFilter`: optional metadata for explicit filters applied before metrics computation, including excluded PR classes and before/after PR counts. Live dry-run completion receipts may also include requested `analysisFilter.excludedPrClasses` with null before/after counts because dry-run coverage probes do not compute filtered metrics or report artifacts.
|
|
32
32
|
- `configuredWorkflow`: optional user-configured workflow context from the repository profile. It is not observed GitHub evidence and does not change scoring, ranking, CSV exports, or PR class matching.
|
|
33
33
|
- `contributorSource`: optional sanitized contributor-source metadata from the repository profile and collection path. It records source type, path, coverage status, parsed hint count, and guardrail note. It does not include raw contributor file contents or contributor rankings.
|
|
34
34
|
- `collectionCoverage`: optional source collection coverage metadata copied into live-generated report JSON artifacts. `collectionCoverage.status` records aggregate coverage, and `collectionCoverage.sourceFamilies` lists source-family entries with `family`, `status`, `attempts`, `source`, `diagnostics`, and `downstreamImpact`. This uses the generic `source-bundle.v1` `coverage.sourceFamilies` name; legacy GitHub `apiFamilies` is not a live `friction-report.v1` field.
|
|
@@ -128,7 +128,7 @@ Full live analysis writes `methodology.md` as a hybrid artifact: stable explanat
|
|
|
128
128
|
|
|
129
129
|
The methodology artifact should stay aligned with this contract and the Markdown methodology summary, but it may be more detailed than the main report.
|
|
130
130
|
|
|
131
|
-
When PR class filtering is applied, `source-bundle.json` remains the full collected sample, while `normalized.json`, `metrics-summary.json`, `friction-report.json`, `friction-report.md`, `methodology.md`, and CSV exports describe the filtered sample. The methodology and CLI completion output must name the excluded PR classes and show the filtered PR count. If filtering excludes every collected PR, the analysis must fail without writing complete-looking empty reports.
|
|
131
|
+
When PR class filtering is applied to a full analysis, `source-bundle.json` remains the full collected sample, while `normalized.json`, `metrics-summary.json`, `friction-report.json`, `friction-report.md`, `methodology.md`, and CSV exports describe the filtered sample. The methodology and CLI completion output must name the excluded PR classes and show the filtered PR count. If filtering excludes every collected PR, the analysis must fail without writing complete-looking empty reports. Live dry-run receipts record requested PR class exclusions without a filtered count because dry-run does not build normalized metrics.
|
|
132
132
|
|
|
133
133
|
## CSV Evidence Exports
|
|
134
134
|
|
|
@@ -143,7 +143,7 @@ Minimum CSV column groups:
|
|
|
143
143
|
- `comment-sources.csv`: source name, total comments, bot/scanner classification, human/author classification, and share of all comments.
|
|
144
144
|
- `collection-coverage.csv`: source family, status, attempts, source label, diagnostics, and downstream impact.
|
|
145
145
|
|
|
146
|
-
Empty CSV cells mean unavailable or not applicable. Numeric zero should be used only for observed or computed zero counts. Count columns that depend on optional GitHub coverage should keep source or coverage labels nearby so spreadsheet readers can tell unavailable evidence apart from observed zeroes. CSVs must not include raw comment bodies, raw workflow logs, tokens, secret-bearing environment details, or individual contributor/reviewer rankings.
|
|
146
|
+
Empty CSV cells mean unavailable or not applicable. Numeric zero should be used only for observed or computed zero counts. Count columns that depend on optional GitHub or sample-bundle coverage should keep source or coverage labels nearby so spreadsheet readers can tell unavailable evidence apart from observed zeroes. `pr-metrics.csv` `review_threads` is populated when normalized review-thread source evidence is available, including synthetic sample evidence and live GraphQL review-thread evidence. CSVs must not include raw comment bodies, raw workflow logs, tokens, secret-bearing environment details, or individual contributor/reviewer rankings.
|
|
147
147
|
|
|
148
148
|
Contributor-source coverage appears in `collection-coverage.csv` as the `contributor_source` source family when configured. CSVs may include aggregate comment-source counts influenced by contributor hints, but they must not include raw `.all-contributorsrc` contents, contributor names, contributor login lists, or person rankings.
|
|
149
149
|
|
package/package.json
CHANGED
package/release-log.md
CHANGED
|
@@ -2,6 +2,14 @@
|
|
|
2
2
|
|
|
3
3
|
## Unreleased
|
|
4
4
|
|
|
5
|
+
### 2026-06-28 — CLI Artifact Truthfulness
|
|
6
|
+
|
|
7
|
+
- What changed: Live dry-run JSON receipts now show requested PR-class exclusions without implying filtered metrics were computed, and `pr-metrics.csv` fills `review_threads` when sample or live review-thread evidence is available.
|
|
8
|
+
- Why it matters: Maintainers and scripts can trust completion receipts and CSV evidence to reflect accepted filters and available review-thread counts.
|
|
9
|
+
- Who is affected: Maintainers and users reading JSON completion receipts, CSV exports, and contract docs from sample or live GitHub analysis.
|
|
10
|
+
- Action needed: None.
|
|
11
|
+
- PR: https://github.com/hannasdev/delivery-friction-analyzer/pull/68
|
|
12
|
+
|
|
5
13
|
### 2026-06-28 — CLI Command Help Clarity
|
|
6
14
|
|
|
7
15
|
- What changed: CLI help now separates the bundled sample, live GitHub analysis, live coverage probes, output controls, interactive setup, and reusable live-run presets, with mode-specific help for `--source sample --help` and `--source github --help`.
|
|
@@ -1695,6 +1695,15 @@ function summarizeResult({ dryRun, outDir, paths, sourceBundle, metrics, report,
|
|
|
1695
1695
|
return summary;
|
|
1696
1696
|
}
|
|
1697
1697
|
|
|
1698
|
+
function requestedAnalysisFilter(excludedPrClasses = []) {
|
|
1699
|
+
if (!excludedPrClasses.length) return null;
|
|
1700
|
+
return {
|
|
1701
|
+
excludedPrClasses,
|
|
1702
|
+
originalPullRequests: null,
|
|
1703
|
+
filteredPullRequests: null,
|
|
1704
|
+
};
|
|
1705
|
+
}
|
|
1706
|
+
|
|
1698
1707
|
function applyPrClassFilter(normalized, excludedPrClasses = []) {
|
|
1699
1708
|
if (!excludedPrClasses.length) return normalized;
|
|
1700
1709
|
const excluded = new Set(excludedPrClasses);
|
|
@@ -1824,7 +1833,7 @@ export async function runAnalyzeGithub(options, {
|
|
|
1824
1833
|
requestedLimit: options.limit,
|
|
1825
1834
|
sampledLimit: collectionLimit,
|
|
1826
1835
|
csv: false,
|
|
1827
|
-
analysisFilter:
|
|
1836
|
+
analysisFilter: requestedAnalysisFilter(options.excludedPrClasses ?? []),
|
|
1828
1837
|
savedProfilePath: options.savedProfilePath,
|
|
1829
1838
|
savedRunPresetPath: options.savedRunPresetPath,
|
|
1830
1839
|
prClassRulesWritten: options.prClassRulesWritten,
|
|
@@ -1988,10 +1997,13 @@ export function formatAnalyzeGithubCompletion(result) {
|
|
|
1988
1997
|
}
|
|
1989
1998
|
|
|
1990
1999
|
if (result.analysisFilter?.excludedPrClasses?.length) {
|
|
1991
|
-
lines.push(
|
|
1992
|
-
|
|
1993
|
-
|
|
1994
|
-
|
|
2000
|
+
lines.push(`Analysis filter: excluded PR class(es): ${result.analysisFilter.excludedPrClasses.join(", ")}.`);
|
|
2001
|
+
if (Number.isInteger(result.analysisFilter.filteredPullRequests)
|
|
2002
|
+
&& Number.isInteger(result.analysisFilter.originalPullRequests)) {
|
|
2003
|
+
lines.push(`Filtered sample: ${result.analysisFilter.filteredPullRequests} of ${result.analysisFilter.originalPullRequests} collected pull request(s).`);
|
|
2004
|
+
} else if (result.dryRun) {
|
|
2005
|
+
lines.push("Filter application: requested only; dry-run coverage probes do not compute filtered metrics or report artifacts.");
|
|
2006
|
+
}
|
|
1995
2007
|
}
|
|
1996
2008
|
|
|
1997
2009
|
if (result.savedProfilePath) {
|
|
@@ -94,9 +94,12 @@ function hasObservedWorkflowRuns(workflowRuns = {}) {
|
|
|
94
94
|
return (workflowRuns.coverage ?? workflowRuns.workflowRunCoverage) === "observed";
|
|
95
95
|
}
|
|
96
96
|
|
|
97
|
-
function hasObservedReviewThreads(reviewThreads = {}) {
|
|
97
|
+
function hasObservedReviewThreads(reviewThreads = {}, coverage = {}) {
|
|
98
98
|
const source = reviewThreads.source ?? reviewThreads.reviewThreadSource ?? "unavailable";
|
|
99
|
-
|
|
99
|
+
if (String(source).startsWith("graphql")) return true;
|
|
100
|
+
if (String(source).startsWith("not_sampled") || source === "unavailable") return false;
|
|
101
|
+
if (String(source).includes("review_threads")) return true;
|
|
102
|
+
return coverage.status === "available";
|
|
100
103
|
}
|
|
101
104
|
|
|
102
105
|
function hasObservedReviewDecision(reviewDecision = {}) {
|
|
@@ -135,7 +138,7 @@ function prMetricsCsv(metricsSummary, analysisFilter) {
|
|
|
135
138
|
...SCORE_COLUMNS.map(([header]) => header),
|
|
136
139
|
];
|
|
137
140
|
const rows = sortedPullRequests(metricsSummary).map(pr => {
|
|
138
|
-
const observedReviewThreads = hasObservedReviewThreads(pr.review?.threads);
|
|
141
|
+
const observedReviewThreads = hasObservedReviewThreads(pr.review?.threads, pr.coverage?.reviewThreads);
|
|
139
142
|
const observedReviewDecision = hasObservedReviewDecision(pr.review?.decision);
|
|
140
143
|
const observedWorkflowRuns = hasObservedWorkflowRuns(pr.ci?.workflowRuns);
|
|
141
144
|
const row = {
|