Skip to content

P-Diff Fixes + Link Deserialization Fix (Deadlock Fixes Clean)#672

Closed
data-coasys wants to merge 16 commits intodevfrom
deadlock-fixes-clean
Closed

P-Diff Fixes + Link Deserialization Fix (Deadlock Fixes Clean)#672
data-coasys wants to merge 16 commits intodevfrom
deadlock-fixes-clean

Conversation

@data-coasys
Copy link
Contributor

@data-coasys data-coasys commented Feb 17, 2026

Summary

This PR contains the fixes from the deadlock-fixes branch, without the deadlock fix commits that are no longer needed now that PR #652 (SurrealDB file-based storage) is merged.

Changes Included

P-Diff Chunking Fixes

  • p-diff chunks as dependencies
  • Fix fast-forward-through-signal case with chunked diffs
  • Retry loop in ChunkedDiffs::from_entries()
  • Remove loop from ChunkedDiff::from_entries() and add debug logs
  • Another p-diff fix for chunked diffs

Tests

  • Test for chunked broadcast
  • Another integration test for chunked diffs

Debug Logging

  • p-diff debug logs
  • debugging PerspectiveInstance subject handling / link committing
  • more debug logs
  • logs in js_core signal receiver
  • more logs around HC signals
  • debug logs in p-diff-sync

Critical Fix

  • fix: link deserialisation - null as empty string (the main fix)

Commits Intentionally Excluded

The following deadlock fix attempts from the original deadlock-fixes branch were intentionally excluded as they are no longer needed after merging PR #652:

  • a947ca42 - wip: deadlock fix
  • 126cd46c - wip: deadlock fixes, deactivate prolog subscriptions
  • 914a729b - fix deadlock in ensure_engine_updated()

Created By

Data (AI Assistant) at Nico's request while he was driving home.

Summary by CodeRabbit

Release Notes

  • Bug Fixes

    • Improved reliability of large data (chunked diff) synchronization with validation and retry mechanisms.
    • Enhanced error handling for missing or invalid dependencies to prevent silent failures.
  • New Features

    • Strengthened validation of data dependencies across distributed peers.
  • Chores

    • Extended test coverage for chunked diff scenarios.
    • Improved system observability with enhanced runtime logging and diagnostics across sync and signal handling.
    • Updated link language configuration.
    • Improved null value handling in data deserialization.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Feb 17, 2026

📝 Walkthrough

Walkthrough

This pull request introduces comprehensive chunked-diff handling improvements and enhanced observability across the p-diff-sync Holochain zomes and executors. Key changes include: a new sweettest suite validating 600-link chunked-diff scenarios (broadcast, pull, render), addition of public get_diff_entry_reference API, chunked-diff verification post-creation with retry logic, updated workspace rendering to resolve chunked diffs before insertion, expanded signal routing logic with explicit error handling, and pervasive logging enhancements throughout signal handlers and commit/pull workflows for improved diagnostics.

Changes

