grift-cli 0.5.8__tar.gz → 0.5.9__tar.gz
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.
Potentially problematic release.
This version of grift-cli might be problematic. Click here for more details.
- {grift_cli-0.5.8 → grift_cli-0.5.9}/.grift/contribution.json +46 -46
- {grift_cli-0.5.8 → grift_cli-0.5.9}/CHANGELOG.md +7 -0
- {grift_cli-0.5.8 → grift_cli-0.5.9}/PKG-INFO +5 -1
- {grift_cli-0.5.8 → grift_cli-0.5.9}/README.en.md +8 -0
- {grift_cli-0.5.8 → grift_cli-0.5.9}/README.md +4 -0
- {grift_cli-0.5.8 → grift_cli-0.5.9}/action.yml +1 -1
- {grift_cli-0.5.8 → grift_cli-0.5.9}/docs/metrics-guide.md +1 -1
- {grift_cli-0.5.8 → grift_cli-0.5.9}/pyproject.toml +1 -1
- {grift_cli-0.5.8 → grift_cli-0.5.9}/src/tep_core/report.py +35 -16
- {grift_cli-0.5.8 → grift_cli-0.5.9}/src/tep_core/version.py +2 -2
- grift_cli-0.5.9/tests/test_gloss_gates.py +210 -0
- {grift_cli-0.5.8 → grift_cli-0.5.9}/tests/test_ux_v057.py +11 -6
- {grift_cli-0.5.8 → grift_cli-0.5.9}/.github/workflows/ci.yml +0 -0
- {grift_cli-0.5.8 → grift_cli-0.5.9}/.github/workflows/kpi-monthly.yml +0 -0
- {grift_cli-0.5.8 → grift_cli-0.5.9}/.github/workflows/publish.yml +0 -0
- {grift_cli-0.5.8 → grift_cli-0.5.9}/.gitignore +0 -0
- {grift_cli-0.5.8 → grift_cli-0.5.9}/LICENSE +0 -0
- {grift_cli-0.5.8 → grift_cli-0.5.9}/corpus/AD-PILOT-20260822.md +0 -0
- {grift_cli-0.5.8 → grift_cli-0.5.9}/corpus/DISCRIMINANT-v2026.09.md +0 -0
- {grift_cli-0.5.8 → grift_cli-0.5.9}/corpus/DISCRIMINANT-v2026.11.md +0 -0
- {grift_cli-0.5.8 → grift_cli-0.5.9}/corpus/ad-pilot.json +0 -0
- {grift_cli-0.5.8 → grift_cli-0.5.9}/corpus/manifest.toml +0 -0
- {grift_cli-0.5.8 → grift_cli-0.5.9}/corpus/pins-v2026.09.toml +0 -0
- {grift_cli-0.5.8 → grift_cli-0.5.9}/corpus/pins-v2026.11.toml +0 -0
- {grift_cli-0.5.8 → grift_cli-0.5.9}/corpus/v2026.09/distributions.json +0 -0
- {grift_cli-0.5.8 → grift_cli-0.5.9}/corpus/v2026.11/distributions.json +0 -0
- {grift_cli-0.5.8 → grift_cli-0.5.9}/docs/corpus-protocol.md +0 -0
- {grift_cli-0.5.8 → grift_cli-0.5.9}/docs/coverage-map.md +0 -0
- {grift_cli-0.5.8 → grift_cli-0.5.9}/docs/en/corpus-protocol.md +0 -0
- {grift_cli-0.5.8 → grift_cli-0.5.9}/docs/en/coverage-map.md +0 -0
- {grift_cli-0.5.8 → grift_cli-0.5.9}/docs/en/export-schema.md +0 -0
- {grift_cli-0.5.8 → grift_cli-0.5.9}/docs/en/identity-schema.md +0 -0
- {grift_cli-0.5.8 → grift_cli-0.5.9}/docs/en/metrics-guide.md +0 -0
- {grift_cli-0.5.8 → grift_cli-0.5.9}/docs/en/norms.md +0 -0
- {grift_cli-0.5.8 → grift_cli-0.5.9}/docs/en/persona-answers.md +0 -0
- {grift_cli-0.5.8 → grift_cli-0.5.9}/docs/en/report-schema.md +0 -0
- {grift_cli-0.5.8 → grift_cli-0.5.9}/docs/export-schema.md +0 -0
- {grift_cli-0.5.8 → grift_cli-0.5.9}/docs/identity-schema.md +0 -0
- {grift_cli-0.5.8 → grift_cli-0.5.9}/docs/norms.md +0 -0
- {grift_cli-0.5.8 → grift_cli-0.5.9}/docs/persona-answers.md +0 -0
- {grift_cli-0.5.8 → grift_cli-0.5.9}/docs/report-schema.md +0 -0
- {grift_cli-0.5.8 → grift_cli-0.5.9}/golden/README.md +0 -0
- {grift_cli-0.5.8 → grift_cli-0.5.9}/golden/coverage.md +0 -0
- {grift_cli-0.5.8 → grift_cli-0.5.9}/golden/expected/G1-click.json +0 -0
- {grift_cli-0.5.8 → grift_cli-0.5.9}/golden/expected/G10-scvi-tools.json +0 -0
- {grift_cli-0.5.8 → grift_cli-0.5.9}/golden/expected/G11-kilo.json +0 -0
- {grift_cli-0.5.8 → grift_cli-0.5.9}/golden/expected/G12-httpx.json +0 -0
- {grift_cli-0.5.8 → grift_cli-0.5.9}/golden/expected/G13-voicevox.json +0 -0
- {grift_cli-0.5.8 → grift_cli-0.5.9}/golden/expected/G2-gitignore.json +0 -0
- {grift_cli-0.5.8 → grift_cli-0.5.9}/golden/expected/G3-spoon-knife.json +0 -0
- {grift_cli-0.5.8 → grift_cli-0.5.9}/golden/expected/G4-express.json +0 -0
- {grift_cli-0.5.8 → grift_cli-0.5.9}/golden/expected/G5-typer.json +0 -0
- {grift_cli-0.5.8 → grift_cli-0.5.9}/golden/expected/G6-claude-code.json +0 -0
- {grift_cli-0.5.8 → grift_cli-0.5.9}/golden/expected/G7-axios.json +0 -0
- {grift_cli-0.5.8 → grift_cli-0.5.9}/golden/expected/G8-co.json +0 -0
- {grift_cli-0.5.8 → grift_cli-0.5.9}/golden/expected/G9-pyscript.json +0 -0
- {grift_cli-0.5.8 → grift_cli-0.5.9}/golden/identity/G1-click.toml +0 -0
- {grift_cli-0.5.8 → grift_cli-0.5.9}/golden/identity/example.toml +0 -0
- {grift_cli-0.5.8 → grift_cli-0.5.9}/golden/pins.toml +0 -0
- {grift_cli-0.5.8 → grift_cli-0.5.9}/scripts/admission_v2026_11.py +0 -0
- {grift_cli-0.5.8 → grift_cli-0.5.9}/scripts/build_dist_v2026_11.py +0 -0
- {grift_cli-0.5.8 → grift_cli-0.5.9}/scripts/build_distributions.py +0 -0
- {grift_cli-0.5.8 → grift_cli-0.5.9}/scripts/check_forbidden_vocab.py +0 -0
- {grift_cli-0.5.8 → grift_cli-0.5.9}/scripts/corpus_ad_pilot.py +0 -0
- {grift_cli-0.5.8 → grift_cli-0.5.9}/scripts/corpus_run.py +0 -0
- {grift_cli-0.5.8 → grift_cli-0.5.9}/scripts/discriminant_v2026.py +0 -0
- {grift_cli-0.5.8 → grift_cli-0.5.9}/scripts/discriminant_v2026_11.py +0 -0
- {grift_cli-0.5.8 → grift_cli-0.5.9}/scripts/gen_coverage_table.py +0 -0
- {grift_cli-0.5.8 → grift_cli-0.5.9}/scripts/gen_golden_expected.py +0 -0
- {grift_cli-0.5.8 → grift_cli-0.5.9}/scripts/hygiene_grep.py +0 -0
- {grift_cli-0.5.8 → grift_cli-0.5.9}/src/tep_cli/__init__.py +0 -0
- {grift_cli-0.5.8 → grift_cli-0.5.9}/src/tep_cli/__main__.py +0 -0
- {grift_cli-0.5.8 → grift_cli-0.5.9}/src/tep_core/__init__.py +0 -0
- {grift_cli-0.5.8 → grift_cli-0.5.9}/src/tep_core/activity.py +0 -0
- {grift_cli-0.5.8 → grift_cli-0.5.9}/src/tep_core/analyze.py +0 -0
- {grift_cli-0.5.8 → grift_cli-0.5.9}/src/tep_core/cochange.py +0 -0
- {grift_cli-0.5.8 → grift_cli-0.5.9}/src/tep_core/context_profile.py +0 -0
- {grift_cli-0.5.8 → grift_cli-0.5.9}/src/tep_core/contribute.py +0 -0
- {grift_cli-0.5.8 → grift_cli-0.5.9}/src/tep_core/core_period.py +0 -0
- {grift_cli-0.5.8 → grift_cli-0.5.9}/src/tep_core/data/v2026.09/distributions.json +0 -0
- {grift_cli-0.5.8 → grift_cli-0.5.9}/src/tep_core/data/v2026.11/distributions.json +0 -0
- {grift_cli-0.5.8 → grift_cli-0.5.9}/src/tep_core/export.py +0 -0
- {grift_cli-0.5.8 → grift_cli-0.5.9}/src/tep_core/gitutil.py +0 -0
- {grift_cli-0.5.8 → grift_cli-0.5.9}/src/tep_core/identity.py +0 -0
- {grift_cli-0.5.8 → grift_cli-0.5.9}/src/tep_core/lineage.py +0 -0
- {grift_cli-0.5.8 → grift_cli-0.5.9}/src/tep_core/observation.py +0 -0
- {grift_cli-0.5.8 → grift_cli-0.5.9}/src/tep_core/origin.py +0 -0
- {grift_cli-0.5.8 → grift_cli-0.5.9}/src/tep_core/paths.py +0 -0
- {grift_cli-0.5.8 → grift_cli-0.5.9}/src/tep_core/reference.py +0 -0
- {grift_cli-0.5.8 → grift_cli-0.5.9}/src/tep_core/rework.py +0 -0
- {grift_cli-0.5.8 → grift_cli-0.5.9}/src/tep_core/schema.py +0 -0
- {grift_cli-0.5.8 → grift_cli-0.5.9}/src/tep_core/scope.py +0 -0
- {grift_cli-0.5.8 → grift_cli-0.5.9}/src/tep_core/survival.py +0 -0
- {grift_cli-0.5.8 → grift_cli-0.5.9}/src/tep_core/tests_observed.py +0 -0
- {grift_cli-0.5.8 → grift_cli-0.5.9}/src/tep_core/verify.py +0 -0
- {grift_cli-0.5.8 → grift_cli-0.5.9}/tests/conftest.py +0 -0
- {grift_cli-0.5.8 → grift_cli-0.5.9}/tests/coverage_matrix.py +0 -0
- {grift_cli-0.5.8 → grift_cli-0.5.9}/tests/git_fixture.py +0 -0
- {grift_cli-0.5.8 → grift_cli-0.5.9}/tests/test_activity.py +0 -0
- {grift_cli-0.5.8 → grift_cli-0.5.9}/tests/test_cli.py +0 -0
- {grift_cli-0.5.8 → grift_cli-0.5.9}/tests/test_cochange.py +0 -0
- {grift_cli-0.5.8 → grift_cli-0.5.9}/tests/test_context_profile.py +0 -0
- {grift_cli-0.5.8 → grift_cli-0.5.9}/tests/test_contribute.py +0 -0
- {grift_cli-0.5.8 → grift_cli-0.5.9}/tests/test_coverage.py +0 -0
- {grift_cli-0.5.8 → grift_cli-0.5.9}/tests/test_default_report_path.py +0 -0
- {grift_cli-0.5.8 → grift_cli-0.5.9}/tests/test_discriminant_claims.py +0 -0
- {grift_cli-0.5.8 → grift_cli-0.5.9}/tests/test_export.py +0 -0
- {grift_cli-0.5.8 → grift_cli-0.5.9}/tests/test_export_recipe.py +0 -0
- {grift_cli-0.5.8 → grift_cli-0.5.9}/tests/test_forbidden_vocab.py +0 -0
- {grift_cli-0.5.8 → grift_cli-0.5.9}/tests/test_gitutil.py +0 -0
- {grift_cli-0.5.8 → grift_cli-0.5.9}/tests/test_golden.py +0 -0
- {grift_cli-0.5.8 → grift_cli-0.5.9}/tests/test_h5_swarm.py +0 -0
- {grift_cli-0.5.8 → grift_cli-0.5.9}/tests/test_hygiene.py +0 -0
- {grift_cli-0.5.8 → grift_cli-0.5.9}/tests/test_identity_validation.py +0 -0
- {grift_cli-0.5.8 → grift_cli-0.5.9}/tests/test_intake_disclosure.py +0 -0
- {grift_cli-0.5.8 → grift_cli-0.5.9}/tests/test_lifecycle_v2.py +0 -0
- {grift_cli-0.5.8 → grift_cli-0.5.9}/tests/test_not_observed.py +0 -0
- {grift_cli-0.5.8 → grift_cli-0.5.9}/tests/test_origin.py +0 -0
- {grift_cli-0.5.8 → grift_cli-0.5.9}/tests/test_persona_answers.py +0 -0
- {grift_cli-0.5.8 → grift_cli-0.5.9}/tests/test_release_gate.py +0 -0
- {grift_cli-0.5.8 → grift_cli-0.5.9}/tests/test_report.py +0 -0
- {grift_cli-0.5.8 → grift_cli-0.5.9}/tests/test_rework.py +0 -0
- {grift_cli-0.5.8 → grift_cli-0.5.9}/tests/test_schema.py +0 -0
- {grift_cli-0.5.8 → grift_cli-0.5.9}/tests/test_scope.py +0 -0
- {grift_cli-0.5.8 → grift_cli-0.5.9}/tests/test_shared_block.py +0 -0
- {grift_cli-0.5.8 → grift_cli-0.5.9}/tests/test_survival.py +0 -0
- {grift_cli-0.5.8 → grift_cli-0.5.9}/tests/test_v058_gates.py +0 -0
- {grift_cli-0.5.8 → grift_cli-0.5.9}/tests/test_verb_semantics.py +0 -0
- {grift_cli-0.5.8 → grift_cli-0.5.9}/tests/test_verify.py +0 -0
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
"purpose": "TEP Report 集計と参照分布 vNext",
|
|
4
4
|
"provenance": {
|
|
5
5
|
"tool_name": "grift",
|
|
6
|
-
"tool_version": "0.5.
|
|
7
|
-
"definition_version": "tep-v0.5.
|
|
6
|
+
"tool_version": "0.5.9",
|
|
7
|
+
"definition_version": "tep-v0.5.9-2026-08-25",
|
|
8
8
|
"origin_definition_version": "origin-v1.1-2026-08-22",
|
|
9
9
|
"activity_definition_version": "activity-v1-2026-08-16",
|
|
10
10
|
"analysis_scope": "repo"
|
|
@@ -13,13 +13,13 @@
|
|
|
13
13
|
"provenance": {
|
|
14
14
|
"tool_name": "grift",
|
|
15
15
|
"method_name": "TEP",
|
|
16
|
-
"tool_version": "0.5.
|
|
17
|
-
"definition_version": "tep-v0.5.
|
|
16
|
+
"tool_version": "0.5.9",
|
|
17
|
+
"definition_version": "tep-v0.5.9-2026-08-25",
|
|
18
18
|
"origin_definition_version": "origin-v1.1-2026-08-22",
|
|
19
19
|
"activity_definition_version": "activity-v1-2026-08-16",
|
|
20
20
|
"analysis_scope": "repo",
|
|
21
21
|
"analyzed_commit_sha": "49248320758d2d9e604a2420c285136e1ea6eff3",
|
|
22
|
-
"analyzed_at": "2026-08-
|
|
22
|
+
"analyzed_at": "2026-08-25T09:17:01Z"
|
|
23
23
|
},
|
|
24
24
|
"lineage": {
|
|
25
25
|
"is_fork": false,
|
|
@@ -167,13 +167,38 @@
|
|
|
167
167
|
}
|
|
168
168
|
},
|
|
169
169
|
"context_profile": {
|
|
170
|
-
"
|
|
171
|
-
|
|
170
|
+
"docs_share": {
|
|
171
|
+
"kind": "observed",
|
|
172
|
+
"value": 0.0,
|
|
173
|
+
"unit": "ratio"
|
|
174
|
+
},
|
|
175
|
+
"language_composition": {
|
|
176
|
+
"kind": "observed",
|
|
177
|
+
"value": {
|
|
178
|
+
"py": 1.0
|
|
179
|
+
},
|
|
180
|
+
"unit": "touch-share"
|
|
181
|
+
},
|
|
172
182
|
"resolved_human_actors": {
|
|
173
183
|
"kind": "observed",
|
|
174
184
|
"value": 1,
|
|
175
185
|
"unit": "actors"
|
|
176
186
|
},
|
|
187
|
+
"lifecycle_stage": {
|
|
188
|
+
"kind": "observed",
|
|
189
|
+
"value": "dormant",
|
|
190
|
+
"unit": "class"
|
|
191
|
+
},
|
|
192
|
+
"release_cadence": {
|
|
193
|
+
"kind": "observed",
|
|
194
|
+
"value": null,
|
|
195
|
+
"unit": "tags/year"
|
|
196
|
+
},
|
|
197
|
+
"pr_flow_share": {
|
|
198
|
+
"kind": "observed",
|
|
199
|
+
"value": 0.0,
|
|
200
|
+
"unit": "ratio"
|
|
201
|
+
},
|
|
177
202
|
"actor_turnover": {
|
|
178
203
|
"kind": "observed",
|
|
179
204
|
"value": {
|
|
@@ -189,68 +214,43 @@
|
|
|
189
214
|
"value": "solo",
|
|
190
215
|
"unit": "class"
|
|
191
216
|
},
|
|
192
|
-
"
|
|
193
|
-
"language_composition": {
|
|
194
|
-
"kind": "observed",
|
|
195
|
-
"value": {
|
|
196
|
-
"py": 1.0
|
|
197
|
-
},
|
|
198
|
-
"unit": "touch-share"
|
|
199
|
-
},
|
|
200
|
-
"monorepo_markers": {
|
|
201
|
-
"kind": "observed",
|
|
202
|
-
"value": [],
|
|
203
|
-
"unit": "markers"
|
|
204
|
-
},
|
|
205
|
-
"issue_link_density": {
|
|
206
|
-
"kind": "observed",
|
|
207
|
-
"value": 0.0,
|
|
208
|
-
"unit": "ratio"
|
|
209
|
-
},
|
|
210
|
-
"lifecycle_stage": {
|
|
211
|
-
"kind": "observed",
|
|
212
|
-
"value": "dormant",
|
|
213
|
-
"unit": "class"
|
|
214
|
-
},
|
|
217
|
+
"definition_version": "context-v3-2026-08-25",
|
|
215
218
|
"repo_age_days": {
|
|
216
219
|
"kind": "observed",
|
|
217
220
|
"value": 0,
|
|
218
221
|
"unit": "days"
|
|
219
222
|
},
|
|
220
|
-
"
|
|
223
|
+
"conventional_commit_share": {
|
|
221
224
|
"kind": "observed",
|
|
222
|
-
"value":
|
|
225
|
+
"value": 1.0,
|
|
223
226
|
"unit": "ratio"
|
|
224
227
|
},
|
|
228
|
+
"dependency_manifests": {
|
|
229
|
+
"kind": "observed",
|
|
230
|
+
"value": [],
|
|
231
|
+
"unit": "manifests"
|
|
232
|
+
},
|
|
233
|
+
"analysis_scope": "repo",
|
|
225
234
|
"test_file_ratio": {
|
|
226
235
|
"kind": "observed",
|
|
227
236
|
"value": 0.3333,
|
|
228
237
|
"unit": "ratio"
|
|
229
238
|
},
|
|
230
|
-
"release_cadence": {
|
|
231
|
-
"kind": "observed",
|
|
232
|
-
"value": null,
|
|
233
|
-
"unit": "tags/year"
|
|
234
|
-
},
|
|
235
239
|
"top_actor_share": {
|
|
236
240
|
"kind": "observed",
|
|
237
241
|
"value": 1.0,
|
|
238
242
|
"unit": "ratio"
|
|
239
243
|
},
|
|
240
|
-
"
|
|
241
|
-
"kind": "observed",
|
|
242
|
-
"value": 1.0,
|
|
243
|
-
"unit": "ratio"
|
|
244
|
-
},
|
|
245
|
-
"dependency_manifests": {
|
|
244
|
+
"monorepo_markers": {
|
|
246
245
|
"kind": "observed",
|
|
247
246
|
"value": [],
|
|
248
|
-
"unit": "
|
|
247
|
+
"unit": "markers"
|
|
249
248
|
},
|
|
250
|
-
"
|
|
249
|
+
"issue_link_density": {
|
|
251
250
|
"kind": "observed",
|
|
252
251
|
"value": 0.0,
|
|
253
252
|
"unit": "ratio"
|
|
254
|
-
}
|
|
253
|
+
},
|
|
254
|
+
"kind": "observed"
|
|
255
255
|
}
|
|
256
256
|
}
|
|
@@ -4,6 +4,13 @@
|
|
|
4
4
|
|
|
5
5
|
タグ・PyPI・リポ public 化は本ファイルの記載対象外(人間ゲート)。
|
|
6
6
|
|
|
7
|
+
## [0.5.9] — 2026-08-25
|
|
8
|
+
|
|
9
|
+
### Changed(代表 UX フィードバック)
|
|
10
|
+
|
|
11
|
+
- **report.md の説明を項目ごと(行末)に配置**: セクション末尾への一括説明を廃止し、各値の行末に短い日英併記の gloss を直付け(origin 11分類・activity 5項目・test co-change・corrective/path retouch・survival・context 各行・test frameworks)。値と説明の距離がゼロになり、レポートを上から読むだけで各数値の意味が分かる
|
|
12
|
+
- **検収ゲート対応(提唱者4点)**: ①全 gloss の**単位一致**を機械強制(origin はコミット単位に統一 —「identityに一致しなかったコミット」等・行の単位と gloss の突合テスト)②gloss の**規範語ゲート**(良い/悪い/優れ/劣る/健全/理想等の混入ゼロをピン。解釈は metrics-guide 側のみ・rework の否定注記は維持)③**report.json は不変**(gloss は md のみ・render が dict を mutate しないことと verify が VERIFIED のままなことをテストで明示)④**Shared block は gloss なしと仕様明文化**(README 日英・metrics-guide に「簡潔さ優先、意味は本文行末 gloss が担う」の一行・gloss-free をピン)
|
|
13
|
+
|
|
7
14
|
## [0.5.8] — 2026-08-25
|
|
8
15
|
|
|
9
16
|
提唱者事前レビューの必須ゲート(A/B/C/D/E)+ 日英併記拡充。
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: grift-cli
|
|
3
|
-
Version: 0.5.
|
|
3
|
+
Version: 0.5.9
|
|
4
4
|
Summary: Deterministic TEP evidence metrics from a single git repository. No LLM.
|
|
5
5
|
Project-URL: Homepage, https://github.com/Cor-Incorporated/grift-cli
|
|
6
6
|
Author: TEP contributors
|
|
@@ -104,6 +104,10 @@ grift contribute --out .grift/contribution.json # ② payload を組み・全
|
|
|
104
104
|
|
|
105
105
|
母数 20 未満では率も分布位置も出さない(`insufficient_population`。件数の生表示のみ)。
|
|
106
106
|
|
|
107
|
+
## Shared block の扱い(仕様)
|
|
108
|
+
|
|
109
|
+
Shared block(レポート冒頭 3-5 行のコピペ要約)には **gloss(説明)を付けない**。経歴書や issue にそのまま貼ったとき自己説明的な長文になるより、簡潔さ・貼りやすさを優先するため。各数値の意味は本文の行末 gloss と [docs/metrics-guide.md](metrics-guide.md) が担う。
|
|
110
|
+
|
|
107
111
|
## 指標の読み方(非エンジニア向け)
|
|
108
112
|
|
|
109
113
|
すべての指標について「何を測っているか・高い/低いで何がわかるか・公開リポジトリ117件の分布上の目安」を [docs/metrics-guide.md](docs/metrics-guide.md) に平易にまとめています。初めてレポートを見る方はまずこちらを。誤読しやすい点(例: corrective rework はバグ件数ではない、dormant は放置ではない)も表にしてあります。
|
|
@@ -95,6 +95,14 @@ grift contribute --out .grift/contribution.json # 2) build & review the payloa
|
|
|
95
95
|
- Use is limited to "TEP Report aggregation and the next reference
|
|
96
96
|
distribution"; retained until the next annual Report; withdrawal via issue
|
|
97
97
|
|
|
98
|
+
## Shared block policy (spec)
|
|
99
|
+
|
|
100
|
+
The Shared block (the 3-5 line copy-pasteable summary at the top of every
|
|
101
|
+
report) carries **no glosses**. Rationale: it is pasted into résumés and
|
|
102
|
+
issues, where compactness beats self-explanation — the per-line glosses in
|
|
103
|
+
the body and [docs/en/metrics-guide.md](en/metrics-guide.md) carry the
|
|
104
|
+
meanings.
|
|
105
|
+
|
|
98
106
|
## How to read the metrics (for non-engineers)
|
|
99
107
|
|
|
100
108
|
[docs/metrics-guide.md](docs/metrics-guide.md) explains every metric in plain
|
|
@@ -81,6 +81,10 @@ grift contribute --out .grift/contribution.json # ② payload を組み・全
|
|
|
81
81
|
|
|
82
82
|
母数 20 未満では率も分布位置も出さない(`insufficient_population`。件数の生表示のみ)。
|
|
83
83
|
|
|
84
|
+
## Shared block の扱い(仕様)
|
|
85
|
+
|
|
86
|
+
Shared block(レポート冒頭 3-5 行のコピペ要約)には **gloss(説明)を付けない**。経歴書や issue にそのまま貼ったとき自己説明的な長文になるより、簡潔さ・貼りやすさを優先するため。各数値の意味は本文の行末 gloss と [docs/metrics-guide.md](metrics-guide.md) が担う。
|
|
87
|
+
|
|
84
88
|
## 指標の読み方(非エンジニア向け)
|
|
85
89
|
|
|
86
90
|
すべての指標について「何を測っているか・高い/低いで何がわかるか・公開リポジトリ117件の分布上の目安」を [docs/metrics-guide.md](docs/metrics-guide.md) に平易にまとめています。初めてレポートを見る方はまずこちらを。誤読しやすい点(例: corrective rework はバグ件数ではない、dormant は放置ではない)も表にしてあります。
|
|
@@ -70,7 +70,7 @@ grift のレポートは3層の観測で構成されます。**層 = その数
|
|
|
70
70
|
|
|
71
71
|
## まず全体の流れ(report.md の構成)
|
|
72
72
|
|
|
73
|
-
1. **Shared block**: 3-5
|
|
73
|
+
1. **Shared block**: 3-5 行の要約(コピペで共有できる形式・**gloss なし — 簡潔さ優先、意味は本文行末 gloss と本書が担う**)
|
|
74
74
|
2. **Provenance**: いつ・どのコミット・どの定義版で測ったか(再現に必要な情報)
|
|
75
75
|
3. **帰属(origin 11分類)**: この repo のコミットが誰の/何の仕事か(上のインベントリ参照)
|
|
76
76
|
4. **証拠系**: test co-change(検証を伴った変更の割合)
|
|
@@ -23,6 +23,22 @@ _DISPLAY_NAME = {
|
|
|
23
23
|
"tenant_merge_or_sync": "merge commits (PR flow)",
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
+
# Inline one-line glosses (ja / en) per origin class — keep short so the
|
|
27
|
+
# value stays scannable; full definitions live in docs/metrics-guide.
|
|
28
|
+
_ORIGIN_GLOSS = {
|
|
29
|
+
"tenant_unique": "本人の独自コミット / this person's original commits",
|
|
30
|
+
"tenant_merge_or_sync": "PRマージ経由 / merged via PR flow",
|
|
31
|
+
"upstream_sync": "上流の取り込み / pulls from upstream",
|
|
32
|
+
"inherited_upstream": "fork由来の他人のコミット / other people's commits from the forked history",
|
|
33
|
+
"tenant_derivative": "親リポ由来の改変コミット / commits derived from the parent repo",
|
|
34
|
+
"external_upstream_contribution": "上流へ還流したコミット / commits contributed back upstream",
|
|
35
|
+
"template_inherited": "テンプレート由来のコミット / template-derived commits",
|
|
36
|
+
"generated_or_vendor": "生成・ベンダー成果物のみのコミット / commits touching only generated or vendored files",
|
|
37
|
+
"ambiguous_origin": "作者情報が欠損したコミット / commits with missing author info",
|
|
38
|
+
"unresolved": "identityに一致しなかったコミット / commits not matched by the identity",
|
|
39
|
+
"bot": "自動化アカウントのコミット / automation-account commits",
|
|
40
|
+
}
|
|
41
|
+
|
|
26
42
|
_SKIP_NOT_OBSERVED = frozenset({"upstream_sync", "tenant_merge_or_sync"})
|
|
27
43
|
|
|
28
44
|
|
|
@@ -122,18 +138,20 @@ def render_markdown(report: dict[str, Any]) -> str:
|
|
|
122
138
|
):
|
|
123
139
|
continue
|
|
124
140
|
label = _DISPLAY_NAME.get(name, name)
|
|
125
|
-
|
|
141
|
+
gloss = _ORIGIN_GLOSS.get(name, "")
|
|
142
|
+
suffix = f" — {gloss}" if gloss else ""
|
|
143
|
+
lines.append(f"- {label}: {_fmt_obs(obs)}{suffix}")
|
|
126
144
|
lines += [
|
|
127
145
|
"",
|
|
128
146
|
"## Activity (tenant_unique commits)",
|
|
129
|
-
f"- tenant commits: {_fmt_obs(activity['tenant_commits'])}",
|
|
130
|
-
f"- active days: {_fmt_obs(activity['active_days'])}",
|
|
131
|
-
f"- commits per active day: {_fmt_obs(activity['commits_per_active_day'])}",
|
|
147
|
+
f"- tenant commits: {_fmt_obs(activity['tenant_commits'])} — identityに一致した人のコミット数 / commits by identity-matched people",
|
|
148
|
+
f"- active days: {_fmt_obs(activity['active_days'])} — コミットした一意な日数 / unique days with commits",
|
|
149
|
+
f"- commits per active day: {_fmt_obs(activity['commits_per_active_day'])} — 1活動日あたりの密度 / per-active-day density",
|
|
132
150
|
(
|
|
133
151
|
"- commits per active day (median): "
|
|
134
|
-
f"{_fmt_obs(activity['commits_per_active_day_median'])}"
|
|
152
|
+
f"{_fmt_obs(activity['commits_per_active_day_median'])} — 中央値(日ごとの偏りに強い)/ median (robust to daily spikes)"
|
|
135
153
|
),
|
|
136
|
-
f"- active days (13 weeks): {_fmt_obs(activity['active_days_13w'])}",
|
|
154
|
+
f"- active days (13 weeks): {_fmt_obs(activity['active_days_13w'])} — 直近13週の活動日数 / active days in the last 13 weeks",
|
|
137
155
|
"",
|
|
138
156
|
"## Core activity period",
|
|
139
157
|
]
|
|
@@ -153,27 +171,27 @@ def render_markdown(report: dict[str, Any]) -> str:
|
|
|
153
171
|
lines.append(f"- not observed ({tests.get('reason')})")
|
|
154
172
|
else:
|
|
155
173
|
names = ", ".join(tests.get("names") or []) or "none named"
|
|
156
|
-
lines.append(
|
|
174
|
+
lines.append(
|
|
175
|
+
f"- observed: {names} (boolean {tests.get('value')})"
|
|
176
|
+
" — 検出されたテスト基盤 / detected test substrate"
|
|
177
|
+
)
|
|
157
178
|
lines += [
|
|
158
179
|
"",
|
|
159
180
|
"## Test co-change",
|
|
160
|
-
"
|
|
161
|
-
f"- {_fmt_metric_block(report.get('test_cochange'))}",
|
|
181
|
+
f"- {_fmt_metric_block(report.get('test_cochange'))} — 本番変更のうち同コミットでテストも変更した割合 / share of production changes paired with tests in the same commit",
|
|
162
182
|
]
|
|
163
183
|
interp = report.get("interpretation") or {}
|
|
164
184
|
lines += _fmt_interp_line("co-change", interp.get("test_cochange"))
|
|
165
185
|
lines += [
|
|
166
186
|
"",
|
|
167
187
|
"## Rework",
|
|
168
|
-
"(何を測るか / What this measures: 作った直後に手直しが発生した傾向の観測。バグ件数でも品質でもなく、件名慣習の影響を受けるため比較・合否には使えない — observed tendency of immediate rework after fresh changes. Not a bug count, not quality; subject-convention dependent, so never use for comparisons or pass/fail.)",
|
|
169
188
|
*_fmt_rework_lines(report.get("rework")),
|
|
170
189
|
]
|
|
171
190
|
lines += _fmt_interp_line("corrective rework", interp.get("corrective_rework"))
|
|
172
191
|
lines += [
|
|
173
192
|
"",
|
|
174
193
|
"## Survival (tau=180 days)",
|
|
175
|
-
"
|
|
176
|
-
f"- {_fmt_metric_block(report.get('survival'))}",
|
|
194
|
+
f"- {_fmt_metric_block(report.get('survival'))} — 6ヶ月後も残っている行の割合(1.0に近い=残り続けている)/ share of lines still present after 6 months (near 1.0 = keeps living)",
|
|
177
195
|
]
|
|
178
196
|
lines += ["", *(_fmt_context_lines(report.get("context_profile")))]
|
|
179
197
|
lines += ["", *readers_guide_lines()]
|
|
@@ -201,11 +219,11 @@ def _fmt_context_lines(ctx: dict[str, Any] | None) -> list[str]:
|
|
|
201
219
|
|
|
202
220
|
lines = [
|
|
203
221
|
"## Context profile (observational; not a ranking)",
|
|
204
|
-
"(このrepoのかたち / The shape of this repo: 協働・活動密度・プロセスの分類。序列ではなく、数値の読み方を条件付ける文脈 — collaboration, activity density, and process classification. Not a ranking; context that conditions how to read the numbers.)",
|
|
205
222
|
(
|
|
206
223
|
f"- collaboration: {val('collaboration_class')} "
|
|
207
224
|
f"({val('resolved_human_actors')} resolved human actors; "
|
|
208
225
|
f"top actor share {val('top_actor_share')} ratio)"
|
|
226
|
+
" — 協働のかたち / shape of collaboration"
|
|
209
227
|
),
|
|
210
228
|
(
|
|
211
229
|
f"- lifecycle: {val('lifecycle_stage')} "
|
|
@@ -213,8 +231,8 @@ def _fmt_context_lines(ctx: dict[str, Any] | None) -> list[str]:
|
|
|
213
231
|
f"days_since_last_human_commit {val('days_since_last_human_commit')} = 最終コミットからの日数 / days since the last human commit; "
|
|
214
232
|
f"repo age {val('repo_age_days')} days)"
|
|
215
233
|
),
|
|
216
|
-
f"- process: pr_flow_share {val('pr_flow_share')} ratio; conventional subjects {val('conventional_commit_share')} ratio",
|
|
217
|
-
f"- languages (touch-share): {_fmt_langs(val('language_composition'))}",
|
|
234
|
+
f"- process: pr_flow_share {val('pr_flow_share')} ratio (PRマージ経由 / via PR merges); conventional subjects {val('conventional_commit_share')} ratio (定型件名 / conventional subjects)",
|
|
235
|
+
f"- languages (touch-share): {_fmt_langs(val('language_composition'))} — 言語構成(接触比率)/ language mix by path touches",
|
|
218
236
|
]
|
|
219
237
|
return lines
|
|
220
238
|
|
|
@@ -276,7 +294,7 @@ def _fmt_rework_lines(obs: dict[str, Any] | None) -> list[str]:
|
|
|
276
294
|
f"- corrective rework (observational, subject-convention dependent; "
|
|
277
295
|
f"not an evidence claim): {corr.get('value')} {corr.get('unit')} "
|
|
278
296
|
f"({corr.get('corrective_commits')} of {corr.get('population')} "
|
|
279
|
-
f"commits; {window} day window)"
|
|
297
|
+
f"commits; {window} day window) — 作った直後の手直し傾向。バグ数でも品質でもない / tendency of immediate rework; not a bug count, not quality"
|
|
280
298
|
)
|
|
281
299
|
lines.append(
|
|
282
300
|
"- limit: corrective rework is fresh-work stability "
|
|
@@ -306,6 +324,7 @@ def _fmt_rework_lines(obs: dict[str, Any] | None) -> list[str]:
|
|
|
306
324
|
"- path retouch (observational, not an evidence claim): "
|
|
307
325
|
f"{touch.get('value')} {touch.get('unit')} "
|
|
308
326
|
f"({touch.get('retouch_commits')} of {touch.get('population')} commits)"
|
|
327
|
+
" — 同じファイルを21日窓で再び触れた割合 / share re-touching the same files within 21 days"
|
|
309
328
|
)
|
|
310
329
|
return lines or ["- observed"]
|
|
311
330
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
__version__ = "0.5.
|
|
1
|
+
__version__ = "0.5.9"
|
|
2
2
|
REPORT_SCHEMA_VERSION = "report-v1"
|
|
3
|
-
DEFINITION_VERSION = "tep-v0.5.
|
|
3
|
+
DEFINITION_VERSION = "tep-v0.5.9-2026-08-25"
|
|
4
4
|
ORIGIN_DEFINITION_VERSION = "origin-v1.1-2026-08-22"
|
|
5
5
|
ACTIVITY_DEFINITION_VERSION = "activity-v1-2026-08-16"
|
|
6
6
|
CORE_ACTIVITY_DEFINITION_VERSION = "core-activity-v1-2026-08-16"
|
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
"""v0.5.9 review gates (提唱者 2026-08-25):
|
|
2
|
+
(1) gloss unit alignment — every glossed line's unit must appear in the gloss
|
|
3
|
+
(2) gloss vocabulary gate — no normative words (良い/悪い/優れ/劣る/健全/理想/...)
|
|
4
|
+
(3) report.json immutability — glosses live in markdown only
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
import json
|
|
10
|
+
from pathlib import Path
|
|
11
|
+
|
|
12
|
+
from tep_core.analyze import analyze_repository
|
|
13
|
+
from tep_core.identity import empty_identity
|
|
14
|
+
from tep_core.lineage import Lineage
|
|
15
|
+
from tep_core.report import (
|
|
16
|
+
_ORIGIN_GLOSS,
|
|
17
|
+
render_markdown,
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
from git_fixture import commit, init_repo
|
|
21
|
+
|
|
22
|
+
ROOT = Path(__file__).resolve().parents[1]
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def _repo_report(tmp_path: Path):
|
|
26
|
+
repo = init_repo(tmp_path / "repo")
|
|
27
|
+
(repo / "pyproject.toml").write_text(
|
|
28
|
+
'[project]\nname = "d"\ndependencies = ["pytest"]\n', encoding="utf-8"
|
|
29
|
+
)
|
|
30
|
+
(repo / "tests").mkdir()
|
|
31
|
+
for index in range(24):
|
|
32
|
+
commit(
|
|
33
|
+
repo,
|
|
34
|
+
email="a@example.com",
|
|
35
|
+
date="2026-01-05",
|
|
36
|
+
message=f"feat: {index}",
|
|
37
|
+
filename="app.py",
|
|
38
|
+
)
|
|
39
|
+
if index % 2 == 0:
|
|
40
|
+
commit(
|
|
41
|
+
repo,
|
|
42
|
+
email="a@example.com",
|
|
43
|
+
date="2026-01-05",
|
|
44
|
+
message=f"test: {index}",
|
|
45
|
+
filename="tests/t.py",
|
|
46
|
+
)
|
|
47
|
+
return analyze_repository(repo, empty_identity(), Lineage(), scope="repo")
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
# --- (1) unit alignment ----------------------------------------------------
|
|
51
|
+
|
|
52
|
+
UNIT_TOKENS = (
|
|
53
|
+
"commits",
|
|
54
|
+
"days",
|
|
55
|
+
"ratio",
|
|
56
|
+
"actors",
|
|
57
|
+
"class",
|
|
58
|
+
"boolean",
|
|
59
|
+
"tags",
|
|
60
|
+
"dirs",
|
|
61
|
+
"manifests",
|
|
62
|
+
"markers",
|
|
63
|
+
"date",
|
|
64
|
+
"month-range",
|
|
65
|
+
"releases",
|
|
66
|
+
)
|
|
67
|
+
# lines whose VALUE unit must be echoed by the gloss: map line-prefix → required token(s)
|
|
68
|
+
_UNIT_EXPECTATIONS = [
|
|
69
|
+
# origin classes are all "commits"
|
|
70
|
+
("tenant_unique:", "コミット"),
|
|
71
|
+
("unresolved:", "コミット"),
|
|
72
|
+
("bot:", "コミット"),
|
|
73
|
+
("generated_or_vendor:", "コミット"),
|
|
74
|
+
("ambiguous_origin:", "コミット"),
|
|
75
|
+
("tenant_derivative:", "コミット"),
|
|
76
|
+
("external_upstream_contribution:", "コミット"),
|
|
77
|
+
("template_inherited:", "コミット"),
|
|
78
|
+
# activity
|
|
79
|
+
("tenant commits:", "コミット"),
|
|
80
|
+
("active days:", "日数"),
|
|
81
|
+
("commits per active day:", "密度"),
|
|
82
|
+
("active days (13 weeks):", "日数"),
|
|
83
|
+
]
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
def test_1_origin_glosses_carry_commit_unit() -> None:
|
|
87
|
+
for name, gloss in _ORIGIN_GLOSS.items():
|
|
88
|
+
if name in ("tenant_merge_or_sync", "upstream_sync"):
|
|
89
|
+
continue # flow-path glosses; line unit still commits but gloss is route
|
|
90
|
+
assert "コミット" in gloss, f"{name}: gloss lacks コミット unit: {gloss}"
|
|
91
|
+
assert "commits" in gloss or "PR" in gloss or "upstream" in gloss, (
|
|
92
|
+
f"{name}: gloss lacks en unit"
|
|
93
|
+
)
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
def test_1_every_glossed_line_echoes_its_unit(tmp_path: Path) -> None:
|
|
97
|
+
report = _repo_report(tmp_path)
|
|
98
|
+
markdown = render_markdown(report)
|
|
99
|
+
for line in markdown.splitlines():
|
|
100
|
+
if "—" not in line or not line.startswith("- "):
|
|
101
|
+
continue
|
|
102
|
+
gloss = line.split("—", 1)[1]
|
|
103
|
+
for prefix, token in _UNIT_EXPECTATIONS:
|
|
104
|
+
if prefix in line.split("—")[0]:
|
|
105
|
+
assert token in gloss, f"unit mismatch: {line.strip()[:80]}"
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
# --- (2) gloss vocabulary gate -----------------------------------------------
|
|
109
|
+
|
|
110
|
+
NORMATIVE = [
|
|
111
|
+
"良い",
|
|
112
|
+
"悪い",
|
|
113
|
+
"優れ",
|
|
114
|
+
"劣る",
|
|
115
|
+
"健全",
|
|
116
|
+
"理想",
|
|
117
|
+
"優秀",
|
|
118
|
+
"優劣",
|
|
119
|
+
"質が高",
|
|
120
|
+
"質が低",
|
|
121
|
+
"excellent",
|
|
122
|
+
"superior",
|
|
123
|
+
"inferior",
|
|
124
|
+
"healthy",
|
|
125
|
+
"ideal",
|
|
126
|
+
"good,",
|
|
127
|
+
"bad,",
|
|
128
|
+
]
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
def test_2_glosses_carry_no_normative_words(tmp_path: Path) -> None:
|
|
132
|
+
report = _repo_report(tmp_path)
|
|
133
|
+
markdown = render_markdown(report)
|
|
134
|
+
for line in markdown.splitlines():
|
|
135
|
+
if "—" not in line:
|
|
136
|
+
continue
|
|
137
|
+
gloss = line.split("—", 1)[1]
|
|
138
|
+
for word in NORMATIVE:
|
|
139
|
+
assert word not in gloss, f"normative word {word!r} in gloss: {gloss.strip()[:60]}"
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
def test_2_gloss_dictionary_clean() -> None:
|
|
143
|
+
for name, gloss in _ORIGIN_GLOSS.items():
|
|
144
|
+
for word in NORMATIVE:
|
|
145
|
+
assert word not in gloss, f"{name}: {word!r} in {gloss!r}"
|
|
146
|
+
|
|
147
|
+
|
|
148
|
+
# --- (3) report.json immutability --------------------------------------------
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
def test_3_report_json_has_no_gloss(tmp_path: Path) -> None:
|
|
152
|
+
report = _repo_report(tmp_path)
|
|
153
|
+
text = json.dumps(report, ensure_ascii=False)
|
|
154
|
+
for marker in ("—", "何を測るか", "このrepoのかたち", "gloss"):
|
|
155
|
+
assert marker not in text, f"report.json carries markdown gloss marker {marker!r}"
|
|
156
|
+
# schema untouched
|
|
157
|
+
assert report["schema_version"] == "report-v1"
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
def test_3_verify_unaffected_by_glosses(tmp_path: Path) -> None:
|
|
161
|
+
"""Glosses are markdown-only decoration: verify recomputes the report dict
|
|
162
|
+
and must return VERIFIED even after rendering the markdown."""
|
|
163
|
+
import copy
|
|
164
|
+
import json as _json
|
|
165
|
+
|
|
166
|
+
from tep_core.verify import VERIFIED, verify_report
|
|
167
|
+
|
|
168
|
+
report = _repo_report(tmp_path)
|
|
169
|
+
before = copy.deepcopy(report)
|
|
170
|
+
render_markdown(report)
|
|
171
|
+
assert report == before, "render_markdown must not mutate the report dict"
|
|
172
|
+
path = tmp_path / "report.json"
|
|
173
|
+
path.write_text(_json.dumps(report), encoding="utf-8")
|
|
174
|
+
outcome = verify_report(path, tmp_path / "repo")
|
|
175
|
+
assert outcome.status == VERIFIED
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
def test_4_shared_block_stays_gloss_free(tmp_path: Path) -> None:
|
|
179
|
+
"""(4) spec: Shared block carries no glosses (paste-friendly compactness)."""
|
|
180
|
+
from tep_core.report import shared_block as _sb
|
|
181
|
+
|
|
182
|
+
report = _repo_report(tmp_path)
|
|
183
|
+
for line in _sb(report):
|
|
184
|
+
assert "—" not in line, f"shared block line carries a gloss: {line}"
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+
def test_g1_no_standalone_paren_note_lines(tmp_path: Path) -> None:
|
|
188
|
+
"""G-1: section-header parenthetical notes are forbidden — glosses live
|
|
189
|
+
on value lines only (Test frameworks used to double-print the note)."""
|
|
190
|
+
report = _repo_report(tmp_path)
|
|
191
|
+
markdown = render_markdown(report)
|
|
192
|
+
for line in markdown.splitlines():
|
|
193
|
+
stripped = line.strip()
|
|
194
|
+
assert not (stripped.startswith("(") and stripped.endswith(")")), (
|
|
195
|
+
f"standalone paren note line present: {stripped[:50]}"
|
|
196
|
+
)
|
|
197
|
+
|
|
198
|
+
|
|
199
|
+
def test_g1_no_immediate_duplicate_gloss_lines(tmp_path: Path) -> None:
|
|
200
|
+
"""G-1: a repo with detected frameworks must not print the same gloss
|
|
201
|
+
twice in a row (header note + value line duplication pattern)."""
|
|
202
|
+
report = _repo_report(tmp_path)
|
|
203
|
+
markdown = render_markdown(report)
|
|
204
|
+
lines = markdown.splitlines()
|
|
205
|
+
for i in range(len(lines) - 1):
|
|
206
|
+
if "—" in lines[i] and "—" in lines[i + 1]:
|
|
207
|
+
g1 = lines[i].split("—", 1)[1].strip()
|
|
208
|
+
g2 = lines[i + 1].split("—", 1)[1].strip()
|
|
209
|
+
if g1 and g1 == g2:
|
|
210
|
+
raise AssertionError(f"consecutive duplicate glosses: {g1[:50]}")
|
|
@@ -135,14 +135,19 @@ def test_report_md_carries_meaning_one_liners(tmp_path, capsys):
|
|
|
135
135
|
from tep_core.report import render_markdown
|
|
136
136
|
|
|
137
137
|
markdown = render_markdown(report)
|
|
138
|
-
|
|
139
|
-
assert "
|
|
140
|
-
assert "
|
|
141
|
-
assert "
|
|
142
|
-
assert "
|
|
143
|
-
|
|
138
|
+
# v0.5.8+: glosses are INLINE on each value line (not section-level)
|
|
139
|
+
assert "share of production changes paired with tests in the same commit" in markdown
|
|
140
|
+
assert "not a bug count, not quality" in markdown
|
|
141
|
+
assert "share of lines still present after 6 months" in markdown
|
|
142
|
+
assert "shape of collaboration" in markdown
|
|
143
|
+
assert "unique days with human commits in the last 180 days" in markdown
|
|
144
|
+
assert "commits by identity-matched people" in markdown
|
|
145
|
+
# reader's guide is bilingual
|
|
144
146
|
assert "## この数値でしてはいけない判断 / Decisions these numbers must NOT be used for" in markdown
|
|
145
147
|
assert "not grades" in markdown and "non-compliant with the TEP norms" in markdown
|
|
148
|
+
# no leftover section-level explanation blocks
|
|
149
|
+
assert "(何を測るか / What this measures" not in markdown
|
|
150
|
+
assert "(このrepoのかたち / The shape of this repo" not in markdown
|
|
146
151
|
|
|
147
152
|
|
|
148
153
|
def test_49_open_fallback_without_gh(tmp_path, capsys, monkeypatch):
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|