Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

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:

  • gerc library code must not depend on parc or linc
  • gerc owns its own generation model
  • gerc consumes 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 / lower modules
  • consumer-side inspection and sidecar helpers

In the toolchain split:

  • parc owns source meaning
  • linc owns link and binary meaning
  • gerc owns Rust lowering, Rust emission, and emitted build output

Audience

This book is for developers who:

  • want to understand how gerc transforms C declarations into Rust FFI code
  • need to integrate gerc as a library in their own tooling
  • are building downstream consumers on top of gerc output

Scope

gerc is intentionally narrow:

ResponsibilityOwner
C header parsing and source extractionparc
Link, validation, and ABI evidencelinc
Rust FFI projection and code generationgerc
Runtime loader policy and deploymentdownstream tooling
fol-specific surface generationdownstream 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:

  1. gerc receives its own input model
  2. any upstream artifact translation happens outside gerc/src/**
  3. gerc gates, lowers, and emits deterministic Rust and build artifacts

What Happens Inside GERC

  1. Intake - gerc receives a GercInput wrapping source plus optional evidence. Tests/examples or external harnesses may translate PARC and LINC artifacts into that model.

  2. 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.

  3. Lowering - Accepted declarations are lowered from the crate-owned C-side model into RustProjection.

  4. Type mapping - C types, pointers, arrays, function pointers, and qualifiers are mapped to Rust FFI-safe equivalents.

  5. 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.

  6. Crate generation - Optionally, gerc writes a Cargo-compatible crate directory or a source bundle plus rustc link arguments.

Design Principles

  • Deterministic - the same input always produces the same output
  • Conservative - refuse generation rather than emit unsound code
  • Library-first - gerc is 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

ModulePurpose
intakeCrate-owned source and evidence input models
cCrate-owned C-side binding model and native evidence types
typemapMaps C-like types to Rust FFI types
gateSafety gating for each declaration
lowerLowers accepted items into RustProjection
irRust projection IR and supporting types
emitRenders the IR into deterministic Rust source
linkgenLowers native link surfaces into Cargo and rustc directives
crategenWrites crate directories and source bundles to disk
contractTop-level generation entry point and JSON output contract
consumerGeneric downstream-consumer contract and metadata sidecar
configGeneration configuration (GercConfig)
outputGeneration output container (GercOutput)
errorCrate 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 on parc or linc
  • tests/examples/external harnesses may translate upstream artifacts into gerc input
  • 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 markers
  • modules: Vec<RustModule> - optional module organization
  • link_requirements: Vec<RustLinkRequirement> - native link metadata
  • notes: 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:

  1. prefer crate-root APIs first
  2. provide gerc’s own source/evidence inputs directly
  3. keep upstream artifact translation outside gerc/src/**
  4. 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:

  • EvidenceInputs
  • GateDecision
  • output_meta, meta_to_json, meta_from_json, projection_to_json, and projection_from_json
  • GercConsumer, ConsumerReport, ConsumerFinding, FindingKind, PassthroughConsumer, FolConsumer, build_sidecar, sidecar_to_json, sidecar_from_json, extern_function_names, record_names, and type_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() and generate_from_source()
  • GercInput, GercConfig, and GercOutput
  • emit_source(), emit_crate(), emit_build_rs(), and emit_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:

  • BindingPackage
  • BindingItem
  • BindingType
  • gate::gate_package(...)
  • lower::lower_package(...)

The emitted crate path supports both:

  • Cargo build-script rendering via build.rs
  • direct rustc argument rendering via rustc-link-args.txt and emit_rustc_args(...)

Downstream Posture

If you are integrating gerc into another tool, prefer:

  1. root-level generation APIs
  2. explicit GercInput construction when evidence is available
  3. emitted Rust/build outputs rather than internal lowering modules
  4. tests/examples/harnesses for any parc or linc artifact translation

Integration Coverage

The current suite exercises realistic split-pipeline paths, not only hand-constructed packages:

  • parc -> gerc source-only generation for zlib and libpng fixtures
  • parc -> linc -> gerc generation with declared link surfaces
  • parc -> linc -> gerc generation 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:

FieldDefaultDescription
crate_name"gerc_output"Name for the generated crate
crate_version"0.1.0"Version string
emit_functionstrueEmit extern "C" function declarations
emit_recordstrueEmit #[repr(C)] struct/union types
emit_enumstrueEmit enum types
emit_type_aliasestrueEmit type aliases
emit_variablestrueEmit static variable declarations
emit_constantstrueEmit constant definitions
emit_build_scripttrueEmit 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:

  • gerc library code owns its own input types
  • gerc library code must not depend on parc or linc
  • 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:

  1. the preferred GercInput path
  2. the lower-level crate-owned gerc::c model that staged helpers and some tests still use directly

Optional Enrichment

Additional evidence forms can optionally be attached.

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 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:

RuleEffect
Bitfield recordsRejected - no safe repr(C) representation
Packed non-bitfield records and unionsAllowed when representation evidence is explicit
Anonymous recordsRejected - Rust requires named types
Anonymous enumsRejected - Rust requires named types
Incomplete or opaque fieldsRejected - cannot determine layout
Unsupported itemsRejected - 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 typeRust type
void() (or omitted)
_Boolbool
intcore::ffi::c_int
unsigned intcore::ffi::c_uint
longcore::ffi::c_long
float / doublecore::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 doubleUnknown (not representable in Rust)

3. Lowering (lower)

Accepted items are lowered from gerc’s C-side model to the internal IR:

  • Functions -> RustFunction
  • Structs -> RustRecord with RustRecordKind::Struct
  • Unions -> RustRecord with RustRecordKind::Union
  • Opaque records -> RustRecord with is_opaque: true
  • Enums -> RustEnum with 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:

  1. Constants
  2. Type aliases
  3. Enums
  4. Records
  5. 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 evidence is lowered into Cargo-compatible build.rs directives and plain rustc argument files:

  • cargo:rustc-link-lib=NAME
  • cargo:rustc-link-lib=static=NAME
  • cargo:rustc-link-lib=dylib=NAME
  • cargo:rustc-link-lib=framework=NAME
  • cargo: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.

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:

PolicyBehavior
FailReturn an error if the directory is not empty
CleanRemove existing contents before writing
OverwriteWrite 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 rustc argument 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 gerc gate 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 GercInput and generate_from_source
  • evidence-aware gating when validation and link evidence are attached
  • staged BindingPackage -> gate -> lower paths
  • 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:

  • gerc tests/examples that translate parc source artifacts
  • gerc tests/examples that translate linc evidence 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:

  1. run make build
  2. run make test
  3. 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
  4. confirm the preferred public workflow in the README and book still matches the tested API
  5. confirm emitted Cargo and raw rustc paths still match the documented output story
  6. 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_gate for validation-driven gate refusals
  • failure_matrix_lower for anonymous and unsupported lowering failures
  • failure_matrix_pipeline for the closed source-only anonymous-type cargo-check regression

Maintenance Rule

When gerc changes:

  1. update the smallest meaningful test first
  2. update emitted-output docs in the same patch when behavior changes
  3. keep upstream translation in tests/examples/harnesses only
  4. 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
  • gerc library code is allowed to absorb upstream crate internals