DEV Community

Jagan
Jagan

Posted on AI-assisted

A Score Is Not an Explanation: My Journey Building SwitchPath with FalkorDB

From a frustrating local setup to traceable codebase evidence: what I learned while building a graph-backed project audit prototype.

I did not start this project as an expert.

I started as a learner who wanted to build something real, understand how the pieces fit together, and see whether an idea could become a working application.

I have tried to learn technical skills many times. Sometimes I worked hard without feeling that I was moving forward. I also have responsibilities beyond my laptop, and financial constraints make opportunities especially important to me. I cannot assume every opportunity will come around again, so when I found a chance to build with FalkorDB for Graph Hacks, I decided to give it a serious attempt.

But this is not a story about motivation alone. It is about the project I chose to build, the technical problems I encountered, the decisions that shaped the implementation, and what I learned by trying to make the idea work.

That project is SwitchPath.

Repository: github.com/jaganbaditya16-note/SwitchPath

The question that started SwitchPath

Imagine a developer receives this request:

Display declared package dependencies with the manifest file where each package is declared.

The developer needs to understand an existing codebase before making a decision. A keyword search might return several files, but a list of matching files does not explain everything.

Which file actually declares the dependency? Which finding led to that result? Which source file supports the conclusion? And what remains unknown?

A filename match is a useful lead, but it is not proof that a feature works.

That distinction became the central problem behind SwitchPath: how can a project audit make its evidence and relationships easier to inspect instead of returning only a score or a flat list?

I wanted to build a tool that could inspect a local project, identify potentially relevant files and dependencies, connect those records in a graph, and help a developer trace the results back to their sources.

I kept the initial goal narrow. Rather than attempting to understand every programming language or automatically approve every feature request, I focused on a bounded static audit with explicit limitations.

First, the tools had to work together

The first challenge was not a sophisticated graph algorithm. It was getting the development environment and application components to work together.

SwitchPath uses a React and TypeScript frontend, a Python and FastAPI backend, and FalkorDB as its graph database. Docker Compose helps run the database locally.

Each component had a specific role:

  • React and TypeScript provide the interface for submitting an audit and examining its results.
  • FastAPI receives the request, invokes the scanner, and exposes endpoints for reading audits and graph traces.
  • The Python scanner inspects eligible files, extracts supported dependency declarations, and ranks candidate evidence.
  • FalkorDB persists the audit records and the relationships between findings, evidence, files, and dependencies.

On paper, the architecture looked straightforward. Making it work on my machine was a different experience.

Docker was not always ready when I needed it. The database had to be running before the API could successfully use it. PowerShell commands occasionally behaved differently from what I expected, and editing or launching the right component at the right time required patience.

These were ordinary development problems, but they were new challenges for me to work through. When a command failed, I had to stop treating the entire application as one mysterious system and start checking individual pieces.

Was the database running? Could the API reach it? Was the correct environment active? Was the server responding at the expected address?

Breaking the problem into smaller checks helped me make progress. It also taught me something practical: a complicated application becomes easier to debug when each layer has a clear responsibility and a way to verify that it works.

The scanner: finding leads without pretending to know everything

Once the local services were connected, I focused on the audit itself.

SwitchPath performs a bounded, read-only inventory of eligible project files. It does not execute the inspected project code or write into the scanned directory.

The scanner records metadata including relative file paths, extensions, sizes, line counts, and SHA-256 fingerprints. It identifies supported dependency manifests, extracts declarations from formats such as package.json and requirements.txt, and searches for terms related to the feature request.

It also applies explicit inventory limits: a maximum of 500 files, 200,000 bytes per file, and 3,000,000 bytes of scanned content in total.

Why impose those limits?

Because a prototype should have a defined scope. An uncontrolled recursive scan could become expensive or inspect files that are unnecessary for the current task. SwitchPath excludes configured directories and certain sensitive filename patterns and file extensions, although these safeguards do not guarantee that every sensitive file will be detected.

