chore: release - merge dev into main#1146
Merged
zbigniewsobiecki merged 58 commits intomainfrom Apr 18, 2026
Merged
Conversation
Bumps [hono](https://github.com/honojs/hono) from 4.12.12 to 4.12.14. - [Release notes](https://github.com/honojs/hono/releases) - [Commits](honojs/hono@v4.12.12...v4.12.14) --- updated-dependencies: - dependency-name: hono dependency-version: 4.12.14 dependency-type: direct:production ... Signed-off-by: dependabot[bot] <support@github.com>
…d-play refactor Spec 006 captures the WHAT and WHY: the Linear rollout this session shipped four separate silent bugs (status-mapping UUID, worker credentials, Bearer-prefix auth, label parity) each traceable to the same structural cause — adding a PM provider requires edits in ~10 cross-cutting locations with no single place enforcing the contract. Five plans decompose the work: - 006/1 — manifest contract + pmProviderRegistry + conformance harness + shared helpers (auth-headers, webhook-verifier, label-id-resolver, project-id-extractor) + generic wizard renderer. Dormant — TestProvider fixture proves the harness works. All three existing providers stay on legacy path. - 006/2 — migrate Trello onto the manifest (chosen first: smallest surface, lowest risk). - 006/3 — migrate JIRA. - 006/4 — migrate Linear. Also consolidates the platform-client auth header and label-id resolver that diverged in this session. - 006/5 — delete legacy registration infrastructure, remove transitional README note. Each migration is independently revertable; per spec AC #6 there's no "half-migrated provider" state at any merged commit. OSS decisions: skip RJSF / JSON Forms (overkill for 5-provider domain), use existing react-hook-form + zod + a lightweight manifest-driven renderer. Reference the Backstage extension-point model architecturally. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…arness (dormant)
Landed the dormant manifest infrastructure that spec 006 is built on:
- PMProviderManifest interface + sub-types (src/integrations/pm/manifest.ts)
One declarative contract per provider: id, label, category, credential
roles, webhook route + verifier, payload parser, router adapter,
extractProjectIdFromJob hook, PMIntegration, trigger handlers, platform
client factory, optional isSelfAuthoredHook + createLabel.
- pmProviderRegistry (src/integrations/pm/registry.ts)
Process-singleton registry; registerPMProvider enforces unique ids so
forgotten renames surface as runtime errors at startup.
- Shared helpers in src/integrations/pm/_shared/:
- auth-headers.ts — linearAuthHeader (bare key), githubAuthHeader
(Bearer + Accept + api-version), jiraAuthHeader (Basic). Guards
against the Bearer-prefix regression fixed in PR #1119.
- webhook-verifier.ts — makeHmacSha256Verifier factory; header-prefix
tolerant, opt-out semantics when secret is null.
- label-id-resolver.ts — UUID-validating label resolver, encapsulates
the check currently duplicated in src/pm/linear/adapter.ts.
- project-id-extractor.ts — extractProjectIdFromJobViaRegistry iterates
the manifest registry; wired into src/router/worker-env.ts as a
first-check fallback so the legacy per-provider branches still fire
for Trello/JIRA/Linear until plans 006/2-006/4 migrate them.
- Conformance harness (tests/unit/integrations/pm-conformance.test.ts)
Iterates listPMProviders() and asserts 11 contract invariants per
manifest. Exercised against TestProvider fixture (tests/helpers/
testPMProvider.ts) in this PR; real providers join in plans 006/2-4.
- pm.discovery tRPC router (src/api/routers/pm-discovery.ts)
Registry-driven listProviders + providerCredentialRoles endpoints.
Lives alongside the legacy integrationsDiscovery router during the
migration window. Mounted at pm.discovery.* in appRouter.
- Frontend provider-wizard registry + generic step renderer
(web/src/components/projects/pm-providers/)
Parallel frontend registry keyed by the same id as the backend
manifest. renderManifestStep helper wired into pm-wizard.tsx ahead of
the legacy per-provider branches; falls back when no wizard is
registered. In this PR, zero providers are registered, so the wizard
behavior is byte-for-byte identical to main.
- src/integrations/README.md — full rewrite as the manifest-first
author's guide with a transitional note that Trello/JIRA/Linear are
migrating in plans 006/2-4. Legacy section kept at the bottom.
- CLAUDE.md — integration abstraction pointer updated to reflect the
hybrid state (manifest for PM, legacy IntegrationModule for SCM +
alerting).
Tests: 42 new (7687 pre-existing + 42 = 7729 total, all green).
Build, lint, typecheck all pass.
No operator-visible changes. Trello/JIRA/Linear continue to register
through bootstrap.ts and builtins.ts; the new registry is consulted
first and returns empty, so legacy paths handle every real request.
Plan: docs/plans/006-pm-integration-plug-and-play/1-infrastructure.md.done
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…cture feat(006/1): PM provider manifest + conformance harness (dormant infra)
…ension Plan 006/2 as written assumed Trello could use makeHmacSha256Verifier from 006/1's shared helpers. Reality: Trello signs HMAC-SHA1(body + callbackUrl) — different algorithm AND different signed payload. Plan updated to wire the existing verifyTrelloSignature helper from src/webhook/signatureVerification.ts into the manifest's verifyWebhookSignature instead. Plan 006/2 also needed a way for provider wizards to declare React hooks (useTrelloDiscovery, useTrelloLabelCreation, etc.). The generic renderer in 006/1 couldn't call those conditionally (React rules-of-hooks). Added an optional useProviderHooks field to ProviderWizardDefinition and a new ManifestProviderWizardSection child component that hosts the unconditional hook calls. Plans 006/3 and 006/4 will use the same contract for JIRA and Linear. Both are additive changes to the 006/1 contract — no rework of landed code is required beyond adding the optional field to types.ts. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Adds src/integrations/pm/trello/ with: - manifest.ts: PMProviderManifest wiring TrelloIntegration, TrelloRouterAdapter, all 7 Trello trigger handlers, and TrelloPlatformClient. verifyWebhookSignature wraps the existing verifyTrelloSignature (HMAC-SHA1 of body+callbackUrl) with Host/X-Forwarded-Proto header reconstruction — no shared factory because Trello's signing scheme is unique among providers. - index.ts: side-effect module that calls registerPMProvider(trelloManifest). src/integrations/pm/index.ts: new barrel importing ./trello/index.js for the side effect. Plans 006/3 and 006/4 append jira + linear. Contract adjustments surfaced during TDD: - Dropped parseWebhookPayload field from PMProviderManifest (redundant with routerAdapter.parseWebhook; had wrong return type in 006/1). Each caller uses the appropriate one: router uses routerAdapter, PM-domain code uses pmIntegration.parseWebhookPayload. - Relaxed conformance harness's platform-client assertion from 3 methods to 2 (postComment + deleteComment). updateComment/postReaction are provider extensions, not contract. - registerTestProvider is now additive (no longer resets the registry), so the conformance harness iterates TestProvider AND every real provider side-by-side — validating AC #2 of the spec. Tests: 15 new Trello manifest tests + conformance now 22 (11 per provider x 2). Trello's legacy registrations (bootstrap.ts, builtins.ts, worker-env extractor branch, pm-wizard.tsx branch) still fire — removed in task 3 of this plan. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Completes plan 006/2. Trello is the first real provider on the manifest
pattern landed in 006/1.
Backend:
- src/integrations/pm/trello/manifest.ts — wires TrelloIntegration,
TrelloRouterAdapter, all 7 Trello trigger handlers, TrelloPlatformClient.
verifyWebhookSignature wraps the existing verifyTrelloSignature helper
(HMAC-SHA1 of body+callbackUrl) with header-based URL reconstruction.
- src/integrations/pm/trello/index.ts + src/integrations/pm/index.ts —
side-effect registration barrel imported by router and worker entries.
- src/triggers/builtins.ts — iterates listPMProviders() to register
Trello triggers via the manifest; removed registerTrelloTriggers call.
- src/router/worker-env.ts — Trello branch of extractProjectIdFromJob
deleted; registry path handles it via the manifest's extractor hook.
Frontend:
- web/src/components/projects/pm-providers/types.ts — extended
ProviderWizardDefinition with optional useProviderHooks field. Context
(state, dispatch, projectId, advanceToStep) flows into the provider
hook composer.
- web/src/components/projects/pm-providers/manifest-section.tsx — new
ManifestProviderWizardSection shell component. Only mounted when a
manifest is registered, so the unconditional useProviderHooks call
inside satisfies React's rules-of-hooks.
- web/src/components/projects/pm-providers/trello/wizard.ts —
trelloProviderWizard composes useTrelloDiscovery +
useTrelloLabelCreation + useTrelloCustomFieldCreation inside
useProviderHooks. Three step adapters in adapters.tsx destructure
providerHooks into the existing TrelloCredentialsStep /
TrelloBoardStep / TrelloFieldMappingStep prop shape — step
implementations stay unchanged.
- web/src/components/projects/pm-wizard.tsx — removed Trello-specific
hook instantiations and three per-step `provider === 'trello'`
branches. The top of the component looks up manifestDef = getProviderWizard(state.provider);
when truthy it renders <ManifestProviderWizardSection .../>, else falls
through to the legacy JIRA/Linear branches (they migrate in 006/3/4).
Contract adjustments surfaced during TDD:
- Dropped the redundant parseWebhookPayload field from PMProviderManifest
(had wrong return type in 006/1; duplicated routerAdapter.parseWebhook).
- Relaxed conformance harness's platform-client assertion to the actual
PlatformCommentClient contract (postComment + deleteComment only;
updateComment / postReaction are provider extensions).
- registerTestProvider is additive (no longer resets), so the conformance
harness iterates TestProvider AND every real provider side-by-side.
- Six existing test files gain a side-effect import of
src/integrations/pm/trello/index.js so the Trello manifest is
registered before they exercise Trello-dependent code.
Deferred to plan 006/5 (all documented in the .done plan):
- Removing Trello's registration from src/integrations/bootstrap.ts —
nine-plus call sites of pmRegistry.get('trello') still rely on the
legacy registration.
- Consolidating createTrelloLabel/createTrelloLabels tRPC endpoints into
pm.discovery.createLabel — additive cleanup, not behavior-changing.
Tests: 7755/7755 pass. 15 new Trello manifest tests; conformance harness
now runs 22 assertions (11 × TestProvider + Trello).
Docs: src/integrations/README.md's migration status note updated.
CHANGELOG entry added.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…fig export CI's build:web step failed because web/tsconfig's stricter resolution caught an import of a function that doesn't exist. The legacy path at `useSaveMutation` builds Trello's integration config inline (unlike the already-extracted `buildLinearIntegrationConfig`). Mirroring that inline shape inside `trelloProviderWizard.buildIntegrationConfig` keeps plan 006/2 compatible with the existing save path; plan 006/5 will consolidate `saveMutation` onto `def.buildIntegrationConfig` and extract one shared builder. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…rello feat(006/2): trello migrated onto PM provider manifest
Mirror of 006/2 for JIRA.
Backend:
- src/integrations/pm/jira/manifest.ts — wires JiraIntegration,
JiraRouterAdapter, all 3 JIRA trigger handlers, JiraPlatformClient.
verifyWebhookSignature uses the shared makeHmacSha256Verifier factory
from 006/1 — JIRA is the first consumer since Trello's scheme is
bespoke. Header: 'x-hub-signature' with 'sha256=' prefix, hex.
- src/integrations/pm/jira/index.ts — registers via side effect.
- src/integrations/pm/index.ts — appends the jira barrel import.
- src/triggers/builtins.ts — registerJiraTriggers removed; manifest
iteration handles it.
- src/router/worker-env.ts — jira branch of extractProjectIdFromJob
removed (registry handles it via manifest.extractProjectIdFromJob).
Frontend:
- web/src/components/projects/pm-providers/jira/wizard.ts —
jiraProviderWizard composes useJiraDiscovery +
useJiraCustomFieldCreation inside useProviderHooks. Three step adapters
in adapters.tsx destructure providerHooks into the existing JIRA step
component prop shape — implementations unchanged.
- pm-wizard.tsx — removed useJiraDiscovery +
useJiraCustomFieldCreation + handleCreateJiraCostField +
creatingJiraCostField state. The three per-step render branches
collapse: with both Trello and JIRA on manifest, the non-manifest
fallback is now Linear-only.
Credential roles for JIRA: email + api_token (required) +
webhook_secret (optional). Plan had a drift (claimed base_url was a
credential role) — corrected: base_url is an integration-config field,
not a credential.
Tests: 7782/7782 pass. 16 new JIRA manifest tests. Conformance harness
now runs 33 assertions (11 × TestProvider + Trello + JIRA).
Tests that exercise JIRA-typed jobs (worker-env, container-manager) and
the builtins-triggers mock all picked up with JIRA manifest side-effect
imports.
Same deferrals as 006/2 (documented in .done plan):
- bootstrap.ts JIRA block stays until plan 006/5 migrates pmRegistry.get('jira') callers.
- createJiraCustomField tRPC endpoint kept (additive consolidation).
Docs: README migration status note updated. CHANGELOG entry added.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
feat(006/3): jira migrated onto PM provider manifest
Completes the third and final PM-provider migration of spec 006. All three providers (Trello, JIRA, Linear) are now on the manifest pattern. Backend: - src/integrations/pm/linear/manifest.ts — wires LinearIntegration, LinearRouterAdapter, 3 Linear trigger handlers, LinearPlatformClient. verifyWebhookSignature uses the shared makeHmacSha256Verifier factory with header 'linear-signature' (no prefix). - src/integrations/pm/linear/index.ts — side-effect registration. - src/integrations/pm/index.ts — appends the linear barrel import. - src/triggers/builtins.ts — registerLinearTriggers call gone; every PM provider now contributes triggers via the manifest registry. SCM + alerting stay on legacy per spec scope. - src/router/worker-env.ts — Linear branch of extractProjectIdFromJob removed; the function now has zero PM-specific branches. Shared-helper adoption (collapses divergent copies that caused the session's production incidents): - src/router/platformClients/linear.ts — switched to linearAuthHeader from _shared/auth-headers. In-file Authorization construction deleted. - src/router/bot-identity-resolvers.ts — same adoption. - src/pm/linear/adapter.ts::resolveLabelId — delegates to _shared/label-id-resolver. Private helper + UUID_PATTERN constant deleted. Single source of truth for the UUID-validation rule. Frontend: - web/src/components/projects/pm-providers/linear/wizard.ts — linearProviderWizard composes useLinearDiscovery + useLinearLabelCreation inside useProviderHooks, plus the creatingSlot state + onCreateLabel / onCreateAllMissingLabels handlers using LINEAR_LABEL_DEFAULTS. - web/src/components/projects/pm-wizard.tsx — with all 3 providers on the manifest, the non-manifest fallback path is deleted entirely. Every PM provider renders via ManifestProviderWizardSection. The parent wizard no longer owns provider-specific hooks, state, or handlers. Tests: 7808/7808 pass. 15 new Linear manifest tests. Conformance harness runs 44 assertions (11 × TestProvider + Trello + JIRA + Linear). Build (backend + web), typecheck, lint all clean. Same deferrals as 006/2 and 006/3 (documented in .done plan): - bootstrap.ts Linear block stays until plan 006/5 migrates the ~dozen pmRegistry.get(...) callers. - createLinearLabel / createLinearLabels tRPC endpoints kept (additive consolidation only, not behavior-changing). Docs: README migration status updated. CHANGELOG entry added. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…inear feat(006/4): linear migrated — all PM providers now on manifest
Closes plan 006/5 — the final cleanup plan of spec 006. Backend: - src/integrations/bootstrap.ts — DELETED. PM registrations flow through src/integrations/pm/index.ts (which also mirrors manifests into integrationRegistry). SCM (GitHub) and alerting (Sentry) self-register via new side-effect modules. - src/github/register.ts + src/sentry/register.ts — new minimal side-effect modules that replace the respective branches of the deleted bootstrap. SCM + alerting stay on the legacy IntegrationModule pattern (out of spec 006 scope). - src/pm/registry.ts — converted to a read-only adapter over pmProviderRegistry. get/getOrNull/all/createProvider/ resolveLifecycleConfig all delegate to the manifest registry. register() is a deprecation warn. The ~9 unmigrated call sites (webhook handlers, manual runner, credential scope, lifecycle, GitHub adapter) keep working unchanged — they now transparently read from the manifest registry, so there is no divergent registration. - src/router/index.ts + src/worker-entry.ts — updated to import the three new side-effect modules instead of the deleted bootstrap. - src/integrations/registry.ts — header comment updated to reflect the new population topology. Tests: - tests/unit/integrations/bootstrap.test.ts — rewritten to cover the new side-effect-module wiring (the file name stays for audit clarity; its content asserts the same end-state invariants). - 8 other test files that imported bootstrap.js for side effect are migrated to import the three new modules (pm barrel + github/register + sentry/register). Docs: - src/integrations/README.md — rewritten. Transitional note + "Legacy path" section removed. The README is now the single canonical author's guide for adding a new PM provider. - CLAUDE.md — integration-abstraction pointer updated to final state. - CHANGELOG.md — entry per plan. Plan-divergence: - AC #2 (delete pm/registry.ts) — became: convert to a read-only delegate. Deleting it would require migrating 9 call sites that are out of spec scope. The delegate preserves the end state (single source of truth = pmProviderRegistry) without downstream churn. - AC #5 (consolidate createXxxLabel tRPC endpoints) — deferred to a follow-up PR. Purely additive cleanup; not required for any spec AC. Both divergences documented in the .done plan. Tests: 7809/7809 pass. Build + lint + typecheck clean. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
All 5 plans of spec 006 (pm-integration-plug-and-play) have landed: - 006/1 infrastructure — manifest contract + registry + conformance harness + shared helpers + generic wizard renderer - 006/2 migrate-trello - 006/3 migrate-jira - 006/4 migrate-linear — completes all 3 PM providers + shared-helper adoption (canonical auth headers + label resolver; divergent copies deleted) - 006/5 cleanup-legacy — bootstrap.ts deleted; pmRegistry becomes a delegate; README rewritten as canonical author's guide Outcome-level ACs of the spec all satisfied: - A new PM provider is added by creating one backend folder + one frontend folder. No edits to shared registries, router routes, wizard routing, trigger dispatch, or job extractors. - Conformance harness iterates every registered manifest (44 tests across TestProvider + Trello + JIRA + Linear) and fails CI on any missing contract surface. - Trello, JIRA, Linear continue to work identically — operators see no change. - Divergent cross-cutting copies (Bearer-prefix auth, UUID-vs-name label resolver, forgotten job-id extractor branch) are physically impossible now — shared helpers are the sole call sites. - Wizard adapts entirely from the manifest registry. - Each migration shipped independently and is independently revertable. - src/integrations/README.md rewritten as the single canonical guide. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…egacy feat(006/5): cleanup legacy — spec 006 complete
Spec 002's two plans landed on dev as 1-save-path-fix.md.done and 2-wizard-webhooks-step.md.done but the spec file itself was never renamed. Closing the loop opportunistically. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…_yarn/hono-4.12.14 chore(deps): bump hono from 4.12.12 to 4.12.14
…1130) When the implementation pipeline (PM-triggered) opens a PR, the GitHub pr-opened webhook fires immediately and queues a review pipeline. The review pipeline captures workItemId synchronously from a DB lookup that returns null (the implementation hasn't yet linked the PR), then later writes that stale null back to pr_work_items, clobbering the correct work_item_id the implementation wrote in between. Effect: lookupWorkItemForPR returns null for the PR, the pr-ready-to-merge trigger bails with "No work item linked to PR", and PRs flagged with `auto` on Linear never auto-merge. Affected every recent llmist PR (15 in a row); Trello/JIRA-backed projects appear unaffected so far but share the racing pipeline code path. Three intersecting fixes, all narrow: - linkPRToWorkItem Step 2 ON CONFLICT now uses COALESCE(EXCLUDED.work_item_id, pr_work_items.work_item_id) so work_item_id is one-way set — a later writer with null can't erase a known link. - linkPRToWorkItem Step 1 deletes any racing orphan (projectId, NULL workItemId, prNumber) row before promoting the work-item-only row, preventing the partial-unique-index violation the implementation otherwise hits silently. - runAgentExecutionPipeline re-resolves workItemId via the existing resolveWorkItemId helper at run time and patches agentInput so the corrected value flows into runAgent (and into agent_runs.work_item_id), not just into the post-execution link. Tests: +2 integration (preservation, orphan cleanup), +5 unit (re-resolution paths + delete/no-delete coverage). All 7814 unit and 524 integration tests pass. Drive-by cleanups so lint+typecheck are clean: drop unused `renderManifestStep` import in pm-wizard.tsx, rename a pm-conformance describe string that triggered noTemplateCurlyInString. Out of scope: backfilling the 15 broken historical llmist rows (separate manual SQL), no PR-body-parsing fallback in resolveWorkItemId, no rewrite of how PROpenedTrigger captures workItemId. Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…ine lists (#1131) After spec 006/5 ("delete legacy bootstrap; pmRegistry becomes a delegate") landed, two paths that the worker container relies on broke for Linear: 1. `cascade-tools` CLI ran with an empty PM registry. Spec 006/5 removed the only path that previously self-bootstrapped on registry access. Router (src/router/index.ts:8) and worker (src/worker-entry.ts:19) were updated to import the integrations barrel explicitly, but the CLI's lazy oclif command loader was missed. Result: every `cascade-tools pm <cmd>` call from inside an agent run threw `Unknown PM integration type: 'linear'. Registered:` (empty), failing every backlog-manager chain that tries to enumerate work items. 2. `buildPipelineLists` in src/agents/definitions/contextSteps.ts only read Trello (`lists`) and JIRA (`statuses`) configs. Linear projects exposed `statuses` in their config (identical shape to JIRA's), but the function never called `getLinearConfig`. Result: every Linear project's `fetchPipelineSnapshotStep` logged `No pipeline lists configured, skipping` and returned `[]`, so the backlog-manager prompt never received the pipeline snapshot it expected. Combined effect: after PR #1130 landed (auto-merge link preservation), the chained backlog-manager fired correctly on llmist (Linear-backed) but bailed without picking up a next card. Fix 1 — `src/cli/bootstrap.ts` (NEW): three side-effect imports that register every provider manifest. Loaded from `bin/cascade-tools.js` (the CLI entry script) before `Config.load`, mirroring the router/worker bootstrap pattern. Routing through `bin/cascade-tools.js` rather than `src/cli/base.ts` intentionally — `cli/base.ts` is transitively imported by gadgets that some integration tests pull in, and prepending the bootstrap there made `tests/integration/trigger-registry.test.ts` fail with a circular-import symptom (`new ReadyToProcessLabelTrigger()` from `trello/manifest.ts` threw "is not a constructor"). Loading from the binary keeps the side-effect off any test path. Fix 2 — extend `buildPipelineLists` to also call `getLinearConfig` and chain `?? linearConfig?.statuses?.X` onto each `addList` call. JIRA and Linear share the `Record<string, string>` `statuses` shape, so the existing nullish-coalescing pattern extends naturally. No behavior change for Trello/JIRA. Tests: tests/unit/cli/bootstrap.test.ts (NEW) asserts `listPMProviders()` returns `['linear', 'jira', 'trello']` after importing the bootstrap module. Extended pipelineSnapshot.test.ts with a Linear fixture asserting all 6 list IDs are passed to `provider.listWorkItems`. All 7816 unit + 524 integration tests pass. Out of scope: re-running the failed MNG-94 backlog-manager (it reported success — just found nothing actionable). Worker container image will pick up the fix on the next deploy via dist/cli/bootstrap.js (verified present after `npm run build`). Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…artup (#1132) The router's [SnapshotCleanup] loop has been a sham since it shipped: evictSnapshots() removes entries from an in-memory Map and that's it. No docker rmi anywhere in the codebase (verified — whole-source grep returns zero matches). The Map dies on every router restart, so every snapshot image for a work item that never re-runs is orphaned forever. Symptom that surfaced: dev disk filled to 100% (50MB free of 436GB), with 13 cascade-snapshot-llmist-* images on disk totaling ~40GB. Six of those dated to March 25 — three weeks past the 24-hour TTL the "cleanup" loop had been pretending to enforce. Also: snapshotMaxSizeBytes (10GB) eviction has never fired because no caller passed imageSizeBytes to registerSnapshot — container-manager:91 called it with three args, leaving size at 0 in the Map so the size phase always thought the registry was empty. Three narrow fixes that together make the configured TTL/max-count/ max-size limits actually mean something on disk: 1. evictSnapshots now returns the array of evicted SnapshotMetadata instead of a count. snapshot-cleanup.runSnapshotCleanup() iterates that list and calls docker.getImage(name).remove({ force: false }). `force: false` so an in-use image survives (Docker returns 409 — we swallow it). 404 means already gone — also swallowed. Anything else logs warn + sentry capture. 2. New snapshot-startup-sync module: on router boot, list every cascade-snapshot-* image via docker.listImages, register each as a "discovered" entry in the in-memory Map (synthetic project key `__discovered__` to avoid colliding with real registrations), then immediately runSnapshotCleanup so TTL/max-count/max-size apply right away. Wired from worker-manager.startWorkerProcessor() as a best-effort post-startup step. This is what would have caught the six March images after the post-Linear-migration router restart. 3. commitContainerToSnapshot now inspects the freshly committed image and passes Size to registerSnapshot, so the max-size eviction phase actually has data to work with. Inspect failures don't block the registration — they just leave imageSizeBytes undefined, which falls back to TTL/max-count enforcement. Tests: extended snapshot-manager.test.ts (return-type change + new registerDiscoveredSnapshot dedup tests), rewrote snapshot-cleanup.test.ts to mock dockerode and assert image.remove + 409/404 swallow + sentry on unexpected error, added snapshot-startup-sync.test.ts (NEW), updated snapshot-integration.test.ts to expect the size 4th arg on registerSnapshot. All 7830 unit + 524 integration tests pass. Out of scope: backfilling the 40GB on disk (cleaned manually with docker prune; the next router restart will keep on-disk state under SNAPSHOT_MAX_COUNT/SNAPSHOT_MAX_SIZE_BYTES going forward). The 119GB build cache hoarding is a separate operational concern (BuildKit GC config, not a Cascade-level bug). Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…cards (#1133) Backlog-manager for Linear-backed projects (e.g. llmist) saw BACKLOG as empty even when items existed (MNG-97 confirmed in backlog). Tracing the chained backlog-manager run for MNG-96/PR-571 confirmed: ``` ## Pipeline Check **Active pipeline count:** 0 (TODO: 0, IN_PROGRESS: 0, IN_REVIEW: 0) The pipeline has capacity (0 < 1), but the BACKLOG is empty ``` Root cause: `PMProvider.listWorkItems(containerId, filter?)` had incompatible per-provider semantics for `containerId`: - Trello: containerId = list ID directly → works (lists ARE statuses) - JIRA: containerId = project key, status filter via `filter.status` → passing a status name as containerId returned 0 from JQL - Linear: containerId = team ID, status filter via `filter.status` → passing a state UUID as containerId queried `listIssues({ teamId: <state-uuid> })` → returned 0 The snapshot loader (`contextSteps.fetchPipelineLists`) called `provider.listWorkItems(list.id)` where `list.id` was a status identifier — silently returning [] for both JIRA and Linear since the day PR #1131 made `buildPipelineLists` populate Linear statuses. This commit unifies the abstraction: - `PMProvider.listWorkItems(containerId: string | undefined, filter?)` — containerId becomes optional. Each provider self-resolves the natural scope from its own config when omitted: Trello uses `config.lists[filter.status]`, JIRA defaults to `config.projectKey`, Linear defaults to `config.teamId`. The `filter.status` is the CASCADE-canonical key (`'backlog'`, `'todo'`, ...), mapped to the provider's native identifier internally. - `contextSteps.fetchPipelineLists` calls `provider.listWorkItems(undefined, { status: list.statusKey })` — one code path for all 3 providers. - `PipelineList` shape: `{ name, statusKey }` (dropped the dead `id` field). Snapshot output now shows `## BACKLOG (status: backlog)` instead of `(list ID: <UUID>)` — the agent uses CASCADE keys with `move-work-item`, not the underlying provider IDs. - `backlog-check.ts:isPipelineAtCapacity` collapsed Trello/JIRA dispatch into one unified path (~50 lines deleted). Now also works for Linear without code change. The per-provider knowledge survives only in `isProviderMisconfigured`, which preserves the pre-existing conservative behaviour: when a project's config is incomplete, return `'misconfigured'` (caller runs the agent anyway) rather than silently treating it as `'backlog-empty'` (which would skip the agent run). `isProviderMisconfigured` uses an exhaustive `switch` over `PMType` with `assertNeverPMType(provider.type)` in the default branch — TypeScript fails the build when a 4th `PMType` member is added without updating the switch. - `agent-execution.ts:propagateAutoLabelAfterSplitting` similarly collapsed (~25 lines deleted). - `TrelloPMProvider` constructor now takes `TrelloConfig` (was optional before this change made it useful). The CLI's `CredentialScopedCommand` synthesizes a minimal Trello shell with no `trello` field for gadget-scope purposes; `TrelloIntegration. createProvider` falls back to an empty config in that case so the adapter still constructs cleanly (the CLI's gadget callers always pass containerId explicitly, so self-resolution is never exercised on this path). Tests added/updated: - `tests/unit/pm/{trello,jira,linear}-adapter.test.ts` — 10 new tests for self-resolution from each provider's config + backwards-compat fallback for explicit containerId. - `tests/unit/agents/definitions/pipelineSnapshot.test.ts` — updated to assert unified call shape; updated `list ID:` → `status:` in output assertions. - `tests/unit/triggers/shared/backlog-check.test.ts` — dropped the `STATUS_KEY_BY_FIXTURE` translation shim, rewrote 27 fixture keys to CASCADE form (so test fixtures correctly say what they ARE), added 5 Linear-specific tests, replaced unsupported-provider test with `.rejects.toThrow(/Unhandled PMType/)` exhaustiveness check. - `tests/helpers/factories.ts` — new `createMockLinearProject` next to the existing Trello/JIRA factories. - `tests/unit/triggers/agent-execution.test.ts` and `tests/unit/ triggers/shared/agent-execution.test.ts` — updated 5 assertions to use the unified call shape; replaced `mockResolvedValue` with per-status `mockImplementation` so capacity checks see empty in-flight statuses correctly. 7845 unit + 524 integration tests pass. lint+typecheck+build clean. Out of scope: the CLI gadget (`cascade-tools pm list-work-items --containerId X`) keeps its existing explicit-containerId form; backfilling MNG-97 manually (next chained backlog-manager will see it after this lands). Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…near projects (#1134) The splitting agent for MNG-98 on llmist (Linear-backed) ran today. Every `cascade-tools pm <cmd>` call from inside the worker container threw: ``` Error: Linear integration requires teamId in config at LinearIntegration.createProvider (file:///app/dist/pm/linear/integration.js:65) ``` The agent fell back to direct Linear API calls and got the work done, but the CLI gadget path was broken for every Linear-backed project. Three combined causes: 1. `src/cli/base.ts` cast `process.env.CASCADE_PM_TYPE` as `'trello' | 'jira' | undefined` — but `secretBuilder.ts` injects the actual `project.pm.type`, so `'linear'` was arriving unboxed at runtime. 2. The `pmProject` synthesis only had a JIRA conditional spread; for `pmType === 'linear'` it produced `{ pm: { type: 'linear' } }` with no `linear` field. `LinearIntegration.createProvider` then read `getLinearConfig(project)` → undefined → threw. 3. Even after the synthesis was fixed, no `withLinearCredentials` wrap meant gadgets calling Linear API would fail with "No Linear credentials in scope". Lines 44-58 wrapped GitHub/Trello/JIRA but not Linear. And on the worker-spawn side, `secretBuilder.ts:46-53` injected `CASCADE_JIRA_*` env vars from `getJiraConfig(project)` but had no Linear equivalent — so even if the CLI tried to read them, they wouldn't be there. This is the third generation of the same architectural omission: the CLI was Trello/JIRA-aware long before Linear existed (spec 006). PR #1131 unblocked the registry (cascade-tools commands actually load), PR #1133 tightened provider validation — both made the latent bug louder. Now LinearIntegration throws cleanly when it has no teamId, and that throw surfaces here. Fix mirrors the JIRA pattern end-to-end: - `src/backends/secretBuilder.ts` — when `getLinearConfig(project)` is truthy, inject `CASCADE_LINEAR_TEAM_ID`, optional `CASCADE_LINEAR_PROJECT_ID`, and `CASCADE_LINEAR_STATUSES` into the worker's env. Mirrors the JIRA injection block. - `src/cli/base.ts`: - Replace the `'trello' | 'jira' | undefined` type lie with `PMType | undefined` (canonical type already exists in `src/pm/types.ts:6`), so future provider additions can't reintroduce this footgun. - Add a `withLinearCredentials` wrap when `LINEAR_API_KEY` is set, mirroring the GitHub/Trello/JIRA wrap pattern. - Add a Linear-config synthesis branch, reading `CASCADE_LINEAR_TEAM_ID`/`PROJECT_ID`/`STATUSES`. - Add `LINEAR_API_KEY`-based pmType inference as a fallback when `CASCADE_PM_TYPE` isn't set (mirrors the JIRA-baseUrl inference). Worker-spawned use is unaffected because `secretBuilder` always sets `CASCADE_PM_TYPE` explicitly; this just helps human-invoked CLI use. - Refactor `run()` into three small helpers (`wrapWithCredentialScopes`, `resolvePmType`, `synthesizeProjectFromEnv`) to keep cognitive complexity inside biome's threshold. Tests: +3 secretBuilder Linear-injection tests, +3 credential-scoping Linear tests (withLinearCredentials wrap, populated linear synthesis, LINEAR_API_KEY-based inference). 7851 unit + 524 integration tests pass. Lint + typecheck + build clean. Out of scope: - Refactoring CLI to load full project config from DB instead of synthesising from env vars. Bigger change; env-var pattern works for JIRA and is the established convention. - `--linear-team-id` flag override. Worker-injected env vars suffice. - Backfilling MNG-98 splitting outputs (agent created them via direct Linear API; they're correct). Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…ook (#1136) * docs(007): spec + plans for robust review dispatch Spec 007 addresses the silent review drop observed on MNG-122/PR-572: the work-item lock's total-concurrency cap (MAX_WORK_ITEM_CONCURRENCY=2) blocked review dispatch while other agents were enqueued for the same work item. Three intersecting fixes specified: per-agent-type locking, lock release timing, and a post-completion review hook. Two plans: - 007/1 (lock-infra): remove MAX_WORK_ITEM_CONCURRENCY total cap, keep per-type MAX_SAME_TYPE_PER_WORK_ITEM=1, enrich lock-skip log. - 007/2 (post-completion-review): deterministic review dispatch from the implementation pipeline after success + green CI. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * chore(007): lock plan 007/1 as .wip * feat(007/1): per-agent-type work-item lock — remove false cross-type serialization Removes the MAX_WORK_ITEM_CONCURRENCY total cap from isWorkItemLocked. The total cap falsely serialized unrelated agent types: the review for MNG-122/PR-572 was silently dropped because 2 agents (implementation + backlog-manager) were already enqueued for the same work item, hitting the total limit of 2. Now only MAX_SAME_TYPE_PER_WORK_ITEM = 1 is enforced. Different agent types can run concurrently on the same work item (e.g. review starts while implementation's container is still cleaning up). Same-type duplicate prevention is preserved. Changes: - src/router/work-item-lock.ts — deleted MAX_WORK_ITEM_CONCURRENCY constant and the total-count checks (in-memory + DB). Simplified getInMemoryCounts → getInMemorySameTypeCount (no longer iterates all keys). Removed the dbTotal query (saves one DB round-trip per lock check). Deleted the unused keyPrefix helper. - src/router/webhook-processor.ts — enriched the lock-skip log with source (adapter type) and renamed agentType → blockedAgentType for clarity. - CLAUDE.md — added per-agent-type lock semantics note under "Agent triggers". Tests: updated 6 existing tests + added 2 new cross-type concurrency tests. All 7852 unit tests pass. Lint + typecheck clean. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * chore(007): lock plan 007/2 as .wip * feat(007/2): post-completion review dispatch — deterministic review after implementation When an implementation agent succeeds with a PR, the execution pipeline now checks CI status and fires the review agent before the container exits. This guarantees review dispatch within seconds of implementation completion, regardless of GitHub webhook timing. Uses the same recursive `runAgentExecutionPipeline` pattern as the splitting → backlog-manager chain. The review runs in the same container, same credential scope. Uses `claimReviewDispatch` with the same dedup key format as the `check-suite-success` trigger, so the two paths cannot double-enqueue. The hook is best-effort: GitHub API failures, Redis errors, or any exception is caught, logged as warn, and does NOT break the implementation pipeline. New function `tryDispatchPostCompletionReview` in agent-execution.ts: 1. Extracts prNumber from agentResult.prUrl 2. Fetches PR details (headSha, headRef) from GitHub 3. Checks CI status via getCheckSuiteStatus — if not allPassing, returns (check-suite-success webhook will handle it when CI finishes) 4. Claims the dedup key via claimReviewDispatch — if already claimed, returns (review was already dispatched by the webhook path) 5. Builds a review TriggerResult and calls runAgentExecutionPipeline recursively (same pattern as splitting → backlog-manager) Tests: +7 new tests covering: fires review on success + green CI, skips for non-implementation, skips on failure, skips when no prUrl, skips when CI not green, skips when already dispatched, swallows errors gracefully. All 7859 unit tests pass. Lint + typecheck clean. CLAUDE.md updated with post-completion review dispatch documentation. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * docs(007): spec complete — all plans done * chore(deps): update protobufjs to fix critical CVE npm audit flagged protobufjs <7.5.5 for arbitrary code execution (GHSA-xq3m-2v4x-88gg). Updated via `npm update protobufjs` — lockfile only, no package.json change. 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(007): spec + plans for robust review dispatch
Spec 007 addresses the silent review drop observed on MNG-122/PR-572:
the work-item lock's total-concurrency cap (MAX_WORK_ITEM_CONCURRENCY=2)
blocked review dispatch while other agents were enqueued for the same
work item. Three intersecting fixes specified: per-agent-type locking,
lock release timing, and a post-completion review hook.
Two plans:
- 007/1 (lock-infra): remove MAX_WORK_ITEM_CONCURRENCY total cap,
keep per-type MAX_SAME_TYPE_PER_WORK_ITEM=1, enrich lock-skip log.
- 007/2 (post-completion-review): deterministic review dispatch from
the implementation pipeline after success + green CI.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* chore(007): lock plan 007/1 as .wip
* feat(007/1): per-agent-type work-item lock — remove false cross-type serialization
Removes the MAX_WORK_ITEM_CONCURRENCY total cap from isWorkItemLocked.
The total cap falsely serialized unrelated agent types: the review for
MNG-122/PR-572 was silently dropped because 2 agents (implementation +
backlog-manager) were already enqueued for the same work item, hitting
the total limit of 2.
Now only MAX_SAME_TYPE_PER_WORK_ITEM = 1 is enforced. Different agent
types can run concurrently on the same work item (e.g. review starts
while implementation's container is still cleaning up). Same-type
duplicate prevention is preserved.
Changes:
- src/router/work-item-lock.ts — deleted MAX_WORK_ITEM_CONCURRENCY
constant and the total-count checks (in-memory + DB). Simplified
getInMemoryCounts → getInMemorySameTypeCount (no longer iterates all
keys). Removed the dbTotal query (saves one DB round-trip per lock
check). Deleted the unused keyPrefix helper.
- src/router/webhook-processor.ts — enriched the lock-skip log with
source (adapter type) and renamed agentType → blockedAgentType for
clarity.
- CLAUDE.md — added per-agent-type lock semantics note under "Agent
triggers".
Tests: updated 6 existing tests + added 2 new cross-type concurrency
tests. All 7852 unit tests pass. Lint + typecheck clean.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* chore(007): lock plan 007/2 as .wip
* feat(007/2): post-completion review dispatch — deterministic review after implementation
When an implementation agent succeeds with a PR, the execution pipeline
now checks CI status and fires the review agent before the container
exits. This guarantees review dispatch within seconds of implementation
completion, regardless of GitHub webhook timing.
Uses the same recursive `runAgentExecutionPipeline` pattern as the
splitting → backlog-manager chain. The review runs in the same container,
same credential scope. Uses `claimReviewDispatch` with the same dedup key
format as the `check-suite-success` trigger, so the two paths cannot
double-enqueue.
The hook is best-effort: GitHub API failures, Redis errors, or any
exception is caught, logged as warn, and does NOT break the
implementation pipeline.
New function `tryDispatchPostCompletionReview` in agent-execution.ts:
1. Extracts prNumber from agentResult.prUrl
2. Fetches PR details (headSha, headRef) from GitHub
3. Checks CI status via getCheckSuiteStatus — if not allPassing, returns
(check-suite-success webhook will handle it when CI finishes)
4. Claims the dedup key via claimReviewDispatch — if already claimed,
returns (review was already dispatched by the webhook path)
5. Builds a review TriggerResult and calls runAgentExecutionPipeline
recursively (same pattern as splitting → backlog-manager)
Tests: +7 new tests covering: fires review on success + green CI, skips
for non-implementation, skips on failure, skips when no prUrl, skips when
CI not green, skips when already dispatched, swallows errors gracefully.
All 7859 unit tests pass. Lint + typecheck clean.
CLAUDE.md updated with post-completion review dispatch documentation.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* docs(007): spec complete — all plans done
* fix(linear): create issues directly in backlog state via stateId
Linear's createIssue API supports stateId, but the adapter was creating
issues in the team's default state ("Ideas") then attempting a separate
moveWorkItem transition — which silently failed. Additionally, the
splitting agent's prompt context provided the backlog status UUID as
containerId, causing "Entity not found: Team" errors and wasting ~15
LLM iterations per run.
- Pass stateId to linearClient.createIssue() for atomic backlog placement
- Remove fragile post-creation moveWorkItem transition (13 LOC of
error-swallowing code)
- Fix promptContext to provide teamId (not status UUID) as backlogListId
for Linear, matching what CreateWorkItem expects as containerId
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The configMapper.ts dropped projectId when mapping Linear integration config from the DB to ProjectConfig. The JSON in project_integrations had projectId, but buildLinearConfig() only copied teamId, statuses, labels, and customFields — never projectId. This broke every downstream consumer: worker env injection (CASCADE_LINEAR_PROJECT_ID never set), createWorkItem/listWorkItems/ addChecklistItem (issues created without project scope), and the router's webhook scope filter (never applied). Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
addChecklistItem() created sub-issues via linearClient.createIssue()
without stateId, so they landed in the team's default state ("Ideas")
instead of "Backlog". Same bug as createWorkItem() (fixed in #1137),
different code path.
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* chore(008): lock plan 008/1 as .wip Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * feat(008/1): shared inline markdown checklist engine Pure string transformer for reading, writing, and mutating inline markdown checklists within issue descriptions. Supports parsing, appending, adding items, toggling checked state, removing items, and stable content-hash IDs. Dormant — no adapter wiring yet (plan 2). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * chore(008): lock plan 008/2 as .wip Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * feat(008/2): inline markdown checklists for Linear and JIRA Replaces sub-issue/subtask checklist implementation with inline markdown checkboxes appended to the parent issue's description. Linear writes plain markdown; JIRA round-trips through ADF. Both adapters use the shared engine from plan 1. PMProvider interface unchanged. Read-modify-write with one retry on conflict. Trello unchanged (uses native checklists). Closes spec 008. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * docs(008): spec complete — all plans done Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * chore(008): cleanup — gitignore lock file and refactor parser Untrack .claude/scheduled_tasks.lock (committed by accident); add to gitignore. Refactor parseInlineChecklists to extract state-handling helper, removing the cognitive complexity warning. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…n a triggering status - Extend LinearStatusChangedTrigger.matches() to also match action: 'create' events - Extend JiraStatusChangedTrigger to match and handle jira:issue_created events - Update Linear and JIRA unit tests to cover creation scenarios Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
JIRA_EMAIL/JIRA_API_TOKEN/JIRA_BASE_URL were set in the CI/dev environment causing resolvePmType() to return 'jira' instead of 'trello' for tests that don't set CASCADE_PM_TYPE, leading to createPMProvider failing with "JIRA integration requires projectKey". Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ng it (#1142) PR #1138 added projectId to the configMapper, but Zod's LinearConfigSchema didn't declare projectId — and z.object() defaults to "strip" mode, silently removing unknown keys during .parse(). So projectId survived the mapper but got dropped by validateConfig(), never reaching augmentProjectSecrets() or the LinearPMProvider. Result: new Linear issues created by splitting / planning agents had no project assignment despite the configMapper fix. Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Spec 009 turns the PMProviderManifest contract from wiring-only to behavioral. Decomposes into 5 plans: infra + 3 provider migrations + cleanup, mirroring spec 006's proven shape. Co-Authored-By: Claude Opus 4 (1M context) <noreply@anthropic.com>
Task 1: Branded StateId, LabelId, ContainerId + parsers + InvalidIdError.
Task 2: Extend PMProvider with optional discover? method + associated
DiscoveryCapability / DiscoveryArgs / DiscoveryResult machinery.
Task 3: Extend PMProviderManifest with optional configSchema,
discoveryCapabilities, wizardSpec, and lifecycle fields +
validateManifestAgainstSchema helper.
Plan divergence note: plan 1's claim that switching the PMProvider method
signatures from string to branded types was non-breaking is incorrect —
branded types are NOT assignable from plain strings. Resolved by keeping
PMProvider method signatures as string at the interface level and
deferring per-adapter narrowing to plans 2/3/4, which matches both plan 1's
"dormant" intent and plans 2/3/4's per-adapter adoption ACs.
All new fields are optional → existing manifests compile unchanged. 44
existing pm-conformance tests still pass.
Co-Authored-By: Claude Opus 4 (1M context) <noreply@anthropic.com>
Task 4: src/integrations/entrypoint.ts centralises every PM/SCM/alerting registration barrel. Router, worker, CLI bootstrap, and dashboard all side-effect-import this single file — no per-surface list of imports that can drift when a new provider is added. Previously dashboard.ts didn't register any PM providers at all, which is also fixed here. Task 5: tests/unit/integrations/entrypoint-usage.test.ts grep-asserts the invariant that every process entry file imports src/integrations/entrypoint.js. Missing this import was the root cause of #1097, #1118, #1131, #1134 — the test references those bug numbers in its failure message. Co-Authored-By: Claude Opus 4 (1M context) <noreply@anthropic.com>
Task 6: tests/helpers/fakePMProvider.ts ships an in-memory FakePMProvider, its matching PMProviderManifest (opts into configSchema, every discoveryCapability, wizardSpec, lifecycle.enabled), and a shared runLifecycleScenario runner. All seven fake-lifecycle tests pass. Task 7: tests/unit/integrations/pm-conformance.test.ts extended with 5 new behavioral assertion groups: - config round-trip identity (guarded by manifest.configSchema) - discovery shape (guarded by manifest.discoveryCapabilities) - full lifecycle scenario (guarded by manifest.lifecycle.enabled) - trigger self-hook filter (guarded by manifest.isSelfAuthoredHook) - webhook verify accept/reject (runs against the fake's HMAC-SHA256) Legacy providers skip the new groups until they opt in during plans 2/3/4. Harness now runs 80 tests (59 pass, 21 skip — the skips are legacy providers pending migration, as designed). Co-Authored-By: Claude Opus 4 (1M context) <noreply@anthropic.com>
Task 8: tests/unit/integrations/auth-header-provenance.test.ts greps the
src tree for `Bearer ${...}` / bare string-concat auth-header patterns
outside src/integrations/pm/_shared/auth-headers.ts. Post-#1119, the PM
provider code is clean; 4 non-PM files (Sentry, GitHub SCM, OpenRouter
LLM) are explicitly accept-listed with reasons — all out of spec 009
scope.
Task 9: Biome can't natively express the required string-pattern rule,
so lefthook.yml runs the provenance test at pre-commit (~250ms) —
failures surface at commit time, not just test time. Equivalent to a
custom Biome rule; matches plan 009/1 task 9's fallback guidance.
Also tightened the expanded conformance harness + fake-lifecycle test
to eliminate Biome complexity/non-null-assertion warnings.
Co-Authored-By: Claude Opus 4 (1M context) <noreply@anthropic.com>
Task 10: src/api/routers/pm-discovery.ts now exposes a generic
`discover({ providerId, capability, args, credentials? })` mutation that
dispatches through the registry. Manifest must declare both
`discoveryCapabilities` and `createDiscoveryProvider`. Returns NOT_FOUND
for unknown providers, NOT_IMPLEMENTED for undeclared capabilities or
missing factories. 7 tests pass.
Task 11: web/src/components/projects/pm-providers/generator.tsx ships
`renderStandardStep(step, ctx)` as dormant scaffolding — returns a
typed placeholder for every StandardStepKind + custom steps. Plans 2/3/4
swap each placeholder for the shared component. Unknown kinds log a
warn-once and render a placeholder instead of crashing.
Task 12: tests/README.md and src/integrations/README.md document the
new fake provider fixture, the lifecycle scenario runner, the behavioral
contract fields on PMProviderManifest, the auth-header provenance test,
and the single-entrypoint invariant.
Co-Authored-By: Claude Opus 4 (1M context) <noreply@anthropic.com>
Ships branded ID types, PMProviderManifest behavioral contract fields, single registration entrypoint, FakePMProvider fixture + lifecycle runner, 5 new behavioral conformance groups, auth-header provenance enforcement, generic pm.discover tRPC endpoint, and wizard step generator scaffolding. All primitives dormant — no provider migrated yet. Plans 2/3/4 flip each real provider on; plan 5 cleans up legacy surfaces. 415 test files / 7963 tests pass / 21 intentional skips. Lint, typecheck, and build all green. Co-Authored-By: Claude Opus 4 (1M context) <noreply@anthropic.com>
Trello opts into configSchema, discoveryCapabilities, wizardSpec, lifecycle, createDiscoveryProvider, and branded-ID narrowing on adapter methods. Inline trello schema in src/config/schema.ts marked @deprecated; plan 5 deletes it. 420 test files, 7988 pass, 19 skip. Lint + typecheck + build green. Plan divergence notes in the .done file document 5 resolved issues. Co-Authored-By: Claude Opus 4 (1M context) <noreply@anthropic.com>
spec 009: PM integration hardening — make the next provider boring
…s-created-status feat(triggers): support PM triggers for work items created directly in a triggering status
Make the create-path firing (added by PR #1141) independently configurable per agent via the existing declarative YAML/CLI/dashboard pipeline. Two boolean params on pm:status-changed: - onMove (default true) — fire when an item is moved into the status - onCreate (default false) — fire when an item is created in the status Linear and JIRA: preserve pre-#1141 behavior by default; users opt in explicitly. Trello: data migration backfills onCreate=true for existing projects so fire-on-create keeps working without silent regression. Also tightens create-path matches() to require status presence, restores fromStatus in JIRA update-path log, de-dups the JIRA test helper's ternary, and extracts resolveAgentType/shouldFireOnEvent helpers to keep handler complexity in check. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…changed-onCreate-onMove-params feat(triggers): onCreate/onMove params for pm:status-changed
Codecov Report❌ Patch coverage is 📢 Thoughts on this report? Let us know! |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Automated release PR created by the release workflow.
Commits (58):