Compare commits

..
Author SHA1 Message Date
weichen 681b195776 Pin intent to the endpoint-migration integration head
Why: the intent integration head (553f) carries the recall-eval stack,
the endpoint migration and the restored fail-closed slot semantics —
the superset this combination needs.

Evidence: host-verified; see Dev PR #706

Impact: pin update only.

Refs: Agent-System-Dev PR #706
2026-10-24 01:53:47 +00:00
weichen 59e796ba3f Align the intent pin with the Dev combination
Why: the pin-consistency gate requires nested pins to match the Dev
top-level pins exactly.

Evidence: host-verified; see Dev PR #706

Impact: pin update only.

Refs: Agent-System-Dev PR #706
2026-10-23 16:37:26 +00:00
weichen e6fdf94def Merge the endpoint migration into the current main line
Why: Dev main advanced this component's pin on the pre-migration
lineage while the endpoint migration landed on main; combine both so
the combined pin carries migrated URLs and the newer functionality.

Evidence: host-verified; see Dev PR #706

Impact: integration commit.

Refs: Agent-System-Dev PR #706

# Conflicts:
#	deps/agent-intent
2026-10-23 14:40:38 +00:00
weichen 4183ea77d9 Pin the nested agent-intent to the minors-cleanup tip
Why: composition consistency - Dev pins agent-intent at the minors
doc/assertion tip; the native container's nested copy must match
(check-pins).
Evidence: pin only.
Impact: nested gitlink pointer change.
Refs: feature/audit-review-minors-cleanup
2026-10-23 11:30:36 +00:00
weichen 9ec1bf7a9d Make the session-scope identity collision-free
Why: review M1 - the slash-joined tenant/project/session identity could
collide for identifiers containing slashes and bind two scopes to one
transcript.
Evidence: collision regression test passes; legacy slash-free scopes
keep their identity encoding (verify-min-native.json, exit=0).
Impact: identity encoding only; transcript filenames for slash-free
scopes unchanged.
Refs: feature/audit-review-minors-cleanup
2026-10-23 08:10:26 +00:00
weichen 2df0d10d96 Merge pull request 'Update Gitea endpoints after server migration' (#49) from fix/gitea-endpoint-migration into main
ci / docker-checkout-hostgateway (push) Successful in 1s
governance / governance (push) Successful in 21s
ci / vet-and-test (push) Successful in 1m33s
2026-10-22 14:50:58 +00:00
weichen 8f113e2376 Bump migrated dependency pins for the endpoint migration
ci / docker-checkout-hostgateway (pull_request) Successful in 5s
governance / governance (pull_request) Successful in 23s
ci / vet-and-test (pull_request) Successful in 1m50s
Why: recursive submodule checkout reads pinned dep commits; their
.gitmodules now carries the new Gitea endpoint base only in the
migrated mains.

Evidence: host-verified; see Dev PR #706

Impact: pin updates only.

Refs: Agent-System-Dev PR #706
2026-10-22 14:43:45 +00:00
weichen 277392acf3 Bump migrated dependency pins for the endpoint migration
ci / docker-checkout-hostgateway (pull_request) Successful in 1s
governance / governance (pull_request) Successful in 37s
ci / vet-and-test (pull_request) Failing after 39s
Why: recursive submodule checkout reads pinned dep commits; their
.gitmodules now carries the new Gitea endpoint base only in the
migrated mains.

Evidence: host-verified; see Dev PR #706

Impact: pin updates only, part of the coordinated endpoint migration.

Refs: Agent-System-Dev PR #706
2026-10-22 14:36:12 +00:00
weichen e05587f165 Bump the development-manager pin for the endpoint migration
ci / docker-checkout-hostgateway (pull_request) Successful in 2s
ci / vet-and-test (pull_request) Failing after 6s
governance / governance (pull_request) Successful in 18s
Why: governance checks validate candidate .gitmodules URLs against the
pinned development-manager scaffold, which now carries the new Gitea
endpoint base after its own migration.

Evidence: host-verified; see Dev PR #706

Impact: pin update only, part of the coordinated endpoint migration.

Refs: Agent-System-Dev PR #706
2026-10-22 14:26:06 +00:00
weichen ad2649b4ab Update Gitea endpoints after server migration
ci / docker-checkout-hostgateway (pull_request) Successful in 1s
ci / vet-and-test (pull_request) Failing after 8s
governance / governance (pull_request) Failing after 27s
Why: the Gitea server moved to https://gitea.naitangbaobao.cn with SSH
on port 52222; endpoint references must follow or superproject CI
checkout refuses the old URLs.

Evidence: host-verified API reach and SSH auth (Dev task card
fix/gitea-endpoint-migration)

Impact: configuration only; no runtime behavior change.

Refs: Dev PR #706
2026-10-22 14:17:11 +00:00
13 changed files with 119 additions and 19 deletions
+1 -1
View File
@@ -24,7 +24,7 @@ jobs:
echo "SUBMODULE_TOKEN is not configured" >&2
exit 1
fi
git config --global url."https://weichen:${SUBMODULE_TOKEN}@git-home.u1680832.nyat.app:30319/".insteadOf "ssh://git@git-ssh.u1680832.nyat.app:31411/"
git config --global url."https://weichen:${SUBMODULE_TOKEN}@gitea.naitangbaobao.cn/".insteadOf "ssh://git@gitea.naitangbaobao.cn:52222/"
git -c fetch.recurseSubmodules=false submodule update --init --recursive
- name: Install Go 1.27.1
run: |
+1 -1
View File
@@ -31,7 +31,7 @@ jobs:
parsed_server = urlsplit(SERVER)
if parsed_server.scheme not in {"http", "https"} or not parsed_server.netloc:
sys.exit("Checkout server must be the platform-injected http(s) URL")
SSH = "ssh://git@git-ssh.u1680832.nyat.app:31411/weichen/"
SSH = "ssh://git@gitea.naitangbaobao.cn:52222/weichen/"
# 审查过的白名单,独立于候选 .gitmodules:仅列出两个治理 gitlink。
REPOSITORIES = {
"deps/development-guidelines": "Development-Guidelines",
+5 -5
View File
@@ -1,15 +1,15 @@
[submodule "deps/development-guidelines"]
path = deps/development-guidelines
url = ssh://git@git-ssh.u1680832.nyat.app:31411/weichen/Development-Guidelines.git
url = ssh://git@gitea.naitangbaobao.cn:52222/weichen/Development-Guidelines.git
[submodule "deps/error-code-system"]
path = deps/error-code-system
url = ssh://git@git-ssh.u1680832.nyat.app:31411/weichen/Error-Code-System.git
url = ssh://git@gitea.naitangbaobao.cn:52222/weichen/Error-Code-System.git
[submodule "deps/logging-system"]
path = deps/logging-system
url = ssh://git@git-ssh.u1680832.nyat.app:31411/weichen/Logging-System.git
url = ssh://git@gitea.naitangbaobao.cn:52222/weichen/Logging-System.git
[submodule "deps/agent-intent"]
path = deps/agent-intent
url = ssh://git@git-ssh.u1680832.nyat.app:31411/weichen/Agent-Intent.git
url = ssh://git@gitea.naitangbaobao.cn:52222/weichen/Agent-Intent.git
[submodule "deps/development-manager"]
path = deps/development-manager
url = ssh://git@git-ssh.u1680832.nyat.app:31411/weichen/Development-Manager.git
url = ssh://git@gitea.naitangbaobao.cn:52222/weichen/Development-Manager.git
+3 -3
View File
@@ -23,9 +23,9 @@
历史文档与旧链接里的 `git-panel.u1680832.nyat.app:30319` 已失效(TLS 握手失败),
见到一律按过期处理,不要再试。当前权威通道:
- **Web / API(HTTPS)**:`https://git-home.u1680832.nyat.app:30319`(Gitea 1.27.3,
- **Web / API(HTTPS)**:`https://gitea.naitangbaobao.cn`(Gitea 1.27.3,
API 前缀 `/api/v1`;偶发 broken pipe / 超时,重试即可)。
- **Git over SSH**:`ssh://git@git-ssh.u1680832.nyat.app:31411/weichen/<Repo>.git`
- **Git over SSH**:`ssh://git@gitea.naitangbaobao.cn:52222/weichen/<Repo>.git`
(各仓 origin 与 gitlink 均为此格式)。
- **API token**:`~/.secrets/gitea`,两行键值 `URL_PREFIX=…` 与
`ACCESS_TOKEN=<40 位 hex>`;取值 `grep ACCESS_TOKEN ~/.secrets/gitea | cut -d= -f2-`,
@@ -33,7 +33,7 @@
(baseline 硬边界 2:只记录来源、字段与可用状态)。
- **SSH key**:`~/.ssh/home_gitea`(ED25519,公钥指纹
`SHA256:GYXaOXIMeloQ1fKSfdJ/ndgPQzs/Ix7Hk62ekfkfQ20`,Gitea 侧密钥名 GMKtec);
`~/.ssh/config` 已有 `git-ssh.u1680832.nyat.app` 主机条目,克隆/推送直接可用。
`~/.ssh/config` 已有 `gitea.naitangbaobao.cn(端口 52222)` 主机条目,克隆/推送直接可用。
## Agent 执行与新项目准入(强制)
+2 -2
View File
@@ -6,7 +6,7 @@
- 目标/产品边界:独立的 Agent 执行基础库。提供执行契约(contract)、执行端口(exec)、自研运行时(runtime)、外部适配器(adapters)与行为验收(conformance)。不实现小队编排,不依赖 Core 或 Squad。
- 源码、资产、文档、机器契约位置:Go 源码在仓库根包目录;模块路径 `agent-native`;人类文档在根 `README.md`、`docs/`、`policy/`;过程记录在 `docs/records/`;机器契约以 `contract` 包类型为准。
- 权威远端、集成基线、受保护分支:`ssh://git@git-ssh.u1680832.nyat.app:31411/weichen/Agent-Native.git`,集成基线 `main`。
- 权威远端、集成基线、受保护分支:`ssh://git@gitea.naitangbaobao.cn:52222/weichen/Agent-Native.git`,集成基线 `main`。
- 并行共同基线记录位置、合入通知/主动检查方式:任务主记录在 Gitea Issue/PR;合入前在本仓 `main` 上 `git fetch` 并确认 HEAD。
- 发布线与批准版本/实际制品查询入口:当前无独立制品仓库。可构建性以本仓 `main` 的 `go test` 为准;依赖子模块版本以 gitlink 为准,不把工作区未提交文件当发布组合。
- 提交/审核/合并/发布身份与权限:仓库所有者 weichen。本机提交不代替远端合并。
@@ -28,7 +28,7 @@
克隆:
```bash
git clone --recurse-submodules ssh://git@git-ssh.u1680832.nyat.app:31411/weichen/Agent-Native.git
git clone --recurse-submodules ssh://git@gitea.naitangbaobao.cn:52222/weichen/Agent-Native.git
# 已克隆时:git submodule update --init --recursive
```
+2 -2
View File
@@ -54,7 +54,7 @@
版本以本仓 gitlink 为准。`scripts/submodule-consistency.sh` 核对 gitlink 与检出的 HEAD。
```bash
git clone --recurse-submodules ssh://git@git-ssh.u1680832.nyat.app:31411/weichen/Agent-Native.git
git clone --recurse-submodules ssh://git@gitea.naitangbaobao.cn:52222/weichen/Agent-Native.git
# 已克隆时:git submodule update --init --recursive
```
@@ -83,7 +83,7 @@ replace agent-native => ./deps/agent-native
本仓自己的 `go.mod` 则把错误码库和日志库替换到 `./deps/`。消费方若同时依赖这三仓,必须在消费方 `go.mod` 里写自己的 `replace`:依赖模块内部的 `replace` 不会在上层构建中生效。
远程:`ssh://git@git-ssh.u1680832.nyat.app:31411/weichen/Agent-Native.git`
远程:`ssh://git@gitea.naitangbaobao.cn:52222/weichen/Agent-Native.git`
## CI
+14
View File
@@ -5,6 +5,7 @@ import (
"crypto/sha256"
"encoding/hex"
"path/filepath"
"strconv"
"strings"
"agent-native/exec"
@@ -57,6 +58,14 @@ func captureText(ctx context.Context, text string) {
// scopeIdentity returns a stable non-empty identity string for a non-zero
// SessionScope, or "" for the legacy one-shot / empty-scope path.
//
// Encoding (collision-free when components contain "/"):
// - Legacy (no component contains "/"): tenant + "/" + project + "/" + session
// so existing workspaces keep the same hashed transcript filenames.
// - Otherwise: length-prefixed concatenation of each trimmed component as
// strconv.Itoa(len(part)) + ":" + part (no extra separators). Distinct
// scopes such as {tenant:"a/b", project:"c"} vs {tenant:"a", project:"b/c"}
// therefore produce different identity strings and transcript paths.
func scopeIdentity(s exec.SessionScope) string {
t := strings.TrimSpace(s.Tenant)
p := strings.TrimSpace(s.Project)
@@ -64,6 +73,11 @@ func scopeIdentity(s exec.SessionScope) string {
if t == "" && p == "" && sess == "" {
return ""
}
if strings.Contains(t, "/") || strings.Contains(p, "/") || strings.Contains(sess, "/") {
return strconv.Itoa(len(t)) + ":" + t +
strconv.Itoa(len(p)) + ":" + p +
strconv.Itoa(len(sess)) + ":" + sess
}
return t + "/" + p + "/" + sess
}
@@ -172,6 +172,92 @@ func TestContractOldStoreWithoutIdentityNotAdopted(t *testing.T) {
}
}
// TestScopeIdentitySlashCollisionFree: tenant/project values that collide under
// naive "/" joins must yield distinct identities and transcript paths (M1).
func TestScopeIdentitySlashCollisionFree(t *testing.T) {
scopeAB := exec.SessionScope{Tenant: "a/b", Project: "c", Session: "s"}
scopeAC := exec.SessionScope{Tenant: "a", Project: "b/c", Session: "s"}
idAB := scopeIdentity(scopeAB)
idAC := scopeIdentity(scopeAC)
if idAB == "" || idAC == "" {
t.Fatal("non-empty scopes must produce non-empty identities")
}
if idAB == idAC {
t.Fatalf("slash-bearing scopes must not collide: both %q", idAB)
}
dir := t.TempDir()
pathAB := transcriptPathForScope(dir, idAB)
pathAC := transcriptPathForScope(dir, idAC)
if pathAB == pathAC {
t.Fatalf("distinct identities must hash to distinct transcript paths: %s", pathAB)
}
}
// TestScopeIdentityLegacySlashFreeUnchanged keeps product workspaces on the
// historical identity string (and thus transcript filename) when no component
// contains "/".
func TestScopeIdentityLegacySlashFreeUnchanged(t *testing.T) {
scope := exec.SessionScope{Tenant: "t1", Project: "p1", Session: "s-a"}
const want = "t1/p1/s-a"
if got := scopeIdentity(scope); got != want {
t.Fatalf("slash-free identity: got %q want %q", got, want)
}
}
// TestBindSessionScopeRejectsMismatchedSlashScope: exact-match check must
// refuse when a store's recorded identity differs from the request, including
// when both identities use the slash-safe encoding.
func TestBindSessionScopeRejectsMismatchedSlashScope(t *testing.T) {
dir := t.TempDir()
scopeA := exec.SessionScope{Tenant: "a/b", Project: "c", Session: "sess"}
scopeB := exec.SessionScope{Tenant: "a", Project: "b/c", Session: "sess"}
idA := scopeIdentity(scopeA)
idB := scopeIdentity(scopeB)
if idA == idB {
t.Fatal("precondition: slash scopes must differ")
}
path := transcriptPathForScope(dir, idA)
if err := os.MkdirAll(filepath.Dir(path), 0o755); err != nil {
t.Fatal(err)
}
store, err := session.Open(path)
if err != nil {
t.Fatal(err)
}
if err := store.SaveMeta(map[string]string{"scope": idB}); err != nil {
t.Fatal(err)
}
b := New(Options{
ModelOptions: ModelOptions{
Model: "fake",
Stream: script(llm.Message{Role: llm.RoleAssistant, Content: "x", StopReason: llm.StopEnd}),
},
})
if err := b.bindSessionScope(store, idA, "fake", "e-mismatch"); err == nil {
t.Fatal("expected scope identity mismatch")
} else if !strings.Contains(err.Error(), "scope identity mismatch") {
t.Fatalf("want mismatch error, got %v", err)
}
// Contract path must also fail-close when meta disagrees with the request scope.
res, err := b.Contract().Execute(context.Background(), exec.ContractRequest{
ExecutionID: "e-mismatch",
Prompt: "hi",
SessionScope: scopeA,
Workspace: exec.WorkspaceHandle{Root: dir},
})
if err != nil {
t.Fatalf("transport: %v", err)
}
if res.Outcome == exec.OutcomeSucceeded {
t.Fatal("mismatched slash scope must not succeed")
}
if res.Err == nil || !strings.Contains(res.Err.Reason, "scope identity mismatch") {
t.Fatalf("want mismatch refusal, got %+v", res.Err)
}
}
func TestContractWritableFileToolHonorsAllowlist(t *testing.T) {
dir := t.TempDir()
b := New(Options{