Architecture Decision Records (ADR) Summary#
Introduction#
Architecture Decision Records (ADRs) are short, focused documents that capture important technical decisions made during the development of a software project. Each ADR records the context that motivated a decision, the decision itself, and the consequences — both positive and negative — that followed. This format, popularized by Michael Nygard, gives future contributors a window into the why behind architectural choices, not just the what.
For Stringy, ADRs are especially valuable because the project sits at the intersection of several complex domains: binary format parsing, multi-encoding string extraction, symbol demangling, and confidence-based ranking. Decisions in these areas often involve non-obvious tradeoffs — for example, choosing between demangling libraries, capping input lengths for safety, or determining how extraction confidence should flow through the scoring pipeline. Without documented rationale, these choices can look arbitrary to a new contributor, or worse, get inadvertently reversed.
This page serves as an index and summary of all Architecture Decision Records for the Stringy project. Each entry below summarizes the context, decision, and consequences of one ADR at a glance. Where you need deeper background, follow the link to the source file.
Note: The
docs/adr/directory and these ADR files are being established as part of formalizing the project's architecture documentation. The decisions they capture reflect real choices already made in the codebase — this page makes them explicit and discoverable.
The ADR Process#
Creating a New ADR#
When a significant architectural decision needs to be recorded — or when revisiting an existing one — follow these steps:
- Copy
docs/adr/template.mdto a new file using the next sequential number:docs/adr/NNNN-short-description.md - Fill in each section of the template (see Template Structure below)
- Open a pull request targeting the main branch with the new ADR file
- After review and approval, merge the PR — the ADR's status moves from Proposed to Accepted
Numbering Scheme#
ADRs use a zero-padded sequential four-digit number prefix:
docs/adr/0001-msvc-demangler-length-cap.md
docs/adr/0002-msvc-demangler-dependency.md
docs/adr/0003-encoding-confidence-via-confidence-path.md
Numbers are never reused. If an ADR is rejected or superseded, its number is retired and the file is kept as a historical record.
Status Lifecycle#
Each ADR carries a status line that evolves over time:
| Status | Meaning |
|---|---|
Proposed | The ADR has been drafted and is open for discussion |
Accepted | The decision has been approved and is in effect |
Rejected | The decision was considered but not adopted; the file is kept for context |
Deprecated | The decision was once in effect but is no longer relevant |
Superseded | A newer ADR replaces this one; the file links to its successor |
Template Structure#
Each ADR follows a consistent template with these sections:
- Title — A short, imperative phrase describing the decision (e.g., Cap MSVC Mangled Symbol Length Before Demangling)
- Status — One of the lifecycle statuses listed above, plus a date
- Context — The situation, problem, or forces that make a decision necessary
- Decision — The specific choice that was made, stated plainly
- Consequences — What happens as a result: what becomes easier, what becomes harder, and any known limitations
Cross-Referencing ADRs#
ADRs may reference each other. For example, ADR-0002 (choosing the msvc-demangler crate) is a prerequisite context for ADR-0001 (capping symbol length before passing it to that library). When an ADR supersedes another, the older ADR's status line is updated to include a link to the newer one:
Status: Superseded by [ADR-0005](0005-updated-demangler-strategy.md)
ADR Index and Summaries#
ADR 0001: MSVC Demangler Length Cap#
Status: Proposed
Context:
Stringy parses PE (Windows) binary files and processes their import/export symbol tables . These symbol tables often contain C++ symbols mangled in MSVC's format. MSVC mangled names can grow to enormous lengths — deeply nested template instantiations, complex function signatures, or deliberately crafted malicious inputs can produce symbols with thousands of characters. Attempting to demangle an arbitrarily long symbol is both computationally expensive (potentially causing hangs or excessive memory allocation) and a potential denial-of-service vector when Stringy is used in automated pipelines processing untrusted binaries. The design specification shows that the classification module handles symbol demangling as part of processing PE import/export tables . The msvc-demangler crate (selected in ADR-0002) does not itself impose an input length limit. PR #124 added Rust and C++ demangling support , establishing the foundation for MSVC symbol handling.
Decision:
Cap the length of any MSVC-mangled symbol string at a fixed maximum number of bytes before passing it to the demangler. Symbols that exceed this cap are passed through as-is (untranslated mangled form) or truncated, with the original_text field preserved in the FoundString data model. PR #123 added the original_text: Option<String> field to FoundString , enabling the preservation of mangled symbol names before demangling.
Consequences:
- POSITIVE: Prevents performance degradation or hangs on pathological inputs
- POSITIVE: Protects automated analysis pipelines from DoS via crafted binaries
- POSITIVE: Makes demangling latency predictable and bounded
- NEGATIVE: Legitimate (but very long) symbols may not be fully demangled; they appear in raw mangled form
- NEGATIVE: The cap value requires tuning — too low truncates real symbols, too high reintroduces the problem
- RELATIONSHIP: Depends on ADR-0002 (the choice of msvc-demangler as the demangling library)
Source file: docs/adr/0001-msvc-demangler-length-cap.md
ADR 0002: MSVC Demangler Dependency#
Status: Proposed
Context:
Stringy's classification module handles symbol demangling as part of processing PE import/export tables . Demangling Rust symbols uses rustc-demangle . For Windows PE binaries, MSVC C++ symbols (beginning with ? or __Z) also need demangling to be human-readable and semantically classifiable.
Available options:
msvc-demanglercrate – Pure Rust MSVC demangler; no FFI, cross-platform, actively maintainedcpp_demanglecrate – Handles Itanium ABI (GCC/Clang) C++ mangling; PR #124 added cpp_demangle alongside rustc-demangle for C++ supportundname.dllvia FFI – Windows-native, definitive MSVC demangling but requires Windows + unsafe FFI- Roll our own – Impractical given complexity of MSVC name mangling spec
The project's tech stack emphasizes pure-Rust safe dependencies . The design document targets cross-platform support for Linux, Windows, and macOS . Current dependencies in Cargo.toml include goblin, pelite, serde, and thiserror, with no demangling libraries beyond those added in PR #124 .
Decision:
Use the msvc-demangler crate as the dedicated library for demangling MSVC C++ symbols. Retain rustc-demangle for Rust symbols and cpp_demangle for Itanium ABI (GCC/Clang) symbols. This gives a clear, pure-Rust demangling stack covering all major symbol formats encountered in PE files — with no FFI and no OS dependencies.
Consequences:
- POSITIVE: Pure Rust — safe, cross-platform, no system libraries required
- POSITIVE: Distinct libraries for distinct symbol formats means each can be updated independently
- POSITIVE: Consistent with the project's broader safe-dependency philosophy
- NEGATIVE:
msvc-demanglermay lag behind MSVC's evolving mangling scheme; edge cases in newer MSVC versions might not demangle correctly - NEGATIVE: Adds a dependency; any bugs or supply-chain issues affect Stringy
- RELATIONSHIP: This decision is a prerequisite for ADR-0001 — the length cap is applied before calling the
msvc-demanglerlibrary
Source file: docs/adr/0002-msvc-demangler-dependency.md
ADR 0003: Encoding Confidence via Confidence Path#
Status: Accepted
Context:
String extraction in Stringy produces strings from multiple encodings: ASCII/UTF-8, UTF-16LE, and UTF-16BE . UTF-16 extraction is inherently noisier than ASCII — a sequence of bytes can appear to be UTF-16 even when it is actually structured binary data with coincidentally printable low bytes. Similarly, even ASCII extraction has variable reliability depending on the section it came from and the ratio of printable to non-printable characters.
The system needs a way to propagate this extraction-time reliability signal all the way through to the final ranked output so that:
- High-confidence strings (clean UTF-8 in
.rodata) surface near the top - Low-confidence strings (borderline UTF-16 from
.data) are ranked down or filterable
Before the "confidence path" approach, confidence was either lost at extraction time or re-calculated independently at ranking time without using the original per-string extraction signal. PR #109 added UTF-16 confidence scoring . The design specification shows RawString with a confidence: f32 field . The ranking specification shows how encoding confidence contributes to ranking score .
Decision:
Establish a "confidence path" — a continuous chain from extraction through to ranking — by:
- Recording a
confidence: f32field onRawStringat extraction time - Carrying this value forward when
RawStringis promoted toFoundString - Having the ranking engine's scoring function use it as a direct scoring input, contributing score bonuses for high-confidence extractions
- The final score formula
Score = SectionWeight + EncodingConfidence + SemanticBoost - NoisePenaltyexplicitly includes this confidence signal
PR #125 introduced the ranking system with RankingEngine and RankingConfig , which implements the confidence-based scoring. PR #123 extended FoundString with score breakdown fields including section_weight, semantic_boost, and noise_penalty , enabling transparent propagation of confidence signals.
Consequences:
- POSITIVE: Extraction-time signal directly influences final ranking — no confidence information is lost in the pipeline
- POSITIVE: Analysts see the most reliable strings first; noisy UTF-16 false positives sink in rankings rather than cluttering output
- POSITIVE: Confidence is configurable and filterable — users can set a minimum score threshold that implicitly filters on encoding confidence
- POSITIVE: PR #109 demonstrated a measurable reduction in UTF-16 false positives
- NEGATIVE:
confidence: f32must be correctly computed at extraction time; incorrect heuristics upstream cause incorrect ranking downstream - NEGATIVE: The path requires multiple structs (
RawString,FoundString) to carry the field, increasing data model complexity - NEGATIVE: The mapping from
f32confidence (0.0–1.0) to integer score contribution requires manual tuning of thresholds
Source file: docs/adr/0003-encoding-confidence-via-confidence-path.md
Audience and Usage#
This page is primarily for contributors to the Stringy project, including:
- New contributors who want to understand why the codebase looks the way it does before making changes — particularly around PE symbol demangling and the string ranking pipeline
- Reviewers and maintainers who need a quick reference when evaluating pull requests that touch MSVC symbol handling, encoding detection, or the confidence scoring path
- Architects making new technical decisions who want to check whether a related decision has already been recorded and reasoned through
When to Read an ADR#
| If you are… | Read… |
|---|---|
| Adding or modifying MSVC symbol demangling logic | ADR-0001, ADR-0002 |
Changing the msvc-demangler crate version or swapping it for another | ADR-0002 |
Touching the extraction confidence field or the ranking algorithm | ADR-0003 |
| Proposing a change that contradicts any of the decisions below | The relevant ADR, then open a discussion or propose a new ADR |
When to Write a New ADR#
Consider writing an ADR whenever a decision:
- Has significant long-term consequences for the codebase
- Involves tradeoffs where the reasoning is not obvious from the code
- Overrides or refines a prior decision
- Involves choosing between two or more viable alternatives
Links and References#
ADR Source Files#
| File | Description |
|---|---|
docs/adr/README.md | ADR process overview and contribution guide |
docs/adr/template.md | Blank ADR template to copy when creating a new record |
docs/adr/0001-msvc-demangler-length-cap.md | ADR 0001 source |
docs/adr/0002-msvc-demangler-dependency.md | ADR 0002 source |
docs/adr/0003-encoding-confidence-via-confidence-path.md | ADR 0003 source |
Related Architecture Documentation#
- Architecture Overview — High-level pipeline design and module structure
- Ranking Algorithm — Detailed scoring formula and encoding confidence contribution
- Classification System — Symbol demangling and semantic tagging
- Technology Stack — Dependency list and rationale summary
- Design Specification — Full component interface and data model specification