From e1c7f20104e908d3eb388a3af8a687940df17755 Mon Sep 17 00:00:00 2001 From: Yudis-bit <85178972+Yudis-bit@users.noreply.github.com> Date: Thu, 6 Aug 2026 05:29:11 +0700 Subject: [PATCH 1/2] chore: stop tracking committed __pycache__ bytecode --- .gitignore | 6 +++++- .../crp/__pycache__/__init__.cpython-310.pyc | Bin 180 -> 0 bytes .../crp/__pycache__/simulation.cpython-310.pyc | Bin 2650 -> 0 bytes .../network/__pycache__/__init__.cpython-310.pyc | Bin 188 -> 0 bytes .../crp/network/__pycache__/node.cpython-310.pyc | Bin 2086 -> 0 bytes .../__pycache__/cognitive_node.cpython-310.pyc | Bin 2921 -> 0 bytes .../__pycache__/dumb_router.cpython-310.pyc | Bin 1390 -> 0 bytes 7 files changed, 5 insertions(+), 1 deletion(-) delete mode 100644 simulation/crp/__pycache__/__init__.cpython-310.pyc delete mode 100644 simulation/crp/__pycache__/simulation.cpython-310.pyc delete mode 100644 simulation/crp/network/__pycache__/__init__.cpython-310.pyc delete mode 100644 simulation/crp/network/__pycache__/node.cpython-310.pyc delete mode 100644 simulation/crp/routing/__pycache__/cognitive_node.cpython-310.pyc delete mode 100644 simulation/crp/routing/__pycache__/dumb_router.cpython-310.pyc diff --git a/.gitignore b/.gitignore index d9952c0..6aa790b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,6 @@ # Node.js / Hardhat -contracts/node_modules/ \ No newline at end of file +contracts/node_modules/ + +# Python +__pycache__/ +*.py[cod] \ No newline at end of file diff --git a/simulation/crp/__pycache__/__init__.cpython-310.pyc b/simulation/crp/__pycache__/__init__.cpython-310.pyc deleted file mode 100644 index a7347c5d5d76fbd05f9a205a73663f5e409dde27..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 180 zcmd1j<>g`k0;zj*Gu(mnV-N=!FakLaKwQiMBvKfH88jLFRx%WUgb~EAaA&KS(Bjmh z;+Rq(8RJ`8oS7Ws=;Pz)p%5G%qU#y#pQ1D(4JnOCY?Oo|4x`iMc5NS=@67I* z$ks)D2;TxxC2#F_=_k0?KJ_agRqD*%If)}$b)_5cpV`@+`Tcgr@ytv`gZAw&zjjB^ z`x6J}n*oCd@X4=1FpZH=>k)_abVn!JBaP|Ic&9PrNOufo?rJsbF9M1+Ju@3I<5~HU zm+%8`=)>ehvtjfAKG_GsHHR?G(HQ|N%A#X3lUvN>`y12_Pe z;Ua;cL6mR-XMhozpXy`q#|`^BeCzPZSrCDiYHlte+z&PG)ysgTiZfz8r*IVl2m)8y(MBcAt^Z`hkB~xOiEU?RNsXtVE+b2Kp(BH3l5$G zP6%JbJi#bZR{`oVCTWlW$_o22=qyk{_r!1sA}B04Q{atihA3ly8boH|omB{PF@=*h zSafj#@sRlRD!L6mn-hMImHyq$?_lStn+uG0z-hl|IlnD$@(BL50{0FMjb z11`aPBljNTFG?WJhrlTpn=VFS8XYXwuEQpY_~(HrLNPz4z&Xu{XkfTcLC5U~>M_85 zLKLivJ3J8qyfp+C15Vo_?oFV$KLltc-F$coVrF!B0)U=^c=6&ktSk6#;;r!xRsD>v z=n(g^I*?`f|y5f6~zMTtHg9K|G9q= ziJ9UO3Jv)U=ohc4LToZet{bC;F@+{HCo&|)9N(&n`ESrkpul0|;8!nx^D$-={n$9s zj>tpp`3BEO`fJEgZd>$MJFLM1y@_w)8{e&`hDE-OvD6 zla=AO1iE%=v8neatE45cG_9-~CxGXNlCpC5%{*wSyRa${d}h>qg7HIkcLz|P>X5~l zw;ysUcwcY{H3murRF}9tfpkZB{jPfJ$o=y`-~Rr8w$UxBT4Q7HS##$x-D^H+ZZ#i0 zr$2A*K3&_|bk_DZn~jlCU!@<(@@O8EUo>Lik75lLtCwdekFdbi>-6>(u*F!q-yYdL zxk!I_2E)qseqYvLbrncd7M}q?SxLqs;Y?+n%zVv+X95V~?6*C~5 z>9GntN2hY;x?{l8boBj$iyWJUn%xh*p*t?}cfpMO3WN-J(c2(e#v-8Ta-ELO^{%VOVk1y+d6kcm+BMO=cR zFi>1ZfzK+l+F|S^nE`AN*Kqa=6j-{?2`oNB6ryFz5oCK diff --git a/simulation/crp/network/__pycache__/__init__.cpython-310.pyc b/simulation/crp/network/__pycache__/__init__.cpython-310.pyc deleted file mode 100644 index 98e90cbb16c0132bc62c7bd521267bd555fd522a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 188 zcmd1j<>g`k0=;{4GyH+{V-N=!FakLaKwQiMBvKfH88jLFRx%WUgb~EAcxS7a(Bjmh z;+Rq(8RJ`8oS7Ws=;Pz)p%5G%qU#y#9YUZm>u~YU+qkr4&@bvf7!o#$D~IGb6iF zOY(J?{2> z?uk+i3%qn*>X&&Lwkx8-tD+iLc#YQ~t?>rGaqjf%yb0T_ywuIOnE%yaSl@_=5?Z82 zvyf>MraV-frBGlpWo9JUWAS{y%Ti%ZGWElby|i!GIFzXY(KRk3BeOJAGnU0n!W5TE zL z1(HV|axUS857iLLy?Q7D>o`Te6W z2H$F-^k51;csA8C8gvd0I$yEgcQ3a0dk39o?CU2_o^^Vi?jXtzQ)%R}*jCxp$ngCl0l>~Gwrt%GRX7eA}nuQL8mzBwi~3DhGP)~c_RqM8J{Nf-3)>sr(v=G5m*XT0 zP41(kZO+uz>hC`t@fLsQ~wPRZRU-zhg+RvtlgZ7qSScOZUyWW97^*N&~G9a|L) zsLD%N?^luGYF>Scd2kZWLI;n&V^mE#4?uh8eOU350ao}!bsmzVVv(6ohCG%7CKydDHL1c1uc*ES0w;S(}O=-PDWn~VIf zX4C(6h@uWbPkg@C6E=Q|@ZFt2MOfI^JM-q^({_WRj_oR%Z909Q*d1aY5W7o^LbTYSbr a5$tBoy;Uyr+HTQ&4@u3=`VIf~z5f7SIRbP5 diff --git a/simulation/crp/routing/__pycache__/cognitive_node.cpython-310.pyc b/simulation/crp/routing/__pycache__/cognitive_node.cpython-310.pyc deleted file mode 100644 index 722a873de06672f9b3174b6da1c996bda0b0be6a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2921 zcmaJ@TW=f36`t7(xui*1k>&W-6w{=LwQVKDFAZ9#Mrb)moLcMy;}%#bSd4at+oJZPf&PvDiGA&p|3Y8fbA}h0Y0&}Z>|D>zobR0POwn#P36xi# z{C&7{jgWs~=l$YA=L@JBg&=}vB$|I|M1>>V%o(|nOUYM6c*4IV!k6w#H}arg6Lsj< zr3Zaq&>jhcx1fb|-#Q>eT6x_<$OMPpFSSKS_n{#P{Dwr1pph#a>GhrONuLT=c$Y0u z>f=vjO$4&uui2S~Xu?b&wna;Nq76Gdu_3Ns`cXq{!pH}*1|wVI#-$fEzb77vuED`> zR_%jgkf$a+mw2e@Kbs6nCueDHWR|4^nHzR4l}?MC6@A7TE@NiM4V!4GVc>9*nRK_K zMpCdxJQt~9JBOV|A>-MgP^lS?tWHy~5kHko6%&)@0|pjIQLEl#PYlZ>SGi^d{EC@$ zB-zC0o$VD2)pQ107~4t-52W4Fgq4F@jUKQjOPhM1wV?gpE6=s-VC@c%M@p`ye{}RN~ zgr!ruuOS>tdg7Gi#673#jv5A57c!On(xcnu*HSyb}M5uvwG-0~$7*!E~1a7?M0DFX_xF9lask9{8w7PN?ucCk}~e z={zRiU7xwI4$OZCI0$O()KQ<7u0tqz@!2im&OA|{`F8E6S8Hdr66oU&nbnQ^$`cKc zKInm1*d{Oon(mR;bQYBLGPp%%jj~btr=IGS4bTNT&vr`yGi*+eY{VgJ^kgOzGsiQR z&kY+EV;~6(b_DF%!J`LPobU_A&x=$nC(%r4G11I=@=9fbA-F6UzvzHBpz7No24Iix zf*C~cpUA1JoRa?8Idggo$PhR11ZVHF$jwvnhN_z|as_AA+|N>t1TubzY@kv9Z8CkZ zj%P9~3N68Bo|_mhw6~uX2{`9NXe@Vk-{LXV77A>=eFsJ1F%{|zYgJ?Ea#}TT7#*nc zM%)a6GtQK$+^iUc&AAieF{2y&oTnK-&hXa@60EK*o8U}Q8!2!#88t@yd90H{$tvJ# zWcexD;1FeeAmcedMw{~aI4cx4K)kV$Y7{jl$?<&K+%jla>+RL`AKd&F%;+5u+rH;` zbi)bUEgDego#%NpaGFqm4E+G+JnH<>bEY5tUrSb7@B=OL)fE;If<&HRG%O272jYGJ zReuYj1eQJ_Krwa9uGlUqc(PkUs`LrOfcrUw(>}pIjC=6);OmzV1*LzRl-@l8J`E9o zGeAq2qy6dcS8n%g3{Y<}hy^Dy2AGcqL;nVzFFb72*k8d`jl9(aESk=y z#bJ}S==9z?25Y-Q+6`Nn*K$6Rkk^`VJSxNlTrRF!aeOx6*0B9+M}0Y_hRn zULguNC^=Sf{0-{H8*k9*ogXTL{5@aQ4Sj{ts6rG!L-BJI4^UjGUg=k#!Nk{4?b`rN z-lBFatf`M+7?KmD{9+Wfa%nCKb-IUCY@Y=d6T9|*DXxP3xz{{I<7m8EKmyuwHl6K9 F{{g^Z)EEE& diff --git a/simulation/crp/routing/__pycache__/dumb_router.cpython-310.pyc b/simulation/crp/routing/__pycache__/dumb_router.cpython-310.pyc deleted file mode 100644 index cd3cb125f8c19f49ab50b2bd49e7b199f37d7fb0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1390 zcmZWpTaVjB6rLG7H*Z2ARG^}&8ueuxm8^I~tAZMJi&(Ln2U3I-8AXm~eAzf2@632t zD@`P%_J1^a1Ut0+MZV!jcg~LmD z)DzekVmL!n#0baC;W%=c%Np<8DPeem2F*Xg292wp(t*^oTrfUMS#`v7wm*c9HQB8m zyx~st3LfmN& z_`@@M^BLx1srfVAOmhp6(Id3s@BeH>bAE5;TyRK#l`iQw(q-8K@1djvEy@NVa4Bx7}2d$a^|AR^@Alv?-W?SYE<6%REHMXrN1x4diwQJG~lmO+u6 z`~&}27i^uJpVjyvJ3}|X;Yzq#>iA0&REmC5bgsQbGOyz+6c;Hoz;<{=iJSeWGE&D1& zQ8@u)RU6V$&sWvSc^W5kAyw5#HD9XA0bSLoZ=SYmRH>3duWIdTE1?;Yv_m;1*6~fM z0LZ2v>|1hXTT)5;8<;)_ODQ2)`(dtJtDJTZ#nsWCgB^XZkfPvFXs)K9xSj2y`US~8 zc>HVr>eT;1L9hBH?EWP*dgzZXE=J$d$&YV_=aY-kCH?O8>&ww(H1f*;v7xyvw+5MyYnS2P4fg|ld3+ka|EvO?o*gm$}_KT%pWyZg@#Z)$X IZS)EG8^>jhEC2ui From 26d3326cb1a792c816a116bddc9ca0d36375bda2 Mon Sep 17 00:00:00 2001 From: Yudis-bit <85178972+Yudis-bit@users.noreply.github.com> Date: Thu, 6 Aug 2026 05:29:11 +0700 Subject: [PATCH 2/2] test: add simulation smoke tests and CI; document cognitive-router delivery trade-off The prototype had no test coverage or CI, tracked six stale .pyc files, and its README reported the latency and congestion-avoidance results without noting that the cognitive router delivers only ~24% of packets in the seeded reference run (1000 packets, MAX_HOPS=25). - simulation/tests/test_simulation_smoke.py: end-to-end smoke tests for run_cognitive_sim (200-packet run: completion, dumb-router 100% delivery, cognitive congested-link usage <5%, positive latency gain) and run_baseline_sim (west-to-east route found) - .github/workflows/ci.yml: run the smoke tests on push and PR - README: report the delivery-rate trade-off next to the headline latency claim and point at both sim scripts and the tests Verified: python3 -m unittest discover -s tests passes (6 tests). --- .github/workflows/ci.yml | 23 +++++++ README.md | 3 +- simulation/tests/__init__.py | 0 simulation/tests/test_simulation_smoke.py | 73 +++++++++++++++++++++++ 4 files changed, 98 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/ci.yml create mode 100644 simulation/tests/__init__.py create mode 100644 simulation/tests/test_simulation_smoke.py diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..d643f7c --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,23 @@ +name: ci + +on: + push: + branches: [main] + pull_request: + +permissions: + contents: read + +jobs: + simulation-tests: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - uses: actions/setup-python@v5 + with: + python-version: "3.12" + + - name: Run simulation smoke tests + working-directory: simulation + run: python3 -m unittest discover -s tests -p "test_*.py" -v diff --git a/README.md b/README.md index 392c724..51bf091 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,8 @@ The Python prototype in this repository has successfully validated the core hypo * **Adaptive Routing:** The Cognitive Router successfully learned to **dynamically avoid a congested network link**, using it less than **0.1%** of the time, compared to the Dumb Router which was stuck in congestion nearly **40%** of the time. * **Performance Gains:** By avoiding these bottlenecks, the Cognitive Router achieved **~22% lower average latency** for successful packet deliveries, proving its ability to optimize for overall network health. -* **Full Analysis:** The complete comparative simulation can be run via the `simulations/run_cognitive_sim.py` script. +* **Known Trade-off:** In the seeded reference run, the Cognitive Router's exploration behaviour delivers only **~24% of packets** (the Dumb Router delivers 100%); the latency figure above is computed over successful deliveries only. These results demonstrate adaptive behaviour, not production readiness — closing the delivery gap is future work (see issue tracker). +* **Full Analysis:** The complete comparative simulation can be run via the `simulations/run_cognitive_sim.py` script; `simulations/run_baseline_sim.py` runs the Dijkstra-only baseline. Smoke tests for both live under `simulation/tests/`. ## Full Project Architecture diff --git a/simulation/tests/__init__.py b/simulation/tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/simulation/tests/test_simulation_smoke.py b/simulation/tests/test_simulation_smoke.py new file mode 100644 index 0000000..4c69d26 --- /dev/null +++ b/simulation/tests/test_simulation_smoke.py @@ -0,0 +1,73 @@ +"""Smoke tests for the CRP simulation scripts. + +These run the shipped entry points end to end with a reduced packet count +and assert the behavioural properties the README advertises, so that future +changes to the routing or network code cannot silently break the prototype's +reference results. +""" +import contextlib +import io +import os +import re +import sys +import unittest + +sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))) + +from simulations import run_baseline_sim, run_cognitive_sim + +PACKETS = 200 + + +def run_sim(module): + """Run a sim main() with a small packet budget and capture stdout.""" + module.NUM_PACKETS = PACKETS + buf = io.StringIO() + with contextlib.redirect_stdout(buf): + module.main() + return buf.getvalue() + + +class CognitiveSimSmokeTest(unittest.TestCase): + @classmethod + def setUpClass(cls): + cls.output = run_sim(run_cognitive_sim) + + def test_simulation_completes(self): + self.assertIn("[SUCCESS] Phase 4: Comparative analysis complete.", self.output) + + def test_dumb_router_delivers_all_packets(self): + self.assertIn(f"Success Rate: 100.00% ({PACKETS}/{PACKETS})", self.output) + + def test_cognitive_router_avoids_congested_link(self): + # Second "Trips through Congested Link" line is the cognitive router. + trips = re.findall(r"Trips through Congested Link: (\d+)/", self.output) + self.assertEqual(len(trips), 2) + cognitive_trips = int(trips[1]) + self.assertLess( + cognitive_trips / PACKETS, + 0.05, + "cognitive router should use the congested link in <5% of trips", + ) + + def test_cognitive_router_reports_latency_gain(self): + match = re.search(r"Performance Improvement \(Lower Latency\): ([\d.]+)%", self.output) + self.assertIsNotNone(match, "expected a latency improvement summary line") + self.assertGreater(float(match.group(1)), 0.0) + + def test_cognitive_router_delivers_some_packets(self): + match = re.search(r"COGNITIVE ROUTER \(CRP\) ---\n Success Rate: ([\d.]+)%", self.output) + self.assertIsNotNone(match) + self.assertGreater(float(match.group(1)), 0.0) + + +class BaselineSimSmokeTest(unittest.TestCase): + def test_baseline_finds_west_to_east_route(self): + output = run_sim(run_baseline_sim) + self.assertIn("GATEWAY_WEST", output) + self.assertIn("GATEWAY_EAST", output) + self.assertIn("[SUCCESS] Phase 2: Baseline 'Dumb' Router executed.", output) + + +if __name__ == "__main__": + unittest.main()