Skip to content

Merge dev to main#995

Merged
zbigniewsobiecki merged 78 commits intomainfrom
dev
Mar 23, 2026
Merged

Merge dev to main#995
zbigniewsobiecki merged 78 commits intomainfrom
dev

Conversation

@zbigniewsobiecki
Copy link
Copy Markdown
Member

Merges current dev into main for production deployment.

Included

🤖 Generated with Claude Code

zbigniewsobiecki and others added 30 commits March 17, 2026 15:44
Migrate all references from zbigniewsobiecki to mongrel-intelligence
(CODEOWNERS, CI workflows, Docker images, clone URLs, issue links).
Normalize "CASCADE" → "Cascade" and "JIRA" → "Jira" across README,
CONTRIBUTING, SECURITY, and getting-started docs. Rewrite README intro
for scannability with updated lifecycle pipeline diagram.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…d-docs-polish

chore: rename org to mongrel-intelligence and polish docs casing
Link a clickable thumbnail (mid-video frame from the Trello workflow
demo) to the YouTube video, placed after the pipeline diagram.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
docs: use YouTube-generated thumbnail for demo video
…i-webhook-ordering

feat(dashboard): move webhook buttons below collapsible curl blocks
Run tests with coverage in CI and upload lcov report to Codecov.
Add CI status and coverage badges to README.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…ger-zone-below-api-keys

feat(dashboard): move Danger Zone below API Keys in project General settings
…erage-monitoring

