Skip to content

rollup: 2026-09-29 ctkm-1 integration into main - #1700

Merged
ctkm-aelf merged 15 commits into
mainfrom
rollup-2026-09-29-ctkm-1
Sep 30, 2026
Merged

ctkm-aelf merged 15 commits into
mainfrom
rollup-2026-09-29-ctkm-1

Conversation

@ctkm-aelf

@ctkm-aelf ctkm-aelf commented Sep 30, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

Integrate six source PRs into main. #1690: signup invitation codes become an operator choice, gated by the global, default-on auth:invitation-code feature flag instead of the INVITE_CODE_REQUIRED environment variable. With billing already provisioning a wallet for every new account, whether registration stays invitation-only is now a runtime toggle under Admin > Feature Flags. #1701: the OAuth consent screen is redesigned to match the connection flows, with no change to the authorization decision it posts. #1702: the Billing → Usage page keeps historical usage priced after a service price is removed or re-authored. Price cleanup used to delete the retired Lago code's billing_rate_cache row, so every historical usage_meter row recorded under that code lost its only price, GET /api/v1/billing/usage returned null costs, and the page showed Unavailable for the affected service (Chrono LLM) and for the whole Spend total. Retired codes now keep their row, historical groups are priced by grant-settled derivation → cached rate → exact per-row reservation rates, and partially unpriced totals display as lower bounds. Grants were never the cause. #1707: connector and channel-bot setup links clicked in NyxChat open the reusable setup component in an in-page overlay, keeping chat in place while standalone URLs retain their existing behavior. Local demos require explicit user submission. #1705: platforms and agents can create tracked bot setup links and receive signed completion, cancellation or expiry callbacks; existing production Connector-link contracts are preserved. #1706: Google Workspace connections accept partial grants, including identity-only consent; product scopes are optional, and service details show the last Google-reported grant.

Verification snapshot: 2026-09-30. The rollup contains six source PRs: #1690, #1701, #1702, #1707, #1705 and #1706. #1705 landed as a29056ef8328ae3cfd5bcca51a352e1408163c04 from validated source d08d3d0c2fb2eedf0da13de21bd5048f6b797fe6; its complete landed tree equals the tested source tree. #1706 landed as c883ea0e350e5e7f7a14047e905aa0483e137a35 from validated source a42bf8a892a214412aeb6ee71a5bac438f48cdde; its source and landed patch IDs match. Main ce4414e6eedbdac2baf33c67dff71c6a38c071af (#1703) was merged normally as 3b80d68f, retaining main ancestry. The shared bot-setup conflict with #1707 was resolved and tested; the CLI wizard was regenerated for the combined source. Final #1705 and #1706 source CI, CodeQL and Release checks passed. Post-merge push CI, CodeQL, and Release passed on docs-only commit a2c786a7fd568b3f156dfe445c30f865d4c3ff07 after squash a29056ef. The PR coverage job was stopped during slow, passing test progress; its unchanged rerun was superseded when #1706 landed. The rollup record now includes #1706 at head 463ca56a; fresh rollup checks are pending. Required main review and the separately tracked #1702 follow-up remain open.

Squash integration and preservation of code/history

All six squash integrations preserve their source patches, and the reviewed main history remains an ancestor of this rollup. Squash merging recorded each source PR as a new commit on the rollup; the source branches' individual development commits are not imported as ancestors, and no existing target commits were rewritten. If this rollup is itself squash-merged into main, main receives one combined commit; the landed squash commits will not become ancestors of main. This PR, the source PRs and the rollup branch ref record the provenance.

Verification went beyond commit ancestry:

Reproduce the check: source=dc5fb1b4be000995027c90412701d66c97766588 squash=e7691afe605770e67128376bf87b610c5e8f37a8 (or source=595ed4b3f192aea999def3abf46b2b6dfce9b859 squash=c3d49700f98be5bb31f1beacb3700bb25564fbbd). Find git merge-base "$squash^" "$source" and compare stable patch IDs for base→source and squash-parent→squash. Then compare git merge-tree --write-tree "$squash^" "$source" with git rev-parse "$squash^{tree}".

Included changes and provenance

Source PR Validated source → landed squash Intended behavior / scope
#1690 dc5fb1b4be000995027c90412701d66c97766588 → e7691afe605770e67128376bf87b610c5e8f37a8 Gate the signup invitation-code requirement behind the global, default-on auth:invitation-code feature flag, replacing INVITE_CODE_REQUIRED. Invitation-code management is retained; organization invitations are unchanged.
#1701 fbf21ac1e7dbed35656b777f64526d8d5bf0f867 → 68ad6d8146460ebd721158522c9fabea4256140e Redesign /oauth-consent to match the connect-link and channel-bot screens. It shows plain-language permissions, collapses app details and removes the client-side risk badges. Service lists gain catalog descriptions and scroll. GET /api/v1/user-services list rows add optional catalog_service_description. The /oauth/authorize/decision form is unchanged.
#1702 595ed4b3f192aea999def3abf46b2b6dfce9b859 → c3d49700f98be5bb31f1beacb3700bb25564fbbd Keep historical usage priced after a service price is removed. Price removal marks the code's billing_rate_cache row retired_at instead of deleting it (fresh_rate refuses it for new reservations; historical readers keep it; a re-synced price replaces it). GET /api/v1/billing/usage prices historical groups by grant-settled derivation, then the cached rate, then exact per-row reservation rates (rate × quantity in Decimal128 credits, as exact settlement computes), else null with grant credits still known. The Usage page shows ≥ lower bounds with an unpriced-record count instead of Unavailable when only some records are unpriced. Docs: glossary precedence and the admin-usage limitation, LAGO_SETUP, PLATFORM_KEYS_AND_INFERENCE, USAGE_BILLING_LAGO_SPEC, ENV, CLAUDE.md.
#1707 9d6d4618b9fd4156f5686402a54fb57b6fdb96e6 → 012dd86f840e77fcb0486120e965b430d4dcc25d Frontend-only setup overlays in NyxBot/actor/group chat. The page and overlay reuse ConnectLinkContent; channel setup opts into staying in place. Existing standalone URLs and default navigation remain supported. Includes explicit-submit demo fixtures, popup lifecycle/recovery fixes, focus restoration, tests and chat documentation.
#1705 d08d3d0c2fb2eedf0da13de21bd5048f6b797fe6 → a29056ef8328ae3cfd5bcca51a352e1408163c04 Tracked manual/managed/Telegram bot setup, signed lifecycle webhooks, optional browser return, CLI create/status/cancel and full integration docs. Separate storage/events/quota preserve existing Connector behavior. Includes CLI secret-file protection and CI resource/compiler fixes.
#1706 a42bf8a892a214412aeb6ee71a5bac438f48cdde → c883ea0e350e5e7f7a14047e905aa0483e137a35 Google Workspace partial grants are accepted; seven product presets use optional scopes, startup reconciles legacy required-scope metadata, and detail views expose saved grant evidence.

Rollup-only commits:

  • 921e5c5e, 62dd17ac and 7304e0a7 add and update docs/rollups/rollup-2026-09-29-ctkm-1.md.
  • 7848cce1 fixes a test only. handlers::nyxbot::tests::the_same_question_is_not_worked_on_twice, inherited from main feat: NyxBot one context for the owner across chat apps; the same question is never worked on twice (0.36.0) #1697, failed once in this PR's backend coverage run. It slept a fixed 300 ms after a Lark relay callback that returns 202 before recording the message. It now polls, bounded to 10 s, with unchanged assertions. It passed 10 of 10 isolated local runs. This fix landed on main through this rollup (rollup: 2026-09-29 ctkm-1 integration into main #1700).
  • b98949e1 fixes a test only. DRAFT: Gate signup invitation codes behind a default-on feature flag #1690's AuthFlow — register > allows email registration without a code when the flag is disabled failed once in frontend coverage. The register call had not happened within waitFor's default 1 s. It passed in the other three frontend runs on that head and on rerun. It now waits up to 5 s, like existing slow frontend waits.
  • On the prior head 62dd17ac, the push run's rerun passed both Backend Test and Coverage (Backend). That was the full backend suite, including feat(oauth): redesign consent screen to match connection flows #1701 and the NyxBot fix.
  • 7a410d9b is CI-only. On head 7304e0a7, Backend Test and Backend Billing Smoke died five times out of seven attempts with exit 143 ("The runner has received a shutdown signal") four to five minutes into compiling the nyxid test binary, before any test ran; the same job passed on that head's pull_request run (the full backend suite), and the 04:17 pull_request run had hit the identical failure on an earlier head. These logs establish runner shutdown during compilation; memory pressure from full debug information is a hypothesis, not a measured OOM diagnosis. Both jobs now set CARGO_PROFILE_TEST_DEBUG=line-tables-only, which keeps panic locations and backtraces and changes nothing for local builds. feat(channels): add tracked bot setup links and signed callbacks #1705 subsequently applies the same profile to both backend coverage jobs while preserving instrumentation and thresholds. These profile changes landed on main through this rollup (rollup: 2026-09-29 ctkm-1 integration into main #1700).
  • 463ca56a adds fix(oauth): make Google Workspace grants optional #1706 provenance, behavior, verification and the scope-evidence limitation to the rollup record.

Code review and behavior verified

These statements describe the reviewed implementation; they do not guarantee that every possible execution has been tested.

