chore: release - merge dev into main - #1547
Merged
Merged
Conversation
GHSA-5p4m-2wfm-xmqj — quadratic CPU consumption resolving !!omap. The advisory covers 4.0.0 through 4.3.0 inclusive, so the pinned 4.3.0 was affected. This was the only HIGH-severity finding in the production tree, so it alone tripped the `npm audit --omit=dev --audit-level=high` gate in ci.yml and failed lint-and-test on every PR. Because that step runs before "Run tests with coverage", the coverage upload was skipped too and codecov/patch failed as a side effect. Both llmist and @llmist/cli declare js-yaml ^4.1.0, so 4.3.1 dedupes to a single copy. The declared range moves to ^4.3.1 so a fresh install cannot resolve back to the vulnerable version.
Spec 024 plan 1 of 5. Ships the dormant foundation for shared board/repo topologies — projects as board x repo pairs rather than board = repo = project. Two directions are unblocked by this groundwork: - Two projects sharing one JIRA project key, where the second silently never received events (first-match on projectKey). - Two projects sharing one GitHub repo, which failed as a raw 500 on the uq_projects_repo unique index. Nothing is wired into a router yet, so behaviour is unchanged for every existing project. Plans 2-4 consume this. - migration 0061: repo_primary column + at-most-one-primary partial unique index, replacing the plain UNIQUE(repo); also drops the drizzle-push table constraint and adds the (repo_full_name, pr_number) link index. - Optional JIRA routing.discriminator config field, threaded through the DB load path (buildJiraConfig hand-picks fields — same drift class as MNG-1736). - Pure, provider-agnostic sibling resolver: exactly one match routes, ambiguity skips loudly rather than guessing an owner. - Payload-aware project lookups; the legacy single-result lookups are untouched. 37 unit tests + 16 integration tests against real Postgres. Patch coverage 92.81%.
…y validation (#1542) Spec 024 plan 2 of 5. Shared JIRA project keys now route by discriminator instead of by position: both resolution sites go through one seam that cannot drift, misses explain themselves in the webhook decision reason, and the configuration that caused the original silent shadowing can no longer be created. Sharing is opt-in. A key where no project declares a discriminator keeps first-match routing plus a WARN and a Sentry capture naming who wins and who is shadowed, so no existing deployment changes behaviour on deploy — the strict matrix engages only once someone opts in. Save-time validation follows the same rule: an existing claimant may re-save in a legacy duplicate state, a new project claiming a taken key is rejected. - New OPTIONAL resolveProjectWithReason on the adapter contract, preferred by webhook-processor when present, so the four adapters this plan does not own keep their behaviour byte-identical. - Ambiguity captures Sentry under pm_routing_ambiguous, deduped per issue. - The ack reaction no longer fires for an event with no owning project. - RouterProjectConfig.jira and pm/config.ts's JiraConfig had to learn 'routing': both are hand-written projections that silently drop fields their author forgot. 28 new tests; 11129 passing. Review converged in round 2 with every finding proved fixed by mutation.
Spec 024 plan 3 of 5. Plan 2 made shared-key events route to the right sibling; this makes the same project's reads and writes symmetric, so a scoped project sees and produces only its own slice of a shared board. - listWorkItems appends AND labels = "..." / AND component = "..." to its JQL, placed BEFORE the ORDER BY. JQL requires the sort clause last, so appending to the finished string would have been a syntax error rather than a filter — the plan's literal wording would have produced exactly that, and writing the tests first caught it. - createWorkItem stamps every item the project creates, so friction reports, alert cards and split children all route home on their own. A label dedup-appends; a component sets components, and the key is omitted entirely when unset because JIRA rejects an empty array on projects with none configured. - The discriminator value is constrained at save time: no quote or backslash (both break out of the quoted JQL value), and no whitespace for label discriminators, which JIRA silently refuses to write. The client needed no change — createIssue takes an open field bag and already forwarded components. Both client tests pass green-from-start and are kept as pins against a future narrowing of that signature. Confirmed during review against Atlassian's docs: JQL 'labels = x' is membership, not set equality, so scoping does not silently drop multi-label issues. 20 new tests; 11149 passing. Also opens docs/BUGS.md with two out-of-scope findings.
…#1544) Spec 024 plan 4 of 5. Routing is link-first: a PR a project has claimed belongs to that project whatever the repository's primary is, so a secondary project's own PRs come back to it. Unlinked events fall back to the primary, which is also the entire single-project path. Saving a shared repository is validated with messages that name the conflict, instead of the raw 500 the unique index used to produce. The 23505 race maps to the same message. Four review rounds, seven must-fixes, converged with zero code findings. Five of the seven were tests asserting a proxy rather than the thing — a fabricated drizzle error shape, a mocked createProject, a mocked sibling query, and two half-wired resolution sites — and every one passed a fully green suite. The write and read paths are now covered by integration tests against a real database. 26 new tests (23 unit + 3 integration); 11172 unit and 673 integration passing. Known gap, disclosed rather than hidden: the worker still resolves its project by repo, so on a shared repository the container can receive the wrong project's credentials. Spec AC #8/#9 are not true end-to-end until #1545 lands, and sharing should not be enabled in production before then.
GitHubJob carried repoFullName but no projectId — unlike TrelloJob and JiraJob, which both carry one — so the worker re-resolved by repository, first match, and could disagree with the router that enqueued it. On a shared repository (spec 024) that meant the container was built with ANOTHER project's credentials, the dispatch compensator and lock classifier acted on the wrong project's lock, and the agent itself ran under an arbitrary sibling: its PM scope, concurrency accounting, watchdog and error persona, so its label writes, status moves and work-item comments would land on another team's board. The router's decision now travels with the job. The repo lookup stays as a fallback purely for jobs already in Redis at deploy time. Declaring projectId REQUIRED rather than optional found a construction site nobody had enumerated — the check-suite reschedule inside the worker — which would otherwise have silently reopened the bug for that path. Review then found two more router-side readers doing the same first-match resolution, posting the timeout comment and the check-suite reaction as the wrong project's bot. This is what makes spec 024's AC #8/#9 true end-to-end.
… 5/5) (#1546) Spec 024's final plan. Shared board and repository topologies are now configurable by an operator rather than only through the API, which is what the README's 'do not configure this in production' caveat had been waiting on since plan 2. - JIRA wizard 'Team routing' step: discriminator kind + value, optional and empty by default. 'None' is a legitimate choice — a key may have exactly one project without a discriminator, and that project is its default owner. - SCM tab 'Repository role': primary/secondary, sent only when the operator touches it, so an unrelated save leaves a shared repository's topology alone. - Operator walkthrough for both topologies, replacing the caveat. Three review rounds, four must-fixes. The first invalidated the plan's premise: cascade-tools rebuilds its project from env vars and the discriminator was not among them, so stamping and JQL scoping silently no-opped inside every worker — an agent's own work items routed to the wrong project. Round 2 found a second, near-identical synthesizer in the friction gadget on the default engine path. Both now share src/jira/config-from-env.ts with a static guard, because a third copy would have guaranteed an eleventh instance of that drift class. 27 new tests; 11207 passing; typecheck clean in both workspaces. AC #5 is deferred, not done: its manual protocol needs a live dev API. Round 1 found a real UX defect in exactly that surface, and a follow-up commit found it was still reachable on the edit path — treat visual placement as unverified. Marks spec 024 done: five plans, thirteen review rounds.
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 (7):