delivery-friction-analyzer 0.2.1 → 0.2.3

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/README.md CHANGED
@@ -1,38 +1,30 @@
1
1
  # Delivery Friction Analyzer
2
2
 
3
- Delivery Friction Analyzer is a product concept for measuring where AI-assisted software delivery still wastes time: review loops, CI churn, scope drift, missing validation, and repeated corrective work after a pull request opens.
3
+ Delivery Friction Analyzer is a local CLI for GitHub pull request analytics. It samples merged PRs from a repository and writes delivery-friction reports that show where work slowed down: review loops, CI churn, scope spread, validation gaps, planning signals, and repeated corrective work.
4
4
 
5
- The core idea is to use GitHub data as the first durable signal. Pull request diffs, review comments by source, check runs, commits, change scope, file roles, and merge timelines can reveal which repositories, modules, and workflow stages create the most back-and-forth before work becomes mergeable.
5
+ Use it when you want to answer questions like:
6
6
 
7
- ## Product Direction
8
-
9
- Delivery Friction Analyzer is currently a local, GitHub-connected analyzer that produces repository-level friction reports from live pull request data. It is repo-source-agnostic: repository-specific assumptions live in profiles, while generated artifacts preserve source evidence, coverage caveats, and interpretation limits.
10
-
11
- `hannasdev/mcp-writing` remains the first validation target and fixture source, not product-specific scope.
12
-
13
- The current product wedge is a maintainer workflow:
7
+ - Where do PRs require the most corrective loops?
8
+ - Which feedback patterns repeat across PRs?
9
+ - Which files, surfaces, or PR classes create the most back-and-forth?
10
+ - Which issues look preventable with better local checks, repo-specific AI instructions, skills, hooks, or smaller delivery slices?
14
11
 
15
- - collect the latest merged PR sample from a target repository;
16
- - classify files and PRs through repository profiles;
17
- - generate Markdown, JSON, methodology, and CSV artifacts;
18
- - explain review, validation, scope, planning, PR-size, and PR-class friction with traceable evidence;
19
- - support explicit follow-up filtering when maintainers want to inspect a configured PR population separately.
12
+ The analyzer runs locally with your GitHub credentials. Generated artifacts preserve source evidence, coverage caveats, and interpretation limits so reports can be inspected before they are shared.
20
13
 
21
- The report helps answer:
14
+ ## Requirements
22
15
 
23
- - Where do PRs require the most corrective loops?
24
- - Which feedback patterns repeat across PRs?
25
- - Which issues are preventable with better local checks, repo-specific AI instructions, skills, hooks, or smaller delivery slices?
26
- - Which changes create the largest gap between the PR opened state and the merged state?
27
- - Which changed files are part of the repository's configured product surface versus tests, docs, generated artifacts, release notes, marketing surfaces, or other support surfaces?
16
+ - Node.js 20 or newer.
17
+ - GitHub CLI (`gh`) installed and authenticated with access to the target repository.
18
+ - A repository profile JSON for the repository you want to analyze.
28
19
 
29
- The product should eventually combine GitHub delivery friction with token and model usage, but GitHub-only analytics remain the active validation surface.
20
+ For public repositories, ordinary read access is usually enough. Private repositories need a `gh` token with enough read access for the requested API families. With a classic PAT, that usually means the `repo` scope. With a fine-grained token or GitHub App, grant read permissions for repository metadata and contents, pull requests, Actions, and checks where available. Missing or partial API coverage is recorded in the generated methodology and coverage artifacts instead of being treated as complete data.
30
21
 
31
- ## Local GitHub Analysis
22
+ ## Quickstart
32
23
 
33
- Run the live analyzer with local `gh` credentials:
24
+ From this repository, install dependencies and run the analyzer against the sample validation target:
34
25
 
35
26
  ```sh
27
+ npm install
36
28
  npm run analyze:github -- \
37
29
  --repo hannasdev/mcp-writing \
38
30
  --limit 30 \
@@ -40,7 +32,7 @@ npm run analyze:github -- \
40
32
  --out reports/mcp-writing
41
33
  ```
42
34
 
43
- After installing from npm, the same analyzer is available as a CLI:
35
+ From another project or script, run the published CLI with `npx`:
44
36
 
