delivery-friction-analyzer 0.1.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Hanna Rosengren
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,91 @@
1
+ # Delivery Friction Analyzer
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.
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, changed-file spread, file roles, and merge timelines can reveal which repositories, modules, and workflow stages create the most back-and-forth before work becomes mergeable.
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:
14
+
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.
20
+
21
+ The report helps answer:
22
+
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?
28
+
29
+ The product should eventually combine GitHub delivery friction with token and model usage, but GitHub-only analytics remain the active validation surface.
30
+
31
+ ## Local GitHub Analysis
32
+
33
+ Run the live analyzer with local `gh` credentials:
34
+
35
+ ```sh
36
+ npm run analyze:github -- \
37
+ --repo hannasdev/mcp-writing \
38
+ --limit 30 \
39
+ --profile fixtures/github/mcp-writing/profile.json \
40
+ --out reports/mcp-writing
41
+ ```
42
+
43
+ After installing from npm, the same analyzer is available as a CLI:
44
+
45
+ ```sh
46
+ npx delivery-friction-analyzer \
47
+ --repo hannasdev/mcp-writing \
48
+ --limit 30 \
49
+ --profile path/to/repository-profile.json \
50
+ --out reports/mcp-writing
51
+ ```
52
+
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.
54
+
55
+ The command writes:
56
+
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`
67
+
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.
69
+
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.
71
+
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.
73
+
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.
75
+
76
+ Known MVP interpretation limits:
77
+
78
+ - 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.
79
+ - Workflow runs are collected from branch-based pull-request Actions history, which can be unavailable or partial for deleted, renamed, reused, or inaccessible branches.
80
+ - Review-thread counts depend on GraphQL review-thread coverage; unavailable thread access is reported instead of silently treated as zero review churn.
81
+ - 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.
82
+
83
+ 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.
84
+
85
+ The existing metrics-summary-only report command remains available for fixture and advanced workflows:
86
+
87
+ ```sh
88
+ npm run report:fixture
89
+ ```
90
+
91
+ Maintainer release automation is documented in `docs/reference/release-automation.md`.
@@ -0,0 +1,52 @@
1
+ # Friction Metrics Contract
2
+
3
+ Milestone 2 introduces `friction-metrics.v1`, a deterministic metrics summary computed from normalized fixture data. The metrics layer does not fetch GitHub data and does not generate the final human-facing report.
4
+
5
+ ## Summary Shape
6
+
7
+ - `metricVersion`: formula version for every repository and PR summary.
8
+ - `targetRepository`: normalized target repository input.
9
+ - `analysisFilter`: optional metadata for explicit analysis filters, such as excluded PR classes and before/after PR counts.
10
+ - `totals`: repository-level counts for pull requests, changed lines, non-generated changed lines, review comments, review threads, failed checks, and cancelled workflow runs.
11
+ - `rankings`: PR rankings by review churn, changed-file spread, validation gap, planning gap, review surprise, and fix amplification.
12
+ - `pullRequests`: per-PR metrics with PR class evidence, diff, file spread, review comments, review-thread churn, review decision evidence, CI, lifecycle, iteration, coverage, and transparent component metrics.
13
+
14
+ ## Component Metrics
15
+
16
+ Every score-like component exposes `formulaVersion`, `value`, and `inputs`.
17
+
18
+ - `commentSourceDensity`: comment counts and per-100-changed-line density by source.
19
+ - `functionalSurfaceDensity`: functional surface count and changed lines by surface.
20
+ - `iterationDrag`: commits after first review, review threads, and failed review attempts.
21
+ - `diffGrowthRatio`: PR-open to merge growth when PR-open diff data is direct or reconstructed; otherwise unavailable.
22
+ - `changedFileSpread`: core file count plus directory and functional-surface spread.
23
+ - `validationGapScore`: failed check runs, failed workflow runs, and cancelled workflow runs.
24
+ - `planningGapScore`: deterministic signal from repository-profile planning-doc changes.
25
+ - `reviewSurpriseScore`: deterministic functional-surface spread signal without title/body NLP.
26
+ - `fixAmplification`: commits after first review plus explicit diff-growth availability.
27
+
28
+ ## Classification And Coverage
29
+
30
+ Observed GitHub data remains separate from inferred or configured classifications:
31
+
32
+ - file paths and changed lines come from normalized GitHub payloads;
33
+ - file categories, roles, functional surfaces, and generated flags come from repository profile or fallback rules;
34
+ - PR class, PR class source, and PR class rule ID come from repository profile rules or fallback rules;
35
+ - `files.classificationSources` counts the classification source used by each changed file;
36
+ - PR-open diff growth and workflow-run metrics carry coverage status when source data is unavailable;
37
+ - review decision evidence carries the normalized review-event source label so clean human approval can be distinguished from unavailable review evidence and from observed absence of human review.
38
+
39
+ Generated or low-signal roles are not hidden. They are counted separately, excluded from core file metrics, and down-weighted in `weightedChangedLines`.
40
+
41
+ When an explicit PR class filter is applied, metrics are computed from the filtered normalized PR set. Rankings, totals, and CSV evidence should describe that filtered sample, while `analysisFilter` records the excluded classes and the original collected count for auditability.
42
+
43
+ ## Formula Constants
44
+
45
+ `friction-metrics.v1` exposes formula constants in code and in metric output where they affect file-spread calculations:
46
+
47
+ - Low-signal roles use `lowSignalRoleWeight: 0.25` in `weightedChangedLines`.
48
+ - Generated files and `generated_or_vendored` files contribute `0` to `weightedChangedLines`.
49
+ - `smallDiffWideSpread` is true when non-generated core files have `coreChangedLines > 0`, `coreChangedLines <= 600`, and `coreFiles >= 3`.
50
+ - Core roles for spread calculations are `core_product_code` and `product_ui`.
51
+
52
+ Validation gap metrics treat GitHub check-run failures and workflow interruptions separately. Failure-like check conclusions include `failure`, `failed`, `timed_failure`, `startup_failure`, `action_required`, `timed_out`, `stale`, `error`, `cancelled`, and `canceled`. Workflow-run `cancelled` / `canceled` conclusions are counted as cancelled workflow runs rather than double-counted as failed workflow runs.
@@ -0,0 +1,131 @@
1
+ # Friction Report Contract
2
+
3
+ Milestone 3 introduces `friction-report.v1`, a deterministic report generated from a `friction-metrics.v1` repository metrics summary. The report layer does not fetch GitHub data, mutate repositories, rank individuals, or depend on services beyond the data collection path that produced the metrics summary.
4
+
5
+ ## Outputs
6
+
7
+ - JSON report artifacts for contract tests and future UI work.
8
+ - Markdown report artifacts for maintainer review.
9
+ - A detailed `methodology.md` artifact for full live analysis runs.
10
+ - Curated CSV evidence exports for full live analysis runs unless `--no-csv` is passed:
11
+ - `pr-metrics.csv`
12
+ - `bottleneck-examples.csv`
13
+ - `comment-sources.csv`
14
+ - `collection-coverage.csv`
15
+
16
+ Local artifact generation is available from an existing metrics summary:
17
+
18
+ ```sh
19
+ node src/report/generate-report.js --metrics-summary fixtures/github/mcp-writing/metrics-summary.golden.json --json-out fixtures/github/mcp-writing/reports/friction-report.golden.json --markdown-out fixtures/github/mcp-writing/reports/friction-report.golden.md
20
+ ```
21
+
22
+ The command reads local `friction-metrics.v1` JSON and writes deterministic `friction-report.v1` JSON and Markdown files. It does not fetch GitHub data, mutate the analyzed repository, or write CSV/methodology companion artifacts.
23
+
24
+ ## Report Shape
25
+
26
+ - `reportVersion`: report contract version.
27
+ - `metricVersion`: source metrics contract version.
28
+ - `targetRepository`: analyzed repository identity; live analysis sample size is encoded as `targetRepository.analysisPullRequestLimit` from collection metadata.
29
+ - `analysisFilter`: optional metadata for explicit filters applied before metrics computation, including excluded PR classes and before/after PR counts.
30
+ - `summary`: repository totals and top bottleneck identifiers.
31
+ - `coverage`: PR-open diff, workflow-run, and review-thread coverage counts plus caveats.
32
+ - `commentSources`: total and source-grouped review comments for Copilot, human, bot, scanner, author replies, and unknown sources.
33
+ - `surfaces`: core, low-signal, generated, support-surface, role, and functional-surface breakdowns.
34
+ - `prClasses`: PR class distribution for the analyzed sample, including PR counts, changed lines, share of PRs, and classification source counts by class.
35
+ - `bottlenecks`: ranked friction patterns with observed data, inferred diagnosis, and suggested action kept as separate fields.
36
+ - `bottlenecks[].observedData[]`: representative PR examples with PR identity, score/value, PR class evidence, final/current additions, deletions, changed-file count, and changed-line count.
37
+ - `bottlenecks[].observedData[].validationEvidence`: workflow-run source label, workflow-run coverage, workflow-run conclusions, failed check-run count, failed workflow-run count, and cancelled workflow-run count for representative PR examples.
38
+ - `bottlenecks[].observedData[].reviewEvidence`: review-thread source label, thread counts, resolution/outdated counts, review decision label/source, human reviewer count, human approval / changes-requested booleans, comment-source breakdown, bot comment count, human reviewer comment count, and author reply count for representative PR examples.
39
+ - `bottlenecks[].dominance`: whether the displayed examples are dominated by a single PR, including the top PR number, share of displayed signal, and a human-readable interpretation note.
40
+ - `bottlenecks[].classDominance`: whether the displayed examples are dominated by one PR class, including the dominant class, share, contribution basis, sample count, and a caveated interpretation note.
41
+ - `sharedSignals`: report-layer interpretation groups for displayed bottlenecks that share a ranking key or the same representative PR evidence. These groups do not change bottleneck scores, ranking, or recommendation categories.
42
+ - `sensitivity`: optional robustness summaries for displayed bottlenecks dominated by one PR. Each summary names the excluded PR, affected bottlenecks, baseline top bottlenecks, top bottlenecks without that PR, and an interpretation note.
43
+ - `recommendationCategories`: supported recommendation categories and how many bottlenecks triggered each one.
44
+ - `guardrails`: machine-readable checks that the report avoids individual ranking, separates evidence from inference, and does not use an opaque composite score.
45
+ - `followUp`: non-automated future work suggested by the report.
46
+
47
+ Bottlenecks are ordered by their strongest observed representative metric value, with stable category order used only to break ties. Final/current PR size fields are context for comparing size against friction signals; they only affect ordering for metric families that explicitly measure changed-file spread.
48
+
49
+ ## Markdown Output
50
+
51
+ The Markdown renderer presents the same report data for human review:
52
+
53
+ - executive summary totals in a table;
54
+ - explicit analysis filter labels when downstream artifacts were generated from a filtered PR class sample;
55
+ - a short "How To Read This Report" guide that distinguishes observed evidence, interpretation, recommendations, and caveats;
56
+ - evidence-quality and coverage tables before detailed recommendations;
57
+ - key findings that highlight top bottlenecks, strongest displayed signal, outlier caveats, PR class caveats, and coverage caveats;
58
+ - a PR class context table that shows analyzed PR counts, changed lines, sample share, and classification sources by class;
59
+ - a top-level shared-signal interpretation callout when multiple displayed bottlenecks share a ranking key or representative PR evidence;
60
+ - outlier and sensitivity analysis when displayed examples are dominated by one PR;
61
+ - a prioritization explanation that describes strongest-signal ordering and how PR size is used as context;
62
+ - ranked bottlenecks with representative PR examples rendered as compact PR-size tables;
63
+ - validation, review, and source-label evidence for each representative PR example rendered as plain Markdown detail lists;
64
+ - separately labeled inferred diagnosis, suggested action, and confidence/caveat blocks for each bottleneck;
65
+ - shared-evidence notes when multiple recommendation categories use the same representative PR set;
66
+ - recommendation-category, comment-source, and core/support-surface tables;
67
+ - a concise methodology summary;
68
+ - a reference to the detailed `methodology.md` artifact generated by full live analysis;
69
+ - guardrails, follow-up, and artifact-sensitivity guidance.
70
+
71
+ Markdown output should not include individual contributor or reviewer rankings.
72
+
73
+ ## Recommendation Boundaries
74
+
75
+ Recommendations are inferred from transparent component metrics and representative PR examples. They suggest workflow interventions such as readiness gates, preflight scripts, smaller milestones, planning artifacts, or scope control. They do not automate repository changes.
76
+
77
+ The M3 report contract supports these recommendation categories:
78
+
79
+ - hooks;
80
+ - preflight scripts;
81
+ - repo-specific AI skills or instructions;
82
+ - PR readiness gates;
83
+ - smaller milestones;
84
+ - planning artifacts;
85
+ - test infrastructure.
86
+
87
+ ## Coverage And Confidence
88
+
89
+ Reports must label unavailable or partial GitHub data instead of inferring unavailable values from merge-time data. PR-open diff growth remains unavailable unless direct or reconstructed counts exist. Workflow coverage and review-thread sources are summarized separately.
90
+
91
+ Representative examples should carry enough source evidence to trace a report claim back to generated artifacts. Validation examples should name the workflow-run source and conclusions. Review churn examples should name the review-thread source, review decision evidence, and comment sources. PR class evidence should be visible in representative bottleneck examples so readers can distinguish workflow populations such as release, dependency, development, or repository-specific classes. When `reviewThreads` is zero, review decision evidence should make clean human approval distinguishable from unavailable review evidence and from observed absence of human review. When displayed examples are dominated by one PR or one PR class, the report should say so instead of implying a repository-wide pattern from an outlier or workflow population.
92
+
93
+ Shared-signal groups are interpretation support only. The report may group bottlenecks by the metric ranking key they use or by identical displayed representative PR sets, but it must still preserve each bottleneck and its recommendation category so readers can distinguish one underlying signal from different possible actions.
94
+
95
+ PR class context and dominance notes are interpretation support only. They must preserve baseline ranking, avoid automatic filtering, and caveat class dominance for small class sample sizes.
96
+
97
+ Sensitivity summaries are robustness context only. They must preserve the baseline ranking, avoid implying that the analyzer discarded inconvenient data, and label excluded-PR summaries as "without this PR" comparisons rather than replacement truth.
98
+
99
+ ## Methodology Artifact
100
+
101
+ Full live analysis writes `methodology.md` as a hybrid artifact: stable explanatory text plus run-specific facts. It should include:
102
+
103
+ - target repository and report/metric versions;
104
+ - profile path when available;
105
+ - requested and collected PR counts;
106
+ - collection coverage status and API-family diagnostics;
107
+ - scoring, ranking, dominance, sensitivity, and limitation explanations;
108
+ - generated artifact names and artifact-sensitivity guidance.
109
+
110
+ The methodology artifact should stay aligned with this contract and the Markdown methodology summary, but it may be more detailed than the main report.
111
+
112
+ 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.
113
+
114
+ ## CSV Evidence Exports
115
+
116
+ Full live analysis writes curated CSV exports by default. `--no-csv` suppresses CSV generation while preserving Markdown, JSON, source bundle, normalized data, metrics summary, and methodology artifacts.
117
+
118
+ CSV exports are supporting evidence trails, not replacements for JSON artifacts. They should be deterministic, properly escaped, mitigate formula-like text cells for spreadsheet inspection, and avoid raw comments or logs.
119
+
120
+ Minimum CSV column groups:
121
+
122
+ - `pr-metrics.csv`: PR number, title, URL, PR class, PR class source/rule evidence, changed lines, non-generated changed lines, review comments, review threads, review decision, human reviewer count, human approval / changes-requested booleans, failed checks, failed workflow runs, cancelled workflow runs, post-review commits, review-thread source, workflow-run source/coverage, and main ranking scores.
123
+ - `bottleneck-examples.csv`: bottleneck identity, recommendation category, PR identity, score/value, changed lines, validation counts, review counts, comment-source counts, workflow/review source and coverage labels, dominance, and source labels.
124
+ - `comment-sources.csv`: source name, total comments, bot/scanner classification, human/author classification, and share of all comments.
125
+ - `collection-coverage.csv`: API family, status, attempts, source label, diagnostics, and downstream impact.
126
+
127
+ 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.
128
+
129
+ ## Guardrails
130
+
131
+ Reports present repository-level patterns, representative PR examples, and file surface evidence. They must keep observed data, inferred diagnosis, and suggested action distinct, and they must not rank contributors or reviewers.
@@ -0,0 +1,39 @@
1
+ # Normalized Entity Contract
2
+
3
+ Schema: `schemas/normalized-entities.schema.json`.
4
+
5
+ Milestone 1 defines the first normalized fixture shape. It is intentionally limited to source inventory and classification transparency, not friction scoring.
6
+
7
+ ## Entities
8
+
9
+ - `TargetRepository`: owner/name/default branch/visibility/window for the repository being analyzed.
10
+ - `AnalysisFilter`: optional metadata for downstream analysis filters applied after collection and normalization. When present, it records excluded PR classes, the original collected PR count, and the filtered PR count.
11
+ - `RepositoryLanguageDistribution`: byte counts from `GET /repos/{owner}/{repo}/languages`, stored as context only.
12
+ - `PullRequest`: source IDs, author login when known, URL, state, PR class evidence, lifecycle timestamps, final diff shape, PR-open diff source confidence, optional PR-open additions/deletions/changed-file counts when direct or reconstructed data is available, files, reviews, review decision summary, review threads, comments, checks, and workflow-run coverage.
13
+ - `PrClassSummary`: profile-driven PR class, classification source, and winning rule ID. Unmatched PRs use `class: "unknown"`, `classificationSource: "fallback_rule"`, and `ruleId: null`.
14
+ - `Commit`: commit OID, authored timestamp, committed timestamp when present, and message headline.
15
+ - `ChangedFile`: path, additions, deletions, change type, category, role, functional surface, generated flag, and classification source.
16
+ - `Review`: review attempt with author source, submitted timestamp, commit OID, generated comment count when known, and failed-attempt marker.
17
+ - `ReviewDecisionSummary`: coarse human review state derived from observed review events, with human approval / changes-requested booleans, unique human reviewer count, and source label. `none` means review events were collected and no human review events were observed; `unavailable` means review-event coverage cannot support an absence claim.
18
+ - `ReviewThread`: GraphQL thread count, resolved count, outdated count, and source coverage.
19
+ - `ReviewCommentSummary`: source-grouped comment counts, separating PR-author replies from human reviewer feedback when author context is available.
20
+ - `CheckRun`: final check/status rollup entries.
21
+ - `WorkflowRunSummary`: pull-request workflow-run coverage by conclusion when branch history is available.
22
+
23
+ ## Source Labels
24
+
25
+ Normalized data must preserve whether a value came from a public API, GraphQL thread query, repository profile rule, fallback rule, internal UI partial, or unavailable coverage. Later metric and report stages should use those source labels before making confidence claims.
26
+
27
+ ## Analysis Filters
28
+
29
+ `source-bundle.json` remains the full collected sample. When a local analysis excludes one or more PR classes, `normalized.json` contains the filtered PR set and an `analysisFilter` object:
30
+
31
+ - `excludedPrClasses`: class names explicitly excluded by the user;
32
+ - `originalPullRequests`: collected PR count before filtering;
33
+ - `filteredPullRequests`: PR count after filtering.
34
+
35
+ Filtering must be explicit and must fail rather than writing complete-looking empty artifacts when every collected PR is excluded.
36
+
37
+ ## PR-Open Diff Counts
38
+
39
+ `prOpenDiff` always records `source` and `confidence`. When `source` is `direct` or `reconstructed`, normalized data may also include non-negative `additions`, `deletions`, and `changedFiles` counts so the metrics engine can compute open-to-merge diff growth. When those counts are missing or the source is `snapshot_only` / `unavailable`, diff-growth metrics must remain explicitly unavailable rather than inferred from merge-time data.
@@ -0,0 +1,24 @@
1
+ # Target Repository Input Contract
2
+
3
+ The product repository is where the analyzer runs. The target repository is the repository being analyzed. They must be modeled separately so the analyzer does not accidentally treat its own repository history as validation data.
4
+
5
+ ## Input And Selection
6
+
7
+ The local analyzer accepts a target repository and a pull request sample size. Target repository identity and sample selection are separate concepts:
8
+
9
+ - `owner`: GitHub owner or organization.
10
+ - `name`: GitHub repository name.
11
+ - `defaultBranch`: expected default branch for merge-base and branch lookup context.
12
+ - `visibility`: `public`, `private`, or `unknown`.
13
+ - `analysisPullRequestLimit`: latest merged pull request count from 1 to 100, supplied by the live CLI as `--limit`.
14
+ - `isValidationTarget`: optional flag for fixture-source repositories such as `hannasdev/mcp-writing`.
15
+
16
+ Schema: `schemas/target-repository.schema.json`. Live analysis selection is latest-N merged pull requests, not a rolling day window.
17
+
18
+ ## Product Repository Separation
19
+
20
+ The validator rejects a target repository that exactly matches the configured product repository. For this repository, the product repository is `hannasdev/delivery-friction-analyzer`; the first validation target is `hannasdev/mcp-writing`.
21
+
22
+ ## Degraded Behavior
23
+
24
+ If a target repository is private or the token lacks access, the analyzer should report coverage as unavailable or partial instead of silently emitting complete-looking metrics. Missing `defaultBranch` or malformed owner/name input is a hard contract error.
@@ -0,0 +1,25 @@
1
+ # GitHub Access And Coverage Matrix
2
+
3
+ The MVP runs locally with the user's GitHub credentials. Reports must expose unavailable or partial data instead of implying complete coverage.
4
+
5
+ | API Family | Auth Mode | Minimum Public Repo Access | Minimum Private Repo Access | Used For | Degraded Output |
6
+ | --- | --- | --- | --- | --- | --- |
7
+ | REST repository metadata | unauthenticated or token | public read | `repo` or fine-grained metadata read | repository visibility, default branch confirmation | mark repository metadata partial |
8
+ | REST languages | unauthenticated or token | public read | `repo` or fine-grained contents/metadata read | language byte distribution context | omit language context; do not infer file role from language |
9
+ | Pull request metadata | `gh` token / GraphQL-backed PR fields | public read | `repo` or pull request read | lifecycle, final diff shape, files, commits, reviews | mark PR inventory partial |
10
+ | REST review comments | token recommended | public read | `repo` or pull request read | individual review comments and comment paths | source breakdown based only on reviews if unavailable |
11
+ | GraphQL review threads | token | public read | `repo` or pull request read | thread count, resolved state, outdated state | thread metrics unavailable; comment count can remain REST-only |
12
+ | Actions workflow runs | token | public Actions read when enabled | `repo` and Actions read | CI churn and rerun history | final check rollup only; mark churn history partial |
13
+ | Check runs per commit | token | public checks read when enabled | `repo` or checks read | check detail by commit SHA | check detail unavailable; retain final status rollup |
14
+ | GitHub UI partials | authenticated browser/session or HTTP request | repo page access | repo page access | experimental Copilot severity source | severity source `unavailable` unless explicitly enabled |
15
+
16
+ ## Rate Limits And Missing Scopes
17
+
18
+ The analyzer should record:
19
+
20
+ - API family attempted.
21
+ - Coverage status: `available`, `partial`, `unavailable`, or `rate_limited`.
22
+ - Required scope or permission when known.
23
+ - Impact on downstream metrics.
24
+
25
+ Missing coverage must flow into report metadata. For example, unavailable GraphQL review threads should disable thread-resolution metrics while preserving REST review-comment counts.
@@ -0,0 +1,55 @@
1
+ # GitHub Data Inventory
2
+
3
+ Checked against `hannasdev/mcp-writing` on 2026-06-08 with `gh` authenticated as `hannasdev`.
4
+
5
+ ## API Fields
6
+
7
+ | Area | Fields | Source | Coverage Notes |
8
+ | --- | --- | --- | --- |
9
+ | Target repository | owner, name, default branch, visibility | local target contract plus REST repository metadata | The target repository is separate from the product repository. |
10
+ | Language distribution | language byte counts | `GET /repos/{owner}/{repo}/languages` | Context only; does not determine file role or risk. |
11
+ | Pull request lifecycle | number, title, URL, state, createdAt, mergedAt, updatedAt, baseRefName, headRefName, headRefOid | `gh pr view --json` / GraphQL-backed PR fields | Directly available for current and historical PRs. |
12
+ | Commits | commit OID, authoredDate, committedDate, message headline | `gh pr view --json commits` | Useful for post-open and post-review iteration counts. |
13
+ | Final diff shape | additions, deletions, changedFiles, files path/additions/deletions/changeType | `gh pr view --json additions,deletions,changedFiles,files` | Final/current PR diff is direct. |
14
+ | PR-open diff shape | files/lines at PR open | reconstruction from commits/timeline, or future snapshot | Not directly available from simple PR metadata; record confidence or unavailable. |
15
+ | Reviews and attempts | review ID, author login, state, submittedAt, commit OID, body summary | `gh pr view --json reviews` | Copilot no-new-comment and failed attempts appear as reviews and should be retained. |
16
+ | Review comments | comment ID, author, path, line, timestamps, URL | REST `GET /repos/{owner}/{repo}/pulls/{number}/comments` and GraphQL review threads | REST is good for individual comments; GraphQL is required for thread grouping. Author login is retained so PR-author replies can be separated from human reviewer feedback when known. |
17
+ | Review thread state | totalCount, isResolved, isOutdated, path, line, grouped comments | GraphQL `pullRequest.reviewThreads` | Required for thread-aware review analytics. |
18
+ | Check runs | name, workflowName, status, conclusion, startedAt, completedAt | `gh pr view --json statusCheckRollup` and check-runs per commit | Final rollup only reflects the current/final head. |
19
+ | Workflow-run churn | run id, workflow name, head SHA, conclusion, status, run timestamps | REST `GET /repos/{owner}/{repo}/actions/runs?branch=...&event=pull_request` | Branch lookup may degrade after branch deletion or rename. |
20
+ | Copilot review effort | review-level effort setting | public docs / currently not observed in checked PR payloads | Store as unavailable or fallback until a stable API path is confirmed. |
21
+ | Copilot comment severity | high/medium/low UI label | GitHub UI partial if experimental extractor is enabled | Not observed in checked REST or GraphQL payloads; label as `internal_ui_partial`, `inferred`, `unavailable`, or excluded. |
22
+ | Vendor confidence / visibility | confidence, hidden-comment state, hide-severity-label state | GitHub UI partial if experimental extractor is enabled | Not observed in checked REST or GraphQL payloads. For MVP scoring, treat as `unavailable` or `internal_ui_partial`; do not infer correctness from it. |
23
+
24
+ ## Diff Snapshot Support
25
+
26
+ PR-open diff support must be recorded as one of:
27
+
28
+ - `direct`: observed from a stable API payload.
29
+ - `reconstructed`: derived from commits/timeline with a confidence label.
30
+ - `snapshot_only`: requires a future GitHub App or webhook snapshot captured at PR open.
31
+ - `unavailable`: not computed for the current run.
32
+
33
+ The Milestone 1 fixtures mark PR-open diff data as `unavailable`; final diff data is direct.
34
+
35
+ ## Vendor Signal Support
36
+
37
+ Copilot review effort, Copilot comment severity, and vendor confidence/visibility are separate fields. The checked PR metadata did not expose review effort as structured data. The checked REST and GraphQL review-comment payloads did not expose comment-level severity, confidence, or hidden-comment visibility state. Prior validation found severity and `hideSeverityLabel` in an undocumented GitHub UI partial. The MVP should not use those unstable labels as primary trend metrics or correctness signals.
38
+
39
+ Availability decision:
40
+
41
+ - Review effort: `unavailable` in checked PR payloads unless a stable public API source is later confirmed.
42
+ - Comment severity: `unavailable` through checked public APIs; `internal_ui_partial` only if an explicit experimental extractor is enabled.
43
+ - Confidence / visibility: `unavailable` through checked public APIs; `internal_ui_partial` only if an explicit experimental extractor is enabled; excluded from MVP scoring.
44
+
45
+ ## Source Commands Used For Fixtures
46
+
47
+ - `gh api repos/hannasdev/mcp-writing/languages`
48
+ - `gh pr view 223 --repo hannasdev/mcp-writing --json ...`
49
+ - `gh pr view 221 --repo hannasdev/mcp-writing --json ...`
50
+ - `gh pr view 239 --repo hannasdev/mcp-writing --json ...`
51
+ - `gh api repos/hannasdev/mcp-writing/pulls/239/comments`
52
+ - `gh api graphql` querying `repository.pullRequest.reviewThreads`
53
+ - `gh api 'repos/hannasdev/mcp-writing/actions/runs?branch=feat/extended-vocabulary-resolution&event=pull_request&per_page=30'`
54
+
55
+ Fixtures store compact, redacted source-shaped data rather than full raw payloads.
@@ -0,0 +1,65 @@
1
+ # Release Automation
2
+
3
+ Delivery Friction Analyzer publishes the unbundled source package to npm. This reference is for maintainers and agents preparing release-related changes; the README stays focused on CLI usage.
4
+
5
+ ## Package Artifact
6
+
7
+ The npm package allowlist includes:
8
+
9
+ - runtime source in `src`;
10
+ - JSON schemas in `schemas`;
11
+ - public contract and reference docs in `docs/contracts` and `docs/reference`;
12
+ - the sample repository profile at `fixtures/github/mcp-writing/profile.json`;
13
+ - `LICENSE`;
14
+ - `README.md`;
15
+ - `release-log.md`.
16
+
17
+ Generated reports, tests, initiative docs, and calibration fixtures are intentionally excluded from the npm artifact.
18
+
19
+ ## CI
20
+
21
+ The CI workflow runs on pull requests and pushes to `main`.
22
+
23
+ It validates:
24
+
25
+ - `npm ci`;
26
+ - `npm test`;
27
+ - `npm pack --dry-run`.
28
+
29
+ CI runs on Node 20 and Node 24 so the advertised `engines.node >=20` floor is exercised before release.
30
+
31
+ ## Release Workflow
32
+
33
+ The release workflow runs on pushes to `main` and skips commits whose subject starts with `Release `.
34
+
35
+ It:
36
+
37
+ - validates that `RELEASE_DEPLOY_KEY` is configured;
38
+ - checks out the repository with full tag history and the deploy key;
39
+ - validates that the package version is not behind the latest `v*` tag;
40
+ - determines the next semantic version from conventional commits since the latest `v*` tag;
41
+ - runs tests;
42
+ - bumps `package.json` and `package-lock.json`;
43
+ - commits the version bump;
44
+ - creates a matching `vX.Y.Z` tag;
45
+ - pushes the release commit and tag atomically;
46
+ - creates a GitHub release with generated notes.
47
+
48
+ `RELEASE_DEPLOY_KEY` must contain a private SSH key whose public key is configured as a write-enabled repository deploy key.
49
+
50
+ ## Publish Workflow
51
+
52
+ The publish workflow runs on `v*.*.*` tags and can also be started manually.
53
+
54
+ Tag-triggered runs:
55
+
56
+ - verify that the package is not private;
57
+ - verify that the Git tag matches the package version;
58
+ - infer `next` for prerelease versions and `latest` for stable versions;
59
+ - skip versions already published on npm;
60
+ - run `npm pack --dry-run`;
61
+ - publish the package to npm.
62
+
63
+ Manual `workflow_dispatch` runs are dry-run only. They use the selected npm dist-tag and execute `npm publish --dry-run`; real publishes require pushing a matching version tag.
64
+
65
+ Configure npm trusted publishing for this repository before relying on tag-triggered publish.
@@ -0,0 +1,55 @@
1
+ # Repository Profile Format
2
+
3
+ Repository profiles map paths to file categories, file roles, and functional surfaces before metrics are computed. They can also classify pull requests into repository-specific classes such as `release`, `dependency`, or `unknown`. The same language or PR title pattern can mean different product surfaces in different repositories, so language distribution and PR class assumptions stay in profile data.
4
+
5
+ Schema: `schemas/repository-profile.schema.json`.
6
+
7
+ ## Categories
8
+
9
+ - `code`
10
+ - `tests`
11
+ - `docs`
12
+ - `config`
13
+ - `generated`
14
+ - `infrastructure`
15
+ - `unknown`
16
+
17
+ ## Roles
18
+
19
+ - `core_product_code`
20
+ - `product_ui`
21
+ - `tests`
22
+ - `generated_docs`
23
+ - `release_notes`
24
+ - `planning_docs`
25
+ - `marketing_site`
26
+ - `config`
27
+ - `infrastructure`
28
+ - `fixtures`
29
+ - `generated_or_vendored`
30
+ - `unknown`
31
+
32
+ ## Rule Matching
33
+
34
+ Rules are evaluated in order and can match by `exact`, `prefix`, `suffix`, `includes`, or `regex`. The first matching rule wins. If no profile rule matches, the fallback classifier assigns a conservative category from path conventions and leaves the role as `unknown` except for tests.
35
+
36
+ This keeps validation-target details in profile data rather than hardcoded product assumptions.
37
+
38
+ ## Pull Request Classes
39
+
40
+ `prClasses` is optional. Rules are evaluated in order and the first matching rule wins. M1 supports title-only matchers:
41
+
42
+ - `titleIncludes`: literal substring match against the PR title.
43
+ - `titleRegex`: JavaScript regular expression matched against the PR title.
44
+
45
+ If both matchers are present on one rule, both must match. If no rule matches, the normalized PR receives:
46
+
47
+ ```json
48
+ {
49
+ "class": "unknown",
50
+ "classificationSource": "fallback_rule",
51
+ "ruleId": null
52
+ }
53
+ ```
54
+
55
+ Class identifiers are validated as lower-kebab-case or lower_snake_case strings. Profile validation rejects duplicate PR class rule IDs, empty match objects, invalid class identifiers, and invalid title regexes.