algoriq 0.2.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.
@@ -0,0 +1,16 @@
1
+ # This file exists for a build reason as well as a VCS one.
2
+ #
3
+ # Hatchling resolves the nearest VCS ignore file by walking up to the repository
4
+ # root and then FORCE-includes it in the sdist (builders/sdist.py
5
+ # get_default_build_data), where `exclude` cannot reach it and `ignore-vcs` does
6
+ # not apply. Without a package-local file the nearest one is the monorepo root's,
7
+ # so every sdist shipped a listing of this repository's internal directories.
8
+ # Keeping one here means the shipped file is this package's own and says nothing
9
+ # about anything else. tests/test_distribution_boundary.py pins that.
10
+
11
+ .venv/
12
+ dist/
13
+ __pycache__/
14
+ *.pyc
15
+ .pytest_cache/
16
+ .ruff_cache/
algoriq-0.2.0/PKG-INFO ADDED
@@ -0,0 +1,193 @@
1
+ Metadata-Version: 2.5
2
+ Name: algoriq
3
+ Version: 0.2.0
4
+ Summary: AlgoriQ Research — notebook SDK: the supported compute surface plus the submission plane client
5
+ Requires-Python: >=3.12
6
+ Requires-Dist: cryptography>=42.0.0
7
+ Requires-Dist: dcor>=0.6
8
+ Requires-Dist: econml<0.17,>=0.16.0
9
+ Requires-Dist: hmmlearn>=0.3.2
10
+ Requires-Dist: holidays>=0.65
11
+ Requires-Dist: httpx>=0.27.0
12
+ Requires-Dist: joblib>=1.3.0
13
+ Requires-Dist: numba>=0.59
14
+ Requires-Dist: numpy>=2.2.6
15
+ Requires-Dist: orjson>=3.9.0
16
+ Requires-Dist: pandas>=2.3.3
17
+ Requires-Dist: pyarrow>=15.0.0
18
+ Requires-Dist: pydantic-settings>=2.3.0
19
+ Requires-Dist: pydantic>=2.9.0
20
+ Requires-Dist: scikit-learn>=1.4.0
21
+ Requires-Dist: scipy>=1.11.0
22
+ Requires-Dist: structlog>=25.0.0
23
+ Requires-Dist: tenacity>=8.2.0
24
+ Requires-Dist: threadpoolctl>=3.1.0
25
+ Provides-Extra: boosting
26
+ Requires-Dist: catboost>=1.2; extra == 'boosting'
27
+ Requires-Dist: lightgbm>=4.5.0; extra == 'boosting'
28
+ Requires-Dist: ngboost>=0.5; extra == 'boosting'
29
+ Requires-Dist: xgboost>=2.1.0; extra == 'boosting'
30
+ Provides-Extra: foundation
31
+ Requires-Dist: chronos-forecasting>=1.4; extra == 'foundation'
32
+ Requires-Dist: torch<2.6,>=2.2; extra == 'foundation'
33
+ Provides-Extra: mlx
34
+ Requires-Dist: cvxpy>=1.5.0; extra == 'mlx'
35
+ Requires-Dist: cvxpylayers>=1.2.0; extra == 'mlx'
36
+ Requires-Dist: mlx>=0.31.0; (sys_platform == 'darwin' and platform_machine == 'arm64') and extra == 'mlx'
37
+ Provides-Extra: signal
38
+ Requires-Dist: pywavelets>=1.7.0; extra == 'signal'
39
+ Requires-Dist: statsmodels>=0.14.0; extra == 'signal'
40
+ Provides-Extra: symbolic
41
+ Requires-Dist: pysr<2,>=1.5; extra == 'symbolic'
42
+ Provides-Extra: tabpfn
43
+ Requires-Dist: tabpfn>=2.0; extra == 'tabpfn'
44
+ Requires-Dist: torch<2.6,>=2.2; extra == 'tabpfn'
45
+ Description-Content-Type: text/markdown
46
+
47
+ # AlgoriQ Research — notebook SDK
48
+
49
+ The pro-code side of AlgoriQ. Install it in any Python kernel — Colab, a local
50
+ Jupyter, a VS Code notebook — and you get two things:
51
+
52
+ 1. **The supported compute surface** of the platform: AFML labeling, purged and
53
+ combinatorial cross-validation, MDI/MDA/SFI importance, sample weighting,
54
+ covariance denoising and ONC clustering, indicators and fractional
55
+ differentiation. These are re-exports, not copies — the notebook runs the
56
+ same code the platform runs.
57
+ 2. **The research submission plane client**: declare an observation, seal a
58
+ snapshot, submit a result, read it back.
59
+
60
+ ```python
61
+ import algoriq_research as aq
62
+
63
+ aq.print_capabilities() # what this install actually supports
64
+ client = aq.ResearchClient() # reads ALGORIQ_SUBMISSION_TOKEN
65
+ ```
66
+
67
+ ## Connecting
68
+
69
+ **There is one connection flow and it does not depend on where your kernel
70
+ runs.** The notebook starts a device authorization (RFC 8628), prints a short
71
+ code and a link, and you approve it in a browser already signed in to AlgoriQ —
72
+ choosing on that screen which account the notebook acts as. The credential is
73
+ then issued straight to the kernel, into `ALGORIQ_SUBMISSION_TOKEN`, and the SDK
74
+ sends it as a bearer. Nothing else identifies you. Colab, a local Jupyter and a
75
+ VS Code kernel take the identical path; no step of this has a per-runtime
76
+ variant.
77
+
78
+ The same credential fetches the SDK itself, because the wheel is served by
79
+ AlgoriQ rather than by a public index: you download it with the credential,
80
+ check it against the digest the server published, and install that exact file.
81
+ So connecting comes first and installing second, on every runtime.
82
+
83
+ Both steps, working, are cells 1 and 2 of
84
+ [`examples/notebooks/research_roundtrip.ipynb`](examples/notebooks/research_roundtrip.ipynb).
85
+
86
+ ⛔ Never paste a credential into a notebook cell. A cell's contents are saved
87
+ with the notebook, and a notebook is the thing people share. The device grant is
88
+ what makes that avoidable — you never see the credential at all.
89
+
90
+ ⛔ Never put a credential on a `pip` command line or in an index URL. It belongs
91
+ in an `Authorization` header: a command line lands in shell history, in the cell
92
+ output saved with the notebook, and in the process table of a shared machine.
93
+
94
+ ⚠️ Send an explicit `User-Agent` on any hand-rolled HTTP call to `*.algoriq.ai`.
95
+ The edge refuses `urllib`'s default `Python-urllib/*` signature with a `403`
96
+ whose body is `error code: 1010` — not JSON, and not our `401`, so a client that
97
+ reads only the status will report the wrong cause. Every other user agent tested
98
+ is accepted, `httpx`'s default among them, so this bites hand-rolled `urllib`
99
+ calls — the bootstrap and install cells — and not the SDK.
100
+
101
+ The credential is **opaque** to this SDK: it is read, sent, and never parsed. If
102
+ the plane answers `401`, the credential is absent, expired or revoked — run the
103
+ connection cell again to get a new one. Revoking one takes effect on the next
104
+ call.
105
+
106
+ ## What "supported" means, and what it does not
107
+
108
+ `print_capabilities()` answers by **running** each capability, not by reading a
109
+ table, so it cannot claim support this environment does not have. Every row comes
110
+ back as one of:
111
+
112
+ | Status | Meaning | What you do |
113
+ | --------------------- | ------------------------------------------ | --------------------------------------------------- |
114
+ | `available` | Installed and proven to execute here | Nothing |
115
+ | `not_installed` | Its extra is not installed | `pip install 'algoriq[<extra>]'` |
116
+ | `broken_install` | **Our own** module is missing from disk | Reinstall the wheel and tell us — no extra fixes it |
117
+ | `unsupported_runtime` | This runtime cannot have it at any version | Use a different backend — installing won't help |
118
+ | `not_entitled` | Your account may not do this | A plan/permission question, raised by the server |
119
+
120
+ `broken_install` is its own word because it is the one state where the obvious
121
+ remedy is wrong: a missing file of ours raises the same `ImportError` a missing
122
+ library does, so reporting it as `not_installed` hands you a `pip install` that
123
+ installs the libraries, changes nothing, and prints the same line again.
124
+
125
+ The extras are `boosting`, `tabpfn`, `foundation`, `symbolic`, `mlx` and `signal`. An extra
126
+ means _not in the default install_ — never _you may not use it_. You are free to
127
+ `pip install xgboost` in Colab and use it directly; the extra is what makes
128
+ **our** wrappers around it resolve.
129
+
130
+ ⛔ **Widening the supported surface does not raise the evidence grade of what you
131
+ submit.** Results declared from a notebook come back graded `descriptive` with
132
+ `population_status='unverified'`, because the platform stores what you declared
133
+ and does not certify that your search was complete. That boundary is independent
134
+ of this table.
135
+
136
+ ## The round trip
137
+
138
+ ```python
139
+ import algoriq_research as aq
140
+
141
+ client = aq.ResearchClient()
142
+
143
+ # 1. declare each terminal execution — including the ones you discarded
144
+ kept = client.record_observation(declaration)
145
+
146
+ # 2. submit the selected result's bytes (declare → upload → seal, in one call)
147
+ sealed = client.submit(submission_intent, parquet_bytes)
148
+
149
+ # 3. seal the scope, naming the server's normalised digest of that result
150
+ snapshot = client.seal_snapshot(snapshot_intent) # selected_result_sha256=sealed.normalized_sha256
151
+
152
+ # 4. bind the result to the snapshot that selected it
153
+ publication = client.publish_submission(sealed.receipt_id, publication_intent)
154
+
155
+ # 5. read it back, any time
156
+ client.get_publication(sealed.receipt_id)
157
+ ```
158
+
159
+ ⛔ Steps 2 and 3 are in that order for a reason: a snapshot names the
160
+ **normalised** digest of its selected result, and that digest is the server's —
161
+ it does not exist until the bytes have been sealed. Sealing the scope first
162
+ leaves you with nothing to put in `selected_result_sha256`.
163
+
164
+ `submit()` checks your declared `raw_sha256` and `size_bytes` against the bytes
165
+ **before** it opens a connection. Found here it costs nothing; found server-side
166
+ it costs the whole upload first, which on a home uplink is minutes.
167
+
168
+ `prepare_submission()` returns an upload form whose `expires_in` is a function of
169
+ the `size_bytes` you declared — a large upload is given proportionally longer.
170
+ Read it rather than assuming a constant.
171
+
172
+ Worked example: [`examples/notebooks/research_roundtrip.ipynb`](examples/notebooks/research_roundtrip.ipynb).
173
+
174
+ ## Not here yet
175
+
176
+ - **Reading platform data.** The read planes (`.../research/ingredients*`,
177
+ market-data) are live and take the same credential, but this SDK has no typed
178
+ client for them yet, so a notebook reaches them with plain HTTP for now.
179
+ - **Installation from an index.** The release flow, version SSOT and download
180
+ authorisation are owned by `docs/guides/notebook-sdk-distribution.md`; until a
181
+ release is published, install from a wheel built out of this repository.
182
+
183
+ ## For maintainers
184
+
185
+ The public API is not written twice. `algoriq_research.capabilities.CAPABILITIES`
186
+ is both the allowlist and the support matrix: `__all__` is derived from it, and
187
+ each name's capability is checked before the name resolves. Adding a public name
188
+ means adding it there and nowhere else.
189
+
190
+ `tests/test_distribution_boundary.py` builds the wheel and the sdist and reads
191
+ the archives — paths, metadata, declared dependencies (including the shared
192
+ package's own base list) and a secret scan. Source-tree exclusion rules are not
193
+ evidence of what shipped.
@@ -0,0 +1,147 @@
1
+ # AlgoriQ Research — notebook SDK
2
+
3
+ The pro-code side of AlgoriQ. Install it in any Python kernel — Colab, a local
4
+ Jupyter, a VS Code notebook — and you get two things:
5
+
6
+ 1. **The supported compute surface** of the platform: AFML labeling, purged and
7
+ combinatorial cross-validation, MDI/MDA/SFI importance, sample weighting,
8
+ covariance denoising and ONC clustering, indicators and fractional
9
+ differentiation. These are re-exports, not copies — the notebook runs the
10
+ same code the platform runs.
11
+ 2. **The research submission plane client**: declare an observation, seal a
12
+ snapshot, submit a result, read it back.
13
+
14
+ ```python
15
+ import algoriq_research as aq
16
+
17
+ aq.print_capabilities() # what this install actually supports
18
+ client = aq.ResearchClient() # reads ALGORIQ_SUBMISSION_TOKEN
19
+ ```
20
+
21
+ ## Connecting
22
+
23
+ **There is one connection flow and it does not depend on where your kernel
24
+ runs.** The notebook starts a device authorization (RFC 8628), prints a short
25
+ code and a link, and you approve it in a browser already signed in to AlgoriQ —
26
+ choosing on that screen which account the notebook acts as. The credential is
27
+ then issued straight to the kernel, into `ALGORIQ_SUBMISSION_TOKEN`, and the SDK
28
+ sends it as a bearer. Nothing else identifies you. Colab, a local Jupyter and a
29
+ VS Code kernel take the identical path; no step of this has a per-runtime
30
+ variant.
31
+
32
+ The same credential fetches the SDK itself, because the wheel is served by
33
+ AlgoriQ rather than by a public index: you download it with the credential,
34
+ check it against the digest the server published, and install that exact file.
35
+ So connecting comes first and installing second, on every runtime.
36
+
37
+ Both steps, working, are cells 1 and 2 of
38
+ [`examples/notebooks/research_roundtrip.ipynb`](examples/notebooks/research_roundtrip.ipynb).
39
+
40
+ ⛔ Never paste a credential into a notebook cell. A cell's contents are saved
41
+ with the notebook, and a notebook is the thing people share. The device grant is
42
+ what makes that avoidable — you never see the credential at all.
43
+
44
+ ⛔ Never put a credential on a `pip` command line or in an index URL. It belongs
45
+ in an `Authorization` header: a command line lands in shell history, in the cell
46
+ output saved with the notebook, and in the process table of a shared machine.
47
+
48
+ ⚠️ Send an explicit `User-Agent` on any hand-rolled HTTP call to `*.algoriq.ai`.
49
+ The edge refuses `urllib`'s default `Python-urllib/*` signature with a `403`
50
+ whose body is `error code: 1010` — not JSON, and not our `401`, so a client that
51
+ reads only the status will report the wrong cause. Every other user agent tested
52
+ is accepted, `httpx`'s default among them, so this bites hand-rolled `urllib`
53
+ calls — the bootstrap and install cells — and not the SDK.
54
+
55
+ The credential is **opaque** to this SDK: it is read, sent, and never parsed. If
56
+ the plane answers `401`, the credential is absent, expired or revoked — run the
57
+ connection cell again to get a new one. Revoking one takes effect on the next
58
+ call.
59
+
60
+ ## What "supported" means, and what it does not
61
+
62
+ `print_capabilities()` answers by **running** each capability, not by reading a
63
+ table, so it cannot claim support this environment does not have. Every row comes
64
+ back as one of:
65
+
66
+ | Status | Meaning | What you do |
67
+ | --------------------- | ------------------------------------------ | --------------------------------------------------- |
68
+ | `available` | Installed and proven to execute here | Nothing |
69
+ | `not_installed` | Its extra is not installed | `pip install 'algoriq[<extra>]'` |
70
+ | `broken_install` | **Our own** module is missing from disk | Reinstall the wheel and tell us — no extra fixes it |
71
+ | `unsupported_runtime` | This runtime cannot have it at any version | Use a different backend — installing won't help |
72
+ | `not_entitled` | Your account may not do this | A plan/permission question, raised by the server |
73
+
74
+ `broken_install` is its own word because it is the one state where the obvious
75
+ remedy is wrong: a missing file of ours raises the same `ImportError` a missing
76
+ library does, so reporting it as `not_installed` hands you a `pip install` that
77
+ installs the libraries, changes nothing, and prints the same line again.
78
+
79
+ The extras are `boosting`, `tabpfn`, `foundation`, `symbolic`, `mlx` and `signal`. An extra
80
+ means _not in the default install_ — never _you may not use it_. You are free to
81
+ `pip install xgboost` in Colab and use it directly; the extra is what makes
82
+ **our** wrappers around it resolve.
83
+
84
+ ⛔ **Widening the supported surface does not raise the evidence grade of what you
85
+ submit.** Results declared from a notebook come back graded `descriptive` with
86
+ `population_status='unverified'`, because the platform stores what you declared
87
+ and does not certify that your search was complete. That boundary is independent
88
+ of this table.
89
+
90
+ ## The round trip
91
+
92
+ ```python
93
+ import algoriq_research as aq
94
+
95
+ client = aq.ResearchClient()
96
+
97
+ # 1. declare each terminal execution — including the ones you discarded
98
+ kept = client.record_observation(declaration)
99
+
100
+ # 2. submit the selected result's bytes (declare → upload → seal, in one call)
101
+ sealed = client.submit(submission_intent, parquet_bytes)
102
+
103
+ # 3. seal the scope, naming the server's normalised digest of that result
104
+ snapshot = client.seal_snapshot(snapshot_intent) # selected_result_sha256=sealed.normalized_sha256
105
+
106
+ # 4. bind the result to the snapshot that selected it
107
+ publication = client.publish_submission(sealed.receipt_id, publication_intent)
108
+
109
+ # 5. read it back, any time
110
+ client.get_publication(sealed.receipt_id)
111
+ ```
112
+
113
+ ⛔ Steps 2 and 3 are in that order for a reason: a snapshot names the
114
+ **normalised** digest of its selected result, and that digest is the server's —
115
+ it does not exist until the bytes have been sealed. Sealing the scope first
116
+ leaves you with nothing to put in `selected_result_sha256`.
117
+
118
+ `submit()` checks your declared `raw_sha256` and `size_bytes` against the bytes
119
+ **before** it opens a connection. Found here it costs nothing; found server-side
120
+ it costs the whole upload first, which on a home uplink is minutes.
121
+
122
+ `prepare_submission()` returns an upload form whose `expires_in` is a function of
123
+ the `size_bytes` you declared — a large upload is given proportionally longer.
124
+ Read it rather than assuming a constant.
125
+
126
+ Worked example: [`examples/notebooks/research_roundtrip.ipynb`](examples/notebooks/research_roundtrip.ipynb).
127
+
128
+ ## Not here yet
129
+
130
+ - **Reading platform data.** The read planes (`.../research/ingredients*`,
131
+ market-data) are live and take the same credential, but this SDK has no typed
132
+ client for them yet, so a notebook reaches them with plain HTTP for now.
133
+ - **Installation from an index.** The release flow, version SSOT and download
134
+ authorisation are owned by `docs/guides/notebook-sdk-distribution.md`; until a
135
+ release is published, install from a wheel built out of this repository.
136
+
137
+ ## For maintainers
138
+
139
+ The public API is not written twice. `algoriq_research.capabilities.CAPABILITIES`
140
+ is both the allowlist and the support matrix: `__all__` is derived from it, and
141
+ each name's capability is checked before the name resolves. Adding a public name
142
+ means adding it there and nowhere else.
143
+
144
+ `tests/test_distribution_boundary.py` builds the wheel and the sdist and reads
145
+ the archives — paths, metadata, declared dependencies (including the shared
146
+ package's own base list) and a secret scan. Source-tree exclusion rules are not
147
+ evidence of what shipped.