45
37
  ```sh
46
38
  npx delivery-friction-analyzer \
@@ -50,45 +42,92 @@ npx delivery-friction-analyzer \
50
42
  --out reports/mcp-writing
51
43
  ```
52
44
 
53
- The npm CLI still expects a local repository profile JSON. Use the sample profile from this repository as a starting point, then save a copy for the repository you want to analyze.
45
+ Open `reports/mcp-writing/friction-report.md` first. It is the main human-readable report. Use the JSON and CSV files when you want to audit a finding, compare PRs, or build follow-up analysis.
54
46
 
55
- The command writes:
47
+ ## Repository Profiles
56
48
 
57
- - `source-bundle.json`
58
- - `normalized.json`
59
- - `metrics-summary.json`
60
- - `friction-report.json`
61
- - `friction-report.md`
62
- - `methodology.md`
63
- - `pr-metrics.csv`
64
- - `bottleneck-examples.csv`
65
- - `comment-sources.csv`
66
- - `collection-coverage.csv`
49
+ Every run needs a repository profile. Profiles keep repository-specific assumptions out of the analyzer code by describing how paths and pull request titles should be classified.
67
50
 
68
- Use `--dry-run` or `--metadata-only` to validate repository access, profile JSON, output directory writability, and sampled API coverage without writing full report artifacts. Use `--no-csv` when you want the Markdown, JSON, source, normalized, metrics, and methodology artifacts without spreadsheet-friendly CSV exports. Use `--exclude-pr-class <class>` to explicitly remove a configured PR class from downstream normalized, metrics, report, methodology, and CSV artifacts; `source-bundle.json` still preserves the full collected sample for auditability.
51
+ Profiles can define:
69
52
 
70
- Successful runs print a concise completion message with `friction-report.md` first, followed by the key supporting artifacts and collection coverage status. Use `--json` when automation needs the full machine-readable completion receipt on stdout.
53
+ - file categories such as code, tests, docs, generated files, infrastructure, or config;
54
+ - file roles such as core product code, release notes, fixtures, planning docs, or generated docs;
55
+ - functional surfaces such as runtime, test suite, release notes, or user docs;
56
+ - PR classes such as release, dependency, feature, or other repository-specific groups.
71
57
 
72
- Read `friction-report.md` first, then inspect `methodology.md`, the CSV exports, `friction-report.json`, and `source-bundle.json` when a bottleneck looks surprising. Each ranked bottleneck example includes the workflow-run source, workflow-run conclusions, review-thread source, comment-source breakdown, and a dominance note when one PR contributes most of the displayed signal.
58
+ Use `fixtures/github/mcp-writing/profile.json` as a starting point, then save a copy for the repository you want to analyze. The full profile format is documented in `docs/reference/repository-profile.md`, and the schema lives at `schemas/repository-profile.schema.json`.
73
59
 
74
- Ranked bottlenecks are ordered by their strongest displayed representative score, not by an opaque composite priority score. PR size columns show final/current additions, deletions, changed files, and changed lines so maintainers can compare size against review, validation, and planning signals.
60
+ ## Outputs
75
61
 
76
- ### Optional narrative drafting
62
+ A successful run writes a report bundle to the output directory:
77
63
 
78
- The generated artifacts are also enough context for an optional local workflow where a separate model drafts a narrative report. Use `friction-report.json` as the structured source of truth, `friction-report.md` as the human-readable source of truth, and the curated CSV exports only as supporting evidence when the draft needs per-PR detail.
64
+ - `friction-report.md`: the main report to read first.
65
+ - `methodology.md`: data coverage, caveats, and interpretation notes.
66
+ - `friction-report.json`: machine-readable report data.
67
+ - `metrics-summary.json`: computed metrics used by the report.
68
+ - `normalized.json`: normalized repository, PR, file, review, and validation entities.
69
+ - `source-bundle.json`: collected source data for auditability.
70
+ - `pr-metrics.csv`: per-PR metrics for spreadsheet review.
71
+ - `bottleneck-examples.csv`: representative bottleneck examples.
72
+ - `comment-sources.csv`: review-comment source breakdowns.
73
+ - `collection-coverage.csv`: API coverage diagnostics.
79
74
 
