From: Thomas Walker Lynch Date: Fri, 7 Aug 2026 09:11:07 +0000 (+0000) Subject: check point X-Git-Url: https://git.reasoningtechnology.com/%27%20%20%20resolved_path%20%20%20%27?a=commitdiff_plain;h=fcfee0bd26543bff51a48fb1613bc6547dcee13e;p=TM-2026 check point --- diff --git a/document/book/TM-2026.html b/document/book/TM-2026.html index f169f17..0bec940 100644 --- a/document/book/TM-2026.html +++ b/document/book/TM-2026.html @@ -419,7 +419,7 @@

Here is the programmed controller for a Turing Machine that reverses a binary string. Although by definition each state transition matches exactly one value under the head, as a practical matter, disjunctive selection is allowed via a comma list. A conjunctive phrasing for a state transition proposition would require stringing intermediate states in series.

- HU reverse machine + HU reverse machine

Provided the site is still alive, the following YAML can be entered at TuringMachine.io to watch the machine run.

@@ -541,15 +541,13 @@

The total number of steps for reversing an n symbol string:

-
- - \text{steps} = - \begin{cases} - 2 & \text{if } n = 0 \\ - 3n^2 + 6n + 5 & \text{if } n \ge 1 - \end{cases} - -
+ + \text{steps} = + \begin{cases} + 2 & \text{if } n = 0 \\ + 3n^2 + 6n + 5 & \text{if } n \ge 1 + \end{cases} +

This shows string reversal to be an O(n^2) complexity problem, which might appear to some programmers as a peculiar result, as the same problem can be solved in O(n) time with a C program. This justifies further analysis.

@@ -557,19 +555,15 @@

For a real machine, symbols are machine word encodings. For example, ASCII uses 7 data bits, so there are 128 symbols available. If the width of the word for encoding symbols is n bits, then the total number of states required for this string reverse machine is:

-
- - \text{states} = 2^n + 8 - -
+ + \text{states} = 2^n + 8 +

The number of arcs in the machine:

-
- - \text{arcs} = 2^{2n} + 9(2^n) + 12 - -
+ + \text{arcs} = 2^{2n} + 9(2^n) + 12 +

These equations show that the state controller size explodes with word width. It would be impractical to implement for all but the smallest of word sizes. This is one of the reasons that computation theory books use modest-sized symbol alphabets in their examples, perhaps the first few letters of the Latin alphabet, or the letter 's' for unary arithmetic. Previous sections discussed challenges transitioning the Turing Machine to a real architecture due to the tape length, and discussed how this could be mitigated. In contrast, there is no practical mediation for implementing a Turing Machine controller even for modest-sized real problems.

@@ -584,11 +578,9 @@

Because emptiness is a property of a container, Turing's first statement can be modeled with a sequence of sets. For a Turing Machine tape, each sequence member is either an empty set or a singleton set. In the language of mathematics an empty tape can be defined as a empty sets:

-
- - T_0 = [ \{ \}, \{ \}, \{ \}, \dots ] - -
+ + T_0 = [ \{ \}, \{ \}, \{ \}, \dots ] +

Here, each tape member set is called a cell. This definition for an empty tape is specific to Turing Machines, as in mathematics an empty sequence has zero length. An empty tape is not an empty sequence, rather it is an infinite sequence where every member is an empty set. In one sense this is a little peculiar that something said to be empty is infinite, in another sense it is consistent for the model that an empty Turing Machine tape keeps its defining characteristics. That is, it remains a single ended Turing Machine tape, where any cell of the tape could be written with a symbol value, while the basic form of the tape will not change.

@@ -614,11 +606,9 @@

Now imagine machine B, where the concept of an empty cell is jettisoned, and what remains is the mere memory of emptiness, a symbol called empty. Then using the language of mathematics, the mathematician defines an initial empty tape as:

-
- - T_0 = [ \mathtt{empty}, \mathtt{empty}, \mathtt{empty}, \ldots ] - -
+ + T_0 = [ \mathtt{empty}, \mathtt{empty}, \mathtt{empty}, \ldots ] +

For machine B, no modifications are required to the native read and write functions.

