grift-cli 0.5.0__tar.gz → 0.5.1__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.1/.github/workflows/publish-testpypi.yml +27 -0
- {grift_cli-0.5.0 → grift_cli-0.5.1}/CHANGELOG.md +22 -0
- {grift_cli-0.5.0 → grift_cli-0.5.1}/PKG-INFO +17 -1
- {grift_cli-0.5.0 → grift_cli-0.5.1}/README.en.md +16 -0
- {grift_cli-0.5.0 → grift_cli-0.5.1}/README.md +16 -0
- grift_cli-0.5.1/corpus/AD-PILOT-20260822.md +34 -0
- grift_cli-0.5.1/corpus/ad-pilot.json +127 -0
- grift_cli-0.5.0/golden/pins.toml → grift_cli-0.5.1/corpus/manifest.toml +36 -18
- grift_cli-0.5.1/corpus/runs/discriminant-latest.json +46 -0
- grift_cli-0.5.1/corpus/runs/failures.jsonl +0 -0
- grift_cli-0.5.1/corpus/runs/summary.json +9 -0
- grift_cli-0.5.1/docs/export-schema.md +127 -0
- grift_cli-0.5.1/docs/identity-schema.md +32 -0
- grift_cli-0.5.1/docs/persona-answers.md +168 -0
- grift_cli-0.5.1/docs/report-schema.md +138 -0
- grift_cli-0.5.1/golden/coverage.md +69 -0
- {grift_cli-0.5.0 → grift_cli-0.5.1}/golden/expected/G1-click.json +8 -1
- grift_cli-0.5.1/golden/expected/G10-scvi-tools.json +138 -0
- grift_cli-0.5.1/golden/expected/G11-kilo.json +131 -0
- grift_cli-0.5.1/golden/expected/G12-httpx.json +138 -0
- grift_cli-0.5.1/golden/expected/G13-voicevox.json +139 -0
- {grift_cli-0.5.0 → grift_cli-0.5.1}/golden/expected/G2-gitignore.json +1 -1
- {grift_cli-0.5.0 → grift_cli-0.5.1}/golden/expected/G3-spoon-knife.json +1 -1
- {grift_cli-0.5.0 → grift_cli-0.5.1}/golden/expected/G4-express.json +1 -1
- {grift_cli-0.5.0 → grift_cli-0.5.1}/golden/expected/G5-typer.json +1 -1
- grift_cli-0.5.1/golden/expected/G6-claude-code.json +131 -0
- grift_cli-0.5.1/golden/expected/G7-axios.json +139 -0
- grift_cli-0.5.1/golden/expected/G8-co.json +138 -0
- grift_cli-0.5.1/golden/expected/G9-pyscript.json +131 -0
- grift_cli-0.5.1/golden/pins.toml +203 -0
- {grift_cli-0.5.0 → grift_cli-0.5.1}/pyproject.toml +1 -1
- grift_cli-0.5.1/scripts/gen_coverage_table.py +100 -0
- grift_cli-0.5.1/scripts/gen_golden_expected.py +95 -0
- {grift_cli-0.5.0 → grift_cli-0.5.1}/src/tep_cli/__main__.py +29 -2
- {grift_cli-0.5.0 → grift_cli-0.5.1}/src/tep_core/analyze.py +36 -20
- grift_cli-0.5.1/src/tep_core/data/v2026.09/distributions.json +110 -0
- grift_cli-0.5.1/src/tep_core/export.py +220 -0
- {grift_cli-0.5.0 → grift_cli-0.5.1}/src/tep_core/identity.py +33 -1
- grift_cli-0.5.1/src/tep_core/schema.py +543 -0
- {grift_cli-0.5.0 → grift_cli-0.5.1}/src/tep_core/version.py +3 -2
- grift_cli-0.5.1/tests/coverage_matrix.py +215 -0
- {grift_cli-0.5.0 → grift_cli-0.5.1}/tests/test_cli.py +1 -1
- grift_cli-0.5.1/tests/test_coverage.py +93 -0
- grift_cli-0.5.1/tests/test_export.py +352 -0
- grift_cli-0.5.1/tests/test_export_recipe.py +127 -0
- {grift_cli-0.5.0 → grift_cli-0.5.1}/tests/test_hygiene.py +10 -1
- grift_cli-0.5.1/tests/test_identity_validation.py +205 -0
- grift_cli-0.5.1/tests/test_persona_answers.py +136 -0
- grift_cli-0.5.1/tests/test_schema.py +146 -0
- grift_cli-0.5.0/docs/identity-schema.md +0 -14
- {grift_cli-0.5.0 → grift_cli-0.5.1}/.github/workflows/ci.yml +0 -0
- {grift_cli-0.5.0 → grift_cli-0.5.1}/.github/workflows/publish.yml +0 -0
- {grift_cli-0.5.0 → grift_cli-0.5.1}/.gitignore +0 -0
- {grift_cli-0.5.0 → grift_cli-0.5.1}/LICENSE +0 -0
- {grift_cli-0.5.0 → grift_cli-0.5.1}/corpus/DISCRIMINANT-v2026.09.md +0 -0
- {grift_cli-0.5.0 → grift_cli-0.5.1}/corpus/pins-v2026.09.toml +0 -0
- {grift_cli-0.5.0/src/tep_core/data → grift_cli-0.5.1/corpus}/v2026.09/distributions.json +0 -0
- {grift_cli-0.5.0 → grift_cli-0.5.1}/docs/corpus-protocol.md +0 -0
- {grift_cli-0.5.0 → grift_cli-0.5.1}/golden/README.md +0 -0
- {grift_cli-0.5.0 → grift_cli-0.5.1}/golden/identity/G1-click.toml +0 -0
- {grift_cli-0.5.0 → grift_cli-0.5.1}/golden/identity/example.toml +0 -0
- {grift_cli-0.5.0 → grift_cli-0.5.1}/scripts/build_distributions.py +0 -0
- {grift_cli-0.5.0 → grift_cli-0.5.1}/scripts/check_forbidden_vocab.py +0 -0
- {grift_cli-0.5.0 → grift_cli-0.5.1}/scripts/corpus_ad_pilot.py +0 -0
- {grift_cli-0.5.0 → grift_cli-0.5.1}/scripts/corpus_run.py +0 -0
- {grift_cli-0.5.0 → grift_cli-0.5.1}/scripts/discriminant_v2026.py +0 -0
- {grift_cli-0.5.0 → grift_cli-0.5.1}/scripts/hygiene_grep.py +0 -0
- {grift_cli-0.5.0 → grift_cli-0.5.1}/src/tep_cli/__init__.py +0 -0
- {grift_cli-0.5.0 → grift_cli-0.5.1}/src/tep_core/__init__.py +0 -0
- {grift_cli-0.5.0 → grift_cli-0.5.1}/src/tep_core/activity.py +0 -0
- {grift_cli-0.5.0 → grift_cli-0.5.1}/src/tep_core/cochange.py +0 -0
- {grift_cli-0.5.0 → grift_cli-0.5.1}/src/tep_core/core_period.py +0 -0
- {grift_cli-0.5.0 → grift_cli-0.5.1}/src/tep_core/gitutil.py +0 -0
- {grift_cli-0.5.0 → grift_cli-0.5.1}/src/tep_core/lineage.py +0 -0
- {grift_cli-0.5.0 → grift_cli-0.5.1}/src/tep_core/observation.py +0 -0
- {grift_cli-0.5.0 → grift_cli-0.5.1}/src/tep_core/origin.py +0 -0
- {grift_cli-0.5.0 → grift_cli-0.5.1}/src/tep_core/paths.py +0 -0
- {grift_cli-0.5.0 → grift_cli-0.5.1}/src/tep_core/reference.py +0 -0
- {grift_cli-0.5.0 → grift_cli-0.5.1}/src/tep_core/report.py +0 -0
- {grift_cli-0.5.0 → grift_cli-0.5.1}/src/tep_core/rework.py +0 -0
- {grift_cli-0.5.0 → grift_cli-0.5.1}/src/tep_core/scope.py +0 -0
- {grift_cli-0.5.0 → grift_cli-0.5.1}/src/tep_core/survival.py +0 -0
- {grift_cli-0.5.0 → grift_cli-0.5.1}/src/tep_core/tests_observed.py +0 -0
- {grift_cli-0.5.0 → grift_cli-0.5.1}/tests/conftest.py +0 -0
- {grift_cli-0.5.0 → grift_cli-0.5.1}/tests/git_fixture.py +0 -0
- {grift_cli-0.5.0 → grift_cli-0.5.1}/tests/test_activity.py +0 -0
- {grift_cli-0.5.0 → grift_cli-0.5.1}/tests/test_cochange.py +0 -0
- {grift_cli-0.5.0 → grift_cli-0.5.1}/tests/test_forbidden_vocab.py +0 -0
- {grift_cli-0.5.0 → grift_cli-0.5.1}/tests/test_gitutil.py +0 -0
- {grift_cli-0.5.0 → grift_cli-0.5.1}/tests/test_golden.py +0 -0
- {grift_cli-0.5.0 → grift_cli-0.5.1}/tests/test_h5_swarm.py +0 -0
- {grift_cli-0.5.0 → grift_cli-0.5.1}/tests/test_not_observed.py +0 -0
- {grift_cli-0.5.0 → grift_cli-0.5.1}/tests/test_origin.py +0 -0
- {grift_cli-0.5.0 → grift_cli-0.5.1}/tests/test_report.py +0 -0
- {grift_cli-0.5.0 → grift_cli-0.5.1}/tests/test_rework.py +0 -0
- {grift_cli-0.5.0 → grift_cli-0.5.1}/tests/test_scope.py +0 -0
- {grift_cli-0.5.0 → grift_cli-0.5.1}/tests/test_survival.py +0 -0
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
name: publish-testpypi
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
workflow_dispatch:
|
|
5
|
+
|
|
6
|
+
jobs:
|
|
7
|
+
publish:
|
|
8
|
+
runs-on: ubuntu-latest
|
|
9
|
+
environment: testpypi
|
|
10
|
+
permissions:
|
|
11
|
+
contents: read
|
|
12
|
+
steps:
|
|
13
|
+
- uses: actions/checkout@v4
|
|
14
|
+
- uses: actions/setup-python@v5
|
|
15
|
+
with:
|
|
16
|
+
python-version: "3.12"
|
|
17
|
+
- name: Build
|
|
18
|
+
run: |
|
|
19
|
+
python -m pip install --upgrade pip build
|
|
20
|
+
python -m build
|
|
21
|
+
- name: Publish to TestPyPI
|
|
22
|
+
env:
|
|
23
|
+
TWINE_USERNAME: __token__
|
|
24
|
+
TWINE_PASSWORD: ${{ secrets.TEST_PYPI_API_TOKEN }}
|
|
25
|
+
run: |
|
|
26
|
+
python -m pip install twine
|
|
27
|
+
python -m twine upload --repository testpypi dist/*
|
|
@@ -4,6 +4,28 @@
|
|
|
4
4
|
|
|
5
5
|
タグ・PyPI・リポ public 化は本ファイルの記載対象外(人間ゲート)。
|
|
6
6
|
|
|
7
|
+
## [0.5.1] — 2026-08-22
|
|
8
|
+
|
|
9
|
+
WP-P1e 二層契約 + Golden v2 第1波。Grift 本体統合(WP-G1)の unblock マイルストーン。
|
|
10
|
+
|
|
11
|
+
### Added
|
|
12
|
+
|
|
13
|
+
- export-v1(`--export <dir>`・opt-in): commits.ndjson / actors.json / export-meta.json。生メール・生 author 文字列ゼロ出力。per-actor 品質指標は恒久禁止(`docs/export-schema.md`)
|
|
14
|
+
- `docs/report-schema.md`: report-v1 凍結(追加互換)・純stdlib検証器 `tep_core.schema.validate_report`
|
|
15
|
+
- golden G6〜G13 増設(計13本・上限内): AI共著(claude-code)・引き継ぎ(axios)・dormant(co)・polyglot(pyscript)・テンプレ派生(scvi-tools)・solo(kilo)・founder(httpx)・日本語圏(voicevox)
|
|
16
|
+
- `golden/coverage.md` カバレッジ行列 + HOLE 機械検出(issue 紐付け強制)
|
|
17
|
+
- `docs/persona-answers.md`: 敵対レビュー21問の実数値実演集(転記数値は CI が golden 期待値と機械突合)
|
|
18
|
+
- パリティ検算レシピ(export-schema.md)+ 逐語実行テスト
|
|
19
|
+
- 終了コードと stdout 純度規約(README 日英)
|
|
20
|
+
|
|
21
|
+
### Fixed
|
|
22
|
+
|
|
23
|
+
- F-P10-3: identity loader が空・@含有・重複 canonical_id を受理し生メールが export に漏れる producer gap を修正。`CANONICAL_ID_PATTERN`(`^[a-z0-9][a-z0-9._-]{0,63}$`・版管理)で `IdentityValidationError`(CLI は exit 2・export 未書き出し)。schema 文書と実装は逐語一致テストで固定。性質テスト「exit 0 ⇒ export 内 `@` 0 バイト」
|
|
24
|
+
|
|
25
|
+
### Changed
|
|
26
|
+
|
|
27
|
+
- `schema_version` を `tep-report-v1` から `report-v1` へ改名(凍結前の最後の変更)
|
|
28
|
+
|
|
7
29
|
## [0.5.0] — 2026-08-22
|
|
8
30
|
|
|
9
31
|
定義Bの節目(`--scope`・参照分布 v2026.09・解釈層)。行レベル rework は v0.6 予約のまま。
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: grift-cli
|
|
3
|
-
Version: 0.5.
|
|
3
|
+
Version: 0.5.1
|
|
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
|
|
@@ -48,6 +48,22 @@ grift analyze ./my-repo --scope repo
|
|
|
48
48
|
|
|
49
49
|
自リポで `grift analyze . --format md` を実行する。各数値に単位と provenance(method=TEP・tool=grift・定義版・分析 SHA・`analysis_scope`)が付く。
|
|
50
50
|
|
|
51
|
+
## 終了コードと stdout / stderr 規約
|
|
52
|
+
|
|
53
|
+
| 終了コード | 意味 |
|
|
54
|
+
|---|---|
|
|
55
|
+
| 0 | 成功 |
|
|
56
|
+
| 2 | 使用法エラー、または指定パスが git リポジトリでない |
|
|
57
|
+
| 1 | その他の予期しない失敗(詳細は stderr) |
|
|
58
|
+
|
|
59
|
+
`--format json` の stdout は **JSON 1 件のみ**(機械消費向けの純度保証)。`--format md` は markdown のみ、`--format both` は markdown → 空行 → JSON の順。診断とエラーは常に stderr。`--out DIR` を使っても stdout 規約は変わらない(`report.md` / `report.json` の追記のみ)。
|
|
60
|
+
|
|
61
|
+
report.json の全フィールド定義は [docs/report-schema.md](docs/report-schema.md)(schema `report-v1`・凍結済み・追加互換)。
|
|
62
|
+
|
|
63
|
+
## 機械取込用 export(opt-in)
|
|
64
|
+
|
|
65
|
+
`grift analyze <repo> --export <dir>` で commits.ndjson(1行=1コミット・origin/actor/cochange)・actors.json(canonical_id ごとの帰属と活動)・export-meta.json(`config_digest` つき)を書く。**生メールアドレス・生 author 文字列は一切出力しない**。顧客向け叙述に載る数値は report.json の集計値が正。詳細は [docs/export-schema.md](docs/export-schema.md)。
|
|
66
|
+
|
|
51
67
|
例(click、tenant スコープ。ゴールデン G1):
|
|
52
68
|
|
|
53
69
|
- test co-change: 0.2664 ratio(73 of 274)
|
|
@@ -35,6 +35,22 @@ Example (click, tenant scope, golden G1):
|
|
|
35
35
|
|
|
36
36
|
Below population 20, neither the rate nor a distribution position is shown (`insufficient_population`; raw counts only).
|
|
37
37
|
|
|
38
|
+
## Exit codes and stdout / stderr contract
|
|
39
|
+
|
|
40
|
+
| Exit code | Meaning |
|
|
41
|
+
|---|---|
|
|
42
|
+
| 0 | success |
|
|
43
|
+
| 2 | usage error, or the given path is not a git repository |
|
|
44
|
+
| 1 | any other unexpected failure (details on stderr) |
|
|
45
|
+
|
|
46
|
+
With `--format json`, stdout is **exactly one JSON document** (purity guarantee for machine consumption). `--format md` writes markdown only; `--format both` writes markdown, a blank line, then JSON. Diagnostics and errors always go to stderr. `--out DIR` does not change the stdout contract (it additionally writes `report.md` / `report.json`).
|
|
47
|
+
|
|
48
|
+
The full field-by-field definition of report.json lives in [docs/report-schema.md](docs/report-schema.md) (schema `report-v1`, frozen, additive-only).
|
|
49
|
+
|
|
50
|
+
## Machine ingestion export (opt-in)
|
|
51
|
+
|
|
52
|
+
`grift analyze <repo> --export <dir>` writes commits.ndjson (one row per commit: origin / actor / cochange), actors.json (attribution and engagement per canonical_id), and export-meta.json (with `config_digest`). **No raw emails or author strings are ever exported.** Aggregates in report.json remain authoritative for narrative. Details: [docs/export-schema.md](docs/export-schema.md).
|
|
53
|
+
|
|
38
54
|
## Metrics and limits
|
|
39
55
|
|
|
40
56
|
| Metric | What it is evidence of | Limit |
|
|
@@ -25,6 +25,22 @@ grift analyze ./my-repo --scope repo
|
|
|
25
25
|
|
|
26
26
|
自リポで `grift analyze . --format md` を実行する。各数値に単位と provenance(method=TEP・tool=grift・定義版・分析 SHA・`analysis_scope`)が付く。
|
|
27
27
|
|
|
28
|
+
## 終了コードと stdout / stderr 規約
|
|
29
|
+
|
|
30
|
+
| 終了コード | 意味 |
|
|
31
|
+
|---|---|
|
|
32
|
+
| 0 | 成功 |
|
|
33
|
+
| 2 | 使用法エラー、または指定パスが git リポジトリでない |
|
|
34
|
+
| 1 | その他の予期しない失敗(詳細は stderr) |
|
|
35
|
+
|
|
36
|
+
`--format json` の stdout は **JSON 1 件のみ**(機械消費向けの純度保証)。`--format md` は markdown のみ、`--format both` は markdown → 空行 → JSON の順。診断とエラーは常に stderr。`--out DIR` を使っても stdout 規約は変わらない(`report.md` / `report.json` の追記のみ)。
|
|
37
|
+
|
|
38
|
+
report.json の全フィールド定義は [docs/report-schema.md](docs/report-schema.md)(schema `report-v1`・凍結済み・追加互換)。
|
|
39
|
+
|
|
40
|
+
## 機械取込用 export(opt-in)
|
|
41
|
+
|
|
42
|
+
`grift analyze <repo> --export <dir>` で commits.ndjson(1行=1コミット・origin/actor/cochange)・actors.json(canonical_id ごとの帰属と活動)・export-meta.json(`config_digest` つき)を書く。**生メールアドレス・生 author 文字列は一切出力しない**。顧客向け叙述に載る数値は report.json の集計値が正。詳細は [docs/export-schema.md](docs/export-schema.md)。
|
|
43
|
+
|
|
28
44
|
例(click、tenant スコープ。ゴールデン G1):
|
|
29
45
|
|
|
30
46
|
- test co-change: 0.2664 ratio(73 of 274)
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# A/D 判別力パイロット(2026-08-22)
|
|
2
|
+
|
|
3
|
+
基準は実行前に `docs/corpus-protocol.md` へ登録済み(`5f2665e`)。
|
|
4
|
+
本ファイルは結果のみ。基準は動かしていない。
|
|
5
|
+
|
|
6
|
+
実行: `python3 scripts/corpus_ad_pilot.py`(golden cache、生存スキャンなし)
|
|
7
|
+
|
|
8
|
+
## 判定(事前基準の適用)
|
|
9
|
+
|
|
10
|
+
| 層 | 事前基準 | 結果 |
|
|
11
|
+
|---|---|---|
|
|
12
|
+
| Tier 1 観測状態 | D は co-change が not_observed。identity 付き A は narrate_rate | **pass** |
|
|
13
|
+
| Tier 2 率・効果量 | 両群 n≥2 のとき中央値差≥0.10・区間包含なし・Cliff δ≥0.33 | **inconclusive_small_n**(A narratable=1, D=0) |
|
|
14
|
+
|
|
15
|
+
率の判別力は、このピン集合ではまだ宣言しない。D は低率ではなく「未観測」で分かれており、それは Tier 1 の事前方向どおり。click の 0.2664 を D の欠測と引き算して効果量にしたわけではない。
|
|
16
|
+
|
|
17
|
+
## 行(リポ名のみ。個人名なし)
|
|
18
|
+
|
|
19
|
+
| 群 | リポ | test_frameworks | test_cochange | corrective_rework |
|
|
20
|
+
|---|---|---|---|---|
|
|
21
|
+
| A | click | pytest | 0.2664 (n=274, narrate) | 0.0109(fresh-work stability。バグ件数ではない) |
|
|
22
|
+
| A | express | mocha, nyc | not_observed (pending_attribution) | not_observed (pending_attribution) |
|
|
23
|
+
| A | typer | pytest | not_observed (pending_attribution) | not_observed (pending_attribution) |
|
|
24
|
+
| D | gitignore | not_observed | not_observed (no_test_framework_or_directory) | not_observed (pending_attribution) |
|
|
25
|
+
| D | Spoon-Knife | not_observed | not_observed (no_test_framework_or_directory) | not_observed (pending_attribution) |
|
|
26
|
+
|
|
27
|
+
## C pin(選定のみ。本パイロットでは未計測)
|
|
28
|
+
|
|
29
|
+
- C1-vibe: `https://github.com/mabene/vibe.git` @ `c53ab3cb3461ef43bb1b6336da4e9cdd477c63ac`
|
|
30
|
+
- 理由: README が「ソースは AI 対話で生成、人間が直接書いていない」と自己記述している。個人スコアカードには使わない。
|
|
31
|
+
|
|
32
|
+
## 次
|
|
33
|
+
|
|
34
|
+
Tier 2 を閉じるには、identity 付き A をあと1件以上、および(必要なら)テスト基盤があり tenant が測れる D ではない別ピンか、C との corrective 比較。基準の数値は変えない。
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
{
|
|
2
|
+
"protocol": "docs/corpus-protocol.md",
|
|
3
|
+
"criteria_registered_before_run": true,
|
|
4
|
+
"tier1_observation_status": {
|
|
5
|
+
"verdict": "pass",
|
|
6
|
+
"failures": []
|
|
7
|
+
},
|
|
8
|
+
"tier2_rates": {
|
|
9
|
+
"verdict": "inconclusive_small_n",
|
|
10
|
+
"n_A_narratable": 1,
|
|
11
|
+
"n_D_narratable": 0
|
|
12
|
+
},
|
|
13
|
+
"rows": [
|
|
14
|
+
{
|
|
15
|
+
"repo": "click",
|
|
16
|
+
"pending_attribution": false,
|
|
17
|
+
"test_frameworks": {
|
|
18
|
+
"kind": "observed",
|
|
19
|
+
"reason": null,
|
|
20
|
+
"names": [
|
|
21
|
+
"pytest"
|
|
22
|
+
]
|
|
23
|
+
},
|
|
24
|
+
"test_cochange": {
|
|
25
|
+
"status": "observed",
|
|
26
|
+
"value": 0.2664,
|
|
27
|
+
"narrate_rate": true,
|
|
28
|
+
"population": 274
|
|
29
|
+
},
|
|
30
|
+
"corrective_rework": {
|
|
31
|
+
"status": "observed",
|
|
32
|
+
"value": 0.0109,
|
|
33
|
+
"narrate_rate": true,
|
|
34
|
+
"population": 274
|
|
35
|
+
},
|
|
36
|
+
"origin_tenant_unique": 326,
|
|
37
|
+
"group": "A",
|
|
38
|
+
"identity_bearing": true
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
"repo": "express",
|
|
42
|
+
"pending_attribution": true,
|
|
43
|
+
"test_frameworks": {
|
|
44
|
+
"kind": "observed",
|
|
45
|
+
"reason": null,
|
|
46
|
+
"names": [
|
|
47
|
+
"mocha",
|
|
48
|
+
"nyc"
|
|
49
|
+
]
|
|
50
|
+
},
|
|
51
|
+
"test_cochange": {
|
|
52
|
+
"status": "not_observed",
|
|
53
|
+
"reason": "pending_attribution"
|
|
54
|
+
},
|
|
55
|
+
"corrective_rework": {
|
|
56
|
+
"status": "not_observed",
|
|
57
|
+
"reason": "pending_attribution"
|
|
58
|
+
},
|
|
59
|
+
"origin_tenant_unique": 0,
|
|
60
|
+
"group": "A",
|
|
61
|
+
"identity_bearing": false
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
"repo": "typer",
|
|
65
|
+
"pending_attribution": true,
|
|
66
|
+
"test_frameworks": {
|
|
67
|
+
"kind": "observed",
|
|
68
|
+
"reason": null,
|
|
69
|
+
"names": [
|
|
70
|
+
"pytest"
|
|
71
|
+
]
|
|
72
|
+
},
|
|
73
|
+
"test_cochange": {
|
|
74
|
+
"status": "not_observed",
|
|
75
|
+
"reason": "pending_attribution"
|
|
76
|
+
},
|
|
77
|
+
"corrective_rework": {
|
|
78
|
+
"status": "not_observed",
|
|
79
|
+
"reason": "pending_attribution"
|
|
80
|
+
},
|
|
81
|
+
"origin_tenant_unique": 0,
|
|
82
|
+
"group": "A",
|
|
83
|
+
"identity_bearing": false
|
|
84
|
+
},
|
|
85
|
+
{
|
|
86
|
+
"repo": "gitignore",
|
|
87
|
+
"pending_attribution": true,
|
|
88
|
+
"test_frameworks": {
|
|
89
|
+
"kind": "not_observed",
|
|
90
|
+
"reason": "no_test_framework_or_directory",
|
|
91
|
+
"names": null
|
|
92
|
+
},
|
|
93
|
+
"test_cochange": {
|
|
94
|
+
"status": "not_observed",
|
|
95
|
+
"reason": "no_test_framework_or_directory"
|
|
96
|
+
},
|
|
97
|
+
"corrective_rework": {
|
|
98
|
+
"status": "not_observed",
|
|
99
|
+
"reason": "pending_attribution"
|
|
100
|
+
},
|
|
101
|
+
"origin_tenant_unique": 0,
|
|
102
|
+
"group": "D",
|
|
103
|
+
"identity_bearing": false
|
|
104
|
+
},
|
|
105
|
+
{
|
|
106
|
+
"repo": "Spoon-Knife",
|
|
107
|
+
"pending_attribution": true,
|
|
108
|
+
"test_frameworks": {
|
|
109
|
+
"kind": "not_observed",
|
|
110
|
+
"reason": "no_test_framework_or_directory",
|
|
111
|
+
"names": null
|
|
112
|
+
},
|
|
113
|
+
"test_cochange": {
|
|
114
|
+
"status": "not_observed",
|
|
115
|
+
"reason": "no_test_framework_or_directory"
|
|
116
|
+
},
|
|
117
|
+
"corrective_rework": {
|
|
118
|
+
"status": "not_observed",
|
|
119
|
+
"reason": "pending_attribution"
|
|
120
|
+
},
|
|
121
|
+
"origin_tenant_unique": 0,
|
|
122
|
+
"group": "D",
|
|
123
|
+
"identity_bearing": false
|
|
124
|
+
}
|
|
125
|
+
],
|
|
126
|
+
"narrative_lock": "corrective_rework low is not a bug count; it is fresh-work stability"
|
|
127
|
+
}
|
|
@@ -1,17 +1,41 @@
|
|
|
1
|
-
#
|
|
2
|
-
# Expected JSON was written from git log inspection before tep_core existed.
|
|
1
|
+
# Corpus pins. Group C is selected here; A/D pilot uses golden cache only.
|
|
3
2
|
|
|
4
3
|
[[repos]]
|
|
5
|
-
id = "
|
|
4
|
+
id = "A-click"
|
|
5
|
+
group = "A"
|
|
6
6
|
name = "click"
|
|
7
7
|
url = "https://github.com/pallets/click.git"
|
|
8
8
|
sha = "2c8cd3ac958a7eb316d67f2d316c27086c4c0369"
|
|
9
9
|
identity = "golden/identity/G1-click.toml"
|
|
10
10
|
fork = false
|
|
11
11
|
parent = ""
|
|
12
|
+
note = "identity-bearing A pin for tenant rates"
|
|
12
13
|
|
|
13
14
|
[[repos]]
|
|
14
|
-
id = "
|
|
15
|
+
id = "A-express"
|
|
16
|
+
group = "A"
|
|
17
|
+
name = "express"
|
|
18
|
+
url = "https://github.com/expressjs/express.git"
|
|
19
|
+
sha = "a3714473feb3d2908add734d340e7755fd85e0a3"
|
|
20
|
+
identity = ""
|
|
21
|
+
fork = false
|
|
22
|
+
parent = ""
|
|
23
|
+
note = "culture marker only until identity is configured"
|
|
24
|
+
|
|
25
|
+
[[repos]]
|
|
26
|
+
id = "A-typer"
|
|
27
|
+
group = "A"
|
|
28
|
+
name = "typer"
|
|
29
|
+
url = "https://github.com/tiangolo/typer.git"
|
|
30
|
+
sha = "9a7b2e83f6b62c750d6026b0de9ebf2026a8b8fa"
|
|
31
|
+
identity = ""
|
|
32
|
+
fork = false
|
|
33
|
+
parent = ""
|
|
34
|
+
note = "culture marker only until identity is configured"
|
|
35
|
+
|
|
36
|
+
[[repos]]
|
|
37
|
+
id = "D-gitignore"
|
|
38
|
+
group = "D"
|
|
15
39
|
name = "gitignore"
|
|
16
40
|
url = "https://github.com/github/gitignore.git"
|
|
17
41
|
sha = "57286c3887203259752b747db94e6c3ad10ec53d"
|
|
@@ -20,7 +44,8 @@ fork = false
|
|
|
20
44
|
parent = ""
|
|
21
45
|
|
|
22
46
|
[[repos]]
|
|
23
|
-
id = "
|
|
47
|
+
id = "D-spoon-knife"
|
|
48
|
+
group = "D"
|
|
24
49
|
name = "Spoon-Knife"
|
|
25
50
|
url = "https://github.com/octocat/Spoon-Knife.git"
|
|
26
51
|
sha = "d0dd1f61b33d64e29d8bc1372a94ef6a2fee76a9"
|
|
@@ -29,19 +54,12 @@ fork = true
|
|
|
29
54
|
parent = "octocat/Hello-World"
|
|
30
55
|
|
|
31
56
|
[[repos]]
|
|
32
|
-
id = "
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
fork = false
|
|
38
|
-
parent = ""
|
|
39
|
-
|
|
40
|
-
[[repos]]
|
|
41
|
-
id = "G5-typer"
|
|
42
|
-
name = "typer"
|
|
43
|
-
url = "https://github.com/tiangolo/typer.git"
|
|
44
|
-
sha = "9a7b2e83f6b62c750d6026b0de9ebf2026a8b8fa"
|
|
57
|
+
id = "C1-vibe"
|
|
58
|
+
group = "C"
|
|
59
|
+
name = "vibe"
|
|
60
|
+
url = "https://github.com/mabene/vibe.git"
|
|
61
|
+
sha = "c53ab3cb3461ef43bb1b6336da4e9cdd477c63ac"
|
|
45
62
|
identity = ""
|
|
46
63
|
fork = false
|
|
47
64
|
parent = ""
|
|
65
|
+
note = "self-described 100% AI-generated product; SHA at first clone; A/D pilot does not wait"
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
[
|
|
2
|
+
{
|
|
3
|
+
"metric": "test_cochange A vs D",
|
|
4
|
+
"verdict": "inconclusive_small_n",
|
|
5
|
+
"n_A": 18,
|
|
6
|
+
"n_other": 1
|
|
7
|
+
},
|
|
8
|
+
{
|
|
9
|
+
"metric": "test_cochange A vs C",
|
|
10
|
+
"verdict": "separated",
|
|
11
|
+
"median_A": 0.2379,
|
|
12
|
+
"median_other": 0.0306,
|
|
13
|
+
"gap": 0.2073,
|
|
14
|
+
"range_A": [
|
|
15
|
+
0.1113,
|
|
16
|
+
0.4964
|
|
17
|
+
],
|
|
18
|
+
"range_other": [
|
|
19
|
+
0.0,
|
|
20
|
+
0.4154
|
|
21
|
+
],
|
|
22
|
+
"contained": false,
|
|
23
|
+
"cliffs_delta": 0.7143,
|
|
24
|
+
"n_A": 18,
|
|
25
|
+
"n_other": 7
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
"metric": "corrective_rework A vs C",
|
|
29
|
+
"verdict": "fail_tier2",
|
|
30
|
+
"median_A": 0.0522,
|
|
31
|
+
"median_other": 0.1063,
|
|
32
|
+
"gap": -0.0541,
|
|
33
|
+
"range_A": [
|
|
34
|
+
0.0,
|
|
35
|
+
0.1499
|
|
36
|
+
],
|
|
37
|
+
"range_other": [
|
|
38
|
+
0.047,
|
|
39
|
+
0.1971
|
|
40
|
+
],
|
|
41
|
+
"contained": false,
|
|
42
|
+
"cliffs_delta": -0.7083,
|
|
43
|
+
"n_A": 18,
|
|
44
|
+
"n_other": 8
|
|
45
|
+
}
|
|
46
|
+
]
|
|
File without changes
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
{
|
|
2
|
+
"run_id": "20260821T164827Z",
|
|
3
|
+
"pins": 47,
|
|
4
|
+
"ok": 47,
|
|
5
|
+
"failed": 0,
|
|
6
|
+
"analysis_scope": "repo",
|
|
7
|
+
"failures_path": "/Users/teradakousuke/Developer/grift-cli/corpus/runs/failures.jsonl",
|
|
8
|
+
"results_path": "/Users/teradakousuke/Developer/grift-cli/corpus/runs/results.jsonl"
|
|
9
|
+
}
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
# export-v1 スキーマ — 機械取込用 opt-in 出力(凍結 2026-08-22)
|
|
2
|
+
|
|
3
|
+
`grift analyze <repo> --export <dir>` が書く3ファイルの契約。Grift 本体統合(WP-G1)の取込対象。
|
|
4
|
+
report-v1(`docs/report-schema.md`)と同じ追加互換規約: **export-v1 の間は追加のみ**(改名・削除・意味変更は v2)。
|
|
5
|
+
|
|
6
|
+
- 定数: `tep_core.export.EXPORT_SCHEMA_VERSION = "tep-export-v1"`
|
|
7
|
+
- report と export は同一の `prepare_inputs()`(commits 読み込み + origin 分類)を共有する。**単一実装**であり、二つの出力が乖離する余地は構造的にない
|
|
8
|
+
|
|
9
|
+
## 境界(裁定 2026-08-22 二層契約)
|
|
10
|
+
|
|
11
|
+
- 顧客向け叙述に載る数値は **report.json の集計値が正**(消費者は明細から独自集計した別の数を narrate しない)
|
|
12
|
+
- 参照分布の位置は repo スコープ実行の出力のみ
|
|
13
|
+
- 母数<20 非表示・`not_observed` ≠ 0 の上書き禁止 — 従来どおり
|
|
14
|
+
- **per-actor の品質指標(actor別 co-change 等)は export-v2 でも解禁しない**(個人を評価対象にする出力の禁止レール)
|
|
15
|
+
|
|
16
|
+
## ファイル構成
|
|
17
|
+
|
|
18
|
+
| ファイル | 内容 |
|
|
19
|
+
|---|---|
|
|
20
|
+
| `commits.ndjson` | 1行 = 1コミット(NDJSON)。**git log 順(新しいコミットが先頭)** |
|
|
21
|
+
| `actors.json` | canonical_id ごとの帰属と活動(engagement)。JSON 配列 |
|
|
22
|
+
| `export-meta.json` | スキーマ版・provenance・`config_digest` |
|
|
23
|
+
|
|
24
|
+
## commits.ndjson(1行のフィールド)
|
|
25
|
+
|
|
26
|
+
| フィールド | 型 | 意味 |
|
|
27
|
+
|---|---|---|
|
|
28
|
+
| `sha` | string (40 hex) | コミット SHA |
|
|
29
|
+
| `ts` | string `YYYY-MM-DD` | author date(日精度。他の全指標と同じ `--date=short` 由来) |
|
|
30
|
+
| `origin` | string | 11分類のいずれか(report-v1 origin と同一語彙) |
|
|
31
|
+
| `actor` | string \| null | 解決できたら `canonical_id`、できなければ null。**生メール・生 author 文字列は出ない** |
|
|
32
|
+
| `bot` | bool | origin == `bot` と同値 |
|
|
33
|
+
| `is_merge` | bool | 親コミット複数 |
|
|
34
|
+
| `prod_paths_touched` | int >= 0 | 本番パス変更数(report と同一の path 分類) |
|
|
35
|
+
| `test_paths_touched` | int >= 0 | テストパス変更数 |
|
|
36
|
+
| `cochange` | bool \| null | **本番変更コミットのみ値を持つ**(prod_paths_touched > 0)。そのコミットがテストも変更したか。それ以外は null |
|
|
37
|
+
| `subject_class` | string | `fix` \| `revert` \| `other`(report の rework 定義と同一正規表現) |
|
|
38
|
+
|
|
39
|
+
merge コミットは `git log --name-only` の仕様上ファイル一覧が空になるため `prod_paths_touched = 0`・`cochange = null` になる。
|
|
40
|
+
|
|
41
|
+
## actors.json(1要素のフィールド)
|
|
42
|
+
|
|
43
|
+
| フィールド | 型 | 意味 |
|
|
44
|
+
|---|---|---|
|
|
45
|
+
| `canonical_id` | string | identity の安定 ID(**`@` を含めてはならない**) |
|
|
46
|
+
| `attribution_state` | string | identity の当該 actor の状態 |
|
|
47
|
+
| `commits` | int >= 1 | この actor の `tenant_unique` コミット数 |
|
|
48
|
+
| `active_days` | int >= 1 | 一意な活動日数 |
|
|
49
|
+
| `first_ts` / `last_ts` | string `YYYY-MM-DD` | 最初・最後の tenant_unique コミット日 |
|
|
50
|
+
| `core_period` | object | report-v1 の `core_activity_period` と同一構造(この actor の日付で計算) |
|
|
51
|
+
|
|
52
|
+
actor 行を持つのは **tenant_unique コミットが1以上の canonical_id のみ**。pattern 推論(actor 行なし)・bot・unresolved は行を持たない(commits.ndjson の `actor` が null で表現)。actor 順は canonical_id 辞書順(決定論的)。
|
|
53
|
+
|
|
54
|
+
## export-meta.json
|
|
55
|
+
|
|
56
|
+
| フィールド | 型 | 意味 |
|
|
57
|
+
|---|---|---|
|
|
58
|
+
| `schema` | string | 常に `"tep-export-v1"` |
|
|
59
|
+
| `tool_name` / `tool_version` | string | `"grift"` / SEMVER |
|
|
60
|
+
| `definition_version` / `origin_definition_version` / `activity_definition_version` | string | report-v1 provenance と同一 |
|
|
61
|
+
| `analysis_scope` | string | `tenant` \| `repo` |
|
|
62
|
+
| `analyzed_commit_sha` | string (40 hex) | |
|
|
63
|
+
| `analyzed_at` | string UTC | |
|
|
64
|
+
| `config_digest` | string (64 hex) | 下記 |
|
|
65
|
+
| `commit_count` | int | commits.ndjson の行数 |
|
|
66
|
+
|
|
67
|
+
## config_digest の正規化(Grift 側再計算用の完全仕様)
|
|
68
|
+
|
|
69
|
+
`sha256( json.dumps(payload, sort_keys=True, separators=(",", ":"), ensure_ascii=False).encode("utf-8") )` の hexdigest。
|
|
70
|
+
|
|
71
|
+
`payload` の内容:
|
|
72
|
+
|
|
73
|
+
```json
|
|
74
|
+
{
|
|
75
|
+
"schema": "tep-export-v1",
|
|
76
|
+
"definition_version": "<DEFINITION_VERSION>",
|
|
77
|
+
"origin_definition_version": "<ORIGIN_DEFINITION_VERSION>",
|
|
78
|
+
"activity_definition_version": "<ACTIVITY_DEFINITION_VERSION>",
|
|
79
|
+
"analysis_scope": "<tenant|repo>",
|
|
80
|
+
"lineage": {"is_fork": <bool>, "parent": <string|null>},
|
|
81
|
+
"template_provided": <bool>,
|
|
82
|
+
"parent_repo_provided": <bool>,
|
|
83
|
+
"vendor_scan": <bool>,
|
|
84
|
+
"identity": {
|
|
85
|
+
"actors": [
|
|
86
|
+
{"canonical_id": "<id>", "attribution_state": "<state>",
|
|
87
|
+
"emails": [<sorted strings>], "github_login": <string|null>}
|
|
88
|
+
],
|
|
89
|
+
"email_patterns": [<sorted raw pattern strings>]
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
- actors は canonical_id 辞書順、emails と email_patterns は辞書順ソート
|
|
95
|
+
- 生メールは digest 計算には入るが**ディスクには出力されない**。identity.toml を生成した側(Grift)は同じ正規化でローカル再計算・照合できる
|
|
96
|
+
- digest は設定のみから計算(analyzed_at / SHA を含まない)。同一設定なら再実行しても不変
|
|
97
|
+
|
|
98
|
+
## 取込パリティ(消費者の義務 — 裁定3)
|
|
99
|
+
|
|
100
|
+
取込側は commits.ndjson から origin 別行数合計(および test co-change)を再計算し、report.json の集計値と**一致しない場合は取込を中止**すること。CLI 側テスト(`tests/test_export.py`)がこの再計算を tenant / repo 両スコープで自動検証している。
|
|
101
|
+
|
|
102
|
+
### パリティ検算レシピ(取込側はこの式を逐語実行する — F-P10-1)
|
|
103
|
+
|
|
104
|
+
行 `r` は commits.ndjson の1行(JSON object)。以下の式は Python 式としてそのまま実行可能であること(`tests/test_export_recipe.py` が本節の式を文字列どおり取り出して実行し、doc と実装の乖離を検出する)。
|
|
105
|
+
|
|
106
|
+
**origin パリティ(スコープ共通)**:
|
|
107
|
+
|
|
108
|
+
- 各クラス c の行数: `sum(1 for r in rows if r["origin"] == c)`
|
|
109
|
+
- 突合先: `report["origin"][c]`。`kind == "observed"` なら `value` と一致すること。`kind == "not_observed"` なら行数 0 であること
|
|
110
|
+
|
|
111
|
+
**test co-change パリティ — tenant スコープ**:
|
|
112
|
+
|
|
113
|
+
- 母集団フィルタ(tenant): `r["origin"] == "tenant_unique" and r["cochange"] is not None`
|
|
114
|
+
- cochanged フィルタ(tenant): `r["origin"] == "tenant_unique" and r["cochange"] is True`
|
|
115
|
+
- 突合先: `report["test_cochange"]["all_time"]` の `population` / `cochanged`(`test_cochange.kind == "not_observed"` のときは検算対象なし)
|
|
116
|
+
|
|
117
|
+
**test co-change パリティ — repo スコープ**:
|
|
118
|
+
|
|
119
|
+
- 母集団フィルタ(repo): `r["bot"] is False and r["is_merge"] is False and r["cochange"] is not None`
|
|
120
|
+
- cochanged フィルタ(repo): `r["bot"] is False and r["is_merge"] is False and r["cochange"] is True`
|
|
121
|
+
- 突合先: 同上
|
|
122
|
+
|
|
123
|
+
**既知の誤実装(検収 追記9 の実例)**: tenant スコープで `cochange is not None` を忘れると、テスト専用コミットや merge まで母集団に混入し、誤った率(click で 73/274=0.2664 が正しいのに 444/1537=0.2889 を出す)を「パリティ不一致」として誤検知する。`cochange is not None`(= 本番変更コミット)の絞り込みは省略禁止。
|
|
124
|
+
|
|
125
|
+
## 終了コードと stdout
|
|
126
|
+
|
|
127
|
+
`--export` は stdout 規約を変えない(`--format json` の stdout は JSON 1 件のまま)。export は常にファイルのみに書く。
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# Identity file schema (identity-v1)
|
|
2
|
+
|
|
3
|
+
Local entry point for the same concept as Grift `actor_attributions`.
|
|
4
|
+
|
|
5
|
+
| Field | Grift column | Meaning |
|
|
6
|
+
|---|---|---|
|
|
7
|
+
| `canonical_id` | stable member id (email is the DB key there) | Durable id for a person. CLI uses a non-email id so reports are not scorecards. |
|
|
8
|
+
| `emails` | `canonical_email` plus aliases | Raw git author emails that map to this actor. |
|
|
9
|
+
| `github_login` | `github_login` | Optional. |
|
|
10
|
+
| `attribution_state` | `attribution_state` | `verified` / `claimed` / `inferred` / `unresolved` / `external` / `bot`. |
|
|
11
|
+
|
|
12
|
+
## canonical_id validity (F-P10-3・版管理)
|
|
13
|
+
|
|
14
|
+
`canonical_id` は次の正規表現に **fullmatch** しなければならない(producer が `IdentityValidationError` で拒否する):
|
|
15
|
+
|
|
16
|
+
```
|
|
17
|
+
^[a-z0-9][a-z0-9._-]{0,63}$
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
意味: 小文字英数字で開始・以降は小文字英数字と `.` `_` `-` のみ・長さ 1〜64。**`@`・空白・制御文字・大文字・多バイト文字は不正**(export の no-`@` 契約をデータ非依存に保証するための定義パターン。blocklist ではない)。
|
|
21
|
+
|
|
22
|
+
追加の拒否条件: 空文字(上記正規表現の fullmatch で自動的に拒否)・**重複 canonical_id**(各行一意であること)。
|
|
23
|
+
|
|
24
|
+
本正規表現は実装(`tep_core.identity.CANONICAL_ID_PATTERN`)と**逐語一致**しなければならない — `tests/test_identity_validation.py` が schema 文書と実装の一致を検査する(レシピテストと同型の doc-code パリティ)。正規表現を変える場合は schema 文書・実装・テストを同じ PR で更新し、`CANONICAL_ID_PATTERN_VERSION` を上げる。
|
|
25
|
+
|
|
26
|
+
| 版 | 正規表現 | 導入 |
|
|
27
|
+
|---|---|---|
|
|
28
|
+
| 1 | `^[a-z0-9][a-z0-9._-]{0,63}$` | 2026-08-22(F-P10-3 修正) |
|
|
29
|
+
|
|
30
|
+
`tenant.email_patterns` are regular expressions matched against author emails. A match counts as tenant membership even without an `[[actors]]` row (`attribution_state` then becomes `inferred`).
|
|
31
|
+
|
|
32
|
+
Empty file / missing file: `pending_attribution = true`. No built-in organisation pattern exists.
|