Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 34 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# Changelog

All notable changes to HLV-RAPS are documented in this file.

## [2.4.0] - 2026-03-04

### Security
- Fix division-by-zero in power & resource management when `elapsed_ms == 0`
- Fix PID controller parameter type (`float` → `uint64_t`) and add proportional-only fallback for zero dt
- Fix Monte Carlo division by zero in PDT engine when `monte_carlo_runs == 0`
- Clamp exponential argument in field coupling stress model to prevent `+inf` propagation
- Add request size limit (`MAX_REQUEST_SIZE = 8192`) and CORS risk comment to REST API server
- Add compile-time guard to prevent stub cryptography in production builds

### Robustness
- Add NaN/Inf state sanitizer (`include/safety/state_sanitizer.hpp`) with check in APCU safety update
- Fix rollback store bounds: evict oldest entry instead of resetting counter to zero
- Fix telemetry report truncated-line detection for JSONL lines exceeding buffer size
- Fix implicit narrowing in artificial gravity rate-limit computation

### Architecture
- Deduplicate `RAPSConfig` struct and conflicting constants from `hlv_field_dynamics.hpp`
- Add non-production compile guard to reference integrator header
- Fix broken include paths in `advanced_propulsion_control_unit.hpp`

### Maintainability
- Add `VERSION` file (`2.4.0`)
- Add `CHANGELOG.md`
- Add `RAPSVersion` namespace constants to `raps_core_types.hpp`
- Update REST API health endpoint to use `RAPSVersion::STRING`

## [2.3.0] - (previous release)

<!-- placeholder: details for v2.3.0 not available -->
1 change: 1 addition & 0 deletions VERSION
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
2.4.0
6 changes: 3 additions & 3 deletions include/apcu/advanced_propulsion_control_unit.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@
#include <cstring>

// Core types / constants should be declared elsewhere and included here.
#include "SpacetimeModulationTypes.hpp" // SpacetimeModulationState, Command, constants
#include "PlatformHAL.hpp" // now_ms(), metric_emit(), sha256(), etc.
#include "Hash256.hpp"
#include "hlv/spacetime_modulation_types.hpp" // SpacetimeModulationState, Command, constants
#include "platform/platform_hal.hpp" // now_ms(), metric_emit(), sha256(), etc.
#include "raps/core/raps_core_types.hpp" // Hash256 and other core types

