GERC (gerc crate)
gerc is the Rust lowering and emission layer in the PARC -> LINC -> GERC
toolchain.
It is the crate you use when you already have a normalized source contract and,
optionally, evidence about native symbols or link plans. gerc then turns that
input into Rust FFI output.
The target architecture is strict:
gerclibrary code must not depend onparcorlincgercowns its own generation modelgercconsumes translated source and evidence inputs- translation from PARC or LINC artifacts belongs only in tests, examples, or external harnesses
- there is no shared ABI crate and no backward-compatibility burden for discarded pipeline shapes
gerc generates Rust FFI bindings from C declarations. The output can be a
standalone Rust source bundle or a Cargo-compatible crate directory, and it
also emits plain rustc link arguments for non-Cargo toolchains.
One correction matters up front: the current public crate surface is broader
than just generate() and generate_from_source(). The crate also exposes:
- a crate-owned C-side model under
gerc::c - explicit staged
gate/lowermodules - consumer-side inspection and sidecar helpers
In the toolchain split:
parcowns source meaninglincowns link and binary meaninggercowns Rust lowering, Rust emission, and emitted build output
Audience
This book is for developers who:
- want to understand how
gerctransforms C declarations into Rust FFI code - need to integrate
gercas a library in their own tooling - are building downstream consumers on top of
gercoutput
Scope
gerc is intentionally narrow:
| Responsibility | Owner |
|---|---|
| C header parsing and source extraction | parc |
| Link, validation, and ABI evidence | linc |
| Rust FFI projection and code generation | gerc |
| Runtime loader policy and deployment | downstream tooling |
fol-specific surface generation | downstream tooling |
Quick Start
#![allow(unused)]
fn main() {
use gerc::{generate_from_source, GercConfig, emit_source};
use gerc::intake::{SourceDeclaration, SourceFunction, SourcePackage, SourceType};
let mut source = SourcePackage::default();
source.declarations.push(SourceDeclaration::Function(SourceFunction {
name: "init".into(),
parameters: vec![],
return_type: SourceType::Int,
variadic: false,
source_offset: None,
}));
let config = GercConfig::new("mylib_sys");
let output = generate_from_source(source, &config).unwrap();
let emitted = emit_source(&output.projection);
println!("{emitted}");
}
If validation evidence is present, gerc treats it as a gating input for
functions and variables. Declarations without usable evidence are filtered out
and reported through diagnostics instead of being emitted.
Overview
gerc sits between parc, linc, and downstream Rust tooling in the
toolchain:
PARC (source contracts)
-> LINC (link and evidence contracts)
-> GERC (Rust lowering and emission)
-> generated Rust bindings crate or source bundle
Read this chapter as the workflow summary:
gercreceives its own input model- any upstream artifact translation happens outside
gerc/src/** gercgates, lowers, and emits deterministic Rust and build artifacts
What Happens Inside GERC
-
Intake -
gercreceives aGercInputwrapping source plus optional evidence. Tests/examples or external harnesses may translate PARC and LINC artifacts into that model. -
Safety gating - Each declaration is checked against generation rules. Items that cannot be safely represented in Rust are rejected with diagnostics rather than guessed into existence.
-
Lowering - Accepted declarations are lowered from the crate-owned C-side model into
RustProjection. -
Type mapping - C types, pointers, arrays, function pointers, and qualifiers are mapped to Rust FFI-safe equivalents.
-
Emission - The projection is rendered into deterministic Rust source. Items are emitted in a stable order: constants, type aliases, enums, records, then
extern "C"declarations. -
Crate generation - Optionally,
gercwrites a Cargo-compatible crate directory or a source bundle plusrustclink arguments.
Design Principles
- Deterministic - the same input always produces the same output
- Conservative - refuse generation rather than emit unsound code
- Library-first -
gercis a Rust library, not a CLI tool - Generic - no
fol-specific assumptions in the core crate - Artifact-boundary integration - cross-package composition belongs outside
gerc/src/** - No back-compat burden - discarded shapes are deleted, not preserved
Architecture
What GERC Owns
gerc owns Rust lowering, projection, emission, and generated build output
for this toolchain layer.
It does not own:
- source parsing
- binary inspection
- upstream artifact translation inside
src/**
Module Layout
| Module | Purpose |
|---|---|
intake | Crate-owned source and evidence input models |
c | Crate-owned C-side binding model and native evidence types |
typemap | Maps C-like types to Rust FFI types |
gate | Safety gating for each declaration |
lower | Lowers accepted items into RustProjection |
ir | Rust projection IR and supporting types |
emit | Renders the IR into deterministic Rust source |
linkgen | Lowers native link surfaces into Cargo and rustc directives |
crategen | Writes crate directories and source bundles to disk |
contract | Top-level generation entry point and JSON output contract |
consumer | Generic downstream-consumer contract and metadata sidecar |
config | Generation configuration (GercConfig) |
output | Generation output container (GercOutput) |
error | Crate error types (GercError, GercResult) |
gerc is the only Rust emitter in this pipeline layer. If older Rust-emission
logic still exists elsewhere, the end state is to move the useful behavior here
and delete the duplicate path.
At the crate root, gerc exposes four top-level API families:
- generation and crate emission
- staged intake and evidence attachment
- JSON metadata and projection contracts
- consumer inspection helpers and metadata sidecars
It also exposes a large crate-owned C-side compatibility model through
gerc::c. That model exists because gerc still supports staged workflows
and internal lowering paths that operate on binding-style inputs, even though
the preferred top-level story is source-first.
Data Flow
GercInput
│
├── gate::gate_package() -> Vec<GateDecision> + diagnostics
│ │
│ └── filter: only accepted items pass through
│
├── lower::lower_package() -> RustProjection + diagnostics
│
├── linkgen lowering -> native link requirements
│
└── GercOutput { projection, diagnostics }
│
├── emit_source() -> Rust source string
├── emit_crate() -> Cargo crate or source bundle on disk
└── build_sidecar() -> JSON metadata for consumers
This is an internal gerc data flow. It is not permission for gerc/src/**
to import upstream crate types. Upstream artifacts must be translated outside
the library boundary and then handed to gerc in gerc’s own input model.
Artifact Boundary
gerc consumes its own source/evidence model and emits its own generation
artifacts.
The boundary rule is:
gerc/src/**must not depend onparcorlinc- tests/examples/external harnesses may translate upstream artifacts into
gercinput - generated Rust/build outputs are the downstream-facing product
Key Types
gerc should not import parc or linc in library code.
If another package’s artifact needs to be consumed, the translation belongs in
tests/examples or an external harness.
GercInput
The primary input container. It wraps:
- a required
SourcePackage - optional
EvidenceInputs
EvidenceInputs can carry LinkAnalysisPackage, ValidationReport, and
ResolvedLinkPlan data.
RustProjection
The central IR type. It contains:
items: Vec<RustItem>- functions, records, enums, type aliases, constants, statics, unsupported markersmodules: Vec<RustModule>- optional module organizationlink_requirements: Vec<RustLinkRequirement>- native link metadatanotes: Vec<ProjectionNote>- provenance and diagnostic notes
GateDecision
Either Accept or Reject(reason). Rejected items produce diagnostics but no
Rust code.
gerc::c::*
This module is a crate-owned C-side model used by staged lowering, tests, and compatibility-style flows. It is public and root-reexported, so the documentation needs to treat it as part of the actual surface, not as a hidden implementation detail.
API Reference
First Principle
gerc is the Rust lowering and emission layer of the toolchain.
The safest downstream posture is:
- prefer crate-root APIs first
- provide
gerc’s own source/evidence inputs directly - keep upstream artifact translation outside
gerc/src/** - treat emitted Rust and build artifacts as the product boundary
API Tiers
gerc organizes its public API into two tiers:
- Tier 1:
generate(),generate_from_source(),GercConfig,GercInput,GercOutput,GercOutputMeta,SCHEMA_VERSION - Tier 2: the individual modules (
lower,gate,emit,typemap,linkgen,crategen,consumer,c)
The crate root also re-exports the common emission entrypoints so downstream
code does not need to import emit or crategen directly for routine use:
emit_source, emit_type, emit_crate, emit_build_rs, emit_rustc_args,
emit_rustc_link_args, OutputMode, OverwritePolicy, CrateManifest, and
EmittedCrate.
For explicit staged workflows, the crate root also re-exports:
EvidenceInputsGateDecisionoutput_meta,meta_to_json,meta_from_json,projection_to_json, andprojection_from_jsonGercConsumer,ConsumerReport,ConsumerFinding,FindingKind,PassthroughConsumer,FolConsumer,build_sidecar,sidecar_to_json,sidecar_from_json,extern_function_names,record_names, andtype_alias_names
For staged inspection, import the modules explicitly:
gerc::gate::gate_package(...)gerc::lower::lower_package(...)
The root also re-exports many gerc::c::* types directly, because the crate
still supports staged and compatibility-style workflows over its own binding
model.
Preferred Public Surface
These are the main consumer-facing entrypoints:
generate()andgenerate_from_source()GercInput,GercConfig, andGercOutputemit_source(),emit_crate(),emit_build_rs(), andemit_rustc_args()- JSON metadata and projection helpers
- consumer-sidecar helpers
Primary Workflow
generate_from_source() is the preferred entrypoint when the caller already
has a SourcePackage. Use GercInput directly when attaching optional
translated evidence in parallel with source.
#![allow(unused)]
fn main() {
use gerc::{
emit_crate, emit_rustc_args, emit_source, generate, generate_from_source, GercConfig,
GercInput, OutputMode, OverwritePolicy,
};
let input = GercInput::from_source_package(source.clone())
.with_analysis(analysis)
.with_validation(validation)
.with_link_plan(plan);
let output = generate_from_source(source, &GercConfig::new("mylib_sys")).unwrap();
let config = GercConfig::new("mylib_sys");
let output = generate(&input, &config).unwrap();
let source = emit_source(&output.projection);
let rustc_args = emit_rustc_args(&output.projection);
let emitted = emit_crate(
&output.projection,
&config,
std::path::Path::new("/tmp/mylib_sys"),
OutputMode::Crate,
OverwritePolicy::Overwrite,
).unwrap();
}
GercInput also exposes from_source_json(...) for explicit JSON intake.
When validation evidence is attached, generate() filters out declarations
that fail validation gating instead of emitting speculative Rust bindings.
For lower-level staged work, the public API still supports:
BindingPackageBindingItemBindingTypegate::gate_package(...)lower::lower_package(...)
The emitted crate path supports both:
- Cargo build-script rendering via
build.rs - direct
rustcargument rendering viarustc-link-args.txtandemit_rustc_args(...)
Downstream Posture
If you are integrating gerc into another tool, prefer:
- root-level generation APIs
- explicit
GercInputconstruction when evidence is available - emitted Rust/build outputs rather than internal lowering modules
- tests/examples/harnesses for any
parcorlincartifact translation
Integration Coverage
The current suite exercises realistic split-pipeline paths, not only hand-constructed packages:
parc -> gercsource-only generation for zlib and libpng fixturesparc -> linc -> gercgeneration with declared link surfacesparc -> linc -> gercgeneration with resolved link-plan evidence
Those paths are proved in tests and examples. They are not library-level crate dependencies.
Configuration
GercConfig controls what gets generated:
| Field | Default | Description |
|---|---|---|
crate_name | "gerc_output" | Name for the generated crate |
crate_version | "0.1.0" | Version string |
emit_functions | true | Emit extern "C" function declarations |
emit_records | true | Emit #[repr(C)] struct/union types |
emit_enums | true | Emit enum types |
emit_type_aliases | true | Emit type aliases |
emit_variables | true | Emit static variable declarations |
emit_constants | true | Emit constant definitions |
emit_build_script | true | Emit build.rs with link metadata |
Explicit Non-Goals
The current contract does not promise:
- parsing or preprocessing C
- binary inspection inside
gerc - automatic invention of missing ABI facts
- library-level dependencies on upstream pipeline crates
Error Handling
All fallible operations return GercResult<T>, which is Result<T, GercError>.
JSON Contract
Output metadata can be serialized for downstream tooling:
#![allow(unused)]
fn main() {
use gerc::contract::{output_meta, meta_to_json};
let meta = output_meta(&config, &output);
let json = meta_to_json(&meta).unwrap();
}
The JSON includes schema_version as an artifact-shape gate.
meta_from_json() rejects metadata with a schema version newer than the
current build supports rather than guessing.
Consumer Contract
Downstream tools implement the GercConsumer trait:
#![allow(unused)]
fn main() {
use gerc::consumer::{GercConsumer, ConsumerReport};
use gerc::ir::RustProjection;
struct MyConsumer;
impl GercConsumer for MyConsumer {
fn inspect(&self, proj: &RustProjection) -> ConsumerReport {
ConsumerReport::default()
}
}
}
A MetadataSidecar (JSON) can be generated alongside the crate for tools that
do not need to parse Rust source:
#![allow(unused)]
fn main() {
use gerc::consumer::{build_sidecar, sidecar_to_json};
let sidecar = build_sidecar("mylib_sys", &output.projection);
let json = sidecar_to_json(&sidecar).unwrap();
}
Generated crate metadata and crate-level src/lib.rs markers identify the
emitter as GERC.
Intake Contract
Primary Input
gerc is source-first, but the important ownership rule is:
gerclibrary code owns its own input typesgerclibrary code must not depend onparcorlinc- translation from PARC or LINC artifacts belongs outside
gerc/src/**
GercInput is therefore the crate-owned intake boundary.
In practice there are two real intake layers:
- the preferred
GercInputpath - the lower-level crate-owned
gerc::cmodel that staged helpers and some tests still use directly
Optional Enrichment
Additional evidence forms can optionally be attached.
Link analysis artifact
The preferred binary/link evidence contract derived from linc.
When present, gerc can read:
- resolved link-plan data
- declared link surface
- attached validation evidence
without forcing source declarations to flow through linc as the only path.
Validation report artifact
Declaration-vs-artifact validation evidence. When present, gerc uses
validation findings to drive safety gating decisions.
Attached validation evidence is not advisory. gerc rejects functions and
variables that are missing validation matches or that only have unusable
matches such as ABI mismatches, duplicate providers, hidden providers,
decoration mismatches, or wrong-kind matches.
Representation evidence is also treated conservatively. If a record or enum
already carries a representation block but upstream left required fields unset
such as record size, record alignment, or enum underlying size, gerc rejects
that declaration instead of guessing.
Resolved link-plan artifact
Resolved native link requirements. When present, gerc uses the resolved
plan, with concrete artifact paths and search directories, instead of the raw
source-declared link surface.
Building a GercInput
#![allow(unused)]
fn main() {
use gerc::intake::{GercInput, SourcePackage};
let input = GercInput::from_source_package(SourcePackage::default());
let input = GercInput::from_source_package(SourcePackage::default())
.with_analysis(analysis)
.with_validation(report)
.with_link_plan(plan);
let input = GercInput::from_source_json(source_json).unwrap();
}
Normalization
GercInput::normalize() is called automatically during generate(). It:
- deduplicates function declarations by name
- aligns provenance markers
- is idempotent
Internally, normalization still routes through the crate-owned binding-style model before reconstructing source-shaped state. That is important drift from the cleaner architecture story, and the docs should say so plainly.
What GERC Does Not Accept
gerc does not accept raw C source code or header files directly. Source
extraction belongs in parc, and link/binary evidence belongs in linc.
The library also should not grow direct PARC/LINC dependency paths in src/.
That would violate the intended boundary.
Hardening Matrix
This chapter translates the large GERC generation suite into an explicit hardening ladder.
The point is not to count tests. The point is to make it obvious which surfaces are carrying confidence for lowering, emission, and build-output generation.
Tier 1: Hermetic Canonical Baselines
These should stay green everywhere:
- source-only sqlite3 lowering
- source-only zlib lowering
- source-only libpng lowering
- deterministic emitted crate output on vendored fixtures
- large internal corpus fixtures and root API tests
- source-only incomplete-handle lowering
- keyword-safe placeholder emission on unresolved named types
These surfaces prove that GERC can:
- ingest its own source model
- gate declarations conservatively
- lower accepted declarations deterministically
- emit stable Rust and build artifacts
Tier 2: Host-Dependent High-Value Ladders
These strengthen confidence on real native environments:
- OpenSSL link-directive generation
- libxml2 link-directive generation
- Apple framework link-directive generation
- Windows system-library link-directive generation
- combined Linux event-loop link-directive generation
- libc and system-library evidence-aware generation families
These surfaces matter because they prove that GERC can use real upstream evidence without taking a library dependency on upstream crates.
Tier 3: Conservative-Rejection Surfaces
These are good failures, not bad coverage:
- anonymous-type lowering fallback and refusal when by-value naming is not honest
- bitfield-by-value and representation-sensitive record rejection
- unsupported layout or ABI-sensitive gating
- source-only degradation when link evidence is absent
- explicit rejection of declarations that would produce unsound Rust
Those tests should remain:
- deterministic
- diagnostic
- easy to point to in release discussions
Determinism Anchors
The most important repeat-run anchors right now are:
- source-only zlib projection
- source-only libpng projection
- source-only sqlite3 projection
- emitted crate output on deterministic fixtures
- libxml2 link directives when available
- Apple framework link directives
- Windows system-library link directives
- incomplete-handle lowering
- keyword-placeholder emission
- OpenSSL link directives when available
- combined Linux event-loop link directives when available
Code Generation
gerc owns Rust FFI emission in the PARC -> LINC -> GERC toolchain.
Useful older emitter behavior is rehomed here when it still belongs in gerc;
obsolete output shapes are not kept alive just to preserve dead paths.
Pipeline Stages
Code generation in gerc proceeds through several stages:
1. Safety Gating (gate)
Each item in the source-derived lowering package is evaluated against generation rules:
| Rule | Effect |
|---|---|
| Bitfield records | Rejected - no safe repr(C) representation |
| Packed non-bitfield records and unions | Allowed when representation evidence is explicit |
| Anonymous records | Rejected - Rust requires named types |
| Anonymous enums | Rejected - Rust requires named types |
| Incomplete or opaque fields | Rejected - cannot determine layout |
Unsupported items | Rejected - explicitly unsupported upstream |
Pointer-only references to anonymous or otherwise unnameable declarations are a
special case: those degrade to opaque *mut/*const core::ffi::c_void instead
of forcing the whole surface to fail.
Rejected items produce diagnostics in the output but no Rust code.
2. Type Mapping (typemap)
C types are mapped to Rust FFI-safe equivalents:
| C type | Rust type |
|---|---|
void | () (or omitted) |
_Bool | bool |
int | core::ffi::c_int |
unsigned int | core::ffi::c_uint |
long | core::ffi::c_long |
float / double | core::ffi::c_float / core::ffi::c_double |
void* | *mut core::ffi::c_void |
const void* | *const core::ffi::c_void |
T* | *mut T / *const T |
T[N] | [T; N] |
T[] (flexible array) | [T; 0] |
int (*)(int) | Option<unsafe extern "C" fn(c_int) -> c_int> |
long double | Unknown (not representable in Rust) |
3. Lowering (lower)
Accepted items are lowered from gerc’s C-side model to the internal IR:
- Functions ->
RustFunction - Structs ->
RustRecordwithRustRecordKind::Struct - Unions ->
RustRecordwithRustRecordKind::Union - Opaque records ->
RustRecordwithis_opaque: true - Enums ->
RustEnumwith variants and repr selection - Type aliases ->
RustTypeAlias - Variables ->
RustStatic - Integer macros ->
RustConstant
4. Source Emission (emit)
The IR is rendered into Rust source in a deterministic order:
- Constants
- Type aliases
- Enums
- Records
extern "C"declarations
This ordering is stable and deterministic: the same input always produces the same output.
Intentional Canonicalizations
Some emitted forms intentionally differ from older linc Rust output:
- named opaque handles emit as named zero-sized structs, not erased comments
- enums emit as
#[repr(...)] pub enum NAME { ... }, not typedef-plus-const groups - function-pointer aliases emit as
Option<unsafe extern "C" fn(...)>
These are the supported gerc forms going forward.
Link Metadata (linkgen)
Link evidence is lowered into Cargo-compatible build.rs directives and plain
rustc argument files:
cargo:rustc-link-lib=NAMEcargo:rustc-link-lib=static=NAMEcargo:rustc-link-lib=dylib=NAMEcargo:rustc-link-lib=framework=NAMEcargo:rustc-link-search=native=PATH
Platform filtering is supported via cfg!() guards when platform constraints
are specified.
When a resolved ResolvedLinkPlan is attached to GercInput, gerc prefers
that evidence over the source-declared raw link surface.
Emitted Crate
Output Modes
gerc supports two output modes via the crate-root OutputMode re-export:
Crate Mode
Writes a complete Cargo-compatible crate directory:
output_dir/
├── Cargo.toml
├── build.rs (if link requirements exist and build_script is enabled)
├── rustc-link-args.txt (if link requirements exist)
└── src/
└── lib.rs
Source Bundle Mode
Writes only the Rust source file:
output_dir/
├── rustc-link-args.txt (if link requirements exist)
└── src/
└── lib.rs
Cargo.toml
The generated Cargo.toml includes the crate name, version, edition, and a
short generated-artifact description.
build.rs
When link requirements exist, gerc generates a build.rs that emits Cargo
link directives.
rustc-link-args.txt
When link requirements exist, gerc also generates a plain text file with
direct rustc arguments. This file is intended for non-Cargo toolchains or
custom build orchestration.
Overwrite Policies
OverwritePolicy controls behavior when the output directory already exists:
| Policy | Behavior |
|---|---|
Fail | Return an error if the directory is not empty |
Clean | Remove existing contents before writing |
Overwrite | Write over existing files without removing extras |
Crate Naming
normalize_crate_name() ensures valid Cargo package names:
- replaces non-alphanumeric characters (except
_) with_ - rejects empty names
- rejects names starting with a digit
Usage
#![allow(unused)]
fn main() {
use gerc::{emit_crate, OutputMode, OverwritePolicy};
let emitted = emit_crate(
&output.projection,
&config,
std::path::Path::new("/tmp/mylib_sys"),
OutputMode::Crate,
OverwritePolicy::Clean,
).unwrap();
assert!(emitted.root.join("Cargo.toml").exists());
assert!(emitted.root.join("src/lib.rs").exists());
assert!(emitted.files.iter().any(|path| path.ends_with("Cargo.toml")));
}
EmittedCrate records the crate root directory and the concrete files that
were written. In crate mode that file list is deterministic and includes
Cargo.toml, src/lib.rs, rustc-link-args.txt, and build.rs when link
requirements require them.
Readiness Scorecard
This chapter ties GERC readiness to the current hardening ladder instead of general optimism.
Overall Posture
GERC should currently be read as:
- strong on source-only lowering fundamentals
- strong on deterministic emission and emitted-crate generation
- strong on conservative rejection of unsupported shapes
- useful and increasingly hardened on evidence-aware large surfaces
- still dependent on host availability for the biggest OpenSSL and Linux-system evidence ladders
For Level 1 production, that posture should be read as Linux/ELF-first and canonical-corpus-backed, with Apple and Windows serving as confidence-raising secondary targets.
That is a good release posture for a young lowering crate, but it is not yet a claim that every ugly native surface will lower cleanly.
Subsystem Scorecard
- source-first intake: high
- gate and refusal diagnostics: high
- lowering and typemapping: high
- deterministic source emission: high
- emitted crate output: high
- raw
rustcargument rendering: high - source-only large-surface confidence: high
- evidence-aware large-surface confidence: medium-high
- conservative rejection on difficult layouts: high
Canonical Readiness Anchors
The release posture should be judged against these anchors first:
- source-only sqlite3
- source-only zlib
- source-only libpng
- emitted crate output from deterministic fixtures
- source-only pointer-only opaque-handle lowering
- evidence-aware framework link rendering
- packed union acceptance with explicit representation evidence
- OpenSSL link directives
- libxml2 link directives
- Windows system-library link directives
- combined Linux event-loop link directives
If those anchors drift, the scorecard should drop even if the smaller unit tests still look healthy.
For the Level 1 production claim, the hermetic subset of those anchors is the minimum production floor. The host-dependent anchors are confidence raises, not the only basis for trust.
Testing And Release
gerc is the lowering and emission crate in the toolchain, so its test and
release posture is different from parc and linc.
The core questions are:
- can
gercgate unsafe or unsupported input correctly - can it lower accepted input deterministically
- can it emit stable Rust and build artifacts
- can tests/examples prove upstream composition without turning upstream crates into library dependencies
Contract Tests
The main contract tests should cover:
- source-first intake through
GercInputandgenerate_from_source - evidence-aware gating when validation and link evidence are attached
- staged
BindingPackage -> gate -> lowerpaths - deterministic projection and emission
- emitted crate and source-bundle output for the documented modes
- grouped gate, lowering, and pipeline failure matrices
Those tests are the practical statement of what downstream code may rely on.
Artifact-Boundary Integration Proof
gerc/src/** must not import parc or linc.
Cross-package proof belongs in:
gerctests/examples that translateparcsource artifactsgerctests/examples that translatelincevidence artifacts- external harnesses that exercise the whole pipeline
If a change requires gerc library code to know another pipeline crate’s
internal types, the change is architecturally wrong.
Determinism Rules
Generated output should be deterministic for the same intake model.
That means tests should prefer:
- stable item ordering
- stable build sidecar output
- stable Rust source snapshots where formatting is part of the contract
- semantic assertions when exact text is intentionally flexible
Release Checklist
Before releasing gerc:
- run
make build - run
make test - confirm the canonical hardening anchors still pass
- source-only sqlite3
- source-only zlib
- source-only libpng
- emitted crate output on deterministic fixtures
- OpenSSL link directives when available
- libxml2 link directives when available
- Apple framework link directives
- Windows system-library link directives
- libcurl link directives when available
- combined Linux event-loop link directives when available
- confirm the preferred public workflow in the README and book still matches the tested API
- confirm emitted Cargo and raw
rustcpaths still match the documented output story - confirm tests/examples still keep PARC/LINC translation outside
gerc/src/**
For the Level 1 production claim, interpret that checklist in two layers:
- hermetic production floor
- source-only sqlite3
- source-only zlib
- source-only libpng
- emitted crate output from deterministic fixtures
- source-only pointer-only opaque-handle lowering
- packed union acceptance with explicit representation evidence
- host-dependent confidence raises
- OpenSSL link directives when available
- libxml2 link directives when available
- libcurl link directives when available
- Apple framework link directives
- Windows system-library link directives
- combined Linux event-loop link directives when available
Hermeticity Split
Read the large test surfaces in three groups:
- always-on hermetic baselines
- host-dependent but high-value evidence ladders
- conservative rejection and degradation paths
The hermetic baselines are the confidence floor. The host-dependent ladders raise confidence on real targets. The conservative-failure paths prove that GERC refuses unsound lowering instead of inventing answers.
The grouped failure suites now live in:
failure_matrix_gatefor validation-driven gate refusalsfailure_matrix_lowerfor anonymous and unsupported lowering failuresfailure_matrix_pipelinefor the closed source-only anonymous-type cargo-check regression
Maintenance Rule
When gerc changes:
- update the smallest meaningful test first
- update emitted-output docs in the same patch when behavior changes
- keep upstream translation in tests/examples/harnesses only
- delete stale workflow language instead of preserving it for history
What “Supported” Means
For gerc, support means:
- accepted declarations lower to deterministic Rust and build artifacts
- rejected declarations fail conservatively and diagnostically
- documented output modes are covered by tests
It does not mean:
- every upstream C declaration can already be emitted
- every rejected item is a bug rather than a deliberate safety boundary
gerclibrary code is allowed to absorb upstream crate internals