diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml new file mode 100644 index 0000000..c97bafb --- /dev/null +++ b/.github/workflows/publish.yml @@ -0,0 +1,68 @@ +name: publish (pypi) + +on: + workflow_dispatch: + inputs: + ref: + description: "Tag to build and publish, for example v1.1.0" + required: true + +permissions: + contents: read + +jobs: + publish: + name: verify + publish + runs-on: ubuntu-latest + environment: pypi-production + permissions: + contents: read + id-token: write + steps: + - uses: actions/checkout@v4 + with: + ref: ${{ inputs.ref }} + + - uses: actions/setup-python@v5 + with: + python-version: "3.12" + + - name: Install release tooling + run: python -m pip install build twine pytest + + - name: Require tag and package versions to match + env: + RELEASE_REF: ${{ inputs.ref }} + run: | + python - <<'PY' + import pathlib + import re + import sys + import tomllib + + ref = __import__("os").environ["RELEASE_REF"] + if not re.fullmatch(r"v\d+\.\d+\.\d+", ref): + sys.exit(f"release ref must be an exact vX.Y.Z tag, got {ref!r}") + + declared = tomllib.loads(pathlib.Path("pyproject.toml").read_text())["project"]["version"] + init = pathlib.Path("nano/__init__.py").read_text() + runtime = re.search(r'^__version__ = "([^"]+)"$', init, re.M).group(1) + expected = ref.removeprefix("v") + if declared != runtime or declared != expected: + sys.exit( + f"version mismatch: tag={expected}, pyproject={declared}, runtime={runtime}" + ) + print(f"release version: {declared}") + PY + + - name: Run tests + run: python -m pytest -q + + - name: Build distributions + run: python -m build + + - name: Check distribution metadata + run: python -m twine check dist/* + + - name: Publish to PyPI + uses: pypa/gh-action-pypi-publish@release/v1 diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..7020a34 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,42 @@ +# Changelog + +All notable changes to `aether-nano` are documented here. This project follows +[Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## [Unreleased] + +## [1.1.0] — 2026-09-18 + +### Added + +- A deterministic Intent frontend that turns bounded natural-language requests + into typed, host-governed plans with canonical receipts. +- Project intelligence for parsing and searching PR, commit, and memory records, + including evidence-bearing tags, grouping, title suggestions, and compact + context capsules. +- A faster README on-ramp with a direct PyPI install, live package/star badges, + and a reproducible CLI demo. +- A manual, OIDC-backed PyPI release workflow with package and test gates. + +### Changed + +- The package description and project links now expose Nano's rule-engine, + replay, audit, issue, and changelog surfaces directly in package indexes. + +## [1.0.12] — 2026-08-20 + +### Added + +- The curated G3 strategy batch and its byte-stable conformance artifacts. + +## [0.1.0] — 2026-07-22 + +### Added + +- First public compiler preview with Nano IR, the reference interpreter, + host-governed intents, pattern memory, and the initial strategy library. + +[Unreleased]: https://github.com/AetherAI3/Nano/compare/v1.1.0...HEAD +[1.1.0]: https://github.com/AetherAI3/Nano/compare/7410e58...v1.1.0 +[1.0.12]: https://github.com/AetherAI3/Nano/commit/7410e58 +[0.1.0]: https://github.com/AetherAI3/Nano/releases/tag/v0.1.0 diff --git a/README.md b/README.md index 69f4314..59b5e05 100644 --- a/README.md +++ b/README.md @@ -7,8 +7,10 @@ ### Trading and agent rules that run the same way every time — with a receipt. [![CI](https://github.com/AetherAI3/Nano/actions/workflows/ci.yml/badge.svg)](https://github.com/AetherAI3/Nano/actions/workflows/ci.yml) +[![PyPI](https://img.shields.io/pypi/v/aether-nano?style=flat-square&logo=pypi&logoColor=white&color=22d3ee)](https://pypi.org/project/aether-nano/) [![License: MIT](https://img.shields.io/badge/License-MIT-22d3ee.svg)](LICENSE) [![Python](https://img.shields.io/badge/python-3.10%2B-38bdf8.svg)](pyproject.toml) +[![GitHub stars](https://img.shields.io/github/stars/AetherAI3/Nano?style=flat-square&logo=github&color=facc15)](https://github.com/AetherAI3/Nano/stargazers) ### **[→ Browse the Strategy Library](https://aethersystems.net/nano)** @@ -16,6 +18,10 @@ Read every strategy in this repo — source, compiled IR, signals and the corpus provenance policy — in your browser. No install, no account. Open any one of them straight into an editor. +Nano CLI demo: install, browse deterministic strategies, compile an intent, and parse a project query + +[Install](#install-and-explore) · [Strategy library](nano/library/README.md) · [Language](docs/language.md) · [Receipts](docs/receipts.md) · [Contribute](docs/first-contribution.md) + > **Write the rule in plain text. Replay any decision. Keep final authority in your application.** @@ -35,6 +41,19 @@ strategy MaxDrawdownBreaker { That is the risk breaker from the [strategy library](nano/library/risk/max_drawdown_breaker.nano), with its comment header trimmed: when portfolio drawdown reaches 5 percent, propose a `PAUSE` and escalate to a named risk desk. Nano cannot halt anything by itself — your application's gate decides whether to act on the proposal. That separation is the whole design. +## Install and explore + +```bash +pip install aether-nano +nano library search momentum +nano intent compile "when is spy earnings" --json +``` + +The package has zero required dependencies and includes the compiler, runtime, +CLI, 55-strategy conformance library, 40 deterministic indicators, Intent +frontend, and project-search fixtures. Nano does not fetch market data or take +actions: hosts supply observations and retain final authority. + ### Why that matters when money is on the line - **Deterministic** — the same rule over the same inputs replays to the same decision, every time. @@ -58,25 +77,10 @@ IR `0.1.0`, catalogs, effects, consent policy, and canonical fixtures. ## Quick start -### Project search and compact memory +### Strategy replay from source -Nano also supports general application discovery through `nano.project`: -classify PRs, commits, and memory records into evidence-bearing tags; compile -searches such as `frontend css pending review`; group results; suggest titles; -and emit compact agent summaries. It uses no model or network calls. - -```bash -nano project parse "frontend css pending review group by area" -nano project search nano/project/fixtures/records.json "css" --project-id example-project -``` - -The host supplies authorized records and current status observations. Nano -does not rename PRs or upload memory. See the [project intelligence contract -and APR integration guide](docs/project-intelligence.md). - -### Strategy quick start - -From a fresh checkout, run the bundled Momentum strategy and then the test suite: +Clone the repository to run the bundled Momentum strategy and the full test +suite: ```bash git clone https://github.com/AetherAI3/Nano.git @@ -113,6 +117,22 @@ strategy Momentum { `RSI(14)` is the **feed-signal form**: the host computes and injects the `RSI` series. v1.0 adds a **computed form** — `RSI(close, 14)`, where `close` is a declared `input` and Nano derives the series itself from 40 deterministic kernels. Nano still never *fetches* market data. See the [language reference](docs/language.md) for both contracts. +### Project search and compact memory + +Nano also supports general application discovery through `nano.project`: +classify PRs, commits, and memory records into evidence-bearing tags; compile +searches such as `frontend css pending review`; group results; suggest titles; +and emit compact agent summaries. It uses no model or network calls. + +```bash +nano project parse "frontend css pending review group by area" +nano project search nano/project/fixtures/records.json "css" --project-id example-project +``` + +The host supplies authorized records and current status observations. Nano +does not rename PRs or upload memory. See the [project intelligence contract +and APR integration guide](docs/project-intelligence.md). + ## Start with the strategy library The [strategy library](nano/library/README.md) is Nano's community on-ramp: a small, tested corpus of familiar trading ideas — and deterministic watchdog controls — translated into the DSL. Every entry pairs readable `.nano` source with expected IR, so quant researchers can learn the language, compare conventions, and contribute a new rule with confidence. diff --git a/RELEASING.md b/RELEASING.md new file mode 100644 index 0000000..2ccb1db --- /dev/null +++ b/RELEASING.md @@ -0,0 +1,35 @@ +# Releasing `aether-nano` + +Nano publishes from one reviewed commit to PyPI and GitHub Releases. + +## One-time setup + +Configure `aether-nano` on PyPI with a trusted publisher matching: + +| Field | Value | +| --- | --- | +| Owner | `AetherAI3` | +| Repository | `Nano` | +| Workflow | `publish.yml` | +| Environment | `pypi-production` | + +Create the matching `pypi-production` environment in the GitHub repository. +No long-lived PyPI token is required. + +## Cut a release + +1. Update the identical version strings in `pyproject.toml` and + `nano/__init__.py`. +2. Move the release notes from `Unreleased` into a dated section in + `CHANGELOG.md`. +3. Regenerate version-bound receipts with `python tests/regen_goldens.py`. +4. Run `python -m pytest -q`, build the distributions, and inspect them with + `twine check`. +5. Merge the release PR after every required check passes. +6. Create an annotated `vX.Y.Z` tag on that merge commit. +7. Dispatch `publish.yml` with the tag as `ref`. +8. Create the GitHub Release from the same tag and paste the matching changelog + section into its notes. + +PyPI files are immutable. Never reuse a version after any artifact for it has +been uploaded. diff --git a/assets/make_demo_gif.py b/assets/make_demo_gif.py new file mode 100644 index 0000000..9dd9bc6 --- /dev/null +++ b/assets/make_demo_gif.py @@ -0,0 +1,99 @@ +"""Regenerate the compact terminal demo used at the top of the README.""" + +from __future__ import annotations + +from pathlib import Path + +from PIL import Image, ImageDraw, ImageFont + + +WIDTH, HEIGHT = 1000, 560 +BACKGROUND = "#071018" +PANEL = "#0b1722" +BORDER = "#1f3545" +TEXT = "#d7e6ee" +MUTED = "#7795a6" +CYAN = "#22d3ee" +GREEN = "#4ade80" +YELLOW = "#facc15" +OUTPUT = Path(__file__).with_name("nano-demo.gif") + + +def font(size: int, *, bold: bool = False) -> ImageFont.FreeTypeFont: + family = "DejaVuSansMono-Bold.ttf" if bold else "DejaVuSansMono.ttf" + candidates = ( + Path("/usr/share/fonts/truetype/dejavu") / family, + Path("/usr/local/share/fonts") / family, + ) + for candidate in candidates: + if candidate.exists(): + return ImageFont.truetype(str(candidate), size) + return ImageFont.load_default() + + +TITLE = font(19, bold=True) +BODY = font(18) +BODY_BOLD = font(18, bold=True) +SMALL = font(14) + + +LINES: list[tuple[str, str]] = [ + ("$ pip install aether-nano", CYAN), + ("✓ installed aether-nano", GREEN), + ("", TEXT), + ("$ nano library search momentum", CYAN), + ("ID IR HOST SIGNALS", MUTED), + ("momentum/absolute_momentum_filter 1.0.0 close", TEXT), + ("momentum/rsi_oversold_reversal 0.1.0 RSI", TEXT), + ("trend/ema_pullback_continuation 1.0.0 close", TEXT), + ("", TEXT), + ('$ nano intent compile "when is spy earnings" --json', CYAN), + ('{"operation":"lookup", "effects":["data.read","llm.call"],', TEXT), + (' "confirmation":{"mode":"submit_is_consent"}}', TEXT), + ("", TEXT), + ('$ nano project parse "frontend css pending review group by area"', CYAN), + ('{"valid":true, "groupBy":"area", "sort":"updated"}', TEXT), + ("", TEXT), + ("same input → same plan → replayable receipt", YELLOW), +] + + +def render(visible: int) -> Image.Image: + image = Image.new("RGB", (WIDTH, HEIGHT), BACKGROUND) + draw = ImageDraw.Draw(image) + draw.rounded_rectangle((20, 20, WIDTH - 20, HEIGHT - 20), 18, fill=PANEL, outline=BORDER, width=2) + draw.ellipse((43, 43, 57, 57), fill="#fb7185") + draw.ellipse((67, 43, 81, 57), fill="#facc15") + draw.ellipse((91, 43, 105, 57), fill="#4ade80") + draw.text((132, 38), "nano — deterministic rules", font=TITLE, fill=TEXT) + draw.text((760, 42), "real CLI paths", font=SMALL, fill=MUTED) + draw.line((42, 76, WIDTH - 42, 76), fill=BORDER, width=2) + + x, y = 48, 96 + for index, (line, color) in enumerate(LINES[:visible]): + chosen = BODY_BOLD if line.startswith("$") or line.startswith("✓") else BODY + draw.text((x, y), line, font=chosen, fill=color) + y += 25 + + draw.text((48, HEIGHT - 48), "Nano proposes. Your host decides.", font=SMALL, fill=MUTED) + return image + + +def main() -> None: + stops = (1, 3, 5, 9, 11, 13, 15, len(LINES)) + frames = [render(stop).convert("P", palette=Image.Palette.ADAPTIVE) for stop in stops] + durations = [700, 850, 850, 1150, 900, 1100, 950, 2600] + frames[0].save( + OUTPUT, + save_all=True, + append_images=frames[1:], + duration=durations, + loop=0, + optimize=True, + disposal=2, + ) + print(f"wrote {OUTPUT} ({OUTPUT.stat().st_size:,} bytes)") + + +if __name__ == "__main__": + main() diff --git a/assets/nano-demo.gif b/assets/nano-demo.gif new file mode 100644 index 0000000..0561a85 Binary files /dev/null and b/assets/nano-demo.gif differ diff --git a/docs/status.md b/docs/status.md index 0f75746..66566ac 100644 --- a/docs/status.md +++ b/docs/status.md @@ -1,14 +1,15 @@ # Nano status -Nano is an **alpha reference implementation**. This page distinguishes code that is present today from adjacent experiments and future work. +Nano is a **beta reference implementation**. This page distinguishes code that is present today from adjacent experiments and future work. | Area | Status | Evidence and boundary | | --- | --- | --- | +| Intent frontend | Implemented; host execution separate | `nano/intent/` parses bounded human requests into typed, canonical plans with explicit effects, confirmation policy, and receipts. Nano can describe a `data.read` or `llm.call` step but does not execute either one. See [intent-compiler.md](intent-compiler.md). | | Project search and semantic annotations | Implemented in Nano; host integration separate | `nano/project/` derives tags with evidence, suggests titles, compiles bounded read-only queries, groups supplied records, and emits compact capsules. The host owns corpus completeness, freshness, GitHub, and APR graph persistence. See [project-intelligence.md](project-intelligence.md). | | `.nano` lexer, parser, and canonical code generation | Implemented | `nano/compiler/` parses the v1.0 grammar and produces `StrategyGraph` (baseline IR) or `NanoModule` (v1.0 IR). | | Static typing and look-ahead protection | Implemented | `nano/types/` types `series`, resolves indicator periods at compile time, and rejects any series offset that is negative or not a compile-time constant. | | Computed indicators | Implemented | `nano/indicators/` ships 40 deterministic kernels with pinned degenerate-case conventions. The feed-signal form still works. | -| CLI | Implemented | `nano check / compile / replay / visualize / indicators / version` in `nano/cli/`. | +| CLI | Implemented | `nano check / compile / replay / visualize / indicators / library / intent / project / version` in `nano/cli/`. | | Risk-limit enforcement | Implemented for five of seven limits | `nano/runtime/risk.py` withholds `BUY`/`SELL`/`EXECUTE` when `max_daily_loss`, `max_drawdown`, `max_orders_per_day`, `stop_trading_after_losses`, or `min_confidence` is breached, and logs `risk.violation` plus `intent.suppressed`. Measurements come from the host frame (`risk.drawdown`, `risk.daily_loss`, `risk.orders_today`, `risk.consecutive_losses`); for `max_orders_per_day`, the VM deterministically adds actuating intents already accepted at the same timestamp. A missing, absent, non-finite, or outside-domain measurement is a breach, not a pass: drawdown and count measurements cannot be negative, while negative `risk.daily_loss` remains a valid profit/no-loss value. `PAUSE` and `OBSERVE` are never suppressed. A `min_confidence` no intent in the program could ever clear is a compile error, and `nano replay` refuses data that omits a measurement a limit reads. See [language.md](language.md#risk-limits-v10). | | `max_position_size` and `max_open_positions` | **Declared, not enforced by Nano** | These reach the IR and are logged as `risk.unenforced` at run time. Nano cannot enforce them honestly: an intent carries no order size, and Nano cannot tell an opening trade from a closing one, so neither cap is decidable from what the runtime can see. Hosts should read them from the `risk.limits` node and apply them at their own gate. This is a deliberate boundary, not a to-do. | | Strategy IR validation | Implemented | `nano/ir/` validates the supported data shape and selected effect-manifest constraints. `StrategyGraph` is serializable but not content-addressed. | @@ -23,17 +24,21 @@ Nano is an **alpha reference implementation**. This page distinguishes code that ## Not implemented in this repository -- static typing, `Series`, look-ahead protection, arithmetic, or indicator computation -- LLM calls, automatic escalation, confidence routing, or multi-agent coordination +- built-in market-data, GitHub, memory-graph, or LLM providers; Intent plans can declare host-executed `data.read` and `llm.call` effects, but Nano does not perform them +- autonomous model escalation, model routing, or multi-agent coordination - live market data, exchange/API clients, or order execution - a policy or risk *engine*: nothing here tracks a book, a position, or an order across timestamps. The `risk` block compares host-supplied measurements (plus same-timestamp accepted-intent capacity for the daily order cap) against declared limits and withholds proposals; it does not measure external state itself - persistent core audit storage, full provenance chains, or input-data authentication -- a general strategy-DAG executor, autonomous loop runner, self-modifying deployment, or real quantum-hardware dispatch +- an autonomous loop runner, self-modifying deployment, or real quantum-hardware dispatch ## Reading the research material -The [paper series](papers/README.md) explores broader design hypotheses. It is intentionally more ambitious than the alpha runtime. Do not infer an implemented API, benchmark, or guarantee from a paper unless it is corroborated by the reference documentation and code. +The [paper series](papers/README.md) explores broader design hypotheses. It is intentionally more ambitious than the beta runtime. Do not infer an implemented API, benchmark, or guarantee from a paper unless it is corroborated by the reference documentation and code. ## Compatibility posture -The public Python functions exported by `nano.compiler`, `nano.runtime`, and `nano.bridge` are the usable API surface for v0.1.0. The grammar and IR version are intentionally narrow while the conformance corpus establishes expected behavior. As an alpha project, breaking changes may occur before a stable release. +The public Python functions exported by `nano.compiler`, `nano.runtime`, +`nano.bridge`, `nano.intent`, and `nano.project` are the usable API surface. The +package, strategy IR, Intent IR, and project-query schema are independently +versioned; compatibility is judged against the explicit version carried by each +artifact. Incompatible package API changes require a new major package version. diff --git a/nano/__init__.py b/nano/__init__.py index 8458304..2b01a4b 100644 --- a/nano/__init__.py +++ b/nano/__init__.py @@ -28,4 +28,4 @@ artifact cannot change behavior because a transitive dependency did. """ -__version__ = "1.0.12" +__version__ = "1.1.0" diff --git a/pyproject.toml b/pyproject.toml index a78db4c..ef64c53 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,7 +1,7 @@ [project] name = "aether-nano" -version = "1.0.12" -description = "A deterministic strategy DSL and reference runtime for host-governed decision rules." +version = "1.1.0" +description = "Deterministic rule engine and strategy DSL for AI agents and quantitative systems — compile, replay, and audit every decision." readme = "README.md" license = { text = "MIT" } requires-python = ">=3.10" @@ -36,6 +36,8 @@ Homepage = "https://aethersystems.net" "Aether Code (web IDE)" = "https://app.aethersystems.net/code" Repository = "https://github.com/AetherAI3/Nano" Documentation = "https://github.com/AetherAI3/Nano/tree/main/docs" +Issues = "https://github.com/AetherAI3/Nano/issues" +Changelog = "https://github.com/AetherAI3/Nano/blob/main/CHANGELOG.md" [project.optional-dependencies] # Signed, non-repudiable audit receipts over decision-gate records. diff --git a/tests/golden/receipt_drift.json b/tests/golden/receipt_drift.json index 436eda3..0475b03 100644 --- a/tests/golden/receipt_drift.json +++ b/tests/golden/receipt_drift.json @@ -1 +1 @@ -{"identity":{"compiler":{"name":"nnc","version":"1.0.0"},"effects":["intent.emit","log.append"],"irVersion":"1.0.0","module":"Drift","moduleHash":"sha256:f43458398231b977af7a1114b0e0e7760cd18a09910c9e32d178f7d8d1e45c24","nanoVersion":"1.0.12","reasoningRequired":false,"tier":"nano","warmupDeclared":2},"inputs":{"bars":5,"firstTimestamp":0,"frameHash":"sha256:173b1650bc76a5efe8f882e3695d2b03047fc813ac4ddd51eaafbbd576dd7f8f","lastTimestamp":240,"signals":["close"]},"provenance":{"sourceHash":"sha256:308da8d305e125c2e5d35a97bd7e2cd32ab3f255635c5c67116cfc4c09c10bea"},"receiptVersion":1,"run":{"escalations":[],"intents":[{"intent":"OBSERVE","timestamp":120},{"asset":"BTC","confidence":0.7,"intent":"BUY","timestamp":180},{"intent":"OBSERVE","timestamp":240}],"log":[{"detail":"Drift tier=nano effects=['intent.emit', 'log.append'] warmup=2","event":"module.loaded","timestamp":0},{"detail":"n6 has no value at bar 0","event":"condition.unwarmed","timestamp":0},{"detail":"n6 has no value at bar 1","event":"condition.unwarmed","timestamp":60},{"detail":"n6 -> False","event":"condition.evaluated","timestamp":120},{"detail":"OBSERVE asset=None","event":"intent.emitted","timestamp":120},{"detail":"n6 -> True","event":"condition.evaluated","timestamp":180},{"detail":"BUY asset=BTC","event":"intent.emitted","timestamp":180},{"detail":"n6 -> False","event":"condition.evaluated","timestamp":240},{"detail":"OBSERVE asset=None","event":"intent.emitted","timestamp":240}],"warmupBarsSkipped":2}} \ No newline at end of file +{"identity":{"compiler":{"name":"nnc","version":"1.0.0"},"effects":["intent.emit","log.append"],"irVersion":"1.0.0","module":"Drift","moduleHash":"sha256:f43458398231b977af7a1114b0e0e7760cd18a09910c9e32d178f7d8d1e45c24","nanoVersion":"1.1.0","reasoningRequired":false,"tier":"nano","warmupDeclared":2},"inputs":{"bars":5,"firstTimestamp":0,"frameHash":"sha256:173b1650bc76a5efe8f882e3695d2b03047fc813ac4ddd51eaafbbd576dd7f8f","lastTimestamp":240,"signals":["close"]},"provenance":{"sourceHash":"sha256:308da8d305e125c2e5d35a97bd7e2cd32ab3f255635c5c67116cfc4c09c10bea"},"receiptVersion":1,"run":{"escalations":[],"intents":[{"intent":"OBSERVE","timestamp":120},{"asset":"BTC","confidence":0.7,"intent":"BUY","timestamp":180},{"intent":"OBSERVE","timestamp":240}],"log":[{"detail":"Drift tier=nano effects=['intent.emit', 'log.append'] warmup=2","event":"module.loaded","timestamp":0},{"detail":"n6 has no value at bar 0","event":"condition.unwarmed","timestamp":0},{"detail":"n6 has no value at bar 1","event":"condition.unwarmed","timestamp":60},{"detail":"n6 -> False","event":"condition.evaluated","timestamp":120},{"detail":"OBSERVE asset=None","event":"intent.emitted","timestamp":120},{"detail":"n6 -> True","event":"condition.evaluated","timestamp":180},{"detail":"BUY asset=BTC","event":"intent.emitted","timestamp":180},{"detail":"n6 -> False","event":"condition.evaluated","timestamp":240},{"detail":"OBSERVE asset=None","event":"intent.emitted","timestamp":240}],"warmupBarsSkipped":2}} \ No newline at end of file diff --git a/tests/golden/receipt_empty.json b/tests/golden/receipt_empty.json index b38db8b..0b5be56 100644 --- a/tests/golden/receipt_empty.json +++ b/tests/golden/receipt_empty.json @@ -1 +1 @@ -{"identity":{"compiler":{"name":"nnc","version":"1.0.0"},"effects":["intent.emit","log.append"],"irVersion":"1.0.0","module":"Drift","moduleHash":"sha256:f43458398231b977af7a1114b0e0e7760cd18a09910c9e32d178f7d8d1e45c24","nanoVersion":"1.0.12","reasoningRequired":false,"tier":"nano","warmupDeclared":2},"inputs":{"bars":0,"frameHash":"sha256:fad6747b2406c3e3e67ed553f010625725bc2f910129ed7479a1e50d5e9fdbea","signals":["close"]},"provenance":{"sourceHash":"sha256:308da8d305e125c2e5d35a97bd7e2cd32ab3f255635c5c67116cfc4c09c10bea"},"receiptVersion":1,"run":{"escalations":[],"intents":[],"log":[{"detail":"Drift tier=nano effects=['intent.emit', 'log.append'] warmup=2","event":"module.loaded","timestamp":0}],"warmupBarsSkipped":0}} \ No newline at end of file +{"identity":{"compiler":{"name":"nnc","version":"1.0.0"},"effects":["intent.emit","log.append"],"irVersion":"1.0.0","module":"Drift","moduleHash":"sha256:f43458398231b977af7a1114b0e0e7760cd18a09910c9e32d178f7d8d1e45c24","nanoVersion":"1.1.0","reasoningRequired":false,"tier":"nano","warmupDeclared":2},"inputs":{"bars":0,"frameHash":"sha256:fad6747b2406c3e3e67ed553f010625725bc2f910129ed7479a1e50d5e9fdbea","signals":["close"]},"provenance":{"sourceHash":"sha256:308da8d305e125c2e5d35a97bd7e2cd32ab3f255635c5c67116cfc4c09c10bea"},"receiptVersion":1,"run":{"escalations":[],"intents":[],"log":[{"detail":"Drift tier=nano effects=['intent.emit', 'log.append'] warmup=2","event":"module.loaded","timestamp":0}],"warmupBarsSkipped":0}} \ No newline at end of file diff --git a/tests/golden/receipt_reasoning.json b/tests/golden/receipt_reasoning.json index de0e7df..8e61bd3 100644 --- a/tests/golden/receipt_reasoning.json +++ b/tests/golden/receipt_reasoning.json @@ -1 +1 @@ -{"identity":{"compiler":{"name":"nnc","version":"1.0.0"},"effects":["intent.emit","llm.call","llmre.escalate","log.append"],"irVersion":"1.0.0","module":"Ask","moduleHash":"sha256:64f6b7772c76b293a9e5a8ddd3ddf6cb51e5fb1370cd6cd3979a5f3b6a0eabbc","nanoVersion":"1.0.12","reasoningRequired":true,"tier":"nano+","warmupDeclared":0},"inputs":{"bars":2,"firstTimestamp":0,"frameHash":"sha256:dad557a402d06845035c88d772fac0be496eb9a7099fa628a45cda7402142604","lastTimestamp":60,"signals":["close"]},"provenance":{"sourceHash":"sha256:31491116b0c6c727dedf4c7c71ce8c64d37a1d4869c7f35058ef5bf7cae2ae78"},"receiptVersion":1,"run":{"escalations":[{"escalate":"Desk","isAgent":true,"reason":"rule body","timestamp":60}],"intents":[{"asset":"BTC","intent":"BUY","timestamp":0}],"log":[{"detail":"Ask tier=nano+ effects=['intent.emit', 'llm.call', 'llmre.escalate', 'log.append'] warmup=0","event":"module.loaded","timestamp":0},{"detail":"Judge -> ['score']","event":"infer.called","timestamp":0},{"detail":"Judge -> ['score']","event":"infer.called","timestamp":60},{"detail":"n9 -> True","event":"condition.evaluated","timestamp":0},{"detail":"BUY asset=BTC","event":"intent.emitted","timestamp":0},{"detail":"n9 -> False","event":"condition.evaluated","timestamp":60},{"detail":"Desk: rule body","event":"llmre.escalated","timestamp":60}],"warmupBarsSkipped":0}} \ No newline at end of file +{"identity":{"compiler":{"name":"nnc","version":"1.0.0"},"effects":["intent.emit","llm.call","llmre.escalate","log.append"],"irVersion":"1.0.0","module":"Ask","moduleHash":"sha256:64f6b7772c76b293a9e5a8ddd3ddf6cb51e5fb1370cd6cd3979a5f3b6a0eabbc","nanoVersion":"1.1.0","reasoningRequired":true,"tier":"nano+","warmupDeclared":0},"inputs":{"bars":2,"firstTimestamp":0,"frameHash":"sha256:dad557a402d06845035c88d772fac0be496eb9a7099fa628a45cda7402142604","lastTimestamp":60,"signals":["close"]},"provenance":{"sourceHash":"sha256:31491116b0c6c727dedf4c7c71ce8c64d37a1d4869c7f35058ef5bf7cae2ae78"},"receiptVersion":1,"run":{"escalations":[{"escalate":"Desk","isAgent":true,"reason":"rule body","timestamp":60}],"intents":[{"asset":"BTC","intent":"BUY","timestamp":0}],"log":[{"detail":"Ask tier=nano+ effects=['intent.emit', 'llm.call', 'llmre.escalate', 'log.append'] warmup=0","event":"module.loaded","timestamp":0},{"detail":"Judge -> ['score']","event":"infer.called","timestamp":0},{"detail":"Judge -> ['score']","event":"infer.called","timestamp":60},{"detail":"n9 -> True","event":"condition.evaluated","timestamp":0},{"detail":"BUY asset=BTC","event":"intent.emitted","timestamp":0},{"detail":"n9 -> False","event":"condition.evaluated","timestamp":60},{"detail":"Desk: rule body","event":"llmre.escalated","timestamp":60}],"warmupBarsSkipped":0}} \ No newline at end of file diff --git a/tests/golden/receipt_tuned.json b/tests/golden/receipt_tuned.json index 3505a33..b2ff68c 100644 --- a/tests/golden/receipt_tuned.json +++ b/tests/golden/receipt_tuned.json @@ -1 +1 @@ -{"identity":{"compiler":{"name":"nnc","version":"1.0.0"},"effects":["intent.emit","log.append"],"irVersion":"1.0.0","module":"Tuned","moduleHash":"sha256:9bac1ba07ba7516c289efeac8bbd55b8d93202ba983e6127fa2ab59d7b00724f","nanoVersion":"1.0.12","params":[{"name":"window","type":"int","value":3}],"reasoningRequired":false,"tier":"nano","warmupDeclared":2},"inputs":{"bars":5,"firstTimestamp":0,"frameHash":"sha256:fe7d16ee1e9ce451bbbf20366d16d6cbd0987aed76fef08f41777ff4ce7035ab","lastTimestamp":240,"signals":["close"]},"provenance":{"sourceHash":"sha256:c243804836eecc54c7893626032216ff0b6a808738916af343d339232ad6cfcf"},"receiptVersion":1,"run":{"escalations":[],"intents":[{"asset":"BTC","intent":"BUY","timestamp":120},{"asset":"BTC","intent":"BUY","timestamp":180},{"asset":"BTC","intent":"BUY","timestamp":240}],"log":[{"detail":"Tuned tier=nano effects=['intent.emit', 'log.append'] warmup=2","event":"module.loaded","timestamp":0},{"detail":"n5 has no value at bar 0","event":"condition.unwarmed","timestamp":0},{"detail":"n5 has no value at bar 1","event":"condition.unwarmed","timestamp":60},{"detail":"n5 -> True","event":"condition.evaluated","timestamp":120},{"detail":"BUY asset=BTC","event":"intent.emitted","timestamp":120},{"detail":"n5 -> True","event":"condition.evaluated","timestamp":180},{"detail":"BUY asset=BTC","event":"intent.emitted","timestamp":180},{"detail":"n5 -> True","event":"condition.evaluated","timestamp":240},{"detail":"BUY asset=BTC","event":"intent.emitted","timestamp":240}],"warmupBarsSkipped":2}} \ No newline at end of file +{"identity":{"compiler":{"name":"nnc","version":"1.0.0"},"effects":["intent.emit","log.append"],"irVersion":"1.0.0","module":"Tuned","moduleHash":"sha256:9bac1ba07ba7516c289efeac8bbd55b8d93202ba983e6127fa2ab59d7b00724f","nanoVersion":"1.1.0","params":[{"name":"window","type":"int","value":3}],"reasoningRequired":false,"tier":"nano","warmupDeclared":2},"inputs":{"bars":5,"firstTimestamp":0,"frameHash":"sha256:fe7d16ee1e9ce451bbbf20366d16d6cbd0987aed76fef08f41777ff4ce7035ab","lastTimestamp":240,"signals":["close"]},"provenance":{"sourceHash":"sha256:c243804836eecc54c7893626032216ff0b6a808738916af343d339232ad6cfcf"},"receiptVersion":1,"run":{"escalations":[],"intents":[{"asset":"BTC","intent":"BUY","timestamp":120},{"asset":"BTC","intent":"BUY","timestamp":180},{"asset":"BTC","intent":"BUY","timestamp":240}],"log":[{"detail":"Tuned tier=nano effects=['intent.emit', 'log.append'] warmup=2","event":"module.loaded","timestamp":0},{"detail":"n5 has no value at bar 0","event":"condition.unwarmed","timestamp":0},{"detail":"n5 has no value at bar 1","event":"condition.unwarmed","timestamp":60},{"detail":"n5 -> True","event":"condition.evaluated","timestamp":120},{"detail":"BUY asset=BTC","event":"intent.emitted","timestamp":120},{"detail":"n5 -> True","event":"condition.evaluated","timestamp":180},{"detail":"BUY asset=BTC","event":"intent.emitted","timestamp":180},{"detail":"n5 -> True","event":"condition.evaluated","timestamp":240},{"detail":"BUY asset=BTC","event":"intent.emitted","timestamp":240}],"warmupBarsSkipped":2}} \ No newline at end of file