80
- When using a model this way, keep the deterministic artifacts authoritative: preserve coverage, outlier, PR-class, and analysis-filter caveats; distinguish observed evidence from inferred diagnosis and suggested action; do not invent missing data; and do not rank individuals. Review any generated prose against the Markdown, JSON, and CSV evidence before sharing it.
75
+ Each ranked bottleneck example includes source references, workflow-run conclusions, review-thread source information, comment-source breakdowns, and a dominance note when one PR contributes most of the displayed signal.
81
76
 
82
- No separate model-ready context artifact is required for this workflow. Reconsider a new artifact only if a concrete consumer needs a smaller single-file context, machine-readable prompt packaging, or fields that cannot be represented clearly by `friction-report.json` plus curated CSV evidence.
77
+ ## Common Options
78
+
79
+ Use `--dry-run` or `--metadata-only` to validate repository access, profile JSON, output directory writability, and sampled API coverage without writing full report artifacts.
80
+
81
+ Use `--no-csv` when you want the Markdown, JSON, source, normalized, metrics, and methodology artifacts without spreadsheet-friendly CSV exports.
82
+
83
+ Use `--exclude-pr-class <class>` to remove a configured PR class from downstream normalized, metrics, report, methodology, and CSV artifacts. `source-bundle.json` still preserves the full collected sample for auditability.
84
+
85
+ Use `--json` when automation needs the full machine-readable completion receipt on stdout.
86
+
87
+ ## How To Read A Report
88
+
89
+ Start with `friction-report.md`. If a bottleneck looks surprising, inspect `methodology.md`, the CSV exports, `friction-report.json`, and `source-bundle.json`.
90
+
91
+ Ranked bottlenecks are ordered by their strongest displayed representative score, not by an opaque composite priority score. PR size columns show final or current additions, deletions, changed files, and changed lines so maintainers can compare size against review, validation, and planning signals.
83
92
 
84
- Known MVP interpretation limits:
93
+ Generated artifacts may contain repository names, PR URLs, PR titles, file paths, comment metadata, curated CSV evidence, and coverage diagnostics. Treat source bundles, normalized data, metrics summaries, reports, methodology, and CSV exports as local or private unless you intentionally review and share them.
94
+
95
+ ## Interpretation Limits
96
+
97
+ Known MVP limits:
85
98
 
86
99
  - PR-open diff growth is unavailable unless an open-time snapshot or reconstruction exists; the local historical collector does not infer it from merge-time diff data.
87
100
  - Workflow runs are collected from branch-based pull-request Actions history, which can be unavailable or partial for deleted, renamed, reused, or inaccessible branches.
88
101
  - Review-thread counts depend on GraphQL review-thread coverage; unavailable thread access is reported instead of silently treated as zero review churn.
89
- - A single PR or PR class, such as release, dependency, bot-driven, or unusually broad feature work, can dominate validation or review findings. Treat PR and class dominance notes as prompts to inspect the raw evidence before generalizing; use `--exclude-pr-class` only when you intentionally want a filtered follow-up view.
102
+ - A single PR or PR class, such as release, dependency, bot-driven, or unusually broad feature work, can dominate validation or review findings. Treat PR and class dominance notes as prompts to inspect the raw evidence before generalizing.
103
+
104
+ More detail on GitHub API coverage is documented in `docs/reference/github-access-coverage.md`.
105
+
106
+ ## Optional Narrative Drafting
107
+
108
+ The generated artifacts are enough context for an optional local workflow where a separate model drafts a narrative report. Use `friction-report.json` as the structured source of truth, `friction-report.md` as the human-readable source of truth, and the curated CSV exports only as supporting evidence when the draft needs per-PR detail.
109
+
110
+ When using a model this way, keep the deterministic artifacts authoritative: preserve coverage, outlier, PR-class, and analysis-filter caveats; distinguish observed evidence from inferred diagnosis and suggested action; do not invent missing data; and do not rank individuals. Review any generated prose against the Markdown, JSON, and CSV evidence before sharing it.
111
+
112
+ No separate model-ready context artifact is required for this workflow. Reconsider a new artifact only if a concrete consumer needs a smaller single-file context, machine-readable prompt packaging, or fields that cannot be represented clearly by `friction-report.json` plus curated CSV evidence.
113
+
114
+ ## Current Direction
115
+
116
+ Delivery Friction Analyzer is currently a local, GitHub-connected analyzer that produces repository-level friction reports from live pull request data. It is repo-source-agnostic: repository-specific assumptions live in profiles.
117
+
118
+ The current product wedge is a maintainer workflow:
119
+
120
+ - collect the latest merged PR sample from a target repository;
121
+ - classify files and PRs through repository profiles;
122
+ - generate Markdown, JSON, methodology, and CSV artifacts;
123
+ - explain review, validation, scope, planning, PR-size, and PR-class friction with traceable evidence;
124
+ - support explicit follow-up filtering when maintainers want to inspect a configured PR population separately.
125
+
126
+ The product should eventually combine GitHub delivery friction with token and model usage, but GitHub-only analytics remain the active validation surface.
127
+
128
+ `hannasdev/mcp-writing` remains the first validation target and fixture source, not product-specific scope.
90
129
 
