Skip to content

Scope the registry to the target host's shell - #110

Merged
jonchun merged 1 commit into
mainfrom
feat/shell-scoped-registry
Aug 1, 2026
Merged

Scope the registry to the target host's shell#110
jonchun merged 1 commit into
mainfrom
feat/shell-scoped-registry

Conversation

@jonchun

@jonchun jonchun commented Aug 1, 2026

Copy link
Copy Markdown
Collaborator

Why

A Windows host accepted ls -la — it resolved to the POSIX manifest, then failed at the
OS. A Unix host accepted Get-Service the same way. Both burn exactly the turns this
guard rail exists to save, and the fuzzy suggester compounded it by proposing commands
from the wrong dialect.

The load-bearing decision

The obvious fix — filter POSIX manifests on Windows and vice versa — is wrong. It
would break docker, kubectl, aws, svn, curl, wget, python, node, and
psql on Windows hosts, all of which run fine under PowerShell. The registry is 181 POSIX
to 104 PowerShell, and the POSIX set is a mix of Unix-only and cross-platform.

So the shell field becomes three-way:

Value Meaning Examples
shell: bash Unix only ls, df, uname, systemctl
shell: powershell Windows only Get-Service, netstat, DSCheckLS.exe
absent universal docker, curl, python, aws, psql

Absent means universal, not POSIX. Only a manifest naming a different shell is filtered,
so marking is additive: an unmarked Unix-only manifest stays reachable everywhere until
someone marks it, and nothing breaks in the meantime.

Implementation

A registry filter at the entry point (ScopeRegistry), not a shell parameter threaded
through validateSegment, validateSudo, validateXargs, validateSubcommand,
lookupManifest, and closestCmdlet. Lookup and the suggester then only ever see
in-dialect manifests.

No signature churn: ValidatePipeline is unchanged, and Core.Validate keeps its type so
the eight test injection sites still compile. Execute already computed the shell three
lines above the validate call to pick the parser — it simply wasn't passing it.

Marks 47 manifests, including the systemctl_* subcommand manifests. That one was
found by testing, not reasoning: systemctl status resolves to systemctl_status, so
marking only the parent left it reachable on Windows.

An unknown shell filters nothing, so the standalone validate tool — which has no
connection and therefore no dialect — is unaffected.

Testing

TestScopeRegistryByShell asserts all three categories in both directions (12 commands ×
2 shells). TestScopeRegistryUnknownShellIsPermissive pins the no-connection case.
3DX session replay still runs 16/17 under PowerShell scoping — no regression.

Full suite passes including -race; go vet clean.

Known limit

Marking is incomplete by design. 47 of ~181 POSIX manifests are marked — the ones that
cause false-accepts today. The rest stay universal and therefore still reachable on
Windows. That is safe (nothing breaks) but not finished; the remainder can be marked as
they surface.

No real Windows host available, so this is verified against the recorded transcript and
unit tests only.

🤖 Generated with Claude Code

A Windows host accepted `ls -la`: it resolved to the POSIX manifest, then
failed at the OS. A Unix host accepted `Get-Service` the same way. Both
burn exactly the turns this guard rail exists to save, and the fuzzy
suggester compounded it by proposing commands from the wrong dialect.

The shell field becomes three-way:

  shell: bash        Unix only - ls, df, uname, systemctl
  shell: powershell  Windows only - Get-Service, netstat, DSCheckLS.exe
  absent             universal - docker, curl, python, aws, psql

Absent means universal rather than POSIX. That is the load-bearing
choice: a strict two-way filter would have broken docker, kubectl, aws,
svn, curl, wget, python, node, and psql on Windows hosts, all of which
run fine under PowerShell. Only a manifest naming a *different* shell is
filtered, so marking is additive - an unmarked Unix-only manifest stays
reachable everywhere until someone marks it, and nothing breaks meanwhile.

Implemented as a registry filter at the entry point rather than by
threading a shell parameter through validateSegment, validateSudo,
validateXargs, validateSubcommand, lookupManifest, and closestCmdlet.
lookupManifest and the suggester then only ever see in-dialect manifests,
with no signature churn: ValidatePipeline is unchanged, and Core.Validate
keeps its type so the eight test injection sites still compile.

Marks 47 manifests, including the systemctl_* subcommand manifests -
found by testing, since `systemctl status` resolves to systemctl_status
and marking only the parent left it reachable on Windows.

An unknown shell filters nothing, so the standalone validate tool, which
has no connection and therefore no dialect, is unaffected.
@jonchun
jonchun merged commit 83fe1b2 into main Aug 1, 2026
2 checks passed
@jonchun
jonchun deleted the feat/shell-scoped-registry branch August 1, 2026 14:52
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