Skip to content

fix: filter partial form fields and fix centered text in scroll mode#674

Open
torlando-tech wants to merge 3 commits intomainfrom
fix/nomadnet-partial-fields-and-centering
Open

fix: filter partial form fields and fix centered text in scroll mode#674
torlando-tech wants to merge 3 commits intomainfrom
fix/nomadnet-partial-fields-and-centering

Conversation

@torlando-tech
Copy link
Copy Markdown
Owner

Summary

  • Partial field filtering: PartialManager.buildFormDataJson now only forwards form fields declared by each partial's fieldNames list, matching NomadNet TUI's __get_partial_request_data() behavior. "*" = all fields, empty list = none. Prevents undeclared fields (e.g. password inputs) from leaking to unrelated partial endpoints.
  • Scroll-mode centering: Centered/right-aligned lines in MONOSPACE_SCROLL mode now use exact viewport width (fillMaxWidth + TextAlign) so text actually centers instead of left-aligning with widthIn(min=).
  • Test update: MicronParserTest.backtick before link with formatting now uses a real-world NomadNet node index line with trailing text after a styled link.

Test plan

  • Browse a NomadNet page with partials that declare specific fields — verify only those fields are forwarded
  • Browse a page with centered text in scroll mode — verify it actually centers
  • Run :micron:testDebugUnitTest — updated parser test passes

🤖 Generated with Claude Code

PartialManager now only forwards form fields declared by each partial's
field list, matching NomadNet TUI's __get_partial_request_data behavior.
"*" forwards all fields; an empty list forwards none. This prevents
undeclared fields (e.g. password inputs) from leaking to unrelated
partial endpoints.

MicronComposables scroll-mode centering fix: centered/right-aligned
lines now use exact viewport width (fillMaxWidth + TextAlign) instead of
min-width, so text actually centers rather than left-aligning.

Updated MicronParserTest to use a real-world NomadNet node index line
with trailing text after a styled link.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Comment thread app/src/main/java/com/lxmf/messenger/nomadnet/PartialManager.kt
@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps bot commented Mar 13, 2026

Greptile Summary