91
- Generated artifacts may contain repository names, PR URLs, PR titles, file paths, comment metadata, curated CSV evidence, and coverage diagnostics. Treat source bundles, normalized data, metrics summaries, reports, methodology, and CSV exports as local/private unless you intentionally review and share them.
130
+ ## Development Notes
92
131
 
93
132
  The existing metrics-summary-only report command remains available for fixture and advanced workflows:
94
133
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "delivery-friction-analyzer",
3
- "version": "0.2.1",
3
+ "version": "0.2.3",
4
4
  "description": "Local GitHub pull request analytics for delivery friction reports.",
5
5
  "license": "MIT",
6
6
  "type": "module",
package/release-log.md CHANGED
@@ -2,6 +2,14 @@
2
2
 
3
3
  ## Unreleased
4
4
 
5
+ ### 2026-06-15 — Review Decision Author Detection
6
+
7
+ - What changed: Review decision evidence now recognizes human approvals from live `gh pr view` review events that include only an author login.
8
+ - Why it matters: Maintainers can trust `review_decision`, `human_approved`, and `human_reviewer_count` for zero-thread PRs instead of seeing approved PRs reported as having no human review.
9
+ - Who is affected: Maintainers and contributors running or inspecting live GitHub analysis outputs.
10
+ - Action needed: Re-run affected reports to refresh the corrected review decision evidence.
11
+ - PR: https://github.com/hannasdev/delivery-friction-analyzer/pull/32
12
+
5
13
  ### 2026-06-15 — Optional Narrative Drafting Guidance
6
14
 
7
15
  - What changed: The README and friction report contract now document how to use `friction-report.json` with curated CSV evidence as sufficient context for optional downstream narrative drafting, without adding a separate model-ready artifact.
@@ -22,6 +22,15 @@ function flattenThreadComments(reviewThreads = {}) {
22
22
  ));
23
23
  }
24
24
 
25
+ function classifyReviewEventSource(author, { pullRequestAuthorLogin } = {}) {
26
+ const source = classifyCommentSource(author, { pullRequestAuthorLogin });
27
+ const login = String(author?.login ?? "").trim();
28
+ if (source !== "unknown" || !login) {
29
+ return source;
30
+ }
31
+ return "human_reviewer";
32
+ }
33
+
25
34
  function normalizeReview(review, { pullRequestAuthorLogin } = {}) {
26
35
  const author = review.author ?? {};
27
36
  return {
@@ -29,7 +38,7 @@ function normalizeReview(review, { pullRequestAuthorLogin } = {}) {
29
38
  submittedAt: review.submittedAt,
30
39
  state: review.state,
31
40
  commitOid: review.commitOid ?? review.commit?.oid ?? null,
32
- source: classifyCommentSource(author, { pullRequestAuthorLogin }),
41
+ source: classifyReviewEventSource(author, { pullRequestAuthorLogin }),
33
42
  generatedCommentCount: review.generatedCommentCount ?? null,
34
43
  failedAttempt: Boolean(review.failedAttempt),
35
44
  };
@@ -77,7 +86,7 @@ function summarizeReviewDecision(pr) {
77
86
  }
78
87
 
79
88
  const humanReviews = pr.reviews.filter(review => (
80
- classifyCommentSource(review.author, { pullRequestAuthorLogin: pr.author?.login }) === "human_reviewer"
89
+ classifyReviewEventSource(review.author, { pullRequestAuthorLogin: pr.author?.login }) === "human_reviewer"
81
90
  ));
82
91
  const humanReviewerKeys = new Set(humanReviews.map(reviewAuthorKey).filter(Boolean));
83
92
  const states = new Set(humanReviews.map(reviewState));