@@ -717,48 +707,49 @@

The TTCA Machine fixed part

-
- \mathit{MF} = (\mathit{QF}, \mathit{ΣF}, \mathit{AF}) -
+ + \mathit{MF} = (\mathit{QF}, \mathit{ΣF}, \mathit{AF}) +

In the following, the middle dot acts as a namespace operator, N{·}x. By doing this we assure there will be no aliasing with the symbols provided by the programmer when he defines a programmed state controller.

The set of predefined states:

-
- \mathit{QF} = \{\mathit{QF}{·}\mathtt{initial}\} -
+ + + \mathit{QF} = \{\mathit{QF}{·}\mathtt{initial}\} + +

The state controller always starts in the QF·initial state. This is a symbol representing the state; it is not a register that holds a state. The 'F' values are all fixed.

The programmer cannot add instructions to the machine definition, so there are no symbol aliasing issues here:

-
- - \begin{aligned} - \mathit{AF} = \{& \\ - & \mathtt{no\_op} \\ - ,& \mathtt{left} \\ - ,& \mathtt{right} \\ - ,& \mathtt{read}(\mathtt{d} \mid \mathtt{s}) \\ - ,& \mathtt{status} \\ - ,& \mathtt{write}(\mathtt{d} \mid \mathtt{s} \mid \mathtt{σ}, [σ]) \\ - \} - \end{aligned} - -
+ + + \begin{aligned} + \mathit{AF} = \{& \\ + & \mathtt{no\_op} \\ + ,& \mathtt{left} \\ + ,& \mathtt{right} \\ + ,& \mathtt{read}(\mathtt{d} \mid \mathtt{s}) \\ + ,& \mathtt{status} \\ + ,& \mathtt{write}(\mathtt{d} \mid \mathtt{s} \mid \mathtt{σ}, [σ]) \\ + \} + \end{aligned} + +

where σ must be in Σ.

The set of predefined symbols:

-
- \mathit{ΣF} = \{\mathit{ΣF}{·}\mathtt{leftmost}\} -
+ + + \mathit{ΣF} = \{\mathit{ΣF}{·}\mathtt{leftmost}\} +

Machine variables

-
- - \mathit{MV} = (q, s, d) - -
+ + \mathit{MV} = (q, s, d) +

q: is the current state of the machine.

@@ -769,98 +760,116 @@

Programmable part

-
- - \mathit{MP} = (\mathit{QP}, \mathit{ΣP}, \mathit{ΛP}, Δ_0, Δ_1, Δ_2, Δ_3, \mathit{HP}) - -
+ + \mathit{MP} = (\mathit{QP}, \mathit{ΣP}, \mathit{ΛP}, Δ_0, Δ_1, Δ_2, Δ_3, \mathit{HP}) +

A set of programmed state symbols:

-
- \mathit{QP} -
+ + + \mathit{QP} + +

A set of programmed data symbols:

-
- \mathit{ΣP} -
+ + + \mathit{ΣP} +

The programmed instructions. A set of pairs of the form:

-
- \mathit{ΛP} = \{ \langle q_i, a \rangle, \dots \} -
+ + + \mathit{ΛP} = \{ \langle q_i, a \rangle, \dots \} + +

where q_i is matched to the current state, and a is a member of \mathit{A}.

The conditional transition table. A set of state transition triples; each triple is of the form:

-
- Δ_0 = \{ \langle q_i, σ, q_{i+1} \rangle, \dots \} -
+ + + Δ_0 = \{ \langle q_i, σ, q_{i+1} \rangle, \dots \} + +

Here q_i and q_{i+1} are two states from the total set of Q. They need not be distinct. While the machine is running, state q_i is to be matched against the contents of the q register, the current state. Symbol σ is a member of the total set Σ and is to be matched against the contents of the s register, the machine status. When q_i matches the current state and σ matches the current status, then q_{i+1} becomes the next state.

The state default transition table. A set of state transition pairs; each pair is of the form:

-
- Δ_1 = \{ \langle q_i, q_{i+1} \rangle, \dots \} -
+ + + Δ_1 = \{ \langle q_i, q_{i+1} \rangle, \dots \} + +

