Merge authoritative main into the task branch

Why: include the current integration baseline before verification.

Evidence: fetched origin/main=5aae47ebca20ad1f3add3b080212cca7e1c6edf9.

Impact: integrate upstream changes without rewriting task history.

Refs: task-sync
This commit is contained in:
2026-10-13 15:18:55 +00:00
15 changed files with 1153 additions and 48 deletions
File diff suppressed because one or more lines are too long
@@ -0,0 +1,32 @@
[
{
"original": "/tmp/project-member-rdm-final-gate-2973.json",
"artifact": ".task/artifacts/project-member-access-receipts/project-member-rdm-final-gate-2973.json",
"sha256": "c66c14f86bfeb60578ce1d694b1070c770a1c951b9368c3d7406729fa7494b00",
"source": "SELF receipt or separately named reviewer attestation; not imported across repositories"
},
{
"original": "/tmp/project-member-rdm-actual-merge-354.json",
"artifact": ".task/artifacts/project-member-access-receipts/project-member-rdm-actual-merge-354.json",
"sha256": "bffb0c17ee3e2042aceea5263db1e71c22010e5119018b180bfc9287a49fc6b1",
"source": "SELF receipt or separately named reviewer attestation; not imported across repositories"
},
{
"original": "/tmp/project-member-rdm-upstream-final-review.md",
"artifact": ".task/artifacts/project-member-access-receipts/project-member-rdm-upstream-final-review.md",
"sha256": "919b78f85f0b6a5426494c4f47e4dda98a997422f10385c6e9481327751faca2",
"source": "SELF receipt or separately named reviewer attestation; not imported across repositories"
},
{
"original": "/tmp/project-member-rdm-tag-final-review.md",
"artifact": ".task/artifacts/project-member-access-receipts/project-member-rdm-tag-final-review.md",
"sha256": "b67566a39c913652a5349a41c0b574fa8a9e7382a6b5963b4affdb73ecbe5cf9",
"source": "SELF receipt or separately named reviewer attestation; not imported across repositories"
},
{
"original": "/tmp/project-member-rdm-synced-final-test.json",
"artifact": ".task/artifacts/project-member-access-receipts/project-member-rdm-synced-final-test.json",
"sha256": "ec5d2b2cd64ebf43bd3c9a811eb1e1be2821d9e3a6376b78babe84234683748a",
"source": "SELF receipt or separately named reviewer attestation; not imported across repositories"
}
]
@@ -0,0 +1,12 @@
{
"actual_merge": "249d7980028f035124f6a74dd9cae132084b81c5",
"tested_head": "7243a7044c9a4d96292efbb88acc219cac08d321",
"tree": "a29f99852c0d49cf9138698c4bcdee356de36dcd",
"pins": {
"modules/backend": "5d5fc9891c0eb8994545ccb8b740535d9b99fb0e",
"modules/frontend": "eb2d6d32f9323094d568bc9d80b4e5ed4f0af25b",
"modules/documents": "047d362c72ec2c095ec14e1d2f2d152f94471faf",
"modules/core": "5773e74086791731059730bd3726dc8c9cd1381f",
"modules/ui": "2c4322ef56df64ad72f65907d25b048a74bb5ffc"
}
}
@@ -0,0 +1,15 @@
import subprocess,sys
from pathlib import Path
base=sys.argv[1]
allowed_prefixes=('.task/artifacts/project-member-access-receipts/',)
allowed={'.task/feature-project-member-access.md','.task/archive/feature-project-member-access.md'}
files=subprocess.check_output(['git','diff','--name-only',base,'HEAD'],text=True).splitlines()
assert files and all(p in allowed or p.startswith(allowed_prefixes) for p in files),files
card=Path('.task/archive/feature-project-member-access.md')
assert card.is_file() and not Path('.task/feature-project-member-access.md').exists()
s=card.read_text()
assert '状态:已完成' in s and 'https://git-home.u1680832.nyat.app:30319/weichen/' in s.splitlines()[2]
assert '8788' in s
subprocess.run(['git','diff','--check',base,'HEAD'],check=True)
print('Scoped archive check PASS: only this task card and its original receipts changed; product and unrelated cards unchanged.')
for p in files: print(p)
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1,454 @@
{
"run": {
"id": 2952,
"url": "https://git-home.u1680832.nyat.app:30319/api/v1/repos/weichen/Agent-System-Dev/actions/runs/2952",
"previous_attempt_url": null,
"html_url": "https://git-home.u1680832.nyat.app:30319/weichen/Agent-System-Dev/actions/runs/2952",
"display_title": "Record merged-component final sync evidence",
"path": "ci.yaml@refs/pull/526/head",
"event": "pull_request",
"run_attempt": 1,
"run_number": 1520,
"repository_id": 0,
"head_sha": "7243a7044c9a4d96292efbb88acc219cac08d321",
"status": "completed",
"actor": {
"id": 1,
"login": "weichen",
"login_name": "",
"source_id": 0,
"full_name": "",
"email": "1+weichen@noreply.git-panel.u1680832.nyat.app",
"avatar_url": "https://git-home.u1680832.nyat.app:30319/avatars/51e6cd4a83883a2910632d26ebc6d665",
"html_url": "https://git-home.u1680832.nyat.app:30319/weichen",
"language": "",
"is_admin": false,
"last_login": "0001-01-01T00:00:00Z",
"created": "2026-09-06T14:39:07Z",
"restricted": false,
"active": false,
"prohibit_login": false,
"location": "",
"website": "",
"description": "",
"visibility": "public",
"followers_count": 0,
"following_count": 0,
"starred_repos_count": 0,
"username": "weichen"
},
"trigger_actor": {
"id": 1,
"login": "weichen",
"login_name": "",
"source_id": 0,
"full_name": "",
"email": "1+weichen@noreply.git-panel.u1680832.nyat.app",
"avatar_url": "https://git-home.u1680832.nyat.app:30319/avatars/51e6cd4a83883a2910632d26ebc6d665",
"html_url": "https://git-home.u1680832.nyat.app:30319/weichen",
"language": "",
"is_admin": false,
"last_login": "0001-01-01T00:00:00Z",
"created": "2026-09-06T14:39:07Z",
"restricted": false,
"active": false,
"prohibit_login": false,
"location": "",
"website": "",
"description": "",
"visibility": "public",
"followers_count": 0,
"following_count": 0,
"starred_repos_count": 0,
"username": "weichen"
},
"repository": {
"id": 29,
"owner": {
"id": 1,
"login": "weichen",
"login_name": "",
"source_id": 0,
"full_name": "",
"email": "1+weichen@noreply.git-panel.u1680832.nyat.app",
"avatar_url": "https://git-home.u1680832.nyat.app:30319/avatars/51e6cd4a83883a2910632d26ebc6d665",
"html_url": "https://git-home.u1680832.nyat.app:30319/weichen",
"language": "",
"is_admin": false,
"last_login": "0001-01-01T00:00:00Z",
"created": "2026-09-06T14:39:07Z",
"restricted": false,
"active": false,
"prohibit_login": false,
"location": "",
"website": "",
"description": "",
"visibility": "public",
"followers_count": 0,
"following_count": 0,
"starred_repos_count": 0,
"username": "weichen"
},
"name": "Agent-System-Dev",
"full_name": "weichen/Agent-System-Dev",
"description": "开发集成仓:以 submodule 固定全部模块组合,承载跨仓构建、测试编排与原生(非容器)开发环境;发布物在 Agent-System-Releases。",
"empty": false,
"private": false,
"fork": false,
"template": false,
"mirror": false,
"size": 23204,
"language": "Shell",
"languages_url": "https://git-panel.u1680832.nyat.app:30319/api/v1/repos/weichen/Agent-System-Dev/languages",
"html_url": "https://git-home.u1680832.nyat.app:30319/weichen/Agent-System-Dev",
"url": "https://git-panel.u1680832.nyat.app:30319/api/v1/repos/weichen/Agent-System-Dev",
"link": "",
"ssh_url": "ssh://git@git-ssh.u1680832.nyat.app:31411/weichen/Agent-System-Dev.git",
"clone_url": "https://git-home.u1680832.nyat.app:30319/weichen/Agent-System-Dev.git",
"original_url": "",
"website": "",
"stars_count": 0,
"forks_count": 0,
"watchers_count": 1,
"branch_count": 46,
"open_issues_count": 1,
"open_pr_counter": 8,
"release_counter": 0,
"default_branch": "main",
"archived": false,
"created_at": "2026-09-29T08:29:40Z",
"updated_at": "2026-10-13T11:54:42Z",
"archived_at": "1970-01-01T00:00:00Z",
"permissions": {
"admin": false,
"push": false,
"pull": false
},
"has_code": true,
"has_issues": true,
"internal_tracker": {
"enable_time_tracker": true,
"allow_only_contributors_to_track_time": true,
"enable_issue_dependencies": true
},
"has_wiki": true,
"has_pull_requests": true,
"has_projects": true,
"projects_mode": "all",
"has_releases": true,
"has_packages": true,
"has_actions": true,
"ignore_whitespace_conflicts": false,
"allow_merge_commits": true,
"allow_rebase": true,
"allow_rebase_explicit": true,
"allow_squash_merge": true,
"allow_fast_forward_only_merge": true,
"allow_merge_update": true,
"allow_rebase_update": true,
"allow_manual_merge": false,
"autodetect_manual_merge": false,
"default_delete_branch_after_merge": false,
"default_merge_style": "merge",
"default_update_style": "merge",
"default_allow_maintainer_edit": true,
"avatar_url": "",
"internal": false,
"mirror_interval": "",
"object_format_name": "sha1",
"mirror_updated": "0001-01-01T00:00:00Z",
"mirror_last_sync_at": "0001-01-01T00:00:00Z",
"topics": [],
"licenses": []
},
"conclusion": "success",
"pull_requests": [
{
"id": 1488,
"number": 526,
"url": "https://git-home.u1680832.nyat.app:30319/api/v1/repos/weichen/Agent-System-Dev/pulls/526",
"head": {
"ref": "feature/project-member-access",
"sha": "7243a7044c9a4d96292efbb88acc219cac08d321",
"repo": {
"id": 29,
"url": "https://git-home.u1680832.nyat.app:30319/api/v1/repos/weichen/Agent-System-Dev",
"name": "Agent-System-Dev"
}
},
"base": {
"ref": "main",
"sha": "d2c23f3a55a77711ded4328aa6215d9469c2b420",
"repo": {
"id": 29,
"url": "https://git-home.u1680832.nyat.app:30319/api/v1/repos/weichen/Agent-System-Dev",
"name": "Agent-System-Dev"
}
}
}
],
"started_at": "2026-10-13T11:54:43Z",
"completed_at": "2026-10-13T12:03:33Z"
},
"jobs": [
{
"id": 4419,
"url": "https://git-home.u1680832.nyat.app:30319/api/v1/repos/weichen/Agent-System-Dev/actions/jobs/4419",
"html_url": "https://git-home.u1680832.nyat.app:30319/weichen/Agent-System-Dev/actions/runs/2952/jobs/4419",
"run_id": 2952,
"run_url": "https://git-home.u1680832.nyat.app:30319/api/v1/repos/weichen/Agent-System-Dev/actions/runs/2952",
"name": "test",
"labels": [
"ubuntu-latest"
],
"run_attempt": 1,
"head_sha": "7243a7044c9a4d96292efbb88acc219cac08d321",
"status": "completed",
"conclusion": "success",
"runner_id": 3,
"runner_name": "home-runner",
"steps": [
{
"name": "Checkout",
"number": 0,
"status": "completed",
"conclusion": "success",
"started_at": "2026-10-13T11:54:44Z",
"completed_at": "2026-10-13T11:54:53Z"
},
{
"name": "Install Go 1.27.1",
"number": 1,
"status": "completed",
"conclusion": "success",
"started_at": "2026-10-13T11:54:53Z",
"completed_at": "2026-10-13T11:54:58Z"
},
{
"name": "Install Node 22",
"number": 2,
"status": "completed",
"conclusion": "success",
"started_at": "2026-10-13T11:54:58Z",
"completed_at": "2026-10-13T11:55:01Z"
},
{
"name": "Install house-style Python packages",
"number": 3,
"status": "completed",
"conclusion": "success",
"started_at": "2026-10-13T11:55:01Z",
"completed_at": "2026-10-13T11:55:05Z"
},
{
"name": "make test (boundaries, pins, libs, core, backend, frontend, ui, agent-command)",
"number": 4,
"status": "completed",
"conclusion": "success",
"started_at": "2026-10-13T11:55:05Z",
"completed_at": "2026-10-13T11:59:43Z"
},
{
"name": "Build the single binary",
"number": 5,
"status": "completed",
"conclusion": "success",
"started_at": "2026-10-13T11:59:43Z",
"completed_at": "2026-10-13T12:00:04Z"
}
],
"created_at": "2026-10-13T11:54:42Z",
"started_at": "2026-10-13T11:54:43Z",
"completed_at": "2026-10-13T12:00:06Z"
},
{
"id": 4420,
"url": "https://git-home.u1680832.nyat.app:30319/api/v1/repos/weichen/Agent-System-Dev/actions/jobs/4420",
"html_url": "https://git-home.u1680832.nyat.app:30319/weichen/Agent-System-Dev/actions/runs/2952/jobs/4420",
"run_id": 2952,
"run_url": "https://git-home.u1680832.nyat.app:30319/api/v1/repos/weichen/Agent-System-Dev/actions/runs/2952",
"name": "test-pg",
"labels": [
"ubuntu-latest"
],
"run_attempt": 1,
"head_sha": "7243a7044c9a4d96292efbb88acc219cac08d321",
"status": "completed",
"conclusion": "success",
"runner_id": 3,
"runner_name": "home-runner",
"steps": [
{
"name": "Checkout",
"number": 0,
"status": "completed",
"conclusion": "success",
"started_at": "2026-10-13T11:54:44Z",
"completed_at": "2026-10-13T11:54:53Z"
},
{
"name": "Install Go 1.27.1",
"number": 1,
"status": "completed",
"conclusion": "success",
"started_at": "2026-10-13T11:54:53Z",
"completed_at": "2026-10-13T11:54:57Z"
},
{
"name": "Install house-style Python packages",
"number": 2,
"status": "completed",
"conclusion": "success",
"started_at": "2026-10-13T11:54:57Z",
"completed_at": "2026-10-13T11:55:02Z"
},
{
"name": "Install PostgreSQL, pgvector and Redis",
"number": 3,
"status": "completed",
"conclusion": "success",
"started_at": "2026-10-13T11:55:02Z",
"completed_at": "2026-10-13T11:56:09Z"
},
{
"name": "Start PostgreSQL and Redis",
"number": 4,
"status": "completed",
"conclusion": "success",
"started_at": "2026-10-13T11:56:09Z",
"completed_at": "2026-10-13T11:56:12Z"
},
{
"name": "Backend tests against real PostgreSQL and Redis (required, no silent skip)",
"number": 5,
"status": "completed",
"conclusion": "success",
"started_at": "2026-10-13T11:56:12Z",
"completed_at": "2026-10-13T11:56:36Z"
},
{
"name": "Two-process HTTP acceptance over shared PostgreSQL (U7, required)",
"number": 6,
"status": "completed",
"conclusion": "success",
"started_at": "2026-10-13T11:56:36Z",
"completed_at": "2026-10-13T11:57:02Z"
},
{
"name": "RDM lifecycle pin is three fixed SHAs",
"number": 7,
"status": "completed",
"conclusion": "success",
"started_at": "2026-10-13T11:57:02Z",
"completed_at": "2026-10-13T11:57:02Z"
},
{
"name": "Clone Agent-System-RDM with nested pins (reviewed allowlist addition)",
"number": 8,
"status": "completed",
"conclusion": "success",
"started_at": "2026-10-13T11:57:02Z",
"completed_at": "2026-10-13T11:58:24Z"
},
{
"name": "Install Node 22",
"number": 9,
"status": "completed",
"conclusion": "success",
"started_at": "2026-10-13T11:58:24Z",
"completed_at": "2026-10-13T11:58:27Z"
},
{
"name": "Build the real agent-system binary",
"number": 10,
"status": "completed",
"conclusion": "success",
"started_at": "2026-10-13T11:58:27Z",
"completed_at": "2026-10-13T11:58:47Z"
},
{
"name": "Real-combination lifecycle gate (make test-lifecycle, required)",
"number": 11,
"status": "completed",
"conclusion": "success",
"started_at": "2026-10-13T11:58:47Z",
"completed_at": "2026-10-13T12:03:31Z"
}
],
"created_at": "2026-10-13T11:54:42Z",
"started_at": "2026-10-13T11:54:44Z",
"completed_at": "2026-10-13T12:03:33Z"
},
{
"id": 4421,
"url": "https://git-home.u1680832.nyat.app:30319/api/v1/repos/weichen/Agent-System-Dev/actions/jobs/4421",
"html_url": "https://git-home.u1680832.nyat.app:30319/weichen/Agent-System-Dev/actions/runs/2952/jobs/4421",
"run_id": 2952,
"run_url": "https://git-home.u1680832.nyat.app:30319/api/v1/repos/weichen/Agent-System-Dev/actions/runs/2952",
"name": "svc-realcombo",
"labels": [
"ubuntu-latest"
],
"run_attempt": 1,
"head_sha": "7243a7044c9a4d96292efbb88acc219cac08d321",
"status": "completed",
"conclusion": "success",
"runner_id": 3,
"runner_name": "home-runner",
"steps": [
{
"name": "Checkout",
"number": 0,
"status": "completed",
"conclusion": "success",
"started_at": "2026-10-13T11:54:44Z",
"completed_at": "2026-10-13T11:54:53Z"
},
{
"name": "Install Go 1.27.1",
"number": 1,
"status": "completed",
"conclusion": "success",
"started_at": "2026-10-13T11:54:53Z",
"completed_at": "2026-10-13T11:54:57Z"
},
{
"name": "Install Node 22",
"number": 2,
"status": "completed",
"conclusion": "success",
"started_at": "2026-10-13T11:54:57Z",
"completed_at": "2026-10-13T11:55:01Z"
},
{
"name": "Build the real agent-system binary",
"number": 3,
"status": "completed",
"conclusion": "success",
"started_at": "2026-10-13T11:55:01Z",
"completed_at": "2026-10-13T11:56:42Z"
},
{
"name": "Clone Agent-System-RDM with nested pins (reviewed allowlist addition)",
"number": 4,
"status": "completed",
"conclusion": "success",
"started_at": "2026-10-13T11:56:42Z",
"completed_at": "2026-10-13T11:57:05Z"
},
{
"name": "Run real-combination lifecycle gates (SQLite, U3, required)",
"number": 5,
"status": "completed",
"conclusion": "success",
"started_at": "2026-10-13T11:57:05Z",
"completed_at": "2026-10-13T11:57:33Z"
}
],
"created_at": "2026-10-13T11:54:42Z",
"started_at": "2026-10-13T11:54:44Z",
"completed_at": "2026-10-13T11:57:34Z"
}
],
"verified_head": "7243a7044c9a4d96292efbb88acc219cac08d321"
}
@@ -0,0 +1,20 @@
[
{
"component": "backend",
"merged": "5d5fc9891c0eb8994545ccb8b740535d9b99fb0e",
"tree": "f2c80faac929a26ca51036dfd2aa54b6dec8553f",
"tested": "d26f3cf2e864a76ad0b868fd968da3257cc7bb44"
},
{
"component": "frontend",
"merged": "eb2d6d32f9323094d568bc9d80b4e5ed4f0af25b",
"tree": "95498c511e440dc3711c626c0f8cd04fb81b84af",
"tested": "40c2afe05449b30e4ed92991487f4eac57221366"
},
{
"component": "documents",
"merged": "047d362c72ec2c095ec14e1d2f2d152f94471faf",
"tree": "eb46876d3a10f4c0b37eb134fc22f40c2b3b1216",
"tested": "6c096b9360094bec9f5d8c9a6db0c701da463fca"
}
]
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -0,0 +1,18 @@
# RDM v0.4.0 tag 消费独立复审
结论:PASS;本增量无 P1/P2 findings。审阅者 `/root/backend_review` 未参与产品实现,仅执行只读审阅、独立临时测试和隔离产品 smoke。
审阅范围:RDM `589f030a5f5b7b12fb9dfd7014a93fb98ff6a9f9` → `b03f27354b309d5d2d44bee0ab42718f37cea241`。四项 pin 与远端已发布 `v0.4.0` annotated tag 的 peeled commit 及本地 tag 一致:Backend `5d5fc9891c0eb8994545ccb8b740535d9b99fb0e`,Core `5773e74086791731059730bd3726dc8c9cd1381f`,Frontend `eb2d6d32f9323094d568bc9d80b4e5ed4f0af25b`,UI `2c4322ef56df64ad72f65907d25b048a74bb5ffc`。Core 直 pin 与 Backend 内嵌 Core 一致;Backend/Frontend 的完整源码树与此前验收对象一致。
独立重放使用仓内默认 `go.mod`、空 `GOFLAGS/GOWORK`,实际模块路径指向 `pins/`。项目、注册、canonical ID、私域、发布/epoch、职责与审计正文边界测试均通过。正式 `bin/agent-system-rdm-product` 在隔离 `/tmp` 数据和空闲端口启动:验证真实 `/proc` executable、React 根页及 JS asset、匿名 commands=401、认证后的项目/私域/发布命令注册;自有进程已停止,诊断数据保留,未触及 8788。
实际正式构建对象为 `0bb8bcc7f727954fc36f32978bf427379fcb435e`;到审阅 HEAD `b03f273...` 的 `git diff -- ':!.task'` 为空。Manifest 的构建对象及作者正式 make test 收据与该事实一致;不要求 manifest 冒称新的证据提交。已核实际 binary SHA256 `2ad5559aa8bce7b67dde0d3f1a41707f0808e1f2f447b6db0a2167995866a2e5`、dist 摘要 `3f1646dd90abaf03`、实际 served JS SHA256 `e7d21720387057e5592e386a9b1e292383956b30d4fb74b2835350fd4e9db4e4` 与现有 manifest/产物匹配。
原始现代工具收据(均保持 SELF;独立执行身份单独用于 REPLAY attestation):
- `/tmp/project-member-rdm-tag-independent-tests.json` — PASS,默认 go.mod 与聚焦测试。
- `/tmp/project-member-rdm-tag-independent-smoke.json` — PASS,真实正式产品入口。
- `/tmp/project-member-rdm-tag-independent-pins-product.json` — 原始 FAIL 保留;四 tag 核验已通过,失败原因是审阅脚本误断言 manifest 构建 SHA 必须等于证据 HEAD。
- `/tmp/project-member-rdm-tag-independent-pins-product-v2.json` — PASS,按真实构建对象核验等价性及实际产物摘要。
RDM 自身旧版 `scripts/evidence.sh` 会写任务卡,本轮改用 Dev 的现代 wrapper 在 RDM cwd 的 RECEIPT 模式,未改产品、任务卡或索引。Root 的授权任务证据写入不改变上述固定产品对象。最终同步后的当前 HEAD CI、平台准入及 FF 合入由 root 另行核验;本报告不沿用旧 CI 作为新门禁,未执行部署。
@@ -0,0 +1,16 @@
# RDM 上游同步增量独立复审
结论:PASS;本增量无 P1/P2 findings。审阅者 `/root/backend_review` 未参与实现,未修改源码、任务卡或索引,未操作 8788。
对象:`b03f27354b309d5d2d44bee0ab42718f37cea241` → `a4edf708336398552af6cf6f65f88807473d460c`。独立执行时 HEAD 已为证据提交 `c058bfcf651c42b2dfc9c93ec7cb1f1036d3fd95`;现代收据内先执行 `git diff --exit-code a4edf708 HEAD -- . ':!.task'`,确认为同一产品、治理脚本及 pins 对象。
账号 query/name 转发保留 canonical 项目注册与命令包装;目录读取先检查 member.manage,姓名仅随受管目录 DTO 返回,未增加联系方式。默认 go.mod、空 GOFLAGS 的账号目录、项目注册/canonical ID、成员权限/override/archive 相关测试通过。post-merge 和 task-finish 仅提示显式 task-close,4 个真实临时 Git 仓库治理用例通过;未自动扫描、归档、提交或推送其他任务卡。四 pins 与 go.mod 未变化。
原始现代工具收据(均保持 SELF;独立执行身份另作 attestation):
- `/tmp/project-member-rdm-upstream-independent-tests-v2.json` — PASS,默认模块账号/项目/权限重放。
- `/tmp/project-member-rdm-upstream-independent-governance-v2.json` — PASS,make test-governance,4 用例。
- `/tmp/project-member-rdm-upstream-independent-tests.json` — 首轮 HEAD guard FAIL,测试 NOT_RUN;保留。
- `/tmp/project-member-rdm-upstream-independent-governance.json` — 首轮 HEAD guard FAIL,治理测试 NOT_RUN;保留。
已在独立重放后核验作者完整测试收据。此前 tag/正式产品/组合 Review 在未受影响范围保留;当前待合入 HEAD 的 CI、平台准入及实际合入由 root 单独核验,不以旧 CI 放行新 HEAD。
File diff suppressed because one or more lines are too long
@@ -1,7 +1,11 @@
#!/usr/bin/env bash
# P8 第八节十场景验收(提案 rdm-settings-members-duties-perms-increment §8)。
# 走真实 dev 服务 HTTP(--auth 会话),多账号多角色;输出逐场景 PASS/FAIL。
# 用法:BASE=http://127.0.0.1:8788 ADMIN_USER=weichen ADMIN_PASS=<密码> ./acceptance_scenarios.sh
# 走真实服务 HTTP(--auth 会话),多账号多角色;输出逐场景 PASS/FAIL。
# v0.4.0 版:RDM 命令面用 rdm.project.create 的 RID(不再直用基座项目);
# 场景 2 姓名过滤全量断言(基座 v0.4.0+ AccountSearcher);setRole→set-role(#350)。
# 前置:ADMIN 账号须为基座管理员(改密门已过)且已登记 RDM 域管理员
# (组合二进制 -bootstrap-admin <owner>,仅空台账生效)。
# 用法:BASE=http://127.0.0.1:8799 ADMIN_USER=rootadmin ADMIN_PASS=<密码> ./acceptance_scenarios.sh
set -u
BASE="${BASE:-http://127.0.0.1:8788}"
ADMIN_USER="${ADMIN_USER:?需要管理员账号}"
@@ -33,19 +37,27 @@ JA="$T/admin"; login "$ADMIN_USER" "$ADMIN_PASS" "$JA"
say "== 准备:账号与两项目 =="
TS=$(date +%s)
# 建号:非管理员负责人 owner2 / 普通成员 mem1 / 三权三人 w1 a1 r1(密码同式)
# 建号:非管理员负责人 owner2 / 普通成员 mem1 / 三权三人 w1 a1 r1(密码同式;name=角色-<u>)
for u in owner2 mem1 w1 a1 r1; do
resp=$(api "$JA" POST /api/admin/users "{\"owner\":\"$u\",\"name\":\"角色-$u\",\"password\":\"Pass-$TS-x8z\",\"isAdmin\":false}")
[ "$(echo "$resp" | code)" = "200" ] || say " ($u 已存在或其他:$(echo "$resp" | code))"
done
# 各自完成改密门(登录→改密)
# 各自完成改密门(登录→改密);基座 #195 起改密撤销旧会话 → 用新密码重登刷新 jar
for u in owner2 mem1 w1 a1 r1; do
J="$T/$u"; login "$u" "Pass-$TS-x8z" "$J"
api "$J" POST /api/auth/password "{\"current\":\"Pass-$TS-x8z\",\"next\":\"Pass2-$TS\"}" >/dev/null
login "$u" "Pass2-$TS" "$J"
done
JPASS="Pass2-$TS"
# 场景 10 前置数据 + 项目创建走 owner2(非管理员)
RDM() { # jar cmd json
api "$1" POST "/api/commands/$2" "{\"params\":$3}" | body
}
PAYLOAD() { # stdin json → payload 子对象(命令应答信封 {payload,receipt})
python3 -c 'import json,sys; print(json.dumps(json.load(sys.stdin)["payload"], ensure_ascii=False))'
}
# 基座项目(场景 1/10 用):owner2(非管理员)创建
JO="$T/owner2"
P1=$(api "$JO" POST /api/projects "{\"name\":\"验收甲-$TS\"}")
PID1=$(echo "$P1" | body | python3 -c 'import json,sys; print(json.load(sys.stdin)["id"])' 2>/dev/null)
@@ -53,9 +65,15 @@ P2=$(api "$JO" POST /api/projects "{\"name\":\"验收乙-$TS\"}")
PID2=$(echo "$P2" | body | python3 -c 'import json,sys; print(json.load(sys.stdin)["id"])' 2>/dev/null)
[ -n "${PID1:-}" ] && [ -n "${PID2:-}" ] && ok "准备:两项目创建($PID1 / $PID2)" || { bad "准备:项目创建" "$P1"; exit 1; }
RDM() { # jar cmd json
api "$1" POST "/api/commands/$2" "{\"params\":$3}" | body
}
# RDM 项目(场景 2-8 用):域管理员建项(创建者自动为 owner)+ 绑定基座项目;
# owner2 入项为 owner 后域管理员自移出——owner2 成为唯一 owner(场景 3b 前提)
RID=$(RDM "$JA" rdm.project.create "{\"name\":\"验收RDM甲-$TS\"}" | python3 -c 'import json,sys; print(json.load(sys.stdin)["payload"]["projectId"])' 2>/dev/null)
[ -n "${RID:-}" ] && ok "准备:RDM 项目创建($RID)" || { bad "准备:RDM 项目创建" ""; exit 1; }
RDM "$JA" rdm.project.bind "{\"hostProjectId\":\"$PID1\",\"projectId\":\"$RID\"}" >/dev/null
out=$(RDM "$JA" rdm.project.member.add "{\"projectId\":\"$RID\",\"member\":\"owner2\",\"role\":\"owner\"}")
echo "$out" | grep -q '"owner"' || { bad "准备:owner2 入项" "$out"; exit 1; }
out=$(RDM "$JA" rdm.project.member.remove "{\"projectId\":\"$RID\",\"member\":\"$ADMIN_USER\"}")
echo "$out" | grep -q '"removed":true' && ok "准备:owner2 为 RDM 项目唯一 owner(管理员自移出)" || { bad "准备:管理员自移出" "$out"; exit 1; }
say "== 场景 1:受管项写入拒绝(user/project 层,含手造请求)=="
r=$(api "$JO" PUT /api/settings/user '{"models":{"chat":{"model":"m-hack"}}}' | code)
@@ -66,51 +84,68 @@ r=$(api "$JO" PUT "/api/settings/project/$PID1" '{"models":{"chat":{"apiKey":"sk
r=$(api "$JO" PUT /api/settings/system '{"models":{"chat":{"model":"x"}}}' | code)
[ "$r" = "403" ] && ok "1c 非管理员写系统面 403" || bad "1c" "$r"
say "== 场景 2:目录查找成员(账号/分页;姓名过滤待发版 tag 后全量)=="
out=$(RDM "$JO" rdm.account.list "{\"projectId\":\"$PID1\",\"limit\":5}")
n=$(echo "$out" | python3 -c 'import json,sys; d=json.load(sys.stdin); print(len(d.get("accounts",[])))' 2>/dev/null)
say "== 场景 2:目录查找成员(账号/分页 + 姓名过滤 v0.4.0 全量)=="
out=$(RDM "$JO" rdm.account.list "{\"projectId\":\"$RID\",\"limit\":5}")
n=$(echo "$out" | python3 -c 'import json,sys; d=json.load(sys.stdin)["payload"]; print(len(d.get("accounts",[])))' 2>/dev/null)
[ "${n:-0}" -gt 0 ] && ok "2a 目录分页浏览($n 条)" || bad "2a" "$out"
# 2b 姓名子串「角色-w」→ 仅 w1(角色-w1),姓名随行、检索无游标
out=$(RDM "$JO" rdm.account.list "{\"projectId\":\"$RID\",\"query\":\"角色-w\",\"limit\":20}")
r=$(echo "$out" | python3 -c 'import json,sys
d=json.load(sys.stdin)["payload"]; a=d.get("accounts",[])
print("ok" if len(a)==1 and a[0]["owner"]=="w1" and a[0].get("name")=="角色-w1" and d.get("next","")=="" else json.dumps(d,ensure_ascii=False))' 2>/dev/null)
[ "$r" = "ok" ] && ok "2b 姓名过滤「角色-w」仅 w1 且姓名随行无游标" || bad "2b" "$r"
# 2c 账号子串大小写不敏感「MEM」→ 仅 mem1(角色-mem1)
out=$(RDM "$JO" rdm.account.list "{\"projectId\":\"$RID\",\"query\":\"MEM\",\"limit\":20}")
r=$(echo "$out" | python3 -c 'import json,sys
d=json.load(sys.stdin)["payload"]; a=d.get("accounts",[])
print("ok" if len(a)==1 and a[0]["owner"]=="mem1" and a[0].get("name")=="角色-mem1" else json.dumps(d,ensure_ascii=False))' 2>/dev/null)
[ "$r" = "ok" ] && ok "2c 账号过滤「MEM」(不区分大小写)仅 mem1" || bad "2c" "$r"
# 2d 多命中(角色- 前缀 5 人)+ limit 截断
out=$(RDM "$JO" rdm.account.list "{\"projectId\":\"$RID\",\"query\":\"角色\",\"limit\":3}")
r=$(echo "$out" | python3 -c 'import json,sys
d=json.load(sys.stdin)["payload"]; a=d.get("accounts",[])
print("ok" if len(a)==3 and all(str(e.get("name","")).startswith("角色-") for e in a) else json.dumps(d,ensure_ascii=False))' 2>/dev/null)
[ "$r" = "ok" ] && ok "2d 多命中姓名检索按 limit 截断(3/5)" || bad "2d" "$r"
say "== 场景 3:重复添加与最后负责人保护 =="
RDM "$JO" rdm.project.member.add "{\"projectId\":\"$PID1\",\"member\":\"mem1\",\"role\":\"member\"}" >/dev/null
out=$(RDM "$JO" rdm.project.member.add "{\"projectId\":\"$PID1\",\"member\":\"mem1\",\"role\":\"owner\"}")
RDM "$JO" rdm.project.member.add "{\"projectId\":\"$RID\",\"member\":\"mem1\",\"role\":\"member\"}" >/dev/null
out=$(RDM "$JO" rdm.project.member.add "{\"projectId\":\"$RID\",\"member\":\"mem1\",\"role\":\"owner\"}")
echo "$out" | grep -q "已是成员" && ok "3a 重复添加拒绝且不隐式变更" || bad "3a" "$out"
out=$(RDM "$JO" rdm.project.member.setRole "{\"projectId\":\"$PID1\",\"member\":\"owner2\",\"role\":\"member\"}")
out=$(RDM "$JO" rdm.project.member.set-role "{\"projectId\":\"$RID\",\"member\":\"owner2\",\"role\":\"member\"}")
echo "$out" | grep -q "最后一位负责人" && ok "3b 降级唯一负责人被拒" || bad "3b" "$out"
out=$(RDM "$JO" rdm.project.member.setRole "{\"projectId\":\"$PID1\",\"member\":\"mem1\",\"role\":\"owner\"}")
out=$(RDM "$JO" rdm.project.member.set-role "{\"projectId\":\"$RID\",\"member\":\"mem1\",\"role\":\"owner\"}")
echo "$out" | grep -q '"role":"owner"' && ok "3c 显式升级成功" || bad "3c" "$out"
RDM "$JO" rdm.project.member.setRole "{\"projectId\":\"$PID1\",\"member\":\"mem1\",\"role\":\"member\"}" >/dev/null
RDM "$JO" rdm.project.member.set-role "{\"projectId\":\"$RID\",\"member\":\"mem1\",\"role\":\"member\"}" >/dev/null
# 成员补充:三权三人入项目
for u in w1 a1 r1; do RDM "$JO" rdm.project.member.add "{\"projectId\":\"$PID1\",\"member\":\"$u\"}" >/dev/null; done
for u in w1 a1 r1; do RDM "$JO" rdm.project.member.add "{\"projectId\":\"$RID\",\"member\":\"$u\"}" >/dev/null; done
say "== 场景 4:文档目录与职责分配对象校验 =="
# 建文档(经 RDM 世界初始化:用 rdm.init 或模板?最小:rdm.duty.catalog 应答;docId 误提交由场景 5 的 assign 覆盖
cat_out=$(RDM "$JO" rdm.duty.catalog "{\"projectId\":\"$PID1\"}")
echo "$cat_out" | python3 -c 'import json,sys; d=json.load(sys.stdin); assert "docs" in d' 2>/dev/null && ok "4a duty.catalog 目录可读" || bad "4a" "$cat_out"
cat_out=$(RDM "$JO" rdm.duty.catalog "{\"projectId\":\"$RID\"}")
echo "$cat_out" | python3 -c 'import json,sys; assert "docs" in json.load(sys.stdin)["payload"]' 2>/dev/null && ok "4a duty.catalog 目录可读" || bad "4a" "$cat_out"
# 章节误提交:构造不存在的 docId → assign 拒绝
out=$(RDM "$JO" rdm.review.assign.doc "{\"projectId\":\"$PID1\",\"docId\":\"section-not-doc\",\"author\":\"w1\",\"reviewers\":[\"a1\"],\"approver\":\"r1\"}")
out=$(RDM "$JO" rdm.review.assign.doc "{\"projectId\":\"$RID\",\"docId\":\"section-not-doc\",\"author\":\"w1\",\"reviewers\":[\"a1\"],\"approver\":\"r1\"}")
echo "$out" | grep -qE "不存在|失败|错误" && ok "4b 不存在对象整笔拒绝" || bad "4b" "$out"
say "== 场景 5:非成员职责目标被拒;移出成员保存被拒 =="
out=$(RDM "$JO" rdm.review.assign.doc "{\"projectId\":\"$PID1\",\"docId\":\"any\",\"author\":\"zombie-$TS\",\"reviewers\":[\"a1\"],\"approver\":\"r1\"}")
out=$(RDM "$JO" rdm.review.assign.doc "{\"projectId\":\"$RID\",\"docId\":\"any\",\"author\":\"zombie-$TS\",\"reviewers\":[\"a1\"],\"approver\":\"r1\"}")
echo "$out" | grep -q "成员" && ok "5a 非成员职责目标被拒" || bad "5a" "$out"
# mem1 移出后 setRole 保存拒绝
RDM "$JO" rdm.project.member.remove "{\"projectId\":\"$PID1\",\"member\":\"mem1\"}" >/dev/null
out=$(RDM "$JO" rdm.project.member.setRole "{\"projectId\":\"$PID1\",\"member\":\"mem1\",\"role\":\"owner\"}")
# mem1 移出后 set-role 保存拒绝
RDM "$JO" rdm.project.member.remove "{\"projectId\":\"$RID\",\"member\":\"mem1\"}" >/dev/null
out=$(RDM "$JO" rdm.project.member.set-role "{\"projectId\":\"$RID\",\"member\":\"mem1\",\"role\":\"owner\"}")
echo "$out" | grep -q "不是" && ok "5b 移出成员的成员面操作被拒" || bad "5b" "$out"
say "== 场景 6:批量整批拒绝(预检列原因)=="
out=$(RDM "$JO" rdm.review.assign.doc.batch "{\"projectId\":\"$PID1\",\"docs\":[{\"docId\":\"x1\",\"author\":\"w1\",\"reviewers\":[\"a1\"],\"approver\":\"r1\"},{\"docId\":\"x2\",\"author\":\"zombie-$TS\",\"reviewers\":[\"a1\"],\"approver\":\"r1\"}]}")
out=$(RDM "$JO" rdm.review.assign.doc.batch "{\"projectId\":\"$RID\",\"docs\":[{\"docId\":\"x1\",\"author\":\"w1\",\"reviewers\":[\"a1\"],\"approver\":\"r1\"},{\"docId\":\"x2\",\"author\":\"zombie-$TS\",\"reviewers\":[\"a1\"],\"approver\":\"r1\"}]}")
echo "$out" | grep -q "整批拒绝" && ok "6 批量含非成员整批拒绝并列原因" || bad "6" "$out"
say "== 场景 7:单成员解释与矩阵同源 =="
chk=$(RDM "$JO" rdm.perm.check "{\"projectId\":\"$PID1\",\"member\":\"owner2\"}")
mtx=$(RDM "$JO" rdm.perm.matrix "{\"projectId\":\"$PID1\"}")
chk=$(RDM "$JO" rdm.perm.check "{\"projectId\":\"$RID\",\"member\":\"owner2\"}")
mtx=$(RDM "$JO" rdm.perm.matrix "{\"projectId\":\"$RID\"}")
same=$(python3 - "$chk" "$mtx" <<'PY'
import json,sys
c=json.loads(sys.argv[1]); m=json.loads(sys.argv[2])
c=json.loads(sys.argv[1])["payload"]; m=json.loads(sys.argv[2])["payload"]
row=[r for r in m.get("rows",[]) if r["member"]==c["member"]]
if not row: print("no-row"); sys.exit(1)
if not row: print("no-row"); sys.exit(0)
ca={a["action"]:(a["allowed"],a.get("label"),a.get("scope")) for a in c["actions"]}
ra={a["action"]:(a["allowed"],a.get("label"),a.get("scope")) for a in row[0]["actions"]}
print("same" if ca==ra else "diff")
@@ -119,15 +154,15 @@ PY
[ "$same" = "same" ] && ok "7 单成员详情与矩阵单元格一致" || bad "7" "$same"
# 普通成员自省:a1 查自己
ja="$T/a1"
out=$(RDM "$ja" rdm.perm.check "{\"projectId\":\"$PID1\",\"member\":\"a1\"}")
out=$(RDM "$ja" rdm.perm.check "{\"projectId\":\"$RID\",\"member\":\"a1\"}")
echo "$out" | grep -q '"actions"' && ok "7b 普通成员自省可用" || bad "7b" "$out"
say "== 场景 8:系统动作不可项目覆盖 =="
out=$(RDM "$JO" rdm.perm.set "{\"projectId\":\"$PID1\",\"member\":\"a1\",\"action\":\"project.create\",\"allow\":true}")
out=$(RDM "$JO" rdm.perm.set "{\"projectId\":\"$RID\",\"member\":\"a1\",\"action\":\"project.create\",\"allow\":true}")
echo "$out" | grep -q "系统范围" && ok "8a project.create 覆盖被服务端拒绝" || bad "8a" "$out"
out=$(RDM "$JO" rdm.perm.set "{\"projectId\":\"$PID1\",\"member\":\"a1\",\"action\":\"doc.write\",\"allow\":true}")
echo "$out" | grep -q '"ok"' || echo "$out" | grep -q 'ok' && ok "8b 项目范围动作覆盖可用" || bad "8b" "$out"
out=$(RDM "$JO" rdm.perm.unset "{\"projectId\":\"$PID1\",\"member\":\"a1\",\"action\":\"doc.write\"}")
out=$(RDM "$JO" rdm.perm.set "{\"projectId\":\"$RID\",\"member\":\"a1\",\"action\":\"doc.write\",\"allow\":true}")
echo "$out" | grep -q '"allow":true' && ok "8b 项目范围动作覆盖可用" || bad "8b" "$out"
out=$(RDM "$JO" rdm.perm.unset "{\"projectId\":\"$RID\",\"member\":\"a1\",\"action\":\"doc.write\"}")
echo "$out" | grep -q '"restored":true' && ok "8c 恢复默认(实际撤销)" || bad "8c" "$out"
say "== 场景 9:迟到响应/断网(UI 行为)=="