Sync upstream paradigmxyz/centaur - #54
Open
darkmatter[bot] wants to merge 198 commits into
Open
Conversation
* fix(workflows): shut down Python host cleanly * fix(workflows): accept large host messages
* feat: scope company context reader user sources * fix: retain Google subject context authorization * test: strengthen company context reader RLS guards
* fix(console): restore inline markdown links * fix(console): parse markdown placeholder indexes * fix(console): preserve restored markdown fragments * test(console): generalize markdown link regression
* feat(console): promote principal identity fields * refactor(console): normalize principal identifiers * revert(console): remove normalized principal identifiers * fix(console): infer principal kinds from foreign IDs * fix(console): require scoped Slack DM identifiers * refactor(console): keep principal identity out of labels * refactor(console): simplify principal label aliases * fix(console): validate principal identity fields * fix(console): support Slack enterprise identity scopes * test: cover principal identity reconciliation * fix: preserve principal identity compatibility * fix: narrow principal kind backfill * fix: validate reconciled Slack identities * refactor: centralize principal identity promotion * fix: validate MCP Slack identities * fix: show principal identity labels in console
* feat: add default role assignments * fix: preserve default roles when settings omit them
* feat(console): promote console user identity fields * fix(console): reference console users by database id * fix(console): allow stale console user references * refactor(console): centralize principal identity labels
* fix(chart): require console * refactor(api-rs): always enable iron-proxy * fix(chart): ignore removed enable values
Co-authored-by: Perry Dime <260989497+svc-paradigm@users.noreply.github.com>
Selects the awscliv2 package matching the image's dpkg architecture (x86_64/aarch64), following the same pattern already used for kubectl and Nushell in this Dockerfile.
Co-authored-by: Perry Dime <260989497+svc-paradigm@users.noreply.github.com>
* fix(docsend): encode browserbase session metadata * refactor(docsend): use base64 session metadata * refactor(docsend): require encoded session metadata * refactor(docsend): simplify base64 decoding --------- Co-authored-by: Perry Dime <260989497+svc-paradigm@users.noreply.github.com>
* feat(slackbotv2): decouple response metadata from Console * feat(slackbotv2): split response metadata controls * chore(chart): bump release to 0.1.110 * feat(slackbotv2): add response metadata modes --------- Co-authored-by: Liam Horne <liam@lihorne.com>
_serialize_message builds a fixed dict from the Slack payload and drops everything it doesn't name, including the reactions array. Every read path funnels through it (get_channel_history_page, get_thread_replies_page, and the search fallback fetch), so no caller of the serialized shape can see reaction signal at all. That's a real blind spot in channels where people answer by reacting rather than replying. A message with 12 check-marks and no replies serializes to reply_count 0, which reads as "nobody responded" when the opposite is true. An agent working off that shape either reports the reply count as the roster or has to admit it can't answer. The data is already on the wire and needs no new OAuth scope. reactions:read gates the reactions.* methods, while the reactions array on a conversations.history payload rides along with channels:history, which this tool already requires. feedback.py:372 has been reading them straight off the raw responses this way for its thumbsup/thumbsdown signal. Only the serializer was throwing them away. Consistent across both read paths: the API server proxy hands back an untyped serde_json::Value, so reactions survive it and the proxy and direct fetches agree. Defaults to [] like reply_users so callers can index without a guard. Slack caps the per-reaction users array, so count can exceed len(users); anyone needing a complete reactor list on a heavily reacted message still wants reactions.get and the reactions:read scope it requires. The comment says so at the call site. Co-authored-by: Aadharsh Pannirselvam <19518661+oddharsh@users.noreply.github.com> Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
…ebhooks (paradigmxyz#1248) * feat(githubbot): produce durable workflow events from CI and review webhooks Add a workflow-event producer module, independent of the owned-PR manager: lifecycle webhooks are translated into curated durable events on api-rs (POST /api/workflows/events) that workflows suspend on via ctx.wait_for_event. Emission runs before any owned-PR gating, because workflow waiters are not bot-owned PRs. - ci-completed (<owner>/<repo>:<head_sha>, payload {failed, failing}) fires once every check for the sha has settled. The settled evaluation reads GitHub's GraphQL statusCheckRollup — the same aggregate gh pr checks uses, covering check runs and commit statuses including EXPECTED — because fine-grained PATs get an ungrantable 403 on the REST check-runs list. An unreadable rollup is unknown, never settled, and a settled-green rollup is confirmed by one delayed re-read before emission: a push can read SUCCESS moments before the real suite registers. - review-submitted (<owner>/<repo>:pr-<n>:<head_sha>:<reviewer>, payload {review_id, state}) fires on every submitted review. Author-scoped correlations give each reviewer an independent row, so a waiter keys on exactly the author it cares about with no emission-side config. Durable events are immutable per correlation (first write wins), which forces two curation rules documented in the module header: an event must be semantically complete when emitted (the settled gate), and anything a waiter filters on belongs in the correlation. Correlations are computable from data the waiter already has and are lowercased so case drift between a PR URL slug and repository.full_name can never miss. The manager shares the settled evaluation so an owned PR is not evaluated twice per CI event. Off by default (githubbot.workflowEvents / GITHUBBOT_WORKFLOW_EVENTS); the api-rs URL and service token are already wired for the session API. * fix(githubbot): harden workflow event delivery * refactor(githubbot): simplify workflow event code
…e in the ruby-dependencies group (paradigmxyz#1259) chore(deps): bump solid_queue Bumps the ruby-dependencies group in /services/console with 1 update: [solid_queue](https://github.com/rails/solid_queue). Updates `solid_queue` from 1.5.0 to 1.6.0 - [Release notes](https://github.com/rails/solid_queue/releases) - [Commits](rails/solid_queue@v1.5.0...v1.6.0) --- updated-dependencies: - dependency-name: solid_queue dependency-version: 1.6.0 dependency-type: direct:production update-type: version-update:semver-minor dependency-group: ruby-dependencies ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
* feat: add OpenAI workflow dependency * fix: require OpenAI SDK 2.53
darkmatter
Bot
force-pushed
the
sync/upstream-main
branch
from
August 27, 2026 22:26
d38e916 to
8978397
Compare
darkmatter
Bot
force-pushed
the
sync/upstream-main
branch
from
August 27, 2026 22:35
8978397 to
2150df7
Compare
Iron-proxy pods were created with restartPolicy=Never, so any container crash left the pod permanently Failed while its sandbox kept running with zero egress: Codex gets connection refused to api.openai.com, in-sandbox tools fail, and the turn dies. Nothing repairs the proxy until the next session execute calls assign_proxy_principal and recreates it, so every in-flight turn on that sandbox is lost. This went from latent to load-bearing on prd-centaur-na when tempoxyz/prd-centaur-infra#669 added a 512Mi memory limit: iron-proxy buffers bodies while proxying, large transfers burst past the limit in seconds, and the resulting OOM kills produced 40+ mid-turn 'stream disconnected before completion' failures since 2026-08-27. OnFailure makes the kubelet restart the container in place: same pod IP, the per-sandbox Service keeps routing, and the proxy re-syncs its principal config from iron-control on startup, so an OOM becomes a seconds-long blip instead of a dead session. pod_running() requires the Ready condition, so ensure/assign paths still treat a crash-looping proxy as unusable, and wait_until_proxy_running now bounds a proxy that never comes up by ready_timeout instead of failing on first crash. Amp-Thread-ID: https://ampcode.com/threads/T-01a048d9-a0bb-72f0-b6cd-4769da726fdc Co-authored-by: Amp <amp@ampcode.com>
darkmatter
Bot
force-pushed
the
sync/upstream-main
branch
from
August 28, 2026 19:01
2150df7 to
dc87a81
Compare
darkmatter
Bot
force-pushed
the
sync/upstream-main
branch
4 times, most recently
from
August 28, 2026 20:02
9dd553d to
dc87a81
Compare
darkmatter
Bot
force-pushed
the
sync/upstream-main
branch
from
August 29, 2026 21:01
9dd553d to
dc87a81
Compare
darkmatter
Bot
force-pushed
the
sync/upstream-main
branch
from
August 29, 2026 22:01
9dd553d to
dc87a81
Compare
…z#1496) * feat: bind the console user's principal on console thread turns Console sessions register an anonymous per-thread principal, so a user's connected OAuth credentials (e.g. GitHub) never reach console-driven turns: reconciliation matches identity-scoped credentials to principals, and the thread principal carries no user identity. The proxy falls back to shared role-granted tokens and PRs open as the bot. The console now provisions the authenticated user's console-user principal on each execute and passes its foreign ID as requester_principal_foreign_id in the execute metadata. api-rs resolves it fetch-only for console: thread keys (a namespace only the console service may write) and binds it as the turn's requester principal, so the proxy serves the RFC 0005 union: the thread principal's grants plus the requester's always-available OAuth direct grants. Shared threads stay safe — a reply binds the replier's principal, never the creator's. The provisioner no longer rewrites an unchanged principal on repeat calls. The RFC 0005 availability gate is unchanged: a credential joins console turns only when an admin marked its OAuth app always-available. Generated with [Devin](https://devin.ai) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com> * feat: bind the comment author's principal on GitHub turns GitHub-triggered turns ran with only the anonymous per-thread principal, so a commenter's connected GitHub OAuth credential never applied: githubbot already forwards the webhook-verified sender (`user_id`, the numeric GitHub id, and `user_name`) in every execute's metadata, but api-rs resolved a requester only for Slack. api-rs now derives and upserts a per-user `github-user-<id>` principal for `github:` thread keys, labeled `github_subject: <id>`, and binds it as the turn's requester principal. Reconciliation gains GitHub as a subject-label provider (`Principal::KINDS` learns `github_user`), so the credential owner is matched by GitHub user id — the only workable anchor, since the consent flow collects no email scope. The proxy then serves the RFC 0005 union: thread principal's grants plus the requester's always-available OAuth direct grants, so pushes and PRs authenticate as the commenter. A commenter can only bind their own identity: the sender id is authentic from the signature-verified webhook, turns only run for author associations the deployment allowlisted, and the hoisted credential is always the commenter's own. Generated with [Devin](https://devin.ai) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com> * refactor: tighten console requester comments Generated with [Devin](https://devin.ai) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com> * refactor: plan-based requester resolution and review cleanup Address review findings on the requester binding: - Collapse register_requester's per-source branches into a typed RequesterPlan (FetchExisting for console-provisioned principals, UpsertDerived for api-rs-owned Slack/GitHub principals) produced by one dispatch function, so a new source is one arm instead of another branch in the registrar. - The test stub now records request bodies, and the GitHub upsert test asserts the serialized kind/name/github_subject payload, not just the path. - RFC 0005 §4 rewritten around the single precedence rule (provider-native subject first, owner-identity/email fallback) so it no longer contradicts the GitHub subject path; Security Considerations lists the webhook and console trust anchors. Generated with [Devin](https://devin.ai) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com> * fix: resolve GitHub requesters on work sessions --------- Co-authored-by: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com> Co-authored-by: Matthew Slipper <me@matthewslipper.com>
Co-authored-by: Liam Horne <1933029+snario@users.noreply.github.com>
* feat: add experimental memory generation workflow * fix: resolve memory workflow CI failures * fix: align memory generation model with evals * fix: prevent memory generation pipeline wedges * fix: preserve cursor on transient memory failures * fix: reject all Slack group DMs from memory scope * feat: add self-draining memory backfill
* fix(codex): set default reasoning to medium * test: update Slack reasoning metadata expectations --------- Co-authored-by: Perry Dime <260989497+svc-paradigm@users.noreply.github.com> Co-authored-by: Matthew Slipper <me@matthewslipper.com>
* feat: add Centaur agent plugin registry * test: lock centaur plugin identity
* fix: retry transient console sync failures * test: fix Granola sync retry stub --------- Co-authored-by: Perry Dime <260989497+svc-paradigm@users.noreply.github.com>
Merge upstream tip f5ef8b8 into product base c9fadb1. Conflicts resolved using the prior validated merge 87af8b8 (base c9fadb1 + fd3c260) as resolution oracle for all paths upstream did not touch in fd3c260..f5ef8b8; paths upstream changed after fd3c260 take the upstream tip version. Fork invariants preserved: telemetry opentelemetry- proto/prost deps, migration renumbering (0057/0058), sandbox api_server_enabled capability, workspace-diff API, OMP harness support.
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.
Upstream sync candidate — PR #54 is the long-lived sync PR; do not close or recreate.
f5ef8b8fcbdcea7b9d9690ffaa96d9090f995941c9fadb1dec5439c80325060970a1093134a9e7194519575e44c26f4b67161278a8604430dd57533bThis candidate contains both current product
mainand the current upstream tip. The repair stage must validate or rebuild this merge before it goes ready-for-review.