fix: comment retention taxonomy — TTL by (post policy x signing class)
Retention was keyed on comment type, so public and post-key-signed comments carried a randomized 30-365d expiry inside their signed digest. Under the ruling neither should ever expire; only the private, non-post-key-signed (open-slot/greeting) channel gets an automatic TTL, since that is the throwaway-identity retirement mechanism. New crates/core/src/comment_ttl.rs is the single authority: CommentClass (Public / PostKeySigned / OpenSlot / Unverifiable) x CommentTtlRule (Never | Window | UnknownParent), with draw_expiry (writer) and ttl_ok (holder). expires_at_ms == 0 is the never-expires sentinel, honored by the sweep, the ingest gate, and the store_comment upsert. - Post.comment_ttl: Option<CommentTtlPolicy> — a GENERIC per-post policy, so an author-set TTL is a future config surface, not a redesign. Registry posts declare a flat 30d policy that binds EVERY comment on them (registrations, duplicate reports, anything else), replacing the registration-only rule. - OpenSlotDecl.max_comments: author-declarable cap on private PK-unsigned comments, enforced holder-side (clamped to the holder default), replacing the hardcoded per-bio greeting cap. Refusal remains "declare no slot". Node::set_greetings_max + `greetings-max` CLI command to write it. - Holder enforcement rejects TTLs contradicting the parent's policy in both directions; a comment naming a different post than its envelope is rejected. - UnknownParent rule: bounded TTLs accepted from unheld parents (self-heal), never-expires refused — permanence is not granted on unseen evidence. Also fixed while here: five Post-reconstructing queries silently dropped comment_ttl AND the pre-existing fof_gating (shipped in v0.8.0-alpha), so any gated or policy-carrying post failed BLAKE3 verification on sync/export and was discarded with no diagnostic. All hydration now goes through one POST_COLUMNS/post_from_row path; export/import round-trips the policy. Registry frozen bytes regenerated for the policy field; REGISTRY_POST_ID is now 10a1be3383efb2977607fe45c4a7b3f1b5e626e81d0ac1af9c0f3d7eb9864d32. design.html section 21 rewritten to the corrected taxonomy. 250 core tests (was 228); a3 integration 12/12 (new step 6 asserts registry comments hold exactly 30d while greetings randomize); c_topology 33/33. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LGiPD2cF75mnvneSCjdDC5
This commit is contained in:
parent
fa02ace4cc
commit
8b042f6598
20 changed files with 1676 additions and 255 deletions
|
|
@ -245,6 +245,7 @@ async fn main() -> anyhow::Result<()> {
|
|||
println!(" reply <greeting_index> <text> Sealed reply to a greeting's return path (fresh reply key)");
|
||||
println!(" dismiss <greeting_index> Dismiss a greeting (local only)");
|
||||
println!(" greetings-open <on|off> Toggle the greeting slot on your bio (republishes bio)");
|
||||
println!(" greetings-max <n|default> Limit live stranger greetings on your bio (republishes bio)");
|
||||
println!(" stats Show node stats");
|
||||
println!(" export-key Export identity key (KEEP SECRET)");
|
||||
println!(" id Show this node's ID");
|
||||
|
|
@ -1164,6 +1165,44 @@ async fn main() -> anyhow::Result<()> {
|
|||
}
|
||||
}
|
||||
|
||||
// v0.8 ruling #6: author-declarable LIMIT on live stranger
|
||||
// greetings. Baked into the bio's signed OpenSlotDecl, so
|
||||
// setting it republishes the bio (holders clamp it to their
|
||||
// own ceiling; authors may lower it, never raise it).
|
||||
"greetings-max" => {
|
||||
let pid = node.default_posting_id;
|
||||
match arg.map(|a| a.trim()).filter(|a| !a.is_empty()) {
|
||||
Some(a) => {
|
||||
let limit = if a == "default" || a == "off" {
|
||||
None
|
||||
} else {
|
||||
match a.parse::<u32>() {
|
||||
Ok(n) => Some(n),
|
||||
Err(_) => {
|
||||
println!("Usage: greetings-max <n|default>");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
};
|
||||
match node.set_greetings_max(&pid, limit).await {
|
||||
Ok(()) => match limit {
|
||||
Some(n) => println!("Greeting limit set to {} (bio republished).", n),
|
||||
None => println!("Greeting limit cleared — holder default applies (bio republished)."),
|
||||
},
|
||||
Err(e) => println!("Error: {}", e),
|
||||
}
|
||||
}
|
||||
None => match node.get_greetings_max(&pid).await {
|
||||
Ok(Some(n)) => println!("Greeting limit: {}. Usage: greetings-max <n|default>", n),
|
||||
Ok(None) => println!(
|
||||
"Greeting limit: holder default ({}). Usage: greetings-max <n|default>",
|
||||
itsgoin_core::connection::MAX_GREETINGS_PER_BIO,
|
||||
),
|
||||
Err(e) => println!("Error: {}", e),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
"quit" | "exit" | "q" => {
|
||||
println!("Shutting down...");
|
||||
break;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue