Private
Public Access
0
0
Files
manual_slop/conductor/archive/tier2_no_appdata_20260618/plan.md
T
2026-06-18 18:50:48 -04:00

15 KiB
Raw Blame History

Track Plan: Tier 2 Sandbox - Move State/Failures Off AppData

Goal: move failcount state and failure-report locations inside the Tier 2 clone; remove all AppData references from Tier 2 conventions, permissions, scripts, docs, and tests. Scope: 11 source files + 3 test files + 1 doc + 1 workflow.md section + 1 .gitignore. Convention: 1-space Python indentation. CRLF where the file is already CRLF (do not normalize).

Phase 1: Move the default state and failure-report paths

Focus: change the Python defaults so load/save use scripts/tier2/state/... and scripts/tier2/failures/... when no env-var override is set.

Task 1.1: Update scripts/tier2/failcount.py:_state_dir default

  • WHERE: scripts/tier2/failcount.py:117-123 (the _state_dir(track_name) function).
  • WHAT: change the default base from r"C:\Users\Ed\AppData\Local\manual_slop\tier2" to Path.cwd() / "scripts" / "tier2" / "state" (computed when the function is called; Path import already present at line 11).
  • HOW: rewrite the function as:
    def _state_dir(track_name: str) -> Path:
        base_str = os.environ.get("TIER2_STATE_DIR")
        if base_str:
            return Path(base_str) / track_name
        return Path.cwd() / "scripts" / "tier2" / "state" / track_name
    
  • SAFETY: preserve the env-var escape hatch (TIER2_STATE_DIR); preserve the Path return type. The function has no other callers.
  • COMMIT: fix(tier2): move failcount state default inside Tier 2 clone (scripts/tier2/state/)

Task 1.2: Update scripts/tier2/write_report.py:_failures_dir default

  • WHERE: scripts/tier2/write_report.py:20-23 (the _failures_dir() function).
  • WHAT: change the default from r"C:\Users\Ed\AppData\Local\manual_slop\tier2_failures" to Path.cwd() / "scripts" / "tier2" / "failures".
  • HOW: rewrite the function as:
    def _failures_dir() -> Path:
        base_str = os.environ.get("TIER2_FAILURES_DIR")
        if base_str:
            return Path(base_str)
        return Path.cwd() / "scripts" / "tier2" / "failures"
    
  • SAFETY: preserve TIER2_FAILURES_DIR env-var override; preserve the Path return type. Callers are compute_report_path, compute_stopped_flag_path, and write_failure_report (all in the same file).
  • COMMIT: fix(tier2): move failure-report default inside Tier 2 clone (scripts/tier2/failures/)

Task 1.3: scripts/tier2/run_track.py chdir before state calls

  • WHERE: scripts/tier2/run_track.py:run_init (around line 78, before save_state) and run_track.py:run_report (around line 100, before write_failure_report).
  • WHAT: add os.chdir(repo_path) so Path.cwd() in _state_dir / _failures_dir resolves to the repo root.
  • HOW: add import os at the top (the file already imports argparse, subprocess, sys, datetime, pathlib); add os.chdir(repo_path) as the first line of run_init and run_report.
  • SAFETY: os.chdir is process-global; this is acceptable because run_track.py is the CLI entry point, not a library. The chdir is idempotent within a single invocation.
  • COMMIT: fix(tier2): chdir to repo_path in run_track before state/report calls

Task 1.4: Add scripts/tier2/state/ and scripts/tier2/failures/ to .gitignore

  • WHERE: .gitignore (top-level). Currently excludes scripts/generated on line 11.
  • WHAT: add scripts/tier2/state/ and scripts/tier2/failures/ after the scripts/generated line.
  • HOW: edit the file in place.
  • SAFETY: these are track-isolated scratch dirs; committing them would pollute the tree.
  • COMMIT: chore(tier2): gitignore scripts/tier2/state/ and scripts/tier2/failures/

Phase 2: Update OpenCode permissions and agent/command prompts

Focus: remove AppData allow rules from the OpenCode JSON fragment; update the agent prompt and slash command to say "NEVER USE APPDATA".

