RFDB Metadata Gotchas

SkillFiles & storage

Fix silent metadata issues in RFDB node storage. Covers two traps: (1) metadata flattening — nested metadata fields become top-level after serialization, so node.metadata.field is undefined but node.field works. (2) reserved keys — fields named "type", "id", "name", "file", "exported" are silently stripped from metadata by _parseNode() to prevent overwriting top-level node fields.

Available today. Use it from your connected AI after setup.

Connect ahel once, and every AI you use reads what you have installed.

Then ask your AI: use the RFDB Metadata Gotchas skill

What this skill tells your AI

The instructions your AI receives, as published by disentinel/grafema in .claude/skills/grafema-metadata-flattening/SKILL.md and read by ahel’s review.

Trap 1: Metadata Flattening

RFDB serialization flattens nested metadata to the node's top level.

What happens:

  1. Analyzer stores: {id, type, file, metadata: {handlerStart: 93}}
  2. client.addNodes serializes metadata as JSON string
  3. _parseNode deserializes and spreads onto top level
  4. After retrieval: handlerStart is at TOP LEVEL, not nested

Wrong:

const handlerStart = route.metadata?.handlerStart;  // undefined!

Correct:

const handlerStart = route.handlerStart;  // 93

TypeScript interfaces — define custom fields at top level:

interface HttpRouteNode extends BaseNodeRecord {
  type: 'http:route';
  handlerStart?: number;  // top level, not nested under metadata
}

Trap 2: Reserved Keys (Silent Data Loss)

_parseNode() strips these keys from metadata to prevent overwriting top-level node fields:

KeyWhy reserved
typeWould overwrite node type (VARIABLE, FUNCTION, etc.)
idWould overwrite semantic ID
nameWould overwrite display name
fileWould overwrite file path
exportedWould overwrite export flag
nodeTypeInternal RFDB wire field
originalIdInternal legacy field
semanticIdInternal field

Use non-colliding names:

Don't useUse instead
metadata.typemetadata.tsType
metadata.namemetadata.displayName
metadata.idmetadata.externalId

Detection

  1. console.log(JSON.stringify(node, null, 2)) — check if field is at top level
  2. Raw wire format: backend._client.getAllNodes() returns WireNode with metadata as JSON string
  3. If field appears in raw wire but not in parsed node → reserved key stripping

Notes

  • Applies to ALL custom fields on nodes, not just metadata
  • Both TestDatabaseBackend and RFDBServerBackend have this behavior
  • If you need truly nested data, store it as a JSON string that doesn't get auto-parsed

Signals

GitHub stars
36
Forks
3
Last commit
Aug 2026
Advanced
Catalog kind
skill
Gateway key
rfdb-metadata-gotchas
Source
github.com/disentinel/grafema