feat: remote MarkRoleDegraded + task-cancel HIVE endpoints - #94
Conversation
Closes two long-deferred HIVE validation gaps: forced role recycle and single-task cancellation were both only reachable from internal code paths, never remotely. Adds POST /hive/roles/degrade and POST /hive/tasks/cancel, Warchief-only authenticated, mirroring the existing /hive/update/deploy pattern. Task cancel required a new per-task CancellationTokenSource registry in HiveWorkerAgent, separate from the worker's whole-process lifetime token, so a remote cancel interrupts exactly one task. Live-verified against a real deployed daemon (HardcorePC), not just unit tests. That verification surfaced a genuine pre-existing bug: HiveElectionService.WarchiefNodeId was never wired from static config, meaning the pre-existing /hive/update/deploy endpoint was silently unusable in this fleet's actual deployment shape. Fixed alongside the new endpoints. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Replaces every stale "Ollama stays default" / "not the default yet" line with dated status notes reflecting the 2026-07-29 §6 decision, following the doc's own established pattern of layering status updates rather than rewriting history. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
|
Important Review skippedAuto incremental reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Plus Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
📝 WalkthroughWalkthroughThe daemon now wires authenticated Warchief-only Hive endpoints for native role degradation and per-task cancellation. Native runtime and worker cancellation APIs implement these actions, with tests and validation documentation covering authorization, unknown tasks, and live endpoint behavior. The roadmap records native defaults. ChangesHive control operations
Estimated code review effort: 4 (Complex) | ~45 minutes Sequence Diagram(s)sequenceDiagram
participant Warchief
participant HiveNodeServer
participant NativeRoleRuntime
participant HiveWorkerAgent
Warchief->>HiveNodeServer: POST /hive/roles/degrade
HiveNodeServer->>NativeRoleRuntime: MarkRoleDegraded(role)
NativeRoleRuntime-->>HiveNodeServer: Return success response
Warchief->>HiveNodeServer: POST /hive/tasks/cancel
HiveNodeServer->>HiveWorkerAgent: TryCancelTask(taskId)
HiveWorkerAgent-->>HiveNodeServer: Return cancellation result
Possibly related PRs
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches 💡 1📝 Generate docstrings 💡
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 4
🧹 Nitpick comments (1)
OrchestratorIDE/Services/Hive/HiveNodeServer.cs (1)
1026-1036: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winFire-and-forget failure bypasses this class's own diagnostics channel.
The catch inside the background
Task.Runlogs viaConsole.Error.WriteLineinstead ofOnLog?.Invoke(...), which is what every other diagnostic path in this class uses (per the doc comment at line 171-173,OnLogis what "UI subscribes and surfaces ... in the HIVE Activity panel"). In the WPF-hosted case this class also serves (per this file's own doc comments elsewhere), aMarkRoleDegradedfailure written to stderr is invisible to the operator, whereas routing it throughOnLogwould surface it the same way pairing/re-sync/dev-approve diagnostics already do.♻️ Proposed fix
- catch (Exception ex) { /* best-effort: the next mint will still recycle on its own detection paths */ Console.Error.WriteLine($"[HiveNodeServer] MarkRoleDegraded({role}) failed: {ex.Message}"); } + catch (Exception ex) + { + // best-effort: the next mint will still recycle on its own detection paths + OnLog?.Invoke($"⚠ MarkRoleDegraded({role}) failed: {ex.Message}"); + }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@OrchestratorIDE/Services/Hive/HiveNodeServer.cs` around lines 1026 - 1036, Update the exception handler in the background task around MarkRoleDegradedHandler to report failures through this class’s OnLog?.Invoke diagnostic channel instead of Console.Error.WriteLine, preserving the existing failure context and best-effort fire-and-forget behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@docs/NATIVE_RUNTIME_HIVE_VALIDATION_PLAN.md`:
- Line 765: Add language identifiers to both fenced request examples in the
validation plan, using http for HTTP requests or text where appropriate. Update
both referenced examples consistently without changing their contents.
- Around line 895-899: Update the HV-4 Item 1 coverage status in the plan so it
is not marked fully covered unless Tools/Hv4RecoveryRunner actively starts a
task, invokes the worker-side cancellation endpoint during generation, and
verifies OperationCanceledException or the resulting failure; otherwise retain
the partial-coverage status.
In `@docs/ROADMAP.md`:
- Around line 663-676: Update the Phase 3 roadmap row and the section preface to
remove stale “live opt-in” and “not the default” wording, while preserving
qualifiers about prototype or production readiness. Ensure the text consistently
states that native runtime selection is now the default and Ollama remains an
opt-out alternative, referencing the status note and Phase 3 entry.
In `@OrchestratorIDE/Services/Hive/HiveNodeServer.cs`:
- Around line 1015-1024: Update the role validation in the MarkRoleDegraded
request handling before invoking MarkRoleDegradedHandler to reject parsed
RuntimeRole values that are not defined enum members. Preserve the existing
case-insensitive name parsing and documented 400 response, including the
expected-role message, for undefined numeric or other invalid values.
---
Nitpick comments:
In `@OrchestratorIDE/Services/Hive/HiveNodeServer.cs`:
- Around line 1026-1036: Update the exception handler in the background task
around MarkRoleDegradedHandler to report failures through this class’s
OnLog?.Invoke diagnostic channel instead of Console.Error.WriteLine, preserving
the existing failure context and best-effort fire-and-forget behavior.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro Plus
Run ID: ef73da05-e612-4bd2-a36d-e17014816031
📒 Files selected for processing (8)
OrchestratorIDE.Daemon/HiveService.csOrchestratorIDE.UnitTests/HiveNodeServerAuthorizationTests.csOrchestratorIDE.UnitTests/HiveWorkerAgentTests.csOrchestratorIDE/Core/Runtime/IRoleRuntime.csOrchestratorIDE/Services/Hive/HiveNodeServer.csOrchestratorIDE/Services/Hive/HiveWorkerAgent.csdocs/NATIVE_RUNTIME_HIVE_VALIDATION_PLAN.mddocs/ROADMAP.md
| signed-request harness (deleted after use, matching this session's earlier spike/probe | ||
| convention) hit the real endpoint over the network with a genuine HMAC-signed, Warchief-identity | ||
| request: | ||
| ``` |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
Add language identifiers to the fenced request examples.
Use an appropriate fence such as ```http or ```text for both examples.
Also applies to: 884-884
🧰 Tools
🪛 markdownlint-cli2 (0.23.1)
[warning] 765-765: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@docs/NATIVE_RUNTIME_HIVE_VALIDATION_PLAN.md` at line 765, Add language
identifiers to both fenced request examples in the validation plan, using http
for HTTP requests or text where appropriate. Update both referenced examples
consistently without changing their contents.
Source: Linters/SAST tools
| **Item 1 is now fully covered.** The plan's original ask — cancellation surfacing mid-generation | ||
| as an `OperationCanceledException` on the worker via a real remote trigger — has that trigger. | ||
| `Tools/Hv4RecoveryRunner`'s `cancel` phase still exercises only the Warchief-side campaign-cancel | ||
| path (a different, already-covered mechanism); wiring the harness to also exercise this new | ||
| worker-side endpoint is a natural follow-up, not yet done. |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | 🏗️ Heavy lift
Do not mark HV-4 item 1 fully covered without exercising cancellation of an active task.
Lines [888-893] explicitly state that no in-flight task was available and that the successful cancellation path rests only on code review. Either add a live test that starts a task and verifies OperationCanceledException/failure, or keep item 1 partially covered until the harness exercises that path.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@docs/NATIVE_RUNTIME_HIVE_VALIDATION_PLAN.md` around lines 895 - 899, Update
the HV-4 Item 1 coverage status in the plan so it is not marked fully covered
unless Tools/Hv4RecoveryRunner actively starts a task, invokes the worker-side
cancellation endpoint during generation, and verifies OperationCanceledException
or the resulting failure; otherwise retain the partial-coverage status.
| > evidence artifact (PR #81) has landed too, verified on real hardware. | ||
| > | ||
| > **Status changed 2026-07-29 — native IS now the default, superseding every "not the default | ||
| > yet" line in this section below.** `NATIVE_RUNTIME_V2_SPEC.md` §6's gated milestone (live | ||
| > multi-machine HIVE validation, `docs/NATIVE_RUNTIME_HIVE_VALIDATION_PLAN.md` HV-1 through | ||
| > HV-6) completed with HV-6 at genuine 3×-repeated, 9/9-lane evidence, and the explicit product | ||
| > decision that milestone requires was recorded the same day. | ||
| > `AppSettings.ExperimentalNativeHiveWorkerEnabled`/`ExperimentalNativeMainChatEnabled` now | ||
| > default to `true`. Ollama remains fully implemented and available as `IModelRuntime`'s other | ||
| > backend — installs can still opt back out — it is simply no longer the default construction | ||
| > path in `MainWindow`'s HIVE-worker and main-chat runtime builders. The "until the ModelDepot + | ||
| > installer first-run story is bulletproof..." criterion further down this section is superseded | ||
| > by that decision, made against the HV-6 evidence instead. | ||
|
|
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
Reconcile the new native-default claim with the remaining opt-in wording.
The updated status says native is the default, but the phase-3 row still calls it a “live opt-in proof path,” while the section preface retains “not the default” language. Update these qualifiers so the roadmap clearly distinguishes default runtime selection from prototype/production readiness.
Also applies to: 687-687
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@docs/ROADMAP.md` around lines 663 - 676, Update the Phase 3 roadmap row and
the section preface to remove stale “live opt-in” and “not the default” wording,
while preserving qualifiers about prototype or production readiness. Ensure the
text consistently states that native runtime selection is now the default and
Ollama remains an opt-out alternative, referencing the status note and Phase 3
entry.
| MarkRoleDegradedRequest? payload; | ||
| try { payload = JsonSerializer.Deserialize<MarkRoleDegradedRequest>(body, _jsonIn); } | ||
| catch { resp.StatusCode = 400; Error(resp, "bad request"); return; } | ||
|
|
||
| if (payload is null || !Enum.TryParse<RuntimeRole>(payload.Role, ignoreCase: true, out var role)) | ||
| { | ||
| resp.StatusCode = 400; | ||
| Error(resp, $"invalid or missing role (expected one of: {string.Join(", ", Enum.GetNames<RuntimeRole>())})"); | ||
| return; | ||
| } |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/usr/bin/env bash
set -euo pipefail
echo "Repository files containing HiveNodeServer.cs:"
git ls-files | grep -F 'HiveNodeServer.cs' || true
echo
echo "Relevant source excerpt:"
if [ -f "OrchestratorIDE/Services/Hive/HiveNodeServer.cs" ]; then
sed -n '980,1080p' "OrchestratorIDE/Services/Hive/HiveNodeServer.cs" | nl -ba -v980
fi
echo
echo "Search RuntimeRole and MarkRoleDegradedHandler:"
rg -n "enum RuntimeRole|RuntimeRole|MarkRoleDegradedHandler|MarkRoleDegradedRequest" -S .
echo
echo ".NET Enum.TryParse behavior probe:"
python3 - <<'PY'
# Python enum TryParse has different behavior; this block exists only to satisfy framework if present.
PYRepository: hardcoreerik/TheOrc
Length of output: 319
🏁 Script executed:
#!/usr/bin/env bash
set -euo pipefail
# Behavioral probe outside repository code: compile and run a small .cs file if dotnet is available.
cat > /tmp/EnumTryParseProbe.cs <<'CS'
using System;
using System.Reflection;
enum RuntimeRole { None = 0, Leader = 1, Follower = 2 }
class Program
{
static int Main()
{
string[] testCases = new[] { "Leader", "999", "leader", "1", "0", "abc" };
foreach (var role in testCases)
{
if (Enum.TryParse<RuntimeRole>(role, ignoreCase: true, out var parsed))
Console.WriteLine($"{role,-6} -> parsed={parsed} (undefined={(!Enum.IsDefined<RuntimeRole>(parsed)).ToString().ToLower()})");
else
Console.WriteLine($"{role,-6} -> parsed_null");
}
return 0;
}
}
CS
if command -v dotnet >/dev/null 2>&1; then
tmpdir="$(mktemp -d)"
cp /tmp/EnumTryParseProbe.cs "$tmpdir/Program.cs"
(
cd "$tmpdir"
dotnet new console --force --no-restore >/dev/null 2>&1 || true
dotnet build >/dev/null 2>&1 || exit 1
dotnet run
)
else
echo "dotnet not available; cannot run behavioral probe"
fi
rm -f /tmp/EnumTryParseProbe.cs
rm -rf "${tmpdir:-}"Repository: hardcoreerik/TheOrc
Length of output: 207
🏁 Script executed:
#!/usr/bin/env bash
set -euo pipefail
# Behavioral probe outside repository code: compile and run a small .cs file if dotnet is available.
cat > /tmp/EnumTryParseProbe.cs <<'CS'
using System;
using System.Reflection;
enum RuntimeRole { None = 0, Leader = 1, Follower = 2 }
class Program
{
static int Main()
{
string[] testCases = new[] { "Leader", "999", "leader", "1", "0", "abc" };
foreach (var role in testCases)
{
if (Enum.TryParse<RuntimeRole>(role, ignoreCase: true, out var parsed))
Console.WriteLine($"{role,-6} -> parsed={parsed} (undefined={(!Enum.IsDefined<RuntimeRole>(parsed)).ToString().ToLower()})");
else
Console.WriteLine($"{role,-6} -> parsed_null");
}
return 0;
}
}
CS
if command -v dotnet >/dev/null 2>&1; then
tmpdir="$(mktemp -d)"
cp /tmp/EnumTryParseProbe.cs "$tmpdir/Program.cs"
(
cd "$tmpdir"
dotnet new console --force --no-restore >/dev/null 2>&1 || true
dotnet build >/dev/null 2>&1 || exit 1
dotnet run
)
else
echo "dotnet not available; cannot run behavioral probe"
fi
2> /tmp/enum_probe_err.txt; true
rm -f /tmp/EnumTryParseProbe.cs /tmp/enum_probe_err.txt
rm -rf "${tmpdir:-}"Repository: hardcoreerik/TheOrc
Length of output: 207
🌐 Web query:
Microsoft .NET Enum.TryParse numeric string undefined enum value IsDefined behavior
💡 Result:
In.NET, the Enum.TryParse method is designed to parse both the names and the underlying numeric values of an enumeration [1][2][3]. When a numeric string is provided, Enum.TryParse will successfully parse it into the target enum type even if that numeric value is not explicitly defined in the enumeration [1][4][5]. This behavior occurs because Enum.TryParse treats any string representation of an integer as a valid attempt to convert to the enum's underlying integral type [1][2][5]. Consequently, the method will return true and output the corresponding enum value, regardless of whether that value corresponds to a named member [4][6]. If this behavior is undesirable and you need to ensure that the parsed value is a valid, defined member of the enumeration, you must explicitly call Enum.IsDefined after a successful parse [1][2][5]. Example of the safe usage pattern: string input = "99"; // An undefined value if (Enum.TryParse(input, out MyEnum result) && Enum.IsDefined(typeof(MyEnum), result)) { // Result is a valid, defined member of the enum } else { // Handle invalid or undefined value } Note that Enum.IsDefined evaluates whether the specific value (or name) exists within the enumeration [7][5]. In cases where you are dealing with enumerations marked with the [Flags] attribute, keep in mind that Enum.IsDefined may return false for composite values (e.g., bitwise combinations) even if they are logically valid for your use case, and you should use Enum.HasFlag instead [7].
Citations:
- 1: https://learn.microsoft.com/en-us/dotnet/api/system.enum.tryparse?view=net-10.0
- 2: https://learn.microsoft.com/en-us/dotnet/api/system.enum.tryparse?view=net-9.0
- 3: https://learn.microsoft.com/en-us/dotnet/api/system.enum.tryparse?view=netframework-4.8.1
- 4: https://stackoverflow.com/questions/60076457/enumt-parse-allows-parsing-any-string-that-is-an-integer-is-it-a-bug-in-net
- 5: https://learn.microsoft.com/en-us/dotnet/fundamentals/runtime-libraries/system-enum
- 6: https://gaevoy.com/2021/12/01/parsing-enum-pitfalls.html
- 7: https://learn.microsoft.com/en-us/dotnet/api/system.enum.isdefined?view=net-9.0
🌐 Web query:
Microsoft .NET Enum.TryParse numeric string undefined enum value IsDefined behavior
💡 Result:
In.NET, the Enum.TryParse method is designed to succeed even when the input numeric string does not correspond to a defined constant within the enumeration [1][2][3]. If the input string is a valid representation of the underlying integral type of the enum, Enum.TryParse will parse it and return true, assigning the resulting value to the output parameter [1][4]. This behavior is intentional, as it allows the method to support the parsing of underlying integral values that may not be explicitly named constants [1][5]. Because Enum.TryParse returns true for these undefined values, it does not implicitly validate that the result is a defined member of the enumeration [6][3]. To ensure that a parsed value is an actual defined member of the enum, you must explicitly call Enum.IsDefined [1][6]. When using Enum.IsDefined for this purpose, it is critical to pass the enum value itself, not the original string [6][7]. Enum.IsDefined(typeof(TEnum), "some_string") looks for a member named "some_string" and will return false if the string is numeric, even if that number corresponds to a valid enum constant [7]. Instead, you should perform the following sequence [6][8][7]: 1. Use Enum.TryParse to convert the string to the enum type [1][8]. 2. Pass the resulting enum value to Enum.IsDefined to verify it is a defined constant [6][8]. Example: string input = "99"; // Undefined value if (Enum.TryParse(input, out MyEnum result)) { if (Enum.IsDefined(typeof(MyEnum), result)) { // Value is defined } else { // Value is parsed but not defined in the enum } }
Citations:
- 1: https://learn.microsoft.com/en-us/dotnet/api/system.enum.tryparse?view=net-9.0
- 2: https://learn.microsoft.com/en-us/dotnet/api/system.enum.tryparse?view=net-10.0
- 3: https://stackoverflow.com/questions/60076457/enumt-parse-allows-parsing-any-string-that-is-an-integer-is-it-a-bug-in-net
- 4: https://learn.microsoft.com/en-us/dotnet/api/system.enum.tryparse?view=netframework-4.8.1
- 5: https://learn.microsoft.com/en-us/dotnet/api/system.enum.parse?view=net-9.0
- 6: https://learn.microsoft.com/en-us/dotnet/fundamentals/runtime-libraries/system-enum
- 7: https://stackoverflow.com/questions/62739215/enum-is-defined-not-giving-value-from-index
- 8: https://gaevoy.com/2021/12/01/parsing-enum-pitfalls.html
🏁 Script executed:
#!/usr/bin/env bash
set -euo pipefail
echo "Relevant HiveNodeServer excerpt:"
sed -n '980,1090p' "OrchestratorIDE/Services/Hive/HiveNodeServer.cs" | awk '{printf "%6d\t%s\n", NR+979, $0}'
echo
echo "RuntimeRole definition and handler usages:"
rg -n "enum RuntimeRole|RuntimeRole|MarkRoleDegradedHandler|MarkRoleDegradedRequest|IsDefined" -S "OrchestratorIDE/Services/Hive"Repository: hardcoreerik/TheOrc
Length of output: 7935
Reject undefined RuntimeRole values before invoking the handler.
.NET enum parsing accepts valid integer strings for undefined values, so {"role":"999"} currently returns success and calls MarkRoleDegradedHandler(999) instead of returning the documented 400 role validation error.
🛡️ Proposed fix
- if (payload is null || !Enum.TryParse<RuntimeRole>(payload.Role, ignoreCase: true, out var role))
+ if (payload is null
+ || !Enum.TryParse<RuntimeRole>(payload.Role, ignoreCase: true, out var role)
+ || !Enum.IsDefined(role))
{📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| MarkRoleDegradedRequest? payload; | |
| try { payload = JsonSerializer.Deserialize<MarkRoleDegradedRequest>(body, _jsonIn); } | |
| catch { resp.StatusCode = 400; Error(resp, "bad request"); return; } | |
| if (payload is null || !Enum.TryParse<RuntimeRole>(payload.Role, ignoreCase: true, out var role)) | |
| { | |
| resp.StatusCode = 400; | |
| Error(resp, $"invalid or missing role (expected one of: {string.Join(", ", Enum.GetNames<RuntimeRole>())})"); | |
| return; | |
| } | |
| MarkRoleDegradedRequest? payload; | |
| try { payload = JsonSerializer.Deserialize<MarkRoleDegradedRequest>(body, _jsonIn); } | |
| catch { resp.StatusCode = 400; Error(resp, "bad request"); return; } | |
| if (payload is null | |
| || !Enum.TryParse<RuntimeRole>(payload.Role, ignoreCase: true, out var role) | |
| || !Enum.IsDefined(role)) | |
| { | |
| resp.StatusCode = 400; | |
| Error(resp, $"invalid or missing role (expected one of: {string.Join(", ", Enum.GetNames<RuntimeRole>())})"); | |
| return; | |
| } |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@OrchestratorIDE/Services/Hive/HiveNodeServer.cs` around lines 1015 - 1024,
Update the role validation in the MarkRoleDegraded request handling before
invoking MarkRoleDegradedHandler to reject parsed RuntimeRole values that are
not defined enum members. Preserve the existing case-insensitive name parsing
and documented 400 response, including the expected-role message, for undefined
numeric or other invalid values.
grok-review (PR #94, full mode) caught it before merge: a remote /hive/tasks/cancel reported status "failed" back to the Warchief, and HiveTaskQueue.HandleFailAsync requeues campaign work whenever attempts remain -- so cancelling a task would have quietly resurrected it on another attempt instead of stopping it. Fixed by giving remote cancellation its own terminal status. ClaimAndExecuteAsync distinguishes a taskCts-triggered OperationCanceledException from a genuine failure and reports "cancelled" instead of "failed"; HandleFailAsync now checks that field first and skips its requeue branch when set, reusing the "cancelled" status that already exists for Warchief-initiated campaign cancellation rather than inventing a second vocabulary. Also from the same review pass: HandleMarkRoleDegraded now awaits its handler and reports real failures instead of responding 200 before a fire-and-forget call that could silently fail (this exact endpoint hit a real MissingMethodException during its own deployment verification); and /hive/update/deploy uses the shared IsWarchief helper instead of a duplicate inline check. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Reject undefined RuntimeRole values: Enum.TryParse alone accepts any
integer string as a "successfully parsed" undefined value, so
{"role":"999"} would have called MarkRoleDegradedHandler((RuntimeRole)999)
instead of the documented 400. Added Enum.IsDefined.
Softened the HV-4 item 1 "fully covered" claim to accurately reflect what
was actually live-verified (routing/auth/validation, via 404/400 responses)
versus what still rests on code review (the actual mid-generation cancel
path, since no task was in flight during verification).
Reconciled ROADMAP.md's Phase 2/3 rows, which still read "not
production/default" and "opt-in" right below the new "native is now
default" status note -- clarified that those rows are about prototype
completeness, a different axis from runtime-selection default status.
Fixed two markdownlint fenced-code-language warnings.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
The last real gap flagged in this session's HIVE-testing work: TryCancelTask's "found and actually cancels" path had no coverage, only the "unknown taskId" negative case. This needed a task genuinely claimed in flight, not just a constructed HiveWorkerAgent. TryCancelTask_OnATaskActuallyInFlight_ReportsCancelledNotFailed starts a real HiveWorkerAgent against a fake Warchief (bare HttpListener -- only needs to hand out one lease and accept one fail-POST, not validate HMAC auth like the real HiveNodeServer) leasing a task backed by a Runtime whose StreamCompletionAsync blocks on the cancellation token indefinitely. A TaskCompletionSource signals the instant generation actually starts, so the cancel is synchronized against genuinely in-flight work rather than a fixed sleep guess. Asserts the terminal report is "Cancellation reported to Warchief," never "Failure reported" -- the exact distinction PR #94's grok-review fix exists to preserve (a plain "failed" status would let HiveTaskQueue.HandleFailAsync silently requeue the same work, the opposite of what cancelling means). Verified stable across 5 repeated runs (~585ms each) before landing. Full suite: 693/706 (13 skipped, native-GGUF-gated as always). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Summary
POST /hive/roles/degrade(forced role recycle) andPOST /hive/tasks/cancel(single in-flight task cancel), both Warchief-only authenticated, mirroring the existing/hive/update/deploypattern.HiveWorkerAgentgained a per-taskCancellationTokenSourceregistry so a remote cancel interrupts exactly one task, independent of the worker's own lifetime token.HiveElectionService.WarchiefNodeIdwas never wired from static config, so the existing/hive/update/deployendpoint was silently unusable in this fleet's actual deployment shape the whole time.docs/ROADMAP.mdupdated to reflect the 2026-07-29 native-runtime default flip.Test plan
docs/NATIVE_RUNTIME_HIVE_VALIDATION_PLAN.mdHV-3/HV-4 sections updated with the full live-verification trail🤖 Generated with Claude Code
Summary by CodeRabbit
New Features
Bug Fixes
Documentation