Task: Full-GI Alignment: Contracts Check + Richer GI States, dincli Commands, Integration Suite on Foundry, GI Docs
ID: task_061026_21
Assigned to: Umer Majeed (@umermjd11)
Created: 2026-10-06
Status: Open (assigned)
Dates: Oct 6 – Oct 17, 2026 (about 8.5 working days; per-Part estimates below). The Parts run in order: A → B → C → D → E. If anything slips, say so early in the tracking discussion.
Repo: https://github.com/InfiniteZeroFoundation/DevNet
Base branch: develop. The spec was written against a1fcce2 (2026-10-05). Re-pull before starting.
Roadmap ref: P3 onboarding (dincli), P3-6.3b (audit preparation), DevNet 2.0 launch readiness
Source plan: Developer/tasks-plan/umermjd11/task-plan-051026-2.md, reviewed in PR #229 (verification review, reviewer decisions, decisions applied)
Companion task: task_061026_20 (contract follow-ups #201 A4, #180, #193). See Coordination.
Tracking:
- Part C: #223 (closes, pending review): BL-27 deploy constructors and BL-28 release slots.
- Parts C and E: the Discussion #216 follow-ups left by task_021026_19 (mapped below).
- Follow-up, not in this task: #228, running the integration suite in its own CI job once Part D passes.
- Discussion #231 (progress updates, questions, PR links)
The task contracts on develop now have:
- commit-then-reveal in all three scoring and aggregation phases
- future-block batch seeds
- encrypted test data
- per-GI reward pools with pull claims
- disputes
- the
modelIdconstructor argument
dincli and the full-GI integration suite never caught up:
-
The integration suite (
tests/dincli/) can't pass with either toolchain.- Phase 1 assertion. It asserts a
proxyAdminkey (test_01_platform.py:135-137,:164).DeployPlatform.s.solwrites seven per-contractproxyAdmin*keys instead. - Old task contracts. It deploys the hardhat task contracts (
constants.py:50,ARTIFACT_BASE = hardhat/artifacts/contracts). Those predate foundry: no commit-reveal, rewards, seed lock or encrypted test data, and a 23-memberGIstates, while dincli mirrors foundry's 26. - ABI overwrite.
dump-abi --official(test_01_platform.py:167-197,test_02_task_contracts.py:74-107) overwrites the tracked foundry ABIs indincli/abis/. - Missing steps.
test_04_gi.pynever funds the pool, registers auditor keys or runs any reveal phase. Its final check (:478) passes on the name but keeps a staleor "23"fallback;GIendedis 25.
- Phase 1 assertion. It asserts a
-
dincli can't drive a full GI.
model-owner deploysends the old constructors (deploy.py:35,:77) and never callssetDinToken.- These have no command:
depositRewards/DinEmission.fundGI, sogi startreverts withTC_GIRewardPoolNotFundedregisterEncryptionKey, socreate-testdataset --submitfails. The error message atauditor.py:39names adincli auditor register-encryption-keythat doesn't existreleaseGIRegistrationSlots, claims, and both dispute families
-
The GI state machine hides progress. Three steps change no state:
- audit seed waiting vs locked
- batches created vs test data assigned
- aggregation seed waiting vs locked
Worse,
startLMsubmissionsEvaluation(DINTaskCoordinator.sol:532-538) doesn't check that test data was assigned. The auditor-side flag (DINTaskAuditor.sol:1033-1045) is one-way, but it's only the owner's own claim; nothing checks that every batch actually has test data. -
The public GI docs are stale: wrong command names, and the funding, key, seed and reveal steps are missing.
| Follow-up | Part |
|---|---|
model-owner deploy still uses the old constructors (no modelId) |
C (closes #223 with BL-28) |
No dincli commands for depositing/claiming rewards, registerEncryptionKey or disputes |
C |
din-workflow.md still lists 4 contracts and withdraw |
E |
Old command names in roles/clients.md, roles/auditors.md, roles/model-owner.md, model-workflow.md |
E |
setup.md's broken @main#subdirectory=dist install line |
E |
ROADMAP.md:19 deploy-blocker sentence (wrong since PR #211) |
E |
| Part | PR | Touches | Conflicts with | Rule |
|---|---|---|---|---|
| A | with B | Read-only audit, recorded in this spec. Two text fixes: DINShared.sol:30-34, and the utils.py state-24 text |
— | First |
| B | PR 1 | DINShared.sol enum + new error, DINTaskCoordinator.sol (3 transitions + gates), DINTaskAuditor.setTestDataAssignedFlag (commitment check), foundry tests, dincli/cli/utils.py mirrors and every dincli state gate, dincli/abis/, DINShared.md, DINTaskCoordinator.md, DINTaskAuditor.md |
task_061026_20 PR 1 (DINShared.sol interface; DINTaskAuditor bytes and ABI); PR #29 (subgraph enum); PR #218 (lifecycle test ordinals) |
After A. Before C/D, so commands and the suite are built on the final state machine |
| C | PR 2 | dincli/cli/modelownerd/deploy.py, new commands, dincli/abis/DinEmission.json, cli/context.py helper, dinrep approval check, unit tests |
— | After B |
| D | PR 3 | tests/dincli/**, tests/dincli/NOTES.md, dincli-testing-guide.md |
— | After C |
| E | PR 4 | Documentation/public/**, CLAUDE.md, DINShared.md §2.2 diagram, ROADMAP.md:19 |
— | Last |
Rebase each PR on develop after the previous one merges; no stacked branches.
This is a read-only pass over every owner and role GI function in DINTaskCoordinator, DINTaskAuditor, DinValidatorStake and DinEmission, checked against DINTaskCoordinator.md §6 and the GIstates enum. The result below is the reference for Parts B–E. Update it in PR 1 if anything has moved.
Preconditions for a complete GI:
| Precondition | Where | Without it |
|---|---|---|
modelId constructor argument on both task contracts |
DINTaskCoordinator.sol:290, DINTaskAuditor.sol:406 |
Deploy fails at ABI encoding (BL-27) |
setDinToken on the auditor (and the coordinator, for dispute bonds) |
DINTaskAuditor.sol:440, DINTaskCoordinator.sol:1307 |
depositRewards, claims and bonds can't move DIN |
The GI's reward pool funded before each startGI |
DINTaskCoordinator.sol:380 → DINTaskAuditor.depositRewards (:481) or DinEmission.fundGI (DinEmission.sol:212) |
TC_GIRewardPoolNotFunded |
Every batch auditor has an X25519 key on DinValidatorStake |
registerEncryptionKey (DinValidatorStake.sol:509), checked at DINTaskAuditor.sol:1018-1019 |
TA_AuditorEncryptionKeyNotRegistered when test data is assigned |
| Seed blocks get mined | disputeSeedDelay = 7 blocks; dincli polls (utils.py:1029-1143); anvil --block-time 2 mines |
The seed lock hangs |
| The owner opens each of the three reveal windows | start*Reveal |
close / finalize revert |
Re-checked at eb8085d (PR 1's base): the preconditions hold, and line references in this spec are updated to that commit. The coverage table below is unchanged: every row marked missing is still missing.
dincli coverage at a1fcce2:
| GI step | Contract function | dincli command |
|---|---|---|
| Deploy + wire | task-contract constructors; setDINTaskAuditorContract |
model-owner deploy task-coordinator / task-auditor (old constructors) |
| Slashers | DinCoordinator.addSlasherContract; task-side slasher flags |
dinrep add-slasher; model-owner add-slasher |
| Genesis, registry | setGenesisModelIpfsHash; requestModelRegistration / approveModel |
model-owner model submit-genesis-model; task model-owner register-request; dinrep registry approve-* |
| Wire DIN token | setDinToken (both) |
missing |
| Fund pool | depositRewards / DinEmission.fundGI |
missing |
| Start, registration | startGI; registration windows; registerDINaggregator / registerDINAuditor |
gi start; gi reg …; aggregator register; auditor register |
| Encryption key | DinValidatorStake.registerEncryptionKey |
missing |
| LMS | start/closeLMsubmissions; submitLocalModel |
lms open/close; client train-lms + submit-lm |
| Seeds | lockAuditSeed / lockAggSeed |
auditor lock-seed / aggregator lock-seed, and automatic in batch creation |
| Audit batches, test data | createAuditorsBatches; assignAuditTestDataset + setTestDataAssignedFlag |
auditor-batches create; auditor-batches create-testdataset --submit |
| Score commit/reveal/close | startLMsubmissionsEvaluation, commitAuditScore, startLMsubmissionsEvaluationReveal, revealAuditScore, closeLMsubmissionsEvaluation |
lms-evaluation start / start-reveal / close; auditor lms-evaluation evaluate --submit / reveal |
| T1/T2 | autoCreateTier1AndTier2; start/commit/startReveal/reveal/finalize T1 and T2; setTier2Score |
aggregation create-t1nt2-batches, T1/T2 start / start-reveal / close, T2 set-score; aggregator aggregate-t1/t2 --submit, reveal-t1/t2 |
| Slash, end | slashAuditors, slashAggregators, endGI |
slash auditors / aggregators; gi end |
| Release slots | releaseGIRegistrationSlots |
missing (BL-28) |
| Claim | claimReward(gi) / claimRewards() |
missing |
| Disputes | coordinator openDispute … claimDisputeBond; auditor openTestDataDispute … reassignAuditTestDataset |
missing |
| Owner parameter setters | setDisputeParams, setS1/S2/S3*, setRewardSplit, setNetworkFeeFloor, … |
missing (out of scope) |
Text fixes (land in PR 1):
DINShared.sol:30-34says the table has "24 members". There are 26 today, and more after Part B.- The
dincli/cli/utils.pystateDescriptionentry for state 24 says "Validators slashed"; it should say aggregators slashed.
If the check turns up any other blocker to a complete GI, fix it in Part B, or raise it on its own issue if it needs a decision. Don't work around it in dincli.
- Preconditions and coverage tables re-checked at the PR's base and updated here if needed
- Both text fixes in PR 1
Estimate: 0.5 day.
Each new state is set by the function that already does the step, so a GI needs no extra owner transactions, and dincli task gi show-state (and the subgraph, and dashboards) can say exactly where a GI is. Decision 1, option B: add all three. If the coordinator budget runs short, keep them in this priority: AuditTestDataAssigned first (it closes a real gap), then AuditSeedLocked, then AggSeedLocked.
| New state (lifecycle / enum order) | Inserted | Set by | Gate change |
|---|---|---|---|
AuditSeedLocked |
between LMSclosed and AuditorsBatchesCreated |
lockAuditSeed (DINTaskCoordinator.sol:1483, anyone). Only on a successful lock, never on a re-anchor |
createAuditorsBatches requires AuditSeedLocked |
AuditTestDataAssigned |
between AuditorsBatchesCreated and LMSevaluationStarted |
setTestDataAssignedFlag (:519) |
startLMsubmissionsEvaluation requires it. The auditor side (DINTaskAuditor.sol:1033-1045) checks that every batch of the GI has a stored commitment (testDataCommitments[gi][b] != 0, written by assignAuditTestDataset), else it reverts with a new TA_TestDataNotAssigned. The flag is already one-way (TA_FlagMustBeTrue, TA_FlagAlreadySet) |
AggSeedLocked |
between LMSevaluationClosed and T1nT2Bcreated |
lockAggSeed (:1459) |
autoCreateTier1AndTier2 requires AggSeedLocked |
Not added, and why:
- A "reward pool funded" state. Funding lives on the auditor contract, anyone can fund, and it targets the next GI. dincli reads
giRewardPool(gi)instead. - A "test-data dispute pending" state. Disputes are per batch and can overlap evaluation.
- A "rewards settled" state.
endGIsettles the pool, soGIendedalready means that.
Constraints:
- Insert at the lifecycle position, not at the end, as PR #63 and #197 did. Every later ordinal shifts; with all three,
GIendedgoes from 25 to 28. - In the same PR, update everything that encodes ordinals or names:
- the
dincli/cli/utils.pystates/stateDescriptionmirrors - every dincli state gate (grep for
GIstateToStrand name comparisons) DINShared.md§2.1 / §2.2DINTaskCoordinator.md§6- foundry tests that assert ordinals or names
- the bundled ABIs (
dump-abi --official)
- the
- Post the new ordinal table on PR #29 (the subgraph regenerates its
GIstatesmapping). Don't push to that branch. If PR #218 has merged, update any ordinals its lifecycle test asserts. - Size:
- Coordinator:
DINTaskCoordinatorhas a 1,079 B margin. Measure each state alone and all three together. Anything that doesn't fit with the gate green follows the priority order above and becomes a view; say so in the PR. - Auditor: the commitment check costs
DINTaskAuditor+75 B (measured). The combined auditor budget, and the way back out of the warn band, is in task_061026_20 Part A. OnceAuditTestDataAssignedguards the double-set,Is_testdataCIDs_Assignedcan be removed.
- Coordinator:
lockAuditSeed/lockAggSeedstay permissionless. The state change happens after the seed is stored.
Tests:
- each transition happens
createAuditorsBatches/autoCreateTier1AndTier2revert before the lock- a re-anchor leaves the state unchanged
startLMsubmissionsEvaluationreverts until test data is assigned (regression test for the gap)- with one batch unassigned,
setTestDataAssignedFlagreverts withTA_TestDataNotAssigned, and evaluation can't start - the full lifecycle test walks every ordinal
- Three states (or the subset that fits, by priority), the commitment check and the gates, with the tests above
- dincli mirrors and gates, docs, ABIs and foundry tests updated in the same PR. Ordinal table posted on PR #29
- Coordinator and auditor sizes in the PR (combined with task_061026_20 if that landed first). Gate green,
forge testandpytest -m "not integration"green
Estimate: 1.5 days.
Closes #223 (BL-27 + BL-28).
Deploy (BL-27).
model-owner deploy task-coordinator/task-auditorget--model-id, defaulting toDINModelRegistry.totalModels(). That's the ID the next approval assigns (DINModelRegistry.sol:237, 0-based). Warn that the guess only holds if no other request is approved first.- The auditor deploy reads
modelId()from the coordinator and refuses a mismatch. - Both deploys call
setDinToken. - Fix the latent
NameErrorwhen thestakeentry is missing (deploy.py:27-28,:63-64). modelIdcheck at approval (Decision 2: dincli-side).dinrep registry approve-registration-requestcompares the requested contracts'modelId()withtotalModels()and refuses on a mismatch unless--forceis passed. A contract-side check inDINModelRegistry.approveModelis a mainnet-registry follow-up, in the same area as BL-34 / #224.
New commands:
| Command | Calls | Notes |
|---|---|---|
dincli model-owner rewards deposit <model_id> --gi N --amount <DIN> |
approve + depositRewards |
Anyone can fund |
dincli model-owner rewards fund-emission <model_id> --gi N |
DinEmission.fundGI |
Adds dincli/abis/DinEmission.json and get_deployed_din_emission_contract (din_info already has emission) |
dincli rewards claim <model_id> --gi N / dincli rewards withdraw <model_id> |
claimReward(gi) / claimRewards() |
All roles. First checks giRewardSnapshot(gi).settled and rewardClaimed |
dincli auditor register-encryption-key |
DinValidatorStake.registerEncryptionKey |
Generates the X25519 key per wallet (e.g. auditor_x25519_<address>.key, chmod 600), replacing today's single shared auditor_x25519.key, which breaks several --demokey auditors on one machine. Updates _load_auditor_x25519_key (auditor.py:33-41) to match. The owner key (auditor_batches.py:170-177) also gets chmod 600 |
dincli model-owner gi release-slots <model_id> --gi N |
releaseGIRegistrationSlots |
BL-28 |
dincli auditor dispute-test-data, dincli model-owner disputes resolve-test-data / reassign-test-data, … disputes close-expired |
openTestDataDispute (DINTaskAuditor.sol:1496), resolveTestDataDispute (:1540), closeExpiredDispute (:1573), reassignAuditTestDataset (:1617) |
Decision 4: in this task. Built against the PR #215 shape: only batch auditors open a dispute, only the owner resolves, an unanswered dispute is upheld on expiry, there's no penalty after settlement, and TA_RewardsAlreadySettled applies. Bond approval comes first |
dincli aggregator dispute, dincli model-owner disputes resolve-aggregation / settle-recomputation, … expire, … claim-bond |
openDispute (DINTaskCoordinator.sol:1368), resolveDispute (:1535), settleRecomputation (:1609), expireDispute (:1671), claimDisputeBond (:1583) |
S4 |
Fail fast instead of reverting:
gi startchecksgiRewardPool(next GI) > 0and points torewards deposit.create-testdataset --submitchecks every batch auditor's key and names any that are missing.
Reuse:
build_and_send_tx(dincli/cli/utils.py:978)- the
ctx.obj.get_deployed_din_task_*_contract(model_id)lookups (cli/context.py:339,:357) - a new
approve_din(ctx, spender, amount)helper, taken from the inline approve indintoken.stake_dintokens(dincli/cli/dintoken.py:71-128)
Tests: one pytest per command group, in the tests/test_dinrep_add_slasher.py style (SimpleNamespace context, monkeypatched build_and_send_tx). They cover:
- call arguments
- approve before act
- the fail-fast checks
- the
modelIdmismatch refusal
- Deploy with
--model-id+setDinToken,NameErrorfixed, approval-timemodelIdcheck - Rewards, encryption-key, release-slots and both dispute command families, plus the fail-fast checks
- Unit tests.
pytest -m "not integration"green - BL-27 / BL-28 status in
Developer/BACK_LOG.md, and the "dincli lags" caveats removed (DINTaskCoordinator.md§10 No. 10,DINTaskAuditor.md§13 No. 8)
Estimate: 3 days.
Toolchain:
- Point
ARTIFACT_BASEatfoundry/out. It's the sameX.sol/X.jsonlayout, andget_contract_instancealready readsbytecode.object(contract_utils.py:150-152). - Run
npx hardhat compileonly whenPLATFORM_DEPLOY_TOOLCHAIN=hardhat. Hardhat task contracts leave the GI path. - The
dump-abitests write toDIN_TEMP(--output), never--official. - Phase 1 asserts the per-contract
proxyAdmin*keys.
test_04_gi.py walks one complete GI (Decision 3). Assert the state after every phase with the existing, unused _gi_state helper (:52-58):
setDinToken(from deploy) →rewards deposit(orfund-emission) →gi start- aggregator and auditor registration →
auditor register-encryption-keyfor each auditor - LMS →
auditor lock-seed(AuditSeedLocked) →auditor-batches create→create-testdataset --submit(AuditTestDataAssigned) lms-evaluation start→evaluate --submit→lms-evaluation start-reveal→auditor lms-evaluation reveal→closeaggregator lock-seed(AggSeedLocked) →create-t1nt2-batchesT1 start→aggregate-t1 --submit→T1 start-reveal→reveal-t1→T1 close; the same for T2; thenT2 set-scoreslash auditors→slash aggregators→gi end(assertGIendedby name and its new ordinal; drop theor "23"fallback)rewards claim/withdrawfor one client, one auditor and one aggregator (assert each DIN balance rises) →gi release-slots
Once task_061026_20 Part B has landed, add a negative check: an aggregator trying to register as an auditor reverts.
Optional second GI: fund GI 2, then gi start from GIended. This proves the loop and slot reuse. Mark it integration + slow and keep it out of CI. Add it only after the single-GI run passes.
Docs: update tests/dincli/NOTES.md (drop the INTERIM hardhat notes, refresh the GI map) and Documentation/technical/testing/dincli-testing-guide.md:
- 7 platform contracts
- no hardhat compile
- the new phases
- client accounts are really
range(2, 11)
- Suite on foundry artifacts, no tracked-file writes, Phase 1 assertions fixed
- One complete GI with state asserted after every phase, claims and release slots
- A local
pytest tests/dincli/ -v -x -m integration --tb=shortrun (anvil, IPFS, Docker), passing end to end, with its summary pasted in the PR -
NOTES.mdand the testing guide updated
Estimate: 2 days.
Bring each doc in line with the final commands and states:
| Doc | Main fixes |
|---|---|
Documentation/public/workflows/model-workflow.md |
Foundry artifacts + --model-id; create-genesis-model / submit-genesis-model; task model-owner register-request + DIN-Rep approval; update-manifest-request; funding before gi start; train-lms → submit-lm; auditor key prerequisite; the three reveal windows; seed and test-data states; claim and release slots after gi end |
Documentation/public/roles/model-owner.md |
get-registry-fee; task model-owner … registry commands (replacing the nonexistent model-owner registry …); genesis names; funding; start-reveal for evaluation, T1 and T2; create-testdataset --submit; claim; release slots; disputes |
Documentation/public/roles/auditors.md |
register-encryption-key, lms-evaluation reveal, claim, disputes |
Documentation/public/roles/clients.md |
train-lms then submit-lm, claim |
Documentation/public/roles/aggregators.md |
claim, reveal-t2 --batch, dispute |
Documentation/public/getting-started.md |
aggregator show-t1/t2-batches; auditor key + reveal + lock-seed; submit-lm; the outdated "rewards not the focus" line |
Documentation/public/manifest.md, guides/keystore-migration.md |
genesis command name; train-lms --submit |
Documentation/public/workflows/din-workflow.md |
7 contracts; withdraw → sweep-fees; the fee-value conflict |
Documentation/public/setup.md |
Option B's pip install git+…@main#subdirectory=dist can't build: dist/ on main holds only wheels and sdists, with no pyproject.toml. Replace it with a working install, e.g. pip install "git+https://github.com/InfiniteZeroFoundation/DevNet.git@main" from the repo root, or a direct wheel URL. Bring Option A's wheel name (dincli-0.1.0) to the current version |
Developer/ROADMAP.md:19 |
Rewrite the deploy-blocker sentence ("24,585 B … 9 B over EIP-170") for the PR #211 sizes and the CI size gate. Flag the "DevNet 3.0" vs "DevNet 2.0" naming in the PR for Umer to decide |
Documentation/technical/contracts/DINShared.md §2.2 |
Diagram with the funding gate and the seed and test-data states |
CLAUDE.md |
7 platform contracts; GI summary with funding, seed locks, keys, reveals, claim and release slots |
Flag the node README's "local Hardhat devnet" line in the PR; don't change it.
After merge, follow up on the wiki pages that still say "no dincli command yet".
- Every doc in the table updated
-
python3 .github/scripts/check_doc_links.py Documentationand… Developergreen - Wiki follow-up listed in the PR
Estimate: 1.5 days.
DINShared.sol. Part B edits theGIstatesenum and addsTA_TestDataNotAssigned. task_061026_20 Part B addsisDINAggregatortoIDINTaskCoordinatorandTA_DualRoleNotAllowed. The sections differ; whichever PR merges second rebases.DINTaskAuditorbytes and ABI. Part B's commitment check (+75 B) counts against the shared budget in task_061026_20 Part A. Both tasks regeneratedincli/abis/DINTaskAuditor.json; the second to merge regenerates on top of the first.- Getters. task_061026_20 keeps
giRewardSnapshot,rewardClaimedandtestDataDisputespublic for Part C. Once Part B's state guards the double-set,Is_testdataCIDs_Assignedcan go entirely. Settle that in whichever PR lands second. - #180 guard. The suite uses disjoint role accounts. Part D adds the negative check once task_061026_20 Part B lands.
- #228: the integration-suite CI job. It follows once Part D passes.
- #201 A4, #180, #193: covered by task_061026_20.
- Owner parameter setters in dincli (
setDisputeParams,setS1/S2/S3*,setRewardSplit,setNetworkFeeFloor): revisit with #155. - A contract-side
modelIdcheck inDINModelRegistry: a mainnet follow-up (BL-34 / #224). - BL-29 to BL-33, #194, #78, #181, #178: each needs a design decision first, or is mainnet-grade.