-
Notifications
You must be signed in to change notification settings - Fork 0
Provider Architecture
SpecGit's evidence model rests on two seams: git facts come exclusively from local git; forge evidence flows exclusively through authenticated CLIs (gh for GitHub, glab for declared GitLab). No direct REST clients, no stored or logged tokens.
Local git facts plus the delivery-bootstrap write operations. Production implementation: LocalGitAdapter (src/gitfacts/local.ts).
| Member | Role |
|---|---|
facts |
Read side: repo, toplevel, branch, HEAD sha, dirty state, worktree layout, origin URL, upstream drift. Feeds the context and drift gates |
headContains |
Ancestor-or-equal containment of a full hex SHA in HEAD history (merged-delivery lineage); non-hex anchors fail closed |
checkoutOrCreateBranch |
Bootstrap: check out the delivery branch, creating it from HEAD when absent |
commitFile |
Bootstrap: pathspec-limited commit of one state file (idempotent) |
pushBranch |
Bootstrap: git push -u of the delivery branch |
remoteDefaultBranch |
origin/HEAD for the PR base (main fallback) |
hooksPath |
The hooks directory git actually uses (worktree and core.hooksPath aware) |
Platform-neutral forge evidence and mutations, composed of two surfaces:
-
ForgeReadPort— evidence collection and delivery-lifecycle operations:preflight,getIssue,getOpenIssueNumbers,getOpenIssues,getPr,getCheckRuns,createIssue,createDraftPr,listOpenPrsByHead,addIssueComment -
ForgeAdminPort— branch-protection and auto-merge administration:getBranchProtection,enableBranchProtection,getRepoAutomerge,enableRepoAutomerge
Every member is required: each feeds a gate or bootstrap decision, and each returns an Evidence envelope so a runtime failure is classified evidence that fails closed — never a silent skip.
| Adapter | File | Platform |
|---|---|---|
GhCliGitHubProvider |
src/providers/github/gh-cli.ts |
GitHub.com — spawns the authenticated gh CLI |
GlabProvider |
src/providers/gitlab/glab-cli.ts |
Self-managed GitLab — spawns the authenticated glab CLI; failure taxonomy mirrors gh per platform (glab_missing, glab_unauthenticated, glab_transport, plus gitlab_version_unsupported) |
Both adapters share the CLI transport at src/providers/cli-spawn.ts.
The production composition wires one PlatformRoutingProvider that dispatches per call on the ref's platform marker:
- a GitHub ref's issues, PRs, and check runs flow through
gh - a GitLab-declared origin's issues, MRs, and pipeline jobs flow through
glab
The platform is declared, never guessed: specgit init --gitlab-host <hostname> persists the declaration in spec_git/providers.yaml (committed, shared by the team). A github.com origin defaults to GitHub. An undeclared non-github origin fails closed (gitlab_unsupported / origin_unresolvable with a platform_undecided warning). The invariant: no gh call ever sees a group/subgroup ref.
Member inventories (GIT_PORT_MEMBERS, FORGE_PROVIDER_MEMBERS, plus the surface inventories) are compile-checked against the ports and pinned by the contract test — changing a port forces the same delivery to update every in-tree implementation, the inventories, and the docs. One delivery never spans platforms.
SpecGit 的证据模型建立在两条边界上:git 事实只来自本地 git;forge 证据只通过已认证的 CLI 获取(GitHub 用 gh,声明的 GitLab 用 glab)。没有直接 REST 客户端,不存储、不记录任何 token。
本地 git 事实与交付引导的写操作。生产实现:LocalGitAdapter(src/gitfacts/local.ts)。
| 成员 | 作用 |
|---|---|
facts |
读侧:仓库、根目录、分支、HEAD sha、脏状态、worktree 布局、origin URL、上游漂移。供上下文与漂移门禁使用 |
headContains |
HEAD 历史中完整十六进制 SHA 的祖先包含判断(已合并交付的血缘);非十六进制锚点 fail-closed |
checkoutOrCreateBranch |
引导:检出交付分支,不存在时从 HEAD 创建 |
commitFile |
引导:按 pathspec 限定提交单个状态文件(幂等) |
pushBranch |
引导:git push -u 推送交付分支 |
remoteDefaultBranch |
PR base 用的 origin/HEAD(回退 main) |
hooksPath |
git 实际使用的 hooks 目录(兼容 worktree 和 core.hooksPath) |
平台中立的 forge 证据与变更,由两个面组合而成:
-
ForgeReadPort—— 证据收集与交付生命周期操作:preflight、getIssue、getOpenIssueNumbers、getOpenIssues、getPr、getCheckRuns、createIssue、createDraftPr、listOpenPrsByHead、addIssueComment -
ForgeAdminPort—— 分支保护与自动合并管理:getBranchProtection、enableBranchProtection、getRepoAutomerge、enableRepoAutomerge
所有成员都是必需的:每个成员都服务于某个门禁或引导决策,且都返回 Evidence 信封,因此运行时失败会被归类为证据并 fail-closed —— 绝不静默跳过。
| 适配器 | 文件 | 平台 |
|---|---|---|
GhCliGitHubProvider |
src/providers/github/gh-cli.ts |
GitHub.com —— 调用已认证的 gh CLI |
GlabProvider |
src/providers/gitlab/glab-cli.ts |
自建 GitLab —— 调用已认证的 glab CLI;失败分类按平台镜像 gh(glab_missing、glab_unauthenticated、glab_transport,另有 gitlab_version_unsupported) |
两个适配器共用 src/providers/cli-spawn.ts 的 CLI 传输层。
生产环境组装唯一的 PlatformRoutingProvider,它按调用的 ref 的平台标记分发:
- GitHub ref 的 issues、PR、check runs 走
gh - 声明为 GitLab 的 origin,其 issues、MR、pipeline jobs 走
glab
平台是声明出来的,不是猜出来的:specgit init --gitlab-host <hostname> 把声明持久化到 spec_git/providers.yaml(提交到仓库,团队共享)。github.com origin 默认 GitHub。未声明的非 github origin 会 fail-closed(gitlab_unsupported / origin_unresolvable,附 platform_undecided 警告)。不变式:gh 永远不会看到 group/subgroup 形式的 ref。
成员清单(GIT_PORT_MEMBERS、FORGE_PROVIDER_MEMBERS 及各面清单)与端口做编译期校验,并由契约测试钉死 —— 改动端口必须在同一次交付中更新所有树内实现、清单和文档。一次交付永不跨平台。