Sync current Nous Hermes main into Ace patches - #14
Merged
Conversation
After multiple in-place compactions, short tool-heavy sessions can leave nearly every remaining message inside protect_last_n while those messages are huge completed file/tool outputs. The middle compress window then makes no material token progress and the turn dies with "Cannot compress further" (NousResearch#61932). Cap the prune message floor at the same bound as tail-cut, and under pressure demote bulky protected-tail tool bodies (keeping a short recent floor) so preflight can reclaim headroom without wiping the active ask.
…hape as compressible Regression test for the exact issue NousResearch#61932 report: head + an 8-message protected tail made exclusively of oversized tool pairs. Pre-fix, compress_start >= compress_end made compress() a pure no-op and the retry loop ended in 'Cannot compress further'; post-fix the Phase-1 pressure demotion reclaims the tail in one pass while preserving tool_call/tool_result pairing.
… consecutive user/user turns After context compression, the preserved todo list was unconditionally appended as a standalone user message. When the compressed transcript already ends with a user message (common case), this creates consecutive user/user turns — a role-alternation violation some providers reject. Fix: fold the snapshot into the trailing user message (blank-line separated) when one exists with plain-string content. Falls back to append when the tail is non-user, empty, or has structured (list) content. Rebased on current upstream/main. Closes NousResearch#53890
…h stale snapshots Follow-up hardening on the salvaged merge-into-trailing-turn fix: - Merge only into REAL user tails (_is_real_user_message probe). Merging into scaffolding tails (continuation marker, summary-as-user handoff) would upgrade them to real-user evidence after SessionDB projection strips the flags, breaking zero-user provenance (NousResearch#69292 - _is_synthetic_compression_user_turn keys on the TODO_INJECTION_HEADER content marker, which merge-at-tail would bury mid-content). - Strip a previously merged snapshot block before re-injection so repeated boundaries refresh rather than accumulate todo state, and refresh a bare stale snapshot row in place instead of stacking a duplicate (empty/stale-skip semantics from NousResearch#26981 by @YLChen-007). - Scaffolding tails keep the flagged standalone append (pre-NousResearch#53890 status quo; adjacent user rows are repaired downstream by repair_message_sequence / _merge_consecutive_roles).
…pshot refresh Covers the follow-up hardening: continuation-marker and summary-as-user tails keep the flagged standalone snapshot (zero-user provenance NousResearch#69292 verified via _transcript_has_real_user_turn on the projected rows), stale snapshot rows are refreshed in place, a previously merged snapshot is stripped before re-injection, and an all-completed todo store injects nothing (NousResearch#26981).
… the quiet-engine resolver Follow-up for the salvaged NousResearch#35191: the mid-turn pre-API pressure emit in conversation_loop.py and the idle-resume emit in turn_context.py were not routed through automatic_compaction_status_message, so an engine with emit_automatic_compaction_status=False still leaked those lines. Both now resolve through the hook (phases "pre_api" and "idle") while keeping the NousResearch#69550 template constants as the default wording. Suppression also skips the NousResearch#69546 structured 'compacted' terminal edge for compress-phase events that opened no visible phase; failure warnings (_emit_warning) remain never suppressible, pinned by test.
… lookup + verify lock reacquire after fence cancel - gateway/run.py: use _adapter_for_source(source) instead of the raw adapters.get(source.platform) map so the compression-timeout warning respects transport provenance, relay ingress, and multiplexed profiles (matches every other user-facing send in the hygiene block). - tests: add a lock-release verification regression — a fence-cancelled hygiene compression must leave the per-session compression lock free so the next attempt (manual /compress retry) acquires it and commits normally.
… detect squash-merged work (NousResearch#69831) The startup pruner only considered directories named hermes-* (the hermes -w scratch trees), so salvage/review/port lanes created with raw 'git worktree add' accumulated forever — a real checkout reached 117 directories / 26 GB with trees dating back months. Two further leaks: squash-merged branches' local commits stay unreachable from refs/remotes/* forever, so the unpushed-commits guard preserved fully merged scratch trees indefinitely; and preserved trees rotted silently with no visibility. - Pruner now covers every directory under .worktrees/ except kanban task trees (t_<hex>, owned by 'hermes kanban gc'). Named (non hermes-*) trees get a 3x timeline (72h soft / 9d hard) since they were created deliberately. - New _worktree_commits_all_merged_upstream(): git-cherry patch-equivalence check against origin/HEAD|main|master, bounded at 20 commits ahead, fails safe toward preserve. Lets the pruner reap trees whose every local-only commit already landed upstream via squash-merge/cherry-pick. - Dirty guard now applies at every tier (previously the 24-72h tier skipped it — it only survived because the unpushed check usually caught the same trees). - Trees preserved for unpushed/dirty reasons older than 7 days are listed in a single WARNING so in-flight work can't rot silently. - tips.py text updated; 13 new behavior-contract tests.
Upgrade pip before lazy refreshes, probe core imports when a lazy install fails, force-reinstall corrupted packages with pyproject pins, use package-only install (no shim quarantine) for repair, and keep the .update-incomplete marker until refresh/repair succeeds (NousResearch#57828).
Add repair/probe/quarantine regression tests and update autostash mocks for the new lazy-refresh signature.
Keep .update-incomplete across normal hermes.exe launches, heal via package-only import probes first, and only clear the marker after repair succeeds (NousResearch#57828 / NousResearch#58004 review).
Keep .update-incomplete for full .[all] recovery only. Lazy refresh uses .lazy-refresh-incomplete and clears only after confirmed import probes; unavailable probes are indeterminate, not healthy (NousResearch#58004 review).
The hermes console entry point is hermes_cli.main:main, and main.py imports dotenv (via env_loader) and yaml (via config) at module level. In the NousResearch#57828 failure state — a failed lazy backend refresh wiping a core package's import files while metadata survives — a normal launch crashed while importing main.py, before _recover_from_interrupted_install() and the recovery markers from PR NousResearch#58004 could act. - hermes_cli/_early_recovery.py: stdlib-only bootstrap repair invoked at the very top of main.py, before any third-party import. Probes the fragile core packages via real imports, force-reinstalls broken ones using the pyproject.toml pins, shares main.py's single-flight recovery lock, and never clears markers (the confirmed lifecycle stays with the full recovery path in main.py). - Probe/repair tables now have one canonical home in _early_recovery, reused by main.py so the two layers cannot drift. - Manual --force-reinstall fallback commands now print pinned specs via _lazy_refresh_repair_specs() instead of bare package names. - tests: entry-point lifecycle coverage proving a broken dotenv import crashes main.py without repair and imports cleanly with it, a stdlib-only import guard for _early_recovery, and unit coverage for marker gating, lock single-flight, pinned specs, and marker preservation.
…the shared current() pointer
recover_with_credential_pool identified "which credential failed" via
pool.current(), a shared mutable pointer that is advanced by every
select() (round-robin rotation, concurrent turns, and other processes
reloading the pool reset it to None). By the time recovery ran, it
routinely pointed at a different, healthy entry — mark_exhausted_and_rotate
then stamped the failing request's error message and reset time onto that
innocent entry. With round_robin and one hard-capped key this
deterministically exhausted the healthy key too and took the entire pool
offline ("no available entries") from a single rate-limited credential.
mark_exhausted_and_rotate already supports api_key_hint for exactly this
(the auxiliary-client path passes it); the main conversation-loop path
never did. Pass agent.api_key — kept in sync with the entry in use by
_swap_credential — as the hint on all four rotation call sites, and make
the "already exhausted → rotate immediately" pre-check look up the failing
entry by key with the same fallback to current().
Adds regression tests that fail on the old attribution logic: a fresh
pool (current() is None) failing on key B must mark entry B, never
entry A.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…th recovery Review follow-up: the auth path called pool.try_refresh_current() before the hinted rotation, so a stale current() pointer could force-refresh a different, healthy entry — consuming its single-use refresh token, or (for non-OAuth entries, where a forced refresh marks the entry exhausted outright) killing it entirely before api_key_hint was ever consulted. Use try_refresh_matching(api_key_hint=...) to resolve and refresh the entry that supplied the failing key under the pool lock, falling back to the previous behavior when no key is known. Adds a regression test with current() deliberately pointed at the healthy entry: on the old code the healthy entry is exhausted by the forced refresh and the pool ends up fully offline; with the fix the failing entry is exhausted and recovery rotates to the healthy one. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Follow-up to the NousResearch#58738 salvage: the pre-exhausted check now enumerates pool.entries() to find the failing key, so the MagicMock pool double must expose entries as a callable, not a bare list.
…ovider transports (NousResearch#56747) Six spawn sites reachable from the desktop GUI / TUI gateway lacked CREATE_NO_WINDOW, so a windowless parent (pythonw/Electron) flashed a conhost per spawn: cli.exec RPC, quick-commands exec dispatch, and shell.exec RPC in tui_gateway/server.py; the CLI REPL quick-commands exec in cli.py; and the per-session provider transports in agent/copilot_acp_client.py and agent/transports/codex_app_server.py (Popen, hide-only so PIPE stdio stays intact). All use hermes_cli._subprocess_compat.windows_hide_flags() (no-op on POSIX), matching the pattern already used at three other sites in tui_gateway/server.py. Deliberately hide-only — no detach flags, no Electron changes (per the NousResearch#54220 revert history). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…e-flag sites Mocked-subprocess tests asserting creationflags == CREATE_NO_WINDOW for each path salvaged from PR NousResearch#56877: tui_gateway cli.exec / shell.exec / quick-command dispatch, the CLI quick-command exec handler, and the Copilot ACP + Codex app-server Popen transports (pipes asserted intact). Verified: all 6 fail with the fix reverted, pass with it applied.
…ation tests The three subprocess tests spawn 'sys.executable -c' children that import hermes_cli. From a worktree, the child resolved the MAIN checkout's editable install instead of the tree under test, so the new DB/CLI guards appeared missing and the tests failed with rc=0. Route the spawns through a helper that pins the repo root under test on PYTHONPATH.
…he literal name _resolve_task_provider_model() returned an explicit provider="moa" override (from a caller-passed arg, or auxiliary.<task>.provider: moa in config.yaml) verbatim, with no MoA-preset unwrap. Only the *implicit* "main provider is moa" path inside _resolve_auto() unwraps to the aggregator slot (NousResearch#53827) — this function never goes through _resolve_auto() at all, so the explicit case was never covered. MoA is a virtual provider with no real HTTP endpoint: resolve_provider_client() looks "moa" up in PROVIDER_REGISTRY (no such entry), falls to the unknown-provider dead end, and call_llm surfaces a nonsensical "Provider 'moa' is set in config.yaml but no API key was found. Set the MOA_API_KEY environment variable..." error for a provider that was never meant to be reached over the wire. Fix mirrors NousResearch#53827's aggregator-resolution approach exactly: when either the explicit `provider` arg or the config-derived `cfg_provider` is "moa", resolve the named (or default) MoA preset via resolve_moa_preset() and continue with its aggregator's real provider+model, dropping any explicit base_url/api_key (the moa:// virtual endpoint and placeholder key belong to the facade, not the aggregator's real provider). If the preset can't be resolved (renamed/deleted), degrades gracefully to the pre-fix behavior instead of raising harder. - agent/auxiliary_client.py: _unwrap_moa_provider() helper + call sites for both the explicit-arg and config-derived provider="moa" cases in _resolve_task_provider_model(). Also tightened base_url/api_key parameter types to Optional[str] (matching their actual None-accepting behavior), which incidentally resolved 5 pre-existing ty diagnostics at call sites. - 5 new regression tests in tests/agent/test_auxiliary_client.py: explicit arg unwrap, config-derived unwrap, default-preset fallback when no model is configured, graceful degradation on preset-resolution failure, and a non-moa regression guard.
Adds moa.privacy_filter ('' | display | full, default off — issue NousResearch#59959):
- display: redact user-visible surfaces only (reference blocks emitted to
the UI + saved MoA trace records, including per-advisor full input/output
and the aggregator-input copy); the aggregator sees raw advisor text so
synthesis quality is unaffected.
- full: additionally redact the advisor text injected into the aggregator
prompt, on both the persistent facade path and the one-shot /moa
synthesis path (the issue's literal ask). Legacy boolean true maps here.
Secret/credential shapes (API-key prefixes, JWTs, private keys, DB
connection strings) are delegated to the central redactor
(agent.redact.redact_sensitive_text, force=True + code_file=True); the MoA
filter adds only email and clearly delimited phone-number patterns. No
bare 10-digit matching: line numbers, timestamps, epoch values, git SHAs,
IPs, versions, and source-code assignments in code-review-shaped advisory
text pass through byte-identical. The reference cache always holds raw
text — redaction happens at each consuming surface, so a mid-session mode
change never leaks or double-redacts.
Reworked from PR NousResearch#60463: replaced its hand-rolled pattern list (which
matched bare digit runs and re-implemented key shapes) with central-
redactor reuse + safe patterns, and split the single boolean into
display/full modes. Credited for the feature framing.
Co-authored-by: webtecnica <75556242+webtecnica@users.noreply.github.com>
The Windows /restart watcher's outer Popen spawns the watcher with windows_detach_popen_kwargs() (which carries CREATE_BREAKAWAY_FROM_JOB), but a restrictive parent job object can reject that bit with OSError and the current call has no retry. Preserve the current watcher implementation and add a focused breakaway-denied fallback. Preserved from current main: watcher_python / pythonw.exe selection, the str(restart_after_s) deadline, the scrubbed watcher_env, the intentional no-breakaway inline respawn, and the entire POSIX setsid/bash path. - primary keeps **windows_detach_popen_kwargs() - on OSError, retry the same argv/env with creationflags=windows_detach_flags_without_breakaway() - on dual failure, log a definitive, path-safe warning (interpreter basename + numeric winerror/errno only) and return without crashing Replace the superseded breakaway-first inline design and its AST tests with focused behavioral coverage that drives the real coroutine with a mocked subprocess.Popen (retry, argv/env/DEVNULL preservation, POSIX single-session kwarg, no-breakaway inline respawn, secret-safe logging). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…r subprocesses Salvaged from PR NousResearch#47971 (LSP subset). On Windows, .cmd-wrapped language servers (e.g. pyright-langserver.CMD launched via cmd.exe /c) and the npm/go/pip LSP auto-installers spawn without CREATE_NO_WINDOW, so a console window flashes whenever the spawn happens under a console-less parent — e.g. a VS Code/Zed extension host running the ACP adapter. - agent/lsp/client.py::_spawn: pass creationflags=windows_hide_flags() to the language-server asyncio subprocess (inert 0 on POSIX; start_new_session is kept — it is POSIX-only and ignored on Windows). - agent/lsp/install.py: same flags on the npm and go installer subprocess.run calls. The pip path goes through hermes_cli.tools_config._pip_install, which already hides its windows. Adapted from the PR's hand-rolled _NO_WINDOW constant to the repo's hermes_cli._subprocess_compat.windows_hide_flags() convention.
…o installers Regression tests for the NousResearch#47971 salvage: the LSP language-server spawn must pass windows_hide_flags() creationflags while keeping PIPE stdio and start_new_session, and the npm/go LSP auto-installer subprocess.run calls must carry the same hide flags with DEVNULL stdin and capture_output intact.
Port the HERMES_GIT_BASH_PATH env var check from main.cjs to main.ts after the TS conversion. Also extract findGitBash to a dedicated module for testability and add focused regression tests for override precedence and invalid-override fallback.
…t-bash The extracted findGitBash builds Windows-style candidate paths, but the vitest suite (and any POSIX CI host) runs with posix path.join, which mangles 'C:\Program Files' + segments into slash-joined paths and broke the invalid-override fallback test. Use path.win32.join explicitly so candidate construction is host-independent.
…dule npx eslint --fix + prettier --write on the new files: braces on single-line if returns and blank-line padding per the desktop lint config.
…placing Every moa.reference event called appendReasoningDelta(..., replace=true), which wipes ALL existing reasoning-type message parts and seeds exactly one new part. With two or more MoA reference models, each later reference erased the reasoning disclosure built by earlier references, so only the last advisor's output ever stayed visible instead of one labelled block per reference (contradicting the multi-reference visibility behavior from NousResearch#53855). Only the first reference (index <= 1, or missing) now replaces — preserving the original "clear stale reasoning from before this turn" behavior. Every later reference accumulates via the existing queue-then-flush path instead, applied immediately since each reference arrives as one complete block rather than incremental tokens. Fixes NousResearch#64658
… is hidden Every moa.reference gateway event stores its labelled reference-model output in a Msg's generic `thinking` field (turnController's recordMoaReference), which messageLine.tsx and the ToolTrail component gate on `display.sections.thinking`'s resolved mode. When that mode resolves to `hidden`, MoA reference blocks were suppressed along with ordinary model reasoning — even though (per NousResearch#53855) references are the mixture-of-agents process the user explicitly opted into, not private reasoning, and should stay visible regardless of the thinking-section setting. Adds Msg.isMoaReference (set by recordMoaReference), a shouldShowThinkingTrail helper mirroring the existing shouldShowResponseSeparator pattern, and a reasoningAlwaysVisible prop threaded into ToolTrail to bypass the two suppression gates (the trail-wrapper return-null check and the allHidden/panel-push checks) plus the panel's initial open state and the shift-click expand-all gesture, so a MoA reference panel is not just present in the tree but actually visible and openable on first paint. Fixes NousResearch#64657
…ce panels Maintainer review (hermes-sweeper) on this PR found the fix was incomplete: two paths still hid the MoA reference panel under thinking: hidden. 1. thinking.tsx: the mount useState correctly seeds openThinking from (visible.thinking === 'expanded' || reasoningAlwaysVisible), but the re-sync effect on [visible] fires after the FIRST render too, not just later updates, and lacks the reasoningAlwaysVisible OR — so it immediately collapsed a just-opened MoA panel right after mount. Skip only the effect's very first run (a ref flag); every later visible change still re-syncs without the override, preserving the documented no-OR-at-effect-time contract (manual collapse sticks). 2. useMainApp.ts: showProgressArea's streamSegments predicate gated thinking content on thinkingPanelVisible alone, so an MoA reference segment (segment.isMoaReference, same flag messageLine.tsx's shouldShowThinkingTrail already honors per NousResearch#64657) never kept the live progress area up when thinking was hidden — StreamingAssistant then returned early before MessageLine was ever reached. Added the same override. Added tests/thinkingMoaReferenceVisibility.test.tsx: mounts ToolTrail with reasoningAlwaysVisible + sections.thinking: hidden, awaits queued effects, and asserts the chevron is still open (▾, not ▸) once they settle. Validation: npx vitest run src/__tests__/thinkingMoaReferenceVisibility.test.tsx -> 1 passed Fail-before: reverting only the thinking.tsx ref-guard reproduces the exact regression -- the same test's frame capture shows the panel open on first paint then collapsing to ▸ once the effect fires, and the 'not.toContain(▸)' assertion fails as expected. npx vitest run (full ui-tui suite): 1115 passed, 8 failed -- all 8 pre-existing and unrelated (terminalSetup/terminalParity/editor resolution env-path tests), confirmed by running them in isolation with the same result regardless of this diff. npx tsc --noEmit: clean. npx eslint src/components/thinking.tsx src/app/useMainApp.ts: clean.
Salvaged from PR NousResearch#59743. Original author email was malformed (sr@samirusani, not resolvable to a GitHub account), so the commit is re-authored with credit via trailer. Co-authored-by: Sami Rusani <samrusani@users.noreply.github.com>
Adds per-reference progress events and a phase-transition marker to the
MoA display pipeline so TUI / CLI / desktop surfaces can render a status
bar like `MOA: 2/3 refs done` and surface which phase (reference vs
aggregator) is currently active.
- `moa.progress` — fired once per reference completion with
`refs_done`, `refs_total`, and the source label
- `moa.phase` — fired on phase transitions (currently the single
`phase="aggregator"` transition once the fan-out
finishes)
Plumbed through the existing `reference_callback` →
`tool_progress_callback` → gateway path; no new UI surface. The legacy
`moa.reference` / `moa.aggregating` events are unchanged for backwards
compatibility.
AI-assisted fix by https://github.com/SquabbyZ/peaks-loop
….phase Frontend consumers for the events added by PR NousResearch#59646: the TUI shows a replace-in-place 'MoA: refs k/n' activity line (swapped for 'MoA: aggregating…' on the aggregator phase), and desktop streams '◇ MoA refs k/n' lines into the reasoning disclosure, self-cleaned by the first moa.reference block.
Follow-up for salvaged PR NousResearch#59753 rebased over the per-slot reasoning_effort feature: _clean_slot now round-trips reasoning_effort AND enabled together; add a normalize→normalize regression test, update the validate/normalize agreement contract for the canonical enabled default, restore the desktop per-slot toggle test on the current autosave editor, and map oppenheimor's contributor email.
…abled flag The per-reference-model enabled toggle (NousResearch#59753 salvage) intentionally adds 'enabled' to normalized slot dicts. The two endpoint tests asserted the exact key set {provider, model} — convert them to subset + round-trip contracts so optional slot keys (enabled, reasoning_effort, max_tokens) don't break them again.
…-cluster rebase The per-advisor enabled toggle adds enabled=True to normalized slots; the JSON-string-parse and per-slot max_tokens tests from sibling clusters asserted exact dicts. Compare against the enabled-augmented expectation instead.
…talls, and platform.win32_ver()
From windowless processes (the pythonw gateway and the kanban workers it
spawns), three spawn paths flash visible console windows on Windows:
1. tools/env_probe.py::_run() ran its interpreter/pip probes
(python3 / python / pip / 'python3 -m pip' / PEP-668 check, ~5 per
worker start) without creationflags — one console flash per probe.
2. tools/lazy_deps.py had four spawn sites with the same defect:
'uv pip install', the 'pip --version' probe, ensurepip, and the
pip install fallback.
Both now pass creationflags=windows_hide_flags() (CREATE_NO_WINDOW on
Windows, 0 on POSIX) — stdio capture still works because the child is
hidden, not detached.
3. CPython 3.11's platform.win32_ver() unconditionally calls
_syscmd_ver(), which runs 'cmd /c ver' via
subprocess.check_output(shell=True) with no window suppression. Any
dependency touching platform.uname()/version()/platform() at import
time flashes one 'cmd' window per windowless process. New helper
_subprocess_compat.suppress_platform_ver_console() (Windows-only,
never raises) stubs platform._syscmd_ver so win32_ver() falls back to
sys.getwindowsversion().platform_version — verified byte-identical
platform.platform() output on CPython 3.11
('Windows-10-10.0.26100-SP0' either way). Called at the top of
hermes_cli/main.py, right after the hermes_bootstrap guard, before
heavyweight imports.
Verified on Windows 11 by polling EnumWindows at ~15 ms and attributing
new visible HWNDs to the suspect process tree (conhost child presence is
NOT evidence of a visible window — it appears even with
CREATE_NO_WINDOW). Tests: tests/tools/test_windows_native_support.py,
test_env_probe.py, test_lazy_deps.py, test_lazy_deps_durable_target.py —
153 passed; the 3 failures are pre-existing on upstream/main in a
Windows environment (POSIX-only assertions and NTFS chmod semantics).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…run + add no-window tests (NousResearch#67690 follow-up) Follow-up to the NousResearch#67690 salvage (@m4r13y). The PR's tools/env_probe.py hunk was written against the old capture_output=True _run(); NousResearch#67964/NousResearch#67999 rewrote _run to temp-file capture on July 20, so that hunk no longer applied — but the rewritten _run still lacked creationflags and kept flashing one console per probe (~5 per kanban worker start) from windowless parents. Re-implement the one-line fix against the current shape: creationflags=windows_hide_flags() on the temp-file subprocess.run, preserving the NousResearch#67964 grandchild-can't-wedge-the-pipe contract. Also add the tests the PR didn't ship, in tests/test_windows_subprocess_no_window_flags.py: - env_probe._run passes CREATE_NO_WINDOW and keeps temp-file (non-PIPE) stdout/stderr + DEVNULL stdin - lazy_deps uv install / pip --version probe / pip install fallback / ensurepip bootstrap all pass CREATE_NO_WINDOW - suppress_platform_ver_console: POSIX no-op (platform._syscmd_ver untouched, win32_ver() still returns), and simulated-Windows stubbing (echo stub installed, idempotent, never raises)
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 fail-closed upstream sync. Locally verified head: fde81f6