class AdvancedPropulsionControlUnit {
public:
Expand Down
11 changes: 11 additions & 0 deletions include/raps/core/raps_core_types.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -127,3 +127,14 @@ struct RollbackPlan {
Hash256 rollback_hash;
bool valid;
};

// =====================================================
// Version
// =====================================================

namespace RAPSVersion {
constexpr uint32_t MAJOR = 2;
constexpr uint32_t MINOR = 4;
constexpr uint32_t PATCH = 0;
constexpr const char* STRING = "2.4.0";
}
12 changes: 5 additions & 7 deletions include/raps/hlv/hlv_field_dynamics.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
#include <numeric>
#include <iostream>

#include "hlv/hlv_constants.hpp"

// =====================================================
// HLV Framework Mathematical Constants
// =====================================================
Expand All @@ -31,14 +33,10 @@ constexpr float TCC_COUPLING_J = 0.25f;
// RAPS System Constants
// =====================================================

constexpr float MAX_WARP_FIELD_STRENGTH = 10.0f;
constexpr float MAX_FLUX_BIAS = 5.0f;
constexpr float ANTIMATTER_BURN_RATE_GW_TO_KG_PER_MS = 1e-6f;

struct RAPSConfig {
static constexpr float CRITICAL_ANTIMATTER_KG = 5.0f;
static constexpr float EMERGENCY_ANTIMATTER_RESERVE_KG = 20.0f;
};
// MAX_WARP_FIELD_STRENGTH and ANTIMATTER_BURN_RATE_GW_TO_KG_PER_MS
// are defined in include/hlv/hlv_constants.hpp — do not redefine here.
// RAPSConfig safety thresholds are defined in include/config/raps_safety_limits.hpp.

// =====================================================
// HLV Triadic Time
Expand Down
8 changes: 8 additions & 0 deletions include/raps/pdt/hlv_pdt_engine.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,14 @@ class HlvPdtEngine {
uint32_t horizon_ms,
uint32_t monte_carlo_runs
) {
if (monte_carlo_runs == 0) {
PredictionResult result{};
result.status = PredictionResult::Status::INVALID;
result.confidence = 0.0f;
result.uncertainty = 1.0f;
return result;
}

std::vector<float> final_warp;
std::vector<float> final_curvature;
std::vector<float> final_stability;
Expand Down
21 changes: 21 additions & 0 deletions include/safety/state_sanitizer.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#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_finite_and_valid(s.field_coupling_stress)
&& is_finite_and_valid(s.control_authority_remaining);
}
5 changes: 5 additions & 0 deletions reference/hlv_reference_integrator.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,11 @@
//
═══════════════════════════════════════════════════════
════════════════════════
// ⚠️ 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.
#error "Do not include hlv_reference_integrator.hpp in production builds."
#endif
#ifndef HLV_PDT_ENGINE_HPP
#define HLV_PDT_ENGINE_HPP
#include <vector>
Expand Down
22 changes: 18 additions & 4 deletions src/api/rest_api_server.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
#include <iomanip>
#include <algorithm>

#include "raps/core/raps_core_types.hpp"

// POSIX sockets
#include <sys/socket.h>
#include <netinet/in.h>
Expand All @@ -16,10 +18,15 @@ namespace raps::api {

namespace {

// Maximum HTTP request size in bytes — protects against oversized/malformed requests
constexpr size_t MAX_REQUEST_SIZE = 8192;

// HTTP response templates
constexpr const char* HTTP_200_HEADER =
"HTTP/1.1 200 OK\r\n"
"Content-Type: application/json\r\n"
// Access-Control-Allow-Origin: * is intentional for an internal-only observability API.
// RISK ACCEPTED: This server must only be bound to a loopback/trusted interface.
"Access-Control-Allow-Origin: *\r\n"
"Connection: close\r\n"
"Content-Length: ";
Expand Down Expand Up @@ -177,13 +184,20 @@ void RestApiServer::server_thread_main() {
}

void RestApiServer::handle_client(int client_sock) {
// Read request
char buffer[4096];
ssize_t bytes_read = ::recv(client_sock, buffer, sizeof(buffer) - 1, 0);
// Read request with size limit to prevent oversized/malicious requests
char buffer[MAX_REQUEST_SIZE + 1];
ssize_t bytes_read = ::recv(client_sock, buffer, MAX_REQUEST_SIZE, 0);

if (bytes_read <= 0) {
return;
}

// 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;
}
Comment on lines +195 to +200
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.

buffer[bytes_read] = '\0';
std::string request(buffer);
Expand Down Expand Up @@ -235,7 +249,7 @@ std::string RestApiServer::handle_health() {
json << "{"
<< "\"status\":\"ok\","
<< "\"service\":\"HLV-RAPS Flight Middleware\","
<< "\"api_version\":\"1.0\","
<< "\"api_version\":\"" << RAPSVersion::STRING << "\","
<< "\"observability_only\":true"
<< "}";

Expand Down
27 changes: 11 additions & 16 deletions src/control/pid_controller.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,26 +11,21 @@ inline float compute_pid_output(
float ki,
float kd,
float integral_limit,
float elapsed_ms) {
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;
Comment on lines +14 to +20
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.

if (dt_s > 0.0f) {
integral += error * dt_s;
integral = std::max(
-integral_limit,
std::min(integral_limit, integral)
);
}
integral += error * dt_s;
integral = std::max(
-integral_limit,
std::min(integral_limit, integral)
);

float derivative = 0.0f;
if (dt_s > 0.0f) {
derivative = (error - previous_error) / dt_s;
}
float derivative = (error - previous_error) / dt_s;

float output =
(kp * error) +
Expand Down
4 changes: 2 additions & 2 deletions src/hlv/artificial_gravity_control.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,9 @@ inline void update_artificial_gravity_control(
gravity_pid_output * capability_scale * response_scale;

gravity_change = std::max(
-GRAVITY_RESPONSE_RATE_PER_MS * elapsed_ms,
-GRAVITY_RESPONSE_RATE_PER_MS * static_cast<float>(elapsed_ms),
std::min(
GRAVITY_RESPONSE_RATE_PER_MS * elapsed_ms,
GRAVITY_RESPONSE_RATE_PER_MS * static_cast<float>(elapsed_ms),
gravity_change
)
);
Expand Down
5 changes: 3 additions & 2 deletions src/hlv/field_coupling_stress_model.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,9 @@ inline float compute_field_coupling_stress(
(D - 1.0f) *
COUPLING_STRESS_EXPONENT_SCALAR;

float coupling_stress =
std::exp(stress_term * stability_penalty_factor) - 1.0f;
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;

return std::max(0.0f, coupling_stress);
}
6 changes: 4 additions & 2 deletions src/hlv/power_and_resource_management.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,11 @@ inline void update_power_and_resources(

// Power Draw & Resource Consumption (Section 7)

// 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
Comment on lines +16 to +20
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.
);

// Apply effective power budget (constrained by resource capability)
Expand Down
4 changes: 4 additions & 0 deletions src/platform/platform_hal.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,10 @@ uint32_t PlatformHAL::now_ms() {
// Crypto (STUBS — NOT production crypto)
// ------------------------------------------------------------

#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

Hash256 PlatformHAL::sha256(const void* data, size_t len) {
Hash256 h{};
std::memset(h.data, 0, sizeof(h.data));
Expand Down
10 changes: 10 additions & 0 deletions src/safety/apcu_state_management_and_safety.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
#include <algorithm>
#include <cstring>
#include <cmath>
#include "safety/state_sanitizer.hpp"

class AdvancedPropulsionControlUnit {

Expand Down Expand Up @@ -63,6 +64,15 @@ inline void AdvancedPropulsionControlUnit::update_diagnostics_and_safety(
current_propulsion_state_.emergency_mode_active =
emergency_mode_active_;

// NaN/Inf state sanitization: detect corrupted state before proceeding
if (!sanitize_spacetime_state(current_propulsion_state_)) {
PlatformHAL::metric_emit("apcu.nan_inf_detected", 1.0f);
if (!emergency_mode_active_) {
enter_emergency_mode();
}
return; // Do not proceed with corrupted state
}

// 10. State Management & Safety
current_propulsion_state_.timestamp_ms += elapsed_ms;
current_propulsion_state_.state_hash =
Expand Down
7 changes: 6 additions & 1 deletion src/safety/rollback_store.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,12 @@ inline void store_rollback_plan(
const Policy& safe_fallback_policy) {

if (rollback_count >= RAPSConfig::MAX_ROLLBACK_STORE) {
rollback_count = 0; // overwrite oldest
PlatformHAL::metric_emit("safety.rollback_store_full", 1.0f);
// Evict oldest entry by shifting to make room for new entry
for (size_t i = 1; i < RAPSConfig::MAX_ROLLBACK_STORE; ++i) {
rollback_store[i - 1] = rollback_store[i];
}
rollback_count = static_cast<uint32_t>(RAPSConfig::MAX_ROLLBACK_STORE) - 1;
}

RollbackPlan plan{};
Expand Down
8 changes: 8 additions & 0 deletions tools/telemetry_report.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,14 @@ int main(int argc, char** argv) {

char buf[8192];
while (std::fgets(buf, sizeof(buf), f)) {
size_t len = std::strlen(buf);
if (len > 0 && buf[len - 1] != '\n') {
// Line was truncated; skip remainder to avoid corrupting counters
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.
}
++total;

if (contains(buf, "\"type\":\"telemetry_summary\"")) {
Expand Down