grift-cli 0.5.2__tar.gz → 0.5.3__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.
Files changed (115) hide show
  1. {grift_cli-0.5.2 → grift_cli-0.5.3}/CHANGELOG.md +14 -0
  2. {grift_cli-0.5.2 → grift_cli-0.5.3}/PKG-INFO +3 -3
  3. {grift_cli-0.5.2 → grift_cli-0.5.3}/README.en.md +1 -1
  4. {grift_cli-0.5.2 → grift_cli-0.5.3}/README.md +2 -2
  5. {grift_cli-0.5.2 → grift_cli-0.5.3}/action.yml +1 -1
  6. {grift_cli-0.5.2 → grift_cli-0.5.3}/pyproject.toml +1 -1
  7. {grift_cli-0.5.2 → grift_cli-0.5.3}/scripts/hygiene_grep.py +4 -0
  8. {grift_cli-0.5.2 → grift_cli-0.5.3}/src/tep_cli/__main__.py +75 -10
  9. {grift_cli-0.5.2 → grift_cli-0.5.3}/src/tep_core/version.py +2 -2
  10. grift_cli-0.5.3/tests/test_default_report_path.py +114 -0
  11. {grift_cli-0.5.2 → grift_cli-0.5.3}/tests/test_hygiene.py +4 -0
  12. {grift_cli-0.5.2 → grift_cli-0.5.3}/.github/workflows/ci.yml +0 -0
  13. {grift_cli-0.5.2 → grift_cli-0.5.3}/.github/workflows/kpi-monthly.yml +0 -0
  14. {grift_cli-0.5.2 → grift_cli-0.5.3}/.github/workflows/publish-testpypi.yml +0 -0
  15. {grift_cli-0.5.2 → grift_cli-0.5.3}/.github/workflows/publish.yml +0 -0
  16. {grift_cli-0.5.2 → grift_cli-0.5.3}/.gitignore +0 -0
  17. {grift_cli-0.5.2 → grift_cli-0.5.3}/LICENSE +0 -0
  18. {grift_cli-0.5.2 → grift_cli-0.5.3}/corpus/AD-PILOT-20260822.md +0 -0
  19. {grift_cli-0.5.2 → grift_cli-0.5.3}/corpus/DISCRIMINANT-v2026.09.md +0 -0
  20. {grift_cli-0.5.2 → grift_cli-0.5.3}/corpus/DISCRIMINANT-v2026.11.md +0 -0
  21. {grift_cli-0.5.2 → grift_cli-0.5.3}/corpus/ad-pilot.json +0 -0
  22. {grift_cli-0.5.2 → grift_cli-0.5.3}/corpus/manifest.toml +0 -0
  23. {grift_cli-0.5.2 → grift_cli-0.5.3}/corpus/pins-v2026.09.toml +0 -0
  24. {grift_cli-0.5.2 → grift_cli-0.5.3}/corpus/pins-v2026.11.toml +0 -0
  25. {grift_cli-0.5.2 → grift_cli-0.5.3}/corpus/v2026.09/distributions.json +0 -0
  26. {grift_cli-0.5.2 → grift_cli-0.5.3}/corpus/v2026.11/distributions.json +0 -0
  27. {grift_cli-0.5.2 → grift_cli-0.5.3}/docs/corpus-protocol.md +0 -0
  28. {grift_cli-0.5.2 → grift_cli-0.5.3}/docs/coverage-map.md +0 -0
  29. {grift_cli-0.5.2 → grift_cli-0.5.3}/docs/export-schema.md +0 -0
  30. {grift_cli-0.5.2 → grift_cli-0.5.3}/docs/identity-schema.md +0 -0
  31. {grift_cli-0.5.2 → grift_cli-0.5.3}/docs/norms.md +0 -0
  32. {grift_cli-0.5.2 → grift_cli-0.5.3}/docs/persona-answers.md +0 -0
  33. {grift_cli-0.5.2 → grift_cli-0.5.3}/docs/report-schema.md +0 -0
  34. {grift_cli-0.5.2 → grift_cli-0.5.3}/golden/README.md +0 -0
  35. {grift_cli-0.5.2 → grift_cli-0.5.3}/golden/coverage.md +0 -0
  36. {grift_cli-0.5.2 → grift_cli-0.5.3}/golden/expected/G1-click.json +0 -0
  37. {grift_cli-0.5.2 → grift_cli-0.5.3}/golden/expected/G10-scvi-tools.json +0 -0
  38. {grift_cli-0.5.2 → grift_cli-0.5.3}/golden/expected/G11-kilo.json +0 -0
  39. {grift_cli-0.5.2 → grift_cli-0.5.3}/golden/expected/G12-httpx.json +0 -0
  40. {grift_cli-0.5.2 → grift_cli-0.5.3}/golden/expected/G13-voicevox.json +0 -0
  41. {grift_cli-0.5.2 → grift_cli-0.5.3}/golden/expected/G2-gitignore.json +0 -0
  42. {grift_cli-0.5.2 → grift_cli-0.5.3}/golden/expected/G3-spoon-knife.json +0 -0
  43. {grift_cli-0.5.2 → grift_cli-0.5.3}/golden/expected/G4-express.json +0 -0
  44. {grift_cli-0.5.2 → grift_cli-0.5.3}/golden/expected/G5-typer.json +0 -0
  45. {grift_cli-0.5.2 → grift_cli-0.5.3}/golden/expected/G6-claude-code.json +0 -0
  46. {grift_cli-0.5.2 → grift_cli-0.5.3}/golden/expected/G7-axios.json +0 -0
  47. {grift_cli-0.5.2 → grift_cli-0.5.3}/golden/expected/G8-co.json +0 -0
  48. {grift_cli-0.5.2 → grift_cli-0.5.3}/golden/expected/G9-pyscript.json +0 -0
  49. {grift_cli-0.5.2 → grift_cli-0.5.3}/golden/identity/G1-click.toml +0 -0
  50. {grift_cli-0.5.2 → grift_cli-0.5.3}/golden/identity/example.toml +0 -0
  51. {grift_cli-0.5.2 → grift_cli-0.5.3}/golden/pins.toml +0 -0
  52. {grift_cli-0.5.2 → grift_cli-0.5.3}/scripts/admission_v2026_11.py +0 -0
  53. {grift_cli-0.5.2 → grift_cli-0.5.3}/scripts/build_dist_v2026_11.py +0 -0
  54. {grift_cli-0.5.2 → grift_cli-0.5.3}/scripts/build_distributions.py +0 -0
  55. {grift_cli-0.5.2 → grift_cli-0.5.3}/scripts/check_forbidden_vocab.py +0 -0
  56. {grift_cli-0.5.2 → grift_cli-0.5.3}/scripts/corpus_ad_pilot.py +0 -0
  57. {grift_cli-0.5.2 → grift_cli-0.5.3}/scripts/corpus_run.py +0 -0
  58. {grift_cli-0.5.2 → grift_cli-0.5.3}/scripts/discriminant_v2026.py +0 -0
  59. {grift_cli-0.5.2 → grift_cli-0.5.3}/scripts/discriminant_v2026_11.py +0 -0
  60. {grift_cli-0.5.2 → grift_cli-0.5.3}/scripts/gen_coverage_table.py +0 -0
  61. {grift_cli-0.5.2 → grift_cli-0.5.3}/scripts/gen_golden_expected.py +0 -0
  62. {grift_cli-0.5.2 → grift_cli-0.5.3}/src/tep_cli/__init__.py +0 -0
  63. {grift_cli-0.5.2 → grift_cli-0.5.3}/src/tep_core/__init__.py +0 -0
  64. {grift_cli-0.5.2 → grift_cli-0.5.3}/src/tep_core/activity.py +0 -0
  65. {grift_cli-0.5.2 → grift_cli-0.5.3}/src/tep_core/analyze.py +0 -0
  66. {grift_cli-0.5.2 → grift_cli-0.5.3}/src/tep_core/cochange.py +0 -0
  67. {grift_cli-0.5.2 → grift_cli-0.5.3}/src/tep_core/context_profile.py +0 -0
  68. {grift_cli-0.5.2 → grift_cli-0.5.3}/src/tep_core/contribute.py +0 -0
  69. {grift_cli-0.5.2 → grift_cli-0.5.3}/src/tep_core/core_period.py +0 -0
  70. {grift_cli-0.5.2 → grift_cli-0.5.3}/src/tep_core/data/v2026.09/distributions.json +0 -0
  71. {grift_cli-0.5.2 → grift_cli-0.5.3}/src/tep_core/data/v2026.11/distributions.json +0 -0
  72. {grift_cli-0.5.2 → grift_cli-0.5.3}/src/tep_core/export.py +0 -0
  73. {grift_cli-0.5.2 → grift_cli-0.5.3}/src/tep_core/gitutil.py +0 -0
  74. {grift_cli-0.5.2 → grift_cli-0.5.3}/src/tep_core/identity.py +0 -0
  75. {grift_cli-0.5.2 → grift_cli-0.5.3}/src/tep_core/lineage.py +0 -0
  76. {grift_cli-0.5.2 → grift_cli-0.5.3}/src/tep_core/observation.py +0 -0
  77. {grift_cli-0.5.2 → grift_cli-0.5.3}/src/tep_core/origin.py +0 -0
  78. {grift_cli-0.5.2 → grift_cli-0.5.3}/src/tep_core/paths.py +0 -0
  79. {grift_cli-0.5.2 → grift_cli-0.5.3}/src/tep_core/reference.py +0 -0
  80. {grift_cli-0.5.2 → grift_cli-0.5.3}/src/tep_core/report.py +0 -0
  81. {grift_cli-0.5.2 → grift_cli-0.5.3}/src/tep_core/rework.py +0 -0
  82. {grift_cli-0.5.2 → grift_cli-0.5.3}/src/tep_core/schema.py +0 -0
  83. {grift_cli-0.5.2 → grift_cli-0.5.3}/src/tep_core/scope.py +0 -0
  84. {grift_cli-0.5.2 → grift_cli-0.5.3}/src/tep_core/survival.py +0 -0
  85. {grift_cli-0.5.2 → grift_cli-0.5.3}/src/tep_core/tests_observed.py +0 -0
  86. {grift_cli-0.5.2 → grift_cli-0.5.3}/src/tep_core/verify.py +0 -0
  87. {grift_cli-0.5.2 → grift_cli-0.5.3}/tests/conftest.py +0 -0
  88. {grift_cli-0.5.2 → grift_cli-0.5.3}/tests/coverage_matrix.py +0 -0
  89. {grift_cli-0.5.2 → grift_cli-0.5.3}/tests/git_fixture.py +0 -0
  90. {grift_cli-0.5.2 → grift_cli-0.5.3}/tests/test_activity.py +0 -0
  91. {grift_cli-0.5.2 → grift_cli-0.5.3}/tests/test_cli.py +0 -0
  92. {grift_cli-0.5.2 → grift_cli-0.5.3}/tests/test_cochange.py +0 -0
  93. {grift_cli-0.5.2 → grift_cli-0.5.3}/tests/test_context_profile.py +0 -0
  94. {grift_cli-0.5.2 → grift_cli-0.5.3}/tests/test_contribute.py +0 -0
  95. {grift_cli-0.5.2 → grift_cli-0.5.3}/tests/test_coverage.py +0 -0
  96. {grift_cli-0.5.2 → grift_cli-0.5.3}/tests/test_discriminant_claims.py +0 -0
  97. {grift_cli-0.5.2 → grift_cli-0.5.3}/tests/test_export.py +0 -0
  98. {grift_cli-0.5.2 → grift_cli-0.5.3}/tests/test_export_recipe.py +0 -0
  99. {grift_cli-0.5.2 → grift_cli-0.5.3}/tests/test_forbidden_vocab.py +0 -0
  100. {grift_cli-0.5.2 → grift_cli-0.5.3}/tests/test_gitutil.py +0 -0
  101. {grift_cli-0.5.2 → grift_cli-0.5.3}/tests/test_golden.py +0 -0
  102. {grift_cli-0.5.2 → grift_cli-0.5.3}/tests/test_h5_swarm.py +0 -0
  103. {grift_cli-0.5.2 → grift_cli-0.5.3}/tests/test_identity_validation.py +0 -0
  104. {grift_cli-0.5.2 → grift_cli-0.5.3}/tests/test_lifecycle_v2.py +0 -0
  105. {grift_cli-0.5.2 → grift_cli-0.5.3}/tests/test_not_observed.py +0 -0
  106. {grift_cli-0.5.2 → grift_cli-0.5.3}/tests/test_origin.py +0 -0
  107. {grift_cli-0.5.2 → grift_cli-0.5.3}/tests/test_persona_answers.py +0 -0
  108. {grift_cli-0.5.2 → grift_cli-0.5.3}/tests/test_release_gate.py +0 -0
  109. {grift_cli-0.5.2 → grift_cli-0.5.3}/tests/test_report.py +0 -0
  110. {grift_cli-0.5.2 → grift_cli-0.5.3}/tests/test_rework.py +0 -0
  111. {grift_cli-0.5.2 → grift_cli-0.5.3}/tests/test_schema.py +0 -0
  112. {grift_cli-0.5.2 → grift_cli-0.5.3}/tests/test_scope.py +0 -0
  113. {grift_cli-0.5.2 → grift_cli-0.5.3}/tests/test_shared_block.py +0 -0
  114. {grift_cli-0.5.2 → grift_cli-0.5.3}/tests/test_survival.py +0 -0
  115. {grift_cli-0.5.2 → grift_cli-0.5.3}/tests/test_verify.py +0 -0
