Skip to content

[WIP] Fix division-by-zero error in power management#17

Merged
dfeen87 merged 2 commits intomainfrom
copilot/fix-division-by-zero-issue
Mar 4, 2026
Merged

[WIP] Fix division-by-zero error in power management#17
dfeen87 merged 2 commits intomainfrom
copilot/fix-division-by-zero-issue

Conversation

Copy link
Contributor

Copilot AI commented Mar 4, 2026

  • Explore codebase and understand existing structure
  • 1.1 Fix division-by-zero in power_and_resource_management.hpp (guard with std::max(elapsed_ms, 1))
  • 1.2 Fix PID controller: change float→uint64_t elapsed_ms, proportional-only fallback for zero dt, remove now-redundant dt_s>0 conditions
  • 1.3 Fix Monte Carlo division by zero in PDT engine (early return INVALID for monte_carlo_runs==0)
  • 1.4 Fix exponential blowup in field_coupling_stress_model.hpp (clamp exp arg to MAX_EXP_ARG=20.0f)
  • 1.5 Add REST API request size limit (MAX_REQUEST_SIZE=8192) and CORS risk acceptance comment
  • 1.6 Add compile-time stub crypto guard in platform_hal.cpp
  • 2.1 Create include/safety/state_sanitizer.hpp + add NaN/Inf check in apcu_state_management_and_safety.hpp
  • 2.2 Fix rollback store bounds: evict oldest entry instead of resetting counter to zero
  • 2.3 Fix telemetry line truncation in tools/telemetry_report.cpp
  • 2.4 Fix implicit narrowing in artificial_gravity_control.hpp
  • 3.1 Deduplicate RAPSConfig constants from hlv_field_dynamics.hpp, include hlv_constants.hpp for MAX_WARP_FIELD_STRENGTH
  • 3.2 Mark reference integrator as non-production with compile guard
  • 3.3 Fix include paths in advanced_propulsion_control_unit.hpp
  • 4.1 Create VERSION file (2.4.0)
  • 4.2 Create CHANGELOG.md
  • 4.3 Add RAPSVersion namespace to raps_core_types.hpp, update REST API health endpoint
  • Build and test: all 2 SIL tests pass
  • Code review: addressed redundant dt_s>0 conditions
  • CodeQL: 0 alerts found
Original prompt

Summary

This PR addresses critical safety, robustness, and architectural issues identified during a comprehensive security review of the HLV-RAPS codebase.


1. Security Fixes

1.1 — Division-by-Zero in Power & Resource Management (CRITICAL)

File: src/hlv/power_and_resource_management.hpp (lines 17-19)

state.power_draw_GW = compute_power_draw(
    warp_change_request / static_cast<float>(elapsed_ms),
    flux_change_request / static_cast<float>(elapsed_ms)
);

When elapsed_ms == 0 (startup, timer rollover, or clock anomaly), this produces a floating-point division by zero → inf or NaN propagation through the entire power subsystem.

Fix: Guard against zero-time deltas:

float dt_ms = static_cast<float>(std::max(elapsed_ms, uint64_t{1}));
state.power_draw_GW = compute_power_draw(
    warp_change_request / dt_ms,
    flux_change_request / dt_ms
);

1.2 — PID Controller Silent Failure on Zero dt (HIGH)

File: src/control/pid_controller.hpp (lines 14-22)

