ai-profile-cli 0.3.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 (153) hide show
  1. ai_profile_cli-0.3.0/.gitattributes +3 -0
  2. ai_profile_cli-0.3.0/.github/workflows/ci.yml +29 -0
  3. ai_profile_cli-0.3.0/.github/workflows/publish.yml +40 -0
  4. ai_profile_cli-0.3.0/.gitignore +17 -0
  5. ai_profile_cli-0.3.0/.hypothesis/.gitignore +9 -0
  6. ai_profile_cli-0.3.0/.hypothesis/constants/015c2e410aaf7eb9 +4 -0
  7. ai_profile_cli-0.3.0/.hypothesis/constants/0ba88f907dc84408 +4 -0
  8. ai_profile_cli-0.3.0/.hypothesis/constants/181e26901f2aa440 +4 -0
  9. ai_profile_cli-0.3.0/.hypothesis/constants/1d91045722da8d58 +4 -0
  10. ai_profile_cli-0.3.0/.hypothesis/constants/300729828f9fc1d2 +4 -0
  11. ai_profile_cli-0.3.0/.hypothesis/constants/3dd03d239e44486d +4 -0
  12. ai_profile_cli-0.3.0/.hypothesis/constants/46484eb265dbc142 +4 -0
  13. ai_profile_cli-0.3.0/.hypothesis/constants/469682b22d658606 +4 -0
  14. ai_profile_cli-0.3.0/.hypothesis/constants/4787e114548c11ed +4 -0
  15. ai_profile_cli-0.3.0/.hypothesis/constants/4b3dc9d999dfb5d7 +4 -0
  16. ai_profile_cli-0.3.0/.hypothesis/constants/5b73d75526838a3e +4 -0
  17. ai_profile_cli-0.3.0/.hypothesis/constants/606cf4e2a9f0bcd3 +4 -0
  18. ai_profile_cli-0.3.0/.hypothesis/constants/66104b2322415e55 +4 -0
  19. ai_profile_cli-0.3.0/.hypothesis/constants/6939069d327ecd0c +4 -0
  20. ai_profile_cli-0.3.0/.hypothesis/constants/6a7bfa945445f617 +4 -0
  21. ai_profile_cli-0.3.0/.hypothesis/constants/6d23c053eeec8d84 +4 -0
  22. ai_profile_cli-0.3.0/.hypothesis/constants/6e9774fcaa01b7a7 +4 -0
  23. ai_profile_cli-0.3.0/.hypothesis/constants/9487c4f418fac494 +4 -0
  24. ai_profile_cli-0.3.0/.hypothesis/constants/a762b1fa0f7c34ce +4 -0
  25. ai_profile_cli-0.3.0/.hypothesis/constants/a7a1f2134e21af76 +4 -0
  26. ai_profile_cli-0.3.0/.hypothesis/constants/ae8276b72ed1f0ea +4 -0
  27. ai_profile_cli-0.3.0/.hypothesis/constants/c827650f32894259 +4 -0
  28. ai_profile_cli-0.3.0/.hypothesis/constants/ce0d3408eab3b4ef +4 -0
  29. ai_profile_cli-0.3.0/.hypothesis/constants/e409c1c2a387079e +4 -0
  30. ai_profile_cli-0.3.0/.hypothesis/constants/f191e6a3a01e3bf3 +4 -0
  31. ai_profile_cli-0.3.0/.hypothesis/constants/f579a39123bc3edb +4 -0
  32. ai_profile_cli-0.3.0/.hypothesis/unicode_data/15.0.0/charmap.json.gz +0 -0
  33. ai_profile_cli-0.3.0/AGENTS.md +129 -0
  34. ai_profile_cli-0.3.0/CHANGELOG.md +132 -0
  35. ai_profile_cli-0.3.0/CONTRIBUTING.md +44 -0
  36. ai_profile_cli-0.3.0/LICENSE +21 -0
  37. ai_profile_cli-0.3.0/PKG-INFO +215 -0
  38. ai_profile_cli-0.3.0/README.md +191 -0
  39. ai_profile_cli-0.3.0/README.zh-TW.md +178 -0
  40. ai_profile_cli-0.3.0/THIRD_PARTY_NOTICES.md +48 -0
  41. ai_profile_cli-0.3.0/docs/PRIVACY.md +69 -0
  42. ai_profile_cli-0.3.0/docs/ROADMAP.md +155 -0
  43. ai_profile_cli-0.3.0/docs/architecture.md +347 -0
  44. ai_profile_cli-0.3.0/docs/assets/badge-sample-dark.svg +12 -0
  45. ai_profile_cli-0.3.0/docs/assets/badge-sample-light.svg +12 -0
  46. ai_profile_cli-0.3.0/docs/assets/banner-dark.svg +59 -0
  47. ai_profile_cli-0.3.0/docs/assets/banner-light.svg +59 -0
  48. ai_profile_cli-0.3.0/docs/assets/heatmap-sample-dark.svg +414 -0
  49. ai_profile_cli-0.3.0/docs/assets/heatmap-sample-light.svg +414 -0
  50. ai_profile_cli-0.3.0/docs/assets/social-preview.png +0 -0
  51. ai_profile_cli-0.3.0/docs/assets/social-preview.svg +60 -0
  52. ai_profile_cli-0.3.0/docs/assets/summary-sample-dark.svg +194 -0
  53. ai_profile_cli-0.3.0/docs/assets/summary-sample-light.svg +194 -0
  54. ai_profile_cli-0.3.0/docs/decisions/ADR-001-language-and-packaging.md +30 -0
  55. ai_profile_cli-0.3.0/docs/decisions/ADR-002-cli-framework.md +21 -0
  56. ai_profile_cli-0.3.0/docs/decisions/ADR-003-data-validation.md +30 -0
  57. ai_profile_cli-0.3.0/docs/decisions/ADR-004-sqlite-access-and-migrations.md +27 -0
  58. ai_profile_cli-0.3.0/docs/decisions/ADR-005-git-metadata-format.md +75 -0
  59. ai_profile_cli-0.3.0/docs/decisions/ADR-006-git-notes-namespace.md +30 -0
  60. ai_profile_cli-0.3.0/docs/decisions/ADR-007-deterministic-event-ids.md +41 -0
  61. ai_profile_cli-0.3.0/docs/decisions/ADR-008-evidence-precedence.md +51 -0
  62. ai_profile_cli-0.3.0/docs/decisions/ADR-009-private-data-handling.md +76 -0
  63. ai_profile_cli-0.3.0/docs/decisions/ADR-010-svg-rendering.md +50 -0
  64. ai_profile_cli-0.3.0/docs/decisions/ADR-011-github-authentication.md +31 -0
  65. ai_profile_cli-0.3.0/docs/decisions/ADR-012-schema-versioning.md +40 -0
  66. ai_profile_cli-0.3.0/docs/decisions/ADR-013-provider-normalization.md +41 -0
  67. ai_profile_cli-0.3.0/docs/decisions/ADR-014-rewritten-history.md +44 -0
  68. ai_profile_cli-0.3.0/docs/decisions/ADR-015-identity-matching.md +28 -0
  69. ai_profile_cli-0.3.0/docs/decisions/ADR-016-repository-identity-canonicalization.md +120 -0
  70. ai_profile_cli-0.3.0/docs/decisions/ADR-017-provider-brand-glyphs.md +390 -0
  71. ai_profile_cli-0.3.0/docs/decisions/ADR-018-daily-activity-series.md +87 -0
  72. ai_profile_cli-0.3.0/docs/decisions/ADR-019-two-tier-provider-vocabulary.md +139 -0
  73. ai_profile_cli-0.3.0/docs/decisions/ADR-020-collaboration-heatmap-and-badge.md +68 -0
  74. ai_profile_cli-0.3.0/docs/landscape.md +220 -0
  75. ai_profile_cli-0.3.0/docs/mvp.md +269 -0
  76. ai_profile_cli-0.3.0/docs/progress.md +352 -0
  77. ai_profile_cli-0.3.0/docs/proposal.md +1731 -0
  78. ai_profile_cli-0.3.0/docs/reviews/gate-disposition.md +354 -0
  79. ai_profile_cli-0.3.0/docs/reviews/gate-review.md +113 -0
  80. ai_profile_cli-0.3.0/docs/reviews/gate2-disposition.md +55 -0
  81. ai_profile_cli-0.3.0/docs/reviews/gate2-review.md +601 -0
  82. ai_profile_cli-0.3.0/docs/reviews/gate9-second-opinion.md +79 -0
  83. ai_profile_cli-0.3.0/docs/reviews/v0.1-run-log.md +98 -0
  84. ai_profile_cli-0.3.0/docs/schema.md +572 -0
  85. ai_profile_cli-0.3.0/pyproject.toml +50 -0
  86. ai_profile_cli-0.3.0/scripts/release_smoke.py +387 -0
  87. ai_profile_cli-0.3.0/scripts/vendor_brand_icons.py +575 -0
  88. ai_profile_cli-0.3.0/src/aiprofile/__init__.py +7 -0
  89. ai_profile_cli-0.3.0/src/aiprofile/__main__.py +7 -0
  90. ai_profile_cli-0.3.0/src/aiprofile/adapters/__init__.py +1 -0
  91. ai_profile_cli-0.3.0/src/aiprofile/adapters/trailers.py +381 -0
  92. ai_profile_cli-0.3.0/src/aiprofile/aggregate.py +338 -0
  93. ai_profile_cli-0.3.0/src/aiprofile/cli.py +299 -0
  94. ai_profile_cli-0.3.0/src/aiprofile/config.py +233 -0
  95. ai_profile_cli-0.3.0/src/aiprofile/errors.py +33 -0
  96. ai_profile_cli-0.3.0/src/aiprofile/export.py +201 -0
  97. ai_profile_cli-0.3.0/src/aiprofile/gitio.py +326 -0
  98. ai_profile_cli-0.3.0/src/aiprofile/privacy.py +256 -0
  99. ai_profile_cli-0.3.0/src/aiprofile/registry.py +200 -0
  100. ai_profile_cli-0.3.0/src/aiprofile/render/__init__.py +1 -0
  101. ai_profile_cli-0.3.0/src/aiprofile/render/badge_svg.py +90 -0
  102. ai_profile_cli-0.3.0/src/aiprofile/render/brand.py +514 -0
  103. ai_profile_cli-0.3.0/src/aiprofile/render/heatmap_svg.py +369 -0
  104. ai_profile_cli-0.3.0/src/aiprofile/render/summary_svg.py +1180 -0
  105. ai_profile_cli-0.3.0/src/aiprofile/render/themes.py +76 -0
  106. ai_profile_cli-0.3.0/src/aiprofile/scanner.py +203 -0
  107. ai_profile_cli-0.3.0/src/aiprofile/schema/__init__.py +37 -0
  108. ai_profile_cli-0.3.0/src/aiprofile/schema/event.py +528 -0
  109. ai_profile_cli-0.3.0/src/aiprofile/schema/vocab.py +208 -0
  110. ai_profile_cli-0.3.0/src/aiprofile/storage/__init__.py +1 -0
  111. ai_profile_cli-0.3.0/src/aiprofile/storage/db.py +136 -0
  112. ai_profile_cli-0.3.0/src/aiprofile/storage/migrations.py +76 -0
  113. ai_profile_cli-0.3.0/src/aiprofile/storage/store.py +186 -0
  114. ai_profile_cli-0.3.0/src/aiprofile/viz.py +535 -0
  115. ai_profile_cli-0.3.0/tests/integration/helpers.py +100 -0
  116. ai_profile_cli-0.3.0/tests/integration/test_cherry_pick.py +160 -0
  117. ai_profile_cli-0.3.0/tests/integration/test_console_privacy.py +241 -0
  118. ai_profile_cli-0.3.0/tests/integration/test_end_to_end.py +699 -0
  119. ai_profile_cli-0.3.0/tests/snapshots/badge_dark.svg +12 -0
  120. ai_profile_cli-0.3.0/tests/snapshots/badge_light.svg +12 -0
  121. ai_profile_cli-0.3.0/tests/snapshots/badge_zero_dark.svg +12 -0
  122. ai_profile_cli-0.3.0/tests/snapshots/badge_zero_light.svg +12 -0
  123. ai_profile_cli-0.3.0/tests/snapshots/heatmap_dark.svg +414 -0
  124. ai_profile_cli-0.3.0/tests/snapshots/heatmap_empty_dark.svg +13 -0
  125. ai_profile_cli-0.3.0/tests/snapshots/heatmap_empty_light.svg +13 -0
  126. ai_profile_cli-0.3.0/tests/snapshots/heatmap_light.svg +414 -0
  127. ai_profile_cli-0.3.0/tests/snapshots/summary_populated_dark.svg +194 -0
  128. ai_profile_cli-0.3.0/tests/snapshots/summary_populated_light.svg +194 -0
  129. ai_profile_cli-0.3.0/tests/snapshots/summary_privacy_false_dark.svg +56 -0
  130. ai_profile_cli-0.3.0/tests/snapshots/summary_privacy_false_light.svg +56 -0
  131. ai_profile_cli-0.3.0/tests/snapshots/summary_privacy_true_dark.svg +56 -0
  132. ai_profile_cli-0.3.0/tests/snapshots/summary_privacy_true_light.svg +56 -0
  133. ai_profile_cli-0.3.0/tests/snapshots/summary_zero_dark.svg +15 -0
  134. ai_profile_cli-0.3.0/tests/snapshots/summary_zero_light.svg +15 -0
  135. ai_profile_cli-0.3.0/tests/unit/test_aggregate.py +747 -0
  136. ai_profile_cli-0.3.0/tests/unit/test_brand.py +281 -0
  137. ai_profile_cli-0.3.0/tests/unit/test_calendar_band.py +622 -0
  138. ai_profile_cli-0.3.0/tests/unit/test_config.py +177 -0
  139. ai_profile_cli-0.3.0/tests/unit/test_dependency_isolation.py +112 -0
  140. ai_profile_cli-0.3.0/tests/unit/test_export_atomic.py +348 -0
  141. ai_profile_cli-0.3.0/tests/unit/test_gitio_paths.py +51 -0
  142. ai_profile_cli-0.3.0/tests/unit/test_gitio_uid.py +460 -0
  143. ai_profile_cli-0.3.0/tests/unit/test_hardening.py +245 -0
  144. ai_profile_cli-0.3.0/tests/unit/test_heatmap_svg.py +394 -0
  145. ai_profile_cli-0.3.0/tests/unit/test_privacy_boundary.py +298 -0
  146. ai_profile_cli-0.3.0/tests/unit/test_properties.py +477 -0
  147. ai_profile_cli-0.3.0/tests/unit/test_render_summary.py +854 -0
  148. ai_profile_cli-0.3.0/tests/unit/test_scanner_orchestration.py +207 -0
  149. ai_profile_cli-0.3.0/tests/unit/test_schema_event.py +899 -0
  150. ai_profile_cli-0.3.0/tests/unit/test_storage.py +565 -0
  151. ai_profile_cli-0.3.0/tests/unit/test_trailers.py +479 -0
  152. ai_profile_cli-0.3.0/tests/unit/test_viz_contract.py +550 -0
  153. ai_profile_cli-0.3.0/tests/unit/test_vocab_registry.py +246 -0
@@ -0,0 +1,3 @@
1
+ * text=auto eol=lf
2
+ *.png binary
3
+ *.svg text eol=lf
@@ -0,0 +1,29 @@
1
+ # Continuous verification on every push/PR: the full suite + lint.
2
+ # This is the workflow behind the README's tests badge - the badge is
3
+ # only as honest as this file stays.
4
+ name: tests
5
+
6
+ on:
7
+ push:
8
+ branches: ["main"]
9
+ pull_request:
10
+
11
+ permissions:
12
+ contents: read
13
+
14
+ jobs:
15
+ tests:
16
+ runs-on: ubuntu-latest
17
+ timeout-minutes: 15
18
+ steps:
19
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
20
+ with:
21
+ persist-credentials: false
22
+ - uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
23
+ with:
24
+ python-version: "3.12"
25
+ - name: Full suite + lint
26
+ run: |
27
+ python -m pip install -e ".[dev]"
28
+ python -m pytest tests -p no:cacheprovider
29
+ python -m ruff check src tests scripts
@@ -0,0 +1,40 @@
1
+ # Tag-triggered PyPI publish via Trusted Publishing (OIDC - no stored
2
+ # secrets anywhere). Prerequisite (one-time, PyPI web UI): a publisher
3
+ # for project `ai-profile-cli`, owner WenyuChiou, repository ai-profile,
4
+ # workflow publish.yml. The suite + ruff gate the upload: a red test
5
+ # means no release, ever.
6
+ name: publish
7
+
8
+ on:
9
+ push:
10
+ tags: ["v*"]
11
+
12
+ permissions:
13
+ contents: read
14
+
15
+ jobs:
16
+ publish:
17
+ runs-on: ubuntu-latest
18
+ timeout-minutes: 15
19
+ environment: pypi
20
+ permissions:
21
+ contents: read
22
+ id-token: write # OIDC token for PyPI Trusted Publishing
23
+ steps:
24
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
25
+ with:
26
+ persist-credentials: false
27
+ - uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
28
+ with:
29
+ python-version: "3.12"
30
+ - name: Gate - full suite + lint
31
+ run: |
32
+ python -m pip install -e ".[dev]"
33
+ python -m pytest tests -p no:cacheprovider
34
+ python -m ruff check src tests scripts
35
+ - name: Build sdist + wheel
36
+ run: |
37
+ python -m pip install build==1.4.3
38
+ python -m build
39
+ - name: Publish to PyPI (Trusted Publishing)
40
+ uses: pypa/gh-action-pypi-publish@ba38be9e461d3875417946c167d0b5f3d385a247 # v1.14.1
@@ -0,0 +1,17 @@
1
+ __pycache__/
2
+ *.py[cod]
3
+ *.egg-info/
4
+ .pytest_cache/
5
+ .ruff_cache/
6
+ dist/
7
+ build/
8
+ .venv/
9
+ .playwright-mcp/
10
+
11
+ # Agent-collaboration working files (briefs, transcripts, replies) and
12
+ # local artifact exports — never repo content. Shared here (not in
13
+ # .git/info/exclude) so fresh clones are protected too: these files can
14
+ # carry local absolute paths.
15
+ /.ai/
16
+ /.artifact/
17
+ .claude/settings.local.json
@@ -0,0 +1,9 @@
1
+ # This .gitignore file was automatically created by Hypothesis. Hypothesis gitignores
2
+ # .hypothesis by default, because we generally recommend that .hypothesis not be checked
3
+ # into version control.
4
+ #
5
+ # If you *would* like to check .hypothesis into version control, you should delete this
6
+ # file. Hypothesis will not re-create this .gitignore unless .hypothesis is deleted (and
7
+ # if it does, that's a bug - please report it!)
8
+
9
+ *
@@ -0,0 +1,4 @@
1
+ # file: /home/runner/work/ai-profile/ai-profile/src/aiprofile/storage/db.py
2
+ # hypothesis_version: 6.161.1
3
+
4
+ [384, ';', 'BEGIN', 'version', 'win32']
@@ -0,0 +1,4 @@
1
+ # file: /home/runner/work/ai-profile/ai-profile/src/aiprofile/scanner.py
2
+ # hypothesis_version: 6.161.1
3
+
4
+ ['sha1']
@@ -0,0 +1,4 @@
1
+ # file: /home/runner/work/ai-profile/ai-profile/src/aiprofile/viz.py
2
+ # hypothesis_version: 6.161.1
3
+
4
+ [365, 'All time', 'active_ai_days', 'active_days', 'actor_presences', 'ai_actor_presences', 'ai_commits', 'attributed_commits', 'commits_scanned', 'counts', 'daily', 'daily container', 'daily date', 'date', 'declared', 'display name', 'display_name', 'each day cell', 'each day count', 'each provider row', 'evidence', 'evidence_records', 'from', 'generated_on', 'imported', 'inferred', 'label', 'period', 'period.label', 'privacy', 'provider', 'provider slug', 'provider_count', 'providers', 'providers container', 'schema_version', 'to', 'total_commits', 'total_records', 'totals', 'unknown', 'unknown_commits', 'verified']
@@ -0,0 +1,4 @@
1
+ # file: /home/runner/work/ai-profile/ai-profile/src/aiprofile/render/themes.py
2
+ # hypothesis_version: 6.161.1
3
+
4
+ ['#033d8b', '#0550ae', '#0969da', '#0d1117', '#161b22', '#1f2328', '#1f6feb', '#21262d', '#218bff', '#388bfd', '#3d444d', '#4493f8', '#58a6ff', '#59636e', '#6e7681', '#6e7781', '#9198a1', '#a5d6ff', '#d1d9e0', '#eff2f5', '#f0f6fc', '#f6f8fa', '#ffffff', 'github-dark', 'github-light']
@@ -0,0 +1,4 @@
1
+ # file: /home/runner/work/ai-profile/ai-profile/src/aiprofile/render/summary_svg.py
2
+ # hypothesis_version: 6.161.1
3
+
4
+ [0.2, 0.3, 0.35, 0.5, 0.52, 0.55, 0.56, 0.66, 0.72, 0.75, 0.82, 1.0, 100, 104, 112, 120, 122, 140, 144, 160, 164, 172, 184, 208, 224, 360, 400, 500, 512, 600, 700, 830, '0%', '0.583333', '100%', '</svg>', '<1%', '>99%', '?', 'AI actor presences', 'AI providers', 'Apr', 'Aug', 'Dec', 'Feb', 'Jan', 'Jul', 'Jun', 'Mar', 'May', 'Nov', 'Oct', 'Sep', 'Unknown commits', 'declared', 'end', 'github-dark', "iIl.,:;'`|!ftj ()[]·", 'imported', 'inferred', 'mMW@%&', 'middle', 'start', 'unknown', 'unrecognized', 'verified', '…']
@@ -0,0 +1,4 @@
1
+ # file: /home/runner/work/ai-profile/ai-profile/src/aiprofile/cli.py
2
+ # hypothesis_version: 6.161.1
3
+
4
+ ['%Y-%m-%d', '--full', '--out', '--verbose', '--version', '-v', '.git', 'aggregate', 'aiprofile', 'badge-dark.svg', 'badge-light.svg', 'command', 'dist', 'github-dark', 'github-light', 'heatmap-dark.svg', 'heatmap-light.svg', 'imported', 'inferred', 'init', 'path', 'render', 'scan', 'seconds', 'store_true', 'summary-dark.svg', 'summary-light.svg', 'verified', 'version']
@@ -0,0 +1,4 @@
1
+ # file: /home/runner/work/ai-profile/ai-profile/src/aiprofile/registry.py
2
+ # hypothesis_version: 6.161.1
3
+
4
+ ['aider', 'aider@aider.chat', 'alibaba', 'amazon', 'amazon q', 'amazon-q', 'amazon-q@amazon.com', 'amp', 'amp@ampcode.com', 'anthropic', 'cascade', 'cascade@windsurf.ai', 'cascade@windsurf.com', 'claude code', 'claude-code', 'claudecode', 'codex', 'codex cli', 'codex-cli', 'cognition', 'copilot', 'copilot@github.com', 'cursor', 'deepseek', 'devin', 'gemini', 'gemini cli', 'gemini-cli', 'gemini-code-assist', 'github', 'github copilot', 'github-copilot', 'google', 'jules', 'kimi code', 'kimi-code', 'meta', 'meta ai', 'mistral', 'mistral ai', 'moonshot', 'moonshot ai', 'noreply@google.com', 'noreply@openai.com', 'ollama', 'openai', 'openhands', 'qwen code', 'qwen-code', 'replit', 'replit agent', 'replit-agent', 'roo code', 'roo-code', 'roocode', 'roomote@roocode.com', 'vibe code', 'vibe-code', 'windsurf', 'x.ai', 'xai', 'z.ai', 'zhipu']
@@ -0,0 +1,4 @@
1
+ # file: /home/runner/work/ai-profile/ai-profile/src/aiprofile/config.py
2
+ # hypothesis_version: 6.161.1
3
+
4
+ [384, 448, ', ', '.aiprofile', '.json.tmp', 'AIPROFILE_HOME', 'aiprofile.db', 'config.json', 'identities', 'path', 'publication_level', 'repositories', 'repository_uid', 'salt', 'utf-8', 'win32']
@@ -0,0 +1,4 @@
1
+ # file: /home/runner/work/ai-profile/ai-profile/src/aiprofile/schema/vocab.py
2
+ # hypothesis_version: 6.161.1
3
+
4
+ ['Aider', 'Amazon Q', 'Amp', 'Claude', 'Copilot', 'Cursor', 'DeepSeek', 'Devin', 'GLM', 'Gemini', 'Grok', 'Kimi', 'Llama', 'Mistral', 'Ollama', 'OpenAI', 'OpenHands', 'Qwen', 'Replit', 'Roo Code', 'Unrecognized', 'Windsurf', 'aggregate_only', 'ai', 'ai-mode', 'ai-provider', 'ai-tool', 'ai_assisted', 'ai_generated', 'ai_reviewed', 'aider', 'alibaba', 'amazon', 'amazon-q', 'amp', 'anthropic', 'claude-code', 'co-authored-by', 'codex-cli', 'cognition', 'commit', 'copilot', 'cursor', 'declared', 'deepseek', 'devin', 'documentation', 'excluded', 'full', 'gemini-cli', 'gemini-code-assist', 'git_trailer', 'git_trailer_coauthor', 'github', 'google', 'human', 'human_only', 'human_reviewed_ai', 'implementation', 'imported', 'inferred', 'jules', 'kimi-code', 'manual_declaration', 'meta', 'mistral', 'mixed', 'moonshot', 'none', 'ollama', 'openai', 'openhands', 'other', 'qwen-code', 'replit', 'replit-agent', 'repository_anonymous', 'review', 'roo-code', 'testing', 'unknown', 'unrecognized', 'verified', 'vibe-code', 'windsurf', 'xai', 'zhipu']
@@ -0,0 +1,4 @@
1
+ # file: /home/runner/work/ai-profile/ai-profile/src/aiprofile/adapters/trailers.py
2
+ # hypothesis_version: 6.161.1
3
+
4
+ [',', '-', ':', '_', 'ai-mode', 'ai-model', 'ai-provider', 'ai-reviewed-by', 'ai-role', 'ai-schema', 'ai-tool', 'co-authored-by', 'contradictory-group', 'email', 'human', 'incomplete-group', 'malformed-mode', 'name', 'none', 'present', 'unknown-role', 'values']
@@ -0,0 +1,4 @@
1
+ # file: /home/runner/work/ai-profile/ai-profile/src/aiprofile/storage/__init__.py
2
+ # hypothesis_version: 6.161.1
3
+
4
+ []
@@ -0,0 +1,4 @@
1
+ # file: /home/runner/work/ai-profile/ai-profile/src/aiprofile/export.py
2
+ # hypothesis_version: 6.161.1
3
+
4
+ ['.bak', '.tmp', 'badge-dark.svg', 'badge-light.svg', 'heatmap-dark.svg', 'heatmap-light.svg', 'profile.json', 'summary-dark.svg', 'summary-light.svg', 'utf-8', 'x']
@@ -0,0 +1,4 @@
1
+ # file: /home/runner/work/ai-profile/ai-profile/src/aiprofile/errors.py
2
+ # hypothesis_version: 6.161.1
3
+
4
+ []
@@ -0,0 +1,4 @@
1
+ # file: /home/runner/work/ai-profile/ai-profile/src/aiprofile/storage/store.py
2
+ # hypothesis_version: 6.161.1
3
+
4
+ ['BEGIN', 'id']
@@ -0,0 +1,4 @@
1
+ # file: /home/runner/work/ai-profile/ai-profile/src/aiprofile/schema/__init__.py
2
+ # hypothesis_version: 6.161.1
3
+
4
+ ['AceEvent', 'ActivityType', 'ActorType', 'ContributionMode', 'EvidenceLevel', 'ProvenanceSource', 'PublicationLevel', 'Role', 'SourceType', 'build_event', 'canonical_json', 'compute_event_id', 'merge_event_group', 'to_dict']
@@ -0,0 +1,4 @@
1
+ # file: /home/runner/work/ai-profile/ai-profile/src/aiprofile/schema/event.py
2
+ # hypothesis_version: 6.161.1
3
+
4
+ [',', ', ', ':', '^[0-9a-f]{40}$', 'ace-identity-v1', 'ace_', 'activity', 'activity.roles', 'activity.timestamp', 'activity.type', 'actor', 'actor.type', 'commit_sha', 'contribution_mode', 'event_id', 'evidence_level', 'human_reviewed', 'model', 'model_raw', 'provenance', 'provider', 'provider_raw', 'recorded_at', 'repository_uid', 'roles', 'schema_version', 'source', 'source_reference', 'source_type', 'sources', 'timestamp', 'tool', 'tool_raw', 'type', 'utf-8']
@@ -0,0 +1,4 @@
1
+ # file: /home/runner/work/ai-profile/ai-profile/src/aiprofile/storage/migrations.py
2
+ # hypothesis_version: 6.161.1
3
+
4
+ []
@@ -0,0 +1,4 @@
1
+ # file: /home/runner/work/ai-profile/ai-profile/src/aiprofile/adapters/__init__.py
2
+ # hypothesis_version: 6.161.1
3
+
4
+ []
@@ -0,0 +1,4 @@
1
+ # file: /home/runner/work/ai-profile/ai-profile/src/aiprofile/render/badge_svg.py
2
+ # hypothesis_version: 6.161.1
3
+
4
+ [0.999, '</g>', '</svg>', 'AI-assisted', 'no data', 'verified by git']
@@ -0,0 +1,4 @@
1
+ # file: /home/runner/work/ai-profile/ai-profile/src/aiprofile/__init__.py
2
+ # hypothesis_version: 6.161.1
3
+
4
+ ['0.2.0', '0.3.0']
@@ -0,0 +1,4 @@
1
+ # file: /home/runner/work/ai-profile/ai-profile/src/aiprofile/privacy.py
2
+ # hypothesis_version: 6.161.1
3
+
4
+ ['actor_presences', 'attributed_commits', 'dates']
@@ -0,0 +1,4 @@
1
+ # file: /home/runner/work/ai-profile/ai-profile/src/aiprofile/render/heatmap_svg.py
2
+ # hypothesis_version: 6.161.1
3
+
4
+ [0.45, 0.65, 0.85, 1.0, 112, 120, 124, 364, 600, '#', '0%', '1', '100%', '2-4', '5-7', '8+', '</svg>', 'AI share:', 'Apr', 'Aug', 'Dec', 'Feb', 'Fri', 'Jan', 'Jul', 'Jun', 'Mar', 'May', 'Mon', 'Nov', 'Oct', 'Sep', 'Volume:', 'Wed', 'end', 'middle', '≤25%', '≤50%', '≤75%']
@@ -0,0 +1,4 @@
1
+ # file: /home/runner/work/ai-profile/ai-profile/src/aiprofile/render/brand.py
2
+ # hypothesis_version: 6.161.1
3
+
4
+ ['#000000', '#0B100F', '#152347', '#17171A', '#1B1F24', '#1D1547', '#1E3833', '#2B1547', '#2B203C', '#2D2D2D', '#2E2E2E', '#2E3138', '#33302E', '#3C231B', '#4377FE', '#472315', '#472815', '#5786FE', '#6950EF', '#7A7A7A', '#8E75B2', '#97D8CB', '#9844FF', '#B74C2A', '#DE5A06', '#DFE6F6', '#E2A28D', '#E3DFF6', '#E3E5E8', '#E3F2EF', '#E7E6E4', '#E9DFF6', '#EBEBEB', '#ECE6F4', '#EEEDEC', '#EEEFF1', '#F04805', '#F26207', '#F6E5DF', '#F6E6DF', '#F6E8DF', '#FA520F', 'aider', 'alibaba', 'amazon', 'amp', 'anthropic', 'cognition', 'cursor', 'deepseek', 'github', 'google', 'meta', 'mistral', 'moonshot', 'ollama', 'openai', 'openhands', 'replit', 'roo-code', 'windsurf', 'xai', 'zhipu']
@@ -0,0 +1,4 @@
1
+ # file: /home/runner/work/ai-profile/ai-profile/src/aiprofile/render/__init__.py
2
+ # hypothesis_version: 6.161.1
3
+
4
+ []
@@ -0,0 +1,4 @@
1
+ # file: /home/runner/work/ai-profile/ai-profile/src/aiprofile/aggregate.py
2
+ # hypothesis_version: 6.161.1
3
+
4
+ ['.', '0.1', '0.2', 'activity_timestamp', 'actor_type', 'ai', 'ai_commits', 'attributed_commits', 'commit_id', 'date', 'evidence_level', 'human', 'id', 'mixed', 'n', 'provider', 'provider_raw', 'repository_uid', 'schema_version', 'tool_raw', 'total_commits', 'unknown']
@@ -0,0 +1,4 @@
1
+ # file: /home/runner/work/ai-profile/ai-profile/src/aiprofile/gitio.py
2
+ # hypothesis_version: 6.161.1
3
+
4
+ [300, 65535, '#', '--get', '--show-object-format', '--show-toplevel', '.git', '/', '0', '22', '443', '80', '9418', ':', '?', '@', 'HEAD', '[A-Za-z]', 'bad default revision', 'config', 'file', 'get-url', 'git', 'git+ssh', 'github.com', 'host', 'http', 'https', 'log', 'origin', 'path', 'remote', 'replace', 'rev-parse', 'sha1', 'ssh', 'user.email', 'utf-8', 'v5']
@@ -0,0 +1,129 @@
1
+ # AGENTS.md — agent orientation for ai-profile
2
+
3
+ `aiprofile` is a local-first CLI that scans local Git repos for explicit
4
+ AI provenance (AI-* trailers, known co-author trailers) and renders
5
+ privacy-safe SVG/JSON profile summaries. It is NOT an AI code detector.
6
+ Read `README.md` and `CONTRIBUTING.md` first; where docs and code
7
+ disagree, docs win and the code is the bug.
8
+
9
+ ## Quality gates (must stay green after every change)
10
+
11
+ - `python -m pytest tests -p no:cacheprovider` — full suite; state the
12
+ count you observe (as of 2026-07-21: 340 passed, 1 skipped — the skip
13
+ is a POSIX-only fixture on Windows; if your run differs, update this
14
+ line in the same commit).
15
+ - `python -m ruff check src tests` — clean.
16
+ - Privacy invariants are test-enforced; anything weakening `VizStats`
17
+ structural redaction needs its own ADR. Snapshot/sample regeneration
18
+ only via the sanctioned per-family commands (byte-drift guarded):
19
+ `python tests/unit/test_render_summary.py` (summary family) and
20
+ `python tests/unit/test_heatmap_svg.py` (heatmap/badge family, D4).
21
+ - Contract changes need an ADR under `docs/decisions/` + schema bump.
22
+
23
+ ## Collaboration contract (Fable ↔ Codex gate loop)
24
+
25
+ This repo is built through numbered independent "gate" review rounds:
26
+
27
+ - **Fable (Claude Code)** implements, resolves review findings
28
+ red-first (regression proven failing pre-fix), records dispositions in
29
+ `docs/reviews/gate-disposition.md` + `docs/progress.md`, and is the
30
+ ONLY party that commits (`Resolve gate-N review: ...`).
31
+ - **Codex** acts as independent Principal-Software-Engineer reviewer:
32
+ verification only, adversarial reproduction with runnable probes,
33
+ never commits, never changes production/test/design code. The review
34
+ overwrites `docs/reviews/gate-review.md` (repo convention; usually
35
+ committed alongside the commit that resolves it — but a round may
36
+ leave it deliberately uncommitted, as gate-9's did; check `git status`
37
+ and the round's own commit message/brief before assuming which).
38
+
39
+ ## Handoff protocol (replaces clipboard copy-paste between apps)
40
+
41
+ Round files live in `.ai/handoff/` (git-ignored via `.git/info/exclude`;
42
+ Codex's file tools read them regardless):
43
+
44
+ - `NNN_<slug>.to_codex.md` — a task/review brief authored by Fable.
45
+ - `NNN_<slug>.to_fable.md` — Codex's durable reply (same NNN; this file
46
+ is never overwritten by later rounds, unlike gate-review.md).
47
+ - Exception: `000_gate8_review_snapshot.to_fable.md` is a one-off
48
+ bootstrap snapshot authored by Fable (preserving the never-committed
49
+ gate-8 review text), not a Codex reply.
50
+ - NNN is single-use: a second round over the same range or brief (a
51
+ second opinion, a re-run) ALWAYS gets its own fresh NNN brief — never
52
+ point a new round at an existing NNN, because its reply instruction
53
+ would overwrite that round's supposedly-durable `.to_fable.md`
54
+ (this happened live on 2026-07-21: an app round reusing brief 001
55
+ silently clobbered the headless round's 001 reply; recovered from a
56
+ session transcript, which will not always exist).
57
+ - While an external review of a committed range is in flight, do not
58
+ draft next-round files in the same working tree: the reviewer's
59
+ `git status` picks up the strays (observed live during gate-11 — a
60
+ concurrently-drafted test file appeared mid-review; the reviewer
61
+ disclosed rather than touched it, but the ambiguity is avoidable).
62
+ Range-pinned checks are immune, tree-state checks are not.
63
+
64
+ To run a round from the Codex app, open it with cwd = this repo's root
65
+ and say exactly:
66
+
67
+ > Read .ai/handoff/NNN_<slug>.to_codex.md and execute all instructions;
68
+ > write your reply to .ai/handoff/NNN_<slug>.to_fable.md.
69
+
70
+ The brief itself carries all round-specific instructions (review range,
71
+ expected test counts, output contract) — the sentence never changes.
72
+
73
+ Preferred transport (proven on the gate-10 round, 2026-07-22): Fable
74
+ runs the same brief headlessly — no human in the transport at all —
75
+ via the codex-delegate wrapper (personal-environment tooling from the
76
+ maintainer's global skills install, optional; the Codex-app sentence
77
+ above is the portable path for anyone else):
78
+
79
+ ```bash
80
+ bash ~/.claude/skills/codex-delegate/scripts/run_codex.sh \
81
+ --brief-file .ai/handoff/NNN_<slug>.to_codex.md --repo <repo-root>
82
+ ```
83
+
84
+ Machine-readable status lands at `<brief>.txt.result.json`
85
+ (`success` / `fallback` = Codex quota exhausted / `error`). On
86
+ `fallback`, wait for the quota reset or fall back to the Codex-app
87
+ sentence above — never substitute a same-vendor review for the
88
+ independent external round.
89
+
90
+ ## Commit trailers (dogfood — this repo's own product)
91
+
92
+ Every commit here declares its AI participation with the tool's own
93
+ schema (README "Declaring AI participation"), so `aiprofile scan` on
94
+ this repo reports the true multi-tool history. One block per AI actor;
95
+ a repeated `AI-Provider:` key starts the next block (ADR-005). Example
96
+ for the standard round shape (Fable implements, Codex reviews):
97
+
98
+ ```text
99
+ AI-Provider: Anthropic
100
+ AI-Model: Claude-Fable-5
101
+ AI-Tool: Claude-Code
102
+ AI-Role: implementation, documentation
103
+ AI-Mode: AI-Assisted
104
+ AI-Provider: OpenAI
105
+ AI-Model: GPT-5.5
106
+ AI-Tool: Codex-CLI
107
+ AI-Role: review
108
+ AI-Mode: AI-Assisted
109
+ ```
110
+
111
+ ONE CONTIGUOUS BLOCK — never put a blank line between groups: git's
112
+ trailer extraction (`%(trailers:only)`) keeps only the last contiguous
113
+ paragraph, so a blank line silently drops every group above it
114
+ (verified empirically 2026-07-21: the blank-line form lost the entire
115
+ Anthropic group). The repeated `AI-Provider:` key alone is the group
116
+ separator.
117
+
118
+ AND a blank line BEFORE the block — the trailer paragraph must be
119
+ separated from the body prose, or git rejects the whole paragraph as
120
+ non-trailers (too many non-trailer lines in it). Found by dogfooding
121
+ 2026-07-23: commits ea5f37d / d2c1147 / 66bc3e9 glued their trailer
122
+ block to the preceding body line and scan as `unknown` forever (pushed
123
+ history is never rewritten here — this note is the erratum). The two
124
+ rules together: blank line before the block, no blank line inside it.
125
+
126
+ Honesty rules: only list actors that actually touched the commit;
127
+ `AI-Reviewed-By: Human` only when a human actually read the diff
128
+ (omit or `None` otherwise); keep the `Co-Authored-By:` line too
129
+ (GitHub UI + the tool's registry fallback both read it).
@@ -0,0 +1,132 @@
1
+ # Changelog
2
+
3
+ Format: [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
4
+ Versioning: [SemVer](https://semver.org/spec/v2.0.0.html) on the CLI
5
+ package. The ACE event schema carries its own semver (ADR-012) and the
6
+ SQLite store its own migration chain (ADR-004) — see the upgrade policy
7
+ below.
8
+
9
+ ## Upgrade policy
10
+
11
+ - **Within a minor line (0.1.x):** drop-in. The database migration
12
+ runner applies any pending migrations automatically on the next
13
+ command; config.json is read-compatible; no action needed.
14
+ - **Across minors (0.1 → 0.2):** read the release notes first. The ACE
15
+ schema refuses aggregation across incompatible `major.minor` payload
16
+ versions by design (ADR-012) — a release that bumps the event schema
17
+ states explicitly whether existing scanned data re-aggregates or a
18
+ rescan is needed. Your raw repositories are always the source of
19
+ truth: worst case, `aiprofile scan` re-derives everything.
20
+ - **Downgrades are unsupported:** the migration chain is forward-only.
21
+ If you must roll back the CLI, delete `~/.aiprofile` (or your
22
+ `AIPROFILE_HOME`) and re-init + rescan — nothing in it is
23
+ irreplaceable (config identities/policy aside, which are a few lines
24
+ of JSON you can note down first).
25
+
26
+ ## [Unreleased]
27
+
28
+ (nothing yet)
29
+
30
+ ## [0.3.0] — 2026-07-23
31
+
32
+ ### Added
33
+
34
+ - **Collaboration-ratio heatmap** (`heatmap-{light,dark}.svg`,
35
+ ADR-020): GitHub-style year grid where intensity = total commits
36
+ that day — your own human commits included — and hue = the day's
37
+ AI-collaboration share (five quantized bins, neutral → accent). The
38
+ daily series window widens to 365 days (ADR-018 addendum);
39
+ `profile.json` day cells gain `total_commits`/`ai_commits`
40
+ (additive).
41
+ - **AI-collaboration badge** (`badge-{light,dark}.svg`): a small flat
42
+ shield — "AI-assisted | K% · verified by git" — using the summary
43
+ card's own headline share and rounding. `aiprofile render` now
44
+ writes all six SVG assets plus profile.json in one atomic bundle.
45
+ - Provider brand marks for **OpenAI** and **Grok (xAI)** from a second
46
+ icon source (lobe-icons, MIT, pinned commit) via
47
+ `vendor_brand_icons.py --source lobe`; new `THIRD_PARTY_NOTICES.md`
48
+ carries the MIT text (ADR-017 D5 addendum).
49
+ - Two-tier provider model (ADR-019): the DECLARATION tier grows by ten
50
+ providers - Kimi (moonshot), DeepSeek, Qwen (alibaba), Mistral, Grok
51
+ (xai), GLM (zhipu), Ollama, Llama (meta), Replit, Amp - so
52
+ hand-written `AI-Provider:` trailers resolve and rank; the AUTO-MATCH
53
+ tier stays evidence-gated and gains exactly one identity: Amp
54
+ (`amp@ampcode.com`, documented default-on co-author trailer).
55
+ - Eight new provider marks vendored mechanically from the pinned CC0
56
+ simple-icons commit via the new `scripts/vendor_brand_icons.py`
57
+ (byte-verified provenance; Amp keeps the honest letter tile - its
58
+ lobe icon is multi-path - and Grok gained its mark via the second
59
+ source above).
60
+ - Calendar band polish: intensity-bin legend + "publishable repos only"
61
+ cue, clock-free month boundary labels, and clearer provider-overflow
62
+ wording.
63
+ - Repo social-preview card (docs/assets/social-preview.{svg,png}) in
64
+ the banner's visual language.
65
+
66
+ ### Fixed
67
+
68
+ - Display-name provider declarations resolve (latent since v0.1):
69
+ `AI-Provider: Claude` / `Gemini` / `Copilot` / `Kimi` / `Qwen` /
70
+ `Grok` / `GLM` / `Llama` etc. previously produced canonical-null
71
+ events that published as "Unrecognized". `PROVIDER_ALIASES` now
72
+ derives an entry from every schema-owned display name plus common
73
+ spacing/punctuation variants (Mistral AI, Meta AI, x.ai, Z.ai,
74
+ Moonshot AI), closing the class for future providers too.
75
+ - `aiprofile --version` now reports the real version: 0.2.0 bumped
76
+ `pyproject.toml` but not `__version__`, so the CLI kept saying
77
+ 0.1.0. Both sources are now pinned together by a regression test.
78
+
79
+ ## [0.2.0] — 2026-07-23
80
+
81
+ ### Added
82
+
83
+ - Provider brand identity on the summary card (round D1, ADR-017):
84
+ official marks for Claude / Gemini / GitHub Copilot / Cursor /
85
+ Windsurf (CC0 simple-icons subset, byte-verified) with per-theme
86
+ brand-colored bars; honest letter-tile fallback for providers with
87
+ no CC0 mark (OpenAI, Amazon Q, Aider, Roo Code, OpenHands, Devin).
88
+ - README banner (docs/assets/banner-{light,dark}.svg): deterministic
89
+ generated hero in the card's own visual language (isometric brand
90
+ stacks), theme-paired.
91
+ - Tag-triggered PyPI publish workflow (.github/workflows/publish.yml)
92
+ via PyPI Trusted Publishing (OIDC, no stored secrets); gated on the
93
+ full test suite + ruff before build/upload.
94
+ - Isometric daily AI-collaboration calendar (round D2, ADR-018):
95
+ a 12-week 3D activity grid, stacked by provider color, built ONLY
96
+ from explicitly-publishable repositories — aggregate-only
97
+ repositories never surface their activity dates. Fully static SVG
98
+ (no animation - two entrance attempts were invisible in static
99
+ captures and were removed).
100
+
101
+ ### Changed
102
+
103
+ - ACE schema version 0.1.0 -> 0.2.0: `profile.json` and the internal
104
+ visualization contract gain the additive `daily` series (ADR-012's
105
+ minor-bump rule for additive optional fields, binding post-v0.1.0).
106
+ Databases scanned under 0.1 remain fully aggregatable; new scans
107
+ stamp 0.2.0.
108
+
109
+ ## [0.1.0] — 2026-07-22
110
+
111
+ First public release.
112
+
113
+ ### Added
114
+
115
+ - Vertical slice: `aiprofile init` / `scan` / `aggregate` / `render` —
116
+ explicit AI provenance (AI-* trailers + verified co-author registry)
117
+ from local git repositories into a local SQLite store, rendered as
118
+ privacy-safe SVG cards (light/dark) + `profile.json`.
119
+ - Privacy model: local-first (zero network, zero telemetry),
120
+ `aggregate_only` by default, `aggregate` output IS the publish
121
+ preview, structurally sealed `VizStats` publication boundary
122
+ (ten adversarial gate rounds, gates 2–11, each independently
123
+ verified; see `docs/reviews/`).
124
+ - Evidence-quality ladder (`verified > declared > imported > inferred
125
+ > unknown`); honest `unknown` for commits without explicit evidence —
126
+ never inferred from code style.
127
+ - Pre-release hardening: owner-only file permissions (POSIX-enforced,
128
+ retrofitted to existing installations on every load), git-worktree
129
+ placement warning, cp950-safe console text, packaged-install release
130
+ smoke script, cherry-pick counting semantics documented + tested,
131
+ console (stdout/stderr) canary sweeps, hypothesis property fuzzing
132
+ over the schema invariants.
@@ -0,0 +1,44 @@
1
+ # Contributing
2
+
3
+ Thanks for considering a contribution. This project is small on purpose;
4
+ the bar is correctness and privacy, not feature count.
5
+
6
+ ## Setup and verification
7
+
8
+ ```bash
9
+ pip install -e ".[dev]" # Python >= 3.11, git >= 2.17 (SHA-1 repos)
10
+ python -m pytest # full suite must pass (states its count)
11
+ python -m ruff check src tests
12
+ ```
13
+
14
+ Integration tests build throwaway git repositories under pytest tmp dirs;
15
+ no network is used anywhere in the suite, ever.
16
+
17
+ ## Ground rules
18
+
19
+ - `docs/schema.md` is the normative event contract; `docs/architecture.md`
20
+ pins module boundaries (renderers/exporters consume `VizStats` only).
21
+ Where code and docs disagree, the docs win and the code is a bug.
22
+ - **Contract changes require an ADR** under `docs/decisions/` (and a schema
23
+ version bump per ADR-012). New sections in existing docs get review.
24
+ - **Registry additions need primary evidence**: an entry in
25
+ `src/aiprofile/registry.py` must cite an official doc, tool source code,
26
+ or verified real-commit usage (see `docs/landscape.md` §2.1 for the
27
+ verification standard). Unverified strings stay out.
28
+ - **Attribution is explicit-evidence-only.** No code-style inference, no
29
+ LLM classification of historical commits — patches adding either will be
30
+ declined regardless of accuracy.
31
+ - Privacy invariants are test-enforced (leak tests, policy tests); a change
32
+ that weakens `VizStats`' structural redaction needs its own ADR and a
33
+ very good reason. Read `docs/PRIVACY.md` first.
34
+ - Deterministic rendering: snapshot updates must be intentional; regenerate
35
+ via `python tests/unit/test_render_summary.py` and inspect the diff. That
36
+ one command regenerates BOTH the test snapshots and the committed README
37
+ sample assets (`docs/assets/summary-sample-{light,dark}.svg`) from their
38
+ authoritative synthetic fixture — never hand-edit or copy either set; a
39
+ byte-exact drift guard fails the suite if they fall out of sync.
40
+
41
+ ## Reporting privacy/security issues
42
+
43
+ Open an issue titled "privacy report" without including the sensitive
44
+ details, and the maintainer will follow up privately.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Wenyu Chiou
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.