Audience: Integrators, schema owners, operators. Use: Apply canonical naming rules for subjects, predicates, schemas, streams, and zone identities.
Overview
BSFG integrations span multiple systems, zones, and teams. Without consistent naming conventions, systems quickly accumulate semantic drift:
OrderCreated (PascalCase) order_created (snake_case) ← standard order-created (kebab-case) order.created (dotted) orderCreated (camelCase)
This multiplicity breaks integration consistency and makes the fact vocabulary fragile.
This guide defines the canonical naming grammar for all identifiers used in BSFG systems:
- Subjects: Entity identifiers (what the fact is about)
- Predicates: State transitions and events (what happened)
- Schemas: Object structure versions
- Streams: JetStream channels organizing facts
- Artifacts: Binary files referenced by facts
- Identities: BSFG node and zone names
Identifier Principles
All BSFG identifiers follow these principles:
Canonical case: lower_snake_case (no spaces, no special characters except underscore)
Readability: Names should be self-documenting and pronounceable
Stability: Identifiers are immutable once deployed. Never rename or reuse.
Domain-oriented: Use domain vocabulary, not generic system terms
ASCII only: No Unicode, no accents, no emoji (for compatibility)
What to Use
| Pattern | Example | Use Case |
|---|---|---|
| lower_snake_case | order_created | Predicates, schemas, streams, artifacts |
| lowercase | batch, order | Entity type names (subject kinds) |
| dash-separated hierarchies | plantA-bsfg | Zone identities only |
What to Avoid
| Anti-Pattern | Example | Problem |
|---|---|---|
| PascalCase | OrderCreated | Inconsistent with system conventions, hard to parse |
| camelCase | orderCreated | Conflicts with JSON key conventions |
| kebab-case | order-created | Conflicts with URL parsing, harder to read in code |
| dotted.names | order.created | Conflicts with namespace semantics |
| generic verbs | update, change | Lacks semantic meaning; what changed? |
Subject Naming
Subjects identify the entities that facts describe. A subject is a unique reference to something in the world.
Format:
subject := <entity_type>:
Entity types: Lowercase entity kind (what is this subject?)
batch (a production batch) order (a sales or production order) device (equipment or sensor) recipe (a process recipe) lot (a material lot) container (shipping or storage container)
Identifiers: Unique reference within the entity type
batch:B1042 (simple ID) batch:PlantA/B1042 (hierarchical: plant/batch) device:reactor_7 (device with underscore) order:ENT-12345 (order with dash)
Hierarchical Subjects
Use forward slashes (/) to denote hierarchy when an identifier is scoped to a parent entity:
| Subject | Meaning | Scope |
|---|---|---|
| batch:B1042 | Batch B1042 (globally unique) | Global |
| batch:PlantA/B1042 | Batch B1042 at Plant A | Plant-scoped |
| batch_step:PlantA/B1042/step3 | Step 3 of batch B1042 at Plant A | Batch-scoped |
| recipe:ENT/R-STANDARD | Standard recipe at Enterprise | Enterprise-scoped |
Subject Naming Rules
Entity types are lowercase: batch, order, not Batch or Order
Identifiers can contain alphanumerics, dashes, and slashes: PlantA/B1042, ENT-12345, reactor_7
Use forward slash (/) for hierarchies, never backslash or dot: PlantA/B1042 not PlantA.B1042 or PlantA\B1042
Identifiers must be stable: Once a subject is used in a fact, it never changes. If you need a different identifier, create a new subject.
Predicate Naming
Predicates express semantic meaning — what happened or what state changed.
Format:
predicate :=
Examples:
| Predicate | Meaning | Subject Example |
|---|---|---|
| order_created | An order came into being | order:ENT-12345 |
| order_modified | Order details changed | order:ENT-12345 |
| batch_started | Production batch began | batch:PlantA/B1042 |
| batch_completed | Production batch finished | batch:PlantA/B1042 |
| step_completed | A manufacturing step finished | batch_step:PlantA/B1042/step3 |
| temperature_recorded | Sensor reading was logged | sensor_reading:T-023 |
| quality_result_recorded | Lab result was documented | quality_test:QT-999 |
Predicate Naming Rules
Past tense preferred: order_created (completed action) not create_order (imperative)
Verbs first, object second: step_completed not completed_step
Use specific verbs: order_shipped not order_updated
Predicates are stable: Once order_created is deployed, it is never renamed. New predicates are created for new semantics.
Avoid generic verbs: update, change, modify (except when specificity is impossible). Prefer quantity_reduced or destination_changed.
Schema Naming
Each predicate has one or more associated schemas (object structures). Schemas are versioned.
Format:
schema_id :=
Examples:
order_created_v1 (original schema) order_created_v2 (backwards-compatible change) order_created_v3 (breaking change) batch_started_v1 temperature_recorded_v1
Schema Versioning Rules
Increment version when schema changes: New version = new identifier. Old versions remain deployed for replay compatibility.
Backwards compatibility within major version: v1 → v2 allows adding optional fields. v2 → v3 allows breaking changes (rename, delete, type change).
Schema is immutable once published: Once order_created_v1 is deployed, it never changes. To modify, create order_created_v2.
Consumers must handle version variance: A consumer written for v1 must be able to process v2 facts (if v2 is backwards-compatible).
Artifact Naming
Artifacts (binary files referenced by facts) use structured, hierarchical paths.
Format:
artifact_path := <artifact_type>/
Artifact types (bucket names):
| Bucket | Contents | Retention |
|---|---|---|
| batch-files | Batch records, recipes, instructions | 10 years |
| asset-files | CAD drawings, equipment specs, manuals | Indefinite |
| alarm-files | Alarm logs, historical trends | 1 year |
| document-files | General documents, reports, certificates | 7 years |
| lot-files | Lot traceability, genealogy, testing | 3 years |
Examples
batch-files/PlantA/B1042/batch_record.pdf batch-files/PlantA/B1042/recipe_v2.docx asset-files/equipment/reactor_7/specifications.pdf asset-files/equipment/reactor_7/manual.pdf alarm-files/PlantA/2026_03/alarm_log.csv document-files/compliance/batch_B1042_review.pdf
Artifact Naming Rules
Paths are immutable: Once a fact references batch-files/PlantA/B1042/recipe.pdf, that path can never change or be deleted.
Use content-addressable names when possible: batch-files/PlantA/B1042/recipe_sha256_abc123.pdf (content hash in filename)
Organize by hierarchy: batch-files/PlantA/B1042/report.pdf is better than batch-files/PlantA_B1042_report.pdf (allows directory-level operations)
Identity Naming
BSFG nodes and zones are identified for mTLS and operational reference.
Format:
zone_identity := <zone_name>-bsfg
Examples:
enterprise-bsfg (Enterprise IT zone) plantA-bsfg (Plant A OT zone) plantB-bsfg (Plant B OT zone) idmz-bsfg (Industrial DMZ, optional)
Zone Naming Rules
Zone names are DNS-friendly: Lowercase, dash-separated (not underscore or dot). Must be valid hostnames.
Zone names appear in mTLS certificate CN: The certificate CN is the zone identity (e.g., enterprise-bsfg). Peers verify CN to authenticate.
Zone names are stable: Once deployed, a zone name is never changed. Renaming zones requires infrastructure updates including certificate reissuance. See NATS/JetStream Reference for substrate-specific naming rules.
Complete Example
Here is a complete example showing all naming conventions in context:
message envelope message_id: "msg_abc123" from_zone: "enterprise-bsfg" to_zone: "plantA-bsfg" object_schema: "order_created_v1" fact subject: "order:ENT-12345" predicate: "order_created" object_json order_id: "ENT-12345" customer: "CUST-999" ship_to: "PlantA" total_amount: 15000.00 created_at: "2026-03-06T14:30:00Z" artifact bucket: "batch-files" path: "batch-files/PlantA/B1042/batch_record_sha256_def789.pdf" stream: "facts.operational.order.*"
Naming Audit Checklist
Before deployment, verify naming consistency:
- ☐ All subject entity types are lowercase
- ☐ All subjects use
: format - ☐ All predicates are lower_snake_case (not camelCase, PascalCase, or kebab-case)
- ☐ Predicates use past tense (created, started, completed)
- ☐ All schema IDs follow
_v<#> - ☐ Artifact paths follow
/ / - ☐ Zone identities follow
-bsfg - ☐ All identifiers use ASCII characters only (no accents, emoji, Unicode)
- ☐ No abbreviations or acronyms that reduce clarity (use full words)
- ☐ Naming is consistent across all systems and documentation
For NATS/JetStream-specific naming (stream names, subject patterns, account names), see NATS Naming Profile.
Cross-Links to Related Documentation
- Message Model — Envelope and fact structure
- Message Catalog Framework — Registering facts and schemas
- Boundary Roles — How subjects and predicates flow through zones
- Producer Guide — Generating stable subject and predicate identifiers
- Identity Model — Zone identity and certificate binding
- NATS Naming Profile — NATS/JetStream-specific naming conventions