WIP: docs: plan read-only IMAP Notes server (#766) #830
Closed
kayg
wants to merge 1 commit from
docs/imap-766-readonly-slice into dev
pull from: docs/imap-766-readonly-slice
merge into: kayg:dev
kayg:main
kayg:feat/style-sheet-fixes
kayg:storage/wal-checkpoint-off-save-1051
kayg:t3/paged-search-reconcile-final
kayg:feat/pass8
kayg:review/calendar-2
kayg:fix/shared-row-swipes
kayg:feat/contrast
kayg:dev
kayg:feat/collections-db
kayg:fix/instant-keys-1056
kayg:feat/money-round
kayg:perf/stalls-1054
kayg:wip/tiering-v3-cold4
kayg:wip/tiering-v3-cold5
kayg:port/rows-actions
kayg:port/rows-drop
kayg:port/hidden-blocks
kayg:port/rows
kayg:port/port-tables
kayg:port/port-tables-2
kayg:t3/mail-1011-liveness
kayg:port/devices
kayg:port/port-attachments
kayg:port/port-attachments-2
kayg:port/port-attachments-3
kayg:docs/design-consistency
kayg:docs/engineering-standards
kayg:fix/rusqlite-0.41-rustsec-2026-0459
kayg:feat/iphone-fixes
kayg:shared/restore-and-stale-918-919
kayg:fix/phone-top-band-contrast
kayg:feat/notes-approve
kayg:perf/soak-max-gate
kayg:feat/files-s1-identity
kayg:fix/lifecycle-event-id
kayg:feat/quickfix
kayg:wip/tiering-v3-cold
kayg:perf/web-mockup-frame-fixes
kayg:port/contacts-merge
kayg:port/contacts-edit
kayg:test/shared-room-no-deleted-text
kayg:perf/first-paint-credits
kayg:fix/shared-history-after-grant
kayg:fix/phone-swipe-regressions
kayg:feat/contrast-r1
kayg:review/sharing-pr3-review
kayg:feat/tiering-v3-s2-tags
kayg:feat/folder-drop
kayg:fix/deskpills-lazy-share
kayg:feat/sharing-s1-pr3
kayg:tmp/money-round-before
kayg:fix/phone-pane-backdrop-roots
kayg:fix/palette-preload-chips
kayg:fix/invite-defaults
kayg:port/tasks-matrix
kayg:fix/restore-green-gates
kayg:fix/sharing-fast-path-hardening
kayg:t3/photos-s1
kayg:feat/tiering-v3-s1-namespace
kayg:notes-archive-hide
kayg:feat/tasks-actions
kayg:t3/photos-plan-slice-one
kayg:feat/whiteboard-s1
kayg:t3/paged-search-reconcile
kayg:t3/smooth-pane-transitions
kayg:t3/index-position-startup-scan
kayg:fix/private-staging-759b-r2
kayg:feat/dav-transport
kayg:feat/imap-notes-fetch
kayg:feat/imap-notes-projection
kayg:feat/imap-notes-readonly
kayg:feat/imap-notes-auth
kayg:feat/imap-notes-server-foundation
kayg:docs/undo-block-ids-plan
kayg:fix/undo-768
kayg:proto/block-identity-v7d
kayg:issue/carddav-read-perf-fix-r2
kayg:issue/carddav-read-r2
kayg:docs/imap-766-plan-v2
kayg:docs/imap-notes-plan
kayg:docs/quota-plan-2
kayg:fix/parallel-test-flakes
kayg:feat/contacts-companion-pure
kayg:docs/calendar-backend-v2-plan
kayg:feat/calendar-ical-converter
kayg:docs/tasks-writes-v2-plan
kayg:docs/carddav-writes-v2-plan
kayg:docs/contacts-import-v2-plan
kayg:issue/610-pm-midnight
kayg:feat/calendar-v2-s1-containment
kayg:docs/dav-recorder-v2-plan
kayg:plan/previews-865
kayg:plan/save-log-durable-entry
kayg:fix/e2e-data-on-ram
kayg:feat/appwindow3
kayg:feat/appwindow2
kayg:feat/appwindow
kayg:feat/money-p1
kayg:feat/keys-sheet
kayg:review/calendar-2-themes
kayg:feat/smooth-cursor
kayg:fix/float-style
kayg:review/calendar-2-float
kayg:release/2026-11-06-hotfix
kayg:archive/port/rows-drop-code
kayg:archive/port/rows-actions
kayg:archive/port/rows
kayg:scratch/tasks-894-ui-gates
kayg:review/calendar-2-night-wip
kayg:release/2026-11-05
kayg:archive/feat/tiering-v3-s1-namespace
kayg:archive/flaky/rows-drop-fixed
kayg:archive/flaky/rows-actions
kayg:archive/feat/tiering-v3-reader
kayg:archive/feat/tiering-v3-roots
kayg:archive/flaky/rows
kayg:sim/bm15-final
kayg:sim/bm15-fix
kayg:sim/bm15-bis-932
kayg:sim/bm15-bis-909
kayg:sim/bm15
kayg:sim/bm15-bis-887
kayg:perf/tiering-option-b
kayg:port/style-3
kayg:port/style-2
kayg:port/style
kayg:fix/sw-lazy-precache
kayg:fix/vim-w-waits-for-save
kayg:fix/signout-test-races
kayg:fp-scratch/all
kayg:sim/bm15-first-paint
kayg:archive/bm15/rows-drop
kayg:archive/bm15/rows-actions
kayg:fix/palette-snippet-contrast
kayg:archive/bm15/rows
kayg:archive/bm15/hidden
kayg:archive/plan/save-log-durable-entry
kayg:mock/money-fix2
kayg:archive/fix/e2e-data-on-ram
kayg:mock/appearance-all
kayg:mock/pill-press
kayg:archive/docs/design-consistency
kayg:mock/auto-swipes
kayg:mock/mail-actions
kayg:archive/feat/mail-p1
kayg:mock/money-static
kayg:archive/review/standards-917
kayg:archive/docs/engineering-standards
kayg:perf/tiering-761-fix
kayg:mock/type-audit
kayg:mock/third-pane
kayg:feat/contacts-import-v2-s1
kayg:perf/executor-hot-path
kayg:archive/port/hidden-blocks
kayg:archive/port/devices
kayg:scratch/executor-on-894
kayg:scratch/executor-spans2
kayg:scratch/executor-spans
kayg:train/2026-11-03-bm14c
kayg:archive/port/rows-drop
kayg:feat/tiering-761-d-scale
kayg:feat/tiering-761-c-index
kayg:feat/tiering-761-b-reader
kayg:archive/review/sharing-pr3-review-9fec3d1f
kayg:train/2026-11-03-bm14b
kayg:perf/ports-lazy-budgets
kayg:feat/tiering-761-a-migration
kayg:train/2026-11-03-bm14
kayg:train/2026-11-03-bm12
kayg:archive/review/sharing-pr3-review
kayg:archive/feat/sharing-s1-pr3
kayg:train/2026-11-03-bm11
kayg:archive/feat/imap-notes-fetch
kayg:train/2026-11-03-bm10
kayg:archive/review/sharing-pr3-review-code
kayg:archive/plan/previews-865
kayg:train/2026-11-02-bm9
kayg:archive/port/port-attachments-3
kayg:archive/port/contacts-merge
kayg:fix/motion-audit-859
kayg:train/2026-11-02-bm8
kayg:archive/scratch/bm8-prep
kayg:archive/port/port-pickers
kayg:archive/port/port-tables-2
kayg:archive/port/port-tables
kayg:archive/feat/sharing-s1-pr3-code
kayg:archive/scratch/bm7-fixed
kayg:train/2026-11-02-bm7
kayg:archive/fix/parallel-test-flakes-code-minipc01
kayg:train/2026-11-02-bm6
kayg:feat/dav-recorder-v3
kayg:research/788-diagnosis
kayg:archive/fix/parallel-test-flakes
kayg:archive/perf/pr792-cold-index-edit
kayg:docs/sharing-slice-1
kayg:archive/docs/imap-766-plan-v2
kayg:feat/dav-recorder-v2
kayg:archive/docs/dav-recorder-v2-plan
kayg:spike/imap-766-s0-cases
kayg:archive/fix/undo-768
kayg:feat/dav-recorder
kayg:archive/docs/contacts-import-v2-plan
kayg:archive/feat/calendar-ical-converter
kayg:feat/contacts-import
kayg:perf/cold-growth-on-764
kayg:perf/cold-growth-on-tiering
kayg:archive/docs/tasks-writes-v2-plan
kayg:archive/docs/calendar-backend-v2-plan
kayg:archive/feat/contacts-companion-pure
kayg:feat/tasks-set-status
kayg:feat/tasks-move-reorder
kayg:archive/docs/carddav-writes-v2-plan
kayg:archive/feat/calendar-v2-s1-containment
kayg:feat/tasks-delete-promote-duplicate
kayg:archive/feat/dav-transport
kayg:archive/fix/carddav-rebuild-r1
kayg:archive/fix/carddav-retention-r1
kayg:feat/carddav-writes
kayg:perf/quota-on-tiering
kayg:perf/quota-simple
kayg:perf/cold-growth-on-quota-stack
kayg:feat/calendar-identity
kayg:feat/calendar-event-parser
kayg:feat/calendar-props-maps
kayg:port/glass-when-ring
kayg:feat/tiering-761-s1
kayg:wip/10by32-01-impl-759b-scratch-20261030
kayg:wip/6by32-01-bm3-webkit-pause-20261030
kayg:wip/10by32-01-bm3-chromium-pause-20261030
kayg:wip/6by32-01-tier-761-s1-pause-20261030
kayg:spike/imap-766-s0
kayg:wip/6by32-02-calternal-pause-20261030
kayg:wip/8by64-01-review-688-pause-20261030
kayg:wip/6by32-01-verify-744-pause-20261030
kayg:wip/6by32-01-verify-742-pause-20261030
kayg:fix/private-staging-759b
kayg:wip/6by32-01-review-748-pause-20261030
kayg:wip/6by32-01-review-733c-pause-20261030
kayg:wip/6by32-01-review-733b-pause-20261030
kayg:wip/6by32-01-perf-idle-8-pause-20261030
kayg:wip/6by32-01-perf767-base-pause-20261030
kayg:wip/6by32-01-perf767b-767-pause-20261030
kayg:wip/6by32-01-perf767b-764-pause-20261030
kayg:wip/6by32-01-perf767-767-pause-20261030
kayg:wip/6by32-01-perf767-764-pause-20261030
kayg:wip/6by32-01-lists-b-pause-20261030
kayg:wip/6by32-01-ids-verify5-pause-20261030
kayg:wip/6by32-01-ids-verify4-pause-20261030
kayg:review/calendar-month
kayg:wip/10by32-02-undo-768-20261030
kayg:test/ids-verify3
kayg:wip/10by32-02-bm3-chromium-20261030
kayg:wip/10by32-01-review-753-20261030
kayg:wip/10by32-01-perf-idle-2-20261030
kayg:wip/10by32-01-bm2-webkit2-20261030
kayg:plan/759b-staging
kayg:train/2026-10-30-bm2
kayg:review/758b-tests
kayg:review/758-tests
kayg:review/764d-tests
kayg:review/767b-tests
kayg:review/preview-2026-10-29
kayg:review/767-tests
kayg:docs/tiering-731-plan
kayg:wip/c6b02-when2
kayg:wip/c6b02-tasks-create-fix5
kayg:wip/c6b02-settings-frost-mock
kayg:wip/c6b02-settings-frost-base
kayg:wip/c6b02-settings-frost
kayg:wip/c6b02-ring
kayg:wip/c6b02-review-733d
kayg:wip/c6b02-bm1-full-a
kayg:wip/compute02-when-field
kayg:wip/compute02-webkit-lists-repro
kayg:wip/compute02-train-bl2-dev
kayg:wip/compute02-dev-green-pw164
kayg:docs/deploy-plan
kayg:review/764c-tests
kayg:review/764b-tests
kayg:review/748g-tests
kayg:review/764-tests
kayg:review/759b-tests
kayg:fix/storage-owner-liveness-642
kayg:fix/storage-fix-7
kayg:wip/compute02-storage-fix-7
kayg:review/759-tests
kayg:feat/tiering-731
kayg:wip/tiering-731-first-attempt
kayg:wip/compute02-storage-fix-1
kayg:review/754g-tests
kayg:perf/idle-honest-2
kayg:review/754f-tests
kayg:review/754e-tests
kayg:review/755-tests
kayg:review/754d-tests
kayg:review/754c-tests
kayg:review/754b-tests
kayg:review/754-tests
kayg:fix/storage-private-tmp-642-dev
kayg:wip/compute02-verify-750
kayg:test/ids-verify5
kayg:test/ids-verify4
kayg:fix/storage-exact-file-quarantine-642
kayg:wip/compute02-verify-740
kayg:perf/one-flush-save
kayg:review/calendar-static
kayg:wip/compute02-verify-737
kayg:review/indexing-ring
kayg:review/when-field-2
kayg:wip/compute02-review-733
kayg:proto/block-identity-2-review
kayg:proto/block-identity-review
kayg:wip/c6b02-tc-design
kayg:review/when-field
kayg:issue/tasks-create-ids
kayg:issue/tasks-create
kayg:review/combined
kayg:wip/compute02-review-combined
kayg:review/task-polish
kayg:review/top-buttons
kayg:review/q1-q5
kayg:train/2026-10-26-bl2
kayg:archive/wt-398h
kayg:archive/train-bm-proptest-seed
kayg:archive/integ325-293
kayg:archive/integ325-ci
kayg:archive/client-auth-review-baseline
kayg:archive/wt-sim-4853
kayg:archive/wt-sim-4811
kayg:archive/wt-448m
kayg:archive/wt-398a-allocator
kayg:issue/calendar-adr
kayg:archive/old/train/2026-10-23bk2
kayg:archive/old/train/2026-10-23bk
kayg:issue/469-mockup-9a
kayg:issue/smart-tasks-mockup
kayg:issue/469-menus
kayg:issue/652-signout-flake
kayg:issue/652-history-fix7
kayg:issue/652-history-fix6
kayg:archive/old/issue/spring-check-perf
kayg:issue/spring-check-perf
kayg:issue/659-rename-fast
kayg:archive/old/train/2026-10-21ar
kayg:issue/search-hardening-3
kayg:issue/652-history-fix5
kayg:issue/660-port-sheets-glass
kayg:issue/652-history-fix4
kayg:issue/652-history-fix3
kayg:issue/652-history-fix2
kayg:issue/652-history-flake
kayg:train/2026-10-21an
kayg:issue/settings-admin-port
kayg:issue/search-port
kayg:train/2026-10-20am
kayg:issue/storage-split-fix2
kayg:issue/storage-split
kayg:archive/old/issue/folder-ids-fix
kayg:train/2026-10-20al
kayg:archive/old/issue/folder-ids
kayg:train/2026-10-20ak
kayg:issue/tables-mockup
kayg:train/2026-10-19aj
kayg:train/2026-10-19ai
kayg:issue/469-merge-fixes
kayg:issue/sidebar-band
kayg:archive/old/issue/608-settings-spec
kayg:train/2026-10-19ah
kayg:issue/swipe-offscreen
kayg:train/2026-10-19ag
kayg:archive/old/issue/590-nlp-adr
kayg:archive/old/issue/587-event-after-write-2
kayg:train/2026-10-19af
kayg:archive/old/issue/587-event-after-write
kayg:issue/469-pill-room-c
kayg:issue/469-pill-room
kayg:train/2026-10-19ae
kayg:issue/469-narrow-handle
kayg:issue/397-ios-swipe-2
kayg:archive/old/issue/adrs-photos-files-tasks
kayg:issue/469-desk-fixes
kayg:archive/old/issue/auto-update-adr
kayg:issue/469-filter-gap
kayg:issue/469-port-1b
kayg:issue/442-opacity-flake
kayg:archive/397-ios-swipe-2
kayg:issue/327-web-fast-3
kayg:archive/old/issue/469-port-1
kayg:issue/469-port-1
kayg:issue/327-web-fast-2
kayg:archive/old/issue/327-web-fast
kayg:archive/old/issue/425-stt-bench-vq1
kayg:archive/old/issue/445-no-bleed
kayg:archive/old/issue/400-swipe-mockup-2
kayg:issue/426-client-review
kayg:issue/426-client-2
kayg:issue/426-client
kayg:archive/old/issue/476-safe-area-lab
kayg:archive/445-top-light-2
kayg:archive/old/issue/445-top-light
kayg:issue/471-blocks-mockup
kayg:archive/old/issue/448-links-app-2
kayg:archive/old/issue/448-links-app
kayg:archive/old/issue/398-cold-links
kayg:issue/434-442-small-2
kayg:issue/434-442-small
kayg:archive/old/issue/398-unload
kayg:archive/old/issue/445-bottom-band
kayg:issue/445-bottom-band
kayg:issue/351-rem-3
kayg:archive/312-views-mockup
kayg:issue/351-rem-2
kayg:issue/351-rem
kayg:archive/old/issue/327-first-note
kayg:issue/395-width-phone
kayg:archive/old/issue/327-typing
kayg:issue/396-ios-edges
kayg:issue/397-ios-swipe
kayg:archive/398-allocator
kayg:archive/old/issue/327-notes-index
kayg:issue/345-347-contrast-empty-2
kayg:archive/old/issue/44-arenas
kayg:issue/44-arenas
kayg:archive/integ325
kayg:archive/old/issue/327-perf-harness
kayg:archive/old/issue/44-thp
kayg:issue/44-thp
kayg:archive/old/issue/285-sticky-pills
kayg:archive/old/issue/44-trim-3
kayg:issue/44-trim-3
kayg:archive/old/issue/165-cards
kayg:archive/old/issue/165-picker-2
kayg:archive/old/issue/212-multi-select
No reviewers
Labels
Milestone
Clear milestone
No items
No milestone
Projects
Clear projects
No items
No project
Assignees
Clear assignees
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".
No due date set.
Dependencies
No dependencies set
Reference
kayg/calternal!830
Loading…
Reference in a new issue
No description provided.
Delete branch "docs/imap-766-readonly-slice"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Documentation-only plan for the read-only Apple Notes IMAP server slice.
mail.notes.readapp-password scope and documents the minimal IMAP command set from slice-0 captures.devindependently.Validation:
git diff --cached --checkpassed. No build, tests or native experiment were run; this PR contains the plan only.docs: plan read-only IMAP Notes server (#766)to WIP: docs: plan read-only IMAP Notes server (#766)Independent plan review
verdict: revise. reviewed #830 at
840ec0d022105fc680e16ea846fbd39afb59c7ae, against #775 at39d0553d, its slice-0/native fresh-mailbox evidence, and #824 atf1c1aa96. no P0 findings; two P1s and three P2s below. no separate P3 findings. this is a plan review; no native experiment or product tests were run, and nothing was pushed.findings
P1: the native gate does not yet establish preservation under this read-only contract (plan lines 52–56, failure table, gate 4).
slice-0 findings E2-3 establish a narrower result:
APPEND NO [OVERQUOTA]retained the full local text through quit/relaunch, caused no cleanup or retry for at least two minutes, and the next small edit uploaded all pending text. the report explicitly says the failed-save UI was not reviewed. neither that result nor E2-2's successful STORE/EXPUNGE followed by republication establishes behavior forSELECT [READ-ONLY]or explicitNO [READ-ONLY]on APPEND/STORE. the fresh-mailbox run also demonstrates that server retention can coexist with pending text being hidden in Notes; it is not a read-only-selection test.gate 4 already has a useful conditional retention check, but “if the client queues” leaves the decisive case optional. make this a mandatory release gate with a deliberately seeded offline edit before reconnecting to the read-only server. separately exercise initial read-only selection, an edit/delete attempted after selection, and actual queued-command refusals. include a Calternal edit that publishes a replacement UID while the native edit remains pending. require exact pending text to remain visibly accessible through reconnect and quit/relaunch, unchanged bystanders, no successful mutation or false server-save indication, and a bounded retry rate over a recorded observation interval. capture all connections and the native error/UI state. if Notes prevents editing entirely, record that result and still test the pre-existing offline queue. export and verify pending text before removing the disposable account. do not enable outside dev if any pending text disappears or becomes inaccessible. change the failure-table recovery assertion “Notes keeps the pending edit” to an unproven acceptance condition until this passes.
P1: pre-auth command dispatch and credential framing need an explicit boundary (command table, auth section, lines 54 and 74–81).
the table assigns no connection states, so the plan does not establish whether LIST, NAMESPACE, STATUS, SELECT, FETCH, SEARCH, CHECK, IDLE or the APPEND literal-drain path are reachable before authentication. require a state/command matrix and reject mailbox commands before mailbox lookup, rendering, UID access or literal continuation. enforce the process connection permit from TCP acceptance, covering TLS handshakes and unauthenticated sockets; add Installation/user permits after verification and release all permits on every failure path.
an 8 KiB command line does not bound a LOGIN literal or a SASL continuation. specify small independent credential-literal, encoded SASL and decoded SASL limits, strict PLAIN framing/identity handling, cancellation, bounded authentication attempts/work, and an absolute authentication deadline that partial input cannot extend. the 96 MiB message bound must not become the pre-auth credential bound. since LITERAL+ is not advertised, closing on an unsolicited non-synchronizing literal is a simpler option than draining it. gate large/malformed LOGIN literals, both AUTHENTICATE forms, cancellation, partial input, pipelined mailbox commands after failed auth, and connections held before TLS/auth completion.
one RFC qualification to the four-command question: RFC 3501 §6.1 also permits NOOP before auth. explicitly choose that harmless fifth command, with no mailbox updates, or document a deliberate restriction. nothing else should expose mailbox work before auth. RFC 4616 §2 defines PLAIN's identity/password framing.
P2: separate input-progress deadlines from authenticated inactivity (lines 80–82).
“command inactivity 30 s” risks disconnecting a healthy authenticated client between commands. a hard BYE at 28 minutes of IDLE is also below RFC 3501 §5.4's minimum 30-minute inactivity autologout. RFC 2177 advises the client to renew IDLE at least every 29 minutes; it does not prescribe a shorter server disconnect. keep short handshake/auth/partial-command/literal-progress deadlines, give authenticated inactivity at least 30 minutes, and exempt IDLE/DONE from the ordinary partial-command timer. test these timer states independently, including a healthy quiet session.
P2: the streaming budget needs a concrete storage boundary (lines 68, 77–87, persistence gate).
the immutable-byte rule is correct, but #824's current
getreturns an entire payload asVec<u8>andappendaccepts the whole byte slice. storing complete 96 MiB MIME there and fetching it through that API does not meet the stated ≤8 MiB incremental RSS per connection. name the representation: for example, immutable serialized blobs with bounded streaming reads and durable references under UID authority, or a smaller first-slice message cap. account for shared cache/source memory as well as socket buffers. pin attachment bytes and serialization version before advertising a UID; a streaming source failure after announcing a literal must close rather than promise that no partial literal was sent. preflight removes some failures, not mid-transfer read failures.P2: the first implementation PR combines too many independently risky changes (“first implementation PR size”).
10–14 files / 1,400–2,000 lines is an estimate, not sufficient review containment for new TLS lifecycle/deployment, auth schema/scope, a stateful literal parser, persistent projection, MIME/attachments and IDLE fan-out together. establish smaller dependency PRs and explicit activation gates.
cuts
UID decision
passes at the plan level: lines 12 and 68 explicitly require a new server-owned UID for every Calternal content revision, immutable bytes for an issued UID, and exact-tuple retirement of the old revision. that matches RFC 3501 §2.3.1.1 and #824; the stable note UUID must not be reused as the IMAP UID. add a positive edit gate: fetch U1, edit the note in Calternal, observe U2 > U1 with the same note UUID and new bytes, and verify U1 either returns its original bytes while retained or no message after retirement, across concurrent fetch, reconnect and restart. never re-render changed bytes under U1.
IMAPS-only on 993 is supported by RFC 8314 §3.2. the explicit Notes-only scope and retaining the observed minimal commands are sound choices. approval waits on the native-safety gate definition, pre-auth boundary, timeout correction, concrete streaming design and smaller first PR.
Plan revised in place and pushed at
7927d06.multipart/relatedwith stable CIDs; retaindavand addmail.notes.read. TLS termination remains open for kayg, with a recommendation at the end of the plan.git diff --checkpassed; no build, tests or native experiment were run.Infrastructure for this plan is in place (Maintainer, 2026-11-02; homelab-private PR #3, dab294db). Implementation must follow these facts:
imaps→ IngressRouteTCPcalternal/calternal-imaps(tls.passthrough=true, HostSNI(*)) → prod 10.70.3.162:993 over the private LAN, not NetBird. No TLS termination at the edge: Calternal terminates implicit TLS itself.ip_unprivileged_port_start=1024stays as it is. The app listens on 9993 inside the container, published as host :9993. A narrow root-owned socket forwarder maps host 10.70.3.162:993 → :9993 (the Maintainer installs it). Bind to 10.70.3.162 or to all interfaces.calternal/calternal-tls)./etc/calternal/imap-tls/current/{fullchain.pem,privkey.pem}, readable by usercalternal.calternal-imap-tls-sync.timerrefreshes them every 5 min by atomically rotating thecurrentsymlink./etc/calternal/imap-tlsdirectory read-only (not the resolved files).currentsymlink generation changes. Sync does not restart the app.scripts/calternal-imaps/README.md..mobileconfigprofiles are signed with the Developer ID Application certificate (1Password "Apps / Calternal" → "Apple Certificates", issued to Aayushy Swetapragyan). Each device gets its ownmail.notes.readapp password. This is the setup step after the read-only server works.The port 993 forwarder is installed on prod (Maintainer, 2026-11-02; homelab-private PR #4):
calternal-imaps.socket: enabled and active, owned by the root system manager. It listens on 10.70.3.162:993.calternal-imaps.service: started by that socket. It runs asystemd-socket-proxydworker with DynamicUser=yes that forwards to 10.70.3.162:9993, and exits after 5 idle minutes. It does no TLS termination.10.70.3.162:9993:9993for the IMAP listener (the app listens on 9993 inside the container)./etc/calternal/imap-tlsread-only as a directory, and reload when thecurrentsymlink changes.calternal.cloud:993TLS handshake, the IMAP greeting and NOOP all work through the proxy to a temporary 9993 listener running ascalternal. A direct connection to 9993 from a k3s node is blocked. No listener remains, and the socket is ready for the train that ships the server.kayg referenced this pull request2026-11-05 23:21:11 +00:00
Housekeeping #1009 status: audited head
7927d06ac60e83ac3eee9780e333d047a4305901against devcd7f84432feb.git cherry origin/dev <head>reports 2 unmatched commits and 0 equivalent patches. Separate stable patch-id indexing and key-file checks do not establish full landing. Absent from dev:docs/plans/766-slice1-read-only-imap.md. Left unchanged as WIP, per kayg’s instruction; no rebase, close, tests, or merge. The #1009 audit records the unmatched commit list.Superseded by #775; closing.
Pull request closed