<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Mohith Dande</title>
    <description>The latest articles on DEV Community by Mohith Dande (@mohith_dande_07).</description>
    <link>https://dev.to/mohith_dande_07</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4078114%2F02878e22-6ff2-4075-b860-86a92698e8c0.jpg</url>
      <title>DEV Community: Mohith Dande</title>
      <link>https://dev.to/mohith_dande_07</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/mohith_dande_07"/>
    <language>en</language>
    <item>
      <title>TraceSieve: See What Your Program Actually Did</title>
      <dc:creator>Mohith Dande</dc:creator>
      <pubDate>Tue, 01 Sep 2026 15:01:50 +0000</pubDate>
      <link>https://dev.to/mohith_dande_07/tracesieve-see-what-your-program-actually-did-2dml</link>
      <guid>https://dev.to/mohith_dande_07/tracesieve-see-what-your-program-actually-did-2dml</guid>
      <description>&lt;p&gt;When I entered the Zero Dependency Hackathon 2026, I thought the hard part would be coming up with an interesting project concept.&lt;/p&gt;

&lt;p&gt;It wasn't.&lt;/p&gt;

&lt;p&gt;The hard part was realizing how often software engineering relies on external packages for problems that look simple—until you try to implement them from scratch.&lt;/p&gt;

&lt;p&gt;For this hackathon, I built TraceSieve: an offline Python CLI tool that records what actually happens during program execution, turns that execution into reusable evidence records, and lets you query, reconstruct, and compare different execution scenarios.&lt;/p&gt;

&lt;p&gt;The interesting part wasn't just building a tracer.&lt;/p&gt;

&lt;p&gt;The interesting part was building the entire analytical machinery around the trace without reaching for any of the packages I would normally pip install.&lt;/p&gt;

&lt;p&gt;No third-party runtime dependencies.&lt;br&gt;
No external cloud service or agent.&lt;br&gt;
No framework.&lt;br&gt;
Just 100% Python standard library.&lt;br&gt;
💡 The Core Idea: Execution as an Artifact&lt;br&gt;
When developers inspect a codebase, they usually look at its possibilities.&lt;/p&gt;

&lt;p&gt;A static analysis tool or IDE tells us:&lt;/p&gt;

&lt;p&gt;Which modules exist&lt;br&gt;
Which functions and classes exist&lt;br&gt;
Which imports are defined in source&lt;br&gt;
text&lt;/p&gt;

&lt;p&gt;app/&lt;br&gt;
├── auth.py&lt;br&gt;
├── payments.py&lt;br&gt;
├── cache.py&lt;br&gt;
├── legacy.py&lt;br&gt;
└── plugins.py&lt;br&gt;
Static tools treat all these files equally. But a running program tells a completely different story.&lt;/p&gt;

&lt;p&gt;A user triggering a basic checkout request might only execute: $$\text{auth.py} \longrightarrow \text{cache.py} \longrightarrow \text{payments.py}$$&lt;/p&gt;

&lt;p&gt;While another execution (e.g. an admin refund) takes a completely different path, leaving legacy.py untouched.&lt;/p&gt;

&lt;p&gt;That led me to a simple question:&lt;/p&gt;

&lt;p&gt;What if an execution run itself became a named artifact that we could query, inspect, and compare later?&lt;/p&gt;

&lt;p&gt;That became TraceSieve. Instead of treating runtime tracing as temporary log output destined for stdout, TraceSieve captures Execution Evidence Records.&lt;/p&gt;

&lt;p&gt;bash&lt;/p&gt;

&lt;h1&gt;
  
  
  1. Capture execution runs as named scenarios
&lt;/h1&gt;

&lt;p&gt;tracesieve run --name login -- python app.py login&lt;br&gt;
tracesieve run --name checkout -- python app.py checkout&lt;/p&gt;

&lt;h1&gt;
  
  
  2. Reconstruct caller evidence for specific execution decisions
&lt;/h1&gt;

&lt;p&gt;tracesieve why checkout process_payment&lt;/p&gt;

&lt;h1&gt;
  
  
  3. Compute scenario behavioral deltas
&lt;/h1&gt;

&lt;p&gt;tracesieve diff login checkout&lt;/p&gt;

&lt;h1&gt;
  
  
  4. Expose untested static code gaps for a scenario