Task 2.1: conductor/tier2/opencode.json.fragment — remove AppData allow rules

  • WHERE: lines 10-11, 16-17, 62-63, 68-69 (the permission.read and permission.write blocks at top level and at the tier2-autonomous agent level).
  • WHAT: delete the two C:\\Users\\Ed\\AppData\\Local\\manual_slop\\tier2\\** and C:\\Users\\Ed\\AppData\\Local\\manual_slop\\tier2_failures\\** allow rules. The remaining allow rule (the Tier 2 clone path) is unchanged.
  • HOW: four targeted edit_file calls (one per read/write block × top-level/agent).
  • SAFETY: keep the existing *AppData\\Local\\Temp\\* bash deny rule. Do NOT modify the bash rules in this task — that's Task 2.2.
  • COMMIT: fix(tier2): remove AppData allow rules from OpenCode permission JSON

Task 2.2: conductor/tier2/opencode.json.fragment — add *AppData\\* bash deny

  • WHERE: the permission.bash block at top level (line 46) and at the tier2-autonomous agent level (line 73).
  • WHAT: add "*AppData\\*": "deny" after the existing "*AppData\\Local\\Temp\\*": "deny" rule. The broader pattern catches Local, LocalLow, Roaming, and any other subdir.
  • HOW: two targeted edits.
  • SAFETY: the rule denies any bash command containing AppData\. Legitimate Tier 2 work does not write there. Combined with Task 2.1 (no allow rules), this is belt-and-suspenders.
  • COMMIT: fix(tier2): add *AppData\\* bash deny rule (broader than just Temp)

Task 2.3: conductor/tier2/agents/tier2-autonomous.md — replace AppData convention

  • WHERE: line 47 (the "Temp files" bullet under "Conventions (MUST follow - added 2026-06-17)").
  • WHAT: replace the entire bullet. The new bullet says: "All scratch, state, audit-output, and intermediate files MUST live inside the Tier 2 clone (the OpenCode * deny rule blocks everything else). Default locations: scripts/tier2/state/<track>/state.json for failcount state, scripts/tier2/failures/ for failure reports, scripts/tier2/artifacts/<track>/ for throwaway scripts. The C:\Users\Ed\AppData\... tree is OFF-LIMITS for any read, write, or shell command. The OpenCode *AppData\\* bash deny rule enforces this."
  • HOW: edit_file on the bullet's full text.
  • SAFETY: preserve the env-var escape-hatch language (TIER2_STATE_DIR / TIER2_FAILURES_DIR are honored if set).
  • COMMIT: docs(tier2): agent prompt - replace AppData convention with inside-clone convention

Task 2.4: conductor/tier2/commands/tier-2-auto-execute.md — replace AppData convention

  • WHERE: line 46 (the "Temp files" bullet under "Conventions (MUST follow - added 2026-06-17)").
  • WHAT: identical change to Task 2.3, applied to the slash command prompt. Also update line 19 ("Check for a previous run" — the path is <app-data>/tier2/<track-name>/state.json) and line 25 (step 3 in Protocol — "Initialize failcount state at <app-data>/tier2/<track-name>/state.json") to reference scripts/tier2/state/<track-name>/state.json.
  • HOW: three edit_file calls.
  • SAFETY: the slash command prompt is what the Tier 2 agent reads; if it still says <app-data>, the agent will continue trying to use AppData.
  • COMMIT: docs(tier2): slash command - replace AppData paths with inside-clone paths

Phase 3: Update bootstrap scripts

Focus: setup_tier2_clone.ps1 and run_tier2_sandboxed.ps1 stop creating/referencing AppData dirs.

Task 3.1: scripts/tier2/setup_tier2_clone.ps1 — remove AppData dir creation

  • WHERE: lines 23 ($AppDataDir), 30 ($AppDataFailuresDir), 122-133 (the New-Item / Get-Acl / Set-Acl block).
  • WHAT: delete the $AppDataDir and $AppDataFailuresDir parameter / variable declarations and the entire "Create app-data dir with restricted ACLs" step block. Update the docstring (lines 6-9) to remove the "creates the app-data temp dir with restricted ACLs" sentence.
  • HOW: three edit_file calls.
  • SAFETY: the script must still create the Tier 2 clone, copy templates, install git hooks, and create the desktop shortcut. The deleted step is purely about AppData dirs.
  • COMMIT: fix(tier2): setup_tier2_clone.ps1 - stop creating AppData dirs

Task 3.2: scripts/tier2/run_tier2_sandboxed.ps1 — remove AppData dir references

  • WHERE: lines 20-21 ($AppDataDir, $AppDataFailuresDir), line 7 (docstring), line 77 (the "Set explicit ACLs on the Tier 2 clone + app-data dir" comment).
  • WHAT: delete the $AppDataDir / $AppDataFailuresDir variable declarations and any ACL-set logic that references them. Update the docstring (line 7) to remove "app-data dir" from the list.
  • HOW: four edit_file calls.
  • SAFETY: the restricted-token + Job-Object + launch logic must stay intact.
  • COMMIT: fix(tier2): run_tier2_sandboxed.ps1 - remove AppData dir references

Phase 4: Update tests

Focus: flip the slash-command-spec tests so they assert "no AppData refs" instead of "AppData refs required"; update test_no_temp_writes.py docstring and fix-message.

Task 4.1: tests/test_tier2_slash_command_spec.py:test_agent_denies_temp_writes

  • WHERE: lines 82-91 (the entire test_agent_denies_temp_writes function).
  • WHAT: flip the assertions. Replace:
    assert 'AppData\\Local\\Temp' in content, "agent prompt must include Temp deny rule in frontmatter bash"
    assert 'AppData\\Local\\manual_slop\\tier2' in content or 'app-data' in content.lower(), "agent prompt must point agent at the app-data dir for temp files"
    
    with:
    assert 'AppData\\Local\\Temp' in content, "agent prompt must include Temp deny rule in frontmatter bash"
    assert "*AppData\\\\*" in content or "AppData\\\\*" in content, "agent prompt must include the broader AppData deny rule"
    assert "scripts/tier2/state" in content, "agent prompt must point agent at scripts/tier2/state for failcount state"
    assert "scripts/tier2/failures" in content, "agent prompt must point agent at scripts/tier2/failures for failure reports"
    assert "AppData\\Local\\manual_slop\\tier2" not in content, "agent prompt must NOT reference the AppData tier2 dir (2026-06-18 hard ban)"
    
    Update the docstring to mention the 2026-06-18 reversal.
  • HOW: edit_file on the function body and docstring.
  • SAFETY: the *AppData\\* substring check matches the literal JSON bash key "*AppData\\*". Be careful with Python string-escape semantics — use a raw string or a literal substring that survives the JSON double-escape.
  • COMMIT: test(tier2): slash_command_spec - assert no AppData refs, point at inside-clone

Task 4.2: tests/test_tier2_slash_command_spec.py:test_command_denies_temp_writes (or the equivalent for the command file)

  • WHERE: the parallel test for the slash command prompt (likely also in tests/test_tier2_slash_command_spec.py).
  • WHAT: apply the same flip as Task 4.1 to the command prompt content.
  • HOW: edit_file.
  • SAFETY: keep the Temp deny assertion; add the new inside-clone-pointing assertions; remove the AppData-required assertion.
  • COMMIT: test(tier2): slash_command_spec - command prompt assert no AppData refs

Task 4.3: tests/test_no_temp_writes.py docstring + fix message

  • WHERE: lines 1-15 (the docstring) and line 33 (the fix-message string).
  • WHAT: replace the AppData paths in the docstring (lines 6-7) with scripts/tier2/state/ and scripts/tier2/failures/. Replace the fix-message suggestion on line 33 (C:\\Users\\Ed\\AppData\\Local\\manual_slop\\tier2\\ instead of %TEMP%.) with scripts/tier2/state/ or scripts/tier2/failures/ instead of %TEMP%..
  • HOW: edit_file.
  • SAFETY: the audit script's behavior is unchanged; only the human-facing strings change.
  • COMMIT: test(tier2): no_temp_writes - replace AppData refs in docstring + fix message

