From b34c46093bacfbadc43e87e7922b195ed621ab52 Mon Sep 17 00:00:00 2001 From: Tim Taplin Date: Fri, 30 Oct 2026 08:06:43 -0500 Subject: [PATCH] Docs: remove local paths and working-setup notes from the rewrite plan The plan stays as design history (source comments cite its sections), but it named local directories and review tooling. Those now point at the public Lariat repo or are dropped. The README's Perfect-Lasso link now goes to Lariat, its current name. Co-Authored-By: Claude Opus 5.5 --- Documentation/swift6-nio-rewrite-plan.md | 26 ++++++++++++------------ README.md | 2 +- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/Documentation/swift6-nio-rewrite-plan.md b/Documentation/swift6-nio-rewrite-plan.md index 46354ad..0d3a7eb 100644 --- a/Documentation/swift6-nio-rewrite-plan.md +++ b/Documentation/swift6-nio-rewrite-plan.md @@ -1,7 +1,7 @@ # Perfect-SMTP Swift 6.2 / SwiftNIO Rewrite — Plan Date: 2026-07-18 -Status: **Implemented; shipped in 6.0.0. Kept as design history.** Source comments cite this plan's sections ("plan §4.3") for the reasoning behind a choice, so it stays here unedited. Several review passes changed the final API after it was written: for how the shipped code actually behaves, read [the user guide](user-guide.md) and the README, not this plan. Original status, as written: *Planned, reviewed, not yet implemented.* This document is the actionable output of a design → architecture → parallel expert review cycle (application architect, Swift-concurrency expert, SMTP-protocol/adversarial reviewer). No code has been written yet. All work described here happens on feature branches, never directly on `master`. +Status: **Implemented; shipped in 6.0.0. Kept as design history.** Source comments cite this plan's sections ("plan §4.3") for the reasoning behind a choice, so it stays here. Its only edits since are to remove local file paths and other notes about the working setup. Several review passes changed the final API after it was written: for how the shipped code actually behaves, read [the user guide](user-guide.md) and the README, not this plan. Original status, as written: *Planned, reviewed, not yet implemented.* This document is the actionable output of a design → architecture → parallel expert review cycle (application architect, Swift-concurrency expert, SMTP-protocol/adversarial reviewer). No code has been written yet. All work described here happens on feature branches, never directly on `master`. ## 1. Why this library needs a full rewrite, not a modernization pass @@ -12,19 +12,19 @@ Two real correctness bugs were found by direct inspection of the current code an 1. **Bcc header leak** (`makeBody()`, line ~313): Bcc addresses are correctly placed in the SMTP envelope (`RCPT TO`) but a `Bcc:` **header** is also written into the message body sent to every recipient — defeating the entire purpose of Bcc. 2. **Fake quoted-printable subject encoding** (`makeBody()`, line ~331): a fallback path emits `Subject: =?utf-8?Q??=` — labeled quoted-printable but never actually QP-encoded. Corrupts any subject containing non-ASCII or special characters that hits this branch. -Given the scope of what's missing (§7) and the two structural bugs, patching the existing file is not viable — this is a ground-up rewrite using this ecosystem's established resurrection conventions. +Given the scope of what's missing (§7) and the two structural bugs, patching the existing file is not viable — this is a ground-up rewrite using the conventions of the other modernized Perfect packages. ## 2. Dependency audit — no other Perfect library needs updating -The current `Package.swift` depends on three GitHub packages. Checked against the local resurrection set at `/Users/timtaplin/Perfect-Resurrection/`: +The current `Package.swift` depends on three GitHub packages. Checked against the other Perfect packages: -| Dependency | Local resurrection status | Disposition | +| Dependency | Status among the Perfect packages | Disposition | |---|---|---| -| `Perfect-CURL` | Present, already resurrected | **Dropped.** Per this ecosystem's own established direction (Perfect-FileMaker already migrated off it — task history: "drop PerfectCURL, convert to async/await URLSession"), and because libcurl's SMTP path is internally synchronous, wrapping it can't deliver the "fully concurrent" requirement without repeating the exact blocking-bridge pattern (`AsyncBridge`) this project's own Perfect-Lasso history already identified as a real bug source. | -| `Perfect-Crypto` | **Absent from the local set** | **Not resurrected.** Used only for base64 encoding — trivially replaced by `Foundation.Data.base64EncodedString()` and, for DKIM, `apple/swift-crypto` (the same official package Perfect-Notifications already depends on for its APNs JWT signing). | -| `Perfect-MIME` | **Absent from the local set** | **Not resurrected.** Used only for a MIME-type-by-file-extension lookup table — replaced by a small hand-rolled table in `PerfectSMTPCore`. | +| `Perfect-CURL` | Archived (replaced by `URLSession`) | **Dropped.** Per this ecosystem's own established direction (Perfect-FileMaker already migrated off it and uses async/await `URLSession`), and because libcurl's SMTP path is internally synchronous, wrapping it can't deliver the "fully concurrent" requirement without repeating the exact blocking-bridge pattern (`AsyncBridge`) this project's own Perfect-Lasso history already identified as a real bug source. | +| `Perfect-Crypto` | **Not modernized** | **Not resurrected.** Used only for base64 encoding — trivially replaced by `Foundation.Data.base64EncodedString()` and, for DKIM, `apple/swift-crypto` (the same official package Perfect-Notifications already depends on for its APNs JWT signing). | +| `Perfect-MIME` | **Not modernized** | **Not resurrected.** Used only for a MIME-type-by-file-extension lookup table — replaced by a small hand-rolled table in `PerfectSMTPCore`. | -**Conclusion: no other Perfect-Resurrection library requires new work as a consequence of this rewrite.** The two genuinely-missing upstream dependencies (Perfect-Crypto, Perfect-MIME) are deliberately *not* resurrected — every other library in this ecosystem was either modernized in place as a first-party fork, or had a legacy dependency dropped in favor of an *official* Apple/SSWG package (never a competing third party's implementation of the same thing), and Perfect-SMTP follows that same pattern rather than growing the resurrection set to cover two libraries whose entire purpose here is satisfied by `Foundation` + `swift-crypto`. +**Conclusion: no other Perfect package requires new work as a consequence of this rewrite.** The two genuinely-missing upstream dependencies (Perfect-Crypto, Perfect-MIME) are deliberately *not* resurrected — every other library in this ecosystem was either modernized in place as a first-party fork, or had a legacy dependency dropped in favor of an *official* Apple/SSWG package (never a competing third party's implementation of the same thing), and Perfect-SMTP follows that same pattern rather than modernizing two libraries whose entire purpose here is satisfied by `Foundation` + `swift-crypto`. New dependencies are `swift-nio`, `swift-nio-ssl`, `swift-crypto` — all official, and all already used elsewhere in this exact ecosystem (Perfect-NIO for the first two, Perfect-Notifications for the third). @@ -59,7 +59,7 @@ PerfectSMTP // + swift-nio, swift-nio-ssl, swift-log. // @_exported import PerfectSMTPCore ``` -**Perfect-SMTP has zero knowledge of Lasso — no third target, no Lasso-shaped types, no dash-param anywhere in this package.** This corrects the original draft of this plan, which had sketched a `PerfectSMTPLasso` target living inside this repo. That's inconsistent with how every other consumed-by-Lasso library in this ecosystem is actually structured: `PerfectFileMakerLassoExecutor` and `PerfectCRUDLassoExecutor` don't live in Perfect-FileMaker or Perfect-CRUD — they live entirely inside `/Users/timtaplin/Perfect-Lasso/Sources/LassoPerfectFileMaker/` and `.../LassoPerfectCRUD/`, as targets in the *Perfect-Lasso* repo that take a plain dependency on the resurrected library. Perfect-FileMaker itself has zero Lasso imports (confirmed by inspection — one doc-comment mentions a consumer's tool name for context, nothing more). Perfect-SMTP follows the identical pattern: it is a general-purpose, domain-agnostic SMTP library with a plain Swift-native API; a Lasso-compatibility adapter, if and when one is wanted, is a **separate, future task that belongs entirely in the Perfect-Lasso repository** (analogous to `LassoPerfectFileMaker`), consuming this library's public API exactly as any other Swift caller would. §6 below is kept as reference research for that future task, but is explicitly not part of this package or this plan's deliverable — see the note at the top of §6. +**Perfect-SMTP has zero knowledge of Lasso — no third target, no Lasso-shaped types, no dash-param anywhere in this package.** This corrects the original draft of this plan, which had sketched a `PerfectSMTPLasso` target living inside this repo. That's inconsistent with how every other consumed-by-Lasso library in this ecosystem is actually structured: `PerfectFileMakerLassoExecutor` and `PerfectCRUDLassoExecutor` don't live in Perfect-FileMaker or Perfect-CRUD — they live entirely [Lariat](https://github.com/taplin/Lariat)'s `Sources/LassoPerfectFileMaker/` and `Sources/LassoPerfectCRUD/`, as targets in the Lasso adapter's own repository that take a plain dependency on the resurrected library. Perfect-FileMaker itself has zero Lasso imports (confirmed by inspection — one doc-comment mentions a consumer's tool name for context, nothing more). Perfect-SMTP follows the identical pattern: it is a general-purpose, domain-agnostic SMTP library with a plain Swift-native API; a Lasso-compatibility adapter, if and when one is wanted, is a **separate, future task that belongs entirely in the Perfect-Lasso repository** (analogous to `LassoPerfectFileMaker`), consuming this library's public API exactly as any other Swift caller would. §6 below is kept as reference research for that future task, but is explicitly not part of this package or this plan's deliverable — see the note at the top of §6. The `PerfectSMTPCore` / no-NIO-import boundary is a deliberate compile-time enforcement of "MIME composition and DKIM signing are transport-agnostic and must not be able to reach into a live channel or re-encode after signing" — a build error, not a code-review hope. @@ -394,7 +394,7 @@ The actual, complete public surface of this package is: single-shot `send` (§4. ## 6. Lasso 8.5 / Lasso 9 compatibility surface (reference only — NOT part of this package) -**This entire section documents research for a future, separate task that belongs in the Perfect-Lasso repository, not in Perfect-SMTP.** Nothing described here is part of this plan's deliverable, is present in `Package.swift`, or is implemented by any phase in §9 — Perfect-SMTP has no Lasso-shaped types, no dash-param API, and no knowledge that Lasso exists (§4.1). It's kept here because the research (verified against the actual local PDF and lassoguide.com, not assumed) is valuable groundwork for whoever eventually builds a `LassoPerfectSMTP`-style adapter in `/Users/timtaplin/Perfect-Lasso/Sources/`, structured the same way `LassoPerfectFileMaker`/`LassoPerfectCRUD` already are there — consuming this package's plain public API (§4.9) from the outside, exactly as any other Swift caller would. +**This entire section documents research for a future, separate task that belongs in the Perfect-Lasso repository, not in Perfect-SMTP.** Nothing described here is part of this plan's deliverable, is present in `Package.swift`, or is implemented by any phase in §9 — Perfect-SMTP has no Lasso-shaped types, no dash-param API, and no knowledge that Lasso exists (§4.1). It's kept here because the research (verified against the actual local PDF and lassoguide.com, not assumed) is valuable groundwork for whoever eventually builds a `LassoPerfectSMTP`-style adapter in [Lariat](https://github.com/taplin/Lariat), structured the same way `LassoPerfectFileMaker`/`LassoPerfectCRUD` already are there — consuming this package's plain public API (§4.9) from the outside, exactly as any other Swift caller would. Both Lasso versions ship a built-in, first-class, near-identically-named email API — **`[Email_Send]`** (Lasso 8.5, *Lasso 8.5 Language Guide.pdf*, Chapter 47, pp. 587-600) and **`email_send`** (Lasso 9, lassoguide.com — same name, now a method). This is not ambiguous or an external-binding case; both are fully documented, first-class built-ins. Lasso 9 kept essentially every 8.5 parameter name verbatim (lowercased), which is very favorable for a Lasso-9-primary, 8.5-overlay design. @@ -476,14 +476,14 @@ This plan is the output of a full design → review cycle, not a single pass: 1. **Research** — modern SMTP/RFC/deliverability requirements (RFC-cited, web-verified against 2025-2026 provider policy changes) and Lasso 8.5/9 email-tag semantics (verified against the actual local PDF and lassoguide.com, not assumed), run in parallel. 2. **Transport-options review** — adopt-vs-build-vs-wrap-vs-shell-out, with live verification of third-party library candidates (platform support, feature completeness) rather than assumption. Result: hand-roll on NIO behind a pluggable `Transport` abstraction (§3). 3. **Application-architect design pass** — produced the full architecture in §4, grounded in this ecosystem's actual established conventions (read from Perfect-NIO, Perfect-Notifications, Perfect-FileMaker directly, not inferred). -4. **Swift-concurrency-expert review** (using this project's `swift-concurrency-pro` skill) — found one critical data race (the promise-correlation queue as originally specified) and several required-but-unspecified behaviors (cancellation handling, shutdown draining, reentrancy discipline, bounded batch fan-out). All findings are folded into §4 as corrected, authoritative specification, not left as open review comments. +4. **Swift-concurrency-expert review** — found one critical data race (the promise-correlation queue as originally specified) and several required-but-unspecified behaviors (cancellation handling, shutdown draining, reentrancy discipline, bounded batch fan-out). All findings are folded into §4 as corrected, authoritative specification, not left as open review comments. 5. **SMTP-protocol/adversarial review** — confirmed the DKIM ordering and STARTTLS capability-reset logic as sound, and found several protocol-correctness gaps (quote-unaware address splitting, missing null-return-path handling, an incomplete STARTTLS timing guarantee, under-specified RFC 2047 folding, the 421-vs-greylist conflation, missing EHLO-hostname/timeout/Message-ID requirements, incomplete DKIM oversigning semantics, and untested PIPELINING partial-failure behavior). All findings are likewise folded into §4/§7/§9 as corrected specification. Every finding from both review passes is either (a) resolved in the corrected design text above, or (b) explicitly carried forward as a named open decision in §9's phasing (DANE/DNSSEC scope -- **resolved at the start of Phase 4: DANE deferred entirely, MTA-STS only, see §9's Phase 4 bullet for the full rationale** -- CRAM-MD5/SCRAM deprioritization pending a swift-crypto PBKDF2 check, the `_RSA.Signing.PrivateKey` Sendable-conformance check). Nothing was silently dropped. ## 11. Process notes -- All implementation work happens on feature branches (this plan document itself was written on `swift6-nio-rewrite-plan`, branched from `master`); no phase merges to `master` without its own build+test+review pass, matching this project's established discipline elsewhere in the Perfect-Resurrection ecosystem. -- No other Perfect-Resurrection library needs any change as a prerequisite for this work (§2). +- All implementation work happens on feature branches (this plan document itself was written on `swift6-nio-rewrite-plan`, branched from `master`); no phase merges to `master` without its own build+test+review pass, as with the other modernized Perfect packages. +- No other Perfect package needs any change as a prerequisite for this work (§2). - **Perfect-SMTP itself never depends on, imports, or references Perfect-Lasso, and has no target shaped around Lasso's parameter surface** (§4.1). When Perfect-Lasso wants email-sending support, that work happens entirely on the Perfect-Lasso side: a new target there (analogous to `LassoPerfectFileMaker`/`LassoPerfectCRUD`, e.g. `LassoPerfectSMTP`) takes a plain dependency on this package's public `PerfectSMTP` product and maps Lasso's `email_send` dash-params onto it, using §6 as reference research. That task is out of scope for this plan and is not tracked as one of its phases. - **On the future/promise question raised during review:** the public API is `async`/`await` throughout with no `EventLoopFuture` crossing any package boundary. Internally, `EventLoopPromise` is used only within the small, explicit Phase-A bootstrap handler (§4.3) for the connect/EHLO/STARTTLS sequence, where NIO's event-loop-driven pipeline genuinely requires it — one promise at a time, never a queue. The bulk conversation (Phase B, everything after the channel is TLS-ready) is driven by `NIOAsyncChannel`'s native `AsyncSequence`/`AsyncIterator` API, matching Perfect-NIO's own established pattern (`WebSocketHandler.swift`, `NIOAsyncHTTPHandler.swift`) rather than introducing a second, competing concurrency style. No Combine anywhere — ruled out categorically by this ecosystem's Linux-compatibility requirement, and unnecessary given structured concurrency (`TaskGroup`, actors, `AsyncSequence`) covers every queue/stream need this design has. diff --git a/README.md b/README.md index 72c40b7..e7f8b1c 100644 --- a/README.md +++ b/README.md @@ -29,7 +29,7 @@ operate mail, or let Perfect-SMTP be the terminal MTA itself. This package is domain-agnostic by design — it has no Lasso-specific code and no Lasso dependency. It is, however, a **core dependency** of -[Perfect-Lasso](https://github.com/taplin/Perfect-Lasso) — a Swift +[Lariat](https://github.com/taplin/Lariat) (formerly Perfect-Lasso) — a Swift reimplementation of the Lasso language, still in active development — which uses it to implement its `email_send` tag.