From 7417c84b8ab1c34dac9d953b77137ce31fb3040b Mon Sep 17 00:00:00 2001 From: DBarr3 <143002219+DBarr3@users.noreply.github.com> Date: Wed, 19 Aug 2026 18:19:02 -0400 Subject: [PATCH 1/3] fix(catalog): preserve generated artifact LF bytes --- .gitattributes | 1 + 1 file changed, 1 insertion(+) create mode 100644 .gitattributes diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..9f69ebc --- /dev/null +++ b/.gitattributes @@ -0,0 +1 @@ +nano/library/catalog/strategy_metadata_v1.json text eol=lf From c3c09113506c3065f7af3a50ef3616b7d0747356 Mon Sep 17 00:00:00 2001 From: DBarr3 <143002219+DBarr3@users.noreply.github.com> Date: Wed, 19 Aug 2026 18:22:05 -0400 Subject: [PATCH 2/3] fix(catalog): refresh canonical artifact bytes --- nano/library/catalog.py | 6 +++++- nano/library/catalog/strategy_metadata_v1.json | 1 + tests/test_catalog.py | 2 ++ 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/nano/library/catalog.py b/nano/library/catalog.py index de954cf..d138db8 100644 --- a/nano/library/catalog.py +++ b/nano/library/catalog.py @@ -579,7 +579,11 @@ def build_catalog(library_root: Optional[Any] = None) -> dict[str, Any]: def render_catalog(document: Mapping[str, Any]) -> str: """Render a catalog with one canonical byte representation.""" - return json.dumps(document, ensure_ascii=False, indent=2) + "\n" + # The separator after the root opener is part of the byte contract. It + # changes the blob when the LF-only Git attribute first lands, forcing old + # Windows checkouts to replace an already-materialized CRLF copy. + rendered = json.dumps(document, ensure_ascii=False, indent=2) + return rendered.replace("{\n", "{\n\n", 1) + "\n" def generate_catalog_text(library_root: Optional[Any] = None) -> str: diff --git a/nano/library/catalog/strategy_metadata_v1.json b/nano/library/catalog/strategy_metadata_v1.json index 7b51c0b..636f96f 100644 --- a/nano/library/catalog/strategy_metadata_v1.json +++ b/nano/library/catalog/strategy_metadata_v1.json @@ -1,4 +1,5 @@ { + "type": "NanoStrategyCatalog", "schemaVersion": 1, "metadataVersion": "StrategyMetadataV1", diff --git a/tests/test_catalog.py b/tests/test_catalog.py index 863c63a..739b6d5 100644 --- a/tests/test_catalog.py +++ b/tests/test_catalog.py @@ -96,6 +96,8 @@ def test_checked_in_catalog_is_byte_identical_and_counts_the_landed_corpus(): document = json.loads(first) assert first == second + assert first.startswith("{\n\n") + assert first.endswith("}\n") assert catalog_path(LIBRARY).read_bytes() == first.encode("utf-8") assert document["strategyCount"] == 53 assert document["irMaturityCounts"] == {"baseline": 41, "v1": 12} From d1561f50d18fb13b7e383d8ddc7ba36e18ac6542 Mon Sep 17 00:00:00 2001 From: DBarr3 <143002219+DBarr3@users.noreply.github.com> Date: Wed, 19 Aug 2026 18:24:15 -0400 Subject: [PATCH 3/3] chore(release): publish 1.0.6 --- nano/__init__.py | 2 +- pyproject.toml | 2 +- tests/golden/receipt_drift.json | 2 +- tests/golden/receipt_empty.json | 2 +- tests/golden/receipt_reasoning.json | 2 +- tests/golden/receipt_tuned.json | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/nano/__init__.py b/nano/__init__.py index 57b4482..db48342 100644 --- a/nano/__init__.py +++ b/nano/__init__.py @@ -26,4 +26,4 @@ artifact cannot change behavior because a transitive dependency did. """ -__version__ = "1.0.5" +__version__ = "1.0.6" diff --git a/pyproject.toml b/pyproject.toml index 1d57761..99b2203 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "aether-nano" -version = "1.0.5" +version = "1.0.6" description = "A deterministic strategy DSL and reference runtime for host-governed decision rules." readme = "README.md" license = { text = "MIT" } diff --git a/tests/golden/receipt_drift.json b/tests/golden/receipt_drift.json index 35fc056..91463a4 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.5","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.0.6","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 856bd05..ed82cce 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.5","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.0.6","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 3e5f429..bec3682 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.5","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.0.6","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 bb5140b..2a712dc 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.5","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.0.6","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