From f8eb31bd4b767d6d99d95878fcee45110cac83d1 Mon Sep 17 00:00:00 2001 From: Lan_zhijiang Date: Wed, 4 Nov 2026 22:06:41 +0800 Subject: [PATCH 1/3] =?UTF-8?q?ref(core):=20=E7=BB=9F=E4=B8=80=E5=BA=94?= =?UTF-8?q?=E7=94=A8=E4=B8=8E=20Peer=20=E8=A7=92=E8=89=B2=E5=91=BD?= =?UTF-8?q?=E5=90=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Web 默认展示名使用 web,保留 Peer UUID 和历史兼容标识 - 当前部署与扩展文档使用 App 和 Peer 描述产品角色 - 补充独立 SDK 源码的 Core 发布归属及回归验证 --- .changes/app-peer-naming.changed.md | 1 + deploy/profiles/production.json | 2 +- docs/30-unit-tdd/mail-extension.md | 4 ++-- docs/30-unit-tdd/security-model.md | 4 ++-- docs/30-unit-tdd/twitter-extension.md | 2 +- docs/40-deployment/database-contract.md | 2 +- docs/40-deployment/development-environment.md | 8 ++++++-- docs/40-deployment/heroku-neon-self-host.md | 2 +- docs/40-deployment/observability.md | 10 +++++----- docs/40-deployment/render-neon-self-host.md | 4 ++-- extensions/memos/docs/global/connect.md | 2 +- inkcre_core/auth.py | 2 +- inkcre_core/database_contract/constants.py | 2 +- scripts/release.py | 2 +- tests/test_release.py | 13 +++++++++++++ 15 files changed, 39 insertions(+), 21 deletions(-) create mode 100644 .changes/app-peer-naming.changed.md create mode 100644 tests/test_release.py diff --git a/.changes/app-peer-naming.changed.md b/.changes/app-peer-naming.changed.md new file mode 100644 index 00000000..432387ff --- /dev/null +++ b/.changes/app-peer-naming.changed.md @@ -0,0 +1 @@ +统一使用 App 表示应用、Peer 表示参与运行的实例;Web 部署和开发种子的默认展示名改为 web 与 web-development,保持 Peer UUID 与协议身份不变,并更新部署和扩展连接说明。 diff --git a/deploy/profiles/production.json b/deploy/profiles/production.json index c68c3eff..d2d53bc8 100644 --- a/deploy/profiles/production.json +++ b/deploy/profiles/production.json @@ -8,7 +8,7 @@ }, "peer": { "id": "1eaaadc6-2c1d-4515-ad06-22905dc890a9", - "name": "client-web" + "name": "web" }, "core": { "peer_id": "063cd1df-c495-5006-a119-67aa633b26be", diff --git a/docs/30-unit-tdd/mail-extension.md b/docs/30-unit-tdd/mail-extension.md index 3a683a01..c6e17611 100644 --- a/docs/30-unit-tdd/mail-extension.md +++ b/docs/30-unit-tdd/mail-extension.md @@ -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 @@ -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; diff --git a/docs/30-unit-tdd/security-model.md b/docs/30-unit-tdd/security-model.md index 68904486..68707d81 100644 --- a/docs/30-unit-tdd/security-model.md +++ b/docs/30-unit-tdd/security-model.md @@ -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。 @@ -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 diff --git a/docs/30-unit-tdd/twitter-extension.md b/docs/30-unit-tdd/twitter-extension.md index 358ec2fe..ecb05468 100644 --- a/docs/30-unit-tdd/twitter-extension.md +++ b/docs/30-unit-tdd/twitter-extension.md @@ -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 使用补充策略,避免较少详情的正文覆盖完整捕获;该选择不作为字段写进持久记录。 diff --git a/docs/40-deployment/database-contract.md b/docs/40-deployment/database-contract.md index 7d52dc4e..4853d433 100644 --- a/docs/40-deployment/database-contract.md +++ b/docs/40-deployment/database-contract.md @@ -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: diff --git a/docs/40-deployment/development-environment.md b/docs/40-deployment/development-environment.md index 34521c8d..7523746f 100644 --- a/docs/40-deployment/development-environment.md +++ b/docs/40-deployment/development-environment.md @@ -40,12 +40,12 @@ Runtime state is written to `.runtime/database//`. 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 @@ -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. diff --git a/docs/40-deployment/heroku-neon-self-host.md b/docs/40-deployment/heroku-neon-self-host.md index e827d09f..cdc0d39f 100644 --- a/docs/40-deployment/heroku-neon-self-host.md +++ b/docs/40-deployment/heroku-neon-self-host.md @@ -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 diff --git a/docs/40-deployment/observability.md b/docs/40-deployment/observability.md index cb01e155..27ea379f 100644 --- a/docs/40-deployment/observability.md +++ b/docs/40-deployment/observability.md @@ -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.` 关联,未产生的历史事件不会补写。 @@ -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,不回显上游错误体。转发会唤醒其宿主并消耗按请求资源,因此必须由部署显式选择;它不承诺遥测零额外运行费用。 @@ -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 数据边界 diff --git a/docs/40-deployment/render-neon-self-host.md b/docs/40-deployment/render-neon-self-host.md index 4421f983..6ab2e617 100644 --- a/docs/40-deployment/render-neon-self-host.md +++ b/docs/40-deployment/render-neon-self-host.md @@ -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. @@ -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 diff --git a/extensions/memos/docs/global/connect.md b/extensions/memos/docs/global/connect.md index 90564cb4..eb766867 100644 --- a/extensions/memos/docs/global/connect.md +++ b/extensions/memos/docs/global/connect.md @@ -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. diff --git a/inkcre_core/auth.py b/inkcre_core/auth.py index 8b6a9734..b1573de0 100644 --- a/inkcre_core/auth.py +++ b/inkcre_core/auth.py @@ -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: diff --git a/inkcre_core/database_contract/constants.py b/inkcre_core/database_contract/constants.py index c5dd790f..beb328a3 100644 --- a/inkcre_core/database_contract/constants.py +++ b/inkcre_core/database_contract/constants.py @@ -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" diff --git a/scripts/release.py b/scripts/release.py index 1c611336..bf35a150 100644 --- a/scripts/release.py +++ b/scripts/release.py @@ -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", diff --git a/tests/test_release.py b/tests/test_release.py new file mode 100644 index 00000000..eeebadf0 --- /dev/null +++ b/tests/test_release.py @@ -0,0 +1,13 @@ +"""Release ownership follows the independently packaged Core source tree.""" + +from scripts import release + + +def test_sdk_only_change_requires_core_release_intent(monkeypatch): + monkeypatch.setattr( + release, + "_changed_paths", + lambda _base: ("inkcre_core/database_contract/constants.py",), + ) + + assert release.affected_projects("parent") == {"core"} From 3581b76f869b482fc1f5afee17b39de7ce1b4b92 Mon Sep 17 00:00:00 2001 From: Lan_zhijiang Date: Wed, 4 Nov 2026 22:09:27 +0800 Subject: [PATCH 2/3] =?UTF-8?q?docs(core):=20=E5=BC=95=E7=94=A8=20App=20?= =?UTF-8?q?=E4=B8=8E=20Peer=20=E5=91=BD=E5=90=8D=E5=90=88=E5=90=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/_shared | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/_shared b/docs/_shared index 33f5a13c..d7c4d0c9 160000 --- a/docs/_shared +++ b/docs/_shared @@ -1 +1 @@ -Subproject commit 33f5a13c4ec4ba5b3cad73a0e8f3a097139458de +Subproject commit d7c4d0c998455d40c30deb25da5b5060eb85aba1 From 4314c2f6010d3eadc5798b8091941b1b5d008202 Mon Sep 17 00:00:00 2001 From: Lan_zhijiang Date: Wed, 4 Nov 2026 22:14:39 +0800 Subject: [PATCH 3/3] =?UTF-8?q?test(core):=20=E7=A7=BB=E9=99=A4=E9=87=8D?= =?UTF-8?q?=E5=A4=8D=E5=8F=91=E5=B8=83=E5=BD=92=E5=B1=9E=E5=A3=B0=E6=98=8E?= =?UTF-8?q?=E7=9A=84=E6=B5=8B=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 保留真实 check:releases 作为 SDK 发布归属修复的验证依据 --- tests/test_release.py | 13 ------------- 1 file changed, 13 deletions(-) delete mode 100644 tests/test_release.py diff --git a/tests/test_release.py b/tests/test_release.py deleted file mode 100644 index eeebadf0..00000000 --- a/tests/test_release.py +++ /dev/null @@ -1,13 +0,0 @@ -"""Release ownership follows the independently packaged Core source tree.""" - -from scripts import release - - -def test_sdk_only_change_requires_core_release_intent(monkeypatch): - monkeypatch.setattr( - release, - "_changed_paths", - lambda _base: ("inkcre_core/database_contract/constants.py",), - ) - - assert release.affected_projects("parent") == {"core"}