The next problem was deciding which files to show first.

A feature request could match many files. Displaying every match in an arbitrary order would not help much. I implemented a heuristic that ranks evidence using matched terms and their distinctiveness across the inventoried files. For dependency-focused requests, recognized manifest files also receive a ranking bonus.

This is intentionally simple.

The score is a relevance heuristic, not a probability that the requested feature works. The matching can miss useful evidence or highlight irrelevant code. That limitation helped shape the next decision: rather than presenting the score as the final answer, SwitchPath needed a way to show the relationships behind its results.

Why I needed a graph

A conventional list can store a filename and a result. But an audit involves several different kinds of records: requests, findings, files, evidence candidates, and dependencies.

I wanted those records to be connected explicitly.

FalkorDB became the persistence and traversal layer for that part of SwitchPath.

The graph uses nodes such as:

Node What it represents
ProjectAudit One project audit request
AuditFinding A finding produced by the audit
ProjectFile An inspected file and its metadata
AuditEvidence A candidate evidence record
AuditDependency A discovered declared dependency

Relationships connect these nodes. For example, HAS_FINDING links an audit to a finding, CANDIDATE_EVIDENCE links a finding to candidate evidence, and POINTS_TO links that evidence to its source file.

Dependency records use a different path. LISTS_DEPENDENCY connects a finding to a dependency, while DECLARED_IN connects the dependency to its manifest file.

Conceptually, the evidence path looks like this:

ProjectAudit
    |
    | HAS_FINDING
    v
AuditFinding
    |
    | CANDIDATE_EVIDENCE
    v
AuditEvidence
    |
    | POINTS_TO
    v
ProjectFile
Enter fullscreen mode Exit fullscreen mode

The dependency path looks like this:

ProjectAudit
    |
    | HAS_FINDING
    v
AuditFinding
    |
    | LISTS_DEPENDENCY
    v
AuditDependency
    |
    | DECLARED_IN
    v
ProjectFile (manifest)
Enter fullscreen mode Exit fullscreen mode

The important part is that these relationships are persisted in the database. They are not simply drawn in the interface to make the project look graph-based.

The API queries FalkorDB to retrieve the connected records when a user asks for a trace. That is where the graph becomes useful to the application.

The moment the relationships became inspectable

One of the most useful checks was verifying that the trace endpoint returned actual paths from the stored graph.

For evidence, SwitchPath uses a Cypher traversal along these relationships:

MATCH (a:ProjectAudit {id: $id})-[:HAS_FINDING]->(f:AuditFinding)
      -[:CANDIDATE_EVIDENCE]->(e:AuditEvidence)
      -[:POINTS_TO]->(p:ProjectFile)
RETURN f.finding_id, f.status, e.path,
       e.matched_terms_json, e.matching_lines_json, p.sha256
ORDER BY f.finding_id, e.path
Enter fullscreen mode Exit fullscreen mode

The query connects the audit to a finding, the finding to candidate evidence, and the evidence to its source file.

For dependencies, the trace follows a different chain:

MATCH (a:ProjectAudit {id: $id})-[:HAS_FINDING]->(f:AuditFinding)
      -[:LISTS_DEPENDENCY]->(d:AuditDependency)
      -[:DECLARED_IN]->(p:ProjectFile)
RETURN f.finding_id, d.name, p.path, p.sha256
ORDER BY d.name, p.path
Enter fullscreen mode Exit fullscreen mode

This returns the dependency, its associated finding, and the manifest file connected to that dependency.

The API exposes these results at:

GET /api/audits/{audit_id}/trace

The response contains separate evidence_paths and dependency_paths collections. The frontend can then present them in the relevant evidence and dependency views.

During one local verification run, the trace endpoint returned 11 evidence paths and 11 dependency paths. Those counts belong to that particular run, rather than representing a general benchmark or a guaranteed result.

I also recorded 18 passing backend tests and a successful frontend build during development. These checks gave me useful feedback about the implementation, although they cannot prove the absence of every defect.

For me, the important milestone was not the number itself. It was being able to follow a result through the API and see that the expected relationships were being returned from the graph.

The code for this part is available in audit_graph.py.

What I learned from the difficult parts

The problems were not limited to one database connection or one failing command. The bigger challenge was understanding how each layer affected the next.

A working frontend was not enough if the API could not communicate with the database. An API response was not enough if the expected relationships had not been saved. A successful graph query was not enough if the interface gave users no practical way to inspect the result.

I learned to verify the chain instead of trusting one successful step.

I also learned to be careful about what the output means.

A file hash can identify the bytes that were inspected, but it cannot prove those bytes are trustworthy. A matched keyword can point a developer toward relevant code, but it cannot prove implementation correctness. And a graph can accurately represent stored relationships while those relationships still provide incomplete evidence about a feature.

This last point is especially important. FalkorDB does not magically make a heuristic correct. It enables SwitchPath to store relationships and traverse them so that the connections behind a result can be examined.

That is a more limited claim than automatic code understanding, but it is also a claim the current prototype can demonstrate.

What SwitchPath is today—and what it is not

SwitchPath is a working local prototype for graph-backed, static project audits.

It can inventory eligible files within defined limits, extract supported dependency declarations, rank evidence candidates, persist connected audit records, and return evidence and dependency paths through its API.

It is not yet a fully autonomous AI agent. It does not use an LLM in the current audit-matching workflow, execute the inspected project, or automatically run the project's tests. Its keyword-based evidence ranking is limited, and a static scan cannot establish every property of a feature or prove a project's total future operating costs.

I want to be explicit about these boundaries because a professional engineering project should explain not only what works, but also what remains unfinished.

My next steps would include richer language-aware analysis, additional dependency and import relationships, and a carefully controlled way to run selected project tests with user approval. I would also like to develop a review workflow that lets developers record whether evidence was accepted or rejected.

Those are future directions, not features I am claiming to have completed.

More than the final result

There is a personal reason I cared about finishing this project, but I do not want that to overshadow the engineering work.

I am still learning. I do not always find technical problems easy, and sometimes the distance between an idea and a working application feels large. I have responsibilities and financial constraints, so opportunities to build, learn, and show my work matter to me.

The opportunity to work with FalkorDB felt like a small light in a difficult stretch—not because a database can solve personal problems, but because a chance to build something gave me another reason to keep learning.

I cannot know whether this project will win the competition. What I can control is whether I give the opportunity a serious attempt, check what I have built, explain it honestly, and learn from the result.

That mindset influenced the way I approached SwitchPath. I tried to turn a broad ambition into a specific engineering problem, break the work into smaller parts, and keep checking whether the implementation matched the idea.

Final thoughts: make the path visible

The central idea behind SwitchPath is simple: an audit finding should not be an unexplained score.

By connecting audits, findings, evidence candidates, source files, and dependencies in FalkorDB, the prototype can trace stored relationships and return paths for developers to review.

There is plenty left to improve. The current scanner is heuristic, the coverage is limited, and the project is not a production-grade autonomous agent. But it provides a concrete foundation to build on: a bounded scanner, a graph-backed data model, real Cypher traversals, an API, and an interface for reviewing the results.

For me, the project has also been a lesson in how software gets built. Not through one perfect command or one inspired moment, but through small decisions, failed attempts, careful checks, and gradual understanding.

I started with a question about making audit results more explainable. I ended up with a working prototype that lets me investigate the relationships behind those results—and a clearer understanding of what I need to learn next.

Explore the implementation: SwitchPath on GitHub


AI-assistance disclosure: AI assistance was used during development for planning, architecture discussions, code proposals and refinement, regression-test work, debugging from terminal output, and documentation. AI assistance was also used to help draft and edit this article from the participant's project context and personal reflections. The participant remains responsible for checking technical claims, understanding the submitted implementation and graph queries, and accurately representing what was built.

Top comments (0)