The bullets below cover #1690. #1701 landed in the rollup after this review. Its behavior is as described in #1701 and verified by its 31 consent-page tests; its code has not been independently reviewed here. Its own CI Backend Test job was lost to a runner shutdown, so this rollup's CI is the first backend run over it.

  • Default unchanged: auth:invitation-code defaults to enabled, so deployments that required codes keep requiring them until a platform admin disables the flag. No restart is needed.
  • Flag enabled:
    • Email signup requires a valid code.
    • Browser social signup can redeem one.
    • Existing social users still sign in.
    • Native social token exchange (subject_token_type=id_token) still rejects first-time signup.
  • Flag disabled: email and first-time social signup succeed without a code. Email verification, rate limits and billing wallet provisioning are unchanged.
  • Global only: a new account has no user or org scope yet. Scoped overrides are rejected on write, and the admin UI shows only the global control.
  • Server authority:
    • Email, browser social and native social signup each resolve the flag on every attempt.
    • GET /api/v1/public/config reports the effective requirement.
    • The signup screen refreshes public config, so an open form follows a change.
    • A flip between display and submit is decided by the server.
  • Management retained: the admin page, API and CLI for invitation codes remain, including reservations, redemption accounting, telemetry and indexes. The page states when codes are not currently required. Organization membership invitations are separate and unchanged.

#1702 was reviewed line by line by Claude Fable 5.1, by a Claude Opus 5.5 adversarial pass (nine minor findings, all resolved before merge), and by two GPT-6-Astra passes (pre- and post-rebase). Astra verified that the exact-Credits valuation matches settle_usage_funding, that the grant-settled derivation is sound for both pre-cutover (whole-credit ceiling) and exact rows, that null handling stays conservative, and that the frontend availability rules match the emitted rows. Behavior verified for #1702:

  • Root cause closed: complete_price_removal, the lane-cleanup branch and cleanup_components retire the code's cache rows (retired_at) instead of deleting them. fresh_rate refuses a retired row before its staleness check, so new reservations cannot size holds from a removed price; find_rate, settlement_rate_pico, estimate_credits, the usage handler and admin usage keep reading retired rows. A full-row re-sync (pricing or Lago plan refresh) replaces the row and clears the mark.
  • Historical pricing precedence in get_usage: exact persisted settlements are unchanged; for a group's historical rows: (1) all settled with a zero wallet debit and zero consumed allowance units → gross = grant consumption exactly; (2) model-specific then generic cached rate; (3) every row carries a reservation rate → per-row rate × quantity ÷ 1e12 in Decimal128 (allowance = rate × units), summed and read back through Credits::from_bson (fails closed on overflow); (4) otherwise null gross/wallet/allowance with grant credits still reported. Legacy Int64 wallet_charge_credits and amount_micros keys are honored.
  • Usage page: totals are ≥ n lower bounds with an unpriced-record count when some charged rows are unpriced; "Unavailable" only when no charged record is priced; free rows contribute zero but never make a total known; groups sort by their known sum. Pending/Acknowledged/Free semantics are unchanged.
  • Admin usage keeps only the cached-rate historical rule (no grant-settled or reservation fallback); retained rows mean future removals stay priced there, while codes whose rows were deleted before this change remain unknown on that page. This is documented in the glossary.
  • Review outcome and follow-up: Astra withheld its sign-off on two retention-safety gaps that do not affect the historical pricing fix itself: (1) after a code is re-authored, a retained model-specific cache row (no production writer creates one today; only manual seeding can) would be preferred by settlement of new usage; (2) the pre-existing write order in price sync and plan refresh (cache row written before the catalog fence / plan snapshot replaced unconditionally) can re-activate a retired row if a stale operation completes after removal. It also flagged that partial (≥) sums use the rounding display formatter. A follow-up source PR (active-first rate lookup, created_at-gated settlement, transactional sync/retirement fences, plan refresh preserving retired_at, exact 12-decimal partial formatting, with regression tests) is in progress and will be integrated into this rollup before main review completes.

#1707 received an initial Fable 5.1 adversarial review. A later Fable attempt was unavailable because Claude usage credits were exhausted; the final independent review used the available default model and reported no blocking findings after verifying all three audit fixes. This is not a claim of final Fable sign-off. Behavior verified for #1707:

  • Frontend presentation and reusable layers: a chat-owned adapter intercepts ordinary clicks on same-origin /connect/nyx_clk_<token> and /channel-bots/connect/<platform> URLs. Page and overlay render shared setup content. Modified clicks, unrelated/external links and direct full-page routes retain browser behavior. Channel query values are limited to label/org. Shared link components stay unaware of overlays; backend/message protocols are unchanged.
  • Minimal overlay: the connector card renders directly with a close button and screen-reader title; closing returns focus to its initiating link. Channel setup opts into stayInPlace, preserving all existing callers' navigation defaults.
  • OAuth lifecycle: the provider popup is reserved in the submit gesture and gets its recovery token in its own session storage before navigation, so an isolated return page can finish without an opener. Chat polls status. Dismissal closes the popup and ignores late responses; embedded content preserves the chat theme. Standalone OAuth and device-code flows remain supported.
  • Interactive demos: opening, waiting, filling or dismissing does not approve a connector or create a bot. Explicit submission is required; the manual /assistant?mock=1&nyxbot=1 URL works without automated-test setup and persists the selected engine within the tab. Entered fixture credentials are not stored.

Tracked bot setup links (#1705)

Platforms and agents can create a single-use bot setup URL through
POST /api/v1/channel-connect-links or nyxid channel-bot connect-link, send it
to the human owner, and receive signed channel_connect.completed,
channel_connect.cancelled, or channel_connect.expired notifications. The
hosted page is /connect/bot/{token}. An optional callback_url returns the
browser after the owner acknowledges any one-time setup secret.

  • Direct HTTP callers receive the webhook signing secret once. The CLI requires
    --webhook-signing-secret-file and saves it to a new file (mode 0600 on Unix);
    terminal and JSON output contain only the path and signing key ID. Existing
    files and symlinks are rejected before link creation. OAuth apps reuse their
    registered connection webhook and redirect policy.
  • Terminal callbacks have a stable event identity and snapshot, leased retries,
    public HTTPS destinations with DNS pinning, disabled redirects, and a separate
    app quota. Agent Keys can create, read, and cancel requests; completion requires
    an authorized human and preserves the owner, platform, and label from creation.
  • All currently registrable channel platforms share the tracked lifecycle: Telegram
    (existing token and native creation), Discord, Slack, Lark, Feishu, WhatsApp, X,
    and Aurinko email. Platform eligibility and manual/managed setup use the shared
    adapter registry. OpenClaw’s separate integration and botless device channels
    are outside this registration flow.
  • Completion means the bot was saved; receivers inspect bot_status and
    webhook_registered with the platform’s ingestion mode to determine readiness.
    Manual provider setup may remain, and polling platforms do not universally
    require webhook_registered=true.
  • The bot-link change preserves production Connector-link routes, schemas,
    tokens, events, standalone browser flows, webhook client behavior, and quota. Ordinary bot
    setup continues through the original service entry points.
  • API examples and implementation references are in docs/API.md and
    docs/CHANNEL_BOT_RELAY.md; published CLI/web guides and the agent playbook
    cover creation, signing, retries, expiry, and callback setup.
  • Live external-provider onboarding was not manually exercised. Automated
    regressions cover tracked setup and existing Connector-link behavior.

The shared setup-component conflict with #1707 preserves chat overlays and
tracked-link one-time results. Main #1703 was merged into the rollup as
3b80d68f; the CLI wizard was rebuilt from the combined source and its Rust
freshness test passed. Existing main history remains an ancestor of the rollup.

CI repairs keep ordinary bot creation using its existing service functions,
resolve strict Clippy warnings, save CLI webhook signing secrets in private
files instead of logging them, and apply CARGO_PROFILE_TEST_DEBUG=line-tables-only
to both backend coverage jobs. Tests, coverage instrumentation and thresholds
remain enabled. The high-severity CodeQL logging alert was fixed in source,
without dismissal or suppression.

Optional Google Workspace grants (#1706)

All seven Google Workspace product presets treat requested OAuth scopes as
optional. A connection can complete with only identity scopes even when its
initial request included Drive, Calendar and Gmail permissions. Startup
removes old seeded required-scope metadata while preserving unrelated custom
requirements. Gmail sending remains a default request, not a required grant.

AI Service details show Google's last reported scope list and derived product
access. Refresh updates that list when Google supplies scopes; an absent scope
response can leave the prior list in place. Ordinary Google API calls do not
return a fresh grant list, so the display does not verify scopes on every use.
Google rejects operations that need a scope the token lacks. Existing grants
are unchanged; users must reconnect to approve additional scopes.

Validation evidence

#1705 final source d08d3d0c2fb2eedf0da13de21bd5048f6b797fe6: CI, CodeQL and Release passed, including backend tests/coverage, baseline coverage comparison, workspace Clippy, KMS builds, frontend/CLI tests and coverage, wizard freshness, image inputs, billing smoke and all CodeQL analyses. The PR has no open code-scanning alerts. Local integration checks passed 134 focused frontend tests, 25 Playwright browser cases, targeted ESLint, the production build and the regenerated wizard freshness test. Earlier focused validation passed 19 bot-link backend tests, 180 compatibility regressions, 92 CLI tests and 18 documentation tests; the backend groups overlap by one test.

#1706 final source a42bf8a892a214412aeb6ee71a5bac438f48cdde: CI, CodeQL and Release passed against the latest rollup base. CI includes backend tests, both backend coverage jobs, frontend tests and coverage, Clippy, Rust feature builds, image inputs, billing smoke and the pipeline gate. Local focused verification passed 159 frontend tests, TypeScript, ESLint and Rust formatting. The landed squash has the same stable patch ID as the source and matches the git merge-tree result exactly.

Full integration CI on reviewed code dc5fb1b4: CI, CodeQL, Release. Checked through GitHub check results and job logs:

Check Result
All workflows on reviewed code 24 successful checks, 10 path/release skips; no failures
Backend (nextest) 6,832 passed; 2 skipped
Independent backend coverage suite 6,817 passed; 2 ignored
Frontend 3,938 passed in 386 files
Line coverage: backend / frontend 87.39% / 71.16%; gates passed
Other checks Formatting, Clippy, AWS/GCP KMS feature combinations, billing smoke, backend image inputs, wizard freshness and CodeQL (actions, JS/TS, Python, Rust) passed

CLI, Mobile, SDK, Oracle worker and Cursor plugin jobs were skipped by path detection for that earlier #1690 run. Later #1705 changes include CLI work; its source CI exercised those jobs. The existing invitation-code CLI commands are unchanged.

The first run on the pre-sync head 15cb5f07 had one Backend Coverage failure: the runner received a shutdown signal (exit 143) mid-compile. It passed on rerun; no test failed.

Full integration CI on #1702's source head 595ed4b3 (already on the rollup base b98949e1): CI, CodeQL, Release. All 24 checks passed and 10 were path/release skips, with no failures: Backend Test (nextest), Coverage (Backend and Frontend), Frontend, Rust Format, Rust Clippy, the AWS/GCP KMS feature builds, Backend Billing Smoke, Backend Image Inputs, CLI Wizard Bundle Freshness, Release Integrity Manifest and CodeQL (actions, JS/TS, Python, Rust). Because the landed tree equals the source tree, this run exercised exactly the code now on the rollup.

Fresh local verification on the merged tree against a MongoDB replica set:

  • 45 feature-flag tests, including the pinned registry and nyxbot gateway flag tests.
  • 57 invitation-code tests.
  • 36 auth-handler tests.
  • 57 social-signup tests.
  • 3 public-config tests.
  • 874 frontend flag/lib tests passed, and TypeScript compiled.
  • fix(billing): keep historical usage priced after price removal #1702 (MongoDB 8.0 single-node replica set): billing_integration_tests::usage, services::billing::{pricing,reservation,tests,funding,reconcile,meter,exact_tests} and handlers::services::tests — 141 passed, 0 failed; cargo clippy -p nyxid --all-targets -- -D warnings clean; frontend eslint 0 errors, vitest 66/66 for the billing and credits files, npm run build (type-check) passes.

These were selected tests, not a new full-suite run.

#1707 source validation at 9d6d4618: CI, CodeQL, Release. All 13 applicable checks passed; 19 path/release checks were intentionally skipped. This source PR changes frontend/docs only, so source CI skipped backend tests. The rollup's post-merge checks exercise the combined changes.

#1707 validation Result
Full frontend suite, local and Node 22 CI 3,970 tests passed in 389 files
Frontend line coverage 71.01%; configured 15% gate passed (base 71.18%)
Lint/build Zero lint errors (29 existing warnings); TypeScript, both production bundles and mock-footprint assertion pass
Selected Playwright suites 38 cases pass across the main run (36) and targeted rerun (2): both chat engines' setup overlays, standalone channel pages, NyxAgent waiting flows, mobile/desktop, explicit completion and focus
Local interactive review Desktop/mobile opening, idle, close/reopen, cancel and explicit submit observed; chat URL remains unchanged
Squash preservation Source and landed complete trees identical; stable patch IDs match; no merge conflicts

Two stale standalone Telegram test selectors were corrected. Default-concurrency local unit runs hit unrelated routing/auth timing limits; the complete suite passed with three workers and unchanged assertions, and unmodified default-concurrency CI also passed. Live external connector OAuth providers were not exercised; automated tests cover recovery/lifecycle.

Post-merge checks on 012dd86f: push CI, pull-request CI, CodeQL, Release. Three backend coverage jobs failed during compilation with runner shutdown/exit 143 before tests ran (PR head, PR base and push head). Both frontend jobs passed. The coverage profile mitigation landed through #1705 at a29056ef. #1711 was initially closed as a duplicate, then repurposed at the user's request into a broader CI reliability/speed enhancement targeting main. The final #1711 head e1585ea9 adds pinned compiler/test/coverage/database inputs, at least 8 GiB swap on heavy backend runners, resource diagnostics, bounded setup and jobs, exact base-report cache identity, cancellation of obsolete PR scans, Mobile aggregation and removal of unused coverage-report passes. It also fixes a separate direct-group callback test race introduced by #1712, using test-only completion synchronization; the earlier same-question timing fix (7848cce1) and line-table profile already landed through #1700. Production behavior is unchanged. Final CI, CodeQL and Release passed on the merge with main 14d76f4a, including both backend coverage jobs. Full backend nextest passed 6,873 tests (2 existing skips). Backend head/base coverage executed the same 6,860 named tests and outcomes (6,858 passed / 2 ignored / 0 filtered) across the same 509 files; the only denominator difference is one added measured test-hook line. Head/base coverage is 87.44% backend / 72.45% CLI / 71.00% frontend, with unchanged gates of 73% / 64% / 15%. Final head/base coverage sampled 3.259/3.310 GiB swap, above the old 3 GiB capacity. These measurements support additional reserve and preserved coverage; they do not prove elimination of future infrastructure failures or a controlled speedup. #1711 is ready for review; main requires one approving review before merge. Both backend coverage jobs now use CARGO_PROFILE_TEST_DEBUG=line-tables-only, preserving instrumentation, full test commands and the 73% gate. #1705's source CI passed; the independent #1711 candidate also passed all 30 applicable checks (4 intentional skips), with 6,826 backend coverage tests passing and 87.43% line coverage in run 36716209962. These successful runs validate compatibility, not a proven elimination of infrastructure failures.

Backend coverage reliability audit, September 30: 17 inspected failed coverage job executions comprise 16 runner shutdowns during compilation and one assertion failure; none failed the coverage-percentage threshold. This is a diagnostic sample, not a repository-wide failure rate. It includes failed jobs within later-cancelled workflows; some history API requests returned 502/504. Three workflows later passed on the same actual checkout commit, confirmed in logs: 36662907994 (shutdown twice, then 6,817 tests / 87.39%), 36670664278 (shutdown, then 6,817 tests / 87.38%), and 36680454361 (shutdown, then 6,823 tests / 87.40%). The assertion was google_mail_callback_accepts_partial_grants on the separate Gmail investigation branch (job 109880567254): expected None, observed retained fixture scope openid; this is a test/behavior mismatch, not established intermittency. The earlier NyxBot fixed-sleep timing flake is separately addressed by 7848cce1 above.

The compilation-shutdown signature also occurred in the older serial coverage workflow on September 25: 36111800751 and two attempts of 36113291552 passed head tests, then lost runners during base compilation. The evidence does not establish OOM, exhaustion of GitHub-wide compute, or a before/after failure-rate increase attributable to #1669. Next reliability work should record resource peaks and resolved coverage inputs, distinguish build/test/report/cancellation outcomes, cancel obsolete PR scans, and remove duplicate push/PR validation only when actual tested trees and inputs are equivalent. Preserve all suites, thresholds and release gates while tuning worker counts against measured resource use and latency. An unchanged control rerun of 36715953490 was cancelled after approximately 92 seconds and is inconclusive; do not keep rerunning obsolete rollup revisions.

Deployment and remaining acceptance

🤖 Generated with Claude Code

ctkm-aelf and others added 2 commits September 30, 2026 10:48
…ag (#1690)

Signup invitation codes are now an operator choice. The requirement is behind
the global, default-on `auth:invitation-code` feature flag, which replaces the
`INVITE_CODE_REQUIRED` environment variable and can be toggled in
Admin > Feature Flags without a restart.

- Enabled (default): email signup requires a valid code; browser social signup
  can redeem one; native social token exchange still rejects first-time signup.
- Disabled: email and first-time social signup succeed without a code.
- Flag is global only; scoped overrides are rejected. The backend resolves it on
  every signup attempt and /api/v1/public/config reports the effective state.
- Invitation-code admin page, API and CLI are retained; the page states when
  codes are not required. Organization invitations are unchanged.
- Rollout: deploy backend before frontend. Deployments with
  INVITE_CODE_REQUIRED=false must disable the flag to keep signup open.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Records #1690 (default-on auth:invitation-code signup gate), its reviewed
head and squash commit, the main sync to e96a507, rollout notes and
verification.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@github-actions

github-actions Bot commented Sep 30, 2026 •

Copy link
Copy Markdown

📊 Code coverage

Component Lines Threshold Status Δ vs base
Backend (nyxid) 87.41% 73% ✅ 🔺 +0.01
CLI (nyxid-cli) 71.62% 64% ✅ 🔺 +0.10
Frontend (vitest) 70.99% 15% ✅ 🔻 -0.16

Gate: line coverage must stay at or above the threshold. Ratchet plan (W21): Backend → 55%, CLI → 50%, Frontend → 30% by quarter end.

ctkm-aelf and others added 4 commits September 30, 2026 12:16
Rework the OAuth consent page into the centered card used by connect links
and channel-bot connections: circular NyxID mark, "Authorize application"
heading with the requesting app highlighted, plain-language permission rows,
and a trust note above Allow/Decline. Client ID, redirect and raw scopes move
under App details. The Low/Medium/High scope badges are removed; they were
client-side labels, not server decisions.

Service access shows each service's catalog description (two lines max) in a
scrollable list with edge fades. Customize toggles a picker that closes via
Done or Save selection. GET /user-services list responses now include
catalog_service_description. Form fields posted to
/oauth/authorize/decision are unchanged.

Adds a dev-only /oauth-consent-preview route with sample data and disabled
decisions.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
the_same_question_is_not_worked_on_twice slept 300 ms after a Lark relay
callback that returns 202 before recording the message. The instrumented
coverage build on rollup PR #1700 took longer, so the reply target was not
yet recorded. Poll the home thread (bounded to 10 s) until it is, keeping
the assertions unchanged. Record the follow-up in the rollup notes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The #1690 test 'allows email registration without a code when the flag is
disabled' failed once in the rollup's frontend coverage run: the register
call had not happened within waitFor's default 1 s. Use a 5 s timeout, as
other slow frontend waits do, and record the follow-up in the rollup notes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
ctkm-aelf and others added 3 commits September 30, 2026 14:40
Re-authoring a service price deleted the retired Lago code's
billing_rate_cache row, so every historical usage_meter row recorded
under that code lost its only price and GET /billing/usage returned
null costs; the Usage page then showed Unavailable for the service and
for the Spend total. Grants were never the cause.

- Price removal marks the rate row retired_at instead of deleting it;
  new reservations refuse retired rates, historical pricing keeps
  reading them, and a re-synced price clears the mark.
- get_usage prices historical groups by grant-settled derivation, then
  the cached rate, then per-row reservation rates (exact Decimal128
  credits, as exact settlement does), else null with grant credits
  still known.
- The Usage page shows lower bounds (≥) with an unpriced-record count
  instead of Unavailable when only some records are unpriced.
- Docs: glossary precedence, admin usage limitation, rollout note.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Backend Test and Backend Billing Smoke died five times out of seven
attempts on the 2026-09-29 rollup head with exit 143 ("The runner has
received a shutdown signal") four to five minutes into compiling the
nyxid test binary, before any test ran. The full-DWARF test binary
exhausts the hosted runner's memory during codegen and linking. Both
jobs now set CARGO_PROFILE_TEST_DEBUG=line-tables-only, which keeps
panic locations and backtraces and changes nothing for local builds or
the coverage jobs.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
)

* feat(chat): open connector and channel setup in reusable overlays

* fix(chat): harden setup popup lifecycle and restore link focus
* feat(channels): add tracked bot setup links and signed callbacks

* fix(channels): preserve bot creation calls in production builds

* fix(cli): save bot webhook signing secrets to private files

* ci: bound backend coverage debug information
* fix(oauth): make Google Workspace grants optional

Accept partial Google consent, remove seeded required-scope metadata across Workspace products, and show last reported grants in service details.

* test(oauth): match optional Workspace seed wording

* feat(oauth): show grants for every Google Workspace product

* test(oauth): retain prior scope evidence when response omits scopes

* ci: bound backend coverage debug info for hosted runners
@ctkm-aelf
ctkm-aelf merged commit 1f6fad5 into main Sep 30, 2026
57 checks passed
ctkm-aelf added a commit that referenced this pull request Sep 30, 2026
* rollup: 2026-09-29 ctkm-1 integration into main (#1700)

* feat(auth): gate signup invitation codes behind default-on feature flag (#1690)

Signup invitation codes are now an operator choice. The requirement is behind
the global, default-on `auth:invitation-code` feature flag, which replaces the
`INVITE_CODE_REQUIRED` environment variable and can be toggled in
Admin > Feature Flags without a restart.

- Enabled (default): email signup requires a valid code; browser social signup
  can redeem one; native social token exchange still rejects first-time signup.
- Disabled: email and first-time social signup succeed without a code.
- Flag is global only; scoped overrides are rejected. The backend resolves it on
  every signup attempt and /api/v1/public/config reports the effective state.
- Invitation-code admin page, API and CLI are retained; the page states when
  codes are not required. Organization invitations are unchanged.
- Rollout: deploy backend before frontend. Deployments with
  INVITE_CODE_REQUIRED=false must disable the flag to keep signup open.

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

* docs(rollup): record 2026-09-29 ctkm-1 rollup

Records #1690 (default-on auth:invitation-code signup gate), its reviewed
head and squash commit, the main sync to e96a507, rollout notes and
verification.

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

* feat(oauth): redesign consent screen to match connection flows (#1701)

Rework the OAuth consent page into the centered card used by connect links
and channel-bot connections: circular NyxID mark, "Authorize application"
heading with the requesting app highlighted, plain-language permission rows,
and a trust note above Allow/Decline. Client ID, redirect and raw scopes move
under App details. The Low/Medium/High scope badges are removed; they were
client-side labels, not server decisions.

Service access shows each service's catalog description (two lines max) in a
scrollable list with edge fades. Customize toggles a picker that closes via
Done or Save selection. GET /user-services list responses now include
catalog_service_description. Form fields posted to
/oauth/authorize/decision are unchanged.

Adds a dev-only /oauth-consent-preview route with sample data and disabled
decisions.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>

* test(nyxbot): wait for relayed message instead of a fixed sleep

the_same_question_is_not_worked_on_twice slept 300 ms after a Lark relay
callback that returns 202 before recording the message. The instrumented
coverage build on rollup PR #1700 took longer, so the reply target was not
yet recorded. Poll the home thread (bounded to 10 s) until it is, keeping
the assertions unchanged. Record the follow-up in the rollup notes.

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

* docs(rollup): record #1701 in the 2026-09-29 ctkm-1 rollup

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

* test(auth): allow the code-free registration test 5 s under coverage

The #1690 test 'allows email registration without a code when the flag is
disabled' failed once in the rollup's frontend coverage run: the register
call had not happened within waitFor's default 1 s. Use a 5 s timeout, as
other slow frontend waits do, and record the follow-up in the rollup notes.

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

* fix(billing): keep historical usage priced after price removal (#1702)

Re-authoring a service price deleted the retired Lago code's
billing_rate_cache row, so every historical usage_meter row recorded
under that code lost its only price and GET /billing/usage returned
null costs; the Usage page then showed Unavailable for the service and
for the Spend total. Grants were never the cause.

- Price removal marks the rate row retired_at instead of deleting it;
  new reservations refuse retired rates, historical pricing keeps
  reading them, and a re-synced price clears the mark.
- get_usage prices historical groups by grant-settled derivation, then
  the cached rate, then per-row reservation rates (exact Decimal128
  credits, as exact settlement does), else null with grant credits
  still known.
- The Usage page shows lower bounds (≥) with an unpriced-record count
  instead of Unavailable when only some records are unpriced.
- Docs: glossary precedence, admin usage limitation, rollout note.

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>

* docs(rollup): record #1702 in the 2026-09-29 ctkm-1 rollup

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

* ci: build backend test binaries with line-table debuginfo

Backend Test and Backend Billing Smoke died five times out of seven
attempts on the 2026-09-29 rollup head with exit 143 ("The runner has
received a shutdown signal") four to five minutes into compiling the
nyxid test binary, before any test ran. The full-DWARF test binary
exhausts the hosted runner's memory during codegen and linking. Both
jobs now set CARGO_PROFILE_TEST_DEBUG=line-tables-only, which keeps
panic locations and backtraces and changes nothing for local builds or
the coverage jobs.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

* feat(chat): open connector and channel setup in reusable overlays (#1707)

* feat(chat): open connector and channel setup in reusable overlays

* fix(chat): harden setup popup lifecycle and restore link focus

* feat(channels): add tracked bot setup links and signed callbacks (#1705)

* feat(channels): add tracked bot setup links and signed callbacks

* fix(channels): preserve bot creation calls in production builds

* fix(cli): save bot webhook signing secrets to private files

* ci: bound backend coverage debug information

* docs: record bot-link callbacks and rollup verification

* fix(oauth): make Google Workspace grants optional (#1706)

* fix(oauth): make Google Workspace grants optional

Accept partial Google consent, remove seeded required-scope metadata across Workspace products, and show last reported grants in service details.

* test(oauth): match optional Workspace seed wording

* feat(oauth): show grants for every Google Workspace product

* test(oauth): retain prior scope evidence when response omits scopes

* ci: bound backend coverage debug info for hosted runners

* docs: record Google OAuth grant fix in rollup

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>

* feat: NyxBot guests use specialists' services at owner-set levels; Telegram bot creators are owners; Lark groups answer only bot mentions (0.38.0) (#1712)

* fix: a Telegram bot created through NyxID knows its owner: the creating account is verified on link or first message, and Start greets instead of refusing

* fix: only a creator bound by the owner's own setup challenge is trusted, in private chats; link-time grants are audited and NyxBot keeps the verify link as a fallback

* chore: bump version to 0.37.2

* fix: guests use a specialist's services except deleting; Lark groups count only mentions of the bot itself

* fix: guests are refused calls that look like deleting by what they send, and never raise approvals; Lark bot ids cached per app

* fix: guest delete checks cover GETs, body method overrides, unparsable JSON and code fields; guests never run on the owner's approval grants

* feat: owners set what guests may do with each of a specialist's services (read, use, all), from the agent page or by asking NyxBot; destructive operations come from spec markers, not word lists

* test: agent fixtures carry guest_access

* fix: guest access judges every requested method, keeps levels beside grants for rolling deploys, honours read-only specs and catalog markers on mounted specs; Drive trash and content replace are destructive

* fix: grants form builds its request without an unused binding

* fix: guest calls never carry method overrides; Calendar event and Bitable record updates are destructive; a re-granted service starts at the default guest level

* fix: guests' default use is reading, creating and acting (no PUT/PATCH/DELETE); Aevatar's destructive markers stay unchanged and NyxID marks POST edits itself; only stored catalog contracts widen reads; override keys read as PHP reads them

* fix: NyxID's per-operation x-nyxid-changes-existing (true for POST edits, false for PUT actions); override checks follow the body's content type; hosted overlays mounted by URL are catalog contracts; all-level grants say they include deleting

* fix: only a catalog contract may say an operation only acts; method fields count when they name another changing verb, in JSON bodies too; ; separates fields; hosted overlays share one check

* fix: override checks skip empty, text and binary bodies; hosted overlay lookups share NyxID's compiled copy without cloning

* chore: bump version to 0.38.0

---------

Co-authored-by: chrono-kw <chrono-kw@users.noreply.github.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Co-authored-by: chronoai-kai <kaiweichronoai@gmail.com>
Co-authored-by: chrono-kw <chrono-kw@users.noreply.github.com>
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.

1 participant