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.

Files changed (129) hide show
  1. {grift_cli-0.5.8 → grift_cli-0.5.9}/.grift/contribution.json +46 -46
  2. {grift_cli-0.5.8 → grift_cli-0.5.9}/CHANGELOG.md +7 -0
  3. {grift_cli-0.5.8 → grift_cli-0.5.9}/PKG-INFO +5 -1
  4. {grift_cli-0.5.8 → grift_cli-0.5.9}/README.en.md +8 -0
  5. {grift_cli-0.5.8 → grift_cli-0.5.9}/README.md +4 -0
  6. {grift_cli-0.5.8 → grift_cli-0.5.9}/action.yml +1 -1
  7. {grift_cli-0.5.8 → grift_cli-0.5.9}/docs/metrics-guide.md +1 -1
  8. {grift_cli-0.5.8 → grift_cli-0.5.9}/pyproject.toml +1 -1
  9. {grift_cli-0.5.8 → grift_cli-0.5.9}/src/tep_core/report.py +35 -16
  10. {grift_cli-0.5.8 → grift_cli-0.5.9}/src/tep_core/version.py +2 -2
  11. grift_cli-0.5.9/tests/test_gloss_gates.py +210 -0
  12. {grift_cli-0.5.8 → grift_cli-0.5.9}/tests/test_ux_v057.py +11 -6
  13. {grift_cli-0.5.8 → grift_cli-0.5.9}/.github/workflows/ci.yml +0 -0
  14. {grift_cli-0.5.8 → grift_cli-0.5.9}/.github/workflows/kpi-monthly.yml +0 -0
  15. {grift_cli-0.5.8 → grift_cli-0.5.9}/.github/workflows/publish.yml +0 -0
  16. {grift_cli-0.5.8 → grift_cli-0.5.9}/.gitignore +0 -0
  17. {grift_cli-0.5.8 → grift_cli-0.5.9}/LICENSE +0 -0
  18. {grift_cli-0.5.8 → grift_cli-0.5.9}/corpus/AD-PILOT-20260822.md +0 -0
  19. {grift_cli-0.5.8 → grift_cli-0.5.9}/corpus/DISCRIMINANT-v2026.09.md +0 -0
  20. {grift_cli-0.5.8 → grift_cli-0.5.9}/corpus/DISCRIMINANT-v2026.11.md +0 -0
  21. {grift_cli-0.5.8 → grift_cli-0.5.9}/corpus/ad-pilot.json +0 -0
  22. {grift_cli-0.5.8 → grift_cli-0.5.9}/corpus/manifest.toml +0 -0
  23. {grift_cli-0.5.8 → grift_cli-0.5.9}/corpus/pins-v2026.09.toml +0 -0
  24. {grift_cli-0.5.8 → grift_cli-0.5.9}/corpus/pins-v2026.11.toml +0 -0
  25. {grift_cli-0.5.8 → grift_cli-0.5.9}/corpus/v2026.09/distributions.json +0 -0
  26. {grift_cli-0.5.8 → grift_cli-0.5.9}/corpus/v2026.11/distributions.json +0 -0
  27. {grift_cli-0.5.8 → grift_cli-0.5.9}/docs/corpus-protocol.md +0 -0
  28. {grift_cli-0.5.8 → grift_cli-0.5.9}/docs/coverage-map.md +0 -0
  29. {grift_cli-0.5.8 → grift_cli-0.5.9}/docs/en/corpus-protocol.md +0 -0
  30. {grift_cli-0.5.8 → grift_cli-0.5.9}/docs/en/coverage-map.md +0 -0
  31. {grift_cli-0.5.8 → grift_cli-0.5.9}/docs/en/export-schema.md +0 -0
  32. {grift_cli-0.5.8 → grift_cli-0.5.9}/docs/en/identity-schema.md +0 -0
  33. {grift_cli-0.5.8 → grift_cli-0.5.9}/docs/en/metrics-guide.md +0 -0
  34. {grift_cli-0.5.8 → grift_cli-0.5.9}/docs/en/norms.md +0 -0
  35. {grift_cli-0.5.8 → grift_cli-0.5.9}/docs/en/persona-answers.md +0 -0
  36. {grift_cli-0.5.8 → grift_cli-0.5.9}/docs/en/report-schema.md +0 -0
  37. {grift_cli-0.5.8 → grift_cli-0.5.9}/docs/export-schema.md +0 -0
  38. {grift_cli-0.5.8 → grift_cli-0.5.9}/docs/identity-schema.md +0 -0
  39. {grift_cli-0.5.8 → grift_cli-0.5.9}/docs/norms.md +0 -0
  40. {grift_cli-0.5.8 → grift_cli-0.5.9}/docs/persona-answers.md +0 -0
  41. {grift_cli-0.5.8 → grift_cli-0.5.9}/docs/report-schema.md +0 -0
  42. {grift_cli-0.5.8 → grift_cli-0.5.9}/golden/README.md +0 -0
  43. {grift_cli-0.5.8 → grift_cli-0.5.9}/golden/coverage.md +0 -0
  44. {grift_cli-0.5.8 → grift_cli-0.5.9}/golden/expected/G1-click.json +0 -0
  45. {grift_cli-0.5.8 → grift_cli-0.5.9}/golden/expected/G10-scvi-tools.json +0 -0
  46. {grift_cli-0.5.8 → grift_cli-0.5.9}/golden/expected/G11-kilo.json +0 -0
  47. {grift_cli-0.5.8 → grift_cli-0.5.9}/golden/expected/G12-httpx.json +0 -0
  48. {grift_cli-0.5.8 → grift_cli-0.5.9}/golden/expected/G13-voicevox.json +0 -0
  49. {grift_cli-0.5.8 → grift_cli-0.5.9}/golden/expected/G2-gitignore.json +0 -0
  50. {grift_cli-0.5.8 → grift_cli-0.5.9}/golden/expected/G3-spoon-knife.json +0 -0
  51. {grift_cli-0.5.8 → grift_cli-0.5.9}/golden/expected/G4-express.json +0 -0
  52. {grift_cli-0.5.8 → grift_cli-0.5.9}/golden/expected/G5-typer.json +0 -0
  53. {grift_cli-0.5.8 → grift_cli-0.5.9}/golden/expected/G6-claude-code.json +0 -0
  54. {grift_cli-0.5.8 → grift_cli-0.5.9}/golden/expected/G7-axios.json +0 -0
  55. {grift_cli-0.5.8 → grift_cli-0.5.9}/golden/expected/G8-co.json +0 -0
  56. {grift_cli-0.5.8 → grift_cli-0.5.9}/golden/expected/G9-pyscript.json +0 -0
  57. {grift_cli-0.5.8 → grift_cli-0.5.9}/golden/identity/G1-click.toml +0 -0
  58. {grift_cli-0.5.8 → grift_cli-0.5.9}/golden/identity/example.toml +0 -0
  59. {grift_cli-0.5.8 → grift_cli-0.5.9}/golden/pins.toml +0 -0
  60. {grift_cli-0.5.8 → grift_cli-0.5.9}/scripts/admission_v2026_11.py +0 -0
  61. {grift_cli-0.5.8 → grift_cli-0.5.9}/scripts/build_dist_v2026_11.py +0 -0
  62. {grift_cli-0.5.8 → grift_cli-0.5.9}/scripts/build_distributions.py +0 -0
  63. {grift_cli-0.5.8 → grift_cli-0.5.9}/scripts/check_forbidden_vocab.py +0 -0
  64. {grift_cli-0.5.8 → grift_cli-0.5.9}/scripts/corpus_ad_pilot.py +0 -0
  65. {grift_cli-0.5.8 → grift_cli-0.5.9}/scripts/corpus_run.py +0 -0
  66. {grift_cli-0.5.8 → grift_cli-0.5.9}/scripts/discriminant_v2026.py +0 -0
  67. {grift_cli-0.5.8 → grift_cli-0.5.9}/scripts/discriminant_v2026_11.py +0 -0
  68. {grift_cli-0.5.8 → grift_cli-0.5.9}/scripts/gen_coverage_table.py +0 -0
  69. {grift_cli-0.5.8 → grift_cli-0.5.9}/scripts/gen_golden_expected.py +0 -0
  70. {grift_cli-0.5.8 → grift_cli-0.5.9}/scripts/hygiene_grep.py +0 -0
  71. {grift_cli-0.5.8 → grift_cli-0.5.9}/src/tep_cli/__init__.py +0 -0
  72. {grift_cli-0.5.8 → grift_cli-0.5.9}/src/tep_cli/__main__.py +0 -0
  73. {grift_cli-0.5.8 → grift_cli-0.5.9}/src/tep_core/__init__.py +0 -0
  74. {grift_cli-0.5.8 → grift_cli-0.5.9}/src/tep_core/activity.py +0 -0
  75. {grift_cli-0.5.8 → grift_cli-0.5.9}/src/tep_core/analyze.py +0 -0
  76. {grift_cli-0.5.8 → grift_cli-0.5.9}/src/tep_core/cochange.py +0 -0
  77. {grift_cli-0.5.8 → grift_cli-0.5.9}/src/tep_core/context_profile.py +0 -0
  78. {grift_cli-0.5.8 → grift_cli-0.5.9}/src/tep_core/contribute.py +0 -0
  79. {grift_cli-0.5.8 → grift_cli-0.5.9}/src/tep_core/core_period.py +0 -0
  80. {grift_cli-0.5.8 → grift_cli-0.5.9}/src/tep_core/data/v2026.09/distributions.json +0 -0
  81. {grift_cli-0.5.8 → grift_cli-0.5.9}/src/tep_core/data/v2026.11/distributions.json +0 -0
  82. {grift_cli-0.5.8 → grift_cli-0.5.9}/src/tep_core/export.py +0 -0
  83. {grift_cli-0.5.8 → grift_cli-0.5.9}/src/tep_core/gitutil.py +0 -0
  84. {grift_cli-0.5.8 → grift_cli-0.5.9}/src/tep_core/identity.py +0 -0
  85. {grift_cli-0.5.8 → grift_cli-0.5.9}/src/tep_core/lineage.py +0 -0
  86. {grift_cli-0.5.8 → grift_cli-0.5.9}/src/tep_core/observation.py +0 -0
  87. {grift_cli-0.5.8 → grift_cli-0.5.9}/src/tep_core/origin.py +0 -0
  88. {grift_cli-0.5.8 → grift_cli-0.5.9}/src/tep_core/paths.py +0 -0
  89. {grift_cli-0.5.8 → grift_cli-0.5.9}/src/tep_core/reference.py +0 -0
  90. {grift_cli-0.5.8 → grift_cli-0.5.9}/src/tep_core/rework.py +0 -0
  91. {grift_cli-0.5.8 → grift_cli-0.5.9}/src/tep_core/schema.py +0 -0
  92. {grift_cli-0.5.8 → grift_cli-0.5.9}/src/tep_core/scope.py +0 -0
  93. {grift_cli-0.5.8 → grift_cli-0.5.9}/src/tep_core/survival.py +0 -0
  94. {grift_cli-0.5.8 → grift_cli-0.5.9}/src/tep_core/tests_observed.py +0 -0
  95. {grift_cli-0.5.8 → grift_cli-0.5.9}/src/tep_core/verify.py +0 -0
  96. {grift_cli-0.5.8 → grift_cli-0.5.9}/tests/conftest.py +0 -0
  97. {grift_cli-0.5.8 → grift_cli-0.5.9}/tests/coverage_matrix.py +0 -0
  98. {grift_cli-0.5.8 → grift_cli-0.5.9}/tests/git_fixture.py +0 -0
  99. {grift_cli-0.5.8 → grift_cli-0.5.9}/tests/test_activity.py +0 -0
  100. {grift_cli-0.5.8 → grift_cli-0.5.9}/tests/test_cli.py +0 -0
  101. {grift_cli-0.5.8 → grift_cli-0.5.9}/tests/test_cochange.py +0 -0
  102. {grift_cli-0.5.8 → grift_cli-0.5.9}/tests/test_context_profile.py +0 -0
  103. {grift_cli-0.5.8 → grift_cli-0.5.9}/tests/test_contribute.py +0 -0
  104. {grift_cli-0.5.8 → grift_cli-0.5.9}/tests/test_coverage.py +0 -0
  105. {grift_cli-0.5.8 → grift_cli-0.5.9}/tests/test_default_report_path.py +0 -0
  106. {grift_cli-0.5.8 → grift_cli-0.5.9}/tests/test_discriminant_claims.py +0 -0
  107. {grift_cli-0.5.8 → grift_cli-0.5.9}/tests/test_export.py +0 -0
  108. {grift_cli-0.5.8 → grift_cli-0.5.9}/tests/test_export_recipe.py +0 -0
  109. {grift_cli-0.5.8 → grift_cli-0.5.9}/tests/test_forbidden_vocab.py +0 -0
  110. {grift_cli-0.5.8 → grift_cli-0.5.9}/tests/test_gitutil.py +0 -0
  111. {grift_cli-0.5.8 → grift_cli-0.5.9}/tests/test_golden.py +0 -0
  112. {grift_cli-0.5.8 → grift_cli-0.5.9}/tests/test_h5_swarm.py +0 -0
  113. {grift_cli-0.5.8 → grift_cli-0.5.9}/tests/test_hygiene.py +0 -0
  114. {grift_cli-0.5.8 → grift_cli-0.5.9}/tests/test_identity_validation.py +0 -0
  115. {grift_cli-0.5.8 → grift_cli-0.5.9}/tests/test_intake_disclosure.py +0 -0
  116. {grift_cli-0.5.8 → grift_cli-0.5.9}/tests/test_lifecycle_v2.py +0 -0
  117. {grift_cli-0.5.8 → grift_cli-0.5.9}/tests/test_not_observed.py +0 -0
  118. {grift_cli-0.5.8 → grift_cli-0.5.9}/tests/test_origin.py +0 -0
  119. {grift_cli-0.5.8 → grift_cli-0.5.9}/tests/test_persona_answers.py +0 -0
  120. {grift_cli-0.5.8 → grift_cli-0.5.9}/tests/test_release_gate.py +0 -0
  121. {grift_cli-0.5.8 → grift_cli-0.5.9}/tests/test_report.py +0 -0
  122. {grift_cli-0.5.8 → grift_cli-0.5.9}/tests/test_rework.py +0 -0
  123. {grift_cli-0.5.8 → grift_cli-0.5.9}/tests/test_schema.py +0 -0
  124. {grift_cli-0.5.8 → grift_cli-0.5.9}/tests/test_scope.py +0 -0
  125. {grift_cli-0.5.8 → grift_cli-0.5.9}/tests/test_shared_block.py +0 -0
  126. {grift_cli-0.5.8 → grift_cli-0.5.9}/tests/test_survival.py +0 -0
  127. {grift_cli-0.5.8 → grift_cli-0.5.9}/tests/test_v058_gates.py +0 -0
  128. {grift_cli-0.5.8 → grift_cli-0.5.9}/tests/test_verb_semantics.py +0 -0
  129. {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.8",
7
- "definition_version": "tep-v0.5.8-2026-08-25",
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.8",
17
- "definition_version": "tep-v0.5.8-2026-08-25",
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-25T06:16:56Z"
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
- "definition_version": "context-v3-2026-08-25",
171
- "analysis_scope": "repo",
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
- "kind": "observed",
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
- "pr_flow_share": {
223
+ "conventional_commit_share": {
221
224
  "kind": "observed",
222
- "value": 0.0,
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
- "conventional_commit_share": {
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": "manifests"
247
+ "unit": "markers"
249
248
  },
250
- "docs_share": {
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.8
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 は放置ではない)も表にしてあります。
@@ -16,7 +16,7 @@ inputs:
16
16
  version:
17
17
  description: "grift-cli version to install (pinned)"
18
18
  required: false
19
- default: "0.5.8"
19
+ default: "0.5.9"
20
20
  comment:
21
21
  description: "Opt-in: post the shared block as a PR comment (default off)"
22
22
  required: false
@@ -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(検証を伴った変更の割合)
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "grift-cli"
3
- version = "0.5.8"
3
+ version = "0.5.9"
4
4
  description = "Deterministic TEP evidence metrics from a single git repository. No LLM."
5
5
  readme = "README.md"
6
6
  license = { text = "MIT" }
@@ -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
- lines.append(f"- {label}: {_fmt_obs(obs)}")
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(f"- observed: {names} (boolean {tests.get('value')})")
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
- "(何を測るか / What this measures: 本番コードを変えたコミットのうち、同じコミットでテストも変更した割合。高い=変更にテストが伴う習慣。テストが前提でない仕事は正当に低くなる — the share of production-changing commits whose same commit also changed tests. High = the habit of pairing changes with tests. Work where tests are not the norm legitimately lands low.)",
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
- "(何を測るか / What this measures: 6ヶ月後も残っている行の割合。1.0に近い=書いたものが残り続けている — the share of lines still present after 6 months. Near 1.0 = what was written keeps living.)",
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.8"
1
+ __version__ = "0.5.9"
2
2
  REPORT_SCHEMA_VERSION = "report-v1"
3
- DEFINITION_VERSION = "tep-v0.5.8-2026-08-25"
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
- assert "何を測るか / What this measures" in markdown
139
- assert "本番コードを変えたコミットのうち" in markdown and "share of production-changing commits" in markdown
140
- assert "バグ件数でも品質でもなく" in markdown and "not a bug count" in markdown
141
- assert "このrepoのかたち / The shape of this repo" in markdown
142
- assert "直近180日で人がコミットした日数" in markdown and "unique days with human commits" in markdown
143
- # reader's guide is bilingual too
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