where q_i is matched to the current state, and upon a match q_{i+1} will be taken as the next state.

The status default transition table. A set of state transition pairs; each pair is of the form:

-
- Δ_2 = \{ \langle σ, q_{i+1} \rangle, \dots \} -
+ + + Δ_2 = \{ \langle σ, q_{i+1} \rangle, \dots \} + +

where σ matches the symbol in s register, and upon a match q_{i+1} will be taken as the next state.

The global default next state:

-
- Δ_3 = q_{i+1} -
+ + + Δ_3 = q_{i+1} + +

This is the transition of last resort. It is unconditional; the next state becomes q_{i+1}.

A set of programmer-defined halting states:

-
- \mathit{HP} -
+ + + \mathit{HP} + +

The TTCA Machine definition in total

-
- - M = (q, s, d, Q, Σ, A, Λ, Δ, H) - -
+ + M = (q, s, d, Q, Σ, A, Λ, Δ, H) + +

The variables used by the executor, \mathit{MV} = (q, s, d).

The complete set of states, uniting the fixed predefined states and the programmed states:

-
- Q = \mathit{QF} \cup \mathit{QP} -
+ + + Q = \mathit{QF} \cup \mathit{QP} +

The complete set of symbols, uniting the fixed control symbols and the programmed data symbols:

-
- Σ = \mathit{ΣF} \cup \mathit{ΣP} -
+ + + Σ = \mathit{ΣF} \cup \mathit{ΣP} +

All members of the set of available instructions are fixed:

-
- A = \mathit{AF} -
+ + A = \mathit{AF} +

The table of state-instruction pairs is strictly programmed.

-
- Λ = \mathit{ΛP} -
+ + + Λ = \mathit{ΛP} +

The ordered sequence of next state transition rules:

-
- Δ = [Δ_0 \mid Δ_1 \mid Δ_2 \mid Δ_3] -
+ + + Δ = [Δ_0 \mid Δ_1 \mid Δ_2 \mid Δ_3] +

The set of halt states is strictly programmed, and thus could be empty.

-
- H = \mathit{HP} -
+ + + H = \mathit{HP} + +

Computation theoretic TTCA Machine executor

@@ -1039,7 +1048,7 @@ Q·Done - TTCAM reverse machine + TTCAM reverse machine

Analysis of the TTCA reverse machine

@@ -1103,15 +1112,14 @@

The total number of steps for reversing an n symbol string using the TTCA Machine:

-
- - \text{steps} = - \begin{cases} - 7 & \text{if } n = 0 \\ - 4.5n^2 + 11.5n + 5 & \text{if } n \ge 1 - \end{cases} - -
+ + \text{steps} = + \begin{cases} + 7 & \text{if } n = 0 \\ + 4.5n^2 + 11.5n + 5 & \text{if } n \ge 1 + \end{cases} + +

Two-headed reverse string example

@@ -1218,21 +1226,20 @@ Q·Done - TTCAM 2 hd reverse machine + TTCAM 2 hd reverse machine

Analysis of the two-headed reverse string machine

The number of states has dropped from 24 to 18, while the speed increase is dramatic, with the former quadratic performance becoming linear performance. The total number of steps for reversing an n symbol string using a two-head TTCA architecture:

-
- - \text{steps} = - \begin{cases} - 4 & \text{if } n = 0 \\ - 9n + 4 & \text{if } n \ge 1 - \end{cases} - -
+ + + \text{steps} = + \begin{cases} + 4 & \text{if } n = 0 \\ + 9n + 4 & \text{if } n \ge 1 + \end{cases} +

The two paths through the state machine, and the one loop, translate well into code:

@@ -1287,10 +1294,8 @@ The TTCA Machine design -
- Figure 1: A Turing Machine -
Figure 1: A Turing Machine
-
+ Figure 1: A Turing Machine +