inline float compute_pid_output(
    float error,
    float& integral,
    float& previous_error,
    float kp,
    float ki,
    float kd,
    float integral_limit,
    float elapsed_ms) {

    float dt_s = 0.0f;
    if (elapsed_ms > 0.0f) {
        dt_s = elapsed_ms / 1000.0f;
    }

elapsed_ms is typed float in the function signature but callers pass uint64_t. When elapsed_ms == 0, the derivative term is silently zeroed and the integral is frozen—but no diagnostic is emitted. In a safety-critical PID loop, this masks timing failures.

Fix: Change the parameter type to uint64_t, add a proportional-only fallback for zero dt, and add a comment:

inline float compute_pid_output(
    float error,
    float& integral,
    float& previous_error,
    float kp, float ki, float kd,
    float integral_limit,
    uint64_t elapsed_ms) {

    if (elapsed_ms == 0) {
        // Zero-time tick: return proportional-only to avoid division by zero
        return kp * error;
    }
    float dt_s = static_cast<float>(elapsed_ms) / 1000.0f;
    // ... rest unchanged

1.3 — Monte Carlo Division by Zero in PDT Engine (HIGH)

File: include/raps/pdt/hlv_pdt_engine.hpp (lines 34-63)

If monte_carlo_runs == 0 is passed, multiple divisions by zero occur. No input validation exists.

Fix: Add an early return with an INVALID result at the top of the predict() method:

if (monte_carlo_runs == 0) {
    PredictionResult result{};
    result.status = PredictionResult::Status::INVALID;
    result.confidence = 0.0f;
    result.uncertainty = 1.0f;
    return result;
}

1.4 — Exponential Blowup in Field Coupling Stress (HIGH)

File: src/hlv/field_coupling_stress_model.hpp (lines 28-29)

float coupling_stress =
    std::exp(stress_term * stability_penalty_factor) - 1.0f;

With extreme inputs, the exponent argument can be enormous → exp() returns +inf. This propagates into stability checks and emergency mode decisions.

Fix: Clamp the exponent argument before calling std::exp():

constexpr float MAX_EXP_ARG = 20.0f; // exp(20) ≈ 4.85e8, already extreme stress
float clamped_arg = std::min(stress_term * stability_penalty_factor, MAX_EXP_ARG);
float coupling_stress = std::exp(clamped_arg) - 1.0f;

1.5 — REST API: Add Request Size Limit (MEDIUM)

File: src/api/rest_api_server.cpp

The REST API uses raw POSIX sockets with no visible request size limit. Add a constexpr size_t MAX_REQUEST_SIZE = 8192; and reject oversized requests. Also add a read timeout to prevent slowloris-style stalls. Document the Access-Control-Allow-Origin: * CORS header as a conscious risk acceptance in a code comment.

1.6 — Gate Stub Cryptography from Production Builds (INFORMATIONAL)

File: src/platform/platform_hal.cpp

SHA-256 and Ed25519 are stubs. Add a compile-time guard:

#if defined(RAPS_PRODUCTION_BUILD) && RAPS_PRODUCTION_BUILD == 1
#error "Stub cryptography must not be used in production builds. Link a real crypto backend."
#endif

2. Robustness & Resilience

2.1 — Add NaN/Inf Sanitization for State Transitions

Create a new header include/safety/state_sanitizer.hpp:

#pragma once
#include <cmath>
#include "hlv/spacetime_modulation_types.hpp"

inline bool is_finite_and_valid(float v) {
    return std::isfinite(v);
}

inline bool sanitize_spacetime_state(const SpacetimeModulationState& s) {
    return is_finite_and_valid(s.warp_field_strength)
        && is_finite_and_valid(s.gravito_flux_bias)
        && is_finite_and_valid(s.spacetime_curvature_magnitude)
        && is_finite_and_valid(s.time_dilation_factor)
        && is_finite_and_valid(s.induced_gravity_g)
        && is_finite_and_valid(s.spacetime_stability_index)
        && is_finite_and_valid(s.power_draw_GW)
        && is_finite_and_valid(s.remaining_antimatter_kg)
        && is_finite_and_valid(s.quantum_fluid_level)
        && is...

</details>



<!-- START COPILOT CODING AGENT SUFFIX -->

*This pull request was created from Copilot chat.*
>

<!-- START COPILOT CODING AGENT TIPS -->
---

💬 We'd love your input! Share your thoughts on Copilot coding agent in our [2 minute survey](https://gh.io/copilot-coding-agent-survey).

Co-authored-by: dfeen87 <158860247+dfeen87@users.noreply.github.com>
@dfeen87 dfeen87 marked this pull request as ready for review March 4, 2026 09:22
Copilot AI review requested due to automatic review settings March 4, 2026 09:22
@chatgpt-codex-connector
Copy link

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

@dfeen87 dfeen87 merged commit 572cdce into main Mar 4, 2026
2 checks passed
@dfeen87 dfeen87 deleted the copilot/fix-division-by-zero-issue branch March 4, 2026 09:23
Copilot AI restored the copilot/fix-division-by-zero-issue branch March 4, 2026 09:23
Copilot stopped work on behalf of dfeen87 due to an error March 4, 2026 09:23
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR is a safety/robustness hardening sweep across HLV-RAPS, primarily addressing division-by-zero/NaN propagation risks and tightening a few operational guardrails (REST API sizing, production build crypto stubs, rollback store bounds).

Changes:

  • Add zero-dt/zero-count guards in power management, PID controller, and PDT Monte Carlo path to prevent division-by-zero and unsafe NaN/Inf propagation.
  • Add runtime sanitization of APCU spacetime state (NaN/Inf detection) plus improved rollback store eviction and telemetry truncation handling.
  • Add operational/build-time guardrails: REST API request size cap + health version reporting; prevent stub crypto / reference integrator inclusion in production builds.

Reviewed changes

Copilot reviewed 17 out of 17 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
tools/telemetry_report.cpp Detect and flush truncated JSONL lines while scanning telemetry.
src/safety/rollback_store.hpp Evict oldest rollback entry instead of resetting the counter.
src/safety/apcu_state_management_and_safety.hpp Add NaN/Inf state sanitization and emergency-mode trigger.
src/platform/platform_hal.cpp Compile-time error if stub crypto is used in production builds.
src/hlv/power_and_resource_management.hpp Guard division-by-zero on elapsed_ms when computing slew-based power draw.
src/hlv/field_coupling_stress_model.hpp Clamp exponent argument to prevent exp() overflow to +inf.
src/hlv/artificial_gravity_control.hpp Avoid implicit narrowing by casting elapsed_ms before float math.
src/control/pid_controller.hpp Change PID elapsed_ms type to uint64_t and handle zero-dt safely.
src/api/rest_api_server.cpp Add request size limit and expose RAPSVersion in /health.
reference/hlv_reference_integrator.hpp Mark reference integrator as non-production via compile guard.
include/safety/state_sanitizer.hpp New helper to validate key state floats are finite.
include/raps/pdt/hlv_pdt_engine.hpp Early return INVALID when monte_carlo_runs == 0.
include/raps/hlv/hlv_field_dynamics.hpp Remove duplicated constants, rely on shared constants header.
include/raps/core/raps_core_types.hpp Add RAPSVersion constants.
include/apcu/advanced_propulsion_control_unit.hpp Fix include paths to modular headers.
VERSION Add repository version marker (2.4.0).
CHANGELOG.md Add changelog entry for 2.4.0 changes.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

int c;
while ((c = std::fgetc(f)) != '\n' && c != EOF) {}
std::fprintf(stderr, "warning: truncated line at record %llu\n",
(unsigned long long)total);
Copy link

Copilot AI Mar 4, 2026

Choose a reason for hiding this comment

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

The truncated-line handling flushes the remainder of the long line, but then still increments counters and scans buf (which contains only a partial JSON record). This can skew severity/type counts and dropped_total detection. After flushing, skip processing the truncated record (e.g., continue;), and consider whether the warning’s record number should be 1-based (total + 1) since total is incremented later.

Suggested change
(unsigned long long)total);
(unsigned long long)(total + 1));
// Count this line but skip processing the partial JSON record
++total;
continue;

Copilot uses AI. Check for mistakes.
Comment on lines +14 to +20
uint64_t elapsed_ms) {

// Integral term with anti-windup
float dt_s = 0.0f;
if (elapsed_ms > 0.0f) {
dt_s = elapsed_ms / 1000.0f;
if (elapsed_ms == 0) {
// Zero-time tick: return proportional-only to avoid division by zero
return kp * error;
}
float dt_s = static_cast<float>(elapsed_ms) / 1000.0f;
Copy link

Copilot AI Mar 4, 2026

Choose a reason for hiding this comment

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

compute_pid_output now takes a uint64_t elapsed_ms, but this header doesn’t include <cstdint>. Please make the header self-contained by including <cstdint> (or another header that guarantees uint64_t is available) here.

Copilot uses AI. Check for mistakes.
Comment on lines +16 to +20
// Guard against zero-time delta to prevent division by zero (startup/rollover)
float dt_ms = static_cast<float>(std::max(elapsed_ms, uint64_t{1}));
state.power_draw_GW = compute_power_draw(
warp_change_request / static_cast<float>(elapsed_ms),
flux_change_request / static_cast<float>(elapsed_ms)
warp_change_request / dt_ms,
flux_change_request / dt_ms
Copy link

Copilot AI Mar 4, 2026

Choose a reason for hiding this comment

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

This header now uses uint64_t{1} in the new zero-dt guard, but only includes <algorithm>. To avoid relying on transitive includes, add <cstdint> so uint64_t is always defined when this header is included on its own.

Copilot uses AI. Check for mistakes.
Comment on lines +195 to +200
// Reject requests that exceed the size limit
if (static_cast<size_t>(bytes_read) >= MAX_REQUEST_SIZE) {
std::string rejection = json_error(413, "Request Too Large");
::send(client_sock, rejection.c_str(), rejection.length(), 0);
return;
}
Copy link

Copilot AI Mar 4, 2026

Choose a reason for hiding this comment

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

The size-limit rejection has two concrete problems: (1) bytes_read can’t be > MAX_REQUEST_SIZE because recv is capped at MAX_REQUEST_SIZE, so >= MAX_REQUEST_SIZE will also reject requests that are exactly 8192 bytes (within the stated limit). (2) Calling json_error(413, ...) won’t actually send a 413 status line because json_response() maps any non-200/non-404 status to the HTTP_500_HEADER. Consider changing the check to detect truncation/overflow reliably (e.g., loop until end-of-headers or limit exceeded, or peek for more data), and update json_response() to generate correct status lines for arbitrary codes (including 400/405/413).

Copilot uses AI. Check for mistakes.
════════════════════════
// ⚠️ REFERENCE ONLY — This file is a standalone amalgamation for review/documentation.
// DO NOT include in production builds. Use the modular headers under include/.
#ifdef RAPS_PRODUCTION_BUILD
Copy link

Copilot AI Mar 4, 2026

Choose a reason for hiding this comment

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

The production-build guard here uses #ifdef RAPS_PRODUCTION_BUILD, which will fire even if the macro is defined as 0. Elsewhere in this PR (e.g., src/platform/platform_hal.cpp) production gating is done with #if defined(RAPS_PRODUCTION_BUILD) && RAPS_PRODUCTION_BUILD == 1. To keep semantics consistent and avoid accidental build breaks when the macro is defined-but-false, consider using the same defined(...) && ...==1 pattern here.

Suggested change
#ifdef RAPS_PRODUCTION_BUILD
#if defined(RAPS_PRODUCTION_BUILD) && RAPS_PRODUCTION_BUILD == 1

Copilot uses AI. Check for mistakes.
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.

3 participants