Skip to content

nix build, nix profile: Report failing/succeeding installables#281

Merged
edolstra merged 7 commits intomainfrom
show-build-result
Dec 4, 2025
Merged

nix build, nix profile: Report failing/succeeding installables#281
edolstra merged 7 commits intomainfrom
show-build-result

Conversation

@edolstra
Copy link
Collaborator

@edolstra edolstra commented Nov 26, 2025

Motivation

If any installable fails to build in nix build or nix profile install/upgrade, Nix will print something like

# nix build /home/eelco/Dev/patchelf /home/eelco/Dev/patchelf#hydraJobs.coverage nixpkgs#hello 
✅ flake:nixpkgs#hello
❌ git+file:///home/eelco/Dev/patchelf#packages.x86_64-linux.default
error: Cannot build '/nix/store/nh2dx9cqcy9lw4d4rvd0dbsflwdsbzdy-patchelf-0.18.0.drv'.
       Reason: builder failed with exit code 2.
       ...
❓ git+file:///home/eelco/Dev/patchelf#hydraJobs.coverage (cancelled)

It doesn't print anything if all installables succeed.

Context


Add 👍 to pull requests you find important.

The Nix maintainer team uses a GitHub project board to schedule and track reviews.

Summary by CodeRabbit

  • Bug Fixes

    • Improved error handling: build errors are reported and raised before results are consumed; cancelled builds are distinguished and reported.
    • Added explicit "Cancelled" status for clearer failure reporting.
  • Chores

    • Reworked per-item build result representation and extraction for more reliable result propagation.
  • Tests

    • Updated functional test expectations to match refined failure/cancellation behavior.

✏️ Tip: You can customize this high-level summary in your review settings.

This denotes the result of a build that didn't succeed or fail, but
was cancelled because some other goal failed and --keep-going was not
enabled.
@coderabbitai
Copy link

coderabbitai bot commented Nov 26, 2025

Walkthrough

Replaces pair-based build results with a variant-wrapped InstallableWithBuildResult, changes Installable::build2() to return those, adds Installable::throwBuildErrors(), moves statusToString helpers into BuildResult nested types, adds Failure::Cancelled, initializes Goal.buildResult to Cancelled, and updates profile code and tests to the new flow.

Changes

Cohort / File(s) Summary
Installable API & header
src/libcmd/include/nix/cmd/installables.hh
Adds public InstallableWithBuildResult (variant Success/Failure + getSuccess()), changes Installable::build2() to return std::vector<InstallableWithBuildResult>, and declares Installable::throwBuildErrors()
Installable implementation
src/libcmd/installables.cc
Implements InstallableWithBuildResult, adapts build logic to populate Success/Failure variants, adds getSuccess(), implements throwBuildErrors() and a wrapper build() that delegates to build2() and extracts successes
Build-result helpers (header + impl)
src/libstore/include/nix/store/build-result.hh, src/libstore/build-result.cc
Adds static statusToString(Status) to BuildResult::Success and BuildResult::Failure, introduces Failure::Cancelled, implements status-to-string functions and updates call sites to use scoped helpers
Goal default initialization
src/libstore/include/nix/store/build/goal.hh
Initializes Goal::buildResult by default to a Failure with Cancelled status
Profile integration
src/nix/profile.cc
Updates builtPathsPerInstallable() to accept std::vector<InstallableWithBuildResult>, changes profile commands to call build2(), then throwBuildErrors(), then extract successes via getSuccess()
Tests
tests/functional/build.sh
Adjusts expectations for failures vs cancelled builds and updates per-derivation hash-mismatch assertions to match new error reporting behavior

Sequence Diagram(s)

