github / github/spec-kit

[Feature]: Add deterministic contribution IDs and stack lookup IDs for resolved artifacts

未关闭
#4,210 11 条评论 0 个 reaction 已指派 0 人 在 GitHub 查看
enhancement feature-assess feature-go
主要语言
Python
星标
137k
派生
12.3k
平均合并
2 天 12 小时
30 天内合并 PR
159

描述

### Problem Statement

Spec Kit identifies contributed commands, templates, scripts, and hooks primarily by `name`. Names can collide across artifact kinds and source layers, and a name alone cannot reliably link a resolved artifact-stack layer to the exact manifest contribution that supplied it. Consumers such as `preset info --json`, `extension info --json`, and `specify artifact` need stable contribution identifiers and a join key that works across reinstalls and machines.

### Proposed Solution

Introduce computed, opaque `id` fields for every command, template, script, and hook returned by public preset/extension manifest and info APIs, plus a `lookupId` field on every provenance-backed non-built-in resolved artifact-stack layer.

For named preset, extension, and project-override contributions, derive IDs using:

```text
{layer}:{sourceId}:{kind}:{name}
```

Use `project`, `preset`, or `extension` for `layer`; `_` only for the project-override source ID; and the preset or extension manifest ID for manifest-declared sources. Use `command`, `template`, or `script` for `kind`. Examples include `preset:speckit.core:command:speckit.plan`, `extension:speckit.git:template:pr-body`, and `project:_:template:spec-template`.

For hooks, use `{eventName}:{command}` as the name component. Hooks are valid only for preset and extension layers. If duplicate event/command hook entries are valid, add an appropriate stable discriminator or reject duplicates; do not use array position.

Built-in artifacts do not have an originating manifest contribution and therefore do not receive a contribution `lookupId`. Every artifact, including built-ins, instead has a source-agnostic public ID of the form `{kind}:{name}`. Built-in stack rows are recognized by absent provenance fields (`layer`, `sourceId`, and `lookupId` are null), and round-trip through the public artifact ID.

Compute IDs at read, serialization, or resolution time rather than persisting them in authored or installed manifests. For manifest-declared preset and extension layers, `lookupId` must exactly match the originating contribution's `id`. Preserve existing name-based behavior and document IDs as opaque strings.

### Alternatives Considered

Install-time UUIDs are unsuitable because they differ across machines and reinstalls. Existing names are insufficient because they collide across sources and kinds. Content hashes are unsuitable because IDs would change whenever artifact content is edited. Array indexes are unsuitable for hooks because reordering entries would change their IDs.

A synthetic `core:_:...` contribution ID was considered for built-in assets. It was rejected because built-ins have no originating preset or extension manifest contribution to join to; the source-agnostic `{kind}:{name}` artifact ID provides their stable round-trip key without overloading `lookupId`.

Do not use the existing integration manifest as the ID source; it tracks installed file hashes and paths rather than manifest contribution identity.

### Component

Specify CLI (initialization, commands)

### AI Agent (if applicable)

_No response_

### Use Cases

1. A wizard can read an artifact stack and follow each provenance-backed layer's `lookupId` to the full contribution detail without re-parsing manifests.
2. Developers on different machines can use identical IDs when reporting or diagnosing a contribution.
3. Tooling can hash or cache resolved compositions using public artifact IDs plus the available layer `lookupId` values.
4. Future JSON output for `preset info`, `extension info`, and `specify artifact` can expose consistent cross-references.

### Acceptance Criteria

- [ ] Document the `layer:sourceId:kind:name` contribution grammar, the source-agnostic `kind:name` artifact ID, and the `lookupId` relationship in `extensions/EXTENSION-API-REFERENCE.md` and the preset API/manifest reference.
- [ ] Public preset/extension manifest and info representations expose computed `id` values for commands, templates, scripts, and hooks.
- [ ] Hook IDs are deterministic and collision-free without install paths or list indexes.
- [ ] Manifest-declared preset and extension artifact-stack layers expose `lookupId` equal to the corresponding contribution's `id`.
- [ ] Project-local override layers use the synthetic `project:_:{kind}:{name}` lookup form and intentionally have no manifest contribution match.
- [ ] Built-in artifact-stack layers expose no contribution provenance (`layer`, `sourceId`, and `lookupId` are null) and round-trip through the public `{kind}:{name}` artifact ID.
- [ ] Identical manifest coordinates produce identical IDs across processes, machines, project locations, and reinstalls.
- [ ] Manifest-backed IDs do not depend on artifact contents, timestamps, manifest hashes, archive paths, or installation directories.
- [ ] Existing `name` fields and name-based resolution remain unchanged.
- [ ] Tests cover each provenance-backed layer and artifact kind, hook uniqueness, resolver repeatability, manifest lookup round-trips, built-in public-ID round-trips, and backward compatibility.

### Additional Context

This request defines the ID contract only. Adding the JSON output surfaces themselves for `preset info --json`, `extension info --json`, or `specify artifact` is out of scope and will be handled separately. Changing precedence, resolution, installation, or uninstall behavior is also out of scope. Relevant implementation areas include the extension manifest schema and validation and `PresetResolver` composition handling. IDs must not expose install paths, secrets, or connection strings.

贡献指南

打开贡献指南

调研方向

先从扩展清单的 schema 和验证开始,然后跟踪 PresetResolver 对 provenance 支持的层进行组合处理的方式。阅读 extensions/EXTENSION-API-REFERENCE.md 以及 preset API/manifest 参考,并运行现有的 schema 和 resolver 测试。完成的标准是:所有列出的 artifact 类型、hooks、built-ins、overrides 和兼容性情况都覆盖确定性 ID 与 lookupId 关系。

由索引模型根据 Issue 内容生成。

评估

技术栈
python
领域
cli, documentation, testing, tooling
Issue 类型
功能
难度
5/5
预计耗时
一周以上
活跃度
活跃
描述清晰度
基本清楚
新手友好度
38/100

把新 issue 发到你的邮箱

精选适合新手参与的 GitHub issue 摘要。