From 1c7f4ac2886cbfcfae745c33e0ff4f7ba77be7e5 Mon Sep 17 00:00:00 2001 From: egallmann Date: Sat, 30 May 2026 15:23:57 -0400 Subject: [PATCH 1/3] Normalize ADR authors to erik.gallmann and document convention. Replace ste-runtime/system placeholder authors across 22 ADRs, regenerate discovery outputs and rendered markdown, and add adrs/README guidance so scaffolded ADRs default to the human author handle. Co-authored-by: Cursor --- adrs/README.md | 8 + adrs/entities/registry.yaml | 78 +- adrs/index/architecture-index.yaml | 5 +- adrs/index/capability-registry.yaml | 102 +- adrs/index/component-registry.yaml | 52 +- adrs/index/decision-registry.yaml | 282 ++++- adrs/index/entity-registry.yaml | 1002 ++++++++++++++++- adrs/index/invariant-registry.yaml | 336 ++++++ adrs/index/relationship-registry.yaml | 260 +++++ adrs/index/rule-registry.yaml | 3 + adrs/index/system-registry.yaml | 227 ++-- ...s-and-obligation-projection-semantics.yaml | 2 +- ...-L-0009-unified-workspace-scope-model.yaml | 2 +- ...-L-0010-bootstrap-and-init-capability.yaml | 2 +- .../ADR-L-0011-adapter-role-conformance.yaml | 2 +- .../ADR-L-0012-polyglot-interop-contract.yaml | 2 +- .../ADR-L-0013-path-portability-contract.yaml | 2 +- ...ADR-L-0014-private-registry-isolation.yaml | 2 +- ...-0015-workspace-agnosticism-invariant.yaml | 2 +- ...workspace-graph-slice-schema-contract.yaml | 2 +- ...17-recon-workspace-execution-contract.yaml | 2 +- adrs/manifest.yaml | 44 +- ...-PC-0001-mcp-server-and-tool-registry.yaml | 2 +- ...0002-watchdog-and-update-coordination.yaml | 2 +- ...t-freshness-and-reconciliation-gating.yaml | 2 +- ...ation-projection-and-context-assembly.yaml | 2 +- .../ADR-PC-0005-json-semantic-extraction.yaml | 2 +- ...-PC-0006-frontend-semantic-extraction.yaml | 2 +- ...07-cloudformation-semantic-extraction.yaml | 2 +- ...C-0008-service-wiring-post-processing.yaml | 2 +- ...-PC-0011-adr-yaml-semantic-extraction.yaml | 2 +- ...chestration-and-assistant-integration.yaml | 2 +- ...PS-0002-semantic-extraction-subsystem.yaml | 2 +- ...005-extractor-validation-requirements.yaml | 2 +- adrs/rendered/ADR-L-0007.md | 6 +- adrs/rendered/ADR-L-0009.md | 6 +- adrs/rendered/ADR-L-0010.md | 6 +- adrs/rendered/ADR-L-0011.md | 6 +- adrs/rendered/ADR-L-0012.md | 6 +- adrs/rendered/ADR-L-0013.md | 6 +- adrs/rendered/ADR-L-0014.md | 6 +- adrs/rendered/ADR-L-0015.md | 6 +- adrs/rendered/ADR-L-0016.md | 6 +- adrs/rendered/ADR-L-0017.md | 6 +- adrs/rendered/ADR-P-0005.md | 6 +- adrs/rendered/ADR-PC-0001.md | 6 +- adrs/rendered/ADR-PC-0002.md | 6 +- adrs/rendered/ADR-PC-0003.md | 6 +- adrs/rendered/ADR-PC-0004.md | 6 +- adrs/rendered/ADR-PC-0005.md | 6 +- adrs/rendered/ADR-PC-0006.md | 6 +- adrs/rendered/ADR-PC-0007.md | 6 +- adrs/rendered/ADR-PC-0008.md | 6 +- adrs/rendered/ADR-PC-0011.md | 6 +- adrs/rendered/ADR-PS-0001.md | 6 +- adrs/rendered/ADR-PS-0002.md | 6 +- 56 files changed, 2364 insertions(+), 211 deletions(-) create mode 100644 adrs/index/rule-registry.yaml diff --git a/adrs/README.md b/adrs/README.md index 663cd76..95afeaa 100644 --- a/adrs/README.md +++ b/adrs/README.md @@ -96,6 +96,14 @@ npm run rss:search "RECON decisions" ## Updating ADRs +### Authors + +`authors` records **who wrote the decision** (human accountability), not repo ownership. +For this repository, use **`erik.gallmann`**. Do not use `ste-runtime`, `system`, or package +names — ownership is already expressed in `PROJECT.yaml` and `architecture_namespace`. + +After `adr scaffold` or generator commands, set `authors` before committing. + 1. Edit YAML file directly 2. Validate: `python -m adr_kit.validator adrs/logical/ADR-L-0001.yaml` 3. Regenerate manifest: `python -m adr_kit.generators.manifest_generator adrs/` diff --git a/adrs/entities/registry.yaml b/adrs/entities/registry.yaml index 74d4d77..709a172 100644 --- a/adrs/entities/registry.yaml +++ b/adrs/entities/registry.yaml @@ -130,6 +130,18 @@ entities: depends_on: [] implements: [] realizes: [] + - entity_id: CAP-0021 + entity_type: capability + name: Experimental MVC-D to MVC-S candidate emission + introduced_by: ADR-L-0021 + lifecycle_stage: proposed + source_path: adrs/logical/ADR-L-0021-experimental-mvc-d-to-mvc-s-contract-consumption.yaml + source_artifact_type: logical_adr + related_adrs: [] + relationships: + depends_on: [] + implements: [] + realizes: [] - entity_id: COMP-0001 entity_type: component name: MCP Server and Tool Registry @@ -374,7 +386,7 @@ entities: realizes: [] - entity_id: DEC-0010 entity_type: decision - name: ste init is the canonical one-command install experience + name: ste setup is the canonical one-command install experience introduced_by: ADR-L-0010 lifecycle_stage: proposed source_path: adrs/logical/ADR-L-0010-bootstrap-and-init-capability.yaml @@ -538,6 +550,22 @@ entities: - INV-0027 - INV-0028 - INV-0029 + - entity_id: DEC-0023 + entity_type: decision + name: Add an experimental contract-consumption builder for MVC-D to MVC-S fixtures + introduced_by: ADR-L-0021 + lifecycle_stage: proposed + source_path: adrs/logical/ADR-L-0021-experimental-mvc-d-to-mvc-s-contract-consumption.yaml + source_artifact_type: logical_adr + related_adrs: [] + relationships: + depends_on: [] + implements: + - CAP-0021 + realizes: + - INV-0030 + - INV-0031 + - INV-0032 - entity_id: INV-0001 entity_type: invariant name: INV-0001 @@ -826,6 +854,18 @@ entities: depends_on: [] implements: [] realizes: [] + - entity_id: INV-0025 + entity_type: invariant + name: INV-0025 + introduced_by: ADR-L-0016 + lifecycle_stage: proposed + source_path: adrs/logical/ADR-L-0016-workspace-graph-slice-schema-contract.yaml + source_artifact_type: logical_adr + related_adrs: [] + relationships: + depends_on: [] + implements: [] + realizes: [] - entity_id: INV-0027 entity_type: invariant name: INV-0027 @@ -862,3 +902,39 @@ entities: depends_on: [] implements: [] realizes: [] + - entity_id: INV-0030 + entity_type: invariant + name: INV-0030 + introduced_by: ADR-L-0021 + lifecycle_stage: proposed + source_path: adrs/logical/ADR-L-0021-experimental-mvc-d-to-mvc-s-contract-consumption.yaml + source_artifact_type: logical_adr + related_adrs: [] + relationships: + depends_on: [] + implements: [] + realizes: [] + - entity_id: INV-0031 + entity_type: invariant + name: INV-0031 + introduced_by: ADR-L-0021 + lifecycle_stage: proposed + source_path: adrs/logical/ADR-L-0021-experimental-mvc-d-to-mvc-s-contract-consumption.yaml + source_artifact_type: logical_adr + related_adrs: [] + relationships: + depends_on: [] + implements: [] + realizes: [] + - entity_id: INV-0032 + entity_type: invariant + name: INV-0032 + introduced_by: ADR-L-0021 + lifecycle_stage: proposed + source_path: adrs/logical/ADR-L-0021-experimental-mvc-d-to-mvc-s-contract-consumption.yaml + source_artifact_type: logical_adr + related_adrs: [] + relationships: + depends_on: [] + implements: [] + realizes: [] diff --git a/adrs/index/architecture-index.yaml b/adrs/index/architecture-index.yaml index 679177c..b2e02fd 100644 --- a/adrs/index/architecture-index.yaml +++ b/adrs/index/architecture-index.yaml @@ -1,7 +1,7 @@ schema_version: '1.1' type: architecture_index architecture_namespace: ste-runtime -generated_at: '2026-05-27T05:44:06Z' +generated_at: '2026-05-30T19:23:29Z' generator: adr-architecture-index entity_registry_path: adrs/index/entity-registry.yaml relationship_registry_path: adrs/index/relationship-registry.yaml @@ -11,12 +11,13 @@ capability_registry_path: adrs/index/capability-registry.yaml invariant_registry_path: adrs/index/invariant-registry.yaml component_registry_path: adrs/index/component-registry.yaml system_registry_path: adrs/index/system-registry.yaml +rule_registry_path: adrs/index/rule-registry.yaml validation_summary: hard_failures: 0 warnings: 0 unresolved_entries: 0 source_coverage: - logical_adrs: 19 + logical_adrs: 20 physical_adrs: 5 physical_system_adrs: 2 physical_component_adrs: 11 diff --git a/adrs/index/capability-registry.yaml b/adrs/index/capability-registry.yaml index cc4d10d..63987c8 100644 --- a/adrs/index/capability-registry.yaml +++ b/adrs/index/capability-registry.yaml @@ -6,6 +6,7 @@ entities: name: Surface graph freshness and obligation projection semantics summary: Provide canonical freshness, invalidation, and obligation semantics for runtime consumers. lifecycle_stage: proposed + admission_status: admitted canonical_source: source_type: logical_adr source_ref: ADR-L-0007#CAP-0007 @@ -40,6 +41,9 @@ entities: superseded_by: [] refines: [] refined_by: [] + contradicts: [] + rejects: [] + rejected_by: [] completeness: status: complete missing_fields: [] @@ -54,6 +58,7 @@ entities: name: Workspace-scoped analysis summary: All reconnaissance and evidence emission operates on workspace scope. lifecycle_stage: proposed + admission_status: admitted canonical_source: source_type: logical_adr source_ref: ADR-L-0009#CAP-0009 @@ -87,6 +92,9 @@ entities: superseded_by: [] refines: [] refined_by: [] + contradicts: [] + rejects: [] + rejected_by: [] completeness: status: complete missing_fields: [] @@ -99,8 +107,11 @@ entities: - id: CAP-0010 entity_type: capability name: One-command workspace initialization - summary: ste init creates a fully configured workspace. + summary: >- + ste setup creates a fully configured workspace (config, MCP, gitignore, initial RECON). ste init remains as the + sub-capability for scaffolding workspace.yaml specifically. lifecycle_stage: proposed + admission_status: admitted canonical_source: source_type: logical_adr source_ref: ADR-L-0010#CAP-0010 @@ -134,6 +145,9 @@ entities: superseded_by: [] refines: [] refined_by: [] + contradicts: [] + rejects: [] + rejected_by: [] completeness: status: complete missing_fields: [] @@ -146,8 +160,9 @@ entities: - id: CAP-0011 entity_type: capability name: ArchitectureEvidence emission - summary: Emit ArchitectureEvidence v2 at .ste-workspace/evidence/architecture-evidence.json. + summary: Emit ArchitectureEvidence v2 at .workspace-graph/evidence/architecture-evidence.json. lifecycle_stage: proposed + admission_status: admitted canonical_source: source_type: logical_adr source_ref: ADR-L-0011#CAP-0011 @@ -181,6 +196,9 @@ entities: superseded_by: [] refines: [] refined_by: [] + contradicts: [] + rejects: [] + rejected_by: [] completeness: status: complete missing_fields: [] @@ -197,6 +215,7 @@ entities: ste-runtime consumes architecture-evidence.schema.json via fixture sync in test/fixtures/. Drift is detected by spec-schema-fixture-sync.test.ts. lifecycle_stage: proposed + admission_status: admitted canonical_source: source_type: logical_adr source_ref: ADR-L-0012#CAP-0012 @@ -230,6 +249,9 @@ entities: superseded_by: [] refines: [] refined_by: [] + contradicts: [] + rejects: [] + rejected_by: [] completeness: status: complete missing_fields: [] @@ -246,6 +268,7 @@ entities: ste-runtime operates identically in any workspace without source code changes. All workspace-specific values (repo names, output directories, domain vocabulary) are derived from workspace.yaml at runtime. lifecycle_stage: proposed + admission_status: admitted canonical_source: source_type: logical_adr source_ref: ADR-L-0015#CAP-0015 @@ -280,6 +303,9 @@ entities: superseded_by: [] refines: [] refined_by: [] + contradicts: [] + rejects: [] + rejected_by: [] completeness: status: complete missing_fields: [] @@ -296,6 +322,7 @@ entities: ste-runtime emits workspace graph slices that conform to a defined schema contract, enabling any compliant merger to consume them without validation errors. lifecycle_stage: proposed + admission_status: admitted canonical_source: source_type: logical_adr source_ref: ADR-L-0016#CAP-0016 @@ -330,6 +357,9 @@ entities: superseded_by: [] refines: [] refined_by: [] + contradicts: [] + rejects: [] + rejected_by: [] completeness: status: complete missing_fields: [] @@ -346,6 +376,7 @@ entities: Load workspace infra graph slices into a typed in-memory graph and execute deterministic, non-LLM traversal queries that answer standard workspace-level questions (system dependencies, component integration, blast radius lifecycle_stage: proposed + admission_status: admitted canonical_source: source_type: logical_adr source_ref: ADR-L-0018#CAP-0018 @@ -386,6 +417,9 @@ entities: superseded_by: [] refines: [] refined_by: [] + contradicts: [] + rejects: [] + rejected_by: [] completeness: status: complete missing_fields: [] @@ -402,6 +436,7 @@ entities: Produce architecture projections at five deterministic resolution levels (L0-L4) from the same workspace graph substrate, using semantic compression (endpoint grouping, same-type aggregation, edge tier filtering) to opti lifecycle_stage: proposed + admission_status: admitted canonical_source: source_type: logical_adr source_ref: ADR-L-0019#CAP-0019 @@ -442,6 +477,9 @@ entities: superseded_by: [] refines: [] refined_by: [] + contradicts: [] + rejects: [] + rejected_by: [] completeness: status: complete missing_fields: [] @@ -458,6 +496,7 @@ entities: Resolve workspace graph entities to authoritative source artifacts through stable URI locators, assemble CEM bundles with provenance and validation state, derive bounded MVC bundles, and validate MVC bundles against thei lifecycle_stage: proposed + admission_status: admitted canonical_source: source_type: logical_adr source_ref: ADR-L-0020#CAP-0020 @@ -500,6 +539,9 @@ entities: superseded_by: [] refines: [] refined_by: [] + contradicts: [] + rejects: [] + rejected_by: [] completeness: status: complete missing_fields: [] @@ -509,3 +551,59 @@ entities: extraction_phase: extract_capability classification: explicit generator: adr-architecture-index + - id: CAP-0021 + entity_type: capability + name: Experimental MVC-D to MVC-S candidate emission + summary: >- + Consume ste-spec-owned MVC-D and MVC-S contracts in tests and emit deterministic factual MVC-S candidate snapshots + from fully supplied fixture inputs. + lifecycle_stage: proposed + admission_status: admitted + canonical_source: + source_type: logical_adr + source_ref: ADR-L-0021#CAP-0021 + artifact_path: adrs/logical/ADR-L-0021-experimental-mvc-d-to-mvc-s-contract-consumption.yaml + source_refs: [] + metadata: + adr_id: ADR-L-0021 + domains: + - mvc + - contracts + - runtime + - provenance + implemented_by_components: [] + enabled_by_decisions: [] + relationships: + declared_in: + - ADR-L-0021 + declares: [] + references: [] + referenced_by: [] + related_to: [] + enforces: [] + enforced_by: [] + enabled_by: + - DEC-0023 + enables: [] + governs: [] + governed_by: [] + implemented_by: [] + implements: [] + embodied_in: [] + embodies: [] + supersedes: [] + superseded_by: [] + refines: [] + refined_by: [] + contradicts: [] + rejects: [] + rejected_by: [] + completeness: + status: complete + missing_fields: [] + provenance: + source_type: logical_adr + source_ref: ADR-L-0021#CAP-0021 + extraction_phase: extract_capability + classification: explicit + generator: adr-architecture-index diff --git a/adrs/index/component-registry.yaml b/adrs/index/component-registry.yaml index 75e88c8..f5b1a57 100644 --- a/adrs/index/component-registry.yaml +++ b/adrs/index/component-registry.yaml @@ -8,6 +8,7 @@ entities: - Serve MCP stdio runtime for assistant integration - Register structural, operational, context, optimized, obligation, and workspace graph query tools - Route tool requests onto runtime graph, context, and workspace que lifecycle_stage: proposed + admission_status: admitted canonical_source: source_type: physical_component_adr source_ref: ADR-PC-0001#COMP-0001 @@ -47,6 +48,9 @@ entities: superseded_by: [] refines: [] refined_by: [] + contradicts: [] + rejects: [] + rejected_by: [] completeness: status: complete missing_fields: [] @@ -63,6 +67,7 @@ entities: - Watch source and state changes - Detect coherent edit transactions - Coordinate update batches and reconciliation triggers - Protect runtime behavior from unsafe write loops lifecycle_stage: proposed + admission_status: admitted canonical_source: source_type: physical_component_adr source_ref: ADR-PC-0002#COMP-0002 @@ -101,6 +106,9 @@ entities: superseded_by: [] refines: [] refined_by: [] + contradicts: [] + rejects: [] + rejected_by: [] completeness: status: complete missing_fields: [] @@ -117,6 +125,7 @@ entities: - Resolve intent scope - Evaluate graph freshness - Determine whether reconciliation is required - Surface freshness status for downstream tools lifecycle_stage: proposed + admission_status: admitted canonical_source: source_type: physical_component_adr source_ref: ADR-PC-0003#COMP-0003 @@ -155,6 +164,9 @@ entities: superseded_by: [] refines: [] refined_by: [] + contradicts: [] + rejects: [] + rejected_by: [] completeness: status: complete missing_fields: [] @@ -171,6 +183,7 @@ entities: - Project obligations from change intent and graph state - Surface invalidated validations and advisories - Load source-backed implementation context - Format runtime context for assistant consumption lifecycle_stage: proposed + admission_status: admitted canonical_source: source_type: physical_component_adr source_ref: ADR-PC-0004#COMP-0004 @@ -209,6 +222,9 @@ entities: superseded_by: [] refines: [] refined_by: [] + contradicts: [] + rejects: [] + rejected_by: [] completeness: status: complete missing_fields: [] @@ -225,6 +241,7 @@ entities: - Detect semantically relevant JSON files - Extract controls, schemas, and configuration semantics - Provide RECON-ready assertions for normalization lifecycle_stage: proposed + admission_status: admitted canonical_source: source_type: physical_component_adr source_ref: ADR-PC-0005#COMP-0005 @@ -263,6 +280,9 @@ entities: superseded_by: [] refines: [] refined_by: [] + contradicts: [] + rejects: [] + rejected_by: [] completeness: status: complete missing_fields: [] @@ -279,6 +299,7 @@ entities: - Extract Angular component, service, route, and template semantics - Extract CSS/SCSS tokens, styles, and related frontend semantics - Provide frontend assertions for RECON normalization lifecycle_stage: proposed + admission_status: admitted canonical_source: source_type: physical_component_adr source_ref: ADR-PC-0006#COMP-0006 @@ -318,6 +339,9 @@ entities: superseded_by: [] refines: [] refined_by: [] + contradicts: [] + rejects: [] + rejected_by: [] completeness: status: complete missing_fields: [] @@ -334,6 +358,7 @@ entities: - Extract template, parameter, resource, and output semantics - Derive infrastructure relationships and API/data model evidence - Preserve template-level implementation intent metadata - Detect nested stack topology via lifecycle_stage: proposed + admission_status: admitted canonical_source: source_type: physical_component_adr source_ref: ADR-PC-0007#COMP-0007 @@ -373,6 +398,9 @@ entities: superseded_by: [] refines: [] refined_by: [] + contradicts: [] + rejects: [] + rejected_by: [] completeness: status: complete missing_fields: [] @@ -389,6 +417,7 @@ entities: - Build env-var-to-CFN-resource join maps from per-repo RECON state - Build SDK-service-to-graph-type maps (dynamodb->Database, s3->Bucket, etc.) - Build Lambda-handler-to-function maps from CFN handler metadata - Resolv lifecycle_stage: proposed + admission_status: admitted canonical_source: source_type: physical_component_adr source_ref: ADR-PC-0008#COMP-0008 @@ -427,6 +456,9 @@ entities: superseded_by: [] refines: [] refined_by: [] + contradicts: [] + rejects: [] + rejected_by: [] completeness: status: complete missing_fields: [] @@ -440,9 +472,10 @@ entities: entity_type: component name: Slice Emitter Edge Wiring summary: >- - - Produce reads/writes edges by joining SDK usage with infrastructure resources via env-var bridge - Produce - publishes edges for SQS/SNS SDK usage - Improve consumes edge resolution via CFN logical ID lookup - Produce de + - Emit all extracted CFN resources as workspace graph nodes (no allowlist gate; InfraResource fallback for + unmapped types) - Emit Stack nodes from infrastructure/template slices with contains edges to child resources - P lifecycle_stage: proposed + admission_status: admitted canonical_source: source_type: physical_component_adr source_ref: ADR-PC-0008#COMP-0009 @@ -481,6 +514,9 @@ entities: superseded_by: [] refines: [] refined_by: [] + contradicts: [] + rejects: [] + rejected_by: [] completeness: status: complete missing_fields: [] @@ -497,6 +533,7 @@ entities: - Load workspace graph slices into typed in-memory WorkspaceGraph - Build outAdj/inAdj adjacency maps at load time for O(1) neighbor lookups - Execute systemDependencies, componentIntegration, blastRadiusWorkspace querie lifecycle_stage: proposed + admission_status: admitted canonical_source: source_type: physical_component_adr source_ref: ADR-PC-0009#COMP-0010 @@ -541,6 +578,9 @@ entities: superseded_by: [] refines: [] refined_by: [] + contradicts: [] + rejects: [] + rejected_by: [] completeness: status: complete missing_fields: [] @@ -557,6 +597,7 @@ entities: - Compress CannedQueryResult into CompressedProjection at configurable resolution levels (L0-L4) - Group endpoints by capability domain using path-prefix extraction - Aggregate same-type nodes above threshold into count- lifecycle_stage: proposed + admission_status: admitted canonical_source: source_type: physical_component_adr source_ref: ADR-PC-0010#COMP-0011 @@ -599,6 +640,9 @@ entities: superseded_by: [] refines: [] refined_by: [] + contradicts: [] + rejects: [] + rejected_by: [] completeness: status: complete missing_fields: [] @@ -615,6 +659,7 @@ entities: - Detect and classify ADR YAML files via path-prefix and content sniffing - Parse ADR YAML using js-yaml - Extract ADR documents, invariants, decisions, capabilities, component specifications, and system boundaries as Ra lifecycle_stage: proposed + admission_status: admitted canonical_source: source_type: physical_component_adr source_ref: ADR-PC-0011#COMP-0012 @@ -654,6 +699,9 @@ entities: superseded_by: [] refines: [] refined_by: [] + contradicts: [] + rejects: [] + rejected_by: [] completeness: status: complete missing_fields: [] diff --git a/adrs/index/decision-registry.yaml b/adrs/index/decision-registry.yaml index c0beed1..1a127f5 100644 --- a/adrs/index/decision-registry.yaml +++ b/adrs/index/decision-registry.yaml @@ -8,6 +8,7 @@ entities: ### 1. Semantic Pressure Over Semantic Truth RECON exists to **observe how semantic truth breaks under change**, not to declare what truth is. During exploratory development, the extraction algorithms, normalization sche lifecycle_stage: active + admission_status: admitted canonical_source: source_type: logical_adr source_ref: ADR-L-0001#DEC-0001 @@ -21,6 +22,18 @@ entities: governs_components: [] supersedes: [] refines: [] + contradicts: [] + accumulated_consequences: + - RECON can execute immediately, generating learning pressure + - Conflicts surface early, before they become entrenched + - Developers maintain full control over semantic state acceptance + - Extraction algorithms can evolve without breaking workflows + - No automated enforcement of semantic consistency + - Conflicts may accumulate if not reviewed + - Provisional state cannot be used for authoritative downstream systems + - Document all conflicts for periodic human review + - Track conflict patterns to improve extraction algorithms + - Plan transition to canonical execution once algorithms stabilize relationships: declared_in: - ADR-L-0001 @@ -42,6 +55,9 @@ entities: superseded_by: [] refines: [] refined_by: [] + contradicts: [] + rejects: [] + rejected_by: [] completeness: status: complete missing_fields: [] @@ -58,6 +74,7 @@ entities: ### 1. Non-Blocking Preserves Learning If validation blocked execution on every finding, RECON would become unusable during exploratory development. Many validation findings are informational or represent known limitatio lifecycle_stage: active + admission_status: admitted canonical_source: source_type: logical_adr source_ref: ADR-L-0002#DEC-0002 @@ -71,6 +88,19 @@ entities: governs_components: [] supersedes: [] refines: [] + contradicts: [] + accumulated_consequences: + - Continuous quality visibility without workflow disruption + - Historical trend data for extraction algorithm improvement + - Early detection of regression in extractors + - Developer confidence through transparency + - Findings may be ignored if too numerous + - No enforcement of quality gates + - Report accumulation without review + - Periodic finding review as part of development process + - Track finding counts over time for trend analysis + - Prioritize ERROR findings for immediate investigation + - Use findings to guide extractor improvements relationships: declared_in: - ADR-L-0002 @@ -92,6 +122,9 @@ entities: superseded_by: [] refines: [] refined_by: [] + contradicts: [] + rejects: [] + rejected_by: [] completeness: status: complete missing_fields: [] @@ -108,6 +141,7 @@ entities: ### 1. CEM Orchestrates Components That Must Exist First CEM's stages call into foundational components: - **Orientation** calls RSS for context assembly - **Analysis** reads AI-DOC semantic state - **Deliberation** invo lifecycle_stage: active + admission_status: admitted canonical_source: source_type: logical_adr source_ref: ADR-L-0003#DEC-0003 @@ -121,6 +155,18 @@ entities: governs_components: [] supersedes: [] refines: [] + contradicts: [] + accumulated_consequences: + - Foundation components can be built and tested independently + - API surfaces stabilize before CEM integration + - Reduced rework and premature abstraction + - Faster iteration on extraction/inference/traversal + - Autonomous agent execution blocked until CEM exists + - Formal governance auditing deferred + - Potential for API drift if CEM requirements not considered + - Document CEM's expected API contracts in ste-spec + - Periodically review foundation components against CEM needs + - Use execution pressure to surface integration gaps relationships: declared_in: - ADR-L-0003 @@ -142,6 +188,9 @@ entities: superseded_by: [] refines: [] refined_by: [] + contradicts: [] + rejects: [] + rejected_by: [] completeness: status: complete missing_fields: [] @@ -159,6 +208,7 @@ entities: (authoritative: it observed the file system event) 2. Migration detection scores confidence (1.0 = certain same element) lifecycle_stage: active + admission_status: admitted canonical_source: source_type: logical_adr source_ref: ADR-L-0004#DEC-0004 @@ -172,6 +222,7 @@ entities: governs_components: [] supersedes: [] refines: [] + contradicts: [] relationships: declared_in: - ADR-L-0004 @@ -193,6 +244,9 @@ entities: superseded_by: [] refines: [] refined_by: [] + contradicts: [] + rejects: [] + rejected_by: [] completeness: status: complete missing_fields: [] @@ -207,6 +261,7 @@ entities: name: DEC-0005 summary: '' lifecycle_stage: proposed + admission_status: admitted canonical_source: source_type: logical_adr source_ref: ADR-L-0005#DEC-0005 @@ -220,6 +275,42 @@ entities: governs_components: [] supersedes: [] refines: [] + contradicts: [] + accumulated_consequences: + - Drop into any project and run immediately + - No setup time, no learning curve + - Immediate value delivery + - Works with any project structure + - Works with any naming convention + - Works with any framework combination + - Understands project context automatically + - Tags and relationships use actual project names + - Output reflects real architecture + - Reduces barrier to entry dramatically + - Eliminates configuration errors + - Enables rapid experimentation + - Discovery output shows what was found + - Users understand what runtime sees + - Transparent behavior + - Discovery engine requires careful design + - Edge cases need handling + - More code to maintain + - 4 weeks vs 2 weeks for manual config + - Delays other features + - Higher upfront investment + - Heuristics may fail for unusual structures + - Need robust fallback mechanisms + - Requires extensive testing + - Clear abstractions and interfaces + - Comprehensive unit test coverage + - Well-documented heuristics + - Investment justified by adoption gains + - Phased implementation with validation gates + - Early user testing + - Confidence scoring system + - Graceful fallback to safe defaults + - Optional configuration override for edge cases + - Clear discovery debugging output relationships: declared_in: - ADR-L-0005 @@ -241,6 +332,9 @@ entities: superseded_by: [] refines: [] refined_by: [] + contradicts: [] + rejects: [] + rejected_by: [] completeness: status: complete missing_fields: [] @@ -257,6 +351,7 @@ entities: ### 1. Reduces Cognitive Load for Both Humans and AI Without CQI: ``` Human: "What would be affected by changing the auth service?" → Human must know: use blast-radius, specify key format, parse output → AI must know: co lifecycle_stage: proposed + admission_status: admitted canonical_source: source_type: logical_adr source_ref: ADR-L-0006#DEC-0006 @@ -270,6 +365,19 @@ entities: governs_components: [] supersedes: [] refines: [] + contradicts: [] + accumulated_consequences: + - '**Seamless UX**: Both humans and AI agents use natural language' + - '**Performance**: Sub-5ms queries, <0.3ms cached' + - '**Discoverability**: Suggested queries guide exploration' + - '**Dual output**: Same engine serves terminal and programmatic use' + - '**Foundation for MCP**: CQI becomes the MCP tool interface' + - '**Pattern maintenance**: New intent patterns require code changes' + - '**Cache staleness**: Risk of stale results if cache not invalidated' + - '**Abstraction cost**: Hides RSS complexity (may hinder advanced use)' + - Expose raw RSS API for power users + - Document intent patterns explicitly + - Integrate with Watchdog for automatic cache invalidation relationships: declared_in: - ADR-L-0006 @@ -291,6 +399,9 @@ entities: superseded_by: [] refines: [] refined_by: [] + contradicts: [] + rejects: [] + rejected_by: [] completeness: status: complete missing_fields: [] @@ -307,6 +418,7 @@ entities: The current runtime models freshness and obligation data in public schemas and assistant-facing responses, so these semantics require canonical documentation above the component layer. lifecycle_stage: proposed + admission_status: admitted canonical_source: source_type: logical_adr source_ref: ADR-L-0007#DEC-0007 @@ -320,6 +432,7 @@ entities: governs_components: [] supersedes: [] refines: [] + contradicts: [] relationships: declared_in: - ADR-L-0007 @@ -341,6 +454,9 @@ entities: superseded_by: [] refines: [] refined_by: [] + contradicts: [] + rejects: [] + rejected_by: [] completeness: status: complete missing_fields: [] @@ -357,6 +473,7 @@ entities: Multi-repo analysis cannot be retrofitted onto single-repo scope without pervasive special-casing. Defining workspace as the universal scope from the start eliminates that debt. A workspace containing a single repository lifecycle_stage: proposed + admission_status: admitted canonical_source: source_type: logical_adr source_ref: ADR-L-0009#DEC-0009 @@ -370,6 +487,7 @@ entities: governs_components: [] supersedes: [] refines: [] + contradicts: [] relationships: declared_in: - ADR-L-0009 @@ -391,6 +509,9 @@ entities: superseded_by: [] refines: [] refined_by: [] + contradicts: [] + rejects: [] + rejected_by: [] completeness: status: complete missing_fields: [] @@ -402,11 +523,13 @@ entities: generator: adr-architecture-index - id: DEC-0010 entity_type: decision - name: ste init is the canonical one-command install experience + name: ste setup is the canonical one-command install experience summary: >- - Manual onboarding is error-prone and slow. A first-class init command with binding constraints ensures consistent, - portable, and safe workspace initialization. + Manual onboarding is error-prone and slow. A first-class setup command with binding constraints ensures + consistent, portable, and safe workspace initialization. ste setup supersedes the narrower ste init by also + handling lifecycle_stage: proposed + admission_status: admitted canonical_source: source_type: logical_adr source_ref: ADR-L-0010#DEC-0010 @@ -420,6 +543,7 @@ entities: governs_components: [] supersedes: [] refines: [] + contradicts: [] relationships: declared_in: - ADR-L-0010 @@ -441,6 +565,9 @@ entities: superseded_by: [] refines: [] refined_by: [] + contradicts: [] + rejects: [] + rejected_by: [] completeness: status: complete missing_fields: [] @@ -457,6 +584,7 @@ entities: Explicit role conformance prevents scope leakage across subsystem boundaries and ensures evidence artifacts are schema-compliant. lifecycle_stage: proposed + admission_status: admitted canonical_source: source_type: logical_adr source_ref: ADR-L-0011#DEC-0011 @@ -470,6 +598,7 @@ entities: governs_components: [] supersedes: [] refines: [] + contradicts: [] relationships: declared_in: - ADR-L-0011 @@ -491,6 +620,9 @@ entities: superseded_by: [] refines: [] refined_by: [] + contradicts: [] + rejects: [] + rejected_by: [] completeness: status: complete missing_fields: [] @@ -507,6 +639,7 @@ entities: Polyglot subsystems cannot safely maintain independent copies of shared schemas. Centralizing authority in ste-spec eliminates drift and ensures all subsystems validate against the same contract. lifecycle_stage: proposed + admission_status: admitted canonical_source: source_type: logical_adr source_ref: ADR-L-0012#DEC-0012 @@ -520,6 +653,7 @@ entities: governs_components: [] supersedes: [] refines: [] + contradicts: [] relationships: declared_in: - ADR-L-0012 @@ -541,6 +675,9 @@ entities: superseded_by: [] refines: [] refined_by: [] + contradicts: [] + rejects: [] + rejected_by: [] completeness: status: complete missing_fields: [] @@ -557,6 +694,7 @@ entities: Platform-specific paths in persisted artifacts break cross-platform workflows. Enforcing POSIX-relative paths at the serialization boundary ensures portability without constraining internal disk-IO. lifecycle_stage: proposed + admission_status: admitted canonical_source: source_type: logical_adr source_ref: ADR-L-0013#DEC-0013 @@ -570,6 +708,7 @@ entities: governs_components: [] supersedes: [] refines: [] + contradicts: [] relationships: declared_in: - ADR-L-0013 @@ -591,6 +730,9 @@ entities: superseded_by: [] refines: [] refined_by: [] + contradicts: [] + rejects: [] + rejected_by: [] completeness: status: complete missing_fields: [] @@ -607,6 +749,7 @@ entities: Private registry URLs are work-context IP that must not appear in version-controlled files. Mechanical enforcement via the scanner prevents accidental leakage. lifecycle_stage: proposed + admission_status: admitted canonical_source: source_type: logical_adr source_ref: ADR-L-0014#DEC-0014 @@ -620,6 +763,7 @@ entities: governs_components: [] supersedes: [] refines: [] + contradicts: [] relationships: declared_in: - ADR-L-0014 @@ -641,6 +785,9 @@ entities: superseded_by: [] refines: [] refined_by: [] + contradicts: [] + rejects: [] + rejected_by: [] completeness: status: complete missing_fields: [] @@ -657,6 +804,7 @@ entities: Workspace-specific references in source code create coupling to a single consumer. By codifying workspace agnosticism as an invariant with automated enforcement (grep-based CI check), the tool remains portable across all lifecycle_stage: proposed + admission_status: admitted canonical_source: source_type: logical_adr source_ref: ADR-L-0015#DEC-0015 @@ -670,6 +818,7 @@ entities: governs_components: [] supersedes: [] refines: [] + contradicts: [] relationships: declared_in: - ADR-L-0015 @@ -691,6 +840,9 @@ entities: superseded_by: [] refines: [] refined_by: [] + contradicts: [] + rejects: [] + rejected_by: [] completeness: status: complete missing_fields: [] @@ -707,6 +859,7 @@ entities: Producer-consumer drift between ste-runtime and workspace graph consumers caused validation failures. A defined contract with required core fields, ratified vocabularies, and explicit extension behavior eliminates this c lifecycle_stage: proposed + admission_status: admitted canonical_source: source_type: logical_adr source_ref: ADR-L-0016#DEC-0016 @@ -720,6 +873,7 @@ entities: governs_components: [] supersedes: [] refines: [] + contradicts: [] relationships: declared_in: - ADR-L-0016 @@ -741,6 +895,9 @@ entities: superseded_by: [] refines: [] refined_by: [] + contradicts: [] + rejects: [] + rejected_by: [] completeness: status: complete missing_fields: [] @@ -755,6 +912,7 @@ entities: name: Mandatory per-repo heartbeat (stdout) summary: Operators need deterministic progress granularity per repository. lifecycle_stage: proposed + admission_status: admitted canonical_source: source_type: logical_adr source_ref: ADR-L-0017#DEC-0017 @@ -768,6 +926,7 @@ entities: governs_components: [] supersedes: [] refines: [] + contradicts: [] relationships: declared_in: - ADR-L-0017 @@ -789,6 +948,9 @@ entities: superseded_by: [] refines: [] refined_by: [] + contradicts: [] + rejects: [] + rejected_by: [] completeness: status: complete missing_fields: [] @@ -803,6 +965,7 @@ entities: name: Opt-in cross-run incremental skip via --skip-unchanged and sentinel CONST-0015/CONST-0016. summary: Default runs remain untouched; caches are explicitly requested. lifecycle_stage: proposed + admission_status: admitted canonical_source: source_type: logical_adr source_ref: ADR-L-0017#DEC-0018 @@ -816,6 +979,7 @@ entities: governs_components: [] supersedes: [] refines: [] + contradicts: [] relationships: declared_in: - ADR-L-0017 @@ -837,6 +1001,9 @@ entities: superseded_by: [] refines: [] refined_by: [] + contradicts: [] + rejects: [] + rejected_by: [] completeness: status: complete missing_fields: [] @@ -851,6 +1018,7 @@ entities: name: Opt-in per-repo Promise timeout (--timeout-per-repo) summary: Bounded wait per repo frees concurrency slots; subprocess kill is intentionally out of scope. lifecycle_stage: proposed + admission_status: admitted canonical_source: source_type: logical_adr source_ref: ADR-L-0017#DEC-0019 @@ -864,6 +1032,7 @@ entities: governs_components: [] supersedes: [] refines: [] + contradicts: [] relationships: declared_in: - ADR-L-0017 @@ -885,6 +1054,9 @@ entities: superseded_by: [] refines: [] refined_by: [] + contradicts: [] + rejects: [] + rejected_by: [] completeness: status: complete missing_fields: [] @@ -901,6 +1073,7 @@ entities: Three standard questions (system dependencies, component integration, blast radius) are answerable purely from the typed verb edges in workspace slices. Making them deterministic: 1. Guarantees reproducibility (same grap lifecycle_stage: proposed + admission_status: admitted canonical_source: source_type: logical_adr source_ref: ADR-L-0018#DEC-0020 @@ -917,6 +1090,14 @@ entities: governs_components: [] supersedes: [] refines: [] + contradicts: [] + accumulated_consequences: + - Three standard questions answered without LLM cost or latency. + - Results are reproducible and testable with in-memory fixtures. + - Multiple output projections (Mermaid, table, matrix) from one query. + - Serves CLI, MCP, and programmatic API surfaces from the same engine. + - New loader required (workspace slices were previously unloadable). + - No natural language flexibility; exact node IDs required for blast radius target. relationships: declared_in: - ADR-L-0018 @@ -941,6 +1122,9 @@ entities: superseded_by: [] refines: [] refined_by: [] + contradicts: [] + rejects: [] + rejected_by: [] completeness: status: complete missing_fields: [] @@ -957,6 +1141,7 @@ entities: The current L4-only projection pipeline produces cognitively unusable output for human readers. Rather than introducing LLM-based summarization, the compression layer uses deterministic algorithms: 1. Endpoint path-prefi lifecycle_stage: proposed + admission_status: admitted canonical_source: source_type: logical_adr source_ref: ADR-L-0019#DEC-0021 @@ -973,6 +1158,14 @@ entities: governs_components: [] supersedes: [] refines: [] + contradicts: [] + accumulated_consequences: + - Five resolution levels serve distinct audiences (executive, platform, domain, integration, machine) + - All views derive from the same graph substrate ensuring consistency + - Deterministic output enables CI diffing and fixture-based testing + - Existing L4 projections are fully preserved for backward compatibility + - Additional code surface (compression engine, resolution-aware renderers) + - Capability domain heuristic (path-prefix grouping) may not perfectly match business domains relationships: declared_in: - ADR-L-0019 @@ -997,6 +1190,9 @@ entities: superseded_by: [] refines: [] refined_by: [] + contradicts: [] + rejects: [] + rejected_by: [] completeness: status: complete missing_fields: [] @@ -1013,6 +1209,7 @@ entities: Entity URI resolution is necessary but not sufficient for IDE and conversation-engine reasoning. ste-runtime must assemble a correctness-first CEM bundle, derive a bounded MVC projection, and validate the MVC against the lifecycle_stage: proposed + admission_status: admitted canonical_source: source_type: logical_adr source_ref: ADR-L-0020#DEC-0022 @@ -1030,6 +1227,14 @@ entities: governs_components: [] supersedes: [] refines: [] + contradicts: [] + accumulated_consequences: + - IDE agents can traverse the graph and retrieve authoritative source artifacts + - MVC bundles remain small while preserving provenance to CEM and source + - Source freshness and graph freshness can be validated before reasoning + - Future ste-kernel can consume runtime-produced CEM/MVC validation state + - Additional runtime artifact surface and tests + - More explicit stale and partial-state diagnostics for consumers to handle relationships: declared_in: - ADR-L-0020 @@ -1055,6 +1260,9 @@ entities: superseded_by: [] refines: [] refined_by: [] + contradicts: [] + rejects: [] + rejected_by: [] completeness: status: complete missing_fields: [] @@ -1064,3 +1272,71 @@ entities: extraction_phase: extract_decision classification: explicit generator: adr-architecture-index + - id: DEC-0023 + entity_type: decision + name: Add an experimental contract-consumption builder for MVC-D to MVC-S fixtures + summary: >- + A narrow fixture validator gives ste-runtime a contract-safe baseline before implementing RSS traversal or kernel + handoff. All candidate material is fully supplied to the builder; runtime does not reconstruct architectur + lifecycle_stage: proposed + admission_status: admitted + canonical_source: + source_type: logical_adr + source_ref: ADR-L-0021#DEC-0023 + artifact_path: adrs/logical/ADR-L-0021-experimental-mvc-d-to-mvc-s-contract-consumption.yaml + source_refs: [] + metadata: + adr_id: ADR-L-0021 + related_invariants: + - INV-0030 + - INV-0031 + - INV-0032 + enforces_invariants: [] + enables_capabilities: + - CAP-0021 + governs_components: [] + supersedes: [] + refines: [] + contradicts: [] + accumulated_consequences: + - Runtime can validate ste-spec MVC contracts locally + - Candidate-only semantics are executable and testable + - Code provenance can link implementation to this ADR + - Additional experimental surface must remain clearly separated from legacy CEM/MVC + relationships: + declared_in: + - ADR-L-0021 + declares: [] + references: [] + referenced_by: [] + related_to: [] + enforces: + - INV-0030 + - INV-0031 + - INV-0032 + enforced_by: [] + enabled_by: [] + enables: + - CAP-0021 + governs: [] + governed_by: [] + implemented_by: [] + implements: [] + embodied_in: [] + embodies: [] + supersedes: [] + superseded_by: [] + refines: [] + refined_by: [] + contradicts: [] + rejects: [] + rejected_by: [] + completeness: + status: complete + missing_fields: [] + provenance: + source_type: logical_adr + source_ref: ADR-L-0021#DEC-0023 + extraction_phase: extract_decision + classification: explicit + generator: adr-architecture-index diff --git a/adrs/index/entity-registry.yaml b/adrs/index/entity-registry.yaml index a04a539..936d610 100644 --- a/adrs/index/entity-registry.yaml +++ b/adrs/index/entity-registry.yaml @@ -8,6 +8,7 @@ entities: The STE Architecture Specification defines RECON (Reconciliation Engine) as the mechanism for extracting semantic state from source code and populating AI-DOC. The question arose: How should RECON operate during the expl lifecycle_stage: active + admission_status: admitted canonical_source: source_type: logical_adr source_ref: ADR-L-0001 @@ -65,6 +66,9 @@ entities: superseded_by: [] refines: [] refined_by: [] + contradicts: [] + rejects: [] + rejected_by: [] completeness: status: complete missing_fields: [] @@ -81,6 +85,7 @@ entities: RECON generates AI-DOC state from source code extraction. The question arose: How should RECON validate its own output to ensure consistency and quality? Key tensions: 1. **Blocking vs. Non-Blocking:** Should validation lifecycle_stage: active + admission_status: admitted canonical_source: source_type: logical_adr source_ref: ADR-L-0002 @@ -122,6 +127,9 @@ entities: superseded_by: [] refines: [] refined_by: [] + contradicts: [] + rejects: [] + rejected_by: [] completeness: status: complete missing_fields: [] @@ -138,6 +146,7 @@ entities: The STE Architecture Specification (ste-spec) defines a 9-stage Cognitive Execution Model (CEM): ``` Perception → Orientation → Analysis → Deliberation → Planning → Execution → Observation → Reflection → Adaptation ``` C lifecycle_stage: active + admission_status: admitted canonical_source: source_type: logical_adr source_ref: ADR-L-0003 @@ -179,6 +188,9 @@ entities: superseded_by: [] refines: [] refined_by: [] + contradicts: [] + rejects: [] + rejected_by: [] completeness: status: complete missing_fields: [] @@ -195,6 +207,7 @@ entities: Per STE Architecture (Section 3.1), STE operates across two distinct governance boundaries: 1. **Workspace Development Boundary** - Provisional state, soft + hard enforcement, post-reasoning validation 2. **Runtime Execu lifecycle_stage: active + admission_status: admitted canonical_source: source_type: logical_adr source_ref: ADR-L-0004 @@ -236,6 +249,9 @@ entities: superseded_by: [] refines: [] refined_by: [] + contradicts: [] + rejects: [] + rejected_by: [] completeness: status: complete missing_fields: [] @@ -250,6 +266,7 @@ entities: name: Self-Configuring Domain Discovery summary: '' lifecycle_stage: proposed + admission_status: admitted canonical_source: source_type: logical_adr source_ref: ADR-L-0005 @@ -288,6 +305,9 @@ entities: superseded_by: [] refines: [] refined_by: [] + contradicts: [] + rejects: [] + rejected_by: [] completeness: status: complete missing_fields: [] @@ -304,6 +324,7 @@ entities: E-ADR-004 established the RSS CLI and TypeScript API as the foundation for graph traversal and context assembly. However, a gap exists between: 1. **Raw RSS operations** (search, dependencies, blast-radius) - require kno lifecycle_stage: proposed + admission_status: admitted canonical_source: source_type: logical_adr source_ref: ADR-L-0006 @@ -345,6 +366,9 @@ entities: superseded_by: [] refines: [] refined_by: [] + contradicts: [] + rejects: [] + rejected_by: [] completeness: status: complete missing_fields: [] @@ -361,6 +385,7 @@ entities: ste-runtime now exposes graph freshness checks, invalidated validation signals, change intent handling, and obligation projection behavior through RSS and MCP tooling. These semantics are broader than implementation deta lifecycle_stage: proposed + admission_status: admitted canonical_source: source_type: logical_adr source_ref: ADR-L-0007 @@ -403,6 +428,9 @@ entities: superseded_by: [] refines: [] refined_by: [] + contradicts: [] + rejects: [] + rejected_by: [] completeness: status: complete missing_fields: [] @@ -419,6 +447,7 @@ entities: Reconnaissance tools traditionally assume a single repository as the unit of analysis. Multi-repo systems require scope to expand to the workspace level so that cross-repo relationships, shared configuration, and aggrega lifecycle_stage: proposed + admission_status: admitted canonical_source: source_type: logical_adr source_ref: ADR-L-0009 @@ -463,6 +492,9 @@ entities: superseded_by: [] refines: [] refined_by: [] + contradicts: [] + rejects: [] + rejected_by: [] completeness: status: complete missing_fields: [] @@ -479,6 +511,7 @@ entities: Without a first-class init command, onboarding requires manual file creation and sequencing knowledge. Users must know which files to create, in which order, and which values to populate. This friction slows adoption and lifecycle_stage: proposed + admission_status: admitted canonical_source: source_type: logical_adr source_ref: ADR-L-0010 @@ -517,6 +550,9 @@ entities: superseded_by: [] refines: [] refined_by: [] + contradicts: [] + rejects: [] + rejected_by: [] completeness: status: complete missing_fields: [] @@ -533,6 +569,7 @@ entities: STE defines five subsystems. ste-runtime is the RuntimeAdapter. Its role and publication surface must be declared, not assumed. Without explicit conformance, the runtime risks emitting artifacts outside its authority or lifecycle_stage: proposed + admission_status: admitted canonical_source: source_type: logical_adr source_ref: ADR-L-0011 @@ -571,6 +608,9 @@ entities: superseded_by: [] refines: [] refined_by: [] + contradicts: [] + rejects: [] + rejected_by: [] completeness: status: complete missing_fields: [] @@ -587,6 +627,7 @@ entities: STE subsystems are written in different languages. On-disk artifacts are the only interop boundary. Neither runtime invents schema. Without a single schema authority, subsystems risk copying, re-deriving, or hand-maintai lifecycle_stage: proposed + admission_status: admitted canonical_source: source_type: logical_adr source_ref: ADR-L-0012 @@ -611,6 +652,7 @@ entities: references: [] referenced_by: - ADR-L-0016 + - ADR-L-0021 related_to: [] enforces: [] enforced_by: [] @@ -626,6 +668,9 @@ entities: superseded_by: [] refines: [] refined_by: [] + contradicts: [] + rejects: [] + rejected_by: [] completeness: status: complete missing_fields: [] @@ -642,6 +687,7 @@ entities: Windows, macOS, and Linux represent paths differently. Any path persisted to a file, logged, or used as an identifier must be portable. src/utils/paths.ts already implements the correct helpers (toPosixPath, getRelativeP lifecycle_stage: proposed + admission_status: admitted canonical_source: source_type: logical_adr source_ref: ADR-L-0013 @@ -682,6 +728,9 @@ entities: superseded_by: [] refines: [] refined_by: [] + contradicts: [] + rejects: [] + rejected_by: [] completeness: status: complete missing_fields: [] @@ -698,6 +747,7 @@ entities: Enterprise environments route package installs through private registry instances. These hosts are unreachable outside the corporate network and their URLs are work-context IP. Source code, configuration, generated artif lifecycle_stage: proposed + admission_status: admitted canonical_source: source_type: logical_adr source_ref: ADR-L-0014 @@ -736,6 +786,9 @@ entities: superseded_by: [] refines: [] refined_by: [] + contradicts: [] + rejects: [] + rejected_by: [] completeness: status: complete missing_fields: [] @@ -752,6 +805,7 @@ entities: ste-runtime is an OSS tool that operates on arbitrary workspaces. Each workspace declares its own repository list, output directory, and domain vocabulary in workspace.yaml. The runtime must never contain references to a lifecycle_stage: proposed + admission_status: admitted canonical_source: source_type: logical_adr source_ref: ADR-L-0015 @@ -797,6 +851,9 @@ entities: superseded_by: [] refines: [] refined_by: [] + contradicts: [] + rejects: [] + rejected_by: [] completeness: status: complete missing_fields: [] @@ -813,6 +870,7 @@ entities: ste-runtime produces per-repository graph slices during workspace RECON. These slices are consumed by the runtime-owned workspace merger to produce a unified workspace graph and multi-resolution projections. Without a de lifecycle_stage: proposed + admission_status: admitted canonical_source: source_type: logical_adr source_ref: ADR-L-0016 @@ -838,6 +896,7 @@ entities: - DEC-0016 - INV-0017 - INV-0018 + - INV-0025 references: - ADR-L-0009 - ADR-L-0012 @@ -846,6 +905,7 @@ entities: - ADR-L-0018 - ADR-L-0019 - ADR-L-0020 + - ADR-L-0021 related_to: [] enforces: [] enforced_by: [] @@ -861,6 +921,9 @@ entities: superseded_by: [] refines: [] refined_by: [] + contradicts: [] + rejects: [] + rejected_by: [] completeness: status: complete missing_fields: [] @@ -877,6 +940,7 @@ entities: ADR-L-0009 fixes workspace as the universal scope unit. This ADR records how workspace RECON execution behaves for observability, optional incremental cross-run skips, and optional per-repository timeouts without changin lifecycle_stage: proposed + admission_status: admitted canonical_source: source_type: logical_adr source_ref: ADR-L-0017 @@ -920,6 +984,9 @@ entities: superseded_by: [] refines: [] refined_by: [] + contradicts: [] + rejects: [] + rejected_by: [] completeness: status: complete missing_fields: [] @@ -936,6 +1003,7 @@ entities: The workspace semantic graph (verb-typed edges in slices/*.yaml, produced per ADR-L-0016) already contains the relationships needed to answer standard system-level questions such as "show me the repo dependency map," "sh lifecycle_stage: proposed + admission_status: admitted canonical_source: source_type: logical_adr source_ref: ADR-L-0018 @@ -986,6 +1054,9 @@ entities: superseded_by: [] refines: [] refined_by: [] + contradicts: [] + rejects: [] + rejected_by: [] completeness: status: complete missing_fields: [] @@ -1002,6 +1073,7 @@ entities: ADR-L-0018 established deterministic workspace graph querying with L4 (full fidelity) projection rendering. The resulting projections prove the pipeline works but produce cognitively unusable output for human readers. Ev lifecycle_stage: proposed + admission_status: admitted canonical_source: source_type: logical_adr source_ref: ADR-L-0019 @@ -1050,6 +1122,9 @@ entities: superseded_by: [] refines: [] refined_by: [] + contradicts: [] + rejects: [] + rejected_by: [] completeness: status: complete missing_fields: [] @@ -1066,6 +1141,7 @@ entities: The workspace graph currently supports deterministic traversal and projection, but graph entities need stable, portable links back to authoritative source artifacts before the graph can safely support IDE-native reasonin lifecycle_stage: proposed + admission_status: admitted canonical_source: source_type: logical_adr source_ref: ADR-L-0020 @@ -1101,7 +1177,8 @@ entities: - ADR-L-0017 - ADR-L-0018 - ADR-L-0019 - referenced_by: [] + referenced_by: + - ADR-L-0021 related_to: [] enforces: [] enforced_by: [] @@ -1117,6 +1194,9 @@ entities: superseded_by: [] refines: [] refined_by: [] + contradicts: [] + rejects: [] + rejected_by: [] completeness: status: complete missing_fields: [] @@ -1126,6 +1206,74 @@ entities: extraction_phase: extract_adr classification: explicit generator: adr-architecture-index + - id: ADR-L-0021 + entity_type: adr + name: Experimental MVC-D to MVC-S Contract Consumption + summary: >- + ste-spec now defines draft MVC-D and MVC-S schemas as part of the MVC evolution contract surface. ste-runtime + needs an experimental contract-consumption slice that proves it can validate MVC-D fixtures and emit factual M + lifecycle_stage: proposed + admission_status: admitted + canonical_source: + source_type: logical_adr + source_ref: ADR-L-0021 + artifact_path: adrs/logical/ADR-L-0021-experimental-mvc-d-to-mvc-s-contract-consumption.yaml + source_refs: [] + metadata: + status: proposed + domains: + - mvc + - contracts + - runtime + - provenance + tags: + - mvc-d + - mvc-s + - contract-consumption + - candidate-surface + - provenance + related_reviews: [] + related_overrides: [] + relationships: + declared_in: [] + declares: + - CAP-0021 + - DEC-0023 + - INV-0030 + - INV-0031 + - INV-0032 + references: + - ADR-L-0012 + - ADR-L-0016 + - ADR-L-0020 + referenced_by: [] + related_to: [] + enforces: [] + enforced_by: [] + enabled_by: [] + enables: [] + governs: [] + governed_by: [] + implemented_by: [] + implements: [] + embodied_in: [] + embodies: [] + supersedes: [] + superseded_by: [] + refines: [] + refined_by: [] + contradicts: [] + rejects: [] + rejected_by: [] + completeness: + status: complete + missing_fields: [] + provenance: + source_type: logical_adr + source_ref: ADR-L-0021 + extraction_phase: extract_adr + classification: explicit + generator: adr-architecture-index - id: ADR-P-0001 entity_type: adr name: RSS CLI Implementation for Developer-Invoked Graph Traversal @@ -1133,6 +1281,7 @@ entities: The STE Architecture Specification Section 4.6 defines RSS (Runtime State-Slicing) as the component responsible for graph traversal and context assembly from AI-DOC state. RSS provides six core operations: | Operation | lifecycle_stage: active + admission_status: admitted canonical_source: source_type: physical_adr source_ref: ADR-P-0001 @@ -1171,6 +1320,9 @@ entities: superseded_by: [] refines: [] refined_by: [] + contradicts: [] + rejects: [] + rejected_by: [] completeness: status: complete missing_fields: [] @@ -1187,6 +1339,7 @@ entities: Many enterprise codebases contain JSON files with semantic value beyond simple configuration: | Category | Examples | Semantic Value | |----------|----------|----------------| | Controls/Rules Catalog | Security controls lifecycle_stage: superseded + admission_status: admitted canonical_source: source_type: physical_adr source_ref: ADR-P-0002 @@ -1225,6 +1378,9 @@ entities: superseded_by: [] refines: [] refined_by: [] + contradicts: [] + rejects: [] + rejected_by: [] completeness: status: complete missing_fields: [] @@ -1241,6 +1397,7 @@ entities: The TypeScript extractor currently processes Angular files as standard TypeScript, capturing: - Functions and their signatures - Classes and their methods - Import/export relationships - Module structure However, Angular lifecycle_stage: superseded + admission_status: admitted canonical_source: source_type: physical_adr source_ref: ADR-P-0003 @@ -1280,6 +1437,9 @@ entities: superseded_by: [] refines: [] refined_by: [] + contradicts: [] + rejects: [] + rejected_by: [] completeness: status: complete missing_fields: [] @@ -1296,6 +1456,7 @@ entities: Per STE Architecture Section 3.1, the Workspace Development Boundary requires: - **Provisional state** maintenance (pre-merge, feature branches) - **Soft + hard enforcement** (LLM instruction-following + validation tools lifecycle_stage: superseded + admission_status: admitted canonical_source: source_type: physical_adr source_ref: ADR-P-0004 @@ -1334,6 +1495,9 @@ entities: superseded_by: [] refines: [] refined_by: [] + contradicts: [] + rejects: [] + rejected_by: [] completeness: status: complete missing_fields: [] @@ -1348,6 +1512,7 @@ entities: name: Extractor Validation Requirements summary: '' lifecycle_stage: active + admission_status: admitted canonical_source: source_type: physical_adr source_ref: ADR-P-0005 @@ -1385,6 +1550,9 @@ entities: superseded_by: [] refines: [] refined_by: [] + contradicts: [] + rejects: [] + rejected_by: [] completeness: status: complete missing_fields: [] @@ -1401,6 +1569,7 @@ entities: This component exposes assistant-facing runtime tools over MCP and binds structural, operational, context, optimized, obligation-oriented, and workspace graph query tool surfaces into one discoverable server boundary. lifecycle_stage: proposed + admission_status: admitted canonical_source: source_type: physical_component_adr source_ref: ADR-PC-0001 @@ -1437,6 +1606,9 @@ entities: superseded_by: [] refines: [] refined_by: [] + contradicts: [] + rejects: [] + rejected_by: [] completeness: status: complete missing_fields: [] @@ -1453,6 +1625,7 @@ entities: This component monitors changes, detects transactions, coordinates update batches, and safeguards write-triggered reconciliation behavior for the runtime boundary. lifecycle_stage: proposed + admission_status: admitted canonical_source: source_type: physical_component_adr source_ref: ADR-PC-0002 @@ -1489,6 +1662,9 @@ entities: superseded_by: [] refines: [] refined_by: [] + contradicts: [] + rejects: [] + rejected_by: [] completeness: status: complete missing_fields: [] @@ -1505,6 +1681,7 @@ entities: This component evaluates file freshness, intent scope, and reconciliation requirements before runtime actions rely on semantic graph state. lifecycle_stage: proposed + admission_status: admitted canonical_source: source_type: physical_component_adr source_ref: ADR-PC-0003 @@ -1541,6 +1718,9 @@ entities: superseded_by: [] refines: [] refined_by: [] + contradicts: [] + rejects: [] + rejected_by: [] completeness: status: complete missing_fields: [] @@ -1557,6 +1737,7 @@ entities: This component projects invalidated validations and change-driven obligations, assembles implementation context, and loads source-backed evidence for assistant-facing reasoning. lifecycle_stage: proposed + admission_status: admitted canonical_source: source_type: physical_component_adr source_ref: ADR-PC-0004 @@ -1593,6 +1774,9 @@ entities: superseded_by: [] refines: [] refined_by: [] + contradicts: [] + rejects: [] + rejected_by: [] completeness: status: complete missing_fields: [] @@ -1609,6 +1793,7 @@ entities: JSON semantic extraction captures controls, schemas, and configuration semantics from JSON sources and feeds them into RECON normalization. lifecycle_stage: proposed + admission_status: admitted canonical_source: source_type: physical_component_adr source_ref: ADR-PC-0005 @@ -1645,6 +1830,9 @@ entities: superseded_by: [] refines: [] refined_by: [] + contradicts: [] + rejects: [] + rejected_by: [] completeness: status: complete missing_fields: [] @@ -1661,6 +1849,7 @@ entities: Frontend semantic extraction captures Angular and CSS/SCSS-specific semantics beyond generic TypeScript structure and feeds them into RECON normalization. lifecycle_stage: proposed + admission_status: admitted canonical_source: source_type: physical_component_adr source_ref: ADR-PC-0006 @@ -1697,6 +1886,9 @@ entities: superseded_by: [] refines: [] refined_by: [] + contradicts: [] + rejects: [] + rejected_by: [] completeness: status: complete missing_fields: [] @@ -1714,6 +1906,7 @@ entities: relationships, and template-level implementation intent from CloudFormation sources. This includes nested stack topolo lifecycle_stage: proposed + admission_status: admitted canonical_source: source_type: physical_component_adr source_ref: ADR-PC-0007 @@ -1750,6 +1943,9 @@ entities: superseded_by: [] refines: [] refined_by: [] + contradicts: [] + rejects: [] + rejected_by: [] completeness: status: complete missing_fields: [] @@ -1766,6 +1962,7 @@ entities: RECON produces rich per-repository state (call graphs, SDK usage, env vars, CFN resources, triggers) but the workspace slice emitter collapsed this to a skeleton with only has_contract edges. Cross-domain joins (SDK usag lifecycle_stage: proposed + admission_status: admitted canonical_source: source_type: physical_component_adr source_ref: ADR-PC-0008 @@ -1802,6 +1999,9 @@ entities: superseded_by: [] refines: [] refined_by: [] + contradicts: [] + rejects: [] + rejected_by: [] completeness: status: complete missing_fields: [] @@ -1818,6 +2018,7 @@ entities: ADR-L-0018 established the capability for deterministic workspace graph querying. This component implements the loader, three canned query functions, and three projection renderers that realize that capability. It consum lifecycle_stage: proposed + admission_status: admitted canonical_source: source_type: physical_component_adr source_ref: ADR-PC-0009 @@ -1858,6 +2059,9 @@ entities: superseded_by: [] refines: [] refined_by: [] + contradicts: [] + rejects: [] + rejected_by: [] completeness: status: complete missing_fields: [] @@ -1874,6 +2078,7 @@ entities: ADR-L-0019 established the capability for multi-resolution architecture projection using deterministic semantic compression. This component implements the compression engine, resolution-aware renderers, multi-resolution lifecycle_stage: proposed + admission_status: admitted canonical_source: source_type: physical_component_adr source_ref: ADR-PC-0010 @@ -1914,6 +2119,9 @@ entities: superseded_by: [] refines: [] refined_by: [] + contradicts: [] + rejects: [] + rejected_by: [] completeness: status: complete missing_fields: [] @@ -1930,6 +2138,7 @@ entities: ADR YAML semantic extraction converts Architecture Decision Records authored in the ADR-kit YAML schema into first-class RECON graph slices. This enables the MCP query tools (find, impact, usages, similar) to operate ove lifecycle_stage: proposed + admission_status: admitted canonical_source: source_type: physical_component_adr source_ref: ADR-PC-0011 @@ -1966,6 +2175,9 @@ entities: superseded_by: [] refines: [] refined_by: [] + contradicts: [] + rejects: [] + rejected_by: [] completeness: status: complete missing_fields: [] @@ -1983,6 +2195,7 @@ entities: assistant-facing MCP tools, performs reconciliation gating and freshness checks, and assembles implementation context and lifecycle_stage: proposed + admission_status: admitted canonical_source: source_type: physical_system_adr source_ref: ADR-PS-0001 @@ -2028,6 +2241,9 @@ entities: superseded_by: [] refines: [] refined_by: [] + contradicts: [] + rejects: [] + rejected_by: [] completeness: status: complete missing_fields: [] @@ -2044,6 +2260,7 @@ entities: ste-runtime extraction is now a subsystem containing multiple first-class extractors and normalization flows rather than a pair of isolated physical slices. This ADR groups the implemented extractor estate under a concre lifecycle_stage: proposed + admission_status: admitted canonical_source: source_type: physical_system_adr source_ref: ADR-PS-0002 @@ -2086,6 +2303,9 @@ entities: superseded_by: [] refines: [] refined_by: [] + contradicts: [] + rejects: [] + rejected_by: [] completeness: status: complete missing_fields: [] @@ -2100,6 +2320,7 @@ entities: name: Surface graph freshness and obligation projection semantics summary: Provide canonical freshness, invalidation, and obligation semantics for runtime consumers. lifecycle_stage: proposed + admission_status: admitted canonical_source: source_type: logical_adr source_ref: ADR-L-0007#CAP-0007 @@ -2134,6 +2355,9 @@ entities: superseded_by: [] refines: [] refined_by: [] + contradicts: [] + rejects: [] + rejected_by: [] completeness: status: complete missing_fields: [] @@ -2148,6 +2372,7 @@ entities: name: Workspace-scoped analysis summary: All reconnaissance and evidence emission operates on workspace scope. lifecycle_stage: proposed + admission_status: admitted canonical_source: source_type: logical_adr source_ref: ADR-L-0009#CAP-0009 @@ -2181,6 +2406,9 @@ entities: superseded_by: [] refines: [] refined_by: [] + contradicts: [] + rejects: [] + rejected_by: [] completeness: status: complete missing_fields: [] @@ -2193,8 +2421,11 @@ entities: - id: CAP-0010 entity_type: capability name: One-command workspace initialization - summary: ste init creates a fully configured workspace. + summary: >- + ste setup creates a fully configured workspace (config, MCP, gitignore, initial RECON). ste init remains as the + sub-capability for scaffolding workspace.yaml specifically. lifecycle_stage: proposed + admission_status: admitted canonical_source: source_type: logical_adr source_ref: ADR-L-0010#CAP-0010 @@ -2228,6 +2459,9 @@ entities: superseded_by: [] refines: [] refined_by: [] + contradicts: [] + rejects: [] + rejected_by: [] completeness: status: complete missing_fields: [] @@ -2240,8 +2474,9 @@ entities: - id: CAP-0011 entity_type: capability name: ArchitectureEvidence emission - summary: Emit ArchitectureEvidence v2 at .ste-workspace/evidence/architecture-evidence.json. + summary: Emit ArchitectureEvidence v2 at .workspace-graph/evidence/architecture-evidence.json. lifecycle_stage: proposed + admission_status: admitted canonical_source: source_type: logical_adr source_ref: ADR-L-0011#CAP-0011 @@ -2275,6 +2510,9 @@ entities: superseded_by: [] refines: [] refined_by: [] + contradicts: [] + rejects: [] + rejected_by: [] completeness: status: complete missing_fields: [] @@ -2291,6 +2529,7 @@ entities: ste-runtime consumes architecture-evidence.schema.json via fixture sync in test/fixtures/. Drift is detected by spec-schema-fixture-sync.test.ts. lifecycle_stage: proposed + admission_status: admitted canonical_source: source_type: logical_adr source_ref: ADR-L-0012#CAP-0012 @@ -2324,6 +2563,9 @@ entities: superseded_by: [] refines: [] refined_by: [] + contradicts: [] + rejects: [] + rejected_by: [] completeness: status: complete missing_fields: [] @@ -2340,6 +2582,7 @@ entities: ste-runtime operates identically in any workspace without source code changes. All workspace-specific values (repo names, output directories, domain vocabulary) are derived from workspace.yaml at runtime. lifecycle_stage: proposed + admission_status: admitted canonical_source: source_type: logical_adr source_ref: ADR-L-0015#CAP-0015 @@ -2374,6 +2617,9 @@ entities: superseded_by: [] refines: [] refined_by: [] + contradicts: [] + rejects: [] + rejected_by: [] completeness: status: complete missing_fields: [] @@ -2390,6 +2636,7 @@ entities: ste-runtime emits workspace graph slices that conform to a defined schema contract, enabling any compliant merger to consume them without validation errors. lifecycle_stage: proposed + admission_status: admitted canonical_source: source_type: logical_adr source_ref: ADR-L-0016#CAP-0016 @@ -2424,6 +2671,9 @@ entities: superseded_by: [] refines: [] refined_by: [] + contradicts: [] + rejects: [] + rejected_by: [] completeness: status: complete missing_fields: [] @@ -2440,6 +2690,7 @@ entities: Load workspace infra graph slices into a typed in-memory graph and execute deterministic, non-LLM traversal queries that answer standard workspace-level questions (system dependencies, component integration, blast radius lifecycle_stage: proposed + admission_status: admitted canonical_source: source_type: logical_adr source_ref: ADR-L-0018#CAP-0018 @@ -2480,6 +2731,9 @@ entities: superseded_by: [] refines: [] refined_by: [] + contradicts: [] + rejects: [] + rejected_by: [] completeness: status: complete missing_fields: [] @@ -2496,6 +2750,7 @@ entities: Produce architecture projections at five deterministic resolution levels (L0-L4) from the same workspace graph substrate, using semantic compression (endpoint grouping, same-type aggregation, edge tier filtering) to opti lifecycle_stage: proposed + admission_status: admitted canonical_source: source_type: logical_adr source_ref: ADR-L-0019#CAP-0019 @@ -2536,6 +2791,9 @@ entities: superseded_by: [] refines: [] refined_by: [] + contradicts: [] + rejects: [] + rejected_by: [] completeness: status: complete missing_fields: [] @@ -2552,6 +2810,7 @@ entities: Resolve workspace graph entities to authoritative source artifacts through stable URI locators, assemble CEM bundles with provenance and validation state, derive bounded MVC bundles, and validate MVC bundles against thei lifecycle_stage: proposed + admission_status: admitted canonical_source: source_type: logical_adr source_ref: ADR-L-0020#CAP-0020 @@ -2594,6 +2853,9 @@ entities: superseded_by: [] refines: [] refined_by: [] + contradicts: [] + rejects: [] + rejected_by: [] completeness: status: complete missing_fields: [] @@ -2603,6 +2865,62 @@ entities: extraction_phase: extract_capability classification: explicit generator: adr-architecture-index + - id: CAP-0021 + entity_type: capability + name: Experimental MVC-D to MVC-S candidate emission + summary: >- + Consume ste-spec-owned MVC-D and MVC-S contracts in tests and emit deterministic factual MVC-S candidate snapshots + from fully supplied fixture inputs. + lifecycle_stage: proposed + admission_status: admitted + canonical_source: + source_type: logical_adr + source_ref: ADR-L-0021#CAP-0021 + artifact_path: adrs/logical/ADR-L-0021-experimental-mvc-d-to-mvc-s-contract-consumption.yaml + source_refs: [] + metadata: + adr_id: ADR-L-0021 + domains: + - mvc + - contracts + - runtime + - provenance + implemented_by_components: [] + enabled_by_decisions: [] + relationships: + declared_in: + - ADR-L-0021 + declares: [] + references: [] + referenced_by: [] + related_to: [] + enforces: [] + enforced_by: [] + enabled_by: + - DEC-0023 + enables: [] + governs: [] + governed_by: [] + implemented_by: [] + implements: [] + embodied_in: [] + embodies: [] + supersedes: [] + superseded_by: [] + refines: [] + refined_by: [] + contradicts: [] + rejects: [] + rejected_by: [] + completeness: + status: complete + missing_fields: [] + provenance: + source_type: logical_adr + source_ref: ADR-L-0021#CAP-0021 + extraction_phase: extract_capability + classification: explicit + generator: adr-architecture-index - id: COMP-0001 entity_type: component name: MCP Server and Tool Registry @@ -2610,6 +2928,7 @@ entities: - Serve MCP stdio runtime for assistant integration - Register structural, operational, context, optimized, obligation, and workspace graph query tools - Route tool requests onto runtime graph, context, and workspace que lifecycle_stage: proposed + admission_status: admitted canonical_source: source_type: physical_component_adr source_ref: ADR-PC-0001#COMP-0001 @@ -2649,6 +2968,9 @@ entities: superseded_by: [] refines: [] refined_by: [] + contradicts: [] + rejects: [] + rejected_by: [] completeness: status: complete missing_fields: [] @@ -2665,6 +2987,7 @@ entities: - Watch source and state changes - Detect coherent edit transactions - Coordinate update batches and reconciliation triggers - Protect runtime behavior from unsafe write loops lifecycle_stage: proposed + admission_status: admitted canonical_source: source_type: physical_component_adr source_ref: ADR-PC-0002#COMP-0002 @@ -2703,6 +3026,9 @@ entities: superseded_by: [] refines: [] refined_by: [] + contradicts: [] + rejects: [] + rejected_by: [] completeness: status: complete missing_fields: [] @@ -2719,6 +3045,7 @@ entities: - Resolve intent scope - Evaluate graph freshness - Determine whether reconciliation is required - Surface freshness status for downstream tools lifecycle_stage: proposed + admission_status: admitted canonical_source: source_type: physical_component_adr source_ref: ADR-PC-0003#COMP-0003 @@ -2757,6 +3084,9 @@ entities: superseded_by: [] refines: [] refined_by: [] + contradicts: [] + rejects: [] + rejected_by: [] completeness: status: complete missing_fields: [] @@ -2773,6 +3103,7 @@ entities: - Project obligations from change intent and graph state - Surface invalidated validations and advisories - Load source-backed implementation context - Format runtime context for assistant consumption lifecycle_stage: proposed + admission_status: admitted canonical_source: source_type: physical_component_adr source_ref: ADR-PC-0004#COMP-0004 @@ -2811,6 +3142,9 @@ entities: superseded_by: [] refines: [] refined_by: [] + contradicts: [] + rejects: [] + rejected_by: [] completeness: status: complete missing_fields: [] @@ -2827,6 +3161,7 @@ entities: - Detect semantically relevant JSON files - Extract controls, schemas, and configuration semantics - Provide RECON-ready assertions for normalization lifecycle_stage: proposed + admission_status: admitted canonical_source: source_type: physical_component_adr source_ref: ADR-PC-0005#COMP-0005 @@ -2865,6 +3200,9 @@ entities: superseded_by: [] refines: [] refined_by: [] + contradicts: [] + rejects: [] + rejected_by: [] completeness: status: complete missing_fields: [] @@ -2881,6 +3219,7 @@ entities: - Extract Angular component, service, route, and template semantics - Extract CSS/SCSS tokens, styles, and related frontend semantics - Provide frontend assertions for RECON normalization lifecycle_stage: proposed + admission_status: admitted canonical_source: source_type: physical_component_adr source_ref: ADR-PC-0006#COMP-0006 @@ -2920,6 +3259,9 @@ entities: superseded_by: [] refines: [] refined_by: [] + contradicts: [] + rejects: [] + rejected_by: [] completeness: status: complete missing_fields: [] @@ -2936,6 +3278,7 @@ entities: - Extract template, parameter, resource, and output semantics - Derive infrastructure relationships and API/data model evidence - Preserve template-level implementation intent metadata - Detect nested stack topology via lifecycle_stage: proposed + admission_status: admitted canonical_source: source_type: physical_component_adr source_ref: ADR-PC-0007#COMP-0007 @@ -2975,6 +3318,9 @@ entities: superseded_by: [] refines: [] refined_by: [] + contradicts: [] + rejects: [] + rejected_by: [] completeness: status: complete missing_fields: [] @@ -2991,6 +3337,7 @@ entities: - Build env-var-to-CFN-resource join maps from per-repo RECON state - Build SDK-service-to-graph-type maps (dynamodb->Database, s3->Bucket, etc.) - Build Lambda-handler-to-function maps from CFN handler metadata - Resolv lifecycle_stage: proposed + admission_status: admitted canonical_source: source_type: physical_component_adr source_ref: ADR-PC-0008#COMP-0008 @@ -3029,6 +3376,9 @@ entities: superseded_by: [] refines: [] refined_by: [] + contradicts: [] + rejects: [] + rejected_by: [] completeness: status: complete missing_fields: [] @@ -3042,9 +3392,10 @@ entities: entity_type: component name: Slice Emitter Edge Wiring summary: >- - - Produce reads/writes edges by joining SDK usage with infrastructure resources via env-var bridge - Produce - publishes edges for SQS/SNS SDK usage - Improve consumes edge resolution via CFN logical ID lookup - Produce de + - Emit all extracted CFN resources as workspace graph nodes (no allowlist gate; InfraResource fallback for + unmapped types) - Emit Stack nodes from infrastructure/template slices with contains edges to child resources - P lifecycle_stage: proposed + admission_status: admitted canonical_source: source_type: physical_component_adr source_ref: ADR-PC-0008#COMP-0009 @@ -3083,6 +3434,9 @@ entities: superseded_by: [] refines: [] refined_by: [] + contradicts: [] + rejects: [] + rejected_by: [] completeness: status: complete missing_fields: [] @@ -3099,6 +3453,7 @@ entities: - Load workspace graph slices into typed in-memory WorkspaceGraph - Build outAdj/inAdj adjacency maps at load time for O(1) neighbor lookups - Execute systemDependencies, componentIntegration, blastRadiusWorkspace querie lifecycle_stage: proposed + admission_status: admitted canonical_source: source_type: physical_component_adr source_ref: ADR-PC-0009#COMP-0010 @@ -3143,6 +3498,9 @@ entities: superseded_by: [] refines: [] refined_by: [] + contradicts: [] + rejects: [] + rejected_by: [] completeness: status: complete missing_fields: [] @@ -3159,6 +3517,7 @@ entities: - Compress CannedQueryResult into CompressedProjection at configurable resolution levels (L0-L4) - Group endpoints by capability domain using path-prefix extraction - Aggregate same-type nodes above threshold into count- lifecycle_stage: proposed + admission_status: admitted canonical_source: source_type: physical_component_adr source_ref: ADR-PC-0010#COMP-0011 @@ -3201,6 +3560,9 @@ entities: superseded_by: [] refines: [] refined_by: [] + contradicts: [] + rejects: [] + rejected_by: [] completeness: status: complete missing_fields: [] @@ -3217,6 +3579,7 @@ entities: - Detect and classify ADR YAML files via path-prefix and content sniffing - Parse ADR YAML using js-yaml - Extract ADR documents, invariants, decisions, capabilities, component specifications, and system boundaries as Ra lifecycle_stage: proposed + admission_status: admitted canonical_source: source_type: physical_component_adr source_ref: ADR-PC-0011#COMP-0012 @@ -3256,6 +3619,9 @@ entities: superseded_by: [] refines: [] refined_by: [] + contradicts: [] + rejects: [] + rejected_by: [] completeness: status: complete missing_fields: [] @@ -3272,6 +3638,7 @@ entities: ### 1. Semantic Pressure Over Semantic Truth RECON exists to **observe how semantic truth breaks under change**, not to declare what truth is. During exploratory development, the extraction algorithms, normalization sche lifecycle_stage: active + admission_status: admitted canonical_source: source_type: logical_adr source_ref: ADR-L-0001#DEC-0001 @@ -3285,6 +3652,18 @@ entities: governs_components: [] supersedes: [] refines: [] + contradicts: [] + accumulated_consequences: + - RECON can execute immediately, generating learning pressure + - Conflicts surface early, before they become entrenched + - Developers maintain full control over semantic state acceptance + - Extraction algorithms can evolve without breaking workflows + - No automated enforcement of semantic consistency + - Conflicts may accumulate if not reviewed + - Provisional state cannot be used for authoritative downstream systems + - Document all conflicts for periodic human review + - Track conflict patterns to improve extraction algorithms + - Plan transition to canonical execution once algorithms stabilize relationships: declared_in: - ADR-L-0001 @@ -3306,6 +3685,9 @@ entities: superseded_by: [] refines: [] refined_by: [] + contradicts: [] + rejects: [] + rejected_by: [] completeness: status: complete missing_fields: [] @@ -3322,6 +3704,7 @@ entities: ### 1. Non-Blocking Preserves Learning If validation blocked execution on every finding, RECON would become unusable during exploratory development. Many validation findings are informational or represent known limitatio lifecycle_stage: active + admission_status: admitted canonical_source: source_type: logical_adr source_ref: ADR-L-0002#DEC-0002 @@ -3335,6 +3718,19 @@ entities: governs_components: [] supersedes: [] refines: [] + contradicts: [] + accumulated_consequences: + - Continuous quality visibility without workflow disruption + - Historical trend data for extraction algorithm improvement + - Early detection of regression in extractors + - Developer confidence through transparency + - Findings may be ignored if too numerous + - No enforcement of quality gates + - Report accumulation without review + - Periodic finding review as part of development process + - Track finding counts over time for trend analysis + - Prioritize ERROR findings for immediate investigation + - Use findings to guide extractor improvements relationships: declared_in: - ADR-L-0002 @@ -3356,6 +3752,9 @@ entities: superseded_by: [] refines: [] refined_by: [] + contradicts: [] + rejects: [] + rejected_by: [] completeness: status: complete missing_fields: [] @@ -3372,6 +3771,7 @@ entities: ### 1. CEM Orchestrates Components That Must Exist First CEM's stages call into foundational components: - **Orientation** calls RSS for context assembly - **Analysis** reads AI-DOC semantic state - **Deliberation** invo lifecycle_stage: active + admission_status: admitted canonical_source: source_type: logical_adr source_ref: ADR-L-0003#DEC-0003 @@ -3385,6 +3785,18 @@ entities: governs_components: [] supersedes: [] refines: [] + contradicts: [] + accumulated_consequences: + - Foundation components can be built and tested independently + - API surfaces stabilize before CEM integration + - Reduced rework and premature abstraction + - Faster iteration on extraction/inference/traversal + - Autonomous agent execution blocked until CEM exists + - Formal governance auditing deferred + - Potential for API drift if CEM requirements not considered + - Document CEM's expected API contracts in ste-spec + - Periodically review foundation components against CEM needs + - Use execution pressure to surface integration gaps relationships: declared_in: - ADR-L-0003 @@ -3406,6 +3818,9 @@ entities: superseded_by: [] refines: [] refined_by: [] + contradicts: [] + rejects: [] + rejected_by: [] completeness: status: complete missing_fields: [] @@ -3423,6 +3838,7 @@ entities: (authoritative: it observed the file system event) 2. Migration detection scores confidence (1.0 = certain same element) lifecycle_stage: active + admission_status: admitted canonical_source: source_type: logical_adr source_ref: ADR-L-0004#DEC-0004 @@ -3436,6 +3852,7 @@ entities: governs_components: [] supersedes: [] refines: [] + contradicts: [] relationships: declared_in: - ADR-L-0004 @@ -3457,6 +3874,9 @@ entities: superseded_by: [] refines: [] refined_by: [] + contradicts: [] + rejects: [] + rejected_by: [] completeness: status: complete missing_fields: [] @@ -3471,6 +3891,7 @@ entities: name: DEC-0005 summary: '' lifecycle_stage: proposed + admission_status: admitted canonical_source: source_type: logical_adr source_ref: ADR-L-0005#DEC-0005 @@ -3484,6 +3905,42 @@ entities: governs_components: [] supersedes: [] refines: [] + contradicts: [] + accumulated_consequences: + - Drop into any project and run immediately + - No setup time, no learning curve + - Immediate value delivery + - Works with any project structure + - Works with any naming convention + - Works with any framework combination + - Understands project context automatically + - Tags and relationships use actual project names + - Output reflects real architecture + - Reduces barrier to entry dramatically + - Eliminates configuration errors + - Enables rapid experimentation + - Discovery output shows what was found + - Users understand what runtime sees + - Transparent behavior + - Discovery engine requires careful design + - Edge cases need handling + - More code to maintain + - 4 weeks vs 2 weeks for manual config + - Delays other features + - Higher upfront investment + - Heuristics may fail for unusual structures + - Need robust fallback mechanisms + - Requires extensive testing + - Clear abstractions and interfaces + - Comprehensive unit test coverage + - Well-documented heuristics + - Investment justified by adoption gains + - Phased implementation with validation gates + - Early user testing + - Confidence scoring system + - Graceful fallback to safe defaults + - Optional configuration override for edge cases + - Clear discovery debugging output relationships: declared_in: - ADR-L-0005 @@ -3505,6 +3962,9 @@ entities: superseded_by: [] refines: [] refined_by: [] + contradicts: [] + rejects: [] + rejected_by: [] completeness: status: complete missing_fields: [] @@ -3521,6 +3981,7 @@ entities: ### 1. Reduces Cognitive Load for Both Humans and AI Without CQI: ``` Human: "What would be affected by changing the auth service?" → Human must know: use blast-radius, specify key format, parse output → AI must know: co lifecycle_stage: proposed + admission_status: admitted canonical_source: source_type: logical_adr source_ref: ADR-L-0006#DEC-0006 @@ -3534,6 +3995,19 @@ entities: governs_components: [] supersedes: [] refines: [] + contradicts: [] + accumulated_consequences: + - '**Seamless UX**: Both humans and AI agents use natural language' + - '**Performance**: Sub-5ms queries, <0.3ms cached' + - '**Discoverability**: Suggested queries guide exploration' + - '**Dual output**: Same engine serves terminal and programmatic use' + - '**Foundation for MCP**: CQI becomes the MCP tool interface' + - '**Pattern maintenance**: New intent patterns require code changes' + - '**Cache staleness**: Risk of stale results if cache not invalidated' + - '**Abstraction cost**: Hides RSS complexity (may hinder advanced use)' + - Expose raw RSS API for power users + - Document intent patterns explicitly + - Integrate with Watchdog for automatic cache invalidation relationships: declared_in: - ADR-L-0006 @@ -3555,6 +4029,9 @@ entities: superseded_by: [] refines: [] refined_by: [] + contradicts: [] + rejects: [] + rejected_by: [] completeness: status: complete missing_fields: [] @@ -3571,6 +4048,7 @@ entities: The current runtime models freshness and obligation data in public schemas and assistant-facing responses, so these semantics require canonical documentation above the component layer. lifecycle_stage: proposed + admission_status: admitted canonical_source: source_type: logical_adr source_ref: ADR-L-0007#DEC-0007 @@ -3584,6 +4062,7 @@ entities: governs_components: [] supersedes: [] refines: [] + contradicts: [] relationships: declared_in: - ADR-L-0007 @@ -3605,6 +4084,9 @@ entities: superseded_by: [] refines: [] refined_by: [] + contradicts: [] + rejects: [] + rejected_by: [] completeness: status: complete missing_fields: [] @@ -3621,6 +4103,7 @@ entities: Multi-repo analysis cannot be retrofitted onto single-repo scope without pervasive special-casing. Defining workspace as the universal scope from the start eliminates that debt. A workspace containing a single repository lifecycle_stage: proposed + admission_status: admitted canonical_source: source_type: logical_adr source_ref: ADR-L-0009#DEC-0009 @@ -3634,6 +4117,7 @@ entities: governs_components: [] supersedes: [] refines: [] + contradicts: [] relationships: declared_in: - ADR-L-0009 @@ -3655,6 +4139,9 @@ entities: superseded_by: [] refines: [] refined_by: [] + contradicts: [] + rejects: [] + rejected_by: [] completeness: status: complete missing_fields: [] @@ -3666,11 +4153,13 @@ entities: generator: adr-architecture-index - id: DEC-0010 entity_type: decision - name: ste init is the canonical one-command install experience + name: ste setup is the canonical one-command install experience summary: >- - Manual onboarding is error-prone and slow. A first-class init command with binding constraints ensures consistent, - portable, and safe workspace initialization. + Manual onboarding is error-prone and slow. A first-class setup command with binding constraints ensures + consistent, portable, and safe workspace initialization. ste setup supersedes the narrower ste init by also + handling lifecycle_stage: proposed + admission_status: admitted canonical_source: source_type: logical_adr source_ref: ADR-L-0010#DEC-0010 @@ -3684,6 +4173,7 @@ entities: governs_components: [] supersedes: [] refines: [] + contradicts: [] relationships: declared_in: - ADR-L-0010 @@ -3705,6 +4195,9 @@ entities: superseded_by: [] refines: [] refined_by: [] + contradicts: [] + rejects: [] + rejected_by: [] completeness: status: complete missing_fields: [] @@ -3721,6 +4214,7 @@ entities: Explicit role conformance prevents scope leakage across subsystem boundaries and ensures evidence artifacts are schema-compliant. lifecycle_stage: proposed + admission_status: admitted canonical_source: source_type: logical_adr source_ref: ADR-L-0011#DEC-0011 @@ -3734,6 +4228,7 @@ entities: governs_components: [] supersedes: [] refines: [] + contradicts: [] relationships: declared_in: - ADR-L-0011 @@ -3755,6 +4250,9 @@ entities: superseded_by: [] refines: [] refined_by: [] + contradicts: [] + rejects: [] + rejected_by: [] completeness: status: complete missing_fields: [] @@ -3771,6 +4269,7 @@ entities: Polyglot subsystems cannot safely maintain independent copies of shared schemas. Centralizing authority in ste-spec eliminates drift and ensures all subsystems validate against the same contract. lifecycle_stage: proposed + admission_status: admitted canonical_source: source_type: logical_adr source_ref: ADR-L-0012#DEC-0012 @@ -3784,6 +4283,7 @@ entities: governs_components: [] supersedes: [] refines: [] + contradicts: [] relationships: declared_in: - ADR-L-0012 @@ -3805,6 +4305,9 @@ entities: superseded_by: [] refines: [] refined_by: [] + contradicts: [] + rejects: [] + rejected_by: [] completeness: status: complete missing_fields: [] @@ -3821,6 +4324,7 @@ entities: Platform-specific paths in persisted artifacts break cross-platform workflows. Enforcing POSIX-relative paths at the serialization boundary ensures portability without constraining internal disk-IO. lifecycle_stage: proposed + admission_status: admitted canonical_source: source_type: logical_adr source_ref: ADR-L-0013#DEC-0013 @@ -3834,6 +4338,7 @@ entities: governs_components: [] supersedes: [] refines: [] + contradicts: [] relationships: declared_in: - ADR-L-0013 @@ -3855,6 +4360,9 @@ entities: superseded_by: [] refines: [] refined_by: [] + contradicts: [] + rejects: [] + rejected_by: [] completeness: status: complete missing_fields: [] @@ -3871,6 +4379,7 @@ entities: Private registry URLs are work-context IP that must not appear in version-controlled files. Mechanical enforcement via the scanner prevents accidental leakage. lifecycle_stage: proposed + admission_status: admitted canonical_source: source_type: logical_adr source_ref: ADR-L-0014#DEC-0014 @@ -3884,6 +4393,7 @@ entities: governs_components: [] supersedes: [] refines: [] + contradicts: [] relationships: declared_in: - ADR-L-0014 @@ -3905,6 +4415,9 @@ entities: superseded_by: [] refines: [] refined_by: [] + contradicts: [] + rejects: [] + rejected_by: [] completeness: status: complete missing_fields: [] @@ -3921,6 +4434,7 @@ entities: Workspace-specific references in source code create coupling to a single consumer. By codifying workspace agnosticism as an invariant with automated enforcement (grep-based CI check), the tool remains portable across all lifecycle_stage: proposed + admission_status: admitted canonical_source: source_type: logical_adr source_ref: ADR-L-0015#DEC-0015 @@ -3934,6 +4448,7 @@ entities: governs_components: [] supersedes: [] refines: [] + contradicts: [] relationships: declared_in: - ADR-L-0015 @@ -3955,6 +4470,9 @@ entities: superseded_by: [] refines: [] refined_by: [] + contradicts: [] + rejects: [] + rejected_by: [] completeness: status: complete missing_fields: [] @@ -3971,6 +4489,7 @@ entities: Producer-consumer drift between ste-runtime and workspace graph consumers caused validation failures. A defined contract with required core fields, ratified vocabularies, and explicit extension behavior eliminates this c lifecycle_stage: proposed + admission_status: admitted canonical_source: source_type: logical_adr source_ref: ADR-L-0016#DEC-0016 @@ -3984,6 +4503,7 @@ entities: governs_components: [] supersedes: [] refines: [] + contradicts: [] relationships: declared_in: - ADR-L-0016 @@ -4005,6 +4525,9 @@ entities: superseded_by: [] refines: [] refined_by: [] + contradicts: [] + rejects: [] + rejected_by: [] completeness: status: complete missing_fields: [] @@ -4019,6 +4542,7 @@ entities: name: Mandatory per-repo heartbeat (stdout) summary: Operators need deterministic progress granularity per repository. lifecycle_stage: proposed + admission_status: admitted canonical_source: source_type: logical_adr source_ref: ADR-L-0017#DEC-0017 @@ -4032,6 +4556,7 @@ entities: governs_components: [] supersedes: [] refines: [] + contradicts: [] relationships: declared_in: - ADR-L-0017 @@ -4053,6 +4578,9 @@ entities: superseded_by: [] refines: [] refined_by: [] + contradicts: [] + rejects: [] + rejected_by: [] completeness: status: complete missing_fields: [] @@ -4067,6 +4595,7 @@ entities: name: Opt-in cross-run incremental skip via --skip-unchanged and sentinel CONST-0015/CONST-0016. summary: Default runs remain untouched; caches are explicitly requested. lifecycle_stage: proposed + admission_status: admitted canonical_source: source_type: logical_adr source_ref: ADR-L-0017#DEC-0018 @@ -4080,6 +4609,7 @@ entities: governs_components: [] supersedes: [] refines: [] + contradicts: [] relationships: declared_in: - ADR-L-0017 @@ -4101,6 +4631,9 @@ entities: superseded_by: [] refines: [] refined_by: [] + contradicts: [] + rejects: [] + rejected_by: [] completeness: status: complete missing_fields: [] @@ -4115,6 +4648,7 @@ entities: name: Opt-in per-repo Promise timeout (--timeout-per-repo) summary: Bounded wait per repo frees concurrency slots; subprocess kill is intentionally out of scope. lifecycle_stage: proposed + admission_status: admitted canonical_source: source_type: logical_adr source_ref: ADR-L-0017#DEC-0019 @@ -4128,6 +4662,7 @@ entities: governs_components: [] supersedes: [] refines: [] + contradicts: [] relationships: declared_in: - ADR-L-0017 @@ -4149,6 +4684,9 @@ entities: superseded_by: [] refines: [] refined_by: [] + contradicts: [] + rejects: [] + rejected_by: [] completeness: status: complete missing_fields: [] @@ -4165,6 +4703,7 @@ entities: Three standard questions (system dependencies, component integration, blast radius) are answerable purely from the typed verb edges in workspace slices. Making them deterministic: 1. Guarantees reproducibility (same grap lifecycle_stage: proposed + admission_status: admitted canonical_source: source_type: logical_adr source_ref: ADR-L-0018#DEC-0020 @@ -4181,6 +4720,14 @@ entities: governs_components: [] supersedes: [] refines: [] + contradicts: [] + accumulated_consequences: + - Three standard questions answered without LLM cost or latency. + - Results are reproducible and testable with in-memory fixtures. + - Multiple output projections (Mermaid, table, matrix) from one query. + - Serves CLI, MCP, and programmatic API surfaces from the same engine. + - New loader required (workspace slices were previously unloadable). + - No natural language flexibility; exact node IDs required for blast radius target. relationships: declared_in: - ADR-L-0018 @@ -4205,6 +4752,9 @@ entities: superseded_by: [] refines: [] refined_by: [] + contradicts: [] + rejects: [] + rejected_by: [] completeness: status: complete missing_fields: [] @@ -4221,6 +4771,7 @@ entities: The current L4-only projection pipeline produces cognitively unusable output for human readers. Rather than introducing LLM-based summarization, the compression layer uses deterministic algorithms: 1. Endpoint path-prefi lifecycle_stage: proposed + admission_status: admitted canonical_source: source_type: logical_adr source_ref: ADR-L-0019#DEC-0021 @@ -4237,6 +4788,14 @@ entities: governs_components: [] supersedes: [] refines: [] + contradicts: [] + accumulated_consequences: + - Five resolution levels serve distinct audiences (executive, platform, domain, integration, machine) + - All views derive from the same graph substrate ensuring consistency + - Deterministic output enables CI diffing and fixture-based testing + - Existing L4 projections are fully preserved for backward compatibility + - Additional code surface (compression engine, resolution-aware renderers) + - Capability domain heuristic (path-prefix grouping) may not perfectly match business domains relationships: declared_in: - ADR-L-0019 @@ -4261,6 +4820,9 @@ entities: superseded_by: [] refines: [] refined_by: [] + contradicts: [] + rejects: [] + rejected_by: [] completeness: status: complete missing_fields: [] @@ -4277,6 +4839,7 @@ entities: Entity URI resolution is necessary but not sufficient for IDE and conversation-engine reasoning. ste-runtime must assemble a correctness-first CEM bundle, derive a bounded MVC projection, and validate the MVC against the lifecycle_stage: proposed + admission_status: admitted canonical_source: source_type: logical_adr source_ref: ADR-L-0020#DEC-0022 @@ -4294,6 +4857,14 @@ entities: governs_components: [] supersedes: [] refines: [] + contradicts: [] + accumulated_consequences: + - IDE agents can traverse the graph and retrieve authoritative source artifacts + - MVC bundles remain small while preserving provenance to CEM and source + - Source freshness and graph freshness can be validated before reasoning + - Future ste-kernel can consume runtime-produced CEM/MVC validation state + - Additional runtime artifact surface and tests + - More explicit stale and partial-state diagnostics for consumers to handle relationships: declared_in: - ADR-L-0020 @@ -4319,6 +4890,9 @@ entities: superseded_by: [] refines: [] refined_by: [] + contradicts: [] + rejects: [] + rejected_by: [] completeness: status: complete missing_fields: [] @@ -4328,6 +4902,74 @@ entities: extraction_phase: extract_decision classification: explicit generator: adr-architecture-index + - id: DEC-0023 + entity_type: decision + name: Add an experimental contract-consumption builder for MVC-D to MVC-S fixtures + summary: >- + A narrow fixture validator gives ste-runtime a contract-safe baseline before implementing RSS traversal or kernel + handoff. All candidate material is fully supplied to the builder; runtime does not reconstruct architectur + lifecycle_stage: proposed + admission_status: admitted + canonical_source: + source_type: logical_adr + source_ref: ADR-L-0021#DEC-0023 + artifact_path: adrs/logical/ADR-L-0021-experimental-mvc-d-to-mvc-s-contract-consumption.yaml + source_refs: [] + metadata: + adr_id: ADR-L-0021 + related_invariants: + - INV-0030 + - INV-0031 + - INV-0032 + enforces_invariants: [] + enables_capabilities: + - CAP-0021 + governs_components: [] + supersedes: [] + refines: [] + contradicts: [] + accumulated_consequences: + - Runtime can validate ste-spec MVC contracts locally + - Candidate-only semantics are executable and testable + - Code provenance can link implementation to this ADR + - Additional experimental surface must remain clearly separated from legacy CEM/MVC + relationships: + declared_in: + - ADR-L-0021 + declares: [] + references: [] + referenced_by: [] + related_to: [] + enforces: + - INV-0030 + - INV-0031 + - INV-0032 + enforced_by: [] + enabled_by: [] + enables: + - CAP-0021 + governs: [] + governed_by: [] + implemented_by: [] + implements: [] + embodied_in: [] + embodies: [] + supersedes: [] + superseded_by: [] + refines: [] + refined_by: [] + contradicts: [] + rejects: [] + rejected_by: [] + completeness: + status: complete + missing_fields: [] + provenance: + source_type: logical_adr + source_ref: ADR-L-0021#DEC-0023 + extraction_phase: extract_decision + classification: explicit + generator: adr-architecture-index - id: INV-0001 entity_type: invariant name: INV-0001 @@ -4335,6 +4977,7 @@ entities: Single repository only: RECON discovers files within the current repository. Cross-repository reconciliation is out of scope. lifecycle_stage: active + admission_status: admitted canonical_source: source_type: logical_adr source_ref: ADR-L-0001#INV-0001 @@ -4370,6 +5013,9 @@ entities: superseded_by: [] refines: [] refined_by: [] + contradicts: [] + rejects: [] + rejected_by: [] completeness: status: complete missing_fields: [] @@ -4386,6 +5032,7 @@ entities: Incremental reconciliation: Only files that have changed since the last run are re-extracted (when timestamp detection is available). lifecycle_stage: active + admission_status: admitted canonical_source: source_type: logical_adr source_ref: ADR-L-0001#INV-0002 @@ -4421,6 +5068,9 @@ entities: superseded_by: [] refines: [] refined_by: [] + contradicts: [] + rejects: [] + rejected_by: [] completeness: status: complete missing_fields: [] @@ -4435,6 +5085,7 @@ entities: name: INV-0003 summary: 'Configurable source directories: Specified via `ste.config.json` or auto-detected.' lifecycle_stage: active + admission_status: admitted canonical_source: source_type: logical_adr source_ref: ADR-L-0001#INV-0003 @@ -4468,6 +5119,9 @@ entities: superseded_by: [] refines: [] refined_by: [] + contradicts: [] + rejects: [] + rejected_by: [] completeness: status: complete missing_fields: [] @@ -4484,6 +5138,7 @@ entities: Shallow extraction: Extract structural elements (functions, classes, imports, exports) without deep semantic analysis. lifecycle_stage: active + admission_status: admitted canonical_source: source_type: logical_adr source_ref: ADR-L-0001#INV-0004 @@ -4519,6 +5174,9 @@ entities: superseded_by: [] refines: [] refined_by: [] + contradicts: [] + rejects: [] + rejected_by: [] completeness: status: complete missing_fields: [] @@ -4533,6 +5191,7 @@ entities: name: INV-0005 summary: 'No deep semantic analysis: Do not attempt to understand function behavior, side effects, or complex type flows.' lifecycle_stage: active + admission_status: admitted canonical_source: source_type: logical_adr source_ref: ADR-L-0001#INV-0005 @@ -4566,6 +5225,9 @@ entities: superseded_by: [] refines: [] refined_by: [] + contradicts: [] + rejects: [] + rejected_by: [] completeness: status: complete missing_fields: [] @@ -4582,6 +5244,7 @@ entities: Multi-language support: TypeScript, Python, CloudFormation, JSON (see E-ADR-005), Angular, CSS/SCSS (see E-ADR-006), ADR YAML (see ADR-PC-0011). lifecycle_stage: active + admission_status: admitted canonical_source: source_type: logical_adr source_ref: ADR-L-0001#INV-0006 @@ -4617,6 +5280,9 @@ entities: superseded_by: [] refines: [] refined_by: [] + contradicts: [] + rejects: [] + rejected_by: [] completeness: status: complete missing_fields: [] @@ -4631,6 +5297,7 @@ entities: name: INV-0007 summary: 'Portable execution: RECON must work when dropped into any project.' lifecycle_stage: active + admission_status: admitted canonical_source: source_type: logical_adr source_ref: ADR-L-0001#INV-0007 @@ -4664,6 +5331,9 @@ entities: superseded_by: [] refines: [] refined_by: [] + contradicts: [] + rejects: [] + rejected_by: [] completeness: status: complete missing_fields: [] @@ -4678,6 +5348,7 @@ entities: name: INV-0008 summary: 'Provisional mapping: Normalization to AI-DOC schema is best-effort, not canonical.' lifecycle_stage: active + admission_status: admitted canonical_source: source_type: logical_adr source_ref: ADR-L-0001#INV-0008 @@ -4711,6 +5382,9 @@ entities: superseded_by: [] refines: [] refined_by: [] + contradicts: [] + rejects: [] + rejected_by: [] completeness: status: complete missing_fields: [] @@ -4725,6 +5399,7 @@ entities: name: INV-0009 summary: 'Schema evolution expected: The AI-DOC schema is still evolving; normalization will change.' lifecycle_stage: active + admission_status: admitted canonical_source: source_type: logical_adr source_ref: ADR-L-0001#INV-0009 @@ -4758,6 +5433,9 @@ entities: superseded_by: [] refines: [] refined_by: [] + contradicts: [] + rejects: [] + rejected_by: [] completeness: status: complete missing_fields: [] @@ -4772,6 +5450,7 @@ entities: name: INV-0010 summary: 'ID stability: Element IDs should be stable across runs for the same source element.' lifecycle_stage: active + admission_status: admitted canonical_source: source_type: logical_adr source_ref: ADR-L-0001#INV-0010 @@ -4805,6 +5484,9 @@ entities: superseded_by: [] refines: [] refined_by: [] + contradicts: [] + rejects: [] + rejected_by: [] completeness: status: complete missing_fields: [] @@ -4819,6 +5501,7 @@ entities: name: INV-0011 summary: 'State is authoritative, not historical: Each run produces the current truth, not a delta.' lifecycle_stage: active + admission_status: admitted canonical_source: source_type: logical_adr source_ref: ADR-L-0001#INV-0011 @@ -4852,6 +5535,9 @@ entities: superseded_by: [] refines: [] refined_by: [] + contradicts: [] + rejects: [] + rejected_by: [] completeness: status: complete missing_fields: [] @@ -4866,6 +5552,7 @@ entities: name: INV-0012 summary: 'Create/Update/Delete semantics: New slices are created, changed slices are updated, orphaned slices are deleted.' lifecycle_stage: active + admission_status: admitted canonical_source: source_type: logical_adr source_ref: ADR-L-0001#INV-0012 @@ -4899,6 +5586,9 @@ entities: superseded_by: [] refines: [] refined_by: [] + contradicts: [] + rejects: [] + rejected_by: [] completeness: status: complete missing_fields: [] @@ -4913,6 +5603,7 @@ entities: name: INV-0013 summary: 'Orphan detection: Slices from processed source files that no longer exist in code are removed.' lifecycle_stage: active + admission_status: admitted canonical_source: source_type: logical_adr source_ref: ADR-L-0001#INV-0013 @@ -4946,6 +5637,9 @@ entities: superseded_by: [] refines: [] refined_by: [] + contradicts: [] + rejects: [] + rejected_by: [] completeness: status: complete missing_fields: [] @@ -4960,6 +5654,7 @@ entities: name: INV-0014 summary: Scope is a workspace. Size(workspace) >= 1. lifecycle_stage: proposed + admission_status: admitted canonical_source: source_type: logical_adr source_ref: ADR-L-0009#INV-0014 @@ -4993,6 +5688,9 @@ entities: superseded_by: [] refines: [] refined_by: [] + contradicts: [] + rejects: [] + rejected_by: [] completeness: status: complete missing_fields: [] @@ -5009,6 +5707,7 @@ entities: ste-runtime source code contains zero references to any specific workspace, repository name, output directory name, or domain vocabulary. All such values are derived from workspace.yaml at runtime. lifecycle_stage: proposed + admission_status: admitted canonical_source: source_type: logical_adr source_ref: ADR-L-0015#INV-0015 @@ -5044,6 +5743,9 @@ entities: superseded_by: [] refines: [] refined_by: [] + contradicts: [] + rejects: [] + rejected_by: [] completeness: status: complete missing_fields: [] @@ -5060,6 +5762,7 @@ entities: Unit tests use synthetic repository names (e.g. repo-alpha, repo-beta) and never reference real workspace repository names. lifecycle_stage: proposed + admission_status: admitted canonical_source: source_type: logical_adr source_ref: ADR-L-0015#INV-0016 @@ -5095,6 +5798,9 @@ entities: superseded_by: [] refines: [] refined_by: [] + contradicts: [] + rejects: [] + rejected_by: [] completeness: status: complete missing_fields: [] @@ -5111,6 +5817,7 @@ entities: Every workspace graph slice emitted by ste-runtime contains the required core fields defined in the slice schema contract: schema_version, repo, generated_by, generated_at, nodes, and edges. source_commit and diagnostics lifecycle_stage: proposed + admission_status: admitted canonical_source: source_type: logical_adr source_ref: ADR-L-0016#INV-0017 @@ -5148,6 +5855,9 @@ entities: superseded_by: [] refines: [] refined_by: [] + contradicts: [] + rejects: [] + rejected_by: [] completeness: status: complete missing_fields: [] @@ -5164,6 +5874,7 @@ entities: Runtime-emitted workspace graph edges that assert a resolved relationship use confidence 'high'. Ambiguous resolutions produce diagnostics rather than asserted edges. Consumers must drop non-high edges when they appear i lifecycle_stage: proposed + admission_status: admitted canonical_source: source_type: logical_adr source_ref: ADR-L-0016#INV-0018 @@ -5200,6 +5911,9 @@ entities: superseded_by: [] refines: [] refined_by: [] + contradicts: [] + rejects: [] + rejected_by: [] completeness: status: complete missing_fields: [] @@ -5214,6 +5928,7 @@ entities: name: INV-0019 summary: Workspace RECON emits exactly one progress line per repository before that repository begins processing. lifecycle_stage: proposed + admission_status: admitted canonical_source: source_type: logical_adr source_ref: ADR-L-0017#INV-0019 @@ -5247,6 +5962,9 @@ entities: superseded_by: [] refines: [] refined_by: [] + contradicts: [] + rejects: [] + rejected_by: [] completeness: status: complete missing_fields: [] @@ -5263,6 +5981,7 @@ entities: Canned query functions (systemDependencies, componentIntegration, blastRadiusWorkspace) are pure graph traversal. They do not invoke LLM inference, network calls, or non-deterministic operations. lifecycle_stage: proposed + admission_status: admitted canonical_source: source_type: logical_adr source_ref: ADR-L-0018#INV-0020 @@ -5299,6 +6018,9 @@ entities: superseded_by: [] refines: [] refined_by: [] + contradicts: [] + rejects: [] + rejected_by: [] completeness: status: complete missing_fields: [] @@ -5315,6 +6037,7 @@ entities: Projection is separated from query. Query functions return structured data objects. Rendering to Mermaid, table, or matrix is performed by distinct projection functions. lifecycle_stage: proposed + admission_status: admitted canonical_source: source_type: logical_adr source_ref: ADR-L-0018#INV-0021 @@ -5351,6 +6074,9 @@ entities: superseded_by: [] refines: [] refined_by: [] + contradicts: [] + rejects: [] + rejected_by: [] completeness: status: complete missing_fields: [] @@ -5367,6 +6093,7 @@ entities: Resolution level is a first-class parameter of the projection pipeline. Every MCP tool and CLI command that produces projections accepts an optional resolution parameter (L0|L1|L2|L3|L4) with L4 as the default. lifecycle_stage: proposed + admission_status: admitted canonical_source: source_type: logical_adr source_ref: ADR-L-0019#INV-0022 @@ -5404,6 +6131,9 @@ entities: superseded_by: [] refines: [] refined_by: [] + contradicts: [] + rejects: [] + rejected_by: [] completeness: status: complete missing_fields: [] @@ -5420,6 +6150,7 @@ entities: Compressed projections preserve traceability to source graph nodes. Every aggregate node carries memberIds linking back to the original workspace nodes. Every compressed edge carries sourceEdgeIds when multiplicity > 1. lifecycle_stage: proposed + admission_status: admitted canonical_source: source_type: logical_adr source_ref: ADR-L-0019#INV-0023 @@ -5457,6 +6188,9 @@ entities: superseded_by: [] refines: [] refined_by: [] + contradicts: [] + rejects: [] + rejected_by: [] completeness: status: complete missing_fields: [] @@ -5473,6 +6207,7 @@ entities: Every emitted projection file includes projection_level metadata in its YAML frontmatter, identifying the resolution level (L0-L4) at which the projection was generated. lifecycle_stage: proposed + admission_status: admitted canonical_source: source_type: logical_adr source_ref: ADR-L-0018#INV-0024 @@ -5508,6 +6243,9 @@ entities: superseded_by: [] refines: [] refined_by: [] + contradicts: [] + rejects: [] + rejected_by: [] completeness: status: complete missing_fields: [] @@ -5517,6 +6255,63 @@ entities: extraction_phase: assign_canonical_invariant classification: explicit generator: adr-architecture-index + - id: INV-0025 + entity_type: invariant + name: INV-0025 + summary: >- + All infrastructure resources extracted by RECON are emitted as workspace graph nodes. No extracted resource is + silently dropped by the slice emitter. Resources not covered by an explicit CFN-to-graph-type mapping are emi + lifecycle_stage: proposed + admission_status: admitted + canonical_source: + source_type: logical_adr + source_ref: ADR-L-0016#INV-0025 + artifact_path: adrs/logical/ADR-L-0016-workspace-graph-slice-schema-contract.yaml + source_refs: [] + metadata: + adr_id: ADR-L-0016 + scope: global + statement: >- + All infrastructure resources extracted by RECON are emitted as workspace graph nodes. No extracted resource is + silently dropped by the slice emitter. Resources not covered by an explicit CFN-to-graph-type mapping are + emitted as InfraResource nodes with the original cfn_type preserved in attributes. The logicalId is the + last-resort display name; a null name never causes a node to be dropped. + enforcement_level: must + declaration_mode: local + upheld_by_decisions: [] + relationships: + declared_in: + - ADR-L-0016 + declares: [] + references: [] + referenced_by: [] + related_to: [] + enforces: [] + enforced_by: [] + enabled_by: [] + enables: [] + governs: [] + governed_by: [] + implemented_by: [] + implements: [] + embodied_in: [] + embodies: [] + supersedes: [] + superseded_by: [] + refines: [] + refined_by: [] + contradicts: [] + rejects: [] + rejected_by: [] + completeness: + status: complete + missing_fields: [] + provenance: + source_type: logical_adr + source_ref: ADR-L-0016#INV-0025 + extraction_phase: assign_canonical_invariant + classification: explicit + generator: adr-architecture-index - id: INV-0027 entity_type: invariant name: INV-0027 @@ -5524,6 +6319,7 @@ entities: Workspace graph entities may carry source locator metadata, but graph artifacts must not embed full canonical ADR, DEC, invariant, contract, or source documents by default. lifecycle_stage: proposed + admission_status: admitted canonical_source: source_type: logical_adr source_ref: ADR-L-0020#INV-0027 @@ -5561,6 +6357,9 @@ entities: superseded_by: [] refines: [] refined_by: [] + contradicts: [] + rejects: [] + rejected_by: [] completeness: status: complete missing_fields: [] @@ -5577,6 +6376,7 @@ entities: Every MVC bundle must retain provenance back to its parent CEM bundle, graph snapshot, traversal operation, selected source artifacts, embodiment evidence, and validation state. lifecycle_stage: proposed + admission_status: admitted canonical_source: source_type: logical_adr source_ref: ADR-L-0020#INV-0028 @@ -5614,6 +6414,9 @@ entities: superseded_by: [] refines: [] refined_by: [] + contradicts: [] + rejects: [] + rejected_by: [] completeness: status: complete missing_fields: [] @@ -5630,6 +6433,7 @@ entities: Source locator generation, graph traversal, CEM assembly, MVC derivation, and MVC validation are deterministic for identical workspace graph, source, locator registry, and traversal inputs. lifecycle_stage: proposed + admission_status: admitted canonical_source: source_type: logical_adr source_ref: ADR-L-0020#INV-0029 @@ -5667,6 +6471,9 @@ entities: superseded_by: [] refines: [] refined_by: [] + contradicts: [] + rejects: [] + rejected_by: [] completeness: status: complete missing_fields: [] @@ -5676,6 +6483,177 @@ entities: extraction_phase: assign_canonical_invariant classification: explicit generator: adr-architecture-index + - id: INV-0030 + entity_type: invariant + name: INV-0030 + summary: >- + ste-runtime MUST treat MVC-D and MVC-S schemas as external ste-spec contracts. Runtime tests may mirror schema + fixtures for local validation, but runtime code MUST NOT redefine the public schema authority. + lifecycle_stage: proposed + admission_status: admitted + canonical_source: + source_type: logical_adr + source_ref: ADR-L-0021#INV-0030 + artifact_path: adrs/logical/ADR-L-0021-experimental-mvc-d-to-mvc-s-contract-consumption.yaml + source_refs: [] + metadata: + adr_id: ADR-L-0021 + scope: global + statement: |- + ste-runtime MUST treat MVC-D and MVC-S schemas as external ste-spec contracts. + Runtime tests may mirror schema fixtures for local validation, but runtime + code MUST NOT redefine the public schema authority. + enforcement_level: must + declaration_mode: local + upheld_by_decisions: [] + relationships: + declared_in: + - ADR-L-0021 + declares: [] + references: [] + referenced_by: [] + related_to: [] + enforces: [] + enforced_by: + - DEC-0023 + enabled_by: [] + enables: [] + governs: [] + governed_by: [] + implemented_by: [] + implements: [] + embodied_in: [] + embodies: [] + supersedes: [] + superseded_by: [] + refines: [] + refined_by: [] + contradicts: [] + rejects: [] + rejected_by: [] + completeness: + status: complete + missing_fields: [] + provenance: + source_type: logical_adr + source_ref: ADR-L-0021#INV-0030 + extraction_phase: assign_canonical_invariant + classification: explicit + generator: adr-architecture-index + - id: INV-0031 + entity_type: invariant + name: INV-0031 + summary: >- + Experimental MVC-S candidate emission MUST NOT include admission decisions, caller-facing eligibility, enforcement + outcomes, kernel verdicts, governance state, or admitted payloads. + lifecycle_stage: proposed + admission_status: admitted + canonical_source: + source_type: logical_adr + source_ref: ADR-L-0021#INV-0031 + artifact_path: adrs/logical/ADR-L-0021-experimental-mvc-d-to-mvc-s-contract-consumption.yaml + source_refs: [] + metadata: + adr_id: ADR-L-0021 + scope: global + statement: |- + Experimental MVC-S candidate emission MUST NOT include admission decisions, + caller-facing eligibility, enforcement outcomes, kernel verdicts, governance + state, or admitted payloads. + enforcement_level: must + declaration_mode: local + upheld_by_decisions: [] + relationships: + declared_in: + - ADR-L-0021 + declares: [] + references: [] + referenced_by: [] + related_to: [] + enforces: [] + enforced_by: + - DEC-0023 + enabled_by: [] + enables: [] + governs: [] + governed_by: [] + implemented_by: [] + implements: [] + embodied_in: [] + embodies: [] + supersedes: [] + superseded_by: [] + refines: [] + refined_by: [] + contradicts: [] + rejects: [] + rejected_by: [] + completeness: + status: complete + missing_fields: [] + provenance: + source_type: logical_adr + source_ref: ADR-L-0021#INV-0031 + extraction_phase: assign_canonical_invariant + classification: explicit + generator: adr-architecture-index + - id: INV-0032 + entity_type: invariant + name: INV-0032 + summary: >- + Experimental MVC-S candidate emission MUST be deterministic for identical MVC-D, candidate refs, selector refs, + topology metrics, rationale, and negative-space inputs. Fingerprints MUST be computed over canonicalized inp + lifecycle_stage: proposed + admission_status: admitted + canonical_source: + source_type: logical_adr + source_ref: ADR-L-0021#INV-0032 + artifact_path: adrs/logical/ADR-L-0021-experimental-mvc-d-to-mvc-s-contract-consumption.yaml + source_refs: [] + metadata: + adr_id: ADR-L-0021 + scope: global + statement: |- + Experimental MVC-S candidate emission MUST be deterministic for identical + MVC-D, candidate refs, selector refs, topology metrics, rationale, and + negative-space inputs. Fingerprints MUST be computed over canonicalized input. + enforcement_level: must + declaration_mode: local + upheld_by_decisions: [] + relationships: + declared_in: + - ADR-L-0021 + declares: [] + references: [] + referenced_by: [] + related_to: [] + enforces: [] + enforced_by: + - DEC-0023 + enabled_by: [] + enables: [] + governs: [] + governed_by: [] + implemented_by: [] + implements: [] + embodied_in: [] + embodies: [] + supersedes: [] + superseded_by: [] + refines: [] + refined_by: [] + contradicts: [] + rejects: [] + rejected_by: [] + completeness: + status: complete + missing_fields: [] + provenance: + source_type: logical_adr + source_ref: ADR-L-0021#INV-0032 + extraction_phase: assign_canonical_invariant + classification: explicit + generator: adr-architecture-index - id: SYS-0001 entity_type: system name: Runtime Orchestration and Assistant Integration @@ -5684,6 +6662,7 @@ entities: assistant-facing MCP tools, performs reconciliation gating and freshness checks, and assembles implementation context and lifecycle_stage: proposed + admission_status: admitted canonical_source: source_type: physical_system_adr source_ref: ADR-PS-0001 @@ -5729,6 +6708,9 @@ entities: superseded_by: [] refines: [] refined_by: [] + contradicts: [] + rejects: [] + rejected_by: [] completeness: status: complete missing_fields: [] @@ -5745,6 +6727,7 @@ entities: ste-runtime extraction is now a subsystem containing multiple first-class extractors and normalization flows rather than a pair of isolated physical slices. This ADR groups the implemented extractor estate under a concre lifecycle_stage: proposed + admission_status: admitted canonical_source: source_type: physical_system_adr source_ref: ADR-PS-0002 @@ -5790,6 +6773,9 @@ entities: superseded_by: [] refines: [] refined_by: [] + contradicts: [] + rejects: [] + rejected_by: [] completeness: status: complete missing_fields: [] diff --git a/adrs/index/invariant-registry.yaml b/adrs/index/invariant-registry.yaml index 9645825..d39947c 100644 --- a/adrs/index/invariant-registry.yaml +++ b/adrs/index/invariant-registry.yaml @@ -8,6 +8,7 @@ entities: Single repository only: RECON discovers files within the current repository. Cross-repository reconciliation is out of scope. lifecycle_stage: active + admission_status: admitted canonical_source: source_type: logical_adr source_ref: ADR-L-0001#INV-0001 @@ -43,6 +44,9 @@ entities: superseded_by: [] refines: [] refined_by: [] + contradicts: [] + rejects: [] + rejected_by: [] completeness: status: complete missing_fields: [] @@ -59,6 +63,7 @@ entities: Incremental reconciliation: Only files that have changed since the last run are re-extracted (when timestamp detection is available). lifecycle_stage: active + admission_status: admitted canonical_source: source_type: logical_adr source_ref: ADR-L-0001#INV-0002 @@ -94,6 +99,9 @@ entities: superseded_by: [] refines: [] refined_by: [] + contradicts: [] + rejects: [] + rejected_by: [] completeness: status: complete missing_fields: [] @@ -108,6 +116,7 @@ entities: name: INV-0003 summary: 'Configurable source directories: Specified via `ste.config.json` or auto-detected.' lifecycle_stage: active + admission_status: admitted canonical_source: source_type: logical_adr source_ref: ADR-L-0001#INV-0003 @@ -141,6 +150,9 @@ entities: superseded_by: [] refines: [] refined_by: [] + contradicts: [] + rejects: [] + rejected_by: [] completeness: status: complete missing_fields: [] @@ -157,6 +169,7 @@ entities: Shallow extraction: Extract structural elements (functions, classes, imports, exports) without deep semantic analysis. lifecycle_stage: active + admission_status: admitted canonical_source: source_type: logical_adr source_ref: ADR-L-0001#INV-0004 @@ -192,6 +205,9 @@ entities: superseded_by: [] refines: [] refined_by: [] + contradicts: [] + rejects: [] + rejected_by: [] completeness: status: complete missing_fields: [] @@ -206,6 +222,7 @@ entities: name: INV-0005 summary: 'No deep semantic analysis: Do not attempt to understand function behavior, side effects, or complex type flows.' lifecycle_stage: active + admission_status: admitted canonical_source: source_type: logical_adr source_ref: ADR-L-0001#INV-0005 @@ -239,6 +256,9 @@ entities: superseded_by: [] refines: [] refined_by: [] + contradicts: [] + rejects: [] + rejected_by: [] completeness: status: complete missing_fields: [] @@ -255,6 +275,7 @@ entities: Multi-language support: TypeScript, Python, CloudFormation, JSON (see E-ADR-005), Angular, CSS/SCSS (see E-ADR-006), ADR YAML (see ADR-PC-0011). lifecycle_stage: active + admission_status: admitted canonical_source: source_type: logical_adr source_ref: ADR-L-0001#INV-0006 @@ -290,6 +311,9 @@ entities: superseded_by: [] refines: [] refined_by: [] + contradicts: [] + rejects: [] + rejected_by: [] completeness: status: complete missing_fields: [] @@ -304,6 +328,7 @@ entities: name: INV-0007 summary: 'Portable execution: RECON must work when dropped into any project.' lifecycle_stage: active + admission_status: admitted canonical_source: source_type: logical_adr source_ref: ADR-L-0001#INV-0007 @@ -337,6 +362,9 @@ entities: superseded_by: [] refines: [] refined_by: [] + contradicts: [] + rejects: [] + rejected_by: [] completeness: status: complete missing_fields: [] @@ -351,6 +379,7 @@ entities: name: INV-0008 summary: 'Provisional mapping: Normalization to AI-DOC schema is best-effort, not canonical.' lifecycle_stage: active + admission_status: admitted canonical_source: source_type: logical_adr source_ref: ADR-L-0001#INV-0008 @@ -384,6 +413,9 @@ entities: superseded_by: [] refines: [] refined_by: [] + contradicts: [] + rejects: [] + rejected_by: [] completeness: status: complete missing_fields: [] @@ -398,6 +430,7 @@ entities: name: INV-0009 summary: 'Schema evolution expected: The AI-DOC schema is still evolving; normalization will change.' lifecycle_stage: active + admission_status: admitted canonical_source: source_type: logical_adr source_ref: ADR-L-0001#INV-0009 @@ -431,6 +464,9 @@ entities: superseded_by: [] refines: [] refined_by: [] + contradicts: [] + rejects: [] + rejected_by: [] completeness: status: complete missing_fields: [] @@ -445,6 +481,7 @@ entities: name: INV-0010 summary: 'ID stability: Element IDs should be stable across runs for the same source element.' lifecycle_stage: active + admission_status: admitted canonical_source: source_type: logical_adr source_ref: ADR-L-0001#INV-0010 @@ -478,6 +515,9 @@ entities: superseded_by: [] refines: [] refined_by: [] + contradicts: [] + rejects: [] + rejected_by: [] completeness: status: complete missing_fields: [] @@ -492,6 +532,7 @@ entities: name: INV-0011 summary: 'State is authoritative, not historical: Each run produces the current truth, not a delta.' lifecycle_stage: active + admission_status: admitted canonical_source: source_type: logical_adr source_ref: ADR-L-0001#INV-0011 @@ -525,6 +566,9 @@ entities: superseded_by: [] refines: [] refined_by: [] + contradicts: [] + rejects: [] + rejected_by: [] completeness: status: complete missing_fields: [] @@ -539,6 +583,7 @@ entities: name: INV-0012 summary: 'Create/Update/Delete semantics: New slices are created, changed slices are updated, orphaned slices are deleted.' lifecycle_stage: active + admission_status: admitted canonical_source: source_type: logical_adr source_ref: ADR-L-0001#INV-0012 @@ -572,6 +617,9 @@ entities: superseded_by: [] refines: [] refined_by: [] + contradicts: [] + rejects: [] + rejected_by: [] completeness: status: complete missing_fields: [] @@ -586,6 +634,7 @@ entities: name: INV-0013 summary: 'Orphan detection: Slices from processed source files that no longer exist in code are removed.' lifecycle_stage: active + admission_status: admitted canonical_source: source_type: logical_adr source_ref: ADR-L-0001#INV-0013 @@ -619,6 +668,9 @@ entities: superseded_by: [] refines: [] refined_by: [] + contradicts: [] + rejects: [] + rejected_by: [] completeness: status: complete missing_fields: [] @@ -633,6 +685,7 @@ entities: name: INV-0014 summary: Scope is a workspace. Size(workspace) >= 1. lifecycle_stage: proposed + admission_status: admitted canonical_source: source_type: logical_adr source_ref: ADR-L-0009#INV-0014 @@ -666,6 +719,9 @@ entities: superseded_by: [] refines: [] refined_by: [] + contradicts: [] + rejects: [] + rejected_by: [] completeness: status: complete missing_fields: [] @@ -682,6 +738,7 @@ entities: ste-runtime source code contains zero references to any specific workspace, repository name, output directory name, or domain vocabulary. All such values are derived from workspace.yaml at runtime. lifecycle_stage: proposed + admission_status: admitted canonical_source: source_type: logical_adr source_ref: ADR-L-0015#INV-0015 @@ -717,6 +774,9 @@ entities: superseded_by: [] refines: [] refined_by: [] + contradicts: [] + rejects: [] + rejected_by: [] completeness: status: complete missing_fields: [] @@ -733,6 +793,7 @@ entities: Unit tests use synthetic repository names (e.g. repo-alpha, repo-beta) and never reference real workspace repository names. lifecycle_stage: proposed + admission_status: admitted canonical_source: source_type: logical_adr source_ref: ADR-L-0015#INV-0016 @@ -768,6 +829,9 @@ entities: superseded_by: [] refines: [] refined_by: [] + contradicts: [] + rejects: [] + rejected_by: [] completeness: status: complete missing_fields: [] @@ -784,6 +848,7 @@ entities: Every workspace graph slice emitted by ste-runtime contains the required core fields defined in the slice schema contract: schema_version, repo, generated_by, generated_at, nodes, and edges. source_commit and diagnostics lifecycle_stage: proposed + admission_status: admitted canonical_source: source_type: logical_adr source_ref: ADR-L-0016#INV-0017 @@ -821,6 +886,9 @@ entities: superseded_by: [] refines: [] refined_by: [] + contradicts: [] + rejects: [] + rejected_by: [] completeness: status: complete missing_fields: [] @@ -837,6 +905,7 @@ entities: Runtime-emitted workspace graph edges that assert a resolved relationship use confidence 'high'. Ambiguous resolutions produce diagnostics rather than asserted edges. Consumers must drop non-high edges when they appear i lifecycle_stage: proposed + admission_status: admitted canonical_source: source_type: logical_adr source_ref: ADR-L-0016#INV-0018 @@ -873,6 +942,9 @@ entities: superseded_by: [] refines: [] refined_by: [] + contradicts: [] + rejects: [] + rejected_by: [] completeness: status: complete missing_fields: [] @@ -887,6 +959,7 @@ entities: name: INV-0019 summary: Workspace RECON emits exactly one progress line per repository before that repository begins processing. lifecycle_stage: proposed + admission_status: admitted canonical_source: source_type: logical_adr source_ref: ADR-L-0017#INV-0019 @@ -920,6 +993,9 @@ entities: superseded_by: [] refines: [] refined_by: [] + contradicts: [] + rejects: [] + rejected_by: [] completeness: status: complete missing_fields: [] @@ -936,6 +1012,7 @@ entities: Canned query functions (systemDependencies, componentIntegration, blastRadiusWorkspace) are pure graph traversal. They do not invoke LLM inference, network calls, or non-deterministic operations. lifecycle_stage: proposed + admission_status: admitted canonical_source: source_type: logical_adr source_ref: ADR-L-0018#INV-0020 @@ -972,6 +1049,9 @@ entities: superseded_by: [] refines: [] refined_by: [] + contradicts: [] + rejects: [] + rejected_by: [] completeness: status: complete missing_fields: [] @@ -988,6 +1068,7 @@ entities: Projection is separated from query. Query functions return structured data objects. Rendering to Mermaid, table, or matrix is performed by distinct projection functions. lifecycle_stage: proposed + admission_status: admitted canonical_source: source_type: logical_adr source_ref: ADR-L-0018#INV-0021 @@ -1024,6 +1105,9 @@ entities: superseded_by: [] refines: [] refined_by: [] + contradicts: [] + rejects: [] + rejected_by: [] completeness: status: complete missing_fields: [] @@ -1040,6 +1124,7 @@ entities: Resolution level is a first-class parameter of the projection pipeline. Every MCP tool and CLI command that produces projections accepts an optional resolution parameter (L0|L1|L2|L3|L4) with L4 as the default. lifecycle_stage: proposed + admission_status: admitted canonical_source: source_type: logical_adr source_ref: ADR-L-0019#INV-0022 @@ -1077,6 +1162,9 @@ entities: superseded_by: [] refines: [] refined_by: [] + contradicts: [] + rejects: [] + rejected_by: [] completeness: status: complete missing_fields: [] @@ -1093,6 +1181,7 @@ entities: Compressed projections preserve traceability to source graph nodes. Every aggregate node carries memberIds linking back to the original workspace nodes. Every compressed edge carries sourceEdgeIds when multiplicity > 1. lifecycle_stage: proposed + admission_status: admitted canonical_source: source_type: logical_adr source_ref: ADR-L-0019#INV-0023 @@ -1130,6 +1219,9 @@ entities: superseded_by: [] refines: [] refined_by: [] + contradicts: [] + rejects: [] + rejected_by: [] completeness: status: complete missing_fields: [] @@ -1146,6 +1238,7 @@ entities: Every emitted projection file includes projection_level metadata in its YAML frontmatter, identifying the resolution level (L0-L4) at which the projection was generated. lifecycle_stage: proposed + admission_status: admitted canonical_source: source_type: logical_adr source_ref: ADR-L-0018#INV-0024 @@ -1181,6 +1274,9 @@ entities: superseded_by: [] refines: [] refined_by: [] + contradicts: [] + rejects: [] + rejected_by: [] completeness: status: complete missing_fields: [] @@ -1190,6 +1286,63 @@ entities: extraction_phase: assign_canonical_invariant classification: explicit generator: adr-architecture-index + - id: INV-0025 + entity_type: invariant + name: INV-0025 + summary: >- + All infrastructure resources extracted by RECON are emitted as workspace graph nodes. No extracted resource is + silently dropped by the slice emitter. Resources not covered by an explicit CFN-to-graph-type mapping are emi + lifecycle_stage: proposed + admission_status: admitted + canonical_source: + source_type: logical_adr + source_ref: ADR-L-0016#INV-0025 + artifact_path: adrs/logical/ADR-L-0016-workspace-graph-slice-schema-contract.yaml + source_refs: [] + metadata: + adr_id: ADR-L-0016 + scope: global + statement: >- + All infrastructure resources extracted by RECON are emitted as workspace graph nodes. No extracted resource is + silently dropped by the slice emitter. Resources not covered by an explicit CFN-to-graph-type mapping are + emitted as InfraResource nodes with the original cfn_type preserved in attributes. The logicalId is the + last-resort display name; a null name never causes a node to be dropped. + enforcement_level: must + declaration_mode: local + upheld_by_decisions: [] + relationships: + declared_in: + - ADR-L-0016 + declares: [] + references: [] + referenced_by: [] + related_to: [] + enforces: [] + enforced_by: [] + enabled_by: [] + enables: [] + governs: [] + governed_by: [] + implemented_by: [] + implements: [] + embodied_in: [] + embodies: [] + supersedes: [] + superseded_by: [] + refines: [] + refined_by: [] + contradicts: [] + rejects: [] + rejected_by: [] + completeness: + status: complete + missing_fields: [] + provenance: + source_type: logical_adr + source_ref: ADR-L-0016#INV-0025 + extraction_phase: assign_canonical_invariant + classification: explicit + generator: adr-architecture-index - id: INV-0027 entity_type: invariant name: INV-0027 @@ -1197,6 +1350,7 @@ entities: Workspace graph entities may carry source locator metadata, but graph artifacts must not embed full canonical ADR, DEC, invariant, contract, or source documents by default. lifecycle_stage: proposed + admission_status: admitted canonical_source: source_type: logical_adr source_ref: ADR-L-0020#INV-0027 @@ -1234,6 +1388,9 @@ entities: superseded_by: [] refines: [] refined_by: [] + contradicts: [] + rejects: [] + rejected_by: [] completeness: status: complete missing_fields: [] @@ -1250,6 +1407,7 @@ entities: Every MVC bundle must retain provenance back to its parent CEM bundle, graph snapshot, traversal operation, selected source artifacts, embodiment evidence, and validation state. lifecycle_stage: proposed + admission_status: admitted canonical_source: source_type: logical_adr source_ref: ADR-L-0020#INV-0028 @@ -1287,6 +1445,9 @@ entities: superseded_by: [] refines: [] refined_by: [] + contradicts: [] + rejects: [] + rejected_by: [] completeness: status: complete missing_fields: [] @@ -1303,6 +1464,7 @@ entities: Source locator generation, graph traversal, CEM assembly, MVC derivation, and MVC validation are deterministic for identical workspace graph, source, locator registry, and traversal inputs. lifecycle_stage: proposed + admission_status: admitted canonical_source: source_type: logical_adr source_ref: ADR-L-0020#INV-0029 @@ -1340,6 +1502,9 @@ entities: superseded_by: [] refines: [] refined_by: [] + contradicts: [] + rejects: [] + rejected_by: [] completeness: status: complete missing_fields: [] @@ -1349,3 +1514,174 @@ entities: extraction_phase: assign_canonical_invariant classification: explicit generator: adr-architecture-index + - id: INV-0030 + entity_type: invariant + name: INV-0030 + summary: >- + ste-runtime MUST treat MVC-D and MVC-S schemas as external ste-spec contracts. Runtime tests may mirror schema + fixtures for local validation, but runtime code MUST NOT redefine the public schema authority. + lifecycle_stage: proposed + admission_status: admitted + canonical_source: + source_type: logical_adr + source_ref: ADR-L-0021#INV-0030 + artifact_path: adrs/logical/ADR-L-0021-experimental-mvc-d-to-mvc-s-contract-consumption.yaml + source_refs: [] + metadata: + adr_id: ADR-L-0021 + scope: global + statement: |- + ste-runtime MUST treat MVC-D and MVC-S schemas as external ste-spec contracts. + Runtime tests may mirror schema fixtures for local validation, but runtime + code MUST NOT redefine the public schema authority. + enforcement_level: must + declaration_mode: local + upheld_by_decisions: [] + relationships: + declared_in: + - ADR-L-0021 + declares: [] + references: [] + referenced_by: [] + related_to: [] + enforces: [] + enforced_by: + - DEC-0023 + enabled_by: [] + enables: [] + governs: [] + governed_by: [] + implemented_by: [] + implements: [] + embodied_in: [] + embodies: [] + supersedes: [] + superseded_by: [] + refines: [] + refined_by: [] + contradicts: [] + rejects: [] + rejected_by: [] + completeness: + status: complete + missing_fields: [] + provenance: + source_type: logical_adr + source_ref: ADR-L-0021#INV-0030 + extraction_phase: assign_canonical_invariant + classification: explicit + generator: adr-architecture-index + - id: INV-0031 + entity_type: invariant + name: INV-0031 + summary: >- + Experimental MVC-S candidate emission MUST NOT include admission decisions, caller-facing eligibility, enforcement + outcomes, kernel verdicts, governance state, or admitted payloads. + lifecycle_stage: proposed + admission_status: admitted + canonical_source: + source_type: logical_adr + source_ref: ADR-L-0021#INV-0031 + artifact_path: adrs/logical/ADR-L-0021-experimental-mvc-d-to-mvc-s-contract-consumption.yaml + source_refs: [] + metadata: + adr_id: ADR-L-0021 + scope: global + statement: |- + Experimental MVC-S candidate emission MUST NOT include admission decisions, + caller-facing eligibility, enforcement outcomes, kernel verdicts, governance + state, or admitted payloads. + enforcement_level: must + declaration_mode: local + upheld_by_decisions: [] + relationships: + declared_in: + - ADR-L-0021 + declares: [] + references: [] + referenced_by: [] + related_to: [] + enforces: [] + enforced_by: + - DEC-0023 + enabled_by: [] + enables: [] + governs: [] + governed_by: [] + implemented_by: [] + implements: [] + embodied_in: [] + embodies: [] + supersedes: [] + superseded_by: [] + refines: [] + refined_by: [] + contradicts: [] + rejects: [] + rejected_by: [] + completeness: + status: complete + missing_fields: [] + provenance: + source_type: logical_adr + source_ref: ADR-L-0021#INV-0031 + extraction_phase: assign_canonical_invariant + classification: explicit + generator: adr-architecture-index + - id: INV-0032 + entity_type: invariant + name: INV-0032 + summary: >- + Experimental MVC-S candidate emission MUST be deterministic for identical MVC-D, candidate refs, selector refs, + topology metrics, rationale, and negative-space inputs. Fingerprints MUST be computed over canonicalized inp + lifecycle_stage: proposed + admission_status: admitted + canonical_source: + source_type: logical_adr + source_ref: ADR-L-0021#INV-0032 + artifact_path: adrs/logical/ADR-L-0021-experimental-mvc-d-to-mvc-s-contract-consumption.yaml + source_refs: [] + metadata: + adr_id: ADR-L-0021 + scope: global + statement: |- + Experimental MVC-S candidate emission MUST be deterministic for identical + MVC-D, candidate refs, selector refs, topology metrics, rationale, and + negative-space inputs. Fingerprints MUST be computed over canonicalized input. + enforcement_level: must + declaration_mode: local + upheld_by_decisions: [] + relationships: + declared_in: + - ADR-L-0021 + declares: [] + references: [] + referenced_by: [] + related_to: [] + enforces: [] + enforced_by: + - DEC-0023 + enabled_by: [] + enables: [] + governs: [] + governed_by: [] + implemented_by: [] + implements: [] + embodied_in: [] + embodies: [] + supersedes: [] + superseded_by: [] + refines: [] + refined_by: [] + contradicts: [] + rejects: [] + rejected_by: [] + completeness: + status: complete + missing_fields: [] + provenance: + source_type: logical_adr + source_ref: ADR-L-0021#INV-0032 + extraction_phase: assign_canonical_invariant + classification: explicit + generator: adr-architecture-index diff --git a/adrs/index/relationship-registry.yaml b/adrs/index/relationship-registry.yaml index 85f984f..db06213 100644 --- a/adrs/index/relationship-registry.yaml +++ b/adrs/index/relationship-registry.yaml @@ -101,6 +101,16 @@ relationships: canonical_source_ref: ADR-L-0020#CAP-0020 confidence: 1 metadata: {} + - relationship_id: declared_in:CAP-0021:ADR-L-0021 + relationship_type: declared_in + from_entity_id: CAP-0021 + to_entity_id: ADR-L-0021 + provenance_classification: explicit + evidence: + - ADR-L-0021#CAP-0021 + canonical_source_ref: ADR-L-0021#CAP-0021 + confidence: 1 + metadata: {} - relationship_id: declared_in:COMP-0001:ADR-PC-0001 relationship_type: declared_in from_entity_id: COMP-0001 @@ -431,6 +441,16 @@ relationships: canonical_source_ref: ADR-L-0020#DEC-0022 confidence: 1 metadata: {} + - relationship_id: declared_in:DEC-0023:ADR-L-0021 + relationship_type: declared_in + from_entity_id: DEC-0023 + to_entity_id: ADR-L-0021 + provenance_classification: explicit + evidence: + - ADR-L-0021#DEC-0023 + canonical_source_ref: ADR-L-0021#DEC-0023 + confidence: 1 + metadata: {} - relationship_id: declared_in:INV-0001:ADR-L-0001 relationship_type: declared_in from_entity_id: INV-0001 @@ -671,6 +691,16 @@ relationships: canonical_source_ref: ADR-L-0018#INV-0024 confidence: 1 metadata: {} + - relationship_id: declared_in:INV-0025:ADR-L-0016 + relationship_type: declared_in + from_entity_id: INV-0025 + to_entity_id: ADR-L-0016 + provenance_classification: explicit + evidence: + - ADR-L-0016#INV-0025 + canonical_source_ref: ADR-L-0016#INV-0025 + confidence: 1 + metadata: {} - relationship_id: declared_in:INV-0027:ADR-L-0020 relationship_type: declared_in from_entity_id: INV-0027 @@ -701,6 +731,36 @@ relationships: canonical_source_ref: ADR-L-0020#INV-0029 confidence: 1 metadata: {} + - relationship_id: declared_in:INV-0030:ADR-L-0021 + relationship_type: declared_in + from_entity_id: INV-0030 + to_entity_id: ADR-L-0021 + provenance_classification: explicit + evidence: + - ADR-L-0021#INV-0030 + canonical_source_ref: ADR-L-0021#INV-0030 + confidence: 1 + metadata: {} + - relationship_id: declared_in:INV-0031:ADR-L-0021 + relationship_type: declared_in + from_entity_id: INV-0031 + to_entity_id: ADR-L-0021 + provenance_classification: explicit + evidence: + - ADR-L-0021#INV-0031 + canonical_source_ref: ADR-L-0021#INV-0031 + confidence: 1 + metadata: {} + - relationship_id: declared_in:INV-0032:ADR-L-0021 + relationship_type: declared_in + from_entity_id: INV-0032 + to_entity_id: ADR-L-0021 + provenance_classification: explicit + evidence: + - ADR-L-0021#INV-0032 + canonical_source_ref: ADR-L-0021#INV-0032 + confidence: 1 + metadata: {} - relationship_id: declared_in:SYS-0001:ADR-PS-0001 relationship_type: declared_in from_entity_id: SYS-0001 @@ -1121,6 +1181,16 @@ relationships: canonical_source_ref: ADR-L-0016#INV-0018 confidence: 1 metadata: {} + - relationship_id: declares:ADR-L-0016:INV-0025 + relationship_type: declares + from_entity_id: ADR-L-0016 + to_entity_id: INV-0025 + provenance_classification: derived + evidence: + - ADR-L-0016#INV-0025 + canonical_source_ref: ADR-L-0016#INV-0025 + confidence: 1 + metadata: {} - relationship_id: declares:ADR-L-0017:DEC-0017 relationship_type: declares from_entity_id: ADR-L-0017 @@ -1301,6 +1371,56 @@ relationships: canonical_source_ref: ADR-L-0020#INV-0029 confidence: 1 metadata: {} + - relationship_id: declares:ADR-L-0021:CAP-0021 + relationship_type: declares + from_entity_id: ADR-L-0021 + to_entity_id: CAP-0021 + provenance_classification: derived + evidence: + - ADR-L-0021#CAP-0021 + canonical_source_ref: ADR-L-0021#CAP-0021 + confidence: 1 + metadata: {} + - relationship_id: declares:ADR-L-0021:DEC-0023 + relationship_type: declares + from_entity_id: ADR-L-0021 + to_entity_id: DEC-0023 + provenance_classification: derived + evidence: + - ADR-L-0021#DEC-0023 + canonical_source_ref: ADR-L-0021#DEC-0023 + confidence: 1 + metadata: {} + - relationship_id: declares:ADR-L-0021:INV-0030 + relationship_type: declares + from_entity_id: ADR-L-0021 + to_entity_id: INV-0030 + provenance_classification: derived + evidence: + - ADR-L-0021#INV-0030 + canonical_source_ref: ADR-L-0021#INV-0030 + confidence: 1 + metadata: {} + - relationship_id: declares:ADR-L-0021:INV-0031 + relationship_type: declares + from_entity_id: ADR-L-0021 + to_entity_id: INV-0031 + provenance_classification: derived + evidence: + - ADR-L-0021#INV-0031 + canonical_source_ref: ADR-L-0021#INV-0031 + confidence: 1 + metadata: {} + - relationship_id: declares:ADR-L-0021:INV-0032 + relationship_type: declares + from_entity_id: ADR-L-0021 + to_entity_id: INV-0032 + provenance_classification: derived + evidence: + - ADR-L-0021#INV-0032 + canonical_source_ref: ADR-L-0021#INV-0032 + confidence: 1 + metadata: {} - relationship_id: declares:ADR-PC-0001:COMP-0001 relationship_type: declares from_entity_id: ADR-PC-0001 @@ -1711,6 +1831,16 @@ relationships: canonical_source_ref: ADR-L-0020#DEC-0022 confidence: 1 metadata: {} + - relationship_id: enabled_by:CAP-0021:DEC-0023 + relationship_type: enabled_by + from_entity_id: CAP-0021 + to_entity_id: DEC-0023 + provenance_classification: derived + evidence: + - ADR-L-0021 + canonical_source_ref: ADR-L-0021#DEC-0023 + confidence: 1 + metadata: {} - relationship_id: enables:DEC-0020:CAP-0018 relationship_type: enables from_entity_id: DEC-0020 @@ -1741,6 +1871,16 @@ relationships: canonical_source_ref: ADR-L-0020#DEC-0022 confidence: 1 metadata: {} + - relationship_id: enables:DEC-0023:CAP-0021 + relationship_type: enables + from_entity_id: DEC-0023 + to_entity_id: CAP-0021 + provenance_classification: explicit + evidence: + - ADR-L-0021 + canonical_source_ref: ADR-L-0021#DEC-0023 + confidence: 1 + metadata: {} - relationship_id: enforced_by:INV-0020:DEC-0020 relationship_type: enforced_by from_entity_id: INV-0020 @@ -1811,6 +1951,36 @@ relationships: canonical_source_ref: ADR-L-0020#DEC-0022 confidence: 1 metadata: {} + - relationship_id: enforced_by:INV-0030:DEC-0023 + relationship_type: enforced_by + from_entity_id: INV-0030 + to_entity_id: DEC-0023 + provenance_classification: derived + evidence: + - ADR-L-0021 + canonical_source_ref: ADR-L-0021#DEC-0023 + confidence: 1 + metadata: {} + - relationship_id: enforced_by:INV-0031:DEC-0023 + relationship_type: enforced_by + from_entity_id: INV-0031 + to_entity_id: DEC-0023 + provenance_classification: derived + evidence: + - ADR-L-0021 + canonical_source_ref: ADR-L-0021#DEC-0023 + confidence: 1 + metadata: {} + - relationship_id: enforced_by:INV-0032:DEC-0023 + relationship_type: enforced_by + from_entity_id: INV-0032 + to_entity_id: DEC-0023 + provenance_classification: derived + evidence: + - ADR-L-0021 + canonical_source_ref: ADR-L-0021#DEC-0023 + confidence: 1 + metadata: {} - relationship_id: enforces:DEC-0020:INV-0020 relationship_type: enforces from_entity_id: DEC-0020 @@ -1881,6 +2051,36 @@ relationships: canonical_source_ref: ADR-L-0020#DEC-0022 confidence: 1 metadata: {} + - relationship_id: enforces:DEC-0023:INV-0030 + relationship_type: enforces + from_entity_id: DEC-0023 + to_entity_id: INV-0030 + provenance_classification: explicit + evidence: + - ADR-L-0021 + canonical_source_ref: ADR-L-0021#DEC-0023 + confidence: 1 + metadata: {} + - relationship_id: enforces:DEC-0023:INV-0031 + relationship_type: enforces + from_entity_id: DEC-0023 + to_entity_id: INV-0031 + provenance_classification: explicit + evidence: + - ADR-L-0021 + canonical_source_ref: ADR-L-0021#DEC-0023 + confidence: 1 + metadata: {} + - relationship_id: enforces:DEC-0023:INV-0032 + relationship_type: enforces + from_entity_id: DEC-0023 + to_entity_id: INV-0032 + provenance_classification: explicit + evidence: + - ADR-L-0021 + canonical_source_ref: ADR-L-0021#DEC-0023 + confidence: 1 + metadata: {} - relationship_id: implemented_by:CAP-0018:COMP-0010 relationship_type: implemented_by from_entity_id: CAP-0018 @@ -2141,6 +2341,16 @@ relationships: canonical_source_ref: ADR-L-0016 confidence: 1 metadata: {} + - relationship_id: referenced_by:ADR-L-0012:ADR-L-0021 + relationship_type: referenced_by + from_entity_id: ADR-L-0012 + to_entity_id: ADR-L-0021 + provenance_classification: derived + evidence: + - ADR-L-0021 + canonical_source_ref: ADR-L-0021 + confidence: 1 + metadata: {} - relationship_id: referenced_by:ADR-L-0013:ADR-L-0015 relationship_type: referenced_by from_entity_id: ADR-L-0013 @@ -2211,6 +2421,16 @@ relationships: canonical_source_ref: ADR-L-0020 confidence: 1 metadata: {} + - relationship_id: referenced_by:ADR-L-0016:ADR-L-0021 + relationship_type: referenced_by + from_entity_id: ADR-L-0016 + to_entity_id: ADR-L-0021 + provenance_classification: derived + evidence: + - ADR-L-0021 + canonical_source_ref: ADR-L-0021 + confidence: 1 + metadata: {} - relationship_id: referenced_by:ADR-L-0017:ADR-L-0020 relationship_type: referenced_by from_entity_id: ADR-L-0017 @@ -2261,6 +2481,16 @@ relationships: canonical_source_ref: ADR-L-0020 confidence: 1 metadata: {} + - relationship_id: referenced_by:ADR-L-0020:ADR-L-0021 + relationship_type: referenced_by + from_entity_id: ADR-L-0020 + to_entity_id: ADR-L-0021 + provenance_classification: derived + evidence: + - ADR-L-0021 + canonical_source_ref: ADR-L-0021 + confidence: 1 + metadata: {} - relationship_id: references:ADR-L-0001:ADR-L-0002 relationship_type: references from_entity_id: ADR-L-0001 @@ -2521,6 +2751,36 @@ relationships: canonical_source_ref: ADR-L-0020 confidence: 1 metadata: {} + - relationship_id: references:ADR-L-0021:ADR-L-0012 + relationship_type: references + from_entity_id: ADR-L-0021 + to_entity_id: ADR-L-0012 + provenance_classification: explicit + evidence: + - ADR-L-0021 + canonical_source_ref: ADR-L-0021 + confidence: 1 + metadata: {} + - relationship_id: references:ADR-L-0021:ADR-L-0016 + relationship_type: references + from_entity_id: ADR-L-0021 + to_entity_id: ADR-L-0016 + provenance_classification: explicit + evidence: + - ADR-L-0021 + canonical_source_ref: ADR-L-0021 + confidence: 1 + metadata: {} + - relationship_id: references:ADR-L-0021:ADR-L-0020 + relationship_type: references + from_entity_id: ADR-L-0021 + to_entity_id: ADR-L-0020 + provenance_classification: explicit + evidence: + - ADR-L-0021 + canonical_source_ref: ADR-L-0021 + confidence: 1 + metadata: {} - relationship_id: related_to:ADR-PC-0001:ADR-PS-0001 relationship_type: related_to from_entity_id: ADR-PC-0001 diff --git a/adrs/index/rule-registry.yaml b/adrs/index/rule-registry.yaml new file mode 100644 index 0000000..903ac30 --- /dev/null +++ b/adrs/index/rule-registry.yaml @@ -0,0 +1,3 @@ +schema_version: '1.1' +type: normalized_entity_registry +entities: [] diff --git a/adrs/index/system-registry.yaml b/adrs/index/system-registry.yaml index e96af41..1d401d4 100644 --- a/adrs/index/system-registry.yaml +++ b/adrs/index/system-registry.yaml @@ -1,99 +1,134 @@ schema_version: '1.1' type: normalized_entity_registry entities: -- id: SYS-0001 - entity_type: system - name: Runtime Orchestration and Assistant Integration - summary: ste-runtime now contains a runtime orchestration boundary that keeps semantic - state fresh, exposes assistant-facing MCP tools, performs reconciliation gating - and freshness checks, and assembles implementation context and - lifecycle_stage: active - canonical_source: - source_type: physical_system_adr - source_ref: ADR-PS-0001 - artifact_path: adrs/physical-system/ADR-PS-0001-runtime-orchestration-and-assistant-integration.yaml - source_refs: [] - metadata: - adr_id: ADR-PS-0001 - implements_logical: - - ADR-L-0004 - - ADR-L-0006 - - ADR-L-0007 - - ADR-L-0018 - technologies: - - typescript - - node.js - - mcp - - chokidar - - zod - relationships: - declared_in: - - ADR-PS-0001 - references: [] - related_to: [] - enforces: [] - enabled_by: [] - enables: [] - governs: [] - implemented_by: [] - embodied_in: [] - supersedes: [] - superseded_by: [] - refines: [] - completeness: - status: complete - missing_fields: [] - provenance: - source_type: physical_system_adr - source_ref: ADR-PS-0001 - extraction_phase: extract_system - classification: explicit - generator: adr-architecture-index -- id: SYS-0002 - entity_type: system - name: Semantic Extraction Subsystem - summary: ste-runtime extraction is now a subsystem containing multiple first-class - extractors and normalization flows rather than a pair of isolated physical slices. - This ADR groups the implemented extractor estate under a concre - lifecycle_stage: active - canonical_source: - source_type: physical_system_adr - source_ref: ADR-PS-0002 - artifact_path: adrs/physical-system/ADR-PS-0002-semantic-extraction-subsystem.yaml - source_refs: [] - metadata: - adr_id: ADR-PS-0002 - implements_logical: - - ADR-L-0001 - - ADR-L-0005 - technologies: - - typescript - - node.js - - json - - angular - - css - - cloudformation - - adr-yaml - relationships: - declared_in: - - ADR-PS-0002 - references: [] - related_to: [] - enforces: [] - enabled_by: [] - enables: [] - governs: [] - implemented_by: [] - embodied_in: [] - supersedes: [] - superseded_by: [] - refines: [] - completeness: - status: complete - missing_fields: [] - provenance: - source_type: physical_system_adr - source_ref: ADR-PS-0002 - extraction_phase: extract_system - classification: explicit - generator: adr-architecture-index + - id: SYS-0001 + entity_type: system + name: Runtime Orchestration and Assistant Integration + summary: >- + ste-runtime now contains a runtime orchestration boundary that keeps semantic state fresh, exposes + assistant-facing MCP tools, performs reconciliation gating and freshness checks, and assembles implementation + context and + lifecycle_stage: proposed + admission_status: admitted + canonical_source: + source_type: physical_system_adr + source_ref: ADR-PS-0001 + artifact_path: adrs/physical-system/ADR-PS-0001-runtime-orchestration-and-assistant-integration.yaml + source_refs: [] + metadata: + adr_id: ADR-PS-0001 + implements_logical: + - ADR-L-0004 + - ADR-L-0006 + - ADR-L-0007 + - ADR-L-0018 + technologies: + - typescript + - node.js + - mcp + - chokidar + - zod + relationships: + declared_in: + - ADR-PS-0001 + declares: [] + references: [] + referenced_by: [] + related_to: [] + enforces: [] + enforced_by: [] + enabled_by: [] + enables: [] + governs: [] + governed_by: [] + implemented_by: [] + implements: [] + embodied_in: [] + embodies: + - COMP-0001 + - COMP-0002 + - COMP-0003 + - COMP-0004 + - COMP-0010 + - COMP-0011 + supersedes: [] + superseded_by: [] + refines: [] + refined_by: [] + contradicts: [] + rejects: [] + rejected_by: [] + completeness: + status: complete + missing_fields: [] + provenance: + source_type: physical_system_adr + source_ref: ADR-PS-0001 + extraction_phase: extract_system + classification: explicit + generator: adr-architecture-index + - id: SYS-0002 + entity_type: system + name: Semantic Extraction Subsystem + summary: >- + ste-runtime extraction is now a subsystem containing multiple first-class extractors and normalization flows + rather than a pair of isolated physical slices. This ADR groups the implemented extractor estate under a concre + lifecycle_stage: proposed + admission_status: admitted + canonical_source: + source_type: physical_system_adr + source_ref: ADR-PS-0002 + artifact_path: adrs/physical-system/ADR-PS-0002-semantic-extraction-subsystem.yaml + source_refs: [] + metadata: + adr_id: ADR-PS-0002 + implements_logical: + - ADR-L-0001 + - ADR-L-0005 + technologies: + - typescript + - node.js + - json + - angular + - css + - cloudformation + - adr-yaml + relationships: + declared_in: + - ADR-PS-0002 + declares: [] + references: [] + referenced_by: [] + related_to: [] + enforces: [] + enforced_by: [] + enabled_by: [] + enables: [] + governs: [] + governed_by: [] + implemented_by: [] + implements: [] + embodied_in: [] + embodies: + - COMP-0005 + - COMP-0006 + - COMP-0007 + - COMP-0008 + - COMP-0009 + - COMP-0012 + supersedes: [] + superseded_by: [] + refines: [] + refined_by: [] + contradicts: [] + rejects: [] + rejected_by: [] + completeness: + status: complete + missing_fields: [] + provenance: + source_type: physical_system_adr + source_ref: ADR-PS-0002 + extraction_phase: extract_system + classification: explicit + generator: adr-architecture-index diff --git a/adrs/logical/ADR-L-0007-graph-freshness-and-obligation-projection-semantics.yaml b/adrs/logical/ADR-L-0007-graph-freshness-and-obligation-projection-semantics.yaml index 659bc71..b6a245d 100644 --- a/adrs/logical/ADR-L-0007-graph-freshness-and-obligation-projection-semantics.yaml +++ b/adrs/logical/ADR-L-0007-graph-freshness-and-obligation-projection-semantics.yaml @@ -5,7 +5,7 @@ title: Graph Freshness and Obligation Projection Semantics status: proposed created_date: '2026-03-15' authors: -- ste-runtime +- erik.gallmann domains: - rss - obligations diff --git a/adrs/logical/ADR-L-0009-unified-workspace-scope-model.yaml b/adrs/logical/ADR-L-0009-unified-workspace-scope-model.yaml index 44debf8..6e8b4ef 100644 --- a/adrs/logical/ADR-L-0009-unified-workspace-scope-model.yaml +++ b/adrs/logical/ADR-L-0009-unified-workspace-scope-model.yaml @@ -5,7 +5,7 @@ title: Unified Workspace Scope Model status: proposed created_date: '2026-04-21' authors: -- ste-runtime +- erik.gallmann domains: - workspace - scope diff --git a/adrs/logical/ADR-L-0010-bootstrap-and-init-capability.yaml b/adrs/logical/ADR-L-0010-bootstrap-and-init-capability.yaml index 4e61a24..ffda4ab 100644 --- a/adrs/logical/ADR-L-0010-bootstrap-and-init-capability.yaml +++ b/adrs/logical/ADR-L-0010-bootstrap-and-init-capability.yaml @@ -5,7 +5,7 @@ title: Bootstrap and Init Capability status: proposed created_date: '2026-04-21' authors: -- ste-runtime +- erik.gallmann domains: - workspace - init diff --git a/adrs/logical/ADR-L-0011-adapter-role-conformance.yaml b/adrs/logical/ADR-L-0011-adapter-role-conformance.yaml index be1f6a2..312c640 100644 --- a/adrs/logical/ADR-L-0011-adapter-role-conformance.yaml +++ b/adrs/logical/ADR-L-0011-adapter-role-conformance.yaml @@ -5,7 +5,7 @@ title: Adapter Role Conformance status: proposed created_date: '2026-04-21' authors: -- ste-runtime +- erik.gallmann domains: - architecture - integration diff --git a/adrs/logical/ADR-L-0012-polyglot-interop-contract.yaml b/adrs/logical/ADR-L-0012-polyglot-interop-contract.yaml index 739caea..9759111 100644 --- a/adrs/logical/ADR-L-0012-polyglot-interop-contract.yaml +++ b/adrs/logical/ADR-L-0012-polyglot-interop-contract.yaml @@ -5,7 +5,7 @@ title: Polyglot Interop Contract status: proposed created_date: '2026-04-21' authors: -- ste-runtime +- erik.gallmann domains: - architecture - interop diff --git a/adrs/logical/ADR-L-0013-path-portability-contract.yaml b/adrs/logical/ADR-L-0013-path-portability-contract.yaml index 86fc874..823e36f 100644 --- a/adrs/logical/ADR-L-0013-path-portability-contract.yaml +++ b/adrs/logical/ADR-L-0013-path-portability-contract.yaml @@ -5,7 +5,7 @@ title: Path Portability Contract status: proposed created_date: '2026-04-21' authors: -- ste-runtime +- erik.gallmann domains: - portability - paths diff --git a/adrs/logical/ADR-L-0014-private-registry-isolation.yaml b/adrs/logical/ADR-L-0014-private-registry-isolation.yaml index 718c8da..08c4a83 100644 --- a/adrs/logical/ADR-L-0014-private-registry-isolation.yaml +++ b/adrs/logical/ADR-L-0014-private-registry-isolation.yaml @@ -5,7 +5,7 @@ title: Private Registry Isolation status: proposed created_date: '2026-04-21' authors: -- ste-runtime +- erik.gallmann domains: - security - registry diff --git a/adrs/logical/ADR-L-0015-workspace-agnosticism-invariant.yaml b/adrs/logical/ADR-L-0015-workspace-agnosticism-invariant.yaml index 08c5357..1a2929b 100644 --- a/adrs/logical/ADR-L-0015-workspace-agnosticism-invariant.yaml +++ b/adrs/logical/ADR-L-0015-workspace-agnosticism-invariant.yaml @@ -5,7 +5,7 @@ title: Workspace Agnosticism Invariant status: proposed created_date: '2026-04-24' authors: -- ste-runtime +- erik.gallmann domains: - workspace - portability diff --git a/adrs/logical/ADR-L-0016-workspace-graph-slice-schema-contract.yaml b/adrs/logical/ADR-L-0016-workspace-graph-slice-schema-contract.yaml index 063b044..9e493cf 100644 --- a/adrs/logical/ADR-L-0016-workspace-graph-slice-schema-contract.yaml +++ b/adrs/logical/ADR-L-0016-workspace-graph-slice-schema-contract.yaml @@ -5,7 +5,7 @@ title: Workspace Graph Slice Schema Contract status: proposed created_date: '2026-04-24' authors: -- ste-runtime +- erik.gallmann domains: - workspace - interop diff --git a/adrs/logical/ADR-L-0017-recon-workspace-execution-contract.yaml b/adrs/logical/ADR-L-0017-recon-workspace-execution-contract.yaml index 1c61748..2306761 100644 --- a/adrs/logical/ADR-L-0017-recon-workspace-execution-contract.yaml +++ b/adrs/logical/ADR-L-0017-recon-workspace-execution-contract.yaml @@ -5,7 +5,7 @@ title: RECON Workspace Execution Contract status: proposed created_date: '2026-04-30' authors: -- ste-runtime +- erik.gallmann domains: - workspace - recon diff --git a/adrs/manifest.yaml b/adrs/manifest.yaml index 3cab9f3..b883f37 100644 --- a/adrs/manifest.yaml +++ b/adrs/manifest.yaml @@ -1,6 +1,6 @@ schema_version: '1.0' type: manifest -generated_date: '2026-05-27T05:44:06Z' +generated_date: '2026-05-30T19:23:29Z' generated_from: adrs/**/*.yaml adrs: - id: ADR-L-0001 @@ -343,7 +343,7 @@ adrs: implements_logical: [] technologies: [] decision_count: 1 - invariant_count: 2 + invariant_count: 3 gap_count: 0 blocking_gaps: 0 component_count: 0 @@ -450,6 +450,32 @@ adrs: related_reviews: [] related_overrides: [] related_ledgers: [] + - id: ADR-L-0021 + type: logical + title: Experimental MVC-D to MVC-S Contract Consumption + status: proposed + file_path: adrs/logical/ADR-L-0021-experimental-mvc-d-to-mvc-s-contract-consumption.yaml + domains: + - mvc + - contracts + - runtime + - provenance + tags: + - mvc-d + - mvc-s + - contract-consumption + - candidate-surface + - provenance + implements_logical: [] + technologies: [] + decision_count: 1 + invariant_count: 3 + gap_count: 0 + blocking_gaps: 0 + component_count: 0 + related_reviews: [] + related_overrides: [] + related_ledgers: [] - id: ADR-P-0001 type: physical title: RSS CLI Implementation for Developer-Invoked Graph Traversal @@ -653,7 +679,7 @@ adrs: - zod decision_count: 0 invariant_count: 0 - gap_count: 0 + gap_count: 1 blocking_gaps: 0 component_count: 1 related_reviews: [] @@ -995,20 +1021,20 @@ decision_ledgers: [] objection_overrides: [] steelman_reviews: [] gaps_summary: - total: 3 + total: 4 blocking: 0 by_adr: {} statistics: - total_adrs: 37 - logical_adrs: 19 + total_adrs: 38 + logical_adrs: 20 physical_adrs: 5 physical_system_adrs: 2 physical_component_adrs: 11 decision_adrs: 0 - total_decisions: 21 - total_invariants: 27 + total_decisions: 22 + total_invariants: 31 total_components: 19 - total_gaps: 3 + total_gaps: 4 blocking_gaps: 0 total_entities: 0 total_requirements_snapshots: 0 diff --git a/adrs/physical-component/ADR-PC-0001-mcp-server-and-tool-registry.yaml b/adrs/physical-component/ADR-PC-0001-mcp-server-and-tool-registry.yaml index 4ecbed6..ec14d54 100644 --- a/adrs/physical-component/ADR-PC-0001-mcp-server-and-tool-registry.yaml +++ b/adrs/physical-component/ADR-PC-0001-mcp-server-and-tool-registry.yaml @@ -5,7 +5,7 @@ title: MCP Server and Tool Registry status: proposed created_date: '2026-03-15' authors: -- ste-runtime +- erik.gallmann domains: - mcp - integration diff --git a/adrs/physical-component/ADR-PC-0002-watchdog-and-update-coordination.yaml b/adrs/physical-component/ADR-PC-0002-watchdog-and-update-coordination.yaml index 6ab356c..81b2eb3 100644 --- a/adrs/physical-component/ADR-PC-0002-watchdog-and-update-coordination.yaml +++ b/adrs/physical-component/ADR-PC-0002-watchdog-and-update-coordination.yaml @@ -5,7 +5,7 @@ title: Watchdog and Update Coordination status: proposed created_date: '2026-03-15' authors: -- ste-runtime +- erik.gallmann domains: - watch - runtime diff --git a/adrs/physical-component/ADR-PC-0003-preflight-freshness-and-reconciliation-gating.yaml b/adrs/physical-component/ADR-PC-0003-preflight-freshness-and-reconciliation-gating.yaml index 5b91ca4..8f320ec 100644 --- a/adrs/physical-component/ADR-PC-0003-preflight-freshness-and-reconciliation-gating.yaml +++ b/adrs/physical-component/ADR-PC-0003-preflight-freshness-and-reconciliation-gating.yaml @@ -5,7 +5,7 @@ title: Preflight Freshness and Reconciliation Gating status: proposed created_date: '2026-03-15' authors: -- ste-runtime +- erik.gallmann domains: - preflight - freshness diff --git a/adrs/physical-component/ADR-PC-0004-obligation-projection-and-context-assembly.yaml b/adrs/physical-component/ADR-PC-0004-obligation-projection-and-context-assembly.yaml index dd17087..2ebcc16 100644 --- a/adrs/physical-component/ADR-PC-0004-obligation-projection-and-context-assembly.yaml +++ b/adrs/physical-component/ADR-PC-0004-obligation-projection-and-context-assembly.yaml @@ -5,7 +5,7 @@ title: Obligation Projection and Context Assembly status: proposed created_date: '2026-03-15' authors: -- ste-runtime +- erik.gallmann domains: - obligations - context diff --git a/adrs/physical-component/ADR-PC-0005-json-semantic-extraction.yaml b/adrs/physical-component/ADR-PC-0005-json-semantic-extraction.yaml index 1e49661..3cbfb52 100644 --- a/adrs/physical-component/ADR-PC-0005-json-semantic-extraction.yaml +++ b/adrs/physical-component/ADR-PC-0005-json-semantic-extraction.yaml @@ -5,7 +5,7 @@ title: JSON Semantic Extraction status: proposed created_date: '2026-03-15' authors: -- ste-runtime +- erik.gallmann domains: - extraction - json diff --git a/adrs/physical-component/ADR-PC-0006-frontend-semantic-extraction.yaml b/adrs/physical-component/ADR-PC-0006-frontend-semantic-extraction.yaml index 86e358a..5befb4f 100644 --- a/adrs/physical-component/ADR-PC-0006-frontend-semantic-extraction.yaml +++ b/adrs/physical-component/ADR-PC-0006-frontend-semantic-extraction.yaml @@ -5,7 +5,7 @@ title: Frontend Semantic Extraction status: proposed created_date: '2026-03-15' authors: -- ste-runtime +- erik.gallmann domains: - extraction - frontend diff --git a/adrs/physical-component/ADR-PC-0007-cloudformation-semantic-extraction.yaml b/adrs/physical-component/ADR-PC-0007-cloudformation-semantic-extraction.yaml index 0d4e345..94920ac 100644 --- a/adrs/physical-component/ADR-PC-0007-cloudformation-semantic-extraction.yaml +++ b/adrs/physical-component/ADR-PC-0007-cloudformation-semantic-extraction.yaml @@ -5,7 +5,7 @@ title: CloudFormation Semantic Extraction status: proposed created_date: '2026-03-15' authors: -- ste-runtime +- erik.gallmann domains: - extraction - cloudformation diff --git a/adrs/physical-component/ADR-PC-0008-service-wiring-post-processing.yaml b/adrs/physical-component/ADR-PC-0008-service-wiring-post-processing.yaml index 9ca3655..7457d21 100644 --- a/adrs/physical-component/ADR-PC-0008-service-wiring-post-processing.yaml +++ b/adrs/physical-component/ADR-PC-0008-service-wiring-post-processing.yaml @@ -5,7 +5,7 @@ title: Service Wiring Post-Processing status: proposed created_date: '2026-04-24' authors: -- ste-runtime +- erik.gallmann domains: - workspace - graph diff --git a/adrs/physical-component/ADR-PC-0011-adr-yaml-semantic-extraction.yaml b/adrs/physical-component/ADR-PC-0011-adr-yaml-semantic-extraction.yaml index 09d4e64..56b5ce2 100644 --- a/adrs/physical-component/ADR-PC-0011-adr-yaml-semantic-extraction.yaml +++ b/adrs/physical-component/ADR-PC-0011-adr-yaml-semantic-extraction.yaml @@ -5,7 +5,7 @@ title: ADR YAML Semantic Extraction status: proposed created_date: '2026-05-26' authors: -- ste-runtime +- erik.gallmann domains: - extraction - architecture diff --git a/adrs/physical-system/ADR-PS-0001-runtime-orchestration-and-assistant-integration.yaml b/adrs/physical-system/ADR-PS-0001-runtime-orchestration-and-assistant-integration.yaml index d78023f..acf1965 100644 --- a/adrs/physical-system/ADR-PS-0001-runtime-orchestration-and-assistant-integration.yaml +++ b/adrs/physical-system/ADR-PS-0001-runtime-orchestration-and-assistant-integration.yaml @@ -5,7 +5,7 @@ title: Runtime Orchestration and Assistant Integration status: proposed created_date: '2026-03-15' authors: -- ste-runtime +- erik.gallmann domains: - runtime - mcp diff --git a/adrs/physical-system/ADR-PS-0002-semantic-extraction-subsystem.yaml b/adrs/physical-system/ADR-PS-0002-semantic-extraction-subsystem.yaml index ac7189e..b026ec9 100644 --- a/adrs/physical-system/ADR-PS-0002-semantic-extraction-subsystem.yaml +++ b/adrs/physical-system/ADR-PS-0002-semantic-extraction-subsystem.yaml @@ -5,7 +5,7 @@ title: Semantic Extraction Subsystem status: proposed created_date: '2026-03-15' authors: -- ste-runtime +- erik.gallmann domains: - extraction - recon diff --git a/adrs/physical/ADR-P-0005-extractor-validation-requirements.yaml b/adrs/physical/ADR-P-0005-extractor-validation-requirements.yaml index 2230f8b..db2de35 100644 --- a/adrs/physical/ADR-P-0005-extractor-validation-requirements.yaml +++ b/adrs/physical/ADR-P-0005-extractor-validation-requirements.yaml @@ -6,7 +6,7 @@ status: accepted created_date: '2026-01-11' modified_date: '2026-01-11' authors: -- system +- erik.gallmann domains: - validation - extraction diff --git a/adrs/rendered/ADR-L-0007.md b/adrs/rendered/ADR-L-0007.md index aec91cf..5f3e040 100644 --- a/adrs/rendered/ADR-L-0007.md +++ b/adrs/rendered/ADR-L-0007.md @@ -5,15 +5,15 @@ artifact_kind: rendered_adr_markdown generator_id: adr-rendered-markdown generator_version: 1 hash_algorithm: sha256 -source_hash: a7a15933cea196db8c50170fbd36a41f9d45c8b28dd5892364a4a52de89260b1 -rendered_hash: 5d311f67fc53940862e64265de11979d4e42a249b41042d13da855c6fcc2b813 +source_hash: abdacdd4d9a01fa745b05a78adb1467ae21f3f4fe7751848e9477d2218df38f8 +rendered_hash: 42ed4932e8f42b073384e5cff0e68badcc862a7212de8baacfce5305a8ab1ace --> # ADR-L-0007: Graph Freshness and Obligation Projection Semantics **Status:** proposed **Created:** 2026-03-15 -**Authors:** ste-runtime +**Authors:** erik.gallmann **Domains:** rss, obligations, freshness **Tags:** freshness, obligations, preflight, validation diff --git a/adrs/rendered/ADR-L-0009.md b/adrs/rendered/ADR-L-0009.md index 216b213..7819646 100644 --- a/adrs/rendered/ADR-L-0009.md +++ b/adrs/rendered/ADR-L-0009.md @@ -5,15 +5,15 @@ artifact_kind: rendered_adr_markdown generator_id: adr-rendered-markdown generator_version: 1 hash_algorithm: sha256 -source_hash: 3b0c89175db6301d49efd9c622c156bde55feb55f45d253128fdcca71272378e -rendered_hash: c4f500f88acdd00d5bf1ab736de4beed097ce0a90e695a10a9bae7d361e14cd0 +source_hash: ac3f676cc29355f11e56e116fd16b0fabc0e3322683b8c6adbd3f681e9c0e1b3 +rendered_hash: 275b82a6f33e7b58597a3b76fe36a4465d987a727a85ecbe28c8249eded5e49f --> # ADR-L-0009: Unified Workspace Scope Model **Status:** proposed **Created:** 2026-04-21 -**Authors:** ste-runtime +**Authors:** erik.gallmann **Domains:** workspace, scope **Tags:** workspace, scope, multi-repo diff --git a/adrs/rendered/ADR-L-0010.md b/adrs/rendered/ADR-L-0010.md index 03e04d0..31fc466 100644 --- a/adrs/rendered/ADR-L-0010.md +++ b/adrs/rendered/ADR-L-0010.md @@ -5,15 +5,15 @@ artifact_kind: rendered_adr_markdown generator_id: adr-rendered-markdown generator_version: 1 hash_algorithm: sha256 -source_hash: 274822d861dcb895fbbb91d64599cae0e7cc971b901a2488fb014d5fbc1349c2 -rendered_hash: ef0574b189177ad28091c720a9fef12a1405cf0718494c71007d9f51d3713aba +source_hash: 45ec016138e9614ae97ba46ee0efd085a3a76973d7145a5162f3e6d7ee367683 +rendered_hash: f3ab939ed09b41223957b2a178bb179fbb2ce59055ba842f696c7d1d146ba942 --> # ADR-L-0010: Bootstrap and Init Capability **Status:** proposed **Created:** 2026-04-21 -**Authors:** ste-runtime +**Authors:** erik.gallmann **Domains:** workspace, init **Tags:** init, bootstrap, onboarding diff --git a/adrs/rendered/ADR-L-0011.md b/adrs/rendered/ADR-L-0011.md index 6336885..ab12a52 100644 --- a/adrs/rendered/ADR-L-0011.md +++ b/adrs/rendered/ADR-L-0011.md @@ -5,15 +5,15 @@ artifact_kind: rendered_adr_markdown generator_id: adr-rendered-markdown generator_version: 1 hash_algorithm: sha256 -source_hash: 511c75679011f2323a1aa5ec926ecc3e112f84ebdc88cada089dd9d4fcfdf13a -rendered_hash: eb35bbf13fd138865e0b71e263e2c2b1abdcf40b2bf796d87f5b51bab67c74e3 +source_hash: 940b4abd89aecab6d77b11793749b987bc82e6e10ff140ee288afd041288bd1c +rendered_hash: f7263d352907f363c574e7c98e91e3439706df1c42711a908e586d915f2b1903 --> # ADR-L-0011: Adapter Role Conformance **Status:** proposed **Created:** 2026-04-21 -**Authors:** ste-runtime +**Authors:** erik.gallmann **Domains:** architecture, integration **Tags:** adapter, role, evidence diff --git a/adrs/rendered/ADR-L-0012.md b/adrs/rendered/ADR-L-0012.md index 8d4d33e..efa77e7 100644 --- a/adrs/rendered/ADR-L-0012.md +++ b/adrs/rendered/ADR-L-0012.md @@ -5,15 +5,15 @@ artifact_kind: rendered_adr_markdown generator_id: adr-rendered-markdown generator_version: 1 hash_algorithm: sha256 -source_hash: 0f889c4359169a5eb1f8ebc783ba990ab0f5e0ce9c7e27b44150f2aad684c8be -rendered_hash: c71d0269c367c8b0d3c1fec6c99ba2bfeb59486182ddb025641dec33f20e3413 +source_hash: 5d0a5320d3f0e9d6890a7bd50372b651cad60a37cdd1386be6455b29e49b2584 +rendered_hash: 57fcf65a9289998c9876878bc265c0302cfe91012f133f85d568217c35541378 --> # ADR-L-0012: Polyglot Interop Contract **Status:** proposed **Created:** 2026-04-21 -**Authors:** ste-runtime +**Authors:** erik.gallmann **Domains:** architecture, interop **Tags:** polyglot, schema, interop diff --git a/adrs/rendered/ADR-L-0013.md b/adrs/rendered/ADR-L-0013.md index 32f6618..e71bfb8 100644 --- a/adrs/rendered/ADR-L-0013.md +++ b/adrs/rendered/ADR-L-0013.md @@ -5,15 +5,15 @@ artifact_kind: rendered_adr_markdown generator_id: adr-rendered-markdown generator_version: 1 hash_algorithm: sha256 -source_hash: f6fc023e125773e665a74bc0246e7b895bf6fc5ca02701fb9a04f554fc408851 -rendered_hash: bbf9b5c30448e863e07b6221d4bd2d5e14662144ed1c2fff34e2a2e58339fc20 +source_hash: 9bcfea1fb7dda076f11910264ae9a747138222960a663f1b293095063711e2f7 +rendered_hash: df82c6c59d0b58853bde240700ca94b880d86925dc2f315fdd623b4b97c5173f --> # ADR-L-0013: Path Portability Contract **Status:** proposed **Created:** 2026-04-21 -**Authors:** ste-runtime +**Authors:** erik.gallmann **Domains:** portability, paths **Tags:** paths, portability, cross-platform diff --git a/adrs/rendered/ADR-L-0014.md b/adrs/rendered/ADR-L-0014.md index 5d406ec..08c00ad 100644 --- a/adrs/rendered/ADR-L-0014.md +++ b/adrs/rendered/ADR-L-0014.md @@ -5,15 +5,15 @@ artifact_kind: rendered_adr_markdown generator_id: adr-rendered-markdown generator_version: 1 hash_algorithm: sha256 -source_hash: 70520b57e59b56fc1b1462025fbe82f6c34ab7ae206320efb0507335b196c15a -rendered_hash: ba81edabd62467a36540e714aa2803f1763470c17ada82faccb3d90552fe7b6c +source_hash: f405609fe101144b93950e6cc2ffb93b47edb0aca91b2475dfaee1a1c1bb3d33 +rendered_hash: 05e3d56235fb8702417bfad9bbbc109339863fd5bddfde62b67e3f7906109fca --> # ADR-L-0014: Private Registry Isolation **Status:** proposed **Created:** 2026-04-21 -**Authors:** ste-runtime +**Authors:** erik.gallmann **Domains:** security, registry **Tags:** registry, isolation, ip-protection diff --git a/adrs/rendered/ADR-L-0015.md b/adrs/rendered/ADR-L-0015.md index 9986aed..b22e4bb 100644 --- a/adrs/rendered/ADR-L-0015.md +++ b/adrs/rendered/ADR-L-0015.md @@ -5,15 +5,15 @@ artifact_kind: rendered_adr_markdown generator_id: adr-rendered-markdown generator_version: 1 hash_algorithm: sha256 -source_hash: 4bcf158ec4664c30e1ed2b276be6f5fca5706958bce23a5f48ed4ab3b5b59e21 -rendered_hash: 86e13f88ed19103cae1cf543823227309330bc22680a771e9744b17a07412a85 +source_hash: cdd61dd237b693bd284fd99f29a76ef2dd573611fd49a5338e231c9a968934f8 +rendered_hash: 10e410a663dec4447785dc5877ad0995f8428147a95f2339fe66dba71fc1b1c0 --> # ADR-L-0015: Workspace Agnosticism Invariant **Status:** proposed **Created:** 2026-04-24 -**Authors:** ste-runtime +**Authors:** erik.gallmann **Domains:** workspace, portability, architecture **Tags:** workspace-agnosticism, invariant, oss, manifest-driven diff --git a/adrs/rendered/ADR-L-0016.md b/adrs/rendered/ADR-L-0016.md index 58e6e7c..47298a5 100644 --- a/adrs/rendered/ADR-L-0016.md +++ b/adrs/rendered/ADR-L-0016.md @@ -5,15 +5,15 @@ artifact_kind: rendered_adr_markdown generator_id: adr-rendered-markdown generator_version: 1 hash_algorithm: sha256 -source_hash: fa9019bfdbd24218c83b1a3e70d51855217ebebe3a95b38f9dde94ec6a263eef -rendered_hash: fd199018d41f62e18e86dafa9a39084a35ab955242dfabc1a23473dd0cdf279f +source_hash: 5c2374a81b3e04d1bfbe4a8dfc66d6655c49b87bd06269510c271ee852c6a50f +rendered_hash: 3376e84d0c24085f81cc36de9195bb1345171f7e637ebe6cecb45fd9343e1350 --> # ADR-L-0016: Workspace Graph Slice Schema Contract **Status:** proposed **Created:** 2026-04-24 -**Authors:** ste-runtime +**Authors:** erik.gallmann **Domains:** workspace, interop, graph **Tags:** slice-schema, graph, interop, contract diff --git a/adrs/rendered/ADR-L-0017.md b/adrs/rendered/ADR-L-0017.md index e8e7ca3..1f9a367 100644 --- a/adrs/rendered/ADR-L-0017.md +++ b/adrs/rendered/ADR-L-0017.md @@ -5,15 +5,15 @@ artifact_kind: rendered_adr_markdown generator_id: adr-rendered-markdown generator_version: 1 hash_algorithm: sha256 -source_hash: b4da495a7e28a8ca19262ec0ffd1ba78302af729a6db620440d7a39e248ec193 -rendered_hash: 9100857efafcf01d9695b9ca30d33a2f2aa660d14ffafc792e89231f17b03b85 +source_hash: 39d252b25d789912400dbf7486b4b553e8991bd551e615baa9a8544e91daa337 +rendered_hash: b10b9468dd88608c5d3211b02438db5fcb779e38e6ac6086d5c45a99880b3e1b --> # ADR-L-0017: RECON Workspace Execution Contract **Status:** proposed **Created:** 2026-04-30 -**Authors:** ste-runtime +**Authors:** erik.gallmann **Domains:** workspace, recon **Tags:** workspace, recon, reliability diff --git a/adrs/rendered/ADR-P-0005.md b/adrs/rendered/ADR-P-0005.md index 2562fd8..1ff0430 100644 --- a/adrs/rendered/ADR-P-0005.md +++ b/adrs/rendered/ADR-P-0005.md @@ -5,15 +5,15 @@ artifact_kind: rendered_adr_markdown generator_id: adr-rendered-markdown generator_version: 1 hash_algorithm: sha256 -source_hash: 42ab9e33279b5fcbdc7bb02b3df8e81624f02826e92f1c76ff50ad5be020aeac -rendered_hash: f835cc19c96ee70200201d2e259c77737efae61c2159895d33c78bccb6b8366a +source_hash: 8a264dc2b3efe64f15ec413effc8199584479f0aa4c4951d9115cd6037f79dba +rendered_hash: 15027b83f630c14ba4b77d4b79faacfc08e8999b4799541c64c71bad626294a4 --> # ADR-P-0005: Extractor Validation Requirements **Status:** accepted **Created:** 2026-01-11 -**Modified:** 2026-01-11 **Authors:** system +**Modified:** 2026-01-11 **Authors:** erik.gallmann **Domains:** validation, extraction, implementation **Tags:** validation, extractors, quality-assurance **Implements Logical:** ADR-L-0002 diff --git a/adrs/rendered/ADR-PC-0001.md b/adrs/rendered/ADR-PC-0001.md index dd55e3e..d6db982 100644 --- a/adrs/rendered/ADR-PC-0001.md +++ b/adrs/rendered/ADR-PC-0001.md @@ -5,15 +5,15 @@ artifact_kind: rendered_adr_markdown generator_id: adr-rendered-markdown generator_version: 1 hash_algorithm: sha256 -source_hash: faa5887192f0f63a1e7faeaf1723339da7c53a902a67c61fa4339c61c1633858 -rendered_hash: f21db8c9b9178d86552a0df5af850b1b898715f477d7e9651ed0304972f5d458 +source_hash: 66909b2de238af2839aa7ac0731914f2a487869f8ade66db1f8823ae7e276c58 +rendered_hash: 9c754205d8e1c33f8db6a392e89e77e61f77cb99aef28a2ceec30cf35e77228a --> # ADR-PC-0001: MCP Server and Tool Registry **Status:** proposed **Created:** 2026-03-15 -**Modified:** 2026-05-22 **Authors:** ste-runtime +**Modified:** 2026-05-22 **Authors:** erik.gallmann **Domains:** mcp, integration, runtime **Implements Logical:** ADR-L-0004, ADR-L-0006, ADR-L-0007, ADR-L-0018 diff --git a/adrs/rendered/ADR-PC-0002.md b/adrs/rendered/ADR-PC-0002.md index 25d1480..d33a450 100644 --- a/adrs/rendered/ADR-PC-0002.md +++ b/adrs/rendered/ADR-PC-0002.md @@ -5,15 +5,15 @@ artifact_kind: rendered_adr_markdown generator_id: adr-rendered-markdown generator_version: 1 hash_algorithm: sha256 -source_hash: 16f231caa57ccd42229fc0a2e3b8e4dc656349b64a42efab17b112d4b705166f -rendered_hash: 1271837befca44fec7578b9435d47ce3f7bbb95c2be6774739fd896bdd631936 +source_hash: 8bbdb43158a3ab78b90ca9675c4761158f7a7abdebacec92206517a8d2f3bf24 +rendered_hash: 77e069aecaf967c7d73e43f3f4f881bbc7e64797f765af3baaf4186e22e6b776 --> # ADR-PC-0002: Watchdog and Update Coordination **Status:** proposed **Created:** 2026-03-15 -**Authors:** ste-runtime +**Authors:** erik.gallmann **Domains:** watch, runtime, reconciliation **Implements Logical:** ADR-L-0004 diff --git a/adrs/rendered/ADR-PC-0003.md b/adrs/rendered/ADR-PC-0003.md index 7770029..37677fe 100644 --- a/adrs/rendered/ADR-PC-0003.md +++ b/adrs/rendered/ADR-PC-0003.md @@ -5,15 +5,15 @@ artifact_kind: rendered_adr_markdown generator_id: adr-rendered-markdown generator_version: 1 hash_algorithm: sha256 -source_hash: a2de2a193fe1907e99fe0823599e072cdffac0797e0b0262160def2eaadd5c06 -rendered_hash: b22826b20a2ac77c9869f37d414b6233bafb9252fec0c9118c8a9693ff1653dc +source_hash: 1cb4c2c6f9796dae7feded69fbd49f9c015ba3e95f10942f645abc027660b5a7 +rendered_hash: e50c32d08d49de1568ddefb3cc0d16caf690da739017daade81ac262160ab0cb --> # ADR-PC-0003: Preflight Freshness and Reconciliation Gating **Status:** proposed **Created:** 2026-03-15 -**Authors:** ste-runtime +**Authors:** erik.gallmann **Domains:** preflight, freshness, reconciliation **Implements Logical:** ADR-L-0004, ADR-L-0007 diff --git a/adrs/rendered/ADR-PC-0004.md b/adrs/rendered/ADR-PC-0004.md index fbde8fb..a2b8c57 100644 --- a/adrs/rendered/ADR-PC-0004.md +++ b/adrs/rendered/ADR-PC-0004.md @@ -5,15 +5,15 @@ artifact_kind: rendered_adr_markdown generator_id: adr-rendered-markdown generator_version: 1 hash_algorithm: sha256 -source_hash: 341c467fcca98fcfbff75eb38eca5554c09ddbc39a382ab8d710a84dad98eed7 -rendered_hash: 1506570a390e0981f697bb5156d9c061c0a06d9d761a143503105d88eead852d +source_hash: c38024673d002db24fde9cced2af35fb053e72b6902bd312b6f829f138b80477 +rendered_hash: 0f66ff3ff7b6b9f733b62b9385132f0fed73b0f297f8ffed99738f65996184a6 --> # ADR-PC-0004: Obligation Projection and Context Assembly **Status:** proposed **Created:** 2026-03-15 -**Authors:** ste-runtime +**Authors:** erik.gallmann **Domains:** obligations, context, rss **Implements Logical:** ADR-L-0006, ADR-L-0007 diff --git a/adrs/rendered/ADR-PC-0005.md b/adrs/rendered/ADR-PC-0005.md index b4a9104..ba75cac 100644 --- a/adrs/rendered/ADR-PC-0005.md +++ b/adrs/rendered/ADR-PC-0005.md @@ -5,15 +5,15 @@ artifact_kind: rendered_adr_markdown generator_id: adr-rendered-markdown generator_version: 1 hash_algorithm: sha256 -source_hash: 08563fb3d721fe653e31daed41cf81d473dc4ce01f3929700b972375eca6d5ca -rendered_hash: 5daa87bd7631944f11f816b0c38447aa40a9569a8a355ba2f1f5935149e071e6 +source_hash: b51dc98f2c6b885e4105f06bc181bbc53bf768df6fd84f4730dae6bb78f2af62 +rendered_hash: 7f590fcb9c663266b24e75a2184eb77ae71e01e07033451ed396d2bb9a0716d7 --> # ADR-PC-0005: JSON Semantic Extraction **Status:** proposed **Created:** 2026-03-15 -**Authors:** ste-runtime +**Authors:** erik.gallmann **Domains:** extraction, json, recon **Implements Logical:** ADR-L-0001 diff --git a/adrs/rendered/ADR-PC-0006.md b/adrs/rendered/ADR-PC-0006.md index c4b0580..db431ff 100644 --- a/adrs/rendered/ADR-PC-0006.md +++ b/adrs/rendered/ADR-PC-0006.md @@ -5,15 +5,15 @@ artifact_kind: rendered_adr_markdown generator_id: adr-rendered-markdown generator_version: 1 hash_algorithm: sha256 -source_hash: 1f110e8b84f1983604bc915733370f6f66fa1f26e9a2fc0196bdd1bcc82d83d2 -rendered_hash: 7910af2e101eba576d8c2a1ca0c043fa032d12d96ca1e4e2e0e023c22c4b107f +source_hash: 3a17d07ebf21f5e2d615e710d583a1d487240eb1d0eedbf9f0cfc31937e90404 +rendered_hash: 94a2aea50e32f240a0f1ea4b8e249117bb8c3e05d2fe09647a5fae417515ada1 --> # ADR-PC-0006: Frontend Semantic Extraction **Status:** proposed **Created:** 2026-03-15 -**Authors:** ste-runtime +**Authors:** erik.gallmann **Domains:** extraction, frontend, recon **Implements Logical:** ADR-L-0001 diff --git a/adrs/rendered/ADR-PC-0007.md b/adrs/rendered/ADR-PC-0007.md index e79d618..8bc9d90 100644 --- a/adrs/rendered/ADR-PC-0007.md +++ b/adrs/rendered/ADR-PC-0007.md @@ -5,15 +5,15 @@ artifact_kind: rendered_adr_markdown generator_id: adr-rendered-markdown generator_version: 1 hash_algorithm: sha256 -source_hash: c523151bf8959a8d66ababb36b18b046eb4102885cf9da5f8eace503bc39bf63 -rendered_hash: 7e871c053e9ef5fa15390dea764ceb74c64424133fdfa84f775aeb5a430b56ab +source_hash: 79a6a7cfa373569b4dbe1188223d58efb29f9b2b4cb4fe8016d18982e8144008 +rendered_hash: f935a91b7b20f061a974dacbd4b284735de2c1f5d38d2479dc0b9d0346e0c389 --> # ADR-PC-0007: CloudFormation Semantic Extraction **Status:** proposed **Created:** 2026-03-15 -**Authors:** ste-runtime +**Authors:** erik.gallmann **Domains:** extraction, cloudformation, recon **Implements Logical:** ADR-L-0001 diff --git a/adrs/rendered/ADR-PC-0008.md b/adrs/rendered/ADR-PC-0008.md index d4d1ec1..649abc3 100644 --- a/adrs/rendered/ADR-PC-0008.md +++ b/adrs/rendered/ADR-PC-0008.md @@ -5,15 +5,15 @@ artifact_kind: rendered_adr_markdown generator_id: adr-rendered-markdown generator_version: 1 hash_algorithm: sha256 -source_hash: 26b93b64666720500c7794e7d5ffa98d83205bb1a0749da334fccda339d500b4 -rendered_hash: 951392b08a2893c69646a64ea2b677c44e62f1e33f382df13d61962903e825d6 +source_hash: a2ba9dd3fac8c0053c368c49819e09f9c38eb191b94d5819ce9d5333d5f9e861 +rendered_hash: db9c2824ffd89fff4420f63564212821624a6bc3373bb084d5d8662fcb0494ab --> # ADR-PC-0008: Service Wiring Post-Processing **Status:** proposed **Created:** 2026-04-24 -**Authors:** ste-runtime +**Authors:** erik.gallmann **Domains:** workspace, graph, extraction **Implements Logical:** ADR-L-0015, ADR-L-0016 diff --git a/adrs/rendered/ADR-PC-0011.md b/adrs/rendered/ADR-PC-0011.md index c59e14e..318c822 100644 --- a/adrs/rendered/ADR-PC-0011.md +++ b/adrs/rendered/ADR-PC-0011.md @@ -5,15 +5,15 @@ artifact_kind: rendered_adr_markdown generator_id: adr-rendered-markdown generator_version: 1 hash_algorithm: sha256 -source_hash: 32654b95f6c1332304311b45416fe836f0bb812db739ed1a6139d69998c2ec76 -rendered_hash: 2f4b4415b9c4761dcad92e33d6bab1e1cd071681c68151786e11660c84fbd93b +source_hash: b41ce8c5cf04c7d8a79ace4cd64fcfc2fb7455aacaba7f15f04ac831bc621217 +rendered_hash: 8953bed52e86f32d3bbe60cd45479f00f29f776ab99477aa6d507872bcfc5f88 --> # ADR-PC-0011: ADR YAML Semantic Extraction **Status:** proposed **Created:** 2026-05-26 -**Authors:** ste-runtime +**Authors:** erik.gallmann **Domains:** extraction, architecture, recon **Implements Logical:** ADR-L-0001, ADR-L-0005 diff --git a/adrs/rendered/ADR-PS-0001.md b/adrs/rendered/ADR-PS-0001.md index d25f8d2..7a40b93 100644 --- a/adrs/rendered/ADR-PS-0001.md +++ b/adrs/rendered/ADR-PS-0001.md @@ -5,15 +5,15 @@ artifact_kind: rendered_adr_markdown generator_id: adr-rendered-markdown generator_version: 1 hash_algorithm: sha256 -source_hash: 8ad95837f2c20f44acea4ded73917592861532ec2a407b7c501a832485d55ef3 -rendered_hash: 4f937b55dfafc7428ef634a2c7282daaaa2fd2ce4a2898a97f1bebff0b96e144 +source_hash: 3eb6d5c42481f9dd7f034f70f6bdab860e913d0c2ed57702757ff290c57e82c1 +rendered_hash: 9f8879f6e8768087fdfc21873a7016c89caa2c5dd07ac5ce60a6ec52987eb5ad --> # ADR-PS-0001: Runtime Orchestration and Assistant Integration **Status:** proposed **Created:** 2026-03-15 -**Modified:** 2026-05-22 **Authors:** ste-runtime +**Modified:** 2026-05-22 **Authors:** erik.gallmann **Domains:** runtime, mcp, rss, watch **Tags:** runtime, mcp, watchdog, obligations **Implements Logical:** ADR-L-0004, ADR-L-0006, ADR-L-0007, ADR-L-0018 diff --git a/adrs/rendered/ADR-PS-0002.md b/adrs/rendered/ADR-PS-0002.md index b48aa39..d127884 100644 --- a/adrs/rendered/ADR-PS-0002.md +++ b/adrs/rendered/ADR-PS-0002.md @@ -5,15 +5,15 @@ artifact_kind: rendered_adr_markdown generator_id: adr-rendered-markdown generator_version: 1 hash_algorithm: sha256 -source_hash: 3b2505bb9e8a57856c8bebebb98e18b03a31f6e7042aa20536afcb008729c351 -rendered_hash: a244434cde1fa53c585474c34d429e42ee431130e8c5c6e15c5864c4936dd9fb +source_hash: d6ee7ddcdd2f9f9609b61fb4eb9c8fef0d0a96de70cb3a535a42aef66dd52ef9 +rendered_hash: 16ec691f081e565fdea0589f076c66c736db1c98f920d8a63ac097c9f87124d1 --> # ADR-PS-0002: Semantic Extraction Subsystem **Status:** proposed **Created:** 2026-03-15 -**Authors:** ste-runtime +**Authors:** erik.gallmann **Domains:** extraction, recon, normalization **Tags:** extraction, recon, semantic-state **Implements Logical:** ADR-L-0001, ADR-L-0005 From 6958069020cfc093b2171598140827d3a206bc2b Mon Sep 17 00:00:00 2001 From: egallmann Date: Sat, 30 May 2026 17:14:06 -0400 Subject: [PATCH 2/3] Complete ste-runtime implementation attribution retrofit. Declare ADR/INV linkage on public surfaces via intent decorators, extend RECON extraction for class static metadata and implements_adr_method, split ADR-L-0011 vs 0007 evidence claims, and add contract-guard tests plus closure docs. Co-authored-by: Cursor --- ...l-mvc-d-to-mvc-s-contract-consumption.yaml | 110 +++++++ docs/attribution-adr-0011-0007-boundary.md | 43 +++ .../attribution-capability-linkage-backlog.md | 22 ++ docs/attribution-negative-space.md | 61 ++++ package.json | 2 +- src/architecture/intent-decorators.ts | 87 ++++++ src/cli/architecture-evidence-freshness.ts | 10 +- src/cli/evidence-command.ts | 23 +- .../mvc-evolution-schema-fixture-sync.test.ts | 45 +++ src/config/index.ts | 7 +- src/discovery/architecture-bundle.ts | 8 +- src/index.ts | 15 + .../attribution-evidence-sync.test.ts | 95 ++++++ src/provenance/provenance-test-helpers.ts | 51 +++ .../retrofit-contract-guards.test.ts | 189 +++++++++++ src/recon/index.ts | 9 +- src/recon/phases/extraction.test.ts | 126 ++++++++ src/recon/phases/extraction.ts | 249 ++++++++++++++- src/recon/phases/self-validation.ts | 15 +- src/recon/recon-provenance.test.ts | 45 +++ src/rss/conversational-query.ts | 23 +- src/watch/watchdog.ts | 3 + src/workspace/canned-queries.ts | 26 +- src/workspace/cem-mvc.ts | 46 ++- src/workspace/compression.ts | 10 +- src/workspace/emit-multi-res-projections.ts | 10 +- src/workspace/emit-projections.ts | 10 +- src/workspace/manifest.ts | 35 ++- src/workspace/mvc-evolution.test.ts | 295 ++++++++++++++++++ src/workspace/mvc-evolution.ts | 285 +++++++++++++++++ src/workspace/projection-families.ts | 7 +- src/workspace/projections.ts | 33 +- src/workspace/slice-emitter.ts | 13 +- src/workspace/slice-schema.ts | 11 +- src/workspace/source-locator-registry.ts | 9 +- src/workspace/source-uri.ts | 14 +- src/workspace/workspace-graph-loader.ts | 8 +- src/workspace/workspace-index.ts | 12 +- src/workspace/workspace-recon.ts | 12 +- .../mvc-evolution/mvc-definition.schema.json | 156 +++++++++ .../mvc-evolution/mvc-definition.valid.json | 56 ++++ .../mvc-evolution/mvc-snapshot.schema.json | 206 ++++++++++++ .../mvc-evolution/mvc-snapshot.valid.json | 71 +++++ tsconfig.json | 3 +- 44 files changed, 2472 insertions(+), 94 deletions(-) create mode 100644 adrs/logical/ADR-L-0021-experimental-mvc-d-to-mvc-s-contract-consumption.yaml create mode 100644 docs/attribution-adr-0011-0007-boundary.md create mode 100644 docs/attribution-capability-linkage-backlog.md create mode 100644 docs/attribution-negative-space.md create mode 100644 src/architecture/intent-decorators.ts create mode 100644 src/cli/mvc-evolution-schema-fixture-sync.test.ts create mode 100644 src/provenance/attribution-evidence-sync.test.ts create mode 100644 src/provenance/provenance-test-helpers.ts create mode 100644 src/provenance/retrofit-contract-guards.test.ts create mode 100644 src/recon/recon-provenance.test.ts create mode 100644 src/workspace/mvc-evolution.test.ts create mode 100644 src/workspace/mvc-evolution.ts create mode 100644 test/fixtures/mvc-evolution/mvc-definition.schema.json create mode 100644 test/fixtures/mvc-evolution/mvc-definition.valid.json create mode 100644 test/fixtures/mvc-evolution/mvc-snapshot.schema.json create mode 100644 test/fixtures/mvc-evolution/mvc-snapshot.valid.json diff --git a/adrs/logical/ADR-L-0021-experimental-mvc-d-to-mvc-s-contract-consumption.yaml b/adrs/logical/ADR-L-0021-experimental-mvc-d-to-mvc-s-contract-consumption.yaml new file mode 100644 index 0000000..172752f --- /dev/null +++ b/adrs/logical/ADR-L-0021-experimental-mvc-d-to-mvc-s-contract-consumption.yaml @@ -0,0 +1,110 @@ +schema_version: '1.0' +adr_type: logical +id: ADR-L-0021 +title: Experimental MVC-D to MVC-S Contract Consumption +status: proposed +created_date: '2026-05-30' +authors: +- erik.gallmann +domains: +- mvc +- contracts +- runtime +- provenance +tags: +- mvc-d +- mvc-s +- contract-consumption +- candidate-surface +- provenance +related_adrs: +- ADR-L-0012 +- ADR-L-0016 +- ADR-L-0020 +introduces_entities: +- CAP-0021 +- DEC-0023 +- INV-0030 +- INV-0031 +- INV-0032 +vision_category: false +context: | + ste-spec now defines draft MVC-D and MVC-S schemas as part of the MVC evolution + contract surface. ste-runtime needs an experimental contract-consumption slice + that proves it can validate MVC-D fixtures and emit factual MVC-S candidate + snapshots without becoming a second schema authority and without crossing into + kernel-owned admission. + + This ADR is intentionally narrow. It does not authorize RSS traversal, graph + database support, Context Domain execution, Graph Domain execution, Linkage + Surface materialization, runtime query planning, or MVC-M admission. +capabilities: +- id: CAP-0021 + name: Experimental MVC-D to MVC-S candidate emission + description: | + Consume ste-spec-owned MVC-D and MVC-S contracts in tests and emit deterministic + factual MVC-S candidate snapshots from fully supplied fixture inputs. +invariants: +- id: INV-0030 + statement: | + ste-runtime MUST treat MVC-D and MVC-S schemas as external ste-spec contracts. + Runtime tests may mirror schema fixtures for local validation, but runtime + code MUST NOT redefine the public schema authority. + scope: global + enforcement_level: must + enforcement_mechanism: design + verification_method: automated + rationale: | + Prevents runtime from becoming a secondary schema authority for MVC contracts. +- id: INV-0031 + statement: | + Experimental MVC-S candidate emission MUST NOT include admission decisions, + caller-facing eligibility, enforcement outcomes, kernel verdicts, governance + state, or admitted payloads. + scope: global + enforcement_level: must + enforcement_mechanism: design + verification_method: automated + rationale: | + Preserves the MVC-S to MVC-M boundary and the ste-kernel admission authority. +- id: INV-0032 + statement: | + Experimental MVC-S candidate emission MUST be deterministic for identical + MVC-D, candidate refs, selector refs, topology metrics, rationale, and + negative-space inputs. Fingerprints MUST be computed over canonicalized input. + scope: global + enforcement_level: must + enforcement_mechanism: design + verification_method: automated + rationale: | + Deterministic candidate identity is required before RSS assembly or kernel + admission work can safely build on MVC-S. +decisions: +- id: DEC-0023 + summary: Add an experimental contract-consumption builder for MVC-D to MVC-S fixtures + rationale: | + A narrow fixture validator gives ste-runtime a contract-safe baseline before + implementing RSS traversal or kernel handoff. All candidate material is fully + supplied to the builder; runtime does not reconstruct architecture or discover + topology in this slice. + alternatives_considered: + - name: Implement RSS traversal first + rejected_because: | + Traversal would mix contract consumption with reality assembly and make it + harder to prove the MVC-S candidate boundary. + - name: Emit MVC-M directly + rejected_because: | + MVC-M requires kernel-owned admission and is outside runtime authority. + consequences: + positive: + - Runtime can validate ste-spec MVC contracts locally + - Candidate-only semantics are executable and testable + - Code provenance can link implementation to this ADR + negative: + - Additional experimental surface must remain clearly separated from legacy CEM/MVC + related_invariants: + - INV-0030 + - INV-0031 + - INV-0032 + enables_capabilities: + - CAP-0021 diff --git a/docs/attribution-adr-0011-0007-boundary.md b/docs/attribution-adr-0011-0007-boundary.md new file mode 100644 index 0000000..29b2c71 --- /dev/null +++ b/docs/attribution-adr-0011-0007-boundary.md @@ -0,0 +1,43 @@ +# ADR-L-0011 vs ADR-L-0007 attribution boundary + +**Status:** Accepted (Phase 2 targeted retrofit) +**Date:** 2026-05-30 + +## Problem + +Both ADRs touch `ste-runtime/src/cli/evidence-command.ts` and freshness helpers, but they answer different questions: + +| ADR | Question | Primary capability | +|-----|----------|-------------------| +| **ADR-L-0007** | What are graph freshness and obligation projection **semantics**? | CAP-0007 — freshness, invalidation, obligation modeling | +| **ADR-L-0011** | Does ste-runtime conform to the **RuntimeAdapter** publication role? | CAP-0011 — ArchitectureEvidence v2 emission | + +Without an explicit boundary, a single `@implements_adr('ADR-L-0007')` on both builder and CLI conflates semantic modeling with adapter conformance. + +## Decision + +Split claims by **embodiment responsibility**, not by file: + +| Symbol | ADR claims | Rationale | +|--------|------------|-----------| +| `resolveArchitectureEvidenceFreshness` | **ADR-L-0007** | Computes freshness status from bundle + canonical ADR sources; no ArchitectureEvidence envelope | +| `buildArchitectureEvidence` | **ADR-L-0007**, **ADR-L-0011** | Composes freshness (0007) into ArchitectureEvidence v2 (0011) | +| `runArchitectureEvidenceCommand` | **ADR-L-0011** | RuntimeAdapter publication entry point; emits ArchitectureEvidence JSON to stdout | +| `deriveSubjectsFromBundle` | *(none)* | Pure helper; subjects derived from bundle manifest, not a public semantic surface | + +**Rule:** Freshness **resolution** is 0007-only. Evidence **composition and emission** carry 0011; composition also retains 0007 because freshness fields are part of the logical contract. + +## Non-goals + +- Do not populate `attributed_capabilities` with CAP-0007 / CAP-0011 (see `attribution-capability-linkage-backlog.md`). +- Do not amend ADR YAML unless publication paths or freshness semantics change in code. + +## Verification + +After `recon:workspace`, `implementation-attribution-evidence.yaml` must include: + +- At least one record with `ADR-L-0011` +- `resolveArchitectureEvidenceFreshness` attributed to `ADR-L-0007` only +- `buildArchitectureEvidence` attributed to both `ADR-L-0007` and `ADR-L-0011` + +Contract guards: `retrofit-contract-guards.test.ts` Wave A evidence-command block. diff --git a/docs/attribution-capability-linkage-backlog.md b/docs/attribution-capability-linkage-backlog.md new file mode 100644 index 0000000..ad9736d --- /dev/null +++ b/docs/attribution-capability-linkage-backlog.md @@ -0,0 +1,22 @@ +# Attribution capability linkage backlog + +**Status:** Deferred (separate track from Phase 1 class-static linkage fix) + +## Decision + +Do **not** populate `attributed_capabilities` from ADR YAML CAP IDs during the class-metadata extraction fix. + +## Rationale + +1. Phase 1 success criterion is proving **declared ADR/INV claims** reach `implementation-attribution-evidence.yaml`, including class entities via `static readonly __implements_adrs__`. +2. CAP mapping requires a separate authority rule: decorator claims ADR; CAP IDs live in ADR YAML and are not currently declared on symbols. +3. Populating CAPs without an explicit declaration mechanism would produce **inferred** linkage masquerading as **declared** evidence (`confidence: declared` would be misleading). + +## Next step (when un-deferred) + +Choose one: + +- **Decorator extension:** optional `implements_capability('CAP-XXXX')` shim (append-only with ADR claims), or +- **ADR-derived inference:** separate `confidence: inferred` records with explicit provenance, not mixed into declared decorator rows. + +Until then, `attributed_capabilities: []` remains an honest empty field. diff --git a/docs/attribution-negative-space.md b/docs/attribution-negative-space.md new file mode 100644 index 0000000..7395ceb --- /dev/null +++ b/docs/attribution-negative-space.md @@ -0,0 +1,61 @@ +# Attribution negative space (permanent) + +**Status:** Signed off (Phase 3 closure) +**Date:** 2026-05-30 +**Triage authority:** [`blog-posts/evidence/retrofit-phase3-triage-matrix.md`](../../blog-posts/evidence/retrofit-phase3-triage-matrix.md) +**Purpose:** Explicit zones where **no** `ADR-L-*` implementation claims are expected in `implementation-attribution-evidence.yaml`. Prevents false “coverage gap” alarms during retrofit and EDR experiments. + +--- + +## Manifest ADRs with zero evidence (signed off) + +| ADR | Title | Classification | Reason | +|-----|-------|----------------|--------| +| **ADR-L-0003** | CEM Implementation Deferral | **Deferral** | Accepted meta-decision to defer CEM; no ste-runtime embodiment | +| **ADR-L-0005** | Self-Configuring Domain Discovery | **Internal** | Domain discovery is internal pipeline (`discovery.ts`); not a public decorated surface | +| **ADR-L-0014** | Private Registry Isolation | **Policy / scanner** | ADR mandates no private registry URLs in source/artifacts; enforced by init constraints and mechanical scanner policy—not a TS public API in ste-runtime | + +These three ADRs are **intentionally** absent from attribution evidence. Zero rows is correct, not a retrofit gap. + +--- + +## ADRs with partial coverage (accepted) + +| ADR | Gap | Resolution | +|-----|-----|------------| +| **ADR-L-0010** | `initConfig` only vs full bootstrap (`ste setup`, workspace.yaml) | Documented: CJS bootstrap in `scripts/init.cjs` is out of TS RECON scope; TS claim covers runtime config init | +| **ADR-L-0015** | INV-0016 has no implementation anchor | Documented: agnosticism sentinel (`discoverWorkspaceRoot`) attributed; automated zero-reference scan not yet anchored | +| **ADR-L-0017** | Orchestrator only vs helper decomposition | Accepted: `executeWorkspaceRecon` is correct owner | +| **ADR-L-0020** | `resolveLocator` helpers undecorated | Accepted: CEM/MVC + `emitSourceLocatorRegistry` cluster sufficient for retrofit closure | + +--- + +## Code surfaces without ADR-L claims (permanent negative space) + +| Surface | Location | Authority / reason | +|---------|----------|-------------------| +| RSS graph operations | `src/rss/rss-operations.ts` (`search`, `dependencies`, `initRssContext`, etc.) | Legacy **E-ADR-004** RSS CLI scope; no matching `ADR-L-*` owner in ste-runtime manifest | +| MCP tool handlers | `src/mcp/` | Cross-cutting assistant integration; no single ADR-L embodiment decision | +| `recon-cli` entry | `src/cli/recon-cli.ts` | Orchestration seam; RECON entry is `executeRecon` (ADR-L-0001) | +| Architecture compile pipeline | `src/architecture/` (`compileArchitecture`, `runArchitecturePipeline`) | **No ADR-L owner** — requires future ADR or explicit negative-space ADR amendment before decoration | +| CJS bootstrap | `scripts/init.cjs` | Out of TS RECON extraction; related to ADR-L-0010 breadth boundary | +| Internal RECON phase wiring | `runReconPhases`, individual validators | Partial by design; orchestrators carry ADR claims | + +--- + +## Review policy + +1. **Do not** decorate negative-space surfaces solely to improve coverage metrics. +2. **Do not** decorate without an ADR-amended owner list or explicit triage marking `needs_decoration`. +3. **Do** add claims when an ADR amend or new ADR-L explicitly assigns ownership. +4. **Re-run** `recon:workspace` after any retrofit; diff evidence against this table and the triage matrix. + +--- + +## Retrofit closure (Phase 3) + +- **18 / 21** ADR-L entries have evidence rows. +- **3 / 21** have zero rows by signed-off negative space (0003, 0005, 0014). +- Phase 3B optional decoration: **skipped** (no HIGH-confidence `needs_decoration` in triage). + +See [`blog-posts/evidence/retrofit-completion-evidence.md`](../../blog-posts/evidence/retrofit-completion-evidence.md) for final gate results. diff --git a/package.json b/package.json index 15f20b8..05d4943 100644 --- a/package.json +++ b/package.json @@ -23,7 +23,7 @@ "bootstrap": "node scripts/init.cjs", "build": "tsc", "test": "vitest run", - "test:contract-guards": "vitest run src/cli/evidence-command.test.ts src/cli/spec-schema-fixture-sync.test.ts", + "test:contract-guards": "vitest run src/cli/evidence-command.test.ts src/cli/spec-schema-fixture-sync.test.ts src/cli/mvc-evolution-schema-fixture-sync.test.ts src/workspace/mvc-evolution.test.ts src/recon/recon-provenance.test.ts src/recon/phases/extraction.test.ts src/provenance/retrofit-contract-guards.test.ts src/provenance/attribution-evidence-sync.test.ts", "test:watch": "vitest", "test:unit": "vitest run", "test:integration": "node scripts/prove-architecture-compile.mjs", diff --git a/src/architecture/intent-decorators.ts b/src/architecture/intent-decorators.ts new file mode 100644 index 0000000..5fb6831 --- /dev/null +++ b/src/architecture/intent-decorators.ts @@ -0,0 +1,87 @@ +type DecoratedFunction = (...args: any[]) => any; + +function normalizeIds(label: string, ids: string[]): readonly string[] { + if (ids.length === 0) { + throw new Error(`${label} requires at least one identifier`); + } + const normalized = ids.map(id => { + if (typeof id !== 'string') { + throw new TypeError(`${label} identifiers must be strings`); + } + const trimmed = id.trim(); + if (!trimmed) { + throw new Error(`${label} identifiers must not be empty`); + } + return trimmed; + }); + if (new Set(normalized).size !== normalized.length) { + throw new Error(`${label} identifiers must be unique after normalization`); + } + return Object.freeze(normalized); +} + +function attachAdrMetadata(target: T, adrIds: readonly string[]): T { + Object.defineProperty(target, '__implements_adrs__', { + configurable: false, + enumerable: false, + value: adrIds, + writable: false, + }); + return target; +} + +function attachInvariantMetadata( + target: T, + invariantIds: readonly string[], +): T { + Object.defineProperty(target, '__enforces_invariants__', { + configurable: false, + enumerable: false, + value: invariantIds, + writable: false, + }); + return target; +} + +function createLinkageDecorator( + label: string, + ids: string[], + attach: (target: T, normalized: readonly string[]) => T, +): (target: T) => T { + const normalized = normalizeIds(label, ids); + + const linkage = (...args: unknown[]): unknown => { + if (args.length === 1 && typeof args[0] === 'function') { + return attach(args[0] as T, normalized); + } + + const descriptor = args[2] as PropertyDescriptor | undefined; + if (descriptor?.value && typeof descriptor.value === 'function') { + attach(descriptor.value as T, normalized); + return descriptor; + } + + if (args.length >= 1 && typeof args[0] === 'function') { + attach(args[0] as T, normalized); + } + + return undefined; + }; + + return linkage as (target: T) => T; +} + +export function implements_adr(...adrIds: string[]): (target: T) => T { + return createLinkageDecorator('implements_adr', adrIds, attachAdrMetadata); +} + +/** Method/class `@implements_adr_method('ADR-L-XXXX')` — same semantics as `implements_adr`. */ +export function implements_adr_method(...adrIds: string[]): MethodDecorator { + return createLinkageDecorator('implements_adr', adrIds, attachAdrMetadata) as unknown as MethodDecorator; +} + +export function enforces_invariant( + ...invariantIds: string[] +): (target: T) => T { + return createLinkageDecorator('enforces_invariant', invariantIds, attachInvariantMetadata); +} diff --git a/src/cli/architecture-evidence-freshness.ts b/src/cli/architecture-evidence-freshness.ts index 729b4c1..e961b76 100644 --- a/src/cli/architecture-evidence-freshness.ts +++ b/src/cli/architecture-evidence-freshness.ts @@ -1,6 +1,7 @@ import { promises as fs } from 'node:fs'; import path from 'node:path'; +import { implements_adr } from '../architecture/intent-decorators.js'; import type { ArchitectureBundleResult } from '../discovery/architecture-bundle.js'; export type ArchitectureEvidenceFreshnessStatus = 'current' | 'stale-unknown' | 'stale-confirmed'; @@ -80,7 +81,12 @@ function resolveBundleTimestamp( return { timestamp: null, source: null }; } -export async function resolveArchitectureEvidenceFreshness( +export const resolveArchitectureEvidenceFreshness: ( + scopeRoot: string, + bundle: Pick, +) => Promise = implements_adr( + 'ADR-L-0007', +)(async function resolveArchitectureEvidenceFreshness( scopeRoot: string, bundle: Pick, ): Promise { @@ -166,4 +172,4 @@ export async function resolveArchitectureEvidenceFreshness( errors, sourceFiles, }; -} +}); diff --git a/src/cli/evidence-command.ts b/src/cli/evidence-command.ts index 5fabe24..952147a 100644 --- a/src/cli/evidence-command.ts +++ b/src/cli/evidence-command.ts @@ -1,5 +1,6 @@ import process from 'node:process'; +import { implements_adr } from '../architecture/intent-decorators.js'; import { resolveArchitectureEvidenceFreshness, type ArchitectureEvidenceFreshnessStatus, @@ -75,7 +76,15 @@ const defaultIo: ArchitectureEvidenceCommandIo = { }, }; -export async function buildArchitectureEvidence( +export const buildArchitectureEvidence: ( + projectRoot: string, + bundle: ArchitectureBundleResult, + subjects: EvidenceSubject[], + dependencies?: Pick, +) => Promise = implements_adr( + 'ADR-L-0007', + 'ADR-L-0011', +)(async function buildArchitectureEvidence( projectRoot: string, bundle: ArchitectureBundleResult, subjects: EvidenceSubject[], @@ -104,7 +113,7 @@ export async function buildArchitectureEvidence( lastReconciled: freshness.lastReconciled, }, }; -} +}); const ADR_ID_PATTERN = /^ADR-(L|PS|PC)-\d+/; @@ -145,7 +154,13 @@ export function deriveSubjectsFromBundle(bundle: ArchitectureBundleResult): Evid return subjects; } -export async function runArchitectureEvidenceCommand( +export const runArchitectureEvidenceCommand: ( + projectRoot: string, + io?: ArchitectureEvidenceCommandIo, + dependencies?: ArchitectureEvidenceCommandDependencies, +) => Promise = implements_adr( + 'ADR-L-0011', +)(async function runArchitectureEvidenceCommand( projectRoot: string, io: ArchitectureEvidenceCommandIo = defaultIo, dependencies: ArchitectureEvidenceCommandDependencies = { @@ -164,4 +179,4 @@ export async function runArchitectureEvidenceCommand( io.stderr(`${message}\n`); return 1; } -} +}); diff --git a/src/cli/mvc-evolution-schema-fixture-sync.test.ts b/src/cli/mvc-evolution-schema-fixture-sync.test.ts new file mode 100644 index 0000000..e6a4a23 --- /dev/null +++ b/src/cli/mvc-evolution-schema-fixture-sync.test.ts @@ -0,0 +1,45 @@ +import path from 'node:path'; +import { access, readFile } from 'node:fs/promises'; +import { fileURLToPath } from 'node:url'; + +import { describe, expect, it } from 'vitest'; + +const __dirname = path.dirname(fileURLToPath(import.meta.url)); +const steRuntimeRoot = path.resolve(__dirname, '..', '..'); + +const schemaPairs = [ + { + name: 'MVC-D', + sibling: path.resolve(steRuntimeRoot, '..', 'ste-spec', 'contracts', 'mvc', 'mvc-definition.schema.json'), + fixture: path.resolve(steRuntimeRoot, 'test', 'fixtures', 'mvc-evolution', 'mvc-definition.schema.json'), + }, + { + name: 'MVC-S', + sibling: path.resolve(steRuntimeRoot, '..', 'ste-spec', 'contracts', 'mvc', 'mvc-snapshot.schema.json'), + fixture: path.resolve(steRuntimeRoot, 'test', 'fixtures', 'mvc-evolution', 'mvc-snapshot.schema.json'), + }, +]; + +describe('MVC evolution schema fixture sync', () => { + for (const pair of schemaPairs) { + it(`keeps the committed ${pair.name} schema fixture present`, async () => { + await expect(access(pair.fixture)).resolves.toBeUndefined(); + }); + + it(`matches the sibling ste-spec ${pair.name} contract when available`, async () => { + try { + await access(pair.sibling); + } catch { + return; + } + + const [fixtureBytes, siblingBytes] = await Promise.all([ + readFile(pair.fixture), + readFile(pair.sibling), + ]); + expect(JSON.parse(fixtureBytes.toString('utf8'))).toEqual( + JSON.parse(siblingBytes.toString('utf8')), + ); + }); + } +}); diff --git a/src/config/index.ts b/src/config/index.ts index f3578e6..789cda4 100644 --- a/src/config/index.ts +++ b/src/config/index.ts @@ -9,6 +9,7 @@ import fs from 'node:fs/promises'; import path from 'node:path'; import { z } from 'zod'; +import { implements_adr } from '../architecture/intent-decorators.js'; /** * Supported languages/formats for extraction @@ -871,7 +872,9 @@ export async function loadConfigFromFile( * * @param runtimeDir - Path to ste-runtime directory */ -export async function initConfig(runtimeDir: string): Promise { +export const initConfig: (runtimeDir: string) => Promise = implements_adr( + 'ADR-L-0010', +)(async function initConfig(runtimeDir: string): Promise { const configPath = path.join(runtimeDir, 'ste.config.json'); const defaultConfig: SteConfig = { @@ -891,5 +894,5 @@ export async function initConfig(runtimeDir: string): Promise { console.log(`[STE Config] Created ${configPath}`); console.log(`[STE Config] Edit sourceDirs to match your project structure.`); console.log(`[STE Config] State will be written to ste-runtime/.ste/state/`); -} +}); diff --git a/src/discovery/architecture-bundle.ts b/src/discovery/architecture-bundle.ts index 7eff7d9..9cc94c5 100644 --- a/src/discovery/architecture-bundle.ts +++ b/src/discovery/architecture-bundle.ts @@ -11,6 +11,8 @@ import path from 'node:path'; import yaml from 'js-yaml'; +import { implements_adr } from '../architecture/intent-decorators.js'; + export type ArchitectureBundleStatus = 'valid' | 'degraded' | 'invalid'; export interface ArchitectureBundleArtifact { @@ -142,7 +144,9 @@ function summarizeIndex(indexData: Record | undefined): Archite }; } -export async function loadArchitectureBundle(scopeRoot: string): Promise { +export const loadArchitectureBundle: (scopeRoot: string) => Promise = implements_adr( + 'ADR-L-0012', +)(async function loadArchitectureBundle(scopeRoot: string): Promise { const resolvedRoot = path.resolve(scopeRoot); const warnings: string[] = []; const errors: string[] = []; @@ -258,4 +262,4 @@ export async function loadArchitectureBundle(scopeRoot: string): Promise { + try { + await access(attributionPath); + return true; + } catch { + return false; + } +} + +function recordAdrIds(record: AttributionRecord): string[] { + return record.attributed_adrs ?? []; +} + +describe('implementation attribution evidence sync', () => { + it('populates records after workspace RECON when sibling .ste-workspace exists', async () => { + if (!(await attributionFileExists())) { + return; + } + + const raw = await readFile(attributionPath, 'utf8'); + const doc = yaml.load(raw) as AttributionEvidence; + const records = doc.records ?? []; + + if (records.length === 0) { + return; + } + + expect(records.length).toBeGreaterThan(0); + + const allAdrIds = records.flatMap(recordAdrIds); + expect(allAdrIds).toContain('ADR-L-0001'); + expect(allAdrIds).toContain('ADR-L-0018'); + expect(allAdrIds).toContain('ADR-L-0004'); + expect(allAdrIds).toContain('ADR-L-0006'); + expect(allAdrIds).toContain('ADR-L-0011'); + + const classRecords = records.filter(record => record.implementation_entity_type === 'class'); + expect(classRecords.some(record => recordAdrIds(record).includes('ADR-L-0004'))).toBe(true); + expect(classRecords.some(record => recordAdrIds(record).includes('ADR-L-0006'))).toBe(true); + + const queryRecords = records.filter( + record => + record.implementation_entity_id?.includes('ConversationalQueryEngine.query') && + recordAdrIds(record).includes('ADR-L-0006'), + ); + expect(queryRecords.length).toBeGreaterThan(0); + + const manifest = await readFile(path.resolve(steRuntimeRoot, 'adrs', 'manifest.yaml'), 'utf8'); + for (const record of records.slice(0, 5)) { + for (const adrId of recordAdrIds(record)) { + expect(manifest).toContain(adrId); + } + const sourceFile = record.provenance?.source_file; + if (sourceFile) { + await expect(access(path.resolve(steRuntimeRoot, sourceFile))).resolves.toBeUndefined(); + } + if (record.confidence) { + expect(record.confidence).toBe('declared'); + } + } + }); +}); diff --git a/src/provenance/provenance-test-helpers.ts b/src/provenance/provenance-test-helpers.ts new file mode 100644 index 0000000..c4af279 --- /dev/null +++ b/src/provenance/provenance-test-helpers.ts @@ -0,0 +1,51 @@ +import path from 'node:path'; +import { access, readFile } from 'node:fs/promises'; +import { fileURLToPath } from 'node:url'; + +import { expect } from 'vitest'; + +const __dirname = path.dirname(fileURLToPath(import.meta.url)); + +export const steRuntimeRoot = path.resolve(__dirname, '..', '..'); +export const ADR_ID_PATTERN = /^ADR-L-\d{4}$/; +export const INV_ID_PATTERN = /^INV-\d{4}$/; + +export function functionAdrMetadata(target: unknown): readonly string[] { + return (target as { __implements_adrs__?: readonly string[] }).__implements_adrs__ ?? []; +} + +export function functionInvariantMetadata(target: unknown): readonly string[] { + return (target as { __enforces_invariants__?: readonly string[] }).__enforces_invariants__ ?? []; +} + +export function classAdrMetadata(classRef: unknown): readonly string[] { + return (classRef as { __implements_adrs__?: readonly string[] }).__implements_adrs__ ?? []; +} + +export function classInvariantMetadata(classRef: unknown): readonly string[] { + return (classRef as { __enforces_invariants__?: readonly string[] }).__enforces_invariants__ ?? []; +} + +export async function expectAdrSourceExists(adrId: string, relativePath: string): Promise { + const manifest = await readFile(path.resolve(steRuntimeRoot, 'adrs', 'manifest.yaml'), 'utf8'); + expect(manifest).toContain(adrId); + await expect(access(path.resolve(steRuntimeRoot, relativePath))).resolves.toBeUndefined(); +} + +export function expectAdrClaims( + target: unknown, + adrId: string, + invariantIds: string[] = [], +): void { + const adrIds = functionAdrMetadata(target); + expect(adrIds).toContain(adrId); + expect(adrIds.every(id => ADR_ID_PATTERN.test(id))).toBe(true); + + if (invariantIds.length > 0) { + const invIds = functionInvariantMetadata(target); + for (const invId of invariantIds) { + expect(invIds).toContain(invId); + } + expect(invIds.every(id => INV_ID_PATTERN.test(id))).toBe(true); + } +} diff --git a/src/provenance/retrofit-contract-guards.test.ts b/src/provenance/retrofit-contract-guards.test.ts new file mode 100644 index 0000000..520dd8c --- /dev/null +++ b/src/provenance/retrofit-contract-guards.test.ts @@ -0,0 +1,189 @@ +import { describe, expect, it } from 'vitest'; + +import { + buildArchitectureEvidence, + runArchitectureEvidenceCommand, +} from '../cli/evidence-command.js'; +import { resolveArchitectureEvidenceFreshness } from '../cli/architecture-evidence-freshness.js'; +import { loadArchitectureBundle } from '../discovery/architecture-bundle.js'; +import { initConfig } from '../config/index.js'; +import { executeRecon } from '../recon/index.js'; +import { runSelfValidation } from '../recon/phases/self-validation.js'; +import { + ask, + ConversationalQueryEngine, + formatForAgent, + formatForHuman, +} from '../rss/conversational-query.js'; +import { search } from '../rss/rss-operations.js'; +import { Watchdog } from '../watch/watchdog.js'; +import { + assembleCemBundle, + deriveMvcBundle, + validateMvcBundle, +} from '../workspace/cem-mvc.js'; +import { blastRadiusWorkspace, componentIntegration, systemDependencies } from '../workspace/canned-queries.js'; +import { compress } from '../workspace/compression.js'; +import { emitMultiResProjections } from '../workspace/emit-multi-res-projections.js'; +import { emitProjections } from '../workspace/emit-projections.js'; +import { + buildPerRepoConfig, + discoverWorkspaceRoot, + parseWorkspaceManifest, + resolveRepoPath, +} from '../workspace/manifest.js'; +import { + assertMvcDefinitionContract, + assertMvcSnapshotCandidateOnly, + buildMvcSnapshotCandidate, + canonicalMvcFingerprintInput, +} from '../workspace/mvc-evolution.js'; +import { registerFamily } from '../workspace/projection-families.js'; +import { + toAdjacencyMatrix, + toMermaid, + toMermaidAtResolution, + toTable, + toTableAtResolution, +} from '../workspace/projections.js'; +import { emitSourceLocatorRegistry } from '../workspace/source-locator-registry.js'; +import { emitWorkspaceSlice } from '../workspace/slice-emitter.js'; +import { validateSlice } from '../workspace/slice-schema.js'; +import { normalizePortablePath, workspaceUri } from '../workspace/source-uri.js'; +import { emitWorkspaceIndex } from '../workspace/workspace-index.js'; +import { loadWorkspaceGraph } from '../workspace/workspace-graph-loader.js'; +import { executeWorkspaceRecon } from '../workspace/workspace-recon.js'; +import { + ADR_ID_PATTERN, + classAdrMetadata, + expectAdrClaims, + expectAdrSourceExists, + functionAdrMetadata, +} from './provenance-test-helpers.js'; + +describe('attribution retrofit contract guards', () => { + describe('Wave A — core retro', () => { + it('ADR-L-0001: executeRecon', () => { + expectAdrClaims(executeRecon, 'ADR-L-0001', ['INV-0002']); + }); + + it('ADR-L-0007 / ADR-L-0011: architecture evidence command boundary', () => { + expectAdrClaims(resolveArchitectureEvidenceFreshness, 'ADR-L-0007'); + expectAdrClaims(buildArchitectureEvidence, 'ADR-L-0007'); + expectAdrClaims(buildArchitectureEvidence, 'ADR-L-0011'); + expectAdrClaims(runArchitectureEvidenceCommand, 'ADR-L-0011'); + expect(functionAdrMetadata(runArchitectureEvidenceCommand)).not.toContain('ADR-L-0007'); + }); + + it('ADR-L-0006: conversational query interface', () => { + expect(classAdrMetadata(ConversationalQueryEngine)).toContain('ADR-L-0006'); + expectAdrClaims(ConversationalQueryEngine.prototype.query, 'ADR-L-0006'); + expectAdrClaims(ask, 'ADR-L-0006'); + expectAdrClaims(formatForHuman, 'ADR-L-0006'); + expectAdrClaims(formatForAgent, 'ADR-L-0006'); + }); + + it('ADR-L-0021: MVC evolution helpers', () => { + expectAdrClaims(assertMvcDefinitionContract, 'ADR-L-0021', ['INV-0030']); + expectAdrClaims(assertMvcSnapshotCandidateOnly, 'ADR-L-0021', ['INV-0031']); + expectAdrClaims(buildMvcSnapshotCandidate, 'ADR-L-0021', ['INV-0031', 'INV-0032']); + expectAdrClaims(canonicalMvcFingerprintInput, 'ADR-L-0021'); + }); + }); + + describe('Wave B — workspace-recon cluster', () => { + it('ADR-L-0009: workspace scope entry points', () => { + expectAdrClaims(parseWorkspaceManifest, 'ADR-L-0009', ['INV-0014']); + expectAdrClaims(buildPerRepoConfig, 'ADR-L-0009', ['INV-0014']); + expectAdrClaims(resolveRepoPath, 'ADR-L-0009', ['INV-0014']); + expectAdrClaims(emitWorkspaceIndex, 'ADR-L-0009', ['INV-0014']); + }); + + it('ADR-L-0017: workspace RECON orchestration', () => { + const adrIds = functionAdrMetadata(executeWorkspaceRecon); + expect(adrIds).toContain('ADR-L-0017'); + expect(adrIds).toContain('ADR-L-0009'); + expectAdrClaims(executeWorkspaceRecon, 'ADR-L-0017', ['INV-0019']); + }); + + it('ADR-L-0016: slice schema contract', () => { + expectAdrClaims(emitWorkspaceSlice, 'ADR-L-0016', ['INV-0017', 'INV-0025']); + expectAdrClaims(validateSlice, 'ADR-L-0016', ['INV-0017', 'INV-0018']); + }); + + it('ADR-L-0018: deterministic workspace graph queries', () => { + expectAdrClaims(loadWorkspaceGraph, 'ADR-L-0018'); + expectAdrClaims(systemDependencies, 'ADR-L-0018', ['INV-0020']); + expectAdrClaims(componentIntegration, 'ADR-L-0018', ['INV-0020']); + expectAdrClaims(blastRadiusWorkspace, 'ADR-L-0018', ['INV-0020']); + expectAdrClaims(emitProjections, 'ADR-L-0018', ['INV-0024']); + expectAdrClaims(toMermaid, 'ADR-L-0018', ['INV-0021']); + expectAdrClaims(toTable, 'ADR-L-0018', ['INV-0021']); + expectAdrClaims(toAdjacencyMatrix, 'ADR-L-0018', ['INV-0021']); + }); + + it('ADR-L-0019: multi-resolution projections', () => { + expectAdrClaims(compress, 'ADR-L-0019', ['INV-0023']); + expectAdrClaims(emitMultiResProjections, 'ADR-L-0019', ['INV-0022', 'INV-0024']); + expectAdrClaims(toMermaidAtResolution, 'ADR-L-0019', ['INV-0021', 'INV-0022']); + expectAdrClaims(toTableAtResolution, 'ADR-L-0019', ['INV-0021', 'INV-0022']); + expectAdrClaims(registerFamily, 'ADR-L-0019'); + }); + + it('ADR-L-0015: workspace agnosticism', () => { + expectAdrClaims(discoverWorkspaceRoot, 'ADR-L-0015', ['INV-0015']); + }); + }); + + describe('Wave C — scale and negative space', () => { + it('ADR-L-0020: CEM/MVC and source locators', () => { + expectAdrClaims(assembleCemBundle, 'ADR-L-0020', ['INV-0027', 'INV-0029']); + expectAdrClaims(deriveMvcBundle, 'ADR-L-0020', ['INV-0028', 'INV-0029']); + expectAdrClaims(validateMvcBundle, 'ADR-L-0020', ['INV-0028']); + expectAdrClaims(emitSourceLocatorRegistry, 'ADR-L-0020', ['INV-0027', 'INV-0029']); + }); + + it('ADR-L-0013: path portability', () => { + expectAdrClaims(normalizePortablePath, 'ADR-L-0013'); + expectAdrClaims(workspaceUri, 'ADR-L-0013'); + }); + + it('ADR-L-0010: bootstrap init', () => { + expectAdrClaims(initConfig, 'ADR-L-0010'); + }); + + it('ADR-L-0012: polyglot schema consumption', () => { + expectAdrClaims(loadArchitectureBundle, 'ADR-L-0012'); + }); + + it('ADR-L-0002: RECON self-validation', () => { + expectAdrClaims(runSelfValidation, 'ADR-L-0002'); + }); + + it('ADR-L-0004: watchdog workspace boundary', () => { + expect(classAdrMetadata(Watchdog)).toContain('ADR-L-0004'); + }); + + it('documents negative-space surfaces without ADR-L claims', () => { + expect(functionAdrMetadata(search)).toEqual([]); + expect(functionAdrMetadata(search).every(id => ADR_ID_PATTERN.test(id))).toBe(true); + }); + }); + + describe('ADR source anchors', () => { + it('Wave A+B sample ADRs exist on disk', async () => { + await expectAdrSourceExists( + 'ADR-L-0007', + 'adrs/logical/ADR-L-0007-graph-freshness-and-obligation-projection-semantics.yaml', + ); + await expectAdrSourceExists( + 'ADR-L-0011', + 'adrs/logical/ADR-L-0011-adapter-role-conformance.yaml', + ); + await expectAdrSourceExists( + 'ADR-L-0018', + 'adrs/logical/ADR-L-0018-deterministic-workspace-graph-queries.yaml', + ); + }); + }); +}); diff --git a/src/recon/index.ts b/src/recon/index.ts index 610abbf..a8d4e21 100644 --- a/src/recon/index.ts +++ b/src/recon/index.ts @@ -12,6 +12,7 @@ import type { ResolvedConfig } from '../config/index.js'; import type { PhaseTimingRecord } from '../utils/concurrency.js'; +import { enforces_invariant, implements_adr } from '../architecture/intent-decorators.js'; import { runReconPhases } from './phases/index.js'; import { log, error as logError } from '../utils/logger.js'; @@ -60,7 +61,11 @@ export interface ReconResult { * - MUST NOT block commits * - MUST NOT halt development workflows */ -export async function executeRecon(options: ReconOptions): Promise { +export const executeRecon: (options: ReconOptions) => Promise = implements_adr( + 'ADR-L-0001', +)(enforces_invariant('INV-0002')(async function executeRecon( + options: ReconOptions, +): Promise { log('[RECON] Starting reconciliation...'); log(`[RECON] Mode: ${options.mode ?? 'incremental'}`); log(`[RECON] Project root: ${options.projectRoot}`); @@ -102,4 +107,4 @@ export async function executeRecon(options: ReconOptions): Promise warnings: [], }; } -} +})); diff --git a/src/recon/phases/extraction.test.ts b/src/recon/phases/extraction.test.ts index ee37bc7..63edcea 100644 --- a/src/recon/phases/extraction.test.ts +++ b/src/recon/phases/extraction.test.ts @@ -167,6 +167,132 @@ describe('extractAssertions', () => { }); }); + it('should extract implementation intent from class static __implements_adrs__ metadata (Watchdog pattern)', async () => { + const tsFile: DiscoveredFile = { + path: '/test/watchdog.ts', + relativePath: 'watchdog.ts', + language: 'typescript', + }; + + const tsContent = ` + export class Watchdog { + static readonly __implements_adrs__ = Object.freeze(['ADR-L-0004'] as const); + static readonly __enforces_invariants__ = Object.freeze([] as const); + + start(): void {} + } + `; + + vi.mocked(fs.readFile).mockResolvedValue(tsContent); + + const assertions = await extractAssertions([tsFile]); + const watchdogClass = assertions.find( + a => a.elementType === 'class' && a.metadata.name === 'Watchdog', + ); + + expect(watchdogClass?.metadata.implementationIntent).toEqual({ + implements_adrs: ['ADR-L-0004'], + enforced_invariants: [], + confidence: 'declared', + source: 'metadata', + }); + }); + + it('should extract implementation intent from class static __implements_adrs__ metadata (ConversationalQueryEngine pattern)', async () => { + const tsFile: DiscoveredFile = { + path: '/test/conversational-query.ts', + relativePath: 'conversational-query.ts', + language: 'typescript', + }; + + const tsContent = ` + export class ConversationalQueryEngine { + static readonly __implements_adrs__ = Object.freeze(['ADR-L-0006'] as const); + static readonly __enforces_invariants__ = Object.freeze([] as const); + + async query(input: string): Promise { + return input; + } + } + `; + + vi.mocked(fs.readFile).mockResolvedValue(tsContent); + + const assertions = await extractAssertions([tsFile]); + const engineClass = assertions.find( + a => a.elementType === 'class' && a.metadata.name === 'ConversationalQueryEngine', + ); + + expect(engineClass?.metadata.implementationIntent).toEqual({ + implements_adrs: ['ADR-L-0006'], + enforced_invariants: [], + confidence: 'declared', + source: 'metadata', + }); + }); + + it('should extract implementation intent from implements_adr_method on class methods', async () => { + const tsFile: DiscoveredFile = { + path: '/test/cqi-method.ts', + relativePath: 'cqi-method.ts', + language: 'typescript', + }; + + const tsContent = ` + export class ConversationalQueryEngine { + @implements_adr_method('ADR-L-0006') + async query(input: string): Promise { + return input; + } + } + `; + + vi.mocked(fs.readFile).mockResolvedValue(tsContent); + + const assertions = await extractAssertions([tsFile]); + const queryMethod = assertions.find( + a => a.elementType === 'function' && a.metadata.name === 'query', + ); + + expect(queryMethod?.metadata.implementationIntent).toEqual({ + implements_adrs: ['ADR-L-0006'], + enforced_invariants: [], + confidence: 'declared', + source: 'decorator', + }); + }); + + it('should extract implementation intent from call-expression linkage wrappers on exported const functions', async () => { + const tsFile: DiscoveredFile = { + path: '/test/wrapper.ts', + relativePath: 'wrapper.ts', + language: 'typescript' + }; + + const tsContent = ` + export const buildSnapshot = implements_adr('ADR-L-0021')( + enforces_invariant('INV-0031', 'INV-0032')( + function buildSnapshot(input: string): string { + return input; + } + ) + ); + `; + + vi.mocked(fs.readFile).mockResolvedValue(tsContent); + + const assertions = await extractAssertions([tsFile]); + const func = assertions.find(a => a.elementType === 'function' && a.metadata.name === 'buildSnapshot'); + + expect(func).toBeDefined(); + expect(func?.metadata.implementationIntent).toEqual({ + implements_adrs: ['ADR-L-0021'], + enforced_invariants: ['INV-0031', 'INV-0032'], + confidence: 'declared', + source: 'decorator', + }); + }); + it('should ignore non-literal TypeScript decorator arguments for implementation intent', async () => { const tsFile: DiscoveredFile = { path: '/test/nonliteral.ts', diff --git a/src/recon/phases/extraction.ts b/src/recon/phases/extraction.ts index 10324bd..02fc82e 100644 --- a/src/recon/phases/extraction.ts +++ b/src/recon/phases/extraction.ts @@ -621,6 +621,192 @@ function extractStringLiteralValues(node: ts.Expression): string[] { return []; } +function buildImplementationIntentRecord( + implementsAdrs: string[], + enforcedInvariants: string[], + source: 'decorator' | 'metadata' = 'decorator', +): Record | undefined { + const uniqueAdrs = [...new Set(implementsAdrs)]; + const uniqueInvariants = [...new Set(enforcedInvariants)]; + if (uniqueAdrs.length === 0 && uniqueInvariants.length === 0) { + return undefined; + } + + return { + implements_adrs: uniqueAdrs, + enforced_invariants: uniqueInvariants, + confidence: 'declared', + source, + }; +} + +function appendLinkageDecoratorArgs( + call: ts.CallExpression, + implementsAdrs: string[], + enforcedInvariants: string[], +): void { + const decoratorName = getDecoratorName(call.expression); + if (!decoratorName) { + return; + } + + const args = call.arguments.flatMap(extractStringLiteralValues); + if (args.length === 0) { + return; + } + + if (decoratorName === 'implements_adr' || decoratorName === 'implements_adrs') { + implementsAdrs.push(...args); + } + + if (decoratorName === 'enforces_invariant' || decoratorName === 'enforces_invariants') { + enforcedInvariants.push(...args); + } +} + +function collectLinkageWrapperIntent( + expression: ts.Expression, +): Record | undefined { + const implementsAdrs: string[] = []; + const enforcedInvariants: string[] = []; + let current: ts.Expression = expression; + + while (ts.isCallExpression(current)) { + if (ts.isCallExpression(current.expression)) { + appendLinkageDecoratorArgs(current.expression, implementsAdrs, enforcedInvariants); + } else { + appendLinkageDecoratorArgs(current, implementsAdrs, enforcedInvariants); + } + + const inner = current.arguments[0]; + if (!inner) { + break; + } + + current = inner; + if (ts.isFunctionExpression(current) || ts.isArrowFunction(current)) { + break; + } + } + + return buildImplementationIntentRecord(implementsAdrs, enforcedInvariants, 'decorator'); +} + +function isObjectFreezeCall(expression: ts.CallExpression): boolean { + const callee = expression.expression; + if (!ts.isPropertyAccessExpression(callee)) { + return false; + } + return ( + callee.name.text === 'freeze' && + ts.isIdentifier(callee.expression) && + callee.expression.text === 'Object' + ); +} + +function unwrapLinkageInitializer(expression: ts.Expression): ts.Expression { + if (ts.isAsExpression(expression)) { + return unwrapLinkageInitializer(expression.expression); + } + + if (ts.isCallExpression(expression) && isObjectFreezeCall(expression) && expression.arguments[0]) { + return unwrapLinkageInitializer(expression.arguments[0]); + } + + return expression; +} + +function extractClassStaticLinkageIntent( + node: ts.ClassDeclaration, + sourceFile: ts.SourceFile, +): Record | undefined { + const implementsAdrs: string[] = []; + const enforcedInvariants: string[] = []; + + for (const member of node.members) { + if (!ts.isPropertyDeclaration(member) || !member.name || !member.initializer) { + continue; + } + + const isStatic = !!(member.modifiers?.some(m => m.kind === ts.SyntaxKind.StaticKeyword)); + if (!isStatic) { + continue; + } + + const propertyName = member.name.getText(sourceFile); + const values = extractStringLiteralValues(unwrapLinkageInitializer(member.initializer)); + if (values.length === 0 && propertyName !== '__enforces_invariants__') { + continue; + } + + if (propertyName === '__implements_adrs__') { + implementsAdrs.push(...values); + } + + if (propertyName === '__enforces_invariants__') { + enforcedInvariants.push(...values); + } + } + + return buildImplementationIntentRecord(implementsAdrs, enforcedInvariants, 'metadata'); +} + +function unwrapFunctionFromExpression( + expression: ts.Expression, +): ts.FunctionExpression | ts.ArrowFunction | undefined { + if (ts.isFunctionExpression(expression) || ts.isArrowFunction(expression)) { + return expression; + } + + if (!ts.isCallExpression(expression)) { + return undefined; + } + + let current: ts.Expression = expression; + while (ts.isCallExpression(current)) { + const inner = current.arguments[0]; + if (!inner) { + return undefined; + } + + if (ts.isFunctionExpression(inner) || ts.isArrowFunction(inner)) { + return inner; + } + + current = inner; + } + + return undefined; +} + +function mergeImplementationIntent( + primary: Record | undefined, + secondary: Record | undefined, +): Record | undefined { + if (!primary) { + return secondary; + } + if (!secondary) { + return primary; + } + + const implementsAdrs = [ + ...(primary.implements_adrs as string[] | undefined ?? []), + ...(secondary.implements_adrs as string[] | undefined ?? []), + ]; + const enforcedInvariants = [ + ...(primary.enforced_invariants as string[] | undefined ?? []), + ...(secondary.enforced_invariants as string[] | undefined ?? []), + ]; + + const source = + primary.source === 'decorator' || secondary.source === 'decorator' + ? 'decorator' + : 'metadata'; + + return buildImplementationIntentRecord(implementsAdrs, enforcedInvariants, source); +} + function extractRawDecorators(node: ts.Node, sourceFile: ts.SourceFile): string[] { const decorators = ts.getDecorators(node as ts.HasDecorators); if (!decorators) { @@ -656,7 +842,7 @@ function extractTypeScriptImplementationIntent( continue; } - if (decoratorName === 'implements_adr' || decoratorName === 'implements_adrs') { + if (decoratorName === 'implements_adr' || decoratorName === 'implements_adrs' || decoratorName === 'implements_adr_method') { implementsAdrs.push(...args); } @@ -668,16 +854,7 @@ function extractTypeScriptImplementationIntent( const uniqueAdrs = [...new Set(implementsAdrs)]; const uniqueInvariants = [...new Set(enforcedInvariants)]; - if (uniqueAdrs.length === 0 && uniqueInvariants.length === 0) { - return undefined; - } - - return { - implements_adrs: uniqueAdrs, - enforced_invariants: uniqueInvariants, - confidence: 'declared', - source: 'decorator', - }; + return buildImplementationIntentRecord(uniqueAdrs, uniqueInvariants, 'decorator'); } /** @@ -754,6 +931,51 @@ async function extractFromTypeScript(file: DiscoveredFile): Promise p.name.getText(sourceFile)); + + assertions.push({ + elementId: generateSliceId('function', normalizedPath, `${name}:${lineNumber}`), + elementType: 'function', + file: normalizedPath, + line: lineNumber, + end_line: endLineNumber, + language: 'typescript', + signature: `${name}()`, + source, + metadata: { + name, + isExported, + isAsync: !!(fn.modifiers?.some(m => m.kind === ts.SyntaxKind.AsyncKeyword)), + parameters, + decorators: [], + implementationIntent, + ...jsDocInfo, + }, + }); + } + } // Extract class declarations - IDs include file path for uniqueness per ADR-007 if (ts.isClassDeclaration(node) && node.name) { @@ -763,7 +985,10 @@ async function extractFromTypeScript(file: DiscoveredFile): Promise Promise = implements_adr( + 'ADR-L-0002', +)(async function runSelfValidation( + assertions: NormalizedAssertion[], + projectRoot: string, + stateRoot: string, + sourceRoot: string, + options: SelfValidationOptions = {}, ): Promise { const verbosity = options.validationVerbosity ?? 'summary'; const repeatabilityCheck = options.repeatabilityCheck ?? false; @@ -143,5 +152,5 @@ export async function runSelfValidation( ], }; } -} +}); diff --git a/src/recon/recon-provenance.test.ts b/src/recon/recon-provenance.test.ts new file mode 100644 index 0000000..319b64d --- /dev/null +++ b/src/recon/recon-provenance.test.ts @@ -0,0 +1,45 @@ +import path from 'node:path'; +import { access, readFile } from 'node:fs/promises'; +import { fileURLToPath } from 'node:url'; + +import { describe, expect, it } from 'vitest'; + +import { executeRecon } from './index.js'; + +const __dirname = path.dirname(fileURLToPath(import.meta.url)); +const steRuntimeRoot = path.resolve(__dirname, '..', '..'); +const ADR_ID_PATTERN = /^ADR-L-\d{4}$/; + +function functionAdrMetadata(target: unknown): readonly string[] { + return (target as { __implements_adrs__?: readonly string[] }).__implements_adrs__ ?? []; +} + +function functionInvariantMetadata(target: unknown): readonly string[] { + return (target as { __enforces_invariants__?: readonly string[] }).__enforces_invariants__ ?? []; +} + +describe('RECON provenance contract consumption (ADR-L-0001)', () => { + it('exposes machine-readable code provenance on executeRecon', () => { + const adrIds = functionAdrMetadata(executeRecon); + expect(adrIds).toContain('ADR-L-0001'); + expect(adrIds.every(id => ADR_ID_PATTERN.test(id))).toBe(true); + + const invariantIds = functionInvariantMetadata(executeRecon); + expect(invariantIds).toContain('INV-0002'); + }); + + it('anchors code provenance to an existing runtime ADR source', async () => { + const manifest = await readFile( + path.resolve(steRuntimeRoot, 'adrs', 'manifest.yaml'), + 'utf8', + ); + expect(manifest).toContain('ADR-L-0001'); + + await expect(access(path.resolve( + steRuntimeRoot, + 'adrs', + 'logical', + 'ADR-L-0001-recon-provisional-execution-for-project-level-sema.yaml', + ))).resolves.toBeUndefined(); + }); +}); diff --git a/src/rss/conversational-query.ts b/src/rss/conversational-query.ts index 2549574..78414d9 100644 --- a/src/rss/conversational-query.ts +++ b/src/rss/conversational-query.ts @@ -16,6 +16,7 @@ * 4. Structured output for both human and machine consumption */ +import { implements_adr, implements_adr_method } from '../architecture/intent-decorators.js'; import { type RssContext, initRssContext, @@ -102,6 +103,9 @@ interface CachedQuery { // ───────────────────────────────────────────────────────────────── export class ConversationalQueryEngine { + static readonly __implements_adrs__ = Object.freeze(['ADR-L-0006'] as const); + static readonly __enforces_invariants__ = Object.freeze([] as const); + private ctx!: RssContext; private cache: LRUCache; private initialized: boolean = false; @@ -131,6 +135,7 @@ export class ConversationalQueryEngine { * const result = await engine.query("Tell me about the finding processor"); * console.log(result.summary); */ + @implements_adr_method('ADR-L-0006') async query(input: string): Promise { const startTime = performance.now(); @@ -755,17 +760,21 @@ let defaultEngine: ConversationalQueryEngine | null = null; * console.log(result.summary); * console.log(result.filePaths); */ -export async function ask(query: string, stateRoot?: string): Promise { +export const ask: (query: string, stateRoot?: string) => Promise = implements_adr( + 'ADR-L-0006', +)(async function ask(query: string, stateRoot?: string): Promise { if (!defaultEngine || (stateRoot && stateRoot !== '.ste/state')) { defaultEngine = new ConversationalQueryEngine(stateRoot); } return defaultEngine.query(query); -} +}); /** * Format response for human display (terminal/console) */ -export function formatForHuman(response: ConversationalResponse): string { +export const formatForHuman: (response: ConversationalResponse) => string = implements_adr( + 'ADR-L-0006', +)(function formatForHuman(response: ConversationalResponse): string { const lines: string[] = []; lines.push('═'.repeat(60)); @@ -812,12 +821,14 @@ export function formatForHuman(response: ConversationalResponse): string { `cache: ${response.metrics.fromCache}]`); return lines.join('\n'); -} +}); /** * Format response for AI agent consumption (structured JSON) */ -export function formatForAgent(response: ConversationalResponse): object { +export const formatForAgent: (response: ConversationalResponse) => object = implements_adr( + 'ADR-L-0006', +)(function formatForAgent(response: ConversationalResponse): object { return { query: response.query, intent: response.intent, @@ -833,5 +844,5 @@ export function formatForAgent(response: ConversationalResponse): object { cached: response.metrics.fromCache, }, }; -} +}); diff --git a/src/watch/watchdog.ts b/src/watch/watchdog.ts index 4e87c62..fb11fc9 100644 --- a/src/watch/watchdog.ts +++ b/src/watch/watchdog.ts @@ -35,6 +35,9 @@ export interface WatchdogStats { * and incremental RECON triggering. */ export class Watchdog extends EventEmitter { + static readonly __implements_adrs__ = Object.freeze(['ADR-L-0004'] as const); + static readonly __enforces_invariants__ = Object.freeze([] as const); + private options: WatchdogOptions; private watcher: chokidar.FSWatcher | null = null; private editQueue: EditQueueManager; diff --git a/src/workspace/canned-queries.ts b/src/workspace/canned-queries.ts index dfe1990..a784b60 100644 --- a/src/workspace/canned-queries.ts +++ b/src/workspace/canned-queries.ts @@ -4,6 +4,7 @@ */ import type { WorkspaceGraph, WorkspaceNode, WorkspaceEdge } from './workspace-graph-loader.js'; +import { enforces_invariant, implements_adr } from '../architecture/intent-decorators.js'; // --------------------------------------------------------------------------- // Result types — systemDependencies @@ -129,7 +130,9 @@ function computeRisk( * Collect cross-repo edges, group by repo pair, and produce a repo-level * dependency DAG. */ -export function systemDependencies(graph: WorkspaceGraph): SystemDependencyResult { +export const systemDependencies: (graph: WorkspaceGraph) => SystemDependencyResult = implements_adr( + 'ADR-L-0018', +)(enforces_invariant('INV-0020')(function systemDependencies(graph: WorkspaceGraph): SystemDependencyResult { const repoNodes = new Map>(); for (const node of graph.nodes.values()) { @@ -184,7 +187,7 @@ export function systemDependencies(graph: WorkspaceGraph): SystemDependencyResul .sort((a, b) => b.count - a.count); return { kind: 'system-dependencies', repos, dependencies: deps, connectionTypes }; -} +})); // --------------------------------------------------------------------------- // Query: componentIntegration @@ -194,7 +197,12 @@ export function systemDependencies(graph: WorkspaceGraph): SystemDependencyResul * Collect the subgraph scoped to a single repo or the full workspace, * grouping edges by integration pattern. */ -export function componentIntegration( +export const componentIntegration: ( + graph: WorkspaceGraph, + opts?: { repo?: string }, +) => ComponentIntegrationResult = implements_adr( + 'ADR-L-0018', +)(enforces_invariant('INV-0020')(function componentIntegration( graph: WorkspaceGraph, opts?: { repo?: string }, ): ComponentIntegrationResult { @@ -245,7 +253,7 @@ export function componentIntegration( patterns, }, }; -} +})); // --------------------------------------------------------------------------- // Query: blastRadiusWorkspace @@ -255,7 +263,13 @@ export function componentIntegration( * BFS from the target node in both directions, classifying reachable nodes * into blast-radius tiers. */ -export function blastRadiusWorkspace( +export const blastRadiusWorkspace: ( + graph: WorkspaceGraph, + targetId: string, + opts?: { maxDepth?: number }, +) => WorkspaceBlastRadiusResult = implements_adr( + 'ADR-L-0018', +)(enforces_invariant('INV-0020')(function blastRadiusWorkspace( graph: WorkspaceGraph, targetId: string, opts?: { maxDepth?: number }, @@ -338,7 +352,7 @@ export function blastRadiusWorkspace( affectedNodeCount: tierMap.size, risk: computeRisk(tierTwoPlus, affectedRepos.length), }; -} +})); // --------------------------------------------------------------------------- // Query: whatCalls (Section 11 port) diff --git a/src/workspace/cem-mvc.ts b/src/workspace/cem-mvc.ts index e869282..51caa72 100644 --- a/src/workspace/cem-mvc.ts +++ b/src/workspace/cem-mvc.ts @@ -3,6 +3,7 @@ import crypto from 'node:crypto'; import type { WorkspaceGraph, WorkspaceNode } from './workspace-graph-loader.js'; import type { SourceLocator, SourceLocatorRegistry } from './source-locator-registry.js'; import { resolveLocator } from './source-locator-registry.js'; +import { enforces_invariant, implements_adr } from '../architecture/intent-decorators.js'; export interface CemDiagnostic { kind: string; @@ -143,7 +144,17 @@ function traverse(graph: WorkspaceGraph, startId: string, maxDepth: number, maxN }; } -export function assembleCemBundle(args: { +export const assembleCemBundle: (args: { + graph: WorkspaceGraph; + registry: SourceLocatorRegistry; + query: string; + generatedAt?: string; + generatedBy?: string; + maxDepth?: number; + maxNodes?: number; +}) => CemBundle = implements_adr( + 'ADR-L-0020', +)(enforces_invariant('INV-0027', 'INV-0029')(function assembleCemBundle(args: { graph: WorkspaceGraph; registry: SourceLocatorRegistry; query: string; @@ -238,12 +249,20 @@ export function assembleCemBundle(args: { unresolved_risks: [...negativeSpace], partial_state_diagnostics: partialStateDiagnostics, }; -} - -export function deriveMvcBundle(cem: CemBundle, options: { - generatedAt?: string; - maxSourceRefs?: number; -} = {}): MvcBundle { +})); + +export const deriveMvcBundle: ( + cem: CemBundle, + options?: { generatedAt?: string; maxSourceRefs?: number }, +) => MvcBundle = implements_adr( + 'ADR-L-0020', +)(enforces_invariant('INV-0028', 'INV-0029')(function deriveMvcBundle( + cem: CemBundle, + options: { + generatedAt?: string; + maxSourceRefs?: number; + } = {}, +): MvcBundle { const generatedAt = options.generatedAt ?? new Date().toISOString(); const maxSourceRefs = options.maxSourceRefs ?? 8; const selectedSourceRefs = cem.authoritative_source_refs.slice(0, maxSourceRefs); @@ -300,9 +319,14 @@ export function deriveMvcBundle(cem: CemBundle, options: { unresolved_risk_summary: cem.unresolved_risks, token_or_size_budget: { max_source_refs: maxSourceRefs }, }; -} - -export function validateMvcBundle(mvc: MvcBundle, cem: CemBundle): MvcValidationResult { +})); + +export const validateMvcBundle: (mvc: MvcBundle, cem: CemBundle) => MvcValidationResult = implements_adr( + 'ADR-L-0020', +)(enforces_invariant('INV-0028')(function validateMvcBundle( + mvc: MvcBundle, + cem: CemBundle, +): MvcValidationResult { const warnings: string[] = []; const errors: string[] = []; @@ -357,4 +381,4 @@ export function validateMvcBundle(mvc: MvcBundle, cem: CemBundle): MvcValidation warnings, errors, }; -} +})); diff --git a/src/workspace/compression.ts b/src/workspace/compression.ts index 4d460e5..2fe150f 100644 --- a/src/workspace/compression.ts +++ b/src/workspace/compression.ts @@ -15,6 +15,7 @@ import type { WorkspaceBlastRadiusResult, } from './canned-queries.js'; import { AUXILIARY_NODE_TYPES } from './cfn-type-mapping.js'; +import { enforces_invariant, implements_adr } from '../architecture/intent-decorators.js'; // --------------------------------------------------------------------------- // Public types @@ -747,7 +748,12 @@ function intentForLevel(level: ResolutionLevel): string { // Public API: compress // --------------------------------------------------------------------------- -export function compress( +export const compress: ( + result: CannedQueryResult, + config: Partial & { level: ResolutionLevel }, +) => CompressedProjection = implements_adr( + 'ADR-L-0019', +)(enforces_invariant('INV-0023')(function compress( result: CannedQueryResult, config: Partial & { level: ResolutionLevel }, ): CompressedProjection { @@ -785,4 +791,4 @@ export function compress( sourceResult: result, }; } -} +})); diff --git a/src/workspace/emit-multi-res-projections.ts b/src/workspace/emit-multi-res-projections.ts index 56053d8..3c79600 100644 --- a/src/workspace/emit-multi-res-projections.ts +++ b/src/workspace/emit-multi-res-projections.ts @@ -16,6 +16,7 @@ import { toMermaidAtResolution, toTableAtResolution, navigationBar } from './pro import { compress } from './compression.js'; import type { CompressedProjection, ResolutionLevel, ProjectionMetadata } from './compression.js'; import type { WorkspaceManifest } from './manifest.js'; +import { enforces_invariant, implements_adr } from '../architecture/intent-decorators.js'; // --------------------------------------------------------------------------- // Public types @@ -110,7 +111,12 @@ function renderProjection( // Public API // --------------------------------------------------------------------------- -export async function emitMultiResProjections( +export const emitMultiResProjections: ( + outputDir: string, + manifest: WorkspaceManifest, +) => Promise = implements_adr( + 'ADR-L-0019', +)(enforces_invariant('INV-0022', 'INV-0024')(async function emitMultiResProjections( outputDir: string, manifest: WorkspaceManifest, ): Promise { @@ -229,4 +235,4 @@ export async function emitMultiResProjections( } return { fileCount: filePaths.length, filePaths }; -} +})); diff --git a/src/workspace/emit-projections.ts b/src/workspace/emit-projections.ts index aefd940..f844f8e 100644 --- a/src/workspace/emit-projections.ts +++ b/src/workspace/emit-projections.ts @@ -8,6 +8,7 @@ import fs from 'node:fs/promises'; import path from 'node:path'; import { loadWorkspaceGraph } from './workspace-graph-loader.js'; +import { enforces_invariant, implements_adr } from '../architecture/intent-decorators.js'; import { systemDependencies, componentIntegration } from './canned-queries.js'; import type { SystemDependencyResult, ComponentIntegrationResult } from './canned-queries.js'; import { toMermaid, toTable } from './projections.js'; @@ -149,7 +150,12 @@ function assembleSkeleton( // Public API // --------------------------------------------------------------------------- -export async function emitProjections( +export const emitProjections: ( + outputDir: string, + manifest: WorkspaceManifest, +) => Promise = implements_adr( + 'ADR-L-0018', +)(enforces_invariant('INV-0024')(async function emitProjections( outputDir: string, manifest: WorkspaceManifest, ): Promise { @@ -194,4 +200,4 @@ export async function emitProjections( filePaths.push(skeletonPath); return { fileCount: filePaths.length, filePaths }; -} +})); diff --git a/src/workspace/manifest.ts b/src/workspace/manifest.ts index e080732..cda79c6 100644 --- a/src/workspace/manifest.ts +++ b/src/workspace/manifest.ts @@ -14,6 +14,7 @@ import { type ResolvedConfig, type SupportedLanguage, } from '../config/index.js'; +import { enforces_invariant, implements_adr } from '../architecture/intent-decorators.js'; import { toPosixPath } from '../utils/paths.js'; const INFRA_SOURCE_SUBDIRS = [ @@ -82,7 +83,9 @@ const WORKSPACE_MANIFEST_FILENAMES = ['workspace.yaml', 'workspace.yml'] as cons * that contains a workspace manifest file. Agnostic to repo layout — enables `recon --workspace` * without hardcoded paths. */ -export async function discoverWorkspaceRoot(startDir: string): Promise { +export const discoverWorkspaceRoot: (startDir: string) => Promise = implements_adr( + 'ADR-L-0015', +)(enforces_invariant('INV-0015')(async function discoverWorkspaceRoot(startDir: string): Promise { let dir = path.resolve(startDir); const root = path.parse(dir).root; while (true) { @@ -102,7 +105,7 @@ export async function discoverWorkspaceRoot(startDir: string): Promise { +export const parseWorkspaceManifest: (workspacePathInput: string) => Promise = implements_adr( + 'ADR-L-0009', +)(enforces_invariant('INV-0014')(async function parseWorkspaceManifest( + workspacePathInput: string, +): Promise { const resolved = path.resolve(workspacePathInput); let manifestFile: string; let workspaceRoot: string; @@ -262,25 +269,37 @@ export async function parseWorkspaceManifest(workspacePathInput: string): Promis throw new Error(`workspace manifest validation failed: ${parsed.error.message}`); } return { manifest: parsed.data, workspaceRoot, manifestFile }; -} +})); /** * Resolve a repository entry to an absolute path and verify it exists as a directory. */ -export async function resolveRepoPath(workspaceRoot: string, repo: RepoEntry): Promise { +export const resolveRepoPath: (workspaceRoot: string, repo: RepoEntry) => Promise = implements_adr( + 'ADR-L-0009', +)(enforces_invariant('INV-0014')(async function resolveRepoPath( + workspaceRoot: string, + repo: RepoEntry, +): Promise { const abs = path.resolve(workspaceRoot, repo.path); const st = await fs.stat(abs); if (!st.isDirectory()) { throw new Error(`workspace repo path is not a directory: ${abs} (repo ${repo.name})`); } return abs; -} +})); /** * Build {@link ResolvedConfig} for one repository in workspace mode. * State is written under {@code //state//} (Invariant 2: never under the scanned repo tree). */ -export async function buildPerRepoConfig( +export const buildPerRepoConfig: ( + runtimeDir: string, + repo: RepoEntry, + workspaceRoot: string, + outputDir: string, +) => Promise = implements_adr( + 'ADR-L-0009', +)(enforces_invariant('INV-0014')(async function buildPerRepoConfig( runtimeDir: string, repo: RepoEntry, workspaceRoot: string, @@ -342,4 +361,4 @@ export async function buildPerRepoConfig( mcp: defaultMcp(), rss, }; -} +})); diff --git a/src/workspace/mvc-evolution.test.ts b/src/workspace/mvc-evolution.test.ts new file mode 100644 index 0000000..d1c9d32 --- /dev/null +++ b/src/workspace/mvc-evolution.test.ts @@ -0,0 +1,295 @@ +import path from 'node:path'; +import { access, readFile } from 'node:fs/promises'; +import { fileURLToPath } from 'node:url'; + +import Ajv2020 from 'ajv/dist/2020.js'; +import { describe, expect, it } from 'vitest'; + +import { + assertMvcDefinitionContract, + assertMvcSnapshotCandidateOnly, + buildMvcSnapshotCandidate, + canonicalMvcFingerprintInput, + type BuildMvcSnapshotInput, + type MvcDefinition, +} from './mvc-evolution.js'; + +const __dirname = path.dirname(fileURLToPath(import.meta.url)); +const steRuntimeRoot = path.resolve(__dirname, '..', '..'); +const ADR_ID_PATTERN = /^ADR-L-\d{4}$/; + +async function loadJson(relativePath: string): Promise { + return JSON.parse(await readFile(path.resolve(steRuntimeRoot, relativePath), 'utf8')); +} + +async function loadMvcSchema(schemaFile: string): Promise { + const candidates = [ + path.resolve(steRuntimeRoot, '..', 'ste-spec', 'contracts', 'mvc', schemaFile), + path.resolve(steRuntimeRoot, 'test', 'fixtures', 'mvc-evolution', schemaFile), + ]; + for (const schemaPath of candidates) { + try { + await access(schemaPath); + return JSON.parse(await readFile(schemaPath, 'utf8')) as object; + } catch { + /* try next */ + } + } + throw new Error(`MVC schema not found (tried: ${candidates.join(', ')})`); +} + +async function expectMatchesSchema(schemaFile: string, payload: unknown): Promise { + const ajv = new Ajv2020({ strict: false }); + const schema = await loadMvcSchema(schemaFile); + const validate = ajv.compile(schema); + expect(validate(payload), JSON.stringify(validate.errors, null, 2)).toBe(true); +} + +async function expectSchemaRejects(schemaFile: string, payload: unknown): Promise { + const ajv = new Ajv2020({ strict: false }); + const schema = await loadMvcSchema(schemaFile); + const validate = ajv.compile(schema); + expect(validate(payload)).toBe(false); +} + +async function mvcDefinitionFixture(): Promise { + return await loadJson('test/fixtures/mvc-evolution/mvc-definition.valid.json') as MvcDefinition; +} + +async function buildInput(overrides: Partial = {}): Promise { + const mvcDefinition = await mvcDefinitionFixture(); + return { + mvcDefinition, + irSnapshotRef: { + id: 'architecture-ir:fixture', + version: '0.1.0', + snapshot_hash: 'sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa', + }, + graphSnapshotRefs: [ + { + id: 'graph-domain:runtime-workspace', + version: '0.1.0', + snapshot_hash: 'sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb', + }, + { + id: 'graph-domain:architecture-ir', + version: '0.1.0', + snapshot_hash: 'sha256:cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc', + }, + ], + linkageSurfaceRefs: [ + { + id: 'linkage-surface:adr-to-code', + version: '0.1.0', + snapshot_hash: 'sha256:dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd', + }, + ], + selectorVersionRefs: [ + { id: 'selector:mvc-fixture:decision', version: '0.1.0' }, + { id: 'selector:mvc-fixture:embodiment', version: '0.1.0' }, + ], + candidateEntities: [ + { id: 'decision:adr-l-0043', version: '0.1.0' }, + { id: 'component:runtime-mvc-fixture', version: '0.1.0' }, + ], + candidateRelationships: [ + { id: 'relationship:decision-to-component', version: '0.1.0' }, + ], + candidateEvidence: [ + { id: 'evidence:runtime-fixture', version: '0.1.0' }, + ], + candidateConstraints: [ + { id: 'invariant:inv-0031', version: '0.1.0' }, + ], + topologyMetrics: { + node_count: 2, + edge_count: 1, + branching_factor: 0.5, + convergence_score: 1, + recommended_depth: 1, + }, + inclusionRationale: [ + { + reason: 'Architectural decision and runtime candidate component are fully supplied by fixture.', + selector_path: 'selector:mvc-fixture:decision/entity:decision:adr-l-0043', + persona_ref: 'architect', + task_ref: 'task:mvc-evolution-fixture', + }, + ], + exclusionRationale: [ + { + reason: 'Admission state is excluded because MVC-S is candidate-only.', + selector_path: 'runtime-boundary/admission', + policy_ref: 'policy:runtime-candidate-only', + }, + ], + negativeSpace: [ + { + id: 'missing:direct-code-to-invariant', + reason: 'Fixture preserves missing direct code to invariant linkage as negative space.', + }, + ], + ...overrides, + }; +} + +function functionAdrMetadata(target: unknown): readonly string[] { + return (target as { __implements_adrs__?: readonly string[] }).__implements_adrs__ ?? []; +} + +function functionInvariantMetadata(target: unknown): readonly string[] { + return (target as { __enforces_invariants__?: readonly string[] }).__enforces_invariants__ ?? []; +} + +describe('MVC evolution contract consumption', () => { + it('validates the MVC-D fixture against the ste-spec contract', async () => { + const mvcD = await mvcDefinitionFixture(); + await expectMatchesSchema('mvc-definition.schema.json', mvcD); + expect(() => assertMvcDefinitionContract(mvcD)).not.toThrow(); + }); + + it('emits schema-valid MVC-S candidate snapshots from fully supplied inputs', async () => { + const snapshot = buildMvcSnapshotCandidate(await buildInput()); + + await expectMatchesSchema('mvc-snapshot.schema.json', snapshot); + expect(snapshot.candidate_entities).toHaveLength(2); + expect(snapshot.candidate_relationships).toHaveLength(1); + expect(snapshot.topology_metrics.node_count).toBe(2); + expect(snapshot.inclusion_rationale).toHaveLength(1); + expect(snapshot.exclusion_rationale).toHaveLength(1); + expect(snapshot.negative_space).toContainEqual( + expect.objectContaining({ id: 'missing:direct-code-to-invariant' }), + ); + }); + + it('rejects missing and unsupported MVC-D schema version fields', async () => { + const mvcD = await mvcDefinitionFixture(); + const missingVersion = { ...mvcD }; + delete (missingVersion as Partial).schema_version; + expect(() => assertMvcDefinitionContract(missingVersion)).toThrow('schema_version'); + await expectSchemaRejects('mvc-definition.schema.json', missingVersion); + + const unsupportedVersion = { ...mvcD, schema_version: '9.9.9' }; + expect(() => assertMvcDefinitionContract(unsupportedVersion)).toThrow('Unsupported MVC-D schema_version'); + await expectSchemaRejects('mvc-definition.schema.json', unsupportedVersion); + }); + + it('rejects missing required MVC-D fields instead of auto-healing input', async () => { + const mvcD = await mvcDefinitionFixture(); + const missingTaskContext = { ...mvcD }; + delete (missingTaskContext as Partial).task_context; + expect(() => assertMvcDefinitionContract(missingTaskContext)).toThrow('task_context'); + await expectSchemaRejects('mvc-definition.schema.json', missingTaskContext); + }); + + it('rejects mismatched schema identifiers when inputs try to carry one', async () => { + const mvcD = { ...(await mvcDefinitionFixture()), schema_id: 'runtime-owned-mvc-definition' }; + await expectSchemaRejects('mvc-definition.schema.json', mvcD); + }); + + it('rejects invalid MVC-S output without auto-healing admission semantics', async () => { + const invalidSnapshot = { + ...buildMvcSnapshotCandidate(await buildInput()), + admission_decision: { admitted: true }, + }; + + expect(() => assertMvcSnapshotCandidateOnly(invalidSnapshot)).toThrow('admission_decision'); + await expectSchemaRejects('mvc-snapshot.schema.json', invalidSnapshot); + }); + + it('does not silently default admission, eligibility, kernel, enforcement, or governance fields', async () => { + const snapshot = buildMvcSnapshotCandidate(await buildInput()); + + for (const field of [ + 'admission_decision', + 'admission_status', + 'admitted_payload', + 'caller_facing_eligibility', + 'eligibility_outcome', + 'enforcement_outcome', + 'governance_state', + 'kernel_assessment_state', + 'kernel_verdict', + ]) { + expect(snapshot).not.toHaveProperty(field); + } + }); + + it('emits identical snapshots and fingerprints for identical inputs', async () => { + const input = await buildInput(); + const first = buildMvcSnapshotCandidate(input); + const second = buildMvcSnapshotCandidate(input); + + expect(second).toEqual(first); + expect(second.fingerprint).toBe(first.fingerprint); + expect(second.ir_snapshot_ref).toEqual(first.ir_snapshot_ref); + expect(second.graph_snapshot_refs).toEqual(first.graph_snapshot_refs); + expect(second.linkage_surface_refs).toEqual(first.linkage_surface_refs); + }); + + it('canonicalizes ordering and JSON formatting before fingerprinting', async () => { + const input = await buildInput(); + const reversed = await buildInput({ + graphSnapshotRefs: [...input.graphSnapshotRefs].reverse(), + selectorVersionRefs: [...input.selectorVersionRefs].reverse(), + candidateEntities: [...input.candidateEntities].reverse(), + }); + + const first = buildMvcSnapshotCandidate(input); + const second = buildMvcSnapshotCandidate(JSON.parse(JSON.stringify(reversed)) as BuildMvcSnapshotInput); + + expect(second).toEqual(first); + expect(second.fingerprint).toBe(first.fingerprint); + expect(canonicalMvcFingerprintInput(reversed)).toEqual(canonicalMvcFingerprintInput(input)); + }); + + it('changes fingerprint when topology-affecting inputs change', async () => { + const first = buildMvcSnapshotCandidate(await buildInput()); + const second = buildMvcSnapshotCandidate(await buildInput({ + topologyMetrics: { + node_count: 3, + edge_count: 2, + branching_factor: 0.75, + convergence_score: 0.9, + recommended_depth: 2, + }, + })); + + expect(second.fingerprint).not.toBe(first.fingerprint); + }); + + it('rejects calls without fully supplied candidate material instead of reconstructing it', async () => { + const input = await buildInput(); + const missingCandidates = { ...input }; + delete (missingCandidates as Partial).candidateEntities; + + expect(() => buildMvcSnapshotCandidate(missingCandidates as BuildMvcSnapshotInput)).toThrow( + 'candidateEntities', + ); + }); + + it('exposes machine-readable code provenance for ADR-L-0021 and runtime invariants', () => { + for (const target of [ + assertMvcDefinitionContract, + assertMvcSnapshotCandidateOnly, + buildMvcSnapshotCandidate, + ]) { + const adrIds = functionAdrMetadata(target); + expect(adrIds).toContain('ADR-L-0021'); + expect(adrIds.every(id => ADR_ID_PATTERN.test(id))).toBe(true); + } + + expect(functionInvariantMetadata(assertMvcDefinitionContract)).toContain('INV-0030'); + expect(functionInvariantMetadata(assertMvcSnapshotCandidateOnly)).toContain('INV-0031'); + expect(functionInvariantMetadata(buildMvcSnapshotCandidate)).toEqual(['INV-0031', 'INV-0032']); + }); + + it('anchors code provenance to an existing runtime ADR source', async () => { + await expect(access(path.resolve( + steRuntimeRoot, + 'adrs', + 'logical', + 'ADR-L-0021-experimental-mvc-d-to-mvc-s-contract-consumption.yaml', + ))).resolves.toBeUndefined(); + }); +}); diff --git a/src/workspace/mvc-evolution.ts b/src/workspace/mvc-evolution.ts new file mode 100644 index 0000000..427f919 --- /dev/null +++ b/src/workspace/mvc-evolution.ts @@ -0,0 +1,285 @@ +import crypto from 'node:crypto'; + +import { enforces_invariant, implements_adr } from '../architecture/intent-decorators.js'; + +export interface MvcRef { + id: string; + version: string; +} + +export interface MvcRefWithHash extends MvcRef { + snapshot_hash?: string; +} + +export interface MvcRationale { + reason: string; + selector_path: string; + persona_ref?: string; + task_ref?: string; + policy_ref?: string; +} + +export interface MvcNegativeSpace { + id: string; + reason: string; +} + +export interface MvcTopologyMetrics { + node_count: number; + edge_count: number; + branching_factor: number; + convergence_score: number; + recommended_depth?: number; +} + +export interface MvcDefinition { + schema_version: '0.1.0'; + mvc_d_id: string; + version: string; + status: string; + task_context: Record; + persona_set: MvcRef[]; + context_domain_requirements: Array>; + graph_domain_refs: MvcRef[]; + linkage_surface_refs: MvcRef[]; + traversal_policy_ref: MvcRef; + projection_policy_ref: MvcRef; + admission_policy_ref: MvcRef; + budgets: Record; + mvc_d_boundary: 'definition_not_materialized_context'; +} + +export interface MvcSnapshot { + schema_version: '0.1.0'; + mvc_s_id: string; + fingerprint: string; + mvc_d_ref: MvcRef; + ir_snapshot_ref: MvcRefWithHash; + graph_snapshot_refs: MvcRefWithHash[]; + linkage_surface_refs: MvcRefWithHash[]; + selector_version_refs: MvcRef[]; + candidate_entities: MvcRef[]; + candidate_relationships: MvcRef[]; + candidate_evidence: MvcRef[]; + candidate_constraints: MvcRef[]; + topology_metrics: MvcTopologyMetrics; + inclusion_rationale: MvcRationale[]; + exclusion_rationale: MvcRationale[]; + negative_space: MvcNegativeSpace[]; + mvc_s_boundary: 'candidate_surface_prior_to_admission'; +} + +export interface BuildMvcSnapshotInput { + mvcDefinition: MvcDefinition; + irSnapshotRef: MvcRefWithHash; + graphSnapshotRefs: MvcRefWithHash[]; + linkageSurfaceRefs: MvcRefWithHash[]; + selectorVersionRefs: MvcRef[]; + candidateEntities: MvcRef[]; + candidateRelationships: MvcRef[]; + candidateEvidence: MvcRef[]; + candidateConstraints: MvcRef[]; + topologyMetrics: MvcTopologyMetrics; + inclusionRationale: MvcRationale[]; + exclusionRationale: MvcRationale[]; + negativeSpace: MvcNegativeSpace[]; +} + +const REQUIRED_INPUT_FIELDS: Array = [ + 'mvcDefinition', + 'irSnapshotRef', + 'graphSnapshotRefs', + 'linkageSurfaceRefs', + 'selectorVersionRefs', + 'candidateEntities', + 'candidateRelationships', + 'candidateEvidence', + 'candidateConstraints', + 'topologyMetrics', + 'inclusionRationale', + 'exclusionRationale', + 'negativeSpace', +]; + +const MVC_D_REQUIRED_FIELDS: Array = [ + 'schema_version', + 'mvc_d_id', + 'version', + 'status', + 'task_context', + 'persona_set', + 'context_domain_requirements', + 'graph_domain_refs', + 'linkage_surface_refs', + 'traversal_policy_ref', + 'projection_policy_ref', + 'admission_policy_ref', + 'budgets', + 'mvc_d_boundary', +]; + +const MVC_S_FORBIDDEN_FIELDS = [ + 'admission_decision', + 'admission_status', + 'admitted', + 'admitted_payload', + 'caller_facing_eligibility', + 'eligibility_outcome', + 'enforcement_outcome', + 'governance_state', + 'kernel_assessment_state', + 'kernel_verdict', +]; + +function assertRecord(value: unknown, label: string): asserts value is Record { + if (!value || typeof value !== 'object' || Array.isArray(value)) { + throw new Error(`${label} must be an object`); + } +} + +function assertArray(value: unknown, label: string): asserts value is unknown[] { + if (!Array.isArray(value)) { + throw new Error(`${label} must be fully supplied as an array`); + } +} + +function canonicalize(value: unknown): unknown { + if (Array.isArray(value)) { + return value + .map(item => canonicalize(item)) + .sort((left, right) => JSON.stringify(left).localeCompare(JSON.stringify(right))); + } + if (value && typeof value === 'object') { + return Object.fromEntries( + Object.entries(value as Record) + .filter(([, item]) => item !== undefined) + .sort(([left], [right]) => left.localeCompare(right)) + .map(([key, item]) => [key, canonicalize(item)]), + ); + } + return value; +} + +function stableHash(value: unknown): string { + return `sha256:${crypto.createHash('sha256').update(JSON.stringify(canonicalize(value))).digest('hex')}`; +} + +function canonicalArray(items: T[]): T[] { + return canonicalize(items) as T[]; +} + +export const assertMvcDefinitionContract = implements_adr( + 'ADR-L-0021', +)(enforces_invariant('INV-0030')(function assertMvcDefinitionContract(value: unknown): asserts value is MvcDefinition { + assertRecord(value, 'MVC-D'); + for (const field of MVC_D_REQUIRED_FIELDS) { + if (!(field in value)) { + throw new Error(`MVC-D is missing required field: ${field}`); + } + } + if (value.schema_version !== '0.1.0') { + throw new Error(`Unsupported MVC-D schema_version: ${String(value.schema_version)}`); + } + if (value.mvc_d_boundary !== 'definition_not_materialized_context') { + throw new Error('MVC-D boundary must be definition_not_materialized_context'); + } +})); + +export const assertMvcSnapshotCandidateOnly = implements_adr( + 'ADR-L-0021', +)(enforces_invariant('INV-0031')(function assertMvcSnapshotCandidateOnly(value: unknown): void { + assertRecord(value, 'MVC-S candidate'); + for (const field of MVC_S_FORBIDDEN_FIELDS) { + if (field in value) { + throw new Error(`MVC-S candidate must not contain ${field}`); + } + } +})); + +export const buildMvcSnapshotCandidate = implements_adr( + 'ADR-L-0021', +)(enforces_invariant('INV-0031', 'INV-0032')(function buildMvcSnapshotCandidate( + input: BuildMvcSnapshotInput, +): MvcSnapshot { + assertRecord(input, 'MVC-S builder input'); + for (const field of REQUIRED_INPUT_FIELDS) { + if (!(field in input)) { + throw new Error(`MVC-S builder input is missing required field: ${field}`); + } + } + assertMvcDefinitionContract(input.mvcDefinition); + assertMvcSnapshotCandidateOnly(input); + + assertArray(input.graphSnapshotRefs, 'graphSnapshotRefs'); + assertArray(input.linkageSurfaceRefs, 'linkageSurfaceRefs'); + assertArray(input.selectorVersionRefs, 'selectorVersionRefs'); + assertArray(input.candidateEntities, 'candidateEntities'); + assertArray(input.candidateRelationships, 'candidateRelationships'); + assertArray(input.candidateEvidence, 'candidateEvidence'); + assertArray(input.candidateConstraints, 'candidateConstraints'); + assertArray(input.inclusionRationale, 'inclusionRationale'); + assertArray(input.exclusionRationale, 'exclusionRationale'); + assertArray(input.negativeSpace, 'negativeSpace'); + + const canonicalBody = { + mvc_d_ref: { + id: input.mvcDefinition.mvc_d_id, + version: input.mvcDefinition.version, + }, + ir_snapshot_ref: input.irSnapshotRef, + graph_snapshot_refs: input.graphSnapshotRefs, + linkage_surface_refs: input.linkageSurfaceRefs, + selector_version_refs: input.selectorVersionRefs, + candidate_entities: input.candidateEntities, + candidate_relationships: input.candidateRelationships, + candidate_evidence: input.candidateEvidence, + candidate_constraints: input.candidateConstraints, + topology_metrics: input.topologyMetrics, + }; + const fingerprint = stableHash(canonicalBody); + const snapshot: MvcSnapshot = { + schema_version: '0.1.0', + mvc_s_id: `mvc-s:${fingerprint.slice(7, 23)}`, + fingerprint, + mvc_d_ref: { + id: input.mvcDefinition.mvc_d_id, + version: input.mvcDefinition.version, + }, + ir_snapshot_ref: canonicalize(input.irSnapshotRef) as MvcRefWithHash, + graph_snapshot_refs: canonicalArray(input.graphSnapshotRefs), + linkage_surface_refs: canonicalArray(input.linkageSurfaceRefs), + selector_version_refs: canonicalArray(input.selectorVersionRefs), + candidate_entities: canonicalArray(input.candidateEntities), + candidate_relationships: canonicalArray(input.candidateRelationships), + candidate_evidence: canonicalArray(input.candidateEvidence), + candidate_constraints: canonicalArray(input.candidateConstraints), + topology_metrics: canonicalize(input.topologyMetrics) as MvcTopologyMetrics, + inclusion_rationale: canonicalArray(input.inclusionRationale), + exclusion_rationale: canonicalArray(input.exclusionRationale), + negative_space: canonicalArray(input.negativeSpace), + mvc_s_boundary: 'candidate_surface_prior_to_admission', + }; + assertMvcSnapshotCandidateOnly(snapshot); + return snapshot; +})); + +export const canonicalMvcFingerprintInput: (input: BuildMvcSnapshotInput) => unknown = implements_adr( + 'ADR-L-0021', +)(function canonicalMvcFingerprintInput(input: BuildMvcSnapshotInput): unknown { + assertMvcDefinitionContract(input.mvcDefinition); + return canonicalize({ + mvc_d_ref: { + id: input.mvcDefinition.mvc_d_id, + version: input.mvcDefinition.version, + }, + ir_snapshot_ref: input.irSnapshotRef, + graph_snapshot_refs: input.graphSnapshotRefs, + linkage_surface_refs: input.linkageSurfaceRefs, + selector_version_refs: input.selectorVersionRefs, + candidate_entities: input.candidateEntities, + candidate_relationships: input.candidateRelationships, + candidate_evidence: input.candidateEvidence, + candidate_constraints: input.candidateConstraints, + topology_metrics: input.topologyMetrics, + }); +}); diff --git a/src/workspace/projection-families.ts b/src/workspace/projection-families.ts index 41c5e0d..39ed3b4 100644 --- a/src/workspace/projection-families.ts +++ b/src/workspace/projection-families.ts @@ -5,6 +5,7 @@ */ import type { ResolutionLevel, ResolutionConfig } from './compression.js'; +import { implements_adr } from '../architecture/intent-decorators.js'; // --------------------------------------------------------------------------- // Public types @@ -25,9 +26,11 @@ export interface ProjectionFamily { const families = new Map(); -export function registerFamily(family: ProjectionFamily): void { +export const registerFamily: (family: ProjectionFamily) => void = implements_adr( + 'ADR-L-0019', +)(function registerFamily(family: ProjectionFamily): void { families.set(family.id, family); -} +}); export function getFamily(id: string): ProjectionFamily | undefined { return families.get(id); diff --git a/src/workspace/projections.ts b/src/workspace/projections.ts index 5448e4a..2f55a0b 100644 --- a/src/workspace/projections.ts +++ b/src/workspace/projections.ts @@ -24,6 +24,7 @@ import type { ResolutionConfig, ResolutionLevel, } from './compression.js'; +import { enforces_invariant, implements_adr } from '../architecture/intent-decorators.js'; // --------------------------------------------------------------------------- // Mermaid helpers @@ -57,7 +58,9 @@ function mermaidNodeDef(node: WorkspaceNode): string { // toMermaid // --------------------------------------------------------------------------- -export function toMermaid(result: CannedQueryResult): string { +export const toMermaid: (result: CannedQueryResult) => string = implements_adr( + 'ADR-L-0018', +)(enforces_invariant('INV-0021')(function toMermaid(result: CannedQueryResult): string { switch (result.kind) { case 'system-dependencies': return mermaidSystemDeps(result); @@ -72,7 +75,7 @@ export function toMermaid(result: CannedQueryResult): string { case 'node-blast-radius': return mermaidNodeList(result.targetId, 'affected', result.affected); } -} +})); function mermaidNodeList(targetId: string, label: string, nodes: string[]): string { const lines: string[] = ['flowchart TD']; @@ -178,7 +181,9 @@ function mermaidBlastRadius(result: WorkspaceBlastRadiusResult): string { // toTable // --------------------------------------------------------------------------- -export function toTable(result: CannedQueryResult): Array> { +export const toTable: (result: CannedQueryResult) => Array> = implements_adr( + 'ADR-L-0018', +)(enforces_invariant('INV-0021')(function toTable(result: CannedQueryResult): Array> { switch (result.kind) { case 'system-dependencies': return tableSystemDeps(result); @@ -193,7 +198,7 @@ export function toTable(result: CannedQueryResult): Array case 'node-blast-radius': return tableNodeList(result.targetId, 'affected', result.affected); } -} +})); function tableSystemDeps(result: SystemDependencyResult): Array> { const rows: Array> = []; @@ -247,7 +252,9 @@ export interface AdjacencyMatrixResult { matrix: string[][]; } -export function toAdjacencyMatrix(result: CannedQueryResult): AdjacencyMatrixResult { +export const toAdjacencyMatrix: (result: CannedQueryResult) => AdjacencyMatrixResult = implements_adr( + 'ADR-L-0018', +)(enforces_invariant('INV-0021')(function toAdjacencyMatrix(result: CannedQueryResult): AdjacencyMatrixResult { switch (result.kind) { case 'system-dependencies': return matrixSystemDeps(result); @@ -260,7 +267,7 @@ export function toAdjacencyMatrix(result: CannedQueryResult): AdjacencyMatrixRes case 'node-blast-radius': return { labels: [], matrix: [] }; } -} +})); function matrixSystemDeps(result: SystemDependencyResult): AdjacencyMatrixResult { const labels = result.repos.map(r => r.name).sort(); @@ -359,7 +366,9 @@ function navigationBar(currentLevel: ResolutionLevel): string { return `> **Resolution:** ${parts.join(' | ')}`; } -export function toMermaidAtResolution(projection: CompressedProjection): string { +export const toMermaidAtResolution: (projection: CompressedProjection) => string = implements_adr( + 'ADR-L-0019', +)(enforces_invariant('INV-0022', 'INV-0021')(function toMermaidAtResolution(projection: CompressedProjection): string { const { nodes, edges, groups, metadata } = projection; const level = metadata.level; const lines: string[] = ['flowchart TD']; @@ -427,9 +436,13 @@ export function toMermaidAtResolution(projection: CompressedProjection): string } return lines.join('\n'); -} +})); -export function toTableAtResolution( +export const toTableAtResolution: ( + projection: CompressedProjection, +) => Array> = implements_adr( + 'ADR-L-0019', +)(enforces_invariant('INV-0022', 'INV-0021')(function toTableAtResolution( projection: CompressedProjection, ): Array> { const { nodes, edges, groups, metadata } = projection; @@ -487,6 +500,6 @@ export function toTableAtResolution( 'Via': e.verb, 'Count': String(e.multiplicity), })); -} +})); export { navigationBar }; diff --git a/src/workspace/slice-emitter.ts b/src/workspace/slice-emitter.ts index 74c8feb..70d14c1 100644 --- a/src/workspace/slice-emitter.ts +++ b/src/workspace/slice-emitter.ts @@ -20,6 +20,7 @@ import type { ExternalSystemEntry } from './manifest.js'; import { getCfnGraphType, NODE_NAME_KEYS, AUXILIARY_NODE_TYPES } from './cfn-type-mapping.js'; import { entityUri, workspaceUri } from './source-uri.js'; import { computeFileHash } from './source-locator-registry.js'; +import { enforces_invariant, implements_adr } from '../architecture/intent-decorators.js'; const require = createRequire(import.meta.url); const pkg = require('../../package.json') as { name: string; version: string }; @@ -704,7 +705,15 @@ export async function loadRepoState(stateDir: string): Promise Promise = implements_adr( + 'ADR-L-0016', +)(enforces_invariant('INV-0017', 'INV-0025')(async function emitWorkspaceSlice( repoName: string, stateDir: string, outputPath: string, @@ -899,4 +908,4 @@ export async function emitWorkspaceSlice( edgeCount: edges.length, contentHash, }; -} +})); diff --git a/src/workspace/slice-schema.ts b/src/workspace/slice-schema.ts index aa4fb84..978000d 100644 --- a/src/workspace/slice-schema.ts +++ b/src/workspace/slice-schema.ts @@ -9,6 +9,8 @@ */ import { z } from 'zod'; +import { enforces_invariant, implements_adr } from '../architecture/intent-decorators.js'; + export const NODE_TYPES = [ 'Service', 'Lambda', @@ -104,7 +106,12 @@ const edgeVerbSet = new Set(EDGE_VERBS); * Validate a parsed slice document. In warn mode (default), unknown types/verbs * produce warnings but the slice is accepted. In reject mode, they produce errors. */ -export function validateSlice( +export const validateSlice: ( + doc: unknown, + mode?: 'warn' | 'reject', +) => SliceValidationResult = implements_adr( + 'ADR-L-0016', +)(enforces_invariant('INV-0017', 'INV-0018')(function validateSlice( doc: unknown, mode: 'warn' | 'reject' = 'warn', ): SliceValidationResult { @@ -151,4 +158,4 @@ export function validateSlice( warnings, errors, }; -} +})); diff --git a/src/workspace/source-locator-registry.ts b/src/workspace/source-locator-registry.ts index e9ad525..d64b4b3 100644 --- a/src/workspace/source-locator-registry.ts +++ b/src/workspace/source-locator-registry.ts @@ -4,6 +4,7 @@ import path from 'node:path'; import yaml from 'js-yaml'; import { entityUri, parseSourceUri, workspaceUri, type LineRange } from './source-uri.js'; +import { enforces_invariant, implements_adr } from '../architecture/intent-decorators.js'; export interface SourceLocator { entity_uri: string; @@ -200,7 +201,11 @@ async function locatorsFromArchitectureRegistry( return locators; } -export async function emitSourceLocatorRegistry( +export const emitSourceLocatorRegistry: ( + options: EmitSourceLocatorRegistryOptions, +) => Promise<{ registry: SourceLocatorRegistry; registryPath: string }> = implements_adr( + 'ADR-L-0020', +)(enforces_invariant('INV-0027', 'INV-0029')(async function emitSourceLocatorRegistry( options: EmitSourceLocatorRegistryOptions, ): Promise<{ registry: SourceLocatorRegistry; registryPath: string }> { const repos = repoPathMap(options); @@ -252,7 +257,7 @@ export async function emitSourceLocatorRegistry( const registryPath = path.join(options.outputDir, 'source-locator-registry.yaml'); await fs.writeFile(registryPath, yaml.dump(registry, { lineWidth: 120, noRefs: true }), 'utf-8'); return { registry, registryPath }; -} +})); export async function loadSourceLocatorRegistry(outputDir: string): Promise { const raw = await fs.readFile(path.join(outputDir, 'source-locator-registry.yaml'), 'utf-8'); diff --git a/src/workspace/source-uri.ts b/src/workspace/source-uri.ts index f5bb7d2..b73d5c1 100644 --- a/src/workspace/source-uri.ts +++ b/src/workspace/source-uri.ts @@ -1,3 +1,5 @@ +import { implements_adr } from '../architecture/intent-decorators.js'; + export interface LineRange { start: number; end: number; @@ -30,7 +32,9 @@ function normalizeRepo(repo: string): string { return trimmed; } -export function normalizePortablePath(input: string): string { +export const normalizePortablePath: (input: string) => string = implements_adr( + 'ADR-L-0013', +)(function normalizePortablePath(input: string): string { const raw = input.trim().replace(/\\/g, '/'); if (!raw) { throw new Error('Source URI path must be non-empty'); @@ -43,7 +47,7 @@ export function normalizePortablePath(input: string): string { throw new Error(`Source URI path is not portable: ${input}`); } return parts.join('/'); -} +}); function formatLineRange(lineRange?: LineRange): string { if (!lineRange) return ''; @@ -58,12 +62,14 @@ function formatLineRange(lineRange?: LineRange): string { return `#L${lineRange.start}-L${lineRange.end}`; } -export function workspaceUri(repo: string, sourcePath: string, lineRange?: LineRange): string { +export const workspaceUri: (repo: string, sourcePath: string, lineRange?: LineRange) => string = implements_adr( + 'ADR-L-0013', +)(function workspaceUri(repo: string, sourcePath: string, lineRange?: LineRange): string { const normalizedRepo = normalizeRepo(repo); const normalizedPath = normalizePortablePath(sourcePath); const encodedPath = normalizedPath.split('/').map(encodePathSegment).join('/'); return `workspace://${encodePathSegment(normalizedRepo)}/${encodedPath}${formatLineRange(lineRange)}`; -} +}); export function entityUri(entityId: string): string { const trimmed = entityId.trim(); diff --git a/src/workspace/workspace-graph-loader.ts b/src/workspace/workspace-graph-loader.ts index dab636a..c464b6d 100644 --- a/src/workspace/workspace-graph-loader.ts +++ b/src/workspace/workspace-graph-loader.ts @@ -7,6 +7,8 @@ import fs from 'node:fs/promises'; import path from 'node:path'; import yaml from 'js-yaml'; +import { enforces_invariant, implements_adr } from '../architecture/intent-decorators.js'; + // --------------------------------------------------------------------------- // Public types // --------------------------------------------------------------------------- @@ -107,7 +109,9 @@ function pushToAdjList( * * Returns a unified {@link WorkspaceGraph} with pre-built adjacency lists. */ -export async function loadWorkspaceGraph(outputDir: string): Promise { +export const loadWorkspaceGraph: (outputDir: string) => Promise = implements_adr( + 'ADR-L-0018', +)(async function loadWorkspaceGraph(outputDir: string): Promise { const resolved = path.resolve(outputDir); const indexPath = path.join(resolved, 'workspace-index.yaml'); @@ -177,4 +181,4 @@ export async function loadWorkspaceGraph(outputDir: string): Promise Promise = implements_adr( + 'ADR-L-0009', +)(enforces_invariant('INV-0014')(async function emitWorkspaceIndex( repos: RepoIndexEntry[], outputDir: string, generatedAt: string, @@ -34,4 +42,4 @@ export async function emitWorkspaceIndex( const outPath = path.join(outputDir, 'workspace-index.yaml'); await fs.mkdir(path.dirname(outPath), { recursive: true }); await fs.writeFile(outPath, yaml.dump(doc, { lineWidth: 120, noRefs: true }), 'utf-8'); -} +})); diff --git a/src/workspace/workspace-recon.ts b/src/workspace/workspace-recon.ts index 4b71e8b..1cd658c 100644 --- a/src/workspace/workspace-recon.ts +++ b/src/workspace/workspace-recon.ts @@ -7,6 +7,7 @@ import path from 'node:path'; import crypto from 'node:crypto'; import type { ResolvedConfig } from '../config/index.js'; import { executeRecon } from '../recon/index.js'; +import { enforces_invariant, implements_adr } from '../architecture/intent-decorators.js'; import { discoverFilesFromConfig } from '../recon/phases/discovery.js'; import { log } from '../utils/logger.js'; import { PhaseTimer, repoLimiter, type PhaseTimingRecord } from '../utils/concurrency.js'; @@ -138,7 +139,14 @@ function repoIsFailure(r: RepoResult): boolean { /** * Run RECON once per repository in manifest order; write slices and workspace index at workspace root. */ -export async function executeWorkspaceRecon(options: WorkspaceReconOptions): Promise { +export const executeWorkspaceRecon: ( + options: WorkspaceReconOptions, +) => Promise = implements_adr( + 'ADR-L-0017', + 'ADR-L-0009', +)(enforces_invariant('INV-0019')(async function executeWorkspaceRecon( + options: WorkspaceReconOptions, +): Promise { const wsTimer = new PhaseTimer('Workspace Orchestration'); wsTimer.start(); @@ -376,4 +384,4 @@ export async function executeWorkspaceRecon(options: WorkspaceReconOptions): Pro multiResProjectionResult, orchestrationTiming: wsTiming, }; -} +})); diff --git a/test/fixtures/mvc-evolution/mvc-definition.schema.json b/test/fixtures/mvc-evolution/mvc-definition.schema.json new file mode 100644 index 0000000..cb2d473 --- /dev/null +++ b/test/fixtures/mvc-evolution/mvc-definition.schema.json @@ -0,0 +1,156 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://github.com/egallmann/ste-spec/contracts/mvc/mvc-definition.schema.json", + "title": "MVCDefinition (MVC-D, DRAFT)", + "description": "Draft declarative admissible context definition for task-scoped architectural reality assembly. Pre-normative.", + "type": "object", + "additionalProperties": false, + "required": [ + "schema_version", + "mvc_d_id", + "version", + "status", + "task_context", + "persona_set", + "context_domain_requirements", + "graph_domain_refs", + "linkage_surface_refs", + "traversal_policy_ref", + "projection_policy_ref", + "admission_policy_ref", + "budgets", + "mvc_d_boundary" + ], + "properties": { + "schema_version": { + "const": "0.1.0" + }, + "mvc_d_id": { + "$ref": "#/$defs/stableId" + }, + "version": { + "$ref": "#/$defs/semver" + }, + "status": { + "type": "string", + "enum": ["draft", "experimental", "deprecated"] + }, + "task_context": { + "$ref": "#/$defs/taskContext" + }, + "persona_set": { + "type": "array", + "items": { + "$ref": "#/$defs/ref" + }, + "minItems": 1 + }, + "context_domain_requirements": { + "type": "array", + "items": { + "$ref": "#/$defs/contextDomainRequirement" + }, + "minItems": 1 + }, + "graph_domain_refs": { + "type": "array", + "items": { + "$ref": "#/$defs/ref" + } + }, + "linkage_surface_refs": { + "type": "array", + "items": { + "$ref": "#/$defs/ref" + } + }, + "traversal_policy_ref": { + "$ref": "#/$defs/ref" + }, + "projection_policy_ref": { + "$ref": "#/$defs/ref" + }, + "admission_policy_ref": { + "$ref": "#/$defs/ref" + }, + "budgets": { + "type": "object", + "additionalProperties": false, + "required": ["max_candidate_items"], + "properties": { + "max_candidate_items": { + "type": "integer", + "minimum": 1 + }, + "max_output_items": { + "type": "integer", + "minimum": 1 + } + } + }, + "mvc_d_boundary": { + "type": "string", + "enum": ["definition_not_materialized_context"] + } + }, + "$defs": { + "stableId": { + "type": "string", + "pattern": "^[a-z][a-z0-9._:/-]*$" + }, + "semver": { + "type": "string", + "pattern": "^\\d+\\.\\d+\\.\\d+$" + }, + "nonEmptyString": { + "type": "string", + "minLength": 1 + }, + "ref": { + "type": "object", + "additionalProperties": false, + "required": ["id", "version"], + "properties": { + "id": { + "$ref": "#/$defs/nonEmptyString" + }, + "version": { + "$ref": "#/$defs/nonEmptyString" + } + } + }, + "taskContext": { + "type": "object", + "additionalProperties": false, + "required": ["task_id", "intent", "declared_scope"], + "properties": { + "task_id": { + "$ref": "#/$defs/stableId" + }, + "intent": { + "$ref": "#/$defs/nonEmptyString" + }, + "declared_scope": { + "$ref": "#/$defs/nonEmptyString" + } + } + }, + "contextDomainRequirement": { + "type": "object", + "additionalProperties": false, + "required": ["context_domain_ref", "necessity", "reason"], + "properties": { + "context_domain_ref": { + "$ref": "#/$defs/ref" + }, + "necessity": { + "type": "string", + "enum": ["required", "optional"] + }, + "reason": { + "$ref": "#/$defs/nonEmptyString" + } + } + } + } +} diff --git a/test/fixtures/mvc-evolution/mvc-definition.valid.json b/test/fixtures/mvc-evolution/mvc-definition.valid.json new file mode 100644 index 0000000..0dd3753 --- /dev/null +++ b/test/fixtures/mvc-evolution/mvc-definition.valid.json @@ -0,0 +1,56 @@ +{ + "schema_version": "0.1.0", + "mvc_d_id": "mvc-d:mvc-evolution-fixture", + "version": "0.1.0", + "status": "experimental", + "task_context": { + "task_id": "task:mvc-evolution-fixture", + "intent": "Evaluate whether MVC evolution preserves runtime/kernel authority boundaries.", + "declared_scope": "ste-spec contract draft fixture" + }, + "persona_set": [ + { + "id": "architect", + "version": "0.1.0" + } + ], + "context_domain_requirements": [ + { + "context_domain_ref": { + "id": "decision-context", + "version": "0.1.0" + }, + "necessity": "required", + "reason": "The task depends on accepted runtime/kernel boundary decisions." + } + ], + "graph_domain_refs": [ + { + "id": "architecture-intent-graph", + "version": "0.1.0" + } + ], + "linkage_surface_refs": [ + { + "id": "adr-code-linkage-surface", + "version": "0.1.0" + } + ], + "traversal_policy_ref": { + "id": "rss-depth-from-mvc-s-topology", + "version": "0.1.0" + }, + "projection_policy_ref": { + "id": "preserve-rationale", + "version": "0.1.0" + }, + "admission_policy_ref": { + "id": "kernel-admission-required", + "version": "0.1.0" + }, + "budgets": { + "max_candidate_items": 100, + "max_output_items": 50 + }, + "mvc_d_boundary": "definition_not_materialized_context" +} diff --git a/test/fixtures/mvc-evolution/mvc-snapshot.schema.json b/test/fixtures/mvc-evolution/mvc-snapshot.schema.json new file mode 100644 index 0000000..b4e02f6 --- /dev/null +++ b/test/fixtures/mvc-evolution/mvc-snapshot.schema.json @@ -0,0 +1,206 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://github.com/egallmann/ste-spec/contracts/mvc/mvc-snapshot.schema.json", + "title": "MVCSnapshot (MVC-S, DRAFT)", + "description": "Draft candidate task-relevant architectural reality surface prior to admission. Pre-normative.", + "type": "object", + "additionalProperties": false, + "required": [ + "schema_version", + "mvc_s_id", + "fingerprint", + "mvc_d_ref", + "ir_snapshot_ref", + "graph_snapshot_refs", + "linkage_surface_refs", + "selector_version_refs", + "candidate_entities", + "candidate_relationships", + "candidate_evidence", + "candidate_constraints", + "topology_metrics", + "inclusion_rationale", + "exclusion_rationale", + "negative_space", + "mvc_s_boundary" + ], + "properties": { + "schema_version": { + "const": "0.1.0" + }, + "mvc_s_id": { + "$ref": "#/$defs/stableId" + }, + "fingerprint": { + "$ref": "#/$defs/sha256" + }, + "mvc_d_ref": { + "$ref": "#/$defs/ref" + }, + "ir_snapshot_ref": { + "$ref": "#/$defs/refWithHash" + }, + "graph_snapshot_refs": { + "type": "array", + "items": { + "$ref": "#/$defs/refWithHash" + } + }, + "linkage_surface_refs": { + "type": "array", + "items": { + "$ref": "#/$defs/refWithHash" + } + }, + "selector_version_refs": { + "type": "array", + "items": { + "$ref": "#/$defs/ref" + }, + "minItems": 1 + }, + "candidate_entities": { + "$ref": "#/$defs/refArray" + }, + "candidate_relationships": { + "$ref": "#/$defs/refArray" + }, + "candidate_evidence": { + "$ref": "#/$defs/refArray" + }, + "candidate_constraints": { + "$ref": "#/$defs/refArray" + }, + "topology_metrics": { + "type": "object", + "additionalProperties": false, + "required": ["node_count", "edge_count", "branching_factor", "convergence_score"], + "properties": { + "node_count": { + "type": "integer", + "minimum": 0 + }, + "edge_count": { + "type": "integer", + "minimum": 0 + }, + "branching_factor": { + "type": "number" + }, + "convergence_score": { + "type": "number" + }, + "recommended_depth": { + "type": "integer", + "minimum": 0 + } + } + }, + "inclusion_rationale": { + "$ref": "#/$defs/rationaleArray" + }, + "exclusion_rationale": { + "$ref": "#/$defs/rationaleArray" + }, + "negative_space": { + "type": "array", + "items": { + "$ref": "#/$defs/negativeSpace" + } + }, + "mvc_s_boundary": { + "type": "string", + "enum": ["candidate_surface_prior_to_admission"] + } + }, + "$defs": { + "stableId": { + "type": "string", + "pattern": "^[a-z][a-z0-9._:/-]*$" + }, + "nonEmptyString": { + "type": "string", + "minLength": 1 + }, + "ref": { + "type": "object", + "additionalProperties": false, + "required": ["id", "version"], + "properties": { + "id": { + "$ref": "#/$defs/nonEmptyString" + }, + "version": { + "$ref": "#/$defs/nonEmptyString" + } + } + }, + "refWithHash": { + "type": "object", + "additionalProperties": false, + "required": ["id", "version"], + "properties": { + "id": { + "$ref": "#/$defs/nonEmptyString" + }, + "version": { + "$ref": "#/$defs/nonEmptyString" + }, + "snapshot_hash": { + "$ref": "#/$defs/sha256" + } + } + }, + "refArray": { + "type": "array", + "items": { + "$ref": "#/$defs/ref" + } + }, + "rationaleArray": { + "type": "array", + "items": { + "$ref": "#/$defs/rationale" + } + }, + "rationale": { + "type": "object", + "additionalProperties": false, + "required": ["reason", "selector_path"], + "properties": { + "reason": { + "$ref": "#/$defs/nonEmptyString" + }, + "selector_path": { + "$ref": "#/$defs/nonEmptyString" + }, + "persona_ref": { + "$ref": "#/$defs/nonEmptyString" + }, + "task_ref": { + "$ref": "#/$defs/nonEmptyString" + }, + "policy_ref": { + "$ref": "#/$defs/nonEmptyString" + } + } + }, + "negativeSpace": { + "type": "object", + "additionalProperties": false, + "required": ["id", "reason"], + "properties": { + "id": { + "$ref": "#/$defs/stableId" + }, + "reason": { + "$ref": "#/$defs/nonEmptyString" + } + } + }, + "sha256": { + "type": "string", + "pattern": "^sha256:[a-f0-9]{64}$" + } + } +} diff --git a/test/fixtures/mvc-evolution/mvc-snapshot.valid.json b/test/fixtures/mvc-evolution/mvc-snapshot.valid.json new file mode 100644 index 0000000..37a61ca --- /dev/null +++ b/test/fixtures/mvc-evolution/mvc-snapshot.valid.json @@ -0,0 +1,71 @@ +{ + "schema_version": "0.1.0", + "mvc_s_id": "mvc-s:mvc-evolution-fixture", + "fingerprint": "sha256:eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee", + "mvc_d_ref": { + "id": "mvc-d:mvc-evolution-fixture", + "version": "0.1.0" + }, + "ir_snapshot_ref": { + "id": "compiled-ir:test", + "version": "0.1.0", + "snapshot_hash": "sha256:aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" + }, + "graph_snapshot_refs": [ + { + "id": "architecture-intent-graph:snapshot", + "version": "0.1.0", + "snapshot_hash": "sha256:bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" + } + ], + "linkage_surface_refs": [ + { + "id": "adr-code-linkage-surface", + "version": "0.1.0", + "snapshot_hash": "sha256:cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc" + } + ], + "selector_version_refs": [ + { + "id": "decision-selector", + "version": "0.1.0" + } + ], + "candidate_entities": [ + { + "id": "decision:ADR-L-0031", + "version": "1" + } + ], + "candidate_relationships": [ + { + "id": "adr-code-link-001", + "version": "0.1.0" + } + ], + "candidate_evidence": [], + "candidate_constraints": [], + "topology_metrics": { + "node_count": 2, + "edge_count": 1, + "branching_factor": 1, + "convergence_score": 1, + "recommended_depth": 1 + }, + "inclusion_rationale": [ + { + "reason": "Decision and code linkage are candidates for runtime/kernel boundary review.", + "selector_path": "mvc-d:mvc-evolution-fixture/context-domain:decision-context", + "persona_ref": "architect", + "task_ref": "task:mvc-evolution-fixture" + } + ], + "exclusion_rationale": [], + "negative_space": [ + { + "id": "missing:direct-code-to-invariant", + "reason": "Fixture has ADR to code linkage but no direct code to invariant linkage." + } + ], + "mvc_s_boundary": "candidate_surface_prior_to_admission" +} diff --git a/tsconfig.json b/tsconfig.json index b391e47..d2552db 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -13,7 +13,8 @@ "resolveJsonModule": true, "declaration": true, "declarationMap": true, - "sourceMap": true + "sourceMap": true, + "experimentalDecorators": true }, "include": ["src/**/*"], "exclude": ["node_modules", "dist", "**/*.test.ts"] From 6d963a11a300907124e5c9171954e88e0521f3a3 Mon Sep 17 00:00:00 2001 From: egallmann Date: Tue, 2 Jun 2026 00:53:53 -0400 Subject: [PATCH 3/3] feat(workspace): consume attribution federation after RECON (ADR-L-0022) Repo-qualified entity URIs for ADR, decision, and invariant locators. Invoke adr-kit workspace-report after workspace RECON with no TypeScript merge or per-repo evidence mutation. Co-authored-by: Cursor --- adrs/entities/registry.yaml | 36 +++ adrs/index/architecture-index.yaml | 4 +- adrs/index/decision-registry.yaml | 55 +++++ adrs/index/entity-registry.yaml | 232 ++++++++++++++++++ adrs/index/invariant-registry.yaml | 110 +++++++++ adrs/index/relationship-registry.yaml | 120 +++++++++ ...ce-attribution-federation-consumption.yaml | 74 ++++++ adrs/manifest.yaml | 34 ++- docs/workspace-adr-federation.md | 58 +++++ src/architecture/architecture-merge.test.ts | 80 ++++++ .../retrofit-contract-guards.test.ts | 7 + src/workspace/source-locator-registry.test.ts | 59 +++++ src/workspace/source-locator-registry.ts | 14 +- src/workspace/source-uri.test.ts | 17 ++ src/workspace/source-uri.ts | 63 ++++- .../workspace-attribution-federation.test.ts | 39 +++ .../workspace-attribution-federation.ts | 33 +++ src/workspace/workspace-recon.ts | 9 + 18 files changed, 1025 insertions(+), 19 deletions(-) create mode 100644 adrs/logical/ADR-L-0022-workspace-attribution-federation-consumption.yaml create mode 100644 docs/workspace-adr-federation.md create mode 100644 src/architecture/architecture-merge.test.ts create mode 100644 src/workspace/workspace-attribution-federation.test.ts create mode 100644 src/workspace/workspace-attribution-federation.ts diff --git a/adrs/entities/registry.yaml b/adrs/entities/registry.yaml index 709a172..5819f9b 100644 --- a/adrs/entities/registry.yaml +++ b/adrs/entities/registry.yaml @@ -566,6 +566,18 @@ entities: - INV-0030 - INV-0031 - INV-0032 + - entity_id: DEC-0024 + entity_type: decision + name: ste-runtime orchestrates workspace federation via adr-kit CLI after workspace RECON + introduced_by: ADR-L-0022 + lifecycle_stage: active + source_path: adrs/logical/ADR-L-0022-workspace-attribution-federation-consumption.yaml + source_artifact_type: logical_adr + related_adrs: [] + relationships: + depends_on: [] + implements: [] + realizes: [] - entity_id: INV-0001 entity_type: invariant name: INV-0001 @@ -938,3 +950,27 @@ entities: depends_on: [] implements: [] realizes: [] + - entity_id: INV-0033 + entity_type: invariant + name: INV-0033 + introduced_by: ADR-L-0022 + lifecycle_stage: active + source_path: adrs/logical/ADR-L-0022-workspace-attribution-federation-consumption.yaml + source_artifact_type: logical_adr + related_adrs: [] + relationships: + depends_on: [] + implements: [] + realizes: [] + - entity_id: INV-0034 + entity_type: invariant + name: INV-0034 + introduced_by: ADR-L-0022 + lifecycle_stage: active + source_path: adrs/logical/ADR-L-0022-workspace-attribution-federation-consumption.yaml + source_artifact_type: logical_adr + related_adrs: [] + relationships: + depends_on: [] + implements: [] + realizes: [] diff --git a/adrs/index/architecture-index.yaml b/adrs/index/architecture-index.yaml index b2e02fd..ff65f74 100644 --- a/adrs/index/architecture-index.yaml +++ b/adrs/index/architecture-index.yaml @@ -1,7 +1,7 @@ schema_version: '1.1' type: architecture_index architecture_namespace: ste-runtime -generated_at: '2026-05-30T19:23:29Z' +generated_at: '2026-06-02T04:30:56Z' generator: adr-architecture-index entity_registry_path: adrs/index/entity-registry.yaml relationship_registry_path: adrs/index/relationship-registry.yaml @@ -17,7 +17,7 @@ validation_summary: warnings: 0 unresolved_entries: 0 source_coverage: - logical_adrs: 20 + logical_adrs: 21 physical_adrs: 5 physical_system_adrs: 2 physical_component_adrs: 11 diff --git a/adrs/index/decision-registry.yaml b/adrs/index/decision-registry.yaml index 1a127f5..c21357f 100644 --- a/adrs/index/decision-registry.yaml +++ b/adrs/index/decision-registry.yaml @@ -1340,3 +1340,58 @@ entities: extraction_phase: extract_decision classification: explicit generator: adr-architecture-index + - id: DEC-0024 + entity_type: decision + name: ste-runtime orchestrates workspace federation via adr-kit CLI after workspace RECON + summary: >- + Federation merge logic lives in adr-architecture-kit as single authority; ste-runtime must not duplicate merge in + TypeScript. + lifecycle_stage: active + admission_status: admitted + canonical_source: + source_type: logical_adr + source_ref: ADR-L-0022#DEC-0024 + artifact_path: adrs/logical/ADR-L-0022-workspace-attribution-federation-consumption.yaml + source_refs: [] + metadata: + adr_id: ADR-L-0022 + related_invariants: [] + enforces_invariants: [] + enables_capabilities: [] + governs_components: [] + supersedes: [] + refines: [] + contradicts: [] + relationships: + declared_in: + - ADR-L-0022 + declares: [] + references: [] + referenced_by: [] + related_to: [] + enforces: [] + enforced_by: [] + enabled_by: [] + enables: [] + governs: [] + governed_by: [] + implemented_by: [] + implements: [] + embodied_in: [] + embodies: [] + supersedes: [] + superseded_by: [] + refines: [] + refined_by: [] + contradicts: [] + rejects: [] + rejected_by: [] + completeness: + status: complete + missing_fields: [] + provenance: + source_type: logical_adr + source_ref: ADR-L-0022#DEC-0024 + extraction_phase: extract_decision + classification: explicit + generator: adr-architecture-index diff --git a/adrs/index/entity-registry.yaml b/adrs/index/entity-registry.yaml index 936d610..ae812e5 100644 --- a/adrs/index/entity-registry.yaml +++ b/adrs/index/entity-registry.yaml @@ -477,6 +477,7 @@ entities: - ADR-L-0017 - ADR-L-0018 - ADR-L-0019 + - ADR-L-0022 related_to: [] enforces: [] enforced_by: [] @@ -906,6 +907,7 @@ entities: - ADR-L-0019 - ADR-L-0020 - ADR-L-0021 + - ADR-L-0022 related_to: [] enforces: [] enforced_by: [] @@ -969,6 +971,7 @@ entities: - ADR-L-0013 referenced_by: - ADR-L-0020 + - ADR-L-0022 related_to: [] enforces: [] enforced_by: [] @@ -1274,6 +1277,70 @@ entities: extraction_phase: extract_adr classification: explicit generator: adr-architecture-index + - id: ADR-L-0022 + entity_type: adr + name: Workspace Attribution Federation Consumption + summary: >- + Per-repo RECON emits implementation-attribution-evidence.yaml with bare ADR-L-XXXX ids scoped to each repository + manifest. The same bare id string may denote different decisions in different repos (for example ADR-L-0013 + lifecycle_stage: active + admission_status: admitted + canonical_source: + source_type: logical_adr + source_ref: ADR-L-0022 + artifact_path: adrs/logical/ADR-L-0022-workspace-attribution-federation-consumption.yaml + source_refs: [] + metadata: + status: accepted + domains: + - workspace + - federation + - attribution + tags: + - workspace + - federation + - qualified-id + - attribution + related_reviews: [] + related_overrides: [] + relationships: + declared_in: [] + declares: + - DEC-0024 + - INV-0033 + - INV-0034 + references: + - ADR-L-0009 + - ADR-L-0016 + - ADR-L-0017 + referenced_by: [] + related_to: [] + enforces: [] + enforced_by: [] + enabled_by: [] + enables: [] + governs: [] + governed_by: [] + implemented_by: [] + implements: [] + embodied_in: [] + embodies: [] + supersedes: [] + superseded_by: [] + refines: [] + refined_by: [] + contradicts: [] + rejects: [] + rejected_by: [] + completeness: + status: complete + missing_fields: [] + provenance: + source_type: logical_adr + source_ref: ADR-L-0022 + extraction_phase: extract_adr + classification: explicit + generator: adr-architecture-index - id: ADR-P-0001 entity_type: adr name: RSS CLI Implementation for Developer-Invoked Graph Traversal @@ -4970,6 +5037,61 @@ entities: extraction_phase: extract_decision classification: explicit generator: adr-architecture-index + - id: DEC-0024 + entity_type: decision + name: ste-runtime orchestrates workspace federation via adr-kit CLI after workspace RECON + summary: >- + Federation merge logic lives in adr-architecture-kit as single authority; ste-runtime must not duplicate merge in + TypeScript. + lifecycle_stage: active + admission_status: admitted + canonical_source: + source_type: logical_adr + source_ref: ADR-L-0022#DEC-0024 + artifact_path: adrs/logical/ADR-L-0022-workspace-attribution-federation-consumption.yaml + source_refs: [] + metadata: + adr_id: ADR-L-0022 + related_invariants: [] + enforces_invariants: [] + enables_capabilities: [] + governs_components: [] + supersedes: [] + refines: [] + contradicts: [] + relationships: + declared_in: + - ADR-L-0022 + declares: [] + references: [] + referenced_by: [] + related_to: [] + enforces: [] + enforced_by: [] + enabled_by: [] + enables: [] + governs: [] + governed_by: [] + implemented_by: [] + implements: [] + embodied_in: [] + embodies: [] + supersedes: [] + superseded_by: [] + refines: [] + refined_by: [] + contradicts: [] + rejects: [] + rejected_by: [] + completeness: + status: complete + missing_fields: [] + provenance: + source_type: logical_adr + source_ref: ADR-L-0022#DEC-0024 + extraction_phase: extract_decision + classification: explicit + generator: adr-architecture-index - id: INV-0001 entity_type: invariant name: INV-0001 @@ -6654,6 +6776,116 @@ entities: extraction_phase: assign_canonical_invariant classification: explicit generator: adr-architecture-index + - id: INV-0033 + entity_type: invariant + name: INV-0033 + summary: >- + Workspace attribution federation MUST NOT mutate per-repo attribution evidence or ADR corpora; it only reads state + and manifests to emit a derived index. + lifecycle_stage: active + admission_status: admitted + canonical_source: + source_type: logical_adr + source_ref: ADR-L-0022#INV-0033 + artifact_path: adrs/logical/ADR-L-0022-workspace-attribution-federation-consumption.yaml + source_refs: [] + metadata: + adr_id: ADR-L-0022 + scope: global + statement: |- + Workspace attribution federation MUST NOT mutate per-repo attribution evidence + or ADR corpora; it only reads state and manifests to emit a derived index. + enforcement_level: must + declaration_mode: local + upheld_by_decisions: [] + relationships: + declared_in: + - ADR-L-0022 + declares: [] + references: [] + referenced_by: [] + related_to: [] + enforces: [] + enforced_by: [] + enabled_by: [] + enables: [] + governs: [] + governed_by: [] + implemented_by: [] + implements: [] + embodied_in: [] + embodies: [] + supersedes: [] + superseded_by: [] + refines: [] + refined_by: [] + contradicts: [] + rejects: [] + rejected_by: [] + completeness: + status: complete + missing_fields: [] + provenance: + source_type: logical_adr + source_ref: ADR-L-0022#INV-0033 + extraction_phase: assign_canonical_invariant + classification: explicit + generator: adr-architecture-index + - id: INV-0034 + entity_type: invariant + name: INV-0034 + summary: >- + Federation embodiment counts MUST be computed per qualified_id only; bare ADR ids shared across repos MUST NOT + have embodiment counts summed across corpora. + lifecycle_stage: active + admission_status: admitted + canonical_source: + source_type: logical_adr + source_ref: ADR-L-0022#INV-0034 + artifact_path: adrs/logical/ADR-L-0022-workspace-attribution-federation-consumption.yaml + source_refs: [] + metadata: + adr_id: ADR-L-0022 + scope: global + statement: |- + Federation embodiment counts MUST be computed per qualified_id only; bare ADR + ids shared across repos MUST NOT have embodiment counts summed across corpora. + enforcement_level: must + declaration_mode: local + upheld_by_decisions: [] + relationships: + declared_in: + - ADR-L-0022 + declares: [] + references: [] + referenced_by: [] + related_to: [] + enforces: [] + enforced_by: [] + enabled_by: [] + enables: [] + governs: [] + governed_by: [] + implemented_by: [] + implements: [] + embodied_in: [] + embodies: [] + supersedes: [] + superseded_by: [] + refines: [] + refined_by: [] + contradicts: [] + rejects: [] + rejected_by: [] + completeness: + status: complete + missing_fields: [] + provenance: + source_type: logical_adr + source_ref: ADR-L-0022#INV-0034 + extraction_phase: assign_canonical_invariant + classification: explicit + generator: adr-architecture-index - id: SYS-0001 entity_type: system name: Runtime Orchestration and Assistant Integration diff --git a/adrs/index/invariant-registry.yaml b/adrs/index/invariant-registry.yaml index d39947c..07c43e4 100644 --- a/adrs/index/invariant-registry.yaml +++ b/adrs/index/invariant-registry.yaml @@ -1685,3 +1685,113 @@ entities: extraction_phase: assign_canonical_invariant classification: explicit generator: adr-architecture-index + - id: INV-0033 + entity_type: invariant + name: INV-0033 + summary: >- + Workspace attribution federation MUST NOT mutate per-repo attribution evidence or ADR corpora; it only reads state + and manifests to emit a derived index. + lifecycle_stage: active + admission_status: admitted + canonical_source: + source_type: logical_adr + source_ref: ADR-L-0022#INV-0033 + artifact_path: adrs/logical/ADR-L-0022-workspace-attribution-federation-consumption.yaml + source_refs: [] + metadata: + adr_id: ADR-L-0022 + scope: global + statement: |- + Workspace attribution federation MUST NOT mutate per-repo attribution evidence + or ADR corpora; it only reads state and manifests to emit a derived index. + enforcement_level: must + declaration_mode: local + upheld_by_decisions: [] + relationships: + declared_in: + - ADR-L-0022 + declares: [] + references: [] + referenced_by: [] + related_to: [] + enforces: [] + enforced_by: [] + enabled_by: [] + enables: [] + governs: [] + governed_by: [] + implemented_by: [] + implements: [] + embodied_in: [] + embodies: [] + supersedes: [] + superseded_by: [] + refines: [] + refined_by: [] + contradicts: [] + rejects: [] + rejected_by: [] + completeness: + status: complete + missing_fields: [] + provenance: + source_type: logical_adr + source_ref: ADR-L-0022#INV-0033 + extraction_phase: assign_canonical_invariant + classification: explicit + generator: adr-architecture-index + - id: INV-0034 + entity_type: invariant + name: INV-0034 + summary: >- + Federation embodiment counts MUST be computed per qualified_id only; bare ADR ids shared across repos MUST NOT + have embodiment counts summed across corpora. + lifecycle_stage: active + admission_status: admitted + canonical_source: + source_type: logical_adr + source_ref: ADR-L-0022#INV-0034 + artifact_path: adrs/logical/ADR-L-0022-workspace-attribution-federation-consumption.yaml + source_refs: [] + metadata: + adr_id: ADR-L-0022 + scope: global + statement: |- + Federation embodiment counts MUST be computed per qualified_id only; bare ADR + ids shared across repos MUST NOT have embodiment counts summed across corpora. + enforcement_level: must + declaration_mode: local + upheld_by_decisions: [] + relationships: + declared_in: + - ADR-L-0022 + declares: [] + references: [] + referenced_by: [] + related_to: [] + enforces: [] + enforced_by: [] + enabled_by: [] + enables: [] + governs: [] + governed_by: [] + implemented_by: [] + implements: [] + embodied_in: [] + embodies: [] + supersedes: [] + superseded_by: [] + refines: [] + refined_by: [] + contradicts: [] + rejects: [] + rejected_by: [] + completeness: + status: complete + missing_fields: [] + provenance: + source_type: logical_adr + source_ref: ADR-L-0022#INV-0034 + extraction_phase: assign_canonical_invariant + classification: explicit + generator: adr-architecture-index diff --git a/adrs/index/relationship-registry.yaml b/adrs/index/relationship-registry.yaml index db06213..b91a89b 100644 --- a/adrs/index/relationship-registry.yaml +++ b/adrs/index/relationship-registry.yaml @@ -451,6 +451,16 @@ relationships: canonical_source_ref: ADR-L-0021#DEC-0023 confidence: 1 metadata: {} + - relationship_id: declared_in:DEC-0024:ADR-L-0022 + relationship_type: declared_in + from_entity_id: DEC-0024 + to_entity_id: ADR-L-0022 + provenance_classification: explicit + evidence: + - ADR-L-0022#DEC-0024 + canonical_source_ref: ADR-L-0022#DEC-0024 + confidence: 1 + metadata: {} - relationship_id: declared_in:INV-0001:ADR-L-0001 relationship_type: declared_in from_entity_id: INV-0001 @@ -761,6 +771,26 @@ relationships: canonical_source_ref: ADR-L-0021#INV-0032 confidence: 1 metadata: {} + - relationship_id: declared_in:INV-0033:ADR-L-0022 + relationship_type: declared_in + from_entity_id: INV-0033 + to_entity_id: ADR-L-0022 + provenance_classification: explicit + evidence: + - ADR-L-0022#INV-0033 + canonical_source_ref: ADR-L-0022#INV-0033 + confidence: 1 + metadata: {} + - relationship_id: declared_in:INV-0034:ADR-L-0022 + relationship_type: declared_in + from_entity_id: INV-0034 + to_entity_id: ADR-L-0022 + provenance_classification: explicit + evidence: + - ADR-L-0022#INV-0034 + canonical_source_ref: ADR-L-0022#INV-0034 + confidence: 1 + metadata: {} - relationship_id: declared_in:SYS-0001:ADR-PS-0001 relationship_type: declared_in from_entity_id: SYS-0001 @@ -1421,6 +1451,36 @@ relationships: canonical_source_ref: ADR-L-0021#INV-0032 confidence: 1 metadata: {} + - relationship_id: declares:ADR-L-0022:DEC-0024 + relationship_type: declares + from_entity_id: ADR-L-0022 + to_entity_id: DEC-0024 + provenance_classification: derived + evidence: + - ADR-L-0022#DEC-0024 + canonical_source_ref: ADR-L-0022#DEC-0024 + confidence: 1 + metadata: {} + - relationship_id: declares:ADR-L-0022:INV-0033 + relationship_type: declares + from_entity_id: ADR-L-0022 + to_entity_id: INV-0033 + provenance_classification: derived + evidence: + - ADR-L-0022#INV-0033 + canonical_source_ref: ADR-L-0022#INV-0033 + confidence: 1 + metadata: {} + - relationship_id: declares:ADR-L-0022:INV-0034 + relationship_type: declares + from_entity_id: ADR-L-0022 + to_entity_id: INV-0034 + provenance_classification: derived + evidence: + - ADR-L-0022#INV-0034 + canonical_source_ref: ADR-L-0022#INV-0034 + confidence: 1 + metadata: {} - relationship_id: declares:ADR-PC-0001:COMP-0001 relationship_type: declares from_entity_id: ADR-PC-0001 @@ -2331,6 +2391,16 @@ relationships: canonical_source_ref: ADR-L-0019 confidence: 1 metadata: {} + - relationship_id: referenced_by:ADR-L-0009:ADR-L-0022 + relationship_type: referenced_by + from_entity_id: ADR-L-0009 + to_entity_id: ADR-L-0022 + provenance_classification: derived + evidence: + - ADR-L-0022 + canonical_source_ref: ADR-L-0022 + confidence: 1 + metadata: {} - relationship_id: referenced_by:ADR-L-0012:ADR-L-0016 relationship_type: referenced_by from_entity_id: ADR-L-0012 @@ -2431,6 +2501,16 @@ relationships: canonical_source_ref: ADR-L-0021 confidence: 1 metadata: {} + - relationship_id: referenced_by:ADR-L-0016:ADR-L-0022 + relationship_type: referenced_by + from_entity_id: ADR-L-0016 + to_entity_id: ADR-L-0022 + provenance_classification: derived + evidence: + - ADR-L-0022 + canonical_source_ref: ADR-L-0022 + confidence: 1 + metadata: {} - relationship_id: referenced_by:ADR-L-0017:ADR-L-0020 relationship_type: referenced_by from_entity_id: ADR-L-0017 @@ -2441,6 +2521,16 @@ relationships: canonical_source_ref: ADR-L-0020 confidence: 1 metadata: {} + - relationship_id: referenced_by:ADR-L-0017:ADR-L-0022 + relationship_type: referenced_by + from_entity_id: ADR-L-0017 + to_entity_id: ADR-L-0022 + provenance_classification: derived + evidence: + - ADR-L-0022 + canonical_source_ref: ADR-L-0022 + confidence: 1 + metadata: {} - relationship_id: referenced_by:ADR-L-0018:ADR-L-0019 relationship_type: referenced_by from_entity_id: ADR-L-0018 @@ -2781,6 +2871,36 @@ relationships: canonical_source_ref: ADR-L-0021 confidence: 1 metadata: {} + - relationship_id: references:ADR-L-0022:ADR-L-0009 + relationship_type: references + from_entity_id: ADR-L-0022 + to_entity_id: ADR-L-0009 + provenance_classification: explicit + evidence: + - ADR-L-0022 + canonical_source_ref: ADR-L-0022 + confidence: 1 + metadata: {} + - relationship_id: references:ADR-L-0022:ADR-L-0016 + relationship_type: references + from_entity_id: ADR-L-0022 + to_entity_id: ADR-L-0016 + provenance_classification: explicit + evidence: + - ADR-L-0022 + canonical_source_ref: ADR-L-0022 + confidence: 1 + metadata: {} + - relationship_id: references:ADR-L-0022:ADR-L-0017 + relationship_type: references + from_entity_id: ADR-L-0022 + to_entity_id: ADR-L-0017 + provenance_classification: explicit + evidence: + - ADR-L-0022 + canonical_source_ref: ADR-L-0022 + confidence: 1 + metadata: {} - relationship_id: related_to:ADR-PC-0001:ADR-PS-0001 relationship_type: related_to from_entity_id: ADR-PC-0001 diff --git a/adrs/logical/ADR-L-0022-workspace-attribution-federation-consumption.yaml b/adrs/logical/ADR-L-0022-workspace-attribution-federation-consumption.yaml new file mode 100644 index 0000000..4fe9adb --- /dev/null +++ b/adrs/logical/ADR-L-0022-workspace-attribution-federation-consumption.yaml @@ -0,0 +1,74 @@ +schema_version: '1.0' +adr_type: logical +id: ADR-L-0022 +title: Workspace Attribution Federation Consumption +status: accepted +created_date: '2026-06-02' +authors: +- erik.gallmann +domains: +- workspace +- federation +- attribution +tags: +- workspace +- federation +- qualified-id +- attribution +vision_category: false +related_adrs: +- ADR-L-0009 +- ADR-L-0016 +- ADR-L-0017 +context: | + Per-repo RECON emits implementation-attribution-evidence.yaml with bare + ADR-L-XXXX ids scoped to each repository manifest. The same bare id string + may denote different decisions in different repos (for example ADR-L-0013 in + adr-architecture-kit vs ste-runtime). + + Federation authority and qualified identity are defined in + adr-architecture-kit ADR-L-0012 (accepted). ste-runtime consumes that model + at the workspace boundary: after workspace RECON completes for all manifest + repos, it invokes adr-architecture-kit `adr attribution workspace-report` to + write a derived `.ste-workspace/workspace-attribution-federation.yaml` keyed + by `{workspaceRepoKey}:{bareAdrId}`. + + This artifact is derived state, not canonical architecture authority. Per-repo + attribution validation (`adr attribution check --scope `) is unchanged. +invariants: +- id: INV-0033 + statement: | + Workspace attribution federation MUST NOT mutate per-repo attribution evidence + or ADR corpora; it only reads state and manifests to emit a derived index. + scope: global + enforcement_level: must + enforcement_mechanism: design + verification_method: automated + rationale: | + Aligns with federation read-only aggregation (adr-architecture-kit ADR-L-0012). +- id: INV-0034 + statement: | + Federation embodiment counts MUST be computed per qualified_id only; bare ADR + ids shared across repos MUST NOT have embodiment counts summed across corpora. + scope: global + enforcement_level: must + enforcement_mechanism: test + verification_method: automated + rationale: | + Prevents homonym collapse at workspace reasoning time. +decisions: +- id: DEC-0024 + summary: ste-runtime orchestrates workspace federation via adr-kit CLI after workspace RECON + rationale: | + Federation merge logic lives in adr-architecture-kit as single authority; + ste-runtime must not duplicate merge in TypeScript. + decision: | + executeWorkspaceRecon invokes `adr attribution workspace-report + --workspace-root <.ste-workspace>` after all per-repo RECON completes. + Output path is `.ste-workspace/workspace-attribution-federation.yaml`. +consequences: + positive: + - Cross-repo ADR traceability without qualified decorators in source + - Complementary embodiment on shared bare ids remains visible as separate clusters + negative: + - Workspace runs require adr-architecture-kit on PATH or documented venv diff --git a/adrs/manifest.yaml b/adrs/manifest.yaml index b883f37..8a59849 100644 --- a/adrs/manifest.yaml +++ b/adrs/manifest.yaml @@ -1,6 +1,6 @@ schema_version: '1.0' type: manifest -generated_date: '2026-05-30T19:23:29Z' +generated_date: '2026-06-02T04:30:56Z' generated_from: adrs/**/*.yaml adrs: - id: ADR-L-0001 @@ -476,6 +476,30 @@ adrs: related_reviews: [] related_overrides: [] related_ledgers: [] + - id: ADR-L-0022 + type: logical + title: Workspace Attribution Federation Consumption + status: accepted + file_path: adrs/logical/ADR-L-0022-workspace-attribution-federation-consumption.yaml + domains: + - workspace + - federation + - attribution + tags: + - workspace + - federation + - qualified-id + - attribution + implements_logical: [] + technologies: [] + decision_count: 1 + invariant_count: 2 + gap_count: 0 + blocking_gaps: 0 + component_count: 0 + related_reviews: [] + related_overrides: [] + related_ledgers: [] - id: ADR-P-0001 type: physical title: RSS CLI Implementation for Developer-Invoked Graph Traversal @@ -1025,14 +1049,14 @@ gaps_summary: blocking: 0 by_adr: {} statistics: - total_adrs: 38 - logical_adrs: 20 + total_adrs: 39 + logical_adrs: 21 physical_adrs: 5 physical_system_adrs: 2 physical_component_adrs: 11 decision_adrs: 0 - total_decisions: 22 - total_invariants: 31 + total_decisions: 23 + total_invariants: 33 total_components: 19 total_gaps: 4 blocking_gaps: 0 diff --git a/docs/workspace-adr-federation.md b/docs/workspace-adr-federation.md new file mode 100644 index 0000000..d0f8942 --- /dev/null +++ b/docs/workspace-adr-federation.md @@ -0,0 +1,58 @@ +# Workspace ADR federation + +**Status:** Implemented (ADR-L-0022 consumption; adr-kit ADR-L-0012 authority) +**Artifact:** `.ste-workspace/workspace-attribution-federation.yaml` (derived) + +**AI / builder orientation (full context):** [docs/ai-orientation-workspace-attribution-federation.md](../../docs/ai-orientation-workspace-attribution-federation.md) + +## Problem + +Each repository maintains its own `adrs/manifest.yaml` and per-repo +`implementation-attribution-evidence.yaml` with **bare** `ADR-L-XXXX` ids. +The same bare id in two repos (for example `ADR-L-0013` in adr-architecture-kit +vs ste-runtime) denotes **different decisions**. Per-repo `adr attribution check` +is correct locally; workspace-wide reasoning must not collapse homonyms. + +## Qualified identity + +| Field | Format | +|-------|--------| +| `qualified_id` | `{workspaceRepoKey}:{bareAdrId}` e.g. `ste-runtime:ADR-L-0013` | +| `workspaceRepoKey` | `name` from root `workspace.yaml` `repos[]` | + +Bare `implements_adr('ADR-L-XXXX')` in source remains valid within each repo. + +## Traceability workflow + +1. **Manifest** — `adrs/manifest.yaml` in the **named repo** (confirm id + title). +2. **ADR YAML** — canonical intent for that repo only. +3. **Attribution** — `.ste-workspace/state/{repo}/attribution/implementation-attribution-evidence.yaml`. +4. **Cross-repo** — `.ste-workspace/workspace-attribution-federation.yaml` (homonym groups + per-qualified embodiment). + +Shortcut: `adr attribution workspace-report --workspace-root `. + +## Entity URIs (locator registry) + +Architecture entities (ADR, decision, invariant) use **repo-qualified** URIs: + +- `entity://ste-runtime/ADR-L-0013` + +Infra/graph slice nodes continue to use workspace-scoped URIs: + +- `entity://workspace/Lambda%3Arepo%3Afn` + +## Authority split + +| Component | Role | +|-----------|------| +| [ADR-L-0012](../../adr-architecture-kit/adrs/logical/ADR-L-0012-federation-authority-and-qualified-identity.yaml) (kit) | Federation + qualified identity doctrine | +| [ADR-L-0022](../adrs/logical/ADR-L-0022-workspace-attribution-federation-consumption.yaml) (ste-runtime) | Orchestrates `workspace-report` after `recon:workspace` | +| `build_workspace_attribution_federation` (adr-kit) | Single merge implementation | + +Requires `adr` CLI on PATH (or `ADR_CLI`) from adr-architecture-kit. + +## Non-goals + +- Global ADR renumbering across repos. +- Qualified decorators in source (`ste-runtime:ADR-L-XXXX` in `@implements_adr`). +- Feeding federation YAML into per-repo `architectureMerge` (single-corpus only). diff --git a/src/architecture/architecture-merge.test.ts b/src/architecture/architecture-merge.test.ts new file mode 100644 index 0000000..b5c5915 --- /dev/null +++ b/src/architecture/architecture-merge.test.ts @@ -0,0 +1,80 @@ +import { describe, expect, it } from 'vitest'; + +import { architectureMerge, emptyReconSnapshot } from './architecture-merge.js'; +import { emptyRelationshipBuckets, type ArchModelState, type IrEntity } from './types.js'; + +function adrEntity(id: string): IrEntity { + return { + id, + entity_type: 'adr', + name: id, + summary: '', + canonical_source: { + source_type: 'logical_adr', + source_ref: id, + artifact_path: `adrs/logical/${id}.yaml`, + }, + source_refs: [], + metadata: {}, + completeness: { status: 'complete', missing_fields: [] }, + provenance: { + source_type: 'adr', + source_ref: id, + extraction_phase: 'test', + classification: 'explicit', + generator: 'test', + }, + relationships: emptyRelationshipBuckets(), + }; +} + +function minimalModel(entities: IrEntity[]): ArchModelState { + const map = new Map(); + for (const e of entities) map.set(e.id, e); + return { + scopeRoot: '.', + namespace: 'test', + generatedAt: '2026-01-01T00:00:00.000Z', + entities: map, + relationships: new Map(), + unresolved: new Map(), + coverage: { + logical_adrs: 0, + physical_adrs: 0, + physical_system_adrs: 0, + physical_component_adrs: 0, + standalone_invariants: 0, + }, + corpus: new Map(), + logicalAdrs: [], + adrGraph: { nodes: [], edges: [] }, + }; +} + +describe('architectureMerge', () => { + it('keys embodiment by bare adr id within a single corpus only', () => { + const merged = architectureMerge(minimalModel([adrEntity('ADR-L-0013')]), { + version: '1', + attribution_records: [ + { + implementation_entity_id: 'function:a:one:1', + attributed_adrs: ['ADR-L-0013'], + enforced_invariants: [], + }, + { + implementation_entity_id: 'function:b:one:1', + attributed_adrs: ['ADR-L-0013'], + enforced_invariants: [], + }, + ], + }); + + expect(merged.entities.get('ADR-L-0013')?.metadata.embodiment_count).toBe(2); + expect(merged.entities.get('ADR-L-0013')?.metadata.attributed_code_slices).toHaveLength(2); + }); + + it('does not consume workspace federation artifacts (empty snapshot is no-op)', () => { + const merged = architectureMerge(minimalModel([adrEntity('ADR-L-0013')]), emptyReconSnapshot); + expect(merged.entities.get('ADR-L-0013')?.metadata.embodiment_count).toBeUndefined(); + }); +}); diff --git a/src/provenance/retrofit-contract-guards.test.ts b/src/provenance/retrofit-contract-guards.test.ts index 520dd8c..7dd5398 100644 --- a/src/provenance/retrofit-contract-guards.test.ts +++ b/src/provenance/retrofit-contract-guards.test.ts @@ -52,6 +52,7 @@ import { validateSlice } from '../workspace/slice-schema.js'; import { normalizePortablePath, workspaceUri } from '../workspace/source-uri.js'; import { emitWorkspaceIndex } from '../workspace/workspace-index.js'; import { loadWorkspaceGraph } from '../workspace/workspace-graph-loader.js'; +import { runWorkspaceAttributionFederation } from '../workspace/workspace-attribution-federation.js'; import { executeWorkspaceRecon } from '../workspace/workspace-recon.js'; import { ADR_ID_PATTERN, @@ -103,9 +104,15 @@ describe('attribution retrofit contract guards', () => { const adrIds = functionAdrMetadata(executeWorkspaceRecon); expect(adrIds).toContain('ADR-L-0017'); expect(adrIds).toContain('ADR-L-0009'); + expect(adrIds).toContain('ADR-L-0022'); expectAdrClaims(executeWorkspaceRecon, 'ADR-L-0017', ['INV-0019']); }); + it('ADR-L-0022: workspace attribution federation', () => { + expectAdrClaims(runWorkspaceAttributionFederation, 'ADR-L-0022'); + expectAdrSourceExists('ADR-L-0022', 'adrs/logical/ADR-L-0022-workspace-attribution-federation-consumption.yaml'); + }); + it('ADR-L-0016: slice schema contract', () => { expectAdrClaims(emitWorkspaceSlice, 'ADR-L-0016', ['INV-0017', 'INV-0025']); expectAdrClaims(validateSlice, 'ADR-L-0016', ['INV-0017', 'INV-0018']); diff --git a/src/workspace/source-locator-registry.test.ts b/src/workspace/source-locator-registry.test.ts index e235e42..0b2054b 100644 --- a/src/workspace/source-locator-registry.test.ts +++ b/src/workspace/source-locator-registry.test.ts @@ -128,5 +128,64 @@ describe('SourceLocatorRegistry', () => { expect(resolveLocator(registry, 'adr://ADR-L-0001')?.source_uri).toBe( 'workspace://repoA/adrs/logical/ADR-L-0001-test.yaml', ); + expect(resolveLocator(registry, 'entity://repoA/ADR-L-0001')?.source_uri).toBe( + 'workspace://repoA/adrs/logical/ADR-L-0001-test.yaml', + ); + expect(registry.locators.find(l => l.entity_id === 'ADR-L-0001')?.entity_uri).toBe( + 'entity://repoA/ADR-L-0001', + ); + }); + + it('uses distinct repo-qualified entity URIs for homonymous ADR ids across repos', async () => { + for (const repoName of ['repoA', 'repoB', 'repoC']) { + await mkdir(path.join(tmpDir, repoName, 'adrs', 'index'), { recursive: true }); + await mkdir(path.join(tmpDir, repoName, 'adrs', 'logical'), { recursive: true }); + await writeFile( + path.join(tmpDir, repoName, 'adrs', 'logical', 'ADR-L-0012-test.yaml'), + 'id: ADR-L-0012\n', + 'utf-8', + ); + await writeFile( + path.join(tmpDir, repoName, 'adrs', 'index', 'entity-registry.yaml'), + yaml.dump({ + schema_version: '1.1', + type: 'normalized_entity_registry', + entities: [ + { + id: 'ADR-L-0012', + entity_type: 'adr', + name: `ADR in ${repoName}`, + canonical_source: { + source_type: 'logical_adr', + source_ref: 'ADR-L-0012', + artifact_path: 'adrs/logical/ADR-L-0012-test.yaml', + }, + }, + ], + }), + 'utf-8', + ); + } + + await emitSourceLocatorRegistry({ + outputDir: path.join(tmpDir, 'out'), + workspaceRoot: tmpDir, + repos: [ + { name: 'repoA', path: 'repoA' }, + { name: 'repoB', path: 'repoB' }, + { name: 'repoC', path: 'repoC' }, + ], + graphSnapshotHash: 'sha256:graph', + workspaceManifestHash: 'sha256:manifest', + generatedAt: '2026-01-01T00:00:00.000Z', + generatedBy: 'test', + }); + + const registry = await loadSourceLocatorRegistry(path.join(tmpDir, 'out')); + const adrLocators = registry.locators.filter(l => l.entity_id === 'ADR-L-0012'); + expect(adrLocators).toHaveLength(3); + const uris = new Set(adrLocators.map(l => l.entity_uri)); + expect(uris).toEqual(new Set(['entity://repoA/ADR-L-0012', 'entity://repoB/ADR-L-0012', 'entity://repoC/ADR-L-0012'])); + expect(uris.has('entity://workspace/ADR-L-0012')).toBe(false); }); }); diff --git a/src/workspace/source-locator-registry.ts b/src/workspace/source-locator-registry.ts index d64b4b3..649e787 100644 --- a/src/workspace/source-locator-registry.ts +++ b/src/workspace/source-locator-registry.ts @@ -3,7 +3,7 @@ import fs from 'node:fs/promises'; import path from 'node:path'; import yaml from 'js-yaml'; -import { entityUri, parseSourceUri, workspaceUri, type LineRange } from './source-uri.js'; +import { parseSourceUri, resolveEntityUri, workspaceUri, type LineRange } from './source-uri.js'; import { enforces_invariant, implements_adr } from '../architecture/intent-decorators.js'; export interface SourceLocator { @@ -120,7 +120,7 @@ function locatorForNode( return null; } return { - entity_uri: node.entity_uri ?? entityUri(node.id), + entity_uri: node.entity_uri ?? resolveEntityUri(repo, node.id, node.type), entity_id: node.id, entity_type: node.type, source_uri: sourceUri, @@ -180,7 +180,7 @@ async function locatorsFromArchitectureRegistry( try { const sourceHash = await computeFileHash(path.resolve(repoRoot, sourcePath)); locators.push({ - entity_uri: entityUri(entity.id), + entity_uri: resolveEntityUri(repo, entity.id, entity.entity_type), entity_id: entity.id, entity_type: entity.entity_type, source_uri: workspaceUri(repo, sourcePath), @@ -271,7 +271,13 @@ export function resolveLocator( const parsed = parseSourceUri(entityOrUri); switch (parsed.kind) { case 'entity': - return registry.locators.find(l => l.entity_id === parsed.entityId || l.entity_uri === entityOrUri); + return registry.locators.find(l => { + if (l.entity_uri === entityOrUri) return true; + if (parsed.repo) { + return l.repo === parsed.repo && l.entity_id === parsed.entityId; + } + return l.entity_id === parsed.entityId; + }); case 'workspace': return registry.locators.find(l => l.repo === parsed.repo && l.path === parsed.path); case 'adr': diff --git a/src/workspace/source-uri.test.ts b/src/workspace/source-uri.test.ts index 39351f6..00edc2c 100644 --- a/src/workspace/source-uri.test.ts +++ b/src/workspace/source-uri.test.ts @@ -2,8 +2,10 @@ import { describe, expect, it } from 'vitest'; import { entityUri, + entityUriForRepo, normalizeWorkspaceUri, parseSourceUri, + resolveEntityUri, workspaceUri, } from './source-uri.js'; @@ -36,4 +38,19 @@ describe('source URI normalization', () => { it('normalizes entity URIs with segment encoding', () => { expect(entityUri('Lambda:repo:my function')).toBe('entity://workspace/Lambda%3Arepo%3Amy%20function'); }); + + it('builds repo-qualified entity URIs for architecture entities', () => { + expect(entityUriForRepo('ste-runtime', 'ADR-L-0013')).toBe('entity://ste-runtime/ADR-L-0013'); + expect(parseSourceUri('entity://ste-runtime/ADR-L-0013')).toEqual({ + kind: 'entity', + entityId: 'ADR-L-0013', + repo: 'ste-runtime', + }); + expect(resolveEntityUri('adr-architecture-kit', 'ADR-L-0012', 'adr')).toBe( + 'entity://adr-architecture-kit/ADR-L-0012', + ); + expect(resolveEntityUri('repoA', 'Lambda:repoA:fn', 'Lambda')).toBe( + 'entity://workspace/Lambda%3ArepoA%3Afn', + ); + }); }); diff --git a/src/workspace/source-uri.ts b/src/workspace/source-uri.ts index b73d5c1..9124c05 100644 --- a/src/workspace/source-uri.ts +++ b/src/workspace/source-uri.ts @@ -7,8 +7,8 @@ export interface LineRange { export type ParsedSourceUri = | { kind: 'workspace'; repo: string; path: string; lineRange?: LineRange } - | { kind: 'entity'; entityId: string } - | { kind: 'adr'; adrId: string } + | { kind: 'entity'; entityId: string; repo?: string } + | { kind: 'adr'; adrId: string; repo?: string } | { kind: 'decision'; decisionId: string } | { kind: 'graph'; graphSnapshotHash: string; entityId: string } | { kind: 'projection'; family: string; projectionId: string }; @@ -71,6 +71,16 @@ export const workspaceUri: (repo: string, sourcePath: string, lineRange?: LineRa return `workspace://${encodePathSegment(normalizedRepo)}/${encodedPath}${formatLineRange(lineRange)}`; }); +/** Repo-qualified entity URI for architecture entities (ADR, decision, invariant). */ +export function entityUriForRepo(repo: string, entityId: string): string { + const trimmed = entityId.trim(); + if (!trimmed) { + throw new Error('Entity URI id must be non-empty'); + } + return `entity://${encodePathSegment(normalizeRepo(repo))}/${encodePathSegment(trimmed)}`; +} + +/** Workspace-scoped entity URI for infra/graph nodes (legacy). */ export function entityUri(entityId: string): string { const trimmed = entityId.trim(); if (!trimmed) { @@ -79,6 +89,21 @@ export function entityUri(entityId: string): string { return `entity://workspace/${encodePathSegment(trimmed)}`; } +export function resolveEntityUri(repo: string, entityId: string, entityType: string): string { + const type = entityType.toLowerCase(); + if ( + type === 'adr' || + type === 'decision' || + type === 'invariant' || + /^ADR-[LP]/.test(entityId) || + /^DEC-/.test(entityId) || + /^INV-/.test(entityId) + ) { + return entityUriForRepo(repo, entityId); + } + return entityUri(entityId); +} + function parseLineRange(fragment: string): LineRange | undefined { if (!fragment) return undefined; const match = fragment.match(/^L(\d+)-L(\d+)$/); @@ -117,14 +142,36 @@ export function parseSourceUri(uriOrId: string): ParsedSourceUri { } return parsed; } - if (value.startsWith('entity://workspace/')) { - return { - kind: 'entity', - entityId: decodePathSegment(value.slice('entity://workspace/'.length)), - }; + if (value.startsWith('entity://')) { + const withoutScheme = value.slice('entity://'.length); + if (withoutScheme.startsWith('workspace/')) { + return { + kind: 'entity', + entityId: decodePathSegment(withoutScheme.slice('workspace/'.length)), + }; + } + const slashIdx = withoutScheme.indexOf('/'); + if (slashIdx >= 1) { + const repo = decodePathSegment(withoutScheme.slice(0, slashIdx)); + const entityId = decodePathSegment(withoutScheme.slice(slashIdx + 1)); + return { + kind: 'entity', + entityId, + repo: normalizeRepo(repo), + }; + } } if (value.startsWith('adr://')) { - return { kind: 'adr', adrId: value.slice('adr://'.length) }; + const body = value.slice('adr://'.length); + const colonIdx = body.indexOf(':'); + if (colonIdx > 0 && body.indexOf('/', colonIdx) < 0) { + const maybeRepo = body.slice(0, colonIdx); + const maybeId = body.slice(colonIdx + 1); + if (/^ADR-[LP]/.test(maybeId)) { + return { kind: 'adr', adrId: maybeId, repo: normalizeRepo(maybeRepo) }; + } + } + return { kind: 'adr', adrId: body }; } if (value.startsWith('decision://')) { return { kind: 'decision', decisionId: value.slice('decision://'.length) }; diff --git a/src/workspace/workspace-attribution-federation.test.ts b/src/workspace/workspace-attribution-federation.test.ts new file mode 100644 index 0000000..13e4e52 --- /dev/null +++ b/src/workspace/workspace-attribution-federation.test.ts @@ -0,0 +1,39 @@ +import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; +import { mkdtemp, rm, writeFile, mkdir } from 'node:fs/promises'; +import os from 'node:os'; +import path from 'node:path'; + +import { runWorkspaceAttributionFederation } from './workspace-attribution-federation.js'; + +vi.mock('execa', () => ({ + execa: vi.fn(async () => ({ stdout: 'qualified_adr_count: 2', stderr: '' })), +})); + +describe('runWorkspaceAttributionFederation', () => { + let tmpDir: string; + + beforeEach(async () => { + tmpDir = await mkdtemp(path.join(os.tmpdir(), 'ws-fed-')); + await mkdir(tmpDir, { recursive: true }); + await writeFile( + path.join(tmpDir, 'workspace.yaml'), + 'schema_version: "1.0"\noutput_dir: .ste-workspace/\nrepos: []\n', + 'utf-8', + ); + }); + + afterEach(async () => { + await rm(tmpDir, { recursive: true, force: true }); + vi.clearAllMocks(); + }); + + it('invokes adr attribution workspace-report without throwing', async () => { + const { execa } = await import('execa'); + await expect(runWorkspaceAttributionFederation(tmpDir)).resolves.toBeUndefined(); + expect(execa).toHaveBeenCalledWith( + 'adr', + ['attribution', 'workspace-report', '--workspace-root', path.resolve(tmpDir)], + expect.objectContaining({ cwd: path.resolve(tmpDir) }), + ); + }); +}); diff --git a/src/workspace/workspace-attribution-federation.ts b/src/workspace/workspace-attribution-federation.ts new file mode 100644 index 0000000..d1578d6 --- /dev/null +++ b/src/workspace/workspace-attribution-federation.ts @@ -0,0 +1,33 @@ +import path from 'node:path'; + +import { execa } from 'execa'; + +import { implements_adr } from '../architecture/intent-decorators.js'; +import { log, warn } from '../utils/logger.js'; + +/** + * Invoke adr-architecture-kit to emit workspace-attribution-federation.yaml. + * Federation merge authority lives in adr-kit (ADR-L-0012); ste-runtime orchestrates only. + */ +export const runWorkspaceAttributionFederation: (workspaceRoot: string) => Promise = implements_adr( + 'ADR-L-0022', +)(async function runWorkspaceAttributionFederation(workspaceRoot: string): Promise { + const resolvedRoot = path.resolve(workspaceRoot); + const adrCommand = process.env.ADR_CLI?.trim() || 'adr'; + try { + const { stdout } = await execa( + adrCommand, + ['attribution', 'workspace-report', '--workspace-root', resolvedRoot], + { cwd: resolvedRoot }, + ); + if (stdout.trim()) { + log(`[workspace-recon] Attribution federation: ${stdout.trim().split('\n')[0]}`); + } + } catch (err) { + const message = err instanceof Error ? err.message : String(err); + warn( + `[workspace-recon] Workspace attribution federation failed (non-fatal): ${message}. ` + + 'Ensure adr-architecture-kit is installed and `adr` is on PATH (or set ADR_CLI).', + ); + } +}); diff --git a/src/workspace/workspace-recon.ts b/src/workspace/workspace-recon.ts index 1cd658c..4cc6569 100644 --- a/src/workspace/workspace-recon.ts +++ b/src/workspace/workspace-recon.ts @@ -22,6 +22,7 @@ import type { ProjectionEmitResult } from './emit-projections.js'; import { emitMultiResProjections } from './emit-multi-res-projections.js'; import type { MultiResEmitResult } from './emit-multi-res-projections.js'; import { mergeWorkspaceGraph } from './workspace-merge.js'; +import { runWorkspaceAttributionFederation } from './workspace-attribution-federation.js'; import { emitSourceLocatorRegistry } from './source-locator-registry.js'; export interface WorkspaceReconOptions { @@ -144,6 +145,7 @@ export const executeWorkspaceRecon: ( ) => Promise = implements_adr( 'ADR-L-0017', 'ADR-L-0009', + 'ADR-L-0022', )(enforces_invariant('INV-0019')(async function executeWorkspaceRecon( options: WorkspaceReconOptions, ): Promise { @@ -284,6 +286,13 @@ export const executeWorkspaceRecon: ( const anySuccess = repos.some(r => r.status === 'success' || r.status === 'skipped'); + try { + await runWorkspaceAttributionFederation(workspaceRoot); + } catch (err) { + const msg = err instanceof Error ? err.message : String(err); + log(`[workspace-recon] Attribution federation hook failed (non-fatal): ${msg}`); + } + const allSuccess = repos.every(r => !repoIsFailure(r)); const failedRepos = repos.filter(repoIsFailure); const success = options.failOnAnyError ? allSuccess : anySuccess;