Core Protocol Spec

Two-Tier Tag Taxonomy & Affinity Scoring

In a decentralized barter network with thousands of diverse skills, finding circular trade loops requires fast, deterministic classification. NodeHash organizes all value offerings into a two-tier taxonomy tree. This structure partitions search spaces while scoring trade compatibility with mathematical precision.

📐
Hard Structural Invariant: Depth ≤ 2

NodeHash strictly bounds taxonomy nesting to a depth of two levels. Tier 1 tags represent broad functional domains. Tier 2 tags represent granular proficiencies. Any tag definition with depth exceeding two is rejected by backend schema validators with an HTTP 400 response.

The Two Tiers Explained

Instead of deep, sprawling ontologies, NodeHash splits skill and compute descriptions into two distinct operational layers:

Tier 1: Primary Tags

Role: Coarse-grained candidate clustering and graph partitioning.

Properties: tier: 1, depth: 1, parentTagId: null.

Examples: software-dev, cloud-infra, design, audio-engineering.

Matching Impact: Powers the InvertedSupplyIndex. Users who share a primary tag between supply and demand are clustered into active candidate pools via O(1) hash lookups.

Tier 2: Sub-Tags

Role: Fine-grained skill specialization and affinity scoring.

Properties: tier: 2, depth: 2, parentTagId: <tier1_id>.

Examples: typescript, react, kubernetes, figma.

Matching Impact: Calculates Jaccard set similarity between supply and demand items, contributing up to 15 points to the composite cycle ranking score.

Candidate Pooling Mechanics

When a peer registers an active demand item, the matching engine must locate suitable supply providers without scanning the entire database. The engine achieves this through the InvertedSupplyIndex:

  1. Bucket Partitioning: As supply items arrive, they are indexed into discrete buckets keyed by their normalized Tier 1 primary_tag.
  2. O(1) Candidate Retrieval: When a demand request arrives with primary_tag = "software-dev", the index immediately retrieves all providers indexed under that key. Unrelated domains like landscaping or translation are pruned instantly.
  3. Directed Edge Construction: The engine builds directed graph edges only between nodes whose supply primary tag matches the recipient's demand primary tag.

This two-tier separation guarantees that graph construction scales linearly with the number of active peers in the matching category, rather than quadratically across the entire network.

Precision Affinity Scoring via Jaccard Similarity

Once candidate edges are established by primary tag clustering, Tier 2 sub-tags determine the exact quality of fit. The engine computes the Jaccard similarity coefficient between the supply item sub-tags ($S$) and the demand item sub-tags ($D$):

Mathematical Formula
Jaccard(S, D) = |S ∩ D| / |S ∪ D|

If either the supply or demand set is empty, the alignment score defaults to 0.0. When both sets contain tags, the engine divides the count of shared tags by the total count of unique tags across both sets.

Ranking Weight in Cycle Scoring

In the composite multi-parameter ranker, sub-tag alignment is weighted alongside proficiency, temporal overlap, and trust scores:

Component Evaluation Method Max Score
Cycle Efficiency Length penalty: 40 pts for K=2, 30 pts for K=3 40 pts
Proficiency Score Average skill level normalized (Proficiency / 5 × 20) 20 pts
Sub-Tag Alignment Jaccard similarity coefficient × 15 pts 15 pts
Temporal Overlap Mutual UTC weekly minute overlap × 15 pts 15 pts
Reputation Trust Average network trust score × 10 pts 10 pts
Category Diversity Bonus for cross-disciplinary trades in 3-party loops 5 pts

Sub-tag alignment provides 15% of the total composite score, ensuring that candidates with identical specializations rise to the top of the recommendation feed.

Why Depth ≤ 2 is Strictly Enforced

Developers familiar with deep category hierarchies often ask why NodeHash caps depth strictly at two. The restriction stems from three mathematical and operational constraints:

1. Combinatorial Latency in Cycle Traversal

Cycle discovery finds closed loops of length $K \le 3$ using canonical depth-first search. If taxonomy nodes existed at arbitrary depths, evaluating whether item A matches item B would require traversing ancestor chains, evaluating semantic subsumption, and resolving multi-parent inheritance. In a graph with thousands of edges, recursive tree walks turn sub-millisecond graph checks into second-long bottlenecks. Flat two-tier lookups keep edge scoring in memory at native pointer speeds.

2. Elimination of Taxonomic Ambiguity and Loops

Deep hierarchies encourage subjective categorization. One user places PostgreSQL under Databases > SQL > OpenSource, while another places it under Backend > Storage > Relational. Deep trees also risk circular inheritance if administrators misconfigure category parent pointers. Capping depth at two enforces clear, unambiguous boundaries: a tag is either a root domain (Tier 1) or a specific skill under that domain (Tier 2).

3. Predictable Jaccard Similarity Sets

Jaccard similarity relies on well-defined discrete sets. In deeply nested trees, two users might mean the same thing using nodes at different levels of abstraction (for example, Frontend versus React). By flattening all specific skills into Tier 2 sibling tags under the primary tag, set intersections remain deterministic and mathematically fair.

Validation Rules and Error Responses

The backend validates every tag mutation using Zod schemas and database indexes. The system enforces three non-negotiable rules:

  • Rule 1: Tier 1 tags must not declare a parentTagId and must set depth: 1.
  • Rule 2: Tier 2 tags must supply a valid parentTagId referencing an active Tier 1 tag and must set depth: 2.
  • Rule 3: Depth values of 0, 3, or higher trigger immediate validation rejection.

If an invalid payload is sent, the API returns an HTTP 400 error:

JSON Error (400 Bad Request)
{
  "success": false,
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "Tier 2 (SubTag) requires a valid parentTagId and must have depth 2"
  }
}

Interacting with the Taxonomy API

You can query the taxonomy tree or fetch tags by category using the public REST API:

Shell / curl
curl -X GET http://localhost:3000/api/v1/taxonomy

The endpoint returns the structured hierarchy organized by functional category:

JSON Response
{
  "success": true,
  "data": [
    {
      "category": "Engineering",
      "primaryTags": [
        {
          "tagId": "software-dev",
          "name": "Software Development",
          "tier": 1,
          "depth": 1,
          "subTags": [
            { "tagId": "typescript", "name": "TypeScript", "tier": 2, "depth": 2 },
            { "tagId": "react", "name": "React", "tier": 2, "depth": 2 },
            { "tagId": "node.js", "name": "Node.js", "tier": 2, "depth": 2 },
            { "tagId": "rust", "name": "Rust", "tier": 2, "depth": 2 }
          ]
        }
      ]
    }
  ]
}