- packages/schema: 15 Vitest tests (6 valid + 6 invalid frontmatter + 3 round-trip) - packages/sanitize: fail-closed remark plugin + 12 private fixtures + 6 clean fixtures, 20 tests - packages/observability: Pino + correlation IDs + redaction; 5 tests with 100-log validation - packages/linkedin-client: Posts API client + token store; 10 tests; AES-256-GCM substituted for libsodium crypto_secretbox (Bun ESM bug, see docs/deferred-gates.md D-001) 50/50 tests pass across 4 packages. All Stage 1 DoDs verified. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
3.9 KiB
Deferred gates
Items that could not be completed in the Stage 0 execution window and must be resolved before the gate they block.
Gate 0.8 — Postgres + Redis on PaaS
Status: Deferred 2026-04-19.
Reason: Dokploy MCP tools (mcp__dokploy__*) were not loaded in the Stage 0 session, and DOKPLOY_API_KEY was not in the WSL environment. Direct API query not possible in-session.
Blocks: Stage 2 (database + API) — the scheduler and admin cannot run without a Postgres + Redis pair.
Resolution options:
- Recommended: Restart Claude Code with the vault's
.mcp.jsonDokploy MCP attached; runmcp__dokploy__list_applications/ equivalent againstsg-paas-s1.stargue.netto verify or provision. - Angelo confirms via Dokploy web UI and reports service names + connection hostnames.
- Provision fresh Postgres + Redis services in the
stargue-publishing-engineDokploy stack (clean room; isolates blast radius from other PaaS apps).
Acceptance when resolved: this file updated with service names, hostnames, and connection-string env-var locations (Dokploy secrets).
Gate 0.9 — LinkedIn Developer Portal apps
Status: Pending Angelo's manual action.
Reason: Dev Portal registration cannot be automated — requires human auth at linkedin.com/developers/.
Blocks: Stage 3.1 (OAuth flow) live integration — structure + contract tests can proceed in parallel.
Resolution: follow the checklist in linkedin-apps.md. Expected time ~30 min for OIDC + Share; multi-week for Community Management API + MDP partner approvals.
Acceptance when resolved: linkedin-apps.md registry filled in with app IDs; client credentials stored in Dokploy secrets LINKEDIN_CLIENT_ID, LINKEDIN_CLIENT_SECRET, LINKEDIN_TOKEN_ENCRYPTION_KEY.
What proceeds in parallel
Stages 1–2 (local DB), 3 structural (OAuth code + tool shapes + msw fixtures), 4 (scheduler), 5 (admin UI with Authentik stub), 6 (sanitize integration in stargue-com/.net), 7.1 (/market audit baseline), 7.2 (7 Cs post drafting) can all proceed without these gates. Live integration tests and first production publish require both gates resolved.
D-001 — Token store cipher: AES-256-GCM instead of XSalsa20-Poly1305
Plan §3.2 specified: libsodium crypto_secretbox (XSalsa20-Poly1305), per architect gap 3.
Implemented (2026-04-26): Node stdlib aes-256-gcm via node:crypto. Same AEAD security profile (256-bit key, 96-bit nonce, 128-bit auth tag), zero external dependencies.
Reason: libsodium-wrappers and libsodium-wrappers-sumo (v0.7.16) both have a known ESM resolution bug under Bun where the loader fails to find ./libsodium.mjs / ./libsodium-sumo.mjs from within their own dist folder. Reproduced cleanly on Bun 1.3.11. AES-256-GCM is the recommended AEAD when libsodium isn't available — same security guarantees, FIPS-compliant, in stdlib of every JavaScript runtime (Node, Bun, Deno, Cloudflare Workers).
Security review:
- AEAD: ✅ (authenticity + confidentiality)
- Key length: 256 bits (same as XSalsa20-Poly1305)
- Nonce length: 96 bits (sufficient for random nonces; collision probability < 2^-32 after 2^32 messages — well within Phase 1 envelope of <100k tokens lifetime)
- Tag length: 128 bits (same as XSalsa20-Poly1305)
- Implementation: Node stdlib (audited, FIPS 140-2 validated under common builds)
Remediation path: When libsodium-wrappers ships a Bun-compatible ESM build, migrate by: (1) restore dep, (2) re-implement encrypt/decrypt with crypto_secretbox_easy, (3) one-time decrypt-and-re-encrypt migration on linkedin_tokens.*_ct rows, (4) drop AES-GCM code path.
Risk: Low. Both ciphers offer equivalent security for this use case (encrypting OAuth tokens at rest in Postgres). The deviation is purely about the cipher primitive, not the threat model or key management.
Status: Accepted. 4/4 token-store round-trip tests pass. Production-ready.