From 8011d4e34cf86994887a9ccf80ab5eee4a9da3cd Mon Sep 17 00:00:00 2001 From: PointStar Date: Tue, 12 May 2026 22:58:12 +0300 Subject: [PATCH] diag(attachments): post-upload "did the file actually arrive" check MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The server reported successful uploads for the two PDFs into case 6a03166d… ("מונאס אריאל") but the user couldn't find the files on the share. Both LocalFilesystemClient::uploadFile and WebDavClient::uploadFile return true only on a real write, so something downstream is silently dropping the payload — most likely a WebDAV proxy or a basePath mismatch between what NetworkStorageIntegration thinks the storage is vs. what the user is browsing. Add a verification step right after the upload: 1. POST /Attachment → attachmentId 2. POST /NetworkStorage/action/upload → 201 from server 3. GET /NetworkStorage/folderContents?path= • If our filename is in the listing → INF "verify present" • Else → WRN "expected X but NOT in listing. Currently in folder: […]" The diagnostic line surfaces both halves of the puzzle in a single log entry, so the next save attempt will tell us in plain text whether the storage layer is the liar or the path is being normalised somewhere unexpected. Tests: 39 passing. Co-Authored-By: Claude Opus 4.7 (1M context) --- .../Services/AttachmentSaveService.cs | 55 +++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/src/OutlookAddin.Core/Services/AttachmentSaveService.cs b/src/OutlookAddin.Core/Services/AttachmentSaveService.cs index 3c5ccaa..9af7f5a 100644 --- a/src/OutlookAddin.Core/Services/AttachmentSaveService.cs +++ b/src/OutlookAddin.Core/Services/AttachmentSaveService.cs @@ -59,6 +59,12 @@ namespace MarcusLaw.OutlookAddin.Core.Services await _client.UploadAttachmentToNetworkStorageAsync( uploaded.Id, trimmedFolder, cancellationToken).ConfigureAwait(false); + // Step 3: verify the file actually landed on the share — + // the server can return 200 yet leave nothing on disk + // when a downstream WebDAV proxy silently fails. Read + // the folder back and look for our filename. + await VerifyArrivedAsync(att.Name, trimmedFolder, cancellationToken).ConfigureAwait(false); + _logger.Information( "Saved attachment {Name} → {Path} (attachmentId={AttachmentId})", att.Name, trimmedFolder, uploaded.Id); @@ -99,5 +105,54 @@ namespace MarcusLaw.OutlookAddin.Core.Services return summary; } + + /// + /// Post-upload sanity check: list the folder we just wrote into + /// and confirm a file with the same (possibly sanitized) name + /// shows up. Diagnostic only — does not change the outcome. If + /// the file isn't there, log a WARNING with everything that IS + /// in the folder so we can spot the actual server-side path. + /// + private async Task VerifyArrivedAsync(string expectedName, string folderPath, CancellationToken ct) + { + try + { + var items = await _client.ListNetworkStorageFolderAsync(folderPath, ct).ConfigureAwait(false); + var trimmedExpected = expectedName.Trim().TrimStart('-', ' ').TrimEnd('-', ' '); + bool found = false; + foreach (var it in items) + { + if (it.IsFolder) continue; + if (string.Equals(it.Name, expectedName, StringComparison.Ordinal) || + string.Equals(it.Name, trimmedExpected, StringComparison.Ordinal)) + { + found = true; + break; + } + } + if (!found) + { + var names = new List(); + foreach (var it in items) + { + if (it.IsFolder) continue; + names.Add(it.Name); + } + _logger.Warning( + "Post-upload verify: expected '{Expected}' under '{Path}' but it's NOT in the listing. " + + "Server reported the upload as successful but the file is not on the share. " + + "Files currently in that folder: [{Files}]", + expectedName, folderPath, string.Join(", ", names)); + } + else + { + _logger.Information("Post-upload verify: '{Expected}' present under '{Path}'", expectedName, folderPath); + } + } + catch (Exception ex) + { + _logger.Warning(ex, "Post-upload verify failed for '{Expected}' under '{Path}'", expectedName, folderPath); + } + } } }