sequenceDiagram
    participant Cmd as Command (profile/add/upgrade)
    participant Build2 as Installable::build2()
    participant Store as Store
    participant Throw as Installable::throwBuildErrors()
    participant Extract as InstallableWithBuildResult::getSuccess()
    participant Caller as Caller finalizing results

    Cmd->>Build2: invoke build2(...)
    Build2-->>Cmd: returns [InstallableWithBuildResult{Success|Failure}, ...]
    Cmd->>Throw: throwBuildErrors(buildResults, Store)
    alt any Failure present
        Throw->>Cmd: logs successes, reports cancelled as notices, throws on non-cancelled failures
        Cmd-->>Caller: propagation of thrown Exit/error
    else all Success
        Throw-->>Cmd: returns normally
        Cmd->>Extract: for each InstallableWithBuildResult call getSuccess()
        alt variant == Success
            Extract-->>Cmd: returns BuiltPathWithResult
        else variant == Failure
            Extract->>Cmd: rethrows stored Failure
        end
        Cmd-->>Caller: vector<BuiltPathWithResult>
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

  • Focus areas:
    • Correct construction/population of InstallableWithBuildResult::Success vs ::Failure in all build branches
    • Behavior and messaging in throwBuildErrors (ordering: successes first, notices for Cancelled, throw for other failures)
    • getSuccess() semantics and exception propagation from stored Failure
    • BuildResult::Failure::isCancelled() and Cancelled status handling across codepaths
    • Tests adjusted for changed failure/cancel counts

Suggested reviewers

  • cole-h

Poem

🐰 I hopped through builds with a variant in paw,

Successes tucked, failures I saw.
Pairs turned to boxes with labels so bright,
Errors get thrown, cancelled ones light.
Hop, test, and package — a rabbit-made sight!

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately captures the main objective: adding per-installable build result reporting to nix build and nix profile commands.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch show-build-result

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (2)
src/libcmd/include/nix/cmd/installables.hh (1)

99-113: Clean wrapper type for build results per installable.

The InstallableWithBuildResult struct provides a well-structured way to associate build outcomes with their installables. The type aliases improve readability.

One minor observation: the comment on line 105 states that Failure "must be a BuildResult::Failure", but the type alias is just BuildResult (which contains a variant). Consider whether the type could be tightened to BuildResult::Failure directly, or if the full BuildResult is needed for additional metadata (like timing info). The current approach works but relies on the caller to uphold the invariant.

src/libcmd/installables.cc (1)

594-602: Consider using std::get for clarity.

Since the variant can only hold Success or Failure, using std::get<Success>(result) would be clearer and provide a runtime check, avoiding the nullable pointer dereference pattern.

 const BuiltPathWithResult & InstallableWithBuildResult::getSuccess() const
 {
     if (auto * failure = std::get_if<Failure>(&result)) {
         auto failure2 = failure->tryGetFailure();
         assert(failure2);
         failure2->rethrow();
-    } else
-        return *std::get_if<Success>(&result);
+    }
+    return std::get<Success>(result);
 }
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6859aed and aef7257.

