Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
86 changes: 86 additions & 0 deletions docs/adr/0002-directory-project-targets.md
Original file line number Diff line number Diff line change
@@ -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.

Comment thread
Teakowa marked this conversation as resolved.
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.
94 changes: 94 additions & 0 deletions docs/adr/0003-owner-selected-source-identity.md
Original file line number Diff line number Diff line change
@@ -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.
Comment thread
Teakowa marked this conversation as resolved.

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).
18 changes: 18 additions & 0 deletions docs/adr/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand All @@ -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.