The prior chapter on the computation theoretic TTCA machine serves as the architectural template, with only a few modifications. The architecture requires explicit data rather than accepting meta-symbols like 'unspecified' as presumed initial values 'by definition'. Actual values are transacted. Now that data and control have been separated, the controller is practical to implement, and even more so because it was defined in terms of tables that can be built in hardware. As the read status instruction returns the cell type, it will in its current form be able to return 'rightmost', so the right end of the tape can be detected. In order to extend the tape, the machine will stop and ask the operator to mount a new reel. This could be signaled when the user attempts to step right of rightmost, either by a panel light that illuminates upon the machine finding a rightmost status, or by the program printing a message on the console teletype. As this is a constant-time operation, it is computation theoretic inconsequential.

@@ -1434,7 +1439,7 @@

The machine block diagram

- Figure: TTCA block diagram + Figure: TTCA block diagram
Figure: TTCA block diagram
@@ -1941,9 +1946,7 @@ Now suppose defining a Turing Machine that initially has the head on the leftmos

A person interprets these sequences as numbers by using a weighted sum.

-
- a = \sum_{i=0}^n x_i \cdot ten^i -
+ a = \sum_{i=0}^n x_i \cdot ten^i

Here a is a numeric value, so it is written in lower case. Each x_i is the ith component of the sequence X. The value x_i is also known as the 'ith digit' of the number. The value ten is called the base or the radix of the number. It is fortunate that ten is so well known that it has a name, because otherwise an author is tempted to write the base while using the exact representation that he is trying to define. Although this function gives numeric meaning to our digit sequences, performing the suggested computation is pointless. The result is a number, and a person must represent that number, resulting in the exact sequence that was given as the input to the function in the first place.

@@ -2011,9 +2014,7 @@ Now suppose defining a Turing Machine that initially has the head on the leftmos

A person interprets a sequence of n bits as a number by using this function:

-
- \sum_{i=0}^n x_i \cdot two^i -
+ \sum_{i=0}^n x_i \cdot two^i

As with sequences of decimal digits, a person drops the sequence notation to yield strings of bits. Similar to decimal digit strings, there are two options for writing the string: most-significant-digit-first, or least-significant-digit-first.

@@ -2107,14 +2108,14 @@ Now suppose defining a Turing Machine that initially has the head on the leftmos

Figure 10 depicts a word featuring byte addresses represented in hexadecimal, running from c0 to c3. (In decimal these addresses represent 192, 193, 194, 195). The address of the byte before c0 is bf. The address after c3 is c4. The address for the word itself evaluates to c0, as it is the minimum byte address. This word holds a little-endian number. Treating a byte as an octet digit, the binary encoding for the least-significant digit of this number is 0001 1000. The most-significant digit is 1010 1110.

- Figure 10: Left justified, least-significant-digit-first + Figure 10: Left justified, least-significant-digit-first
Figure 10: Left justified, least-significant-digit-first

In Figure 11, the same number populates the word using big-endian architecture. For all but very large numbers, the digit pointed at by the allocation pointer evaluates to zero. A system continues to scan zeros until reaching either the end of the allocation or the most-significant digit. If it reaches the end of the allocation, the contained number evaluates to zero. Because this is the exact same number shown in the prior figure, it retains the identical least-significant digit and most-significant digit.

- Figure 11: Same number using big-endian digit order + Figure 11: Same number using big-endian digit order
Figure 11: Same number using big-endian digit order
@@ -2149,14 +2150,14 @@ Now suppose defining a Turing Machine that initially has the head on the leftmos

The following figure displays a stream of bytes arriving as data and being copied into a word. The digits of the word (the bytes) arrive in little-endian order and target a little-endian machine, so they are written in the exact order they are scanned off the channel.

- Figure 12: In-address-order byte by byte copy + Figure 12: In-address-order byte by byte copy
Figure 12: In-address-order byte by byte copy

In the second case, the identical data stream arrives with words serialized as bytes in little-endian order, but the receiving machine is big-endian. The system must reverse the bytes strictly on a word-by-word basis.

- Figure 13: Reverse order byte copy for words + Figure 13: Reverse order byte copy for words
Figure 13: Reverse order byte copy for words
@@ -3054,17 +3055,17 @@ Now suppose defining a Turing Machine that initially has the head on the leftmos The exact algebraic composition of this mechanical expansion is formalized by Newton's calculus of finite differences Isaac Newton formalized this interpolation method in 1675, later published in his Methodus Differentialis (1711). For a comprehensive foundational treatment, see George Boole, A Treatise on the Calculus of Finite Differences (Cambridge: Macmillan and Co., 1860), Chapter II.. Instead of executing the machine incrementally, a person can calculate the function value at call \omega directly as a linear combination of the initial tape components using Newton's forward difference formula:

