Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,8 @@ Grab the latest build for your platform from [Releases](https://github.com/fuzzz

## Troubleshooting

For FileMaker clipboard problems, use **Tools > FileMaker Clipboard Diagnostics…** to capture untouched payloads and save a ZIP snapshot for an issue report. Copy a small, non-sensitive example first: snapshots include full clipboard data, including accompanying text. Nothing is uploaded automatically. See [capture instructions and privacy details](docs/filemaker-clipboard-diagnostics.md).

Logs are stored in `${specialfolder:folder=CommonApplicationData}\SharpFM` and rotate after thirty days.

## Similar Tools
Expand Down
69 changes: 69 additions & 0 deletions docs/filemaker-clipboard-diagnostics.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
# FileMaker clipboard diagnostic snapshots

Use **Tools > FileMaker Clipboard Diagnostics…** when copying between FileMaker and SharpFM fails, or when maintainers need a real clipboard payload from your platform. The helper works independently of normal FileMaker decoding: it does not strip a length prefix or modify the clipboard.

## Capture and share

1. In FileMaker, copy a **small, non-sensitive example**: a script, script steps, table, fields, or layout.
2. In SharpFM, open **Tools > FileMaker Clipboard Diagnostics…**.
3. Optionally enter your FileMaker version and describe what you copied. These fields are saved in the snapshot.
4. Choose **Capture FileMaker Clipboard**. Review the discovered formats, retrieval outcomes, and interpretation summaries. Select an entry to see its details.
5. Choose **Save Snapshot…** and select a local ZIP destination. Saving exports the retained capture, not a fresh clipboard read.
6. Attach the ZIP to the issue only if its contents are safe to share. Include the copy/paste direction, what happened, and what you expected.

A partial capture is still useful. Save it even if some formats return null, are unsupported, or fail to read. The ZIP includes successful payloads and failure metadata. A capture with no payloads can still explain a discovery/access failure.

For a two-direction investigation, save separate snapshots immediately after copying in FileMaker and after using SharpFM's normal **Copy to FileMaker** command. Describe which is which. The diagnostic helper does not replay or write custom clipboard payloads itself.

## Privacy

**Snapshots contain full clipboard data, not just diagnostic metadata.** They capture all formats Avalonia exposes from that copy, including accompanying text and unfamiliar identifiers. They may contain proprietary scripts, credentials, personal information, or other sensitive content. The optional description, XML root/type observations, and leading-byte previews may also contain private information.

- Use a newly created, non-sensitive FileMaker example where possible.
- Capturing does not upload anything. Saving writes a local ZIP; attaching it to an issue is your choice.
- Payloads are not written to application logs or persisted automatically.
- The ZIP is not encrypted. Protect it like the original data. On Unix systems, newly exported archives are created with owner-only read/write permissions.
- Inspect `manifest.json` and the files under `payloads/` locally if necessary. Summaries are not a redacted substitute for reviewing the full capture.
- Closing the helper discards its in-memory capture. Delete exported snapshots when no longer needed.

## What is captured

The manifest records:

- Schema version, UTC capture time, SharpFM build version, OS version, process architecture, and Avalonia version.
- Optional FileMaker version and description.
- Every format identifier exposed by the transfer and its exposed representation/kind.
- Per-item/per-format retrieval outcomes, returned runtime types, sizes, sanitized errors, payload references, and SHA-256 checksums.
- Independent interpretation results and explicit capture limitations.

Every successfully retained byte array is exported **exactly as returned by Avalonia**. Supported text values are encoded as strict UTF-8 without a BOM and explicitly labeled as text representations, not original wire bytes. There is no XML formatting, prefix removal, newline normalization, arbitrary object serialization, or dereferencing of clipboard file objects.

One transfer is held open while its items are read, then disposed. This is a best-effort capture through Avalonia, **not a complete native macOS pasteboard/Windows clipboard dump**. Avalonia may expose converted representations or omit native formats. Atomicity and clipboard-change detection are not guaranteed. Unknown object representations are reported by type but not persisted.

The retention budget is 128 MiB per capture. Entries exceeding the remaining budget are marked `ResourceLimit`, with their observed size and no payload file; they are not silently truncated. Smaller subsequent entries can still be retained. The platform API may allocate data before the helper can check its size, so use small examples.

## Interpretation summaries

For retained payloads, the helper reports:

- Up to 32 leading bytes as hex and a BOM observation.
- The first four bytes as an unsigned little-endian length and whether that matches the remaining byte count.
- Strict UTF-8 decoding and XML well-formedness probes starting at offsets **0** and **4**, with BOM observations at each offset.
- XML root name and `fmxmlsnippet` type if parsing succeeds. Long values are abbreviated only in the summary.

These are hypotheses, not a platform-specific decoding decision. XML probes are limited to 2 MiB each; larger probes are explicitly skipped while retained payloads remain complete. DTDs and external XML resolution are disabled. Errors omit exception messages to avoid embedding clipboard contents or local paths.

For issue [#186](https://github.com/fuzzzerd/SharpFM/issues/186), a matching length plus valid XML at offset 4 supports the prefixed-payload hypothesis. Valid XML at offset 0 supports the unprefixed hypothesis. Neither replaces checking the real bytes and testing both copy/paste directions in FileMaker.

## Archive layout (schema version 1)

```text
manifest.json
payloads/0000.bin
payloads/0001.txt
...
```

`manifest.json` uses camel-case property names and string retrieval outcomes. Each entry includes its zero-based `itemIndex`, `format`, `outcome`, and, when retained, `payloadFile`, `payloadRepresentation`, `byteLength`, and `sha256`. Payload filenames are generated independently of format identifiers. Missing or unsupported values have no payload file. `isPartial`, `issues`, `captureBoundary`, and `limits` describe omissions and collection constraints.

No ZIP import or special viewer is required: maintainers can read the JSON and use a `.bin` file directly as a regression fixture. Export writes a temporary archive beside the destination and replaces the destination only after the archive is complete. If saving fails, the in-memory capture remains available for retry.
160 changes: 160 additions & 0 deletions docs/plans/186-filemaker-clipboard-diagnostics.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
# FileMaker clipboard diagnostic snapshots

Status: implemented; real FileMaker platform validation/captures pending
Related issue: [#186](https://github.com/fuzzzerd/SharpFM/issues/186)

## Goal

Let a FileMaker user on Windows, macOS, or Linux capture clipboard evidence and save a snapshot they can attach to an issue. Preserve the original payloads independently of SharpFM's normal decoding assumptions, so maintainers can diagnose format discovery, data retrieval, encoding, framing, and round-trip failures.

This is a FileMaker support tool, not a general-purpose clipboard editor or a collection of hex/text/XML viewers.

## Current limitation

In v2.0.0, **Tools → Raw Clipboard Viewer**:

- Filters identifiers to `Mac-XM*` and reads only the first matching format.
- Uses the normal clipboard service, which requests a byte representation.
- Calls `Clip.FromWireBytes`, which unconditionally skips four bytes.
- Shows decoded XML and a byte count, but cannot export untouched bytes.

The viewer therefore shares the assumption investigated by #186. It cannot provide an independent payload fixture.

Relevant implementation:

- `src/SharpFM/Diagnostics/RawClipboardWindow.axaml.cs`
- `src/SharpFM/Diagnostics/RawClipboardWindow.axaml`
- `src/SharpFM/Services/ClipboardService.cs`
- `src/SharpFM.Model/Clip.cs`

## Scope

Expand the existing helper into **FileMaker Clipboard Diagnostics** with two primary actions:

1. **Capture FileMaker Clipboard** — read the clipboard and retain an in-memory snapshot.
2. **Save Snapshot…** — export that captured snapshot without rereading the clipboard.

Keep the UI to a capture summary, a simple format/result list, interpretation summaries, and export status. No dedicated payload viewers are required.

Do not change normal FileMaker import/export behavior or introduce a platform-specific prefix fix in this work.

## Capture model

Separate capture, interpretation, and export from the window and from `Clip.FromWireBytes`.

### Environment

Record:

- Snapshot schema version and UTC capture time.
- SharpFM version/build, OS version, process architecture, and Avalonia version.
- Optional user-entered FileMaker version and description of what was copied.
- Capture source explicitly identified as Avalonia's clipboard API.

Do not collect usernames, machine names, unrelated filesystem paths, or other unnecessary identifying details.

### Formats and payloads

- Enumerate every format exposed by Avalonia. Do not filter discovery by `Mac-XM*`; different platform identifiers may be part of the failure.
- Attempt to capture the available payloads from that FileMaker copy, preserving every successfully retrieved byte payload in full.
- Where the API exposes a supported non-byte representation, record its representation/type explicitly; preserve text separately without calling it original wire bytes.
- For each entry, record its identifier, requested/exposed representation where available, retrieval outcome, returned runtime type, payload length, and sanitized error details.
- Keep null, unsupported, and failed retrievals visible. One failing format must not discard successful captures.
- Never strip a prefix, pretty-print XML, normalize line endings, or re-encode a byte payload before storing it.
- Prefer one clipboard transfer/read session per capture, retaining it until retrieval completes. Do not use a fresh clipboard read for each format as the existing service does.
- A capture is best-effort, not a guarantee of an atomic native pasteboard dump. Record limitations and any detected clipboard change.

Audit Avalonia's format/retrieval APIs before implementing the collector. The current `GetDataAsync(string)` forces a byte-format request and is insufficient to describe every exposed representation. Keep any new diagnostic access separate from normal paste behavior.

The snapshot preserves what Avalonia returns. Do not claim it includes native formats or bytes that Avalonia cannot expose. Native platform collectors are a possible follow-up only if real captures demonstrate that gap.

## Non-destructive interpretations

Run interpretations against stored payloads, never against the live clipboard. Retain results separately from original bytes; interpretation failures must not prevent export.

For plausible FileMaker byte payloads, summarize:

- Total byte length and a limited leading-byte hex preview.
- First four bytes interpreted as an unsigned little-endian length, when present.
- Whether that value matches the remaining payload length.
- Strict UTF-8 decoding and XML well-formedness results at offsets **0** and **4**.
- XML root name and snippet type, where parsing succeeds.
- Encoding/BOM observations and concise errors where relevant.

Label offset-0 and offset-4 results as hypotheses, not a detected platform rule. Do not route these probes through `Clip.FromWireBytes` or require domain-model parsing.

Bound interpretation work for large payloads, disable XML external resolution/DTDs, and report skipped probes explicitly. Limits on interpretation must not silently truncate exported raw payloads.

## Shareable snapshot format

Export a ZIP containing:

- `manifest.json`: versioned environment, format/retrieval metadata, interpretation results, and payload references.
- `payloads/`: exact captured byte payloads and explicitly identified supported non-byte representations.

Use generated filenames rather than clipboard identifiers as paths. Record byte lengths and SHA-256 checksums for binary payloads. Include a brief description in the manifest of the capture boundary and any incomplete entries.

A successful export means the saved payloads match the in-memory capture. If export fails, show the error, retain the snapshot for retry, and avoid leaving a misleading completed archive.

The archive must be useful without opening it in SharpFM: maintainers should be able to inspect the JSON and use a binary payload directly as a regression fixture. Importing snapshots into the app is not required initially.

## User experience and privacy

- Explain the workflow: copy a small, non-sensitive example in FileMaker, switch to SharpFM, capture, then save and attach the ZIP to an issue.
- Show capture time, all discovered identifiers, retrieval outcomes, sizes, interpretation summaries, and whether capture was partial.
- Disable Save until a snapshot exists. Export the retained snapshot even if the live clipboard has subsequently changed.
- Warn that the archive contains full clipboard contents, including accompanying text formats, and may contain proprietary scripts, credentials, or personal data.
- Never upload automatically or log payload contents. Do not present a hex preview or summary as automatically safe to share.
- Capture, interpretation, and export must not modify the clipboard. Avoid retaining the existing **Copy XML** action in this capture-focused workflow.
- Keep the UI responsive during capture/export. If a resource limit prevents complete capture, report that entry as incomplete rather than silently exporting truncated bytes.

## Validation

Unit-test capture orchestration using a fake clipboard source, with interpretation and export tests independent of Avalonia windows:

- Multiple identifiers, including unfamiliar/non-`Mac-XM` identifiers.
- Null, unsupported, non-byte, and throwing retrievals alongside successful entries.
- One capture session and export without a clipboard reread.
- Prefixed XML, unprefixed XML, mismatched length headers, empty/short payloads, invalid UTF-8, and malformed XML.
- Safe XML parsing and explicitly skipped oversized interpretations.
- Exact binary preservation, checksums, generated safe filenames, schema versioning, and partial capture metadata.
- Export failure/retry and large-payload behavior without silent truncation.

Manually validate against real FileMaker copies on Windows and macOS, recording FileMaker versions. Validate the Linux capture/export path where an appropriate clipboard source is available; do not imply FileMaker runs natively there.

## Delivery order

1. Define the snapshot schema and diagnostic collector boundary.
2. Implement untouched capture, independent interpretations, and archive export with tests.
3. Replace the current viewer UI with the compact capture/save workflow.
4. Document capture instructions and the privacy warning in user-facing documentation.
5. Collect real Mac and Windows snapshots for #186, then use the evidence to plan any wire-format correction and regression fixtures separately.

## Implementation and validation

- Implemented on `fuzzz/186-filemaker-clipboard-diagnostics`, based on latest `origin/master` at `f09da3e`.
- Replaced the existing helper with a compact capture/save workflow; normal clipboard import/export is unchanged.
- Added a version-1 JSON/ZIP snapshot format, per-item/per-format collection through one Avalonia transfer, exact byte preservation, strict UTF-8 text export, independent interpretations, and atomic local-file export.
- Retention is limited to 128 MiB per capture, with explicit omitted-entry outcomes; XML probes are limited to 2 MiB without truncating retained payloads.
- Added [user instructions, archive details, limitations, and privacy guidance](../filemaker-clipboard-diagnostics.md).
- Added 31 automated tests under `tests/SharpFM.Tests/Diagnostics/` covering capture, interpretations, summaries, and export.
- `dotnet build SharpFM.sln --no-restore` passes (existing unrelated warnings remain).
- `dotnet test SharpFM.sln --no-restore --disable-build-servers -m:1` passes: 2,374 tests across both test projects. A default parallel invocation encountered a transient CLR host abort; two subsequent isolated full-suite runs passed.
- `dotnet format whitespace SharpFM.sln --no-restore --verify-no-changes --include src/SharpFM/Diagnostics tests/SharpFM.Tests/Diagnostics` passes.
- Real FileMaker captures and native UI smoke tests on macOS/Windows are still required; no prefix correction has been inferred or implemented.

### Remaining platform validation

1. On Windows and macOS, copy a small non-sensitive FileMaker example, capture it, save the ZIP, and verify the listed formats and exported byte lengths/checksums.
2. Repeat after copying from SharpFM; label the two archives by direction and test actual pasting into FileMaker separately.
3. Confirm partial failures remain exportable and saving does not replace the live clipboard.
4. On Linux, validate native clipboard capture/save with an appropriate source, without implying FileMaker runs natively there.
5. Attach safe real captures to #186 and derive framing changes/regression fixtures from that evidence.

## Deferred

- Dedicated hex, text, or XML viewers.
- Snapshot comparison UI or in-app snapshot import.
- Arbitrary clipboard editing or payload replay.
- Native platform collectors without demonstrated need.
- Any automatic prefix correction or platform-specific import/export change.
Loading
Loading