Skip to main content
Welcome. This site supports keyboard navigation and screen readers. Press ? at any time for keyboard shortcuts. Press [ to focus the sidebar, ] to focus the content. High-contrast themes are available via the toolbar.
serard@dev00:~/cv

2. Architecture Across Three Times

BinaryWrapper operates at three times: collecting evidence, compiling APIs and executing commands. Separating them allows a build to use cached inputs, business code to use contracts and a process execution to choose a fresh parser.

The architecture is easier to understand by following dependencies than by treating every project containing “Design” as a runtime library.

Three times and three sets of inputs

Design time runs collectors and help acquisition. Its outputs are versioned JSON trees and reusable help evidence. Build time reads those artifacts and declarative catalogues through Roslyn. Runtime consumes compiled command types, a binary binding and output parser factories.

Diagram
Acquisition, compilation and execution have distinct inputs and failure boundaries.

Failures belong to the boundary where they occur. An image recipe failure is an acquisition problem. A malformed JSON input is a compilation-input problem. An unknown output version is a parsing-contract problem. A nonzero process exit is an execution result.

Framework project responsibilities

The project names describe actual ownership in the inspected source.

Project Responsibility
BinaryWrapper.Contracts Shared commands, process values, output records, parser/collector contracts, runner and executor interfaces, environment abstractions.
BinaryWrapper.Lib Semantic-version values and comparison used across generation and execution.
BinaryWrapper.Attributes Descriptor and environment declaration metadata.
BinaryWrapper.SourceGenerator Roslyn command, builder, client, environment-attribute and forwarding generation.
BinaryWrapper Concrete process execution, binary resolution, parser strategies and runner implementation.
BinaryWrapper.Design Help models, parsers, scraping and container-related support.
BinaryWrapper.Design.Lib Design pipeline orchestration and, in a separate target, environment catalogue generation.
BinaryWrapper.Testing Fake transports, commands and helpers for testing execution and scraping.

The runtime and contracts inspected here target net11.0. Roslyn components use netstandard2.0. These are the current project targets, rather than a statement about every past release.

The two faces of Design.Lib

BinaryWrapper.Design.Lib targets both netstandard2.0 and net11.0, with different compiled source sets.

Its net11.0 target supplies the pipeline runner, CLI, image plans and Windows-binary acquisition. Its netstandard2.0 target supplies the environment catalogue reader and incremental generator, with Roslyn dependencies kept private.

The contracts project references the generator target as an analyzer. That reference does not make the Design executable or its container operations a runtime dependency of the contracts assembly. Environment generation explains the inputs read by this analyzer.

Consumer package ownership

A tool integration normally has a Design executable, a Contracts library, an implementation library and tests.

Diagram
Generated commands and observed messages are usable without depending on concrete parsers or process runners.

Contracts own generated commands, typed environments, output events, result records and IVagrantRunner. The implementation owns the concrete runner, parser strategies, parsers, collectors, generated builders and generated client. The existing tool namespace is retained even when assembly ownership changes.

This split is controlled by descriptor generation flags. A contracts descriptor requests BinaryWrapperGeneration.Commands. The implementation descriptor requests Builders | Client. Both use the same help data and environment type.

Runtime data flow

The generated client constructs commands. It does not implicitly execute them. The runner or executor resolves a binding, builds argument and environment snapshots, then asks IProcessRunner to produce a stream or buffered result.

For typed streaming, the executor resolves the binding once and creates a parser with the selected command/binary version. Both process channels reach that parser. After drainage, Complete(actualExitCode) emits final observations. A collector can aggregate the same events.

ICommandExecutor is an interface in shared contracts. A concrete tool runner can therefore be assembled with an injected execution service, while business code needs only its tool-specific runner interface.

Different artifacts have different lifecycles

Help snapshots are acquired and updated by Design tools. Roslyn output is recomputed from build inputs. Vagrant's source-derived UI catalogue is regenerated by a developer maintenance tool and checked into its projects. Runtime state belongs to a single execution.

These distinctions affect packaging and debugging. A missing command type sends you to inputs and generation flags. A mismatched UI template sends you to the pinned output catalogue and profile. A process hang sends you to stream lifetime and cancellation. Chapter 13 turns those boundaries into a maintenance workflow.

Source snapshot

Source inspection: 2 October 2026. These implementation paths are relative to Net/FrenchExDev in the local ecosystem checkout. The v2 changes are largely uncommitted; these paths identify inspected code, without claiming that public branch links contain it.

  • BinaryWrapper/doc/ARCHITECTURE.md
  • BinaryWrapper/src/FrenchExDev.Net.BinaryWrapper.Design.Lib/FrenchExDev.Net.BinaryWrapper.Design.Lib.csproj
  • Vagrant/src/FrenchExDev.Net.Vagrant.Contracts/FrenchExDev.Net.Vagrant.Contracts.csproj

Previous · Series index · Next

⬇ Download