Skip to content

Commit b1bb910

Browse files
committed
ADR-006: shared action types as the action identity contract. Add guide how to write ADRs
1 parent bb0dbc5 commit b1bb910

3 files changed

Lines changed: 105 additions & 0 deletions

File tree

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
# ADR-0006: Shared action types as the action identity contract
2+
3+
- **Status:** accepted
4+
- **Date:** 2026-03-21
5+
- **Deciders:** @Aksem
6+
- **Tags:** actions, api, architecture, environments
7+
8+
## Context
9+
10+
Handlers may discover and invoke other actions at runtime through `IActionRunner`.
11+
That raises a contract question: how should one action identify another across
12+
extension environments?
13+
14+
Two architectural directions were considered:
15+
16+
- **Type-based identification.** Actions are identified by their shared action
17+
definition type. Callers depend on the same lightweight definition package and
18+
use that type when requesting an action.
19+
- **String-based identification.** Actions are identified by a string key that can
20+
be resolved even when the action definition type is not installed in the caller's
21+
environment.
22+
23+
The main force behind the string-based option is cross-environment invocation: one
24+
environment may want to call an action implemented elsewhere. If action definitions
25+
are not available everywhere, a string identifier appears to decouple callers from
26+
those packages.
27+
28+
However, introducing string identity shifts the architecture toward looser and less
29+
verifiable contracts. It makes action lookup depend on convention rather than shared
30+
types, and it weakens refactor safety and discoverability.
31+
32+
This decision therefore depends on a broader packaging rule: whether FineCode treats
33+
action definitions as lightweight shared contracts that can be installed in every
34+
participating environment, or as implementation-bound artifacts that may be absent
35+
from some environments.
36+
37+
## Related ADRs Considered
38+
39+
None — no existing ADR covers the `IActionRunner` API design.
40+
41+
## Decision
42+
43+
FineCode will use **type-based action identification**. Actions are identified
44+
through their shared action definition types, not through string-only
45+
identifiers.
46+
47+
This decision establishes the following architectural rule:
48+
49+
- **Action definition packages are shared contract packages.** They must remain
50+
lightweight, dependency-safe, and installable in any environment that needs to
51+
refer to those actions.
52+
- **Action implementations belong elsewhere.** Heavy runtime dependencies,
53+
platform-specific integrations, and tool execution logic belong in handler or
54+
environment-specific packages, not in the shared action-definition package.
55+
56+
With that boundary in place, cross-environment action invocation still works because
57+
all participating environments can depend on the same shared action-definition
58+
package. A string-based lookup mechanism is therefore not part of the primary
59+
architecture.
60+
61+
## Consequences
62+
63+
- **Action identity is explicit and type-safe.** Callers and runners share the same
64+
contract type, which improves readability, refactor safety, and tooling support.
65+
- **Package boundaries matter more.** Action-definition packages must be kept small
66+
and free of heavy implementation dependencies. Extensions that define new actions
67+
are expected to separate contract types from execution logic.
68+
- **Cross-environment compatibility becomes a packaging concern, not a lookup concern.**
69+
Environments that collaborate on actions must share the relevant contract package.
70+
- **String-only lookup is deferred, not rejected.** If FineCode later needs to invoke
71+
actions whose definitions genuinely cannot be installed in the calling environment,
72+
the architecture should be revisited and an additional identifier mechanism may be
73+
introduced at that time.

docs/adr/README.md

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,29 @@ a new ADR supersedes the old one rather than editing it.
2424
4. Set status to `proposed` and open a PR for review.
2525
5. Once merged, update status to `accepted` and add a row to the index table below.
2626

27+
## How to write a good ADR
28+
29+
ADRs should capture the **durable architectural decision**, not the current
30+
implementation shape. A useful test is: if we refactor the API next month but
31+
keep the same decision, would the ADR still read correctly?
32+
33+
- Write the decision at the level of architecture, contracts, boundaries,
34+
ownership, compatibility, or policy.
35+
- Prefer titles that describe the enduring rule, not the current mechanism.
36+
- Record the forces and constraints that make the decision necessary, not just
37+
the selected solution.
38+
- Use one primary term consistently throughout the ADR. If a language-specific
39+
implementation term is helpful, introduce it once as an example rather than
40+
switching terms back and forth.
41+
- Keep method names, function signatures, field layouts, and matching logic out
42+
of the main narrative unless they are themselves the architectural decision.
43+
- Put narrow implementation details in `Implementation Notes` only when they are
44+
needed to avoid ambiguity.
45+
- If an alternative is deferred rather than rejected, say when the decision
46+
should be revisited and what condition would trigger that review.
47+
- Keep examples short. Prefer explaining the rule and trade-off over documenting
48+
the present code structure.
49+
2750
## Index
2851

2952
| # | Title | Status | Date | Tags |
@@ -33,3 +56,4 @@ a new ADR supersedes the old one rather than editing it.
3356
| 0003 | [One Extension Runner process per execution environment](0003-process-isolation-per-extension-environment.md) | accepted | 2026-03-19 | architecture, extension-runner |
3457
| 0004 | [Auto-shutdown on disconnect timeout](0004-auto-shutdown-on-disconnect-timeout.md) | accepted | 2026-03-19 | lifecycle, wm-server |
3558
| 0005 | [Zero-based line numbers and ResourceUri fields in action payloads and results](0005-zero-based-lines-and-resourceuri-fields-in-action-payloads-and-results.md) | accepted | 2026-03-20 | actions, conventions |
59+
| 0006 | [Shared action types as the action identity contract](0006-shared-action-types-as-the-action-identity-contract.md) | accepted | 2026-03-21 | actions, api, architecture, environments |

docs/adr/template.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,14 @@ What becomes easier or harder as a result of this decision? What are the
2828
trade-offs?
2929

3030
<!--
31+
Authoring checklist:
32+
- Does the title describe the enduring decision rather than the current implementation?
33+
- Would this ADR still be correct if the API or method names changed next month?
34+
- Is the "Decision" section framed as an architectural rule, contract, or boundary?
35+
- Are implementation details kept out of the main narrative unless they are the decision?
36+
- Is one primary term used consistently throughout the document?
37+
- If an alternative is deferred, does the ADR say when to revisit it?
38+
3139
## Optional sections
3240
3341
The sections above are the minimal required set. Add any of the following

0 commit comments

Comments
 (0)