Skip to content

Commit f495f27

Browse files
author
JonesRobM
committed
Fixing ci/cd workflows
1 parent ae22902 commit f495f27

7 files changed

Lines changed: 56 additions & 34 deletions

File tree

.github/workflows/ci.yml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ jobs:
1212
steps:
1313
- uses: actions/checkout@v4
1414
- uses: astral-sh/setup-uv@v5
15+
with:
16+
python-version: "3.12"
1517
- run: uv sync --all-extras
1618
- run: uv run ruff check src/ tests/
1719
- run: uv run ruff format --check src/ tests/
@@ -21,6 +23,8 @@ jobs:
2123
steps:
2224
- uses: actions/checkout@v4
2325
- uses: astral-sh/setup-uv@v5
26+
with:
27+
python-version: "3.12"
2428
- run: uv sync --all-extras
2529
- run: uv run mypy src/physbound/
2630

@@ -38,7 +42,7 @@ jobs:
3842
- run: uv run pytest tests/ -v --tb=short --cov=physbound --cov-report=xml --cov-report=term-missing
3943
- name: Upload coverage
4044
if: matrix.python-version == '3.12'
41-
uses: codecov/codecov-action@v4
45+
uses: codecov/codecov-action@v5
4246
with:
4347
file: coverage.xml
4448
fail_ci_if_error: false

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ wheels/
1919
.mypy_cache/
2020
.pytest_cache/
2121
.ruff_cache/
22+
.hypothesis/
2223
.secrets.baseline
2324

2425
# IDE

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,9 @@ LLMs routinely hallucinate physics. PhysBound catches it:
3131
| 4 | Thermal Noise | "Noise floor of -180 dBm/Hz at room temperature" | Actual: **-174.0 dBm/Hz** at 290K | CAUGHT |
3232
| 5 | Link Budget | "Wi-Fi at 2.4 GHz reaches 10 km at -40 dBm" | Actual RX power: **-94.1 dBm** | CAUGHT |
3333
| 6 | Link Budget | "1W to GEO with 0 dBi antennas at -80 dBm" | Actual RX power: **-175.1 dBm** | CAUGHT |
34-
| 7 | Link Budget | "Bluetooth reaches 1 km at -60 dBm" | Actual RX power: **-100.0 dBm** | CAUGHT |
34+
| 7 | Link Budget | "Bluetooth reaches 1 km at -60 dBm" | Actual RX power: **-100.1 dBm** | CAUGHT |
3535
| 8 | Shannon-Hartley | "10 MHz LTE at 10 dB SNR supports 1 Gbps" | Shannon limit: **34.6 Mbps** | CAUGHT |
36-
| 9 | Noise Cascade | "Stage order doesn't affect system NF" | LNA first: **1.57 dB** vs mixer first: **8.03 dB** | CAUGHT |
36+
| 9 | Noise Cascade | "Stage order doesn't affect system NF" | LNA first: **1.66 dB** vs mixer first: **8.03 dB** | CAUGHT |
3737
| 10 | Antenna Aperture | "10 cm patch at 900 MHz provides 20 dBi" | Aperture limit: **-3.1 dBi** | CAUGHT |
3838

3939
*Generated automatically by `pytest tests/test_marketing.py -s`*

examples/catching-hallucinations.md

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,9 @@ PhysBound's `shannon_hartley` tool is called automatically:
2727
"error": true,
2828
"violation_type": "PhysicalViolationError",
2929
"law_violated": "Shannon-Hartley Theorem",
30-
"message": "Claimed throughput 500000000.0 bps exceeds Shannon limit of 100584898.2 bps by 397.1%",
30+
"message": "Claimed throughput 500000000.0 bps exceeds Shannon limit of 100556153.5 bps by 397.2%",
3131
"latex_explanation": "$C = B \\log_2(1 + \\text{SNR}) = 100.6\\,\\text{Mbps} < 500.0\\,\\text{Mbps}$",
32-
"computed_limit": 100584898.2,
32+
"computed_limit": 100556153.5,
3333
"claimed_value": 500000000.0,
3434
"unit": "bps"
3535
}
@@ -125,16 +125,16 @@ PhysBound's `noise_floor` tool with cascading:
125125