&lt;/h1&gt;

&lt;p&gt;tracesieve gaps checkout app/&lt;br&gt;
⚖️ Why Not Just Use Existing Packages?&lt;br&gt;
Python has a rich ecosystem for profiling (cProfile), line coverage (coverage.py), call graphs (pycallgraph), and CLI frameworks (Click, Typer).&lt;/p&gt;

&lt;p&gt;In a standard commercial project, I would pull these packages down in seconds. But the Zero Dependency Hackathon rules require an empty requirements.txt and zero runtime pip packages.&lt;/p&gt;

&lt;p&gt;Instead of asking: "Which package should I install?"&lt;br&gt;
I had to ask: "What primitives does Python's standard library already provide?"&lt;/p&gt;

&lt;p&gt;Here is how TraceSieve replaced standard third-party libraries with standard library implementations:&lt;/p&gt;

&lt;p&gt;Domain  Typical 3rd-Party Package   TraceSieve Standard Library Primitive   Key Implementation Highlight&lt;br&gt;
CLI Engine  Click / Typer   argparse    Robust subcommands (run, report, diff, why, gaps, export) with clean validation &amp;amp; ANSI coloring&lt;br&gt;
Runtime Observation hunter / PySnooper  sys.settrace &amp;amp; threading.settrace   Zero-overhead frame hook filtering out stdlib &amp;amp; site-packages&lt;br&gt;
Persistence Store   SQLAlchemy / Peewee sqlite3 Local ACID database (.tracesieve/runs.db) with indexes on sequence, module, and functions&lt;br&gt;
Static Code Parsing redbaron / parso    ast (ast.NodeVisitor)   Complete AST inventory generator tracking classes, functions, and imports&lt;br&gt;
Graph Analysis  NetworkX    dict + set + BFS/DFS    In-memory graph traversal algorithms for caller path reconstruction&lt;br&gt;
Data Models Pydantic / attrs    dataclasses Strongly-typed, memory-efficient data structures&lt;br&gt;
Single Executable   PyInstaller zipapp  Compiles into tracesieve.pyz runnable on any Python 3.10+ installation&lt;br&gt;
Test Suite  pytest  unittest    Comprehensive unit &amp;amp; integration testing suite&lt;br&gt;
🛠️ Deep Dive: The 5 Stdlib Replacements&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;CLI Tooling: Crafting an Application CLI with argparse
argparse is often seen as basic compared to Click or Typer. But argparse supports full subcommand hierarchies, argument validation, custom formatters, and error handling.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Building subcommands with argparse forced explicit control over:&lt;/p&gt;

&lt;p&gt;Subcommand routing (run, report, diff, why, gaps)&lt;br&gt;
Positional vs optional flag parsing&lt;br&gt;
Standard error (stderr) vs standard output (stdout) separation&lt;br&gt;
Custom help formatters and clean exit codes (0 for success, 1 for missing target, 2 for target runtime failure, 3 for analysis errors)&lt;br&gt;
python&lt;/p&gt;

&lt;h1&gt;
  
  
  System subcommand initialization with standard library argparse
&lt;/h1&gt;

&lt;p&gt;parser = argparse.ArgumentParser(prog="tracesieve", description="Runtime Execution Evidence Tool")&lt;br&gt;
subparsers = parser.add_subparsers(dest="command", required=True)&lt;/p&gt;

&lt;h1&gt;
  
  
  Subcommand: why
&lt;/h1&gt;

&lt;p&gt;why_parser = subparsers.add_parser("why", help="Explain why a function executed in a scenario")&lt;br&gt;
why_parser.add_argument("scenario", help="Name of recorded scenario")&lt;br&gt;
why_parser.add_argument("target", help="Function or qualified name to explain")&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Runtime Observation: sys.settrace &amp;amp; Thread Safety
Collecting runtime evidence is fundamentally different from taking line coverage snapshots or measuring CPU clock cycles. I needed to capture:&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Sequential event ordering (sequence_number)&lt;br&gt;
Frame nesting depth (depth)&lt;br&gt;
Parent/caller relationships (caller_func, caller_file)&lt;br&gt;
Exception boundaries (event_type == "exception")&lt;br&gt;
Multi-threaded execution isolation (thread_id)&lt;br&gt;
Python's sys.settrace and threading.settrace hooks allow intercepting every frame event. The primary technical challenge was filtering out standard library internals so that tracing didn't slow down the interpreter or bloat the evidence log.&lt;/p&gt;