Cohort / File(s) Summary
Test Suite Additions
bootstrap-languages/p-diff-sync/hc-dna/tests/sweettest/src/test_commit_pull.rs
Added comprehensive tests for chunked-diff behavior: test_chunked_broadcast_does_not_update_revision_on_failure, test_render_returns_chunked_diffs, test_pull_initial_with_chunked_diffs. Tests validate current_revision updates, 600-link rendering, and network isolation retry loops. +338/-8 lines.
Holochain Zome: Core & Integrity
bootstrap-languages/p-diff-sync/hc-dna/zomes/perspective_diff_sync/src/lib.rs, bootstrap-languages/p-diff-sync/hc-dna/zomes/perspective_diff_sync_integrity/src/lib.rs
Added public export of PerspectiveDiffEntryReference and new public function get_diff_entry_reference(hash). Upgraded logging from debug to info across signal handlers. Enhanced validation in integrity zome to check both parent and chunk dependencies, aggregating missing hashes before returning unresolved errors. +53/-14 lines.
Holochain Zome: Chunked Diffs & Commit
bootstrap-languages/p-diff-sync/hc-dna/zomes/perspective_diff_sync/src/link_adapter/chunked_diffs.rs, bootstrap-languages/p-diff-sync/hc-dna/zomes/perspective_diff_sync/src/link_adapter/commit.rs
Added extensive chunk-loading instrumentation and fail-fast error paths in ChunkedDiffs::from_entries. Introduced chunked-diff verification workflow with up-to-10-retry loop (100ms delays) after chunk creation to ensure retrievability. Enhanced commit logging with statistics (additions/removals), path selection (chunked vs. inline), and profiling timers. +138/-23 lines.
Holochain Zome: Pull & Render
bootstrap-languages/p-diff-sync/hc-dna/zomes/perspective_diff_sync/src/link_adapter/pull.rs, bootstrap-languages/p-diff-sync/hc-dna/zomes/perspective_diff_sync/src/link_adapter/render.rs
Replaced pull/broadcast debug logs with info-level, added load-before-update safety in handle_broadcast, per-diff telemetry, and error propagation on load failure. In render, added intermediate collection logging, per-entry diff counters, and totals reporting. +129/-37 lines.
Holochain Zome: Workspace
bootstrap-languages/p-diff-sync/hc-dna/zomes/perspective_diff_sync/src/link_adapter/workspace.rs
Made handle_parents generic over Retriever with error-propagating return type SocialContextResult<()>. Updated to load and resolve chunked diffs to inline form before inserting into entry_map, ensuring render sees complete additions/removals. Propagated errors throughout call chain with ? operator. +26/-5 lines.
JS/TS Executor: Signal Routing & Links
bootstrap-languages/p-diff-sync/index.ts, bootstrap-languages/p-diff-sync/linksAdapter.ts
Refactored signal handler in index.ts with explicit branching for link updates, routed telepresence (recipient_did), and broadcast telepresence. Added recipient-DID validation, PerspectiveExpression reconstruction, and try-catch with verbose error logging. Enhanced linksAdapter with gossip pull logging, peer-update tracing, and diff/addition sample reporting. +85/-55 lines.
Rust Executor: Holochain Service
executor/src/core/storage-services/Holochain/HolochainService.ts, rust-executor/src/holochain_service/mod.rs, rust-executor/src/js_core/mod.rs
Added callback handling diagnostics in HolochainService (registered callback counts, mismatch details). Holochain service now logs app_id context in signal forwarding and errors. JS core updated with emoji-prefixed signal logging (zome_name, callback completion, error details). +29/-13 lines.
Rust Executor: Perspectives
rust-executor/src/perspectives/mod.rs, rust-executor/src/perspectives/perspective_instance.rs
Enhanced diff handling with info logging on link language dispatch (additions/removals counts). Perspective instance expanded with verbose commit/batch logging (per-link details, source/predicate/target), improved error handling for pending-diffs (missing link language warning), and Prolog/SurrealDB operation tracing. +116/-44 lines.
Type & Configuration Updates
rust-executor/src/types.rs, cli/mainnet_seed.json, rust-executor/src/mainnet_seed.json
Updated Link struct deserialization to convert JSON nulls to empty strings for source and target fields via custom serde helper. Updated knownLinkLanguages seed entry in both CLI and Rust executor configs. +16/-3 lines.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Suggested reviewers

  • lucksus
  • jhweir

Poem

🐰 Chunks and diffs, oh what a sight,
Verification loops spinning through the night,
Logging traces light the way,
From pull to render, all in play,
Chunked retrieval's now done right! 🎉

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly identifies the two main focus areas: p-diff fixes and link deserialization fix, with a parenthetical note indicating deadlock-related changes were excluded.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch deadlock-fixes-clean

Tip

Issue Planner is now in beta. Read the docs and try it out! Share your feedback on Discord.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@data-coasys
Copy link
Contributor Author

Closing - will recreate as two separate PRs per Nico's instructions

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🧹 Nitpick comments (8)
bootstrap-languages/p-diff-sync/hc-dna/tests/sweettest/src/test_commit_pull.rs (3)

418-435: Excessive println! explanations in test output.

Lines 418–435 print a multi-paragraph explanation of the bug and fix every time the test runs. This is better suited for a doc comment on the test function (which already exists at lines 271–284) rather than runtime output. Consider removing or condensing to a single summary line.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@bootstrap-languages/p-diff-sync/hc-dna/tests/sweettest/src/test_commit_pull.rs`
around lines 418 - 435, The test prints a long multi-paragraph explanation at
runtime (the block of println! calls summarizing the bug/fix referencing
handle_broadcast(), load_diff_from_entry(), update_current_revision(), and
pull()), which is noisy; remove those runtime println! statements and either
convert the content into a doc comment on the test function (where existing docs
live around lines 271–284) or replace them with a single concise println!
summary line (e.g., "Fix: swapped load_diff_from_entry() and
update_current_revision() in handle_broadcast()") so the test output remains
brief.

403-416: Test can never fail — both branches pass.

The if bob_pull_result.is_err() / else block accepts both outcomes, making this test always pass regardless of whether chunks propagated in time. This documents the intended behavior but doesn't reliably catch regressions.

If the goal is to verify the fix, consider isolating the test by deferring exchange_peer_info until after Alice's commit and Bob's pull attempt (i.e., set network: false initially), so chunks are guaranteed absent on Bob's DHT. Then the is_err branch would always execute.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@bootstrap-languages/p-diff-sync/hc-dna/tests/sweettest/src/test_commit_pull.rs`
around lines 403 - 416, The test currently accepts both outcomes because it
allows network propagation, so change the setup to guarantee chunks are absent
on Bob before his pull: configure the test to start with network disabled (e.g.,
set network: false or defer calling exchange_peer_info) so Alice commits, then
call bob.pull() (check bob_pull_result) and assert that bob_current_after ==
bob_current_before in the is_err branch; only after asserting the error branch,
enable networking or call exchange_peer_info and re-run the successful
propagation assertions; reference bob_pull_result, bob_current_before,
bob_current_after, exchange_peer_info, and the pull()/handle_broadcast()
behavior to locate and modify the test setup and order of operations.

