Repository navigation
Conversation
…trate Key custody, content-protection, on-chain rights, and commerce rails seated on the ESP component runtime: op->action capability enforcement, first-writer-wins provider pinning with identity-keyed teardown, passkey step-up on money verbs (intent-, launch-, and time-bound), fragment-delivered launch tokens, viewer session lifecycle with sweeper, and the dkms rail end-to-end test anchor.
CENC cipher core with PQ-hybrid threshold envelopes, ddrm media packaging, encrypt/decrypt/key/rights/drm providers, content-market and act-emitter microvm capsules, dkms-authority with its release fail-closed invariant, protected viewers (elacity-player, ddrm-viewer), the Creator portal, and ESP projection-schema manifests.
Owned-asset open flow with staged loading and buy-then-retry, viewer session release on window close, Home-chrome spend-intent confirmation gating the passkey ceremony, Home-cookie-authenticated money verbs, wallet-metamask approval auto-poll and EIP-6963 rediscovery, and Library open-with-viewer with .ddrm cover art and session-scoped tags.
verify-ci and the dDRM capsule gate, the dkms-authority release invariant job, a non-vacuous bus-conformance recipe, review/** branch gating, entropy/alignment checker updates for the commerce shell, and dkms dev scripts (docker harness, av-forensics, demo servers).
Consolidate the scattered convergence-era and marketplace notes into one
onboarding-first hub at docs/dkms/, and add the terminology glossary.
Structure
docs/dkms/README.md the entry: what/why, the three rails, the security
model in brief, a quickstart, and a guided reading path
ARCHITECTURE.md planes, isolation substrates, the full pipeline,
capsule inventory
SECURITY_MODEL.md boundaries, the two invariants, threat model,
invariant -> test table
MEDIA_PIPELINE.md encrypt, CENC, envelopes, packaging, the decrypt rail
VIEWER_SESSIONS.md session lifecycle, launch tokens, the open path
COMMERCE.md discovery, buy, acquire, resale, the Library handoff
COMMERCE_API.md the /api/market/* seam between shell and gateway
COMMERCE_CONTRACTS.md selectors, addresses, ABIs on Base
RUN_E2E.md the operator runbook
DEV_SETUP.md the local harness: smoke scripts, run-creator-gateway.sh,
dkms-docker, dev-mode caveats, macOS vs Linux
deploy/ quorum node provisioning, runbook, ceremony, templates
diagrams/ rendered architecture diagrams + mermaid sources
history/ convergence-era working notes, with a README index
explaining they are rationale, not current status
tools/ selector verifier, index prototype, design tokens
Consolidation
36 markdown pages under docs/convergence/ + docs/marketplace/
-> 32 under docs/dkms/: 25 relocated, 11 folded into the current pages, and
7 written fresh (README, ARCHITECTURE, COMMERCE, MEDIA_PIPELINE,
VIEWER_SESSIONS, DEV_SETUP, history/README). Both old directories are gone.
Accuracy
Every claim is checked against the code on this branch; where an older doc
disagreed, the code won. That covers fragment-form launch tokens, the
dev-modes-only ELASTOS_DDRM_SUBJECT pin and its release-build boot guard,
the 404-non-oracle contract on unowned assets, the Home-cookie money verbs
with their spend confirmation dialog, and first-writer-wins provider pinning.
Inbound links
68 references to the moved and deleted paths retargeted repo-wide, across
GLOSSARY.md, the docs index, THREAT_MODEL/SECURITY_AUDIT/ARCHITECTURE_MAP,
the dev and dDRM scripts, and doc-path comments in capsules/ and
elastos-server. The comment updates are comment-only; no code changed.
Gates: home-entropy-check (markdown links resolve), check-wci-alignment,
just alignment-check — all green.
Coverage report (functional vs ESP-aligned percentages per roadmap item) promoted to the measurement baseline, plus one bulk plan covering every sub-100% item: current state, remaining workstreams, test anchors, dependencies, and open questions where implementation is unsettled.
SashaMIT
left a comment
There was a problem hiding this comment.
Hi Irzhy — thanks for the review request. Focused early security pass on the money / viewer / custody seams (not a full 529-file product review). CI green and the architecture claims in the PR description largely hold on the branch.
Verified as solid (matching what you listed):
- Passkey step-up on
/api/market/buyand/api/create/mint(authorize_money_verb— intent-/launch-/time-bound, single-use) - Launch tokens in URL fragments, not query strings
- Live buy binds real ledger
tokenIdviaresolve_token_id_live(not a content-hash fallback) ELASTOS_DDRM_SUBJECTbehinddev-modes+ release boot guard- Viewer close routes + 60s sweeper
- dKMS release invariant (
compile_error!/ CI job)
Remaining items I'd treat as pre-merge (or explicitly gate as operator-dogfood-only):
-
High —
ELASTOS_DDRM_BUY_SIGN=walletauto-approve. Passkey is required (good), butsign_with_managed_accountstill inline-approves. Combined with the known PARKED subject-resolution rewire (empty subject fail-closed — which you already call out), that flag also lets chain buy proceed with no linked wallet and no Wallet/Inbox human ceremony. Fine as a documented operator opt-in for dogfood; for anything beyond that, live signing should go through Inbox consent (the footgun comment inwallet_signer.rsalready points there). -
Medium — expired media sessions.
authorize_media_sessiondoes not checkexpires_at, so manifest / init / cover can still serve after expiry until the 60s sweeper. Segments already fail closed — worth aligning those routes. -
Medium — trade-approval vs buy resolver.
scan_asset_created_for_content_idcontinues when mint calldata is unavailable; buy's resolver fails closed (candidate_input_unavailable). Same fail-closed rule on the trade-approval path would close a wrong-operative window. -
Medium — Library re-buy
content_id. Open prefers.ddrmcapsulecontent_id/kid; legacy Library buy still usescontent_cid/owned:{name}. Share one resolver so buy and open key the same id.
Not blocking on the PARKED RequiredHomeLaunchToken subject rewire itself — fail-closed empty is the right interim; just don't let the wallet auto-sign flag quietly widen that gap.
Happy to re-review a follow-up commit.
— Sash
|
@SashaMIT 2 points have been retained, the rest have already been treated my side as hotfix 12. Addendum — 2026-08-12 external review (Sash,
|
| ID | Severity | Established finding | Required outcome |
|---|---|---|---|
| ESP-1 | P1 | The trade-approval resolver scan_asset_created_for_content_id (capsules/chain-provider/src/main.rs) silently continues when a candidate mint's calldata is unavailable (tx_input → Ok(None)), while the buy resolver's MKT-1 hardening fails closed with candidate_input_unavailable on the same condition. Because candidates are sorted newest-first and a re-mint reuses the KID, an unavailable newest calldata can fall through to an older binder — a wrong-operative/token-id approval window. |
Trade approval applies the same fail-closed rule as the buy resolver: any candidate whose mint calldata cannot be fetched aborts the resolve; no decision is made on a partial candidate set. |
| ESP-2 | P1 | Legacy Library re-buy (buy_owned_access in elastos/crates/elastos-server/src/api/viewer_open.rs) derives content_id as owned.content_cid / owned:{name} and never parses the .ddrm capsule, while the open path prefers the capsule's content_id/kid first. The doc comment claiming buy resolves "EXACTLY as /api/viewers/open does" is false for dKMS capsule assets: a re-buy is keyed on an id the rights gate never reads back, so money is spent and the open still denies. |
Buy and open share one content-id resolver (capsule content_id/kid first, then content_cid, then owned:{name}); a regression test proves a dKMS-capsule Library asset re-buy keys the same id the subsequent open's rights check reads. |
ESP-1 acceptance: unavailable calldata on any candidate aborts with a stable fail-closed error (mirror candidate_input_unavailable); a test with newest-calldata-unavailable + older same-KID binder proves no fallback to the older asset; transport errors keep propagating as errors (already the case via ?).
ESP-2 acceptance: shared resolver extracted and called by both buy_owned_access and the open path; re-buy of a dKMS-minted capsule asset records ownership under the capsule content_id; the misleading doc comment is corrected by the shared code path itself.
Dispositions — no plan change
- Wallet auto-approve (
ELASTOS_DDRM_BUY_SIGN=wallet), raised High: already shipped in the state the review asks for.wallet_signing()requirescfg!(feature = "dev-modes")and is unconditionallyfalsein release builds (buy_authority.rs), the inline approve carries the explicit council-S41-F1 FOOTGUN comment pointing at the Wallet/Inbox consent split, and the PARKED subject-resolution rewire is tracked indocs/superpowers/specs/2026-08-07-roadmap-gap-bulk-plan.mdand theviewer_open.rsPARKED block. Routing live signing through Inbox consent remains the tracked follow-up before anything beyond operator dogfood; the compile gate is the "explicitly gate as operator-dogfood-only" mitigation. - Expired media sessions (manifest/init/cover), raised Medium: did not reproduce on the reviewed commit. Every media route — manifest, init, cover, segment, track init/segment — authorizes via
authorize_media_session→get_media_session, andget_media_sessionrunssession_bounds::sweep_expiredinline on every lookup (viewer_media.rs), so an expired session 404s immediately on all routes; there is no 60s-sweeper window. The explicitexpires_atchecks in the segment handlers are redundant defense-in-depth, not the only expiry gate.
Staged remediation of eight authorization, replay, lifecycle, revocation, initialization, persistence, and configuration findings from the 2nd review of the dKMS path (feat/dkms-esp-port), without weakening the fail-closed CEK boundary. Each stage was implemented test-first and security-reviewed; every regression test's #[ignore] is removed as its fix lands, so the final tree leaves zero dKMS regression tests ignored. Stage 0 — reproduce and freeze the vulnerabilities: - 16 focused regression tests across capsules/dkms-authority and capsules/ddrm-envelope, each asserting the secure invariant and run RED on the reviewed baseline. - Adversarial counting RPC double (magic / non-magic / revert / malformed / timeout / transport-error, ordered scripts) at the node's RPC boundary. Stage 1 — bound and bind grant addresses (DKMS-1, DKMS-4): - Owner-only access: pure validate_covered_addresses rejects empty, over- cardinality, over-size, malformed, duplicate, and unrelated entries before any signature or RPC work; normalize_evm_address canonicalizes every address before equality, dedup, cache-key, and RPC construction. - VerifiedAccess now exposes only the validated [owner] set, never a caller-supplied clone; new CoveredInvalid fail-closed error. - Named bounds (MAX_COVERED_ADDRESSES, per-entry/per-list size caps) and an explicit pre-dispatch fan-out guard (validated_subjects x rpc_pool_len). Stage 2 — unify EIP-1271 quorum decisions (DKMS-2): - One typed RpcVote<T> outcome model and a single generic combine_votes<T> agreement combiner shared by hasAccessByContentId and EIP-1271, so one endpoint can never decide smart-account signature validity. - EIP-1271 aggregation polls the entire configured pool (no first-reply short-circuit), classifies each endpoint (magic=Valid, non-magic/revert= Invalid, malformed/transport=Unavailable), and fails closed on insufficient reachability or valid/invalid disagreement; verdict is order-independent. EIP-191 fast path and endpoint-URL non-leakage preserved. Stage 3 — bounded two-phase replay state machine (DKMS-3): - New ddrm-envelope::replay module: injected ReplayStore + RAII Reservation (begin->InFlight, commit->seen, Drop->abort) so no lock is ever held across EIP-1271/access RPC, KEM, signature, or I/O work. Fixed-size Keccak nonce keys with decoded-length caps; time-ordered heap pruning with bounded work per call; documented global + per-delegation bounds; capacity fails closed without evicting unexpired records. Structural-, owner-signature-, and request-signature-invalid input reserves nothing; concurrent identical requests commit at most once. commit records the seen entry unconditionally, and NodeChain::from_env fails closed unless IN_FLIGHT_TTL > MAX_COVERED_ADDRESSES x pool_len x ETH_CALL_TIMEOUT. Retires the process-global replay_guard singleton for an injected store. Stage 4 — secure bootstrap and atomic persistence (DKMS-7): - New secure_store module: exclusive same-directory temp created O_EXCL at mode 0600 (no chmod-after-write window), hard_link install that refuses to overwrite or follow a planted final symlink, fstat-verified no-follow read, fsync of file and directory, RAII temp cleanup. Concurrent first starts converge on one durable identity (race loser re-reads the winner); corrupt or unreadable state fails closed and never resets to empty. - Node identity is loaded/validated before any listener binds; Request::Init is refused on every network transport; keystore path comes only from process configuration; provisioning moves to an offline provision subcommand. Primitive is reusable by Stage 6 revocation state. Stage 5 — version and fully bind lifecycle authorization (DKMS-5): - One shared ddrm-envelope::lifecycle v2 encoder with four phase-separated domains (reshare-contribute, reshare-install, dkg-contribute, dkg-install), length-framed and collision-resistant, locked by byte-pinned golden vectors. LifecycleManifestV2 -> SHA-256 digest -> domain-separated AAD binds operation+version, kid, scheme, ceremony id, old/new set ids, thresholds, ordered member records INCLUDING recipient keys (the field the node-set-id derivation provably omits), executing node/coordinate, cek_len, and per-input-object digests. All four node ops verify operator authorization and reserve ceremony replay BEFORE opening any share/sub-share or deriving polynomial material; dkg_install recomputes node_set_id from supplied membership. v1 lifecycle AAD is gone from node paths (no mixed v1/v2). Stage 6 — complete and persist revocation (DKMS-6): - New security_state module: versioned durable SecurityState (caller + delegation revocations) persisted through the Stage 4 secure_store primitive; in-memory RevokedSet/ReplayStore are caches hydrated from durable truth at startup on every adapter including stdio. New node-reachable revoke_delegation op carries an operator-signed, domain-separated record (delegation nonce, scope, expiry, issued-at) verified before persisting; wrong-signer/foreign-nonce/expired are rejected. Caller and delegation revocations persist before success is returned and are consulted before replay reservation / CEK work. Corrupt/unreadable/unknown-schema state fails closed and never resets to empty. Compaction drops only expired delegation revocations, never standing caller revocations, atomically. Durable write failure cannot return success. Stage 7 — fail-closed allow-list configuration (DKMS-8): - Typed caller_policy_from_env -> Result<CallerPolicy, ConfigError> parsed once before any listener binds on every serve path. Anonymous mode requires the explicit DKMS_AUTHORITY_ALLOW_ANONYMOUS=1 opt-in; unset, empty, malformed, mixed, duplicate, and contradictory are distinct fatal states that can never silently degrade to anonymous. Whole-list rejection on any malformed entry; duplicates rejected deterministically; startup diagnostics report mode/count only (never key material). Stage 8 — integration, observability, docs, and CI gate: - Wire capsules/dkms-authority into the just verify-capsules gate (both default and dev-modes lanes) so the whole dKMS regression suite runs in CI; the suite previously never executed under any gate. - New secret-free operational counters (counters.rs) for fail-closed events: rejected list bounds, quorum disagreement/unavailability, replay capacity/ in-flight, revocation load/write failure, invalid allow-list, and lifecycle manifest mismatch. Counters are event-only AtomicU64 tallies rendered to stderr; no keys, nonces, seeds, addresses, signatures, or URLs. Wiring is strictly observe-only and changes no control flow or auth decision. - Deployment runbooks, DKG/re-share ceremony docs, env templates, preflight, and dev harnesses updated for offline provisioning, the revocation migration (existing nodes start with empty durable revocation state after upgrade and must re-issue standing revocations), v2 lifecycle manifests (no mixed v1/v2 ceremony), owner-only grants, and the explicit-anonymous posture. The ddrm-runtime-open dev harness main verify rail is migrated to offline provisioning; its adversarial-probe / live-lifecycle scenarios (which still drive wire init + v1 auth against the now-hardened node) are marked PENDING-MIGRATION in-code and documented in DEV_SETUP, and are excluded from the security gate.
…family Fixes a family of pre-existing flaky tests in the elastos-server gateway test suite that failed non-deterministically under `cargo test --workspace` / `just test` parallel load. All are TEST-HARNESS timing artifacts — no production reconciler/gateway/room code is touched. Three distinct mechanisms, one theme (a test waits on a proxy signal instead of the real completion condition, and a clock race cancels an instant op): - browser_reconciliation (hanging / stale / transient / runtime_restart, and the latent sibling newly_committed_launch_obligation_wakes_reconciler): under a paused virtual clock, a retry close briefly parked on the global BROWSER_SESSION_REGISTRY async mutex (held by parallel tests across blocking std::fs I/O in load_durable_ownerships) leaves the runtime idle, so tokio's paused-clock auto-advance jumps virtual time to the 30s tokio::time::timeout and cancels a close that completes in microseconds. Fixed by a settlement helper that keeps a task runnable (denying auto-advance) and waits on the real drained/obligation condition under a bounded cap, replacing fixed 0..N sweep budgets. - gateway_browser_route_tests (wallet_read_timeout_does_not_poison_ chain_dispatch / _wallet_refresh): a real-clock race on the `!late_result_observed` observation; fixed by converting to a paused clock (start_paused) so the ordering is deterministic. - room (chat_room_transport_joins_bootstrap_peer_after_topic_already_joined): a real-clock cadence race against a ~2s OS-thread bridge starved under CPU oversubscription; fixed with a bounded wall-clock deadline in the shared transport test helpers. No assertion was weakened and no retry budget was merely bumped: every fix waits on the real completion condition under a generous BOUNDED cap, so a genuine hang still fails loudly. The periodic controlled-reconciler tests were investigated and deliberately left unchanged — their retry sweeps legitimately require virtual-time auto-advance and are not part of this family. Proof: full elastos-server lib 11/11 runs under parallel load at 1359 passed / 0 failed; focused hammer of all five affected tests 30/30 runs at 5 passed / 0 failed.
Two P1 findings from the 2026-08-12 external review (Sash) of the branch's
money path. Marketplace/runtime seams, not dKMS-authority-node paths, but
they block production exposure of the buy/trade path.
ESP-1 — trade approval fails closed on unavailable mint calldata:
- capsules/chain-provider/src/main.rs scan_asset_created_for_content_id (the
trade-approval resolver) silently continue'd when a candidate mint's
calldata could not be fetched, while the buy resolver already fails closed
(candidate_input_unavailable). Because candidates are sorted newest-first
and a re-mint reuses the KID, an unavailable newest calldata could fall
through to an OLDER same-KID binder — a wrong-operative/token-id approval.
The trade resolver now pre-fetches every candidate's calldata and aborts
the whole resolve on any unavailable one, mirroring the buy resolver; no
decision is made on a partial candidate set. Transport errors still
propagate. Regression tests: newest-calldata-unavailable + older same-KID
binder aborts (no fallback); fully-available set still resolves; transport
error propagates.
ESP-2 — buy and open share one content-id resolver:
- elastos-server/src/api/viewer_open.rs buy_owned_access derived content_id
from content_cid / owned:{name} and never parsed the .ddrm capsule, while
the open path prefers the capsule content_id/kid first — so a dKMS-capsule
Library re-buy was keyed on an id the rights gate never reads back (money
spent, open still denies). One shared resolve_owned_content_id (capsule
content_id -> kid -> content_cid -> owned:{name}, byte-identical to the
open path's prior derivation) is now called by both the open path and
buy's legacy owned-root branch; the req.content_id fast path is unchanged
and the previously-false "resolves EXACTLY as /api/viewers/open does"
comment is now true. Regression test proves a capsule re-buy keys the same
id the subsequent open's rights check reads.
seal_operator_auth was the v1-AAD operator-seal test helper; the DKMS-5 v2-manifest migration moved every call site to seal_v2, leaving it dead in both CI lanes and failing just verify-capsules under -D warnings.
Anders' review, mapped to current branch state — remaining workMapping of Anders' 2026-08 review note against what has already landed on
Remaining (untreated) — todo
Note: |
|
Decision: do not merge feat/dkms-esp-port into upstream/0.7-dev as one change. Keep the branch as source material. We will extract the useful work into smaller review branches built on review/collaboration-candidate. The August goal remains one complete path: A creator encrypts content with a CEK. The custody layer protects that key under a declared quorum policy. A buyer finds the content, pays, and receives a signed right. Opening the content requires both the declared availability threshold and dKMS threshold. The raw CEK must never appear in the content object, Runtime, Carrier, an application capsule, or an ordinary receipt. It may exist only inside the reviewed custody and decrypt boundaries. feat/dkms-esp-port combines custody, protected open, commerce, Home UI, deployment configuration, and a large Runtime workflow. That is too much authority and too much product behavior for one merge. The intended boundaries are:
Current base The current 0.7 work line is review/collaboration-candidate. It contains the collaboration foundation, product integration, Profile authority, and Runtime-owned Carrier provider path. The protected-content work must build on that line, not on bare upstream/0.7-dev or feat/dkms-esp-port. Before publishing it, we will add the general Home source-setup guide to review/collaboration-candidate and rebase the protected-content branch onto the updated parent. First branch for review feat/protected-content-contracts currently contains seven commits. It defines:
This branch is source-only. It does not run dKMS nodes, replace the provisional Runtime provider surface, reconstruct keys, prove recipient encryption, decrypt content, play media, sell content, or modify the installer. The branch needs independent cryptographic and custody review before provider integration. Proposed extraction order
Required gates
The old WireGuard deployment and bespoke dKMS ALPN bridge remain useful evidence only. They must not define the 0.7 capsule or Runtime contract. We will mine feat/dkms-esp-port for reviewed code and tests. We will not merge it as one branch. |
… and document viewing - Introduced elacity-player capsule for playing owned fMP4/CENC audio and video assets. - Added ddrm-viewer capsule for viewing owned non-media assets. - Updated entry points in capsule.json files to reflect new directory structure. - Implemented HTML, CSS, and JavaScript for elacity-player, including media streaming and overlay handling. - Enhanced library actions to ensure protected assets are opened correctly from the user's library. - Introduced server-side support for owned asset opening, ensuring proper authorization and context handling. - Added favicon and styling for elacity-player interface. - Updated setup scripts to include new viewer capsules for installation.
- Introduced a new HTML interface for creating assets in the `capsules/creator/browser/index.html` file. - Updated the capsule entry point in `capsules/creator/capsule.json` to point to the new HTML file. - Adjusted comments in `capsules/home/browser/home-shell-host.js` to reflect the new file structure. - Modified tests in `elastos/crates/elastos-runtime/tests/capability_conformance.rs` to use a temporary directory for audit logs. - Cleaned up imports in `elastos/crates/elastos-server/src/api/gateway.rs` and `elastos/crates/elastos-server/src/api/viewer_open.rs`. - Added a test to ensure browser capsules remain launchable after changes in `elastos/crates/elastos-server/src/api/gateway_tests/dkms_capsule_manifests.rs`.
…signed grants Protected `.ddrm` / owned media assets hung forever on "Preparing secure session" (or looped on a passkey sign-in) and never opened. The ESP Home shell could not produce the wallet-signed access delegation the dKMS quorum requires: the open path signed the delegation via `window.ethereum`, which is not injected into the shell iframe, and several downstream gates were unwired for the shell-driven, connector-brokered flow. Route the delegation signature through the user's DEFAULT wallet connector capsule (which holds the injected wallet), end to end: - Resolve the DRM subject per-principal from the signed-in principal's own verified EVM proof binding — no operator-pinned wallet. - Admit the graphical/CLI Home shells to the owned-open auth gate (same actor set, no widening) and add a launch-returning variant so the open path can mint a wallet authority. - `prepare-grant` surfaces the principal's default EVM connector; a new `/api/viewers/prepare-grant/sign` mints a `ddrm_delegation_sign` personal_sign approval bound to the owned open and validated against that default connector; the connector signs the `delegation_canonical` verbatim with its own wallet; the gateway assembles the grant. The wallet-provider now accepts, message-binds, and surfaces this signing intent. - The shell auto-routes the approval to the default connector and polls (bounded, fail-soft) for the signature, then opens. A 403 now shows an explicit error instead of an infinite sign-in reload loop.
…arrier-node - Added a logging mechanism with configurable log levels (error, warn, info, debug, trace) for both dkms-authority and dkms-carrier-node. - Enhanced logging to include connection details, stream relays, and error handling while ensuring no sensitive information is logged. - Updated docker-compose to bind log directories for easier access to logs during debugging sessions. - Modified entrypoint script to mirror daemon logs to host-visible files for better traceability.
A chain of legacy→ESP contract mismatches broke minting and opening protected
dDRM assets in the ESP shell — each a component still speaking the pre-ESP
contract. This fixes those code paths and adds the per-stage diagnostics used to
find them.
Mint (creator.rs):
- Migrate the entire creator money-path off the legacy v1 wallet protocol to the
v2 WalletContract: account lookups, signature requests, and approval reads now
dispatch WalletProviderOperationV2 (ListAccounts / RequestApproval /
ListApprovals) through a single `wallet_invoke` seam and one
`request_transaction_approval`. The v2 provider rejected the old
`{op:"accounts"|"request_signature"|"approval_requests"}` shapes. Each handler
mints a RuntimeWalletAuthority from its creator launch token; since the authority
carries the principal, the now-redundant `principal_id` params and the duplicate
token-validation gates were removed.
- Build a fully-specified transaction via chain-provider `prepare_transaction`
(nonce/gas_price/gas_limit) before the connector handoff — the ESP handoff
validates gas/gasPrice/nonce and rejected the gas-less "let MetaMask estimate"
intent ("missing field `gas`").
Open (viewer_open.rs):
- Mint viewer launch tokens via projection (authority_actor=home), not direct
(authority_actor=<viewer>). The auth-session grant admits only the shells
[home, system], so direct tokens failed object-session reads with a 401
"authority context mismatch". Applies to both object and media viewers.
Diagnostics:
- viewer_open: host-side dKMS node-set precheck (MATCH/MISMATCH) + vk-fingerprint
evidence and per-attempt recover traces.
- creator: creator_status / creator_wallet outcome logging.
- viewer_object: surface the object-session 401 reason.
- gateway_home_runtime: log the launch route with the home_token value masked
(proves fragment delivery without leaking the capability).
- browser_capsules: log every capsule asset fetch.
Docs:
- TROUBLESHOOTING.md §11–§17: symptom→cause→fix for each failure, plus the log
surfaces and grep lines used to diagnose the flow.
- run cargo fmt over the three files committed unformatted - shrink the raw-wallet-dispatch debt ledger: creator.rs no longer dispatches raw "op":"accounts" (rewired onto RuntimeWalletAuthority) - browser wallet-read timeout tests: measure the paused virtual clock (tokio::time::Instant) instead of wall time, which flaked under load - wrong_session_key_fails_closed: assert the CEK never materializes rather than relying on PKCS#7 unpadding to reject (~1/256 flake)
|
@andersalm it's now fixed, e2e mint -> open/playback is working now. Im not sure if the implementation fit with the intended way you were thinking but today dkms and dDRM workflow is working on top of the ESP basically. Any further insights would be welcome so we can adjust it when working it on the new branch based on the |
…inks (PoC) A purpose-built logging library (not log/tracing) with five severity levels and a multi-sink writer interface, wired into the Rust components touched by the recent dDRM/dKMS work as a proof of concept. Motivated by that debugging session, where diagnostics had to be added ad-hoc across `eprintln!` providers and two hand-rolled per-component leveled loggers. Crate elastos/crates/elastos-logger: - Level: Trace < Info < Warn < Error < Critical; a record emits iff level >= threshold. "debug" is accepted as an alias for Trace. - LogSink writer interface (the SOLID extensibility seam): StderrSink, StdoutSink, FileSink, VecSink (test double). A future provider sink is one more impl with no change to Logger. - Logger facade fans a single record out to many sinks at once; process-global init/enabled/emit with a pre-init stderr@Info fallback so early logging never panics. - LoggerConfig + resolve_level with precedence CLI > env > default(Info); each binary owns its own arg parsing and chooses which env vars it honors. - log_critical!/log_error!/log_warn!/log_info!/log_trace! macros (lazy — no formatting cost when below threshold) + fp() privacy fingerprint so TRACE stays secret-free. - Dependencies: std + time + sha2 + hex only. Full unit coverage of level filtering, parsing, fan-out, config precedence, macros, and fp. Wiring (the components changed in the last commits): - key-provider, chain-provider, wallet-provider: eprintln! -> levelled logging. - dkms-authority, dkms-carrier-node: bespoke LogLevel/oplog! subsumed into the shared crate; the legacy DKMS_*_LOG_LEVEL env vars are preserved; every lifecycle/error line converted and the doubled component prefix dropped so the level knob governs all output. - docker-compose: the local dKMS quorum nodes default to trace. The gateway (elastos-server) and JS/browser capsules are intentionally out of scope for this PoC and fold in during the system-wide rollout. Plan: docs/superpowers/plans/2026-08-17-elastos-logger.md
|
@irzhywau Thanks. The working mint -> open/playback path is useful. We will use it as product and test reference, but we still will not merge this PR as one branch. The extraction has moved forward:
We will bring over the PR's user flow: Creator publish, buyer purchase, and viewer open/play. We will also reuse reviewed node-operation ideas such as encrypted share storage, signed contributions, quorum failure tests, health checks, and rotation runbooks. The final boundary is different from the current PR wiring:
We are adding one missing policy layer before product integration: a signed eligible custody pool and a fixed per-object committee. The first release should use 2-of-3 nodes across independent operators or failure domains. Pool changes must not silently replace an object's nodes. Replacement requires an explicit re-share and a new signed custody epoch. We are not adding staking, election, or consensus in this release. The most useful follow-up from your side would be a short map of:
The new |
|
@andersalm Re: your required gate "new providers and capsules are present in the normal installer before any installed-product claim" — we've set up CI that mechanically proves this: #19 runs (For avoidance of doubt: the failing |
|
@SashaMIT re-run the failing job (without any changes) seems have the failure gone :-/ |
|
Thanks. Good the re-run went green. Still treating this PR as source material for the smaller extract branches, not as one merge, per Anders. |
|
@irzhywau @SashaMIT update since the last extraction note. PR #15 remains useful source material, not the merge target. The next source-only custody slice is now complete locally:
This branch now proves the custody-provider boundary:
The relevant contract, custody, and native provider-process tests pass. Independent review found and closed path-redirection, unbounded-frame, shutdown, secret-zeroization, and rights-denial classification issues. From PR #15, we kept the useful product behavior and test ideas: the mint/open/playback flow, threshold custody shape, one-share-per-node direction, recipient-sealed contributions, CEK commitment, and lifecycle/failure cases. We did not carry forward the public aggregate The new provider is still local, unpublished, unregistered, and not installed. The old provisional Next:
So PR #15 remains valuable as working UX and integration evidence, while the merge path stays the smaller reviewed protected-content branches. |
Protected-content alignment — preliminary brainstormingDate: 2026-08-18 · Revised: 2026-08-20 (remote refresh: custody-provider published, three 0. How to use this document (for humans and agents)This file is the working synthesis for the protected-content alignment program: getting Rules for agents working from this doc:
Pinned refs (all verified 2026-08-21; re-run
Reading order: §1–2 (goal + canonical invariants) → §5–6 (stack + gap) → §10 (latest 1. GoalA working application with e2e Mint → Play/Read — like 2. Source-of-truth status
Already implemented on the candidate (the "foundational parts"):
Still todo / to-pick (adjusted, not copied): everything that makes those providers real — Canonical boundary invariants (the bar every ported piece must meet):
3. PR #15 inventory (what exists on
|
| Area | Key files (branch: feat/dkms-esp-port) |
|---|---|
| Creator publish/mint | capsules/creator/; elastos-server/src/api/{creator.rs,mint_authority.rs} (passkey step-up on /api/create/mint; WalletProviderOperationV2 rewire in ffea5998/e148218b) |
| Encrypt/package pipeline | capsules/encrypt-provider/ (+CENC vectors), capsules/cenc-core/, capsules/ddrm-media/ (mp4.rs,mpd.rs,rail.rs,seal.rs), capsules/ddrm-envelope/, capsules/ddrm-plan-runner/, capsules/publish-provider/, capsules/availability-provider/ |
| Buyer purchase | /api/market/* rail: gateway_marketplace.rs, market_reads.rs, buy_authority.rs, trade_authority.rs, owned_ledger.rs, rights_authority.rs, chain_tx.rs, wallet_signer.rs, gateway_passkey_step_up.rs; capsules/content-market/, capsules/marketplace-content/, capsules/chain-provider/ |
| Viewer open/play | /api/viewers/*: viewer_open.rs (~2.2k L, PARKED block), viewer_media.rs, viewer_object.rs, viewer_gateway.rs, viewer_grant_sign.rs, media_authority.rs, object_authority.rs, access_grant.rs, session_bounds.rs, session_lifecycle.rs; capsules/elacity-player/ (fMP4/CENC), capsules/ddrm-viewer/ (3D/docs, vendored three.js loaders) |
| dKMS node | capsules/dkms-authority/ (main.rs 8.8k L, secure_store.rs, security_state.rs, counters.rs, node_chain.rs; release compile_error! guard on dev-modes/legacy-receipt-authz), capsules/dkms-keygen/, capsules/key-provider/ (client, 5k L), quorum smokes (1-node / 2-of-2 XOR / 2-of-3 Shamir GF(256)), scripts/dev/dkms-docker/ 3-node compose, docs/dkms/deploy/ runbooks |
| Decrypt boundary | capsules/decrypt-provider/: CENC engine (src/cenc/), PQ envelope x25519+ML-KEM-768 (pq_envelope.rs), pixel-lock renderers (src/render/), 14 golden-vector suites |
| Transports (rejected wiring) | see §7.3 |
| Logger PoC (tip) | elastos/crates/elastos-logger/ — see §8 |
| CI / proof | just verify-ci, just verify-capsules, dKMS release-invariant CI job (release must FAIL to build with dev features), ddrm-*-smoke.sh family, gateway_tests/dkms_rail.rs |
| Docs | docs/dkms/ hub (50 files incl. 16-file history/), DKMS_OVER_CARRIER.md, specs under docs/superpowers/specs/ |
Working-e2e caveat. Mint → open/playback works and is accepted as reference, but
chain-gated open/buy is dev-lane-only: resolve_subject_address (viewer_open.rs)
is fail-closed pending the PARKED RequiredHomeLaunchToken subject rewire;
ELASTOS_DDRM_SUBJECT is dev-modes-only with a release boot guard. The dkms_rail.rs
gateway tests prove the join, deliberately not the decrypt legs (stated in-file).
4. PR #15 thread — decision log (chronological)
- 2026-08-12 SashaMIT (review) — targeted security pass; money-verb step-up, fragment
launch tokens, live tokenId binding, dKMS release invariant all verified; 4 pre-merge
items (wallet auto-approve lane, media-session expiry, trade resolver, Library re-buy id). - 2026-08-12 irzhy — 2 items retained as ESP-1/ESP-2 (P1, marketplace/runtime seams);
wallet auto-approve alreadydev-modes-gated; media-expiry did not reproduce
(sweep_expiredruns inline on everyget_media_session). - 2026-08-13 irzhy — maps Anders' review note: cross-wallet grant flaw closed
(943c10d1, owner-only grants), execution model reconciled (WASI dropped); six open
items acknowledged incl. wrong-base, carrier end-state, installer, trusted-core slimming. - 2026-08-13 Anders — the governing decision. Do not merge as one branch; keep as
source material; extract ontoreview/collaboration-candidate. August goal: one complete
path (creator encrypts CEK; custody under declared quorum policy; buyer pays and receives
signed right; open requires availability threshold AND dKMS threshold; raw CEK only inside
reviewed custody + decrypt boundaries). Extraction order: 1 custody → 2 content
availability → 3 Runtime integration → 4 protected open → 5 commerce. Gates: no dual
authority, installer presence before installed-product claims, physical quorum tests
(restart, revocation, partial failure, exact settlement). WireGuard/ALPN bridge =
evidence only. - 2026-08-17 irzhy — e2e mint → open/playback working.
- 2026-08-17 Anders — accepted as product/test reference; still no single-branch merge.
Extraction now at contracts1865595f/ custody29879b25/ key-reconstruction
a8d0a9a6. Final boundary restated (capsules: typed requests only; Runtime: authority,
provider selection, coordination, audit; Carrier: transport, no IP/port/WireGuard/ALPN in
capsule or product contract; nodes: independent verification, one recipient-encrypted
signed contribution; decrypt boundary: reconstructs and uses CEK). New policy layer before
product integration: signed eligible custody pool + fixed per-object committee, first
release 2-of-3 across independent operators/failure domains; pool changes must not
silently replace an object's nodes — explicit re-share + new signed custody epoch; no
staking/election/consensus. Requests the file map (§7). elastos-logger excluded
from the protected-content extraction as separate work. - 2026-08-18 SashaMIT — PR chore(ci): source-gate and source-home on ubuntu-latest and macos-14 #19 adds the installer CI gate (
setup-source-home.sh+
installed-provider-verify.shon linux-amd64/arm64 + darwin-arm64 per PR); the PR dKMS/dDRM foundation on the ESP substrate (inspired from flint-5.0) #15
CI red is the knownbrowser_reconciliationtiming flake (1396/1397, green on re-run). - 2026-08-18 18:51 Anders (latest, after the comment quoted in-session) — local branch
feat/protected-content-custody-provider@f7cd6c3d(treeb9b93460): custody-
provider boundary proven source-only — per-object binding to exact pool/epoch/committee/
node-set/threshold; one sealed share per node; owner-only durable restart-validated
corruption-detecting exact-idempotent node state; release requires valid signed rights
decision, returns only a recipient-sealed contribution; frames bounded; responses expose
no CEKs/shares/routes/addresses/ports/paths/credentials. Kept from PR dKMS/dDRM foundation on the ESP substrate (inspired from flint-5.0) #15: flow shape,
threshold custody, one-share-per-node, recipient-sealed contributions, CEK commitment,
failure cases. Not carried: publicshares[], capsule-owned authority, raw-CEK ops,
network topology in product contracts, compatibility rails, static auth fallback.
Next: (1) atomic Runtime registry cutover removing old key/DRM path, (2) contribution
collection → private reconstruction/decrypt → scoped viewer output, (3) real installed
mint → buy → open → play with deny/tamper/replay/restart/cleanup. - 2026-08-18/20 (branches, no new PR dKMS/dDRM foundation on the ESP substrate (inspired from flint-5.0) #15 comments) — the custody-provider branch is
published (origin/feat/protected-content-custody-provider@f7cd6c3d), and the
stack extends with three new published steps:feat/protected-content-wallet-rights
(2c69d0c2),feat/protected-content-runtime(b00bfeeb),feat/protected-content-rights
(43a83e5b) — see §5. Therightstip carries a truth pass (43a83e5b) that rewrites
docs/PROTECTED_CONTENT.md/TASKS.md/ROADMAP.md/state.mdwith a formal
"PR dKMS/dDRM foundation on the ESP substrate (inspired from flint-5.0) #15 disposition" (keep-as-research / reimplement-at-boundary / reject lists) and
an 8-step "Remaining sequence" — this supersedes §6's first gap table. - PR docs(protected-content): mint→sell→buy→play journey implementation plan #22 (
cursor/protected-content-journey-plan-af9e, based on custody-provider,
one docdocs/PROTECTED_CONTENT_JOURNEY_PLAN.md) — proposal-stage mint→sell→buy→play
journey plan with UI/UX focus (design tokens, Home spend prompt, consolidated Store);
schedules the PARKEDRequiredHomeLaunchTokenrewire into its Phase 2; includes a
reuse/re-derive/reject disposition vs PR dKMS/dDRM foundation on the ESP substrate (inspired from flint-5.0) #15. No review comments yet. - Housekeeping — PR chore(ci): source-gate and source-home on ubuntu-latest and macos-14 #19 CI matrix now ubuntu-latest + macos-14 (
1d6b49e3); PR feat(home): paint house URUX onto freeze contracts #23
feat/home-urux-on-freeze(Home UX track, separate); PR docs(agents): add Cursor Cloud environment setup notes #21 Cursor cloud env docs;
stale shell-protocol/shell-ui branches deleted on the remote.
5. Extraction stack — precedence and per-step additions
origin/main (d358dedb)
└─ review/collaboration-foundation ── product-integration ── … ── b07160cf ← fork point
├─ +3 → review/collaboration-candidate @ 5f1fb004 (HEAD; adds system-map docs merge)
└─ +7 → feat/protected-content-contracts @ 1865595f
└─ +14 → feat/protected-content-custody @ 29879b25
└─ +1 → feat/protected-content-key-reconstruction @ a8d0a9a6
└─ +19 → feat/protected-content-custody-provider @ f7cd6c3d
└─ +1 → feat/protected-content-wallet-rights @ 2c69d0c2
└─ +2 → feat/protected-content-runtime @ b00bfeeb
└─ +3 → feat/protected-content-rights @ 43a83e5b ← stack tip
The stack forks 3 commits behind the candidate tip: it sits on the full collaboration +
Home-shell base but predates the system-map docs merge. Strictly linear, no merges.
- contracts (+7, 62 files, +5.4k) — crate
elastos-protected-content-contracts:
canonical domain-separated binary encoding (JSON inspection-only); content/key-envelope/
recipient/Profile identities;NodeSetV1; EIP-191 wallet-signed rights requests (strict
0/1 recovery byte); signed rights receipts; bounded key-release requests; per-node signed
decisions; recipient-sealed contributions (no Serde on sealed types); signed terminal
receipts (window nesting enforced); 38 tests + golden vectors. Plus strictdid:key
Ed25519 authority threaded through did-provider/identity/collaboration files. - custody (+14, 42 files, +9.2k) — contract modules:
CustodyEnvelopeV1(+HPKE suite
pins),SignedCustodyEpochV1(immutable epoch over node keys/coordinates/threshold/
suites — the review's "signed custody epoch"), narrow EVMRightsPolicyBodyV1,
SignedRecipientKeyAuthorizationV1(explicitly not possession proof),
SignedRuntimeReleaseOperationV1(verification yields replay-pending only). New crate
elastos-protected-content-custody(forbid(unsafe_code); hpke 0.13, vsss-rs GF256
Shamir):provision.rs(split + seal per node + CEK commitment),release.rs(node
re-seals own share to recipient; 13 negative tests),replay_store.rs(1.9k L durable
dual-key claim store, exact-result replay after restart, fail-closed torn state),
reconstruct.rs(exact-threshold, commitment-checked). ~116 tests across both crates. - key-reconstruction (+1, 4 files) — reconstruction re-keyed to
AuthenticatedRuntimeReleaseOperationV1(old bare entry demoted to#[cfg(test)]);
doc wording: reconstruction happens "inside the decrypt boundary"; 24 tests. - custody-provider (+19, 37 files, +15.7k) — now published. Lands all three previously
"local follow-ups" plus the policy layer: private provider protocol (706f330d),
authenticated chunk payload (3a72ca5d), local decrypt output boundary (4521fd4d),
object-bound custody pool policy + object↔policy binding (11bda1a0,f1b3dd4b),
one-node custody state + protocol (bbe0691d,c5bf7fca), provisioning authorization
and validation (88c592df,7777e88f), sealing derived from the verified committee
(25d3e72f), pinned Runtime issuer validation (71f51efc), node-local durable share
persistence (7d5467c9), and the custody provider process itself (1fefa07c); plus
authority-truth doc reconciliations. - wallet-rights (+1) —
wallet-providersigns rights requests:approval.rs,
crypto/evm/signature.rs,validation.rs, newtests/approvals/protected_content.rs. - runtime (+2) — new crate
elastos-protected-content-runtime
(coordinator.rs,journal.rs): durable Runtime release state persistence
(7f609118) and Runtime release-authority coordination (b00bfeeb); touches
elastos-server/src/provider_resource.rs. - rights (+3, stack tip; CP..tip = 35 files, +8.4k) — new crate
elastos-protected-content-rights; chain rights evidence viachain-provider
(backends.rs,validation.rs, tests) (7c747253); typed rights decision evaluation
(a32ae85a); and the truth pass43a83e5brewriting the four truth files (see §6).
All of it is stamped source-only at every level (crate docs, Cargo descriptions,
docs/PROTECTED_CONTENT.md remaining-sequence stages A–D). Known stated limits: no
Runtime wiring/replay orchestration/possession proof/decrypt/install; hpke 0.13 not
formally audited (no external crypto claim); commitment ≠ verifiable secret sharing;
replay store does not defend malicious same-UID rewrite; no durable operation-resume
journal (crash between claim and settlement ⇒ fresh operation).
Anders' three "local source-only follow-ups" map to documented stages: private provider
protocol → stage C atomic DTO/provider replacement; payload sealing → "Future sealed
decrypt handoff"; staged decrypt output → scoped output/opaque session handle in
DECRYPT_PROVIDER.md. The custody-provider branch (§4.8) has since landed the first of
these locally.
6. Gap to the goal
The governing order is now the 8-step "Remaining sequence" in the rights tip's
docs/PROTECTED_CONTENT.md (43a83e5b), which refines Anders' original 5 steps. Status
per step (everything on the stack remains source-only — nothing registered/installed):
| # | Remaining-sequence step (rights tip) | Status today |
|---|---|---|
| 1 | Inactive Runtime provider lifecycle/registration/routing + durable reconciliation seam (Runtime owns selection, journal, audit, retry, terminal settlement, crash recovery) | Started source-only — elastos-protected-content-runtime (coordinator.rs, journal.rs) |
| 2 | Typed rights-provider process adapter, Chain evidence only through Runtime/provider registry (no direct RPC, no caller-supplied evidence) | Started source-only — elastos-protected-content-rights + chain-provider evidence + wallet-signed rights requests |
| 3 | Recipient key-possession proof + decrypt-session authority before CEK reconstruction/use | Not started (Profile authorization alone declared insufficient) |
| 4 | Runtime-owned producer mint journal/state machine for one media flow (stage → bind facts → per-stage receipts → provision shares → recover after restart → commit availability → list; durable mint-abort on partial provisioning; first proof needs three distinct custody identities for 2-of-3) | Exists locally, unpublished per the 2026-08-21 note (§10) — with three known problems to fix before further product work; nothing on published refs. Absorbs the old "content availability" step (availability commit is a mint stage) |
| 5 | Real Wallet purchase + exact Chain evidence + Runtime open + private reconstruction/decrypt + opaque scoped viewer output (no bearer playback URL; launch tokens stay HTTP-edge credentials) | Not started — this is where PR #15's open/play flow gets rebuilt |
| 6 | Full inactive e2e proof: mint → buy → open → play, 3 custody providers, allow/deny/tamper/replay/restart/cleanup, no CEK/share/topology leakage | Not started — adapt PR #15 dkms_rail as behavioral oracle (per PR #22) |
| 7 | Atomic replacement/removal of provisional drm/key/decrypt authority — no fallback, no dual authority |
Not started; only after 6 |
| 8 | Minimum one-media UI + installed two-principal acceptance proof | Not started — PR #22 journey plan covers the UI/UX side |
Cross-cutting gaps (not owned by a single step):
- Transport rewrite —
key-provider's endpoint-aware client (Unix/tcp:/carrier:- sidecars) must become a Runtime-selected route behind the provider registry/Carrier
adapter; the WireGuard mesh + ALPN bridge stay evidence only. See §7.3.
- sidecars) must become a Runtime-selected route behind the provider registry/Carrier
- PARKED subject resolution —
RequiredHomeLaunchTokenrewire so chain-gated open/buy
can leave the dev lane; prerequisite for step 4/5 being honest product paths anywhere. - Committee/pool policy — signed eligible custody pool + fixed per-object 2-of-3
committee + re-share/epoch rotation: partially present in custody epoch types and the
local custody-provider; the pool-signing and rotation runbook side is open. Note the
availability corollary: with a fixed 2-of-3 committee and no silent replacement, losing 2
operators permanently strands the object — rotation must be monitored and run before
reaching threshold (rotation runbooks exist on esp-port as reference:docs/dkms/deploy/). - Installer gate — every new provider/capsule must be in
components.json+
setup-source-home.shbefore installed-product claims; PR chore(ci): source-gate and source-home on ubuntu-latest and macos-14 #19 CI enforces on 3 platforms. - The owed file map — §7, Anders' explicit request to irzhy.
7. DRAFT — the file map Anders requested (review before posting to PR #15)
All paths on feat/dkms-esp-port.
Note (2026-08-20): the rights tip's docs/PROTECTED_CONTENT.md now carries a formal
"PR #15 disposition" — keep-as-research (threshold crypto, node-local custody,
recipient-sealed contributions, CEK commitment, negative tests), reimplement-at-boundary
(durable shard storage, DKG/rotation/re-share, pool/governance, provider roles,
Runtime-open scenarios), reject (public shares[], capsule-owned authority, raw-CEK ops,
rail_shim, old drm-provider orchestration, direct TCP/IP/port topology, static auth
fallbacks, standalone harness as product route). The map below stays useful as the
file-level answer to Anders' three questions, but should cite that disposition
rather than re-argue categories.
7.1 Creator and viewer UI files for publish, buy, open, play
Capsule surfaces:
- Publish/mint:
capsules/creator/{capsule.json,browser/index.html,browser/creator.js} - Buy:
capsules/marketplace-content/browser/{index.html,app.js,api.js,styles.css}
(+wasm/main.rs);capsules/content-market/{capsule.json,src/main.rs}(microVM side) - Library/open-with:
capsules/library/browser/{index.html,library.css,src/{actions,api,app,menu,render,tags}.js} - Play (media):
capsules/elacity-player/{capsule.json,browser/{index.html,player.js,style.css}} - Read (non-media):
capsules/ddrm-viewer/{capsule.json,browser/{index.html,viewer.js,style.css}}
(+ vendored three.js loaders,VENDORING.md) - Home chrome pieces the flow depends on:
capsules/home/browser/{home-spend-prompt.js,home-wallet-connector-host.js,home-shell-host.js},
capsules/home-gui/browser/shell-windows.js,capsules/wallet-metamask/browser/wallet-metamask.js
Gateway counterparts (all elastos/crates/elastos-server/src/api/):
- Publish/mint:
creator.rs,mint_authority.rs,content_index.rs - Buy:
gateway_marketplace.rs,market_reads.rs,buy_authority.rs,trade_authority.rs,
owned_ledger.rs,rights_authority.rs,chain_tx.rs,wallet_signer.rs,gateway_passkey_step_up.rs - Open/play:
viewer_open.rs,viewer_media.rs,viewer_object.rs,viewer_gateway.rs,
viewer_grant_sign.rs,access_grant.rs,media_authority.rs,object_authority.rs,
session_bounds.rs,session_lifecycle.rs,library.rs
7.2 Smallest dKMS node set for encrypted share storage and signed release
capsules/dkms-authority/src/main.rs— request/response ops, release invariant guardcapsules/dkms-authority/src/secure_store.rs— atomic 0600 no-follow durable share storecapsules/dkms-authority/src/security_state.rs— durable versioned revocationscapsules/dkms-authority/src/counters.rs— secret-free fail-closed tallies (health)capsules/dkms-authority/src/node_chain.rs— node-local pinned-RPC rights self-checkcapsules/dkms-keygen/src/main.rs— keygen/ceremony helper
(Reference material rather than product files: docs/dkms/deploy/ runbooks + DKG ceremony,
scripts/dev/dkms-docker/ quorum harness, scripts/ddrm-consumer-dkms-*-smoke.sh.)
7.3 Which files still depend on direct TCP, WireGuard, or the custom ALPN bridge
capsules/key-provider/src/main.rs— the main offender: rawTcpStreamconnects
(~L775–838), endpoint-prefix selection (Unix path /tcp:HOST:PORT/carrier:→loopback
sidecarDKMS_CARRIER_CLIENT_ADDR); knows WireGuard/ALPN context. Under the final
boundary this client logic moves behind the Runtime provider registry/Carrier adapter.scripts/dev/dkms-carrier-node/src/main.rs— node-side iroh bridge, custom ALPN
elastos/dkms-authority/1, relays to10.66.66.1:9443(WireGuard mesh). Evidence only.scripts/dev/dkms-carrier-client/src/main.rs— runtime-side loopback sidecar
(127.0.0.1:9444, DID preamble, warm QUIC streams). Evidence only.capsules/dkms-authority/src/main.rs—DKMS_AUTHORITY_LISTENframed TCP serve
transport (node-side; less problematic, but transport knowledge lives in the capsule).- Runtime-side (acceptable location under the final boundary, needs review not removal):
elastos/crates/elastos-server/src/{carrier.rs,operator_control.rs}. - Clean already:
decrypt-provider,encrypt-provider,cenc-core,ddrm-media,
ddrm-envelope, the viewer capsules and market/creator surfaces (they talk gateway/
provider APIs, not sockets).
8. Logging track (separate from the extraction — own branch)
Decision: port elastos/crates/elastos-logger to a dedicated feat/elastos-logger
branch off review/collaboration-candidate, run as its own PR track parallel to the
extraction. Status 2026-08-21: STARTED — worktree
/Users/maciz/www/ela.city/elastos-runtime-logger, branch feat/elastos-logger @
5f1fb004 (local only, not pushed); handoff brief for the implementing conversation at
<worktree>/.superpowers/sdd/2026-08-21-elastos-logger/brief.md. This respects Anders' exclusion
("separate work") while giving the whole system the tracing rail.
What the PoC already is (tip commit 27d85c6f):
LevelTrace<Info<Warn<Error<Critical; case-insensitive parse with aliases; env fallback.LogRecord+format_line();LogSinktrait (Send+Sync, non-panicking, drop-on-fail) —
StderrSink/StdoutSink/FileSink/VecSink;LoggerwithOnceLockglobal + safe
pre-init stderr fallback;resolve_levelprecedence CLI > env chain > default.fp()=fp:+hex(SHA-256[..4]) privacy fingerprint; rule: TRACE must be secret-free.- Lazy macros
log_trace!..log_critical!passingmodule_path!()as target. - Already wired: key/chain/wallet-provider, dkms-authority, dkms-carrier-node (legacy env
vars preserved). Explicitly not yet:elastos-server, JS/browser capsules.
Rollout brainstorm (phases, each independently reviewable):
- Port the crate to the new branch + workspace registration + tests. Note: the
referenced plan docdocs/superpowers/plans/2026-08-17-elastos-logger.mddoes not exist
in the tree — recreate the plan under.superpowers/or drop the reference. - Gateway adoption (
elastos-server): replace ad-hoceprintln!/bespoke levels;
component naming per surface; keepELASTOS_LOGas the env root. - Remaining Rust capsules/providers mechanical conversion.
- JS/browser capsules: a thin mirror (same levels/format) + gateway ingestion route,
so shell/UI traces land in the same stream. - AI-facing insight sink: the crate's own NOTE anticipates a
ProviderSink— one more
impl LogSink, noLoggerchange. Brainstorm: a structured JSON sink (level, component,
target, ts, fp'd fields) writable to a bounded ring file per component, so an agent (or
docs/DEBUG.mdtooling) can tail/summarize runtime behavior for debugging. Keep it
observe-only and secret-free by construction (fp()at call sites).
Constraint to respect: logging must not enter the protected-content extraction slices;
where those slices need logs, they adopt the crate only after it lands via its own track.
9. Docs & project-context track (CLAUDE.md + skill)
Decision: thin repo CLAUDE.md (auto-loaded every session) + an on-demand
.claude/skills/ skill; no second architecture ledger (system-map discipline:
"does not create a second architecture, glossary, backlog, or readiness ledger").
CLAUDE.md(<~80 lines): truth-chain order and when each file wins; branch roles +
branching rules (base =upstream/XX-devunless user chooses; ask before base
selection); run Rust fromelastos/; the standing verification gate (git diff --check,
home-entropy-check.mjs,cargo fmt --check, narrow tests,system-map-check.mjsfor
map edits,protected-content-provider-contract-smoke.shwhen touching those providers);
publish/deploy verbs are user-gated; pointer to AGENTS.md for the full contract..claude/skills/protected-content-map/SKILL.md: the live navigation for this
program — branch map (§5 diagram), extraction status table (§6), canonical invariants
(§2), PR dKMS/dDRM foundation on the ESP substrate (inspired from flint-5.0) #15 pointers and smoke entry points, the file map (§7). Loaded when working on
protected-content/dKMS/dDRM topics. Keep it status-light: linkstate.md/TASKS.md
instead of restating them, so it doesn't rot.docs/dkms/(50 files) stays onfeat/dkms-esp-portas reference material; do not port
it into the candidate line — the candidate docs already own the canonical contracts.- Possible follow-up: fold the durable parts of this brainstorm's §5/§6 into
TASKS.md
entries once the next planning session confirms ownership (keep volatile analysis here). - System-map update (deferred until Runtime integration lands): when the
protected-content providers are registered/installed (remaining-sequence steps 1/7),
docs/system-map/c4.mdmust gain the coordinator → rights-provider → custody providers
→ decrypt-provider elements (likely a Level 3 component view plus a dynamic
release-operation view), each edit through the map's change gate
(Layer / Capability / Hidden detail / Done-check) with
node scripts/system-map-check.mjsgreen. Do not draw them earlier — the map must not
depict uninstalled source-only components as product structure (readiness vocabulary
rule,c4.md:34).
10. Reviewer insight note (2026-08-21) — digest + code verification
A narrative note (relayed by irzhy) restates the program and adds new specifics. Digest,
with each claim checked against the published refs:
Ownership split (Wallet proves right / Runtime authorizes+selects+records / one sealed
share per custody node / Carrier transports Runtime-selected calls / capsules = workflow
only, never CEK or node selection) — matches the published canonical architecture
(docs/PROTECTED_CONTENT.md "Canonical architecture" on the rights tip) and the
coordinator's shape (elastos-protected-content-runtime/src/coordinator.rs:
RuntimeRightsProvider/RuntimeCustodyProvider traits + WalletProviderOperationV2).
Mint flow (Runtime creates random CEK → encrypts content → m-of-n split → per-node
X25519+ML-KEM-768 seal → node stores only its share). Two findings:
- PQ discrepancy — the published format is classical. The pinned suite is
CUSTODY_HPKE_SUITE_ID_V1 = "hpke-rfc9180-base-x25519-hkdf-sha256-aes256gcm/v1"
(custody_envelope.rs:11),hpke_helpers.rspinsX25519HkdfSha256, and the tip docs
say verbatim "This helper does not make a PQ claim" (docs/PROTECTED_CONTENT.md:236).
The note's "X25519 plus ML-KEM-768 from the first format, no classical fallback" is
either newer local work or the activation bar — if the first shipped format must be
hybrid, the published v1 suite cannot ship as-is (needs a hybrid suite id + envelope
re-provision before any real content is minted, since there is deliberately no
fallback/migration decoder). - Mint-side CEK in Runtime vs the CEK invariant. The published docs say "Runtime and
capsules must never receive raw CEKs" (release-path framing); the note candidly states
Runtime creates the CEK and sees plaintext at mint, listing it as a trust limit. Needs
reconciliation: either a documented mint-side carve-out (Runtime mint boundary as
reviewed custody) or moving CEK creation/encryption into a provider boundary later.
Pool/committee semantics (pool = signed eligible list; epoch freezes a selection;
committee authorization approves it; node set + threshold) — contracts exist and are
verified: elastos-protected-content-contracts/src/custody_pool.rs (landed in the
custody-provider step, 11bda1a0/f1b3dd4b) validates signed pool + epoch against a
pinned expected_policy_authority. Confirmed: no product code loads a trusted signed
pool or selects a committee — validation-only, exactly as the note says. Minimum
solution = one Runtime-pinned policy authority; no voting/elections/degraded-mint repair.
2-of-3 semantics: mint requires all 3 provisioned; playback needs any 2 (published
reconstruct.rs enforces exactly-threshold; provisioning seals to every committee node).
The three "Current Problems" (retry re-encrypts before loading the existing mint
journal; ciphertext stored before custody-provider preflight; docs claim terminal mint
abort but code keeps a nonterminal reconciliation obligation) — not verifiable on any
published ref: the producer mint journal/state machine does not exist in the published
stack (the runtime crate's journal is the release journal,
runtime-release-journal/v1; "mint" greps hit only unrelated server code). Same pattern
as the custody-provider announcement: the note reviews local, unpublished mint-path work.
The docs half of problem 3 IS visible: the tip's Remaining sequence step 4 promises
"durable terminal mint abort" — so the divergence is real on the docs side.
Trust limits (Runtime sees plaintext at mint; decrypt boundary sees CEK+plaintext at
playback; any threshold of colluding nodes reconstructs; operator labels don't prove
independent ownership; rotation/revocation/retirement/orphan cleanup missing) — all
consistent with the published docs' own caveats; framed as completion requirements, not
design flaws.
10-step Path To Completion — refines the docs' 8-step Remaining sequence: adds the
three fixes up front (step 1), Runtime-pinned policy authority + signed pool loading
(step 2), a real immutable object provider (step 3), explicit Carrier connection for
remote custody (step 7), reuse of PR #15's tests as behavioral oracles (step 8; matches
§7/§6), and an independent cryptographic + protocol review before activation (step 10).
Final rejects list matches the in-docs "PR #15 disposition" plus "direct chain booleans"
(rights must flow as evidence-backed typed decisions, not bare hasAccess bools — consistent
with RightsEvaluationEvidenceV1 in policy.rs and the rights crate's typed decisions).
11. Open questions for the next session (revised 2026-08-21)
Resolved since 2026-08-18: custody-provider is published; the PARKED rewire is scheduled
in PR #22 Phase 2, pending review; availability is absorbed into the mint journal
(remaining-sequence step 4); recipient key-possession proof is an explicit gate (step 3);
the pool/committee policy layer has published contracts (custody_pool.rs) — loading and
selection remain product work, per §10.
Still open:
- Is the file map (§7) still owed to Anders as asked, or is the in-docs "PR dKMS/dDRM foundation on the ESP substrate (inspired from flint-5.0) #15
disposition" considered its answer? Recommend still delivering it — the disposition is
category-level, the ask was file-level. - PR docs(protected-content): mint→sell→buy→play journey implementation plan #22 (journey plan) has no review yet — adopt it as the working plan for steps 4–8,
amend it, or wait for Anders' verdict before aligning port work to it? - Where does our own work plug in next? Candidates: remaining-sequence step 3 (recipient
possession proof — small, well-bounded, unblocks reconstruction use) or contributing to
the mint-path fixes once that code publishes; steps 1–2 appear actively owned upstream
(runtime/rights crates), and the note's Path-To-Completion step 1 (journal-first retry,
provider preflight, partial-mint truth) reviews code we cannot see yet. - PQ format decision (new, from §10): the published custody suite is classical-only
(hpke-rfc9180-base-x25519-hkdf-sha256-aes256gcm/v1), while the note requires
X25519+ML-KEM-768 "from the first format" with no fallback. Does a hybrid suite id
replace v1 before any real mint, and who owns that change? - Mint-side CEK carve-out (new, from §10): the note has Runtime creating the CEK and
seeing plaintext at mint; the published docs say Runtime never receives raw CEKs.
Which document gets the reconciliation — a mint-boundary carve-out in
docs/PROTECTED_CONTENT.md/GLOSSARY.md, or a plan to move mint-side encryption into
a provider boundary? - Ask for the local mint-path code (journal/state machine, immutable object provider) to
be published so the three "Current Problems" fixes can be tracked against real refs? - Committee policy: what test topology proves "independent operators or failure domains"
for 2-of-3 beyond the mandated "three distinct custody identities and state roots"
(docker 3-node stays dev-only)? - For the logger's JS mirror (§8 phase 4): gateway ingestion route vs. console-only first?
- The stack still forks at
b07160cf: will it be rebased onto5f1fb004(system-map
docs) or merged forward — and does port work target the stack tip
(feat/protected-content-rights) or the candidate?
Per-question coverage status as of the 2026-08-21 branch audit: see §12.
12. Concern coverage audit (2026-08-21) — active branches vs §10/§11
Audited refs: the full feat/protected-content-* stack (tips unchanged from §0 pins),
cursor/protected-content-journey-plan-af9e @ f0b0aeaf (PR #22's 350-line
docs/PROTECTED_CONTENT_JOURNEY_PLAN.md, now read in full), feat/dkms-esp-port.
New facts found during the audit:
elastos-protected-content-provider-contracts(crate) andcapsules/custody-provider
(the provider process) are published on the stack tip — the private provider protocol is
complete as source, not just described.- The runtime coordinator actively enforces the no-topology-leak invariant in tests:
a forbidden-marker assertion rejectsCEK,raw_share,provider_route,endpoint,
host,ip,port,Carrier,http(s)://on its serialized surface
(coordinator.rs~L1295). - PR docs(protected-content): mint→sell→buy→play journey implementation plan #22's plan is substantive: phase-sequenced (0–5), principle-mapped, and schedules the
PARKED subject rewire in Phase 2 with PR dKMS/dDRM foundation on the ESP substrate (inspired from flint-5.0) #15'sdkms_railadopted as a red-first
behavioral oracle. It also surfaces a WIP item we hadn't tracked: the custody-provider
process tests are wall-clock-coupled and need clock injection (its Phase 0).
| Concern (§11) | Verdict | Evidence |
|---|---|---|
| Q1 file map owed to Anders | Partially covered by PR #22 §8: the adopt/harden list names the Creator/Store/viewer/spend-prompt files and seams (map part 1). Parts 2 (smallest node files) and 3 (transport deps) exist only in our §7. Still worth delivering as the direct answer. | |
| Q2 adopt PR #22? | Still proposal, zero review comments — but it is the only artifact scheduling the PARKED rewire (Phase 2), the e2e oracle, Store consolidation, and naming convergence. Recommend: review it rather than write a competing plan. | |
| Q3 where to plug in | Better informed. Concrete unclaimed items: PR #22 Phase 0 (clock-injection fix for custody-provider tests; naming convergence; adopting dkms_rail as red oracle) and remaining-sequence step 3 (recipient possession proof — see below). |
|
| Q4 PQ format | Contradiction, now three-way. Insight note: hybrid X25519+ML-KEM-768 "from the first format, no classical fallback". Published code + docs: classical suite, "no PQ claim". PR #22: states the classical suite as the custody invariant (§6) and defers PQ-hybrid custody past 0.7 (§7). Needs an explicit decision before any real mint — a deferred hybrid with no fallback decoder means re-provisioning every object minted classical. | |
| Q5 mint-side CEK | Diverges from the note, converges with the docs. PR #22 §4.1 places CEK minting "inside the encrypt/custody boundary", not in Runtime — matching the published invariant and contradicting the note's "Runtime creates the CEK / sees plaintext at mint". The carve-out question stands, but the plan's answer is the stricter one. | |
| Q6 publish mint-path code | Not covered. No mint journal/state machine on any ref; the note's three Current Problems remain unverifiable. PR #22 predates the note and does not mention them; its Phase 1 would re-derive the dev-lane mint slice. | |
| Q7 committee test topology | Tension surfaced. Docs remaining-sequence step 6 requires three distinct custody identities before cutover; PR #22 accepts one-node custody for the dev lane and defers "multi-node production custody topology" past 0.7 — while its Phase 5 performs the atomic cutover. Whether 0.7 cutover requires the 3-node proof is unresolved between the two documents. | |
| Q8 logger | Untouched anywhere (no elastos-logger reference on any stack branch or PR #22) — consistent with the exclusion; our §8 track stands. |
|
| Q9 fork/rebase | Mechanism proposed, decision open: PR #22 Phase 0 proposes "a single 0.7 integration branch that composes collaboration + this journey". | |
| §10: pool loading in product | Not covered — still validation-only contracts; PR #22 does not schedule signed-pool loading/committee selection (the note's Path step 2). | |
| §10: recipient possession proof | Gap in PR #22 — required by docs remaining-sequence step 3 and the note's Path step 4, but absent from PR #22's phases and its deferred list. Must be added to whichever plan wins, or it silently falls through. | |
| §10: Carrier connection for remote custody | Planned only (note Path step 7; PR #22 principle-4 row). No transport code in the stack crates — by design (coordinator uses in-process provider traits; the forbidden-marker test keeps transport out of the contract surface). | |
| §10: terminal-abort docs truth | Not covered — the docs still promise a terminal mint abort; the corrective code is unpublished. | |
| §8/§9 tracks (logger rollout, CLAUDE.md + skill) | Ours alone — nothing on any branch touches either. |
Net reading: the authority spine (contracts → custody → provider process → wallet-signed
rights → runtime coordination/journal → typed rights evaluation) is published and further
along than §6's table suggested when written; the product journey has a serious but
unreviewed plan (PR #22); and the three sharpest unresolved items are the PQ format
decision, the mint-path publication (with its three fixes), and the possession-proof gap
in PR #22.
|
This replies to the 21 Aug alignment note. Update
At Four later local commits exist ( Installed The 17 Aug mint → open report on this PR remains the product-flow §11
Alignment problemThe extraction policy ABI, on GitHub, is only: Content id on that line is The live This PR’s chain-provider names that second form the production A dummy I do not know:
So the two lines do not yet share one on-chain access fact. Decisions that unblock the next shared step
Irzhy: is Where we are The extraction line is public. Library mint, Your 17 Aug mint → open path is still the product-flow reference. I have not re-run it on today’s PR tip ( The interop problem Runtime and Runtime’s published policy is only:
The content id on that line is The live site script I fetched today (
Your chain-provider on this PR already treats that second form as the production read ( A dummy call of the live function reverted. The data started with I also do not know whether the proxy has the string function as well, whether a If those stay different, we get two “has access” facts. Home and What I want from you You know this contract and the mint / KID / Please say:
Proposal (Elastos side, not decided) If both products must see the same paid / may-open fact, Runtime should speak the function ela.city already calls. Do not deploy a second rights contract that only Runtime understands. That would mean:
If that is wrong for how AuthorityGateway, Channel, and The four local commits can wait until this is clear. The string ABI is already public on |
|
@andersalm Answers on the access check, plus status from our side.
|
|
Update — the remaining 0.7 work is now tracked as Jira Deliverables (label
Ordering: 2295 and 2296 run in parallel; 2296 → 2297 → 2298 → 2299 → 2300, and 2299 also waits on 2295 (no cutover before the chain is merged). |
|
@irzhywau I checked the current refs and the remaining 0.7 work. We are using PR #15 as the working example for mint, buy, and playback. The reviewed implementation is split across PRs #27–#36. The current tip is That branch contains the complete source flow:
This code is not selected by the installed Runtime yet. Library is also not connected to it. Library’s current Open action tries a normal viewer or local preview. If neither works, it shows Properties. There is no call from the Library browser code to the protected-content The Library integration should work as follows:
The Creator, Owned Assets, and Media Player work in PR #15 may still contain useful screens, interactions, and tests. We should adapt those parts to the current contracts:
The selected UIUX work from Sash is now published as It also contains the exact Browser orphan-process fix from PR #24, commit The UIUX candidate does not contain protected-content PRs #29–#36. Those are still a separate review stack. PR #25 is also separate because its logger work may be replaced by Before consolidation, we still need to close these points:
The Jira order still looks right: review the PR stack and prove AuthorityGateway in parallel, install the custody and Chain configuration, test the new code while it is still disabled, connect Library playback, perform one cutover, then run mint → buy → play with two principals. We need to list the specific interactions or tests from Creator, Owned Assets, and Media Player that are still missing from Library, Marketplace, or the viewer. File and test references would help us carry over the useful parts without bringing back the old structure. |
|
Progress update on the 0.7 completion checklist (ELACITY-2295, step 1 — review & merge the stacked chain #27–#36):
Remaining inside step 1: land the queued test-correctness fixes, close #36's CI, then the base reconciliation (the system-map docs merge |
|
0.7 status update — the review-and-integration phase is complete:
|
|
Deployed-contract facts on Base 8453 — verified (ELACITY-2296) Follow-up to the revert-trace analysis in the earlier deployed-facts comment: all remaining open questions on the deployed 1. KID-binding write (
|
|
@irzhywau not merged; kept as research. |
Lands the decentralized key custody (dKMS), content protection (dDRM), and content-commerce rails — originally built on the pre-ESP runtime (
review/dkms-foundation) — rebased and re-seated onto the ESP architecture, hardened, test-anchored, and consolidated into 7 commits.What this delivers
elacity-player,ddrm-viewer) decrypt through capability-scoped provider chains with per-open sessions (open → session-bound streaming → close → sweeper reap), fail-closed at every unauthorized step.content-marketcapsule, and Marketplace/Creator surfaces.dkms-authority/dkms-keygenwith a CI-enforced release invariant (release build fails to compile withlegacy-receipt-authz/dev-modes).How it was adapted to ESP (main's architecture wins everywhere)
provider_operation_action(preview==enforce conformance down to 1 tracked divergence)./api/market/buy,/api/create/mint) require passkey step-up — intent-, launch-, and time-bound, single-use — brokered under Home's cookie authority with a new Home-chrome spend-confirmation dialog (what's displayed is what's signed). Launch tokens moved to URL fragments (never query strings).localhostscheme + boot sub-route seizure (first-writer-wins pinning, identity-keyed teardown), authority refusals reaching guests asDenied(wasInternal), release-gating ofELASTOS_DDRM_SUBJECT.Testing
~1,700 tests green across both CI lanes (default +
dev-modes): workspace suites, 10 capsule crates, capability conformance + token fuzz, egress spine, and a newdkms_raile2e anchor proving the full commerce/viewer contract.verify-ci,verify-capsules,bus-conformance(made non-vacuous), lint/fmt, entropy/WCI checkers all pass. Known pre-existing flakes:browser_reconciliationtiming family (passes in isolation, predates this branch).Docs
All dKMS/dDRM/commerce docs consolidated into one onboarding hub at
docs/dkms/(README entry → architecture, security model, media pipeline, viewer sessions, commerce, dev setup; historical notes underhistory/). Roadmap coverage baseline + gap plan indocs/superpowers/specs/.Known follow-ups (documented, non-blocking)
RequiredHomeLaunchTokenthreading): chain-gated open/buy is dev-lane-only until it lands — deliberately fail-closed; prerequisites in theviewer_open.rsPARKED block.