-

- D_{\omega, 0} = \sum_{j=0}^{\omega} \binom{\omega}{j} D_{0, j} -

+ + D_{\omega, 0} = \sum_{j=0}^{\omega} \binom{\omega}{j} D_{0, j} +

Because the binomial coefficient \binom{\omega}{j} evaluates to exactly zero for any integer j > \omega, the summation naturally truncates at index \omega. This algebraic property perfectly mirrors the physical boundary established by the machine execution trace. Furthermore, the relationship is symmetric. A person can compute the specific components of the initial tape, D_{0, n}, directly from the sequence of evaluated function calls, D_{k, 0}, using the alternating binomial sum:

-

- D_{0, n} = \sum_{k=0}^{n} (-1)^{n-k} \binom{n}{k} D_{k, 0} -

+ + D_{0, n} = \sum_{k=0}^{n} (-1)^{n-k} \binom{n}{k} D_{k, 0} +

As a consequence of this lemma, we know that for any finite number of calls, i.e. finite \omega, that a finite prefix of D_0 is used. @@ -3173,9 +3174,9 @@ Now suppose defining a Turing Machine that initially has the head on the leftmos The main diagonal contains strictly non zero factorials, ensuring the matrix is invertible. By inverting this matrix, a person replaces the cascading back substitution with a direct, closed form equation to recover any constant a_i. The inversion utilizes the signed Stirling numbers of the first kind, denoted s(n,i) (see the Appendix on Stirling numbers).

-

- a_i = \sum_{n=i}^{\omega} \frac{s(n,i)}{n!} D_{0,n} -

+ + a_i = \sum_{n=i}^{\omega} \frac{s(n,i)}{n!} D_{0,n} +

Thus, extending this procedure \omega times definitively recovers the constants for exactly a polynomial of degree \omega. @@ -3185,9 +3186,9 @@ Now suppose defining a Turing Machine that initially has the head on the leftmos This mechanical recovery of standard polynomial constants is completely analogous to Newton's interpolation formula Ibid.. Instead of resolving the standard constants a_i through an upper triangular matrix, a person can construct the polynomial directly by treating the initial tape components as the exact coefficients for a basis of binomial terms:

-

- f(t) = \sum_{n=0}^{\omega} D_{0, n} \binom{t}{n} -

+ + f(t) = \sum_{n=0}^{\omega} D_{0, n} \binom{t}{n} +

Because the nth binomial coefficient expands into a polynomial of exactly degree n, and the summation is bounded by the finite extent \omega where D_{0, \omega} is definitively nonzero, the constructed function f(t) is structurally guaranteed to be a polynomial of degree \omega. @@ -3284,7 +3285,7 @@ Now suppose defining a Turing Machine that initially has the head on the leftmos h(t) = \frac{f(t)}{g(t)} = \frac{2^t - 32}{3t - 15} - Figure singularity plot + Figure singularity plot

@@ -3386,7 +3387,7 @@ Now suppose defining a Turing Machine that initially has the head on the leftmos So then, perhaps we set the value at the singularity to x build out the difference table, then solve for x?

- Figure with x variable. + Figure with x variable.

@@ -3415,9 +3416,9 @@ Now suppose defining a Turing Machine that initially has the head on the leftmos

The resulting D_0 vector for the quotient is:

- Figure D_0 h(t) + Figure D_0 h(t) - Figure D table for h(t) + Figure D table for h(t)

I find it fascinating to watch the transcendental difference values march down the table, then all cancel out after h(5) is generated. @@ -3514,7 +3515,7 @@ Now suppose defining a Turing Machine that initially has the head on the leftmos