This PR primarily adds partial form-field filtering to PartialManager (matching NomadNet TUI's __get_partial_request_data() semantics) and improves link-establishment reliability with a 3-attempt retry loop in rns_api.py. The parser test is updated to reflect a real-world NomadNet node index line.

Key changes:

  • PartialManager.buildFormDataJson now filters form fields to only those declared in each partial's fieldNames list ("*" = all, [] = none, explicit list = filtered). fieldNames is correctly threaded through all PartialState transitions (LOADING, LOADED, ERROR, refresh).
  • rns_api.py Phase 4 now retries link establishment up to 3 times instead of failing on the first dropped packet. The late-binding closure bug (stale callback from a prior loop iteration setting the new iteration's Event) is correctly fixed using default-argument capture.
  • MicronParserTest backtick before link with formatting test now exercises a more realistic input with a space-containing label, a : prefixed destination, and trailing text after the link.

Important discrepancy — PR title is stale: The PR title and description claim to "fix centered text in scroll mode," but this change was introduced in commit 4bb570d3 and then explicitly reverted in commit e502ab11 because it caused ASCII-art lines to word-wrap instead of scroll horizontally. The final net effect on MicronComposables.kt relative to the base branch is zero — centered/right-aligned text in MONOSPACE_SCROLL mode is still left-aligned. The PR title and summary bullet should be updated to remove the centering claim, and the known limitation could be documented in a follow-up issue.

Confidence Score: 4/5

  • Safe to merge for the field-filtering and retry logic; PR title/description should be updated to remove the reverted centering claim before merging.
  • The code changes themselves are well-implemented and logically correct. The field-filtering logic matches the NomadNet TUI reference, fieldNames is consistently propagated through all state transitions, and the closure-capture fix in the retry loop is sound. The only functional concern is a misleading log message. The main non-code issue is that the PR title/description advertises a centering fix that was reverted within the same PR, which could confuse reviewers and changelog readers.
  • python/rns_api.py — verify the per-attempt timeout arithmetic (per_attempt_base) is consistent with actual RNS link establishment timing expectations in production.

Important Files Changed

Filename Overview
app/src/main/java/com/lxmf/messenger/nomadnet/PartialManager.kt Adds fieldNames propagation through PartialState and filters form data to only include fields declared by each partial (matching NomadNet TUI behavior). Logic is correct: "*" = all fields, empty list = none, explicit list = filtered subset. All call-sites updated consistently.
python/rns_api.py Refactors link establishment into a retry loop (up to 3 attempts). Closure capture is correctly fixed via default-argument binding. Minor issue: the "all attempts exhausted" warning log always reports MAX_LINK_ATTEMPTS regardless of how many attempts actually ran before a deadline-break, which can mislead debugging.
micron/src/test/java/com/lxmf/messenger/micron/MicronParserTest.kt Test updated to use a real-world NomadNet node index line including a space-containing link label (by CupsofJade), a : prefixed destination, and trailing text after the link. All assertions are correct and the test covers the intended parser behavior.

Sequence Diagram

sequenceDiagram
    participant Caller as request_nomadnet_page
    participant EL as _establish_link
    participant RNS as RNS.Link
    participant CB as on_link_established/closed

    Caller->>EL: _establish_link(dest_hash, deadline)
    note over EL: Phase 1–3: path → identity → destination

    loop attempt 1..MAX_LINK_ATTEMPTS (3)
        EL->>EL: check remaining > 5s
        alt remaining < 5s
            EL-->>Caller: error "Connection timed out"
        end
        EL->>RNS: RNS.Link(node_dest, established_cb, closed_cb)
        note over EL,CB: Callbacks bound via default-arg capture<br/>to avoid late-binding closure bug
        RNS-->>CB: on_link_established(link) OR on_link_closed(link)
        CB->>EL: link_established.set()
        EL->>EL: wait(timeout=min(per_attempt_base, remaining-5), min 5s)
        alt link.status == ACTIVE
            EL-->>Caller: return active link ✓
        else teardown_reason == 0x03 (DESTINATION_CLOSED)
            EL-->>Caller: error "Connection closed by node" (no retry)
        else timeout / other failure
            EL->>RNS: link.teardown()
            note over EL: record last_reason, last_status → retry
        end
    end

    EL-->>Caller: error "Connection timed out (N hops)"
Loading

Comments Outside Diff (1)

  1. python/rns_api.py, line 312-315 (link)

    Attempt count in warning log is always MAX_LINK_ATTEMPTS

    The warning log always reports "failed after 3 attempts" regardless of how many attempts actually ran. If remaining < 5 fires on the first iteration (deadline already near-exhausted coming into Phase 4), the break exits after zero real link attempts, but the log still reads "failed after 3 attempts (last_status=None, last_reason=None)" — which is misleading during debugging.

    Tracking the actual attempt number (e.g. attempts_made) and using that in the log would make post-mortem analysis more accurate:

            attempts_made = 0
            for attempt in range(1, MAX_LINK_ATTEMPTS + 1):
                ...
                remaining = deadline - time.time()
                if remaining < 5:
                    break
    
                attempts_made += 1
                ...
    
            # All attempts exhausted
            log_warning("RnsApi", "request_nomadnet_page",
                       f"Link to {dest_hash_hex[:16]} failed after {attempts_made} attempt(s) "
                       f"(last_status={last_status}, last_reason={last_reason})")
Prompt To Fix All With AI
This is a comment left during a code review.
Path: python/rns_api.py
Line: 312-315

Comment:
**Attempt count in warning log is always `MAX_LINK_ATTEMPTS`**

The warning log always reports "failed after 3 attempts" regardless of how many attempts actually ran. If `remaining < 5` fires on the first iteration (deadline already near-exhausted coming into Phase 4), the `break` exits after zero real link attempts, but the log still reads "failed after 3 attempts (last_status=None, last_reason=None)" — which is misleading during debugging.

Tracking the actual attempt number (e.g. `attempts_made`) and using that in the log would make post-mortem analysis more accurate:

```python
        attempts_made = 0
        for attempt in range(1, MAX_LINK_ATTEMPTS + 1):
            ...
            remaining = deadline - time.time()
            if remaining < 5:
                break

            attempts_made += 1
            ...

        # All attempts exhausted
        log_warning("RnsApi", "request_nomadnet_page",
                   f"Link to {dest_hash_hex[:16]} failed after {attempts_made} attempt(s) "
                   f"(last_status={last_status}, last_reason={last_reason})")
```

How can I resolve this? If you propose a fix, please make it concise.

Last reviewed commit: 5e621c6

torlando-tech and others added 2 commits March 13, 2026 18:32
Link establishment now retries up to 3 times when the single RNS link
request packet is lost (same single-shot-no-retry issue as request_path).
Each attempt waits up to the per-hop timeout before tearing down and
retrying. Destination-closed (0x03) is treated as permanent and not
retried.

Reverts the scroll-mode centering change from the previous commit — it
caused long lines (ASCII art) to word-wrap instead of scrolling
horizontally.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Address Greptile review findings:

- PartialManager: preserve fieldNames in onSuccess and onFailure
  PartialState constructors so reloads retain field filtering.
  Refactor buildFormDataJson to use when-expression, reducing return
  count from 4 to 3 (fixes detekt ReturnCount).

- rns_api.py: capture link_established and link_closed_reason via
  default args in retry loop closures to prevent late-firing callbacks
  from a prior iteration corrupting the next iteration's state.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@sentry
Copy link
Copy Markdown
Contributor

sentry bot commented Mar 13, 2026

Codecov Report

❌ Patch coverage is 0% with 41 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
python/rns_api.py 0.00% 41 Missing ⚠️

📢 Thoughts on this report? Let us know!

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.

1 participant