feat(v3.13.1-p1): resolve_workspace_dir normalizer + load_workspace_json fallback#178
Merged
feat(v3.13.1-p1): resolve_workspace_dir normalizer + load_workspace_json fallback#178
Conversation
…son fallback External AI UX review + Codex plan-time REVISE absorb. The CLI `--workspace-root X` option was asymmetric: - `workspace_root(override=X)` returned X as-is (expected X to be the `.ao/` dir) - `load_workspace_json(X)` expected workspace.json directly under X - Result: `doctor --workspace-root .` FAILed (`./workspace.json` absent) while `doctor --workspace-root .ao` passed v3.13.1 P1 (non-breaking Option B): new public helper `ao_kernel.config.resolve_workspace_dir(path)` that tolerates both conventions. - Accepts **project root** (walks into `.ao/`). - Accepts **workspace dir directly** (`.ao/` itself; legacy). - Returns input unchanged if neither — downstream caller fails closed with the user-supplied path in the error message. `load_workspace_json()` now calls the helper first, so doctor + migrate + workspace.load_config + MCP ao_workspace_status all benefit without explicit rewiring. +10 pins in tests/test_resolve_workspace_dir_v3131_p1.py covering: - Project root with `.ao/` resolves to `.ao/` - `.ao/` dir passthrough - Neither-shape fail-closed - String input accepted - Edge case: direct workspace.json takes precedence over `.ao/` - Integration: load_workspace_json(project_root) works post-fix - Back-compat: load_workspace_json(`.ao/`) still works - Malformed JSON still fails closed - End-to-end: doctor_cmd._check_workspace_json(project_root) OK Verified manually: `doctor --workspace-root .` returns 8/8 OK after `init` (previously 7/1 FAIL on workspace.json valid). Coverage gate holds at 86.10% (was 85.8% pre-P1). Follow-up note for v3.14+: `init_cmd.run(override)` has the WRITE side of the same asymmetry (writes directly under override, not in `override/.ao/`). Not fixed here because P1 is read-side non-breaking; the write-side change would be a contract break for operators who intentionally pass `.ao` dir as override. Deferred with the `system-status` alias question and the demo_bugfix.py cwd workaround. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
📊 Benchmark Scorecard
Baseline: |
Codex post-impl BLOCKER absorb: after P1 load_workspace_json was path-tolerant but migrate's mutation/backup/report paths still used the un-normalized `ws`, so: - `migrate --workspace-root <project_root>` reads .ao/workspace.json (via the P1 helper) but plans/writes a stray workspace.json at the project root and stashes .backup/ there too. Fix: - migrate_cmd.py: resolve ws via resolve_workspace_dir() once, then use `resolved_ws` for mutation file path, report.workspace_path, backup_dir, and legacy comparison. - New resolve_workspace_dir import in migrate_cmd. +2 pins in tests/test_resolve_workspace_dir_v3131_p1.py: - TestMigrateIntegration.test_dry_run_mutation_file_targets_resolved_ao_dir: dry-run report shows mutation file under .ao/, workspace_path ends with /.ao - TestMigrateIntegration.test_non_dry_run_writes_to_ao_workspace_json_and_backup_under_ao: actual mutation updates .ao/workspace.json, project root stays clean, backup path lives under .ao/.backup/ Also hardened the doctor integration pin (Codex iter-1 feedback) to call the real `doctor_cmd._check_workspace_json()` rather than re-testing load_workspace_json. Local: 2762 passed, coverage 86.10%. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
ao_kernel.config.resolve_workspace_dir(path)— tolerant normalization between project root and.ao/workspace dirload_workspace_json()now uses the helper first, so doctor + migrate + workspace.load_config + MCPao_workspace_statusbenefit transparentlytests/test_resolve_workspace_dir_v3131_p1.pyWhy (external AI + Codex REVISE absorb)
Before P1:
workspace_root(override=X)returned X as-is (assumed X was.ao/)load_workspace_json(X)expectedX/workspace.jsondoctor --workspace-root .FAILED because./workspace.jsonis absent (.ao/workspace.jsonis where it really lives)doctor --workspace-root .aopassedAfter P1:
doctor --workspace-root .anddoctor --workspace-root .aowork (8/8 OK verified manually).ao/directly keep workingworkspace_root()orinit_cmd.run()contractsDeferred (follow-up notes)
init_cmd.run(override)WRITE-side same asymmetry (writes under override, notoverride/.ao/). Fixing would break operators who intentionally pass.aoas override; needs Codex consultation + migration note. Deferred to v3.14+.system-statusCLI alias — Codex rejected (name collision withtool_registrykavramı). Docs-only fix already shipped in PR-D1 (docs(v3.13.1-d1): README + CLAUDE.md + examples drift fix #177).Test plan
doctor --workspace-root .→ 8/8 OK🤖 Generated with Claude Code