We are putting coding-agent repositories to the same test we previously applied to HuggingFace’s chat-ui. These systems connect model output to tools, permissions, sandboxes, terminals, patches, configuration, state, and user interfaces. OpenAI’s open-source Codex repository is the first audit in the series.
ChatWidget.dispatch_command reported architectural fan-out 187. We inspected the relations behind the score.
The audit receipt
Every number below comes from one manifest-enabled Enola 0.4.8 snapshot.
| Metric | Value |
|---|---|
| Files accounted for | 6,066 |
| Files parsed | 3,793 |
| Architectural facts | 104,893 |
| Review signals | 129 across 11 explainers |
| Extractors | Rust, TypeScript, Python, manifests, C/C++, Protobuf |
| Parse errors | 0 |
| Cold snapshot time | 7.50s, zero cache reuse |
| Enola version | 0.4.8 |
The receipt records a dirty source tree: .gitignore had local changes and several .enola-* audit-output directories were untracked. The audit configuration excluded the output directories from the census.
Codex audit profile
The signal: fan-out 187
ChatWidget.dispatch_command routes slash commands in the terminal UI. Enola reported four incoming symbols, complexity 73, and architectural fan-out 187.
Enola calculates fan-out from relation–target pairs. This score includes calls, constructed values, enum variants, and the function’s declaration edge.
ChatWidget.dispatch_command | Occurrences | Unique targets |
|---|---|---|
| Calls | 158 | 89 |
| Constructions | 220 | 97 |
| Declaration edge | 1 | 1 |
| Reported architectural fan-out | 187 relation–target pairs | |
The raw fact contains 158 call occurrences and 220 construction occurrences. Repetition is substantial: to_string appears 29 times, send 14 times, SlashCommand 56 times, Some 31 times, and AppEvent 14 times. After relation–target deduplication, six names still occur once as a call target and once as a constructed target. The 187 pairs therefore represent 180 unique outward symbol names.
The score describes dispatcher vocabulary. For a slash-command change, review the selected branch, emitted events, state changes, redraw behavior, and error path.
Complexity measures cases here
Enola starts each Rust function at one and adds one for every if, match arm, ? expression, loop, and && or || branch. Complexity 73 for ChatWidget.dispatch_command means 72 such increments. App.handle_event, the TUI event dispatcher, scores 389: 388 increments.
Both functions route explicit variants to behavior. Each match arm raises the score even when its body is short; every ? adds another increment. Use the score as a count of control-flow cases. Defect probability and runtime cost require separate measurements.
Fan-in identifies compatibility surfaces
Fan-in points in the other direction. BottomPane.request_redraw has 71 dependent symbols, invalid_request has 48, and display_width has 42. Their roles explain the counts: UI invalidation, shared error construction, and text measurement are supposed to be reused.
The actionable question is compatibility. A redraw change can alter timing across many UI paths. An error-constructor change can affect response shapes across request handlers. A width-calculation change can move text throughout the interface. High fan-in locates the surface; reading the implementation establishes the risk.
The pattern repeats outside the TUI
MessageProcessor.handle_initialized_client_request scores 141 because it dispatches request variants and their validation paths. Configuration functions show the same broad-vocabulary pattern: load_config_layers_state has 66 unique call targets and 22 unique constructed targets; ConfigManager.apply_edits has 55 and 28. Each reported score also includes one declaration edge.
These functions coordinate request handling, configuration precedence, managed requirements, writes, and reload behavior. Their aggregate scores locate the orchestration. Branch-level source and tests determine the consequence of a change.
Other signals
| Initial signal | What inspection established |
|---|---|
Dependency depth 52 from codex-rs/cli/src/bin | The result expands members of collapsed strongly connected components. Use it as breadth evidence; adjacency between rendered names is unverified. |
| 37 directed module cycles | Thirty-six stay inside a Rust crate, where mutual module references are legal. The remaining generated TypeScript relationship uses import type, which disappears from emitted JavaScript. |
| 553 of 553 symbols exported from the largest protocol module | The module is generated client-contract output. Its public surface belongs to the schema and compatibility policy. |
The measured evidence supports repository breadth, intra-crate coupling, a generated type graph, and a generated API surface. It provides no verified 52-hop route or runtime initialization cycle.
Coverage boundaries
The receipt accounts for 6,066 files: 3,793 produced facts; 2,082 belonged to file kinds without an enabled extractor; 173 were claimed by an extractor and produced no facts; and 18 matched explicit ignore rules.
| Claimed, no facts emitted | Files |
|---|---|
| Manifests | 129 |
| Rust | 30 |
| TypeScript | 8 |
| C/C++ | 4 |
| Python | 2 |
The non-emitting source files are mainly module barrels, test aggregators, empty __init__.py files, headers without extractable declarations, and manifests without a supported package declaration. Four generated TypeScript union files were skipped because each contains a line longer than the generated-file guard’s 2,000-character threshold: ClientRequest.ts, ResponseItem.ts, ServerNotification.ts, and ServerNotificationEnvelope.ts.
The 2,082 unsupported files include fixtures, prose, data, Bazel definitions, SQL, YAML, and shell scripts. Documentation, CI, and the full build graph remain outside this snapshot.
Result after investigation
ChatWidget.dispatch_command is a wide, handwritten orchestration boundary: 89 call targets, 97 constructed targets, one declaration edge, and repeated operations around commands, events, messaging, conversion, and redraw. Start changes at the affected command branch, then follow its events and state transitions.
FAQ
What did Enola find in the OpenAI Codex repository?
The strongest signal was in the terminal UI's slash-command dispatcher, ChatWidget.dispatch_command, where a single function routes to 89 distinct call targets and 97 distinct constructed values across command handling, events, and redraw.
What does a fan-out of 187 mean for ChatWidget.dispatch_command?
Fan-out is not a raw call count. The underlying fact recorded 158 call occurrences and 220 construction occurrences before deduplication; Enola counts each distinct target once per relation type, which collapses that into 187 relation–target pairs. Six symbols show up as both a call target and a constructed value, which is why the pair count differs slightly from the count of distinct symbol names touched.
Does Codex have a verified 52-module dependency path?
Not in the sense of a checked call chain. Depth 52 comes from expanding the members of collapsed strongly-connected components back out for display, so it measures how much of the module graph a change at that entry point can reach, not a confirmed sequence of 52 consecutive calls.
Are the generated TypeScript protocol cycles runtime risks?
No. The cycle sits entirely in generated TypeScript type declarations (import type), which TypeScript strips before compilation, so nothing in the emitted JavaScript references itself at runtime.
Which Enola version produced this Codex audit?
The published audit used Enola 0.4.8 with Rust, TypeScript, Python, manifest, C/C++, and Protobuf extractors enabled.
enola. is open source under Apache 2.0: free, local, no data leaves your machine.
curl -fsSL https://raw.githubusercontent.com/enola-labs/enola/main/install.sh | sh