Skip to content

fix(deps): preserve local identity display boundaries#2174

Merged
danielmeppiel merged 1 commit into
mainfrom
danielmeppiel-fix-v0250-deps-display-sanitization
Jul 12, 2026
Merged

fix(deps): preserve local identity display boundaries#2174
danielmeppiel merged 1 commit into
mainfrom
danielmeppiel-fix-v0250-deps-display-sanitization

Conversation

@danielmeppiel

Copy link
Copy Markdown
Collaborator

fix(deps): preserve local identity display boundaries

TL;DR

This follow-up closes two display edge cases found after #2173 merged: Windows absolute local paths parsed on a POSIX host could still reach deps tree, and a declared remote identity shaped like a local hash slot could be shortened incorrectly. The patch derives absolute-local labels from the declared path's cross-platform basename and limits hash redaction to confirmed orphan slots.

Important

This is a narrow release-recovery follow-up on top of merged PR #2173; it does not change local dependency storage, resolution, or lockfile identity.

Problem (WHY)

  • A real DependencyReference.parse(r"C:\Users\alice\pkg") to LockedDependency flow rendered _local/C:\Users\alice\pkg@latest on POSIX instead of _local/pkg@latest.
  • _logical_local_display() ran before orphan status was known, so a declared remote identity such as _local/abcdef123456/pkg was displayed as _local/pkg.
  • [!] Both cases sit on user-visible apm deps list/tree output added in fix(deps): render logical local dep keys in deps list/tree; refresh stale v0.25.0 release tests #2173, so they must preserve logical identity without exposing host-specific paths.

The two regression tests were added first and failed with the exact outputs above. That keeps the follow-up grounded in "deterministic tool execution transforms probabilistic generation into verifiable action".

Approach (WHAT)

# Fix
1 For absolute local paths, derive _local/<basename> with PureWindowsPath or PurePosixPath; keep relative paths and missing-path fallbacks unchanged.
2 Determine orphan status from the raw logical identity before display redaction.
3 Strip _local/<12-hex>/ only for confirmed unmapped orphan slots; preserve declared remote identities byte-for-byte.
4 Lock both boundaries with real parser, lockfile, and filesystem regression cases.

Implementation (HOW)

  • src/apm_cli/commands/deps/cli.py - adds a small absolute-local display helper and moves the orphan predicate ahead of display-name selection. Physical identity remains the authority for orphan detection; only the rendered orphan label is sanitized.
  • tests/unit/commands/test_deps_cli_helpers.py - adds a parser-to-lock-to-display Windows regression and a real lockfile/filesystem case proving that a declared remote hash-shaped identity is neither orphaned nor shortened.

Diagrams

Legend: the dashed nodes are the two rendering decisions introduced by this follow-up; storage and lockfile identity stay unchanged.

flowchart LR
    subgraph Inputs[Inputs]
        L[Locked dependency]
        S[Scanned package identity]
    end
    subgraph Decide[Decide]
        A{Absolute local path}
        O{Confirmed orphan}
    end
    subgraph Render[Render]
        B["_local/basename"]:::new
        K[Declared logical identity]
        H["Hash-free orphan name"]:::new
    end
    L --> A
    A -->|yes| B
    A -->|no| K
    S --> O
    O -->|yes| H
    O -->|no| K
    classDef new stroke-dasharray: 5 5;
Loading

Trade-offs

  • Sanitize at the display boundary. Chose a narrow renderer fix; rejected a release-blocking parser/install-path refactor because storage and resolution are already correct for supported host-native paths.
  • Gate redaction on orphan status. Chose identity-preserving conditional redaction; rejected unconditional shape-based rewriting because a valid declared remote name can match the physical-slot pattern.

Benefits

  1. A Windows absolute local declaration renders one portable label, _local/pkg, on POSIX and Windows hosts.
  2. A declared remote identity matching _local/<12-hex>/pkg retains all three path segments and remains non-orphaned.
  3. Existing true orphan slots still render without their physical 12-character hash.

Validation

uv run --extra dev pytest -q tests/unit/commands/test_deps_cli_helpers.py:

