Project Logos is a synthetic information ecosystem for evaluating retrieval, graph traversal, source attribution, trust ranking, and multi-hop reasoning systems. The system separates objective world truth from subjective information flow:
WorldGeneratorcreates a ground-truthTruthGraph.SourceGeneratorcreates information sources with reliability and bias.CommunityGeneratorgroups sources into social communities.ObservationGeneratorturns ground-truth facts into noisy source-specific observations.BeliefGeneratoraggregates observations into source-level beliefs.main.pyexports benchmark statistics, topology reports, SIG artifacts, and a consolidated knowledge-base dataset.
The current implementation is topology-driven. It no longer treats fact_count as a simple loop over adjacent entities. Instead, it generates communities, directed acyclic regions, local strongly connected components, hubs, bridges, hierarchy edges, conflict edges, and controlled random edges. It then materializes those topology edges into Fact objects.
The key design correction is that fact volume and topology volume are measured separately:
Facts: number of storedFactobjects inTruthGraph.facts.Relationships/UniqueSubjectObjectEdges: number of unique directed(subject_id, object_id)edges after projection intonetworkx.DiGraph.UniqueTriples: number of unique(subject_id, predicate, object_id)triples.DuplicateEdgeRatio: how much fact volume collapses onto already existing subject/object edges.
This distinction is essential for benchmark validity. A large number of facts does not imply a structurally rich graph.
logos/main.py orchestrates the pipeline:
generate_sig_pipeline()
-> WorldGenerator.generate()
-> SourceGenerator.generate()
-> CommunityGenerator.process()
-> ObservationGenerator.process()
-> BeliefGenerator.process()
-> output serialization
generate_sig_pipeline accepts the legacy scalar interface:
generate_sig_pipeline(
entity_count=1000,
fact_count=5000,
source_count=100,
)It also accepts a topology configuration object:
generate_sig_pipeline(
source_count=100,
world_config=WorldConfig(...),
)If world_config is supplied, it is passed to WorldGenerator.generate(config=world_config). Otherwise, scalar entity_count and fact_count are converted into a default WorldConfig.
TruthGraph remains intentionally simple:
entities: Dict[str, Entity]facts: List[Fact]add_entity(entity)add_fact(fact)get_all_facts()query(**filters)
This preserves the existing SIG stages. The topology redesign is implemented inside world generation and statistics, not by replacing the graph storage contract.
Entity includes:
idnamedescriptionmetadatadomaincategorytype
Fact includes:
idmetadatasubject_idpredicateobject_idtruth_value
The generator uses metadata to store topology annotations such as:
community_idnode_roletopology_roleduplicate_semantics
These metadata fields are additive. Existing consumers can ignore them safely.
The implemented configuration model is:
WorldConfig(
entities=1000,
facts=5000,
community_count=20,
hub_fraction=0.05,
bridge_fraction=0.02,
local_scc_fraction=0.15,
dag_fraction=0.50,
hierarchy_fraction=0.10,
conflict_fraction=0.05,
random_edge_fraction=0.10,
average_reasoning_depth=8,
average_branching_factor=4,
max_duplicate_edge_ratio=0.15,
max_largest_scc_fraction=0.35,
seed=13,
)These values are topology targets, not hard mathematical guarantees. Generation is stochastic, but deterministic for a fixed seed. For non-trivial worlds, the generated graph is validated before it is returned.
The generator assigns node roles through Entity.metadata["node_role"]:
ordinary_entity: default entity role.hub_entity: selected byhub_fraction; used to create high-degree retrieval distractors and central concepts.bridge_entity: selected bybridge_fraction; used to connect communities.cycle_entity: selected bylocal_scc_fraction; reserved for local SCC generation.
Cycle entities are intentionally isolated from most non-SCC edge generation. This prevents local cycles from merging into one giant SCC.
Topology edges are created internally as _TopologyEdge objects before becoming Fact objects. Each edge has:
subject_idobject_idpredicatetruth_valuerole
Implemented topology roles:
dag: directed causal, temporal, or dependency structure.hierarchy: membership, subtype, part-whole, or governance structure.local_scc: bounded feedback loops inside communities.hub: high-degree central-node structure.bridge: cross-community links.conflict: contradictory or weakening pathways.random: controlled background connectivity.singleton: fallback for one-entity worlds.
When materialized as Fact objects, the edge role is stored in Fact.metadata["topology_role"].
Community sizes are allocated using a log-normal distribution rather than equal partitioning. This creates uneven communities, which better resembles real information domains.
For small worlds, the effective community count is capped so communities are not all singletons:
effective_community_count = min(config.community_count, max(1, config.entities // 3))
Every entity receives a community_id metadata value.
DAG edges are generated inside communities. They use predicates such as:
affectsenablesprecedesconstrainsamplifies
Non-SCC edges are oriented by entity rank. This creates broad directed flow and prevents accidental global cyclic collapse.
DAG regions exist to support:
- ordered multi-hop reasoning
- dependency tracing
- temporal and causal traversal
- long and short directed paths
Hierarchy edges are generated within communities using predicates such as:
member_ofsubtype_ofpart_ofgoverned_by
These edges produce retrieval tasks that require category/entity reasoning rather than only direct entity-to-entity lookup.
Local SCCs are generated as bounded cycles inside eligible communities using predicates such as:
feeds_back_tostabilizesdestabilizesreinforces
Local SCCs model feedback loops and mutually reinforcing systems. They are desirable when bounded. They are harmful when they merge into a giant SCC. The generator therefore prevents most other edge roles from connecting directly to cycle_entity nodes.
Hub edges are generated around selected hub_entity nodes using predicates such as:
influencescoordinatesindexesbroadcasts
Hubs create high-degree nodes that challenge retrieval systems with plausible distractors. They also model central institutions, platforms, categories, or widely referenced concepts.
Bridge edges connect different communities using predicates such as:
bridges_todepends_onexports_toreferences
Bridges are deliberately sparse. They force cross-community traversal and prevent every task from being solved within one local neighborhood.
Conflict edges use predicates such as:
contradictsdisputesweakensrebuts
They create competing information pathways. These are important for fact verification, source disagreement, trust ranking, and belief formation.
The generator first creates a target number of unique topology edges:
target_unique_edges = facts * (1 - max_duplicate_edge_ratio)
It then materializes each topology edge as a Fact. If additional facts are needed to reach config.facts, it creates controlled semantic duplicates using predicates such as:
reported_byobserved_inindependently_observedreconfirmed_by
These duplicates are explicitly marked:
metadata={
"topology_role": edge.role,
"duplicate_semantics": "evidence_restatement",
}This preserves some evidence redundancy without allowing the benchmark to collapse into repeated identical edges.
The implemented generation flow is:
- Resolve
WorldConfig. - Initialize deterministic random generator from
config.seed. - Generate ontology with domains, categories, and types.
- Allocate skewed community sizes.
- Create entities and assign ontology plus
community_id. - Assign node roles: hubs, bridges, cycle entities, ordinary entities.
- Compute target unique edge count from
factsandmax_duplicate_edge_ratio. - Allocate edge budget by topology role.
- Generate local DAG edges.
- Generate hierarchy edges.
- Generate local SCC edges.
- Generate hub edges.
- Generate bridge edges.
- Generate conflict edges.
- Generate controlled random edges.
- Materialize topology edges into
Factobjects. - Add controlled semantic duplicate facts until
config.factsis reached. - Validate topology.
- Return
TruthGraphor raiseValueErrorfor unhealthy non-trivial worlds.
The generator tracks seen subject/object pairs and seen triples while constructing topology edges. This avoids accidental duplicate collapse during unique-edge generation.
Non-SCC edge orientation is rank-based. This is a deliberate protection against reconstructing the original problem: a large graph that is technically connected but topologically collapsed into one giant directed cycle.
logos/world/stats.py builds a networkx.DiGraph projection from the TruthGraph:
Fact(subject_id, predicate, object_id) -> DiGraph edge(subject_id, object_id)
This projection intentionally collapses parallel facts between the same subject and object. Therefore the statistics report both fact counts and unique edge counts.
The following legacy-compatible fields are preserved:
EntitiesRelationshipsNumberOfSCCsLargestSCCSizeAverageInDegreeAverageOutDegreeAverageShortestPathLengthGraphDiameterLongestAcyclicChainEstimatedReasoningDepthBenchmarkHealth
Important: Relationships means unique directed subject/object edges in the networkx.DiGraph, not stored fact objects.
The current implementation adds:
FactsUniqueSubjectObjectEdgesUniqueTriplesDuplicateEdgeRatioDuplicateTripleRatioLargestSCCFractionEffectiveBranchingFactorPathDiversityP50PathDiversityP90BridgeDensityTopHubDegreeShareInDegreeEntropyOutDegreeEntropyPredicateEntropyTopologyRoleDistributionTopologyHealthReasons
DuplicateEdgeRatio:
(Facts - UniqueSubjectObjectEdges) / Facts
This detects whether high fact volume is merely repeated subject/object pairs.
DuplicateTripleRatio:
(Facts - UniqueTriples) / Facts
This detects literal triple repetition.
LargestSCCFraction:
LargestSCCSize / Entities
This detects giant SCC collapse.
EffectiveBranchingFactor:
For sampled nodes, the implementation compares frontier growth across limited directed expansion depth. A ring graph has effective branching near 1. Richer retrieval graphs should exceed that.
PathDiversityP50 and PathDiversityP90:
For sampled source-target pairs, the system counts simple directed paths up to a cutoff and reports distribution percentiles. This captures whether the graph offers multiple routes between entities.
BridgeDensity:
bridge-role facts / total facts
This approximates how much of the fact set contributes to cross-community traversal.
TopHubDegreeShare:
sum(degrees of top 1 percent nodes) / sum(all degrees)
This measures hub concentration.
InDegreeEntropy and OutDegreeEntropy:
Entropy over degree distributions. Low entropy indicates structurally repetitive topology.
PredicateEntropy:
Entropy over fact predicates. Low entropy indicates semantic monotony.
The system flags unhealthy worlds with TopologyHealthReasons.
Current failure modes:
empty_graphno_factsgiant_sccring_graph_collapseduplicate_edge_collapselow_branching_factorlow_degree_diversitylow_predicate_diversityinsufficient_reasoning_depthdisconnected_graph_collapse
For worlds with more than 20 entities, the generator rejects unhealthy outputs by raising ValueError.
Small worlds are exempt from full topology rejection because unit tests and toy examples often use 1 to 20 entities, where many topology metrics are not meaningful.
With the default configuration:
WorldGenerator().generate(entity_count=1000, fact_count=5000)the current deterministic seed produces the following smoke-test profile:
Entities: 1000
Facts: 5000
Relationships / UniqueSubjectObjectEdges: 4236
DuplicateEdgeRatio: 0.153
NumberOfSCCs: 224
LargestSCCSize: 82
LargestSCCFraction: 0.082
AverageInDegree: 4.236
AverageOutDegree: 4.236
GraphDiameter: 7
EstimatedReasoningDepth: 42
EffectiveBranchingFactor: 4.406
PathDiversityP50: 8
PathDiversityP90: 25
BridgeDensity: 0.020
OutDegreeEntropy: 3.477
PredicateEntropy: 4.607
BenchmarkHealth: HEALTHY
TopologyHealthReasons: []
This is materially different from the previous ring topology. The graph no longer has one 1000-node SCC, no longer has average in-degree/out-degree fixed at 1.0, and no longer collapses 5000 facts into 1000 unique edges.
SourceGenerator creates sources with:
reliability- optional
BiasProfileentries - generated names and descriptions
Bias profiles can include:
target_predicatestarget_entitiesskew
CommunityGenerator groups sources and assigns community_id values. This creates social structure in the information layer. It is separate from world-graph communities, which are stored in entity metadata.
The distinction is intentional:
- World communities describe objective topology.
- Source communities describe information-agent grouping.
ObservationGenerator currently iterates over every source and every fact:
observations = source_count * fact_count
For the default benchmark:
100 sources * 5000 facts = 500,000 observations
Each observation records:
source_idfact_id- content containing subject, predicate, object, truth value, and observed value
- uncertainty
- ontology tags
- causal-chain text
- temporal window
- ground-truth quality
Observation uncertainty is influenced by source reliability and bias skew.
BeliefGenerator groups observations by:
(source_id, fact_id)
It emits one belief per source/fact pair in the current default flow. For the default benchmark, this also yields 500,000 beliefs.
The belief stores:
source_idfact_idvalenceconfidenceevidence_ids- ontology tags
- causal chain
- temporal window
- ground-truth quality
Current belief formation is source/fact local. It does not yet propagate through graph neighborhoods. The improved topology makes future graph-aware belief propagation meaningful, but the SIG stages themselves remain intentionally preserved.
The redesigned topology supports richer benchmark tasks.
Retrieval difficulty now comes from:
- branching neighborhoods
- high-degree hubs
- sparse bridges
- conflicting facts
- predicate diversity
- multiple directed paths
- community-local and cross-community tasks
This is a better signal than graph diameter alone. A large ring can have a high diameter while remaining structurally trivial.
DAG regions test ordered traversal. Local SCCs test bounded cyclic reasoning. Bridges test cross-community routing. Hubs test whether traversal can avoid irrelevant high-degree distractors.
Controlled duplicate facts represent evidence restatements rather than accidental topology collapse. Because duplicates are marked with duplicate_semantics, downstream evaluators can distinguish repeated evidence from unique topology.
Trust ranking benefits from:
- conflicting pathways
- different source reliabilities
- repeated observations
- source communities
- bridge-dependent claims
The topology can now produce cases where a claim is locally reinforced but globally contradicted.
Misinformation-like behavior can be modeled through:
- local SCC reinforcement
- hubs broadcasting weak facts
- bridge nodes spreading claims across communities
- conflict predicates creating disagreement paths
This gives future evaluations a realistic substrate for belief propagation and correction.
main.py writes:
output/benchmark_statistics.jsonoutput/graph_audit.mdoutput/reasoning_examples.jsonoutput/topology_report.mdoutput/sources.jsonoutput/communities.jsonoutput/observations.jsonoutput/beliefs.jsonoutput/knowledge_base.json
The SIG output writer intentionally exports only:
sources.jsoncommunities.jsonobservations.jsonbeliefs.json
The truth graph itself is used internally for statistics and observation generation but is not currently serialized as a standalone JSON graph artifact.
The test suite uses pytest.
Important coverage areas:
-
test_world_generator.py- verifies requested entity/fact scale
- verifies
WorldConfigsupport - verifies benchmark-scale generation avoids ring collapse
- checks duplicate-edge ratio, degree entropy, predicate entropy, bridge density, and branching factor
-
test_world_graph.py- verifies
TruthGraphfact storage and query behavior
- verifies
-
test_sig_pipeline.py- verifies end-to-end pipeline outputs, including
truth_graph
- verifies end-to-end pipeline outputs, including
-
SIG feature and schema tests
- verify source, community, observation, belief, and serialization contracts
Current verification command:
python -m pytest -q
Current result:
26 passed
The topology generator is now structurally richer, but several areas remain intentionally evolutionary rather than fully redesigned:
ObservationGeneratorstill has full source-by-fact coverage. This creates large observation sets but does not model selective source access.BeliefGeneratoraggregates by(source_id, fact_id)and does not yet perform graph-aware propagation.- World communities and source communities are separate. Future work may align or deliberately misalign them for more complex trust experiments.
CommunityModularityis not yet reported as a first-class metric.- Bridge density currently uses fact metadata rather than computed community boundary crossings.
- Reasoning examples are sampled from the projected
DiGraph; they do not yet preserve predicate-level path explanations. - The generator rejects unhealthy worlds but does not yet retry with adjusted seeds.
These are acceptable next steps because the main benchmark failure has been corrected: the default topology is no longer a directed ring, and scale is no longer confused with structural diversity.
Project Logos should treat generated topology as a benchmark contract. A world is not valid merely because it contains the requested number of entities and facts. It is valid only if it satisfies structural properties that challenge retrieval and reasoning systems:
- meaningful branching
- bounded cycles
- non-trivial communities
- sparse bridges
- predicate diversity
- controlled evidence redundancy
- multiple paths
- detectable conflicts
- measurable health
The code is the source of truth. Documentation should be updated whenever topology generation or benchmark statistics change.