chore: scrub internal session-log narrative from code comments
Wide sweep across the codebase to remove leftover artifacts of internal
development sessions, internal entity naming, and audit-code references
that point at non-public docs. The technical reasoning for each piece
of code stays; the "Caught 2026-05-XX while debugging XYZ at preprod"
narrative goes.
Categories scrubbed:
- Dated session-log comments ("Caught/Surfaced/Discovered 2026-05-XX")
→ rewritten as neutral technical reasoning.
- Internal audit codes (AUDIT-H2, AUDIT-C2, AUDIT-M2, AUDIT-H5, etc.)
referencing a non-public audit doc → labels stripped, fix reasoning
kept.
- Internal-entity names in code comments (Sulkta-specific, Sulkta runs
X, Terrapin/TRP as gov-token names) → generic phrasing.
- Test fixture helper `sulkta_cfg` → `test_dao_cfg`; test DAO name
string `"sulkta"` → `"test-dao"`. On-chain addresses in test fixtures
kept (they're real-world wire-byte test data on public chain).
- Cross-references to memory files / non-public audit docs
(`internal notes`, `aiken-escrow/README.md`)
→ reasoning inlined or removed.
- Test names renamed: `decodes_sulkta_live_governor_datum` →
`decodes_live_governor_datum`, `decodes_sulkta_live_proposal_zero` →
`decodes_live_finished_proposal`, etc.
Kept (legitimate):
- Cross-references to in-repo audit docs (aiken-escrow/README.md, aiken-escrow/README.md) — they ARE the
public artifacts being referenced.
- HIGH-1/HIGH-2/MED-2/LOW labels on escrow fixes — these correspond to
findings in the in-repo audit doc.
- TODO markers — legitimate work-still-to-do.
This commit is contained in:
parent
93f0d2ebde
commit
564ba3ccb5
28 changed files with 258 additions and 296 deletions
|
|
@ -3,9 +3,7 @@
|
|||
//! Each `#[tool]` becomes a discoverable MCP tool. Tool names use
|
||||
//! `snake_case` only (no dots) — Claude Code's MCP client validates
|
||||
//! tool names against `[a-zA-Z0-9_-]{1,64}` and silently drops names
|
||||
//! with dots. This was an integration-time discovery 2026-05-04 after
|
||||
//! the first session restart found zero aldabra tools advertised
|
||||
//! despite the daemon running.
|
||||
//! with dots, causing the daemon to run without advertising any tools.
|
||||
//!
|
||||
//! ## Phase 1 — read path
|
||||
//!
|
||||
|
|
@ -85,11 +83,11 @@ use aldabra_dao::reader::{DaoReader, KoiosDaoReader};
|
|||
/// raw options; this fn enforces the "at most one" rule and reads
|
||||
/// the file when path is set.
|
||||
///
|
||||
/// The path-based variant exists because of the 2026-05-07 MCP
|
||||
/// transport bug: hex strings >~ 4500 chars get a 1-byte truncation
|
||||
/// + structural rearrangement somewhere between Claude Code and
|
||||
/// aldabra's stdio reader. Reading from a file inside the container
|
||||
/// bypasses the JSON-RPC arg path entirely.
|
||||
/// The path-based variant exists because of an MCP transport bug:
|
||||
/// hex strings >~ 4500 chars get a 1-byte truncation + structural
|
||||
/// rearrangement somewhere between client and stdio reader. Reading
|
||||
/// from a file inside the container bypasses the JSON-RPC arg path
|
||||
/// entirely.
|
||||
fn resolve_ref_script_bytes(
|
||||
cbor_hex: Option<&str>,
|
||||
path: Option<&str>,
|
||||
|
|
@ -127,11 +125,11 @@ fn resolve_ref_script_bytes(
|
|||
/// reads the file when path is set.
|
||||
///
|
||||
/// Mirrors [`resolve_ref_script_bytes`] — same workaround for the
|
||||
/// 2026-05-07 MCP transport bug where hex strings >~ 4500 chars
|
||||
/// get a 1-byte truncation between Claude Code and aldabra's stdio
|
||||
/// reader, surfacing as "odd length" hex decode errors and blocking
|
||||
/// debug-build minting policies. Reading from a file inside the
|
||||
/// container bypasses the JSON-RPC arg path entirely.
|
||||
/// MCP large-string transport bug where hex strings >~ 4500 chars
|
||||
/// get a 1-byte truncation between client and stdio reader,
|
||||
/// surfacing as "odd length" hex decode errors and blocking debug-
|
||||
/// build minting policies. Reading from a file inside the container
|
||||
/// bypasses the JSON-RPC arg path entirely.
|
||||
fn resolve_policy_cbor_bytes(
|
||||
cbor_hex: Option<&str>,
|
||||
path: Option<&str>,
|
||||
|
|
@ -352,7 +350,7 @@ pub struct SendArgs {
|
|||
/// Path INSIDE THE ALDABRA CONTAINER to a file containing the
|
||||
/// hex-encoded reference-script CBOR. Use INSTEAD of
|
||||
/// `reference_script_cbor_hex` for scripts >~ 4KB to bypass the
|
||||
/// MCP large-string transport bug (caught 2026-05-07: hex strings
|
||||
/// MCP large-string transport bug (hex strings
|
||||
/// > ~4500 chars get a 1-byte truncation + structural rearrangement
|
||||
/// > somewhere between Claude Code and aldabra's stdio reader).
|
||||
/// > File contents may include leading/trailing whitespace; only
|
||||
|
|
@ -482,7 +480,7 @@ pub struct PlutusMintUnsignedArgs {
|
|||
/// Path INSIDE THE ALDABRA CONTAINER to a file containing
|
||||
/// hex-encoded Plutus policy CBOR. Use INSTEAD of
|
||||
/// `policy_cbor_hex` for scripts >~ 4500 chars to bypass the
|
||||
/// MCP large-string transport bug (caught 2026-05-07: hex strings
|
||||
/// MCP large-string transport bug (hex strings
|
||||
/// > ~4500 chars get a 1-byte truncation + structural rearrangement
|
||||
/// > somewhere between Claude Code and aldabra's stdio reader,
|
||||
/// > surfacing as "odd length" hex decode errors). File contents
|
||||
|
|
@ -508,7 +506,7 @@ pub struct PlutusMintUnsignedArgs {
|
|||
pub dest_lovelace: u64,
|
||||
/// Non-mint native assets to forward from wallet inputs onto
|
||||
/// the recipient output. Used e.g. on stake bootstrap to send
|
||||
/// gov tokens (tTRP) into the stakes_addr alongside the freshly
|
||||
/// gov tokens into the stakes_addr alongside the freshly
|
||||
/// minted StakeST.
|
||||
#[serde(default)]
|
||||
pub dest_extra_assets: Vec<McpAssetSpec>,
|
||||
|
|
@ -729,11 +727,9 @@ pub struct Cip68NftArgs {
|
|||
fn default_token_lovelace() -> u64 {
|
||||
// 2.5 ADA — Babbage min-utxo for an inline-datum-bearing
|
||||
// multi-asset output is ~1.79 ADA (depends on datum size).
|
||||
// 1.5 was too low; 2.5 gives comfortable margin for typical
|
||||
// CIP-68 metadata (~150 bytes). Larger metadata still requires
|
||||
// the caller to override.
|
||||
// Discovered preprod 2026-05-04 via
|
||||
// BabbageOutputTooSmallUTxO chain rejection.
|
||||
// 2.5 gives comfortable margin for typical CIP-68 metadata
|
||||
// (~150 bytes). Larger metadata still requires the caller to
|
||||
// override.
|
||||
2_500_000
|
||||
}
|
||||
|
||||
|
|
@ -2426,7 +2422,7 @@ impl WalletService {
|
|||
.await
|
||||
.map_err(|e| format!("koios get wallet utxos: {e}"))?;
|
||||
|
||||
// AUDIT-H5 fix: assets in the chain backend are
|
||||
// assets in the chain backend are
|
||||
// `BTreeMap<policy_id_hex || asset_name_hex, qty>`. Previous
|
||||
// implementation silently dropped any key < 56 chars via filter_map
|
||||
// — that could let a corrupt Koios response burn assets on submit.
|
||||
|
|
@ -2527,7 +2523,7 @@ impl WalletService {
|
|||
|
||||
#[tool(
|
||||
name = "dao_stake_destroy_unsigned",
|
||||
description = "Build an unsigned tx that destroys this wallet's stake — burns the StakeST token and returns all locked governance tokens (TRP) + lovelace to the wallet. Owner-only (delegatees rejected). Requires the stake to have NO active locks (no Created/Voted/Cosigned ProposalLocks). Args: dao? + fee_lovelace (~2_000_000)."
|
||||
description = "Build an unsigned tx that destroys this wallet's stake — burns the StakeST token and returns all locked governance tokens + lovelace to the wallet. Owner-only (delegatees rejected). Requires the stake to have NO active locks (no Created/Voted/Cosigned ProposalLocks). Args: dao? + fee_lovelace (~2_000_000)."
|
||||
)]
|
||||
async fn dao_stake_destroy_unsigned(
|
||||
&self,
|
||||
|
|
@ -2700,10 +2696,10 @@ impl WalletService {
|
|||
// either inside the period OR strictly after period_end. Any
|
||||
// straddle = waste of fees.
|
||||
//
|
||||
// AUDIT-2026-05-06 H-1/H-2/H-4 fixes: use STRICT > on PAfter
|
||||
// boundary, require tx-upper to land inside the target period for
|
||||
// PWithin, AND gate Locked→Finished on tx_lower > executing_end so
|
||||
// we never hit the "missing GAT-mint" path.
|
||||
// Boundary discipline: use STRICT > on PAfter, require tx-upper
|
||||
// to land inside the target period for PWithin, AND gate
|
||||
// Locked→Finished on `tx_lower > executing_end` so we never hit
|
||||
// the "missing GAT-mint" path.
|
||||
use aldabra_dao::agora::proposal::ProposalStatus as PS;
|
||||
const VALIDITY_RANGE_MS: i64 =
|
||||
aldabra_dao::builder::proposal_create::VALIDITY_RANGE_SLOTS as i64 * 1000;
|
||||
|
|
@ -3182,20 +3178,19 @@ impl WalletService {
|
|||
tip_slot + aldabra_dao::builder::proposal_create::VALIDITY_RANGE_SLOTS;
|
||||
let tx_lower_ms = slot_to_posix_ms(cfg.network, tip_slot)?;
|
||||
|
||||
// AUDIT-2026-05-06 H-3 fix: validator (Proposal/Scripts.hs PVote
|
||||
// ~L511) demands `pgetRelation == PWithin VotingPeriod`, where
|
||||
// PWithin requires BOTH `voting_start <= lb` AND `ub <= voting_end`.
|
||||
// The builder's existing preflight only verified the upper bound;
|
||||
// a vote-too-early call (tip < voting_start) would burn fees on a
|
||||
// "too early or invalid" script error. Catch lb-vs-voting_start
|
||||
// here too.
|
||||
// Validator (Proposal/Scripts.hs PVote ~L511) demands
|
||||
// `pgetRelation == PWithin VotingPeriod`, where PWithin requires
|
||||
// BOTH `voting_start <= lb` AND `ub <= voting_end`. The earlier
|
||||
// preflight checked only the upper bound; a vote-too-early call
|
||||
// (tip < voting_start) would burn fees on a "too early or
|
||||
// invalid" script error. Catch lb-vs-voting_start here too.
|
||||
//
|
||||
// 2026-05-08 follow-up: when default validity_upper would
|
||||
// overshoot voting_end (e.g. 30-min Sulkta-shape windows where
|
||||
// the 1799-slot validity range starting from current tip lands
|
||||
// past voting_end), clamp validity_upper_slot to voting_end_slot
|
||||
// so the range fits inside the voting window. Same trick the
|
||||
// proposal_advance Draft→VotingReady clamp uses.
|
||||
// When default validity_upper would overshoot voting_end (e.g.
|
||||
// tight 30-min governor windows where the 1799-slot validity
|
||||
// range starting from current tip lands past voting_end), clamp
|
||||
// validity_upper_slot to voting_end_slot so the range fits
|
||||
// inside the voting window. Same trick the proposal_advance
|
||||
// Draft→VotingReady clamp uses.
|
||||
//
|
||||
// Read from prop_datum (target.datum was moved to prop_datum at L2636).
|
||||
let voting_start_check = prop_datum.starting_time + prop_datum.timing_config.draft_time;
|
||||
|
|
@ -3566,12 +3561,12 @@ impl WalletService {
|
|||
// ─── escrow — two-party agreement-with-veto escrow on Plutus V3 ───
|
||||
//
|
||||
// Validator hash: a8081acef26935d9b5f44b92052178e17301b6d6e6808c91c5b56f5d.
|
||||
// Internal audit pass + 9-tx preprod E2E shipped 2026-05-09. Has NOT been
|
||||
// through external third-party audit; the `escrow_open_unsigned` response
|
||||
// carries a runtime "use at own risk" notice so the calling agent has it
|
||||
// in-context for the conversation that opens an escrow. Subsequent escrow
|
||||
// tools (deposit / agree / veto / settle / refund_timeout) don't repeat
|
||||
// the notice — once acknowledged at open, the same caveat carries.
|
||||
// Internal audit only — NOT third-party audited. The
|
||||
// `escrow_open_unsigned` response carries a runtime "use at own
|
||||
// risk" notice so the calling agent has it in-context for the
|
||||
// conversation that opens an escrow. Subsequent escrow tools
|
||||
// (deposit / agree / veto / settle / refund_timeout) don't repeat
|
||||
// the notice — once acknowledged at open, the caveat carries.
|
||||
|
||||
#[tool(
|
||||
name = "escrow_open_unsigned",
|
||||
|
|
@ -4133,7 +4128,7 @@ pub struct DaoRegisterArgs {
|
|||
pub treasury_addr: String,
|
||||
/// 56 hex chars (28 bytes).
|
||||
pub gov_token_policy: String,
|
||||
/// Hex-encoded asset name (e.g. "546572726170696e" for "Terrapin").
|
||||
/// Hex-encoded asset name (e.g. "546572726170696e" hex-decodes to "Terrapin").
|
||||
pub gov_token_name_hex: String,
|
||||
/// `txhash#index` — the Agora bootstrap tx ref that identifies the DAO.
|
||||
pub initial_spend: String,
|
||||
|
|
@ -4146,10 +4141,11 @@ pub struct DaoRegisterArgs {
|
|||
|
||||
// ─── Phase 4 prerequisites — all optional ─────────────────────────────
|
||||
//
|
||||
// Populate these to unlock dao_proposal_create_unsigned and the
|
||||
// upcoming vote/cosign/advance tools. Each can be discovered via
|
||||
// chain queries (the audit pattern at internal notes*.md);
|
||||
// a future dao_discover_scripts MCP tool will fill them automatically.
|
||||
// Populate these to unlock dao_proposal_create_unsigned + the
|
||||
// vote/cosign/advance tools. Each can be discovered via chain
|
||||
// queries against the configured governor + stakes addresses;
|
||||
// see the `dao_discover_scripts` MCP tool which fills them
|
||||
// automatically from on-chain state.
|
||||
/// Proposal validator address (bech32). Where new proposal UTxOs land.
|
||||
#[serde(default)]
|
||||
pub proposal_addr: Option<String>,
|
||||
|
|
@ -4482,8 +4478,8 @@ fn slot_to_posix_ms(network: DaoNetwork, slot: u64) -> Result<i64, String> {
|
|||
/// Shared by every DAO write-path tool that needs to fund + collateralize
|
||||
/// from the wallet. Surfaces malformed asset keys (< 56 chars) as errors
|
||||
/// instead of silently dropping them — a corrupt Koios response would
|
||||
/// otherwise let our builder construct a tx that loses native assets on
|
||||
/// submit. AUDIT-H5 fix from 2026-05-05.
|
||||
/// otherwise let the builder construct a tx that loses native assets
|
||||
/// on submit.
|
||||
async fn pull_wallet_utxos(
|
||||
chain: &KoiosClient,
|
||||
address: &str,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue