Skip to content

PR 5: cd-attribution + subshell isolation + bash -c recursion#8

Merged
Aaronontheweb merged 1 commit into
devfrom
pr5-attribution
May 10, 2026
Merged

PR 5: cd-attribution + subshell isolation + bash -c recursion#8
Aaronontheweb merged 1 commit into
devfrom
pr5-attribution

Conversation

@Aaronontheweb

Copy link
Copy Markdown
Owner

Summary

PR 5 of the v0.1.0-alpha shipping plan. Completes SPEC §9 (cd-in-compound propagation) and §10 (subshell isolation + bash -c recursion) behaviors. Locked interpretations #4 (bash -c overflow), #5 (only cd/chdir propagate), and #6 (cd $VAR → DynamicSkip attribution) now fully materialized.

What landed

  • Internal/Bash/Parsing/CdAttributionContext.cs — parser-internal mutable context with SubshellStack of monotonic IDs (handles sibling subshells like (a) && (b) cleanly).
  • BashCommandParser updates:
  • BashResolver internal overload Resolve(raw, treatAsPath, options, workingDirectoryUnknown) — lets the propagator force DynamicSkip on relative paths under dynamic cd without changing the public BashParserOptions surface.

SPEC.md updates

Tests + corpus

  • 8 new parser tests: attribution propagation, subshell isolation, sequential cd, pushd non-propagation, dynamic cd, sibling subshells, bash -c depth-2 success, depth-6 overflow.
  • 30 new corpus entries (71-100): 10 cd-in-compound + 10 subshell + 10 bash -c.
  • 5 PR 3-4 corpus entries refreshed (25, 28, 34, 35, 52) for the new attribution shape.
  • Total: 337/337 passing. Public API surface unchanged — PublicApiSnapshotTests still 18/18 green.

Deferred to v0.1.x

  • Outer cd attribution leaking into bash -c inner clauses (v0.1: doesn't propagate; v0.1.x or v0.2 may revisit)
  • cd - jump-to-previous-dir explicit handling (currently no-op since - is detected as a flag)
  • pushd/popd directory stack semantics (interp PR 2: BashLexer + opaque-region scanner #5 option-C upgrade — issue to file)

Verification

  • dotnet build -c Release — clean (TreatWarningsAsErrors=true)
  • dotnet test -c Release — 337/337 passing
  • pwsh ./scripts/Add-FileHeaders.ps1 -Verify — all files have headers
  • openspec validate v0.1-locked-interpretations --strict — passes
  • ✅ Cross-platform: no Path.GetFullPath regressions (PR 4 fix preserved)

Test plan

  • CI passes on Test-ubuntu-latest
  • CI passes on Test-windows-latest

Next

PR 6 — corpus completeness (add ~5 more entries to hit 105+ across all SPEC §13 categories), polished AstAssert.Equal helper, PII audit [Fact] per SPEC §14, final cross-platform corpus pass. After that: PR 7 release prep + tag.

Completes the SPEC §9 + §10 behaviors deferred from earlier PRs.
Locked interpretations #4 (bash -c overflow → outer
ParsedCommand.IsUnparseable), #5 (only cd/chdir propagate; pushd/popd
parse but don't), and #6 (cd $VAR → synthetic DynamicSkip attribution
arg) now fully materialized.

What's wired:

- Internal/Bash/Parsing/CdAttributionContext.cs (parser-internal,
  mutable):
  * SubshellStack of monotonic IDs handles sibling subshells cleanly
    (depth alone doesn't distinguish (a) && (b))
  * SetLiteralAttribution / SetDynamicAttribution
  * HasAttribution flag

- BashCommandParser updates:
  * Only cd/chdir update attribution context (interp #5)
  * Subsequent clauses get synthetic IsCwdAttribution arg:
    - Literal cd target → Kind=Literal, IsPath=true, Resolved=<cwd>
    - DynamicSkip cd target → Kind=DynamicSkip, IsPath=false,
      Raw="<dynamic-cwd>" (interp #6)
  * Subshell ( ... ) entry pushes attribution stack, exit pops; clauses
    inside get IsSubshell=true; subshell mutations don't leak out
  * bash -c / sh -c real recursion (was single-clause framework in PR 3):
    inner ParsedCommand surfaced with IsBashCWrapped=true on each clause;
    outer bash -c clause consumed (not emitted)
  * Recursion depth cap at 5 → outer ParsedCommand.IsUnparseable=true
    with reason "bash -c recursion depth exceeded (>5)" (interp #4)
  * Outer cd attribution does NOT leak into bash -c inner clauses (v0.1
    decision; tracked for v0.1.x revisit)

- BashResolver internal overload Resolve(raw, treatAsPath, options,
  workingDirectoryUnknown): lets the propagator force DynamicSkip on
  relative-path args under dynamic cd (interp #6) without polluting
  the public BashParserOptions surface.

Tests:
- 8 new parser tests: attribution propagation, subshell isolation,
  sequential cd, pushd non-propagation, dynamic cd, sibling subshells,
  bash -c depth-2 success, bash -c depth-6 overflow.
- CorpusRunnerTests: added IsCwdAttribution field on ExpectedArg.
- 30 new corpus entries (71-100): 10 cd-in-compound + 10 subshell +
  10 bash -c. 5 PR 3-4 corpus entries refreshed (25, 28, 34, 35, 52).
- Total: 337/337 passing (was 296 at PR 4 baseline).

SPEC.md updated:
- §9 rule 3 explicit on which CwdVerbs propagate (only cd/chdir);
  added "Dynamic-cd attribution" subsection per interp #6
- §10 subshell flattening rephrased; bash -c recursion-limit replaced
  with "set ParsedCommand.IsUnparseable=true" per interp #4

Public API surface unchanged. PublicApiSnapshotTests still 18/18 green.
@Aaronontheweb Aaronontheweb enabled auto-merge (squash) May 10, 2026 19:21
@Aaronontheweb Aaronontheweb merged commit f4643ff into dev May 10, 2026
2 checks passed
@Aaronontheweb Aaronontheweb deleted the pr5-attribution branch May 10, 2026 19:22
@Aaronontheweb Aaronontheweb mentioned this pull request May 10, 2026
2 tasks
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.

1 participant