None of these computation systems, that of Boehm and Cartwright, Mathematica, nor my error analysis approach, makes use of the IEEE 754 standard floating point arithmetic. Rather they all require the use of variable precision. In the case of Boehm and Cartwright's this occurs through the serialization implied through lazy calls for more precision. In the case of Mathematica it is explicit in the significance arithmetic. In my error analysis approach, the means for variable precision was the High Radix Online Arithmetic Thomas W. Lynch, "High Radix On Line Arithmetic for Credible and Accurate Computing," Real Numbers and Computers, École des Mines de Saint Étienne, France, 1995, pp. 78 89. Thomas W. Lynch and Michael J. Schulte, "Software for High Radix On Line Arithmetic," Reliable Computing, vol. 2, no. 2, 1996, pp. 133 138. DOI: 10.1007/BF02425915.. -

+

Hence what would be useful for a replacement of the IEEE 754, would be a variable precision number standard. There is one being proposed by John Gustafson called the Posit number representation John L. Gustafson, The End of Error: Unum Computing, Chapman and Hall/CRC, 2015. Posits serve as a hardware friendly alternative to IEEE 754 floating point numbers, providing variable precision mechanics..

@@ -3727,9 +3728,9 @@ Now suppose defining a Turing Machine that initially has the head on the leftmos However, in the calculus of finite differences, standard exponents are clumsy. Because the Turing Machine evaluates discrete jumps, the natural basis is the falling factorial, denoted as t^{\underline{n}}:

-

- t^{\underline{n}} = t(t - 1)(t - 2) ⋯ (t - n + 1) -

+ + t^{\underline{n}} = t(t - 1)(t - 2) ⋯ (t - n + 1) +

When a person applies the discrete forward difference operator, δ, to a falling factorial, it behaves identically to the continuous derivative: δ(t^{\underline{n}}) = n t^{\underline{n - 1}}. @@ -3759,9 +3760,9 @@ Now suppose defining a Turing Machine that initially has the head on the leftmos The signed Stirling numbers of the first kind perform the exact inverse operation. They reconstruct standard continuous powers from falling factorials:

-

- t^{\underline{n}} = \sum_{k=0}^n s(n,k) t^k -

+ + t^{\underline{n}} = \sum_{k=0}^n s(n,k) t^k +

Combinatorially, the unsigned magnitude of s(n,k) represents the number of ways to arrange n items into k disjoint cycles. The alternating signs account for the algebraic expansion of the falling factorial terms (t - 1)(t - 2), etc. @@ -3840,17 +3841,18 @@ Now suppose defining a Turing Machine that initially has the head on the leftmos Recall the convolution formula for component k of the product:

-

- I_{0, k} = \sum_{i=0}^{k} \sum_{j=0}^{k} A_{0, i} C_{0, j} \binom{k}{i} \binom{i}{k-j} -

+ + I_{0, k} = \sum_{i=0}^{k} \sum_{j=0}^{k} A_{0, i} C_{0, j} \binom{k}{i} \binom{i}{k-j} + +

To perform the deconvolution, we isolate the unknown component C_{0, k}. This term occurs in the summation strictly when j = k. When j = k, the term k-j equals 0, making the binomial coefficient \binom{i}{0} = 1. Factoring C_{0, k} out of the sum yields:

-

- C_{0, k} \sum_{i=0}^{k} A_{0, i} \binom{k}{i} -

+ + C_{0, k} \sum_{i=0}^{k} A_{0, i} \binom{k}{i} +

A person familiar with Newton's forward difference formula will recognize that the summation \sum_{i=0}^{k} A_{0, i} \binom{k}{i} is exactly the evaluation of the original function at step k, or f(k). @@ -3860,9 +3862,9 @@ Now suppose defining a Turing Machine that initially has the head on the leftmos We can now solve for C_{0, k} recursively. For the base case k = 0, where I_{0, 0} = 1:

-

- C_{0, 0} = \frac{1}{A_{0, 0}} -

+ + C_{0, 0} = \frac{1}{A_{0, 0}} +

