Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
name: CI

on:
pull_request:
push:
branches: [main]

jobs:
checks:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: astral-sh/setup-uv@v6
with:
version: "0.8.22"
enable-cache: true
- run: uv python install 3.13
- run: make install
- run: make check
15 changes: 10 additions & 5 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,16 +55,21 @@ measured isolation or performance evidence.
## Commands

```bash
# D0: no runnable application or dependency manifest exists yet.
# WP04 must replace this block with verified install/dev/build/test/lint commands
# before D0 can close.
make install # sync the locked Python 3.13 environment
make build # build wheel and source distribution
make lint # Ruff
make typecheck # strict mypy
make test # unit test suite
make smoke # API and worker process smoke suite
make check # all required repository checks
```

## Verification Contract

Before claiming an implementation done, run the verified commands recorded
above. While D0 has no runnable implementation, report that fact and run the
applicable document/provenance/link checks instead. Never fabricate output.
above. Never fabricate output. A green process smoke proves only boot/readiness;
Runtime delivery, database and worker-job capabilities remain `NOT_ACTIVE` until
their owning issues implement and verify them.

## Safety-Rails / Do Not

Expand Down
21 changes: 21 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
.PHONY: install build lint typecheck test smoke check

install:
uv sync --frozen

build:
uv build

lint:
uv run ruff check .

typecheck:
uv run mypy

test:
uv run pytest -q tests/unit

smoke:
uv run pytest -q tests/process

check: build lint typecheck test smoke
37 changes: 36 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,44 @@
企业微信),下游把「经过授权、带证据、有预算」的 ContextPackage 交付给 agent
应用与 IM bot(飞书群聊问答优先)。

**当前状态**:D0 设计闭环阶段(pre-M0),尚无可运行代码。整体计划见
**当前状态**:M0 工程骨架已启动。API 和独立 Supply worker 可运行,但
Runtime delivery、数据库和 worker job 行为仍为 `NOT_ACTIVE`。整体计划见
[PLAN.md](./PLAN.md)。

## 开发命令

要求 Python 3.13 和 [uv](https://docs.astral.sh/uv/)。依赖版本由
`uv.lock` 固定,仓库命令统一由 `make` 暴露:

```bash
make install # uv sync --frozen
make build # 构建 wheel 和 sdist
make lint # Ruff
make typecheck # strict mypy
make test # 单元测试
make smoke # API / worker 进程 smoke
make check # build + lint + typecheck + test + smoke
```

本地启动 API:

```bash
uv run context-engine-api
```

监听地址和端口可通过 `context-engine-api --help` 中记录的参数覆盖;进程启动后
在所配置地址请求 `/health`。

确定性运行 worker 的 no-op 测试生命周期:

```bash
uv run context-engine-worker --test-mode
```

健康响应中的 `runtime_delivery: NOT_ACTIVE` 和 worker 输出中的
`job_behavior: NOT_ACTIVE` 是能力边界,不表示数据库、授权或 ContextPackage
交付已经实现。

本次公开候选 bundle 包含实现权威、ADR、安全契约、PRD、Tech Spec
与四个公开参考仓的证据基线;经维护者批准并提交后,它们将与实现一同
版本化。公开 prior art 仅限 Dify、RAGFlow、MaxKB、Onyx 的固定版本;
Expand Down
1 change: 1 addition & 0 deletions adapters/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
"""Infrastructure adapters around the shared ContextEngine domain."""
1 change: 1 addition & 0 deletions adapters/http/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
"""HTTP ingress adapter."""
32 changes: 32 additions & 0 deletions adapters/http/app.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
"""Minimal FastAPI composition root."""

from typing import Final

from fastapi import FastAPI

from engine import BUILD_IDENTIFIER
from engine.runtime import Runtime
from engine.runtime.construction import required_kernel_dependencies

HEALTH_RESPONSE: Final = {
"status": "ready",
"service": "context-engine-api",
"version": BUILD_IDENTIFIER,
"runtime_delivery": "NOT_ACTIVE",
}


def create_app() -> FastAPI:
"""Construct the API and fail before serving if kernel wiring is incomplete."""

Runtime(required_kernel_dependencies())
app = FastAPI(title="ContextEngine", version=BUILD_IDENTIFIER)

@app.get("/health", include_in_schema=False)
def health() -> dict[str, str]:
return HEALTH_RESPONSE.copy()

return app


app = create_app()
1 change: 1 addition & 0 deletions applications/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
"""Process composition roots around the shared domain."""
24 changes: 24 additions & 0 deletions applications/api.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
"""Engine API process entry point."""

import argparse
from collections.abc import Sequence

import uvicorn


def main(argv: Sequence[str] | None = None) -> None:
parser = argparse.ArgumentParser(description="ContextEngine API")
parser.add_argument("--host", default="127.0.0.1")
parser.add_argument("--port", default=8000, type=int)
parser.add_argument("--log-level", default="info")
args = parser.parse_args(argv)
uvicorn.run(
"adapters.http.app:app",
host=args.host,
port=args.port,
log_level=args.log_level,
)


if __name__ == "__main__":
main()
45 changes: 45 additions & 0 deletions applications/worker.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
"""Independent Supply worker process entry point."""

import argparse
import json
import threading
from collections.abc import Sequence

from engine import BUILD_IDENTIFIER
from engine.runtime import Runtime
from engine.runtime.construction import required_kernel_dependencies


def run(*, test_mode: bool) -> int:
Runtime(required_kernel_dependencies())
lifecycle = "test-complete" if test_mode else "ready"
print(
json.dumps(
{
"status": lifecycle,
"service": "context-engine-worker",
"version": BUILD_IDENTIFIER,
"job_behavior": "NOT_ACTIVE",
},
sort_keys=True,
),
flush=True,
)
if not test_mode:
threading.Event().wait()
return 0

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Keep the worker alive in normal mode

When the worker is launched normally as context-engine-worker without --test-mode, this unconditional return lets the process print ready and exit immediately. That contradicts the separate --test-mode lifecycle and leaves deployments or smoke scripts with no running Supply worker process; normal mode should block/run its service loop even while job behavior is NOT_ACTIVE.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

will-fix — fixed in e740392. Normal mode now prints readiness with flush and blocks at applications/worker.py:28-29; --test-mode alone exits deterministically. Regression coverage at tests/process/test_processes.py:81-101 proves the installed worker remains alive until terminated.



def main(argv: Sequence[str] | None = None) -> int:
parser = argparse.ArgumentParser(description="ContextEngine Supply worker")
parser.add_argument(
"--test-mode",
action="store_true",
help="complete the deterministic no-op lifecycle and exit",
)
args = parser.parse_args(argv)
return run(test_mode=args.test_mode)


if __name__ == "__main__":
raise SystemExit(main())
5 changes: 5 additions & 0 deletions engine/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
"""Shared ContextEngine domain package."""

from engine.build import BUILD_IDENTIFIER

__all__ = ["BUILD_IDENTIFIER"]
8 changes: 8 additions & 0 deletions engine/build.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
"""Build identity shared by every ContextEngine process."""

from importlib.metadata import PackageNotFoundError, version

try:
BUILD_IDENTIFIER = version("context-engine")
except PackageNotFoundError:
BUILD_IDENTIFIER = "0.1.0+uninstalled"
15 changes: 15 additions & 0 deletions engine/runtime/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
"""Runtime construction boundary; context delivery is not active yet."""

from engine.runtime.construction import (
KernelDependencies,
KernelDependency,
Runtime,
RuntimeConfigurationError,
)

__all__ = [
"KernelDependencies",
"KernelDependency",
"Runtime",
"RuntimeConfigurationError",
]
63 changes: 63 additions & 0 deletions engine/runtime/construction.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
"""Fail-closed construction for the future sealed Runtime.

This module proves mandatory dependency wiring only. It deliberately exposes no
``resolve`` method or authorization behavior before the owning M0 issues land.
"""

from dataclasses import dataclass
from enum import StrEnum


class KernelDependency(StrEnum):
"""Closed set of security-kernel dependency identities."""

POLICY = "policy"
AUDIT = "audit"
BUDGET = "budget"
PROVENANCE = "provenance"


class RuntimeConfigurationError(RuntimeError):
"""Raised when the sealed Runtime composition is incomplete or invalid."""


@dataclass(frozen=True, slots=True)
class KernelDependencies:
"""Explicit mandatory inputs to Runtime construction."""

policy: KernelDependency
audit: KernelDependency
budget: KernelDependency
provenance: KernelDependency

class Runtime:
"""Construction seam for a sealed Runtime whose delivery API is not active."""

def __init__(self, dependencies: KernelDependencies) -> None:
if type(dependencies) is not KernelDependencies:
raise RuntimeConfigurationError(
"runtime dependencies must be KernelDependencies"
)
expected = (
("policy", KernelDependency.POLICY),
("audit", KernelDependency.AUDIT),
("budget", KernelDependency.BUDGET),
("provenance", KernelDependency.PROVENANCE),
)
for field_name, expected_dependency in expected:
if getattr(dependencies, field_name) is not expected_dependency:
raise RuntimeConfigurationError(
f"mandatory kernel dependency is missing or invalid: {field_name}"
)
self._dependencies = dependencies


def required_kernel_dependencies() -> KernelDependencies:
"""Return the only allowed skeleton composition; no disable flag exists."""

return KernelDependencies(
policy=KernelDependency.POLICY,
audit=KernelDependency.AUDIT,
budget=KernelDependency.BUDGET,
provenance=KernelDependency.PROVENANCE,
)
44 changes: 44 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"

[project]
name = "context-engine"
version = "0.1.0"
description = "Permission-aware context delivery engine"
readme = "README.md"
requires-python = ">=3.13,<3.14"
dependencies = [
"fastapi>=0.116,<0.117",
"uvicorn>=0.35,<0.36",
]

[dependency-groups]
dev = [
"httpx>=0.28,<0.29",
"mypy>=1.17,<1.18",
"pytest>=8.4,<8.5",
"ruff>=0.12,<0.13",
]

[project.scripts]
context-engine-api = "applications.api:main"
context-engine-worker = "applications.worker:main"

[tool.hatch.build.targets.wheel]
packages = ["engine", "adapters", "applications"]

[tool.mypy]
python_version = "3.13"
strict = true
files = ["engine", "adapters", "applications", "tests"]

[tool.pytest.ini_options]
testpaths = ["tests"]

[tool.ruff]
target-version = "py313"
line-length = 88

[tool.ruff.lint]
select = ["E", "F", "I", "UP", "B", "SIM"]
Loading
Loading