72-75: Duplicated peer-exchange retry loop.

The 5-iteration exchange_peer_info + sleep(2000) pattern is duplicated across test_merge_fetch (lines 72–75) and test_merge_fetch_deep (lines 178–181). Consider extracting to a helper in utils.rs alongside await_consistency.

Also applies to: 178-181

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@bootstrap-languages/p-diff-sync/hc-dna/tests/sweettest/src/test_commit_pull.rs`
around lines 72 - 75, Extract the duplicated 5-iteration retry loop that calls
conductors.exchange_peer_info().await followed by
tokio::time::sleep(Duration::from_millis(2000)).await into a new helper function
(e.g., await_peer_exchange or retry_peer_exchange) in utils.rs next to
await_consistency; implement it to accept the conductors object (or a reference)
and perform the same loop, then replace the loop in test_merge_fetch and
test_merge_fetch_deep with a call to this new helper to eliminate duplication.
bootstrap-languages/p-diff-sync/hc-dna/zomes/perspective_diff_sync/src/link_adapter/render.rs (1)

30-49: Same per-entry info! verbosity concern as chunked_diffs.rs.

Line 36 logs for every diff entry in the workspace. For perspectives with many diffs, this could produce significant output. The aggregate totals at line 51 are the most useful; consider debug! for per-entry logs.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@bootstrap-languages/p-diff-sync/hc-dna/zomes/perspective_diff_sync/src/link_adapter/render.rs`
around lines 30 - 49, The per-entry logging inside render.rs currently uses
info! when iterating workspace.entry_map (the for (hash, diff_node) loop) which
is too verbose; change that info! call to debug! so per-entry
additions_count/removals_count are emitted at debug level while keeping the
aggregate totals (total_additions, total_removals) logging at info; locate the
info! call that references additions_count, removals_count and hash and replace
it with debug! to reduce noise while leaving the rest of the logic (pushing
additions into perspective.links and inserting removals into removals_set)
unchanged.
bootstrap-languages/p-diff-sync/linksAdapter.ts (1)

235-239: Minor: log output for null targets will show "undefined...".

When link.data.target is null or undefined (which can happen), link?.data?.target?.substring(0, 60) evaluates to undefined, and the template literal produces target='undefined...'. Not a bug, but mildly misleading in logs.

🔧 Suggestion
-      console.log(`[p-diff-sync] 📤 commit():   addition[${i}]: source='${link?.data?.source}', pred='${link?.data?.predicate}', target='${link?.data?.target?.substring(0, 60)}...'`);
+      console.log(`[p-diff-sync] 📤 commit():   addition[${i}]: source='${link?.data?.source ?? '(null)'}', pred='${link?.data?.predicate ?? '(null)'}', target='${(link?.data?.target ?? '(null)').substring(0, 60)}...'`);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@bootstrap-languages/p-diff-sync/linksAdapter.ts` around lines 235 - 239, The
log in commit() prints "undefined..." when link.data.target is null/undefined;
update the logging to safely handle missing targets by using link (or link.data)
and link.data.target checks and a fallback string (e.g., '<null>' or empty
string) before calling substring — reference the commit() loop and the link
variable and replace the inline link?.data?.target?.substring(0, 60) expression
with a guarded expression that only calls substring when target is a string and
uses a clear fallback otherwise so logs show "<null>" (or similar) instead of
"undefined...".
bootstrap-languages/p-diff-sync/index.ts (1)

39-58: Verbose per-signal diagnostic logging may need to be removed/guarded before release.

Every signal (including frequent sync broadcasts) triggers JSON.stringify operations and multiple console.log calls at lines 44-58. This is useful for debugging but could measurably impact throughput and log volume in production. Consider gating behind a debug flag or removing once the chunking issues are confirmed fixed.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@bootstrap-languages/p-diff-sync/index.ts` around lines 39 - 58, The
per-signal diagnostic logging in the signal handler (references: signal,
payload, isArray, payloadKeys and the multiple console.log calls) is unguarded
and will impact production throughput; change it so the heavy JSON.stringify and
console.log blocks are executed only when a debug flag is enabled (e.g., check a
DEBUG_P_DIFF_SYNC env/config or logger.isDebugEnabled()) or remove them for
release — wrap the payload inspection and all console.log statements behind that
check and use a proper logger debug level instead of unconditional console.log
to avoid runtime and logging overhead in production.
bootstrap-languages/p-diff-sync/hc-dna/zomes/perspective_diff_sync/src/link_adapter/chunked_diffs.rs (1)

88-134: Consider reducing log level to debug! for per-chunk iteration logs.

In from_entries, every chunk produces 4 info! calls (load start, load result, processing, processed). For a 10-chunk diff, that's 40 info!-level log lines from this function alone. In a WASM zome, excessive logging adds measurable overhead. The start/complete logs (lines 88-91, 137-140) at info! are reasonable, but per-chunk logs could be debug!.

