Repository navigation
NetGraph-Core 0.12.0: the rebuilt engine - #12
Merged
Merged
Conversation
…, from_hops, cost metadata) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…review artefacts Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…ow core Delete the old library (FlowState, the old FlowGraph and FlowPolicy, the backend, the old search entry points and their bindings: 411 symbols, 65 files) and build the first piece of the streamlined Core against APPROACH revision 25: - StrictMultiDiGraph(num_nodes, src, dst, capacity_units, cost, resolution): capacities as int64 units of an explicit resolution, costs >= 1, edges in the canonical (src, cost, dst, input) order so the forward CSR slot is the public EdgeId, input_index() as the only map, to_units (half up) and as_float, validation in the contract's order (resolution, unit values, shapes, costs, bounds) before any narrowing. - The flow core: successive shortest paths with potentials on reduced costs, Dinic phases per tier, forward and reverse arcs interleaved in ascending EdgeId at every node, virtual terminals, a fresh solve from zero on the view, the two-branch behaviour for an input cap of 0, the closure seeded at the real sources; exposed to the recorder through the private _place_global_units entry with the typed payload (placed, cost_distribution, edge_flows, min_cut, potentials with NEVER_REACHED = -1, six int64 counters). - 38 C++ tests (every validation error, B′ order, the review witnesses: attained value, update-before-drain, two Dinic phases in one tier, the legal maximum, the zero-view cap, masks and cost factors) and 154 Python tests. Gates (dev/design/2026-10-streamline/gates/1a/, uncommitted design tree): workspace check and sanitizers green; independent oracle population 3,821 pass / 0 fail; cross-check against the Python reference on 30,000 random graphs identical; the equivalence run against the G0 baseline 0 failures under the 1a manifest rules; inventory: 0 Core callers of any deleted symbol (NetGraph callers pending until Phase 2); construction and max-flow A/B/A rows 23 to 48 percent faster than df3b894. Reviewed adversarially (review-1a, review-1a-fixes): D1 to D4 fixed or settled in the contract. NetGraph is red from this commit until its migration converges (Phase 2), by decision of 2026-10-04. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…search Build the second piece of the streamlined Core on the 1a graph and flow core, against APPROACH revision 27: - FlowGraph: the integer ledger (records as snapshots in FlowId order, residual and allocated views, bottleneck over member edges, reset only unbound), the lifetime table (bound without flows, bound with flows, orphaned records; copy, move, destroy), epochs, ids never reused; a staged, exception-safe commit (every throwing step before one no-throw publication, an epoch-stamped touched set, all-or-nothing scratch growth) with fault-injection tests. - The three kernels in units: MaxFlow as a fresh minimum-cost solve on the view V_i = R0 + own_i with arcs in B' order; Weighted with membership by priority at creation, frozen weights and highest-averages apportionment; EqualBalanced with round robin on a fixed cohort; Admission.Lossy on EB and Weighted (per-call offers, transit drops, +inf injection); split-graph pruning; T_max by bisection with an exact bracket and a checked 62-probe bound. - PredDAG (from_csr with complete validation, predecessors in ascending via EdgeId), Path(g, hops) with to_dag(), Eligibility with intersect. - The internal search: the unique shortest-path DAG over the eligible member graph, anycast pruning, the staged canonical single path with PathSelection projection. - Bindings, _docs.py and stubs for the public classes; 100 C++ tests and 200 Python tests. Gates (dev/design/2026-10-streamline/gates/1b/, uncommitted design tree): workspace check and sanitizers green; oracle population 3,821 pass / 0 fail; check_spf 3,820/3,820; prototype cross-check identical on 45 fixtures and 16,172 random cases; 909 corpus Manual placements equal their references; the equivalence run 0 failures under the 1b rules (no observable change before the policies of 1c); inventory: 0 Core callers of any deleted symbol; A/B/A: construction and max-flow rows 22 to 47 percent faster than df3b894, the five kernel rows 5 to 36 percent faster after the one-pass PredDAG-native route and plan builder; a per-process bimodality of the proportional-grid row (an out-of-line NodeMap::add in the flow core's subset solve whose callee-saved register reloads stalled in some process layouts) fixed by an allocation-free, noexcept, inlined add with a guard test, both grid rows unimodal (-33 and -4 percent). Reviewed adversarially (review-1b, review-1b-fixes, review-1b-fixes2, review-1b-bimodality): D1 to D3, N1, N2 and R15 fixed; D3 settled in the contract (revision 26), R16 in revision 27. NetGraph stays red until its migration converges (Phase 2). Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
…to 1c tree coherent and groomed Build the third piece of the streamlined Core on the 1a graph, the 1b ledger and kernels, against APPROACH revision 42, then make the whole 1a to 1c tree coherent and groom its public interface before 1d: - FlowPolicy with the four routing modes (CostOnly, CapacityAware, Global, Pinned), DiminishingReturns, the cost ceiling (Absolute, Stretch), explicit placement, admission and selection; place(volume, outputs) -> PlacementResult (placed, remaining, termination, local outcomes per roster source, the two event-accumulating flags, drops, the cumulative cost curve, edge flows, residual, bottleneck, min cut); remove(), records(), record(id), placed_demand(), usable_bundles(); the roster fixed at construction (9.1); the per-source transaction of 9.2 (cumulative round-robin offers, stages 1 to 4 on a per-thread working overlay, growth never repeating a route on a multipath DAG, T_max probes within the 62-probe bound); the termination reduction and the flag table of 9.4; the epoch law and lifetimes of section 8; Global as the cumulative minimum-cost flow on V = W + own with the canonical decomposition and per-source records; every output prepared before one atomic commit, including the Python result objects (all-or-nothing across worker threads and the binding, APPROACH 13, with its two stated limits: the pybind11 object machinery, and a supplied building DagCache as a memo). - Sparse record bundles over member nodes (R16): the public CSR shape on demand, unchanged supplied bundles shared, the builder's grouping by a stable counting sort. - DagCache in building mode: key (root set, direction, Eligibility uid), value the full static support, statistics (hits, misses, entries, bytes, live values), clear(). - Evaluators: capacity, batch_capacity (arguments first, then each pair completely in pair order; the lowest failing index; explicit per-pair sequences length-checked; Pinned rejected), sensitivity (Global positive-flow candidates, the other models every allowed edge of at least one unit, signed losses, unevaluable with a reason); workers with private caches allocated before any thread starts, noexcept worker bodies, every thread joined before the lowest-index failure is rethrown; the exact shortcuts (Global loss from the baseline's maximum flow, CostOnly off-route edges skipped). - One min-cost flow core with the deletion re-solve as a mode (APPROACH 2.2): the deletion state as a value, working potentials as published potentials plus the running sum of the deletion deltas, 128-bit working arithmetic within the stated bounds, the three fixed-origin repairs with the failed-search reuse; it replaces the separate warm solver and the 1b single-bundle driver (_PinnedFlow, src/pinned_flow.cpp); a one-bundle Pinned FlowPolicy stands in for the latter. - The coherence pass of the whole tree: no dead code, no wrong comment, no leaked abstraction, one implementation per rule; profiling removed; the test probes and trace behind the CMake option NETGRAPH_CORE_PRIVATE_HOOKS (OFF for wheels, ON for the development build and the tests; the OFF build exports no hook, probe or trace symbol); transactional copy assignment of the deletion state; validating constructors for every enumeration-typed option (std::invalid_argument naming the field). - The public interface groomed to one scheme: Graph (was StrictMultiDiGraph), FlowLedger (was FlowGraph) taken by FlowPolicy as ledger=, OutputOptions (was Outputs), DiminishingReturns (was Diminishing), MAX_FLOWS_PER_CALL in Python (kMaxFlowsPerCall in C++); the public headers split so each says what it holds (graph.hpp, eligibility.hpp, flow_record.hpp, flow_ledger.hpp, flow_policy.hpp, evaluators.hpp, dag_cache.hpp, options.hpp with the two placement enums, pred_dag.hpp, types.hpp); Counter128 self-contained, so no public header includes a detail/ header; the private headers and the test files on one naming scheme; the policy fixture data in tests/data/ with a maintained exporter; no alias, no re-export, no adapter of a retired spelling. - The kernel's round robin as one inline callback template (one implementation of the split; the span form a wrapper), so allocate and the Lossy step run in one pass: the coherence pass's two-pass form had cost kernel.eb.grid 11 percent against df3b894; results unchanged. - The kernel plan builder fills its arrays by index into pre-sized vectors instead of push_back: under Xcode 27's libc++ 22 the push_back form cost the kernel rows about ten percent (emplace_back's new fast-path and slow-path lambdas); results unchanged. - Bindings, _docs.py stubs and the Python package for every class and function (keyword-only configuration objects, keep-alive of ledger, Eligibility and cache, the GIL released in the evaluators); pytest collects tests/ only; 157 C++ tests (134 ordinary, 23 in the separate fault executable) and 266 Python tests, with fault-injection sweeps of every growth, publication and deletion path at 1, 2 and 4 workers and at every Python allocation position. Gates (dev/design/2026-10-streamline/gates/1c/, uncommitted design tree), on the final groomed build with the private hooks on and off: workspace check and sanitizers green; the fault executable under the sanitizers; the warning-set builds with 0 diagnostics; the literal equivalence run 0 failures (31,788 unchanged, 28,224 new-api, 14,778 rule, 13,701 new-only; the rest invalid-input, deferred to 1d or absent by rule); oracle population 13,901 pass / 0 fail (ksp and spf queries wait for 1d); every returned value checked and proven by mutation (114,222 corruptions of the accepted results, 0 undocumented survivors); inventory CHECK OK on 1,249 rows, 0 Core callers of any deleted symbol; prototype parity identical on the 1b and 1c drivers (45 and 59 fixtures, 8,412 random cases); every recorded result of the groomed build identical to the pre-grooming build's (20,960 of 20,960) and to the frozen 1c baseline; A/B/A against df3b894 on the final tree (both sides Apple clang 21 build 2100.3.34.2, Xcode 27), 15 of 15 rows: construction -43 and -52 percent, the kernels -3 to -28 (kernel.eb.grid -1.8 within tolerance), capacity -28 and -24, max-flow -13 and -14, sensitivity -8 (the deletion re-solve replacing the separate warm solver) and -92, the CapacityAware cohort rows -61 and -99.6; the new-model rows as target-versus-target A/A, 3 of 3. Reviewed adversarially (review-1c, review-1c-fixes, review-1c-r29, review-resolve 1 to 3, review-audit-1abc, review-coherence, review-coherence-rc, review-naming 1 to 4, review-grooming, review-timing-fixes): F1 to F5 fixed (a worker-thread allocation that escaped to std::terminate, Python publication after the commit, batch validation order, the explicit empty eligibility list, the Global zero call's cumulative curve); the coherence audits' findings fixed and RC1 to RC3 closed; the tooling's twelve gate holes (W11) closed by W12 before these gates ran. NetGraph stays red until its migration converges (Phase 2). Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
- Weighted quota division: a 64-bit division when the dividend fits (kernel.weighted.clos 6 to 8 percent faster). - Graph constructor: stop computing the GCD once it reaches 1 (construct.clos about 4 percent faster). Both measured A/B/A against the 1c build; every result byte-identical; a test for each. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
One traversal core now runs every search. The public spf searches from a set of roots, forward or reverse, optionally stopping at the nearest target. ksp lists the K shortest paths in the contract's order, and resolve_to_paths unfolds a DAG into paths. The DagCache gains a frozen mode that every worker of an evaluator can share. Hits are published when the call succeeds; a call ending in DagCacheMiss counts one miss. The Python bindings cover all of it, and the old search entry points are gone. CostOnly placement builds a new flow's route, record DAG and kernel plan in one pass over the cached support, with a few smaller cuts. NetGraph's MSD loop now takes about 3 % less time than 0.12 instead of 35 % more; results are unchanged. Evidence: after the independent review's fixes, the final gates pass with hooks on and off; the timed SPF rows take 9 to 82 % less time than 0.12. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The Graph constructor numbers the edges with stable counting passes instead of a full sort. Costs are ranked through a hash table that reuses the graph's own arrays; above 65,536 distinct costs, or when the table probes too long, the costs are sorted instead. Results are unchanged; construction takes 21 to 91 % less time than 0.12. An empty NumPy view from a graph accessor now also keeps its graph alive. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The bindings are split by subject, the type stub is generated from the module and checked, and docs/semantics.md states the API's rules, each with a test. A double free when a result object could not be wrapped is fixed, and inputs too large for the flow core are now refused. Dead code and the old research and timing material are gone. Results match accepted 1e with the private hooks on and off; only the field that names the producing build differs. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
One driver times the Core's rows as old build, new build, old build again on one machine, so drift shows, and checks that both builds give the same results. Its own tests run with make perf-tool-test and on one macOS CI job, so a library change that breaks the tool fails there. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- The private test hooks build on Python 3.11 (no PyErr_GetRaisedException before 3.12) and keep the exception object and its traceback. - The rank oracle uses += so the portable 128-bit test integer (MSVC) compiles. - The two large fault sweeps get a 600 s ctest timeout; they finish but run long under sanitizers on small CI machines. - The native allocation sweep accepts a failure that the standard library absorbs (GNU stable_partition's optional buffer) only with the exact reference result, state and live count; its discard control now compares a real reference result. Library code and results are unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- The few-allocations control plants a call that makes no native allocation on any platform; reset's count depends on the standard library. - The Python allocation sweep's controls advance at snapshot boundaries, so a tracer that fails before a call enters its body cannot shift them. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- spf and ksp never read capacity; only an explicit residual or a mask removes an edge. HEADROOM without a residual reads 1, or 0 on a zero-capacity edge. - CostOnly supports, rosters, cached DAGs and Stretch baselines keep zero-capacity edges. EqualBalanced still sends them their share; Weighted gives them weight 0 and never routes around them. - Pinned bundles follow the same kernel member rule. - Sensitivity lists every allowed edge; a deletion loss can be negative. - Global's minimum cut lists every allowed edge leaving the source side, zero-capacity ones included. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- A demand's sources are pooled: CostOnly ECMP and WCMP split the summed traffic once at a shared router and attribute it back to each source by highest averages. - Global and CostOnly MAX_FLOW take an origin: OPTIMIZED (one virtual source) or EQUAL (the largest total whose round-robin shares all fit). CostOnly MAX_FLOW is one solve over the union of the sources' routes. - Results drop local_outcomes and gain per-source rows, the epoch accounting, total_cost and the call_* fields; min_cut has its own request flag; NO_ACTIVE_WEIGHT is a termination. - One QueryOptions replaces CapacityOptions and SensitivityOptions; FlowRecord.placement is gone. - Timing rows for pooled sources and the equal origin. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Every computing model records what it decided as a ForwardingProgram: tunnels and split routes with whole-number weights and equal or captured source injection; controllers cut their solved flow into paths. - ForwardingProgram.from_routes builds one from given routes; Pinned forwards one without computing, replayed under its mask or stale with black holes. - Global(support=dag); WCMP weights from WeightBasis. - evaluate, replace and forward; program-based flags and per-entry records; by_tunnel and FlowRecord.entry; QueryOptions.offered. - Lossy forwarding inside one program uses nested highest averages at shared links and recalculates cycles in rounds, with a check or an explicit error. - Weight sums are exact beyond 64 bits. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
CapacityAware is now T1: every head splits its design share over N strict tunnels, each set up by CSPF on the unreserved view and holding its whole request, or down. The tunnels form a forwarding program, so Lossless, Lossy, replay and stale forwarding all work on them. The ledger keeps carried traffic and strict reservations as two separate projections. The old growth model and its options, terminations and reference fixtures are gone. Timing against the previous step: 22 rows within -7 % to +1.5 %, identical results. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Global(tunnels=Tunnels(N)) lays out the same number of single-path tunnels for every live head with one common whole-unit bandwidth: as large as possible, no larger than a finite design needs, on the cheapest routes, then with prefer_headroom on the routes that leave the most spare capacity, then one fixed tie; Tunnels(L, up_to=True) picks the smallest sufficient count. The tunnels form a forwarding program, with Tunnel.planned, T2's TunnelPlan fields, evaluators, sensitivity and failure replay. Every Global now rejects a path selection; the headroom objective is its own option. Timing against the previous step: 24 rows within -1.2 % to +1.6 %, identical results. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Every public and internal name is now final, with no alias left. Each routing model holds its own options (FlowPolicyConfig(routing, admission)); ShortestPaths() is ECMP, CentralizedTE states its source allocation, and a wrong type or a misplaced option is a TypeError when the object is built. One tie rule, RouteTieBreak, replaces PathSelection and EdgePriority. CostStretch is an exact fraction, CentralizedTE takes a support together with a tunnel count, every evaluator takes a finite offer, and ForwardingProgram.from_dag shares ShortestPaths' pooled builder. Enum getters and FlowPolicy.config no longer crash under a Python allocation failure. 155 of the contract's 168 examples run natively in C++ and Python; one is outside the input domain and 12 wait for steps 5 and 6. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
An independent audit of steps 1 to 4 in four dimensions found these, all fixed here: the Python binding of the tunnel models checked an offer before refusing the operation; an allocation failure while reading an integer, a fraction, a list result or a hash raised TypeError or RuntimeError instead of MemoryError; identity counters and the forwarding network's 32-bit positions now refuse instead of overflowing; retired empty policies no longer stay in the owner registry. Two rules implemented twice now live in one place, an old split strategy that only tests reached is gone, public texts no longer promise more than the code does, and the removed-name test reads every kind of text. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Every public entry now raises TypeError for an argument of a type it never accepts and ValueError for an accepted type with a value outside its domain; the texts stay as they were. Integer positions take any exact integer (an object with __index__, never a bool); positions that take a non-integer number take exactly int, float and NumPy numeric scalars, or a sequence or array of them, so a Decimal, a Fraction outside CostStretch or a bool among numbers is refused. The converter is one classifier with a stated order, and an allocation failure inside it is a MemoryError. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
apply_actions(ledger, actions, mode=...) runs Place, Replace and Forward actions together. ORDERED gives what the same calls one by one would give and publishes once, so an error changes nothing. SIMULTANEOUS forwards every participant at the same time on fixed routes: demands share the losses on each link, cyclic losses are solved in rounds as within one program, and a participant's black holes are its own. Black-holed traffic is dropped where it arrives in single calls too, and a tunnel or route member that can carry nothing no longer makes a link wait. A list too large for the forwarding counters is refused with an error that names the counter. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Contract r9 amendment 8: an occurrence that can carry nothing (a share of 0, a member whose whole-unit share is 0, or traffic behind a black hole of its own call or participant) takes no part in the loss rule's no-drop loads, its waits or its serial normalization. Adding such a demand, or a pooled source whose share is 0, no longer turns another demand's result into a loss-iteration error or the other way round. Results without such an occurrence are unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Every operation now converts and checks its arguments with Python's lock held, then releases it for native work: at most one cache lease, then the ledger's single gate, checks of mutable state, private computation and a publication that cannot fail. Calls on one ledger appear one at a time and different ledgers run in parallel; reads of immutable values take no lock. Cache freeze, thaw and clear are served in arrival order, so they are never starved. The free-threaded build relies on the gate and the leases alone. A call with a bad argument and a wrong state now reports the argument's error first. The frozen-cache clear message no longer asks callers to join readers. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
to_units rounds the binary64 value it is given half up, never its printed decimal. The documents and docstrings now state that rule exactly (the ties, the 2^52 and 2^53 steps, the round trip, the error of one value and of a sum), the conversion types follow contract r9, and native and Python tests pin every example. Results do not change. as_float reads an int or a NumPy integer, a subclass included, as one number before it tries the argument as a sequence, as to_units already did. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Sensitivity of the unrestricted optimized CentralizedTE maximum flow now reads each loss from the baseline's residual network: a saturated edge between different strongly connected components loses its whole flow, any other stops its repair once the loss is known. Every candidate still starts from the baseline and nothing intermediate is published. K shortest paths keeps the spur index that produced each alternative (Lawler) and skips the searches it has already done. Paths, their order and every field are unchanged. One strongly-connected-components routine now serves both sensitivity and lossy forwarding. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The A/B/A harness builds now use -falign-functions=64 on the reference and the candidate, so code placement moves timings less (global.equal.random's spread between two layouts of the same source fell from 3.5 % to 0.1 %). Wheel build flags are unchanged. Step 8 measured, and did not adopt, reuse across failure states and Global solver structure (below the 10 % profile trigger), PGO (gains under 5 %, held-out rows slower) and -march=native. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Two crashes at legal limits are gone: an integer NumPy array whose cast runs out of memory now raises MemoryError, and pooled forwarding keeps its head-label offsets at full width. The Windows test build compiles again, ThreadSanitizer runs in CI, and the failure-test comparator checks every result field. One sparse-vector helper and one weight converter replace their copies, a dead trace variant is removed and internal names follow the glossary. Documents, docstrings and stub signatures now say what the code does. Results do not change. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A ShortestPaths policy whose routes and weights read only fixed values (FEWER_HOPS or HIGHER_CAPACITY, EQUAL or WEIGHTED with capacity or explicit weights) now keeps the program it first prepared and uses it again after remove() and at replace(), instead of building it again. Choices that read free capacity still prepare afresh. Results equal a fresh preparation in every field; no API, cache or statistics change. NetGraph's MSD search (one ledger per series, remove before each probe) runs about twice as fast on the new msd.loop.epochs timing row. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
CentralizedTE without tunnels gains SourceAllocation.WEIGHTED with an explicit source_weights vector. At every total the sources inject exactly their highest-averages shares of that total; the controller carries the largest total it can at those shares, then the cheapest flow. The program keeps the declared weights, so a replay at another offer keeps the same proportions. NetGraph's controller uses it to share a destination among sources in proportion to their demands. EQUAL and OPTIMIZED results do not change. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The semantics reference, README, binding docstrings (and the generated stub) explain each rule in plain words first, then exactly, with small worked examples that run as shown. Statements that were false or too broad are corrected, implementation notes are replaced by the guarantees they serve, and the 0.12.0 changelog says what changed against 0.11.0. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Adds a Lean project with machine-checked proofs of the rule that splits whole units among members in order and of its cumulative increments, a plain explanation of each theorem with worked examples, a checker that pins every statement, CI that verifies the proofs, and a release step that publishes only the files whose proofs were checked. Nothing changes at run time, and the wheel does not need Lean. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The README says what the engine is for, its main ideas and a short Quick Start whose printed results the tests run; links are absolute so they work on PyPI. The 0.12.0 changelog splits long entries and says each change in plain words. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Remove the tests that asserted the wording of the README, changelog, docstrings and comments: the search for names removed in 0.11 with its list of exceptions, the docstring name census and literal sentence checks. The proof gate no longer fingerprints the prose it cites; it still checks the cited headings and anchors, the native source, and every proof. Documented examples still run and print what the pages show. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The changelog's unreleased section becomes 0.12.0, dated today. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The C++ test helper `finite` is renamed `design_of`: the GNU C library declares a global `finite(double)`, so calls with an integer were ambiguous on Linux. The test guard asks a free-threaded run to skip the GIL-only tests only when it collected them, and reports an unexpected skip in the same words on every build. Two concurrency tests no longer call `sys._is_gil_enabled`, which Python 3.11 and 3.12 lack. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The test that checks engine calls release the GIL needs the main thread to see at least one call of each operation in its native phase. On CI's CentOS Stream 9 with Python 3.11, 60 calls of a short operation could finish before the main thread looked. Each operation now runs up to 50 batches of 60 calls, and a sighting counts only when two snapshots show the same unfinished call; a call that keeps the GIL still fails it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…t cleanly On Python 3.11-3.13, repr() and hash() turn a failed method lookup into the default repr or a TypeError, so the sweeps now call the type's own method. Two of our reprs used repr() for a nested value and could return a wrong string with no error; they now raise MemoryError. The Python allocation hook suspends a coverage tracer for the call, the native sweep allows a free made inside libc++, the address filter accepts Windows' upper-case hex, and each fault test gets ten minutes under sanitizers. On Linux with Python 3.11 to 3.13.7, a daemon thread whose engine call or policy destructor ended during interpreter exit crashed the process. Such a thread now waits forever, as newer Pythons do, and the exiting thread still retakes the GIL. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The guard's list of tests that skip without the private hooks names the renamed repr tests and the new tracer test. The daemon-exit test holds module teardown with a clock loop: on Windows, time.sleep fails there because Python has already closed the event it waits on. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
One fault sweep took 563 seconds under AddressSanitizer on a CI runner, then passed the ten-minute limit on a slower one with the same code. Each fault test now gets thirty minutes; every attempt is kept. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This branch was successfully deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Draft. 0.12.0 is tagged and published once every CI check below passes. NetGraph 0.25.0 is built on this release.
What changes
0.12.0 replaces the 0.11 API; it is a breaking release.
README.mdgives the ideas and a Quick Start, andCHANGELOG.mdlists every change.q, so no result depends on floating-point tolerance.FlowPolicyplaces a demand on aFlowLedgerwith one routing model:ShortestPaths: ECMP or WCMP;DistributedTE: RSVP-TE-style tunnels set up by each source router;CentralizedTE: an ideal controller, optionally with the same number of equal tunnels for every source router;Pinned: replays a saved program.evaluate_demand: one demand at full capacity; withCentralizedTE, the exact maximum flow, its cost curve and its minimum cut;evaluate_pairs: many independent pairs, in parallel;evaluate_edge_failures: how much delivery each edge's failure takes away.docs/semantics.mdstates each rule, with worked examples that the tests run. The type stub is generated from the compiled module.proofs/holds machine-checked Lean proofs of the rule that splits whole units among members. CI checks them; building or using the package needs no Lean.dev/perf/compares two builds on one machine, timing the reference, the candidate, then the reference again.Checks
🤖 Generated with Claude Code