@@ -4,6 +4,20 @@
4
4
 
5
5
  タグ・PyPI・リポ public 化は本ファイルの記載対象外(人間ゲート)。
6
6
 
7
+ ## [0.5.3] — 2026-08-23
8
+
9
+ UX 改善(代表フィードバック)+ 公開 README の整合。
10
+
11
+ ### Changed
12
+
13
+ - **`grift report`(引数なし)= そのディレクトリを分析して `./out/report.{json,md}` を自動作成**(`out/` がなければ作る)。引数を渡した場合は従来どおり既存 JSON からの再レンダリング(再分析なし)
14
+ - `grift contribute`(引数なし)は `./out/report.json` → `.grift-out/report.json` → `./report.json` を自動探索。無ければ「先に `grift report` を」と案内
15
+ - GitHub Action の使用例を `@v0.5.2` ぼ更新・「本公開は別ゲート」注記を公開済み表示に更新(README 日英)
16
+
17
+ ### Fixed
18
+
19
+ - hygiene 除外リストに内部調査文書プレフィックス(SMOKE / REREVIEW / RELEASE-REHEARSAL / INTERNAL-PILOT)を追加
20
+
7
21
  ## [0.5.2] — 2026-08-23
8
22
 
9
23
  基準の憲法(norms / reader's guide / verify)+ 文脈層(context_profile v2・lifecycle-v2)+ corpus v2026.11 + contribute。
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: grift-cli
3
- Version: 0.5.2
3
+ Version: 0.5.3
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
@@ -107,7 +107,7 @@ v2026.09 の記録(Run 2: A vs C `separated` ほか)は `corpus/DISCRIMINANT
107
107
  ## GitHub Action(観測のみ)
108
108
 
109
109
  ```yaml
110
- uses: Cor-Incorporated/grift-cli@v0.5.1
110
+ uses: Cor-Incorporated/grift-cli@v0.5.3
111
111
  with:
112
112
  scope: repo
113
113
  ```
@@ -128,7 +128,7 @@ with:
128
128
 
129
129
  - 公開リポ: https://github.com/Cor-Incorporated/grift-cli
130
130
  - コマンド名: **`grift`**(方法論名 TEP はレポートに残す)
131
- - PyPI: 配布名 **`grift-cli`**。本公開は別ゲート(未了ならソースから `pipx install .`)
131
+ - PyPI: 配布名 **`grift-cli`**(最新 0.5.2 を公開済み: `pipx install grift-cli`)
132
132
 
133
133
  ## License
134
134
 
@@ -82,7 +82,7 @@ The v2026.09 record (Run 2: A vs C `separated` etc.) remains as history in `corp
82
82
  ## GitHub Action (observation only)
83
83
 
84
84
  ```yaml
85
- uses: Cor-Incorporated/grift-cli@v0.5.1
85
+ uses: Cor-Incorporated/grift-cli@v0.5.3
86
86
  with:
87
87
  scope: repo
88
88
  ```
@@ -84,7 +84,7 @@ v2026.09 の記録(Run 2: A vs C `separated` ほか)は `corpus/DISCRIMINANT
84
84
  ## GitHub Action(観測のみ)
85
85
 
86
86
  ```yaml
87
- uses: Cor-Incorporated/grift-cli@v0.5.1
87
+ uses: Cor-Incorporated/grift-cli@v0.5.3
88
88
  with:
89
89
  scope: repo
90
90
  ```
@@ -105,7 +105,7 @@ with:
105
105
 
106
106
  - 公開リポ: https://github.com/Cor-Incorporated/grift-cli
107
107
  - コマンド名: **`grift`**(方法論名 TEP はレポートに残す)
108
- - PyPI: 配布名 **`grift-cli`**。本公開は別ゲート(未了ならソースから `pipx install .`)
108
+ - PyPI: 配布名 **`grift-cli`**(最新 0.5.2 を公開済み: `pipx install grift-cli`)
109
109
 
110
110
  ## License
111
111
 
@@ -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.1"
19
+ default: "0.5.3"
20
20
  comment:
21
21
  description: "Opt-in: post the shared block as a PR comment (default off)"
22
22
  required: false
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "grift-cli"
3
- version = "0.5.2"
3
+ version = "0.5.3"
4
4
  description = "Deterministic TEP evidence metrics from a single git repository. No LLM."
5
5
  readme = "README.md"
6
6
  license = { text = "MIT" }
@@ -56,6 +56,10 @@ def main() -> int:
56
56
  ":!docs/PREPUB*",
57
57
  ":!docs/kpi*",
58
58
  ":!docs/pilot*",
59
+ ":!docs/SMOKE*",
60
+ ":!docs/REREVIEW*",
61
+ ":!docs/RELEASE-REHEARSAL*",
62
+ ":!docs/INTERNAL-PILOT*",
59
63
  ],
60
64
  cwd=ROOT,
61
65
  capture_output=True,
@@ -16,10 +16,11 @@ from tep_core.verify import CANNOT_VERIFY, MISMATCH, VERIFIED, verify_report
16
16
  from tep_core.version import __version__
17
17
 
18
18
  _EPILOG = """examples:
19
- grift analyze . --scope repo
20
- grift analyze ./repo --format md --out ./out
19
+ grift report # analyze the current repo → ./out/report.{json,md}
20
+ grift report path/report.json # re-render md from an existing report (no re-analysis)
21
+ grift analyze . --scope repo --out ./out
21
22
  grift verify ./out/report.json --repo ./repo
22
- grift contribute ./out/report.json --out contribution.json
23
+ grift contribute # build opt-in payload from ./out/report.json (never sends)
23
24
  詳細: README"""
24
25
 
25
26
 
@@ -141,11 +142,17 @@ def build_parser() -> argparse.ArgumentParser:
141
142
 
142
143
  render = sub.add_parser(
143
144
  "report",
144
- help="Re-render report.md from an existing report.json (no re-analysis)",
145
+ help="Analyze the current repo and write ./out/report.{json,md}; or re-render md from an existing report.json",
145
146
  epilog=_EPILOG,
146
147
  formatter_class=argparse.RawDescriptionHelpFormatter,
147
148
  )
148
- render.add_argument("report_json", type=Path, help="Path to report.json")
149
+ render.add_argument(
150
+ "report_json",
151
+ type=Path,
152
+ nargs="?",
153
+ default=None,
154
+ help="Path to an existing report.json to re-render (default: analyze the current repo into ./out)",
155
+ )
149
156
  render.add_argument(
150
157
  "--out",
151
158
  type=Path,
@@ -159,7 +166,13 @@ def build_parser() -> argparse.ArgumentParser:
159
166
  epilog=_EPILOG,
160
167
  formatter_class=argparse.RawDescriptionHelpFormatter,
161
168
  )
162
- contribute.add_argument("report_json", type=Path, help="Path to a repo-scope report.json")
169
+ contribute.add_argument(
170
+ "report_json",
171
+ type=Path,
172
+ nargs="?",
173
+ default=None,
174
+ help="Path to a repo-scope report.json (default: search ./out, .grift-out, ./)",
175
+ )
163
176
  contribute.add_argument(
164
177
  "--out",
165
178
  type=Path,
@@ -243,11 +256,33 @@ def _run_verify(args: argparse.Namespace) -> int:
243
256
  return 2
244
257
 
245
258
 
259
+ _DEFAULT_REPORT_SEARCH = (
260
+ Path("out") / "report.json",
261
+ Path(".grift-out") / "report.json",
262
+ Path("report.json"),
263
+ )
264
+
265
+
266
+ def _resolve_report_path(explicit: Path | None) -> tuple[Path | None, str]:
267
+ """Return (path, guidance). Search ./out, .grift-out, ./ when no explicit path."""
268
+ if explicit is not None:
269
+ return explicit, ""
270
+ for candidate in _DEFAULT_REPORT_SEARCH:
271
+ if candidate.is_file():
272
+ return candidate, ""
273
+ return None, ""
274
+
275
+
246
276
  def _run_report(args: argparse.Namespace) -> int:
277
+ report_path, _guidance = _resolve_report_path(args.report_json)
278
+ if report_path is None:
279
+ # UX (代表 2026-08-23): bare `grift report` in a repo with no prior
280
+ # output = run the analysis now and write ./out/report.{json,md}.
281
+ return _analyze_to_out(scope="repo")
247
282
  try:
248
- payload = json.loads(args.report_json.read_text(encoding="utf-8"))
283
+ payload = json.loads(report_path.read_text(encoding="utf-8"))
249
284
  except (OSError, json.JSONDecodeError) as exc:
250
- sys.stderr.write(f"report unreadable: {exc}\n")
285
+ sys.stderr.write(f"report unreadable ({report_path}): {exc}\n")
251
286
  return 2
252
287
  try:
253
288
  markdown = render_markdown(payload)
@@ -263,13 +298,43 @@ def _run_report(args: argparse.Namespace) -> int:
263
298
  return 0
264
299
 
265
300
 
301
+ def _analyze_to_out(*, scope: str = "repo") -> int:
302
+ """Run the analysis in the current directory and write ./out/report.{json,md}.
303
+
304
+ UX (代表 2026-08-23): bare `grift report` should just produce the reports —
305
+ create ./out if missing. Reuses the analyze pipeline on '.'.
306
+ """
307
+ repo = Path(".")
308
+ if not (repo / ".git").exists():
309
+ sys.stderr.write("grift: not a git repository (run inside the repo you want to analyze)\n")
310
+ return 2
311
+ identity = discover_identity(repo, None)
312
+ report = analyze_repository(repo, identity, Lineage(), scope=scope)
313
+ markdown = render_markdown(report)
314
+ encoded = json.dumps(report, indent=2, ensure_ascii=False) + "\n"
315
+ out_dir = Path("out")
316
+ out_dir.mkdir(parents=True, exist_ok=True)
317
+ (out_dir / "report.json").write_text(encoded, encoding="utf-8")
318
+ (out_dir / "report.md").write_text(markdown, encoding="utf-8")
319
+ sys.stdout.write(markdown)
320
+ sys.stderr.write(f"\nwrote {out_dir / 'report.json'} and {out_dir / 'report.md'}\n")
321
+ return 0
322
+
323
+
266
324
  def _run_contribute(args: argparse.Namespace) -> int:
267
325
  from tep_core.contribute import CONFIRMATION_TEXT, build_contribution, render_confirmation
268
326
 
327
+ report_path, _guidance = _resolve_report_path(args.report_json)
328
+ if report_path is None:
329
+ sys.stderr.write(
330
+ "contribute: no report.json found (searched ./out/report.json, .grift-out/report.json, ./report.json). "
331
+ "Run `grift report` first — it will analyze the repo and write ./out/report.json.\n"
332
+ )
333
+ return 2
269
334
  try:
270
- report = json.loads(args.report_json.read_text(encoding="utf-8"))
335
+ report = json.loads(report_path.read_text(encoding="utf-8"))
271
336
  except (OSError, json.JSONDecodeError) as exc:
272
- sys.stderr.write(f"report unreadable: {exc}\n")
337
+ sys.stderr.write(f"report unreadable ({report_path}): {exc}\n")
273
338
  return 2
274
339
  try:
275
340
  payload = build_contribution(report)
@@ -1,6 +1,6 @@
1
- __version__ = "0.5.2"
1
+ __version__ = "0.5.3"
2
2
  REPORT_SCHEMA_VERSION = "report-v1"
3
- DEFINITION_VERSION = "tep-v0.5.2-2026-08-23"
3
+ DEFINITION_VERSION = "tep-v0.5.3-2026-08-23"
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,114 @@
1
+ """Bare `grift report` / `grift contribute`: default-path search + guidance.
2
+
3
+ 代表 UX feedback (2026-08-23): invoking the subcommands without a path used
4
+ to hard-error on argparse / file-not-found without telling the user what to
5
+ do first. Now they search ./out, .grift-out, ./ and, when nothing is found,
6
+ exit 2 with actionable guidance.
7
+ """
8
+
9
+ from __future__ import annotations
10
+
11
+ import json
12
+ from pathlib import Path
13
+
14
+ from tep_cli.__main__ import main
15
+
16
+ from git_fixture import commit, init_repo
17
+
18
+
19
+ def _make_report_json(dir_path: Path) -> Path:
20
+ from tep_core.analyze import analyze_repository
21
+ from tep_core.identity import empty_identity
22
+ from tep_core.lineage import Lineage
23
+
24
+ repo = init_repo(dir_path / "repo")
25
+ (repo / "pyproject.toml").write_text(
26
+ '[project]\nname = "demo"\ndependencies = ["pytest"]\n', encoding="utf-8"
27
+ )
28
+ for index in range(12):
29
+ commit(
30
+ repo,
31
+ email="a@example.com",
32
+ date="2026-01-05",
33
+ message=f"feat: {index}",
34
+ filename="app.py",
35
+ )
36
+ report = analyze_repository(repo, empty_identity(), Lineage(), scope="repo")
37
+ target = dir_path / "out" / "report.json"
38
+ target.parent.mkdir(parents=True, exist_ok=True)
39
+ target.write_text(json.dumps(report, ensure_ascii=False), encoding="utf-8")
40
+ return target
41
+
42
+
43
+ def test_report_bare_uses_out_default(tmp_path: Path, capsys: object, monkeypatch: object) -> None:
44
+ _make_report_json(tmp_path)
45
+ monkeypatch.chdir(tmp_path)
46
+ code = main(["report"])
47
+ assert code == 0
48
+ out = capsys.readouterr().out
49
+ assert "# TEP analysis" in out
50
+ assert "## Shared block" in out
51
+
52
+
53
+ def test_report_bare_searches_grift_out(
54
+ tmp_path: Path, capsys: object, monkeypatch: object
55
+ ) -> None:
56
+ _make_report_json(tmp_path)
57
+ (tmp_path / ".grift-out").mkdir(exist_ok=True)
58
+ (tmp_path / ".grift-out" / "report.json").write_text(
59
+ (tmp_path / "out" / "report.json").read_text(encoding="utf-8"), encoding="utf-8"
60
+ )
61
+ monkeypatch.chdir(tmp_path / ".grift-out")
62
+ code = main(["report"])
63
+ assert code == 0
64
+
65
+
66
+ def test_report_bare_without_prior_output_analyzes_cwd(
67
+ tmp_path: Path, capsys: object, monkeypatch: object
68
+ ) -> None:
69
+ """UX: bare `grift report` in a git repo with no ./out → analyze now and
70
+ write ./out/report.{json,md}."""
71
+ from git_fixture import commit as _commit, init_repo as _init
72
+
73
+ repo = _init(tmp_path / "repo")
74
+ for index in range(3):
75
+ _commit(repo, email="a@example.com", date="2026-01-05", message=f"feat: {index}")
76
+ monkeypatch.chdir(repo)
77
+ code = main(["report"])
78
+ assert code == 0
79
+ out = capsys.readouterr()
80
+ assert "## Shared block" in out.out
81
+ assert (repo / "out" / "report.json").is_file()
82
+ assert (repo / "out" / "report.md").is_file()
83
+
84
+
85
+ def test_report_bare_outside_git_repo_refused(
86
+ tmp_path: Path, capsys: object, monkeypatch: object
87
+ ) -> None:
88
+ monkeypatch.chdir(tmp_path)
89
+ code = main(["report"])
90
+ assert code == 2
91
+ assert "not a git repository" in capsys.readouterr().err
92
+
93
+
94
+ def test_contribute_bare_without_report_gives_guidance(
95
+ tmp_path: Path, capsys: object, monkeypatch: object
96
+ ) -> None:
97
+ monkeypatch.chdir(tmp_path)
98
+ code = main(["contribute"])
99
+ assert code == 2
100
+ err = capsys.readouterr().err
101
+ assert "grift report" in err # guidance points to the one-step entry
102
+
103
+
104
+ def test_contribute_bare_uses_out_default(
105
+ tmp_path: Path, capsys: object, monkeypatch: object
106
+ ) -> None:
107
+ # repo-scope report in ./out → bare contribute reaches the F-C1 gate
108
+ _make_report_json(tmp_path)
109
+ monkeypatch.chdir(tmp_path)
110
+ code = main(["contribute", "--out", str(tmp_path / "c.json")]) # non-TTY, no --yes
111
+ assert code == 2 # F-C1 refusal path (not path-resolution error)
112
+ err = capsys.readouterr().err
113
+ assert "公開リポジトリに載ります" in err
114
+ assert "grift analyze . --out ./out" not in err # found the file; failed on consent instead
@@ -19,6 +19,10 @@ _AUDIT_PREFIXES = (
19
19
  "docs/PREPUB",
20
20
  "docs/kpi",
21
21
  "docs/pilot",
22
+ "docs/SMOKE",
23
+ "docs/REREVIEW",
24
+ "docs/RELEASE-REHEARSAL",
25
+ "docs/INTERNAL-PILOT",
22
26
  )
23
27
 
24
28
 
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