Skip to content
Draft
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
1 change: 1 addition & 0 deletions .changes/app-peer-naming.changed.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
统一使用 App 表示应用、Peer 表示参与运行的实例;Web 部署和开发种子的默认展示名改为 web 与 web-development,保持 Peer UUID 与协议身份不变,并更新部署和扩展连接说明。
2 changes: 1 addition & 1 deletion deploy/profiles/production.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
},
"peer": {
"id": "1eaaadc6-2c1d-4515-ad06-22905dc890a9",
"name": "client-web"
"name": "web"
},
"core": {
"peer_id": "063cd1df-c495-5006-a119-67aa633b26be",
Expand Down
4 changes: 2 additions & 2 deletions docs/30-unit-tdd/mail-extension.md
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,7 @@ singular `content` relation 返回任意 existing child;只有缺失且 `mater
Effective Storage 顺序是 `sources.storage` → deployment `core.source` default → built-in PostgreSQL binary `-4`。
Catalog constraint 保证 explicit Source Storage 类型可写;runtime error 仍可以表达具体 instance unavailable。

client-web 无 IMAP socket,使用 exact Peer capability 请求 provider-local materialization,再从共享数据库/Storage
Web App 无 IMAP socket,使用 exact Peer capability 请求 provider-local materialization,再从共享数据库/Storage
自行 solve returned child。Provider inbound 调 non-delegating local Resolver path;不建立 generic Resolver delegation。

## Failure And Concurrency Boundary
Expand All @@ -224,7 +224,7 @@ Source 入口决定逐 Mailbox/occurrence 的异步事务;网络获取和 mark
## Verification Authority

阻塞验收使用 repository-owned professional-reading `.eml` corpus、checksum-verified Dovecot 2.4、disposable
PostgreSQL,以及 built client-web/Mail remote:
PostgreSQL,以及构建后的 Web App/Mail remote:

- J1:ordinary horizon、mailbox exclusions、QRESYNC flags/removals、idempotence;
- J2:exact backfill、ordinary checkpoint independence;
Expand Down
4 changes: 2 additions & 2 deletions docs/30-unit-tdd/security-model.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ This local projection covers the FastAPI runtime,the executable PostgreSQL con
Extension loading,Source collection,Resolver/Storage access,background Jobs and the artifacts
and deployment surfaces delivered by this repository。

Browser rendering,native-client storage and other Peer-local mechanics belong to their owning
Browser rendering,native App storage and other Peer-local mechanics belong to their owning
repositories。Concrete Extension protocol credentials and admission belong to the Extension's
local durable contract。

Expand All @@ -29,7 +29,7 @@ roles,grants and denial behavior are owned by the [Executable Database
Contract](../40-deployment/database-contract.md) and its executable checks。

Public health and probe routes grant only their documented observations。CORS,route naming and
client identifiers do not add authority。
Peer identifiers do not add authority。

### Extension Protocols

Expand Down
2 changes: 1 addition & 1 deletion docs/30-unit-tdd/twitter-extension.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ Python Twitter distribution 把 x-monkey 提交和 Bookmark 采集写入同一

两条写入路径都先取得 `extensions.twitter.reconcile` 全局事务 advisory 锁,再批量重读原生身份。根内容和受管关系一起提交;异常让整批回滚,调用方可安全重放。该锁仅约束正常 Twitter 写入入口,不能替代所有 info-base 原始写入的约束。provider 和媒体网络访问都不能放进此事务。

原生身份、Blocks 和引用边使用批量查询与创建。不要在每个媒体项内单独查询、创建和 flush:Core 与数据库跨网络部署时,这会把一次正常批次放大为数百次串行往返,并在持锁期间耗尽客户端的同步请求期限。
原生身份、Blocks 和引用边使用批量查询与创建。不要在每个媒体项内单独查询、创建和 flush:Core 与数据库跨网络部署时,这会把一次正常批次放大为数百次串行往返,并在持锁期间耗尽调用方的同步请求期限。

匹配先选新版 resolver,再按 Block ID 稳定选择旧 `tweet.v1`。旧根重新采集后原地更新,保留现有 Block ID、引用和旧附件关系;未重新采集的旧根仍由 v1 decoder 读取。旧加工正文不足以重建 native RichText,不能用它伪造新记录。共同合并提供 `replace` 与 `supplement` 正文策略:正常捕获合并已提交的正文结构,补充捕获在已有正文时保留它并增加其他事实。Bookmark 使用补充策略,避免较少详情的正文覆盖完整捕获;该选择不作为字段写进持久记录。

Expand Down
2 changes: 1 addition & 1 deletion docs/40-deployment/database-contract.md
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ Every production candidate also contains `/app/database-contract/`:

The dump comes from a separate fresh database initialized with the runtime profile; it contains
no application row. `db schema --json` verifies the embedded files against that manifest.
Core-py publishes SQL, not client-specific generated types; consumers restore the role and schema
Core-py publishes SQL, not consumer-specific generated types; consumers restore the role and schema
files, then use their own mature language tooling.

Published core images are addressed as:
Expand Down
8 changes: 6 additions & 2 deletions docs/40-deployment/development-environment.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,12 +40,12 @@ Runtime state is written to `.runtime/database/<core-svc-instance>/`. Its `runti
- core and PostgREST loopback URLs.

Peers must consume that exact profile/descriptor. Sharing only an SSH alias, daemon, port,
or contract version does not prove that core-py and client-web use the same database.
or contract version does not prove that core-py and the Web App use the same database.
Only core-py owns Compose startup, reset, volume deletion, credentials, and tunnel cleanup.

After core and PostgREST are reachable, the owner projects the dynamic core loopback URL into the core Peer's
database-owned `config.http_public_base_url`. It then waits for that exact Peer to publish the three built-in HTTP
capabilities and a live database-time lease before writing a converged descriptor. Attached client-web runtimes only verify
capabilities and a live database-time lease before writing a converged descriptor. Attached Web App runtimes only verify
that snapshot; they do not rewrite the owner Peer, reset the database, or stop the owner runtime.

## Stopping the development runtime
Expand Down Expand Up @@ -179,6 +179,10 @@ The repository currently uses Neon branch automation for pull requests.
- `pdm run db:record` appends reviewed new revisions to the integrity manifest.
- `pdm run db:migrate` applies checked-in revisions.
- `pdm run db:init --profile development` creates the complete deterministic baseline.
- The canonical development Peer is named `web-development`; its UUID is unchanged. Existing
development databases can converge this display name with `pdm run db:seed-dev` before the
development readiness check. This updates the existing canonical seed row and does not reset
the database or replace other Peer identities.
- `pdm run db:ready --profile development --json` verifies it without mutation.
- `pdm run db:reset-dev --confirm reset-development-data` restores the same guarded
baseline and refuses every non-development database.
Expand Down
2 changes: 1 addition & 1 deletion docs/40-deployment/heroku-neon-self-host.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ key or another password as the JWT secret.
confirmation authorizes database initialization or migration; it does not bypass readiness or
database checks.
7. Read the workflow summary for the public app URLs, Peer identity, exact commit, and Heroku
releases. Keep using the repository's private `JWT_SECRET` when an admitted client asks for
releases. Keep using the repository's private `JWT_SECRET` when an admitted Peer asks for
the signing key.

## Convergence And Safety
Expand Down
10 changes: 5 additions & 5 deletions docs/40-deployment/observability.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@ OBSRV__LOKI_HEADERS='{"Authorization":"Basic YOUR_ENCODED_VALUE"}'
OBSRV__EXTERNAL_CONTENT_ENABLED=false
```

URL 不带凭据、query 或 fragment;私密 headers 不进入共享 value、浏览器或错误响应。Backend 选择是唯一存储选择源,旧 `OBSRV__LOGGING_BACKEND`/Logtail writer 配置不再选择当前存储;旧 Logtail 配置会给出迁移提示。`OBSRV__LOGGING_BACKEND_LEVEL` 继续控制普通日志级别,最低生命周期事件不依赖该阈值。切换后重启 Peer/重建客户端,历史记录留在旧后端,不自动搬迁、删除或合并查询。
URL 不带凭据、query 或 fragment;私密 headers 不进入共享 value、浏览器或错误响应。Backend 选择是唯一存储选择源,旧 `OBSRV__LOGGING_BACKEND`/Logtail writer 配置不再选择当前存储;旧 Logtail 配置会给出迁移提示。`OBSRV__LOGGING_BACKEND_LEVEL` 继续控制普通日志级别,最低生命周期事件不依赖该阈值。切换后重启 Peer/重建 SDK 消费实例,历史记录留在旧后端,不自动搬迁、删除或合并查询。

`core.observability.v1` 通过已有 Peer HTTP 协议公告 `POST /observability`,复用 Peer JWT;客户端不能传上游 URL 或认证头。请求 action 为 `status`、`query`、`ingest`。外部委派携带 `expected_backend`,与提供方实例不符返回 409,防止选择改变后误写其它后端。内置消费者可直接通过数据库协议读取,不以 Python Peer 在线为前提。
`core.observability.v1` 通过已有 Peer HTTP 协议公告 `POST /observability`,复用 Peer JWT;调用方不能传上游 URL 或认证头。请求 action 为 `status`、`query`、`ingest`。外部委派携带 `expected_backend`,与提供方实例不符返回 409,防止选择改变后误写其它后端。内置消费者可直接通过数据库协议读取,不以 Python Peer 在线为前提。

查询时间窗为 `[since, until)`,最长 31 天、每次 1–500 条。所有 severity、kind、Job、Trace、Peer、operation、文本过滤在后端截断之前执行;文本按字面匹配,不是 LogQL。返回 records、truncated、时间窗及当前 backend,按时间倒序。截断时缩小时间或过滤范围;没有会跳过同刻记录的虚假 cursor。旧 PG 日志保留原 body/attributes 和 `job.<id>` 关联,未产生的历史事件不会补写。

Expand Down Expand Up @@ -51,9 +51,9 @@ Grafana Cloud Free 是当前首个部署目标。`Authorization` 的 Basic 值

## 浏览器转发

浏览器不能使用上述私密 Grafana 写入凭据。client-web 的本地连接配置单独控制启用;需要服务端转发时,显式配置 relay 基础 URL,例如 `https://core.example/telemetry`,由客户端复用该连接的现有短效 Peer JWT。没有 relay 时,只能使用已准入、适合公开客户端的出口。relay URL 本身不启用遥测,也不改变业务的数据库直写或 Peer 路由。
浏览器不能使用上述私密 Grafana 写入凭据。Web App 的本地连接配置单独控制启用;需要 HTTP relay 转发时,显式配置 relay 基础 URL,例如 `https://core.example/telemetry`,由调用 Peer 复用该连接的现有短效 Peer JWT。没有 relay 时,只能使用已准入、适合公开 App 的出口。relay URL 本身不启用遥测,也不改变业务的数据库直写或 Peer 路由。

core-py 的 `POST /telemetry/v1/{traces,logs,metrics}` 复用普通 Peer JWT 认证,仅向自身已成功启用的对应信号出口发送。调用方不能指定目标或转发认证头;服务端使用本地私密认证。它仅接受标准 OTLP/HTTP protobuf,直接使用标准 protobuf 请求与响应;JSON 返回 415。上游的 200 或 204 视为接收成功,204 的空响应映射为空 protobuf 成功响应;仍须独立查询验证持久化。client-web 使用官方 protobuf exporter,避免应用自行实现 OTLP JSON 的十六进制 Trace/Span ID 规则。不增加持久队列、后台重试或任意 URL 代理。
core-py 的 `POST /telemetry/v1/{traces,logs,metrics}` 复用普通 Peer JWT 认证,仅向自身已成功启用的对应信号出口发送。调用方不能指定目标或转发认证头;接收 Peer 使用本地私密认证。它仅接受标准 OTLP/HTTP protobuf,直接使用标准 protobuf 请求与响应;JSON 返回 415。上游的 200 或 204 视为接收成功,204 的空响应映射为空 protobuf 成功响应;仍须独立查询验证持久化。Web App 使用官方 protobuf exporter,避免应用自行实现 OTLP JSON 的十六进制 Trace/Span ID 规则。不增加持久队列、后台重试或任意 URL 代理。

每个请求最多 256 KiB;每个进程最多四个转发请求同时进行,上游 HTTP 使用对应信号的 timeout;请求读取和发送的总预算为该 timeout 加两秒(最多三十二秒),不跟随重定向。不支持压缩请求。关闭或目的地不可用返回 503,满额返回 429,超大返回 413,格式错误返回 400,转发失败返回固定的 502,不回显上游错误体。转发会唤醒其宿主并消耗按请求资源,因此必须由部署显式选择;它不承诺遥测零额外运行费用。

Expand All @@ -72,7 +72,7 @@ core-py 的 `POST /telemetry/v1/{traces,logs,metrics}` 复用普通 Peer JWT 认

资源使用 `service.name`、`service.version`、`service.instance.id`、已知的 `inkcre.deployment.id` 与 `inkcre.peer.id`。查询单个任务用 `inkcre.job.id`,从执行 Trace 的 Link 查提交 Trace;同步 Peer 调用使用标准 W3C context。只有配置的 Peer 传输注入上下文,外部模型请求不注入内部 Trace Context。关闭的提交方写 NULL,关闭的执行方不创建 Trace,但领取和关闭保留已有 carrier。缺失、采样和过期导致的空缺不是业务未执行的证据。

生成的 Job carrier 各最多 512 UTF-8 bytes;SDK 注入的可选 tracestate 超限时整体省略并记录固定原因事件。SQL 容量约束拒绝直接超限输入。正式 migration `3d9593b0c855` 增加两列;nullable 不解除 exact-head 准入,部署需协调更新 schema、Python 与客户端,刷新 PostgREST schema cache。关闭遥测无需 downgrade 或删除任何 Job、PG 日志或 carrier。
生成的 Job carrier 各最多 512 UTF-8 bytes;SDK 注入的可选 tracestate 超限时整体省略并记录固定原因事件。SQL 容量约束拒绝直接超限输入。正式 migration `3d9593b0c855` 增加两列;nullable 不解除 exact-head 准入,部署需协调更新 schema 与所有 Peer,刷新 PostgREST schema cache。关闭遥测无需 downgrade 或删除任何 Job、PG 日志或 carrier。

## AI 数据边界

Expand Down
4 changes: 2 additions & 2 deletions docs/40-deployment/render-neon-self-host.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ continuously available. Wake the core URL and wait for `/readyz` before an inter
session. A stronger hosting plan can improve availability without changing domain behavior.

The current HS256 `JWT_SECRET` grants full admitted-Peer authority. Keep it private. Do not
put it in a repository variable, README, deployment profile, client build, issue, log, or
put it in a repository variable, README, deployment profile, App build, issue, log, or
workflow summary. A public read-only experience needs a different admission surface; a
different role name beside the same signing key does not reduce the key holder's authority.

Expand Down Expand Up @@ -50,7 +50,7 @@ deployment secret. Do not reuse a provider API key or database password as the J
5. Open **Actions → Deploy self-hosted InKCre → Run workflow** and select the commit/branch to
deploy.
6. Read the workflow summary for the non-secret core URL, PostgREST URL, Peer ID, and exact
commit. Keep using the repository's private `JWT_SECRET` when an admitted client asks for
commit. Keep using the repository's private `JWT_SECRET` when an admitted Peer asks for
the signing key.

## What The Controller Owns
Expand Down
2 changes: 1 addition & 1 deletion docs/_shared
Submodule _shared updated 43 files
+3 −3 10-prd/domain-structure/cross-domain-interactions.md
+1 −1 10-prd/domain-structure/derived-boundaries.md
+4 −4 10-prd/glossary.md
+3 −1 20-product-tdd/core-app-boundary.md
+3 −3 20-product-tdd/extension-documentation-hosting.md
+2 −2 20-product-tdd/extension-release-and-installation.md
+4 −4 20-product-tdd/feature-retrieval-and-media-interpretation.md
+1 −1 20-product-tdd/graph-navigation-retrieval.md
+2 −2 20-product-tdd/knowledge-capability-contract.md
+5 −5 20-product-tdd/observability-contract.md
+1 −1 20-product-tdd/peer-database-runtime-contract.md
+3 −3 20-product-tdd/system-state-and-authority.md
+5 −5 website/README.md
+3 −3 website/content/en/developer/architecture.md
+1 −1 website/content/en/developer/contributing.md
+2 −2 website/content/en/developer/index.md
+2 −2 website/content/en/getting-started.md
+1 −1 website/content/en/guide/collect.md
+2 −2 website/content/en/guide/connect.md
+1 −1 website/content/en/guide/daily-use.md
+1 −1 website/content/en/guide/first-source.md
+1 −1 website/content/en/guide/schedules.md
+2 −2 website/content/en/guide/search.md
+1 −1 website/content/en/guide/sources/mail.md
+1 −1 website/content/en/guide/sources/memos.md
+1 −1 website/content/en/guide/sources/rss.md
+4 −4 website/content/en/guide/sources/twitter.md
+1 −1 website/content/en/guide/troubleshooting.md
+1 −1 website/content/en/index.md
+8 −8 website/content/en/self-hosted/custom.md
+1 −1 website/content/en/self-hosted/index.md
+1 −0 website/content/public/_redirects
+ − website/content/public/images/web/collection-job.png
+ − website/content/public/images/web/create-source-type.png
+ − website/content/public/images/web/info-base-graph.png
+ − website/content/public/images/web/lexical-search.png
+ − website/content/public/images/web/mail-content.png
+ − website/content/public/images/web/memos-setup.png
+ − website/content/public/images/web/peers-overview.png
+ − website/content/public/images/web/settings-overview.png
+ − website/content/public/images/web/source-schedule.png
+ − website/content/public/images/web/sources-overview.png
+ − website/content/public/images/web/twitter-setup.png
2 changes: 1 addition & 1 deletion extensions/memos/docs/global/connect.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ token (PAT). Neither is your PostgREST connection setting, and the PAT is not th

1. Open **Extensions**, locate **Memos**, and open **Setup** from its enabled browser extension.
2. Select the Core that should provide the service if more than one is available. If the public
address is missing, configure that Core's Public HTTP Base URL in **Clients → Config**, then
address is missing, configure that Core's Public HTTP Base URL in **Peers → Config**, then
refresh the setup page. Use an address reachable from your phone or other client device.
3. Select **Prepare connection**. If no PAT is saved, the page generates and saves one. If a PAT
already exists, it keeps it. Memos is enabled on the selected Core only if needed.
Expand Down
2 changes: 1 addition & 1 deletion inkcre_core/auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ def create_peer_jwt(
now: float | None = None,
lifetime_seconds: int = 60,
) -> str:
"""Sign a Peer JWT; the default is client policy, not an admission limit."""
"""Sign a Peer JWT; the default is signer policy, not an admission limit."""
if not secret:
raise ValueError("Peer JWT secret is required")
if lifetime_seconds <= 0:
Expand Down
2 changes: 1 addition & 1 deletion inkcre_core/database_contract/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
JWT_MINIMUM_SECRET_BYTES = 32

DEVELOPMENT_PEER_ID = uuid.UUID("00000000-0000-4000-8000-000000000001")
DEVELOPMENT_PEER_NAME = "client-web-development"
DEVELOPMENT_PEER_NAME = "web-development"

DATABASE_ENVIRONMENTS = frozenset({"runtime", "development", "preview", "production"})
RESET_CONFIRMATION = "reset-development-data"
Expand Down
2 changes: 1 addition & 1 deletion scripts/release.py
Original file line number Diff line number Diff line change
Expand Up @@ -220,7 +220,7 @@ def affected_projects(base: str) -> set[str]:
paths = _changed_paths(base)
affected: set[str] = set()
extension_keys = {project.key for project in discover_projects(extensions_only=True)}
core_prefixes = ("app/", "libs/", "migrations/", "utils/")
core_prefixes = ("inkcre_core/", "app/", "libs/", "migrations/", "utils/")
core_files = {
"run.py",
"Dockerfile",
Expand Down
Loading