Skip to content

Commit 46b1357

Browse files
authored
docs: add openspec change arch-05 bridge registry (#210)
Co-authored-by: Dominikus Nold <djm81@users.noreply.github.com>
1 parent c97080b commit 46b1357

File tree

9 files changed

+540
-0
lines changed

9 files changed

+540
-0
lines changed
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
schema: spec-driven
2+
created: 2026-02-08
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
# Change Validation Report: arch-05-bridge-registry
2+
3+
**Validation Date**: 2026-02-08
4+
**Change Proposal**: [proposal.md](./proposal.md)
5+
**Validation Method**: Dry-run interface/dependency analysis + strict OpenSpec validation
6+
7+
## Executive Summary
8+
9+
- **Breaking Changes**: 0 detected
10+
- **Impact Level**: Medium (new registry surface, additive manifest/schema behavior)
11+
- **Validation Result**: Pass
12+
- **User Decision Required**: No
13+
14+
## Breaking Change Analysis
15+
16+
No breaking interfaces were proposed.
17+
18+
Additive-only changes:
19+
20+
1. New `bridge_registry` module and `SchemaConverter` protocol.
21+
2. New optional `service_bridges` manifest metadata.
22+
3. New lifecycle registration behavior for declared bridges.
23+
4. New backlog converter implementations.
24+
25+
Compatibility expectation:
26+
27+
- Modules without `service_bridges` remain valid and operational.
28+
- Existing CLI commands continue functioning when bridge metadata is absent.
29+
30+
## Dependency Analysis
31+
32+
## Directly impacted runtime areas
33+
34+
- `src/specfact_cli/registry/module_packages.py`
35+
- `src/specfact_cli/modules/init/src/commands.py`
36+
- `src/specfact_cli/registry/bootstrap.py`
37+
- `src/specfact_cli/modules/backlog/src/commands.py`
38+
39+
## Directly impacted tests
40+
41+
- `tests/unit/specfact_cli/registry/test_module_packages.py`
42+
- `tests/unit/specfact_cli/registry/test_module_dependencies.py`
43+
- `tests/unit/specfact_cli/registry/test_version_constraints.py`
44+
- `tests/unit/specfact_cli/registry/test_init_module_lifecycle_ux.py`
45+
46+
## Risk notes
47+
48+
- `module_packages` is a shared registration path; metadata shape changes can affect init and bootstrap flows.
49+
- Bridge ID conflict behavior must be deterministic and covered by tests.
50+
- Converter import path validation should warn clearly and degrade gracefully.
51+
52+
## Dry-Run Validation Notes
53+
54+
Dry-run checks were performed as proposal-level analysis only (no implementation changes):
55+
56+
- Interface additions were checked for additive semantics.
57+
- Dependent call sites were identified via `rg` against registry, init, and backlog modules.
58+
- No code execution changes were applied to production files during validation stage.
59+
60+
## Artifact and Format Validation
61+
62+
- `proposal.md`: required sections present (`Why`, `What Changes`, `Capabilities`, `Impact`, `Source Tracking`).
63+
- `design.md`: includes context, decisions, risks, migration, and sequence diagram.
64+
- `tasks.md`: branch-first, tests-before-code ordering, issue creation task, PR-last.
65+
- Spec deltas present for:
66+
- `specs/bridge-registry/spec.md`
67+
- `specs/module-packages/spec.md`
68+
- `specs/module-lifecycle-management/spec.md`
69+
- `specs/backlog-adapter/spec.md`
70+
71+
## OpenSpec Validation
72+
73+
- Command: `openspec validate arch-05-bridge-registry --strict`
74+
- Result: `Change 'arch-05-bridge-registry' is valid`
75+
76+
## Conclusion
77+
78+
`arch-05-bridge-registry` is ready for implementation planning and execution under the documented TDD/SDD workflow.
Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
# Design: Bridge Registry for Cross-Module Service Interoperability
2+
3+
## Context
4+
5+
`arch-04-core-contracts-interfaces` establishes module IO contracts and core/module isolation, but it does not define how modules publish reusable schema converters for external services. The internal analysis dated 2026-02-08 and the implementation plan identify this as the next architectural step (arch-05) required before marketplace-grade module decoupling.
6+
7+
Current state:
8+
9+
- Service mapping logic is module-local and not discoverable through a common registry contract.
10+
- Module manifests support dependencies and core compatibility, but not converter bridge declarations.
11+
- Core must stay decoupled from module internals while still enabling dynamic bridge usage.
12+
13+
## Goals / Non-Goals
14+
15+
**Goals:**
16+
17+
- Introduce a registry-level bridge abstraction (`SchemaConverter`, `BridgeRegistry`) for bidirectional schema conversion.
18+
- Make bridge declarations manifest-driven (`service_bridges`) and validated at module registration time.
19+
- Keep core/module isolation intact: no hardcoded core imports of module adapter implementations.
20+
- Deliver backlog reference converters (ADO, Jira, Linear, GitHub) as first adopters.
21+
- Document extension points for custom enterprise bridge mappings.
22+
23+
**Non-Goals:**
24+
25+
- Cryptographic signature validation and trust chain (arch-06).
26+
- Marketplace install/uninstall UX and remote registry APIs (marketplace-01/02).
27+
- Per-module Python environment isolation.
28+
- Breaking existing module registration APIs.
29+
30+
## Decisions
31+
32+
### Decision 1: Protocol + Registry Pattern for Bridges
33+
34+
**Choice:** Define a `SchemaConverter` Protocol and a centralized `BridgeRegistry` with `register_converter()` and `get_converter()` methods.
35+
36+
**Rationale:**
37+
38+
- Preserves plugin-style extensibility already used in module discovery.
39+
- Keeps conversion contract explicit and testable.
40+
- Avoids hardcoded adapter branching in sync/backlog flows.
41+
42+
**Alternatives considered:**
43+
44+
- Inline converter logic in each command path: duplicates logic and increases coupling.
45+
- Abstract base class with strict inheritance: less flexible than protocol-based structural typing.
46+
47+
### Decision 2: Manifest-Driven Bridge Registration
48+
49+
**Choice:** Extend `module-package.yaml` metadata with `service_bridges` entries containing bridge id, description, and converter class path.
50+
51+
**Rationale:**
52+
53+
- Keeps registration declarative and discoverable.
54+
- Allows lifecycle validation before registration.
55+
- Supports future marketplace metadata verification without changing runtime architecture.
56+
57+
**Alternatives considered:**
58+
59+
- Hardcoded module-specific bridge lists in core: violates core isolation.
60+
- Runtime classpath scanning without manifest declarations: less deterministic and harder to validate.
61+
62+
### Decision 3: Graceful Degradation on Bridge Registration Failures
63+
64+
**Choice:** If a bridge declaration is invalid or import fails, skip that bridge with warning/debug logging; do not crash CLI startup.
65+
66+
**Rationale:**
67+
68+
- Matches existing module lifecycle behavior for compatibility/dependency issues.
69+
- Supports parallel module evolution without blocking unrelated workflows.
70+
71+
**Alternatives considered:**
72+
73+
- Fail-fast for any invalid bridge: safer but too disruptive for modular incremental rollout.
74+
75+
### Decision 4: Backlog Module as Reference Bridge Provider
76+
77+
**Choice:** Implement first converter set in backlog module (`ado`, `jira`, `linear`, `github`) and register through metadata.
78+
79+
**Rationale:**
80+
81+
- Backlog already contains major external service integration surface.
82+
- Provides concrete pattern for future modules to follow.
83+
84+
## Risks / Trade-offs
85+
86+
- **Risk:** Converter class import paths drift from code layout.
87+
- **Mitigation:** Add registration-time path validation tests and clear startup warnings.
88+
- **Risk:** Bridge IDs collide across modules.
89+
- **Mitigation:** Deterministic registration rules and explicit duplicate handling with warnings.
90+
- **Risk:** Converter logic divergence across modules.
91+
- **Mitigation:** Publish docs and contract tests against the `SchemaConverter` protocol.
92+
- **Trade-off:** Non-fatal bridge failures improve resilience but can hide misconfiguration.
93+
- **Mitigation:** Elevated warning logs and dedicated validation tests in CI.
94+
95+
## Migration Plan
96+
97+
1. Add bridge registry and converter protocol with unit tests.
98+
2. Extend manifest schema and parser for `service_bridges` metadata.
99+
3. Add lifecycle registration hooks for bridge declaration validation and registry insertion.
100+
4. Add backlog reference converters and manifest declarations.
101+
5. Update docs and run quality gates.
102+
103+
Rollback strategy:
104+
105+
- Remove bridge registration calls from module lifecycle.
106+
- Remove `service_bridges` metadata usage while keeping manifests backward compatible.
107+
- Keep backlog adapters functional through existing direct paths until reintroduced.
108+
109+
## Open Questions
110+
111+
- Should duplicate bridge IDs fail registration or use first-wins semantics with warnings?
112+
- Should converter registration support versioned bridge contracts in arch-06 or later?
113+
- Should enterprise custom mappings be loaded at bridge-level registration or adapter execution time?
114+
115+
## Sequence Diagram: Manifest-Driven Bridge Registration
116+
117+
```text
118+
CLI Startup -> ModuleRegistry: discover module packages
119+
ModuleRegistry -> ManifestParser: parse module-package.yaml
120+
ManifestParser --> ModuleRegistry: metadata (+service_bridges)
121+
ModuleRegistry -> BridgeRegistry: register_converter(bridge_id, converter_class)
122+
BridgeRegistry --> ModuleRegistry: success or warning
123+
ModuleRegistry --> CLI Startup: module commands + bridges available
124+
CLI Command -> BridgeRegistry: get_converter(service_id)
125+
BridgeRegistry --> CLI Command: SchemaConverter implementation
126+
```
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
# Change: Bridge Registry for Cross-Module Service Interoperability
2+
3+
## Why
4+
5+
6+
`arch-04-core-contracts-interfaces` formalizes module IO contracts and core isolation, but modules still lack a standard way to expose reusable external-service schema converters. Without a bridge registry, modules either duplicate adapter logic or reintroduce coupling, which slows parallel development and blocks marketplace-ready interoperability.
7+
8+
## What Changes
9+
10+
11+
- **NEW**: Add `src/specfact_cli/registry/bridge_registry.py` with `SchemaConverter` protocol and `BridgeRegistry` for converter registration/discovery.
12+
- **MODIFY**: Extend module package metadata to declare `service_bridges` in `module-package.yaml`.
13+
- **MODIFY**: Extend module lifecycle registration to validate and register declared service bridges without direct core-to-module imports.
14+
- **MODIFY**: Add backlog bridge converter implementations (ADO, Jira, Linear, GitHub) under module-local adapters and register them via manifest metadata.
15+
- **NEW**: Add user and developer documentation for bridge registry usage and custom bridge mappings.
16+
- **NEW**: Add tests for bridge registry behavior, manifest parsing, registration-time validation, and module integration.
17+
18+
## Capabilities
19+
### New Capabilities
20+
21+
- `bridge-registry`: Contract-driven registry for service schema converters so modules can publish and consume conversion bridges without hardcoded core logic.
22+
23+
### Modified Capabilities
24+
25+
- `module-packages`: Extend module package manifest schema with declarative bridge metadata.
26+
- `module-lifecycle-management`: Extend discovery/registration flow to validate and register bridge converters safely.
27+
- `backlog-adapter`: Add bridge converter implementations and mapping behaviors for backlog service integrations.
28+
29+
## Impact
30+
31+
- **Affected specs**: New spec for `bridge-registry`; delta specs for `module-packages`, `module-lifecycle-management`, and `backlog-adapter`.
32+
- **Affected code**:
33+
- `src/specfact_cli/registry/bridge_registry.py` (new)
34+
- `src/specfact_cli/registry/module_packages.py` (bridge metadata loading and registration)
35+
- `src/specfact_cli/models/module_package.py` (service bridge metadata)
36+
- `src/specfact_cli/modules/backlog/src/adapters/*.py` (new converter modules)
37+
- `tests/unit/registry/test_bridge_registry.py` (new)
38+
- `tests/unit/registry/test_module_bridge_registration.py` (new)
39+
- **Affected documentation**:
40+
- `docs/reference/bridge-registry.md` (new)
41+
- `docs/guides/creating-custom-bridges.md` (new)
42+
- `docs/reference/architecture.md` and `docs/_layouts/default.html` (updated navigation and architecture notes)
43+
- **Integration points**: module discovery, manifest parsing, registry startup, backlog adapters, sync workflows.
44+
- **Backward compatibility**: Backward compatible. Modules without `service_bridges` remain valid and continue working.
45+
- **Rollback plan**: Disable bridge registration in module lifecycle and remove `service_bridges` manifest handling; modules continue with existing adapter behavior.
46+
47+
---
48+
49+
## Source Tracking
50+
51+
<!-- source_repo: nold-ai/specfact-cli -->
52+
- **GitHub Issue**: #207
53+
- **Issue URL**: <https://github.com/nold-ai/specfact-cli/issues/207>
54+
- **Last Synced Status**: proposed
55+
- **Sanitized**: false
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
# Spec: Backlog Adapter
2+
3+
## ADDED Requirements
4+
5+
### Requirement: Backlog module provides bridge converters for supported services
6+
7+
The system SHALL provide backlog bridge converters for Azure DevOps, Jira, Linear, and GitHub using the shared bridge registry contract.
8+
9+
#### Scenario: Backlog module declares service bridges in manifest
10+
11+
- **WHEN** backlog module package metadata is discovered
12+
- **THEN** manifest `service_bridges` SHALL declare converter entries for `ado`, `jira`, `linear`, and `github`
13+
- **AND** each entry SHALL reference a converter class path under backlog adapters.
14+
15+
#### Scenario: Backlog converters satisfy schema converter contract
16+
17+
- **WHEN** bridge converters are loaded
18+
- **THEN** each converter SHALL implement `to_bundle` and `from_bundle` operations
19+
- **AND** conversion behavior SHALL preserve required backlog fields for round-trip workflows.
20+
21+
### Requirement: Backlog bridge mappings support custom enterprise overrides
22+
23+
The system SHALL allow custom bridge field mappings for backlog converter workflows.
24+
25+
#### Scenario: Custom mapping file overrides default mapping
26+
27+
- **WHEN** a custom mapping YAML exists for a configured service bridge
28+
- **THEN** backlog converter behavior SHALL apply custom mapping before default mapping
29+
- **AND** fallback to defaults when custom mappings are absent or incomplete.
30+
31+
#### Scenario: Invalid custom mapping falls back safely
32+
33+
- **WHEN** custom mapping configuration is malformed
34+
- **THEN** converter execution SHALL continue with default mapping behavior
35+
- **AND** SHALL emit warning/debug context for troubleshooting.
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
# Spec: Bridge Registry
2+
3+
## ADDED Requirements
4+
5+
### Requirement: Bridge registry provides converter registration and lookup
6+
7+
The system SHALL provide a `BridgeRegistry` that supports module-driven registration and lookup of service schema converters.
8+
9+
#### Scenario: Register converter for service ID
10+
11+
- **WHEN** a module lifecycle registration step provides a valid bridge declaration
12+
- **THEN** `BridgeRegistry` SHALL register the converter for the declared bridge ID
13+
- **AND** the converter SHALL be retrievable by that same bridge ID.
14+
15+
#### Scenario: Lookup missing converter fails with explicit error
16+
17+
- **WHEN** code requests a converter for a bridge ID that is not registered
18+
- **THEN** `BridgeRegistry` SHALL raise a clear lookup error
19+
- **AND** the error SHALL include the missing bridge ID.
20+
21+
### Requirement: SchemaConverter protocol defines bidirectional conversion contract
22+
23+
The system SHALL provide a `SchemaConverter` protocol to standardize conversion between external service payloads and ProjectBundle-compatible data.
24+
25+
#### Scenario: Converter defines to_bundle contract
26+
27+
- **WHEN** a converter implements `SchemaConverter`
28+
- **THEN** it SHALL implement `to_bundle(external_data: dict) -> dict`
29+
- **AND** the returned payload SHALL be compatible with ProjectBundle construction.
30+
31+
#### Scenario: Converter defines from_bundle contract
32+
33+
- **WHEN** a converter implements `SchemaConverter`
34+
- **THEN** it SHALL implement `from_bundle(bundle_data: dict) -> dict`
35+
- **AND** the returned payload SHALL be service-specific output.
36+
37+
### Requirement: Bridge registry preserves core-module isolation
38+
39+
The system SHALL enforce bridge registration without introducing direct core imports from `specfact_cli.modules.*`.
40+
41+
#### Scenario: Core retrieves bridge via registry only
42+
43+
- **WHEN** core CLI workflows need a converter
44+
- **THEN** they SHALL call `BridgeRegistry.get_converter()`
45+
- **AND** SHALL NOT import converter implementations directly from module command packages.
46+
47+
#### Scenario: Invalid bridge declaration degrades gracefully
48+
49+
- **WHEN** module metadata declares an invalid converter class path
50+
- **THEN** registration SHALL skip that bridge and log warning/debug context
51+
- **AND** CLI startup SHALL continue for unaffected modules.
52+
53+
### Requirement: Bridge registration supports offline-first workflows
54+
55+
The system SHALL support bridge registration and local converter resolution without requiring network access.
56+
57+
#### Scenario: Offline startup with local manifests
58+
59+
- **WHEN** CLI starts in an offline environment
60+
- **THEN** bridge registration SHALL complete using local module manifests and local Python imports
61+
- **AND** SHALL NOT require external API or registry calls.

0 commit comments

Comments
 (0)