Expand description
The rendering-agnostic core: it computes git state and knows nothing about terminals.
Its public surface is flat, re-exported from the crate root rather than through
fanout, git, entity or snapshot, which stay private: a generic scatter
primitive and a single branch read are not vocabulary a second consumer needs,
and neither is which file happens to define EntityState or Snapshot. The one
exception is liveness, a test-util-gated module of test waits that names
nothing git-shaped and so belongs under a namespace rather than at the root. The
entry points on Core itself (start, refresh, snapshot, try_settle, …)
land in later work and get re-exported the same way once they exist.
§Reviewing an addition to this surface
Every addition to what this crate exports should hold each of these, from
docs/spec/core-api.md’s ownership table and
ADR 0015:
- It does a git-shaped thing (discovery, a probe phase, the metadata poll, a Set
boundary, an override, Generation supersession, the row fold, the display
name, the default branch rung, the environment contract as data, Action
fan-out), never a terminal-shaped one (rendering, the cursor, glyphs, theme,
keybindings, the Launcher, config file discovery,
$HOME, a user-specific environment variable). - An empty Selection carries no meaning here: this crate never defaults it to “the row under the cursor” or anything else that only makes sense on a screen.
refreshtakes an already-ordered&[EntityKey]. This crate never computes or second-guesses that order; cursor-row-first is the consumer’s ordering to make, not this crate’s to infer.- A Filter is a pure predicate over these public types. Deciding when to apply one, if ever, stays with the consumer.
- It has no notification channel, update stream or callback: a consumer reads a
Snapshotwhen it decides to, it is never pushed one.
Four refusals hold for every type this crate ever makes public, reasoned in ADR 0015:
- No
#[non_exhaustive]: it forces a consumer to add a wildcard match arm even when every variant is already matched, reintroducing by attribute the default path ADR 0001 forbids. ADR 0015 argued this against an in-repo consumer; ADR 0021 observes that publishing widens the audience beyond that case, so the refusal stands but is not re-argued for the wider one. - No sealed trait: the enforcement ADR 0015 relies on is a real second consumer
(
repon sets), not defensive API ceremony guarding against a use case nothing presents. - No separate versioning scheme: repon-core is a path dependency with one in-workspace consumer, so a breaking change and its fix land in the same commit.
- No git-backend trait abstraction: the crate’s existing test drives a real disposable repository rather than a mock, so a trait would buy testability already paid for.
Structs§
- Action
Receipt - The most recent Action run against this Entity: a receipt of something Repon did,
not a reading of the world, read by the row summary fold
(
docs/spec/actions.md, ADR 0018). - Action
Spec - One Action fan-out, crossing from the consumer as plain data: no TOML type, no
confirm gate, no palette.
labelis what a receipt’s own label carries: the Action’s name, or the ad hoc command string typed into the palette.nameisREPON_ACTION’s own value and isNonefor an ad hoc run, exactly as config.md’s environment contract already treats a Launcher’s absentREPON_ACTION.whenisNonefor a built-in, a typed command or a configured entry that declares none, in which case every operable row runs;Someis whatCore::run_actionitself now decides the fan-out by, not only what a palette reports about it (docs/spec/actions.md’s “The Selection and the gate”). - Ahead
Behind - Commit counts ahead and behind an Entity’s branch’s upstream.
- Applicability
- How an Action’s
whenpredicate divides the rows it would operate on, once a[[repo]]exclude = truehas already been subtracted: three counts and no verdict. - Auto
Update Spec - The fast-forward-only auto-update’s own crossing data
(config.md’s
[auto_update]table): whether it runs at all. - Capture
Elision - What a step’s captured output lost to the head-plus-tail bound
(
docs/spec/actions.md’s “Capture”): two counts and no mark. - Cell
- A displayed value together with its whole provenance.
- Core
- A running core: its own table, its own dedicated thread, and the rayon pool it shares with the rest of the process for probes.
- Core
Spec - Everything
Core::startneeds, handed as plain data. The core reads no file, no path and no environment variable: this is the whole crossing, perdocs/spec/core-api.md’s “What crosses from config”. - Default
Branch - The default branch’s resolved name.
- Delete
Risk - What accepting a
deleteconfirm gate will destroy in one Repo or Worktree, per repo-management.md’s “The confirm gate”: the facts the gate names per row, read fresh at the moment the gate is built rather than folded out of Cells a Generation may have left stale.linked_worktreesis meaningful on a Repo row alone; a Worktree row’s own gate line never names it, since deleting one Worktree never touches its siblings. - Diagnostics
- Per-Entity facts that are not Cells: which rung of the default branch
resolution chain answered, whether rung 2 and rung 3 disagreed, why
resolution stopped when it did not settle, and whether
.gitmodulesfailed to read or parse. - Dirty
Counts - The
dirtycell’s settled value: phase C’s typed counts, per refresh.md’s “The phases”. A booleanis_dirtycheck was measured and rejected there: proving clean costs the same as counting, and a boolean cannot answer the untracked count at all, so this carries all three rather than folding them into one number at the probe. - Discovery
- What one discovery walk found.
- Entity
Key - An Entity’s identity: a newtype over its own resolved absolute working directory.
- Entity
State - One Entity’s state: a struct of named Cells rather than a map, because the grid is not rectangular and each column carries its own payload type.
- Fetch
Failures - The most recent periodic-fetch cycle’s own failures, read fresh through
Core::fetch_failuresthe same wayCore::discovery_warningandCore::vanished_countare: never latched, so a cycle where every fetch succeeds leaves this empty rather than carrying a stale failure forward from an earlier one. Per-repository independence is unaffected: one entry here is one repositoryrun_fetch_cyclecould not reach, never a reason another repository’s own fetch was skipped. - Fetch
Spec - The periodic fetch’s own crossing data
(config.md’s
[fetch]table): whether it runs at all, its cadence, and how many run at once. Plain bounding data, not the mutating mechanism itself:enabled: falsehere is what keeps the cycle from running, not the absence of any machinery to run it. - Filter
- A Filter: a total, three-valued predicate parsed once from user text and matched against
as many
EntityStatevalues as a consumer needs. Seedocs/spec/filter.md. - Generation
- One refresh, so a newer one can be recognised over an older one still draining.
- KeyVocabulary
- One key’s own completion vocabulary, for the Filter line’s completion list
(filter.md):
its own text, and the fixed values
docs/spec/filter.md’s vocabulary table gives it, empty for the three free-text keys. - Management
Handle - The read-only, path-driven operations a management run’s per-row work needs
(
crates/repon/src/management.rs’s ownrun_one_record), cloned out ofCore::management_handlerather than borrowed from a liveCore:Send + 'static, so a caller can move it onto a background thread the wayCore::run_action’s own fan-out thread already moves itsArc<RwLock<Table>>clone there. Grants none ofCore’s other state (action_running,action_control, the clock thread): a management run is a distinct concern from the one fan-out those track, and this handle’s own methods touch only the table, exactly asCore::run_action_for_entity_blockingalready does. - Recent
Commit - One commit in an entity’s recent history: its seven-character abbreviated id
and its message’s first line. Carries no provenance of its own, the same
reasoning as
InProgressOperation: it is read fresh alongsidebranchrather than tracked as a Cell. - Repo
Override - One Repo’s config-level override, crossing from the consumer as plain data: no
TOML type, no
~expansion left undone. config.md owns parsing it; the core only ever receives the result, and resolvespathto the git common dir itself, since opening a repository is the core’s own work. - Running
Step - The step an
ActionReceiptis executing right now, present only while its run has not yet finished (docs/spec/actions.md’s “The run on screen”: “a running step carries the spinner in the same position the step number’s outcome will occupy”). - SetSpec
- A Set’s bounding specification, handed to the core as plain data: no TOML type, no file
path, no
~expansion left to do. config.md keeps the file format on the consumer’s side; this is what crosses the boundary. - Snapshot
- The whole table, as a consumer reads it.
Core::snapshotclones this every frame, so every field here, and everything reachable from it, isClone, and every text-bearing value on anEntityStateis anArc<str>rather than aStringprecisely because of that per-frame clone. - Step
- One command in an Action’s ordered list, crossing from the consumer as plain data:
from_envalready resolved, so this crate never learns what that means (config.md’s “Actions”, “Launchers” carries the same split for a Launcher’s own argv).shellcrosses over unresolved, because resolving it isexecutor::run_step’s own job, the same convention thereponcrate’s Launchershell = trueuses: withshellset,argvholds exactly one element, the whole command string, per config.md’s “Launchers”.env’s pairs are applied afterenvironment::environment’s own set-or-unset pairs, so a step’s ownenvtable overrides the guaranteed set exactly as config.md’s Launcherenvfield already does. - Step
Result - One step’s own result within an
ActionReceipt: its label, its outcome, its captured output and its elapsed time (docs/spec/actions.md’s “Where the result lives”). - Timestamp
- A wall-clock moment, RFC 3339 on request via
std::fmt::Display.
Enums§
- Auto
Update Attempt - One
Core::attempt_auto_updateresult on a single Repo: the fast-forward-only auto-update’s own five eligibility rules (config.md’s eligibility rule), flattened into one return type so the built-insyncaction (repo-management.md) can report every ineligible reason to the user rather than a bare “did nothing”. - Default
Branch Stopped - Why the default branch resolution chain reached rung 4, from facts the chain already has at no extra cost: which of gix’s own remote enumeration, or rung 3’s own name list, came up empty.
- Head
- HEAD’s three shapes, one to one with gix’s
head::Kind. - InProgress
Operation - One of the ten shapes an in-progress git operation can take, one to one with
gix’s own
state::InProgress(ADR 0019). Read fromRepository::state(), which stats the per-worktree git dir’s own marker files rather than any Cell this crate probes, so it carries no provenance of its own: it is a fact of the moment it was read, not a value that can go stale or fail to resolve. - Kind
- Which of the three domain objects an Entity is.
- OwnWork
- What a step Repon performed itself came to, in Repon’s own words
(
docs/spec/actions.md’s “Why the set grew from four to five”): three grades, matched exhaustively wherever aStepOutcome::OwnWorkis opened. - Presence
- Whether an Entity was found by the Refresh that just ran.
- Probe
Error - Error from a git read, cheap to clone because the whole state table is cloned every frame. A shared trait object was rejected: it gives no discriminant to branch on and nothing to serialise, and nothing in this crate reads a source chain.
- RowSummary
- The one state a row’s Cells fold into, for the gutter.
- Settled
- What a
Cellhas settled to. Never a bareOption<T>, so an absent value can never be read as a default. - Skip
- Why a row’s Action receipt carries no steps and was never operated on, the three ways
Core::run_actiondecides a row out before the fan-out starts (docs/spec/actions.md’s “The Selection and the gate”). Closed and matched exhaustively rather than three booleans, so a fourth reason to skip a row is a compile error here rather than a silent omission. - Step
Outcome - One step’s own outcome: a closed set of exactly five
(
docs/spec/actions.md’s “Step outcomes”). No wildcard arm ever matches this: a sixth variant must be named at every match site or the crate fails to compile. - Sync
State - The
synccell’s settled value: a live upstream’s ahead/behind counts, or one of two facts that preclude a count.NoRemoteoutranksNoUpstream, since a Repo with no remote at all makes every one of its rows, branch or not, unable to have an upstream in the first place (layout-and-provenance.md’s “Glyphs”). - Unknown
- Why a
CellisSettled::Unknown. Closed at exactly these three: every other absence this design once modelled as Unknown turned out to be a settled value rendered elsewhere (a branch with no upstream renders-, a Repo with no remote renders∅), so noNoUpstreamorNoRemotereason exists here. - Worktree
State - The four mutually exclusive Worktree states, proven by ancestry or patch
equivalence.
Dirtyis a separate, orthogonal cell, not a fifth arm here.
Functions§
- count
- Matches a Set against the boundary-stop walk with no probing and no provenance,
for
repon setsto print a count per declared Set. Infallible, likediscoveritself: an unreadable or missing root is silently zero entities rather than an error, so there is noDiscoveryErrorfor this to return. - discover
- Walks every root in
spec, stopping at each Repo boundary, and returns the bounded list. Never descends into a boundary and never descends through a symlink, so a cycle cannot form by descent and needs no visited set or cycle detector to guard against; the set this module does keep exists only to give a symlink’s target the same identity as its real name, never to remember a path already walked. Never reads or writes a cache. - environment
entity’s environment contract: the set-or-unset pairs a Launcher or an Action step’s child receives.Somesets a variable,Noneunsets it, so an absent name can never be misread as one set to the empty string.- summary
- Folds one Entity’s Cells into the state its row’s gutter shows.
- vocabulary
- The Filter’s whole vocabulary, one entry per key in
docs/spec/filter.md’s own table order, read off the parser’s own closed key set so a key it accepts can never be missing from it and a key it does not accept can never be offered: this is the one place a consumer reaches that set from, rather than restating it.