126126
```json
127127
{
128-
"thermal_noise_dbm": -104.0,
129-
"thermal_noise_watts": 4.0e-14,
130-
"cascaded_noise_figure_db": 1.57,
131-
"system_noise_temp_k": 126.42,
132-
"receiver_sensitivity_dbm": -92.43,
133-
"human_readable": "Thermal Noise Floor:\n Temperature: 290.0 K\n Bandwidth: 10.000 MHz\n Noise Power: -104.00 dBm (4.00e-14 W)\n Cascaded NF: 1.57 dB\n Sensitivity: -92.43 dBm"
128+
"thermal_noise_dbm": -103.98,
129+
"thermal_noise_watts": 3.99e-14,
130+
"cascaded_noise_figure_db": 1.66,
131+
"system_noise_temp_k": 135.03,
132+
"receiver_sensitivity_dbm": -92.31,
133+
"human_readable": "Thermal Noise Floor:\n Temperature: 290.0 K\n Bandwidth: 10.000 MHz\n Noise Power: -103.98 dBm (3.99e-14 W)\n Cascaded NF: 1.66 dB\n Sensitivity: -92.31 dBm"
134134
}
135135
```
136136

137-
The Friis noise cascade shows that the LNA's low noise figure dominates — the 8 dB mixer NF is suppressed by the LNA's 20 dB gain to contribute only ~0.07 dB to the system NF. This is why **LNA-first order matters** in receiver design.
137+
The Friis noise cascade shows that the LNA's low noise figure dominates — the 8 dB mixer NF is suppressed by the LNA's 20 dB gain to contribute only ~0.16 dB to the system NF. This is why **LNA-first order matters** in receiver design.
138138

139139
---
140140

tests/test_marketing.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@
8383
"category": "Noise Cascade",
8484
},
8585
{
86-
"id": "small_antenna_c_band",
86+
"id": "small_antenna_uhf",
8787
"hallucination": "A 10 cm patch antenna at 900 MHz provides 20 dBi gain",
8888
"truth": None,
8989
"category": "Antenna Aperture",
@@ -228,7 +228,7 @@ def test_cascade_order_matters(self):
228228

229229

230230
class TestAntennaHallucinations2:
231-
def test_small_antenna_c_band(self):
231+
def test_small_antenna_uhf(self):
232232
"""LLMs overestimate gain for small antennas at low frequencies."""
233233
with pytest.raises(PhysicalViolationError, match="Aperture"):
234234
compute_link_budget(

tests/test_properties.py

Lines changed: 22 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
import math
88

99
import pytest
10-
from hypothesis import given, settings
10+
from hypothesis import assume, given, settings
1111
from hypothesis import strategies as st
1212

1313
from physbound.engines.link_budget import free_space_path_loss_db, max_aperture_gain_dbi
@@ -49,6 +49,7 @@ def test_db_to_linear_roundtrip(self, x):
4949
@given(x=positive_linear, y=positive_linear)
5050
def test_db_preserves_ordering(self, x, y):
5151
"""dB conversion preserves ordering: if x > y then dB(x) > dB(y)."""
52+
assume(x > y * 1.001 or y > x * 1.001) # require meaningful separation
5253
if x > y:
5354
assert linear_to_db(x) > linear_to_db(y)
5455
elif x < y:
@@ -67,18 +68,20 @@ class TestFSPLProperties:
6768
@given(f=positive_freq, d1=positive_dist, d2=positive_dist)
6869
def test_fspl_increases_with_distance(self, f, d1, d2):
6970
"""FSPL is monotonically increasing with distance at fixed frequency."""
70-
if d1 < d2:
71-
assert free_space_path_loss_db(f, d1) < free_space_path_loss_db(f, d2)
71+
assume(d2 > d1 * 1.001)
72+
assert free_space_path_loss_db(f, d1) < free_space_path_loss_db(f, d2)
7273

7374
@given(d=positive_dist, f1=positive_freq, f2=positive_freq)
7475
def test_fspl_increases_with_frequency(self, d, f1, f2):
7576
"""FSPL is monotonically increasing with frequency at fixed distance."""
76-
if f1 < f2:
77-
assert free_space_path_loss_db(f1, d) < free_space_path_loss_db(f2, d)
77+
assume(f2 > f1 * 1.001)
78+
assert free_space_path_loss_db(f1, d) < free_space_path_loss_db(f2, d)
7879

7980
@given(f=positive_freq, d=positive_dist)
80-
def test_fspl_always_positive(self, f, d):
81-
"""FSPL is always a positive loss (in dB)."""
81+
def test_fspl_positive_in_far_field(self, f, d):
82+
"""FSPL is positive when the link is in the far field (d > wavelength)."""
83+
wavelength = 299_792_458 / f
84+
assume(d > wavelength)
8285
assert free_space_path_loss_db(f, d) > 0
8386

8487
@given(f=positive_freq, d=positive_dist)
@@ -97,14 +100,14 @@ class TestShannonProperties:
97100
@given(bw=positive_bw, snr1=positive_snr, snr2=positive_snr)
98101
def test_capacity_increases_with_snr(self, bw, snr1, snr2):
99102
"""Shannon capacity increases with SNR at fixed bandwidth."""
100-
if snr1 < snr2:
101-
assert channel_capacity_bps(bw, snr1) < channel_capacity_bps(bw, snr2)
103+
assume(snr2 > snr1 * 1.001)
104+
assert channel_capacity_bps(bw, snr1) < channel_capacity_bps(bw, snr2)
102105

103106
@given(snr=positive_snr, bw1=positive_bw, bw2=positive_bw)
104107
def test_capacity_increases_with_bandwidth(self, snr, bw1, bw2):
105108
"""Shannon capacity increases with bandwidth at fixed SNR."""
106-
if bw1 < bw2:
107-
assert channel_capacity_bps(bw1, snr) < channel_capacity_bps(bw2, snr)
109+
assume(bw2 > bw1 * 1.001)
110+
assert channel_capacity_bps(bw1, snr) < channel_capacity_bps(bw2, snr)
108111

109112
@given(bw=positive_bw, snr=positive_snr)
110113
def test_capacity_always_positive(self, bw, snr):
@@ -134,14 +137,14 @@ class TestNoiseProperties:
134137
@given(t=positive_temp, bw1=positive_bw, bw2=positive_bw)
135138
def test_noise_increases_with_bandwidth(self, t, bw1, bw2):
136139
"""Thermal noise increases with bandwidth."""
137-
if bw1 < bw2:
138-
assert thermal_noise_power_dbm(bw1, t) < thermal_noise_power_dbm(bw2, t)
140+
assume(bw2 > bw1 * 1.001)
141+
assert thermal_noise_power_dbm(bw1, t) < thermal_noise_power_dbm(bw2, t)
139142

140143
@given(bw=positive_bw, t1=positive_temp, t2=positive_temp)
141144
def test_noise_increases_with_temperature(self, bw, t1, t2):
142145
"""Thermal noise increases with temperature."""
143-
if t1 < t2:
144-
assert thermal_noise_power_dbm(bw, t1) < thermal_noise_power_dbm(bw, t2)
146+
assume(t2 > t1 * 1.001)
147+
assert thermal_noise_power_dbm(bw, t1) < thermal_noise_power_dbm(bw, t2)
145148

146149
@given(bw=positive_bw)
147150
def test_noise_at_290k_anchored(self, bw):
@@ -158,14 +161,14 @@ class TestApertureProperties:
158161
@given(d=diameter, f1=positive_freq, f2=positive_freq)
159162
def test_gain_increases_with_frequency(self, d, f1, f2):
160163
"""Aperture gain increases with frequency (shorter wavelength)."""
161-
if f1 < f2:
162-
assert max_aperture_gain_dbi(d, f1) < max_aperture_gain_dbi(d, f2)
164+
assume(f2 > f1 * 1.001) # require meaningful separation
165+
assert max_aperture_gain_dbi(d, f1) < max_aperture_gain_dbi(d, f2)
163166

164167
@given(f=positive_freq, d1=diameter, d2=diameter)
165168
def test_gain_increases_with_diameter(self, f, d1, d2):
166169
"""Aperture gain increases with antenna diameter."""
167-
if d1 < d2:
168-
assert max_aperture_gain_dbi(d1, f) < max_aperture_gain_dbi(d2, f)
170+
assume(d2 > d1 * 1.001) # require meaningful separation to avoid FP equality
171+
assert max_aperture_gain_dbi(d1, f) < max_aperture_gain_dbi(d2, f)
169172

170173
@given(d=diameter, f=positive_freq)
171174
def test_doubling_diameter_adds_6db(self, d, f):

uv.lock

Lines changed: 15 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)