\renewcommand{\land}{\wedge}
\renewcommand{\lor}{\vee}
-\newcommand{\pancs}[2]{{\mathcal A} ( #1 , #2 ) }
-\newcommand{\pends}[2]{{\mathcal E} ( #1 , #2 ) }
+\newcommand{\pancs}{{\mathcal A}}
+\newcommand{\pends}{{\mathcal E}}
+
+\newcommand{\pancsof}[2]{\pancs ( #1 , #2 ) }
+\newcommand{\pendsof}[2]{\pends ( #1 , #2 ) }
\newcommand{\patchof}[1]{{\mathcal P} ( #1 ) }
\newcommand{\baseof}[1]{{\mathcal B} ( #1 ) }
-\newcommand{\eqn}[2]{ #2 \tag*{\mbox{#1}} }
+\newcommand{\eqn}[2]{ #2 \tag*{\mbox{\bf #1}} }
+\newcommand{\corrolary}[1]{ #1 \tag*{\mbox{\it Corrolary.}} }
%\newcommand{\bigforall}{\mathop{\hbox{\huge$\forall$}}}
\newcommand{\bigforall}{%
{\hbox{\scriptsize$\forall$}}}%
}
+\newcommand{\proof}[1]{{\it Proof.} #1 $\square$}
+
\begin{document}
\section{Notation}
\item[ $ C \has D $ ]
Informally, the tree at commit $C$ contains the change
made in commit $D$. Does not take account of deliberate reversions by
-the user or in non-Topbloke-controlled branches; these are considered
-normal, forward, commits. For merges and Topbloke-generated
-anticommits, the ``change made'' is only to be thought of as any
-conflict resolution. This is not a partial order because it is not
-transitive.
+the user or reversion, rebasing or rewinding in
+non-Topbloke-controlled branches. For merges and Topbloke-generated
+anticommits or re-commits, the ``change made'' is only to be thought
+of as any conflict resolution. This is not a partial order because it
+is not transitive.
\item[ $ \p, \py, \pn $ ]
A patch $\p$ consists of two sets of commits $\pn$ and $\py$, which
\item[ $ \patchof{ C } $ ]
Either $\p$ s.t. $ C \in \p $, or $\bot$.
-A function from commits to sets $\p$.
+A function from commits to patches' sets $\p$.
-\item[ $ \pancs{C}{\set P} $ ]
+\item[ $ \pancsof{C}{\set P} $ ]
$ \{ A \; | \; A \le C \land A \in \set P \} $
i.e. all the ancestors of $C$
which are in $\set P$.
-\item[ $ \pends{C}{\set P} $ ]
-$ \{ E \; | \; E \in \pancs{C}{\set P}
- \land \mathop{\not\exists}_{A \in \pancs{C}{\set P}}
+\item[ $ \pendsof{C}{\set P} $ ]
+$ \{ E \; | \; E \in \pancsof{C}{\set P}
+ \land \mathop{\not\exists}_{A \in \pancsof{C}{\set P}}
A \neq E \land E \le A \} $
-i.e. all $\le$-maximal commits in $\pancs{C}{\set P}$.
+i.e. all $\le$-maximal commits in $\pancsof{C}{\set P}$.
\item[ $ \baseof{C} $ ]
-$ \pends{C}{\pn} = \{ \baseof{C} \} $ where $ C \in \py $.
+$ \pendsof{C}{\pn} = \{ \baseof{C} \} $ where $ C \in \py $.
A partial function from commits to commits.
See ``unique base'', below.
\item[ $ C \haspatch \p $ ]
-$ \bigforall_{D \in \py} D \isin C \equiv D \le C $.
-Informally, $C$ has the contents of $\p$.
+$\displaystyle \bigforall_{D \in \py} D \isin C \equiv D \le C $.
+~ Informally, $C$ has the contents of $\p$.
-\item[ $\displaystyle C \nothaspatch \p $ ]
+\item[ $ C \nothaspatch \p $ ]
$\displaystyle \bigforall_{D \in \py} D \not\isin C $.
-~ Informally, $C$ has none of the contents of $\p$.
+~ Informally, $C$ has none of the contents of $\p$.
-\end{basedescript}
+Non-Topbloke commits are $\nothaspatch \p$ for all $\p$; if a Topbloke
+patch is applied to a non-Topbloke branch and then bubbles back to
+the Topbloke patch itself, we hope that git's merge algorithm will
+DTRT or that the user will no longer care about the Topbloke patch.
+\end{basedescript}
+\newpage
\section{Invariants}
-\[ \eqn{No replay:}{
+We maintain these each time we construct a new commit. \\
+\[ \eqn{No Replay:}{
C \has D \implies C \ge D
}\]
-\[\eqn{Unique base:}{
- \bigforall_{C \in \py} \pends{C}{\pn} = \{ B \}
+\[\eqn{Unique Base:}{
+ \bigforall_{C \in \py} \pendsof{C}{\pn} = \{ B \}
}\]
-\[\eqn{Tip contents:}{
+\[\eqn{Tip Contents:}{
\bigforall_{C \in \py} D \isin C \equiv
{ D \isin \baseof{C} \lor \atop
(D \in \py \land D \le C) }
}\]
-\[\eqn{Base non-circ:}{
+\[\eqn{Base Acyclic:}{
\bigforall_{B \in \pn} D \isin B \implies D \notin \py
}\]
+\[\eqn{Coherence:}{
+ \bigforall_{C,\p} C \haspatch \p \lor C \nothaspatch \p
+}\]
+\[\eqn{Foreign Inclusion:}{
+ \bigforall_{D \text{ s.t. } \patchof{D} = \bot} D \isin C \equiv D \leq C
+}\]
+
+\section{Some lemmas}
+
+\[ \eqn{Exclusive Tip Contents:}{
+ \bigforall_{C \in \py}
+ \neg \Bigl[ D \isin \baseof{C} \land ( D \in \py \land D \le C )
+ \Bigr]
+}\]
+Ie, the two limbs of the RHS of Tip Contents are mutually exclusive.
+
+\proof{
+Let $B = \baseof{C}$ in $D \isin \baseof{C}$. Now $B \in \pn$.
+So by Base Acyclic $D \isin B \implies D \notin \py$.
+}
+\[ \corrolary{
+ \bigforall_{C \in \py} D \isin C \equiv
+ \begin{cases}
+ D \in \py : & D \le C \\
+ D \not\in \py : & D \isin \baseof{C}
+ \end{cases}
+}\]
+
+\[ \eqn{Tip Self Inpatch:}{
+ \bigforall_{C \in \py} C \haspatch \p
+}\]
+Ie, tip commits contain their own patch.
+
+\proof{
+Apply Exclusive Tip Contents to some $D \in \py$:
+$ \bigforall_{C \in \py}\bigforall_{D \in \py}
+ D \isin C \equiv D \le C $
+}
+
+\[ \eqn{Exact Ancestors:}{
+ \bigforall_{ C \hasparents \set{R} }
+ D \le C \equiv
+ ( \mathop{\hbox{\huge{$\vee$}}}_{R \in \set R} D \le R )
+ \lor D = C
+}\]
+
+\[ \eqn{Transitive Ancestors:}{
+ \left[ \bigforall_{ E \in \pendsof{C}{\set P} } E \le M \right] \equiv
+ \left[ \bigforall_{ A \in \pancsof{C}{\set P} } A \le M \right]
+}\]
+
+\proof{
+The implication from right to left is trivial because
+$ \pends() \subset \pancs() $.
+For the implication from left to right:
+by the definition of $\mathcal E$,
+for every such $A$, either $A \in \pends()$ which implies
+$A \le M$ by the LHS directly,
+or $\exists_{A' \in \pancs()} \; A' \neq A \land A \le A' $
+in which case we repeat for $A'$. Since there are finitely many
+commits, this terminates with $A'' \in \pends()$, ie $A'' \le M$
+by the LHS. And $A \le A''$.
+}
+
+\section{Commit annotation}
+
+We annotate each Topbloke commit $C$ with:
+\begin{gather}
+\tag*{} \patchof{C} \\
+\tag*{} \baseof{C}, \text{ if } C \in \py \\
+\tag*{} \bigforall_{\pa{Q}}
+ \text{ either } C \haspatch \pa{Q} \text{ or } C \nothaspatch \pa{Q} \\
+\tag*{} \bigforall_{\pay{Q} \not\ni C} \pendsof{C}{\pay{Q}}
+\end{gather}
+
+We do not annotate $\pendsof{C}{\py}$ for $C \in \py$. Doing so would
+make it wrong to make plain commits with git because the recorded $\pends$
+would have to be updated. The annotation is not needed because
+$\forall_{\py \ni C} \; \pendsof{C}{\py} = \{C\}$.
\section{Test more symbols}