From 5cac57f410e482e23fd00713419d8a76e64b6160 Mon Sep 17 00:00:00 2001 From: Aster Seker Date: Fri, 22 May 2026 11:39:06 +0300 Subject: [PATCH 1/2] fix(otlp): count failed export on compression fallback MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When compress_string_gzip() or compress_string_zstd() fails inside submit_batch_async(), the logger silently falls back to uncompressed payload. This makes compression issues invisible to operators. Increment failed_exports so the failure is observable via the existing FailedExportCount metric. Also adds doc comments to compression helpers clarifying return-value contract and caller responsibility. Directive: compression failure increments failed_exports — do not remove without updating metrics docs. Co-Authored-By: Claude Opus 4.7 --- include/logit_cpp/logit/loggers/OtlpHttpLogger.hpp | 6 ++++++ .../logit_cpp/logit/loggers/otlp/OtlpCompression.hpp | 12 ++++++++++++ 2 files changed, 18 insertions(+) diff --git a/include/logit_cpp/logit/loggers/OtlpHttpLogger.hpp b/include/logit_cpp/logit/loggers/OtlpHttpLogger.hpp index c137934..4eb647e 100644 --- a/include/logit_cpp/logit/loggers/OtlpHttpLogger.hpp +++ b/include/logit_cpp/logit/loggers/OtlpHttpLogger.hpp @@ -344,12 +344,18 @@ namespace logit { if (m_config.compression == OtlpCompression::Gzip) { if (!compress_string_gzip(chunk, post_content, m_config.compression_level)) { + // Compression failed: fallback to uncompressed payload. + // Count this as a failed export attempt so operators can observe compression issues. + m_state->failed_exports.fetch_add(1); post_content = std::move(chunk); } else { chunk_headers.emplace("Content-Encoding", "gzip"); } } else if (m_config.compression == OtlpCompression::Zstd) { if (!compress_string_zstd(chunk, post_content, m_config.compression_level)) { + // Compression failed: fallback to uncompressed payload. + // Count this as a failed export attempt so operators can observe compression issues. + m_state->failed_exports.fetch_add(1); post_content = std::move(chunk); } else { chunk_headers.emplace("Content-Encoding", "zstd"); diff --git a/include/logit_cpp/logit/loggers/otlp/OtlpCompression.hpp b/include/logit_cpp/logit/loggers/otlp/OtlpCompression.hpp index 7daf6a1..3b83df7 100644 --- a/include/logit_cpp/logit/loggers/otlp/OtlpCompression.hpp +++ b/include/logit_cpp/logit/loggers/otlp/OtlpCompression.hpp @@ -17,6 +17,12 @@ namespace logit { enum class OtlpCompression { None, Gzip, Zstd }; +/// \brief Compress a string with gzip. +/// \param input Uncompressed data. +/// \param[out] output Compressed result (valid only on success). +/// \param level Compression level 1-9. +/// \return true on success, false if zlib is unavailable or compression fails. +/// \note Callers must check the return value and handle fallback explicitly. inline bool compress_string_gzip(const std::string& input, std::string& output, int level) { #if defined(LOGIT_HAS_ZLIB) z_stream zs; @@ -65,6 +71,12 @@ inline bool compress_string_gzip(const std::string& input, std::string& output, #endif } +/// \brief Compress a string with zstd. +/// \param input Uncompressed data. +/// \param[out] output Compressed result (valid only on success). +/// \param level Compression level 1-19. +/// \return true on success, false if zstd is unavailable or compression fails. +/// \note Callers must check the return value and handle fallback explicitly. inline bool compress_string_zstd(const std::string& input, std::string& output, int level) { #if defined(LOGIT_HAS_ZSTD) if (level < 1) level = 1; From 9beecc47625fa6e9a875b39fc038899f64a3f53f Mon Sep 17 00:00:00 2001 From: Aster Seker Date: Fri, 22 May 2026 19:03:13 +0300 Subject: [PATCH 2/2] =?UTF-8?q?fix(docs):=20tighten=20agent=20rule=20?= =?UTF-8?q?=E2=80=94=20no=20direct=20commits=20to=20main?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Removes the self-contradicting exception that allowed trivial fixes on main when explicitly requested. The previous wording created a loophole an agent could exploit. Changes: - Expands rule scope from "non-trivial" to "any task". - Adds explicit step: do not edit/commit on main; create branch first. - Tightens exception wording to require per-change owner override. Co-Authored-By: Claude Opus 4.7 --- guides/git-workflow.md | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/guides/git-workflow.md b/guides/git-workflow.md index 3387dba..d87fa3a 100644 --- a/guides/git-workflow.md +++ b/guides/git-workflow.md @@ -53,11 +53,12 @@ Examples: ## Agent Rule -When starting any non-trivial task (feature, bug fix, improvement), an AI agent must: +When starting any task (feature, bug fix, improvement, documentation), an AI agent must: -1. Verify `main` is current with `origin/main`. -2. Create a feature branch with an appropriate prefix. -3. Do all work on that branch. -4. Push the branch and instruct the user to open a PR instead of merging directly. +1. Do not edit or commit while on `main`. If currently on `main`, create a branch before editing files. +2. Verify `main` is current with `origin/main`. +3. Create a feature branch with an appropriate prefix. +4. Do all work on that branch. +5. Push the branch and instruct the user to open a PR instead of merging directly. -Trivial one-line fixes or documentation typos may be committed to `main` only when explicitly requested by the user. +No direct commits to `main`, including trivial documentation fixes, unless the repository owner explicitly overrides this rule for that exact change.