Conversation
Independently verify the three LS-QMSR TODO items: - Path independence: confirmed (degree-1 homogeneity of C) - Bounded loss α(N-1)/(4N)·S: confirmed as upper bound, tight for α ≤ 2 - Strict properness: disproven — displayed prices shrink 50% toward uniform (p = π/2 + 1/(2N)), independent of α Add the adaptive-properness-path-independence trilemma section explaining why this is a fundamental constraint: any state-dependent b makes the price field non-conservative (∇C ≠ p), forcing a choice between adaptive liquidity and price accuracy. LMSR's exponential nonlinearity makes the trilemma operationally soft (small bias ∝ 1/α); QMSR's linearity makes it hard (constant 50% bias). Revise recommendations: standard QMSR replaces LS-QMSR as primary choice for both binary and N-outcome markets. Add adaptive liquidity alternatives (LOB, operator-managed b, time-based b growth). Add cubic polynomial scoring rule as research direction for achieving LS-like adaptation with smaller bias. Also fix QMSR depth profile inconsistency (constant price impact ≠ uniform directional depth) and strengthen first-mover incentive discussion in binary market caveats. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add seed_markets example binary for publishing real on-chain testnet prediction markets via DeadcatNode. Supports publish/list/delete commands with 22 market definitions across 6 categories. Auto-splits UTXOs when only one is available. Uses DEADCAT_SOURCE_NSEC and DEADCAT_MNEMONIC env vars. - Fix market discovery: markets fetched from relays but not yet promoted in the store (candidates table) are cached in memory and merged with store results so they don't flash and disappear between queries. - Add discovery:market-refresh event to notify frontend when background relay fetch finds new markets. - Add wallet-seed-generation-entropy.md documenting the wallet's entropy sources and encryption pipeline.
Replace skeleton loading state with cat bag animation while markets are fetched from relays. Use React Query isLoading instead of manual marketsLoading flag. Remove dead Markets/Live/Social nav links and Help button/modal. Center search bar in header.
Transactions and balances stayed stale until the user manually pressed sync because no background polling existed. Add a 15-second periodic sync loop that runs while the wallet is unlocked, emitting updated state through the existing snapshot pipeline.
Design for grouping related markets under a parent event (e.g. "2026 NBA Champion" with one sub-market per team). Uses a deadcat-group NIP-78 event with a-tags referencing child markets — no on-chain protocol changes required.
Show a success toast when funds are received and an info toast when funds are sent. Detected by diffing txids in the wallet_snapshot event against the previous snapshot in the Zustand store.
Wallet button in the top bar shows border color based on tx state: pulsing green for incoming unconfirmed, pulsing white for outgoing unconfirmed, solid green for new confirmed until dismissed. Balance pulses while unconfirmed txs exist. Transaction rows use green/red for unconfirmed dates and status text.
Replace append-only relay market cache with full replacement so deleted markets disappear on next discovery cycle. Skip cache replacement when relays return empty results to prevent market flashing during transient failures.
Fetch real chain tip in useMarkets so time-remaining shows correct months instead of raw block distance. Convert chart x-axis from block heights to timestamps and rename timescale buttons from block counts to minutes.
Disable buy buttons with "Insufficient funds" label when wallet balance is too low. Map SDK error strings to user-friendly messages. Show separate "Unlock wallet to trade" button with lock icon when wallet is locked instead of the generic account setup prompt.
Green badge no longer fires for outgoing transactions like market creation or sends — only for positive balance changes.
Reorder markets so first 5 span different categories. Add 18 new markets across all categories (40 total). Fetch real chain tip instead of hardcoded estimate. Add UTXO retry loop between markets with auto-split fallback. Document seeder usage and full market list.
Require account password before revealing nsec in settings. Auto-hide nsec when wallet locks. Make entire market card clickable to open detail view.
LazyLock requires Rust 1.80+ but CI MSRV is 1.77.2. Switch to once_cell::sync::Lazy. Also fix redundant closure clippy warning.
QR was lost when switching away from the Liquid tab and back because the address already existed so the generation effect skipped. Now regenerates the QR whenever the Liquid tab is active.
- Add prepare_send / confirm_send Tauri commands with fee breakdown confirmation screen before broadcasting Liquid sends - Add drain_lbtc SDK method using LWK native drain for exact max sends with zero dust - Add estimate_max_send command that prepares and stores the drain tx - Add block explorer link on transaction sent screen - Extract shared friendlyError() for trading panel, send/receive modals — raw SDK errors no longer leak to the UI - Extract DEFAULT_FEE_TARGET_BLOCKS constant - Add PrepareSendResult type
Extract body scroll lock into reusable hook. Apply to NostrEventModal (was missing), WalletPage, ProfilePage, OnboardingOverlay, and SettingsPanel. Fixes background scrolling while any modal is open.
Replace cat bag loader and splash timing hacks with skeleton cards that stay visible until markets actually arrive in the React query cache. marketsLoading only clears inside useMarkets queryFn when data is non-empty. No fallback timeout — skeletons persist until relay data arrives. Removes MarketLoader, CatLoaderSvg, BagLoaderSvg, and OverlayLoader usage from App.tsx.
1. Fix focus stealing bug in manual restore flow where typing in the password field caused focus to return to the seed phrase textarea. The ref callback was running on every re-render. Now uses useEffect to focus only when mnemonicExpanded changes to true. 2. Clear password fields when navigating to any password entry step to ensure users always start fresh. This prevents stale passwords from persisting between navigation flows. https://claude.ai/code/session_018cp7GAwLjq3upwZoQUoUwo Co-authored-by: Claude <noreply@anthropic.com>
Break the blocking dependency chain that caused 30+ second startup when a relay was down. Four changes: 1. Add 3s connect_timeout to all relay connection calls — dead relays are skipped instead of hanging indefinitely 2. Make construct_and_store_node non-blocking — node is stored immediately, start_subscription() runs in background tokio::spawn 3. Restructure bootstrap to not await init_nostr_identity — identity loads in background, splash dismisses unconditionally, parallel Promise.all for independent backend queries 4. Remove fetch_chain_tip from market query critical path — cached at module level in background, never blocks discover_contracts
Markets from relays were only stored in memory (RELAY_MARKET_CACHE) and lost on restart. Every cold start required a full relay fetch (5-30s depending on relay health). Now the cache is saved to relay_market_cache.json and loaded at app startup, giving sub-second market display on returning launches.
Add missing category icons (Politics, Sports, Culture, Bitcoin, Weather, Macro, Resolved) to HomePage CategoryIcon. Show muted icons in page headings. Move Ending Soon next to Resolved after Macro. Shorten to "Ending" in tab bar. Add checkmark icon for Resolved.
useLockScroll() ran on every render of ProfilePage because the early-return guard came after the hook. That locked body/html overflow on app start and never unlocked. Split into a wrapper that guards profileOpen before any hooks and an inner ProfilePageContent that only mounts when the modal is open (same pattern as SettingsPanel).
- hiddenTitle + titleBarStyle: Transparent in tauri.conf - core:window:allow-start-dragging capability for JS drag API - data-os attribute on <html> for platform-scoped CSS - onMouseDown drag handler on empty header space (phi-container and the flex row) so users can drag the window from any empty area of the top bar. Scoped via event.target === currentTarget so interactive children still receive their normal clicks.
titleBarStyle: Transparent left the webview starting below the native chrome, so the top strip showed through to the desktop instead of being painted by our dark header. Overlay extends the webview edge-to-edge and lets bg-slate-950/80 backdrop-blur paint under the traffic lights. Adds 32px top-padding to the header's .phi-container only on macOS (scoped via data-os="macos") so the logo sits below the OS-anchored traffic lights rather than beside them.
- Move onMouseDown drag handler up to <header> so the top-bar corners outside the max-w-1440 phi-container also drag the window. Each nested layer keeps its own handler; target === currentTarget guards against interactive-child clicks. - Lower SearchBar breakpoint from lg (1024px) to md (768px) so the inline input stays expanded at the app's 900px minimum width; the mobile search overlay is unreachable in practice and is retained only for correctness. - Shrink logo from h-10 (40px) to h-9 (36px) to match the Get started button height in the top bar.
Enumerates every precondition an integrator must satisfy for correct chain-only recovery, the failure mode if violated, what the engine verifies, and what it does not. Closes the documentation gap where recovery preconditions were implicit in the flow descriptions — an integrator targeting deadcat-core now has an explicit contract to code against, and several silent-failure modes (wrong xprv derivation path, incomplete rescan, stale backend, wrong network) are named so they can be defended against at the integration layer. The rustdoc-level precondition pass is an implementation-time task guided by this section; a verify_integration helper is noted as a future ergonomic improvement. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…t × N
Closes B2 (multi-outcome expiry redemption divisibility) by restructuring
the denomination model rather than adding a covenant-level mod check.
Under the prior spec, binary markets parameterized on collateral_per_pair
directly while multi-outcome markets required cp mod N == 0 for exact
expiry redemption. Enforcing that divisibility at covenant level would
have been necessary under the self-enforcement principle (otherwise
floor-division on expiry orphans user value proportional to pairs
issued), but the 1-2-5 mantissa table is incompatible with divisibility
for N in {3, 6, 7, 9} — enforcing cp mod N == 0 would have made those
outcome counts uncreatable.
The unified model parameterizes both contracts on base_payout — the
per-outcome YES-expiry payout unit — drawn from the existing 1-2-5
table. The pair cost cp = base_payout × N is derived at covenant compile
time (N=2 for binary, N=outcome_count for multi-outcome). Divisibility
becomes structural: every expiry redemption rate is an integer multiple
of base_payout, no runtime division happens in the covenant, no
denomination-table index is unreachable for any supported N.
Changes:
- multi-outcome-market-contract.md: rename primary param, add Denomination
model subsection with rationale, revise constraints and expiry
redemption section to reflect structural exactness, update OP_RETURN
hint spec and security properties table.
- contract-specification.md: rename binary and multi-outcome param
fields, update spend paths formulas to use cp shorthand, update
pending-refactors row for the superseded collateral_per_pair step.
- market-contract-principles.md: revise principle 12 to state exactness
as structural rather than covenant-asserted.
- chain-only-recovery.md: rename denomination table and OP_RETURN hint
field from collateral_per_pair to base_payout, same 4-bit encoding
and same 1-2-5 values.
- deadcat-core-design.md: update BinaryMarketCreationParams and
MultiOutcomeMarketCreationParams struct fields, revise "Collateral
Per Pair" and "Standard Denomination Conventions" decision log
entries.
- collateral-per-pair-refactor.md: mark as superseded, preserve
historical problem statement as context.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…esign Resolves I5 via shelving rather than specifying. Cross-outcome arb (quote_cross_outcome_arb, build_cross_outcome_arb_pset, ArbQuote, ArbDirection, ArbPoolLeg, as_cross_outcome_arb) was named in several places after the Stage 3 pass but never fully specified. The API surface has unresolved design questions (scope of directions, sizing model, staleness representation, classification rule) and landing it prematurely would bake in choices before the arb ecosystem exists to inform them. Deferring is safe because cross-outcome arb is not safety-critical — coherence gaps are pricing drift, not solvency violations. The covenant's generic solvency-preservation spend path makes arb permissionless by construction, so external bots can close gaps without a core-layer builder while v1 stabilizes. deadcat-core-design.md changes: - Remove quote_cross_outcome_arb / build_cross_outcome_arb_pset method signatures from MultiOutcomeMarket impl. - Remove ArbDirection / ArbQuote / ArbPoolLeg / ArbQuote impl type definitions and the CrossOutcomeArbRealized / ArbPoolLegRealized result types plus as_cross_outcome_arb method. - Add a dedicated "Future: Cross-Outcome Arb API (v2)" section that reserves the API surface names, states the rationale for deferral, lists the five open design questions, and documents v1 behavior on observed arb-shaped txs (ingest cleanly; per-contract transitions preserved; no aggregate classification until v2). - Reframe the "Cross-Outcome Arb: Quote + Build Pattern" decision log entry as "Cross-Outcome Arb: Deferred to v2" with the deferral rationale. - Scrub prose references across the Engine API, TradeSpec narrative, Market view accessor, Market transition section, Multi-Contract Patterns decision log entry, View Types decision log entry, and staging notes so they reflect the deferred surface. - Remove build_cross_outcome_arb_pset row from the multi-outcome builders table; replace with a deferral pointer. trade-routing-algorithm.md changes: - Update the "multi-outcome operations that don't route through quote_trade" paragraph to describe the v2 deferral. - Update Key Files section accordingly. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Resolves B3 (multi-outcome .simf code generation). Key decisions:
Supported N range for v1: {3, 4}. Deliberately conservative — tx size
scales ~quadratically with N and we haven't benchmarked the binary
witness size to project the practical ceiling. Extension to wider N
(e.g. {5..10}) is explicitly non-breaking, since each N has its own
CMR-committed .simf; existing markets are unaffected by adding new N.
Shrinking is breaking and should not happen once markets exist.
N=2 stays on the existing prediction_market.simf (not regenerated from
the template). Binary is the high-volume case, already deeply validated,
and running it through the multi-outcome template would cost tx weight
at the common case without structural benefit. Decision previously
deferred; now locked for v1.
Generator architecture: fully decoupled from deadcat-core at the
dependency level.
- deadcat-codegen (new dev-only workspace crate): pulls MiniJinja,
exposes fn generate(n: usize) -> String plus a CLI binary invoked
via `just generate-simf`.
- deadcat-core: reads committed .simf files via include_bytes!, has no
dep on deadcat-codegen or MiniJinja. Downstream consumers of the
published crate get pre-embedded .simf files, never see the
generator's dep tree.
- Workspace CI runs the drift-detection test in deadcat-codegen which
regenerates in-memory, asserts byte-exact match against committed
files, and invokes the SimplicityHL compiler on generated output
with canonical test params (catches both drift and semantically
invalid template output).
Templating: MiniJinja over Tera/Handlebars/plain Rust. MiniJinja has a
materially smaller dep footprint and strictly Jinja2-compatible syntax
that doesn't collide with SimplicityHL's { } and [ ] delimiters. Tera's
advantages (Rust-web ecosystem, Zola) are irrelevant for this use case.
Not build.rs: OUT_DIR conflicts with committed-output model and silent
regeneration on `cargo build` would clobber developer edits.
Also fixed a misleading doc claim: the prior text at
multi-outcome-market-contract.md:376 said "per-N CMR is deterministic
given a template version" — incorrect, since CMR depends on the full
param set (oracle pubkey, asset IDs, base_payout, expiry_time). The
generator commits .simf source text, not a compiled CMR. Audit-workflow
reproducible CMR recipe is noted as a future tooling TODO, not v1.
Files:
- multi-outcome-market-contract.md: rewrite § Code Generation Strategy
to reflect the MiniJinja + crate-separated + committed-outputs +
drift-test design; add the v1 N={3,4} scope, the non-breaking
extension note, and the CMR-depends-on-params clarification. Lock the
N=2 "keep binary.simf canonical" decision. Update the Impact on
deadcat-core section to reference the deferred cross-outcome arb API.
- deadcat-core-design.md: add "Multi-Outcome .simf Code Generation"
decision log entry between the cross-outcome arb deferral and the
view types decision, documenting the chosen/rejected alternatives.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…enomination Resolves B1 (deterministic F-value algorithm). Pivots the runtime algorithm from fixed-point Taylor (which required substantial spec work on precision, term counts, and constants encoding) to bignum rational arithmetic via num-bigint + num-rational. The closed-form expression F(i) = max_loss_sats + floor(b × ln(cosh(s/b))) is computed directly at arbitrary precision, with floor-to-u64 at the final step. Correctness story: committed reference Merkle roots per param combo live in deadcat-codegen as test fixtures. The regression test re-runs the bignum reference on every cargo test and asserts all 256 committed roots reproduce byte-for-byte, catching any unintended change in the bignum implementation or its transitive dependencies. Cross-implementation conformance (future Taylor port, cross-language ports) targets the same committed roots — any implementation matching all 256 is provably equivalent to bignum over the full valid parameter space. Binary cost: zero embedded roots in deadcat-core. The runtime deps num-bigint + num-rational add ~100 KB compiled. Cold-start cost is 5-10s per unique (max_loss_sats, half_payout_sats) combo, amortized via per-pool in-memory/disk cache. Pool denomination: collapses from 26-mantissa × 16-exponent (416 values per param, 173,056 combos) to the 16-value 1-2-5 table shared with market base_payout encoding (16 values per param, 256 combos). Pool OP_RETURN hint shrinks from 41 bytes to 40 bytes. Range is capped at 10^7 sats per param — expanding the table is explicitly non-breaking in a future release. Files: - lmsr-deterministic-table-spec.md: status flipped from Skeleton to Specified. Replaced the "NOT YET SPECIFIED" F-Value Computation Algorithm section with the bignum runtime design. Replaced the test- vectors section with the committed-fixtures approach. Updated Key Files to point at deadcat-codegen and deadcat-core. - chain-only-recovery.md § Pool Denomination: rewritten around the 16-value 1-2-5 table. Pool hint updated from 9+9 bits (18 bits total) to 4+4 bits (8 bits total). Pool hint total length 41 → 40 bytes. Per-field justification table updated. Builder validation updated. - contract-specification.md: updated LmsrPoolParams comment for half_payout_sats denomination. Pending-refactors section gains a new row for the pool denomination change and reframes the F-value row from Pending to Specified. - deadcat-core-design.md: new "LMSR F-Value Computation" decision log entry documenting the chosen bignum approach, the rejected alternatives (Taylor runtime, embedded tables, embedded roots, hybrid, 26-mantissa encoding), and why. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Captures the from-scratch implementation sequence for deadcat-core, deadcat-codegen, and the accompanying SimplicityHL contracts as a six-phase plan with explicit deliverables, quality gates, and risk flags per phase. Treats the existing deadcat-sdk crate as a reference artifact rather than a refactor target; new covenants are written fresh with every design decision from the pre-implementation review baked in from day one. Six phases: 1. SimplicityHL contracts (highest risk — covenant self-enforcement audit is the gating quality criterion). 2. deadcat-codegen crate (LMSR bignum reference + fixtures + multi-outcome .simf generator). 3. deadcat-core foundations (types, traits, covenant loading). 4. ContractEngine mechanics (ingestion, interpretation, chain sync). 5. View types and PSET builders. 6. Routing, recovery, public API polish. Documents phase dependencies, parallelization opportunities, deferred items (v2 cross-outcome arb, wider N range, expanded pool denomination, Taylor runtime, cross-language ports, etc.), and known implementation risks with mitigations. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Cover Nix flake integration (fetchurl derivation with pinned hashes), justfile commands, Simplex.toml config, typed build artifacts, and version pinning. Maps smplx capabilities to the existing three-tier test methodology — smplx targets Tier 2 regtest integration tests while Tiers 1/1.5 remain unaffected. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Applied clear fixes and small-file updates from the deadcat-core
pre-implementation review.
contract-specification.md:
- v1 multi-outcome scope: N ∈ {3, 4} (was "proposed N=3..10")
- N=2 stays as binary prediction_market.simf, not regenerated from
the multi-outcome template (was deferred)
enforcement-layers.md:
- Terminology sweep: collateral_per_pair → cp (= base_payout × N)
lmsr-pool-design.md / amm-scoring-rule-tradeoffs.md:
- Deterministic Table Generation section: reframed as bignum-first
reference with Taylor runtime as non-breaking v2 optimization;
cite lmsr-deterministic-table-spec.md for the canonical spec
- Fix stale timing claims (~80ms / ~1μs) with bignum reality
(~5-10s per (max_loss_sats, half_payout_sats) combo; cached)
- Quoting strategy reframed to cached-tables at bignum speeds
- Note that deadcat-core mirrors covenant market-state-agnosticism;
no engine-level gate on post-resolution trading
trade-routing-algorithm.md:
- Integer Precision section → Integer Precision and Caching;
bignum caching strategy as the router's dominant pattern
- New Quote Staleness subsection covers pool-admin-adjust subtlety
(pricing curve unchanged but outpoints still invalidate quotes)
and confirms post-resolution trading is allowed
deadcat-core-design.md:
- LMSR Math section: update generate_lmsr_table language to
reference the bignum algorithm and canonical satellite spec
deadcat-core-implementation-plan.md:
- Phase 1: committed smplx build artifacts added as deliverable
- Phase 2: smplx artifact drift test added
- Phase 6 pool lifecycle: no engine-level gate on post-resolution
trading (pool operators manage liquidity via build_lmsr_close_pset)
- src/artifacts/ committed alongside contracts/multi_outcome/
- Typed witness adoption committed from Phase 1 (was deferred to
Phase 5)
- just regenerate-artifacts command
- Dropped verify_integration from scope
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Applied type-system and error-enum refactoring from the deadcat-core
pre-implementation review.
Type system:
- SlotIdentity promoted to public type with BinaryMarketSlot,
MultiOutcomeMarketSlot, PoolSlot, OrderSlot variants
- Labeled outpoints (Vec<(SlotIdentity, OutPoint)>) replace
positional Vec<OutPoint> at six engine/store boundary types:
InitialContractState, ContractMatch, StateUpdate (old/new),
OutpointContractInfo, contract_outpoints signature
- "Outpoints per contract type" subsection rewritten from
positional to labeled semantics
StateUpdate:
- Added old_state: Contract and new_state: Contract fields so the
engine carries all domain logic and the store is a plain
persistence layer (no implicit state derivation required)
Orders:
- OrderTracking three-variant enum: Persistent / EphemeralFresh /
EphemeralMidLife, with rustdoc on persistence behavior and
offered_amount accuracy per mode
- OrderState variants carry tracking and active_txid fields
- Split ingest_order into ingest_persistent_order (maker
monitoring, full history, requires creation tx) and
ingest_ephemeral_order (taker/discovery, no history,
auto-untracks terminal past finality, accepts Creation or
Current snapshot)
- Engine behavior forks on tracking for history writes and
prune_finalized auto-cleanup
- Duplicate ingestion uniformly returns ContractAlreadyTracked
regardless of method
Error enum:
- CovenantInvariantViolation { contract_id, kind } variant with
nested InvariantViolationKind enum for consensus-valid
transactions that defy covenant invariants (bug-adjacent,
not retry-loopable)
- StaleQuote becomes enum with StaleQuoteReason (OutpointsChanged,
ContractUntracked, ContractRemoved) replacing detail: String
- NoLiquidity expanded with outcome, side, direction fields
- InvalidContractState becomes structured with InvalidStateKind
(WrongVariant state-machine rejection vs ConditionFailed
runtime precondition)
Atomicity + subscriptions:
- Per-transaction atomicity of apply_transitions upgraded from
"recommended" to "required"; documented mid-step error handling
- apply_transitions rustdoc sharpened (atomic, durable,
idempotent per (contract_id, txid))
- New Subscription semantics paragraph on ChainSource:
idempotent set operations, register widens coverage,
unregister of never-registered is no-op, no duplicate
notifications
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Applied new sections and rustdoc expansions from the deadcat-core pre-implementation review. New sections: - Design Principles: "engine gates covenant-invalidity and impossibility, not unfavorability" + "multi-role patterns deferred to future versions," establishing the API's discretion boundary vs the correctness invariants above - Pool and Order Lifecycle at Market Resolution: post-resolution trading is intentionally not gated; pool operators manage liquidity via build_lmsr_close_pset; UI-layer warnings are the appropriate safety net (not engine refusal) - State Machine Summary: consolidated valid-transition matrices for all four contract types (binary market, multi-outcome market, LMSR pool, order); creation builders split into their own table; InvalidStateKind WrongVariant vs ConditionFailed error reporting documented Expanded sections: - MultiOutcome delta classification: explicit 7-variant shape table for IssuedPair / CancelledPair / SplitYes / MergeYes / SplitNo / MergeNo / CrossOutcomeSwap, plus pseudocode for the classification algorithm with matching precedence and edge cases (all-zero deltas, shape match with wrong coefficient falls through to Composite) - Cross-outcome arb v1 boundary: explicit statement that single-contract builders don't compose into arb PSETs; new Available/Not-available table for external arb tooling; LMSR F-value runtime is pub in v1 so external tooling shares the bignum algorithm Rustdoc expansions: - as_trade: enumerated preconditions and non-matching cases (pool admin, market-only, arb, multi-outcome bundle, multi-pool-same-outcome); explicit contrast with net_effect_for - TradeRealized: structure, engine-enforced invariants, and "stays single-outcome forever" v2 note - quote_trade: expanded NoLiquidity context payload explanation; explicit "post-resolution trading is not gated" note - build_trade_pset: freshness check algorithm with StaleQuoteReason variant breakdown; pool-admin-adjust subtlety called out - PSET Construction intro: state preconditions explained with InvalidContractState enum structure and State Machine Summary cross-reference (replaces per-builder "Valid from" rustdoc proliferation with one authoritative reference) Cleanup: - Resolved TODO anchor in apply_transitions rustdoc Not in this sprint (deferred): - Pool Chain-Sync Model subsection consolidation — existing Chain Sync section organization is coherent; dedicated subsection is cosmetic polish Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Applied follow-up items that emerged from reviewing the sprint 1-3 commits against the pre-implementation review conversation. lmsr-deterministic-table-spec.md: - New "Precision Calibration" subsection describing the one-time binary-search calibration that empirically validates the 200+ bit precision budget (start at 512 bits, halve until any root diverges from ground truth). Pinned as a development artifact in the spec, not per-CI regression. lmsr-pool-design.md: - Protocol constant encoding note: SimplicityHL lacks const::, so TABLE_DEPTH / S_BIAS / S_MAX_INDEX / MIN_POOL_RESERVE are encoded as zero-argument functions returning their literal values (identical CMR to inline literals, one named declaration per constant for audit legibility). deadcat-core-implementation-plan.md: - Phase 2: new deliverable 10 for precision calibration CLI (just calibrate-precision) + documented empirical result. - Phase 3: new deliverable 9 for deadcat-core-store-testkit crate exposing run_store_compliance / run_chain_source_compliance. - Known implementation risks: new entry 6 documenting that smplx pre-1.0 risk is mitigated by direct Blockstream collaboration. - Ingestion methods list updated: ingest_order → ingest_persistent_order / ingest_ephemeral_order. deadcat-core-design.md: - New "ContractStore Compliance Test Kit" subsection under Persistence: Store Trait, enumerating 10 invariant categories the testkit crate enforces (outpoint tracking, lifecycle, sync state, atomicity, indexing, rollback, pagination, query ordering, processing-log separation, tracking-mode behavior, plus ChainSource invariants). - Updated existing Design Decisions Log entry "Contract-Level Atomicity Required, Transaction-Level Recommended" to reflect sprint 2's upgrade: per-transaction atomicity is now required (title renamed to "Per-Transaction Atomicity Required"). - Added Pool and Order Lifecycle section: new "Ephemeral orders and rollback" subsection distinguishing pre-finality rollback (restores Consumed order to Active) from post-finality rollback (order is auto-untracked and gone; caller re-discovers). - New Design Decisions Log entries: - Labeled Outpoints at the Engine↔Store Boundary - Two Order Ingestion Methods, Not One - No Atomic Order Promotion Method - Post-Resolution Trading Not Gated - CovenantInvariantViolation Retained as Defense-in-Depth Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The "why we don't gate post-resolution trading" reasoning was
captured in the design doc but terse ("rejected on transaction-weight
grounds") and absent from lmsr-pool-design.md, which is where a
pool-focused reader would first look.
lmsr-pool-design.md:
- New "Why the pool covenant can't feasibly gate post-resolution
trading" subsection explaining the architectural constraint:
covenants can only introspect the current transaction, so
enforcement would require co-spending the market covenant's
UTXO on every swap — roughly doubling every swap's footprint
and imposing the cost on every trade, not just near-resolution
ones. The engine-layer non-gating follows from the covenant
choice.
deadcat-core-design.md:
- Pool and Order Lifecycle section: replaced terse "rejected on
transaction-weight grounds" with explicit mechanism (market
UTXO co-spend, ~1,000 vbyte overhead per swap, cost falls on
every trade) plus cross-ref to the pool-design satellite.
- Design Decisions Log (Post-Resolution Trading Not Gated):
expanded "Why" with the same architectural framing — covenant
market-state-agnosticism is architectural necessity, not policy
oversight — plus the same cross-ref.
trade-routing-algorithm.md:
- Quote Staleness subsection: added a parenthetical noting the
non-gating is an architectural consequence, with cross-refs
to both design-doc and pool-design coverage.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Resolves the discussion items and drift from the latest design review pass: - HD path constants frozen: m/86'/1145390932'/... (BIP-86 + SLIP-0044 coin_type "DCAT"). SLIP-0044 registration PR tracked as pre-v1-ship action item. - derive_pool_params / derive_order_params now take MarketParams umbrella + OutcomeIndex, and derive_pool_params takes initial_s_index directly (eliminating the non-injective bps↔s_index inversion on recovery). - Multi-outcome market hint: 37-byte unified layout (distinct type tag from binary); outcome_count derived from creation tx issuance count with a defensive amount/inflation_keys filter instead of being stored. - Pool hint: 41 → 40 bytes, 9-bit mantissa×exp → 4-bit 1-2-5 indices (aligned with the pending-refactors table; 5 stale references in the design doc updated). - Recovery flows updated to iterate outcomes for multi-outcome pools/orders and to pass initial_s_index through unchanged; "recovering without a hint" fallback documented as non-standard. - Oracle BIP-340 satellite marked binary-only with pointer to the unified MarketResolution API in the design doc. - ExternalOutput rustdoc tightened to flag the consolidation caveat and point at TransitionDetails as the authoritative per-role amount source. - Phase 3 parallelism scope replaced with a concrete three-bucket type list. - Phase 5 build_fill_pset reference removed (order fills go through the trade router, not a per-order builder). - PredictionMarketParams → BinaryMarketParams rename propagated across chain-only-recovery, deterministic-rt-blinding, contract-specification, lmsr-pool-design, and UX stories. - Price bound off-by-one fixed (2^24 → 0xFFFFFF = u24 max = 16,777,215). - Multi-outcome codegen "at build time" wording clarified as dev-time generation with committed .simf and src/artifacts outputs. - Trade PSET builder cross-references the composability layout algorithm. - Three new decisions-log entries (HD path, initial_s_index sourcing, outcome_count derivation) plus one update to the derive-functions entry. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Corrections to the preceding commit surfaced by an independent review pass:
- Fix wrong coin_type numeric constant. 0x44434154 ("DCAT") is 1,145,258,324,
not 1,145,390,932 (the latter is 0x44454754 = "DEGT"). The incorrect value
had propagated to 14 locations across chain-only-recovery.md, the design
doc, and the implementation plan. Confirmed 1,145,258,324 is unassigned
in SLIP-0044.
- Recovery flows: drop the claim that outcome_count() == 1 for binary
(contradicts the design doc's "2 for binary" at the Market view). Replace
with explicit per-market-kind iteration (binary → OutcomeIndex::BINARY;
multi-outcome → iterate 0..outcome_count from MultiOutcomeMarketParams)
to avoid depending on the pre-existing outcome_count() accessor semantic
ambiguity.
- enforcement-layers.md Layer 4 mechanism list: "1-2-5 table, 26-value
mantissa" → "shared 16-value 1-2-5 table for market base_payout and pool
max_loss_sats / half_payout_sats" (the 26-mantissa scheme is superseded).
- lmsr-pool-design.md derived-parameter table: replace "derived from the
inverse logistic function" with an explicit note that the bps→s_index
snap lives in estimate_bootstrap and the inverse no longer exists.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The CI workflow's Rust tests step was commented out, so two tests had been silently failing on master. Enable the step, switch the recipe to nextest, and fix the failing tests. * flake.nix, justfile: add cargo-nextest to the dev shell; collapse the workspace + deadcat-sdk test runs into a single `cargo nextest run` invocation, with a follow-up `cargo test --doc` pass since nextest doesn't execute doctests. * .github/workflows/ci.yml: uncomment the `Rust tests` step. * src-tauri/Cargo.toml: set [profile.test] opt-level = 1 to recoup some of the integration-test runtime cost now that CI runs them per-PR. * discovery/social.rs: the test for build_follow_list_event used [0xbb; 32] as a synthetic follow pubkey, but that byte pattern isn't a valid x-only secp256k1 key, so PublicKey::from_hex rejected it. Replace with Keys::generate().public_key().to_hex(). Also update the build_mute_list_event tag-shape assertion to expect the new `client` tag. * node.rs::order_cleanup_tests: 8ce1d69 made sync_wallet skip sync_own_order_state when list_own_maker_pubkeys is empty (60s -> 6s win). The sync_wallet_runs_store_sync test never seeded an own order, so the short-circuit kicked in and the synced_electrum_urls assertion failed empty. Seed a RecordedOwnOrder before calling sync_wallet. Also normalize a few reserve_yes_outpoint test fixtures. * Drop unused crates/deadcat-sdk/examples/seed_markets.rs (no in-tree references) and its [[example]] entry in deadcat-sdk/Cargo.toml.
Resolutions: * social.rs / node.rs: kept HEAD's test fixes (the master versions are the bugs this PR fixes). * seed_markets.rs: kept master's expanded version (The Daniel's Apr-16 work). Required wrapping `keys` in `Arc::new(...)` on setup_node since master's example wasn't actually compiling against master's own `DeadcatNode::new(signer: Arc<dyn NostrSigner>, ...)` signature; CI didn't catch it because clippy --all-targets skips examples gated by required-features. * views.md: kept HEAD's version and stripped stale 4ee5c77 conflict markers from a prior unresolved merge.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
cargo test --docpass since nextest doesn't execute them.cargo-nextestadded to the nix dev shell.build_follow_list_event_preserves_legacy_content_and_rewrites_p_tagsindiscovery/social.rs,sync_wallet_runs_store_sync_and_publishes_pending_deletionsinnode.rs).seed_marketsexample (870 lines, no in-tree references) and itsCargo.tomldeclaration.[profile.test] opt-level = 1to recoup some of the integration-test runtime cost now that CI runs the suite per-PR.This branch also ships a body of accumulated
deadcat-corespec/docs work that had been sitting locally ondocs. The CI commit is the only non-doc commit in the diff; review history withgit log --oneline master..HEADto see the doc commits separately.Failure root causes (for reviewer context)
build_follow_list_event_preserves_…— used[0xbb; 32]as a synthetic follow pubkey. That byte pattern isn't a valid x-only secp256k1 key, soPublicKey::from_hexvalidation (added in the same PR as the test) rightfully rejected it. Test was broken from day one; CI never ran it.sync_wallet_runs_store_sync_and_publishes_pending_deletions—8ce1d69madesync_walletskipsync_own_order_statewhenlist_own_maker_pubkeys()is empty (60s → 6s win). The test never seeded an own order, so the short-circuit kicked in andsynced_electrum_urlsstayed empty, breaking the assertion.Test plan
nix develop --command just biome-check— cleannix develop --command just tsc— cleannix develop --command just cargo-fmt— cleannix develop --command just cargo-clippy— clean (-D warnings)nix develop --command just cargo-test— 629 passed, 0 skipped, 0 failed (nextest) + doctests cleanelementsd-x86_64-unknown-linux-gnuNeed help on this PR? Tag
@codesmithwith what you need.