Skip to content

Latest commit

 

History

History
44 lines (42 loc) · 40.5 KB

BACK_LOG.md

File metadata and controls

44 lines (42 loc) · 40.5 KB

Backlog — Unscheduled / Not Yet Phased

Items identified but not yet assigned to a specific phase or formal Work Package. Triage into P3/P4/P5 (promote to a numbered WP row in ROADMAP.md) as priorities firm up. Goal: keep a visible backlog of independent, scopeable tasks so assignment doesn't become reactive — open a corresponding GitHub issue as each item is triaged.

ID Domain Item Description Candidate Phase Source / Rationale Status
BL-1 dincli / SDK Nonce management for concurrent tx submission DinContext.get_tx_params() (cli/context.py) fetches the nonce via get_transaction_count(address) with no block param — defaults to "latest" (confirmed only), so two transactions fired before the first confirms collide on the same nonce today. Needs a nonce manager/lock before dind submits jobs concurrently from one account. P3 (bug fix) or P4-1.2 Surfaced during SDK interface proposal review, issue #20 (Jul 23, 2026) ✅ Resolved — PR #129 (merged 2026-09-10, develop)
BL-2 Daemon / SDK Wallet/session/tx signing keystone (session.py, wallet.py, tx.py) DinSession, SignerProvider, and tx.send() — the private-key/signing surface of the SDK interface proposal (§2, §5b). Deliberately deferred out of task_220726_7 as its own focused review-and-build task given the security sensitivity. P4-1.2 task_220726_7 scope boundaries; SDK interface proposal v0.3 ⚡ In Progress — dincli/sdk/{session,wallet,tx}.py (SignerProvider, NonceManager, send()) implemented in PR #31; out of draft but still unmerged (feat/din-sdk, head ab1ba24, no push since 2026-09-12)
BL-3 Daemon Validator hardware load-bearing / load-balancing P4-2.2 covers hardware detection and scoring for task eligibility, not balancing load across concurrent jobs a validator is running. Distinct, substantial follow-on once multi-task daemon automation exists. P4/P5 Staffing discussion, Jul 23, 2026 💭 Idea
BL-4 Tooling Client tooling layer Dedicated tooling for clients (dataset configuration, etc.) — distinct from dind's own automation (P4-4.1 covers daemon-driven client automation once configured, not the setup/config tooling itself). P4/P5 Staffing discussion, Jul 23, 2026 💭 Idea
BL-5 Tooling Model-owner tooling layer Dedicated tooling to help model owners author manifest.json/service files (model.py, modelowner.py, client.py, auditor.py, aggregator.py) — explicitly beyond dind's job. P4-5.1 covers IPFS/registration automation, not authoring assistance. P4/P5 SDK proposal §6 review (issue #20); staffing discussion, Jul 23, 2026 💭 Idea
BL-6 Daemon "Agentic dind" extension Once P4 daemon automation is stable, extend dind toward more autonomous/agentic operation beyond scripted automation. Vision-stage, not yet scoped. P5+ Staffing discussion, Jul 23, 2026 💭 Idea
BL-7 Protocol / Mechanism design Evaluator geographic/infrastructure diversity monitoring Distinct from the Sybil/identity gap already tracked (whitepaper-summary.md checklist item #13): honest, uniquely-staked Evaluators could still cluster behind the same cloud provider or jurisdiction (correlated-failure risk, akin to a Nakamoto Coefficient). Proposal is additive/measurement-only, not a slashing change — (1) capture operator metadata (region, hosting ASN, client version) at NFT-stake registration, (2) publish a concentration dashboard, (3) weight random Evaluator assignment toward diversity within the eligible pool. Depends on whatever DID/VC approach gets chosen for item #13, so blocked on that decision. P3/P4 (depends on staking + identity design) Discussion #48, @robertocarlous, Jul 21, 2026 🆕 New — still blocked on the DID/VC decision (item #13)
BL-8 dincli import-deployments still imports only four ProxyAdmin keys _DEPLOYMENTS_TO_DIN_INFO (dincli/cli/system.py) maps four contracts + four proxyAdmin* keys; the foundry deployments JSON emits six of each since PR #51 (fee router). dinTreasury, dinFeeRouter, proxyAdminTreasury, proxyAdminFeeRouter are silently dropped by import-deployments. Nothing breaks today (dincli doesn't use those addresses yet). Also fix the docstring claim that "both flows write the same address schema" — hardhat still writes the four-proxy shape. P3 PR #51 review follow-up (merge d2b7383 extended the foundry deploy script to six proxies but not the dincli import side), Jul 24, 2026 ✅ Resolved — PR #116 (merged 2026-09-09, develop)
BL-9 Daemon / SDK sdk/operations/ layer + real dind job handlers to_envelope() (dincli/sdk/serialize.py, PR #31) is built and tested but has zero production call sites — no SDK operation's dataclass return is ever routed through it, and dind's JOB_HANDLERS registry (PR #32) has exactly one job type ("demo", a no-op). The sdk/operations/ layer that would call real SDK functions (task registration, GI lifecycle, aggregator/auditor scoring, etc.) and feed their dataclass returns through to_envelope() for both dind's job queue and the CLI's future --json output doesn't exist yet in either PR. Expected sequencing, not a regression — operations/ is gated behind the wallet/session/tx keystone (BL-2); real job types (client/auditor/aggregator role automation) get wired in once that lands. P4-1.2 PR #31/#32 code review follow-up, Jul 30, 2026 🟡 Started, unmerged — PR #31's head now has dincli/sdk/operations/ (platform.py: get_platform_addresses, get_stake, …) and PR #32 registers a first real job type, read_stake, next to "demo". The role operations (task registration, GI lifecycle, aggregator/auditor scoring) and their to_envelope() routing still don't exist. Checked 2026-09-30
BL-10 Solidity/foundry (rewards) Reward settlement doubles the C-1 unbounded-loop gas-DoS surface DINTaskAuditor.settleRewards (called from DINTaskCoordinator.endGI, task_210726_6 §3) iterates every client/auditor/aggregator to compute and credit shares, stacking on top of the existing per-GI iteration in slashAuditors/slashAggregators. Extends the already-tracked C-1 finding (2026-07 security review, Developer/audits/2026-07_foundry-src-security-review.md) to roughly 2x its worst measured cost at spec scale (10–50 validators / 100–500 clients). Needs a paginated or claim-time-computed settlement redesign before spec-scale deployment — same treatment C-1 itself is waiting on. P3/P4 PR #64 review, Jul 30, 2026 ✅ Resolved — PR #134 (client/auditor claim-pull) + PR #131 (aggregator weighted extension) + PR #136 (gas benchmark), all merged 2026-09-10, develop
BL-11 Solidity/foundry (slashing, dispute resolution) Dispute-redo aggregator selection reuses the grindable blockhash shuffle (H-2) DINTaskCoordinator._assignFreshSubgroup (task_210726_6 §4c dispute scaffold) shuffles via the same blockhash(block.number - 1)-based entropy flagged as finding H-2 in the 2026-07 security review. Materially worse here: the grinding party (model owner, via resolveDispute) is also the sole adjudicator and faces no deadline, so they can wait indefinitely for a favorable hash — undermining the one mechanism meant to catch owner/aggregator collusion. Should be resolved together with H-2 (commit-reveal or VRF-based randomness) before dispute resolution graduates past scaffold. P3/P4 PR #66 review, linked to H-2 (2026-07 security review), Jul 30, 2026 ✅ Resolved — PR #171 (merged 2026-09-26, develop; task_240926_16 Part A, issue #151): future-block seed. openDispute anchors seedBlock = block.number + disputeSeedDelay (default 7, owner-settable 1–256); permissionless lockDisputeSeed stores keccak256(blockhash(seedBlock), GI, tierKind, batchId); resolveDispute(upheld=true) requires a locked seed, so the draw no longer depends on when the owner resolves. _assignFreshSubgroup shuffles the GI's fixed registered aggregator pool and takes the first still-active, non-accused entries, so an aggregator exiting after the seed is public can only drop itself from the draw, not re-roll it. Residuals: (1) sequencer-produced blockhash is trusted — acceptable for testnet, VRF / multi-party commit-reveal is the mainnet-grade follow-up, tracked in issue #178; (2) if nobody calls lockDisputeSeed within ~256 blocks (~8.5 min on OP) of seedBlock, the lock re-anchors to a fresh future block, giving a second draw — nothing locks automatically today. dincli's model-owner disputes resolve-aggregation --upheld locks the seed itself before resolving (PR #302).
BL-12 Protocol / Mechanism design Dispute bond denomination (DIN) vs. MECHANISM_DESIGN's ETH-denominated validator-fee bonds DINTaskCoordinator's dispute bond (task_210726_6 §4c) is DIN-denominated, while MECHANISM_DESIGN.md's resolved decision (2026-07-21) places validator-network-fee bonds in ETH. Not necessarily wrong — dispute bonds and network-fee bonds may reasonably use different denominations — but wasn't flagged as a deliberate choice anywhere, including the slashing taxonomy doc. Needs an explicit decision recorded either way. P3 PR #66 review, Jul 30, 2026 ✅ Resolved — PR #133 (merged 2026-09-10, develop); decision recorded as DIN-denominated
BL-13 dincli / Auditing Encrypted test-data key correspondence enforced only by array length, not identity DINTaskAuditor.assignAuditTestDataset checks encryptedKeys.length == batch.auditors.length but has no way to verify encryptedKeys[i] actually corresponds to auditors[i] — a misordered off-chain script could silently hand an auditor the wrong encrypted key. Fix likely belongs on the dincli side (keying the off-chain encryption step explicitly by auditor address rather than positional order) once real per-validator encryption is implemented — PR #63 only wired the on-chain plumbing, per task scope. P3/P4 PR #63 review, Jul 30, 2026 ✅ Resolved — PR #110 (merged 2026-09-09, develop); encryptedKeys now built via explicit per-auditor address lookup, not array position
BL-14 Solidity/foundry (rewards) Top-level bps-split rounding dust never swept DINTaskAuditor.settleRewards's integer-division 4-way bps split (client/auditor/aggregator/treasury) leaves a small rounding remainder uncollected — no fund-safety impact (funds stay in the contract), but nothing swept it to treasury either. Minor cleanup once the treasury-forwarding TODO from Part 3 (task_210726_6 §3) is resolved. P3/P4 PR #64 review, Jul 30, 2026 ✅ Resolved, for the top-level split only — folded into PR #134/PR #131's reward-engine rework: the 4-way split's remainder now forwards to the slash-treasury via _forwardToTreasury (burned if unset; counted in treasuryAccrued) (merged 2026-09-10, develop). The original title said "per-recipient," but the fix only ever covered this one top-level split; it was never about the second, per-participant rounding layer inside claimReward (each role's pool divided again per claimant) — that layer is untouched by this fix and is tracked separately as accepted-by-design in issue #250 / DINTaskAuditor.md §13 No. 4
BL-15 Solidity/foundry (slashing, dispute resolution) A resolved dispute can never be reopened against the same batch — undocumented DINTaskCoordinator.resolveDispute has no path back to disputes[gi][tierKind][batchId].resolved == false once set, so exactly one dispute per batch is possible, ever (upheld or rejected). Reasonable as a scaffold-stage design choice, but wasn't called out in code comments or Developer/design/slashing-taxonomy.md. Cheap doc fix; no behavior change needed unless multi-dispute-per-batch is later desired. P3/P4 PR #66 review, Jul 30, 2026 ✅ Fixed — PR #264
BL-16 Governance / din-dao DIN-DAO (Stages A–D) deferred to post-mainnet Abraham's decision: no DinMultisig for Stage A/Devnet 2.0–3.0 — DevNet governs off-chain (team coordination + public discussion, Ethereum All-Core-Devs-style) until well past testing; any near-term multisig is a plain Gnosis Safe scoped to treasury/funds only, never protocol roles. This pulls all of feat/din-dao (PR #27, issue #23) out of active P4 scope, not just the Stage A multisig — Stage C (DinGovernor/DinGovernanceStaking) goes with it. DD-1, DD-2, and DD-3 are the specific design questions that move with it — DD-3 is resolved (no Stage A multisig at all), DD-1/DD-2 (Stage C voting power/model) stay open and unresolved, to revisit once on-chain governance work actually resumes. In the interim, governance discussion moves to forums. Post-mainnet discuss-040826.md (Abraham, Aug 4, 2026); discussion #70 comment (robertocarlous, Aug 4, 2026) confirming the team-call decision 🆕 New — unchanged, still deferred per Abraham's decision
BL-17 Cryptoeconomics / Tokenomics Curated per-model staking & fee attribution Robert's follow-up to the a16z tokenomics piece Abraham shared: today validator staking is one shared network-wide pool and DinFeeRouter distributes revenue without attribution to individual models, so incentives track network-wide averages rather than any one model's performance. Proposal: let validators stake toward individual models/model owners via DINModelRegistry instead, using the modelMinStakeBounds storage already added to DinValidatorStake during P3 staking work, making fee flows traceable per model (closer to an Aave Safety-Module framing than a passive-holder dividend). Most of the wiring already exists; remaining work is mainly task-contract-level enforcement, already flagged as a modelMinStakeBounds follow-up. Robert explicitly leaves P4-vs-P5 placement open. Article summary + context: discussion/application-token-cash-flows-a16z.md. P4/P5 (undecided) Discussion #73, @robertocarlous, Aug 5, 2026 🆕 New — still undecided, no PR
BL-18 Cryptoeconomics / Tokenomics Fair-launch validator token distribution Abraham's vision (Slack, Jul 31, 2026): no ICO, pre-sale, or VC allocation — DIN distributed exclusively to validators/active network participants, programmatically, as a fair launch. Technical blueprint sent Aug 5, 2026: a new Merkle-drop claim contract (Transparent Proxy, treasury-Safe admin per DD-3) funded once from treasury, cliff + linear vesting on claim. Resolves the open ICO-vs-airdrop fork of MECHANISM_DESIGN.md §9 item 14 in favor of the fair-launch validator/active-participant distribution now recorded in §9-8. Abraham confirmed Aug 5, 2026 (Slack, 5:12 PM): testnet dry-run, move fast — local anvil → devnet → testnet → mainnet path. Phase set to P4 (Umer, Aug 5, 2026): eligibility computed off the on-chain indexer (P4-IDX1/P4-IDX2, not a raw RPC-log script) rather than directly off DinValidatorStake/DINTaskAuditor/DINTaskCoordinator events, run by the treasury-admin authority once the indexer exists. Contract-only slice assigned to Robbert: task_050826_9 (feat/fair-launch-distributor, off develop HEAD, no other-PR contract dependency identified) — tracked via issue #75 and discussion #76. Eligibility-computation slice deferred pending P4-IDX1/IDX2. P4 Abraham Slack message, Jul 31, 2026 (HR/Abraham/questions-310726.md); reply drafted, Aug 5, 2026 (HR/Umer/reply-abraham-050826-310726.md); Abraham's phase/network answer + Umer's P4/indexer scoping, Aug 5, 2026 (HR/Abraham/discuss-040826.md) ⚡ In Progress — contract-only slice merged as PR #77 (2026-09-10, develop); eligibility-computation slice still blocked on the indexer (issue #24 / PR #29, unmerged)
BL-19 Daemon dind start PID-file TOCTOU race start() (dincli/dind/main.py — lands with PR #32, not yet on develop) does read_pid → is_process_running → write_pid with no file lock (no O_EXCL, no flock) tying the check to the write, so two concurrent dind start invocations against the same --state-dir both start clean and both run event loops against the same SQLite DB. Last writer wins dind.pid, so dind stop/status can only ever see one — the other is an unstoppable orphan doubling job-claim traffic. Contradicts the "start refuses a live PID" claim under any real concurrency (systemd Restart=on-failure retry, double-invoking deploy script). Reproduced live during review. P4-1.1 (harden before dind runs real jobs) PR #32 code review finding No. 1, Jul 30, 2026 🟢 Fixed on the PR branch, unmerged — PR #32's head adds dincli/dind/lock.py, an flock on the state directory (released by the kernel on a hard kill, unlike an O_EXCL marker), so a second dind start refuses. Lands with PR #32. Checked 2026-09-30
BL-20 Daemon Container healthcheck can't detect degraded status HealthHandler.do_GET() (dincli/dind/health.py — lands with PR #32, not yet on develop) always returns HTTP 200 unless _build_payload() itself raises — the computed status: "degraded" (stale last-tick) appears only in the JSON body, never in the status code. docker-compose.yml's curl -f http://127.0.0.1:8787/health only fails on non-2xx, so a daemon whose event loop has hung while the health thread still answers passes the healthcheck forever. As wired, the check is crash-only, not hang-detecting — undercutting ecf7aa3's "Docker auto-restart an unhealthy daemon" claim. Fix: map degraded to a non-2xx code, or document the healthcheck as crash-only. P4-1.1 (harden before dind runs real jobs) PR #32 code review finding No. 2, Jul 30, 2026 🟢 Fixed on the PR branch, unmerged — PR #32's dincli/dind/health.py now serves a degraded body with HTTP 503, so curl -f fails on a hung event loop. Lands with PR #32. Checked 2026-09-30
BL-21 Daemon dind persists no logs to disk configure_logging() (dincli/dind/logging.py — lands with PR #32, not yet on develop) attaches a plain StreamHandler (stderr) with the JsonFormatter — no RotatingFileHandler, nothing written into StateDirs despite it already holding jobs.db/dind.pid/preferences.json. Under systemd (journald) or a container log driver the supervisor persists logs; run directly in a terminal — the documented and tested path — stderr is gone when the session closes, leaving nothing to grep for "why did my node skip a job three hours ago". For an always-on daemon aimed at non-expert operators (issue #21), dind should own a rotating log file under its own state dir. P4-1.1 (operability, before dind is load-bearing) PR #32 code review finding No. 6, Jul 30, 2026 🟢 Fixed on the PR branch, unmerged — PR #32's dincli/dind/logging.py adds a RotatingFileHandler in the state directory when state_dir is given, alongside stderr. Lands with PR #32. Checked 2026-09-30
BL-22 Daemon / SDK NonceManager._instances never evicted NonceManager (dincli/sdk/tx.py — lands with PR #31, not yet on develop) keys its per-(chain_id, address) cache in a class-level _instances dict with no eviction, so it grows for the process lifetime. Correct and irrelevant for the CLI (one invocation per process), but it's process-wide mutable state — worth a look once dind runs long-lived. Already caused real test pollution: reservations leaked between test classes until each cleared NonceManager._instances in setup_method. P4-1.1 (before dind runs long-lived) task_300726_8 implementation note, Jul 31, 2026 🟢 Fixed on the PR branch, unmerged — PR #31's dincli/sdk/tx.py bounds _instances at _MAX_INSTANCES (strong cache, with live instances tracked separately so an in-flight reservation isn't dropped). Lands with PR #31. Checked 2026-09-30
BL-23 DP / Privacy (cache_model_0) clip_scope: global default paired with an unreviewed clipping_norm: 1.0 may over-clip real weights PR #109 (fix/dp-sensitivity) correctly ties noise to the clip (noise_scale = noise_multiplier * clipping_norm) and defaults clip_scope to global so the clip actually bounds the combined L2 norm the noise is calibrated against — the sensitivity-calibration fix itself is sound (per_layer only bounds the combined norm at clipping_norm * sqrt(n), not clipping_norm, so pairing it with the new noise formula would under-noise as tensor count grows). But cache_model_0/manifest.json's clipping_norm: 1.0 was never revisited: under the old per_layer scope it bounded each tensor independently to norm 1.0; under global it bounds the entire model's combined L2 norm to 1.0, a much tighter constraint for any model with more than one floating tensor (sqrt(Σ‖tensor_i‖²) grows with tensor count even if no individual tensor's norm changes). No test in PR #109 exercises this against cache_model_0's real trained state_dict (the new tests use synthetic tensors), so it's unverified whether the new default clips — and thus degrades — the reference model's weights far more aggressively than before. Follow-up: run apply_dp_mechanism/clip_state_dict against cache_model_0's actual trained weights under the new default and retune clipping_norm if the combined-norm bound turns out to be destructive. P3 (verify before/at merge) PR #109 review, Sep 8, 2026 ✅ Fixed — PR No. 263
BL-24 DP / Privacy (cache_model_0) F4 — Laplace noise calibrated against an L2 clip, not the L1 sensitivity it's normally calibrated against post_training_laplace's laplace_scale is scaled by the same clipping_norm as the Gaussian mechanisms (clip_state_dict's L2-norm clip), but the Laplace mechanism's textbook privacy guarantee is calibrated against L1 sensitivity, not L2. PR #109 flagged this explicitly rather than silently assuming it's fine (Documentation/technical/services/clients.md:210-212: "Laplace noise calibrated against an L2 clip is an open question tracked separately"), and #99's F4 (Documentation/technical/audits/dp-mechanism-review.md §F4) called the structural mismatch confirmed but left the exact magnitude/severity for a DP specialist's sign-off — explicitly excluded from #99's scope rather than fixed. #119 (which closed #99's remaining F8 items) left F4 untouched, so nothing currently tracks it now that #99 is closed. Needs either a DP specialist's opinion that L2-calibrated Laplace is acceptable as-is (and the open-question note downgraded to an explanation), or a fix (e.g. recalibrating against an actual L1 clip, or reclassifying post_training_laplace as experimental alongside F5's per_layer treatment) before any ε is claimed for it. P3/P4 (needs DP specialist input first) #99 F4 (excluded from scope), Documentation/technical/audits/dp-mechanism-review.md §F4, Sep 10, 2026 🟡 Partially addressed — issue #279 Track A reclassified both post_training_gaussian and post_training_laplace as experimental (F5's recommended fix): resolve_dp_config now logs a warning on selection, and Documentation/technical/services/clients.md labels both accordingly. F4's actual L2-vs-L1 mismatch is still unfixed — needs a DP specialist's recommendation per issue #279 Track B before post_training_laplace can carry any ε
BL-25 Tooling / reference model (cache_model_0) cache_model_0/abis/ task-contract artifacts are stale vs. foundry/src cache_model_0/abis/DINTaskCoordinator.json and DINTaskAuditor.json are full hardhat artifacts (abi + bytecode) last regenerated 2026-06-09, missing 67 ABI entries present in foundry/src for the coordinator (104 vs 170) and 96 for the auditor (68 vs 158), with pre-foundry constructors. PR #171 regenerated the six bundled dincli/abis/ files from foundry/out but deliberately left these alone: cache_model_0/manifest.json's task_contracts block pins each artifact to an IPFS CID, records "type": "hardhat-artifact" and a hardhat/cancun/optimizer-off compilation block, and carries deployed addresses, and dincli resolves task artifacts by CID. Regenerating the files locally would leave the manifest describing artifacts it no longer points to. Needs one pass: regenerate both from foundry/out (with bytecode, e.g. dincli system dump-abi --bytecode --output cache_model_0/abis), update the manifest's artifact type and compilation metadata to foundry, re-pin to IPFS and update the CIDs. Addresses only change on a redeploy. P3/P4 PR #171 merge (2026-09-26): out of scope for the PR's ABI refresh ✅ Fixed — PR No. 261
BL-26 Solidity/foundry (task contracts) Batch-assignment seed lock (H-2) shares BL-11's re-roll residual, plus a new pool-reshaping gap DINTaskCoordinator.autoCreateTier1AndTier2/createAuditorsBatches (task_240926_18 Part B, issue #156 H-2 aggregation side) reuse BL-11's future-block-seed + permissionless-lock pattern (lockAggSeed/lockAuditSeed), so they inherit its residual (2): the model owner can decline to lock a seed they dislike and wait out the ~256-block blockhash window for a fresh draw — repeatable, since nothing locks automatically today. A second, distinct gap not present in BL-11's _assignFreshSubgroup (which shuffles a fixed pool and only lets an exiting validator drop itself, not re-roll the rest): _activeAggregatorPool/_activeAuditorPool are evaluated at autoCreateTier1AndTier2/createAuditorsBatches call time, after the seed is already public, and Fisher-Yates re-rolls the whole assignment on any pool-size change — so a validator can unstake between lock and create to reshape everyone else's batch. Cost to the attacker is real but modest (their own Sybils sit out the GI and enter unbonding). Ready-made fix for the pool-reshaping gap: adopt _assignFreshSubgroup's pattern — shuffle the fixed per-GI registration list (dinAggregators[_GI] / the auditor equivalent) with the locked seed, then skip inactive validators while filling seats, so an unstake only forfeits the leaver's own seat instead of re-rolling everyone else's. P3/P4 PR #191 review, Sep 29, 2026 🟡 Partially mitigated — the decline-to-lock re-roll is narrowed by a validator-side lock in dincli, added at the PR #191 merge (dincli aggregator lock-seed / dincli auditor lock-seed, and automatically in show-t1-batches/show-t2-batches/lms-evaluation show-batch before batches exist): any validator online after the seed block locks it, so the owner only gets a re-roll if nobody else is. A contract-side cap on re-anchors was considered and deferred: with no GI-abort path, a GI capped out would be stuck forever (endGI needs AggregatorsSlashed, startGI needs GIended), locking validators' registration slots and the reward pool — it needs a GI-abort design (who may abort, where the reward pool goes) first. Pool-reshaping gap unaddressed. Documented as residuals in the PR (DINTaskCoordinator.md §6.3). Sequencer-trust residual (shared with BL-11) tracked in issue #178; the pool-reshaping gap is now #243 (fix in review, PR #253); the re-roll-by-declining-to-lock gap has no dedicated issue yet, same as BL-11's own un-issued residual (2)
BL-27 dincli (model owner) dincli model-owner deploy still uses the pre-foundry task-contract constructors dincli/cli/modelownerd/deploy.py sends DINTaskCoordinator.constructor(stake) (:35) and DINTaskAuditor.constructor(stake, coordinator) (:77), but foundry/src takes (stake, modelId) and (stake, coordinator, modelId). Against foundry artifacts, which are the bundled dincli/abis/ since PR #171, the deploy fails at ABI encoding, so model owners can't deploy task contracts from dincli. The tests/dincli/ harness hides this because it deploys task contracts from hardhat artifacts. The fix also has to settle where modelId comes from: the registry assigns it only at approval, after the contracts exist (DINTaskCoordinator.md §10 No. 4). P3 (before any model-owner onboarding on DevNet 3.0) PR No. 204 review, Sep 30, 2026 (caveats DINTaskCoordinator.md §10 No. 10, DINTaskAuditor.md §13 No. 8) ✅ Fixed — PR No. 261
BL-28 dincli (model owner) No dincli command for releaseGIRegistrationSlots DINTaskCoordinator.releaseGIRegistrationSlots(gi) (owner-only, once per ended GI) is the only thing that decrements validators' activeRegistrationCount; endGI deliberately doesn't (BL-10). dincli ships the function in its ABI but has no command that calls it, so under a non-zero maxConcurrentRegistrationsPerStakeUnit every GI permanently consumes its validators' concurrent-registration slots until they hit TC_/TA_ConcurrentRegistrationCapReached. Harmless while the cap is 0 (the default). P3 (before the cap is set on any network) task_100926_12 / issue #37 fast-follow; PR No. 204 review 🟡 Fix in review — PR #302 adds dincli model-owner gi release-slots <model_id> [--gi N] (task_061026_21 Part C); tracked in #223 Part 2
BL-29 Solidity/foundry (fees) DinFeeRouter's non-treasury shares accrue with no way out routeFeeETH/routeFeeDIN pay the treasury share out immediately but only count the validatorPool, storage and publicGoods shares in accruedEth/accruedDin. No function withdraws or distributes them, so with the default 95% validator-pool split, 95% of every swept faucet/registry fee stays in the router until an upgrade adds a path. Needs a decision on who can pull each bucket and where the validator-pool share goes (reward pools? DinEmission?). P3/P4 PR No. 204 review (DinCoordinator.md §14 No. 2), Sep 30, 2026; related to issue #43's open items 🆕 New — unaddressed; tracked in #221
BL-30 Solidity/foundry (task contracts) No recovery from a stalled GI If a T1/T2 batch never reaches the reveal quorum, finalizeT1Aggregation/finalizeT2Aggregation revert forever (TC_NoSubmissions/TC_InsufficientSubmissions), and there is no owner path to skip the batch or abort the GI. endGI needs AggregatorsSlashed and startGI needs GIended, so the model is stuck: its reward pool and its validators' registration slots stay locked. This is also why BL-26's contract-side re-anchor cap was deferred. Needs a GI-abort design: who may abort, when, and where the reward pool goes. P3/P4 PR No. 191 review (BL-26); PR No. 204 review (DINTaskCoordinator.md §10 No. 6) 🆕 Decided, unimplemented — Abraham's GI-abort policy (Oct 26, #222): anyone may abort after a stall timeout, locked rewards go back to their funders, slots are released, non-revealers are still penalised; the timeout value is set with the other testnet parameters in #155. Adds code to DINTaskCoordinator, which has 55 B above the size gate (#201)
BL-31 Solidity/foundry (slashing) S6 no-participation slashing is implemented but not wired DinValidatorStake.recordNoParticipation (escalating 10%-per-breach slash past s6NoParticipationThreshold) exists and is tested, but no task contract calls it. They deliberately skip it where slashPartial (S1/S2, with S5 escalation) already penalises the same missed work, to avoid stacking past MIN_STAKE. So S6 never fires. Decide whether S6 should cover something S1/S2 don't (e.g. registered but never assigned or never active), or whether to remove it and its parameters. P3 PR No. 204 review (DinValidatorStake.md §14 No. 1), Sep 30, 2026; slashing taxonomy S6 (issue #38) ⏸️ Parked for testnet — Abraham (Oct 26, #224): S1/S2 plus S5 already cover missed work; leave S6 unwired (or remove it and its parameters) and revisit after testnet. Parked behavior documented in PR #305; storage, parameters and API remain unchanged
BL-32 Tooling / onboarding Contributor environment preflight check No single command checks a dev machine before work starts. Each of these has already cost time: (1) Python ≥ 3.12; (2) forge/anvil installed and solc 0.8.28 available; (3) foundry/node_modules present — without npm ci, forge test's parallel tests race to fetch @openzeppelin/upgrades-core over npx (see CLAUDE.md); (4) eth-account and py-multibase import; (5) torch imports in the active venv (full pytest run); (6) .env/.env.<network> exist, the RPC endpoint answers, and resolve_ipfs_config() resolves. P3/P4 (onboarding; small, ~half a day) preflight.sh pattern from Osomudeya/devops-scripting-labs (reviewed 2026-10-02); no existing equivalent (note: the only "preflight" in dincli/cli/system.py is the bridge's tx preflight — unrelated) 🟡 Mostly fixed — PR #255 added scripts/preflight.py (Python/forge/anvil/node_modules/package checks, --network RPC/IPFS checks, 13 tests in tests/test_preflight.py, a preflight section in Documentation/public/getting-started.md). Remaining (exit non-zero on node_modules, eth-account/py-multibase, --network RPC/IPFS failures) tracked in #245
BL-33 Tooling / deploy On-chain deployment drift check Nothing verifies that foundry/deployments/<network>.json (and the din_info that dincli system import-deployments writes) still matches the chain. Proposal: a read-only check, either a forge script or dincli system verify-deployment, that for each recorded contract compares (1) the proxy's EIP-1967 implementation and admin slots against the recorded implementation/proxyAdmin* addresses; (2) the deployed runtime code hash against the current forge build artifact (immutables masked); (3) owner / DIN-Representative addresses; (4) wiring: DinCoordinator ↔ DinToken/DinValidatorStake/DinModelRegistry/fee router/treasury links and slasher authorizations on DinValidatorStake. Report per-item OK / DRIFT with expected vs. actual. Caveat: it only covers what the deployments JSON records, so a clean run doesn't prove nothing else was deployed or authorized. P3 (before the DevNet 3.0 deploy; re-run after every UpgradePlatform.s.sol run) Terraform state-vs-live drift pattern from Osomudeya/devops-scripting-labs 03-drift-detection (reviewed 2026-10-02); no existing code reads EIP-1967 slots or code hashes in dincli/ or foundry/script/ ✅ Fixed — PR #254 (issue #244). dincli system verify-deployment added: reads the deployments JSON, checks EIP-1967 impl/admin slots, extcodehash, ProxyAdmin owner(), DinCoordinator wiring, and slasher authorizations. DeployPlatform.s.sol and UpgradePlatform.s.sol extended to write impl addresses, codehashes, deployer, and git commit. 16 tests in tests/test_verify_deployment.py.
BL-34 Solidity/foundry (task contracts) DINModelRegistry.disableModel() kill-switch doesn't reach the live task contracts modelDisabled[modelId] only gates requestModelRegistration/requestManifestUpdate inside the registry itself. DINTaskCoordinator/DINTaskAuditor have no dependency on, or awareness of, the registry (confirmed: zero functional references; the auditor has two doc comments naming DINModelRegistry by name (L31, L434) plus two more referencing "model registry" generically without naming the type (L393, L405) — none are functional checks). A model the DIN-Representative has disabled — e.g. because its task contracts are wrongfully slashing honest validators — keeps running full GIs completely unaffected. The task contracts' own doc table calls this a "kill-switch," which it isn't. Needs a decision: wire the task contracts to check modelDisabled before state-changing calls (requires threading the model ID + registry address into contracts that don't know about the registry today), or document disableModel as registry-metadata-only. P3/P4 2026-07 security review M-2 (Documentation/technical/audits/foundry-src-security-review.md) ✅ Resolved — validateGIStart wired in DINTaskAuditor.sol; both startGI overloads check registry approval and disabled status via _startGI. Compatible task pairs required; existing deployed pairs unaffected. PR No. 305.
BL-35 Solidity/foundry (registry) rejectModel()'s non-refund of the registration fee was never confirmed as intentional feePaid (set at requestModelRegistration) is never refunded on rejectModel(), but it's also never refunded on approveModel() either — the fee appears to be a deliberate pay-to-apply cost regardless of outcome (anti-spam), not an oversight specific to rejection. Never written down as a deliberate choice anywhere. Needs confirmation and a doc note in DINModelRegistry.md / the dinrep role docs, so a future reader doesn't "fix" it into an inconsistent partial-refund state. P4 (doc-only once confirmed) 2026-07 security review L-4 (Documentation/technical/audits/foundry-src-security-review.md) ✅ Decided — keep as intended (Abraham, Oct 26, #224): the registration fee is a pay-to-apply anti-spam cost, refunded on neither approval nor rejection. Documented in DINModelRegistry.md and dinrep role docs by PR #305