&lt;p&gt;python&lt;/p&gt;

&lt;p&gt;class ExecutionTracer:&lt;br&gt;
    """Standard-library sys.settrace hook for capturing execution evidence."""&lt;br&gt;
    def &lt;strong&gt;init&lt;/strong&gt;(self, collector: EventCollector, include_stdlib: bool = False):&lt;br&gt;
        self.collector = collector&lt;br&gt;
        self.include_stdlib = include_stdlib&lt;br&gt;
        self._thread_stacks: Dict[int, List[Tuple[str, str, Optional[str]]]] = {}&lt;br&gt;
        self._lock = threading.Lock()&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    # Detect standard library paths to ignore runtime overhead
    self._stdlib_dirs: Set[str] = {
        os.path.abspath(prefix).lower()
        for prefix in (sys.prefix, sys.exec_prefix, getattr(sys, "base_prefix", sys.prefix))
        if prefix
    }
def _trace_dispatch(self, frame, event: str, arg):
    filename = frame.f_code.co_filename
    if not self._should_trace_file(filename):
        return self._trace_dispatch
    thread_id = threading.get_ident()
    func_name = frame.f_code.co_name
    module_name = frame.f_globals.get("__name__")
    line = frame.f_lineno
    with self._lock:
        stack = self._thread_stacks.setdefault(thread_id, [])
        caller_file, caller_func = (stack[-1][0], stack[-1][1]) if stack else (None, None)
        if event == "call":
            depth = len(stack) + 1
            self.collector.add_event(
                event_type="call",
                filename=filename,
                module=module_name,
                function=func_name,
                line=line,
                caller=caller_func,
                caller_file=caller_file,
                depth=depth,
                thread_id=thread_id,
            )
            stack.append((filename, func_name, module_name))
        elif event == "return":
            if stack:
                stack.pop()

    return self._trace_dispatch
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;ol&gt;
&lt;li&gt;Graphs Without NetworkX: Reconstructing Call Paths
Once caller-callee pairs are captured, answering "Why did function X run?" becomes a graph path traversal problem.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Instead of introducing a dependency like NetworkX, a graph in TraceSieve is represented with pure Python dict and set primitives:&lt;/p&gt;

&lt;p&gt;$$\text{Adjacency List}: \text{graph}[\text{caller}] = {\text{callee}_1, \text{callee}_2, \dots}$$&lt;/p&gt;

&lt;p&gt;Reconstructing the shortest observed path from main() to authorize() is accomplished with a breadth-first search (BFS) over the execution event stream:&lt;/p&gt;

&lt;p&gt;python&lt;/p&gt;

&lt;p&gt;def extract_why_trail(events: List[Event], target_func: str) -&amp;gt; Optional[List[str]]:&lt;br&gt;
    """Reconstruct observed caller path from entry point to target function."""&lt;br&gt;
    parent_map: Dict[str, str] = {}&lt;br&gt;
    visited: Set[str] = set()&lt;br&gt;
    queue = []&lt;br&gt;
    for event in events:&lt;br&gt;
        if event.event_type == "call" and event.caller:&lt;br&gt;
            if event.function not in parent_map:&lt;br&gt;
                parent_map[event.function] = event.caller&lt;br&gt;
            if not queue and event.depth == 1:&lt;br&gt;
                queue.append(event.function)&lt;br&gt;
    # Reconstruct path backwards from target&lt;br&gt;
    if target_func not in parent_map:&lt;br&gt;
        return None&lt;br&gt;
    path = [target_func]&lt;br&gt;
    curr = target_func&lt;br&gt;
    while curr in parent_map:&lt;br&gt;
        curr = parent_map[curr]&lt;br&gt;
        path.append(curr)&lt;br&gt;
        if curr == path[-1] and len(path) &amp;gt; 1: # Prevent cycle loops&lt;br&gt;
            break&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;return list(reversed(path))
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;ol&gt;
&lt;li&gt;Persistence with Zero-Config sqlite3
A runtime trace is only useful if it survives the process execution. TraceSieve uses Python's built-in sqlite3 engine to persist execution evidence in a local database file (.tracesieve/runs.db).&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Using SQLite directly required writing clean schema migrations, indexes, and parameterized queries:&lt;/p&gt;

