Skip to content

Commit 3ba6af8

Browse files
fix(roi): split-write checkpoint; scan-range cap; try/except sum
Complete the split-storage pattern for the offchain-deposit checkpoint. round-4 added ``read_offchain_deposits_from_disk`` for the read side of ``_save_agent_performance_summary``; this commit adds the matching ``write_offchain_deposits_to_disk`` on ``SharedState`` and rewires ``_fetch_offchain_prepaid_wei`` to use both. ``_fetch_offchain_prepaid_wei`` now sources ``state`` from ``read_offchain_deposits_from_disk`` (raw JSON, lenient on siblings) and persists via ``write_offchain_deposits_to_disk`` (raw JSON, sibling-preserving). It no longer touches ``read_existing_performance_summary`` or ``overwrite_performance_summary``, so a nested-field ``__post_init__`` raise elsewhere on disk can neither cause a spurious re-seed (sourcing) nor cascade into wiping sibling fields at write time (persistence). Split-write mirrors the split-read and closes both sides of the corruption cascade class. Scan-range cap. Added ``OFFCHAIN_MAX_SCAN_RANGE = 5000`` and clamped ``to_block = min(head_block, from_block + OFFCHAIN_MAX_SCAN_RANGE - 1)``. An agent offline for longer than the provider's ``eth_getLogs`` block-range cap (~14h+ of Gnosis blocks — a Pearl laptop closed over a weekend) previously scanned ``[checkpoint+1, head]`` which exceeded common public-provider caps (Alchemy / Infura ~10k), got rejected every cycle with ERROR performative, and the checkpoint froze. Now each cycle marches the checkpoint forward at most one chunk until it reaches head. Exception guard on the entries sum. Wrapped ``sum(int(entry["amount"]) for entry in entries)`` in ``try/except (KeyError, TypeError, ValueError)`` and routed to the malformed-response branch. Previously a shape drift on the entries wire format raised uncaught, and with ``skill_exception_policy: stop_and_exit`` in aea-config.yaml that terminated the whole agent — harder failure mode than freezing the checkpoint. Reviewer flagged my earlier "raise loudly, the ERROR performative arm catches it" reasoning as wrong; the performative gate above the sum only catches API performatives, not application exceptions inside the sum. Tests. Three model-level tests around ``write_offchain_deposits_to_disk``: sibling-field preservation with a real file round-trip; minimal file when nothing exists on disk; recovery from a truncated JSON prefix. Two behaviour-level tests: ``test_scan_range_capped_at_offchain_max_scan_range`` (long offline stretch, verify ``to_block`` clamped and checkpoint advances by one chunk); ``test_malformed_entry_shape_returns_cached_total_no_raise`` (entries missing ``amount``, verify no raise and warning routing). Existing ``TestFetchOffchainPrepaidWei`` helper reworked to mock the disk helpers and assert (via ``AssertionError`` side-effects) that the whole-summary read/write paths are NOT touched by this behaviour.
1 parent e65d64d commit 3ba6af8

14 files changed

Lines changed: 443 additions & 68 deletions

File tree