Phase 5: Update user-facing docs and workflow

Focus: docs/guide_tier2_autonomous.md and conductor/workflow.md stop referencing AppData.

Task 5.1: docs/guide_tier2_autonomous.md — replace AppData refs

  • WHERE: line 24 (bootstrap step 5), line 59 (the "4 hard bans" table row), line 72 (failure report location), lines 119-129 (Troubleshooting section).
  • WHAT: replace each C:\Users\Ed\AppData\Local\manual_slop\tier2... reference with the new scripts/tier2/state/... / scripts/tier2/failures/... paths.
  • HOW: multiple edit_file calls (one per paragraph that contains an AppData path).
  • SAFETY: the guide's structure and other content stay intact; only path strings change.
  • COMMIT: docs(tier2): guide_tier2_autonomous - replace AppData paths with inside-clone paths

Task 5.2: conductor/workflow.md — update hard bans table

  • WHERE: line 386 (the row "File access outside Tier 2 clone + app-data dir").
  • WHAT: replace with "File access outside Tier 2 clone (AppData, Temp, Documents, etc. all denied at the OpenCode * level + targeted *AppData\\* deny)."
  • HOW: edit_file.
  • SAFETY: the surrounding 3-layer-enforcement table structure stays.
  • COMMIT: docs(tier2): workflow.md hard bans - AppData denied (no exception)

Task 5.3: scripts/tier2/write_track_completion_report.py — update report output

  • WHERE: lines 262, 264 (the "Filesystem boundary" and "Failcount monitored" rows in the generated report).
  • WHAT: replace the AppData path strings with scripts/tier2/state/... / scripts/tier2/failures/....
  • HOW: two edit_file calls.
  • SAFETY: the generated report's structure stays; only path strings change. The report's downstream consumers (the user reading it after a Tier 2 run) need to see the actual paths the next run will use.
  • COMMIT: fix(tier2): write_track_completion_report - use inside-clone paths in output

Phase 6: Conductor verification

Focus: ensure the test suite still passes after the changes; register the track in conductor/tracks.md.

Task 6.1: Run targeted test batches

  • COMMAND: uv run python scripts/run_tests_batched.py --tier tier-1-unit-core tests/test_failcount.py tests/test_tier2_report_writer.py tests/test_tier2_slash_command_spec.py tests/test_no_temp_writes.py
  • EXPECTED: all 4 test files pass. The test_failcount and test_tier2_report_writer env-var tests pass because they monkeypatch the env var (FR7's backward-compat requirement). The test_tier2_slash_command_spec tests pass because the new assertions match the updated agent prompt and slash command. The test_no_temp_writes test passes because the audit script's behavior didn't change.
  • COMMIT: no commit (this is a verification step).

Task 6.2: Run the static analyzer batch

  • COMMAND: uv run python scripts/audit_no_temp_writes.py --strict
  • EXPECTED: CLEAN: no script under ./scripts/ emits to %TEMP% and exit code 0. The audit's exclusion list (scripts/tier2/artifacts) covers the throwaway scripts that may still have AppData path strings.
  • COMMIT: no commit.

Task 6.3: Register the track in conductor/tracks.md

  • WHERE: append a new entry block following the precedent set by tier2_autonomous_sandbox_20260616.
  • WHAT: add the link, spec, plan, metadata, status, and a one-line summary.
  • COMMIT: conductor(tracks): register tier2_no_appdata_20260618 (shipped) (after Phase 1-5 commit SHAs are recorded).

End-of-Track Report (added 2026-06-17 convention)

On Phase 6 completion, write docs/reports/TRACK_COMPLETION_tier2_no_appdata_20260618.md following the precedent set by docs/reports/TRACK_COMPLETION_tier2_autonomous_sandbox_20260616.md. Update conductor/tracks/tier2_no_appdata_20260618/state.toml to status = "completed".