<?xml version="1.0" encoding="UTF-8"?>
<spec xmlns="https://vibevm.org/spec/1">
  <title>GUIDE — C++ (Traditional profile) under the Discipline, v0.1</title>
  <p p="1">**Status.** Beta; one of three sibling C++ profiles (`cpp-traditional`, `cpp-modern`, `cpp-misra2008`). Section structure is isomorphic vertically (to the Rust/TS/Python guides) and horizontally (across the three profiles — diff them; the profiles rewire *bindings*, never principles). Profile granularity is **per build target**: one repository may host targets under different profiles; a cross-profile boundary is treated as an adopted-code relationship (see `GUIDE-CPP-MISRA2008-v0.1.xml` §0, which imports that semantics from MISRA Compliance:2020 §6).</p>
  <p p="2">Framing note. C++ is the language where subset selection is not an instrument but survival. The Traditional profile is the subset that has compiled everywhere since the early 2010s and behaves identically everywhere: the dialect of embedded, games, trading systems, and long-lived vendor toolchains. Its bet: *shrink to the eternal core*. Patterns here only half-dissolve: Strategy = abstract base + factory; Decorator = wrapper; Observer = explicit callback seam; Visitor genuinely survives for open sets — but closed sets use `enum class` + `switch` (§4). Singleton = forbidden; the Meyers function-local static is its C++ disguise.</p>
  <p p="3">**Scope honesty.** For system cores that must build on conservative toolchains (vendor compilers, console SDKs, decade-old enterprise GCC). Greenfield code on current mainstream compilers belongs in `cpp-modern`. Certification-bound code belongs in `cpp-misra2008`.</p>
  <section id="baseline" title="0. Language baseline">
    <list ordered="false" p="4">
      <item>**Standard pinned: C++14**, `-pedantic-errors`, no compiler extensions. (C++11 fallback is a documented per-target deviation, not a default.)</item>
      <item>**`-fno-exceptions -fno-rtti`** project-wide — the defining old-believer move. Expected failures are values (§4); invariant violations are `assert` + configured abort handler. `typeid`/`dynamic_cast` do not exist; closed-set dispatch is `enum class` + `switch`, open-set dispatch is virtual functions.</item>
      <item>**Warnings:** `-Wall -Wextra -Wconversion -Werror`; **`-Werror=switch`** is load-bearing (§4 exhaustiveness).</item>
      <item>**Evidence providers:** clang-tidy (`bugprone-*`, `cppcoreguidelines-*`, `performance-*`, selected `google-*`) consumed via conform as SARIF-class evidence; clang-format for layout (out of discipline scope). `compile_commands.json` is mandatory — it is what feeds T-sem.</item>
      <item>**Suppression policy (xfail-strict by construction):** bare `// NOLINT` is banned; only `// NOLINTNEXTLINE(&lt;check-id&gt;): &lt;reason&gt;` is legal. A conform sweep re-runs the named check against suppressed lines and **fails on stale suppressions** — the suppression registry shrinks truthfully, same mechanism as `@ts-expect-error` and pyright's unnecessary-ignore.</item>
      <item>**Ownership:** `std::unique_ptr` for owning, raw pointers/references are non-owning observers by convention (clang-tidy `cppcoreguidelines-owning-memory` assists); naked `new`/`delete` outside factories is banned.</item>
      <item>**Build/deps:** CMake with pinned toolchain files; third-party code is vendored (`third_party/`) or pinned via `FetchContent` — no live package-manager resolution at build time (reproducibility, A2).</item>
      <item>**Tests:** GoogleTest (BSD-3). **Sanitizers are the safety net the compiler era lacks:** ASan+UBSan on the test suite is a MUST gate; findings are failures, not warnings.</item>
    </list>
  </section>
  <section id="cells" title="1. Cells">
    <p p="5">A cell is a static-library CMake target behind one seam: one public include directory exposing the seam header and the factory declaration — nothing else.</p>
    <list ordered="false" p="6">
      <item>**Import-is-execution, C++ edition: the static initialization order fiasco.** Namespace-scope objects with dynamic initialization are banned in cells — top level admits constants (`constexpr`/POD), type and function definitions. No registration-at-load, no global ctors. Enforced: T-syn (clang-tidy `cppcoreguidelines-avoid-non-const-global-variables` + a conform check for dynamic initializers).</item>
      <item>**No sibling-cell includes** (R-002), including transitively; the include graph is checked at T-syn from `compile_commands.json`. Cross-seam type references go through the seam header only.</item>
      <item>**Platform capabilities are injected:** cells never touch files, sockets, clocks, environment, or global loggers directly — those are seams passed at construction. Consequence: cell tests need no link-time substitution tricks.</item>
      <item>**PImpl SHOULD** be used by cells whose seam crosses a binary or team boundary — the compile-time firewall is this profile's substitute for modules.</item>
      <item>**Promotion** to a separately versioned library when: heavy optional deps, independent release cadence, or ~2 kLoC.</item>
    </list>
    <p p="7">Cell manifest (carrier, §5):</p>
    <fence lang="cpp" p="8">/// @spec implements spec://org.vibevm.core/vibevm/modules/vibe-resolver/PROP-003#solver-upgrade r2