ci: add Codecov coverage monitoring
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The /branch/main/ URL showed "unknown" because coverage was only
uploaded from dev so far. The branch-agnostic URL shows the latest
upload from any branch.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…catalog, definitions (#936)

Co-authored-by: Cascade Bot <bot@cascade.dev>
… Interval setting (#937)

Co-authored-by: Cascade Bot <bot@cascade.dev>
… whoami) (#938)

Co-authored-by: Cascade Bot <bot@cascade.dev>
Co-authored-by: Cascade Bot <bot@cascade.dev>
Co-authored-by: Cascade Bot <bot@cascade.dev>
…ds (#941)

Co-authored-by: Cascade Bot <bot@cascade.dev>
…nds (#942)

Co-authored-by: Cascade Bot <bot@cascade.dev>
…hooks commands (#943)

Co-authored-by: Cascade Bot <bot@cascade.dev>
…hMedia (#946)

Four code-quality issues identified in review, plus a correctness bug:

1. **Type deduplication** — remove local `interface Attachment` shadow that
   weakened `mimeType` to optional. Import the canonical `Attachment` type
   from `src/pm/index.ts` (`mimeType: string`, required), eliminating the
   spurious `.filter((att) => att.mimeType)` guard and `!` non-null assertion.

2. **Section heading** — rename `formatInlineMedia` → `formatPreFetchedImages`
   and change the rendered heading from `## Inline Media` to
   `## Pre-fetched Images` (card-level attachments are not "inline").

3. **URL deduplication** — deduplicate `allMedia` by URL before building the
   text section and returning. In JIRA, description images are always backed
   by an attachment, so the same URL appeared twice (once via
   `item.inlineMedia` with `source: 'description'`, once via
   `getAttachments()` with `source: 'attachment'`), wasting one of the
   MAX_IMAGES_PER_WORK_ITEM slots and printing the image line twice.
   First occurrence wins, preserving description > attachment > comment priority.

4. **Test correctness** — fix the "no mimeType" test, which violated the
   canonical Attachment contract by omitting `mimeType` entirely. Replace with
   a valid fixture (`mimeType: 'application/pdf'`) that tests the real
   invariant: non-image MIME types are excluded.

5. **New deduplication test** — covers the JIRA scenario where the same image
   URL appears in both `inlineMedia` (source: description) and `getAttachments`
   (source: attachment); asserts length=1 and that description source wins.

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
…iggers (#945)

Co-authored-by: Cascade Bot <bot@cascade.dev>
…948)

Inject pre-fetched work-item images as SDK ImageBlockParam content blocks
in the first conversation turn instead of writing them to disk. This
eliminates the file-read round-trip and ensures images are available in
the model's context from the first message.

Changes:
- Add `buildPromptWithImages` (exported for testing) — an async generator
  that yields a single SDKUserMessage with a text block + image blocks
- Add `filterContextImages` helper that filters to SDK-supported MIME types
  (jpeg/png/gif/webp), logs an INFO when images are injected, and warns for
  any skipped unsupported types
- Strip `images` from contextInjections before passing to `buildTaskPrompt`
  so `offloadLargeContext` does not redundantly write images to disk
- Export `ContextImage` from `src/backends/types.ts` for downstream use

Prompt improvements:
- Update native tool execution rules to be engine-agnostic (no engine names
  in agent-facing prompts) and clarify images may be in context or on disk
- Update `contextFiles.ts` module docstring to reflect that Claude Code SDK
  uses native delivery instead of file-based image offloading

Tests:
- New `claude-code-imagePrompt.test.ts` — 8 unit tests for buildPromptWithImages
  covering text+image content, session_id uniqueness, MIME filtering, etc.
- Two new `execute()` integration tests in `claude-code.test.ts` asserting
  that query() receives an AsyncIterable when images are present and that
  raw base64 data does not leak into the text prompt

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
…rkItemStep (#949)

Silent null returns from downloadAttachment were completely invisible in run
logs, making image delivery failures impossible to diagnose. Add INFO logs
before and after the parallel download, plus a WARN when a download returns
null (with query params stripped from the URL to avoid leaking Trello API
credentials).

Also fix a pre-existing bug where the exception-path WARN logged the full URL
including query-param credentials, and correct a stray lowercase 'warn' log
level in builderFactory.ts to match the codebase-wide 'WARN' convention.

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
…950)

Trello's attachment download endpoint (/1/cards/{id}/attachments/{id}/download/...)
requires an Authorization: OAuth header and does NOT accept key/token query-param
auth, causing all attachment downloads to return 401 and downloadAttachment() to
return null (root cause of the image-download null warnings seen in run 6a3d92d5).

Switch from appending key/token as query params to passing an OAuth header via the
existing authHeaders parameter of downloadMedia() — the same pattern already used
by the JIRA client with Basic auth. Update all four downloadAttachment unit tests to
assert header-based auth and use realistic Trello attachment URLs.

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
…lish (#951)

Rewrite docs/architecture.d2 to accurately reflect the codebase topology:
- Nest worker manager and cancel listener inside the Router process
- Show both BullMQ queues (cascade-jobs, cascade-dashboard-jobs)
- Rename "api" to "Dashboard API (:3001)" with port number
- Label DB as PostgreSQL, show Redis as explicit infrastructure
- Add LLM Providers (Anthropic, OpenAI, OpenRouter) as external dependency
- Show cancel flow (Dashboard → Redis pub/sub → Router → kill container)
- Use dashed borders for ephemeral Docker worker containers
- Consolidate worker1/2/N into a single representative worker box

Render to SVG and embed in README.md under the Architecture section.

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
)

* feat(prompts): disable squint features when repo has no .squint.db

* fix(prompts): gate dangling squint references in review.eta Philosophy and body format

Gate the "Use squint to see the forest, not just the trees" line in the
Philosophy section and the "...with squint evidence" examples in the review
body format template behind squintEnabled checks, addressing the remaining
ungated squint references flagged in code review.

Also adds test assertions to cover the Philosophy section gating and the
body format example gating.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Cascade Bot <bot@cascade.dev>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
aaight and others added 29 commits March 21, 2026 16:26
…tions (#971)

Co-authored-by: Cascade Bot <bot@cascade.dev>
…sDashboardJob (#972)

* test(worker-entry): add unit tests for dispatchJob routing and processDashboardJob

* fix(tests): rewrite worker-entry tests to exercise actual source code

Address review feedback: tests were re-implementing source logic inline
rather than calling the real functions.

- Export `dispatchJob`, `processDashboardJob`, `main`, and all job-data
  types from `src/worker-entry.ts` so tests can import them directly
- Add `VITEST` guard around top-level `main().catch()` to prevent
  accidental auto-execution at test-file import time
- Rewrite `tests/unit/worker-entry.test.ts` to call the real exported
  functions: `dispatchJob()` for routing tests, `processDashboardJob()`
  for dashboard-job tests, and `main()` for env-var validation tests
- 20 tests now exercise the actual source code paths and will catch
  regressions in argument ordering, branching logic, and error handling

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Cascade Bot <bot@cascade.dev>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…ecture-diagram

docs: replace architecture SVG with JPG diagram
* feat(backends): make claude-code the default agent engine

* fix(docs): update stale llmist default references to claude-code

Update the JSDoc in src/agents/registry.ts to reflect the actual fallback
engine ('claude-code' not 'llmist'), and fix the credential setup subheadings
in docs/getting-started.md to remove '(default)' from the LLMist heading and
add it to the Claude Code heading.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Cascade Bot <bot@cascade.dev>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: Cascade Bot <bot@cascade.dev>
)

Co-authored-by: Cascade Bot <bot@cascade.dev>
)

Co-authored-by: Cascade Bot <bot@cascade.dev>
Co-authored-by: Cascade Bot <bot@cascade.dev>
…ons (#979)

* fix(db): enable TLS certificate validation by default for DB connections

* fix(db): add existsSync guard for DATABASE_CA_CERT and fix migrate-hooks TLS

- Add existsSync check before readFileSync in getSslConfig() with a
  descriptive error message to help operators diagnose misconfiguration
- Fix tools/migrate-hooks.ts to use rejectUnauthorized: true (same as
  src/db/client.ts) by extracting an identical getSslConfig() helper,
  also with the existsSync guard for DATABASE_CA_CERT
- Add test coverage for the new error case when DATABASE_CA_CERT path
  does not exist

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Cascade Bot <bot@cascade.dev>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
…asking threshold (#981)

* feat(security): enforce 12-char minimum password and fix credential masking threshold

* fix(security): enforce 12-char minimum in CLI tool and frontend form

- tools/create-admin-user.ts: add runtime check rejecting passwords shorter
  than 12 chars, matching the tRPC router validation; update doc comment
  examples to use a compliant password instead of 'changeme' (8 chars)
- web/src/components/settings/user-form-dialog.tsx: add minLength={12} to
  the password input and update placeholder text so users see the requirement
  before submitting the form

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Cascade Bot <bot@cascade.dev>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
The dev database uses a self-signed certificate chain, which started
failing after TLS rejectUnauthorized was enabled by default in #979.
Add DATABASE_SSL=false to all migration steps in the dev deploy workflow.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…module init (#983)

Fixes a ZodError ("Unsupported engine settings for claude-code") that
occurred in the router when loadConfig() ran before registerBuiltInEngines()
was called. The engine settings registry was empty at validation time because
it relied entirely on a bootstrap call that some entry points were missing.

Pre-register the three built-in schemas (claude-code, codex, opencode) in
engineSettings.ts at module initialization. Any process that imports
EngineSettingsSchema now has the schemas available automatically — no
explicit registerBuiltInEngines() call is required for config validation.

The existing registerBuiltInEngines() calls are still needed for runtime
engine dispatch (registerEngine()) and are now harmlessly idempotent for
schema registration.

Adds regression tests for claude-code engine settings acceptance in both
ProjectConfigSchema and validateConfig to prevent silent regressions if
the static registration is accidentally removed.

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
…g services (#986)

PR #979 tightened DB SSL defaults to rejectUnauthorized: true, but the
dev database uses a self-signed certificate. The deploy workflow already
passed DATABASE_SSL=false to one-off migration containers via -e flags,
but the long-running router and dashboard containers read their env from
/opt/services/cascade-dev.env — which never had this variable set.

Result: every router startup since that PR crashed at seedAgentDefinitions
with "self-signed certificate in certificate chain" before the process
could serve any traffic.

Add an idempotent step (sed removes any existing line, echo appends the
correct value) that runs once per deploy, before docker compose restarts
both services. Since both containers share the same env_file, a single
write fixes both the router and the dashboard.

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
sed -i fails with "Read-only file system" because the runner process
cannot create temp files in /opt/services/ (the directory is read-only
for the runner). Running a container via the host Docker socket mounts
the host path as a writable bind mount, so the alpine container can
modify cascade-dev.env even though the runner itself cannot.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…d format (#984)

Co-authored-by: Cascade Bot <bot@cascade.dev>
…ands sections (#987)

* fix(prompts): consolidate duplicate staging safety and forbidden commands sections

* fix(prompts): correct directional reference in commit-and-push partial

The cross-reference said "above" but in all three consumer templates
(respond-to-review.eta, respond-to-ci.eta, respond-to-pr-comment.eta)
the Git partial is rendered after commit-and-push.eta, so the reference
should say "below".

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Cascade Bot <bot@cascade.dev>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
…gent prompts (#988)

Co-authored-by: Cascade Bot <bot@cascade.dev>
Co-authored-by: Cascade Bot <bot@cascade.dev>
Co-authored-by: Cascade Bot <bot@cascade.dev>
…ainers

Worker containers were missing DATABASE_SSL and DATABASE_CA_CERT env vars,
causing `self-signed certificate in certificate chain` SSL errors during
loadConfig() at worker startup. The router had DATABASE_SSL=false set but
buildWorkerEnvWithProjectId() only forwarded DATABASE_URL, so workers always
defaulted to rejectUnauthorized: true.

Also extracts all optional env-var forwarding into appendOptionalEnvVars()
to fix a pre-existing noExcessiveCognitiveComplexity lint warning that our
new if-branches pushed over the threshold.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…-ssl-forwarding

fix(worker): forward DATABASE_SSL and DATABASE_CA_CERT to worker containers
…ering-consistency-tests

test(prompts): add PM terminology, duplicate, VerifyChanges, and debug gadget tests
- Add `dev:all` script (concurrently, with --kill-others-on-fail) to start
  router + dashboard + frontend in one command
- Add `verify` script (lint + typecheck + unit tests) as the pre-PR check
- Move both scripts to logical positions in package.json (dev:all after
  dev:web, verify after typecheck)
- CONTRIBUTING.md: add missing `npm run build` step before dev servers;
  renumber setup steps 5→7; add trigger-discover step in Adding New Agents
- README.md: add dev:all + verify to Commands table; update Contributing
  item 3 to use `npm run verify`; add MIT + Node.js badges
- CLAUDE.md: add Quick Start as first Table of Contents entry

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Migration containers were missing DATABASE_SSL and DATABASE_CA_CERT,
causing SELF_SIGNED_CERT_IN_CHAIN failures after TLS cert validation
was enabled by default in #979.

Add --env-file /opt/services/cascade.env to the three migration steps
(db migrate, trigger config migration, hooks migration) so they pick
up the same SSL configuration already used by the re-encrypt step.

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
@zbigniewsobiecki zbigniewsobiecki merged commit f783c03 into main Mar 23, 2026
13 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants