Branch Visibility and Access Control

Everything is an entity. Entities form a single rooted tree via `belongs-to` relations. Every entity has exactly one parent (except the root). The tree IS the permission model, the merge topology,…

#The model

Everything is an entity. Entities form a single rooted tree via belongs-to relations. Every entity has exactly one parent (except the root). The tree IS the permission model, the merge topology, and the review workflow.

root
├── domains/
│   ├── lab/mainen
│   │   ├── private/zach
│   │   └── private/collaborator
│   └── lab/other
├── methods/
│   ├── peer-review
│   │   └── peer-review-neuro (refinement)
│   └── manuscript-writing
└── actors/
    ├── reviewer
    └── writer

The three main subtrees — domains, methods, actors — are the three axes of the ontology (Definition 1). But they share one root and obey one set of rules. The three-branch split is the current ontology; a fourth axis would be another subtree off root. The machinery doesn't change.

#Three rules

#1. Visibility flows down

If an entity is defined at level N, every branch at level N and below sees it. A person entity defined at lab/mainen is visible to private/zach and private/collaborator. An organization defined at root is visible everywhere.

There is no mechanism to hide something from a child. If it exists at your level, all your descendants see it.

#2. PRs flow up

Changes move upward via pull request. A child branch proposes changes to its parent. The parent reviews and accepts or rejects. This is the only direction content moves.

When a PR is accepted, the child branch merges into the parent. The content now exists at the parent level, visible to all descendants. There is no "selective promotion" — the merge is the unit of sharing. Either the branch merges or it doesn't.

Downward flow is automatic: children inherit from their parent (merge/rebase). This is how shared work reaches private branches — you pull from your parent, which includes everything that was merged into it.

#3. References point up (or lateral within your subtree)

An entity can only reference entities at its own level or above in the tree. This is enforced by the dependency relation: an entity's dependencies must be ancestors, not descendants or siblings in other subtrees.

This eliminates broken links by construction. If you can see a file, you can see everything it references, because references only point to things that are more general (higher in the tree) than the referencing entity. The only way to create a broken reference would be to reference downward (parent referencing a child's private content) or sideways across subtrees — both of which the dependency relation forbids.

#Branches are entities

A git branch maps to a node in the entity tree. The branch name encodes the path: domains/lab/mainen/private/zach. The belongs-to relation in the entity system IS the branch parentage.

entity: branch:private/zach
  (lab/mainen, belongs-to, active, 2026-03-07, NULL)

entity: branch:lab/mainen
  (domains, belongs-to, active, 2026-01-15, NULL)

entity: branch:domains
  (root, belongs-to, active, 2025-01-01, NULL)

This means:

  • Creating a branch = creating an entity with a belongs-to relation to its parent (start_date = creation time)
  • Merging a branch = collapsing the entity into its parent (the entity's content moves up, the branch entity ends)
  • Branch access control = tree traversal (can you see branch X? Walk from X to root — if your branch is on that path or X is an ancestor, yes)

#Cross-axis references via tags

The three axes have independent depth and branching. A method like peer-review sits high in the method subtree (general, widely visible). A lab-specific variant peer-review-neuro sits lower. A private project on private/zach can reference the general peer-review method via tag — this is a cross-axis association, not a dependency edge.

Tags cross-reference between subtrees but don't create visibility requirements. The tag says "this project uses this method." It doesn't mean the method must live on the same branch. The method is visible because it sits at a level that's above (or equal to) the branch where the tag is asserted.

Methods, skills, and patterns can be forked downward (specialize a general method for your branch), modified locally, and PR'd back up to the general level. The PR follows the same upward-only rule. Your fork lives on your branch until merged.

#Conflict resolution

When two sources (or two branches) disagree about an entity's belongings, both assertions coexist as separate belonging rows with different source values. Resolution is a policy question, not an ontological one.

The PR mechanism IS the conflict resolution:

  • Two branches assert different belongings for the same entity
  • A PR proposes one branch's assertions into the parent
  • The parent reviews and accepts or rejects
  • Accepted assertions become the parent's truth, visible to all descendants
  • The policy governing which source wins in which context is itself a document, reviewable and PR-able

This connects 22-lifecycle.md (entities and belongings) to branch governance. No separate conflict resolution system.

#What this replaces

No separate systems for:

  • Permissions — the tree IS the access control
  • Branching strategy — the tree IS the branch topology
  • Review workflow — PRs follow the tree edges
  • Reference integrity — the upward-only rule eliminates broken links
  • Conflict resolution — PRs resolve disagreements between sources

#Relation to existing architecture

  • 22-lifecycle.md (Entities and Relations): The belongs-to relation encodes the tree. This document specifies what the tree means for visibility and access.
  • 23-data-infrastructure.md (Data Infrastructure): SQLite is a local index, not shared. The shared state is the entity tree in git (markdown files). Postgres syncs entity metadata across instances but doesn't govern visibility — the branch structure does.
  • 07-multi-agent-coordination-topology.md (Foundation): The three axes decompose coordination. This document shows that the same decomposition governs access control — who sees what is determined by where in the tree you sit, which is an entity relation.

#Implementation

#Entity tree validation

build_entities.py already scans belongs-to relations. Extend it to:

  1. Build the tree — from all belongs-to events, construct the full entity tree. Verify it's a tree (no cycles, single root, every node has exactly one parent except root).
  2. Validate references — for every reference (tag, cross-reference, dependency), verify the target is at the same level or higher in the tree than the source. Flag violations.

#Git branch mapping

Each node in the entity tree maps to a git branch. The branch name is the path from root:

root              → main
domains           → domains
domains/lab/mainen → domains/lab/mainen
methods/peer-review → methods/peer-review

A script generates branch structure from the entity tree:

# Create branch hierarchy from entity tree
filix branch-sync    # reads entities, creates/updates git branches
filix branch-check   # validates that git branches match entity tree

#Reference validator

A pre-commit hook or CI check that:

  1. Parses all markdown files in the branch
  2. Extracts references (@persona, #project, &pattern, file links)
  3. For each reference, checks that the target entity exists at the current branch level or above
  4. Rejects commits that introduce downward or cross-subtree references
def validate_references(branch_path, entity_tree):
    """Return list of invalid references — targets below the branch level."""
    branch_node = entity_tree.find(branch_path)
    ancestors = branch_node.ancestors()  # everything visible from here

    violations = []
    for ref in extract_references(branch_path):
        target = entity_tree.find(ref.target)
        if target and target not in ancestors and target != branch_node:
            violations.append(ref)
    return violations

#PR direction enforcement

Git hooks or Filix-level policy:

def validate_pr(source_branch, target_branch, entity_tree):
    """PRs must flow from child to parent."""
    source = entity_tree.find(source_branch)
    target = entity_tree.find(target_branch)
    return target == source.parent

#Tree query

Common queries on the entity tree:

-- What can branch X see? (all ancestors)
WITH RECURSIVE ancestors AS (
    SELECT entity_id, target as parent FROM belongings
    WHERE entity_id = 'branch:private/zach'
      AND target LIKE 'branch:%'
    UNION ALL
    SELECT b.entity_id, b.target FROM belongings b
    JOIN ancestors a ON b.entity_id = a.parent
    WHERE b.target LIKE 'branch:%'
)
SELECT * FROM ancestors;

-- Who can see entity Y? (entity's branch + all descendants)
-- Walk down: SELECT entity_id FROM belongings WHERE target = 'branch:Y'

Architecture 24 — Branch Visibility and Access Control — 2026 — Zachary F. Mainen / HAAK