📒 Files selected for processing (7)
  • src/libcmd/include/nix/cmd/installables.hh (2 hunks)
  • src/libcmd/installables.cc (6 hunks)
  • src/libstore/build-result.cc (4 hunks)
  • src/libstore/include/nix/store/build-result.hh (3 hunks)
  • src/libstore/include/nix/store/build/goal.hh (1 hunks)
  • src/nix/profile.cc (4 hunks)
  • tests/functional/build.sh (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (3)
src/nix/profile.cc (2)
src/libcmd/include/nix/cmd/installables.hh (2)
  • buildResults (186-186)
  • store (198-198)
src/libcmd/installables.cc (4)
  • build2 (652-763)
  • build2 (652-653)
  • throwBuildErrors (604-639)
  • throwBuildErrors (604-604)
src/libstore/build-result.cc (1)
src/libstore/include/nix/store/build-result.hh (4)
  • status (34-34)
  • status (45-49)
  • status (45-45)
  • status (83-83)
src/libstore/include/nix/store/build-result.hh (1)
src/libstore/build-result.cc (4)
  • statusToString (16-30)
  • statusToString (16-16)
  • statusToString (32-64)
  • statusToString (32-32)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: build_x86_64-linux / build
  • GitHub Check: build_aarch64-darwin / build
🔇 Additional comments (18)
src/libstore/include/nix/store/build/goal.hh (1)

112-112: LGTM! Sensible default for build result.

Initializing buildResult to Cancelled ensures that goals that never complete (or are interrupted) have a well-defined failed state. This aligns with the new per-installable reporting where cancelled builds show ❓.

src/libstore/include/nix/store/build-result.hh (4)

34-35: LGTM! Clean static helper declaration.

The statusToString helper provides a well-typed way to convert status codes to strings, improving API clarity over a free function.


83-84: LGTM! Symmetric with Success::statusToString.

Provides consistent API for status-to-string conversion across both result types.


106-106: Good fallback for empty error messages.

Using statusToString(status) when errorMsg is empty ensures rethrow() always provides a meaningful error message rather than throwing an empty one.


80-80: Based on my verification, I've found important evidence about the review comment:

Key Findings:

  1. HashMismatch (value 15) in src/libstore/include/nix/store/build-result.hh has an explicit 3-line comment explaining:

    • "The protocols do not yet know about this one"
    • "change it back to OutputRejected before serialization"
  2. Serialization Fallback in src/libstore/build/derivation-building-goal.cc (lines 843-850):

    • When BuildResult::Failure::HashMismatch is encountered, it's unconditionally converted to OutputRejected
    • The comment states: "the protocols don't know about HashMismatch yet"
  3. Cancelled (value 16) has:

    • NO explanatory comment like HashMismatch
    • NO corresponding conversion/fallback in the switch statement
    • NOT handled in the serialization code
  4. Pattern Observed:

    • The switch statement at lines 843-857 handles specific statuses that need adjustment
    • Cancelled is conspicuously absent from this handling
    • The default case says "Other statuses need no adjusting"

The review comment's concern appears valid and substantiated. The question of whether Cancelled needs similar protocol compatibility handling to HashMismatch cannot be definitively answered without understanding: (1) whether Cancelled is sent to older protocol versions, and (2) whether those older versions recognize it. However, the evidence suggests this warrants investigation or clarification.


Verify protocol compatibility for Cancelled status.

Cancelled = 16 lacks the protocol compatibility documentation and serialization fallback that HashMismatch = 15 explicitly requires. HashMismatch (lines 76-78) is documented as needing conversion to OutputRejected before serialization because older protocols don't recognize it. Cancelled has no such comment or fallback in the switch statement at src/libstore/build/derivation-building-goal.cc:843-857. If Cancelled can be sent to older protocol versions, it should receive equivalent treatment.

tests/functional/build.sh (2)

170-174: LGTM! Correct error count for keep-going with 3 failing FODs.

With --keep-going, all three FODs (x1, x2, x3) are attempted and fail independently, so expecting 3 errors is correct. The individual hash mismatch assertions properly validate each failure is reported.


164-166: Based on my analysis of the code:

The test expectation of 3 cancellations is correct.

The fod-failing.nix file defines 4 derivations:

  • x1, x2, x3: Fixed-output derivations (FODs) with identical invalid hashes
  • x4: A regular derivation that depends on x2 and x3

When nix build -f fod-failing.nix is run without explicit targets (line 161), all top-level attributes are attempted:

  1. One FOD (typically x1) fails first with a hash mismatch error → generates 1 error message
  2. The remaining three derivations (x2, x3, x4) are cancelled as a result → 3 cancellations

This aligns with the modern error reporting behavior where:

  • Each installable build attempt generates one error entry
  • Dependent builds are cancelled and counted separately
  • The test correctly validates this by checking for exactly 1 error and 3 cancellations

The test structure is sound and the assertion is accurate.

src/libstore/build-result.cc (3)

16-30: LGTM! Clean implementation with exhaustive switch.

The statusToString implementation correctly covers all Success::Status enum values with unreachable() as a defensive default.


32-64: LGTM! Exhaustive handling of all failure statuses including new Cancelled.

All Failure::Status enum values are handled, with the new Cancelled case properly returning "Cancelled".


71-73: LGTM! JSON serialization updated to use the new member functions.

Using the nested statusToString helpers is cleaner than free functions and provides better API discoverability.

src/libcmd/include/nix/cmd/installables.hh (2)

179-184: LGTM! Improved return type for build2.

Returning std::vector<InstallableWithBuildResult> instead of std::vector<std::pair<ref<Installable>, BuiltPathWithResult>> is a cleaner API that can now represent both successes and failures per installable.


186-187: LGTM! New throwBuildErrors declaration.

This provides a clean separation between collecting build results and reporting errors. Taking a non-const reference suggests it may consume or modify the results, which should be documented in the implementation.

src/nix/profile.cc (3)

315-335: LGTM!

The function correctly adapts to the new InstallableWithBuildResult type. The call to b.getSuccess() is safe here because throwBuildErrors is always invoked before this function at both call sites, ensuring only successful results remain when this code executes.


367-370: LGTM!

The two-phase flow (build → throw errors → extract paths) is clean and makes error handling explicit. This ensures users see proper success/failure reporting before the profile is updated.


772-775: LGTM!

Consistent with the CmdProfileAdd changes, applying the same two-phase build result handling pattern.

src/libcmd/installables.cc (3)

24-24: LGTM!

Required include for the Exit exception used in throwBuildErrors.


641-650: LGTM!

Clean wrapper that maintains the simpler build() API while delegating to build2() internally. The error throwing before extraction ensures getSuccess() is safe.


652-763: LGTM!

The refactored build2() cleanly separates success and failure handling using the new InstallableWithBuildResult wrapper. Failures are detected early and stored directly (lines 718-723), while successes are properly wrapped with path information.

@github-actions
Copy link

github-actions bot commented Nov 26, 2025

@github-actions github-actions bot temporarily deployed to pull request November 26, 2025 21:18 Inactive
If any installable fails to build, it will print something like

  ✅ flake:nixpkgs#hello
  ❌ git+file:///home/eelco/Dev/patchelf#packages.x86_64-linux.default
  error: Cannot build '/nix/store/nh2dx9cqcy9lw4d4rvd0dbsflwdsbzdy-patchelf-0.18.0.drv'.
         Reason: builder failed with exit code 2.
         ...
  ❓ git+file:///home/eelco/Dev/patchelf#hydraJobs.coverage (cancelled)

It doesn't print anything if all installables succeed.
@github-actions github-actions bot temporarily deployed to pull request November 26, 2025 21:32 Inactive
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (2)
src/libcmd/installables.cc (2)

604-639: Well-structured error reporting with clear status differentiation.

The method properly reports successes first, then failures, and distinguishes between actual failures (❌) and cancelled builds (❓). The triple iteration through buildResults is clear and maintainable, though it could be consolidated into a single pass if performance becomes a concern.

Note: The method only prints per-installable status when at least one failure exists, which appears intentional to avoid noise when all builds succeed.

If you'd like to optimize the multiple passes through buildResults, consider collecting the messages in one pass:

 void Installable::throwBuildErrors(std::vector<InstallableWithBuildResult> & buildResults, const Store & store)
 {
+    std::vector<std::string> successMsgs, failureMsgs;
+    bool hasFailures = false;
+    
     for (auto & buildResult : buildResults) {
-        if (std::get_if<InstallableWithBuildResult::Failure>(&buildResult.result)) {
-            // Report success first.
-            for (auto & buildResult : buildResults) {
-                if (std::get_if<InstallableWithBuildResult::Success>(&buildResult.result))
-                    notice("✅ " ANSI_BOLD "%s" ANSI_NORMAL, buildResult.installable->what());
-            }
-
-            // Then failures.
-            for (auto & buildResult : buildResults) {
-                if (auto failure = std::get_if<InstallableWithBuildResult::Failure>(&buildResult.result)) {
-                    auto failure2 = failure->tryGetFailure();
-                    assert(failure2);
-                    if (failure2->status == BuildResult::Failure::Cancelled
-                        // FIXME: remove MiscFailure eventually
-                        || failure2->status == BuildResult::Failure::MiscFailure)
-                        notice(
-                            "❓ " ANSI_BOLD "%s" ANSI_NORMAL ANSI_FAINT " (cancelled)",
-                            buildResult.installable->what());
-                    else {
-                        printError("❌ " ANSI_RED "%s" ANSI_NORMAL, buildResult.installable->what());
-                        try {
-                            failure2->rethrow();
-                        } catch (Error & e) {
-                            logError(e.info());
-                        }
-                    }
-                }
-            }
-
-            throw Exit(1);
+        if (std::get_if<InstallableWithBuildResult::Success>(&buildResult.result)) {
+            successMsgs.push_back(buildResult.installable->what());
+        } else if (auto failure = std::get_if<InstallableWithBuildResult::Failure>(&buildResult.result)) {
+            hasFailures = true;
+            // Store failure details...
         }
     }
+    
+    if (hasFailures) {
+        // Print all collected messages
+        // ...
+        throw Exit(1);
+    }
 }

652-763: Solid implementation of variant-based build result flow.

The method correctly constructs InstallableWithBuildResult entries for all build paths, properly handling both success and failure cases across different realization modes. The distinction between modes that include actual build results (Outputs) versus those that just resolve paths (Nothing/Derivation) is clear.

There's some code duplication in constructing Success results for DerivedPath::Built vs DerivedPath::Opaque cases across different modes (lines 686-697 vs 700-703, and lines 728-742 vs 744-748). Consider extracting a helper function to reduce duplication:

auto makeSuccessResult = [&](const BuiltPath & path, const Aux & aux, 
                              std::optional<BuiltPathWithResult> buildResult = std::nullopt) {
    return InstallableWithBuildResult{
        .installable = aux.installable,
        .result = InstallableWithBuildResult::Success{
            .path = path,
            .info = aux.info,
            .result = buildResult
        }
    };
};

This would make the code more maintainable if the Success structure changes.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between aef7257 and ee75a66.

📒 Files selected for processing (4)
  • src/libcmd/include/nix/cmd/installables.hh (2 hunks)
  • src/libcmd/installables.cc (6 hunks)
  • src/nix/profile.cc (4 hunks)
  • tests/functional/build.sh (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (3)
  • src/nix/profile.cc
  • src/libcmd/include/nix/cmd/installables.hh
  • tests/functional/build.sh
🧰 Additional context used
🧬 Code graph analysis (1)
src/libcmd/installables.cc (1)
src/libcmd/include/nix/cmd/installables.hh (7)
  • buildResults (186-186)
  • evalStore (172-177)
  • evalStore (179-184)
  • evalStore (188-189)
  • evalStore (191-192)
  • evalStore (194-195)
  • evalStore (200-201)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: build_aarch64-darwin / build
  • GitHub Check: build_x86_64-linux / build
🔇 Additional comments (3)
src/libcmd/installables.cc (3)

24-24: LGTM - Required for new error handling.

The new include is necessary for the Exit exception thrown in throwBuildErrors.


594-602: LGTM - Proper variant handling and error propagation.

The method correctly extracts the success result or rethrows the stored failure. The assert ensures the failure state is valid before rethrowing.


641-650: LGTM - Clean delegation and error handling.

The method properly delegates to build2(), centralizes error handling via throwBuildErrors(), and converts results by extracting successful paths. The pattern ensures that callers either get all successful results or an exception.

@cole-h cole-h self-requested a review November 26, 2025 23:14
@cole-h cole-h self-assigned this Nov 26, 2025
@edolstra edolstra requested a review from cole-h December 4, 2025 14:38
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

♻️ Duplicate comments (1)
tests/functional/build.sh (1)

163-166: Comment is inconsistent with the test assertion.

The comment on line 163 says "one cancelled build" but line 165 asserts there are 3 cancelled builds. The comment should be updated to match the actual expected behavior.

-# one "hash mismatch" error, one cancelled build
+# one "hash mismatch" error, three cancelled builds
🧹 Nitpick comments (1)
src/libstore/include/nix/store/build-result.hh (1)

150-156: Consider tracking the FIXME for future cleanup.

The isCancelled() method correctly handles both the new Cancelled status and the legacy MiscFailure status during the transition period. The FIXME comment appropriately documents that MiscFailure should be removed once migration is complete.

Would you like me to open an issue to track the removal of the MiscFailure fallback once all code paths consistently use Cancelled?

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between ee75a66 and ed90b25.

📒 Files selected for processing (3)
  • src/libcmd/installables.cc (6 hunks)
  • src/libstore/include/nix/store/build-result.hh (4 hunks)
  • tests/functional/build.sh (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (2)
src/libstore/include/nix/store/build-result.hh (1)
src/libstore/build-result.cc (4)
  • statusToString (16-30)
  • statusToString (16-16)
  • statusToString (32-64)
  • statusToString (32-32)
src/libcmd/installables.cc (2)
src/libstore/include/nix/store/build-result.hh (1)
  • failure (151-156)
src/libcmd/include/nix/cmd/installables.hh (7)
  • buildResults (186-186)
  • evalStore (172-177)
  • evalStore (179-184)
  • evalStore (188-189)
  • evalStore (191-192)
  • evalStore (194-195)
  • evalStore (200-201)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: build_aarch64-darwin / build
  • GitHub Check: build_x86_64-linux / build
🔇 Additional comments (8)
tests/functional/build.sh (1)

168-174: LGTM!

The test expectations for --keep-going with multiple FODs are correctly updated. Each failing FOD now reports its own hash mismatch error, and the assertions properly verify all three derivations.

src/libstore/include/nix/store/build-result.hh (2)

80-84: LGTM!

The new Cancelled status follows the protocol compatibility requirements by being added at the end of the enum. The statusToString helper is properly declared and implemented in the corresponding .cc file.


104-107: LGTM!

Good improvement to rethrow() - falling back to statusToString(status) ensures a meaningful error message is always provided, even when errorMsg is empty.

src/libcmd/installables.cc (5)

594-602: LGTM!

The getSuccess() method correctly handles the variant - rethrowing failures and returning the success path. The logic is sound since the variant can only be Success or Failure.


604-643: LGTM!

The reporting order now follows the suggested pattern: successes first (✅), then cancelled builds (❓), then failures (❌). This makes it easier to find failures at the bottom of the output rather than having them interleaved with cancelled builds. The format strings are now correct with matching arguments.


645-654: LGTM!

Clean wrapper that delegates to build2() for the actual build, uses throwBuildErrors() for consistent error reporting, and extracts successful results for the public API. Good separation of concerns.


736-752: LGTM!

The success path correctly constructs InstallableWithBuildResult::Success with all necessary fields: the built path, extra path info, and the build result (which includes timing and other metadata).


722-727: No type compatibility issue exists. The buildResult variable (type KeyedBuildResult, which publicly inherits from BuildResult) is correctly assigned to the .result field (type std::variant<BuiltPathWithResult, BuildResult>). The implicit conversion from derived to base class is standard C++ and safe—there is no slicing of critical data. The BuildResult base contains all necessary failure information, and the extra metadata in KeyedBuildResult is not needed in the stored result.

@github-actions github-actions bot temporarily deployed to pull request December 4, 2025 14:42 Inactive
Copy link
Member

@cole-h cole-h left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Awesome!

Before:

Image

After:

Image

@edolstra edolstra added this pull request to the merge queue Dec 4, 2025
Merged via the queue into main with commit 055dfbc Dec 4, 2025
28 checks passed
@edolstra edolstra deleted the show-build-result branch December 4, 2025 21:25
@coderabbitai coderabbitai bot mentioned this pull request Feb 2, 2026
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.

2 participants