.........................                                                [100%]
25 passed in 0.61s

APM_RUN_INTEGRATION_TESTS=1 APM_E2E_TESTS=1 uv run --extra dev pytest -q tests/integration/test_transitive_chain_e2e.py:

....                                                                     [100%]
4 passed in 4.95s
Broader command and lint evidence

uv run --extra dev pytest -q tests/unit/commands -k deps:

........................................................................ [ 41%]
........................................................................ [ 83%]
.............................                                            [100%]
173 passed, 938 deselected in 2.14s

CI lint mirror:

All checks passed!
1468 files already formatted
Your code has been rated at 10.00/10
[+] auth-signal lint clean
[+] architecture boundary lint clean

Scenario Evidence

# Scenario (user promise) Principle(s) Test(s) proving it Type
1 apm deps tree never prints a Windows host path when a local dependency was parsed on POSIX Secure by default, DevX tests/unit/commands/test_deps_cli_helpers.py::TestDepDisplayNameLocal::test_parsed_windows_absolute_path_renders_cross_platform_logical_name (regression trap for #2173 follow-up) unit
2 A declared remote package whose name resembles a local hash slot keeps its full identity and is not marked orphaned Governed by policy, Vendor-neutral tests/unit/commands/test_deps_cli_helpers.py::TestResolveScopeDepsOrphanHashSlot::test_declared_remote_hash_shaped_identity_is_not_redacted (regression trap for #2173 follow-up) unit
3 Transitive local dependencies still use logical names while physical parent-scoped slots remain collision-safe DevX, Governed by policy tests/integration/test_transitive_chain_e2e.py::test_deps_commands_follow_full_lock_graph_and_ignore_embedded_manifests integration

How to test

  • Run the helper test file; expect 25 passing tests.
  • Run the transitive-chain integration file with both E2E environment flags; expect 4 passing tests.
  • Inspect apm deps list and apm deps tree for a transitive local chain; expect no local:/, absolute host path, or _local/<12-hex>/ orphan hash in user-facing output.

Co-authored-by: Copilot 223556219+Copilot@users.noreply.github.com

Derive absolute local dependency labels from cross-platform basenames and redact physical hash slots only after confirming they are orphaned.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 425fcf34-8659-4f23-a91e-a5a590208239
Copilot AI review requested due to automatic review settings July 12, 2026 12:37
@danielmeppiel

Copy link
Copy Markdown
Collaborator Author

Docs sync advisory

Verdict: no_change * Pages affected: 0 * LLM calls: 1/15 * Took: 2s

No documentation impact detected. The PR changes only internal rendering of existing apm deps list/tree identities and adds regression coverage; it introduces no command, flag, schema, workflow, or documented behavior.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR tightens the user-facing apm deps list/tree display boundary for local and local-looking identities by (1) rendering absolute local paths as a portable _local/<basename> label even when parsed cross-platform, and (2) only applying _local/<12hex>/... hash-slot redaction when a package is actually confirmed orphaned.

Changes:

  • Add _absolute_local_display() and use it in _dep_display_name() so absolute local paths (POSIX, ~, Windows drive/UNC) display as _local/<basename> rather than leaking host-specific path structure.
  • Reorder orphan detection in _resolve_scope_deps() so hash-slot redaction is applied only after orphan status is determined.
  • Add regression tests covering Windows absolute local parsing on non-Windows hosts and ensuring a declared “remote” identity shaped like a hash slot is not shortened.
Show a summary per file
File Description
src/apm_cli/commands/deps/cli.py Adds portable absolute-local display helper and gates hash-slot redaction on confirmed orphan status.
tests/unit/commands/test_deps_cli_helpers.py Adds unit regression tests for cross-platform Windows absolute path rendering and non-redaction of declared hash-shaped identities.

Review details

  • Files reviewed: 2/2 changed files
  • Comments generated: 0
  • Review effort level: Low

@danielmeppiel danielmeppiel merged commit d73e6ac into main Jul 12, 2026
15 checks passed
@danielmeppiel danielmeppiel deleted the danielmeppiel-fix-v0250-deps-display-sanitization branch July 12, 2026 12:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants