fuseji 0.1.0__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 (80) hide show
  1. fuseji-0.1.0/.github/ISSUE_TEMPLATE/bug_report.md +41 -0
  2. fuseji-0.1.0/.github/ISSUE_TEMPLATE/config.yml +2 -0
  3. fuseji-0.1.0/.github/ISSUE_TEMPLATE/feature_request.md +25 -0
  4. fuseji-0.1.0/.github/PULL_REQUEST_TEMPLATE.md +14 -0
  5. fuseji-0.1.0/.github/workflows/ci.yml +92 -0
  6. fuseji-0.1.0/.github/workflows/publish.yml +96 -0
  7. fuseji-0.1.0/.gitignore +37 -0
  8. fuseji-0.1.0/.python-version +1 -0
  9. fuseji-0.1.0/CHANGELOG.md +84 -0
  10. fuseji-0.1.0/CLAUDE.md +47 -0
  11. fuseji-0.1.0/CONTRIBUTING.md +55 -0
  12. fuseji-0.1.0/LICENSE +190 -0
  13. fuseji-0.1.0/PKG-INFO +219 -0
  14. fuseji-0.1.0/README.en.md +160 -0
  15. fuseji-0.1.0/README.md +174 -0
  16. fuseji-0.1.0/SECURITY.md +173 -0
  17. fuseji-0.1.0/docs/api.md +333 -0
  18. fuseji-0.1.0/docs/design.md +243 -0
  19. fuseji-0.1.0/examples/README.md +21 -0
  20. fuseji-0.1.0/examples/ginza/README.md +36 -0
  21. fuseji-0.1.0/examples/ginza/main.py +28 -0
  22. fuseji-0.1.0/examples/ginza/requirements.txt +1 -0
  23. fuseji-0.1.0/examples/langfuse_ingestion_callback/README.md +49 -0
  24. fuseji-0.1.0/examples/langfuse_ingestion_callback/docker-compose.yml +21 -0
  25. fuseji-0.1.0/examples/langfuse_sdk/README.md +33 -0
  26. fuseji-0.1.0/examples/langfuse_sdk/main.py +43 -0
  27. fuseji-0.1.0/examples/langfuse_sdk/requirements.txt +2 -0
  28. fuseji-0.1.0/examples/otel/README.md +35 -0
  29. fuseji-0.1.0/examples/otel/otel-collector-config.yaml +40 -0
  30. fuseji-0.1.0/pyproject.toml +118 -0
  31. fuseji-0.1.0/src/fuseji/__init__.py +28 -0
  32. fuseji-0.1.0/src/fuseji/engine.py +176 -0
  33. fuseji-0.1.0/src/fuseji/entity_types.py +46 -0
  34. fuseji-0.1.0/src/fuseji/exceptions.py +32 -0
  35. fuseji-0.1.0/src/fuseji/integrations/__init__.py +5 -0
  36. fuseji-0.1.0/src/fuseji/integrations/langfuse.py +76 -0
  37. fuseji-0.1.0/src/fuseji/ner/__init__.py +5 -0
  38. fuseji-0.1.0/src/fuseji/ner/base.py +19 -0
  39. fuseji-0.1.0/src/fuseji/ner/ginza.py +70 -0
  40. fuseji-0.1.0/src/fuseji/py.typed +0 -0
  41. fuseji-0.1.0/src/fuseji/recognizers/__init__.py +17 -0
  42. fuseji-0.1.0/src/fuseji/recognizers/base.py +117 -0
  43. fuseji-0.1.0/src/fuseji/recognizers/credit_card.py +55 -0
  44. fuseji-0.1.0/src/fuseji/recognizers/email.py +31 -0
  45. fuseji-0.1.0/src/fuseji/recognizers/jp_phone.py +66 -0
  46. fuseji-0.1.0/src/fuseji/recognizers/jp_postal.py +73 -0
  47. fuseji-0.1.0/src/fuseji/recognizers/my_number.py +65 -0
  48. fuseji-0.1.0/src/fuseji/server/__init__.py +5 -0
  49. fuseji-0.1.0/src/fuseji/server/app.py +168 -0
  50. fuseji-0.1.0/src/fuseji/strategies.py +158 -0
  51. fuseji-0.1.0/src/fuseji/types.py +54 -0
  52. fuseji-0.1.0/src/fuseji/vault.py +165 -0
  53. fuseji-0.1.0/tests/__init__.py +0 -0
  54. fuseji-0.1.0/tests/bench/README.md +36 -0
  55. fuseji-0.1.0/tests/bench/__init__.py +0 -0
  56. fuseji-0.1.0/tests/bench/bench_masker.py +43 -0
  57. fuseji-0.1.0/tests/bench/bench_recognizers.py +42 -0
  58. fuseji-0.1.0/tests/bench/bench_replace_spans.py +28 -0
  59. fuseji-0.1.0/tests/bench/bench_vault.py +37 -0
  60. fuseji-0.1.0/tests/conftest.py +30 -0
  61. fuseji-0.1.0/tests/test_engine.py +159 -0
  62. fuseji-0.1.0/tests/test_engine_vault_json.py +121 -0
  63. fuseji-0.1.0/tests/test_entity_types.py +65 -0
  64. fuseji-0.1.0/tests/test_integrations_langfuse.py +137 -0
  65. fuseji-0.1.0/tests/test_latency_regression.py +72 -0
  66. fuseji-0.1.0/tests/test_ner_base.py +21 -0
  67. fuseji-0.1.0/tests/test_ner_ginza.py +59 -0
  68. fuseji-0.1.0/tests/test_public_api.py +69 -0
  69. fuseji-0.1.0/tests/test_recognizers_base.py +80 -0
  70. fuseji-0.1.0/tests/test_recognizers_credit_card.py +97 -0
  71. fuseji-0.1.0/tests/test_recognizers_email.py +53 -0
  72. fuseji-0.1.0/tests/test_recognizers_jp_phone.py +118 -0
  73. fuseji-0.1.0/tests/test_recognizers_jp_postal.py +77 -0
  74. fuseji-0.1.0/tests/test_recognizers_my_number.py +90 -0
  75. fuseji-0.1.0/tests/test_server.py +149 -0
  76. fuseji-0.1.0/tests/test_strategies.py +151 -0
  77. fuseji-0.1.0/tests/test_types.py +78 -0
  78. fuseji-0.1.0/tests/test_vault.py +282 -0
  79. fuseji-0.1.0/tests/test_vault_strategy.py +83 -0
  80. fuseji-0.1.0/uv.lock +2375 -0
@@ -0,0 +1,41 @@
1
+ ---
2
+ name: バグ報告
3
+ about: 不具合を報告する
4
+ title: ""
5
+ labels: bug
6
+ assignees: ""
7
+ ---
8
+
9
+ ## 現象
10
+
11
+ <!-- 何が起きたかを簡潔に記述してください -->
12
+
13
+ ## 再現手順
14
+
15
+ 1.
16
+ 2.
17
+ 3.
18
+
19
+ ## 期待する動作
20
+
21
+ <!-- 本来どうなるべきかを記述してください -->
22
+
23
+ ## 実際の動作
24
+
25
+ <!-- 実際に起きたことを記述してください -->
26
+
27
+ ## 再現コード
28
+
29
+ ```python
30
+ from fuseji import Masker
31
+
32
+ masker = Masker()
33
+ # ここに再現コードを記述
34
+ ```
35
+
36
+ ## 環境
37
+
38
+ - fuseji バージョン:
39
+ - Python バージョン:
40
+ - OS:
41
+ - extras(ginza, server 等):
@@ -0,0 +1,2 @@
1
+ blank_issues_enabled: true
2
+ contact_links: []
@@ -0,0 +1,25 @@
1
+ ---
2
+ name: 機能要望
3
+ about: 新しい機能やエンティティタイプの追加を提案する
4
+ title: ""
5
+ labels: enhancement
6
+ assignees: ""
7
+ ---
8
+
9
+ ## 概要
10
+
11
+ <!-- どのような機能が欲しいかを簡潔に記述してください -->
12
+
13
+ ## 背景・動機
14
+
15
+ <!-- なぜこの機能が必要かを記述してください -->
16
+
17
+ ## 想定する利用イメージ
18
+
19
+ ```python
20
+ # この機能をどのように使いたいかを記述
21
+ ```
22
+
23
+ ## 備考
24
+
25
+ <!-- 参考情報、代替案などがあれば記述してください -->
@@ -0,0 +1,14 @@
1
+ ## 関連 Issue
2
+
3
+ <!-- closes #123 -->
4
+
5
+ ## 変更内容
6
+
7
+ <!-- 何をどう変更したかを簡潔に記述してください -->
8
+
9
+ ## テスト
10
+
11
+ - [ ] 既存テストが通ること(`uv run pytest`)
12
+ - [ ] 新規テストを追加した(該当する場合)
13
+ - [ ] リントが通ること(`uv run ruff check src/ tests/`)
14
+ - [ ] 型チェックが通ること(`uv run mypy src/`)
@@ -0,0 +1,92 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+ branches: [main]
8
+
9
+ concurrency:
10
+ group: ${{ github.workflow }}-${{ github.ref }}
11
+ cancel-in-progress: true
12
+
13
+ jobs:
14
+ lint:
15
+ name: lint / type-check (Python 3.13)
16
+ runs-on: ubuntu-latest
17
+ steps:
18
+ - uses: actions/checkout@v4
19
+ - name: Set up uv
20
+ uses: astral-sh/setup-uv@v6
21
+ with:
22
+ enable-cache: true
23
+ - name: Set up Python
24
+ run: uv python install 3.13
25
+ - name: Install dependencies (all extras for mypy stubs)
26
+ run: uv sync --all-extras
27
+ - name: ruff check
28
+ run: uv run ruff check src/ tests/
29
+ - name: ruff format check
30
+ run: uv run ruff format --check src/ tests/
31
+ - name: mypy
32
+ run: uv run mypy src/
33
+
34
+ test-core:
35
+ name: test (core, ${{ matrix.python }})
36
+ runs-on: ubuntu-latest
37
+ strategy:
38
+ fail-fast: false
39
+ matrix:
40
+ # Python 3.14 まで含める。test-extras(ginza)は spaCy 3.8 の wheel 制約で
41
+ # 3.13 までしか試せないため、本マトリクスは core のみ。
42
+ python: ["3.10", "3.11", "3.12", "3.13", "3.14"]
43
+ steps:
44
+ - uses: actions/checkout@v4
45
+ - name: Set up uv
46
+ uses: astral-sh/setup-uv@v6
47
+ with:
48
+ enable-cache: true
49
+ - name: Set up Python ${{ matrix.python }}
50
+ run: uv python install ${{ matrix.python }}
51
+ - name: Install dependencies (core only — extras なし)
52
+ run: uv sync --python ${{ matrix.python }}
53
+ - name: pytest (extras なし — ginza/server テストは skip)
54
+ run: uv run pytest -q
55
+
56
+ test-extras:
57
+ name: test (all extras, Python 3.13)
58
+ runs-on: ubuntu-latest
59
+ steps:
60
+ - uses: actions/checkout@v4
61
+ - name: Set up uv
62
+ uses: astral-sh/setup-uv@v6
63
+ with:
64
+ enable-cache: true
65
+ - name: Set up Python
66
+ run: uv python install 3.13
67
+ - name: Install all extras (ginza + server)
68
+ run: uv sync --all-extras
69
+ - name: pytest (all extras)
70
+ run: uv run pytest -q
71
+
72
+ bench:
73
+ name: bench (informational)
74
+ runs-on: ubuntu-latest
75
+ # 情報表示のみ。回帰検知 assertion 化は別 Issue で対応。
76
+ continue-on-error: true
77
+ steps:
78
+ - uses: actions/checkout@v4
79
+ - name: Set up uv
80
+ uses: astral-sh/setup-uv@v6
81
+ with:
82
+ enable-cache: true
83
+ - name: Set up Python
84
+ run: uv python install 3.13
85
+ - name: Install dependencies
86
+ run: uv sync --all-extras
87
+ - name: pytest-benchmark (情報表示)
88
+ run: |
89
+ uv run pytest tests/bench/ --benchmark-enable \
90
+ --benchmark-columns=min,mean,max,stddev,median \
91
+ --benchmark-group-by=group \
92
+ --benchmark-warmup=on
@@ -0,0 +1,96 @@
1
+ name: Publish to PyPI
2
+
3
+ on:
4
+ workflow_dispatch:
5
+ inputs:
6
+ target:
7
+ description: '公開先 (testpypi で検証 → pypi で本番公開)'
8
+ required: true
9
+ type: choice
10
+ options:
11
+ - testpypi
12
+ - pypi
13
+ push:
14
+ tags:
15
+ # vX.Y.Z 形式のタグ push 時に PyPI 本番へ自動公開
16
+ - 'v[0-9]+.[0-9]+.[0-9]+'
17
+ - 'v[0-9]+.[0-9]+.[0-9]+rc[0-9]+'
18
+
19
+ jobs:
20
+ build:
21
+ name: Build sdist + wheel
22
+ runs-on: ubuntu-latest
23
+ steps:
24
+ - uses: actions/checkout@v4
25
+ with:
26
+ fetch-depth: 0 # version 推定や changelog 生成のため履歴フル取得
27
+ - name: Set up uv
28
+ uses: astral-sh/setup-uv@v6
29
+ with:
30
+ enable-cache: true
31
+ - name: Set up Python 3.13
32
+ run: uv python install 3.13
33
+ - name: Install dependencies (all extras for mypy stubs)
34
+ run: uv sync --all-extras
35
+ - name: ruff check
36
+ run: uv run ruff check src/ tests/
37
+ - name: ruff format check
38
+ run: uv run ruff format --check src/ tests/
39
+ - name: mypy
40
+ run: uv run mypy src/
41
+ - name: pytest
42
+ run: uv run pytest -q
43
+ - name: Build distributions
44
+ run: uv build
45
+ - name: Verify built artifacts
46
+ run: |
47
+ ls -la dist/
48
+ uv run python -m zipfile -l dist/*.whl | head -20
49
+ - name: Upload build artifacts
50
+ uses: actions/upload-artifact@v4
51
+ with:
52
+ name: dist
53
+ path: dist/
54
+ retention-days: 7
55
+
56
+ publish-testpypi:
57
+ name: Publish to TestPyPI
58
+ needs: build
59
+ if: github.event_name == 'workflow_dispatch' && inputs.target == 'testpypi'
60
+ runs-on: ubuntu-latest
61
+ environment:
62
+ name: testpypi
63
+ url: https://test.pypi.org/p/fuseji
64
+ permissions:
65
+ id-token: write # OIDC token for trusted publishing
66
+ steps:
67
+ - name: Download build artifacts
68
+ uses: actions/download-artifact@v4
69
+ with:
70
+ name: dist
71
+ path: dist/
72
+ - name: Publish to TestPyPI
73
+ uses: pypa/gh-action-pypi-publish@release/v1
74
+ with:
75
+ repository-url: https://test.pypi.org/legacy/
76
+
77
+ publish-pypi:
78
+ name: Publish to PyPI
79
+ needs: build
80
+ if: >-
81
+ github.event_name == 'push' ||
82
+ (github.event_name == 'workflow_dispatch' && inputs.target == 'pypi')
83
+ runs-on: ubuntu-latest
84
+ environment:
85
+ name: pypi
86
+ url: https://pypi.org/p/fuseji
87
+ permissions:
88
+ id-token: write # OIDC token for trusted publishing
89
+ steps:
90
+ - name: Download build artifacts
91
+ uses: actions/download-artifact@v4
92
+ with:
93
+ name: dist
94
+ path: dist/
95
+ - name: Publish to PyPI
96
+ uses: pypa/gh-action-pypi-publish@release/v1
@@ -0,0 +1,37 @@
1
+ # Python
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+ *.so
6
+ *.egg-info/
7
+ *.egg
8
+ dist/
9
+ build/
10
+ *.whl
11
+
12
+ # 仮想環境
13
+ .venv/
14
+ venv/
15
+ env/
16
+
17
+ # テスト・カバレッジ
18
+ .pytest_cache/
19
+ .coverage
20
+ htmlcov/
21
+ .mypy_cache/
22
+ .ruff_cache/
23
+
24
+ # IDE
25
+ .vscode/
26
+ .idea/
27
+ *.swp
28
+ *.swo
29
+ *~
30
+
31
+ # OS
32
+ .DS_Store
33
+ Thumbs.db
34
+
35
+ # 環境変数
36
+ .env
37
+ .env.local
@@ -0,0 +1 @@
1
+ 3.13
@@ -0,0 +1,84 @@
1
+ # 変更履歴 / Changelog
2
+
3
+ 本ファイルは [Keep a Changelog](https://keepachangelog.com/ja/1.1.0/) に従い、
4
+ バージョニングは [Semantic Versioning](https://semver.org/spec/v2.0.0.html) に従います。
5
+
6
+ ## [Unreleased]
7
+
8
+ ## [0.1.0] - 2026-06-12
9
+
10
+ 初回 PyPI リリース。日本語特化の PII 検出・マスキングミドルウェア。
11
+
12
+ ### Added
13
+
14
+ #### コア機能
15
+
16
+ - **コア型**: `Entity`、`MaskResult`(frozen dataclass、バリデーション付き)
17
+ - **マスキング戦略**: `MaskStrategy` プロトコル + `Placeholder` / `Redact` / `Hash` / `VaultStrategy` の 4 実装
18
+ - **仮名化バウルト**: `Vault` プロトコル + `InMemoryVault` 実装。同一 (type, surface) → 同一 placeholder、`MY_NUMBER` をデフォルト除外(番号法対応)
19
+ - `restore()` は placeholder regex マッチで silent corruption を構造的に防ぐ
20
+ - `clear()` で全マッピングを破棄可能(`excluded_types` 設定は維持)
21
+ - `size` プロパティで登録済み placeholder 数を取得
22
+ - `assign()` は `threading.Lock` で保護(並行採番衝突なし)
23
+ - `__repr__` で状態を可視化
24
+ - **PII 認識器(v0.1 セット)**:
25
+ - `EMAIL`(RFC-lite)
26
+ - `CREDIT_CARD`(Luhn 検証)
27
+ - `MY_NUMBER`(12 桁、総務省公開仕様のチェックディジット、recall 優先)
28
+ - `JP_PHONE_NUMBER`(携帯 070/080/090、フリーダイヤル 0120、ナビダイヤル 0570、固定電話)
29
+ - `JP_POSTAL_CODE`(〒、コンテキストブースト)
30
+ - すべて全角数字・全角ハイフン対応、共通ヘルパ(`SEPARATOR_PATTERN`, `has_digit_boundary`)
31
+ - **NER バックエンド**: `NerBackend` プロトコル + GiNZA 実装(`[ginza]` extra)で PERSON 検出
32
+ - **Masker エンジン**:
33
+ - `Masker.mask` / `Masker.mask_json` / `Masker.detect`
34
+ - オーバーラップ解決はスコア優先 → 長 span 優先 → 開始位置順
35
+ - `max_json_depth`(既定 100)で `mask_json` の再帰深度を制限、超過時は fail-closed
36
+ - `Masker(vault=..., strategy=...)` 同時指定で `UserWarning`(vault 優先)
37
+
38
+ #### 統合
39
+
40
+ - **Langfuse SDK アダプタ**: `make_mask_fn()`。fail-closed 設計
41
+ - 例外時は固定 placeholder `"[fuseji: masking failed]"` を返し原データを露出しない
42
+ - デフォルトログは例外型名のみ(traceback 内 PII 漏洩防止)、`FUSEJI_LANGFUSE_LOG_TRACEBACK=1` で詳細出力
43
+ - **FastAPI サーバー**(`[server]` extra):
44
+ - `POST /mask` / `POST /detect` / `GET /healthz` / OpenAPI 自動生成
45
+ - `create_app(masker=..., max_body_bytes=...)` factory で DI
46
+ - `BodySizeLimitMiddleware` で 1MB 超リクエストを 413 で拒否(環境変数で上書き可)
47
+
48
+ #### API ユーティリティ
49
+
50
+ - **`fuseji.entity_types` 定数モジュール**: `EMAIL` / `CREDIT_CARD` / `MY_NUMBER` / `JP_PHONE_NUMBER` / `JP_POSTAL_CODE` / `PERSON` を str 定数として提供
51
+ - **`FusejiError` 例外階層**: `FusejiError`(基底)/ `InvalidEntityError` / `InvalidConfigError`。多重継承で `ValueError` も継承(後方互換)
52
+ - **公開 API の docstring に Example セクション**(doctest として実行可能)
53
+
54
+ #### 品質・運用
55
+
56
+ - **CI**: GitHub Actions で ruff / mypy / pytest を Python 3.10–3.14 マトリクス + 全 extras ジョブ + 情報的 bench ジョブ
57
+ - **fuseji-bench**: `pytest-benchmark` 基盤と 23 ベンチケース
58
+ - **レイテンシ回帰検知テスト**: O(n²) バグ等を通常 pytest で即時 fail(Masker 1KB/4KB、Vault.restore m=1000)
59
+ - **PyPI 公開**: Trusted Publishing (OIDC) workflow
60
+
61
+ ### Performance
62
+
63
+ - `_replace_spans` を list-of-segments の 1 パスに変更し O(n²) → O(n+k)
64
+ - `normalize()` の translate テーブルを統合し 2 パスから 1 パスに
65
+
66
+ ### Security
67
+
68
+ - マイナンバーは Vault のデフォルト除外集合に含み復元不可
69
+ - `InMemoryVault.restore()` を placeholder regex マッチに変更し silent corruption を構造的に排除
70
+ - `InMemoryVault.assign` を `threading.Lock` で保護
71
+ - Langfuse adapter のデフォルトログから traceback 除去
72
+ - `Masker(max_json_depth=...)` で DoS 対策
73
+ - `BodySizeLimitMiddleware` で巨大ペイロードを拒否
74
+
75
+ ### Documentation
76
+
77
+ - README(日本語メイン + 英語ミラー)
78
+ - SECURITY.md(番号法対応・脆弱性報告窓口・設計上の安全保証)
79
+ - docs/design.md / docs/api.md
80
+ - examples/(Langfuse SDK / ingestion callback / OTel / GiNZA)
81
+ - CONTRIBUTING.md
82
+
83
+ [Unreleased]: https://github.com/sserada/fuseji/compare/v0.1.0...HEAD
84
+ [0.1.0]: https://github.com/sserada/fuseji/releases/tag/v0.1.0
fuseji-0.1.0/CLAUDE.md ADDED
@@ -0,0 +1,47 @@
1
+ # fuseji 開発ガイド
2
+
3
+ ## プロジェクト概要
4
+
5
+ fuseji (伏せ字) — 日本語特化のPII検出・マスキングミドルウェア(LLMオブザーバビリティ向け)。
6
+ Python 3.10+、`uv` でパッケージ管理。
7
+
8
+ ## 開発フロー
9
+
10
+ 1. GitHub Issue を作成し、タスクを記述する
11
+ 2. `main` からブランチを作成する: `feat/<issue番号>-<短い説明>`, `fix/<issue番号>-<短い説明>`, `chore/<issue番号>-<短い説明>`
12
+ 3. 開発・コミット
13
+ 4. Issue を参照する PR を `main` に対して作成する
14
+ 5. レビュー後にマージ
15
+
16
+ `main` への直接 push は禁止。必ず PR を経由すること。
17
+
18
+ ## コマンド
19
+
20
+ ```bash
21
+ uv sync # 依存関係のインストール
22
+ uv run ruff check src/ tests/ # リント
23
+ uv run ruff format src/ tests/ # フォーマット
24
+ uv run mypy src/ # 型チェック
25
+ uv run pytest # テスト実行
26
+ ```
27
+
28
+ ## コード規約
29
+
30
+ - ソースレイアウト: `src/fuseji/`
31
+ - 公開APIには型アノテーション必須
32
+ - docstring・コメントは日本語
33
+ - Issue・PR・コミットメッセージは日本語
34
+
35
+ ## ディレクトリ構成
36
+
37
+ ```
38
+ src/fuseji/
39
+ ├── engine.py # Maskerエンジン
40
+ ├── types.py # Entity, MaskResult
41
+ ├── strategies.py # Placeholder / Redact / Hash
42
+ ├── vault.py # 仮名化バウルト
43
+ ├── recognizers/ # PII認識器
44
+ ├── ner/ # NERバックエンド
45
+ ├── integrations/ # 外部サービス連携
46
+ └── server/ # FastAPIサーバー
47
+ ```
@@ -0,0 +1,55 @@
1
+ # コントリビューションガイド
2
+
3
+ fuseji への貢献に感謝します。
4
+
5
+ ## 開発環境のセットアップ
6
+
7
+ ```bash
8
+ # リポジトリをクローン
9
+ git clone https://github.com/sserada/fuseji.git
10
+ cd fuseji
11
+
12
+ # 依存関係をインストール(uv が必要)
13
+ uv sync --all-extras
14
+ ```
15
+
16
+ ## 開発フロー
17
+
18
+ 1. Issue を作成し、やることを記述する
19
+ 2. `main` からブランチを作成する
20
+ - 機能追加: `feat/<issue番号>-<短い説明>`
21
+ - バグ修正: `fix/<issue番号>-<短い説明>`
22
+ - その他: `chore/<issue番号>-<短い説明>`
23
+ 3. 開発・コミット
24
+ 4. PR を作成し、関連 Issue を参照する
25
+
26
+ ## コマンド
27
+
28
+ ```bash
29
+ uv run ruff check src/ tests/ # リント
30
+ uv run ruff format src/ tests/ # フォーマット
31
+ uv run mypy src/ # 型チェック
32
+ uv run pytest # テスト
33
+ ```
34
+
35
+ ## コード規約
36
+
37
+ - docstring・コメントは日本語
38
+ - 公開 API には型アノテーション必須
39
+ - PR 前にリント・型チェック・テストをすべて通すこと
40
+
41
+ ## 認識器の追加
42
+
43
+ 新しい PII 認識器の追加は歓迎します。`Recognizer` プロトコルを実装してください:
44
+
45
+ ```python
46
+ class Recognizer(Protocol):
47
+ entity_type: str
48
+ def analyze(self, text: str) -> Iterable[Entity]: ...
49
+ ```
50
+
51
+ テストには全角/半角バリエーション、コンテキスト語の有無、偽陽性ケースを含めてください。
52
+
53
+ ## ライセンス
54
+
55
+ コントリビューションは Apache-2.0 ライセンスの下で提供されます。