Skip to content

mcpx: Phase 1 of #1531 — exec identity core: a script's identity folds in its resolved directory (internal/config) #1532

Closed

Description

@dezren39

Phase 1 of design #1531 (filed by the design architect, 2026-10-27). Design doc: files/designs/code-mcpx-stdio-exec-identity.md in the keep-the-four-repos-healthy goal workspace.

Decision in force (from #1531, do not re-litigate in triage): for a hashed executable whose content begins with #!, the exec identity is its content plus the resolved directory of the real file; non-script hashed files stay content-only; files above limits.execHashMax stay stat/inode. This implements the first option named in pkgs/mcpx/TODO.md item 4 and the planning/roadmaps/mcpx.md row "Decide what a stdio server's identity is" (proposed).

Scope

  • ExecStamp.Identity() in pkgs/mcpx/internal/config/execid.go (currently lines 114–130) is the single identity implementation — callers are Resolved.ExecState() (execid.go:56), pool construction (internal/pool/pool.go:199) and the exec watch (internal/pool/execwatch.go:84). Keep it single: no second implementation in internal/pool or elsewhere.
  • While the hashed branch streams the file (it is already read whole), note whether its first two bytes are #!. For a script, fold filepath.Dir(s.Path) — s.Path is already the EvalSymlinks-resolved real path (execid.go:94–99) — into the hash under a distinct framing (marker + separators, so no (content, directory) pair can alias another pair's hash input; exact framing is this issue's to settle). The identity string keeps the sha256:<16 hex> form.
  • Non-script hash input must stay byte-for-byte today's, so existing binary identities do not move on rollout. The stat branch, the missing: form, and non-stdio servers are untouched.
  • The execid.go header comment: replace the caveat paragraph ("a program that finds its own files relative to its real location is not [identified]… A restart (mcpx restart) is what moves it") with the new rule, including the one-time identity change for script servers on rollout (recorded handoff identities mismatch → script pools restart once at upgrade/first check, the existing binary-changed path).

Acceptance

  • Defining tests in pkgs/mcpx/internal/config/execid_test.go:
    • identical script bytes in two different directories → different identities;
    • identical script bytes at two names in one directory → same identity;
    • identical non-script bytes in two different directories → same identity (today's rule preserved);
    • a script and a non-script with identical bytes → different identities;
    • framing non-alias: pairs whose content/directory splits differ do not trivially collide;
    • large-file stat identity unchanged (existing TestExecIdentityOfALargeFileIsItsInode keeps passing).
  • TestExecIdentityFollowsTheExecutableNotTheCommandName (execid_test.go:25) pins a #!/bin/sh script's identity to its bare content hash — the design knowingly changes this one expectation to the framed script hash; update it and say so in the PR. The same-directory identical-copy tests (TestExecIdentityOfASmallFileIsItsContentNotItsPath) must pass unmodified in behaviour — if one fails, the implementation is folding in more than the directory (e.g. the full path), which the design rejects.
  • No changes needed in internal/pool, internal/daemon, handoff, or lifecycle code in this phase; Identity() staying platform-independent (the unix/other split is only fileInode) is confirmed, or any build-tag surprise is reported on this issue.
  • Verification via CI per fleet policy: cd pkgs/mcpx && go test ./internal/config/....

Out of scope: daemon-level reload/watch tests and the TODO/roadmap closure (Phase 2, gated on this phase); interpreter-as-command servers; sibling-loading native binaries (both are open questions on #1531).

Acceptance criteria

  • ExecStamp.Identity() folds the resolved directory into the hash for #! scripts only, under a framed (marker + separators) input that cannot alias another (content, directory) pair; non-script hashed input stays byte-for-byte today's.
  • Defining tests in pkgs/mcpx/internal/config/execid_test.go pass: cross-directory identical script → different identity; same-directory identical script → same identity; cross-directory identical non-script → same identity; script vs non-script with identical bytes → different identities; large-file stat identity unchanged.
  • TestExecIdentityFollowsTheExecutableNotTheCommandName is updated to the framed script hash and the PR says so explicitly; the same-directory identical-copy tests pass unmodified in behaviour.
  • The execid.go header caveat is replaced with the new rule, including the one-time identity change / single restart for script servers on rollout.
  • No changes in internal/pool, internal/daemon, handoff, or lifecycle code; CI green on the PR (fleet CI-first policy).

Activity

  1. added
    kind/featureNew feature or capability request
    task/triageQueue packet kind: verify, reproduce, and route this item
    priority/normalOrdinary priority (the default)
    on Oct 28, 2026
  2. developing-today commented on Oct 28, 2026

    @developing-today
    Contributor
  3. added
    queue/queuedHas a queued task in the Supabase agent queue
    app/mcpxPackage/app: mcpx (pkgs/ or apps/ in this repo)
    effort/mMedium: expected under 1 day of work
    on Oct 28, 2026
  4. dezren39 commented on Oct 28, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · filed

  5. added
    meta/enrichedIntake review done: acceptance criteria, links, and normalized labels added
    on Oct 28, 2026
  6. dezren39 commented on Oct 28, 2026

    @dezren39
    MemberAuthor

    Intake review

    Fleet-monitor intake pass (2026-10-28): verified still live — the design #1531 was filed today and this Phase 1 sub-issue is queued (queue/queued); no merged PR implements directory folding in ExecStamp.Identity() yet.

  7. dezren39 commented on Oct 28, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · picked up

  8. 30 remaining items

  9. added
    status/parkedDeliberately paused with a recorded resume condition
    queue/claimedQueue worker lifecycle state
    and removed
    status/parkedDeliberately paused with a recorded resume condition
    queue/parkedQueue task is parked (waiting on CI, time, or an event)
    on Oct 28, 2026
  10. dezren39 commented on Oct 28, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · state: picked-up

  11. added a commit that references this issue on Oct 28, 2026
  12. dezren39 commented on Oct 28, 2026

    @dezren39
    MemberAuthor

    🤖 Agent note · state: done

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

app/mcpxPackage/app: mcpx (pkgs/ or apps/ in this repo)effort/mMedium: expected under 1 day of workkind/featureNew feature or capability requestmeta/enrichedIntake review done: acceptance criteria, links, and normalized labels addedpriority/normalOrdinary priority (the default)source/design-architectFiled by the repo design architect jobstatus:donetask/triageQueue packet kind: verify, reproduce, and route this item

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions