Repository navigation
Closed
Labels
bugSomething isn't workingSomething isn't workingdomain:servicesRetired 2026-10-22, alias of domain:server (services surface); in-flight cards keep it until landedRetired 2026-10-22, alias of domain:server (services surface); in-flight cards keep it until landedpriority:p2Medium: important, M3Medium: important, M3
Description
Filing gate ③: this is an out-of-scope finding, class (a), from the os-dev report on #25335 (PR #25448). The domain:services seat 1 files it (seat post #6021, os-sales, session_016g7nYP9wdNx1GDa5XDr7Uy) and re-read the code on origin/main d0a1361bda. ⛔ Not a claim.
- Who acts:
domain:services. - Dedupe: none found. The open
domain:servicescards were read through the repo-scopedissuesendpoint, with the wordsmail provider log still delivers,None log only no real deliveryandtransport unchanged never delivered. Setup → Email shows provider SMTP with an empty host while mail goes to the development log sink and "Invitation sent" toasts appear — say on the page which transport is live (hotcrm#2194 T2-U12) #25335 (the transport statement) and plugin-email: the Send test email refusals tell the admin to pass "to" in the request body — name the page's control instead (same family as #25345) #25424 (the Send test copy) are different strings.
What happens on main (d0a1361bda)
- Setup → Email offers the provider
logwith the label "None (log only — no real delivery)":service-settings/src/manifests/mail.manifest.ts:34, andtranslations/en.ts:42. applyMailSettingsinplugin-email/src/email-plugin.tsnear:1348handles a savedprovider === 'log'by returning without swapping the transport. It logs "transport unchanged — messages are logged and recorded in sys_email, never delivered."- So after a boot with SMTP (from settings, or from
OS_EMAIL_SMTP_*), savinglogleavesSmtpTransportin place.isConfigured()staystrue, and mail keeps being delivered over SMTP.- The page label says there is no real delivery.
- The info log says mail is never delivered.
- With the env-built boot transport, this holds across a restart too.
- Reach: the save door of Setup → Email (the system administrator). The PR feat(settings,plugin-email): state the live mail transport on Setup → Email #25448 dev measured it with a throwaway probe that was not committed: boot with
smtp+smtp_host, saveprovider=log, and the transport is still SMTP. - An admin who picks "None" to stop mail (a staging copy of production, an incident) gets no stop.
Wanted
- Measure first whether "transport unchanged" was meant to protect an env-configured transport.
- Then make the answer one thing. Either:
- (A) saving
loginstallsLogTransport, so mail stops as the label says; or - (B) the label and the log line say what happens, and the page names the live transport. Setup → Email shows provider SMTP with an empty host while mail goes to the development log sink and "Invitation sent" toasts appear — say on the page which transport is live (hotcrm#2194 T2-U12) #25335's live-status banner already states it.
- (A) saving
- Recommendation is not made here. It is the card's measurement. If the env transport must win, (B) is the honest shape.
Acceptance
- Pinned: after a boot with SMTP, saving
loggives an answer, a page statement and a log line that agree with what the transport then does. A CONTROL covers a boot with no SMTP. Clause-②/Metadata-protocoldeclared per AGENTS.md.
Size: S–M.
Generated by Claude Code
Metadata
Metadata
Assignees
Labels
bugSomething isn't workingSomething isn't workingdomain:servicesRetired 2026-10-22, alias of domain:server (services surface); in-flight cards keep it until landedRetired 2026-10-22, alias of domain:server (services surface); in-flight cards keep it until landedpriority:p2Medium: important, M3Medium: important, M3
Activity
objectstack-fleet commentedon Oct 23, 2026
Claim: PM loop round 1 ·
domain:servicesseat 1 (seat post #6021, project run by the Sales account) · S mechanical card, in-seat subagent · 2026-10-23T15:23ZSession:
session_016g7nYP9wdNx1GDa5XDr7UyAccount:
os-sales(the seat's linked user asGET /useranswers it; the card's assignee)Branch:
claude/issue-25450-mail-log-providerWorktree:
objectstack-issue-25450Domain:
domain:serverSeat:
domain:services#1File surface:
packages/plugins/plugin-email/src/email-plugin.ts(applyMailSettings, the savedprovider === 'log'branch) and its tests. Shape B also touchesplugin-email/src/live-transport-status.tsorservice-settings/src/manifests/mail.manifest.tswith its four translation bundles. Plus a changeset. ⛔packages/specis not edited. Stop on breach; explain in the report.Container & model:
S 级机械卡,mode:subagent(general-purpose subagent loading.claude/agents/os-dev.mdas its role file),model: default tier,effort: mediumClause-②: no
Metadata-protocol: none
Responsibility:
plugin-email's own settings re-apply keeps the previous transport whenlogis saved | the page label and the info log both say no mail is delivered | the system administrator who picks "None" to stop mail, todayThread-read: none
Serial constraints cleared: #25424 (PR #25453, merged 2026-10-23T15:20:06Z) and #25335's server half (PR #25448, merged 2026-10-23T15:09:13Z) were the two open PRs on
email-plugin.ts. Both are onmainnow.Resume-from: none
objectstack-fleet commentedon Oct 23, 2026
os-dev-report
{
"issue": 25450,
"status": "done",
"branch": "claude/issue-25450-mail-log-provider",
"pr": "#25497",
"session": "session_016g7nYP9wdNx1GDa5XDr7Uy",
"premise_still_valid": true,
"summary": "Shape A. The measurement found nothing deliberate protecting the old transport. The 'transport unchanged' line comes from fc9b204, where smtp and log shared one no-op branch because no SMTP transport shipped in core. 41c3b48 gave smtp a real swap and left log as a no-op, with a docstring that assumes the live transport is already the LogTransport. A saved SMTP host or Resend/Postmark key already replaces a boot-built (OS_EMAIL_SMTP_* / providerOptions) or host-supplied transport. The manifest contract says the runtime honours log. So applyMailSettings now installs a LogTransport on a saved log when anything else is live, and the info line names the transport it replaced (or says the LogTransport stays live). The live-status banner, the log line, Send test (ok:false warning) and the transport now agree. Landing: email-plugin.ts, as claimed. The queue-delivery fixture, which stored provider log with a host transport and relied on the removed no-op, now uses the out-of-the-box namespace (smtp default, no host). Base: origin/main 0b8dbea. Head: fa56181.",
"tests": "Head fa56181.
pnpm --filter @objectstack/plugin-email test: Test Files 38 passed (38), Tests 685 passed (685), lock VERDICT command-exit 0.pnpm --filter @objectstack/plugin-email typecheck: tsc --noEmit plus 'check:test-typecheck: OK', exit 0. New pin src/mail-log-provider.pin.test.ts has 5 tests: SMTP saved on the page, SMTP from boot options, host-supplied transport, restart with log stored, and a CONTROL with no-SMTP boot. Each asserts the transport/isConfigured, the registerLiveStatus statement, the log line and the Send test answer, with sendMail never called. ABLATION at fa56181 through scripts/ablation-replace.mjs: the anchor 'this.service.setTransport(new LogTransport(ctx.logger));' was replaced by a no-op. The tool printed 'ok mutation landed: anchor 1 -> 0, blob 6e5d43794b5a -> 0a9522b85240', and the run went RED with 'Tests 4 failed | 1 passed (5)': all 4 SMTP/host legs failed and the CONTROL held. Restore: 'ok restored: blob == HEAD (6e5d43794b5a) andgit diff HEADis empty', and git status was clean. The test imports src (./email-plugin.js), so no dist leg is needed. The same ablation was also red at 9a27ece before the pin's engine double was trimmed.","gates": "
node scripts/pm/dispatch-gates.mjs --commandsat fa56181 derived 67 commands (merge base 0b8dbea, 4 paths, 222 changed lines). All 67 ran locally on the final head and exited 0.--ranwith exit codes recorded: '67 derived famil(ies) accounted for — 67 run, 0 NOT-MEASURED (a DERIVED zero — all 67 recorded an exit code and none of them is 3)', exit 0. First pass at 9a27ece: check:engine-double-contract exited 1 because the new pin's fake engine declared update(). It was fixed by making the fake read-only, rerun gave exit 0, and the whole union was rerun on fa56181. check:dual-build-cjs-loads exited 3 (PREREQUISITE NOT MET: no dist) on the first pass and exit 0 on the final pass. CI check-runs on PR #25497 at fa56181 when the report was written: 'No other open PR may claim the same issue' success; Lint/Type Check/Check Changeset/Governed Surface Queue Guard and the rest in_progress (Test Core and Build Core not yet listed). The required set is NOT MEASURED here; the PM reads its convergence.","dogfood_battery": "n/a — no
!in the PR title and no (narrowing) arm","mcp_calls": "0",
"api_writes": "2 relay writes plus 1 git push. (1) fleet-write pr_create (POST /repos/objectstack-ai/objectstack/pulls, draft, with assignee os-sales via POST /issues/25497/assignees), relay run 39986291225, read back byte-identical. (2) post-stamped os-dev-report comment, POST /repos//issues/25450/comments. git push of the branch (not a REST write).",
"open_questions": [],
"out_of_scope_findings": [
"class: a · reach: Setup → Email 'Send test email' with 'None (log only — no real delivery)' picked on the form but NOT saved, while SMTP is live: the mail/test handler's provider==='log' path tests the live service instead of the form's choice. A throwaway probe at fa56181 (not committed) returned ok:true 'Sent test email to admin@example.test (id=…)', with nodemailer sendMail called once, so a real mail was delivered for a form whose label says no delivery. Landing: packages/plugins/plugin-email/src/email-plugin.ts, the mail/test handler (
else if (provider !== 'log')leaves target = svc). Seam: consumer: none (settings action, not spec). Dedupe words: 'send test log provider unsaved', 'mail/test None delivers', 'test email form provider log live smtp'","carrier: none (承接者:无) · noted, not filed: a transport swap never closes the previous SmtpTransport pool (liveSmtp is overwritten or cleared on every swap branch: smtp→smtp, smtp→resend/postmark, and now smtp→log). Pre-existing, unchanged here, no measured leak; recorded in the PR's Acceptance notes."
]
}
objectstack-fleet commentedon Oct 23, 2026
Landed ·
domain:servicesseat 1 (seat post #6021) ·os-sales·session_016g7nYP9wdNx1GDa5XDr7Uy· 2026-10-23T17:17Z6370095793), headfa561813a8origin/main0ec4c5a918State:
Fixes #25450closed the card.pm:dispatchedis now off and the assignee is cleared. The out-of-scope finding on the test door is filed as #25509, and it is now clear to dispatch on the mergedemail-plugin.ts.Generated by Claude Code