&lt;p&gt;sql&lt;/p&gt;

&lt;p&gt;CREATE TABLE IF NOT EXISTS runs (&lt;br&gt;
    id TEXT PRIMARY KEY,&lt;br&gt;
    name TEXT UNIQUE NOT NULL,&lt;br&gt;
    target_cmd TEXT NOT NULL,&lt;br&gt;
    exit_code INTEGER NOT NULL,&lt;br&gt;
    start_time TEXT NOT NULL,&lt;br&gt;
    end_time TEXT NOT NULL,&lt;br&gt;
    duration_ms REAL NOT NULL,&lt;br&gt;
    total_events INTEGER NOT NULL&lt;br&gt;
);&lt;br&gt;
CREATE TABLE IF NOT EXISTS events (&lt;br&gt;
    id INTEGER PRIMARY KEY AUTOINCREMENT,&lt;br&gt;
    run_id TEXT NOT NULL,&lt;br&gt;
    seq INTEGER NOT NULL,&lt;br&gt;
    event_type TEXT NOT NULL,&lt;br&gt;
    filename TEXT NOT NULL,&lt;br&gt;
    module TEXT,&lt;br&gt;
    function TEXT NOT NULL,&lt;br&gt;
    line INTEGER NOT NULL,&lt;br&gt;
    caller TEXT,&lt;br&gt;
    depth INTEGER NOT NULL,&lt;br&gt;
    thread_id INTEGER NOT NULL,&lt;br&gt;
    FOREIGN KEY(run_id) REFERENCES runs(id) ON DELETE CASCADE&lt;br&gt;
);&lt;br&gt;
CREATE INDEX IF NOT EXISTS idx_events_run_func ON events(run_id, function);&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Static Inventory vs. Runtime Reality (ast)
Static analysis tells us what exists in code. Runtime evidence tells us what actually executed.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Using Python's built-in ast module, TraceSieve walks local source trees (ast.NodeVisitor) to index every defined class, function, and import, then overlays that static inventory against the recorded SQLite evidence.&lt;/p&gt;

&lt;p&gt;python&lt;/p&gt;

&lt;p&gt;class ASTVisitor(ast.NodeVisitor):&lt;br&gt;
    """Parses static functions and classes from AST."""&lt;br&gt;
    def &lt;strong&gt;init&lt;/strong&gt;(self, filename: str):&lt;br&gt;
        self.filename = filename&lt;br&gt;
        self.functions = []&lt;br&gt;
    def visit_FunctionDef(self, node: ast.FunctionDef):&lt;br&gt;
        self.functions.append(node.name)&lt;br&gt;
        self.generic_visit(node)&lt;br&gt;
This contrast powers the tracesieve gaps command:&lt;/p&gt;

&lt;p&gt;text&lt;/p&gt;

&lt;h2&gt;
  
  
  EXECUTION GAP (STATIC &amp;lt;-&amp;gt; RUNTIME MATRIX)
&lt;/h2&gt;

&lt;h2&gt;
  
  
  Module / File                  Static     Runtime   
&lt;/h2&gt;

&lt;p&gt;auth                           [+]        [+]&lt;br&gt;&lt;br&gt;
database                       [+]        [+]&lt;br&gt;&lt;br&gt;
payment                        [+]        [+]&lt;br&gt;&lt;br&gt;
legacy                         [+]        [-]&lt;br&gt;&lt;br&gt;
UNOBSERVED FUNCTIONS (Not executed in scenario)&lt;br&gt;
    refund()     [legacy.py:14]&lt;br&gt;
    chargeback() [legacy.py:32]&lt;br&gt;
⚠️ Important Design Distinction: TraceSieve explicitly avoids calling unobserved code "dead code". An unobserved function in checkout doesn't mean it can't execute; it simply means this scenario never touched it.&lt;/p&gt;

&lt;p&gt;🔥 Features &amp;amp; Practical Terminal Output&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Reconstructing Execution Evidence (tracesieve why)
bash&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;python tracesieve.pyz why checkout authorize&lt;br&gt;
text&lt;/p&gt;

