Repository navigation
Managed headless lineage state blocks implementation bootstrap_clone #5258
Description
Managed headless lineage state blocks implementation bootstrap_clone
Problem
In commissioning attempt 38073152913 for PR #5255, the implementation pipeline
halted before planning. Its managed headless launch stored lineage records in
the sandbox source checkout; the default bootstrap_clone clean-check reported
those untracked runtime files and the orchestrator followed its failure route.
This report concerns that observed default-gate failure, not a claim that every
launch necessarily halts at clone.
Reproduction and live evidence
- Tested commit:
021beadb687a96882fd717dabf36171732a97598, rebased onto
developat265f1e00e1c190808030536f9d4053e8e9fb46fd, including merged fix: one output_dir boundary check for run_skill admission and recipe rules #5257. - Dispatch E2E workflow
e2e.yml, inputtests=implementation, on branch
impl-issue-5233-20261008-implementation. - Reusable OPEN seed: https://github.com/TalonT-Org/autoskillit-e2e-sandbox/issues/1
- First run: https://github.com/TalonT-Org/AutoSkillit/actions/runs/38073152913
- Second run: https://github.com/TalonT-Org/AutoSkillit/actions/runs/38073163382
progressed to planning and failed later at plan-set allocation binding; that
separate failure is not part of this issue.
The first run's e2e-implementation-38073152913-1 artifact contains
out/envelope.json with the exact L3 failure:
bootstrap_clone blocked: uncommitted_changes in source_dir=/workspace/sandbox
(?? .autoskillit/managed-headless-session-lineage/).
Recipe clone on_failure routes to escalate_stop.
Pipeline terminated before plan/implement.
out/result.json records passed=false, outcome=failed, and no expected
findings. The session summary records MiniMax-M3, AutoSkillit 0.10.1266,
Claude Code 2.1.280, normal session completion, and exit code 0. The outer fleet
envelope reports fleet_l3_startup_or_crash; its L3 payload is more specific.
Sandbox installation and baseline tests completed before fleet dispatch. No issue
claim, implementation PR, or owned branch was created. The seed remains OPEN
without an in-progress label.
Source evidence
src/autoskillit/execution/session/_managed_headless_session_lineage.py:28
sets_NAMESPACEto.autoskillit/managed-headless-session-lineage.src/autoskillit/workspace/clone/_detect.py:94reads all nonempty
git status --porcelainlines indetect_uncommitted_changes.- The clone gate therefore treats the launcher's own lineage directory as a
source modification before the implementation recipe can create its clone.
The quoted CI reason is the retained L3 payload parsed from stdout, not a
preserved raw git status response. The small production-code probe below
independently reproduces the runtime-file/clean-check interaction.
clone_repo documents explicit strategy=proceed and strategy=clone_local
retry choices. Run 2's summary records two bootstrap_clone calls and later
planning, but does not retain their arguments/results. Therefore this report
does not identify which strategy made that run proceed.
Additional launch-path evidence at the tested commit:
fleet/dispatch/_lineage.py:151-207resolves the authoritative launch cwd.fleet/_native_shell_capture/_lineage.py:152-170,357-365creates the
FOOD_TRUCK lineage through the store using that anchor.execution/session/_managed_headless_session_lineage_records.py:131-149,185-190
creates the namespace directories and writes the durable record.
Expected behavior and scope
A clean source checkout must remain usable by bootstrap_clone after managed
headless launch. Runtime lineage persistence and source-isolation checks need to
agree about generated state, while retaining rejection of actual user edits.
Rerun the PR #5255 implementation scenario twice against the same seed after the
repair, then continue its pending commissioning checks.
This is distinct from the bounded output_dir mismatch fixed by #5257 / #5256.
The fixed plan and prepare_pr dispatches pass Docker admission checks, and the
rebased worktree passes its full configured local gate. Full implementation
success and an accepted concurrency peak have not been measured.
The automatic failure reporter also hits the already-tracked unsupported
gh issue create --json flag (#5249). That secondary defect is outside this issue.
Refs #5233 and PR #5255. Classification: bug, recipe:remediation.
Reproduction prerequisites
Pinned source: 021beadb687a96882fd717dabf36171732a97598, AutoSkillit 0.10.1266,
Claude Code 2.1.280, and that commit's scripts/docker/Dockerfile toolchain.
The harness uses MiniMax-M3[1m] at https://api.minimax.io/anthropic, with
CLAUDE_CODE_MAX_CONCURRENT_SUBAGENTS=6; the observed native model was MiniMax-M3.
Host prerequisites are Git, authenticated gh, uv and task for the
worktree/probes, and Docker with a working Buildx builder for the local image.
Check docker buildx version before that build.
Live CI requires repository write access, Actions secrets MINIMAX_API_KEY and
E2E_SANDBOX_TOKEN, and repository variable E2E_IMPLEMENTATION_ISSUE_URL set to
https://github.com/TalonT-Org/autoskillit-e2e-sandbox/issues/1. The sandbox token
must support issue claim/release, branch push/delete, PR open/close and CI reads.
Keep the seed OPEN and unclaimed, and preserve the unchanged sandbox baseline.
Observed sandbox main: d6c143d2494488deeb6680d7d5cf2e55e3e01732.
The fixture asks for normalize_whitespace in sandbox/text.py, focused unittest
cases, task test-check, and an open PR targeting main. The harness's MiniMax
settings-file setup matters; a host provider profile alone is not an equivalent
fleet-launch setup. The earlier local planning-only probe hit a managed-join
scope error; that local result is separate from this CI failure.
Replay the exact CI event
gh run rerun 38073152913 -R TalonT-Org/AutoSkillit
gh run view 38073152913 -R TalonT-Org/AutoSkillit \
--json headSha,attempt,status,conclusion,urlGitHub reruns preserve the original GITHUB_SHA and GITHUB_REF; reruns are
available for 30 days. GitHub rerun documentation.
For a fresh dispatch, create a unique verification ref at the tested commit.
The following is for a Bash session with repository write access; execute the
GitHub ref creation and workflow dispatch as separate tool calls when using an
agent, retaining the displayed variable values between calls.
set -euo pipefail
REPRO_DIR="$PWD/.autoskillit/temp/investigate-lineage-38073152913"
mkdir -p "$REPRO_DIR"
REPRO_SHA=021beadb687a96882fd717dabf36171732a97598
SANDBOX_SHA=d6c143d2494488deeb6680d7d5cf2e55e3e01732
test "$(gh api -X GET repos/TalonT-Org/autoskillit-e2e-sandbox/git/ref/heads/main --jq .object.sha)" = "$SANDBOX_SHA"
VERIFY_REF="verify-issue-5258-$(date -u +%Y%m%d-%H%M%S)"
gh api -X POST repos/TalonT-Org/AutoSkillit/git/refs \
-f ref="refs/heads/$VERIFY_REF" -f sha="$REPRO_SHA" \
--jq .object.sha > "$REPRO_DIR/verify-ref.sha" 2> "$REPRO_DIR/verify-ref.err"
test "$(cat "$REPRO_DIR/verify-ref.sha")" = "$REPRO_SHA"Then dispatch that exact ref:
sleep 1
gh workflow run e2e.yml -R TalonT-Org/AutoSkillit \
--ref "$VERIFY_REF" -f tests=implementation
gh run list -R TalonT-Org/AutoSkillit --workflow e2e.yml \
--branch "$VERIFY_REF" --event workflow_dispatch --limit 1 \
--json databaseId,headSha,status,url > "$REPRO_DIR/dispatched-run.json" 2>&1Once the run appears, confirm its headSha is $REPRO_SHA before treating its
result as a reproduction of this source. If the sandbox baseline check fails,
restore an authorized fixture baseline or use a separately owned equivalent
sandbox; a changed fixture is not the recorded reproduction environment.
The E2E queue serializes scenarios. Model behavior varies: the other commissioning
attempt stopped at a different gate. Capture the actual first failure; identical
model output is not guaranteed.
Retrieve attempt 1 evidence
From an AutoSkillit checkout:
REPRO_DIR="$PWD/.autoskillit/temp/investigate-lineage-38073152913"
mkdir -p "$REPRO_DIR"
gh run download 38073152913 -R TalonT-Org/AutoSkillit \
--name e2e-implementation-38073152913-1 --dir "$REPRO_DIR/artifact"
gh run view 38073152913 -R TalonT-Org/AutoSkillit --attempt 1 --log-failed \
> "$REPRO_DIR/failed.log" 2>&1The artifact name pins attempt 1; use the new attempt suffix for reruns. The
workflow retains artifacts for 14 days, so download them while available.
Inspect out/result.json, out/envelope.json, out/ownership.json,
out/session-concurrency.json and the cited logs/sessions/<session_id>/summary.json.
Inspect the envelope's l3_payload and diagnostic_result; the outer fleet reason
can be less specific than the actual failure.
Verified small probe
Save the complete Python block below as $REPRO_DIR/lineage_clone_probe.py. Obtain the
pinned code and configured environment without initializing a worktree project:
REPRO_SHA=021beadb687a96882fd717dabf36171732a97598
git fetch https://github.com/TalonT-Org/AutoSkillit.git "$REPRO_SHA" \
> "$REPRO_DIR/fetch.log" 2>&1
git worktree add --detach "$REPRO_DIR/source" "$REPRO_SHA"
(cd "$REPRO_DIR/source" && task install-worktree) \
> "$REPRO_DIR/install.log" 2>&1Use task install-worktree, not autoskillit init, inside the worktree.
import json
import sys
import uuid
from pathlib import Path
from autoskillit.core import (
ManagedHeadlessSessionKind,
NativeShellCaptureMode,
resolve_native_shell_capture_decision,
)
from autoskillit.execution.session import DefaultManagedHeadlessSessionLineageStore
from autoskillit.workspace.clone import detect_uncommitted_changes
source = Path(sys.argv[1]).resolve()
before = detect_uncommitted_changes(str(source))
assert before == [], before
lineage = DefaultManagedHeadlessSessionLineageStore().create(
lineage_anchor=source,
launch_id=uuid.uuid4().hex,
decision=resolve_native_shell_capture_decision(NativeShellCaptureMode.CAPTURE),
backend="claude-code",
session_kind=ManagedHeadlessSessionKind.FOOD_TRUCK,
dispatch_id=str(uuid.uuid4()),
)
after = detect_uncommitted_changes(str(source))
assert any(".autoskillit/managed-headless-session-lineage/" in row for row in after), after
print(json.dumps({"before": before, "after": after,
"lineage_anchor": lineage.reference.lineage_anchor}, indent=2))Run against a fresh sandbox clone with no user edits:
git clone --quiet https://github.com/TalonT-Org/autoskillit-e2e-sandbox.git \
"$REPRO_DIR/sandbox"
SANDBOX_SHA=d6c143d2494488deeb6680d7d5cf2e55e3e01732
git -C "$REPRO_DIR/sandbox" checkout --detach "$SANDBOX_SHA" \
> "$REPRO_DIR/sandbox-baseline.log" 2>&1
test "$(git -C "$REPRO_DIR/sandbox" rev-parse HEAD)" = "$SANDBOX_SHA"
"$REPRO_DIR/source/.venv/bin/python" "$REPRO_DIR/lineage_clone_probe.py" \
"$REPRO_DIR/sandbox" > "$REPRO_DIR/probe.json" 2>&1Verified exit 0: before=[],
after=["?? .autoskillit/managed-headless-session-lineage/"].
This demonstrates the production lineage-store/clean-check mismatch without a
model call or test suite. It does not execute bootstrap_clone or a full pipeline.
Preserve the generated record and compare porcelain status before/after; adding a
broad ignore rule would mask the behavior being investigated.
Local Docker reproduction and retained files
This mirrors the tested CI user-image build/harness invocation. Supply
MINIMAX_API_KEY and E2E_SANDBOX_TOKEN through the environment. It was not
separately rerun as part of preparing this issue; the small probe above was.
REPRO_DIR is the temp directory established above.
REPRO_SHA=021beadb687a96882fd717dabf36171732a97598
mkdir -p "$REPRO_DIR"/{build-context,e2e/out,e2e/data,e2e/upload}
git fetch https://github.com/TalonT-Org/AutoSkillit.git "$REPRO_SHA" \
> "$REPRO_DIR/fetch.log" 2>&1
git archive "$REPRO_SHA" | tar -x -C "$REPRO_DIR/build-context"
docker buildx build --load --target user --tag autoskillit-commission-repro:021beadb \
--file "$REPRO_DIR/build-context/scripts/docker/Dockerfile" \
"$REPRO_DIR/build-context" > "$REPRO_DIR/build.log" 2>&1
chmod 0777 "$REPRO_DIR/e2e/out" "$REPRO_DIR/e2e/data" "$REPRO_DIR/e2e/upload"
SANDBOX_SHA=d6c143d2494488deeb6680d7d5cf2e55e3e01732
test "$(gh api -X GET repos/TalonT-Org/autoskillit-e2e-sandbox/git/ref/heads/main --jq .object.sha)" = "$SANDBOX_SHA"
export E2E_IMPLEMENTATION_ISSUE_URL=https://github.com/TalonT-Org/autoskillit-e2e-sandbox/issues/1
REPRO_CONTAINER="autoskillit-commission-repro-$(date -u +%Y%m%d-%H%M%S)"
if docker run --name "$REPRO_CONTAINER" \
--env MINIMAX_API_KEY --env E2E_SANDBOX_TOKEN --env E2E_IMPLEMENTATION_ISSUE_URL \
--volume "$REPRO_DIR/build-context/scripts/e2e:/opt/e2e:ro" \
--volume "$REPRO_DIR/e2e/out:/artifacts" \
--volume "$REPRO_DIR/e2e/data:/home/autoskillit/.local/share/autoskillit" \
autoskillit-commission-repro:021beadb \
python3 /opt/e2e/e2e_harness.py run --test implementation --out /artifacts \
> "$REPRO_DIR/e2e/out/local-run.log" 2>&1; then
REPRO_EXIT=0
else
REPRO_EXIT=$?
fi
printf '%s\n' "$REPRO_EXIT" > "$REPRO_DIR/e2e/out/local-run.exit"The scenario budget is 7,200 seconds. The conditional records the expected
nonzero failure without aborting an errexit shell before file recovery. Retain the
container name and inspect the files before cleanup. The missing --rm is
intentional: the stopped container preserves workspace files omitted by CI upload.
For this reported pre-clone failure, recover /workspace/sandbox for the
lineage records. The post-clone plan-recovery command is documented in #5259:
docker cp "$REPRO_CONTAINER:/workspace/sandbox" \
"$REPRO_DIR/retained-sandbox" > "$REPRO_DIR/recover-sandbox.log" 2>&1The first directory is the harness source. /workspace/autoskillit-runs exists
only after clone succeeds: skip its recovery command for the reported pre-clone
failure in #5258. For the observed #5259 failure route, implementation.yaml
registers the clone with status: error, and the clone registry preserves error
clones. Thus a retained stopped container should contain its generated plans.
If they are nevertheless absent, record that unexpected cleanup and perform a
new run with failure-workspace preservation configured before launch.
docker cp cannot recover an already deleted clone; the summaries alone cannot
establish the exact original plan-format defect.
Before sharing new harness output, use the same artifact redactor as CI:
docker run --rm --env MINIMAX_API_KEY --env E2E_SANDBOX_TOKEN \
--volume "$REPRO_DIR/build-context/scripts/e2e:/opt/e2e:ro" \
--volume "$REPRO_DIR/e2e:/e2e" \
autoskillit-commission-repro:021beadb \
python3 /opt/e2e/e2e_harness.py redact --dest /e2e/upload \
--secret-env MINIMAX_API_KEY --secret-env E2E_SANDBOX_TOKEN \
/e2e/out /e2e/data/logs > "$REPRO_DIR/redact.log" 2>&1Keep raw recovered workspaces local; that redactor covers harness output/session
logs rather than arbitrary recovered checkout files. After investigation, verify
the seed remains OPEN/unclaimed and clean up each proven run-owned PR and branch.
At direct remote-ref inspection (snapshot saved 2026-10-10 19:26 UTC), these
fixture refs both pointed to d6c143d2494488deeb6680d7d5cf2e55e3e01732:
refs/heads/e2e-implementation-fixture-normalize-whitespace/1
refs/heads/e2e-implementation-fixture-normalize-whitespace/1-2
This is an inventory observation, not proof that this commissioning run created
both refs. Both ownership artifacts report branches: []. The seed was OPEN with
the fail label and without in-progress; it was not unlabeled. The second run's
peak/coverage report omitted its known planning children. These harness-evidence
gaps are recorded on PR #5255 and are separate from this issue's production cause.
Inspect current refs with gh api -X GET repos/TalonT-Org/autoskillit-e2e-sandbox/git/matching-refs/heads/.
Share only the redacted $REPRO_DIR/e2e/upload output. Fetch, install, build,
recovery and redactor logs outside that tree are raw and stay local. The local run
log is now under e2e/out, so the documented redaction includes it.
After recovering the files and after the Actions run is finished, remove the
stopped container you created:
docker rm "$REPRO_CONTAINER"If the fresh-ref method was used, also remove that investigator-owned verification
ref after the run completes. In an agent session, use the literal recorded ref
from the creation step when issuing this single mutation:
sleep 1
gh api -X DELETE "repos/TalonT-Org/AutoSkillit/git/refs/heads/$VERIFY_REF"If the sandbox harness left resources, supply RUN_OWNED_PR and RUN_OWNED_BRANCH
only after proving their identity from that run's PR, branch and head evidence.
Omit the PR command when that run created no PR; recheck the branch head against
the captured head before deleting it. Do not use the two inventory names above as
ownership proof. These are separate mutating commands:
gh pr close "$RUN_OWNED_PR" -R TalonT-Org/autoskillit-e2e-sandboxsleep 1
gh api -X DELETE "repos/TalonT-Org/autoskillit-e2e-sandbox/git/refs/heads/$RUN_OWNED_BRANCH"Source at the tested commit
-
src/autoskillit/execution/session/_managed_headless_session_lineage.py
-
src/autoskillit/execution/session/_managed_headless_session_lineage_records.py
Investigation
Investigated 2026-10-10 against develop 265f1e00e, which is identical to the tested commit 021beadb68 for everything under src/. The findings were challenged by three adversarial validators and each challenge was re-checked against source, git history, and the attempt-1 artifact. Citations below are relative to src/autoskillit/ unless they start with tests/, scripts/ or .github/.
Root Cause
The lineage store places session runtime state at the .autoskillit/ root with no keep-out, and the guards that enforce the keep-out rule cannot see a directory created by a runtime path. The clone gate is working as designed.
- The writer puts state in the source checkout.
_NAMESPACE = Path(".autoskillit") / "managed-headless-session-lineage"(execution/session/_managed_headless_session_lineage.py:28);_prepare_rootcreates it under the anchor (execution/session/_managed_headless_session_lineage_records.py:131-149). For fleet dispatch the anchor istool_ctx.project_dir(fleet/dispatch/_lineage.py:190-202) — the cwd ofautoskillit fleet run(cli/fleet/_fleet_run.py:83), orAUTOSKILLIT_PROJECT_DIR/ the git toplevel on the MCP dispatch path. Creation is not gated on backend and precedes child dispatch (fleet/_native_shell_capture/_lineage.py:357-365). A prior-success short-circuit and pre-launch failures return before any record is created; a verified resume reuses the existing one. - The namespace has no keep-out. It is not in
_AUTOSKILLIT_GITIGNORE_ENTRIES(core/io/io.py:707-716), not undertemp/, and the store writes no ignore file. - The gate is unfiltered and inspects the checkout that holds the anchor.
detect_uncommitted_changesreturns every non-blankgit status --porcelainline (workspace/clone/_detect.py:94-108) and runs wheneverstrategy == ""(workspace/clone/__init__.py:286-296). The bundledclonestep passes no strategy (recipes/implementation.yaml:355-368). In this runsource_dir=/workspace/sandboxwas passed explicitly and was also the fleet process cwd. - The existing guards cannot see it. See Test Gap.
This is not a regression from PR #5255: its diff against develop touches .github/workflows/e2e.yml, scripts/e2e/ and tests/infra/ only. The sandbox is correctly configured: at baseline d6c143d2 it tracks .autoskillit/.gitignore with exactly the canonical entries, and its root .gitignore covers what the harness's pre-dispatch task install-worktree and task test-check produce.
The gate response is deterministic when the dispatch reaches launch, the anchor lies inside the checkout the gate inspects, no ignore rule already covers the namespace, and the clone call uses the default strategy. Whether the pipeline then halts depends on the orchestrator following on_failure: escalate_stop.
Reproduced on develop HEAD with the production store and detector in commit-free throwaway repositories:
| Sequence | detect_uncommitted_changes |
|---|---|
| Empty repo | [] |
+ one FOOD_TRUCK store.create(...) |
["?? .autoskillit/"] |
+ a .gitignore containing * inside the namespace |
[] |
+ a second create and load_reference with that file present |
[], both succeed |
Empty repo + ensure_project_temp + create + the same * file |
["?? .autoskillit/"] (the untracked .autoskillit/.gitignore) |
Adjacent Defects
- The outer failure reason is erased.
_MANAGED_CAPTURE_DIAGNOSTIC_MARKERSincludes"managed-headless-session-lineage"(fleet/_outcome.py:40-50);_sanitize_managed_capture_diagnosticsdrops every line containing a marker (:61-67); when nothing is left the classifier substitutesFLEET_L3_STARTUP_OR_CRASH(:155-158). The attempt-1out/envelope.jsonhas a single-linel3_payload.reasonnaming the directory, and the sanitizer returns an empty string for it. That is why the outer envelope reportedfleet_l3_startup_or_crash. ensure_project_tempis a second trigger of the same gate. Every dispatch that reaches execution calls it before launch (fleet/dispatch/_api.py:531→fleet/sidecar.py:63-64). It creates.autoskillit/.gitignorewhen absent and appends missing entries when present (core/io/io.py:751-765). A project that has never committed that file, or whose tracked copy predates a new entry, hits the clone gate independently of lineage. It did not contribute to this run. The untracked case was reproduced; the modified-tracked-file case is derived from the code and was not run..autoskillit/.state.yaml(cli/_init_helpers.py:266-273) has no keep-out either.
Exposure
- Recipes reaching the gate with the default strategy:
implementation,remediation,implementation-groups(viabootstrap_clone) andmerge-prs(viapython: autoskillit.workspace.clone.clone_repo,recipes/merge-prs.yaml:104-113). No bundled recipe passes a strategy. run_skillcreates lineage at the skill session cwd only whenbackend.capabilities.session_dir_persistentis true, which is Codex only. In that case the directory lands in clones and worktrees, where these consumers do not exclude it: the merge dirty checks (server/git.py:359-376,:599-613),main_repo_guardandcommit_guard(recipe/cmd_rpc/_cmd_rpc_guards.py), anddetect_zero_changes(smoke_utils/_git.py:145-156), where an untracked lineage directory would mask a zero-change session. The directory has been seen untracked in worktrees; no resulting failure or leaked commit was found.
Test Gap
- Lineage-store tests anchor at a bare
tmp_pathand never use a git repository. - Uncommitted-changes-gate tests mock
subprocess.runor use a user-styleuntracked.txt; thebootstrap_clonetool tests use a mocked clone manager. - No test combines lineage creation or a managed launch with a clean-tree assertion.
tests/infra/test_release_sanity.py:58-62skips directories and inspects only the repository's own.autoskillit/;tests/cli/test_init.py:531-566encodes the directory rule but exercises onlyensure_project_tempand_create_secrets_template.- The existing
headless-smokeE2E recipe never callsbootstrap_clone; theimplementationscenario in PR Add seeded sandbox implementation E2E validation #5255 is the first to exercise fleet →bootstrap_clone. - It stayed latent because
fleetandfleet_headless_runare experimental and default-off, internal live-gate fixtures ignore.autoskillit/wholesale, and an orchestrator can retry the clone with an explicit strategy.
Historical Context
- The namespace landed on
developin29396587e(2026-08-01, Implementation Plan: Session-Scoped Direct Mode for Codex Shell Capture #4431) and its location has not changed. No prior investigation or fix of this specific collision was found. - The same invariant was rectified twice before for files:
afc9f69d5(Rectify: Init Gitignore Completeness Immunity #442, ignore-coverage registry, doctor check, init test) and062e8a090(Rectify: Session-Bridge File Misplaced Outsidetemp/#751, a session file misplaced in the.autoskillit/root, moved intotemp/). Rectify: Session-Bridge File Misplaced Outsidetemp/#751 states the root is "the tier reserved for project-lifetime artifacts" and added the root guard withif not p.is_dir(), which is why a directory passes it. 9e2e45af9([FIX] Fix clone guard false-positive when session writes are under .autoskillit/ #3101) fixed a related false positive in the clone guard only.- The symptom was noticed three times in September without being fixed (a worktree recorded as dirty with "untracked managed-lineage artifacts"; a rebase plan instructing that the untracked directory "must remain untouched"; a
git statuscapture listing it).
This is the third occurrence of the class, so it is a candidate for architectural remediation rather than another point fix.
Recommendations
- The lineage writer guarantees its namespace is invisible to git without touching a tracked file — a self-ignoring directory (
.gitignorecontaining*, written before any record), asensure_project_tempdoes fortemp/. This clears everygit statusconsumer at once, backfills existing directories the next time the root is prepared, and leaves the clone gate unfiltered so real user edits still block. Constraints: the shared helper must be narrow (callingensure_project_tempwould reintroduce the tracked-file rewrite);core/io/io.pyis at 743 budget lines against a 750 cap; a failed ignore write inside_prepare_rootfails lineage creation, so the failure policy should be chosen deliberately. - Decide the namespace's tier. Staying at the root or moving under
.autoskillit/temp/is a design decision, not a prerequisite for clearing the gate. For moving: the Rectify: Session-Bridge File Misplaced Outsidetemp/#751 precedent; the sibling shell-capture state already lives at a hardcoded.autoskillit/temp/shell_capture(hooks/_capture/_authority.py:61); fleet resume reads the lineage reference from state that is itself undertemp/. Costs: store and hook must change path together, existing directories at the old location keep tripping the gate until removed or migrated, and in-flight resumes fall back to the invalid-lineage path. - Enforce the invariant. A real-
git initcontract test that runs the launch-time sequence and asserts the tree stays clean while a genuine user change still trips the gate; extend the root guard to directories (this repository tracks.autoskillit/evidence/,skills/andwaivers/, which must be registered first); give doctor'sgitignore_completenessthe self-ignoring-directory exemption the init test already has. - Completed in Fix remaining runtime-state visibility and failure reporting #5263: failure-reason sanitizing, launch-time tracked-ignore mutation, and
.state.yamlkeep-out were addressed together; no separate tickets were opened.
Considered and rejected: adding the namespace to the ignore entry list only (the append lands in a tracked file and is itself reported by the gate); excluding .autoskillit/ in detect_uncommitted_changes (hides real edits to committed config and recipes); filtering only this namespace at the clone gate (leaves the other consumers exposed); having recipes pass strategy: proceed (removes the protection for every run).
Open Questions
- Run 2's
bootstrap_clonearguments were not retained, so which strategy let it proceed is unknown. - The raw
bootstrap_clonetool result for attempt 1 is not in the artifact; "the lineage directory was the only dirty path" rests on the L3-authored reason, the sandbox ignore rules, and the probe in this issue. - Whether Codex
run_skilllineage directories in clones or worktrees have caused a merge, commit, stash, or zero-change misroute in practice. - Why the store was placed outside
temp/is not documented anywhere.
Completion evidence — 2026-10-11
Runtime-state Git invisibility and all three adjacent fixes are merged in #5261/#5263. The acceptance-policy int_map/default=0 registration is merged in #5264 (20a4cc85be2ff369c676520247c5a91e97633589). Final code checks passed 51,233 tests on 5854498a6f980782aa0b9f883b1e90a282c7f8f3; the registration gate passed 11,771 tests on 3a0a9f8eae7a4d84a7e14d8b0b899ea76b30bd07, against its actual dictionary-shaped base.
Both post-merge runs used 959603ece0ba5f1bc5f81cf6551a0545cf36bc16, descended from verified integration 53ab68d2472153bf5667fce48f25913369527d8e containing runtime repairs #5263 and policy registration #5264. The default bootstrap_clone from /workspace/sandbox succeeded in both runs against unchanged sandbox base d6c143d2494488deeb6680d7d5cf2e55e3e01732.
- Run 1: https://github.com/TalonT-Org/AutoSkillit/actions/runs/38170521660, attempt 1. Clone receipt at
2026-10-11T20:05:01.170Z, tool callcall_01a12c9191907360b2a092bf, clone/workspace/autoskillit-runs/impl-20261011-200500-587134; planning and plan-set binding followed. The full workflow failed withfleet_l3_no_result_blockand incomplete lifecycle measurements. - Run 2: https://github.com/TalonT-Org/AutoSkillit/actions/runs/38170536595, attempt 1. Clone receipt at
2026-10-11T20:19:11.028Z, tool callcall_01a12c9e881f74f585bec830, clone/workspace/autoskillit-runs/impl-20261011-201910-273707. The full workflow failed withdegraded_tool_response; its L3 summary identifies kitchen intent-fingerprint/tracker dependency handling after clone and branch publication.
E-3's narrow clone-admission criterion passes twice on actual successful tool receipts. Both full workflow conclusions remain failure; no successful #5255 commissioning, accepted concurrency peak, or official re-audit GO is claimed. Run 1's missing final L3 payload is preserved as a failure and is not used to infer clone success.
GitHub could not rebase the original #5255 branch (PullRequest::RebaseConflictError). Its final scenario changes were applied with a three-way patch on a replay branch in the same existing worktree, preserving the original branch. Only a README overlap required combining documentation. The replay branch suppresses automatic failure tickets for this exact verification ref. The configured local gate passed on the actual integration base: 15,955 passed, 207 skipped, 12 xfailed; pre-commit passed.
The sandbox seed remains OPEN/unclaimed with its original body, original fail label, and unchanged main commit. No sandbox PR was opened. The two newly created run-owned branches (.../1-3, .../1-4) were proven by their publication receipts and deleted; the pre-existing .../1 and .../1-2 refs were preserved. The harness ownership manifests missed those published branches, so teardown was independently verified instead of relying on the empty manifest lists. No new tracking tickets or review comments were posted.
The runtime-state issue is complete. The remaining failed full-commissioning outcomes are recorded in the existing #5255 PR, whose acceptance criteria remain separate.
Activity
Keep managed lineage runtime state invisible to Git (#5261)
Fix remaining runtime-state visibility and failure reporting (#5263)
Register runtime-state classification in acceptance policy (#5264)