generated from coulomb/repo-seed
Implement infospace scaffold and service baseline
This commit is contained in:
42
README.md
42
README.md
@@ -1 +1,41 @@
|
||||
Building interoperable, adaptable, and extensible information-processing systems.
|
||||
Building interoperable, adaptable, and extensible information-processing systems.
|
||||
|
||||
## Current Service
|
||||
|
||||
This repository now implements one concrete infospace under `infospace/`.
|
||||
The repository root remains the service, governance, and workplan shell.
|
||||
|
||||
The first service surface is intentionally small:
|
||||
|
||||
- JSON-first CLI commands
|
||||
- importable Python service functions
|
||||
- read-only local HTTP API
|
||||
- artifact loading, checks, and graph summaries backed by `infospace-bench`
|
||||
|
||||
## Source-Tree Usage
|
||||
|
||||
```bash
|
||||
PYTHONPATH=src python3 -m info_tech_canon inspect
|
||||
PYTHONPATH=src python3 -m info_tech_canon artifacts
|
||||
PYTHONPATH=src python3 -m info_tech_canon models
|
||||
PYTHONPATH=src python3 -m info_tech_canon standards
|
||||
PYTHONPATH=src python3 -m info_tech_canon validate
|
||||
PYTHONPATH=src python3 -m info_tech_canon graph
|
||||
PYTHONPATH=src python3 -m info_tech_canon api --host 127.0.0.1 --port 8765
|
||||
```
|
||||
|
||||
After package installation, the same commands are available through the
|
||||
`info-tech-canon` console script.
|
||||
|
||||
## API Endpoints
|
||||
|
||||
- `GET /health`
|
||||
- `GET /inspect`
|
||||
- `GET /artifacts`
|
||||
- `GET /artifacts?kind=model`
|
||||
- `GET /models`
|
||||
- `GET /standards`
|
||||
- `GET /validate`
|
||||
- `GET /graph`
|
||||
- `GET /graph?format=mermaid`
|
||||
- `GET /profiles/{profile}/inspect`
|
||||
|
||||
11
canon.yaml
11
canon.yaml
@@ -1,7 +1,7 @@
|
||||
repository: info-tech-canon
|
||||
title: InfoTechCanon
|
||||
status: seed-kernel
|
||||
version: RC1-seed
|
||||
status: service-baseline
|
||||
version: 0.1.0-scaffold
|
||||
description: >
|
||||
An evolving, markdown-first canon for building interoperable, adaptable,
|
||||
and extensible information-processing systems.
|
||||
@@ -16,12 +16,15 @@ layout:
|
||||
- Seed files remain provenance until scaffold migration is reviewed.
|
||||
|
||||
service_surface:
|
||||
planned:
|
||||
implemented:
|
||||
- cli
|
||||
- json
|
||||
- api
|
||||
implementation_basis:
|
||||
- infospace-bench
|
||||
package: info_tech_canon
|
||||
cli_module: info_tech_canon.cli
|
||||
api_module: info_tech_canon.api
|
||||
|
||||
classification:
|
||||
kernel:
|
||||
@@ -135,8 +138,6 @@ first_proofs:
|
||||
- caring-kubernetes-rbac
|
||||
|
||||
next_actions:
|
||||
- implement ITC-WP-0001 infospace scaffold
|
||||
- implement ITC-WP-0002 service surface
|
||||
- implement ITC-WP-0003 validation and generated views
|
||||
- implement ITC-WP-0004 small-saas profile proof
|
||||
- explore ITC-WP-0006 PURPOSES model extension
|
||||
|
||||
8
infospace/README.md
Normal file
8
infospace/README.md
Normal file
@@ -0,0 +1,8 @@
|
||||
# InfoTechCanon Infospace
|
||||
|
||||
This directory is the single concrete infospace implemented by this repository.
|
||||
The repository root remains the service, governance, and workplan shell.
|
||||
|
||||
The current placement pass copies the seed documents into canonical
|
||||
`kernel/`, `models/`, and `standards/` paths while keeping `seeds/` as
|
||||
provenance until the scaffold migration is reviewed.
|
||||
3
infospace/agent/README.md
Normal file
3
infospace/agent/README.md
Normal file
@@ -0,0 +1,3 @@
|
||||
# Agent
|
||||
|
||||
Agent-facing briefs and interface cards live here.
|
||||
226
infospace/artifacts/index.yaml
Normal file
226
infospace/artifacts/index.yaml
Normal file
@@ -0,0 +1,226 @@
|
||||
artifacts:
|
||||
- id: kernel/itc-core
|
||||
path: kernel/InfoTechCanonCore.md
|
||||
kind: kernel
|
||||
title: InfoTechCanon Core
|
||||
provenance:
|
||||
source_path: seeds/InfoTechCanonCore_RC1_seed.md
|
||||
placement: copied
|
||||
placement_workplan: ITC-WP-0001
|
||||
relationships: []
|
||||
- id: kernel/itc-kernel-map
|
||||
path: kernel/InfoTechCanonKernelMap.md
|
||||
kind: kernel
|
||||
title: InfoTechCanon Kernel Map
|
||||
provenance:
|
||||
source_path: seeds/InfoTechCanonKernelMap_RC1.md
|
||||
placement: copied
|
||||
placement_workplan: ITC-WP-0001
|
||||
relationships:
|
||||
- type: maps
|
||||
target: kernel/itc-core
|
||||
- type: maps
|
||||
target: model/information-space
|
||||
- type: maps
|
||||
target: model/landscape
|
||||
- type: maps
|
||||
target: model/organization
|
||||
- type: maps
|
||||
target: model/governance
|
||||
- type: maps
|
||||
target: model/task
|
||||
- type: maps
|
||||
target: model/access-control
|
||||
- type: maps
|
||||
target: model/security
|
||||
- type: maps
|
||||
target: model/data
|
||||
- type: maps
|
||||
target: model/devsecops
|
||||
- type: maps
|
||||
target: model/network
|
||||
- type: maps
|
||||
target: model/observability
|
||||
- type: maps
|
||||
target: standard/tagging
|
||||
- type: maps
|
||||
target: standard/caring
|
||||
- id: model/information-space
|
||||
path: models/information-space/InfoTechCanonInformationSpaceModel.md
|
||||
kind: model
|
||||
title: InfoTechCanon Information Space Model
|
||||
provenance:
|
||||
source_path: seeds/InfoTechCanonInformationSpaceModel_RC1_seed.md
|
||||
placement: copied
|
||||
placement_workplan: ITC-WP-0001
|
||||
relationships:
|
||||
- type: conforms_to
|
||||
target: kernel/itc-core
|
||||
- id: model/landscape
|
||||
path: models/landscape/InfoTechCanonLandscapeModel.md
|
||||
kind: model
|
||||
title: InfoTechCanon Landscape Model
|
||||
provenance:
|
||||
source_path: seeds/InfoTechCanonLandscapeModel_RC1_seed.md
|
||||
placement: copied
|
||||
placement_workplan: ITC-WP-0001
|
||||
relationships:
|
||||
- type: conforms_to
|
||||
target: kernel/itc-core
|
||||
- id: model/organization
|
||||
path: models/organization/InfoTechCanonOrganizationModel.md
|
||||
kind: model
|
||||
title: InfoTechCanon Organization Model
|
||||
provenance:
|
||||
source_path: seeds/InfoTechCanonOrganizationModel_RC1_seed.md
|
||||
placement: copied
|
||||
placement_workplan: ITC-WP-0001
|
||||
relationships:
|
||||
- type: conforms_to
|
||||
target: kernel/itc-core
|
||||
- id: model/governance
|
||||
path: models/governance/InfoTechCanonGovernanceModel.md
|
||||
kind: model
|
||||
title: InfoTechCanon Governance Model
|
||||
provenance:
|
||||
source_path: seeds/InfoTechCanonGovernanceModel_RC1_seed.md
|
||||
placement: copied
|
||||
placement_workplan: ITC-WP-0001
|
||||
relationships:
|
||||
- type: conforms_to
|
||||
target: kernel/itc-core
|
||||
- id: model/task
|
||||
path: models/task/InfoTechCanonTaskModel.md
|
||||
kind: model
|
||||
title: InfoTechCanon Task Model
|
||||
provenance:
|
||||
source_path: seeds/InfoTechCanonTaskModel_RC1_seed.md
|
||||
placement: copied
|
||||
placement_workplan: ITC-WP-0001
|
||||
relationships:
|
||||
- type: conforms_to
|
||||
target: kernel/itc-core
|
||||
- id: model/access-control
|
||||
path: models/access-control/InfoTechCanonAccessControlModel.md
|
||||
kind: model
|
||||
title: InfoTechCanon Access Control Model
|
||||
provenance:
|
||||
source_path: seeds/InfoTechCanonAccessControlModel_RC1_seed.md
|
||||
placement: copied
|
||||
placement_workplan: ITC-WP-0001
|
||||
relationships:
|
||||
- type: conforms_to
|
||||
target: kernel/itc-core
|
||||
- type: uses
|
||||
target: model/organization
|
||||
- type: uses
|
||||
target: model/governance
|
||||
- id: model/security
|
||||
path: models/security/InfoTechCanonSecurityModel.md
|
||||
kind: model
|
||||
title: InfoTechCanon Security Model
|
||||
provenance:
|
||||
source_path: seeds/InfoTechCanonSecurityModel_RC1_seed.md
|
||||
placement: copied
|
||||
placement_workplan: ITC-WP-0001
|
||||
relationships:
|
||||
- type: conforms_to
|
||||
target: kernel/itc-core
|
||||
- type: uses
|
||||
target: model/access-control
|
||||
- id: model/data
|
||||
path: models/data/InfoTechCanonDataModel.md
|
||||
kind: model
|
||||
title: InfoTechCanon Data Model
|
||||
provenance:
|
||||
source_path: seeds/InfoTechCanonDataModel_RC1_seed.md
|
||||
placement: copied
|
||||
placement_workplan: ITC-WP-0001
|
||||
relationships:
|
||||
- type: conforms_to
|
||||
target: kernel/itc-core
|
||||
- type: uses
|
||||
target: model/governance
|
||||
- id: model/devsecops
|
||||
path: models/devsecops/InfoTechCanonDevSecOpsModel.md
|
||||
kind: model
|
||||
title: InfoTechCanon DevSecOps Model
|
||||
provenance:
|
||||
source_path: seeds/InfoTechCanonDevSecOpsModel_RC1_seed.md
|
||||
placement: copied
|
||||
placement_workplan: ITC-WP-0001
|
||||
relationships:
|
||||
- type: conforms_to
|
||||
target: kernel/itc-core
|
||||
- type: uses
|
||||
target: model/security
|
||||
- id: model/network
|
||||
path: models/network/InfoTechCanonNetworkModel.md
|
||||
kind: model
|
||||
title: InfoTechCanon Network Model
|
||||
provenance:
|
||||
source_path: seeds/InfoTechCanonNetworkModel_RC1_seed.md
|
||||
placement: copied
|
||||
placement_workplan: ITC-WP-0001
|
||||
relationships:
|
||||
- type: conforms_to
|
||||
target: kernel/itc-core
|
||||
- type: uses
|
||||
target: model/security
|
||||
- id: model/observability
|
||||
path: models/observability/InfoTechCanonObservabilityModel.md
|
||||
kind: model
|
||||
title: InfoTechCanon Observability Model
|
||||
provenance:
|
||||
source_path: seeds/InfoTechCanonObservabilityModel_RC1_seed.md
|
||||
placement: copied
|
||||
placement_workplan: ITC-WP-0001
|
||||
relationships:
|
||||
- type: conforms_to
|
||||
target: kernel/itc-core
|
||||
- type: uses
|
||||
target: model/task
|
||||
- id: standard/tagging
|
||||
path: standards/tagging/InfoTechCanonTaggingStandard.md
|
||||
kind: standard
|
||||
title: InfoTechCanon Tagging Standard
|
||||
provenance:
|
||||
source_path: seeds/InfoTechCanonTaggingStandard_RC1_seed.md
|
||||
placement: copied
|
||||
placement_workplan: ITC-WP-0001
|
||||
relationships:
|
||||
- type: conforms_to
|
||||
target: kernel/itc-core
|
||||
- type: imports
|
||||
target: model/task
|
||||
- id: standard/caring
|
||||
path: standards/caring/InfoTechCanonCaringAccessGovernanceStandard.md
|
||||
kind: standard
|
||||
title: InfoTechCanon CARING Access Governance Standard
|
||||
provenance:
|
||||
source_path: seeds/InfoTechCanonCaringAccessGovernanceStandard.md
|
||||
placement: copied
|
||||
placement_workplan: ITC-WP-0001
|
||||
relationships:
|
||||
- type: conforms_to
|
||||
target: kernel/itc-core
|
||||
- type: imports
|
||||
target: model/organization
|
||||
- type: imports
|
||||
target: model/governance
|
||||
- type: imports
|
||||
target: model/access-control
|
||||
- type: imports
|
||||
target: model/security
|
||||
- type: imports
|
||||
target: model/data
|
||||
- type: imports
|
||||
target: model/devsecops
|
||||
- type: imports
|
||||
target: model/network
|
||||
- type: imports
|
||||
target: model/observability
|
||||
- type: imports
|
||||
target: model/task
|
||||
- type: imports
|
||||
target: standard/tagging
|
||||
3
infospace/assimilation/README.md
Normal file
3
infospace/assimilation/README.md
Normal file
@@ -0,0 +1,3 @@
|
||||
# Assimilation
|
||||
|
||||
Assimilation records for external knowledge and consumer demand live here.
|
||||
3
infospace/examples/README.md
Normal file
3
infospace/examples/README.md
Normal file
@@ -0,0 +1,3 @@
|
||||
# Examples
|
||||
|
||||
Examples and proof fixtures live here.
|
||||
50
infospace/infospace.yaml
Normal file
50
infospace/infospace.yaml
Normal file
@@ -0,0 +1,50 @@
|
||||
slug: canon
|
||||
name: InfoTechCanon
|
||||
topic:
|
||||
name: InfoTechCanon
|
||||
domain: Canon
|
||||
sources: seeds
|
||||
disciplines:
|
||||
- name: Canon Kernel
|
||||
path: kernel/InfoTechCanonCore.md
|
||||
- name: Kernel Map
|
||||
path: kernel/InfoTechCanonKernelMap.md
|
||||
- name: Information Space Model
|
||||
path: models/information-space/InfoTechCanonInformationSpaceModel.md
|
||||
- name: Landscape Model
|
||||
path: models/landscape/InfoTechCanonLandscapeModel.md
|
||||
- name: Organization Model
|
||||
path: models/organization/InfoTechCanonOrganizationModel.md
|
||||
- name: Governance Model
|
||||
path: models/governance/InfoTechCanonGovernanceModel.md
|
||||
- name: Task Model
|
||||
path: models/task/InfoTechCanonTaskModel.md
|
||||
- name: Access Control Model
|
||||
path: models/access-control/InfoTechCanonAccessControlModel.md
|
||||
- name: Security Model
|
||||
path: models/security/InfoTechCanonSecurityModel.md
|
||||
- name: Data Model
|
||||
path: models/data/InfoTechCanonDataModel.md
|
||||
- name: DevSecOps Model
|
||||
path: models/devsecops/InfoTechCanonDevSecOpsModel.md
|
||||
- name: Network Model
|
||||
path: models/network/InfoTechCanonNetworkModel.md
|
||||
- name: Observability Model
|
||||
path: models/observability/InfoTechCanonObservabilityModel.md
|
||||
- name: Tagging Standard
|
||||
path: standards/tagging/InfoTechCanonTaggingStandard.md
|
||||
- name: CARING Access Governance Standard
|
||||
path: standards/caring/InfoTechCanonCaringAccessGovernanceStandard.md
|
||||
schemas: {}
|
||||
workflows: []
|
||||
viability:
|
||||
redundancy_ratio:
|
||||
max: 0
|
||||
coverage_ratio:
|
||||
min: 1
|
||||
coherence_components:
|
||||
max: 1
|
||||
consistency_cycles:
|
||||
max: 0
|
||||
granularity_entropy:
|
||||
min: 1
|
||||
1982
infospace/kernel/InfoTechCanonCore.md
Normal file
1982
infospace/kernel/InfoTechCanonCore.md
Normal file
File diff suppressed because it is too large
Load Diff
1565
infospace/kernel/InfoTechCanonKernelMap.md
Normal file
1565
infospace/kernel/InfoTechCanonKernelMap.md
Normal file
File diff suppressed because it is too large
Load Diff
3
infospace/mappings/README.md
Normal file
3
infospace/mappings/README.md
Normal file
@@ -0,0 +1,3 @@
|
||||
# Mappings
|
||||
|
||||
Mappings to external standards, repositories, and consumer concepts live here.
|
||||
2302
infospace/models/access-control/InfoTechCanonAccessControlModel.md
Normal file
2302
infospace/models/access-control/InfoTechCanonAccessControlModel.md
Normal file
File diff suppressed because it is too large
Load Diff
2180
infospace/models/data/InfoTechCanonDataModel.md
Normal file
2180
infospace/models/data/InfoTechCanonDataModel.md
Normal file
File diff suppressed because it is too large
Load Diff
2407
infospace/models/devsecops/InfoTechCanonDevSecOpsModel.md
Normal file
2407
infospace/models/devsecops/InfoTechCanonDevSecOpsModel.md
Normal file
File diff suppressed because it is too large
Load Diff
2181
infospace/models/governance/InfoTechCanonGovernanceModel.md
Normal file
2181
infospace/models/governance/InfoTechCanonGovernanceModel.md
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
1938
infospace/models/landscape/InfoTechCanonLandscapeModel.md
Normal file
1938
infospace/models/landscape/InfoTechCanonLandscapeModel.md
Normal file
File diff suppressed because it is too large
Load Diff
2433
infospace/models/network/InfoTechCanonNetworkModel.md
Normal file
2433
infospace/models/network/InfoTechCanonNetworkModel.md
Normal file
File diff suppressed because it is too large
Load Diff
2272
infospace/models/observability/InfoTechCanonObservabilityModel.md
Normal file
2272
infospace/models/observability/InfoTechCanonObservabilityModel.md
Normal file
File diff suppressed because it is too large
Load Diff
1750
infospace/models/organization/InfoTechCanonOrganizationModel.md
Normal file
1750
infospace/models/organization/InfoTechCanonOrganizationModel.md
Normal file
File diff suppressed because it is too large
Load Diff
2234
infospace/models/security/InfoTechCanonSecurityModel.md
Normal file
2234
infospace/models/security/InfoTechCanonSecurityModel.md
Normal file
File diff suppressed because it is too large
Load Diff
2100
infospace/models/task/InfoTechCanonTaskModel.md
Normal file
2100
infospace/models/task/InfoTechCanonTaskModel.md
Normal file
File diff suppressed because it is too large
Load Diff
3
infospace/patterns/README.md
Normal file
3
infospace/patterns/README.md
Normal file
@@ -0,0 +1,3 @@
|
||||
# Patterns
|
||||
|
||||
Reusable canon patterns live here.
|
||||
3
infospace/profiles/README.md
Normal file
3
infospace/profiles/README.md
Normal file
@@ -0,0 +1,3 @@
|
||||
# Profiles
|
||||
|
||||
Application profiles and proof slices live here.
|
||||
27
infospace/reports/scaffold-placement.md
Normal file
27
infospace/reports/scaffold-placement.md
Normal file
@@ -0,0 +1,27 @@
|
||||
# Scaffold Placement Report
|
||||
|
||||
**Workplan:** ITC-WP-0001
|
||||
**Date:** 2026-05-23
|
||||
**Mode:** placement only, no semantic refactor
|
||||
|
||||
## Summary
|
||||
|
||||
The first implementation pass created the concrete `infospace/` root and
|
||||
placed the existing seed corpus into the newer `kernel/`, `models/`, and
|
||||
`standards/` layout. The original files in `seeds/` remain unchanged as
|
||||
provenance.
|
||||
|
||||
## Placement Rules
|
||||
|
||||
- Core and Kernel Map are copied to `infospace/kernel/`.
|
||||
- Broad domain models are copied to `infospace/models/<domain>/`.
|
||||
- Tagging and CARING are copied to `infospace/standards/<standard>/`.
|
||||
- `infospace/artifacts/index.yaml` records canonical path, kind, title,
|
||||
source seed path, and initial graph relationships.
|
||||
- No semantic edits were made to the copied documents.
|
||||
|
||||
## Deferred
|
||||
|
||||
- Domain-level profile extraction remains in ITC-WP-0004 and ITC-WP-0006.
|
||||
- Generated views and stricter validation remain in ITC-WP-0003.
|
||||
- Consumer repository workplans remain owned by the consumer repositories.
|
||||
3
infospace/schemas/README.md
Normal file
3
infospace/schemas/README.md
Normal file
@@ -0,0 +1,3 @@
|
||||
# Schemas
|
||||
|
||||
Schemas and validation contracts live here.
|
||||
File diff suppressed because it is too large
Load Diff
2037
infospace/standards/tagging/InfoTechCanonTaggingStandard.md
Normal file
2037
infospace/standards/tagging/InfoTechCanonTaggingStandard.md
Normal file
File diff suppressed because it is too large
Load Diff
3
infospace/validation/README.md
Normal file
3
infospace/validation/README.md
Normal file
@@ -0,0 +1,3 @@
|
||||
# Validation
|
||||
|
||||
Validation reports and rules live here.
|
||||
3
infospace/views/README.md
Normal file
3
infospace/views/README.md
Normal file
@@ -0,0 +1,3 @@
|
||||
# Views
|
||||
|
||||
Generated and curated views live here.
|
||||
19
pyproject.toml
Normal file
19
pyproject.toml
Normal file
@@ -0,0 +1,19 @@
|
||||
[project]
|
||||
name = "info-tech-canon"
|
||||
version = "0.1.0"
|
||||
description = "Practical service surface for the InfoTechCanon infospace."
|
||||
requires-python = ">=3.12"
|
||||
dependencies = [
|
||||
"PyYAML>=6",
|
||||
"infospace-bench @ file:///home/worsch/infospace-bench",
|
||||
]
|
||||
|
||||
[project.scripts]
|
||||
info-tech-canon = "info_tech_canon.cli:main"
|
||||
|
||||
[tool.setuptools.packages.find]
|
||||
where = ["src"]
|
||||
|
||||
[tool.pytest.ini_options]
|
||||
pythonpath = ["src", "../infospace-bench/src"]
|
||||
testpaths = ["tests"]
|
||||
23
src/info_tech_canon/__init__.py
Normal file
23
src/info_tech_canon/__init__.py
Normal file
@@ -0,0 +1,23 @@
|
||||
"""InfoTechCanon service package."""
|
||||
|
||||
from .service import (
|
||||
CanonServiceError,
|
||||
artifact_graph,
|
||||
inspect_canon,
|
||||
list_artifacts,
|
||||
list_models,
|
||||
list_standards,
|
||||
profile_inspect,
|
||||
validate_canon,
|
||||
)
|
||||
|
||||
__all__ = [
|
||||
"CanonServiceError",
|
||||
"artifact_graph",
|
||||
"inspect_canon",
|
||||
"list_artifacts",
|
||||
"list_models",
|
||||
"list_standards",
|
||||
"profile_inspect",
|
||||
"validate_canon",
|
||||
]
|
||||
3
src/info_tech_canon/__main__.py
Normal file
3
src/info_tech_canon/__main__.py
Normal file
@@ -0,0 +1,3 @@
|
||||
from .cli import main
|
||||
|
||||
raise SystemExit(main())
|
||||
104
src/info_tech_canon/api.py
Normal file
104
src/info_tech_canon/api.py
Normal file
@@ -0,0 +1,104 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
from http import HTTPStatus
|
||||
from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer
|
||||
from pathlib import Path
|
||||
from typing import Any
|
||||
from urllib.parse import parse_qs, urlparse
|
||||
|
||||
from .service import (
|
||||
CanonServiceError,
|
||||
artifact_graph,
|
||||
inspect_canon,
|
||||
list_artifacts,
|
||||
list_models,
|
||||
list_standards,
|
||||
profile_inspect,
|
||||
validate_canon,
|
||||
)
|
||||
|
||||
|
||||
def serve(host: str = "127.0.0.1", port: int = 8765, root: Path | None = None) -> None:
|
||||
handler = _build_handler(root)
|
||||
server = ThreadingHTTPServer((host, port), handler)
|
||||
print(f"InfoTechCanon API listening on http://{host}:{port}", flush=True)
|
||||
try:
|
||||
server.serve_forever()
|
||||
except KeyboardInterrupt:
|
||||
pass
|
||||
finally:
|
||||
server.server_close()
|
||||
|
||||
|
||||
def _build_handler(root: Path | None) -> type[BaseHTTPRequestHandler]:
|
||||
class CanonRequestHandler(BaseHTTPRequestHandler):
|
||||
def do_GET(self) -> None:
|
||||
parsed = urlparse(self.path)
|
||||
query = parse_qs(parsed.query)
|
||||
try:
|
||||
status, payload = _route(parsed.path, query, root)
|
||||
except CanonServiceError as exc:
|
||||
status, payload = HTTPStatus.BAD_REQUEST, exc.to_dict()
|
||||
except Exception as exc:
|
||||
status, payload = HTTPStatus.INTERNAL_SERVER_ERROR, {
|
||||
"ok": False,
|
||||
"error": {
|
||||
"code": "unhandled_error",
|
||||
"message": str(exc),
|
||||
"details": {},
|
||||
},
|
||||
}
|
||||
self._send_json(status, payload)
|
||||
|
||||
def log_message(self, format: str, *args: object) -> None:
|
||||
return
|
||||
|
||||
def _send_json(self, status: HTTPStatus, payload: dict[str, Any]) -> None:
|
||||
body = json.dumps(payload, indent=2, sort_keys=True).encode("utf-8")
|
||||
self.send_response(status.value)
|
||||
self.send_header("Content-Type", "application/json; charset=utf-8")
|
||||
self.send_header("Content-Length", str(len(body)))
|
||||
self.end_headers()
|
||||
self.wfile.write(body)
|
||||
|
||||
return CanonRequestHandler
|
||||
|
||||
|
||||
def _route(
|
||||
path: str,
|
||||
query: dict[str, list[str]],
|
||||
root: Path | None,
|
||||
) -> tuple[HTTPStatus, dict[str, Any]]:
|
||||
if path == "/health":
|
||||
return HTTPStatus.OK, {"ok": True, "service": "info-tech-canon"}
|
||||
if path == "/inspect":
|
||||
return HTTPStatus.OK, inspect_canon(root)
|
||||
if path == "/artifacts":
|
||||
return HTTPStatus.OK, list_artifacts(root, kind=_first(query, "kind"))
|
||||
if path == "/models":
|
||||
return HTTPStatus.OK, list_models(root)
|
||||
if path == "/standards":
|
||||
return HTTPStatus.OK, list_standards(root)
|
||||
if path == "/validate":
|
||||
payload = validate_canon(root)
|
||||
return (HTTPStatus.OK if payload["ok"] else HTTPStatus.BAD_REQUEST), payload
|
||||
if path == "/graph":
|
||||
graph_format = _first(query, "format") or "json"
|
||||
return HTTPStatus.OK, artifact_graph(root, output_format=graph_format)
|
||||
if path.startswith("/profiles/") and path.endswith("/inspect"):
|
||||
profile = path.removeprefix("/profiles/").removesuffix("/inspect").strip("/")
|
||||
return HTTPStatus.OK, profile_inspect(profile, root)
|
||||
return HTTPStatus.NOT_FOUND, {
|
||||
"ok": False,
|
||||
"error": {
|
||||
"code": "not_found",
|
||||
"message": f"Unknown endpoint: {path}",
|
||||
"details": {"path": path},
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
def _first(query: dict[str, list[str]], name: str) -> str | None:
|
||||
values = query.get(name) or []
|
||||
return values[0] if values else None
|
||||
65
src/info_tech_canon/bench.py
Normal file
65
src/info_tech_canon/bench.py
Normal file
@@ -0,0 +1,65 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import importlib.util
|
||||
import sys
|
||||
import types
|
||||
from pathlib import Path
|
||||
from types import ModuleType
|
||||
from typing import Any
|
||||
|
||||
|
||||
BENCH_PACKAGE = "_info_tech_canon_infospace_bench"
|
||||
BENCH_SOURCE_ROOT = (
|
||||
Path(__file__).resolve().parents[3] / "infospace-bench" / "src" / "infospace_bench"
|
||||
)
|
||||
|
||||
|
||||
def _ensure_package() -> ModuleType:
|
||||
existing = sys.modules.get(BENCH_PACKAGE)
|
||||
if existing is not None:
|
||||
return existing
|
||||
package = types.ModuleType(BENCH_PACKAGE)
|
||||
package.__path__ = [str(BENCH_SOURCE_ROOT)] # type: ignore[attr-defined]
|
||||
sys.modules[BENCH_PACKAGE] = package
|
||||
return package
|
||||
|
||||
|
||||
def _load_module(name: str) -> ModuleType:
|
||||
_ensure_package()
|
||||
module_name = f"{BENCH_PACKAGE}.{name}"
|
||||
existing = sys.modules.get(module_name)
|
||||
if existing is not None:
|
||||
return existing
|
||||
path = BENCH_SOURCE_ROOT / f"{name}.py"
|
||||
if not path.is_file():
|
||||
raise RuntimeError(f"Missing infospace-bench module: {path}")
|
||||
spec = importlib.util.spec_from_file_location(module_name, path)
|
||||
if spec is None or spec.loader is None:
|
||||
raise RuntimeError(f"Unable to load infospace-bench module: {path}")
|
||||
module = importlib.util.module_from_spec(spec)
|
||||
sys.modules[module_name] = module
|
||||
spec.loader.exec_module(module)
|
||||
return module
|
||||
|
||||
|
||||
errors = _load_module("errors")
|
||||
models = _load_module("models")
|
||||
lifecycle = _load_module("lifecycle")
|
||||
checks = _load_module("checks")
|
||||
inspection = _load_module("inspection")
|
||||
|
||||
Infospace = models.Infospace
|
||||
KnowledgeArtifact = models.KnowledgeArtifact
|
||||
load_infospace = lifecycle.load_infospace
|
||||
run_collection_checks = checks.run_collection_checks
|
||||
relationship_summary = inspection.relationship_summary
|
||||
export_mermaid = inspection.export_mermaid
|
||||
|
||||
__all__ = [
|
||||
"Infospace",
|
||||
"KnowledgeArtifact",
|
||||
"export_mermaid",
|
||||
"load_infospace",
|
||||
"relationship_summary",
|
||||
"run_collection_checks",
|
||||
]
|
||||
134
src/info_tech_canon/cli.py
Normal file
134
src/info_tech_canon/cli.py
Normal file
@@ -0,0 +1,134 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import json
|
||||
import sys
|
||||
from collections.abc import Callable
|
||||
from pathlib import Path
|
||||
from typing import Any
|
||||
|
||||
from .api import serve
|
||||
from .service import (
|
||||
CanonServiceError,
|
||||
artifact_graph,
|
||||
inspect_canon,
|
||||
list_artifacts,
|
||||
list_models,
|
||||
list_standards,
|
||||
profile_inspect,
|
||||
validate_canon,
|
||||
)
|
||||
|
||||
|
||||
Command = Callable[[argparse.Namespace], dict[str, Any]]
|
||||
|
||||
|
||||
def build_parser() -> argparse.ArgumentParser:
|
||||
parser = argparse.ArgumentParser(prog="info-tech-canon")
|
||||
parser.add_argument(
|
||||
"--root",
|
||||
default="",
|
||||
help="Infospace root. Defaults to ./infospace from the repository root.",
|
||||
)
|
||||
sub = parser.add_subparsers(dest="command", required=True)
|
||||
|
||||
inspect = sub.add_parser("inspect", help="Inspect the canon infospace")
|
||||
inspect.set_defaults(handler=_inspect)
|
||||
|
||||
artifacts = sub.add_parser("artifacts", help="List canon artifacts")
|
||||
artifacts.add_argument("--kind", default="")
|
||||
artifacts.set_defaults(handler=_artifacts)
|
||||
|
||||
models = sub.add_parser("models", help="List canon model artifacts")
|
||||
models.set_defaults(handler=_models)
|
||||
|
||||
standards = sub.add_parser("standards", help="List canon standard artifacts")
|
||||
standards.set_defaults(handler=_standards)
|
||||
|
||||
validate = sub.add_parser("validate", help="Validate the canon infospace")
|
||||
validate.set_defaults(handler=_validate)
|
||||
|
||||
graph = sub.add_parser("graph", help="Export the canon artifact graph")
|
||||
graph.add_argument("--format", choices=["json", "mermaid"], default="json")
|
||||
graph.set_defaults(handler=_graph)
|
||||
|
||||
profile = sub.add_parser("profile", help="Inspect canon profiles")
|
||||
profile_sub = profile.add_subparsers(dest="profile_command", required=True)
|
||||
profile_inspect_cmd = profile_sub.add_parser("inspect", help="Inspect a profile")
|
||||
profile_inspect_cmd.add_argument("profile")
|
||||
profile_inspect_cmd.set_defaults(handler=_profile_inspect)
|
||||
|
||||
api = sub.add_parser("api", help="Run the read-only local API")
|
||||
api.add_argument("--host", default="127.0.0.1")
|
||||
api.add_argument("--port", type=int, default=8765)
|
||||
api.set_defaults(handler=_api)
|
||||
|
||||
return parser
|
||||
|
||||
|
||||
def main(argv: list[str] | None = None) -> int:
|
||||
parser = build_parser()
|
||||
args = parser.parse_args(argv)
|
||||
handler: Command = args.handler
|
||||
try:
|
||||
result = handler(args)
|
||||
except CanonServiceError as exc:
|
||||
_print_json(exc.to_dict())
|
||||
return 2
|
||||
except Exception as exc:
|
||||
_print_json(
|
||||
{
|
||||
"ok": False,
|
||||
"error": {
|
||||
"code": "unhandled_error",
|
||||
"message": str(exc),
|
||||
"details": {},
|
||||
},
|
||||
}
|
||||
)
|
||||
return 1
|
||||
if result:
|
||||
_print_json(result)
|
||||
return 0 if result.get("ok", False) else 1
|
||||
|
||||
|
||||
def _root(args: argparse.Namespace) -> Path | None:
|
||||
return Path(args.root) if args.root else None
|
||||
|
||||
|
||||
def _inspect(args: argparse.Namespace) -> dict[str, Any]:
|
||||
return inspect_canon(_root(args))
|
||||
|
||||
|
||||
def _artifacts(args: argparse.Namespace) -> dict[str, Any]:
|
||||
return list_artifacts(_root(args), kind=args.kind or None)
|
||||
|
||||
|
||||
def _models(args: argparse.Namespace) -> dict[str, Any]:
|
||||
return list_models(_root(args))
|
||||
|
||||
|
||||
def _standards(args: argparse.Namespace) -> dict[str, Any]:
|
||||
return list_standards(_root(args))
|
||||
|
||||
|
||||
def _validate(args: argparse.Namespace) -> dict[str, Any]:
|
||||
return validate_canon(_root(args))
|
||||
|
||||
|
||||
def _graph(args: argparse.Namespace) -> dict[str, Any]:
|
||||
return artifact_graph(_root(args), output_format=args.format)
|
||||
|
||||
|
||||
def _profile_inspect(args: argparse.Namespace) -> dict[str, Any]:
|
||||
return profile_inspect(args.profile, _root(args))
|
||||
|
||||
|
||||
def _api(args: argparse.Namespace) -> dict[str, Any]:
|
||||
serve(host=args.host, port=args.port, root=_root(args))
|
||||
return {}
|
||||
|
||||
|
||||
def _print_json(data: dict[str, Any]) -> None:
|
||||
json.dump(data, sys.stdout, indent=2, sort_keys=True)
|
||||
sys.stdout.write("\n")
|
||||
262
src/info_tech_canon/service.py
Normal file
262
src/info_tech_canon/service.py
Normal file
@@ -0,0 +1,262 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from collections import Counter
|
||||
from dataclasses import asdict, dataclass
|
||||
from pathlib import Path
|
||||
from typing import Any
|
||||
|
||||
import yaml
|
||||
|
||||
from .bench import (
|
||||
Infospace,
|
||||
KnowledgeArtifact,
|
||||
export_mermaid,
|
||||
load_infospace,
|
||||
relationship_summary,
|
||||
run_collection_checks,
|
||||
)
|
||||
|
||||
|
||||
REPO_ROOT = Path(__file__).resolve().parents[2]
|
||||
DEFAULT_INFOSPACE_ROOT = REPO_ROOT / "infospace"
|
||||
|
||||
|
||||
class CanonServiceError(Exception):
|
||||
def __init__(
|
||||
self,
|
||||
code: str,
|
||||
message: str,
|
||||
details: dict[str, Any] | None = None,
|
||||
) -> None:
|
||||
super().__init__(message)
|
||||
self.code = code
|
||||
self.message = message
|
||||
self.details = details or {}
|
||||
|
||||
def to_dict(self) -> dict[str, Any]:
|
||||
return {
|
||||
"ok": False,
|
||||
"error": {
|
||||
"code": self.code,
|
||||
"message": self.message,
|
||||
"details": self.details,
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class CanonContext:
|
||||
repo_root: Path
|
||||
infospace_root: Path
|
||||
infospace: Infospace
|
||||
|
||||
|
||||
def load_context(root: Path | str | None = None) -> CanonContext:
|
||||
infospace_root = Path(root) if root else DEFAULT_INFOSPACE_ROOT
|
||||
try:
|
||||
infospace = load_infospace(infospace_root)
|
||||
except Exception as exc:
|
||||
raise CanonServiceError(
|
||||
"infospace_load_failed",
|
||||
f"Unable to load infospace at {infospace_root}",
|
||||
{"root": str(infospace_root), "reason": str(exc)},
|
||||
) from exc
|
||||
return CanonContext(
|
||||
repo_root=REPO_ROOT,
|
||||
infospace_root=infospace_root,
|
||||
infospace=infospace,
|
||||
)
|
||||
|
||||
|
||||
def inspect_canon(root: Path | str | None = None) -> dict[str, Any]:
|
||||
context = load_context(root)
|
||||
artifacts = context.infospace.artifacts
|
||||
kinds = Counter(artifact.kind for artifact in artifacts)
|
||||
return {
|
||||
"ok": True,
|
||||
"repo": {
|
||||
"slug": "info-tech-canon",
|
||||
"root": str(context.repo_root),
|
||||
},
|
||||
"infospace": {
|
||||
"slug": context.infospace.config.slug,
|
||||
"name": context.infospace.config.name,
|
||||
"root": str(context.infospace_root),
|
||||
"artifact_count": len(artifacts),
|
||||
"kinds": dict(sorted(kinds.items())),
|
||||
},
|
||||
"service": {
|
||||
"package": "info_tech_canon",
|
||||
"contract": "cli-json-api",
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
def list_artifacts(
|
||||
root: Path | str | None = None,
|
||||
*,
|
||||
kind: str | None = None,
|
||||
) -> dict[str, Any]:
|
||||
context = load_context(root)
|
||||
artifacts = [
|
||||
_artifact_to_dict(artifact, context.infospace_root)
|
||||
for artifact in context.infospace.artifacts
|
||||
if kind is None or artifact.kind == kind
|
||||
]
|
||||
return {
|
||||
"ok": True,
|
||||
"count": len(artifacts),
|
||||
"artifacts": artifacts,
|
||||
}
|
||||
|
||||
|
||||
def list_models(root: Path | str | None = None) -> dict[str, Any]:
|
||||
return list_artifacts(root, kind="model")
|
||||
|
||||
|
||||
def list_standards(root: Path | str | None = None) -> dict[str, Any]:
|
||||
return list_artifacts(root, kind="standard")
|
||||
|
||||
|
||||
def validate_canon(root: Path | str | None = None) -> dict[str, Any]:
|
||||
context = load_context(root)
|
||||
errors: list[dict[str, Any]] = []
|
||||
|
||||
artifact_ids = {artifact.id for artifact in context.infospace.artifacts}
|
||||
for artifact in context.infospace.artifacts:
|
||||
artifact_path = context.infospace_root / artifact.path
|
||||
if not artifact_path.is_file():
|
||||
errors.append(
|
||||
{
|
||||
"code": "missing_artifact_path",
|
||||
"artifact_id": artifact.id,
|
||||
"path": artifact.path,
|
||||
}
|
||||
)
|
||||
for relationship in artifact.relationships:
|
||||
target = relationship.get("target")
|
||||
if target not in artifact_ids:
|
||||
errors.append(
|
||||
{
|
||||
"code": "missing_relationship_target",
|
||||
"artifact_id": artifact.id,
|
||||
"target": target,
|
||||
}
|
||||
)
|
||||
|
||||
for discipline in context.infospace.config.disciplines:
|
||||
discipline_path = context.infospace_root / discipline.path
|
||||
if not discipline_path.is_file():
|
||||
errors.append(
|
||||
{
|
||||
"code": "missing_discipline_path",
|
||||
"discipline": discipline.name,
|
||||
"path": discipline.path,
|
||||
}
|
||||
)
|
||||
|
||||
checks = run_collection_checks(context.infospace.artifacts)
|
||||
threshold_errors = _evaluate_thresholds(
|
||||
checks.metrics,
|
||||
context.infospace.config.viability,
|
||||
)
|
||||
errors.extend(threshold_errors)
|
||||
|
||||
return {
|
||||
"ok": not errors,
|
||||
"errors": errors,
|
||||
"metrics": checks.metrics,
|
||||
"details": checks.details,
|
||||
}
|
||||
|
||||
|
||||
def artifact_graph(
|
||||
root: Path | str | None = None,
|
||||
*,
|
||||
output_format: str = "json",
|
||||
) -> dict[str, Any]:
|
||||
context = load_context(root)
|
||||
summary = relationship_summary(context.infospace.artifacts)
|
||||
if output_format == "mermaid":
|
||||
return {"ok": True, "format": "mermaid", "graph": export_mermaid(summary)}
|
||||
if output_format != "json":
|
||||
raise CanonServiceError(
|
||||
"unsupported_graph_format",
|
||||
f"Unsupported graph format: {output_format}",
|
||||
{"supported": ["json", "mermaid"]},
|
||||
)
|
||||
return {
|
||||
"ok": True,
|
||||
"format": "json",
|
||||
"graph": {
|
||||
"node_count": summary.node_count,
|
||||
"edge_count": summary.edge_count,
|
||||
"nodes": summary.nodes,
|
||||
"edges": [asdict(edge) for edge in summary.edges],
|
||||
"relationship_types": summary.relationship_types,
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
def profile_inspect(
|
||||
profile: str,
|
||||
root: Path | str | None = None,
|
||||
) -> dict[str, Any]:
|
||||
context = load_context(root)
|
||||
profile_path = context.infospace_root / "profiles" / profile / "profile.yaml"
|
||||
if not profile_path.is_file():
|
||||
raise CanonServiceError(
|
||||
"missing_profile",
|
||||
f"Profile not found: {profile}",
|
||||
{"profile": profile, "path": str(profile_path)},
|
||||
)
|
||||
with profile_path.open("r", encoding="utf-8") as handle:
|
||||
data = yaml.safe_load(handle) or {}
|
||||
if not isinstance(data, dict):
|
||||
raise CanonServiceError(
|
||||
"invalid_profile",
|
||||
f"Profile must be a YAML mapping: {profile}",
|
||||
{"profile": profile, "path": str(profile_path)},
|
||||
)
|
||||
return {"ok": True, "profile": data, "path": str(profile_path)}
|
||||
|
||||
|
||||
def _artifact_to_dict(
|
||||
artifact: KnowledgeArtifact,
|
||||
infospace_root: Path,
|
||||
) -> dict[str, Any]:
|
||||
data = artifact.to_dict()
|
||||
data["exists"] = (infospace_root / artifact.path).is_file()
|
||||
return data
|
||||
|
||||
|
||||
def _evaluate_thresholds(
|
||||
metrics: dict[str, float],
|
||||
thresholds: dict[str, Any],
|
||||
) -> list[dict[str, Any]]:
|
||||
errors: list[dict[str, Any]] = []
|
||||
for metric, threshold in thresholds.items():
|
||||
value = metrics.get(metric)
|
||||
if value is None:
|
||||
continue
|
||||
min_value = getattr(threshold, "min", None)
|
||||
max_value = getattr(threshold, "max", None)
|
||||
if min_value is not None and value < min_value:
|
||||
errors.append(
|
||||
{
|
||||
"code": "metric_below_threshold",
|
||||
"metric": metric,
|
||||
"value": value,
|
||||
"min": min_value,
|
||||
}
|
||||
)
|
||||
if max_value is not None and value > max_value:
|
||||
errors.append(
|
||||
{
|
||||
"code": "metric_above_threshold",
|
||||
"metric": metric,
|
||||
"value": value,
|
||||
"max": max_value,
|
||||
}
|
||||
)
|
||||
return errors
|
||||
26
tests/test_api.py
Normal file
26
tests/test_api.py
Normal file
@@ -0,0 +1,26 @@
|
||||
from http import HTTPStatus
|
||||
|
||||
from info_tech_canon.api import _route
|
||||
|
||||
|
||||
def test_api_route_inspect() -> None:
|
||||
status, payload = _route("/inspect", {}, None)
|
||||
|
||||
assert status == HTTPStatus.OK
|
||||
assert payload["ok"] is True
|
||||
assert payload["infospace"]["slug"] == "canon"
|
||||
|
||||
|
||||
def test_api_route_validate() -> None:
|
||||
status, payload = _route("/validate", {}, None)
|
||||
|
||||
assert status == HTTPStatus.OK
|
||||
assert payload["ok"] is True
|
||||
|
||||
|
||||
def test_api_route_unknown_endpoint() -> None:
|
||||
status, payload = _route("/missing", {}, None)
|
||||
|
||||
assert status == HTTPStatus.NOT_FOUND
|
||||
assert payload["ok"] is False
|
||||
assert payload["error"]["code"] == "not_found"
|
||||
21
tests/test_cli.py
Normal file
21
tests/test_cli.py
Normal file
@@ -0,0 +1,21 @@
|
||||
import json
|
||||
|
||||
from info_tech_canon.cli import main
|
||||
|
||||
|
||||
def test_cli_inspect_emits_json(capsys) -> None:
|
||||
exit_code = main(["inspect"])
|
||||
|
||||
assert exit_code == 0
|
||||
payload = json.loads(capsys.readouterr().out)
|
||||
assert payload["ok"] is True
|
||||
assert payload["infospace"]["artifact_count"] == 15
|
||||
|
||||
|
||||
def test_cli_missing_profile_uses_structured_error(capsys) -> None:
|
||||
exit_code = main(["profile", "inspect", "small-saas"])
|
||||
|
||||
assert exit_code == 2
|
||||
payload = json.loads(capsys.readouterr().out)
|
||||
assert payload["ok"] is False
|
||||
assert payload["error"]["code"] == "missing_profile"
|
||||
41
tests/test_service.py
Normal file
41
tests/test_service.py
Normal file
@@ -0,0 +1,41 @@
|
||||
from info_tech_canon.service import (
|
||||
artifact_graph,
|
||||
inspect_canon,
|
||||
list_models,
|
||||
list_standards,
|
||||
validate_canon,
|
||||
)
|
||||
|
||||
|
||||
def test_inspect_canon_counts_artifact_kinds() -> None:
|
||||
payload = inspect_canon()
|
||||
|
||||
assert payload["ok"] is True
|
||||
assert payload["infospace"]["slug"] == "canon"
|
||||
assert payload["infospace"]["artifact_count"] == 15
|
||||
assert payload["infospace"]["kinds"] == {
|
||||
"kernel": 2,
|
||||
"model": 11,
|
||||
"standard": 2,
|
||||
}
|
||||
|
||||
|
||||
def test_model_and_standard_lists_are_filtered() -> None:
|
||||
assert list_models()["count"] == 11
|
||||
assert list_standards()["count"] == 2
|
||||
|
||||
|
||||
def test_validate_canon_passes_scaffold() -> None:
|
||||
payload = validate_canon()
|
||||
|
||||
assert payload["ok"] is True
|
||||
assert payload["errors"] == []
|
||||
assert payload["details"]["artifact_count"] == 15
|
||||
|
||||
|
||||
def test_graph_exports_relationship_summary() -> None:
|
||||
payload = artifact_graph()
|
||||
|
||||
assert payload["ok"] is True
|
||||
assert payload["graph"]["node_count"] == 15
|
||||
assert payload["graph"]["edge_count"] > 15
|
||||
@@ -4,7 +4,7 @@ type: workplan
|
||||
title: "Infospace Scaffold And Seed Placement"
|
||||
domain: canon
|
||||
repo: info-tech-canon
|
||||
status: proposed
|
||||
status: finished
|
||||
priority: high
|
||||
created: "2026-05-23"
|
||||
updated: "2026-05-23"
|
||||
@@ -51,7 +51,7 @@ infospace/
|
||||
|
||||
```task
|
||||
id: ITC-WP-0001-T01
|
||||
status: todo
|
||||
status: done
|
||||
priority: high
|
||||
state_hub_task_id: "3a7b29ba-bc15-4ca1-ba61-ec4ffaefa2a1"
|
||||
```
|
||||
@@ -64,7 +64,7 @@ state_hub_task_id: "3a7b29ba-bc15-4ca1-ba61-ec4ffaefa2a1"
|
||||
|
||||
```task
|
||||
id: ITC-WP-0001-T02
|
||||
status: todo
|
||||
status: done
|
||||
priority: high
|
||||
state_hub_task_id: "b5894ec2-e79e-4308-9125-fd10c4b76faf"
|
||||
```
|
||||
@@ -79,7 +79,7 @@ state_hub_task_id: "b5894ec2-e79e-4308-9125-fd10c4b76faf"
|
||||
|
||||
```task
|
||||
id: ITC-WP-0001-T03
|
||||
status: todo
|
||||
status: done
|
||||
priority: high
|
||||
state_hub_task_id: "4826fbad-3dc7-4759-b086-8cb3cf50f6ff"
|
||||
```
|
||||
@@ -94,7 +94,7 @@ state_hub_task_id: "4826fbad-3dc7-4759-b086-8cb3cf50f6ff"
|
||||
|
||||
```task
|
||||
id: ITC-WP-0001-T04
|
||||
status: todo
|
||||
status: done
|
||||
priority: medium
|
||||
state_hub_task_id: "ff5bae40-9e89-4ec7-9f96-6670e140f4fa"
|
||||
```
|
||||
@@ -110,3 +110,11 @@ state_hub_task_id: "ff5bae40-9e89-4ec7-9f96-6670e140f4fa"
|
||||
- The seed documents are available under the newer `kernel/models/standards`
|
||||
layout.
|
||||
- Original seed provenance remains traceable.
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
- Implemented the concrete `infospace/` root with manifest and artifact index.
|
||||
- Copied seed documents to canonical `kernel/`, `models/`, and `standards/`
|
||||
paths without semantic edits.
|
||||
- Preserved source provenance in `infospace/artifacts/index.yaml` and
|
||||
`infospace/reports/scaffold-placement.md`.
|
||||
|
||||
@@ -4,7 +4,7 @@ type: workplan
|
||||
title: "Service Surface Baseline CLI JSON API"
|
||||
domain: canon
|
||||
repo: info-tech-canon
|
||||
status: proposed
|
||||
status: finished
|
||||
priority: high
|
||||
created: "2026-05-23"
|
||||
updated: "2026-05-23"
|
||||
@@ -32,7 +32,7 @@ usable by downstream agents and tools.
|
||||
|
||||
```task
|
||||
id: ITC-WP-0002-T01
|
||||
status: todo
|
||||
status: done
|
||||
priority: high
|
||||
state_hub_task_id: "0d843b8f-0bba-4bd8-8879-5641d2b50848"
|
||||
```
|
||||
@@ -46,7 +46,7 @@ state_hub_task_id: "0d843b8f-0bba-4bd8-8879-5641d2b50848"
|
||||
|
||||
```task
|
||||
id: ITC-WP-0002-T02
|
||||
status: todo
|
||||
status: done
|
||||
priority: high
|
||||
state_hub_task_id: "030955d2-e6af-48d8-a617-943cf4f10628"
|
||||
```
|
||||
@@ -65,7 +65,7 @@ state_hub_task_id: "030955d2-e6af-48d8-a617-943cf4f10628"
|
||||
|
||||
```task
|
||||
id: ITC-WP-0002-T03
|
||||
status: todo
|
||||
status: done
|
||||
priority: high
|
||||
state_hub_task_id: "a926fa1d-7dc0-4450-84c9-c0d49b3744ea"
|
||||
```
|
||||
@@ -78,7 +78,7 @@ state_hub_task_id: "a926fa1d-7dc0-4450-84c9-c0d49b3744ea"
|
||||
|
||||
```task
|
||||
id: ITC-WP-0002-T04
|
||||
status: todo
|
||||
status: done
|
||||
priority: high
|
||||
state_hub_task_id: "070ef996-cf45-47ed-b9d8-1e313c9b0e22"
|
||||
```
|
||||
@@ -100,3 +100,12 @@ state_hub_task_id: "070ef996-cf45-47ed-b9d8-1e313c9b0e22"
|
||||
- Commands can inspect the `infospace/` root.
|
||||
- API and CLI outputs share the same service-layer contracts.
|
||||
- Tests cover the first happy paths and structured failures.
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
- Added the `info_tech_canon` Python package and `info-tech-canon` console
|
||||
script definition.
|
||||
- Added JSON-first CLI commands for inspection, artifact/model/standard lists,
|
||||
validation, graph export, and profile inspection.
|
||||
- Added a read-only local HTTP API mirroring the CLI contracts.
|
||||
- Added service, CLI, and API tests for the baseline behavior.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
repository: info-tech-canon
|
||||
type: workplan-registry
|
||||
status: planned
|
||||
status: active
|
||||
created: "2026-05-23"
|
||||
updated: "2026-05-23"
|
||||
|
||||
@@ -18,7 +18,7 @@ implementation_decisions:
|
||||
workplans:
|
||||
- id: ITC-WP-0001
|
||||
title: Infospace Scaffold And Seed Placement
|
||||
status: planned
|
||||
status: finished
|
||||
priority: high
|
||||
path: workplans/ITC-WP-0001-infospace-scaffold-and-seed-placement.md
|
||||
depends_on: []
|
||||
@@ -29,7 +29,7 @@ workplans:
|
||||
|
||||
- id: ITC-WP-0002
|
||||
title: Service Surface Baseline CLI JSON API
|
||||
status: planned
|
||||
status: finished
|
||||
priority: high
|
||||
path: workplans/ITC-WP-0002-service-surface-cli-json-api.md
|
||||
depends_on:
|
||||
@@ -42,7 +42,7 @@ workplans:
|
||||
|
||||
- id: ITC-WP-0003
|
||||
title: Validation Indexes And Generated Views
|
||||
status: planned
|
||||
status: proposed
|
||||
priority: high
|
||||
path: workplans/ITC-WP-0003-validation-indexes-and-generated-views.md
|
||||
depends_on:
|
||||
@@ -56,7 +56,7 @@ workplans:
|
||||
|
||||
- id: ITC-WP-0004
|
||||
title: Small SaaS Profile Proof
|
||||
status: planned
|
||||
status: proposed
|
||||
priority: high
|
||||
path: workplans/ITC-WP-0004-small-saas-profile-proof.md
|
||||
depends_on:
|
||||
@@ -70,7 +70,7 @@ workplans:
|
||||
|
||||
- id: ITC-WP-0005
|
||||
title: Retrieval Agent Briefs And Interface Cards
|
||||
status: planned
|
||||
status: proposed
|
||||
priority: medium
|
||||
path: workplans/ITC-WP-0005-retrieval-agent-briefs-and-interface-cards.md
|
||||
depends_on:
|
||||
@@ -83,7 +83,7 @@ workplans:
|
||||
|
||||
- id: ITC-WP-0006
|
||||
title: Purpose And Demand Model Extension
|
||||
status: planned
|
||||
status: proposed
|
||||
priority: high
|
||||
path: workplans/ITC-WP-0006-purpose-and-demand-model.md
|
||||
depends_on:
|
||||
@@ -95,7 +95,7 @@ workplans:
|
||||
|
||||
- id: ITC-WP-0007
|
||||
title: User Engine Evaluation Readiness
|
||||
status: planned
|
||||
status: proposed
|
||||
priority: high
|
||||
path: workplans/ITC-WP-0007-user-engine-evaluation-readiness.md
|
||||
depends_on:
|
||||
@@ -109,7 +109,7 @@ workplans:
|
||||
|
||||
- id: ITC-WP-0008
|
||||
title: Railiance Fabric Conformance Support
|
||||
status: planned
|
||||
status: proposed
|
||||
priority: high
|
||||
path: workplans/ITC-WP-0008-railiance-fabric-conformance-support.md
|
||||
depends_on:
|
||||
@@ -123,7 +123,7 @@ workplans:
|
||||
|
||||
- id: ITC-WP-0009
|
||||
title: Repo Scoping Comparison And Extension
|
||||
status: planned
|
||||
status: proposed
|
||||
priority: high
|
||||
path: workplans/ITC-WP-0009-repo-scoping-comparison-and-extension.md
|
||||
depends_on:
|
||||
@@ -136,7 +136,7 @@ workplans:
|
||||
|
||||
- id: ITC-WP-0010
|
||||
title: CARING Kubernetes RBAC Benchmark
|
||||
status: planned
|
||||
status: proposed
|
||||
priority: medium
|
||||
path: workplans/ITC-WP-0010-caring-kubernetes-rbac-benchmark.md
|
||||
depends_on:
|
||||
@@ -146,4 +146,3 @@ workplans:
|
||||
- distinct benchmark workspace
|
||||
- Kubernetes RBAC assimilation
|
||||
- CARING validation stress test
|
||||
|
||||
|
||||
Reference in New Issue
Block a user