&lt;h2&gt;
  
  
  WHY WAS THIS EXECUTED?
&lt;/h2&gt;

&lt;p&gt;Target:&lt;br&gt;
    authorize()&lt;br&gt;
Observed path:&lt;br&gt;
main()&lt;br&gt;
  |&lt;br&gt;
  checkout()&lt;br&gt;
    |&lt;br&gt;
    process_payment()&lt;br&gt;
      |&lt;br&gt;
      authorize()&lt;br&gt;
Observed in:&lt;br&gt;
    scenario = checkout&lt;br&gt;
First observed event:&lt;br&gt;
    #27&lt;br&gt;
Call count:&lt;br&gt;
    1&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Scenario Differential Analysis (tracesieve diff)
bash&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;python tracesieve.pyz diff login checkout&lt;br&gt;
text&lt;/p&gt;

&lt;h2&gt;
  
  
  SCENARIO DIFFERENCE
&lt;/h2&gt;

&lt;p&gt;LOGIN ONLY&lt;br&gt;
     - login&lt;br&gt;
     - session_create&lt;br&gt;
CHECKOUT ONLY&lt;br&gt;
     + authorize&lt;br&gt;
     + load_cart&lt;br&gt;
     + process_payment&lt;br&gt;
SHARED&lt;br&gt;
       connect&lt;br&gt;
       main&lt;br&gt;
       query&lt;br&gt;
       validate&lt;br&gt;
NEW EXECUTION BRANCH&lt;br&gt;
    authorize&lt;br&gt;
      +-- check&lt;br&gt;
EXECUTION DELTA (COUNT CHANGES)&lt;br&gt;
    query                              1 -&amp;gt; 9     (+800.0%)&lt;br&gt;
Execution events&lt;br&gt;
    login:      24&lt;br&gt;
    checkout:   48&lt;br&gt;
🔒 Security &amp;amp; Privacy by Design&lt;br&gt;
Tracing tools often inadvertently capture sensitive production data when logging frame variables (frame.f_locals).&lt;/p&gt;

&lt;p&gt;TraceSieve guarantees privacy by adhering to a strict design boundary:&lt;/p&gt;

&lt;p&gt;Structure over Payload: TraceSieve captures only execution structure (file names, function names, line numbers, caller relationships, event depths, execution times).&lt;br&gt;
Zero Data Leakage: No variable contents, arguments, or return payloads are ever read, serialized, or stored in SQLite.&lt;br&gt;
📦 Single-File Zero-Dependency Executable (zipapp)&lt;br&gt;
Python includes zipapp in the standard library, which bundles Python source trees into a standalone executable .pyz file:&lt;/p&gt;

&lt;p&gt;bash&lt;/p&gt;

&lt;p&gt;python -m zipapp src -o tracesieve.pyz -m "tracesieve.cli:main"&lt;br&gt;
The resulting tracesieve.pyz file is a complete, self-contained executable that runs on any machine with Python 3.10+ without pip install.&lt;/p&gt;

&lt;p&gt;💡 Lessons Learned from Zero Dependencies&lt;br&gt;
Dependencies are often convenience layers over STDLIB primitives: Click wraps argparse, NetworkX wraps dict/set, and Pydantic wraps dataclasses. Building these layers manually yields deep appreciation for stdlib design.&lt;br&gt;
Constraints drive focused architecture: Removing dependencies eliminates supply-chain risks, package version conflicts, and heavy container images.&lt;br&gt;
Execution is data: Treating program execution as an inspectable, persistent artifact fundamentally changes how we debug, audit, and verify complex software.&lt;br&gt;
🛠️ Try TraceSieve&lt;br&gt;
TraceSieve is open-source, zero-dependency, and ready to use offline.&lt;/p&gt;

&lt;p&gt;⭐️ GitHub Repository: Mohith1-stack/TraceSieve&lt;br&gt;
📖 Built for: Zero Dependency Hackathon 2026&lt;br&gt;
What standard library primitives do you often rely on when avoiding third-party packages? Let's discuss in the comments!&lt;/p&gt;

</description>
      <category>python</category>
      <category>architecture</category>
      <category>cli</category>
      <category>devops</category>
    </item>
  </channel>
</rss>