packages/packages.json

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -10,16 +10,16 @@
1010
"contract/valory/mech_prepaid_reader/0.1.0": "bafybeiaitnqi4kc2wiltj3k6a3iujxritwkh5w2a2xoff7dosoqy7p3sou",
1111
"connection/valory/polymarket_client/0.1.0": "bafybeid4eo37pka4tfhsjs6rb3knrugmokcvihust2dpfrgob56y77xd44",
1212
"skill/valory/market_manager_abci/0.1.0": "bafybeig3ak2eoimxwuupybde4napyi2jlf7pxk35se2zclikete2ni5hti",
13-
"skill/valory/decision_maker_abci/0.1.0": "bafybeig67yeaa7dnt7eqxyxmv6jo5ulwp24fu36dl3h5juovhjhajmyjpu",
14-
"skill/valory/trader_abci/0.1.0": "bafybeihxz5ephxy7wq5lvfsd5tp63typcikl6fnlkes3eo6j27w4wbr6le",
15-
"skill/valory/tx_settlement_multiplexer_abci/0.1.0": "bafybeifqnagoqwli3wstgfgyhz3pwlg5676crfsyksdgqjacdjh2p5uuuq",
13+
"skill/valory/decision_maker_abci/0.1.0": "bafybeigwwaumxabujrtouaq2sphjusnex57doqofx625zuwdyxdqh3en4e",
14+
"skill/valory/trader_abci/0.1.0": "bafybeigtsnje4cn624bm27ssrwhwctckeud6etxpixmloj4chnehbnpinq",
15+
"skill/valory/tx_settlement_multiplexer_abci/0.1.0": "bafybeigzpmxt7glz76tdm62k2mcm7drhyeomgl6euf4nbq6q2l75xopjfu",
1616
"skill/valory/staking_abci/0.1.0": "bafybeia6csjgex5zxdt6vymiaengu75lyzjdgfrnp65ewlghthiniquhje",
17-
"skill/valory/agent_performance_summary_abci/0.1.0": "bafybeigouukzr7brpnjubkluoy4whcbr4lesg6odxexj4geybapmpgmv3e",
18-
"skill/valory/check_stop_trading_abci/0.1.0": "bafybeifwkokgn36b6pijkije47ikywtoprtfap5a3kbofnmckpzhahqxui",
19-
"skill/valory/chatui_abci/0.1.0": "bafybeibpnstfaurdsneizqvdrcic3bkz57z2h3rrfy4cxnkypguonncs3i",
20-
"agent/valory/trader/0.1.0": "bafybeibaooayqfkl7vclisdyytj4li3q56a72p3m3enpnjqxnqoh6aabhi",
21-
"service/valory/trader_pearl/0.1.0": "bafybeif55hh6k6pasb3x7dyhlcmcqui7lv6f3jkrefx3dztzmscck6ual4",
22-
"service/valory/polymarket_trader/0.1.0": "bafybeieo4sirdpygxvtonxc4yss4pb534gvskzwdtjm5r5tk56rieprycy"
17+
"skill/valory/agent_performance_summary_abci/0.1.0": "bafybeiagxj4awrr7shhawqfblyhdrcpbb7rvsexxm7k2l3wp3odsmvfa7u",
18+
"skill/valory/check_stop_trading_abci/0.1.0": "bafybeieelax7wbwhpmk2vmcbackin52nahyu6wuv3dtfzmdgyvjpwibtiu",
19+
"skill/valory/chatui_abci/0.1.0": "bafybeig4qckyl7exilbd4egapsttvfrecfu4buywx632gixuvkwcjqqssu",
20+
"agent/valory/trader/0.1.0": "bafybeifgjugs6q2y6kjiecpx3zbc6igowfwlzkx6l6evkkw4vv434t5dja",
21+
"service/valory/trader_pearl/0.1.0": "bafybeih27gjrohcdoobsxq2xu2ckgcbxisth27ydjuow65jhg3cs2cap2m",
22+
"service/valory/polymarket_trader/0.1.0": "bafybeidvop66yzjn7xcl3hyam6k2ocuqksnejlawn7bq3msgpluljwdcsy"
2323
},
2424
"third_party": {
2525
"protocol/valory/acn_data_share/0.1.0": "bafybeieqisfr6lhaaesq37lk7vyaxza2h6nucshksgyo2djqfyf2saqo4i",

packages/valory/agents/trader/aea-config.yaml

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -70,15 +70,15 @@ skills:
7070
- valory/reset_pause_abci:0.1.0:bafybeifrnmlscfiki7wojs6zasppefupd2wkjyq6orhdllfppjud7isrxi
7171
- valory/termination_abci:0.1.0:bafybeih6sa2ttcvvjk7rcfn7ure2ws23kcfufssb4qmluzcfvednkfpvoi
7272
- valory/transaction_settlement_abci:0.1.0:bafybeihizaapype5sz7vlosms3nfo6jzfj4ujycuf5uthviq2otvmw6f6m
73-
- valory/tx_settlement_multiplexer_abci:0.1.0:bafybeifqnagoqwli3wstgfgyhz3pwlg5676crfsyksdgqjacdjh2p5uuuq
73+
- valory/tx_settlement_multiplexer_abci:0.1.0:bafybeigzpmxt7glz76tdm62k2mcm7drhyeomgl6euf4nbq6q2l75xopjfu
7474
- valory/market_manager_abci:0.1.0:bafybeig3ak2eoimxwuupybde4napyi2jlf7pxk35se2zclikete2ni5hti
75-
- valory/decision_maker_abci:0.1.0:bafybeig67yeaa7dnt7eqxyxmv6jo5ulwp24fu36dl3h5juovhjhajmyjpu
76-
- valory/trader_abci:0.1.0:bafybeihxz5ephxy7wq5lvfsd5tp63typcikl6fnlkes3eo6j27w4wbr6le
75+
- valory/decision_maker_abci:0.1.0:bafybeigwwaumxabujrtouaq2sphjusnex57doqofx625zuwdyxdqh3en4e
76+
- valory/trader_abci:0.1.0:bafybeigtsnje4cn624bm27ssrwhwctckeud6etxpixmloj4chnehbnpinq
7777
- valory/staking_abci:0.1.0:bafybeia6csjgex5zxdt6vymiaengu75lyzjdgfrnp65ewlghthiniquhje
78-
- valory/check_stop_trading_abci:0.1.0:bafybeifwkokgn36b6pijkije47ikywtoprtfap5a3kbofnmckpzhahqxui
78+
- valory/check_stop_trading_abci:0.1.0:bafybeieelax7wbwhpmk2vmcbackin52nahyu6wuv3dtfzmdgyvjpwibtiu
7979
- valory/mech_interact_abci:0.1.0:bafybeici5tsgtlypnyrnp5colj7katnsyjfdzt6js4xdbnpdms4232muje
80-
- valory/chatui_abci:0.1.0:bafybeibpnstfaurdsneizqvdrcic3bkz57z2h3rrfy4cxnkypguonncs3i
81-
- valory/agent_performance_summary_abci:0.1.0:bafybeigouukzr7brpnjubkluoy4whcbr4lesg6odxexj4geybapmpgmv3e
80+
- valory/chatui_abci:0.1.0:bafybeig4qckyl7exilbd4egapsttvfrecfu4buywx632gixuvkwcjqqssu
81+
- valory/agent_performance_summary_abci:0.1.0:bafybeiagxj4awrr7shhawqfblyhdrcpbb7rvsexxm7k2l3wp3odsmvfa7u
8282
- valory/funds_manager:0.1.0:bafybeicfw7qjtnlcbw6awsvxdahqu42fxsfsd3wy7mbyhcbls4l5pee3by
8383
customs:
8484
- valory/kelly_criterion:0.1.0:bafybeidme2uybzyzagky3jtosheqmpgc6b6w4rum7cdxw2fc35nnpwblfe

packages/valory/services/polymarket_trader/service.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ license: Apache-2.0
88
fingerprint:
99
README.md: bafybeichoh5tnk4qctaazcjcrxvpwc5yasodleqoeapnfapwrrdh3tm5gu
1010
fingerprint_ignore_patterns: []
11-
agent: valory/trader:0.1.0:bafybeibaooayqfkl7vclisdyytj4li3q56a72p3m3enpnjqxnqoh6aabhi
11+
agent: valory/trader:0.1.0:bafybeifgjugs6q2y6kjiecpx3zbc6igowfwlzkx6l6evkkw4vv434t5dja
1212
number_of_agents: 1
1313
deployment:
1414
agent:

packages/valory/services/trader_pearl/service.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ license: Apache-2.0
88
fingerprint:
99
README.md: bafybeibg7bdqpioh4lmvknw3ygnllfku32oca4eq5pqtvdrdsgw6buko7e
1010
fingerprint_ignore_patterns: []
11-
agent: valory/trader:0.1.0:bafybeibaooayqfkl7vclisdyytj4li3q56a72p3m3enpnjqxnqoh6aabhi
11+
agent: valory/trader:0.1.0:bafybeifgjugs6q2y6kjiecpx3zbc6igowfwlzkx6l6evkkw4vv434t5dja
1212
number_of_agents: 1
1313
deployment:
1414
agent:

packages/valory/skills/agent_performance_summary_abci/behaviours.py

Lines changed: 74 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,15 @@
8585
_ZERO_ADDRESS = (
8686
"0x" + "0" * 40
8787
) # placeholder used to disable off-chain deposit scanning
88+
89+
# Upper bound on the ``eth_getLogs`` block range per cycle. Safely
90+
# below common public-provider caps (Alchemy / Infura ~10k). When an
91+
# agent has been offline long enough that the catchup range exceeds
92+
# this, subsequent cycles march the checkpoint forward one chunk at
93+
# a time until it reaches head — instead of the pre-fix behaviour
94+
# where the range grew unbounded and every scan hit the provider cap,
95+
# permanently freezing the checkpoint.
96+
OFFCHAIN_MAX_SCAN_RANGE = 5_000
8897
QUESTION_DATA_SEPARATOR = "\u241f"
8998
PREDICT_MARKET_DURATION_DAYS = 4
9099
WXDAI_ADDRESS = "0xe91D153E0b41518A2Ce8Dd3D7944Fa863463a97d" # wxDAI on Gnosis Chain
@@ -417,8 +426,22 @@ def _fetch_offchain_prepaid_wei(
417426
# under pre-deposit-as-loss stays counted even if the operator
418427
# flips use_offchain off or clears the tracker address. Once
419428
# counted, always counted.
420-
summary = self.shared_state.read_existing_performance_summary()
421-
state = summary.offchain_deposits or OffchainDepositState()
429+
#
430+
# Source ``state`` from the raw-JSON re-read helper, not from the
431+
# full-summary read. ``read_existing_performance_summary`` degrades
432+
# to a fresh dataclass on ANY nested ``__post_init__`` raise
433+
# (e.g. a rollback where a newer release added an
434+
# ``Achievements`` sub-field that a downgraded reader can't
435+
# validate). If we sourced ``state`` from that degraded summary,
436+
# ``state.last_scanned_block`` would be ``None`` and the seed
437+
# branch below would re-seed from head — wiping a still-valid
438+
# on-disk checkpoint. Reading only the ``offchain_deposits``
439+
# sub-dict leniently insulates this helper from sibling
440+
# ``__post_init__`` failures.
441+
state = (
442+
self.shared_state.read_offchain_deposits_from_disk()
443+
or OffchainDepositState()
444+
)
422445
cached_total = state.total_deposited_wei
423446

424447
marketplace_config = self.params.mech_marketplace_config
@@ -484,13 +507,18 @@ def _fetch_offchain_prepaid_wei(
484507

485508
# First-run seed: don't sweep history from block 0. Policy: only
486509
# deposits from the checkpoint forward count against ROI.
510+
# Split-write via ``write_offchain_deposits_to_disk`` (see the
511+
# sourcing note above and the model docstring): mid-cycle
512+
# writes update only the ``offchain_deposits`` sub-dict on
513+
# disk, so a fresh degraded summary read from another site
514+
# can't cascade into wiping sibling fields at this write.
487515
if state.last_scanned_block is None:
488-
summary.offchain_deposits = OffchainDepositState(
489-
total_deposited_wei=0,
490-
last_scanned_block=head_block,
516+
self.shared_state.write_offchain_deposits_to_disk(
517+
OffchainDepositState(
518+
total_deposited_wei=0,
519+
last_scanned_block=head_block,
520+
)
491521
)
492-
summary.timestamp = self.shared_state.synced_timestamp
493-
self.shared_state.overwrite_performance_summary(summary)
494522
self.context.logger.info(
495523
f"[Offchain Deposits] First run — seeded checkpoint to block "
496524
f"{head_block}, cumulative total starts at 0."
@@ -504,14 +532,24 @@ def _fetch_offchain_prepaid_wei(
504532
# or empty devnet). Nothing to scan; nothing to persist.
505533
return cached_total
506534

535+
# Cap the scan range so an agent that has been offline for
536+
# longer than the provider's ``eth_getLogs`` block-range cap
537+
# (a Pearl laptop closed over a weekend, ~14h+ of Gnosis
538+
# blocks) catches up in chunks over successive cycles rather
539+
# than every scan hitting the cap and permanently freezing the
540+
# checkpoint. Each cycle marches ``last_scanned_block`` forward
541+
# by at most ``OFFCHAIN_MAX_SCAN_RANGE`` blocks until it reaches
542+
# head.
543+
to_block = min(head_block, from_block + OFFCHAIN_MAX_SCAN_RANGE - 1)
544+
507545
response = yield from self.get_contract_api_response(
508546
performative=ContractApiMessage.Performative.GET_STATE, # type: ignore
509547
contract_address=balance_tracker_address,
510548
contract_id=str(MechPrepaidReaderContract.contract_id),
511549
contract_callable="get_deposit_events_for_requester",
512550
requester=safe_address,
513551
from_block=from_block,
514-
to_block=head_block,
552+
to_block=to_block,
515553
chain_id=self.params.mech_chain_id,
516554
)
517555
if response.performative != ContractApiMessage.Performative.STATE:
@@ -535,34 +573,39 @@ def _fetch_offchain_prepaid_wei(
535573

536574
# Aggregation lives here (not in the classmethod) by convention:
537575
# contract classmethods return processed log entries; sum happens
538-
# in the caller.
539-
# Hard-index the flat entry shape returned by
540-
# ``get_deposit_events_for_requester`` (``{"amount": int,
541-
# "block_number": int}`` per entry). ``.get(..., 0)`` would
542-
# silently zero-fill a shape drift while still advancing the
543-
# checkpoint below to ``head_block`` — an irreversible under-count
544-
# that would flatter ROI. Raise loudly instead so the ERROR
545-
# performative arm above catches it and the checkpoint stays put.
546-
new_wei = sum(int(entry["amount"]) for entry in entries)
547-
548-
# Checkpoint advances to the scanned head every successful cycle,
549-
# even with zero matches, so subsequent cycles start from
550-
# ``head_block + 1`` (small range) rather than re-scanning the
551-
# same growing range every cycle. Without this, a long
552-
# deposit-quiet stretch eventually crosses provider ``eth_getLogs``
553-
# caps and the ERROR performative freezes future accrual forever
554-
# with only warning logs.
576+
# in the caller. Wrap the hard-index in
577+
# ``(KeyError, TypeError, ValueError)`` so a shape drift on the
578+
# entries wire format routes into the malformed-response branch
579+
# instead of raising uncaught: the ``if response.performative
580+
# != STATE`` gate above only catches API performatives, and with
581+
# ``skill_exception_policy: stop_and_exit`` an unhandled skill
582+
# exception terminates the whole agent — a harder failure than
583+
# freezing the checkpoint.
584+
try:
585+
new_wei = sum(int(entry["amount"]) for entry in entries)
586+
except (KeyError, TypeError, ValueError) as exc:
587+
self.context.logger.warning(
588+
"Offchain-deposit scan returned entries with unexpected "
589+
f"shape ({exc!r}); leaving checkpoint and cached total unchanged."
590+
)
591+
return cached_total
592+
593+
# Checkpoint advances to the scanned upper bound every successful
594+
# cycle, even with zero matches, so subsequent cycles start from
595+
# ``to_block + 1`` (small range for a caught-up agent, bounded
596+
# by ``OFFCHAIN_MAX_SCAN_RANGE`` for one still catching up)
597+
# rather than re-scanning the same growing range every cycle.
555598
total_wei = cached_total + new_wei
556-
summary.offchain_deposits = OffchainDepositState(
557-
total_deposited_wei=total_wei,
558-
last_scanned_block=head_block,
599+
self.shared_state.write_offchain_deposits_to_disk(
600+
OffchainDepositState(
601+
total_deposited_wei=total_wei,
602+
last_scanned_block=to_block,
603+
)
559604
)
560-
summary.timestamp = self.shared_state.synced_timestamp
561-
self.shared_state.overwrite_performance_summary(summary)
562605

563606
self.context.logger.info(
564607
f"[Offchain Deposits] cached={cached_total}, new_this_cycle={new_wei}, "
565-
f"total={total_wei}, last_scanned_block={head_block}"
608+
f"total={total_wei}, last_scanned_block={to_block}"
566609
)
567610
return total_wei
568611

packages/valory/skills/agent_performance_summary_abci/models.py

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -449,6 +449,62 @@ def read_offchain_deposits_from_disk(self) -> Optional["OffchainDepositState"]:
449449
)
450450
return None
451451

452+
def write_offchain_deposits_to_disk(self, state: "OffchainDepositState") -> None:
453+
"""Atomic-write ``offchain_deposits`` to disk, preserving sibling fields.
454+
455+
Mirrors ``read_offchain_deposits_from_disk`` on the write side.
456+
Reads the raw JSON dict (bypassing every dataclass
457+
``__post_init__``), updates only the ``offchain_deposits`` key,
458+
writes back atomically via tempfile + ``os.replace``.
459+
``_fetch_offchain_prepaid_wei`` uses this instead of
460+
``overwrite_performance_summary(summary)`` because the summary
461+
read it would otherwise pair with can silently degrade to a
462+
fresh dataclass on any nested-field ``__post_init__`` raise,
463+
which would then wipe every sibling field on disk (metrics,
464+
agent_details, prediction_history, ...) during the mid-cycle
465+
checkpoint write. Split-write keeps our checkpoint safe without
466+
depending on other fields' validation state.
467+
468+
If the file is missing or unreadable, writes a minimal
469+
``{"offchain_deposits": ...}`` — the operator has explicitly
470+
opted in to off-chain accounting at this point, so keeping the
471+
checkpoint alive is more important than refusing to write over
472+
a corrupt file. The next cycle-end
473+
``_save_agent_performance_summary`` will re-populate the sibling
474+
fields from live data.
475+
476+
:param state: the ``OffchainDepositState`` to persist.
477+
"""
478+
file_path = self.params.store_path / AGENT_PERFORMANCE_SUMMARY_FILE
479+
480+
try:
481+
with open(file_path, "r") as f:
482+
raw = json.load(f)
483+
if not isinstance(raw, dict):
484+
raw = {}
485+
except (FileNotFoundError, json.JSONDecodeError):
486+
raw = {}
487+
488+
raw["offchain_deposits"] = asdict(state)
489+
490+
# tempfile in the same directory so ``os.replace`` is atomic on
491+
# POSIX (both paths on one filesystem).
492+
fd, tmp_path = tempfile.mkstemp(
493+
prefix=file_path.name + ".", dir=str(file_path.parent)
494+
)
495+
try:
496+
with os.fdopen(fd, "w") as f:
497+
json.dump(raw, f, indent=4)
498+
f.flush()
499+
os.fsync(f.fileno())
500+
os.replace(tmp_path, file_path)
501+
except Exception:
502+
try:
503+
os.unlink(tmp_path)
504+
except OSError:
505+
pass
506+
raise
507+
452508
def overwrite_performance_summary(self, summary: AgentPerformanceSummary) -> None:
453509
"""Write the agent performance summary to a file atomically.
454510

packages/valory/skills/agent_performance_summary_abci/skill.yaml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ fingerprint:
1010
achievements_checker/__init__.py: bafybeih7da3glbp2ljghlw4ign2dxotwwkzrrnj4m5yq27zb6osyfutva4
1111
achievements_checker/base.py: bafybeiegrcxb3d3ivpzm4lsud7kcypphl54yukjuecqlffrkzwdjawrth4
1212
achievements_checker/bet_payout_checker.py: bafybeigqbcvy7fe3apckuscrp4gs5zljppady6bwe6kgjdxxjryyppo6jm
13-
behaviours.py: bafybeibrruinbdq5aqbskdruv237v3swnv2sl242kj66otffwcvejwosau
13+
behaviours.py: bafybeicukxgtup4dfhwubd44ls6hm27xnsrd2j7xtuw36uffpo22v4yfnm
1414
dialogues.py: bafybeignoeakzaf7nmdnsjhnjoga3ks6z424qcwmzkol3kikawhnxf6zju
1515
fsm_specification.yaml: bafybeibjgjldm26nwmidx75ylvr5q7oe4kthiphvceuerkacxd3chj6vuu
1616
graph_tooling/__init__.py: bafybeicek36kwi7hlbhxz4ry5j662srevbhfrhx7ocb2ihc77hhil2utqu
@@ -20,7 +20,7 @@ fingerprint:
2020
graph_tooling/queries.py: bafybeifywkkxfmco3baqjuc5w6fkj2cgfs3znpgoowxdjnrhugaxeevapu
2121
graph_tooling/requests.py: bafybeig35rdi2zpbtlzvgzaymhrsp73t42fuo2sj44fq55fayrs3c2o3j4
2222
handlers.py: bafybeif3pnrfdyhipmizob7zsn65f7qlf6iwuy3fi7s6ku2dvqyu4mr4am
23-
models.py: bafybeidmuegnfwxusmc5kqnqfuvgvd3nxmpm6rssr6tqyqfxjbjrmr3jsu
23+
models.py: bafybeiekpny4cextdog6jvxi4sdnwhpp3xskryw2ac5pp6st77mz3yl324
2424
payloads.py: bafybeigp52f7hcfpzmoinznqt5run3ha4vpsaaoccgvmo5skmze7flupnm
2525
rounds.py: bafybeien3ggbtbjigfkuzv3yadnusifrg7htnk6ialmwkd3o464oughh6i
2626
tests/__init__.py: bafybeibrmret5n6j7oz42ahs3hhfgmr46diwtffrccjzs7z4bcj6bcbtqy
@@ -33,10 +33,10 @@ fingerprint:
3333
tests/graph_tooling/test_predictions_helper.py: bafybeidkmubpjfnxys74bjaqd7ptz4gc6ejfwrrmiodmdjwdovdclvdqhu
3434
tests/graph_tooling/test_queries.py: bafybeih4ybhkq5seb34eqgakfpfrtlijxju3w52cjwvlrbbx2afgai4jm4
3535
tests/graph_tooling/test_requests.py: bafybeic2dyqmf7uj42f2f7d3hjxguw4mmlesloci4uaioui2rx3wfjhouq
36-
tests/test_behaviours.py: bafybeibhwd6zs6gu5kkcmfdmhyxivaj7ggnge6dubdwcputddnitieemfi
36+
tests/test_behaviours.py: bafybeiaomjvleflialemph53yj4krswne65tdbch5b3cggqcnanbnxwylu
3737
tests/test_dialogues.py: bafybeigezi53b2jukm5ju6z6zvecfjkjtzxcge3ehnzxryuhpambzknc3y
3838
tests/test_handlers.py: bafybeigybc6zkku7ldtawjcjjdkndiz3alvckxbeyjj23rsmny5ql7leku
39-
tests/test_models.py: bafybeibeos6fm67nb3w6d7nb2yrygjttz7zmrwlnjogzp77rj4ttp23wgi
39+
tests/test_models.py: bafybeih2uc4wa2mqbjzbj3ophnw2mdmz25owdykqcx4wzy2f3h677agzou
4040
tests/test_payloads.py: bafybeiet4tbmqjf7h23huifwpephtjtx4jwrcapt2kibmkl2oyeclgiggy
4141
tests/test_rounds.py: bafybeicrddacjku5s6h5wn3b6up552qchk7avkfputkqeuj7zcwwcb7jou
4242
tests/test_save_performance_summary.py: bafybeibgyx3n4dn7zhb7vfcc4wwq7nuyfep723cyqfrpnwqgsvhhwagure

0 commit comments

Comments
 (0)