generated from coulomb/repo-seed
Add validation indexes and generated views
This commit is contained in:
19
Makefile
Normal file
19
Makefile
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
PYTHON ?= python3
|
||||||
|
CANON_CLI = PYTHONPATH=src $(PYTHON) -m info_tech_canon
|
||||||
|
|
||||||
|
.PHONY: validate index tree agent-briefs test
|
||||||
|
|
||||||
|
validate:
|
||||||
|
$(CANON_CLI) validate --write infospace/validation/latest.json
|
||||||
|
|
||||||
|
index:
|
||||||
|
$(CANON_CLI) index
|
||||||
|
|
||||||
|
tree:
|
||||||
|
$(CANON_CLI) tree
|
||||||
|
|
||||||
|
agent-briefs:
|
||||||
|
$(CANON_CLI) agent-briefs
|
||||||
|
|
||||||
|
test:
|
||||||
|
$(PYTHON) -m pytest
|
||||||
13
README.md
13
README.md
@@ -21,6 +21,8 @@ PYTHONPATH=src python3 -m info_tech_canon models
|
|||||||
PYTHONPATH=src python3 -m info_tech_canon standards
|
PYTHONPATH=src python3 -m info_tech_canon standards
|
||||||
PYTHONPATH=src python3 -m info_tech_canon validate
|
PYTHONPATH=src python3 -m info_tech_canon validate
|
||||||
PYTHONPATH=src python3 -m info_tech_canon graph
|
PYTHONPATH=src python3 -m info_tech_canon graph
|
||||||
|
PYTHONPATH=src python3 -m info_tech_canon index
|
||||||
|
PYTHONPATH=src python3 -m info_tech_canon views
|
||||||
PYTHONPATH=src python3 -m info_tech_canon api --host 127.0.0.1 --port 8765
|
PYTHONPATH=src python3 -m info_tech_canon api --host 127.0.0.1 --port 8765
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -38,4 +40,15 @@ After package installation, the same commands are available through the
|
|||||||
- `GET /validate`
|
- `GET /validate`
|
||||||
- `GET /graph`
|
- `GET /graph`
|
||||||
- `GET /graph?format=mermaid`
|
- `GET /graph?format=mermaid`
|
||||||
|
- `GET /views`
|
||||||
|
- `GET /views/{name}`
|
||||||
- `GET /profiles/{profile}/inspect`
|
- `GET /profiles/{profile}/inspect`
|
||||||
|
|
||||||
|
## Maintenance
|
||||||
|
|
||||||
|
```bash
|
||||||
|
make validate
|
||||||
|
make index
|
||||||
|
make tree
|
||||||
|
make agent-briefs
|
||||||
|
```
|
||||||
|
|||||||
@@ -108,6 +108,7 @@ planned_directories:
|
|||||||
- infospace/assimilation/
|
- infospace/assimilation/
|
||||||
- infospace/schemas/
|
- infospace/schemas/
|
||||||
- infospace/views/
|
- infospace/views/
|
||||||
|
- infospace/indexes/
|
||||||
- infospace/agent/
|
- infospace/agent/
|
||||||
- infospace/examples/
|
- infospace/examples/
|
||||||
- infospace/validation/
|
- infospace/validation/
|
||||||
|
|||||||
23
infospace/agent/global-agent-brief.md
Normal file
23
infospace/agent/global-agent-brief.md
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
<!-- GENERATED by info_tech_canon; do not edit by hand. -->
|
||||||
|
|
||||||
|
# Global Agent Brief
|
||||||
|
|
||||||
|
This brief summarizes the current canon service surface for agents.
|
||||||
|
|
||||||
|
- Infospace slug: `canon`
|
||||||
|
- Artifact count: 15
|
||||||
|
- Primary confidence command: `make validate`
|
||||||
|
- Refresh generated indexes and views with: `make index`
|
||||||
|
|
||||||
|
## Useful Commands
|
||||||
|
|
||||||
|
- `PYTHONPATH=src python3 -m info_tech_canon inspect`
|
||||||
|
- `PYTHONPATH=src python3 -m info_tech_canon validate`
|
||||||
|
- `PYTHONPATH=src python3 -m info_tech_canon graph`
|
||||||
|
- `PYTHONPATH=src python3 -m info_tech_canon index`
|
||||||
|
|
||||||
|
## Consumption Notes
|
||||||
|
|
||||||
|
- Treat `seeds/` as provenance.
|
||||||
|
- Treat `infospace/` as the service-consumable canon root.
|
||||||
|
- Generated files are marked and can be refreshed deterministically.
|
||||||
3
infospace/indexes/README.md
Normal file
3
infospace/indexes/README.md
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
# Indexes
|
||||||
|
|
||||||
|
Generated machine-readable indexes live here.
|
||||||
153
infospace/indexes/artifact-tree.yaml
Normal file
153
infospace/indexes/artifact-tree.yaml
Normal file
@@ -0,0 +1,153 @@
|
|||||||
|
root: infospace
|
||||||
|
file_count: 50
|
||||||
|
files:
|
||||||
|
- path: README.md
|
||||||
|
directory: .
|
||||||
|
name: README.md
|
||||||
|
- path: agent/README.md
|
||||||
|
directory: agent
|
||||||
|
name: README.md
|
||||||
|
- path: agent/global-agent-brief.md
|
||||||
|
directory: agent
|
||||||
|
name: global-agent-brief.md
|
||||||
|
- path: artifacts/index.yaml
|
||||||
|
directory: artifacts
|
||||||
|
name: index.yaml
|
||||||
|
- path: assimilation/README.md
|
||||||
|
directory: assimilation
|
||||||
|
name: README.md
|
||||||
|
- path: examples/README.md
|
||||||
|
directory: examples
|
||||||
|
name: README.md
|
||||||
|
- path: indexes/README.md
|
||||||
|
directory: indexes
|
||||||
|
name: README.md
|
||||||
|
- path: indexes/artifact-tree.yaml
|
||||||
|
directory: indexes
|
||||||
|
name: artifact-tree.yaml
|
||||||
|
- path: indexes/concept-ownership.yaml
|
||||||
|
directory: indexes
|
||||||
|
name: concept-ownership.yaml
|
||||||
|
- path: indexes/import-matrix.yaml
|
||||||
|
directory: indexes
|
||||||
|
name: import-matrix.yaml
|
||||||
|
- path: infospace.yaml
|
||||||
|
directory: .
|
||||||
|
name: infospace.yaml
|
||||||
|
- path: kernel/InfoTechCanonCore.md
|
||||||
|
directory: kernel
|
||||||
|
name: InfoTechCanonCore.md
|
||||||
|
- path: kernel/InfoTechCanonKernelMap.md
|
||||||
|
directory: kernel
|
||||||
|
name: InfoTechCanonKernelMap.md
|
||||||
|
- path: mappings/README.md
|
||||||
|
directory: mappings
|
||||||
|
name: README.md
|
||||||
|
- path: models/access-control/InfoTechCanonAccessControlModel.md
|
||||||
|
directory: models/access-control
|
||||||
|
name: InfoTechCanonAccessControlModel.md
|
||||||
|
- path: models/data/InfoTechCanonDataModel.md
|
||||||
|
directory: models/data
|
||||||
|
name: InfoTechCanonDataModel.md
|
||||||
|
- path: models/devsecops/InfoTechCanonDevSecOpsModel.md
|
||||||
|
directory: models/devsecops
|
||||||
|
name: InfoTechCanonDevSecOpsModel.md
|
||||||
|
- path: models/governance/InfoTechCanonGovernanceModel.md
|
||||||
|
directory: models/governance
|
||||||
|
name: InfoTechCanonGovernanceModel.md
|
||||||
|
- path: models/information-space/InfoTechCanonInformationSpaceModel.md
|
||||||
|
directory: models/information-space
|
||||||
|
name: InfoTechCanonInformationSpaceModel.md
|
||||||
|
- path: models/landscape/InfoTechCanonLandscapeModel.md
|
||||||
|
directory: models/landscape
|
||||||
|
name: InfoTechCanonLandscapeModel.md
|
||||||
|
- path: models/network/InfoTechCanonNetworkModel.md
|
||||||
|
directory: models/network
|
||||||
|
name: InfoTechCanonNetworkModel.md
|
||||||
|
- path: models/observability/InfoTechCanonObservabilityModel.md
|
||||||
|
directory: models/observability
|
||||||
|
name: InfoTechCanonObservabilityModel.md
|
||||||
|
- path: models/organization/InfoTechCanonOrganizationModel.md
|
||||||
|
directory: models/organization
|
||||||
|
name: InfoTechCanonOrganizationModel.md
|
||||||
|
- path: models/security/InfoTechCanonSecurityModel.md
|
||||||
|
directory: models/security
|
||||||
|
name: InfoTechCanonSecurityModel.md
|
||||||
|
- path: models/task/InfoTechCanonTaskModel.md
|
||||||
|
directory: models/task
|
||||||
|
name: InfoTechCanonTaskModel.md
|
||||||
|
- path: patterns/README.md
|
||||||
|
directory: patterns
|
||||||
|
name: README.md
|
||||||
|
- path: profiles/README.md
|
||||||
|
directory: profiles
|
||||||
|
name: README.md
|
||||||
|
- path: reports/scaffold-placement.md
|
||||||
|
directory: reports
|
||||||
|
name: scaffold-placement.md
|
||||||
|
- path: schemas/README.md
|
||||||
|
directory: schemas
|
||||||
|
name: README.md
|
||||||
|
- path: schemas/agent-brief.schema.yaml
|
||||||
|
directory: schemas
|
||||||
|
name: agent-brief.schema.yaml
|
||||||
|
- path: schemas/assimilation.schema.yaml
|
||||||
|
directory: schemas
|
||||||
|
name: assimilation.schema.yaml
|
||||||
|
- path: schemas/concept.schema.yaml
|
||||||
|
directory: schemas
|
||||||
|
name: concept.schema.yaml
|
||||||
|
- path: schemas/index.yaml
|
||||||
|
directory: schemas
|
||||||
|
name: index.yaml
|
||||||
|
- path: schemas/interface-card.schema.yaml
|
||||||
|
directory: schemas
|
||||||
|
name: interface-card.schema.yaml
|
||||||
|
- path: schemas/mapping.schema.yaml
|
||||||
|
directory: schemas
|
||||||
|
name: mapping.schema.yaml
|
||||||
|
- path: schemas/profile.schema.yaml
|
||||||
|
directory: schemas
|
||||||
|
name: profile.schema.yaml
|
||||||
|
- path: schemas/standard.schema.yaml
|
||||||
|
directory: schemas
|
||||||
|
name: standard.schema.yaml
|
||||||
|
- path: schemas/workplan.schema.yaml
|
||||||
|
directory: schemas
|
||||||
|
name: workplan.schema.yaml
|
||||||
|
- path: standards/caring/InfoTechCanonCaringAccessGovernanceStandard.md
|
||||||
|
directory: standards/caring
|
||||||
|
name: InfoTechCanonCaringAccessGovernanceStandard.md
|
||||||
|
- path: standards/tagging/InfoTechCanonTaggingStandard.md
|
||||||
|
directory: standards/tagging
|
||||||
|
name: InfoTechCanonTaggingStandard.md
|
||||||
|
- path: validation/README.md
|
||||||
|
directory: validation
|
||||||
|
name: README.md
|
||||||
|
- path: validation/latest.json
|
||||||
|
directory: validation
|
||||||
|
name: latest.json
|
||||||
|
- path: views/README.md
|
||||||
|
directory: views
|
||||||
|
name: README.md
|
||||||
|
- path: views/by-concept.md
|
||||||
|
directory: views
|
||||||
|
name: by-concept.md
|
||||||
|
- path: views/by-mapping-target.md
|
||||||
|
directory: views
|
||||||
|
name: by-mapping-target.md
|
||||||
|
- path: views/by-profile.md
|
||||||
|
directory: views
|
||||||
|
name: by-profile.md
|
||||||
|
- path: views/by-standard.md
|
||||||
|
directory: views
|
||||||
|
name: by-standard.md
|
||||||
|
- path: views/import-matrix.md
|
||||||
|
directory: views
|
||||||
|
name: import-matrix.md
|
||||||
|
- path: views/kernel-overview.md
|
||||||
|
directory: views
|
||||||
|
name: kernel-overview.md
|
||||||
|
- path: views/repository-tree.md
|
||||||
|
directory: views
|
||||||
|
name: repository-tree.md
|
||||||
124
infospace/indexes/concept-ownership.yaml
Normal file
124
infospace/indexes/concept-ownership.yaml
Normal file
@@ -0,0 +1,124 @@
|
|||||||
|
concept_count: 30
|
||||||
|
concepts:
|
||||||
|
- concept: InfoTechCanon Core
|
||||||
|
owner: kernel/itc-core
|
||||||
|
path: kernel/InfoTechCanonCore.md
|
||||||
|
source: artifact_title
|
||||||
|
- concept: InfoTechCanon Kernel Map
|
||||||
|
owner: kernel/itc-kernel-map
|
||||||
|
path: kernel/InfoTechCanonKernelMap.md
|
||||||
|
source: artifact_title
|
||||||
|
- concept: InfoTechCanon Access Control Model
|
||||||
|
owner: model/access-control
|
||||||
|
path: models/access-control/InfoTechCanonAccessControlModel.md
|
||||||
|
source: artifact_title
|
||||||
|
- concept: InfoTechCanon Data Model
|
||||||
|
owner: model/data
|
||||||
|
path: models/data/InfoTechCanonDataModel.md
|
||||||
|
source: artifact_title
|
||||||
|
- concept: InfoTechCanon DevSecOps Model
|
||||||
|
owner: model/devsecops
|
||||||
|
path: models/devsecops/InfoTechCanonDevSecOpsModel.md
|
||||||
|
source: artifact_title
|
||||||
|
- concept: InfoTechCanon Governance Model
|
||||||
|
owner: model/governance
|
||||||
|
path: models/governance/InfoTechCanonGovernanceModel.md
|
||||||
|
source: artifact_title
|
||||||
|
- concept: InfoTechCanon Information Space Model
|
||||||
|
owner: model/information-space
|
||||||
|
path: models/information-space/InfoTechCanonInformationSpaceModel.md
|
||||||
|
source: artifact_title
|
||||||
|
- concept: InfoTechCanon Landscape Model
|
||||||
|
owner: model/landscape
|
||||||
|
path: models/landscape/InfoTechCanonLandscapeModel.md
|
||||||
|
source: artifact_title
|
||||||
|
- concept: InfoTechCanon Network Model
|
||||||
|
owner: model/network
|
||||||
|
path: models/network/InfoTechCanonNetworkModel.md
|
||||||
|
source: artifact_title
|
||||||
|
- concept: InfoTechCanon Observability Model
|
||||||
|
owner: model/observability
|
||||||
|
path: models/observability/InfoTechCanonObservabilityModel.md
|
||||||
|
source: artifact_title
|
||||||
|
- concept: InfoTechCanon Organization Model
|
||||||
|
owner: model/organization
|
||||||
|
path: models/organization/InfoTechCanonOrganizationModel.md
|
||||||
|
source: artifact_title
|
||||||
|
- concept: InfoTechCanon Security Model
|
||||||
|
owner: model/security
|
||||||
|
path: models/security/InfoTechCanonSecurityModel.md
|
||||||
|
source: artifact_title
|
||||||
|
- concept: InfoTechCanon Task Model
|
||||||
|
owner: model/task
|
||||||
|
path: models/task/InfoTechCanonTaskModel.md
|
||||||
|
source: artifact_title
|
||||||
|
- concept: InfoTechCanon CARING Access Governance Standard
|
||||||
|
owner: standard/caring
|
||||||
|
path: standards/caring/InfoTechCanonCaringAccessGovernanceStandard.md
|
||||||
|
source: artifact_title
|
||||||
|
- concept: CARINGAccessDescriptor
|
||||||
|
owner: standard/caring
|
||||||
|
path: standards/caring/InfoTechCanonCaringAccessGovernanceStandard.md
|
||||||
|
source: frontmatter.owned_concepts
|
||||||
|
- concept: CARINGCanonicalRole
|
||||||
|
owner: standard/caring
|
||||||
|
path: standards/caring/InfoTechCanonCaringAccessGovernanceStandard.md
|
||||||
|
source: frontmatter.owned_concepts
|
||||||
|
- concept: CARINGOrganizationRelation
|
||||||
|
owner: standard/caring
|
||||||
|
path: standards/caring/InfoTechCanonCaringAccessGovernanceStandard.md
|
||||||
|
source: frontmatter.owned_concepts
|
||||||
|
- concept: CARINGPlane
|
||||||
|
owner: standard/caring
|
||||||
|
path: standards/caring/InfoTechCanonCaringAccessGovernanceStandard.md
|
||||||
|
source: frontmatter.owned_concepts
|
||||||
|
- concept: CARINGCapabilityProfile
|
||||||
|
owner: standard/caring
|
||||||
|
path: standards/caring/InfoTechCanonCaringAccessGovernanceStandard.md
|
||||||
|
source: frontmatter.owned_concepts
|
||||||
|
- concept: CARINGExposureMode
|
||||||
|
owner: standard/caring
|
||||||
|
path: standards/caring/InfoTechCanonCaringAccessGovernanceStandard.md
|
||||||
|
source: frontmatter.owned_concepts
|
||||||
|
- concept: CARINGExposureEvent
|
||||||
|
owner: standard/caring
|
||||||
|
path: standards/caring/InfoTechCanonCaringAccessGovernanceStandard.md
|
||||||
|
source: frontmatter.owned_concepts
|
||||||
|
- concept: CARINGDeclaredAccessMap
|
||||||
|
owner: standard/caring
|
||||||
|
path: standards/caring/InfoTechCanonCaringAccessGovernanceStandard.md
|
||||||
|
source: frontmatter.owned_concepts
|
||||||
|
- concept: CARINGEffectiveAccessMap
|
||||||
|
owner: standard/caring
|
||||||
|
path: standards/caring/InfoTechCanonCaringAccessGovernanceStandard.md
|
||||||
|
source: frontmatter.owned_concepts
|
||||||
|
- concept: CARINGDerivedCapability
|
||||||
|
owner: standard/caring
|
||||||
|
path: standards/caring/InfoTechCanonCaringAccessGovernanceStandard.md
|
||||||
|
source: frontmatter.owned_concepts
|
||||||
|
- concept: CARINGInducedAccess
|
||||||
|
owner: standard/caring
|
||||||
|
path: standards/caring/InfoTechCanonCaringAccessGovernanceStandard.md
|
||||||
|
source: frontmatter.owned_concepts
|
||||||
|
- concept: CARINGRestrictionPrecedence
|
||||||
|
owner: standard/caring
|
||||||
|
path: standards/caring/InfoTechCanonCaringAccessGovernanceStandard.md
|
||||||
|
source: frontmatter.owned_concepts
|
||||||
|
- concept: CARINGAnalysisFitnessTest
|
||||||
|
owner: standard/caring
|
||||||
|
path: standards/caring/InfoTechCanonCaringAccessGovernanceStandard.md
|
||||||
|
source: frontmatter.owned_concepts
|
||||||
|
- concept: CARINGAnalysisProcedure
|
||||||
|
owner: standard/caring
|
||||||
|
path: standards/caring/InfoTechCanonCaringAccessGovernanceStandard.md
|
||||||
|
source: frontmatter.owned_concepts
|
||||||
|
- concept: CARINGRedesignProcedure
|
||||||
|
owner: standard/caring
|
||||||
|
path: standards/caring/InfoTechCanonCaringAccessGovernanceStandard.md
|
||||||
|
source: frontmatter.owned_concepts
|
||||||
|
- concept: InfoTechCanon Tagging Standard
|
||||||
|
owner: standard/tagging
|
||||||
|
path: standards/tagging/InfoTechCanonTaggingStandard.md
|
||||||
|
source: artifact_title
|
||||||
|
duplicate_candidates: []
|
||||||
|
ownership_conflicts: []
|
||||||
137
infospace/indexes/import-matrix.yaml
Normal file
137
infospace/indexes/import-matrix.yaml
Normal file
@@ -0,0 +1,137 @@
|
|||||||
|
artifacts:
|
||||||
|
- kernel/itc-core
|
||||||
|
- kernel/itc-kernel-map
|
||||||
|
- model/access-control
|
||||||
|
- model/data
|
||||||
|
- model/devsecops
|
||||||
|
- model/governance
|
||||||
|
- model/information-space
|
||||||
|
- model/landscape
|
||||||
|
- model/network
|
||||||
|
- model/observability
|
||||||
|
- model/organization
|
||||||
|
- model/security
|
||||||
|
- model/task
|
||||||
|
- standard/caring
|
||||||
|
- standard/tagging
|
||||||
|
rows:
|
||||||
|
- artifact: kernel/itc-core
|
||||||
|
targets: {}
|
||||||
|
- artifact: kernel/itc-kernel-map
|
||||||
|
targets:
|
||||||
|
kernel/itc-core:
|
||||||
|
- maps
|
||||||
|
model/access-control:
|
||||||
|
- maps
|
||||||
|
model/data:
|
||||||
|
- maps
|
||||||
|
model/devsecops:
|
||||||
|
- maps
|
||||||
|
model/governance:
|
||||||
|
- maps
|
||||||
|
model/information-space:
|
||||||
|
- maps
|
||||||
|
model/landscape:
|
||||||
|
- maps
|
||||||
|
model/network:
|
||||||
|
- maps
|
||||||
|
model/observability:
|
||||||
|
- maps
|
||||||
|
model/organization:
|
||||||
|
- maps
|
||||||
|
model/security:
|
||||||
|
- maps
|
||||||
|
model/task:
|
||||||
|
- maps
|
||||||
|
standard/caring:
|
||||||
|
- maps
|
||||||
|
standard/tagging:
|
||||||
|
- maps
|
||||||
|
- artifact: model/access-control
|
||||||
|
targets:
|
||||||
|
kernel/itc-core:
|
||||||
|
- conforms_to
|
||||||
|
model/governance:
|
||||||
|
- uses
|
||||||
|
model/organization:
|
||||||
|
- uses
|
||||||
|
- artifact: model/data
|
||||||
|
targets:
|
||||||
|
kernel/itc-core:
|
||||||
|
- conforms_to
|
||||||
|
model/governance:
|
||||||
|
- uses
|
||||||
|
- artifact: model/devsecops
|
||||||
|
targets:
|
||||||
|
kernel/itc-core:
|
||||||
|
- conforms_to
|
||||||
|
model/security:
|
||||||
|
- uses
|
||||||
|
- artifact: model/governance
|
||||||
|
targets:
|
||||||
|
kernel/itc-core:
|
||||||
|
- conforms_to
|
||||||
|
- artifact: model/information-space
|
||||||
|
targets:
|
||||||
|
kernel/itc-core:
|
||||||
|
- conforms_to
|
||||||
|
- artifact: model/landscape
|
||||||
|
targets:
|
||||||
|
kernel/itc-core:
|
||||||
|
- conforms_to
|
||||||
|
- artifact: model/network
|
||||||
|
targets:
|
||||||
|
kernel/itc-core:
|
||||||
|
- conforms_to
|
||||||
|
model/security:
|
||||||
|
- uses
|
||||||
|
- artifact: model/observability
|
||||||
|
targets:
|
||||||
|
kernel/itc-core:
|
||||||
|
- conforms_to
|
||||||
|
model/task:
|
||||||
|
- uses
|
||||||
|
- artifact: model/organization
|
||||||
|
targets:
|
||||||
|
kernel/itc-core:
|
||||||
|
- conforms_to
|
||||||
|
- artifact: model/security
|
||||||
|
targets:
|
||||||
|
kernel/itc-core:
|
||||||
|
- conforms_to
|
||||||
|
model/access-control:
|
||||||
|
- uses
|
||||||
|
- artifact: model/task
|
||||||
|
targets:
|
||||||
|
kernel/itc-core:
|
||||||
|
- conforms_to
|
||||||
|
- artifact: standard/caring
|
||||||
|
targets:
|
||||||
|
kernel/itc-core:
|
||||||
|
- conforms_to
|
||||||
|
model/access-control:
|
||||||
|
- imports
|
||||||
|
model/data:
|
||||||
|
- imports
|
||||||
|
model/devsecops:
|
||||||
|
- imports
|
||||||
|
model/governance:
|
||||||
|
- imports
|
||||||
|
model/network:
|
||||||
|
- imports
|
||||||
|
model/observability:
|
||||||
|
- imports
|
||||||
|
model/organization:
|
||||||
|
- imports
|
||||||
|
model/security:
|
||||||
|
- imports
|
||||||
|
model/task:
|
||||||
|
- imports
|
||||||
|
standard/tagging:
|
||||||
|
- imports
|
||||||
|
- artifact: standard/tagging
|
||||||
|
targets:
|
||||||
|
kernel/itc-core:
|
||||||
|
- conforms_to
|
||||||
|
model/task:
|
||||||
|
- imports
|
||||||
@@ -35,7 +35,15 @@ disciplines:
|
|||||||
path: standards/tagging/InfoTechCanonTaggingStandard.md
|
path: standards/tagging/InfoTechCanonTaggingStandard.md
|
||||||
- name: CARING Access Governance Standard
|
- name: CARING Access Governance Standard
|
||||||
path: standards/caring/InfoTechCanonCaringAccessGovernanceStandard.md
|
path: standards/caring/InfoTechCanonCaringAccessGovernanceStandard.md
|
||||||
schemas: {}
|
schemas:
|
||||||
|
standard: schemas/standard.schema.yaml
|
||||||
|
concept: schemas/concept.schema.yaml
|
||||||
|
mapping: schemas/mapping.schema.yaml
|
||||||
|
profile: schemas/profile.schema.yaml
|
||||||
|
assimilation: schemas/assimilation.schema.yaml
|
||||||
|
interface-card: schemas/interface-card.schema.yaml
|
||||||
|
agent-brief: schemas/agent-brief.schema.yaml
|
||||||
|
workplan: schemas/workplan.schema.yaml
|
||||||
workflows: []
|
workflows: []
|
||||||
viability:
|
viability:
|
||||||
redundancy_ratio:
|
redundancy_ratio:
|
||||||
|
|||||||
27
infospace/schemas/agent-brief.schema.yaml
Normal file
27
infospace/schemas/agent-brief.schema.yaml
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
$schema: https://json-schema.org/draft/2020-12/schema
|
||||||
|
$id: https://info-tech-canon.local/schemas/agent-brief.schema.yaml
|
||||||
|
title: InfoTechCanon Agent Brief
|
||||||
|
type: object
|
||||||
|
required:
|
||||||
|
- id
|
||||||
|
- title
|
||||||
|
- audience
|
||||||
|
- purpose
|
||||||
|
properties:
|
||||||
|
id:
|
||||||
|
type: string
|
||||||
|
title:
|
||||||
|
type: string
|
||||||
|
audience:
|
||||||
|
type: string
|
||||||
|
purpose:
|
||||||
|
type: string
|
||||||
|
commands:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
entrypoints:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
additionalProperties: true
|
||||||
28
infospace/schemas/assimilation.schema.yaml
Normal file
28
infospace/schemas/assimilation.schema.yaml
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
$schema: https://json-schema.org/draft/2020-12/schema
|
||||||
|
$id: https://info-tech-canon.local/schemas/assimilation.schema.yaml
|
||||||
|
title: InfoTechCanon Assimilation Record
|
||||||
|
type: object
|
||||||
|
required:
|
||||||
|
- id
|
||||||
|
- title
|
||||||
|
- source
|
||||||
|
- disposition
|
||||||
|
properties:
|
||||||
|
id:
|
||||||
|
type: string
|
||||||
|
title:
|
||||||
|
type: string
|
||||||
|
source:
|
||||||
|
type: string
|
||||||
|
disposition:
|
||||||
|
enum:
|
||||||
|
- observe
|
||||||
|
- map
|
||||||
|
- adopt
|
||||||
|
- adapt
|
||||||
|
- reject
|
||||||
|
impacts:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
additionalProperties: true
|
||||||
26
infospace/schemas/concept.schema.yaml
Normal file
26
infospace/schemas/concept.schema.yaml
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
$schema: https://json-schema.org/draft/2020-12/schema
|
||||||
|
$id: https://info-tech-canon.local/schemas/concept.schema.yaml
|
||||||
|
title: InfoTechCanon Concept
|
||||||
|
type: object
|
||||||
|
required:
|
||||||
|
- id
|
||||||
|
- title
|
||||||
|
- owner
|
||||||
|
properties:
|
||||||
|
id:
|
||||||
|
type: string
|
||||||
|
title:
|
||||||
|
type: string
|
||||||
|
owner:
|
||||||
|
type: string
|
||||||
|
definition:
|
||||||
|
type: string
|
||||||
|
aliases:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
relationships:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
type: object
|
||||||
|
additionalProperties: true
|
||||||
17
infospace/schemas/index.yaml
Normal file
17
infospace/schemas/index.yaml
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
schemas:
|
||||||
|
- id: standard
|
||||||
|
path: standard.schema.yaml
|
||||||
|
- id: concept
|
||||||
|
path: concept.schema.yaml
|
||||||
|
- id: mapping
|
||||||
|
path: mapping.schema.yaml
|
||||||
|
- id: profile
|
||||||
|
path: profile.schema.yaml
|
||||||
|
- id: assimilation
|
||||||
|
path: assimilation.schema.yaml
|
||||||
|
- id: interface-card
|
||||||
|
path: interface-card.schema.yaml
|
||||||
|
- id: agent-brief
|
||||||
|
path: agent-brief.schema.yaml
|
||||||
|
- id: workplan
|
||||||
|
path: workplan.schema.yaml
|
||||||
25
infospace/schemas/interface-card.schema.yaml
Normal file
25
infospace/schemas/interface-card.schema.yaml
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
$schema: https://json-schema.org/draft/2020-12/schema
|
||||||
|
$id: https://info-tech-canon.local/schemas/interface-card.schema.yaml
|
||||||
|
title: Canon Interface Card
|
||||||
|
type: object
|
||||||
|
required:
|
||||||
|
- id
|
||||||
|
- title
|
||||||
|
- consumer
|
||||||
|
- canon_surfaces
|
||||||
|
properties:
|
||||||
|
id:
|
||||||
|
type: string
|
||||||
|
title:
|
||||||
|
type: string
|
||||||
|
consumer:
|
||||||
|
type: string
|
||||||
|
canon_surfaces:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
expectations:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
additionalProperties: true
|
||||||
23
infospace/schemas/mapping.schema.yaml
Normal file
23
infospace/schemas/mapping.schema.yaml
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
$schema: https://json-schema.org/draft/2020-12/schema
|
||||||
|
$id: https://info-tech-canon.local/schemas/mapping.schema.yaml
|
||||||
|
title: InfoTechCanon Mapping
|
||||||
|
type: object
|
||||||
|
required:
|
||||||
|
- id
|
||||||
|
- title
|
||||||
|
- source
|
||||||
|
- target
|
||||||
|
properties:
|
||||||
|
id:
|
||||||
|
type: string
|
||||||
|
title:
|
||||||
|
type: string
|
||||||
|
source:
|
||||||
|
type: string
|
||||||
|
target:
|
||||||
|
type: string
|
||||||
|
mapping_type:
|
||||||
|
type: string
|
||||||
|
confidence:
|
||||||
|
type: string
|
||||||
|
additionalProperties: true
|
||||||
24
infospace/schemas/profile.schema.yaml
Normal file
24
infospace/schemas/profile.schema.yaml
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
$schema: https://json-schema.org/draft/2020-12/schema
|
||||||
|
$id: https://info-tech-canon.local/schemas/profile.schema.yaml
|
||||||
|
title: InfoTechCanon Profile
|
||||||
|
type: object
|
||||||
|
required:
|
||||||
|
- id
|
||||||
|
- title
|
||||||
|
- scope
|
||||||
|
properties:
|
||||||
|
id:
|
||||||
|
type: string
|
||||||
|
title:
|
||||||
|
type: string
|
||||||
|
scope:
|
||||||
|
type: string
|
||||||
|
includes:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
constraints:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
type: object
|
||||||
|
additionalProperties: true
|
||||||
33
infospace/schemas/standard.schema.yaml
Normal file
33
infospace/schemas/standard.schema.yaml
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
$schema: https://json-schema.org/draft/2020-12/schema
|
||||||
|
$id: https://info-tech-canon.local/schemas/standard.schema.yaml
|
||||||
|
title: InfoTechCanon Standard
|
||||||
|
type: object
|
||||||
|
required:
|
||||||
|
- id
|
||||||
|
- title
|
||||||
|
- type
|
||||||
|
- status
|
||||||
|
properties:
|
||||||
|
id:
|
||||||
|
type: string
|
||||||
|
title:
|
||||||
|
type: string
|
||||||
|
type:
|
||||||
|
enum:
|
||||||
|
- standard
|
||||||
|
- specialized-standard
|
||||||
|
- model
|
||||||
|
- kernel
|
||||||
|
status:
|
||||||
|
type: string
|
||||||
|
version:
|
||||||
|
type: string
|
||||||
|
imports:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
owned_concepts:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
additionalProperties: true
|
||||||
38
infospace/schemas/workplan.schema.yaml
Normal file
38
infospace/schemas/workplan.schema.yaml
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
$schema: https://json-schema.org/draft/2020-12/schema
|
||||||
|
$id: https://info-tech-canon.local/schemas/workplan.schema.yaml
|
||||||
|
title: State Hub Workplan
|
||||||
|
type: object
|
||||||
|
required:
|
||||||
|
- id
|
||||||
|
- type
|
||||||
|
- title
|
||||||
|
- domain
|
||||||
|
- repo
|
||||||
|
- status
|
||||||
|
properties:
|
||||||
|
id:
|
||||||
|
type: string
|
||||||
|
type:
|
||||||
|
const: workplan
|
||||||
|
title:
|
||||||
|
type: string
|
||||||
|
domain:
|
||||||
|
type: string
|
||||||
|
repo:
|
||||||
|
type: string
|
||||||
|
status:
|
||||||
|
enum:
|
||||||
|
- proposed
|
||||||
|
- ready
|
||||||
|
- active
|
||||||
|
- blocked
|
||||||
|
- backlog
|
||||||
|
- finished
|
||||||
|
- archived
|
||||||
|
depends_on_workplans:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
state_hub_workstream_id:
|
||||||
|
type: string
|
||||||
|
additionalProperties: true
|
||||||
41
infospace/validation/latest.json
Normal file
41
infospace/validation/latest.json
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
{
|
||||||
|
"details": {
|
||||||
|
"artifact_count": 15,
|
||||||
|
"relationship_count": 45
|
||||||
|
},
|
||||||
|
"errors": [],
|
||||||
|
"metrics": {
|
||||||
|
"coherence_components": 1.0,
|
||||||
|
"consistency_cycles": 0.0,
|
||||||
|
"coverage_ratio": 1.0,
|
||||||
|
"granularity_entropy": 1.103307408607834,
|
||||||
|
"redundancy_ratio": 0.0
|
||||||
|
},
|
||||||
|
"ok": true,
|
||||||
|
"warnings": [
|
||||||
|
{
|
||||||
|
"code": "missing_optional_concepts_dir",
|
||||||
|
"path": "infospace/concepts"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": "empty_optional_collection",
|
||||||
|
"path": "infospace/profiles"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": "empty_optional_collection",
|
||||||
|
"path": "infospace/patterns"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": "empty_optional_collection",
|
||||||
|
"path": "infospace/mappings"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": "empty_optional_collection",
|
||||||
|
"path": "infospace/assimilation"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"code": "empty_optional_collection",
|
||||||
|
"path": "infospace/examples"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
46
infospace/views/by-concept.md
Normal file
46
infospace/views/by-concept.md
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
<!-- GENERATED by info_tech_canon; do not edit by hand. -->
|
||||||
|
|
||||||
|
# By Concept
|
||||||
|
|
||||||
|
Concept count: **30**
|
||||||
|
|
||||||
|
| Concept | Owner | Source |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| InfoTechCanon Core | `kernel/itc-core` | `artifact_title` |
|
||||||
|
| InfoTechCanon Kernel Map | `kernel/itc-kernel-map` | `artifact_title` |
|
||||||
|
| InfoTechCanon Access Control Model | `model/access-control` | `artifact_title` |
|
||||||
|
| InfoTechCanon Data Model | `model/data` | `artifact_title` |
|
||||||
|
| InfoTechCanon DevSecOps Model | `model/devsecops` | `artifact_title` |
|
||||||
|
| InfoTechCanon Governance Model | `model/governance` | `artifact_title` |
|
||||||
|
| InfoTechCanon Information Space Model | `model/information-space` | `artifact_title` |
|
||||||
|
| InfoTechCanon Landscape Model | `model/landscape` | `artifact_title` |
|
||||||
|
| InfoTechCanon Network Model | `model/network` | `artifact_title` |
|
||||||
|
| InfoTechCanon Observability Model | `model/observability` | `artifact_title` |
|
||||||
|
| InfoTechCanon Organization Model | `model/organization` | `artifact_title` |
|
||||||
|
| InfoTechCanon Security Model | `model/security` | `artifact_title` |
|
||||||
|
| InfoTechCanon Task Model | `model/task` | `artifact_title` |
|
||||||
|
| InfoTechCanon CARING Access Governance Standard | `standard/caring` | `artifact_title` |
|
||||||
|
| CARINGAccessDescriptor | `standard/caring` | `frontmatter.owned_concepts` |
|
||||||
|
| CARINGCanonicalRole | `standard/caring` | `frontmatter.owned_concepts` |
|
||||||
|
| CARINGOrganizationRelation | `standard/caring` | `frontmatter.owned_concepts` |
|
||||||
|
| CARINGPlane | `standard/caring` | `frontmatter.owned_concepts` |
|
||||||
|
| CARINGCapabilityProfile | `standard/caring` | `frontmatter.owned_concepts` |
|
||||||
|
| CARINGExposureMode | `standard/caring` | `frontmatter.owned_concepts` |
|
||||||
|
| CARINGExposureEvent | `standard/caring` | `frontmatter.owned_concepts` |
|
||||||
|
| CARINGDeclaredAccessMap | `standard/caring` | `frontmatter.owned_concepts` |
|
||||||
|
| CARINGEffectiveAccessMap | `standard/caring` | `frontmatter.owned_concepts` |
|
||||||
|
| CARINGDerivedCapability | `standard/caring` | `frontmatter.owned_concepts` |
|
||||||
|
| CARINGInducedAccess | `standard/caring` | `frontmatter.owned_concepts` |
|
||||||
|
| CARINGRestrictionPrecedence | `standard/caring` | `frontmatter.owned_concepts` |
|
||||||
|
| CARINGAnalysisFitnessTest | `standard/caring` | `frontmatter.owned_concepts` |
|
||||||
|
| CARINGAnalysisProcedure | `standard/caring` | `frontmatter.owned_concepts` |
|
||||||
|
| CARINGRedesignProcedure | `standard/caring` | `frontmatter.owned_concepts` |
|
||||||
|
| InfoTechCanon Tagging Standard | `standard/tagging` | `artifact_title` |
|
||||||
|
|
||||||
|
## Duplicate Candidates
|
||||||
|
|
||||||
|
No duplicate concept candidates detected.
|
||||||
|
|
||||||
|
## Ownership Conflicts
|
||||||
|
|
||||||
|
No ownership conflicts detected.
|
||||||
90
infospace/views/by-mapping-target.md
Normal file
90
infospace/views/by-mapping-target.md
Normal file
@@ -0,0 +1,90 @@
|
|||||||
|
<!-- GENERATED by info_tech_canon; do not edit by hand. -->
|
||||||
|
|
||||||
|
# By Mapping Target
|
||||||
|
|
||||||
|
## `kernel/itc-core`
|
||||||
|
|
||||||
|
- `kernel/itc-kernel-map` via `maps`
|
||||||
|
- `model/access-control` via `conforms_to`
|
||||||
|
- `model/data` via `conforms_to`
|
||||||
|
- `model/devsecops` via `conforms_to`
|
||||||
|
- `model/governance` via `conforms_to`
|
||||||
|
- `model/information-space` via `conforms_to`
|
||||||
|
- `model/landscape` via `conforms_to`
|
||||||
|
- `model/network` via `conforms_to`
|
||||||
|
- `model/observability` via `conforms_to`
|
||||||
|
- `model/organization` via `conforms_to`
|
||||||
|
- `model/security` via `conforms_to`
|
||||||
|
- `model/task` via `conforms_to`
|
||||||
|
- `standard/caring` via `conforms_to`
|
||||||
|
- `standard/tagging` via `conforms_to`
|
||||||
|
|
||||||
|
## `model/access-control`
|
||||||
|
|
||||||
|
- `kernel/itc-kernel-map` via `maps`
|
||||||
|
- `model/security` via `uses`
|
||||||
|
- `standard/caring` via `imports`
|
||||||
|
|
||||||
|
## `model/data`
|
||||||
|
|
||||||
|
- `kernel/itc-kernel-map` via `maps`
|
||||||
|
- `standard/caring` via `imports`
|
||||||
|
|
||||||
|
## `model/devsecops`
|
||||||
|
|
||||||
|
- `kernel/itc-kernel-map` via `maps`
|
||||||
|
- `standard/caring` via `imports`
|
||||||
|
|
||||||
|
## `model/governance`
|
||||||
|
|
||||||
|
- `kernel/itc-kernel-map` via `maps`
|
||||||
|
- `model/access-control` via `uses`
|
||||||
|
- `model/data` via `uses`
|
||||||
|
- `standard/caring` via `imports`
|
||||||
|
|
||||||
|
## `model/information-space`
|
||||||
|
|
||||||
|
- `kernel/itc-kernel-map` via `maps`
|
||||||
|
|
||||||
|
## `model/landscape`
|
||||||
|
|
||||||
|
- `kernel/itc-kernel-map` via `maps`
|
||||||
|
|
||||||
|
## `model/network`
|
||||||
|
|
||||||
|
- `kernel/itc-kernel-map` via `maps`
|
||||||
|
- `standard/caring` via `imports`
|
||||||
|
|
||||||
|
## `model/observability`
|
||||||
|
|
||||||
|
- `kernel/itc-kernel-map` via `maps`
|
||||||
|
- `standard/caring` via `imports`
|
||||||
|
|
||||||
|
## `model/organization`
|
||||||
|
|
||||||
|
- `kernel/itc-kernel-map` via `maps`
|
||||||
|
- `model/access-control` via `uses`
|
||||||
|
- `standard/caring` via `imports`
|
||||||
|
|
||||||
|
## `model/security`
|
||||||
|
|
||||||
|
- `kernel/itc-kernel-map` via `maps`
|
||||||
|
- `model/devsecops` via `uses`
|
||||||
|
- `model/network` via `uses`
|
||||||
|
- `standard/caring` via `imports`
|
||||||
|
|
||||||
|
## `model/task`
|
||||||
|
|
||||||
|
- `kernel/itc-kernel-map` via `maps`
|
||||||
|
- `model/observability` via `uses`
|
||||||
|
- `standard/caring` via `imports`
|
||||||
|
- `standard/tagging` via `imports`
|
||||||
|
|
||||||
|
## `standard/caring`
|
||||||
|
|
||||||
|
- `kernel/itc-kernel-map` via `maps`
|
||||||
|
|
||||||
|
## `standard/tagging`
|
||||||
|
|
||||||
|
- `kernel/itc-kernel-map` via `maps`
|
||||||
|
- `standard/caring` via `imports`
|
||||||
5
infospace/views/by-profile.md
Normal file
5
infospace/views/by-profile.md
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
<!-- GENERATED by info_tech_canon; do not edit by hand. -->
|
||||||
|
|
||||||
|
# By Profile
|
||||||
|
|
||||||
|
No profiles have been registered yet.
|
||||||
31
infospace/views/by-standard.md
Normal file
31
infospace/views/by-standard.md
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
<!-- GENERATED by info_tech_canon; do not edit by hand. -->
|
||||||
|
|
||||||
|
# By Standard
|
||||||
|
|
||||||
|
## InfoTechCanon Core
|
||||||
|
|
||||||
|
- ID: `kernel/itc-core`
|
||||||
|
- Kind: `kernel`
|
||||||
|
- Path: `kernel/InfoTechCanonCore.md`
|
||||||
|
- Relationships: 0
|
||||||
|
|
||||||
|
## InfoTechCanon Kernel Map
|
||||||
|
|
||||||
|
- ID: `kernel/itc-kernel-map`
|
||||||
|
- Kind: `kernel`
|
||||||
|
- Path: `kernel/InfoTechCanonKernelMap.md`
|
||||||
|
- Relationships: 14
|
||||||
|
|
||||||
|
## InfoTechCanon CARING Access Governance Standard
|
||||||
|
|
||||||
|
- ID: `standard/caring`
|
||||||
|
- Kind: `standard`
|
||||||
|
- Path: `standards/caring/InfoTechCanonCaringAccessGovernanceStandard.md`
|
||||||
|
- Relationships: 11
|
||||||
|
|
||||||
|
## InfoTechCanon Tagging Standard
|
||||||
|
|
||||||
|
- ID: `standard/tagging`
|
||||||
|
- Kind: `standard`
|
||||||
|
- Path: `standards/tagging/InfoTechCanonTaggingStandard.md`
|
||||||
|
- Relationships: 2
|
||||||
21
infospace/views/import-matrix.md
Normal file
21
infospace/views/import-matrix.md
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
<!-- GENERATED by info_tech_canon; do not edit by hand. -->
|
||||||
|
|
||||||
|
# Import Matrix
|
||||||
|
|
||||||
|
| Artifact | `kernel/itc-core` | `kernel/itc-kernel-map` | `model/access-control` | `model/data` | `model/devsecops` | `model/governance` | `model/information-space` | `model/landscape` | `model/network` | `model/observability` | `model/organization` | `model/security` | `model/task` | `standard/caring` | `standard/tagging` |
|
||||||
|
| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- |
|
||||||
|
| `kernel/itc-core` | | | | | | | | | | | | | | | |
|
||||||
|
| `kernel/itc-kernel-map` | `maps` | | `maps` | `maps` | `maps` | `maps` | `maps` | `maps` | `maps` | `maps` | `maps` | `maps` | `maps` | `maps` | `maps` |
|
||||||
|
| `model/access-control` | `conforms_to` | | | | | `uses` | | | | | `uses` | | | | |
|
||||||
|
| `model/data` | `conforms_to` | | | | | `uses` | | | | | | | | | |
|
||||||
|
| `model/devsecops` | `conforms_to` | | | | | | | | | | | `uses` | | | |
|
||||||
|
| `model/governance` | `conforms_to` | | | | | | | | | | | | | | |
|
||||||
|
| `model/information-space` | `conforms_to` | | | | | | | | | | | | | | |
|
||||||
|
| `model/landscape` | `conforms_to` | | | | | | | | | | | | | | |
|
||||||
|
| `model/network` | `conforms_to` | | | | | | | | | | | `uses` | | | |
|
||||||
|
| `model/observability` | `conforms_to` | | | | | | | | | | | | `uses` | | |
|
||||||
|
| `model/organization` | `conforms_to` | | | | | | | | | | | | | | |
|
||||||
|
| `model/security` | `conforms_to` | | `uses` | | | | | | | | | | | | |
|
||||||
|
| `model/task` | `conforms_to` | | | | | | | | | | | | | | |
|
||||||
|
| `standard/caring` | `conforms_to` | | `imports` | `imports` | `imports` | `imports` | | | `imports` | `imports` | `imports` | `imports` | `imports` | | `imports` |
|
||||||
|
| `standard/tagging` | `conforms_to` | | | | | | | | | | | | `imports` | | |
|
||||||
19
infospace/views/kernel-overview.md
Normal file
19
infospace/views/kernel-overview.md
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
<!-- GENERATED by info_tech_canon; do not edit by hand. -->
|
||||||
|
|
||||||
|
# Kernel Overview
|
||||||
|
|
||||||
|
- Infospace: `canon`
|
||||||
|
- Artifacts: 15
|
||||||
|
|
||||||
|
## Artifact Kinds
|
||||||
|
|
||||||
|
- `kernel`: 2
|
||||||
|
- `model`: 11
|
||||||
|
- `standard`: 2
|
||||||
|
|
||||||
|
## Relationship Types
|
||||||
|
|
||||||
|
- `conforms_to`: 13
|
||||||
|
- `imports`: 11
|
||||||
|
- `maps`: 14
|
||||||
|
- `uses`: 7
|
||||||
56
infospace/views/repository-tree.md
Normal file
56
infospace/views/repository-tree.md
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
<!-- GENERATED by info_tech_canon; do not edit by hand. -->
|
||||||
|
|
||||||
|
# Repository Tree
|
||||||
|
|
||||||
|
File count: **50**
|
||||||
|
|
||||||
|
- `README.md`
|
||||||
|
- `agent/README.md`
|
||||||
|
- `agent/global-agent-brief.md`
|
||||||
|
- `artifacts/index.yaml`
|
||||||
|
- `assimilation/README.md`
|
||||||
|
- `examples/README.md`
|
||||||
|
- `indexes/README.md`
|
||||||
|
- `indexes/artifact-tree.yaml`
|
||||||
|
- `indexes/concept-ownership.yaml`
|
||||||
|
- `indexes/import-matrix.yaml`
|
||||||
|
- `infospace.yaml`
|
||||||
|
- `kernel/InfoTechCanonCore.md`
|
||||||
|
- `kernel/InfoTechCanonKernelMap.md`
|
||||||
|
- `mappings/README.md`
|
||||||
|
- `models/access-control/InfoTechCanonAccessControlModel.md`
|
||||||
|
- `models/data/InfoTechCanonDataModel.md`
|
||||||
|
- `models/devsecops/InfoTechCanonDevSecOpsModel.md`
|
||||||
|
- `models/governance/InfoTechCanonGovernanceModel.md`
|
||||||
|
- `models/information-space/InfoTechCanonInformationSpaceModel.md`
|
||||||
|
- `models/landscape/InfoTechCanonLandscapeModel.md`
|
||||||
|
- `models/network/InfoTechCanonNetworkModel.md`
|
||||||
|
- `models/observability/InfoTechCanonObservabilityModel.md`
|
||||||
|
- `models/organization/InfoTechCanonOrganizationModel.md`
|
||||||
|
- `models/security/InfoTechCanonSecurityModel.md`
|
||||||
|
- `models/task/InfoTechCanonTaskModel.md`
|
||||||
|
- `patterns/README.md`
|
||||||
|
- `profiles/README.md`
|
||||||
|
- `reports/scaffold-placement.md`
|
||||||
|
- `schemas/README.md`
|
||||||
|
- `schemas/agent-brief.schema.yaml`
|
||||||
|
- `schemas/assimilation.schema.yaml`
|
||||||
|
- `schemas/concept.schema.yaml`
|
||||||
|
- `schemas/index.yaml`
|
||||||
|
- `schemas/interface-card.schema.yaml`
|
||||||
|
- `schemas/mapping.schema.yaml`
|
||||||
|
- `schemas/profile.schema.yaml`
|
||||||
|
- `schemas/standard.schema.yaml`
|
||||||
|
- `schemas/workplan.schema.yaml`
|
||||||
|
- `standards/caring/InfoTechCanonCaringAccessGovernanceStandard.md`
|
||||||
|
- `standards/tagging/InfoTechCanonTaggingStandard.md`
|
||||||
|
- `validation/README.md`
|
||||||
|
- `validation/latest.json`
|
||||||
|
- `views/README.md`
|
||||||
|
- `views/by-concept.md`
|
||||||
|
- `views/by-mapping-target.md`
|
||||||
|
- `views/by-profile.md`
|
||||||
|
- `views/by-standard.md`
|
||||||
|
- `views/import-matrix.md`
|
||||||
|
- `views/kernel-overview.md`
|
||||||
|
- `views/repository-tree.md`
|
||||||
@@ -3,21 +3,33 @@
|
|||||||
from .service import (
|
from .service import (
|
||||||
CanonServiceError,
|
CanonServiceError,
|
||||||
artifact_graph,
|
artifact_graph,
|
||||||
|
generate_agent_briefs,
|
||||||
|
generate_indexes,
|
||||||
|
generate_tree,
|
||||||
inspect_canon,
|
inspect_canon,
|
||||||
list_artifacts,
|
list_artifacts,
|
||||||
list_models,
|
list_models,
|
||||||
list_standards,
|
list_standards,
|
||||||
|
list_views,
|
||||||
profile_inspect,
|
profile_inspect,
|
||||||
|
read_view,
|
||||||
validate_canon,
|
validate_canon,
|
||||||
|
write_validation_report,
|
||||||
)
|
)
|
||||||
|
|
||||||
__all__ = [
|
__all__ = [
|
||||||
"CanonServiceError",
|
"CanonServiceError",
|
||||||
"artifact_graph",
|
"artifact_graph",
|
||||||
|
"generate_agent_briefs",
|
||||||
|
"generate_indexes",
|
||||||
|
"generate_tree",
|
||||||
"inspect_canon",
|
"inspect_canon",
|
||||||
"list_artifacts",
|
"list_artifacts",
|
||||||
"list_models",
|
"list_models",
|
||||||
"list_standards",
|
"list_standards",
|
||||||
|
"list_views",
|
||||||
"profile_inspect",
|
"profile_inspect",
|
||||||
|
"read_view",
|
||||||
"validate_canon",
|
"validate_canon",
|
||||||
|
"write_validation_report",
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -14,7 +14,9 @@ from .service import (
|
|||||||
list_artifacts,
|
list_artifacts,
|
||||||
list_models,
|
list_models,
|
||||||
list_standards,
|
list_standards,
|
||||||
|
list_views,
|
||||||
profile_inspect,
|
profile_inspect,
|
||||||
|
read_view,
|
||||||
validate_canon,
|
validate_canon,
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -86,6 +88,11 @@ def _route(
|
|||||||
if path == "/graph":
|
if path == "/graph":
|
||||||
graph_format = _first(query, "format") or "json"
|
graph_format = _first(query, "format") or "json"
|
||||||
return HTTPStatus.OK, artifact_graph(root, output_format=graph_format)
|
return HTTPStatus.OK, artifact_graph(root, output_format=graph_format)
|
||||||
|
if path == "/views":
|
||||||
|
return HTTPStatus.OK, list_views(root)
|
||||||
|
if path.startswith("/views/"):
|
||||||
|
name = path.removeprefix("/views/").strip("/")
|
||||||
|
return HTTPStatus.OK, read_view(name, root)
|
||||||
if path.startswith("/profiles/") and path.endswith("/inspect"):
|
if path.startswith("/profiles/") and path.endswith("/inspect"):
|
||||||
profile = path.removeprefix("/profiles/").removesuffix("/inspect").strip("/")
|
profile = path.removeprefix("/profiles/").removesuffix("/inspect").strip("/")
|
||||||
return HTTPStatus.OK, profile_inspect(profile, root)
|
return HTTPStatus.OK, profile_inspect(profile, root)
|
||||||
|
|||||||
@@ -11,12 +11,18 @@ from .api import serve
|
|||||||
from .service import (
|
from .service import (
|
||||||
CanonServiceError,
|
CanonServiceError,
|
||||||
artifact_graph,
|
artifact_graph,
|
||||||
|
generate_agent_briefs,
|
||||||
|
generate_indexes,
|
||||||
|
generate_tree,
|
||||||
inspect_canon,
|
inspect_canon,
|
||||||
list_artifacts,
|
list_artifacts,
|
||||||
list_models,
|
list_models,
|
||||||
list_standards,
|
list_standards,
|
||||||
|
list_views,
|
||||||
profile_inspect,
|
profile_inspect,
|
||||||
|
read_view,
|
||||||
validate_canon,
|
validate_canon,
|
||||||
|
write_validation_report,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@@ -46,8 +52,26 @@ def build_parser() -> argparse.ArgumentParser:
|
|||||||
standards.set_defaults(handler=_standards)
|
standards.set_defaults(handler=_standards)
|
||||||
|
|
||||||
validate = sub.add_parser("validate", help="Validate the canon infospace")
|
validate = sub.add_parser("validate", help="Validate the canon infospace")
|
||||||
|
validate.add_argument(
|
||||||
|
"--write",
|
||||||
|
default="",
|
||||||
|
help="Write the JSON validation payload to this path.",
|
||||||
|
)
|
||||||
validate.set_defaults(handler=_validate)
|
validate.set_defaults(handler=_validate)
|
||||||
|
|
||||||
|
index = sub.add_parser("index", help="Refresh generated indexes and views")
|
||||||
|
index.set_defaults(handler=_index)
|
||||||
|
|
||||||
|
tree = sub.add_parser("tree", help="Refresh the generated infospace tree")
|
||||||
|
tree.set_defaults(handler=_tree)
|
||||||
|
|
||||||
|
agent_briefs = sub.add_parser("agent-briefs", help="Refresh generated agent briefs")
|
||||||
|
agent_briefs.set_defaults(handler=_agent_briefs)
|
||||||
|
|
||||||
|
views = sub.add_parser("views", help="List or read generated views")
|
||||||
|
views.add_argument("name", nargs="?", default="")
|
||||||
|
views.set_defaults(handler=_views)
|
||||||
|
|
||||||
graph = sub.add_parser("graph", help="Export the canon artifact graph")
|
graph = sub.add_parser("graph", help="Export the canon artifact graph")
|
||||||
graph.add_argument("--format", choices=["json", "mermaid"], default="json")
|
graph.add_argument("--format", choices=["json", "mermaid"], default="json")
|
||||||
graph.set_defaults(handler=_graph)
|
graph.set_defaults(handler=_graph)
|
||||||
@@ -113,9 +137,29 @@ def _standards(args: argparse.Namespace) -> dict[str, Any]:
|
|||||||
|
|
||||||
|
|
||||||
def _validate(args: argparse.Namespace) -> dict[str, Any]:
|
def _validate(args: argparse.Namespace) -> dict[str, Any]:
|
||||||
|
if args.write:
|
||||||
|
return write_validation_report(args.write, _root(args))
|
||||||
return validate_canon(_root(args))
|
return validate_canon(_root(args))
|
||||||
|
|
||||||
|
|
||||||
|
def _index(args: argparse.Namespace) -> dict[str, Any]:
|
||||||
|
return generate_indexes(_root(args))
|
||||||
|
|
||||||
|
|
||||||
|
def _tree(args: argparse.Namespace) -> dict[str, Any]:
|
||||||
|
return generate_tree(_root(args))
|
||||||
|
|
||||||
|
|
||||||
|
def _agent_briefs(args: argparse.Namespace) -> dict[str, Any]:
|
||||||
|
return generate_agent_briefs(_root(args))
|
||||||
|
|
||||||
|
|
||||||
|
def _views(args: argparse.Namespace) -> dict[str, Any]:
|
||||||
|
if args.name:
|
||||||
|
return read_view(args.name, _root(args))
|
||||||
|
return list_views(_root(args))
|
||||||
|
|
||||||
|
|
||||||
def _graph(args: argparse.Namespace) -> dict[str, Any]:
|
def _graph(args: argparse.Namespace) -> dict[str, Any]:
|
||||||
return artifact_graph(_root(args), output_format=args.format)
|
return artifact_graph(_root(args), output_format=args.format)
|
||||||
|
|
||||||
|
|||||||
427
src/info_tech_canon/generation.py
Normal file
427
src/info_tech_canon/generation.py
Normal file
@@ -0,0 +1,427 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from collections import defaultdict
|
||||||
|
from pathlib import Path
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
|
import yaml
|
||||||
|
|
||||||
|
|
||||||
|
GENERATED_NOTICE = "<!-- GENERATED by info_tech_canon; do not edit by hand. -->"
|
||||||
|
|
||||||
|
|
||||||
|
def generate_indexes(context: Any) -> dict[str, Any]:
|
||||||
|
assets: list[dict[str, Any]] = []
|
||||||
|
ownership = concept_ownership(context)
|
||||||
|
import_matrix = relationship_matrix(context)
|
||||||
|
|
||||||
|
assets.append(
|
||||||
|
_write_yaml(
|
||||||
|
context.infospace_root / "indexes" / "concept-ownership.yaml",
|
||||||
|
ownership,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
assets.append(
|
||||||
|
_write_yaml(
|
||||||
|
context.infospace_root / "indexes" / "import-matrix.yaml",
|
||||||
|
import_matrix,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
assets.append(
|
||||||
|
_write_yaml(
|
||||||
|
context.infospace_root / "indexes" / "artifact-tree.yaml",
|
||||||
|
artifact_tree(context),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
assets.extend(generate_views(context, ownership, import_matrix)["files"])
|
||||||
|
return _result("index", assets)
|
||||||
|
|
||||||
|
|
||||||
|
def generate_views(
|
||||||
|
context: Any,
|
||||||
|
ownership: dict[str, Any] | None = None,
|
||||||
|
import_matrix: dict[str, Any] | None = None,
|
||||||
|
) -> dict[str, Any]:
|
||||||
|
ownership = ownership or concept_ownership(context)
|
||||||
|
import_matrix = import_matrix or relationship_matrix(context)
|
||||||
|
files = [
|
||||||
|
_write_text(
|
||||||
|
context.infospace_root / "views" / "by-standard.md",
|
||||||
|
_render_by_standard(context),
|
||||||
|
),
|
||||||
|
_write_text(
|
||||||
|
context.infospace_root / "views" / "by-concept.md",
|
||||||
|
_render_by_concept(ownership),
|
||||||
|
),
|
||||||
|
_write_text(
|
||||||
|
context.infospace_root / "views" / "by-profile.md",
|
||||||
|
_render_by_profile(context),
|
||||||
|
),
|
||||||
|
_write_text(
|
||||||
|
context.infospace_root / "views" / "by-mapping-target.md",
|
||||||
|
_render_by_mapping_target(context),
|
||||||
|
),
|
||||||
|
_write_text(
|
||||||
|
context.infospace_root / "views" / "kernel-overview.md",
|
||||||
|
_render_kernel_overview(context),
|
||||||
|
),
|
||||||
|
_write_text(
|
||||||
|
context.infospace_root / "views" / "import-matrix.md",
|
||||||
|
_render_import_matrix(import_matrix),
|
||||||
|
),
|
||||||
|
]
|
||||||
|
return _result("views", files)
|
||||||
|
|
||||||
|
|
||||||
|
def generate_tree(context: Any) -> dict[str, Any]:
|
||||||
|
tree = artifact_tree(context)
|
||||||
|
files = [
|
||||||
|
_write_yaml(context.infospace_root / "indexes" / "artifact-tree.yaml", tree),
|
||||||
|
_write_text(
|
||||||
|
context.infospace_root / "views" / "repository-tree.md",
|
||||||
|
_render_repository_tree(tree),
|
||||||
|
),
|
||||||
|
]
|
||||||
|
return _result("tree", files)
|
||||||
|
|
||||||
|
|
||||||
|
def generate_agent_briefs(context: Any) -> dict[str, Any]:
|
||||||
|
files = [
|
||||||
|
_write_text(
|
||||||
|
context.infospace_root / "agent" / "global-agent-brief.md",
|
||||||
|
_render_global_agent_brief(context),
|
||||||
|
)
|
||||||
|
]
|
||||||
|
return _result("agent-briefs", files)
|
||||||
|
|
||||||
|
|
||||||
|
def list_generated_views(context: Any) -> dict[str, Any]:
|
||||||
|
views = []
|
||||||
|
for path in sorted((context.infospace_root / "views").glob("*.md")):
|
||||||
|
views.append(
|
||||||
|
{
|
||||||
|
"name": path.name,
|
||||||
|
"path": str(path.relative_to(context.infospace_root)),
|
||||||
|
"generated": _is_generated(path),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
return {"ok": True, "count": len(views), "views": views}
|
||||||
|
|
||||||
|
|
||||||
|
def read_generated_view(context: Any, name: str) -> dict[str, Any]:
|
||||||
|
if "/" in name or "\\" in name:
|
||||||
|
raise ValueError("View name must be a single file name.")
|
||||||
|
path = context.infospace_root / "views" / name
|
||||||
|
if not path.is_file():
|
||||||
|
raise FileNotFoundError(name)
|
||||||
|
return {
|
||||||
|
"ok": True,
|
||||||
|
"name": name,
|
||||||
|
"path": str(path.relative_to(context.infospace_root)),
|
||||||
|
"generated": _is_generated(path),
|
||||||
|
"content": path.read_text(encoding="utf-8"),
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def concept_ownership(context: Any) -> dict[str, Any]:
|
||||||
|
concepts: list[dict[str, Any]] = []
|
||||||
|
for artifact in sorted(context.infospace.artifacts, key=lambda item: item.id):
|
||||||
|
concepts.append(
|
||||||
|
{
|
||||||
|
"concept": artifact.title,
|
||||||
|
"owner": artifact.id,
|
||||||
|
"path": artifact.path,
|
||||||
|
"source": "artifact_title",
|
||||||
|
}
|
||||||
|
)
|
||||||
|
frontmatter = _frontmatter(context.infospace_root / artifact.path)
|
||||||
|
owned = frontmatter.get("owned_concepts") or []
|
||||||
|
if isinstance(owned, list):
|
||||||
|
for concept in owned:
|
||||||
|
concepts.append(
|
||||||
|
{
|
||||||
|
"concept": str(concept),
|
||||||
|
"owner": artifact.id,
|
||||||
|
"path": artifact.path,
|
||||||
|
"source": "frontmatter.owned_concepts",
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
by_key: dict[str, list[dict[str, Any]]] = defaultdict(list)
|
||||||
|
for item in concepts:
|
||||||
|
by_key[_normalize_concept(item["concept"])].append(item)
|
||||||
|
|
||||||
|
duplicates = [
|
||||||
|
{"normalized": key, "candidates": items}
|
||||||
|
for key, items in sorted(by_key.items())
|
||||||
|
if len(items) > 1
|
||||||
|
]
|
||||||
|
conflicts = [
|
||||||
|
{
|
||||||
|
"normalized": item["normalized"],
|
||||||
|
"owners": sorted({candidate["owner"] for candidate in item["candidates"]}),
|
||||||
|
"candidates": item["candidates"],
|
||||||
|
}
|
||||||
|
for item in duplicates
|
||||||
|
if len({candidate["owner"] for candidate in item["candidates"]}) > 1
|
||||||
|
]
|
||||||
|
return {
|
||||||
|
"concept_count": len(concepts),
|
||||||
|
"concepts": concepts,
|
||||||
|
"duplicate_candidates": duplicates,
|
||||||
|
"ownership_conflicts": conflicts,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def relationship_matrix(context: Any) -> dict[str, Any]:
|
||||||
|
artifact_ids = sorted(artifact.id for artifact in context.infospace.artifacts)
|
||||||
|
rows: list[dict[str, Any]] = []
|
||||||
|
for artifact in sorted(context.infospace.artifacts, key=lambda item: item.id):
|
||||||
|
targets: dict[str, list[str]] = {target: [] for target in artifact_ids}
|
||||||
|
for relationship in artifact.relationships:
|
||||||
|
target = relationship.get("target")
|
||||||
|
relation_type = str(relationship.get("type") or "related")
|
||||||
|
if isinstance(target, str) and target in targets:
|
||||||
|
targets[target].append(relation_type)
|
||||||
|
rows.append(
|
||||||
|
{
|
||||||
|
"artifact": artifact.id,
|
||||||
|
"targets": {
|
||||||
|
target: sorted(types)
|
||||||
|
for target, types in targets.items()
|
||||||
|
if types
|
||||||
|
},
|
||||||
|
}
|
||||||
|
)
|
||||||
|
return {"artifacts": artifact_ids, "rows": rows}
|
||||||
|
|
||||||
|
|
||||||
|
def artifact_tree(context: Any) -> dict[str, Any]:
|
||||||
|
files: list[dict[str, Any]] = []
|
||||||
|
for path in sorted(context.infospace_root.rglob("*")):
|
||||||
|
if path.is_file():
|
||||||
|
relative = path.relative_to(context.infospace_root)
|
||||||
|
files.append(
|
||||||
|
{
|
||||||
|
"path": str(relative),
|
||||||
|
"directory": str(relative.parent),
|
||||||
|
"name": path.name,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
return {"root": "infospace", "file_count": len(files), "files": files}
|
||||||
|
|
||||||
|
|
||||||
|
def _render_by_standard(context: Any) -> str:
|
||||||
|
lines = _heading("By Standard")
|
||||||
|
standards = [
|
||||||
|
artifact
|
||||||
|
for artifact in context.infospace.artifacts
|
||||||
|
if artifact.kind in {"kernel", "standard"}
|
||||||
|
]
|
||||||
|
for artifact in sorted(standards, key=lambda item: item.id):
|
||||||
|
lines.extend(
|
||||||
|
[
|
||||||
|
f"## {artifact.title}",
|
||||||
|
"",
|
||||||
|
f"- ID: `{artifact.id}`",
|
||||||
|
f"- Kind: `{artifact.kind}`",
|
||||||
|
f"- Path: `{artifact.path}`",
|
||||||
|
f"- Relationships: {len(artifact.relationships)}",
|
||||||
|
"",
|
||||||
|
]
|
||||||
|
)
|
||||||
|
return "\n".join(lines).rstrip() + "\n"
|
||||||
|
|
||||||
|
|
||||||
|
def _render_by_concept(ownership: dict[str, Any]) -> str:
|
||||||
|
lines = _heading("By Concept")
|
||||||
|
lines.extend(
|
||||||
|
[
|
||||||
|
f"Concept count: **{ownership['concept_count']}**",
|
||||||
|
"",
|
||||||
|
"| Concept | Owner | Source |",
|
||||||
|
"| --- | --- | --- |",
|
||||||
|
]
|
||||||
|
)
|
||||||
|
for concept in ownership["concepts"]:
|
||||||
|
lines.append(
|
||||||
|
f"| {concept['concept']} | `{concept['owner']}` | `{concept['source']}` |"
|
||||||
|
)
|
||||||
|
lines.extend(["", "## Duplicate Candidates", ""])
|
||||||
|
duplicates = ownership["duplicate_candidates"]
|
||||||
|
if not duplicates:
|
||||||
|
lines.append("No duplicate concept candidates detected.")
|
||||||
|
else:
|
||||||
|
for duplicate in duplicates:
|
||||||
|
lines.append(f"- `{duplicate['normalized']}`")
|
||||||
|
lines.extend(["", "## Ownership Conflicts", ""])
|
||||||
|
conflicts = ownership["ownership_conflicts"]
|
||||||
|
if not conflicts:
|
||||||
|
lines.append("No ownership conflicts detected.")
|
||||||
|
else:
|
||||||
|
for conflict in conflicts:
|
||||||
|
owners = ", ".join(f"`{owner}`" for owner in conflict["owners"])
|
||||||
|
lines.append(f"- `{conflict['normalized']}` owned by {owners}")
|
||||||
|
return "\n".join(lines).rstrip() + "\n"
|
||||||
|
|
||||||
|
|
||||||
|
def _render_by_profile(context: Any) -> str:
|
||||||
|
lines = _heading("By Profile")
|
||||||
|
profiles = sorted((context.infospace_root / "profiles").glob("*/profile.yaml"))
|
||||||
|
if not profiles:
|
||||||
|
lines.append("No profiles have been registered yet.")
|
||||||
|
for path in profiles:
|
||||||
|
lines.extend(
|
||||||
|
[
|
||||||
|
f"## {path.parent.name}",
|
||||||
|
"",
|
||||||
|
f"- Path: `{path.relative_to(context.infospace_root)}`",
|
||||||
|
"",
|
||||||
|
]
|
||||||
|
)
|
||||||
|
return "\n".join(lines).rstrip() + "\n"
|
||||||
|
|
||||||
|
|
||||||
|
def _render_by_mapping_target(context: Any) -> str:
|
||||||
|
incoming: dict[str, list[tuple[str, str]]] = defaultdict(list)
|
||||||
|
for artifact in context.infospace.artifacts:
|
||||||
|
for relationship in artifact.relationships:
|
||||||
|
target = relationship.get("target")
|
||||||
|
relation_type = str(relationship.get("type") or "related")
|
||||||
|
if isinstance(target, str):
|
||||||
|
incoming[target].append((artifact.id, relation_type))
|
||||||
|
lines = _heading("By Mapping Target")
|
||||||
|
for target in sorted(incoming):
|
||||||
|
lines.extend([f"## `{target}`", ""])
|
||||||
|
for source, relation_type in sorted(incoming[target]):
|
||||||
|
lines.append(f"- `{source}` via `{relation_type}`")
|
||||||
|
lines.append("")
|
||||||
|
return "\n".join(lines).rstrip() + "\n"
|
||||||
|
|
||||||
|
|
||||||
|
def _render_kernel_overview(context: Any) -> str:
|
||||||
|
kind_counts: dict[str, int] = defaultdict(int)
|
||||||
|
relationship_counts: dict[str, int] = defaultdict(int)
|
||||||
|
for artifact in context.infospace.artifacts:
|
||||||
|
kind_counts[artifact.kind] += 1
|
||||||
|
for relationship in artifact.relationships:
|
||||||
|
relationship_counts[str(relationship.get("type") or "related")] += 1
|
||||||
|
lines = _heading("Kernel Overview")
|
||||||
|
lines.extend(
|
||||||
|
[
|
||||||
|
f"- Infospace: `{context.infospace.config.slug}`",
|
||||||
|
f"- Artifacts: {len(context.infospace.artifacts)}",
|
||||||
|
"",
|
||||||
|
"## Artifact Kinds",
|
||||||
|
"",
|
||||||
|
]
|
||||||
|
)
|
||||||
|
for kind, count in sorted(kind_counts.items()):
|
||||||
|
lines.append(f"- `{kind}`: {count}")
|
||||||
|
lines.extend(["", "## Relationship Types", ""])
|
||||||
|
for relation_type, count in sorted(relationship_counts.items()):
|
||||||
|
lines.append(f"- `{relation_type}`: {count}")
|
||||||
|
return "\n".join(lines).rstrip() + "\n"
|
||||||
|
|
||||||
|
|
||||||
|
def _render_import_matrix(matrix: dict[str, Any]) -> str:
|
||||||
|
artifacts = matrix["artifacts"]
|
||||||
|
lines = _heading("Import Matrix")
|
||||||
|
header = "| Artifact | " + " | ".join(f"`{artifact}`" for artifact in artifacts) + " |"
|
||||||
|
divider = "| --- | " + " | ".join("---" for _ in artifacts) + " |"
|
||||||
|
lines.extend([header, divider])
|
||||||
|
for row in matrix["rows"]:
|
||||||
|
cells = []
|
||||||
|
targets = row["targets"]
|
||||||
|
for artifact in artifacts:
|
||||||
|
cells.append(", ".join(f"`{item}`" for item in targets.get(artifact, [])))
|
||||||
|
lines.append(f"| `{row['artifact']}` | " + " | ".join(cells) + " |")
|
||||||
|
return "\n".join(lines).rstrip() + "\n"
|
||||||
|
|
||||||
|
|
||||||
|
def _render_repository_tree(tree: dict[str, Any]) -> str:
|
||||||
|
lines = _heading("Repository Tree")
|
||||||
|
lines.append(f"File count: **{tree['file_count']}**")
|
||||||
|
lines.append("")
|
||||||
|
for file_info in tree["files"]:
|
||||||
|
lines.append(f"- `{file_info['path']}`")
|
||||||
|
return "\n".join(lines).rstrip() + "\n"
|
||||||
|
|
||||||
|
|
||||||
|
def _render_global_agent_brief(context: Any) -> str:
|
||||||
|
lines = _heading("Global Agent Brief")
|
||||||
|
lines.extend(
|
||||||
|
[
|
||||||
|
"This brief summarizes the current canon service surface for agents.",
|
||||||
|
"",
|
||||||
|
f"- Infospace slug: `{context.infospace.config.slug}`",
|
||||||
|
f"- Artifact count: {len(context.infospace.artifacts)}",
|
||||||
|
"- Primary confidence command: `make validate`",
|
||||||
|
"- Refresh generated indexes and views with: `make index`",
|
||||||
|
"",
|
||||||
|
"## Useful Commands",
|
||||||
|
"",
|
||||||
|
"- `PYTHONPATH=src python3 -m info_tech_canon inspect`",
|
||||||
|
"- `PYTHONPATH=src python3 -m info_tech_canon validate`",
|
||||||
|
"- `PYTHONPATH=src python3 -m info_tech_canon graph`",
|
||||||
|
"- `PYTHONPATH=src python3 -m info_tech_canon index`",
|
||||||
|
"",
|
||||||
|
"## Consumption Notes",
|
||||||
|
"",
|
||||||
|
"- Treat `seeds/` as provenance.",
|
||||||
|
"- Treat `infospace/` as the service-consumable canon root.",
|
||||||
|
"- Generated files are marked and can be refreshed deterministically.",
|
||||||
|
]
|
||||||
|
)
|
||||||
|
return "\n".join(lines).rstrip() + "\n"
|
||||||
|
|
||||||
|
|
||||||
|
def _heading(title: str) -> list[str]:
|
||||||
|
return [GENERATED_NOTICE, "", f"# {title}", ""]
|
||||||
|
|
||||||
|
|
||||||
|
def _write_text(path: Path, content: str) -> dict[str, Any]:
|
||||||
|
path.parent.mkdir(parents=True, exist_ok=True)
|
||||||
|
old = path.read_text(encoding="utf-8") if path.exists() else None
|
||||||
|
changed = old != content
|
||||||
|
if changed:
|
||||||
|
path.write_text(content, encoding="utf-8")
|
||||||
|
return {"path": str(path), "changed": changed}
|
||||||
|
|
||||||
|
|
||||||
|
def _write_yaml(path: Path, data: dict[str, Any]) -> dict[str, Any]:
|
||||||
|
path.parent.mkdir(parents=True, exist_ok=True)
|
||||||
|
content = yaml.safe_dump(data, sort_keys=False)
|
||||||
|
return _write_text(path, content)
|
||||||
|
|
||||||
|
|
||||||
|
def _result(kind: str, files: list[dict[str, Any]]) -> dict[str, Any]:
|
||||||
|
return {
|
||||||
|
"ok": True,
|
||||||
|
"kind": kind,
|
||||||
|
"count": len(files),
|
||||||
|
"changed": [item for item in files if item["changed"]],
|
||||||
|
"files": files,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def _frontmatter(path: Path) -> dict[str, Any]:
|
||||||
|
text = path.read_text(encoding="utf-8")
|
||||||
|
if not text.startswith("---\n"):
|
||||||
|
return {}
|
||||||
|
end = text.find("\n---\n", 4)
|
||||||
|
if end == -1:
|
||||||
|
return {}
|
||||||
|
data = yaml.safe_load(text[4:end]) or {}
|
||||||
|
return data if isinstance(data, dict) else {}
|
||||||
|
|
||||||
|
|
||||||
|
def _normalize_concept(value: str) -> str:
|
||||||
|
return "-".join(value.lower().replace("_", "-").split())
|
||||||
|
|
||||||
|
|
||||||
|
def _is_generated(path: Path) -> bool:
|
||||||
|
try:
|
||||||
|
return path.read_text(encoding="utf-8").startswith(GENERATED_NOTICE)
|
||||||
|
except FileNotFoundError:
|
||||||
|
return False
|
||||||
@@ -3,10 +3,12 @@ from __future__ import annotations
|
|||||||
from collections import Counter
|
from collections import Counter
|
||||||
from dataclasses import asdict, dataclass
|
from dataclasses import asdict, dataclass
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
import json
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
import yaml
|
import yaml
|
||||||
|
|
||||||
|
from . import generation
|
||||||
from .bench import (
|
from .bench import (
|
||||||
Infospace,
|
Infospace,
|
||||||
KnowledgeArtifact,
|
KnowledgeArtifact,
|
||||||
@@ -15,6 +17,7 @@ from .bench import (
|
|||||||
relationship_summary,
|
relationship_summary,
|
||||||
run_collection_checks,
|
run_collection_checks,
|
||||||
)
|
)
|
||||||
|
from .validation import structural_checks
|
||||||
|
|
||||||
|
|
||||||
REPO_ROOT = Path(__file__).resolve().parents[2]
|
REPO_ROOT = Path(__file__).resolve().parents[2]
|
||||||
@@ -121,6 +124,7 @@ def list_standards(root: Path | str | None = None) -> dict[str, Any]:
|
|||||||
def validate_canon(root: Path | str | None = None) -> dict[str, Any]:
|
def validate_canon(root: Path | str | None = None) -> dict[str, Any]:
|
||||||
context = load_context(root)
|
context = load_context(root)
|
||||||
errors: list[dict[str, Any]] = []
|
errors: list[dict[str, Any]] = []
|
||||||
|
warnings: list[dict[str, Any]] = []
|
||||||
|
|
||||||
artifact_ids = {artifact.id for artifact in context.infospace.artifacts}
|
artifact_ids = {artifact.id for artifact in context.infospace.artifacts}
|
||||||
for artifact in context.infospace.artifacts:
|
for artifact in context.infospace.artifacts:
|
||||||
@@ -161,15 +165,31 @@ def validate_canon(root: Path | str | None = None) -> dict[str, Any]:
|
|||||||
context.infospace.config.viability,
|
context.infospace.config.viability,
|
||||||
)
|
)
|
||||||
errors.extend(threshold_errors)
|
errors.extend(threshold_errors)
|
||||||
|
structural = structural_checks(context)
|
||||||
|
errors.extend(structural["errors"])
|
||||||
|
warnings.extend(structural["warnings"])
|
||||||
|
|
||||||
return {
|
return {
|
||||||
"ok": not errors,
|
"ok": not errors,
|
||||||
"errors": errors,
|
"errors": errors,
|
||||||
|
"warnings": warnings,
|
||||||
"metrics": checks.metrics,
|
"metrics": checks.metrics,
|
||||||
"details": checks.details,
|
"details": checks.details,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def write_validation_report(
|
||||||
|
destination: Path | str,
|
||||||
|
root: Path | str | None = None,
|
||||||
|
) -> dict[str, Any]:
|
||||||
|
payload = validate_canon(root)
|
||||||
|
path = Path(destination)
|
||||||
|
path.parent.mkdir(parents=True, exist_ok=True)
|
||||||
|
path.write_text(json.dumps(payload, indent=2, sort_keys=True) + "\n", encoding="utf-8")
|
||||||
|
payload["report_path"] = str(path)
|
||||||
|
return payload
|
||||||
|
|
||||||
|
|
||||||
def artifact_graph(
|
def artifact_graph(
|
||||||
root: Path | str | None = None,
|
root: Path | str | None = None,
|
||||||
*,
|
*,
|
||||||
@@ -221,6 +241,39 @@ def profile_inspect(
|
|||||||
return {"ok": True, "profile": data, "path": str(profile_path)}
|
return {"ok": True, "profile": data, "path": str(profile_path)}
|
||||||
|
|
||||||
|
|
||||||
|
def generate_indexes(root: Path | str | None = None) -> dict[str, Any]:
|
||||||
|
return generation.generate_indexes(load_context(root))
|
||||||
|
|
||||||
|
|
||||||
|
def generate_tree(root: Path | str | None = None) -> dict[str, Any]:
|
||||||
|
return generation.generate_tree(load_context(root))
|
||||||
|
|
||||||
|
|
||||||
|
def generate_agent_briefs(root: Path | str | None = None) -> dict[str, Any]:
|
||||||
|
return generation.generate_agent_briefs(load_context(root))
|
||||||
|
|
||||||
|
|
||||||
|
def list_views(root: Path | str | None = None) -> dict[str, Any]:
|
||||||
|
return generation.list_generated_views(load_context(root))
|
||||||
|
|
||||||
|
|
||||||
|
def read_view(name: str, root: Path | str | None = None) -> dict[str, Any]:
|
||||||
|
try:
|
||||||
|
return generation.read_generated_view(load_context(root), name)
|
||||||
|
except FileNotFoundError as exc:
|
||||||
|
raise CanonServiceError(
|
||||||
|
"missing_view",
|
||||||
|
f"View not found: {name}",
|
||||||
|
{"view": name},
|
||||||
|
) from exc
|
||||||
|
except ValueError as exc:
|
||||||
|
raise CanonServiceError(
|
||||||
|
"invalid_view_name",
|
||||||
|
str(exc),
|
||||||
|
{"view": name},
|
||||||
|
) from exc
|
||||||
|
|
||||||
|
|
||||||
def _artifact_to_dict(
|
def _artifact_to_dict(
|
||||||
artifact: KnowledgeArtifact,
|
artifact: KnowledgeArtifact,
|
||||||
infospace_root: Path,
|
infospace_root: Path,
|
||||||
|
|||||||
360
src/info_tech_canon/validation.py
Normal file
360
src/info_tech_canon/validation.py
Normal file
@@ -0,0 +1,360 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from pathlib import Path
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
|
import yaml
|
||||||
|
|
||||||
|
|
||||||
|
REQUIRED_TOP_LEVEL_FILES = (
|
||||||
|
"README.md",
|
||||||
|
"INTENT.md",
|
||||||
|
"SCOPE.md",
|
||||||
|
"canon.yaml",
|
||||||
|
"pyproject.toml",
|
||||||
|
"workplans/index.yaml",
|
||||||
|
"infospace/infospace.yaml",
|
||||||
|
"infospace/artifacts/index.yaml",
|
||||||
|
)
|
||||||
|
|
||||||
|
REQUIRED_INFOSPACE_DIRS = (
|
||||||
|
"kernel",
|
||||||
|
"models",
|
||||||
|
"standards",
|
||||||
|
"profiles",
|
||||||
|
"patterns",
|
||||||
|
"mappings",
|
||||||
|
"assimilation",
|
||||||
|
"schemas",
|
||||||
|
"views",
|
||||||
|
"agent",
|
||||||
|
"examples",
|
||||||
|
"validation",
|
||||||
|
"indexes",
|
||||||
|
)
|
||||||
|
|
||||||
|
OPTIONAL_COLLECTION_DIRS = (
|
||||||
|
"profiles",
|
||||||
|
"patterns",
|
||||||
|
"mappings",
|
||||||
|
"assimilation",
|
||||||
|
"examples",
|
||||||
|
)
|
||||||
|
|
||||||
|
REQUIRED_SCHEMAS = (
|
||||||
|
"standard.schema.yaml",
|
||||||
|
"concept.schema.yaml",
|
||||||
|
"mapping.schema.yaml",
|
||||||
|
"profile.schema.yaml",
|
||||||
|
"assimilation.schema.yaml",
|
||||||
|
"interface-card.schema.yaml",
|
||||||
|
"agent-brief.schema.yaml",
|
||||||
|
"workplan.schema.yaml",
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def structural_checks(context: Any) -> dict[str, list[dict[str, Any]]]:
|
||||||
|
errors: list[dict[str, Any]] = []
|
||||||
|
warnings: list[dict[str, Any]] = []
|
||||||
|
|
||||||
|
_check_required_top_level_files(context.repo_root, errors)
|
||||||
|
_check_required_infospace_dirs(context.infospace_root, errors)
|
||||||
|
_check_required_schemas(context.infospace_root, errors)
|
||||||
|
_check_canon_paths(context.repo_root, context.infospace_root, errors)
|
||||||
|
_check_artifact_index(context.repo_root, context.infospace_root, errors)
|
||||||
|
_check_optional_assets(context.infospace_root, warnings)
|
||||||
|
|
||||||
|
return {"errors": errors, "warnings": warnings}
|
||||||
|
|
||||||
|
|
||||||
|
def _check_required_top_level_files(
|
||||||
|
repo_root: Path,
|
||||||
|
errors: list[dict[str, Any]],
|
||||||
|
) -> None:
|
||||||
|
for relative in REQUIRED_TOP_LEVEL_FILES:
|
||||||
|
if not (repo_root / relative).is_file():
|
||||||
|
errors.append(
|
||||||
|
{
|
||||||
|
"code": "missing_required_file",
|
||||||
|
"path": relative,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def _check_required_infospace_dirs(
|
||||||
|
infospace_root: Path,
|
||||||
|
errors: list[dict[str, Any]],
|
||||||
|
) -> None:
|
||||||
|
for relative in REQUIRED_INFOSPACE_DIRS:
|
||||||
|
if not (infospace_root / relative).is_dir():
|
||||||
|
errors.append(
|
||||||
|
{
|
||||||
|
"code": "missing_required_infospace_dir",
|
||||||
|
"path": str(Path("infospace") / relative),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def _check_required_schemas(
|
||||||
|
infospace_root: Path,
|
||||||
|
errors: list[dict[str, Any]],
|
||||||
|
) -> None:
|
||||||
|
for filename in REQUIRED_SCHEMAS:
|
||||||
|
if not (infospace_root / "schemas" / filename).is_file():
|
||||||
|
errors.append(
|
||||||
|
{
|
||||||
|
"code": "missing_schema",
|
||||||
|
"path": str(Path("infospace") / "schemas" / filename),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def _check_canon_paths(
|
||||||
|
repo_root: Path,
|
||||||
|
infospace_root: Path,
|
||||||
|
errors: list[dict[str, Any]],
|
||||||
|
) -> None:
|
||||||
|
canon_path = repo_root / "canon.yaml"
|
||||||
|
canon = _read_yaml(canon_path, errors)
|
||||||
|
if not isinstance(canon, dict):
|
||||||
|
return
|
||||||
|
|
||||||
|
indexed_paths = _artifact_paths_by_path(infospace_root, errors)
|
||||||
|
for section in ("kernel", "models", "standards"):
|
||||||
|
items = canon.get(section) or []
|
||||||
|
if not isinstance(items, list):
|
||||||
|
errors.append(
|
||||||
|
{
|
||||||
|
"code": "invalid_canon_section",
|
||||||
|
"section": section,
|
||||||
|
"message": "Expected a list.",
|
||||||
|
}
|
||||||
|
)
|
||||||
|
continue
|
||||||
|
for item in items:
|
||||||
|
if not isinstance(item, dict):
|
||||||
|
errors.append(
|
||||||
|
{
|
||||||
|
"code": "invalid_canon_entry",
|
||||||
|
"section": section,
|
||||||
|
"message": "Expected a mapping.",
|
||||||
|
}
|
||||||
|
)
|
||||||
|
continue
|
||||||
|
path = str(item.get("path") or "")
|
||||||
|
if not path:
|
||||||
|
errors.append(
|
||||||
|
{
|
||||||
|
"code": "missing_canon_path",
|
||||||
|
"section": section,
|
||||||
|
"id": item.get("id"),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
continue
|
||||||
|
if not (repo_root / path).is_file():
|
||||||
|
errors.append(
|
||||||
|
{
|
||||||
|
"code": "missing_canon_path_target",
|
||||||
|
"section": section,
|
||||||
|
"id": item.get("id"),
|
||||||
|
"path": path,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
relative_infospace_path = _strip_infospace_prefix(path)
|
||||||
|
if relative_infospace_path not in indexed_paths:
|
||||||
|
errors.append(
|
||||||
|
{
|
||||||
|
"code": "canon_path_not_indexed",
|
||||||
|
"section": section,
|
||||||
|
"id": item.get("id"),
|
||||||
|
"path": path,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def _check_artifact_index(
|
||||||
|
repo_root: Path,
|
||||||
|
infospace_root: Path,
|
||||||
|
errors: list[dict[str, Any]],
|
||||||
|
) -> None:
|
||||||
|
index_path = infospace_root / "artifacts" / "index.yaml"
|
||||||
|
index = _read_yaml(index_path, errors)
|
||||||
|
if not isinstance(index, dict):
|
||||||
|
return
|
||||||
|
artifacts = index.get("artifacts")
|
||||||
|
if not isinstance(artifacts, list):
|
||||||
|
errors.append(
|
||||||
|
{
|
||||||
|
"code": "invalid_artifact_index",
|
||||||
|
"path": "infospace/artifacts/index.yaml",
|
||||||
|
"message": "Expected artifacts list.",
|
||||||
|
}
|
||||||
|
)
|
||||||
|
return
|
||||||
|
|
||||||
|
ids: set[str] = set()
|
||||||
|
for artifact in artifacts:
|
||||||
|
if not isinstance(artifact, dict):
|
||||||
|
errors.append(
|
||||||
|
{
|
||||||
|
"code": "invalid_artifact_entry",
|
||||||
|
"message": "Expected artifact mapping.",
|
||||||
|
}
|
||||||
|
)
|
||||||
|
continue
|
||||||
|
artifact_id = str(artifact.get("id") or "")
|
||||||
|
if not artifact_id:
|
||||||
|
errors.append({"code": "missing_artifact_id"})
|
||||||
|
elif artifact_id in ids:
|
||||||
|
errors.append(
|
||||||
|
{
|
||||||
|
"code": "duplicate_artifact_id",
|
||||||
|
"artifact_id": artifact_id,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
ids.add(artifact_id)
|
||||||
|
|
||||||
|
for field in ("path", "kind", "title"):
|
||||||
|
if not artifact.get(field):
|
||||||
|
errors.append(
|
||||||
|
{
|
||||||
|
"code": "missing_artifact_field",
|
||||||
|
"artifact_id": artifact_id,
|
||||||
|
"field": field,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
relative_path = str(artifact.get("path") or "")
|
||||||
|
if relative_path and not (infospace_root / relative_path).is_file():
|
||||||
|
errors.append(
|
||||||
|
{
|
||||||
|
"code": "missing_artifact_path",
|
||||||
|
"artifact_id": artifact_id,
|
||||||
|
"path": relative_path,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
provenance = artifact.get("provenance") or {}
|
||||||
|
if isinstance(provenance, dict):
|
||||||
|
source_path = provenance.get("source_path")
|
||||||
|
if isinstance(source_path, str) and source_path:
|
||||||
|
if not (repo_root / source_path).is_file():
|
||||||
|
errors.append(
|
||||||
|
{
|
||||||
|
"code": "missing_provenance_source",
|
||||||
|
"artifact_id": artifact_id,
|
||||||
|
"source_path": source_path,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
for artifact in artifacts:
|
||||||
|
if not isinstance(artifact, dict):
|
||||||
|
continue
|
||||||
|
artifact_id = str(artifact.get("id") or "")
|
||||||
|
relationships = artifact.get("relationships") or []
|
||||||
|
if not isinstance(relationships, list):
|
||||||
|
errors.append(
|
||||||
|
{
|
||||||
|
"code": "invalid_relationships",
|
||||||
|
"artifact_id": artifact_id,
|
||||||
|
"message": "Expected relationship list.",
|
||||||
|
}
|
||||||
|
)
|
||||||
|
continue
|
||||||
|
for relationship in relationships:
|
||||||
|
if not isinstance(relationship, dict):
|
||||||
|
errors.append(
|
||||||
|
{
|
||||||
|
"code": "invalid_relationship",
|
||||||
|
"artifact_id": artifact_id,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
continue
|
||||||
|
target = relationship.get("target")
|
||||||
|
if target not in ids:
|
||||||
|
errors.append(
|
||||||
|
{
|
||||||
|
"code": "missing_relationship_target",
|
||||||
|
"artifact_id": artifact_id,
|
||||||
|
"target": target,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def _check_optional_assets(
|
||||||
|
infospace_root: Path,
|
||||||
|
warnings: list[dict[str, Any]],
|
||||||
|
) -> None:
|
||||||
|
global_brief = infospace_root / "agent" / "global-agent-brief.md"
|
||||||
|
if not global_brief.is_file():
|
||||||
|
warnings.append(
|
||||||
|
{
|
||||||
|
"code": "missing_optional_agent_brief",
|
||||||
|
"path": "infospace/agent/global-agent-brief.md",
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
concepts_dir = infospace_root / "concepts"
|
||||||
|
if not concepts_dir.is_dir():
|
||||||
|
warnings.append(
|
||||||
|
{
|
||||||
|
"code": "missing_optional_concepts_dir",
|
||||||
|
"path": "infospace/concepts",
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
for relative in OPTIONAL_COLLECTION_DIRS:
|
||||||
|
directory = infospace_root / relative
|
||||||
|
if directory.is_dir() and not _has_substantive_files(directory):
|
||||||
|
warnings.append(
|
||||||
|
{
|
||||||
|
"code": "empty_optional_collection",
|
||||||
|
"path": str(Path("infospace") / relative),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def _artifact_paths_by_path(
|
||||||
|
infospace_root: Path,
|
||||||
|
errors: list[dict[str, Any]],
|
||||||
|
) -> set[str]:
|
||||||
|
index = _read_yaml(infospace_root / "artifacts" / "index.yaml", errors)
|
||||||
|
if not isinstance(index, dict):
|
||||||
|
return set()
|
||||||
|
artifacts = index.get("artifacts") or []
|
||||||
|
if not isinstance(artifacts, list):
|
||||||
|
return set()
|
||||||
|
return {
|
||||||
|
str(artifact.get("path"))
|
||||||
|
for artifact in artifacts
|
||||||
|
if isinstance(artifact, dict) and artifact.get("path")
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def _read_yaml(path: Path, errors: list[dict[str, Any]]) -> Any:
|
||||||
|
try:
|
||||||
|
with path.open("r", encoding="utf-8") as handle:
|
||||||
|
return yaml.safe_load(handle) or {}
|
||||||
|
except FileNotFoundError:
|
||||||
|
errors.append({"code": "missing_yaml", "path": str(path)})
|
||||||
|
except yaml.YAMLError as exc:
|
||||||
|
errors.append(
|
||||||
|
{
|
||||||
|
"code": "invalid_yaml",
|
||||||
|
"path": str(path),
|
||||||
|
"message": str(exc),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def _strip_infospace_prefix(path: str) -> str:
|
||||||
|
prefix = "infospace/"
|
||||||
|
return path[len(prefix) :] if path.startswith(prefix) else path
|
||||||
|
|
||||||
|
|
||||||
|
def _has_substantive_files(directory: Path) -> bool:
|
||||||
|
for path in directory.rglob("*"):
|
||||||
|
if path.is_file() and path.name != "README.md":
|
||||||
|
return True
|
||||||
|
return False
|
||||||
@@ -1,6 +1,8 @@
|
|||||||
from http import HTTPStatus
|
from http import HTTPStatus
|
||||||
|
import shutil
|
||||||
|
|
||||||
from info_tech_canon.api import _route
|
from info_tech_canon.api import _route
|
||||||
|
from info_tech_canon.service import DEFAULT_INFOSPACE_ROOT, generate_indexes
|
||||||
|
|
||||||
|
|
||||||
def test_api_route_inspect() -> None:
|
def test_api_route_inspect() -> None:
|
||||||
@@ -24,3 +26,16 @@ def test_api_route_unknown_endpoint() -> None:
|
|||||||
assert status == HTTPStatus.NOT_FOUND
|
assert status == HTTPStatus.NOT_FOUND
|
||||||
assert payload["ok"] is False
|
assert payload["ok"] is False
|
||||||
assert payload["error"]["code"] == "not_found"
|
assert payload["error"]["code"] == "not_found"
|
||||||
|
|
||||||
|
|
||||||
|
def test_api_route_reads_generated_view(tmp_path) -> None:
|
||||||
|
root = tmp_path / "infospace"
|
||||||
|
shutil.copytree(DEFAULT_INFOSPACE_ROOT, root)
|
||||||
|
generate_indexes(root)
|
||||||
|
|
||||||
|
status, payload = _route("/views/by-standard.md", {}, root)
|
||||||
|
|
||||||
|
assert status == HTTPStatus.OK
|
||||||
|
assert payload["ok"] is True
|
||||||
|
assert payload["generated"] is True
|
||||||
|
assert "# By Standard" in payload["content"]
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
import json
|
import json
|
||||||
|
import shutil
|
||||||
|
|
||||||
from info_tech_canon.cli import main
|
from info_tech_canon.cli import main
|
||||||
|
from info_tech_canon.service import DEFAULT_INFOSPACE_ROOT
|
||||||
|
|
||||||
|
|
||||||
def test_cli_inspect_emits_json(capsys) -> None:
|
def test_cli_inspect_emits_json(capsys) -> None:
|
||||||
@@ -19,3 +21,15 @@ def test_cli_missing_profile_uses_structured_error(capsys) -> None:
|
|||||||
payload = json.loads(capsys.readouterr().out)
|
payload = json.loads(capsys.readouterr().out)
|
||||||
assert payload["ok"] is False
|
assert payload["ok"] is False
|
||||||
assert payload["error"]["code"] == "missing_profile"
|
assert payload["error"]["code"] == "missing_profile"
|
||||||
|
|
||||||
|
|
||||||
|
def test_cli_index_generates_views(capsys, tmp_path) -> None:
|
||||||
|
root = tmp_path / "infospace"
|
||||||
|
shutil.copytree(DEFAULT_INFOSPACE_ROOT, root)
|
||||||
|
|
||||||
|
exit_code = main(["--root", str(root), "index"])
|
||||||
|
|
||||||
|
assert exit_code == 0
|
||||||
|
payload = json.loads(capsys.readouterr().out)
|
||||||
|
assert payload["ok"] is True
|
||||||
|
assert (root / "views" / "kernel-overview.md").is_file()
|
||||||
|
|||||||
@@ -1,10 +1,15 @@
|
|||||||
from info_tech_canon.service import (
|
from info_tech_canon.service import (
|
||||||
artifact_graph,
|
artifact_graph,
|
||||||
|
generate_agent_briefs,
|
||||||
|
generate_indexes,
|
||||||
|
generate_tree,
|
||||||
inspect_canon,
|
inspect_canon,
|
||||||
list_models,
|
list_models,
|
||||||
list_standards,
|
list_standards,
|
||||||
validate_canon,
|
validate_canon,
|
||||||
)
|
)
|
||||||
|
from info_tech_canon.service import DEFAULT_INFOSPACE_ROOT
|
||||||
|
import shutil
|
||||||
|
|
||||||
|
|
||||||
def test_inspect_canon_counts_artifact_kinds() -> None:
|
def test_inspect_canon_counts_artifact_kinds() -> None:
|
||||||
@@ -30,6 +35,7 @@ def test_validate_canon_passes_scaffold() -> None:
|
|||||||
|
|
||||||
assert payload["ok"] is True
|
assert payload["ok"] is True
|
||||||
assert payload["errors"] == []
|
assert payload["errors"] == []
|
||||||
|
assert "warnings" in payload
|
||||||
assert payload["details"]["artifact_count"] == 15
|
assert payload["details"]["artifact_count"] == 15
|
||||||
|
|
||||||
|
|
||||||
@@ -39,3 +45,21 @@ def test_graph_exports_relationship_summary() -> None:
|
|||||||
assert payload["ok"] is True
|
assert payload["ok"] is True
|
||||||
assert payload["graph"]["node_count"] == 15
|
assert payload["graph"]["node_count"] == 15
|
||||||
assert payload["graph"]["edge_count"] > 15
|
assert payload["graph"]["edge_count"] > 15
|
||||||
|
|
||||||
|
|
||||||
|
def test_generators_write_expected_assets(tmp_path) -> None:
|
||||||
|
root = tmp_path / "infospace"
|
||||||
|
shutil.copytree(DEFAULT_INFOSPACE_ROOT, root)
|
||||||
|
|
||||||
|
index_payload = generate_indexes(root)
|
||||||
|
tree_payload = generate_tree(root)
|
||||||
|
brief_payload = generate_agent_briefs(root)
|
||||||
|
|
||||||
|
assert index_payload["ok"] is True
|
||||||
|
assert tree_payload["ok"] is True
|
||||||
|
assert brief_payload["ok"] is True
|
||||||
|
assert (root / "indexes" / "concept-ownership.yaml").is_file()
|
||||||
|
assert (root / "views" / "by-standard.md").read_text(
|
||||||
|
encoding="utf-8"
|
||||||
|
).startswith("<!-- GENERATED")
|
||||||
|
assert (root / "agent" / "global-agent-brief.md").is_file()
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ type: workplan
|
|||||||
title: "Validation Indexes And Generated Views"
|
title: "Validation Indexes And Generated Views"
|
||||||
domain: canon
|
domain: canon
|
||||||
repo: info-tech-canon
|
repo: info-tech-canon
|
||||||
status: proposed
|
status: finished
|
||||||
priority: high
|
priority: high
|
||||||
created: "2026-05-23"
|
created: "2026-05-23"
|
||||||
updated: "2026-05-23"
|
updated: "2026-05-23"
|
||||||
@@ -33,7 +33,7 @@ inconsistencies should fail visibly.
|
|||||||
|
|
||||||
```task
|
```task
|
||||||
id: ITC-WP-0003-T01
|
id: ITC-WP-0003-T01
|
||||||
status: todo
|
status: done
|
||||||
priority: high
|
priority: high
|
||||||
state_hub_task_id: "246d5671-9585-43e1-880c-cc4ce728459f"
|
state_hub_task_id: "246d5671-9585-43e1-880c-cc4ce728459f"
|
||||||
```
|
```
|
||||||
@@ -47,7 +47,7 @@ state_hub_task_id: "246d5671-9585-43e1-880c-cc4ce728459f"
|
|||||||
|
|
||||||
```task
|
```task
|
||||||
id: ITC-WP-0003-T02
|
id: ITC-WP-0003-T02
|
||||||
status: todo
|
status: done
|
||||||
priority: high
|
priority: high
|
||||||
state_hub_task_id: "8db6058f-754f-4d92-a93f-d4119b2cad55"
|
state_hub_task_id: "8db6058f-754f-4d92-a93f-d4119b2cad55"
|
||||||
```
|
```
|
||||||
@@ -62,7 +62,7 @@ state_hub_task_id: "8db6058f-754f-4d92-a93f-d4119b2cad55"
|
|||||||
|
|
||||||
```task
|
```task
|
||||||
id: ITC-WP-0003-T03
|
id: ITC-WP-0003-T03
|
||||||
status: todo
|
status: done
|
||||||
priority: high
|
priority: high
|
||||||
state_hub_task_id: "ea3c6e98-fb3c-44fd-9f54-9a934ab62455"
|
state_hub_task_id: "ea3c6e98-fb3c-44fd-9f54-9a934ab62455"
|
||||||
```
|
```
|
||||||
@@ -81,7 +81,7 @@ state_hub_task_id: "ea3c6e98-fb3c-44fd-9f54-9a934ab62455"
|
|||||||
|
|
||||||
```task
|
```task
|
||||||
id: ITC-WP-0003-T04
|
id: ITC-WP-0003-T04
|
||||||
status: todo
|
status: done
|
||||||
priority: high
|
priority: high
|
||||||
state_hub_task_id: "b33bbda7-8ec6-48b2-a637-571a87473c5a"
|
state_hub_task_id: "b33bbda7-8ec6-48b2-a637-571a87473c5a"
|
||||||
```
|
```
|
||||||
@@ -97,7 +97,7 @@ state_hub_task_id: "b33bbda7-8ec6-48b2-a637-571a87473c5a"
|
|||||||
|
|
||||||
```task
|
```task
|
||||||
id: ITC-WP-0003-T05
|
id: ITC-WP-0003-T05
|
||||||
status: todo
|
status: done
|
||||||
priority: medium
|
priority: medium
|
||||||
state_hub_task_id: "01469609-91fb-48e3-b6e5-11e6342b29af"
|
state_hub_task_id: "01469609-91fb-48e3-b6e5-11e6342b29af"
|
||||||
```
|
```
|
||||||
@@ -113,3 +113,15 @@ state_hub_task_id: "01469609-91fb-48e3-b6e5-11e6342b29af"
|
|||||||
- Validation produces machine-readable output.
|
- Validation produces machine-readable output.
|
||||||
- Generated views can be refreshed deterministically.
|
- Generated views can be refreshed deterministically.
|
||||||
- Concept ownership can be inspected even before all concept pages exist.
|
- Concept ownership can be inspected even before all concept pages exist.
|
||||||
|
|
||||||
|
## Implementation Notes
|
||||||
|
|
||||||
|
- Added `make validate`, `make index`, `make tree`, and `make agent-briefs`.
|
||||||
|
- Added structural validation for required files, infospace directories,
|
||||||
|
`canon.yaml` paths, schema presence, artifact index integrity, relationship
|
||||||
|
targets, and optional collection warnings.
|
||||||
|
- Added initial schemas for standards, concepts, mappings, profiles,
|
||||||
|
assimilation records, interface cards, agent briefs, and workplans.
|
||||||
|
- Added deterministic generated views and indexes for standards, concepts,
|
||||||
|
profiles, mapping targets, kernel overview, import matrix, artifact tree, and
|
||||||
|
global agent guidance.
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ workplans:
|
|||||||
|
|
||||||
- id: ITC-WP-0003
|
- id: ITC-WP-0003
|
||||||
title: Validation Indexes And Generated Views
|
title: Validation Indexes And Generated Views
|
||||||
status: proposed
|
status: finished
|
||||||
priority: high
|
priority: high
|
||||||
path: workplans/ITC-WP-0003-validation-indexes-and-generated-views.md
|
path: workplans/ITC-WP-0003-validation-indexes-and-generated-views.md
|
||||||
depends_on:
|
depends_on:
|
||||||
|
|||||||
Reference in New Issue
Block a user