For all subsequent components where k > 0 and I_{0, k} = 0, we subtract the previously known terms of the convolution and divide by f(k): @@ -3886,4 +3888,4 @@ Now suppose defining a Turing Machine that initially has the head on the leftmos - --> + diff --git a/setup b/setup old mode 100644 new mode 100755 index 7603f3e..f750f1d --- a/setup +++ b/setup @@ -1,61 +1,70 @@ -#!/usr/bin/env bash +#!/usr/bin/env python3 # setup - enter a project role environment -# (must be sourced) - -script_afp=$(realpath "${BASH_SOURCE[0]}") -if [ "${BASH_SOURCE[0]}" == "${0}" ]; then - echo "${script_afp}:: This script must be sourced, not executed." - exit 1 -fi - -project_roles="administrator consumer developer tester" - -print_usage(){ - echo "usage: . setup " - echo "known roles: ${project_roles}" -} - -if [ -z "${1:-}" ] || [ "${1}" == "-h" ] || [ "${1}" == "--help" ]; then - print_usage - return 0 -fi - -role_is_valid=false -for r in ${project_roles}; do - if [ "${1}" == "${r}" ]; then - role_is_valid=true - break - fi -done - -if [ "${role_is_valid}" == "false" ]; then - echo "setup: unrecognized role or option '${1}'" - print_usage - return 1 -fi - -# setup the project -# - source shared/tool/setup - if [[ -f "shared/authored/setup" ]]; then - source shared/authored/setup - fi - -# setup the role -# - export ROLE="${1}" - - tool="${REPO_HOME}/${ROLE}/tool" - if [[ ":${PATH}:" != *":${tool}:"* ]]; then - export PATH="${tool}:${PATH}" - fi - - export SETUP="${ROLE}/tool/setup" - - cd "${ROLE}" || return 1 - if [ -f "tool/setup" ]; then - source "tool/setup" - echo "in environment: ${SETUP}" - else - echo "not found: ${SETUP}" - fi + +import os +import sys +import argparse +import tempfile + +PROJECT_ROLES = ["administrator", "consumer", "developer", "tester"] + +def main(): + parser = argparse.ArgumentParser( + description="Enter a project role environment by spawning an isolated subshell." + ) + parser.add_argument("role", choices=PROJECT_ROLES, help="The project role to assume.") + args = parser.parse_args() + + env = os.environ.copy() + + # Python-domain logic: Variables and Paths + repo_home = env.get("REPO_HOME", os.getcwd()) + role = args.role + role_home = os.path.join(repo_home, role) + tool_dir = os.path.join(role_home, "tool") + setup_file = os.path.join(role, "tool", "setup") + + env["ROLE"] = role + env["ROLE_HOME"] = role_home + env["SETUP"] = setup_file + + print(f"ROLE_HOME {role_home}") + + # Python-domain logic: PATH injection + path_parts = env.get("PATH", "").split(os.pathsep) + if tool_dir not in path_parts: + env["PATH"] = f"{tool_dir}{os.pathsep}{env.get('PATH', '')}" + + # Python-domain logic: Directory validation + if not os.path.isdir(role): + print(f"setup: failed to locate directory for role '{role}'") + sys.exit(1) + + # Bash-domain logic: The rcfile only handles operations Python cannot inherit + # (sourcing bash functions) and performs the directory change internally to + # guarantee the shared scripts are sourced from the project root. + bash_logic = [ + 'if [[ -f ~/.bashrc ]]; then source ~/.bashrc; fi', + 'if [[ -f "shared/tool/setup" ]]; then source "shared/tool/setup"; fi', + 'if [[ -f "shared/authored/setup" ]]; then source "shared/authored/setup"; fi', + f'cd "{role}"', + 'if [[ -f "tool/setup" ]]; then', + ' source "tool/setup"', + f' echo "in environment: {setup_file}"', + 'else', + f' echo "not found: {setup_file}"', + 'fi', + 'if [[ -n "${INSIDE_EMACS}" ]] && command -v env_to_emacs >/dev/null 2>&1; then', + ' env_to_emacs', + 'fi', + 'rm -f "${BASH_SOURCE[0]}"' + ] + + fd, rcfile_path = tempfile.mkstemp(suffix="-rt-setup.sh") + with os.fdopen(fd, "w") as f: + f.write("\n".join(bash_logic) + "\n") + + os.execvpe("bash", ["bash", "--rcfile", rcfile_path], env) + +if __name__ == "__main__": + main()