Asserts that an unquoted UNC path like \\server\share\file.txt survives
extract_path_candidates unchanged, preventing the regression where
shlex.split(posix=True) stripped the backslashes.
Replaces the basic extraction test with an end-to-end test that verifies
UNC paths are correctly denied when outside the workspace (e.g. local root),
but correctly allowed when the workspace root is itself a UNC share.
Validates the fix from the PR review.
Adds explicit test coverage to ensure drive-relative paths (e.g. C:foo)
and escaped UNC paths (e.g. \\\\server\\share\\dir) from JSON payloads
are correctly validated by the workspace containment checks.
Closes final review suggestions.
- Updates _check_bash_state to not short-circuit on the first unusable
bash candidate on Windows, ensuring a working fallback is found if present.
- Clears bash detection cache in unittest setUp/tearDown rather than just
relying on a pytest fixture, covering native unittest runners.
Adds a conftest.py pytest fixture to explicitly clear the lru_cache for bash
detection, addressing the monkeypatching hazard in a way that doesn't rely
solely on comments. (Note: CI currently runs python -m unittest, but this
keeps local pytest runners safe.)
Also updates the bash check to run the execution probe directly inside the
cached _check_bash_state, exposing the difference between 'no bash found'
and 'bash present but execution failed' directly to the unittest skip reason.
Moves get_bash_executable and require_bash into a shared module so their
lru_cache state is per-session rather than per-test-module. Also adds a
comment regarding monkeypatching since lru_cache will silently drop changes
to os.environ if it has already been populated.
Closes follow-up items from PR review.
load_session/save_session built the session file path directly from the
caller-supplied session_id with no validation, so a value like
'../../../tmp/secrets' (reachable from the 'load-session' CLI subcommand)
could read or write JSON files outside the session directory.
Add _validate_session_id() to reject anything outside [A-Za-z0-9_-]
(path separators, '..', absolute/Windows paths) before the id is used to
build a filename. Legitimate ids (uuid4 hex, 'session-<digits>-<n>') are
unaffected.
Adds SessionStorePathTraversalTests covering traversal rejection on both
load and save plus a legitimate-id round-trip.
Constraint: roadmap-next-id.sh must preserve single-id stdout on success while failing closed if duplicate validation cannot run.
Rejected: Relying only on CI/pre-push duplicate checks | the helper is used immediately before appending and must not certify an already-poisoned file.
Confidence: high
Scope-risk: narrow
Directive: Keep roadmap-next-id.sh stdout machine-clean; route validation failures and checker availability errors to stderr, and keep focused helper behavior coverage in the docs/ROADMAP CI path.
Tested: scripts/roadmap-next-id.sh ROADMAP.md printed 725 before appending #725 and 726 after; temp ROADMAP with duplicate 999 exited nonzero and listed duplicate id; scripts/roadmap-check-ids.sh ROADMAP.md; bash -n scripts/roadmap-next-id.sh scripts/roadmap-check-ids.sh; python -m unittest discover -s tests -p test_roadmap_helpers.py; python -m pytest tests/test_roadmap_helpers.py -q; SKIP_CLAW_PRE_PUSH_BUILD=1 bash .github/hooks/pre-push
Not-tested: full cargo workspace build, unchanged docs/script-only path
Add a lightweight regression for the documented local pre-push build gate so the skip hatch and lockfile-grade cargo build command stay aligned with operator docs.
Constraint: Issue #696 scope is limited to pre-push hook contract drift after ROADMAP #694.\nRejected: Reworking the hook harness or roadmap board | unnecessary for the focused drift guard.\nConfidence: high\nScope-risk: narrow\nDirective: Keep the hook docs, skip hatch, and cargo --locked command in sync when changing local push gates.\nTested: bash -n .github/hooks/pre-push; python3 tests/test_pre_push_hook_contract.py -v; git diff --check\nNot-tested: Full cargo workspace build; Rust code was not touched.
The old tracked TypeScript snapshot has been removed from the repository history and the root directory is now a Python porting workspace. README and tests now describe and verify the Python-first layout instead of treating the exposed snapshot as the active source tree.
A local archive can still exist outside Git, but the tracked repository now presents only the Python porting surface, related essay context, and OmX workflow artifacts.
Constraint: Tracked history should collapse to a single commit while excluding the archived snapshot from Git
Rejected: Keep the exposed TypeScript tree in tracked history under an archive path | user explicitly wanted only the Python porting repo state in Git
Confidence: medium
Scope-risk: broad
Reversibility: messy
Directive: Keep future tracked additions focused on the Python port itself; do not reintroduce the exposed snapshot into Git history
Tested: python3 -m unittest discover -s tests -v; python3 -m src.main summary; git diff --check
Not-tested: Behavioral parity with the original TypeScript system beyond the current Python workspace surface