/// @cell seam=DepSolver variant=sat replaces=naive flag=solver
class SatDepSolver final : public DepSolver { /* ... */ };</fence>
  </section>
  <section id="seams" title="2. Seams">
    <list ordered="false" p="9">
      <item>A seam is a **pure abstract base class** in core/seams: virtual destructor, no data members, no implemented methods, non-copyable. Factory functions return `std::unique_ptr&lt;Seam&gt;`.</item>
      <item>**Composition over inheritance is a MUST at seams:** no base classes with behavior, no template methods (hidden control flow, R-021). Implementation inheritance is confined to cell internals; a cell derives from at most one implementation class plus pure interfaces.</item>
      <item>Templates as seams (static polymorphism) are legal *inside* a cell; **cross-cell seams are runtime ABCs** — they keep the compile firewall and stay analyzable without instantiating the world.</item>
      <item>Seam methods that can fail in expected ways return `Result` (§4); the failure surface is in the header.</item>
    </list>
  </section>
  <section id="flags" title="3. Registry and flags">
    <p p="10">R-001 binding — flag at the seam, never in the veins:</p>
    <fence lang="cpp" p="11">// registry.cpp — the only flag reader in the binary target.
std::unique_ptr&lt;DepSolver&gt; makeDepSolver(Flags const&amp; flags, DepProvider&amp; provider) {
    switch (flags.solver()) {                  // provenance: default | env | cli | lockfile
        case Flags::Solver::Sat:   return std::unique_ptr&lt;DepSolver&gt;(new SatDepSolver(provider));
        default:                   return std::unique_ptr&lt;DepSolver&gt;(new NaiveDepSolver(provider));
    }
}</fence>
    <list ordered="false" p="12">
      <item>**Two tiers, never confused:** CMake options that include/exclude *targets* answer "is the code in the binary" (the cargo-feature analog — selection by linking, not by `#ifdef` soup); runtime flags answer "is the cell selected". A build option must not change a seam's surface; a runtime flag must not require recompilation.</item>
      <item>**Preprocessor confinement:** product `#ifdef` is legal only in the CMake-generated config header and at registry/adapter sites — never inside cell bodies (T-lex).</item>
      <item>**No link-time registration magic:** no self-registering statics, no `__attribute__((constructor))`, no singleton registries. The hand-written `switch` is the system's table of contents.</item>
    </list>
  </section>
  <section id="errors" title="4. Errors as contract">
    <p p="13">With exceptions off, the language finally tells the truth in signatures:</p>
    <list ordered="false" p="14">
      <item>**Expected failures are values.** A minimal vendored `Result&lt;T, E&gt;` (single header in core; `tl::expected` MAY be vendored instead — CC0). `E` carries `code` plus the violated REQ URI as a `static constexpr char const*` on the error category; user-facing rendering appends the URI (PROP-014 §2.6).</item>
      <item>**Invariants are `assert` + abort policy** — the panic analog; there is no `throw` to abuse. Release builds keep a configured subset of assertions (cheap ones stay).</item>
      <item>**Exhaustiveness:** closed sets are `enum class` handled by `switch` **without a `default` clause**, under `-Werror=switch` — the compiler errors on a missing enumerator. This is the profile's `assert_never`; adding `default` to silence it is the graveyard move and is banned (T-syn).</item>
      <item>**Out-parameters are banned at seams** in this profile — `Result` carries the payload; reference out-params survive only in hot inner loops inside a cell, documented.</item>
      <item>**Threading:** this profile predates structured concurrency; cells are single-threaded by default, and any thread ownership is a seam (`Executor`-style), never a detached `std::thread` (T-syn: `.detach()` banned).</item>
    </list>
  </section>
  <section id="specmark" title="5. specmark carrier">
    <p p="15">All three C++ profiles share one carrier — the Doxygen-style triple-slash comment — because comments are the only channel that survives every toolchain from C++03 vendors to current clang, and (as in TS) the carrier doubles as the hover/doc surface:</p>
    <fence p="16">/// @spec implements &lt;uri&gt; r&lt;N&gt;              one edge per line; lines repeat
/// @spec deviates &lt;uri&gt; r&lt;N&gt; reason="..."   reason mandatory
/// @verifies &lt;uri&gt; r&lt;N&gt;                     above TEST(...)
/// @specScope &lt;uri&gt; r&lt;N&gt;                    file-top block: file-level inheritance</fence>
    <p p="17">The sidecar reads them via libclang's comment attachment; T-lex regex is the degraded fallback on toolchains without libclang. C++11 attributes (`[[vibevm::spec(...)]]`) were considered and rejected: unknown-attribute warnings vary by compiler and the form buys nothing over comments here. ≤3 edges per item or split.</p>
  </section>
  <section id="naming" title="6. Naming (R-020/R-021 bindings)">
    <list ordered="false" p="18">
      <item>Canonical cell type name is computed: `{Variant}{Seam}` → `SatDepSolver`; hand-written names are linted against the manifest. Length free, ambiguity not.</item>
      <item>**Forbidden in cells regardless of elegance** — the Traditional theater list: non-`explicit` single-argument constructors and implicit conversion operators (`explicit` is MUST); operator overloading beyond value semantics (no DSL operators); function-like macros in domain code; template metaprogramming and CRTP in domain cells (infra libraries only — the proc-macro parallel); default arguments on virtual functions; virtual calls in constructors/destructors; `const_cast`/`reinterpret_cast` outside designated boundary files; Meyers singletons as wiring; `friend` beyond test fixtures.</item>
    </list>
  </section>
  <section id="replacement" title="7. Replacement protocol (R-040 binding)">
    <p p="19">A cell with `replaces=` ships a differential oracle: GoogleTest parameterized suites driving both cells through the seam with deterministic seeded generators, asserting agreement (documented-divergence list otherwise), `/// @verifies`-tagged, run under sanitizers. Golden files follow the promotion protocol — CI never regenerates; local regeneration carries a debt/intent reference in the commit body.</p>
  </section>
  <section id="risks" title="8. Risk table (what conform must cover for this profile)">
    <table p="20">
      <tr>
        <td>Footgun</td>
        <td>Rule</td>
        <td>Tier</td>
      </tr>
      <tr>
        <td>dynamic-initialized namespace-scope object in a cell</td>
        <td>§1</td>
        <td>T-syn</td>
      </tr>
      <tr>
        <td>naked `new`/`delete` outside factories; owning raw pointer</td>
        <td>§0</td>
        <td>T-syn + tidy</td>
      </tr>
      <tr>
        <td>`throw`/`catch`/`typeid`/`dynamic_cast` token anywhere</td>
        <td>§0</td>
        <td>T-lex</td>
      </tr>
      <tr>
        <td>`default` clause on a closed-enum `switch`</td>
        <td>§4</td>
        <td>T-syn</td>
      </tr>
      <tr>
        <td>sibling-cell include (direct or transitive)</td>
        <td>R-002</td>
        <td>T-syn</td>
      </tr>
      <tr>
        <td>non-`explicit` single-arg ctor / conversion operator</td>
        <td>§6</td>
        <td>T-syn</td>
      </tr>
      <tr>
        <td>virtual call in ctor/dtor</td>
        <td>§6</td>
        <td>T-sem</td>
      </tr>
      <tr>
        <td>object slicing (polymorphic pass-by-value)</td>
        <td>§2</td>
        <td>T-sem (tidy)</td>
      </tr>
      <tr>
        <td>uninitialized members / fields</td>
        <td>§0</td>
        <td>T-sem (tidy)</td>
      </tr>
      <tr>
        <td>`#ifdef` inside a cell body</td>
        <td>§3</td>
        <td>T-lex</td>
      </tr>
      <tr>
        <td>`std::thread::detach`; thread created outside an Executor seam</td>
        <td>§4</td>
        <td>T-syn</td>
      </tr>
      <tr>
        <td>bare `NOLINT` / stale suppression</td>
        <td>§0</td>
        <td>T-lex + sweep</td>
      </tr>
      <tr>
        <td>flag read outside the registry</td>
        <td>R-001</td>
        <td>T-syn</td>
      </tr>
      <tr>
        <td>public export without own/inherited spec edge</td>
        <td>PROP-014 §3.2-6</td>
        <td>T-syn + index</td>
      </tr>
    </table>
  </section>
  <section id="docs" title="9. Doc layer">
    <p p="21">Doxygen on every tagged export: error codes and their REQ URIs, ownership and lifetime expectations of every pointer/reference parameter, threading assumptions, edge cases. The `/// @spec` line is already a Doxygen line — zero extra machinery. Spec stays thin; duplication between Doxygen and spec is a defect on the spec side.</p>
    <p p="22">**First carrier note.** No C++ exists in vibevm; this profile ships genre-complete but unexercised. The house clause is therefore carrier-relative:</p>
    <p p="23">*Rules binding here remain DRAFT until a first C++ carrier exists; at that carrier's first milestone, any rule without a conform check (or explicit `WISH` mark in the Charter rule record) is removed rather than carried as aspiration.*</p>
  </section>
</spec>
