Task: sdk/operations/ Layer — First Real (Non-Demo) Operation Through to_envelope() — BL-9 (Issue #20 continued)
ID: task_110926_15
Assigned to: Santiago Rodriguez Cetran (@Santiagocetran)
Created: 2026-09-11
Status: Open
Repo: https://github.com/InfiniteZeroFoundation/DevNet
Base branch: feat/din-sdk (PR #31, draft) — spec written against head dc83f92 (2026-09-11); feat/din-daemon (PR #32) picks this up once its own base is refreshed against the updated feat/din-sdk.
Roadmap ref: P4-1.2, continuation of issue #20 (start DIN-SDK); unblocks part of issue #21 (start DIN daemon)'s role-automation dependency
Tracking: Developer/BACK_LOG.md BL-9 · P4 merging discussion #139 analysis
The SDK interface proposal (Developer/design/sdk-interface-proposal.md §8, your own doc) has always planned an operations/ layer: registry.py, gi.py, aggregation.py, auditor.py, client.py, model.py, dao.py — role operations that return dataclasses, get JSON-serialized via to_envelope(), and are the single code path both the CLI (--json output) and dind (job handlers) run through. task_220726_7 deliberately deferred this because it depends on wallet.py/session.py (the signing keystone), which didn't exist yet at the time.
They exist now. dincli/sdk/{session,wallet,tx}.py are all present and real on feat/din-sdk @ dc83f92 — session.py's DinSession + SignerProvider protocol, wallet.py's non-interactive keystore resolution, tx.py's send() (gas estimation, signing via the SignerProvider protocol, nonce management with stuck-tx replacement support). BL-2 — the thing this was blocked on — is done. Confirmed directly against the branch during the 2026-09-10/11 backlog audit, not taken on faith from commit messages.
The gap Developer/BACK_LOG.md BL-9 flags is still real, though: to_envelope() has zero production call sites — no SDK operation's dataclass return is ever routed through it — and dind's JOB_HANDLERS registry (dincli/dind/jobs.py) has exactly one job type, "demo", a no-op. The operations/ layer itself doesn't exist yet in either PR #31 or PR #32.
None that block starting. Everything this task needs already exists on your own feat/din-sdk branch: session.py (account/w3 resolution), contracts.py (deployed contract access), manifest.py/runtime.py (config), serialize.py (to_envelope() + the encoder rules), errors.py (the DinError taxonomy for mapping failures). You don't need anyone else's PR to merge first, and you don't need sign-off to start — this task is pre-approved. The only thing worth flagging back here if you hit it: if a specific operation turns out to need business logic that's genuinely only in dincli/cli/modelownerd/*.py and isn't a clean lift (interactive confirmation prompts baked into the middle of a function, IPFS upload side effects mid-flow, etc.), that's expected — see scope boundary 2 below, don't fight it, pick a different first operation instead.
The full operations/ surface (7 files, covering task registration, GI lifecycle, aggregator/auditor scoring, DAO actions) is too much for one task, and most of it touches state-mutating role logic that deserves its own careful review pass per role — same reasoning task_220726_7 used to defer the signing keystone in the first place. This task is Part 1: prove the pattern end-to-end with a small, low-risk, read-only slice. It does not close BL-9 entirely, and shouldn't be marked as such.
Scope boundaries — read before starting:
- Read-only operations only. No
tx.pysend()calls in this task — pick operations that query chain/config state, not ones that submit transactions. (tx.pyitself is done and ready for the next task to build write operations on top of — that's deliberately not this one.) - No role-specific business logic refactors. Don't touch
dincli/cli/modelownerd/,client.py,auditor.py, oraggregation.py— those have exactly the interactive-confirmation and mid-flow-IPFS-upload complexity the SDK proposal's plan/apply design (§3) exists to handle carefully, and that's future work, not this task. - Two candidate operations to start with — both already exist as CLI commands you can read for the exact current behavior to preserve:
dincli system din-info(dincli/cli/system.py,din_info()) — reads deployed platform-contract addresses from local config. No contract call at all, the simplest possible first slice.dincli dintoken read-stake(dincli/cli/dintoken.py,read_dintoken_stake()) — a real read-only contract call (current DIN stake for an account), a step up in realism fromdin-info. You don't have to do both — one real end-to-end slice is the deliverable; a second is a bonus if time allows.
- No changes to existing CLI command output. Same shim discipline as every prior extraction wave: the CLI command keeps producing byte-identical console output; it just becomes a thin wrapper that calls the new SDK operation and renders its dataclass, instead of doing the logic inline.
dincli/sdk/operations/package — start with one file (e.g.status.pyorregistry.py, your call) holding the operation(s) you pick from the candidates above. Each operation: takes aDinSession, returns a typed dataclass (per the proposal's existing conventions — see howstate.py/serialize.pyalready model this), raisesDinErrorsubclasses on failure (reuseerrors.py, don't invent a new error shape).- Route the dataclass through
to_envelope()— a test that calls the operation, feeds the result throughto_envelope(), and asserts the resulting{status, data, error, meta}shape is correct. This is the first real (non-synthetic) inputto_envelope()will ever see in a test. - One real
dindjob type — add a job type todincli/dind/jobs.py'sJOB_HANDLERSregistry (alongside, not replacing,"demo") whose handler calls your new operation and stores/logs theto_envelope()result. This is the concrete proof thatdind's job queue → SDK operation → JSON envelope pipeline works end-to-end, not just in theory. - One CLI command refactored to call the same operation — pick whichever candidate you implemented and make its CLI command (
din-infoorread-stake) a thin wrapper: parse args → buildDinSession→ call your new SDK operation → render the dataclass as today's console output. Byte-identical output, per scope boundary 4.
dincli/sdk/operations/exists with at least one real, tested operation.- A test proves the operation's output round-trips through
to_envelope()correctly. - At least one real
dindjob type (not"demo") exists and is tested — the daemon's existing job-queue test harness from PR #32 should extend cleanly to this. - At least one existing CLI command is refactored onto the new operation with unchanged output, and the existing CLI test(s) for that command still pass unmodified (proving the output really is unchanged).
- Full suite still green on
feat/din-sdk(andfeat/din-daemononce its base is refreshed). - Update
Developer/BACK_LOG.md's BL-9 row to reflect the first real operation landing — mark it "Part 1 done," not "Resolved," matching this task's own scope framing. - A short write-up (a few sentences in the PR description is enough, no separate doc needed) on what you'd pick as the next operation to build now that the pattern is proven — seeds Part 2, whoever ends up picking it up.
This directly answers the gap the 2026-09-11 backlog audit and the P4 merging discussion both flagged: issue #20 has real, tested extraction plumbing but zero evidence the CLI can actually run through the SDK layer as designed. This task is that first piece of evidence.