diff --git a/docs/adr/0002-directory-project-targets.md b/docs/adr/0002-directory-project-targets.md new file mode 100644 index 0000000..4d10c4c --- /dev/null +++ b/docs/adr/0002-directory-project-targets.md @@ -0,0 +1,86 @@ +# ADR 0002: Provider-Owned Directory Project Targets + +- Status: Accepted +- Decision date: 2026-09-12 (UTC) +- Backfilled: 2026-09-14 (UTC) +- Scope: LPP 1.2 and later entry-based `lpp/check` and `lpp/compile` requests + +## Context + +ADR 0001 gave the provider ownership of project discovery when the client +selects a source-file entry. That contract still required Wright to select a +file before it could ask the provider to load a project. A user may instead +select a project directory, while the source-language implementation already +owns the rules for finding its effective entry, project root, and source +closure. + +The directory-target need was accepted in [PR #32](https://github.com/wrightkit/language-provider-protocol/pull/32) +as the protocol-side dependency for [wrightkit/wright#317](https://github.com/wrightkit/wright/issues/317). + +## Decision + +LPP 1.2 extends the provider-owned `ProjectEntry` envelope with an optional +`kind` field. A client that selects a directory sends `kind: "directory"` and +the directory's absolute `file` URI. The provider selects the effective entry, +project root, and source closure according to the source language's rules. + +The client MUST NOT enumerate the directory, parse a project manifest, or +select an entry file to reproduce that behavior. The provider MUST return +canonical source URIs for loaded documents and MUST report a structured +`projectLoadFailed` error rather than a partial result when the directory or +language-owned default entry cannot be loaded. An omitted `kind` retains the +LPP 1.1 file-entry behavior; a directory target in an LPP 1.1 session is +rejected as `invalidEntry`. + +This extends the target envelope from ADR 0001 without changing its ownership +decision: source-language repositories remain authoritative for project +discovery, and LPP carries only the selected filesystem target and the +result/error contract. + +The normative contract and conformance evidence are defined by +[specification sections 6.10, 7.3, 7.4, 8.1, 8.2, and 19](../../spec/lpp-v1.md) +and [fixtures 40–42](../../conformance/fixtures/v1/). + +## Consequences + +- Wright can pass a selected directory without implementing source-language + discovery rules. +- Providers can choose a language-appropriate default entry and source closure + while preserving the same `check` and `compile` result shapes. +- Directory selection is an additive LPP 1.2 protocol revision; LPP 1.1 + file-entry behavior remains wire-compatible and has an explicit version + gate. +- Providers need filesystem access and must define the relevant directory + loading behavior in their source-language implementation. +- The protocol still does not define workspace synchronization, unsaved editor + overlays, package dependencies, or language-specific discovery rules. + +## Alternatives considered + +### Client-enumerated directory closure + +Rejected because it would move project discovery into Wright and duplicate the +source-language rules that ADR 0001 deliberately assigns to providers. + +### A separate directory-loading method + +Rejected because a directory is another provider-owned project target for the +existing `check` and `compile` operations, not a distinct operation with a new +result model. + +### Treat every target as a file + +Rejected because it would require the client to guess a default entry and would +make directory selection language-specific client policy. + +## Historical evidence + +- [PR #32](https://github.com/wrightkit/language-provider-protocol/pull/32) + defines the directory-target goal, compatibility boundary, and ownership. +- [PR #32](https://github.com/wrightkit/language-provider-protocol/pull/32) + merged the implementation as commit + [`80a8023`](https://github.com/wrightkit/language-provider-protocol/commit/80a80235e4f58d6265abf5c8837198a96b0d21d4), + including the LPP 1.2 specification and directory-target conformance + fixtures. +- This decision extends [ADR 0001](0001-provider-owned-project-loading.md), + which remains the historical record for file-entry project loading. diff --git a/docs/adr/0003-owner-selected-source-identity.md b/docs/adr/0003-owner-selected-source-identity.md new file mode 100644 index 0000000..15f4719 --- /dev/null +++ b/docs/adr/0003-owner-selected-source-identity.md @@ -0,0 +1,94 @@ +# ADR 0003: Owner-Selected Source Identity for Entry Compilation + +- Status: Accepted +- Decision date: 2026-09-13 (UTC) +- Backfilled: 2026-09-14 (UTC) +- Scope: LPP 1.3 entry-based `lpp/compile` results + +## Context + +ADR 0002 lets a client select a directory while the provider chooses the +effective source entry. A client can therefore request compilation without +knowing which source file the provider selected. The entry `version` identifies +the client's filesystem snapshot, but it is not a content hash, and the opaque +artifact does not expose source identity. Reconstructing an identity in Wright +would either require duplicating provider selection or hashing a source the +client did not select. + +The source-identity need was accepted in [PR #34](https://github.com/wrightkit/language-provider-protocol/pull/34) +as the protocol-side dependency for preserving source identity in +[wrightkit/wright#317](https://github.com/wrightkit/wright/issues/317). + +## Decision + +LPP 1.3 adds an independently negotiated `sourceIdentity` capability for +`lpp/compile`. When a provider advertises `sourceIdentity: true`, an +entry-based compile result MUST include `sourceIdentity`: a lower-case +SHA-256 hexadecimal digest of the provider-selected primary source text. +The provider owns effective entry selection, including for directory targets. + +A client that requires this identity MUST request protocol version `1.3` and +require the capability during initialization. Providers may advertise the +capability as false and still support entry-based compilation; in that case +the field is omitted. LPP 1.1 and 1.2 compile results MUST NOT include the +field, preserving their released wire contracts. Document-supplied compile +requests may omit the field. + +The identity is a deterministic digest of the selected primary source text. It +does not identify the complete source closure, attest semantic equivalence, or +replace the provider's source-loading and entry-selection responsibilities. + +The normative contract and conformance evidence are defined by +[specification sections 6.10, 7.3, 7.4, 8.2, 10, and 19](../../spec/lpp-v1.md) +and [fixtures 43–44](../../conformance/fixtures/v1/). + +## Consequences + +- Wright can preserve the identity of a provider-selected source without + reproducing directory discovery or reading a guessed entry file. +- Providers that can provide the digest expose it through explicit LPP 1.3 + negotiation; providers that cannot remain valid entry-compilation providers. +- The version boundary prevents an optional result field from silently changing + released LPP 1.1 or 1.2 responses. +- The provider hashes the selected source text and must keep that identity + associated with the compile result it returns. +- Consumers must not interpret the digest as a project-wide content hash or a + semantic/compiler-result hash. + +## Alternatives considered + +### Client-computed identity + +Rejected because the client does not know the provider-selected primary source +for a directory target and must not duplicate source-language discovery. + +### Hash the complete source closure + +Rejected because it would require a new protocol-level ordering and identity +model for language-owned project files. The demonstrated consumer need is the +identity of the provider-selected primary source. + +### Reuse the entry version or artifact identity + +Rejected because the entry version is client bookkeeping rather than content +identity, while artifact formats are opaque and may not have a source-derived +hash. + +### Add an unnegotiated optional result field to LPP 1.1 or 1.2 + +Rejected because clients could not require the field reliably and providers +conforming to the released contracts would otherwise become incompatible with +new consumers. + +## Historical evidence + +- [PR #34](https://github.com/wrightkit/language-provider-protocol/pull/34) + defines the source-identity goal and its relationship to the directory-target + workflow. +- [PR #34](https://github.com/wrightkit/language-provider-protocol/pull/34) + merged the implementation as commit + [`7456e62`](https://github.com/wrightkit/language-provider-protocol/commit/7456e62b98ae451655c992c3d4c99e5e53838f42), + including the LPP 1.3 specification and conformance fixtures. +- This decision preserves the provider-ownership boundary established by + [ADR 0001](0001-provider-owned-project-loading.md) and extended by + [ADR 0002](0002-directory-project-targets.md). diff --git a/docs/adr/README.md b/docs/adr/README.md index 6b1f8ea..2166119 100644 --- a/docs/adr/README.md +++ b/docs/adr/README.md @@ -16,6 +16,8 @@ material process or wire-boundary decision. | ADR | Decision | Status | Decision date (UTC) | Backfilled (UTC) | Evidence | | --- | --- | --- | --- | --- | --- | | [0001](0001-provider-owned-project-loading.md) | Provider-owned project loading from a client-selected entry target | Accepted | 2026-09-02 | 2026-09-12 | [Issue #16](https://github.com/wrightkit/language-provider-protocol/issues/16), [PR #17](https://github.com/wrightkit/language-provider-protocol/pull/17) | +| [0002](0002-directory-project-targets.md) | Provider-owned directory project targets | Accepted | 2026-09-12 | 2026-09-14 | [PR #32](https://github.com/wrightkit/language-provider-protocol/pull/32) | +| [0003](0003-owner-selected-source-identity.md) | Owner-selected source identity for entry compilation | Accepted | 2026-09-13 | 2026-09-14 | [PR #34](https://github.com/wrightkit/language-provider-protocol/pull/34) | ## Post-baseline audit @@ -37,3 +39,19 @@ Within the reviewed history through commit [`a9e26a4`](https://github.com/wrightkit/language-provider-protocol/commit/a9e26a4168185b2fd89ea4293fbc89664e574536a), the audit identified no additional material process or wire-boundary decision requiring ADR backfill. + +## Follow-up audit + +The follow-up audit covers accepted changes after the original baseline through +commit [`83f6d37`](https://github.com/wrightkit/language-provider-protocol/commit/83f6d376652db9bce090adba3b23c2dec0d0abaf) +on 2026-09-13. It keeps the original audit scope and records only changes that +materially affect the LPP process or wire boundary. + +| Post-audit area | Classification | Rationale | +| --- | --- | --- | +| Directory project targets ([PR #32](https://github.com/wrightkit/language-provider-protocol/pull/32)) | Backfill-required; resolved by [ADR 0002](0002-directory-project-targets.md) | LPP 1.2 added a directory target shape and version gate while preserving the provider-owned project discovery decision in ADR 0001. | +| Owner-selected source identity ([PR #34](https://github.com/wrightkit/language-provider-protocol/pull/34)) | Backfill-required; resolved by [ADR 0003](0003-owner-selected-source-identity.md) | LPP 1.3 added a negotiated compile-result identity so clients can preserve provider-selected source identity without changing LPP 1.1 or 1.2 responses. | +| Release metadata for LPP 1.3 ([PR #35](https://github.com/wrightkit/language-provider-protocol/pull/35)) | Non-ADR detail | The release changed repository version metadata and did not change the protocol process or wire contract. | + +The follow-up audit finds no material process or wire-boundary decision through +commit `83f6d37` that remains without a discoverable ADR classification.