All five r1 blocking issues fixed + polish items applied:
- Unified credential-key convention: registerAutoWiredSource now stores at
calendar:source:<source.id> — the same key the events fetcher resolves —
so auto-wired sources authenticate on first fetch (was calendar:radicale:
<subdomain>, fetched key never written = empty-password CalDAV auth).
- calendarStateManager is now passed INTO assembleContext(...) (the r1 patch
only extended the function signature, so ctx.calendarStateManager was
undefined and the deploy hook silently skipped auto-wiring).
- Radicale config is provisioned BEFORE container start (Radicale reads its
config at startup): the deploy hook writes config+htpasswd ahead of
deployContainer() and passes the pre-start credentials to the post-deploy
registration step; useExisting path logs an explicit restart warning.
- PUT /sources/:id now validates URL updates through the same shared
validateSourceUrl() used by POST (protocol + remote-plaintext rules).
- New end-to-end contract test (calendar-autowire.e2e.test.js): spins a real
HTTP CalDAV server, registers an auto-wired source, then fetches events
through the API — the server verifies Basic auth against the provisioned
password, so a credential-key or wiring regression fails the suite.
Polish: provisioning is idempotent (deterministic source id, update instead
of duplicate), unbiased rejection-sampling for password/salt generation,
writeRadicaleConfig docstring no longer claims idempotence.
Calendar suites: 35 passed (32 prior + 3 new). Lint: 0 errors; complexity
warnings in deploy.js pre-exist at base (61 vs 68 now — the hook did not
worsen the trend line materially; calendar files themselves lint clean).