Fix support preview and retry races

Issue: #418
User-Visible: yes
This commit is contained in:
Sergey Matyunin
2026-09-02 17:10:05 +03:00
parent e3073f6840
commit 2b978d63ef
25 changed files with 453 additions and 214 deletions
+43
View File
@@ -8,6 +8,8 @@ import {
supportDraftError,
supportErrorCode,
supportRuntimeFacts,
supportSubmissionFingerprint,
supportSubmissionIdentity,
} from '../test-build/support-feedback.js';
test('a fresh dialog never opts into exact plan geometry', () => {
@@ -39,6 +41,47 @@ test('attachment submit requires the exact non-expired preview', () => {
assert.equal(supportDraftError({ ...base, preview }, now + 1), 'preview_expired');
});
test('submission identity follows the effective trimmed payload', () => {
const initial = {
...newSupportDialogState(),
message: ' first message ',
contact: ' user@example.test ',
};
const first = supportSubmissionIdentity(initial);
assert.equal(first.idempotencyKey, initial.idempotencyKey);
assert.equal(
first.fingerprint,
supportSubmissionFingerprint({ ...initial, message: 'first message', contact: 'user@example.test' }),
);
const attempted = { ...initial, submissionFingerprint: first.fingerprint };
assert.equal(
supportSubmissionIdentity({ ...attempted, message: 'first message ' }).idempotencyKey,
initial.idempotencyKey,
);
assert.notEqual(
supportSubmissionIdentity({ ...attempted, message: 'different message' }).idempotencyKey,
initial.idempotencyKey,
);
assert.notEqual(
supportSubmissionIdentity({ ...attempted, contact: 'other@example.test' }).idempotencyKey,
initial.idempotencyKey,
);
const preview = {
token: 'a'.repeat(48), expiresAt: Date.now() + 1_000, size: 2, sha256: 'b'.repeat(64),
spaces: 1, format: 'houseplan-support-package', version: 1, text: '{}\n', preparedAt: Date.now(),
};
assert.notEqual(
supportSubmissionIdentity({ ...attempted, attach: true, preview }).idempotencyKey,
initial.idempotencyKey,
);
assert.equal(
supportSubmissionFingerprint({ ...attempted, attach: false, preview }),
first.fingerprint,
);
});
test('runtime facts are bounded enums without a raw user agent', () => {
const facts = supportRuntimeFacts({
userAgent: 'Mozilla/5.0 Chrome/140.0.0.0 Safari/537.36 private-suffix',