Phases 4-6: Mapping Algebra, FeText, FeWrapper, and Club Hierarchy

Overview

This document covers Phases 4-6 of the Xudanu implementation, adding text manipulation operations, type wrappers with certification, and the full club-based permission hierarchy.

Phase 4: Mapping Algebra and FeText Operations

Mapping Algebra (src/edition/mapping.rs)

The Mapping algebra provides position transformation between coordinate spaces. A Mapping represents a set of (domain, range) position pairs that retarget edition positions.

Types

pub enum Mapping {
    Empty,                                          // maps nothing
    Simple { offset: i64, region: XnRegion },       // shifts positions in region by offset
    Composite(Vec<Mapping>),                        // union of sub-mappings
}

Core Operations

Operation Description
of(pos) -> Option<i64> Transform a single position
of_region(region) -> XnRegion Transform an entire region
inverse() -> Mapping Swap domain/range pairs
combine(other) -> Mapping Union of two mapping pair-sets
restrict(region) -> Mapping Limit domain to region
shift_range(offset) -> Mapping Shift all range positions by offset
domain() -> XnRegion Get the domain region
range() -> XnRegion Get the range region

XnRegion::compactor()

Added to XnRegion, the compactor() method maps disjoint regions to contiguous zero-based positions. For example, region [3,7) ∪ [10,15) produces a mapping that sends: - 3→0, 4→1, 5→2, 6→3 - 10→4, 11→5, 12→6, 13→7, 14→8

Edition::transformed_by_mapping()

Applies a Mapping to an Edition's positions, retargeting each entry:

{ <k2, label, value> | <k1, label, value> in self and <k1, k2> in mapping }

FeText (src/edition/fetext.rs)

FeText wraps an Edition with a contiguous, zero-based integer domain and provides text manipulation operations.

Operations

Operation Description
insert(position, text) Insert text at position
extract(region) Extract and compact a region
delete(region) Remove a region
move_range(pos, region) Move a region to a new position
replace(dest, other) Replace a region with other text

All operations are immutable — they return new FeText instances. They decompose into transformed_by_mapping() and combine() calls on the underlying Edition.

Insert Algorithm

Insert splits the original text into two parts: 1. Positions before position stay in place (identity mapping) 2. Positions at/after position shift right by text.count()

The inserted text is shifted to start at position. All three parts are combined.

Delete Algorithm

Delete = extract the complement of the deleted region, which compacts the remaining content.

Move Algorithm

Move = extract the region + delete the region + insert at new position.

Phase 5: FeWrapper System

Wrapper Spec and Registry (src/edition/wrapper.rs)

The wrapper system provides type certification and endorsement for Editions. Each wrapper type has: - A checker function that validates Edition structure - An endorsement token that stamps certified Editions - A spec that manages the check/certify/wrap lifecycle

Built-in Types

Type Token Check
Text 1 Contiguous, zero-based domain
Set 2 Finite edition
Path 3 Contiguous zero-based domain, all Label elements
HyperLink 4 Non-empty edition
HyperRef 5 Always passes (structural checks in subclasses)

Certification Flow

WrapperSpec::check(edition)     // validate structure
WrapperSpec::certify(endorsements)  // stamp endorsement set
WrapperRegistry::certify_as(edition, endorsements, "Text")

Endorsements use (WRAPPER_CLUB_ID=1, token_id) pairs, integrating with the existing EndorsementSet from Phase 3.

FeSet

FeSet wraps a finite Edition as an unordered set of RangeElements. Operations work by element value (not position):

Operation Description
with(value) Add element
without(value) Remove element
includes(value) Check membership
intersect(other) Elements in both
minus(other) Elements in self but not other
union_with(other) All elements from both

Phase 6: Club Hierarchy Completion

Expanded Club (src/server/club.rs)

Club now supports full membership hierarchy:

Feature Description
members Direct member club IDs
sponsored_works Works sponsored by this club
endorsements EndorsementSet from Phase 3
transitive_super_club_ids() All clubs this club transitively belongs to
transitive_member_ids() All transitively contained clubs
can_be_read_by(keymaster) Permission check
can_be_edited_by(keymaster) Permission check

Membership Direction

Authority flows upward: a KeyMaster for club C has authority over all clubs that C transitively belongs to.

Expanded KeyMaster (src/server/keymaster.rs)

KeyMaster now supports hierarchy-aware authority:

Feature Description
update_authority(all_clubs) Recompute actual authority from login clubs using transitive super clubs
has_signature_authority(club, all_clubs) Check if user can sign for a club (has authority over its signature club)

Authority Computation

When update_authority() is called, the KeyMaster computes:

actual_authority = ∪ (for each login_id: transitive_super_club_ids(login_id))

This means logging in as a member of a sub-club grants authority over all parent clubs.

Work Endorsements

Work now has an integrated EndorsementSet:

Method Description
endorsements() Get current endorsements
endorse(additional) Add endorsements
retract(removed) Remove endorsements

Test Coverage