Gate Context Classifier for Recursive Pipeline Containment in No-Mistakes
The gate context classifier in internal/gatecontext is an authoritative access control mechanism that prevents recursive pipeline execution by verifying both gate-directory identity and IPC peer ancestry before allowing any step to enter the protected worktree.
The no-mistakes repository implements a hardened execution environment where pipeline steps must never recursively invoke themselves within the protected gate worktree. The gate context classifier for recursive pipeline containment serves as the single source of truth for determining caller eligibility, ensuring that critical safety mechanisms—such as credential redaction and run-record integrity—remain uncompromised by nested execution.
How the Gate Context Classifier Enforces Recursive Pipeline Containment
Located in internal/gatecontext/classifier.go, the classifier acts as the sole authority for recursive pipeline containment. Its primary responsibility is to block a pipeline step from launching another step that would re-enter the gate or daemon context. The implementation combines two independent cryptographic and filesystem signals to render its verdict.
Canonical Gate Directory Identity
The classifier verifies that the current working directory belongs to the canonical gate directory registered in the database—the exact path created by no-mistakes init. The gatecontext.Inspector struct queries the database (DB) and path utilities (Paths) to confirm the caller resides within the legitimate gate worktree. If the path check fails, the classifier issues an immediate refusal.
Daemon Peer Ancestry Verification
Even with a valid directory, the classifier requires proof of lineage. It inspects the IPC peer ancestry via the PeerPID field in gatecontext.Request, walking the process chain to verify the caller is a direct child or descendant of the daemon that owns the gate. This prevents external processes from spoofing location while lacking the proper daemon parentage.
Refusal Result Handling
When either signal is missing, the classifier returns a gatecontext.Result whose ErrorCode identifies the refusal type. Callers invoke gatecontext.RefusalMessage(result) to generate a clear abort message, ensuring recursive attempts fail fast with actionable diagnostics.
Protected Entry Points in the No-Mistakes Pipeline
Every component capable of initiating a pipeline step must consult the classifier before proceeding. This universal enforcement guarantees that recursive pipelines are impossible regardless of entry vector.
-
CLI pre-flight – Before executing any
axiorno-mistakescommand,classifyGateControlCallerininternal/cli/gate_context.goinvokes the inspector to validate context. -
Daemon mutation ingress – The daemon’s
gateContextResulthandler ininternal/cli/daemon_cmd.goclassifies the caller before accepting mutation requests, preventing direct circumvention. -
Branch-sync operations –
internal/branchsync/sync.govalidates gate context before modifying the protected worktree, ensuring background sync tasks cannot accidentally recurse. -
Managed pre-receive hooks – Server-side hooks employ the same
gatecontext.Inspectorto block direct pushes that would bypass the gate’s safety envelope.
Code Implementation and Usage Examples
Inspecting the Caller Context
The following pattern demonstrates how entry points instantiate the classifier and interpret results:
// Create an inspector with the DB and path utilities.
inspector := gatecontext.Inspector{DB: db, Paths: paths}
// Build a request describing the current context.
req := gatecontext.Request{
CWD: cwd, // current working directory
MarkerPresent: gatecontext.MarkerPresent(), // optional debug marker
PeerPID: os.Getpid(), // PID of the calling process
}
// Perform the inspection.
result, err := inspector.Inspect(context.Background(), req)
if err != nil {
return fmt.Errorf("gate classification failed: %w", err)
}
if result.Refused() {
return fmt.Errorf("pipeline step refused: %s", gatecontext.RefusalMessage(result))
}
Source: internal/gatecontext/classifier.go
CLI Pre-flight Integration
The CLI wrapper encapsulates inspection logic for command-line invocations:
func classifyGateControlCaller(ctx context.Context) (gatecontext.Result, error) {
// Resolve cwd and paths…
// …
marker := gatecontext.MarkerPresent()
return (gatecontext.Inspector{DB: database, Paths: p}).Inspect(
ctx,
gatecontext.Request{CWD: cwd, MarkerPresent: marker},
)
}
Source: internal/cli/gate_context.go
Daemon Refusal Emission
When the daemon rejects a request, it emits standardized error output:
func emitGateContextRefusal(cmd *cobra.Command, result gatecontext.Result) error {
return cmd.ErrOrStderr().Write([]byte(
fmt.Sprintf("%s (code=%s)\n", gatecontext.RefusalMessage(result), gatecontext.ErrorCode),
))
}
Source: internal/cli/gate_context.go
Summary
- The gate context classifier lives in
internal/gatecontext/classifier.goand serves as the exclusive authority for recursive pipeline containment. - Access requires dual verification: canonical gate-directory identity (database-registered path) and daemon peer ancestry (verified via
PeerPIDchain walking). - All execution vectors—CLI, daemon ingress, branch-sync, and pre-receive hooks—consult the classifier before permitting mutations.
- Refusal results propagate consistent error codes through
gatecontext.ErrorCodeand human-readable messages viagatecontext.RefusalMessage(), ensuring uniform handling across layers.
Frequently Asked Questions
What happens when a recursive pipeline is detected?
The classifier returns a refusal result populated with gatecontext.ErrorCode, causing the caller to abort immediately with a descriptive message from gatecontext.RefusalMessage(). This hard stop prevents the nested step from entering the gate and subverting safety checks like credential redaction.
How does the classifier distinguish legitimate calls from recursive ones?
It mandates two independent signals: the process must reside in the canonical gate directory registered in the database, and its process hierarchy—verified through PeerPID—must descend from the owning daemon. Possession of only one signal results in automatic refusal.
Is the marker file used for security decisions?
No. The gatecontext.MarkerPresent() function serves strictly as a diagnostic debugging aid. The actual authorization decision relies exclusively on database-registered paths and OS-authenticated peer ancestry checks performed by gatecontext.Inspector.
Where is the recursive containment logic tested?
Regression tests such as TestGateStepCannotStartRecursivePipeline validate that the classifier correctly rejects recursive attempts. The single-source-of-truth design in internal/gatecontext/classifier.go ensures any logic drift is caught immediately by the test suite.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →