Audit feature-gate status claims across the multi-repo stack. Use when a doc/plan/issue/commit-message claims a "promotion discrepancy", "not yet wired", or "Default-off until..." state, when fixing stale feature-gate comments, before promoting or demoting any feature flag, or quarterly as a feature-gate-hygiene gate. Enforces four defenses (1) source-code verification of every wiring claim — grep the production tick path, don't trust the doc; (2) multi-surface grep for stale comments across 5 documentation surfaces (source .rs, lib.rs module doc, Cargo.toml default block, downstream Cargo.toml, .benchmarks/*_promotion_review.md); (3) layer-split awareness — engine-layer DEFAULT-ON + game-layer OPT-IN is a deliberate pattern when each layer gates a different concern (generic runtime vs IP-bearing content), NOT a missed propagation; (4) gate-chain resolution — own cfg plus every ancestor mod plus the crate default list, settled by a build not a read. Sibling to goat-audit + doc-sync.
Instal·la
npx skillscat add katopz/katgpt-rs/feature-gate-audit Instal·la des del registre de SkillsCat.
feature-gate-audit — Verify feature-gate claims against production code
This skill exists because of a caught error chain: session f92a7ffe inriir-ai (2026-07-18) framed npc_sleep_time's engine-DEFAULT-ON /
civ-OPT-IN state as a "promotion discrepancy" and claimed the catalog
was "wired but not yet exercised in production civ tick". Sessionf865913e (same day) verified both claims against production code and
found them factually wrong:
- The split is a deliberate layer split (engine = generic runtime;
civ = IP-bearing catalog + graceful-degradation hook intoSleepConsolidateNode::tickGate 3). - The catalog IS exercised in production via
crates/riir-games-civ/src/civ/daily_loop/mod.rs:1071-1078, which
callsctx.sleep_runtime.sleep_cycle_tick(&hla, &self.dirs).
The three defenses below would have caught both errors before they
landed. Apply them to every feature-gate claim you encounter.
When to use
- A doc, plan, issue, commit message, or session summary claims a
"promotion discrepancy" between two crates' feature-gate status - A doc claims a feature is "wired but not yet exercised in production"
- You encounter a
// Default-off until G1–GN GOAT gate passescomment
in source code - Before promoting a feature flag to default-on (or demoting to opt-in)
in any product-set repo (7; canonical list inkatgpt-rs/AGENTS.md
§"Repo count" — read the LIST, not the count: this cell said 7-omittingriir-dapps, then 8-counting-retired-riir-armageddon. A count that drifts
from the canonical list is the exact defect this skill audits in others) - Quarterly as a feature-gate-hygiene gate (alongside
doc-syncandgoat-audit)
The four defenses
Defense 1 — Verify every "discrepancy" / "not yet wired" claim against production code
NEVER propagate a doc/plan/session-summary's framing of feature-gate
state without first grepping the actual production wiring. Plausible-but-
wrong framings are the canonical failure mode — they read as reasoned
verdicts, get propagated through summaries, and solidify into "facts"
that downstream sessions trust.
Protocol:
- Identify the production host(s) — the function that would invoke the
gated code path on the hot tick. Common hosts in this stack:tick_proactive_salience(salience gate)tick_cgsp_curiosity(CGSP runtime)tick_motivation(motivation system)SleepConsolidateNode::tick(sleep-time, daily loop)evolve_feeling_brain(emotion systems)
grepfor the feature name across all.rsfiles in the crate
tree, not just the file the doc cited:grep -rn "FEATURE_NAME" crates/ --include="*.rs"- Read the body of every host function whose signature imports a type
from the gated module. - If a
#[cfg(feature = "FEATURE_NAME")]block is reached along the
tick path, the feature IS exercised in production — regardless of
what the doc says. - If no host reaches the gated block, then the "not yet wired"
claim may be accurate — but verify with a call-graph grep, not just
a single-file read.
Anti-pattern — trust the summary: "the prior session said X, and
the prior session is in git history, so X must be true." Prior sessions
make mistakes. Git commits are not authority — production code is.
Defense 2 — Stale gate-status comments live in MULTIPLE locations; fix all of them
When a feature is promoted from opt-in to DEFAULT-ON, the promotion
must propagate through five documentation surfaces. Missing any one
leaves a stale comment that misleads future readers.
| # | Surface | What to check |
|---|---|---|
| 1 | The feature's source .rs file (top-of-module //! doc) |
"Default-off until..." → "DEFAULT-ON since..." |
| 2 | The crate's lib.rs pub mod declaration comment |
The // Default-OFF until... line above #[cfg(feature = "...")] |
| 3 | The crate's Cargo.toml [features] default = [...] block |
Feature name should appear, OR have an explicit sibling comment explaining intentional opt-in |
| 4 | Every downstream consumer's Cargo.toml [features] block |
Forwarding features don't need to be default-on, but their comments must not cite a pending gate that has already passed |
| 5 | .benchmarks/NNN_<feature>_promotion_review.md |
Must exist + reference the GOAT gate evidence (G1–GN) |
Canonical failure (riir-ai, 2026-07-18): the npc_sleep_time comment// Default-off until G1–G5 GOAT gate passes (Plan 341 Phase 7) existed
in both crates/riir-engine/src/lib.rs:629 andcrates/riir-games-civ/src/npc/sleep_time_catalog.rs:48. A prior session
only caught the latter; the engine lib.rs surface went unfixed.
Protocol — the 5-surface grep (run for every feature under audit):
# In each repo that touches the feature:
grep -rn "Default-off until\|Default-OFF until" crates/ --include="*.rs"
grep -n "FEATURE_NAME" Cargo.toml crates/*/Cargo.toml
grep -n "FEATURE_NAME" crates/*/src/lib.rs
ls .benchmarks/*FEATURE_NAME* 2>/dev/nullFix discipline: all stale surfaces go in one commit, not
piecemeal. The commit message should enumerate which surfaces were
fixed and cite the canonical benchmark (Promotion Review NNN) as
authority.
Defense 3 — Layer splits are deliberate, not bugs
Asymmetric feature-gate status across crates is OFTEN a deliberate
design, not a missed propagation. Before claiming a "discrepancy",
verify that each layer is gating the SAME concern. If they're gating
different concerns, the asymmetry is a layer split — update the
comments to explain the split; do NOT propagate the promotion.
Established layer-split patterns in this codebase:
| Feature | Engine layer | Game layer | Why split |
|---|---|---|---|
npc_sleep_time |
DEFAULT-ON (generic runtime: HlaSleepTimeOp, codec, BLAKE3 commitment) |
OPT-IN (riir-games-civ, riir-games-shared, riir-games) |
Civ layer gates the IP-bearing catalog (per-NPC-type direction vectors) + graceful-degradation hook into SleepConsolidateNode |
cognitive_branches_runtime |
DEFAULT-ON (plasma-tier core) | OPT-IN sub-features (_engram, _closure, _replay, _entity_cognition) |
Engine ships the core; heterogeneous subsystems stay opt-in |
committed_personality_runtime |
DEFAULT-ON (plasma-tier core) | OPT-IN committed_blend_freeze (ArchetypeBlendShard persistence layer) |
Engine ships the core; persistence layer stays opt-in |
arg_runtime |
DEFAULT-ON (plasma-tier core) | OPT-IN _manifold, _action, _offline, _replay |
Engine ships the core; heterogeneous Steps 4/5/7/8 stay opt-in |
cwm_runtime |
DEFAULT-ON (IP-free core with mock LLM) | OPT-IN cwm_gemini / cwm_local_llm / cwm_wasm_loader |
Engine ships the modelless core; concrete LLM backends stay opt-in |
conformal_predictive_intervals |
DEFAULT-ON (Plan 468, 2026-07-20): generic ConformalIntervalCalibrator substrate — pure empirical-quantile math, zero-cost-when-uninvoked |
OPT-IN — 7 consumer surfaces across 2 crates: karc_conformal_width (riir-engine, per-NPC state field on NpcKarcState), salience_conformal_width (riir-games-civ, Delegate-nudge routing — IP-bearing), 5 probe features (conformal_{curiosity,sleep_time,mcts_collapse,salience_tri_gate,per_channel}_probe, riir-engine, standalone measurement) |
Engine ships the math; consumers gate three distinct concerns: (a) per-NPC residual-pool overhead (Bench 567 measured +113.9% G2 — sidecar attachment is consumer choice); (b) IP-bearing nudge policy (Delegate vs Speak — DelegateNudgeSource::ConformalWidth); (c) standalone measurement corpora (#[ignore]-d probes sweep 11×100×100+ configurations). The most granular layer split in the codebase — three opt-in concerns at two consumer crates. |
Three-layer split pattern (the conformal_predictive_intervals extension):
The existing rows above are all two-layer splits (engine + game). The conformal
primitive introduced a three-layer split — engine substrate (katgpt-rs) →
engine consumer state (riir-engine karc_conformal_width) → civ routing
(riir-games-civ salience_conformal_width). The middle layer exists because
the per-NPC Option<KarcConformalSidecar> field has measurable overhead
(Bench 567) that the consumer should opt into explicitly, distinct from the
IP-bearing routing policy at the civ layer. When auditing a UQ primitive
with a similar shape, look for this three-layer pattern: the engine ships
the math, the engine consumer gates the per-NPC state cost, the game layer
gates the IP-bearing policy. Each layer's opt-in is a separate concern and
should NOT be propagated.
Established propagate-the-promotion patterns (NOT splits):
| Feature | Engine | Game | Why propagated |
|---|---|---|---|
karc_runtime |
DEFAULT-ON | DEFAULT-ON (riir-games-civ) |
Both layers gate generic machinery; no IP split |
cgsp_runtime |
DEFAULT-ON | DEFAULT-ON | Generic machinery; no IP split |
proactive_salience |
n/a (no engine dep) | DEFAULT-ON | Self-contained at the civ layer |
Decision rule:
- Both layers gate generic, IP-free machinery → propagate the
promotion to all 5 surfaces per Defense 2. - One layer gates IP-bearing content (catalogs, direction vectors,
game-design data, trained weights) → keep the IP layer opt-in,
document the split with a comment explaining the rationale. - One layer gates heavy optional deps (
riir-neuron-db,riir-chain, GPU crates) → keep that layer opt-in, document the
dep-cost rationale.
Protocol — before claiming a discrepancy:
- Read both crates'
Cargo.tomlcomments. Do they describe the SAME
concern or DIFFERENT concerns? - If different concerns → it's a layer split. Update the comments on
both sides to explain the split; do NOT propagate the promotion. - If same concern → it's a real discrepancy. Propagate the promotion
and update all 5 surfaces per Defense 2.
Defense 4 — "Is it gated?" is a question about a CHAIN, not a line
A gating claim sourced from a bare grep 'pub mod X' is inadmissible. The
matched line almost never carries the whole answer, and each missing link has
already produced a wrong verdict in this workspace:
| link | what it looks like when missed | real case |
|---|---|---|
the item's own #[cfg] |
you read line N (pub mod X;) and miss line N-1 (#[cfg(...)]) |
riir-ai Issue 741 / Proposal 041 called transformer/gemma2_train UNGATED and used "largest AND ungated" to set eviction priority. Line 41 was the pub mod; line 40 was #[cfg(feature = "gemma_lora")]. It was gated at the exact commit measured. |
every ancestor mod up to lib.rs |
the item is bare, so you call it ungated — but its parent module is gated | riir-ai Issue 744 §4: deltanet/{lm_head_lora_train,backward} are bare, so a first pass claimed "compiled into every build, default included". The parent is #[cfg(feature = "deltanet_inference")] pub mod deltanet; (lib.rs:90). Never in a default build. |
the crate's default = [...] |
the list is read with the wrong instrument, and "no match" is mistaken for "no features" | A Python regex ^(\w+)\s*=\s*\[(.*?)\]\s*$ over riir-engine/Cargo.toml returned nothing, and that was written up as "riir-engine declares no default features at all" — in a riir-ai issue, a proposal, and this table. Measured with cargo metadata: 59 default features on a single 14,288-character line, closure 76, including deltanet_inference and lora_still. The wrong reading survived two rounds of "correction" and inverted a real finding (1,507 LOC of BPTT+AdamW were in every default build). cargo metadata --no-deps is the authority; a regex over Cargo.toml is not. |
a consumer's required-features / dep-declaration features |
you walk the [features] table and conclude a feature is unreachable |
riir-ai Issue 744 §5: a closure walk of riir-examples' [features] "proved" deltanet_ternary_inference unreachable from default. It arrives via the bonsai-* rows, and the riir-engine dep is default-features = false. |
Note the first two are the same mistake at different depths — and the second
one was made while writing the correction for the first. That is the signature
of this defense being skipped rather than applied once.
grep -B2 is necessary but not sufficient: it fixes link 1 and is blind to
links 2-4.
# The admissible form. All four links, for one item.
F=crates/riir-engine/src/deltanet/lm_head_lora_train.rs
grep -rnB2 "pub mod lm_head_lora_train;" crates/riir-engine/src/deltanet/mod.rs # link 1
grep -rnB2 "pub mod deltanet;" crates/riir-engine/src/lib.rs # link 2 (repeat per ancestor)
python3 -c "import re,io;print(re.search(r'(?m)^default\s*=\s*\[(.*?)\]',io.open('crates/riir-engine/Cargo.toml').read()))" # link 3Resolve the closure with the tool that owns it. Manifests defeat regexes:
arrays span lines, or are one 14 kB line, or nest.
# The authority. Never a regex over Cargo.toml.
cargo metadata --no-deps --format-version 1 | python3 -c "
import json,sys
p=[x for x in json.load(sys.stdin)['packages'] if x['name']=='CRATE'][0]
f=p['features']; seen=set(); stack=list(f.get('default',[]))
while stack:
k=stack.pop()
if k in seen: continue
seen.add(k); stack += [t for t in f.get(k,[]) if '/' not in t]
print(len(f.get('default',[])),'direct /',len(seen),'in closure'); print(sorted(seen))"And the closing rule: settle it with a build, not a read. Every one of the
four cases above was a reading that survived review and died on first contact
with cargo. A feature matrix is cheap and decisive:
# rc=0 on every arm you claim works; the load-bearing arm is the one where the
# gate is supposed to EXCLUDE something and the crate must still compile.
for f in "" deltanet_inference deltanet_ternary_inference; do ...; doneTwo traps when you do run it, both of which have reported a false verdict
here: cargo ... 2>&1 | tail makes $? the tail's exit, so a failed build
reports success; and in zsh args="--features foo"; cargo check $args passes one
argv entry (error: unexpected argument '--features foo'), so every arm of a
matrix loop "fails" while the code is fine. Redirect to a file and read rc
from cargo directly; pass flags via "$@".
Output format
After running an audit, produce a per-feature verdict table:
| Feature | Surface 1 (src .rs) | Surface 2 (lib.rs) | Surface 3 (Cargo.toml default) | Surface 4 (downstream) | Surface 5 (.benchmarks) | Verdict |
|---|---|---|---|---|---|---|
npc_sleep_time |
✅ L44-66 | ✅ L629-642 | ✅ engine default-on | ✅ civ opt-in by design | ✅ bench 341 | deliberate-split |
<feature> |
✅/❌ + line | ✅/❌ + line | ✅/❌ + line | ✅/❌ + line | ✅/❌ + file | see verdicts |
conformal_predictive_intervals (post-Plan-468 audit, 2026-07-20) |
✅ no stale //! claims in crates/katgpt-core/src/conformal/ |
✅ crates/katgpt-core/src/lib.rs L75-97 — promotion comment accurate (DEFAULT-ON since Plan 468, consumer gates STAY opt-in) |
✅ in default = [...] with Phase 21 comment |
✅ 7 consumer gates stay opt-in (deliberate three-layer split — see Defense 3 table) | ✅ Bench 340 + 560/562/563/564/565/567/568 all accurate | deliberate-split (clean after re-audit caught 3 missed surfaces: Bench 565 L7 header, conformal_uq.md §1.3 table rows 1/4/5, Plan 508 L8 Feature Gate line — all exhibited the append-only anti-pattern: header was updated, body was not) |
| 2026-08-15 quarterly audit — 11 katgpt-core promotions since 2026-07-17 goat-audit window (focus set: poincare/chunked/causal/conformal/karc/hope/hebbian/ane_fused/clr/phase_separation/similarity_inference) | — | — | — | — | — | 7 fix-1-surface + 4 clean — see the 2026-08-15 rows below |
similarity_inference (2026-08-15) |
✅ mod.rs clean | ❌ lib.rs "Opt-in — Phases 2–7 pending" → FIXED (DEFAULT-ON 2026-08-11, Bench 579) | ⚠️ in default but NO phase-chain comment → added Phase 26 | ✅ no downstream | ✅ Bench 579 accurate | fix-2-surfaces |
phase_separation (2026-08-15) |
✅ mod.rs clean | ❌ lib.rs "Opt-in until G1–G4 PASS — Phase 1 skeleton ships now" → FIXED (DEFAULT-ON 2026-08-07) | ✅ default + Phase 25 | ✅ riir-engine phase_separation_salience notes DEFAULT-ON |
✅ bench_571 accurate | fix-1-surface |
causal_identification (2026-08-15) |
❌ mod.rs "G4 DEFERRED" → FIXED in place (closed 2026-07-18, Issue 183 / Bench 465 informational PASS) | ✅ | ✅ default + Phase 20 | ✅ causal_id_consumer clean |
✅ Bench 464/465 | fix-1-surface |
hebbian_kernel_memory (2026-08-15) |
✅ lib.rs accurate (DEFAULT-ON + Defense-3 split) | ✅ | ✅ default + Phase 24 | ✅ neuron-db hebbian_fact_store "(now default-on)" accurate |
❌ bench_559 .rs G5 "BLOCKED/.issues/027" + "stays opt-in" println → FIXED (G5 PASS Bench 462 2026-07-25; .issues/027 resolved+removed) | fix-1-surface |
poincare_navigator (2026-08-15) |
✅ | ✅ | ✅ default + Phase 19 | ✅ riir-engine poincare_imagination STAYS-OPT-IN-PERMANENTLY documented (Plan 497 quality refute) |
❌ Bench 449 L52 in-text "ships opt-in" — append-only anti-pattern (banner exists, body not fixed) → FIXED in place w/ post-promotion annotation | fix-1-surface |
karc_forecaster (2026-08-15) |
✅ | ✅ | ✅ default + Phase 22 | ✅ karc_runtime default-on, probes opt-in by design |
❌ Bench 308 Phase-1 TL;DR "Feature stays opt-in" — append-only anti-pattern (§Phase 5.3 update exists) → FIXED in place w/ Post-Phase-5.3 annotation | fix-1-surface |
clr_weighted_set_attention (2026-08-15) |
✅ no lib.rs status text | ✅ | ⚠️ in default, feature-def comment records promotion, but NO phase-chain comment → added Phase 24b (the 19b precedent) | ✅ Bench 354 update accurate | ✅ | fix-1-surface (convention) |
chunked_content_store, conformal_predictive_intervals, hope_capacity, ane_fused_chain + 14 lib.rs STAYS-OPT-IN claims + fresh set (multistep pending-gate, drift_segment, product_key_memory_episodic "unchanged by Issue 650", FlashAR Eq21/greedy_draft, SoftmaxArgmax) + .docs/01_orientation/overview.md rows (2026-08-15) |
✅ | ✅ | ✅ | ✅ | ✅ | clean |
Verdicts:
- clean — all 5 surfaces accurate; no action.
- fix-N-surfaces — N surfaces have stale comments; fix in one commit
per Defense 2. - deliberate-split — asymmetric gate status is intentional per
Defense 3; update comments on both sides to explain the split. - real-discrepancy — same concern, different gate status across
layers; propagate the promotion per Defense 2. - pending-gate — gate has not yet passed; comment is accurate, no
action (verify the gate is still pending by checking the latest plan
phase status).
Scope — every contract repo, derived
This section used to be a typed 8-row table headed "the 7 workspace repos".
It disagreed with its own header, omitted 11 repos that carry a BOUNDARY.md,
and listed mmorpg-remaster/, which does not exist (the directory ismmorpg-remaster-unity/; the editor lives in mmorpg-editor/). A
feature-gate audit scoped by that table audits a workspace that is not this one.
Derive it. The canonical count and the two axes (product set vs workspace) live
in AGENTS.md §"Repo count" — do not copy either number here.
cd /Users/katopz/git && for d in */; do
[ -f "$d/BOUNDARY.md" ] && [ -d "$d/.git" ] && echo "${d%/}"
done-d "$d/.git", not -e: a git worktree has a .git file, and counting
one audits the same crate twice.
For each repo, read its AGENTS.md first — it documents the
canonical feature-gate layout and the layer-split conventions for that
repo. The repo-local rules override the general guidance here when they
conflict.
Common failure patterns
"Plausible but wrong"
The most common failure: a doc/plan/session-summary claims state X
based on a partial read of the code, and the claim is propagated
through downstream summaries without re-verification. Always grep
the production wiring before propagating the claim. The cost of
verification is ~30 seconds; the cost of a wrong claim landing in a
commit is a future audit to undo it.
"Single-surface fix"
Fixing one stale comment but missing the other four. A reader who finds
a stale comment in lib.rs and a correct comment in the source file
concludes "the comment is just stale" — eroding trust in the whole
documentation surface. Always do the 5-surface grep; fix all stale
surfaces in one commit.
"Append-only anti-pattern"
Touching the right surface but in the WRONG WAY: appending a footnote /
"Post-X update" section at the bottom of a doc while leaving the original
in-text claim untouched. A future reader who hits the in-text claim (which
appears first, in the TL;DR or body) trusts it without scrolling 100+
lines down to find the contradicting footnote. This is more subtle than
the single-surface fix because the surface IS touched — a naive git diff audit concludes "Bench NNN was updated" — but the claim a reader
actually sees is still stale.
Canonical failure (conformal primitive, 2026-07-20): Plan 468's
promotion commit appended a "Plan 468 update" section to Bench 565 but
left the in-text "stays opt-in" claim at line 196 untouched. A follow-up
feature-gate-audit cycle (commits 97f32789 + 9d0716e22) had to fix
the in-text claims across 7 surfaces — exactly because the append-only
approach had left the doc surface internally inconsistent.
Fix discipline: when correcting a stale claim, EDIT the original
sentence in place — convert present-tense "stays opt-in" to past-tense
"was opt-in at the time of this probe/bench" with an inline(Post-X update, YYYY-MM-DD, Plan NNN): ... annotation. Footnotes are
acceptable ONLY for additional context that didn't exist in the original
claim's scope — never as a substitute for correcting the original claim.
"Reflexive discrepancy framing"
Seeing asymmetric gate status and assuming it's a bug. This is the
single most common framing error in this codebase because the layer
split is the dominant pattern (6 of the 10 major runtime/primitive
rows in the Defense 3 table ship as engine-default-on +
consumer-opt-in). Always check whether
each layer gates the same concern before claiming a discrepancy.
"Authoritative-sounding stale comment"
A // Default-off until G1–G5 GOAT gate passes comment in source code
looks authoritative — it cites the plan, the phase, the gates.
Readers trust it. But the comment was written before the gate
passed, and nobody updated it when the promotion landed. Treat any
"until... passes" comment as a candidate for staleness, and verify
against the .benchmarks/NNN_*_promotion_review.md (which is the
authoritative record of the gate's status).
See also
~/.agents/skills/doc-sync/SKILL.md— quarterly doc hygiene gate
(sibling skill; feature-gate-audit focuses specifically on gate-status
accuracy, doc-sync covers the broader.docs/+README.mdsync)katgpt-rs/.agents/skills/goat-audit/SKILL.md— cross-repo GOAT
cherry-pick audit (sibling skill; focuses on primitive propagation,
this skill focuses on feature-flag status accuracy)katgpt-rs/AGENTS.md§"Feature Flag Discipline" — the GOAT promotion
rule (the policy this skill enforces)riir-ai/.benchmarks/341_npc_sleep_time_promotion_review.md—
canonical example of a complete promotion review (G1–G5 + modelless- latent boundary + β-tuning finding)
- Commit
f865913eonriir-ai/develop(2026-07-18) — the canonical
example of this skill's three defenses catching a prior session's
errors