♻️ Suggestion: use debug! for per-chunk logs
         for (idx, hash) in hashes.iter().enumerate() {
-            info!(
+            debug!(
                 "ChunkedDiffs::from_entries: Loading chunk {}/{} (hash: {:?})",
                 idx + 1, hashes.len(), hash
             );
 
             let diff_entry = match Retreiver::get::<PerspectiveDiffEntryReference>(hash.clone()) {
                 Ok(entry) => {
-                    info!(
+                    debug!(
                         "ChunkedDiffs::from_entries: ✓ Chunk {}/{} retrieved successfully",
                         idx + 1, hashes.len()
                     );
                     entry
                 },
                 Err(e) => {
-                    info!(
+                    debug!(
                         "ChunkedDiffs::from_entries: ✗ FAILED to retrieve chunk {}/{} (hash: {:?}) - Error: {:?}",
                         idx + 1, hashes.len(), hash, e
                     );
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@bootstrap-languages/p-diff-sync/hc-dna/zomes/perspective_diff_sync/src/link_adapter/chunked_diffs.rs`
around lines 88 - 134, Change the per-chunk iteration logs in
ChunkedDiffs::from_entries from info! to debug! to reduce WASM logging overhead:
specifically, switch the non-error info! calls inside the for loop that log
"Loading chunk {}/...", the successful retrieval log ("✓ Chunk ... retrieved
successfully"), the "Processing chunk ..." log and the "Chunk ... processed ..."
log to debug!. Keep the outer start/complete info! logs and preserve the Err
branch logs (the failed retrieve and "Chunks not available" messages) at info!
so errors remain visible; locate these around Retreiver::get, diff_entry, and
load_diff_from_entry to apply the changes.
bootstrap-languages/p-diff-sync/hc-dna/zomes/perspective_diff_sync/src/link_adapter/commit.rs (1)

83-119: Busy-wait spin loop for retry delay — consider the CPU cost and preserve the last error.

Two concerns with the chunk verification retry:

  1. Busy-wait (lines 110–115): The inner loop spins on sys_time() to simulate a 100ms delay. In Holochain's WASM environment there may not be a better alternative, but 10 retries × 100ms of CPU spinning (up to 1 second total) is significant. If there's a wasm_utils::sleep or similar available in the HDK, prefer that.

  2. Lost error context (lines 99–101): When retries are exhausted, the original error e is discarded. Capturing it would aid debugging.

Proposed fix for preserving error context
+        let mut last_error = None;
         loop {
             match Retriever::get::<PerspectiveDiffEntryReference>(chunk_hash.clone()) {
                 Ok(_) => {
                     info!("===PerspectiveDiffSync.commit(): Chunk {}/{} verified available", idx + 1, chunk_hashes.len());
                     break;
                 }
                 Err(e) => {
                     retry_count += 1;
                     if retry_count > MAX_RETRIES {
-                        return Err(SocialContextError::InternalError(
-                            "Failed to verify chunk availability after creation"
-                        ));
+                        info!(
+                            "===PerspectiveDiffSync.commit(): Chunk {}/{} verification FAILED after {} retries. Last error: {:?}",
+                            idx + 1, chunk_hashes.len(), MAX_RETRIES, e
+                        );
+                        return Err(SocialContextError::InternalError(
+                            "Failed to verify chunk availability after creation"
+                        ));
                     }
+                    last_error = Some(e);
                     info!(
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@bootstrap-languages/p-diff-sync/hc-dna/zomes/perspective_diff_sync/src/link_adapter/commit.rs`
around lines 83 - 119, Replace the busy-wait and lost-error behavior in the
chunk verification loop: instead of spinning on sys_time() between attempts in
commit, use an available async sleep (e.g., wasm_utils::sleep or HDK sleep) with
RETRY_DELAY_MS to avoid CPU spin; also capture the original
Retriever::get::<PerspectiveDiffEntryReference> error (store e) and when
retry_count > MAX_RETRIES return a SocialContextError::InternalError that
includes or wraps that original error message so failure context is preserved;
keep MAX_RETRIES and RETRY_DELAY_MS constants but remove the inner sys_time spin
loop and reference sys_time only if no sleep alternative exists.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@bootstrap-languages/p-diff-sync/hc-dna/zomes/perspective_diff_sync/src/lib.rs`:
- Around line 134-139: The failure branch in recv_remote_signal logs a handling
failure with info!; change that to a proper higher severity (warn! or error!) —
update the Err(err) arm that contains info!("===recv_remote_signal: ✗
HashBroadcast handling FAILED - Error: {:?}", err) to use warn! (or error!)
instead, keeping the same formatted message and returning
Err(utils::err(&format!("{}", err))) unchanged.

In
`@bootstrap-languages/p-diff-sync/hc-dna/zomes/perspective_diff_sync/src/link_adapter/pull.rs`:
- Around line 266-268: The log shows revision == current_revision.hash but
execution continues; inside PerspectiveDiffSync::handle_broadcast() add an
explicit early return immediately after the info!() when revision equals
current_revision.hash to avoid running the parent-match and downstream work (use
the function's success return form, e.g. return Ok(()) or return Ok(None)
depending on the function signature). If instead you intend to always
re-broadcast at the later re-broadcast step (around the code referenced at line
312), make that behavior explicit with a comment and keep the early return
conditional only when you do NOT want re-broadcasting.

In `@rust-executor/src/perspectives/perspective_instance.rs`:
- Around line 474-503: The per-link info logs in the pending-diffs commit path
expose raw link data (see the loop that iterates pending_diffs.additions and the
log::info! that prints link.data.source, link.data.predicate, link.data.target);
change that per-link log to a debug (or trace) level (e.g., log::debug!) or
redact sensitive fields, so only the summary log (the existing info-level line
that logs pending_ids.len() and additions/removals counts) remains at info;
leave the surrounding commit_result handling (commit, Ok(Some(rev)), Err(e), and
the call to self.set_immediate_commits) unchanged.

---

Duplicate comments:
In `@rust-executor/src/perspectives/perspective_instance.rs`:
- Around line 663-713: The code currently logs full per-link contents at info
level in the commit path (see the loop that logs link.data.source,
link.data.predicate, link.data.target for each addition), which duplicates
earlier sensitive/verbose logs; change these per-link info logs to either debug
level or redact sensitive fields (e.g., log only link indices and types or
hashed/masked source/target) so you avoid duplicate high-volume
privacy-sensitive output while preserving the overall info-level summary (the
existing log::info with counts and the commit outcome via link_language.commit
remain fine).
- Around line 759-771: The current spawn block logs raw link/diff contents at
info level (log::info! and log::error! with {:?}) which duplicates
sensitive/verbose data; update the logging in the tokio::spawn closure (the
log::info! that prints "SPAWN COMMIT: Spawning commit..." and the log::error! /
log::info! that print commit() results) to avoid dumping raw diff
contents—either remove per-link/raw diff details, redact them (e.g. log counts
only like diff.additions.len() and diff.removals.len()), or lower the level to
debug/trace; ensure the messages in the async move block that reference
self_clone.commit(&diff_clone) do not interpolate full diff_clone data.
- Around line 3155-3156: The info-level log emitting raw command/expression data
(the log::info! call that prints commands.len(), expression, batch_id and
references the commands collection) risks privacy and high volume; change it to
a lower verbosity and/or redact sensitive fields — e.g., replace the log::info!
with log::debug! or log::trace! and stop printing the raw expression/commands
(only log commands.len() and batch_id), or mask the expression before logging;
update the statement that references commands.len(), expression, batch_id
accordingly to avoid dumping raw command contents.
- Around line 3453-3525: The code is logging raw command and value data at info
level (sensitive/verbose); change those info logs to a lower level or redact
sensitive fields before emitting. Specifically, in the create flow around
get_constructor_actions, get_property_setter_actions and resolve_property_value
where you log initial_values, each Command in commands, and command.target,
replace log::info! with log::debug! (or sanitize/mask command.target and
initial_values) so detailed payloads are not recorded at info level; ensure the
final completion/info logs remain high-level (e.g., keep timing and counts)
while detailed command/value dumps are either removed or only emitted at debug
level.
- Around line 1099-1100: The info-level log line that prints per-link raw
content and counts (the log::info! call starting "🔗 ADD LINK EXPR (batch):
added to batch=...") duplicates sensitive/verbose data; change it to a
lower-verbosity log (log::debug!) and remove or redact any raw link payloads so
only non-sensitive metadata remains (e.g., batch_id, status, and counts). Also
search for other similar per-link info logs in perspective_instance.rs and
convert them to debug/redacted forms to avoid duplicate noisy/privacy-leaking
logs.
- Around line 777-847: The per-link info-level logging that prints raw link
contents (the log::info! inside the additions loop that logs addition[{}]:
source='{}', pred={:?}, target='{}', author='{}') should be removed or reduced
to avoid sensitive/high-volume output; change that specific log to a lower level
(e.g., log::debug!) or redact sensitive fields (source/target/author) and only
emit non-sensitive metadata (index and counts). Update the loop that iterates
diff.additions (and similarly any equivalent loop over diff.removals) to use
log::debug! or a redacted message, keeping the overall high-level info logs (the
summary count logs using perspective_uuid and the post-dedup counts) unchanged.
- Around line 1008-1010: The info-level log statement in log::info! inside
perspective_instance (publishing diff) exposes raw owners and full
addition/removal counts/IDs (handle.uuid, decorated_diff.additions.len(),
decorated_diff.removals.len(), handle.owners) which duplicates sensitive/verbose
data — change it to redact or reduce detail and lower verbosity: replace the
log::info! with either log::debug! or log::trace! and/or log only safe
summarized fields (e.g., handle.uuid and numeric counts but not handle.owners or
raw IDs), or redact owner identifiers before logging; update the call site that
references decorated_diff and handle to log the sanitized values instead.
- Around line 919-920: The info-level log in perspective_instance.rs that prints
raw per-link contents via log::info!("🔗 ADD LINK: source='{}', pred={:?},
target='{}', status={:?}, batch_id={:?}", link.source, link.predicate,
link.target, status, batch_id) should be reduced or redacted to avoid
high-volume/privacy leaks; change it to a lower-severity log (debug/trace) or
sanitize fields (e.g., redact link.source and link.target or replace with
hashed/partial identifiers) and keep only non-sensitive metadata such as
predicate, status, and batch_id in the log; update the call site that constructs
this message so functionally identical contexts use the new format/severity.
- Around line 3408-3437: The info-level logs in the resolve-property flow expose
raw resolved values (see the log::info that prints result in the resolution
branch and other raw-value info/warn messages around JS_CORE_HANDLE) which is a
privacy/verbosity concern; change those value-displaying info logs to
debug-level (log::debug) or redact the actual content (e.g., mask result with
"[REDACTED]" or log only its size/hashed fingerprint) inside the resolve block
where prolog_query_with_context / prolog_get_first_string_binding and the
JS_CORE_HANDLE execution occur, and ensure the fallback path (the JS_CORE_HANDLE
None branch) does not emit raw value text at info level but instead logs a
non-sensitive message or debug/redacted content.
- Around line 4261-4377: The per-link info-level logging in the batch commit
loop (the log::info call that prints "🔄 BATCH COMMIT:   addition[{}]:
source='{}', pred={:?}, target='{}', status={:?}" inside the for link in
diff.additions loop) leaks raw link contents and should be downgraded or
redacted; change that call to log::debug (or log::trace) and/or replace raw
fields with a redacted/summary representation (e.g. only predicate and status or
a helper like redact_link_display(link.data) that masks source/target) so full
source/target values are not logged at info level. Ensure the same approach is
applied to any similar per-link logging in this commit path so only
non-sensitive summaries remain at info level.

---

Nitpick comments:
In
`@bootstrap-languages/p-diff-sync/hc-dna/tests/sweettest/src/test_commit_pull.rs`:
- Around line 418-435: The test prints a long multi-paragraph explanation at
runtime (the block of println! calls summarizing the bug/fix referencing
handle_broadcast(), load_diff_from_entry(), update_current_revision(), and
pull()), which is noisy; remove those runtime println! statements and either
convert the content into a doc comment on the test function (where existing docs
live around lines 271–284) or replace them with a single concise println!
summary line (e.g., "Fix: swapped load_diff_from_entry() and
update_current_revision() in handle_broadcast()") so the test output remains
brief.
- Around line 403-416: The test currently accepts both outcomes because it
allows network propagation, so change the setup to guarantee chunks are absent
on Bob before his pull: configure the test to start with network disabled (e.g.,
set network: false or defer calling exchange_peer_info) so Alice commits, then
call bob.pull() (check bob_pull_result) and assert that bob_current_after ==
bob_current_before in the is_err branch; only after asserting the error branch,
enable networking or call exchange_peer_info and re-run the successful
propagation assertions; reference bob_pull_result, bob_current_before,
bob_current_after, exchange_peer_info, and the pull()/handle_broadcast()
behavior to locate and modify the test setup and order of operations.
- Around line 72-75: Extract the duplicated 5-iteration retry loop that calls
conductors.exchange_peer_info().await followed by
tokio::time::sleep(Duration::from_millis(2000)).await into a new helper function
(e.g., await_peer_exchange or retry_peer_exchange) in utils.rs next to
await_consistency; implement it to accept the conductors object (or a reference)
and perform the same loop, then replace the loop in test_merge_fetch and
test_merge_fetch_deep with a call to this new helper to eliminate duplication.

In
`@bootstrap-languages/p-diff-sync/hc-dna/zomes/perspective_diff_sync/src/link_adapter/chunked_diffs.rs`:
- Around line 88-134: Change the per-chunk iteration logs in
ChunkedDiffs::from_entries from info! to debug! to reduce WASM logging overhead:
specifically, switch the non-error info! calls inside the for loop that log
"Loading chunk {}/...", the successful retrieval log ("✓ Chunk ... retrieved
successfully"), the "Processing chunk ..." log and the "Chunk ... processed ..."
log to debug!. Keep the outer start/complete info! logs and preserve the Err
branch logs (the failed retrieve and "Chunks not available" messages) at info!
so errors remain visible; locate these around Retreiver::get, diff_entry, and
load_diff_from_entry to apply the changes.

In
`@bootstrap-languages/p-diff-sync/hc-dna/zomes/perspective_diff_sync/src/link_adapter/commit.rs`:
- Around line 83-119: Replace the busy-wait and lost-error behavior in the chunk
verification loop: instead of spinning on sys_time() between attempts in commit,
use an available async sleep (e.g., wasm_utils::sleep or HDK sleep) with
RETRY_DELAY_MS to avoid CPU spin; also capture the original
Retriever::get::<PerspectiveDiffEntryReference> error (store e) and when
retry_count > MAX_RETRIES return a SocialContextError::InternalError that
includes or wraps that original error message so failure context is preserved;
keep MAX_RETRIES and RETRY_DELAY_MS constants but remove the inner sys_time spin
loop and reference sys_time only if no sleep alternative exists.

In
`@bootstrap-languages/p-diff-sync/hc-dna/zomes/perspective_diff_sync/src/link_adapter/render.rs`:
- Around line 30-49: The per-entry logging inside render.rs currently uses info!
when iterating workspace.entry_map (the for (hash, diff_node) loop) which is too
verbose; change that info! call to debug! so per-entry
additions_count/removals_count are emitted at debug level while keeping the
aggregate totals (total_additions, total_removals) logging at info; locate the
info! call that references additions_count, removals_count and hash and replace
it with debug! to reduce noise while leaving the rest of the logic (pushing
additions into perspective.links and inserting removals into removals_set)
unchanged.

In `@bootstrap-languages/p-diff-sync/index.ts`:
- Around line 39-58: The per-signal diagnostic logging in the signal handler
(references: signal, payload, isArray, payloadKeys and the multiple console.log
calls) is unguarded and will impact production throughput; change it so the
heavy JSON.stringify and console.log blocks are executed only when a debug flag
is enabled (e.g., check a DEBUG_P_DIFF_SYNC env/config or
logger.isDebugEnabled()) or remove them for release — wrap the payload
inspection and all console.log statements behind that check and use a proper
logger debug level instead of unconditional console.log to avoid runtime and
logging overhead in production.

In `@bootstrap-languages/p-diff-sync/linksAdapter.ts`:
- Around line 235-239: The log in commit() prints "undefined..." when
link.data.target is null/undefined; update the logging to safely handle missing
targets by using link (or link.data) and link.data.target checks and a fallback
string (e.g., '<null>' or empty string) before calling substring — reference the
commit() loop and the link variable and replace the inline
link?.data?.target?.substring(0, 60) expression with a guarded expression that
only calls substring when target is a string and uses a clear fallback otherwise
so logs show "<null>" (or similar) instead of "undefined...".

Comment on lines +134 to +139
Err(err) => {
info!(
"===recv_remote_signal: ✗ HashBroadcast handling FAILED - Error: {:?}",
err
);
Err(utils::err(&format!("{}", err)))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Error logged at info! level — should be warn! or error!.

Line 135 logs a handling failure ("✗ HashBroadcast handling FAILED") using info!. Failures should use warn! or error! for proper log-level filtering in production.

🔧 Proposed fix
             Err(err) => {
-                info!(
+                error!(
                     "===recv_remote_signal: ✗ HashBroadcast handling FAILED - Error: {:?}",
                     err
                 );
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
Err(err) => {
info!(
"===recv_remote_signal: ✗ HashBroadcast handling FAILED - Error: {:?}",
err
);
Err(utils::err(&format!("{}", err)))
Err(err) => {
error!(
"===recv_remote_signal: ✗ HashBroadcast handling FAILED - Error: {:?}",
err
);
Err(utils::err(&format!("{}", err)))
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@bootstrap-languages/p-diff-sync/hc-dna/zomes/perspective_diff_sync/src/lib.rs`
around lines 134 - 139, The failure branch in recv_remote_signal logs a handling
failure with info!; change that to a proper higher severity (warn! or error!) —
update the Err(err) arm that contains info!("===recv_remote_signal: ✗
HashBroadcast handling FAILED - Error: {:?}", err) to use warn! (or error!)
instead, keeping the same formatted message and returning
Err(utils::err(&format!("{}", err))) unchanged.

Comment on lines 266 to 268
if revision == current_revision.hash {
// debug!("===PerspectiveDiffSync.fast_forward_signal(): Revision is the same as current");
info!("===PerspectiveDiffSync.handle_broadcast(): Revision is the same as current - no action needed");
};
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Missing early return when broadcast revision matches current.

Line 267 logs "no action needed" but execution falls through to the parent-matching check on line 270. If this is the same revision, we should return early to avoid unnecessary work. If the intention is to always re-broadcast (line 312), consider making that explicit.

Proposed fix
         if revision == current_revision.hash {
-            info!("===PerspectiveDiffSync.handle_broadcast(): Revision is the same as current - no action needed");
-        };
+            info!("===PerspectiveDiffSync.handle_broadcast(): Revision is the same as current - no action needed");
+            // Still emit the broadcast signal for other peers, but skip processing
+            emit_signal(broadcast)?;
+            let fn_end = get_now()?.time();
+            info!(
+                "===PerspectiveDiffSync.handle_broadcast(): COMPLETE (no-op) - Took: {}ms",
+                (fn_end - fn_start).num_milliseconds()
+            );
+            return Ok(());
+        };
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if revision == current_revision.hash {
// debug!("===PerspectiveDiffSync.fast_forward_signal(): Revision is the same as current");
info!("===PerspectiveDiffSync.handle_broadcast(): Revision is the same as current - no action needed");
};
if revision == current_revision.hash {
info!("===PerspectiveDiffSync.handle_broadcast(): Revision is the same as current - no action needed");
// Still emit the broadcast signal for other peers, but skip processing
emit_signal(broadcast)?;
let fn_end = get_now()?.time();
info!(
"===PerspectiveDiffSync.handle_broadcast(): COMPLETE (no-op) - Took: {}ms",
(fn_end - fn_start).num_milliseconds()
);
return Ok(());
};
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@bootstrap-languages/p-diff-sync/hc-dna/zomes/perspective_diff_sync/src/link_adapter/pull.rs`
around lines 266 - 268, The log shows revision == current_revision.hash but
execution continues; inside PerspectiveDiffSync::handle_broadcast() add an
explicit early return immediately after the info!() when revision equals
current_revision.hash to avoid running the parent-match and downstream work (use
the function's success return form, e.g. return Ok(()) or return Ok(None)
depending on the function signature). If instead you intend to always
re-broadcast at the later re-broadcast step (around the code referenced at line
312), make that behavior explicit with a comment and keep the early return
conditional only when you do NOT want re-broadcasting.

Comment on lines +474 to 503
log::info!("📤 PENDING DIFFS: Committing {} pending diffs ({} additions, {} removals) for perspective {}",
pending_ids.len(), pending_diffs.additions.len(), pending_diffs.removals.len(), uuid);
for (i, link) in pending_diffs.additions.iter().enumerate() {
log::info!("📤 PENDING DIFFS: addition[{}]: source='{}', pred={:?}, target='{}'",
i, link.data.source, link.data.predicate, link.data.target);
}
let commit_result = link_language.commit(pending_diffs).await;
match commit_result {
Ok(Some(_)) => {
Ok(Some(rev)) => {
Ad4mDb::with_global_instance(|db| {
db.clear_pending_diffs(&uuid, pending_ids)
})?;
// Reset immediate commits counter after successful commit
self.set_immediate_commits(IMMEDIATE_COMMITS_COUNT).await;
log::info!("Successfully committed pending diffs");
log::info!("📤 PENDING DIFFS: Successfully committed, revision={}, reset immediate_commits to {}",
rev, IMMEDIATE_COMMITS_COUNT);
Ok(())
}
Ok(None) => Err(anyhow!("No diff returned from commit")),
Err(e) => Err(e),
Ok(None) => {
log::warn!("📤 PENDING DIFFS: Commit returned None revision");
Err(anyhow!("No diff returned from commit"))
}
Err(e) => {
log::error!("📤 PENDING DIFFS: Commit failed: {:?}", e);
Err(e)
}
}
} else {
log::warn!("📤 PENDING DIFFS: No link language available, keeping {} diffs for later", pending_ids.len());
Ok(()) // Keep diffs if no link language
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Downgrade per-link info logs to avoid PII/volume exposure.
Info-level logs include raw source/predicate/target for every pending diff; this can leak user data and overwhelm logs on bursts. Keep count-only at info and move per-link details to debug/trace (or redact).

Proposed fix (move per-link details to debug)
-                log::info!("📤 PENDING DIFFS: Committing {} pending diffs ({} additions, {} removals) for perspective {}",
-                    pending_ids.len(), pending_diffs.additions.len(), pending_diffs.removals.len(), uuid);
-                for (i, link) in pending_diffs.additions.iter().enumerate() {
-                    log::info!("📤 PENDING DIFFS:   addition[{}]: source='{}', pred={:?}, target='{}'",
-                        i, link.data.source, link.data.predicate, link.data.target);
-                }
+                log::info!(
+                    "📤 PENDING DIFFS: Committing {} pending diffs ({} additions, {} removals) for perspective {}",
+                    pending_ids.len(),
+                    pending_diffs.additions.len(),
+                    pending_diffs.removals.len(),
+                    uuid
+                );
+                if log::log_enabled!(log::Level::Debug) {
+                    for (i, link) in pending_diffs.additions.iter().enumerate() {
+                        log::debug!(
+                            "📤 PENDING DIFFS:   addition[{}]: source='{}', pred={:?}, target='{}'",
+                            i, link.data.source, link.data.predicate, link.data.target
+                        );
+                    }
+                }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@rust-executor/src/perspectives/perspective_instance.rs` around lines 474 -
503, The per-link info logs in the pending-diffs commit path expose raw link
data (see the loop that iterates pending_diffs.additions and the log::info! that
prints link.data.source, link.data.predicate, link.data.target); change that
per-link log to a debug (or trace) level (e.g., log::debug!) or redact sensitive
fields, so only the summary log (the existing info-level line that logs
pending_ids.len() and additions/removals counts) remains at info; leave the
surrounding commit_result handling (commit, Ok(Some(rev)), Err(e), and the call
to self.set_immediate_commits) unchanged.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants