iscc-search 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 (149) hide show
  1. iscc_search-0.1.0/.dockerignore +11 -0
  2. iscc_search-0.1.0/.editorconfig +20 -0
  3. iscc_search-0.1.0/.env.example +85 -0
  4. iscc_search-0.1.0/.gitattributes +25 -0
  5. iscc_search-0.1.0/.github/actions/setup-python-env/action.yml +30 -0
  6. iscc_search-0.1.0/.github/workflows/ci.yml +223 -0
  7. iscc_search-0.1.0/.github/workflows/release.yml +235 -0
  8. iscc_search-0.1.0/.gitignore +168 -0
  9. iscc_search-0.1.0/.pre-commit-config.yaml +31 -0
  10. iscc_search-0.1.0/CHANGELOG.md +55 -0
  11. iscc_search-0.1.0/CLAUDE.md +230 -0
  12. iscc_search-0.1.0/CNAME +1 -0
  13. iscc_search-0.1.0/CONTRIBUTING.md +123 -0
  14. iscc_search-0.1.0/Dockerfile +45 -0
  15. iscc_search-0.1.0/LICENSE +202 -0
  16. iscc_search-0.1.0/PKG-INFO +231 -0
  17. iscc_search-0.1.0/README.md +190 -0
  18. iscc_search-0.1.0/compose.yaml +49 -0
  19. iscc_search-0.1.0/docs/CNAME +1 -0
  20. iscc_search-0.1.0/docs/assets/favicon.png +0 -0
  21. iscc_search-0.1.0/docs/assets/logo_dark.png +0 -0
  22. iscc_search-0.1.0/docs/assets/logo_light.png +0 -0
  23. iscc_search-0.1.0/docs/development/contributing.md +95 -0
  24. iscc_search-0.1.0/docs/explanation/architecture.md +132 -0
  25. iscc_search-0.1.0/docs/explanation/iscc-primer.md +112 -0
  26. iscc_search-0.1.0/docs/explanation/similarity-search.md +152 -0
  27. iscc_search-0.1.0/docs/howto/cli.md +189 -0
  28. iscc_search-0.1.0/docs/howto/deployment.md +218 -0
  29. iscc_search-0.1.0/docs/howto/index-backends.md +99 -0
  30. iscc_search-0.1.0/docs/howto/rest-api.md +160 -0
  31. iscc_search-0.1.0/docs/includes/abbreviations.md +17 -0
  32. iscc_search-0.1.0/docs/index.md +108 -0
  33. iscc_search-0.1.0/docs/javascripts/copilot.js +27 -0
  34. iscc_search-0.1.0/docs/javascripts/copypage.js +202 -0
  35. iscc_search-0.1.0/docs/llms.txt +34 -0
  36. iscc_search-0.1.0/docs/overrides/main.html +28 -0
  37. iscc_search-0.1.0/docs/reference/api.md +34 -0
  38. iscc_search-0.1.0/docs/reference/configuration.md +125 -0
  39. iscc_search-0.1.0/docs/reference/for-coding-agents.md +344 -0
  40. iscc_search-0.1.0/docs/robots.txt +2 -0
  41. iscc_search-0.1.0/docs/stylesheets/copilot.css +119 -0
  42. iscc_search-0.1.0/docs/stylesheets/extra.css +289 -0
  43. iscc_search-0.1.0/docs/tutorials/getting-started.md +229 -0
  44. iscc_search-0.1.0/iscc_search/__init__.py +13 -0
  45. iscc_search-0.1.0/iscc_search/cli/__init__.py +55 -0
  46. iscc_search-0.1.0/iscc_search/cli/__main__.py +6 -0
  47. iscc_search-0.1.0/iscc_search/cli/add.py +343 -0
  48. iscc_search-0.1.0/iscc_search/cli/common.py +190 -0
  49. iscc_search-0.1.0/iscc_search/cli/datasets.py +85 -0
  50. iscc_search-0.1.0/iscc_search/cli/get.py +74 -0
  51. iscc_search-0.1.0/iscc_search/cli/hub.py +332 -0
  52. iscc_search-0.1.0/iscc_search/cli/index.py +225 -0
  53. iscc_search-0.1.0/iscc_search/cli/search.py +70 -0
  54. iscc_search-0.1.0/iscc_search/cli/serve.py +78 -0
  55. iscc_search-0.1.0/iscc_search/config.py +429 -0
  56. iscc_search-0.1.0/iscc_search/indexes/__init__.py +0 -0
  57. iscc_search-0.1.0/iscc_search/indexes/common.py +270 -0
  58. iscc_search-0.1.0/iscc_search/indexes/lmdb/__init__.py +12 -0
  59. iscc_search-0.1.0/iscc_search/indexes/lmdb/index.py +507 -0
  60. iscc_search-0.1.0/iscc_search/indexes/lmdb/manager.py +240 -0
  61. iscc_search-0.1.0/iscc_search/indexes/memory/__init__.py +5 -0
  62. iscc_search-0.1.0/iscc_search/indexes/memory/index.py +244 -0
  63. iscc_search-0.1.0/iscc_search/indexes/simprint/__init__.py +7 -0
  64. iscc_search-0.1.0/iscc_search/indexes/simprint/lmdb_ops.py +315 -0
  65. iscc_search-0.1.0/iscc_search/indexes/simprint/models.py +46 -0
  66. iscc_search-0.1.0/iscc_search/indexes/simprint/usearch_core.py +277 -0
  67. iscc_search-0.1.0/iscc_search/indexes/usearch/__init__.py +17 -0
  68. iscc_search-0.1.0/iscc_search/indexes/usearch/index.py +1634 -0
  69. iscc_search-0.1.0/iscc_search/indexes/usearch/manager.py +274 -0
  70. iscc_search-0.1.0/iscc_search/log_config.json +45 -0
  71. iscc_search-0.1.0/iscc_search/models.py +420 -0
  72. iscc_search-0.1.0/iscc_search/openapi/CommonProperties.yaml +23 -0
  73. iscc_search-0.1.0/iscc_search/openapi/HttpError.yaml +17 -0
  74. iscc_search-0.1.0/iscc_search/openapi/IsccAddResult.yaml +28 -0
  75. iscc_search-0.1.0/iscc_search/openapi/IsccChunk.yaml +151 -0
  76. iscc_search-0.1.0/iscc_search/openapi/IsccChunkMatch.yaml +203 -0
  77. iscc_search-0.1.0/iscc_search/openapi/IsccEntry.yaml +74 -0
  78. iscc_search-0.1.0/iscc_search/openapi/IsccGlobalMatch.yaml +78 -0
  79. iscc_search-0.1.0/iscc_search/openapi/IsccIndex.yaml +31 -0
  80. iscc_search-0.1.0/iscc_search/openapi/IsccMatchedChunk.yaml +90 -0
  81. iscc_search-0.1.0/iscc_search/openapi/IsccMetadata.yaml +52 -0
  82. iscc_search-0.1.0/iscc_search/openapi/IsccQuery.yaml +121 -0
  83. iscc_search-0.1.0/iscc_search/openapi/IsccSearchResult.yaml +55 -0
  84. iscc_search-0.1.0/iscc_search/openapi/IsccSimprint.yaml +66 -0
  85. iscc_search-0.1.0/iscc_search/openapi/TextQuery.yaml +15 -0
  86. iscc_search-0.1.0/iscc_search/openapi/openapi.json +1914 -0
  87. iscc_search-0.1.0/iscc_search/openapi/openapi.yaml +615 -0
  88. iscc_search-0.1.0/iscc_search/options.py +296 -0
  89. iscc_search-0.1.0/iscc_search/processing.py +69 -0
  90. iscc_search-0.1.0/iscc_search/protocols/__init__.py +0 -0
  91. iscc_search-0.1.0/iscc_search/protocols/index.py +170 -0
  92. iscc_search-0.1.0/iscc_search/remote/__init__.py +9 -0
  93. iscc_search-0.1.0/iscc_search/remote/client.py +260 -0
  94. iscc_search-0.1.0/iscc_search/schema.py +538 -0
  95. iscc_search-0.1.0/iscc_search/server/__init__.py +273 -0
  96. iscc_search-0.1.0/iscc_search/server/__main__.py +25 -0
  97. iscc_search-0.1.0/iscc_search/server/assets.py +73 -0
  98. iscc_search-0.1.0/iscc_search/server/auth.py +35 -0
  99. iscc_search-0.1.0/iscc_search/server/indexes.py +103 -0
  100. iscc_search-0.1.0/iscc_search/server/playground.py +458 -0
  101. iscc_search-0.1.0/iscc_search/server/search.py +117 -0
  102. iscc_search-0.1.0/iscc_search/utils.py +5 -0
  103. iscc_search-0.1.0/mkdocs.yml +58 -0
  104. iscc_search-0.1.0/pyproject.toml +146 -0
  105. iscc_search-0.1.0/scripts/bundle_openapi.py +164 -0
  106. iscc_search-0.1.0/scripts/gen_llms_full.py +83 -0
  107. iscc_search-0.1.0/tests/conftest.py +442 -0
  108. iscc_search-0.1.0/tests/test_cli_common.py +156 -0
  109. iscc_search-0.1.0/tests/test_cli_index.py +121 -0
  110. iscc_search-0.1.0/tests/test_cli_serve.py +69 -0
  111. iscc_search-0.1.0/tests/test_config.py +607 -0
  112. iscc_search-0.1.0/tests/test_indexes_common.py +341 -0
  113. iscc_search-0.1.0/tests/test_indexes_lmdb_index.py +476 -0
  114. iscc_search-0.1.0/tests/test_indexes_lmdb_integration.py +363 -0
  115. iscc_search-0.1.0/tests/test_indexes_lmdb_manager.py +382 -0
  116. iscc_search-0.1.0/tests/test_indexes_memory_index.py +516 -0
  117. iscc_search-0.1.0/tests/test_indexes_simprint_lmdb_ops.py +480 -0
  118. iscc_search-0.1.0/tests/test_indexes_simprint_models.py +124 -0
  119. iscc_search-0.1.0/tests/test_indexes_usearch_index.py +815 -0
  120. iscc_search-0.1.0/tests/test_indexes_usearch_manager.py +514 -0
  121. iscc_search-0.1.0/tests/test_indexes_usearch_persistence.py +627 -0
  122. iscc_search-0.1.0/tests/test_indexes_usearch_simprint_approx.py +1260 -0
  123. iscc_search-0.1.0/tests/test_indexes_usearch_simprint_exact.py +468 -0
  124. iscc_search-0.1.0/tests/test_indexes_usearch_simprint_m1.py +119 -0
  125. iscc_search-0.1.0/tests/test_indexes_usearch_simprint_m2.py +316 -0
  126. iscc_search-0.1.0/tests/test_models.py +369 -0
  127. iscc_search-0.1.0/tests/test_models_iscc_base.py +402 -0
  128. iscc_search-0.1.0/tests/test_models_iscc_code.py +430 -0
  129. iscc_search-0.1.0/tests/test_models_iscc_id.py +665 -0
  130. iscc_search-0.1.0/tests/test_models_iscc_item.py +665 -0
  131. iscc_search-0.1.0/tests/test_models_iscc_unit.py +502 -0
  132. iscc_search-0.1.0/tests/test_options.py +255 -0
  133. iscc_search-0.1.0/tests/test_processing.py +259 -0
  134. iscc_search-0.1.0/tests/test_protocols_index.py +260 -0
  135. iscc_search-0.1.0/tests/test_remote.py +479 -0
  136. iscc_search-0.1.0/tests/test_server.py +307 -0
  137. iscc_search-0.1.0/tests/test_server_assets.py +159 -0
  138. iscc_search-0.1.0/tests/test_server_auth.py +279 -0
  139. iscc_search-0.1.0/tests/test_server_indexes.py +146 -0
  140. iscc_search-0.1.0/tests/test_server_search.py +368 -0
  141. iscc_search-0.1.0/tests/test_usearch_add.py +465 -0
  142. iscc_search-0.1.0/tests/test_usearch_contains.py +235 -0
  143. iscc_search-0.1.0/tests/test_usearch_get.py +254 -0
  144. iscc_search-0.1.0/tests/test_usearch_multi.py +456 -0
  145. iscc_search-0.1.0/tests/test_usearch_remove.py +282 -0
  146. iscc_search-0.1.0/tests/test_usearch_search.py +727 -0
  147. iscc_search-0.1.0/tests/test_utils.py +102 -0
  148. iscc_search-0.1.0/uv.lock +3114 -0
  149. iscc_search-0.1.0/zensical.toml +136 -0
@@ -0,0 +1,11 @@
1
+ # Allowlist-style .dockerignore: ignore everything, then explicitly allow the build inputs.
2
+ # The Docker image installs from a pre-built wheel, so no source files are required in the context.
3
+ # This prevents dev artifacts (cauldron/, .claude/, scratch/, tests/, docs/, .git/, secrets) from
4
+ # ever entering the image layers or being cached by BuildKit.
5
+
6
+ # Ignore everything
7
+ **
8
+
9
+ # Allow the Dockerfile and the pre-built wheel produced by `uv build`
10
+ !Dockerfile
11
+ !dist/*.whl
@@ -0,0 +1,20 @@
1
+ # see http://editorconfig.org
2
+
3
+ # Top-level config
4
+ root = true
5
+
6
+
7
+ # All files
8
+ [*]
9
+ charset = utf-8
10
+ indent_style = space
11
+ indent_size = 4
12
+ end_of_line = lf
13
+ insert_final_newline = true
14
+ trim_trailing_whitespace = true
15
+ max_line_length = 119
16
+
17
+
18
+ # YAML files
19
+ [*.{yml,yaml}]
20
+ indent_size = 2
@@ -0,0 +1,85 @@
1
+ # ISCC-Search Configuration
2
+ # Copy to .env and customize as needed. All values shown are defaults.
3
+
4
+ # --- Server ---
5
+
6
+ # Index backend URI (memory://, lmdb:///path, usearch:///path)
7
+ # Default: usearch:/// + platform-specific user data dir (e.g. ~/.local/share/iscc-search)
8
+ # ISCC_SEARCH_INDEX_URI=usearch:///path/to/data
9
+
10
+ # API secret for authentication (unset = public API)
11
+ # ISCC_SEARCH_API_SECRET=
12
+
13
+ # CORS allowed origins (comma-separated, or * for all)
14
+ # ISCC_SEARCH_CORS_ORIGINS=*
15
+
16
+ # Server host and port
17
+ # ISCC_SEARCH_HOST=0.0.0.0
18
+ # ISCC_SEARCH_PORT=8000
19
+
20
+ # Number of worker processes (production only, unset = single worker)
21
+ # NOTE: workers > 1 is REJECTED with the usearch:// backend — concurrent writers
22
+ # corrupt .usearch files. Leave unset (single worker) for usearch-backed deployments.
23
+ # ISCC_SEARCH_WORKERS=
24
+
25
+ # Auto-flush sub-indexes after N dirty key mutations (0 = disabled).
26
+ # Only safe with a single writer process. Production recommendation: 100000.
27
+ # Reduces blast radius of hard crashes (OOM / SIGKILL / power loss).
28
+ # ISCC_SEARCH_FLUSH_INTERVAL=0
29
+
30
+ # Log level (debug, info, warning, error, critical)
31
+ # ISCC_SEARCH_LOG_LEVEL=info
32
+
33
+ # --- Shard Sizes (MB) ---
34
+
35
+ # Maximum shard file size for ISCC-UNIT indexes
36
+ # ISCC_SEARCH_SHARD_SIZE_UNITS=1024
37
+
38
+ # Maximum shard file size for simprint indexes
39
+ # ISCC_SEARCH_SHARD_SIZE_SIMPRINTS=1024
40
+
41
+ # --- HNSW Parameters (Units) ---
42
+
43
+ # Build-time search depth (efConstruction) for unit indexes
44
+ # ISCC_SEARCH_HNSW_EXPANSION_ADD_UNITS=128
45
+
46
+ # Query-time search depth (ef) for unit indexes
47
+ # ISCC_SEARCH_HNSW_EXPANSION_SEARCH_UNITS=64
48
+
49
+ # Graph connectivity (M) for unit indexes
50
+ # ISCC_SEARCH_HNSW_CONNECTIVITY_UNITS=16
51
+
52
+ # --- HNSW Parameters (Simprints) ---
53
+
54
+ # Build-time search depth (efConstruction) for simprint indexes
55
+ # ISCC_SEARCH_HNSW_EXPANSION_ADD_SIMPRINTS=16
56
+
57
+ # Query-time search depth (ef) for simprint indexes
58
+ # ISCC_SEARCH_HNSW_EXPANSION_SEARCH_SIMPRINTS=512
59
+
60
+ # Graph connectivity (M) for simprint indexes
61
+ # ISCC_SEARCH_HNSW_CONNECTIVITY_SIMPRINTS=8
62
+
63
+ # --- Match Thresholds ---
64
+
65
+ # Minimum score for unit similarity matches (0.0-1.0)
66
+ # ISCC_SEARCH_MATCH_THRESHOLD_UNITS=0.75
67
+
68
+ # Minimum score for simprint matches (0.0-1.0)
69
+ # ISCC_SEARCH_MATCH_THRESHOLD_SIMPRINTS=0.75
70
+
71
+ # --- Scoring ---
72
+
73
+ # Exponent for confidence-weighted score aggregation
74
+ # ISCC_SEARCH_CONFIDENCE_EXPONENT=4
75
+
76
+ # Oversampling multiplier for simprint search diversity
77
+ # ISCC_SEARCH_OVERSAMPLING_FACTOR=20
78
+
79
+ # --- Error Tracking (Sentry) ---
80
+
81
+ # Sentry DSN for error tracking (unset = disabled)
82
+ # ISCC_SEARCH_SENTRY_DSN=
83
+
84
+ # Sentry performance sampling rate (0.0-1.0)
85
+ # ISCC_SEARCH_SENTRY_TRACES_SAMPLE_RATE=0.05
@@ -0,0 +1,25 @@
1
+ # Set default behavior to automatically normalize line endings
2
+ * text=auto
3
+
4
+ # Force LF line endings for markdown files
5
+ *.md text eol=lf
6
+
7
+ # Force LF for other text files that should have consistent endings
8
+ *.py text eol=lf
9
+ *.yml text eol=lf
10
+ *.yaml text eol=lf
11
+ *.toml text eol=lf
12
+ *.cfg text eol=lf
13
+ *.ini text eol=lf
14
+ *.json text eol=lf
15
+ *.txt text eol=lf
16
+ *.sh text eol=lf
17
+ Makefile text eol=lf
18
+
19
+ # Binary files
20
+ *.png binary
21
+ *.jpg binary
22
+ *.jpeg binary
23
+ *.gif binary
24
+ *.ico binary
25
+ *.pdf binary
@@ -0,0 +1,30 @@
1
+ name: "Setup Python Environment"
2
+ description: "Set up Python environment for the given Python version"
3
+
4
+ inputs:
5
+ python-version:
6
+ description: "Python version to use"
7
+ required: true
8
+ default: "3.12"
9
+ uv-version:
10
+ description: "uv version to use"
11
+ required: true
12
+ default: "0.6.14"
13
+
14
+ runs:
15
+ using: "composite"
16
+ steps:
17
+ - uses: actions/setup-python@v6
18
+ with:
19
+ python-version: ${{ inputs.python-version }}
20
+
21
+ - name: Install uv
22
+ uses: astral-sh/setup-uv@v8.0.0
23
+ with:
24
+ version: ${{ inputs.uv-version }}
25
+ enable-cache: 'true'
26
+ cache-suffix: ${{ matrix.python-version }}
27
+
28
+ - name: Install Python dependencies
29
+ run: uv sync --frozen
30
+ shell: bash
@@ -0,0 +1,223 @@
1
+ name: CI
2
+
3
+ on:
4
+ pull_request:
5
+ push:
6
+ branches: [develop, main]
7
+
8
+ # Cancel stale in-flight PR runs; let push runs complete so publish isn't cancelled.
9
+ concurrency:
10
+ group: ${{ github.workflow }}-${{ github.ref }}
11
+ cancel-in-progress: ${{ github.event_name == 'pull_request' }}
12
+
13
+ permissions:
14
+ contents: read
15
+
16
+ jobs:
17
+ test-full:
18
+ name: Test (ubuntu-latest, py${{ matrix.python-version }})
19
+ runs-on: ubuntu-latest
20
+ strategy:
21
+ matrix:
22
+ python-version: ["3.11", "3.12", "3.13", "3.14"]
23
+ fail-fast: false
24
+ steps:
25
+ - uses: actions/checkout@v6
26
+ with:
27
+ fetch-depth: 0 # hatch-vcs needs git history to derive version
28
+
29
+ - uses: ./.github/actions/setup-python-env
30
+ with:
31
+ python-version: ${{ matrix.python-version }}
32
+
33
+ # Cache the iscc-sct ONNX model across runs. Parallel pytest-xdist workers
34
+ # otherwise race on the download and can produce a corrupt ONNX file.
35
+ - name: Cache iscc-sct model
36
+ uses: actions/cache@v5
37
+ with:
38
+ path: |
39
+ ~/.local/share/iscc-sct
40
+ ~/Library/Application Support/iscc-sct
41
+ ~\AppData\Local\iscc\iscc-sct
42
+ key: iscc-sct-model-${{ runner.os }}-${{ hashFiles('uv.lock') }}
43
+ restore-keys: |
44
+ iscc-sct-model-${{ runner.os }}-
45
+
46
+ - name: Pre-download iscc-sct model (serial, before parallel tests)
47
+ run: uv run python -c "import iscc_sct.code_semantic_text as sct; sct.model()"
48
+
49
+ - name: OpenAPI build + validation
50
+ run: uv run poe build
51
+
52
+ - name: Run tests
53
+ run: uv run poe test
54
+
55
+ - name: Upload coverage to Codecov
56
+ if: matrix.python-version == '3.11'
57
+ uses: codecov/codecov-action@v6
58
+ env:
59
+ CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
60
+
61
+ test-smoke:
62
+ name: Test (${{ matrix.os }}, py3.12)
63
+ runs-on: ${{ matrix.os }}
64
+ strategy:
65
+ matrix:
66
+ os: [windows-latest, macos-latest]
67
+ fail-fast: false
68
+ defaults:
69
+ run:
70
+ shell: bash
71
+ steps:
72
+ - uses: actions/checkout@v6
73
+ with:
74
+ fetch-depth: 0
75
+
76
+ - uses: ./.github/actions/setup-python-env
77
+ with:
78
+ python-version: "3.12"
79
+
80
+ - name: Cache iscc-sct model
81
+ uses: actions/cache@v5
82
+ with:
83
+ path: |
84
+ ~/.local/share/iscc-sct
85
+ ~/Library/Application Support/iscc-sct
86
+ ~\AppData\Local\iscc\iscc-sct
87
+ key: iscc-sct-model-${{ runner.os }}-${{ hashFiles('uv.lock') }}
88
+ restore-keys: |
89
+ iscc-sct-model-${{ runner.os }}-
90
+
91
+ - name: Pre-download iscc-sct model
92
+ run: uv run python -c "import iscc_sct.code_semantic_text as sct; sct.model()"
93
+
94
+ - name: Run tests
95
+ run: uv run poe test
96
+
97
+ wheel-build:
98
+ name: Build wheel
99
+ runs-on: ubuntu-latest
100
+ steps:
101
+ - uses: actions/checkout@v6
102
+ with:
103
+ fetch-depth: 0
104
+
105
+ - uses: ./.github/actions/setup-python-env
106
+
107
+ - name: Build wheel + sdist
108
+ run: uv build
109
+
110
+ - name: Upload dist artifact
111
+ uses: actions/upload-artifact@v6
112
+ with:
113
+ name: dist
114
+ path: dist/
115
+ retention-days: 7
116
+
117
+ wheel-smoke:
118
+ name: Install wheel and smoke-test
119
+ needs: wheel-build
120
+ runs-on: ubuntu-latest
121
+ steps:
122
+ - uses: actions/setup-python@v6
123
+ with:
124
+ python-version: "3.12"
125
+
126
+ - uses: actions/download-artifact@v7
127
+ with:
128
+ name: dist
129
+ path: dist
130
+
131
+ - name: Install wheel into clean venv
132
+ run: |
133
+ python -m venv .smoke-venv
134
+ .smoke-venv/bin/pip install --upgrade pip
135
+ .smoke-venv/bin/pip install dist/*.whl
136
+
137
+ - name: Verify import and CLI
138
+ run: |
139
+ .smoke-venv/bin/python -c "import iscc_search; print('version:', iscc_search.__version__)"
140
+ .smoke-venv/bin/iscc-search --help
141
+
142
+ docker-smoke:
143
+ name: Build + smoke-test Docker image
144
+ needs: wheel-build
145
+ runs-on: ubuntu-latest
146
+ steps:
147
+ - uses: actions/checkout@v6
148
+
149
+ - uses: actions/download-artifact@v7
150
+ with:
151
+ name: dist
152
+ path: dist
153
+
154
+ - uses: docker/setup-buildx-action@v4
155
+
156
+ - name: Build image (load into local daemon)
157
+ uses: docker/build-push-action@v7
158
+ with:
159
+ context: .
160
+ file: ./Dockerfile
161
+ load: true
162
+ tags: iscc-search:smoke
163
+ cache-from: type=gha
164
+ cache-to: type=gha,mode=max
165
+
166
+ - name: Run container and probe health endpoints
167
+ run: |
168
+ docker run -d --name iscc-search-smoke -p 8000:8000 iscc-search:smoke
169
+ # Wait up to 60s for /readyz to return 200
170
+ for i in $(seq 1 30); do
171
+ if curl -sf http://localhost:8000/readyz > /dev/null; then
172
+ echo "Ready after ${i} attempts"
173
+ break
174
+ fi
175
+ sleep 2
176
+ done
177
+ curl -sf http://localhost:8000/healthz
178
+ curl -sf http://localhost:8000/readyz
179
+ echo "--- container logs ---"
180
+ docker logs iscc-search-smoke
181
+ docker stop iscc-search-smoke
182
+
183
+ publish-develop:
184
+ name: Publish Docker image (develop)
185
+ if: github.event_name == 'push' && github.ref == 'refs/heads/develop'
186
+ needs: [test-full, test-smoke, wheel-smoke, docker-smoke]
187
+ runs-on: ubuntu-latest
188
+ permissions:
189
+ contents: read
190
+ packages: write
191
+ steps:
192
+ - uses: actions/checkout@v6
193
+
194
+ - uses: actions/download-artifact@v7
195
+ with:
196
+ name: dist
197
+ path: dist
198
+
199
+ - uses: docker/setup-buildx-action@v4
200
+
201
+ - uses: docker/login-action@v4
202
+ with:
203
+ registry: ghcr.io
204
+ username: ${{ github.actor }}
205
+ password: ${{ secrets.GITHUB_TOKEN }}
206
+
207
+ - id: meta
208
+ uses: docker/metadata-action@v6
209
+ with:
210
+ images: ghcr.io/${{ github.repository }}
211
+ tags: |
212
+ type=raw,value=develop
213
+ type=sha,prefix=develop-
214
+
215
+ - name: Build and push
216
+ uses: docker/build-push-action@v7
217
+ with:
218
+ context: .
219
+ file: ./Dockerfile
220
+ push: true
221
+ tags: ${{ steps.meta.outputs.tags }}
222
+ labels: ${{ steps.meta.outputs.labels }}
223
+ cache-from: type=gha
@@ -0,0 +1,235 @@
1
+ name: Release
2
+
3
+ # Triggered when a GitHub Release is published. The release tag (vX.Y.Z) becomes the package version
4
+ # via hatch-vcs. Pre-release tags (v1.0.0-rc1) publish to PyPI + ghcr but do NOT update `latest`.
5
+ on:
6
+ release:
7
+ types: [published]
8
+
9
+ permissions:
10
+ contents: read
11
+
12
+ jobs:
13
+ test:
14
+ name: Test (ubuntu-latest, py${{ matrix.python-version }})
15
+ runs-on: ubuntu-latest
16
+ strategy:
17
+ matrix:
18
+ python-version: ["3.11", "3.12", "3.13", "3.14"]
19
+ fail-fast: false
20
+ steps:
21
+ - uses: actions/checkout@v6
22
+ with:
23
+ fetch-depth: 0
24
+
25
+ - uses: ./.github/actions/setup-python-env
26
+ with:
27
+ python-version: ${{ matrix.python-version }}
28
+
29
+ - name: Cache iscc-sct model
30
+ uses: actions/cache@v5
31
+ with:
32
+ path: |
33
+ ~/.local/share/iscc-sct
34
+ ~/Library/Application Support/iscc-sct
35
+ ~\AppData\Local\iscc\iscc-sct
36
+ key: iscc-sct-model-${{ runner.os }}-${{ hashFiles('uv.lock') }}
37
+ restore-keys: |
38
+ iscc-sct-model-${{ runner.os }}-
39
+
40
+ - name: Pre-download iscc-sct model
41
+ run: uv run python -c "import iscc_sct.code_semantic_text as sct; sct.model()"
42
+
43
+ - name: OpenAPI build + validation
44
+ run: uv run poe build
45
+
46
+ - name: Run tests
47
+ run: uv run poe test
48
+
49
+ test-smoke:
50
+ name: Test (${{ matrix.os }}, py3.12)
51
+ runs-on: ${{ matrix.os }}
52
+ strategy:
53
+ matrix:
54
+ os: [windows-latest, macos-latest]
55
+ fail-fast: false
56
+ defaults:
57
+ run:
58
+ shell: bash
59
+ steps:
60
+ - uses: actions/checkout@v6
61
+ with:
62
+ fetch-depth: 0
63
+
64
+ - uses: ./.github/actions/setup-python-env
65
+ with:
66
+ python-version: "3.12"
67
+
68
+ - name: Cache iscc-sct model
69
+ uses: actions/cache@v5
70
+ with:
71
+ path: |
72
+ ~/.local/share/iscc-sct
73
+ ~/Library/Application Support/iscc-sct
74
+ ~\AppData\Local\iscc\iscc-sct
75
+ key: iscc-sct-model-${{ runner.os }}-${{ hashFiles('uv.lock') }}
76
+ restore-keys: |
77
+ iscc-sct-model-${{ runner.os }}-
78
+
79
+ - name: Pre-download iscc-sct model
80
+ run: uv run python -c "import iscc_sct.code_semantic_text as sct; sct.model()"
81
+
82
+ - name: Run tests
83
+ run: uv run poe test
84
+
85
+ wheel-build:
86
+ name: Build wheel + sdist
87
+ runs-on: ubuntu-latest
88
+ steps:
89
+ - uses: actions/checkout@v6
90
+ with:
91
+ fetch-depth: 0
92
+
93
+ - uses: ./.github/actions/setup-python-env
94
+
95
+ - name: Build
96
+ run: uv build
97
+
98
+ - name: Verify version matches release tag
99
+ run: |
100
+ # hatch-vcs strips the leading `v` from tags, so `v0.1.0` → `0.1.0`
101
+ expected="${GITHUB_REF_NAME#v}"
102
+ actual=$(ls dist/iscc_search-*.whl | sed -E 's|dist/iscc_search-([^-]+)-.*|\1|' | head -1)
103
+ if [ "$expected" != "$actual" ]; then
104
+ echo "::error::Wheel version ($actual) does not match release tag ($expected)"
105
+ exit 1
106
+ fi
107
+ echo "Version verified: $actual"
108
+
109
+ - uses: actions/upload-artifact@v6
110
+ with:
111
+ name: dist
112
+ path: dist/
113
+ retention-days: 30
114
+
115
+ wheel-smoke:
116
+ name: Smoke-test wheel (${{ matrix.os }})
117
+ needs: wheel-build
118
+ runs-on: ${{ matrix.os }}
119
+ strategy:
120
+ matrix:
121
+ os: [ubuntu-latest, windows-latest, macos-latest]
122
+ fail-fast: false
123
+ defaults:
124
+ run:
125
+ shell: bash
126
+ steps:
127
+ - uses: actions/setup-python@v6
128
+ with:
129
+ python-version: "3.12"
130
+
131
+ - uses: actions/download-artifact@v7
132
+ with:
133
+ name: dist
134
+ path: dist
135
+
136
+ - name: Install and verify
137
+ run: |
138
+ python -m venv .smoke-venv
139
+ # Cross-platform venv bin dir:
140
+ if [ -d ".smoke-venv/Scripts" ]; then
141
+ BIN=.smoke-venv/Scripts
142
+ else
143
+ BIN=.smoke-venv/bin
144
+ fi
145
+ "$BIN/python" -m pip install --upgrade pip
146
+ "$BIN/python" -m pip install dist/*.whl
147
+ "$BIN/python" -c "import iscc_search; print('version:', iscc_search.__version__)"
148
+ "$BIN/iscc-search" --help
149
+
150
+ publish-pypi:
151
+ name: Publish to PyPI
152
+ needs: [test, test-smoke, wheel-smoke]
153
+ runs-on: ubuntu-latest
154
+ environment: pypi
155
+ steps:
156
+ - uses: actions/download-artifact@v7
157
+ with:
158
+ name: dist
159
+ path: dist
160
+
161
+ - uses: astral-sh/setup-uv@v8.0.0
162
+ with:
163
+ version: "0.6.14"
164
+
165
+ - name: Publish
166
+ run: uv publish dist/*
167
+ env:
168
+ UV_PUBLISH_TOKEN: ${{ secrets.PYPI_TOKEN }}
169
+
170
+ publish-docker:
171
+ name: Publish Docker image
172
+ needs: [test, test-smoke, wheel-smoke]
173
+ runs-on: ubuntu-latest
174
+ permissions:
175
+ contents: read
176
+ packages: write
177
+ steps:
178
+ - uses: actions/checkout@v6
179
+
180
+ - uses: actions/download-artifact@v7
181
+ with:
182
+ name: dist
183
+ path: dist
184
+
185
+ - uses: docker/setup-buildx-action@v4
186
+
187
+ - uses: docker/login-action@v4
188
+ with:
189
+ registry: ghcr.io
190
+ username: ${{ github.actor }}
191
+ password: ${{ secrets.GITHUB_TOKEN }}
192
+
193
+ - id: meta
194
+ uses: docker/metadata-action@v6
195
+ with:
196
+ images: ghcr.io/${{ github.repository }}
197
+ # `latest=auto` attaches `latest` only to the highest non-prerelease tag.
198
+ flavor: |
199
+ latest=auto
200
+ tags: |
201
+ type=semver,pattern={{version}}
202
+ type=semver,pattern={{major}}.{{minor}}
203
+ type=semver,pattern={{major}}
204
+
205
+ - name: Build and push
206
+ uses: docker/build-push-action@v7
207
+ with:
208
+ context: .
209
+ file: ./Dockerfile
210
+ push: true
211
+ tags: ${{ steps.meta.outputs.tags }}
212
+ labels: ${{ steps.meta.outputs.labels }}
213
+ cache-from: type=gha
214
+ cache-to: type=gha,mode=max
215
+
216
+ deploy-docs:
217
+ name: Deploy documentation
218
+ needs: publish-pypi
219
+ runs-on: ubuntu-latest
220
+ permissions:
221
+ contents: write # zensical gh-deploy pushes to gh-pages
222
+ steps:
223
+ - uses: actions/checkout@v6
224
+ with:
225
+ fetch-depth: 0
226
+
227
+ - uses: ./.github/actions/setup-python-env
228
+
229
+ - name: Build docs
230
+ run: |
231
+ uv run zensical build
232
+ uv run python scripts/gen_llms_full.py
233
+
234
+ - name: Deploy to gh-pages
235
+ run: uv run zensical gh-deploy --force