Skip to content

Make @executablemd/git/api names describe Git and Repository operations #835

Description

@taras

Story

As a Plugin or trusted-host author, I want @executablemd/git/api names to describe the Git and Repository operations they provide, so I can call or replace a contextual API without translating package-internal layer names or Git CLI implementation terms.

Example

The public surface reads in the same vocabulary as the components and values it supports:

import { Git, GitQuery, Repository } from "@executablemd/git/api";

const selected = yield* Repository.operations.select(request);
const committed = yield* Git.operations.commit(invocation);
const root = yield* GitQuery.operations.root();

Git.operations.commit(...) is the provider operation behind <Git.Commit>. GitQuery separately answers read-only questions about the repository containing the contextual working directory.

Current gap

#834 established /api as the sole public route to Git's contextual APIs, but those APIs retain names from their former implementation layers:

RepositoryComposition.operations.selectRepository(...)
RepositoryComposition.operations.selectWorktree(...)
RepositoryComposition.operations.repository()

GitComposition.operations.switchBranch(...)
GitComposition.operations.addPaths(...)
GitComposition.operations.commitIndex(...)
GitComposition.operations.pushCurrentBranch(...)

Git.operations.revParse(...)
Git.operations.repositoryRoot()
Git.operations.objectFormat()
Git.operations.readObject(...)

Composition describes an internal layer rather than the answer a consumer receives. The two Git APIs also compete for the name Git: the read-only query capability has it, while the durable operations corresponding to <Git.*> components are called GitComposition.

Their contextual identity strings still name their former workflow owner and, in two cases, the composition layer. These identities were published by @executablemd/workflow@0.12.1; changing them is therefore an intentional compatibility break, not a mechanical rename.

Public contract

Repository selection

export interface RepositoryApi {
  select(request: RepositoryRequest): Operation<RepositorySelection>;
  worktree(
    repository: RepositorySelection,
    request: WorktreeRequest,
  ): Operation<RepositorySelection>;
  ambient(): Operation<RepositorySelection | undefined>;
}

export const Repository = createApi<RepositoryApi>(
  "executablemd.git.repository",
  // existing provider behavior
);

select answers the authored <Repository>, worktree answers its named linked checkout, and ambient asks for the host-provided Repository used outside a lexical <Repository>.

The lexical Repository API keeps its public names and receives its new identity:

RepositoryContext.operations.current
currentRepository()
// identity: executablemd.git.repository.current

Durable Git operations

export interface GitApi {
  switch(invocation: GitSwitchInvocation): Operation<GitSwitchResult>;
  add(invocation: GitAddInvocation): Operation<GitAddResult>;
  commit(invocation: GitCommitInvocation): Operation<GitCommitResult>;
  push(invocation: GitPushInvocation): Operation<GitPushOutcome>;
}

export const Git = createApi<GitApi>(
  "executablemd.git",
  // existing provider behavior
);

The operations correspond directly to <Git.Switch>, <Git.Add>, <Git.Commit>, and <Git.Push>.

Read-only Git queries

export interface GitQueryApi {
  resolve(revision: string): Operation<string>;
  root(): Operation<string>;
  format(): Operation<GitObjectFormat>;
  read(commit: string, path: string): Operation<string>;
}

export const GitQuery = createApi<GitQueryApi>(
  "executablemd.git.query",
  // existing working implementation
);

The direct operation aliases are:

resolveGitRevision
gitRoot
gitObjectFormat
readGitObject

GitQuery stays separate from Git. Its operations work by default and only inspect the contextual checkout; Git performs authored transitions through an installed repository provider and refuses when none is installed.

Neighboring API identities

The remaining contextual APIs keep their TypeScript names and operations while moving from the former Workflow namespace to their Git-package identities:

API Identity
PullRequestAPI executablemd.git.pull-request
IssueApi executablemd.git.issue
IssueTrackerContext executablemd.git.issue-tracker.current
GitHost executablemd.git.host

Compatibility boundary

The old TypeScript names, operation names, and contextual identity strings receive no aliases, dual handlers, or compatibility bridge. A provider built against the released @executablemd/workflow@0.12.1 identities no longer intercepts these APIs. This break is explicit and must be visible in regression evidence rather than hidden behind a fallback.

This source and contextual-identity break does not change executable-document syntax or durable behavior. Existing component names, forms, invocation and result records, normalized failures, effect identities, journal bytes, database rows, and completed replay behavior remain unchanged.

Acceptance

  • @executablemd/git/api publishes Repository, RepositoryApi, Git, GitApi, GitQuery, and GitQueryApi with exactly the operations and direct aliases above.
  • The old RepositoryComposition, RepositoryCompositionApi, GitComposition, GitCompositionApi, revParse, and repositoryRoot exports and their old operation names are absent.
  • Each contextual API uses its exact accepted executablemd.git* identity; none uses an executablemd.workflow* identity or contains .composition..
  • Separately loaded copies using the new identities compose in both directions. A negative control using an old identity does not intercept a new operation.
  • A consumer can replace Repository, Git, or GitQuery and observe ordinary-run and workflow calls reaching that replacement. Renaming only the exports while leaving a host provider on an old identity fails this evidence.
  • A document using <Repository>, <Worktree>, and all four <Git.*> components succeeds in an ordinary run and a workflow with the same normalized results and durable records as before.
  • Replaying completed Git effects performs no Git operation.
  • In a checkout, GitQuery resolves a revision, reports the root and object format, and reads a committed path. A lexical replacement can answer all four without invoking Git. The default provider retains the existing refusal outside a checkout.
  • Deno, Node, and Bun consumers resolve the new API values and types through @executablemd/git/api. The emitted npm package has the same names and identities, and a compiled XMD run executes the unchanged component vocabulary.
  • architecture.md and the Git package/API documentation state the accepted names, ownership, identity break, and separation between durable Git operations and read-only Git queries.

Evidence

Extend the portable packages/git/tests/api-entrypoint.test.ts contract and run it under Deno, Node, and Bun. Its positive path imports every new value and interface through the package export map; its negative path proves the old names are absent from both source and emitted npm surfaces.

Exercise physical loaded-copy composition under every new identity and an old-identity negative control. Run the existing Repository/Git ordinary-run, workflow durability, replay, package-partition, npm-package, and compiled-XMD integration targets that cross these renamed boundaries. deno task check must cover the complete call-site migration, including packages/git/src/deno/composition/provider.ts, whose contents may be skipped by text tools that treat it as binary.

Dependency

#834 delivered the /api boundary and is merged. This Story begins from that delivered surface.

Out of scope

  • Changing executable component names or forms.
  • Merging Git and GitQuery into one API.
  • Changing invocation types, normalized results, failures, durable effect identities, records, journals, database formats, or replay semantics.
  • Adding another Git host, GitHub package, or Plugin.
  • Renaming unrelated internal helpers merely because they still describe an implementation layer.

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    cleanupAuto-generated cleanup finding from repo analysis

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions