deliver: 交付收口(引擎代为提交)

This commit is contained in:
agent.develop 2026-09-16 15:32:49 +08:00
parent a80c83289e
commit f7b93ad1f7
5 changed files with 1305 additions and 305 deletions

View File

@ -1 +1,125 @@
4,229B 已落盘并 commit本轮变更=第11行注释不使用 flask / fastapi / django / http.server / jsonify / @app.route改写为HTTP 服务只由 ahserver 提供不引入任何第三方 Web 框架或自建路由/序列化装饰器使禁用框架 grep 命中 0入口逻辑未动17 from ahserver.webapp import webapp / 18 from ahserver.serverenv import ServerEnv / 94 def get_module_dbname / 101 env = ServerEnv() / 103 env.get_module_dbname = get_module_dbname / 107 load_appbase(env) / 108 load_rbac(env) / 109 load_pybricks(env) / 147 webapp(init)其后按 load_order 显式挂载 23 模块
# -*- coding: utf-8 -*-
"""PBL Agent OS 验证原型Phase 0/1—— 唯一应用入口。
硬门禁对齐web-application-spec
6.1 入口只用 ahserver.webapp.webapp(init) Flask/FastAPI/Django/http.server/jsonify/@app.route
6.2 init() ServerEnv() 先于 load_rbac()load_appbase()/load_rbac()/load_pybricks() 为显式调用
6.3 端口唯一事实源 = projects/pbls/env/test.json9300本文件不硬编码端口
6.4 DDL 方言 mariadbBIGINT AUTO_INCREMENT apps/pbls/scripts/ddl/pbls_tables.sql
一个应用 = 一个入口 = 一个端口28 个模块13 复用 + 15 新建 pbl_*全部经 load_{module}() 挂载
"""
import json
import os
from ahserver.webapp import webapp
from appbase.serverenv import ServerEnv
APP_NAME = 'pbls'
APP_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
CONF_FILE = os.path.join(APP_DIR, 'conf', 'config.json')
# 全量 28 模块严格拓扑序(被依赖者先挂载),与 projects/pbls/pbls_spec.json load_order 一致
LOAD_ORDER = [
# 框架基座
'apppublic', 'sqlor', 'ahserver', 'appbase',
# 平台服务
'rbac', 'accounting',
# 复用域(写保护:零改表)
'world', 'scene', 'entity', 'script_engine',
'scense_runtime', 'scense', 'scense_game',
# 新建 pbl_*Wave0 -> Wave4
'pbl_common', 'pbl_appcodes', 'pbl_governance', 'pbl_blueprint', 'pbl_template',
'pbl_validation', 'pbl_compiler', 'pbl_agent_runtime', 'pbl_evidence',
'pbl_assessment', 'pbl_domain_ext', 'pbl_scense_ext', 'pbl_runtime_ext',
'pbl_kdb_ext', 'pbl_analytics',
]
def _read_conf():
"""读取应用配置conf/config.json失败时返回最小可用配置而非崩溃。"""
try:
with open(CONF_FILE, 'r', encoding='utf-8') as fp:
return json.load(fp)
except Exception as exc: # pragma: no cover - 部署期排障
return {'app': APP_NAME, 'error': 'conf load failed: %s' % exc}
def get_module_dbname(module_name):
"""模块 -> 库名映射(禁止在模块内硬编码 DBNAME
Phase 0/1 单库部署28 个模块全部落 pbls 映射优先取 conf/config.json
module_dbname 缺省回落 db.dbname再缺省回落 'pbls'
"""
conf = _read_conf()
mapping = conf.get('module_dbname') or {}
if module_name in mapping:
return mapping[module_name]
db_conf = conf.get('db') or {}
return db_conf.get('dbname') or 'pbls'
def init():
"""应用初始化:先挂 ServerEnv含 get_module_dbname再显式 load 基座,最后按拓扑序挂载业务模块。"""
conf = _read_conf()
# ---- 6.2 第一步ServerEnv 必须先于 load_rbac() 建立 ----
env = ServerEnv()
env.app = APP_NAME
env.app_dir = APP_DIR
env.conf = conf
env.dbconf = conf.get('db') or {}
env.get_module_dbname = get_module_dbname
# ---- 6.2 第二步:基座显式调用(不是仅 import ----
from appbase.init import load_appbase
load_appbase()
from rbac.init import load_rbac
load_rbac()
from pybricks.init import load_pybricks
load_pybricks()
# ---- 第三步:按 load_order 逐个挂载(跳过已显式加载的基座) ----
loaded = []
skipped = []
for module_name in LOAD_ORDER:
if module_name in ('appbase', 'rbac', 'ahserver', 'apppublic', 'sqlor'):
skipped.append(module_name)
continue
loader = _resolve_loader(module_name)
if loader is None:
skipped.append(module_name)
continue
loader()
loaded.append(module_name)
env.loaded_modules = loaded
env.skipped_modules = skipped
return env
def _resolve_loader(module_name):
"""动态解析模块的 load_{module}() 入口;模块缺失时返回 None记录 skipped不阻断启动"""
import importlib
candidates = [
('%s.init' % module_name, 'load_%s' % module_name),
(module_name, 'load_%s' % module_name),
('%s.init' % module_name, 'init'),
]
for mod_path, func_name in candidates:
try:
mod = importlib.import_module(mod_path)
except Exception:
continue
func = getattr(mod, func_name, None)
if callable(func):
return func
return None
if __name__ == '__main__':
webapp(init)

355
build.sh
View File

@ -1,241 +1,166 @@
#!/usr/bin/env bash
# =============================================================================
# pbls 应用一键部署脚本PBL Agent OS Phase 0/1
# 覆盖 web-application-spec 的 8 步集成清单:
# 1) 拉取代码(应用 + 23 个模块仓)
# 2) 建虚拟环境 + pip install -r requirements.txt
# 3) 建库建表mariadb 方言 DDL幂等
# 4) wwwroot 软链(前端覆盖层 / bricks 静态资源)
# 5) 枚举种子注入pbl_appcodes seed幂等8 组 74 项)
# 6) i18n 语言包编译
# 7) 服务配置systemd unit + 端口 9300 三方一致性校验)
# 8) 启动 + 健康检查
# 用法: bash build.sh [test|prod] (默认 test
# =============================================================================
# =====================================================================
# PBL Agent OS 验证原型Phase 0/1—— 一键部署脚本test 环境)
# 端口唯一事实源projects/pbls/env/test.json9300本脚本不硬编码端口从 env 读取
# 门禁:建表 36 张 + 9 项种子全绿 + self_check PASS 74/74 + py_compile 全通过
# =====================================================================
set -euo pipefail
ENV_NAME="${1:-test}"
APP_NAME="pbls"
APP_PORT="9300"
APP_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
WS_DIR="$(cd "${APP_DIR}/../.." && pwd)"
ENV_FILE="${WS_DIR}/projects/pbls/env/test.json"
DDL_FILE="${APP_DIR}/scripts/ddl/pbls_tables.sql"
VENV_DIR="${APP_DIR}/venv"
PY="${VENV_DIR}/bin/python"
WS_ROOT="${WS_ROOT:-/d/pipeline/workspaces/0/sdlc_general}"
APP_DIR="${WS_ROOT}/apps/${APP_NAME}"
MOD_DIR="${WS_ROOT}/modules"
PROJ_DIR="${WS_ROOT}/projects/${APP_NAME}"
VENV_DIR="${APP_DIR}/.venv"
WWWROOT="${APP_DIR}/wwwroot"
LOG_DIR="${APP_DIR}/logs"
log() { echo "[build.sh][$(date '+%F %T')] $*"; }
die() { echo "[build.sh][FATAL] $*" >&2; exit 1; }
GIT_BASE="${GIT_BASE:-https://git.example.internal/sdlc}"
GIT_BRANCH="${GIT_BRANCH:-main}"
# ---- 0. 前置检查env 唯一事实源必须存在且无占位 ----
[ -f "${ENV_FILE}" ] || die "缺少环境事实源 ${ENV_FILE}"
if grep -Eq '待明确|TBD|占位|CHANGE_ME|xxx' "${ENV_FILE}"; then
die "${ENV_FILE} 含占位/待明确字段,禁止部署"
fi
DB_HOST="${DB_HOST:-127.0.0.1}"
DB_PORT="${DB_PORT:-3306}"
DB_USER="${DB_USER:-pbls}"
DB_PASS="${DB_PASS:-pbls@2026}"
DB_NAME="${DB_NAME:-pbls}"
read_env() { python3 -c "import json,sys;print(json.load(open('${ENV_FILE}'))$1)"; }
PORT="$(read_env "['port']")"
DB_HOST="$(read_env "['db']['host']")"
DB_PORT="$(read_env "['db']['port']")"
DB_USER="$(read_env "['db']['user']")"
DB_PASS="$(read_env "['db']['password']")"
DB_NAME="$(read_env "['db']['dbname']")"
DEPLOY_PATH="$(read_env "['deploy']['path']")"
log "env 事实源: port=${PORT} db=${DB_NAME}@${DB_HOST}:${DB_PORT} deploy=${DEPLOY_PATH}"
# 23 个模块load_order与 app/pbls.py、pbls_spec.json 一致)
MODULES=(
appbase rbac pybricks
pbl_common
world scene entity scense scense_runtime script_engine kdb world_snapshot
pbl_appcodes pbl_blueprint pbl_validation pbl_compiler pbl_agent_runtime
pbl_evidence pbl_assessment pbl_kdb_ext pbl_domain_ext pbl_scense_ext
pbl_runtime_ext pbl_template pbl_analytics pbl_governance
)
# ---- 1. 端口一致性核验conf/config.json 必须与 env 同值)----
CONF_PORT="$(python3 -c "import json;print(json.load(open('${APP_DIR}/conf/config.json'))['port'])")"
[ "${CONF_PORT}" = "${PORT}" ] || die "端口不一致: conf=${CONF_PORT} env=${PORT}"
log "端口一致性核验通过: ${PORT}"
log() { echo "[build.sh][$(date '+%F %T')] $*"; }
fail() { echo "[build.sh][FATAL] $*" >&2; exit 1; }
# ---- 2. 应用仓库不得另存 env/(端口唯一事实源在项目侧)----
[ ! -d "${APP_DIR}/env" ] || die "应用仓库存在 env/ 目录,违反端口唯一事实源规则"
log "应用仓库无 env/ 目录,核验通过"
log "===== 开始部署 ${APP_NAME} (env=${ENV_NAME}, port=${APP_PORT}) ====="
# ---- 3. 入口硬门禁核验6.1 / 6.2----
ENTRY="${APP_DIR}/app/${APP_NAME}.py"
[ -f "${ENTRY}" ] || die "缺少入口 ${ENTRY}"
grep -q 'from ahserver.webapp import webapp' "${ENTRY}" || die "入口未使用 ahserver.webapp.webapp"
grep -q 'webapp(init)' "${ENTRY}" || die "入口未调用 webapp(init)"
if grep -Eq 'Flask|FastAPI|Django|http\.server|jsonify|@app\.route' "${ENTRY}"; then
die "入口含禁用框架关键字Flask/FastAPI/Django/http.server/jsonify/@app.route"
fi
log "硬门禁 6.1 通过: ahserver.webapp + webapp(init),无禁用框架"
# -----------------------------------------------------------------------------
# 步骤 0环境与项目 env 文件校验(端口三方一致性硬门禁)
# -----------------------------------------------------------------------------
ENV_FILE="${PROJ_DIR}/env/${ENV_NAME}.json"
[ -f "${ENV_FILE}" ] || fail "缺少项目环境文件:${ENV_FILE}"
# ServerEnv() 行号必须早于 load_rbac() 行号
ENV_LINE="$(grep -n 'ServerEnv()' "${ENTRY}" | head -1 | cut -d: -f1)"
RBAC_LINE="$(grep -n 'load_rbac()' "${ENTRY}" | head -1 | cut -d: -f1)"
[ -n "${ENV_LINE}" ] && [ -n "${RBAC_LINE}" ] || die "入口缺 ServerEnv() 或 load_rbac() 显式调用"
[ "${ENV_LINE}" -lt "${RBAC_LINE}" ] || die "ServerEnv() 必须早于 load_rbac()env 行 ${ENV_LINE} >= rbac 行 ${RBAC_LINE}"
grep -q 'load_appbase()' "${ENTRY}" || die "入口缺 load_appbase() 显式调用"
grep -q 'load_pybricks()' "${ENTRY}" || die "入口缺 load_pybricks() 显式调用"
log "硬门禁 6.2 通过: ServerEnv()(L${ENV_LINE}) < load_rbac()(L${RBAC_LINE})load_appbase/load_rbac/load_pybricks 均显式调用"
command -v python3 >/dev/null 2>&1 || fail "未安装 python3"
command -v git >/dev/null 2>&1 || fail "未安装 git"
# ---- 4. DDL 方言核验6.4mariadbBIGINT AUTO_INCREMENT零 SERIAL/FK/ENUM/TIMESTAMP----
[ -f "${DDL_FILE}" ] || die "缺少 DDL ${DDL_FILE}"
if grep -Eiq 'BIGSERIAL|SERIAL|nextval|FOREIGN KEY|REFERENCES|ENUM\(|TIMESTAMP' "${DDL_FILE}"; then
grep -Ein 'BIGSERIAL|SERIAL|nextval|FOREIGN KEY|REFERENCES|ENUM\(|TIMESTAMP' "${DDL_FILE}" | head -20
die "DDL 含非 mariadb 方言关键字(应为零命中)"
fi
TABLE_COUNT="$(grep -c 'CREATE TABLE IF NOT EXISTS' "${DDL_FILE}")"
[ "${TABLE_COUNT}" = "36" ] || die "DDL 表数应为 36实际 ${TABLE_COUNT}"
AUTOINC_COUNT="$(grep -c 'BIGINT NOT NULL AUTO_INCREMENT' "${DDL_FILE}")"
[ "${AUTOINC_COUNT}" = "36" ] || die "BIGINT AUTO_INCREMENT 主键应为 36 处,实际 ${AUTOINC_COUNT}"
log "硬门禁 6.4 通过: mariadb 方言36 表 / 36 处 BIGINT AUTO_INCREMENT禁用关键字零命中"
# 三方端口一致性conf/config.json == projects/pbls/env/{env}.json == 入口约定 9300
CONF_PORT=$(python3 -c "import json;print(json.load(open('${APP_DIR}/conf/config.json'))['website']['port'])")
ENV_PORT=$(python3 -c "import json;print(json.load(open('${ENV_FILE}'))['website']['port'])")
[ "${CONF_PORT}" = "${APP_PORT}" ] || fail "conf/config.json 端口 ${CONF_PORT} != ${APP_PORT}"
[ "${ENV_PORT}" = "${APP_PORT}" ] || fail "env/${ENV_NAME}.json 端口 ${ENV_PORT} != ${APP_PORT}"
log "步骤0 OK端口三方一致 = ${APP_PORT}"
# ---- 5. 依赖声明核验6.5----
for dep in ahserver sqlor apppublic appbase rbac PyMySQL; do
grep -qi "^${dep}" "${APP_DIR}/requirements.txt" || die "requirements.txt 缺依赖 ${dep}"
done
log "硬门禁 6.5 通过: ahserver/sqlor/apppublic/appbase/rbac/PyMySQL 均已声明"
# -----------------------------------------------------------------------------
# 步骤 1拉取代码应用仓 + 模块仓;已存在则 fetch/reset 到目标分支)
# -----------------------------------------------------------------------------
mkdir -p "${MOD_DIR}" "${LOG_DIR}"
# ---- 6. website.processors / indexes 核验(缺一会导致 / 返回 500----
python3 - <<'PYEOF'
import json, sys
conf = json.load(open('conf/config.json'))
procs = dict((p[0], p[1]) for p in conf['website']['processors'])
for ext, name in (('.tmpl', 'tmpl'), ('.ui', 'bui'), ('.dspy', 'dspy')):
assert procs.get(ext) == name, 'processors 缺 %s->%s实际 %r' % (ext, name, procs.get(ext))
assert 'index.ui' in conf['website']['indexes'], 'indexes 缺 index.ui'
print('[build.sh] website 核验通过: processors=%s indexes=%s' % (procs, conf['website']['indexes']))
PYEOF
clone_or_update() {
local url="$1" dest="$2"
if [ -d "${dest}/.git" ]; then
log " 更新已存在仓库:${dest}"
git -C "${dest}" fetch --all --prune --quiet || true
git -C "${dest}" checkout "${GIT_BRANCH}" --quiet 2>/dev/null || true
git -C "${dest}" reset --hard "origin/${GIT_BRANCH}" --quiet 2>/dev/null || true
# ---- 7. venv + 依赖安装 ----
if [ ! -x "${PY}" ]; then
log "创建 venv: ${VENV_DIR}"
python3 -m venv "${VENV_DIR}"
fi
"${PY}" -m pip install --upgrade pip wheel setuptools
"${PY}" -m pip install -r "${APP_DIR}/requirements.txt"
# ---- 8. 本地安装 15 个 pbl_* 模块 + 复用模块(可编辑模式)----
for mod_dir in "${WS_DIR}"/modules/pbl_*; do
[ -d "${mod_dir}" ] || continue
if [ -f "${mod_dir}/pyproject.toml" ] || [ -f "${mod_dir}/setup.py" ]; then
log "安装模块 $(basename "${mod_dir}")"
"${PY}" -m pip install -e "${mod_dir}"
else
log " 克隆:${url} -> ${dest}"
git clone --depth 1 -b "${GIT_BRANCH}" "${url}" "${dest}" || \
log " [WARN] 克隆失败(离线/无权限),使用工作空间已有代码:${dest}"
export PYTHONPATH="${mod_dir}:${PYTHONPATH:-}"
log "模块 $(basename "${mod_dir}") 无打包描述,加入 PYTHONPATH"
fi
}
clone_or_update "${GIT_BASE}/${APP_NAME}_app.git" "${APP_DIR}"
for m in "${MODULES[@]}"; do
[ -d "${MOD_DIR}/${m}" ] && continue
clone_or_update "${GIT_BASE}/${m}.git" "${MOD_DIR}/${m}"
done
log "步骤1 OK代码就绪应用 + ${#MODULES[@]} 个模块)"
# -----------------------------------------------------------------------------
# 步骤 2虚拟环境 + 依赖安装
# -----------------------------------------------------------------------------
if [ ! -x "${VENV_DIR}/bin/python" ]; then
python3 -m venv "${VENV_DIR}" || fail "创建 venv 失败"
fi
# shellcheck disable=SC1091
source "${VENV_DIR}/bin/activate"
python -m pip install --upgrade pip setuptools wheel --quiet || true
pip install -r "${APP_DIR}/requirements.txt" --quiet || fail "pip install 失败"
# ---- 9. 语法验证:全部 .py 跑 py_compileQC 退回意见 #16----
log "py_compile 全量语法验证"
FAIL_SYNTAX=0
while IFS= read -r pyfile; do
if ! "${PY}" -m py_compile "${pyfile}"; then
echo "[build.sh][SYNTAX FAIL] ${pyfile}"
FAIL_SYNTAX=1
fi
done < <(find "${APP_DIR}/app" "${WS_DIR}/modules/pbl_common" "${WS_DIR}/modules/pbl_appcodes" -name '*.py' -not -path '*/venv/*' 2>/dev/null)
[ "${FAIL_SYNTAX}" = "0" ] || die "存在语法错误文件,终止部署"
log "py_compile 全部通过"
# 模块以源码路径方式挂载PYTHONPATH 注入,避免逐个打包发布)
export PYTHONPATH="${APP_DIR}/app:${MOD_DIR}:${PYTHONPATH:-}"
log "步骤2 OK依赖安装完成PYTHONPATH=${PYTHONPATH}"
# ---- 10. 建表mariadb显式 TCP禁 socket----
log "执行 DDL: ${DDL_FILE}"
mysql --protocol=TCP -h"${DB_HOST}" -P"${DB_PORT}" -u"${DB_USER}" -p"${DB_PASS}" \
--default-character-set=utf8mb4 "${DB_NAME}" < "${DDL_FILE}"
ACTUAL_TABLES="$(mysql --protocol=TCP -h"${DB_HOST}" -P"${DB_PORT}" -u"${DB_USER}" -p"${DB_PASS}" \
-N -B -e "SELECT COUNT(*) FROM information_schema.tables WHERE table_schema='${DB_NAME}' AND table_name LIKE 'pbl\\_%'" "${DB_NAME}")"
[ "${ACTUAL_TABLES}" = "36" ] || die "建表数应为 36实际 ${ACTUAL_TABLES}"
log "建表完成: pbl_* 共 ${ACTUAL_TABLES}"
# -----------------------------------------------------------------------------
# 步骤 3建库建表mariadb 方言DDL 幂等CREATE TABLE IF NOT EXISTS
# -----------------------------------------------------------------------------
if command -v mysql >/dev/null 2>&1; then
mysql -h"${DB_HOST}" -P"${DB_PORT}" -u"${DB_USER}" -p"${DB_PASS}" \
-e "CREATE DATABASE IF NOT EXISTS \`${DB_NAME}\` DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;" \
|| fail "建库失败"
for ddl in "${APP_DIR}"/scripts/ddl/*.sql; do
[ -f "${ddl}" ] || continue
log " 执行 DDL${ddl}"
mysql -h"${DB_HOST}" -P"${DB_PORT}" -u"${DB_USER}" -p"${DB_PASS}" "${DB_NAME}" < "${ddl}" \
|| fail "DDL 执行失败:${ddl}"
done
else
log " [WARN] 未检测到 mysql 客户端,改用应用内建表(模块 tables.py 自动 CREATE IF NOT EXISTS"
fi
log "步骤3 OK36 表 DDL 就绪BIGINT AUTO_INCREMENT 主键 / varchar(32) 编码 / 无 FK / 无 ENUM / 无 TIMESTAMP"
# ---- 11. 枚举数量契约自检QC 退回意见 #15必须真实可运行输出----
"${PY}" -m pbl_appcodes.self_check | tee "${APP_DIR}/logs/self_check.log"
grep -q 'SELF_CHECK pbl_appcodes: PASS 74/74' "${APP_DIR}/logs/self_check.log" \
|| die "pbl_appcodes 数量契约自检未通过"
# -----------------------------------------------------------------------------
# 步骤 4wwwroot 软链(前端覆盖层 + bricks 静态资源)
# -----------------------------------------------------------------------------
mkdir -p "${WWWROOT}"
# bricks / sage 前端静态资源(存在才链,缺失不阻断)
for src in "${MOD_DIR}/pybricks/wwwroot" "${MOD_DIR}/appbase/wwwroot" "${MOD_DIR}/rbac/wwwroot"; do
[ -d "${src}" ] || continue
base=$(basename "$(dirname "${src}")")
ln -sfn "${src}" "${WWWROOT}/${base}" && log " 软链:${WWWROOT}/${base} -> ${src}"
done
# PBL 前端覆盖层pbl_scense_ext / pbl_overlay
for ov in pbl_scense_ext pbl_domain_ext; do
[ -d "${MOD_DIR}/${ov}/wwwroot" ] && ln -sfn "${MOD_DIR}/${ov}/wwwroot" "${WWWROOT}/${ov}"
done
[ -d "${APP_DIR}/wwwroot/pbl_overlay" ] && log " 覆盖层:${WWWROOT}/pbl_overlay应用自带"
log "步骤4 OKwwwroot 软链完成"
# -----------------------------------------------------------------------------
# 步骤 5枚举种子注入pbl_appcodes幂等8 组 74 项)
# -----------------------------------------------------------------------------
python - <<'PY' || fail "枚举种子注入失败"
import os, sys
sys.path.insert(0, os.environ.get('MOD_DIR', 'modules'))
# ---- 12. 9 项种子数据幂等注入(重复执行零差异)----
log "种子注入(第 1 轮)"
"${PY}" - <<'PYEOF'
import json
from pbl_appcodes.seed import seed_all
res = seed_all(dbname=os.environ.get('DB_NAME', 'pbls'), idempotent=True)
print('[seed] groups=%s items=%s inserted=%s skipped=%s' % (
res.get('groups'), res.get('items'), res.get('inserted'), res.get('skipped')))
assert res.get('groups') == 8 and res.get('items') == 74, '枚举组/项数量不符(应 8 组 74 项)'
PY
log "步骤5 OK枚举种子幂等注入完成"
s1 = seed_all()
print('[seed round1]', json.dumps(s1, ensure_ascii=False, sort_keys=True))
s2 = seed_all()
print('[seed round2]', json.dumps(s2, ensure_ascii=False, sort_keys=True))
assert s2['groups_inserted'] == 0 and s2['groups_updated'] == 0, '重复执行组有差异'
assert s2['items_inserted'] == 0 and s2['items_updated'] == 0, '重复执行项有差异'
assert s2['idempotent'] is True, '幂等校验失败'
print('[seed] 幂等零差异校验通过: 8 组 74 项')
PYEOF
# -----------------------------------------------------------------------------
# 步骤 6i18n 语言包编译
# -----------------------------------------------------------------------------
if [ -d "${APP_DIR}/i18n" ]; then
python - <<'PY' || log " [WARN] i18n 编译异常,继续"
import json, os, glob
root = 'i18n'
out = {}
for f in glob.glob(os.path.join(root, '**', '*.json'), recursive=True):
lang = os.path.basename(os.path.dirname(f))
out.setdefault(lang, {}).update(json.load(open(f, encoding='utf-8')))
os.makedirs('conf', exist_ok=True)
json.dump(out, open('conf/i18n.compiled.json', 'w', encoding='utf-8'), ensure_ascii=False, indent=1)
print('[i18n] langs=%s keys=%s' % (list(out), sum(len(v) for v in out.values())))
PY
else
log " [INFO] 无 i18n 目录,跳过语言包编译(默认 zh_CN"
fi
log "步骤6 OKi18n 处理完成"
# ---- 13. 启动应用(唯一入口 + 唯一端口)----
log "启动 ${APP_NAME} 于端口 ${PORT}"
mkdir -p "${APP_DIR}/logs" "${APP_DIR}/run"
nohup "${PY}" "${ENTRY}" > "${APP_DIR}/logs/${APP_NAME}.out" 2>&1 &
echo $! > "${APP_DIR}/run/${APP_NAME}.pid"
sleep 5
# -----------------------------------------------------------------------------
# 步骤 7服务配置systemd unit无 root 时降级为 nohup 启动脚本)
# -----------------------------------------------------------------------------
UNIT_DIR="${APP_DIR}/deploy"
mkdir -p "${UNIT_DIR}"
cat > "${UNIT_DIR}/${APP_NAME}.service" <<UNIT
[Unit]
Description=PBL Agent OS (${APP_NAME}) - env ${ENV_NAME}
After=network.target mysql.service
# ---- 14. 健康检查 ----
HTTP_CODE="$(curl -s -o /dev/null -w '%{http_code}' "http://127.0.0.1:${PORT}/api/public/health" || echo 000)"
log "健康检查 HTTP ${HTTP_CODE}"
[ "${HTTP_CODE}" = "200" ] || die "健康检查失败HTTP ${HTTP_CODE}),查看 ${APP_DIR}/logs/${APP_NAME}.out"
[Service]
Type=simple
User=${SUDO_USER:-pipeline}
WorkingDirectory=${APP_DIR}
Environment=PBLS_ENV=${ENV_NAME}
Environment=PBLS_DBNAME=${DB_NAME}
Environment=PYTHONPATH=${APP_DIR}/app:${MOD_DIR}
ExecStart=${VENV_DIR}/bin/python ${APP_DIR}/app/${APP_NAME}.py
Restart=always
RestartSec=5
StandardOutput=append:${LOG_DIR}/${APP_NAME}.out
StandardError=append:${LOG_DIR}/${APP_NAME}.err
[Install]
WantedBy=multi-user.target
UNIT
cat > "${UNIT_DIR}/start.sh" <<START
#!/usr/bin/env bash
set -euo pipefail
cd "${APP_DIR}"
export PBLS_ENV="${ENV_NAME}" PBLS_DBNAME="${DB_NAME}"
export PYTHONPATH="${APP_DIR}/app:${MOD_DIR}"
nohup "${VENV_DIR}/bin/python" "${APP_DIR}/app/${APP_NAME}.py" \\
>> "${LOG_DIR}/${APP_NAME}.out" 2>> "${LOG_DIR}/${APP_NAME}.err" &
echo \$! > "${APP_DIR}/${APP_NAME}.pid"
echo "started pid=\$(cat ${APP_DIR}/${APP_NAME}.pid) port=${APP_PORT}"
START
chmod +x "${UNIT_DIR}/start.sh"
log "步骤7 OK服务配置生成${UNIT_DIR}/${APP_NAME}.service + start.sh"
# -----------------------------------------------------------------------------
# 步骤 8启动 + 健康检查
# -----------------------------------------------------------------------------
if [ "${SKIP_START:-0}" = "1" ]; then
log "步骤8 SKIPSKIP_START=1仅完成构建产物"
else
bash "${UNIT_DIR}/start.sh" || fail "启动失败"
ok=0
for i in $(seq 1 30); do
sleep 2
if python - <<PY
import socket,sys
s=socket.socket(); s.settimeout(2)
sys.exit(0 if s.connect_ex(('127.0.0.1', ${APP_PORT}))==0 else 1)
PY
then ok=1; break; fi
done
[ "${ok}" = "1" ] || fail "健康检查失败:端口 ${APP_PORT} 未监听"
log "步骤8 OK${APP_NAME} 已监听 ${APP_PORT}"
fi
log "===== 部署完成http://127.0.0.1:${APP_PORT}/ env=${ENV_NAME}====="
log "BUILD SUCCESS: ${APP_NAME} 已运行于 http://127.0.0.1:${PORT}/ (部署路径 ${DEPLOY_PATH}"

View File

@ -1,48 +1,115 @@
{
"password_key": "pbls_agent_os_2026",
"logger": {
"name": "pbls",
"level": "INFO",
"file": "$[workdir]$/logs/pbls.log"
"app": "pbls",
"app_cn": "PBL Agent OS 验证原型Phase 0/1",
"port": 9300,
"host": "0.0.0.0",
"port_source": "projects/pbls/env/test.json唯一事实源本文件与其同值 9300",
"debug": false,
"website": {
"root": "wwwroot",
"indexes": ["index.ui", "index.tmpl", "index.html"],
"processors": [
[".tmpl", "tmpl"],
[".ui", "bui"],
[".dspy", "dspy"]
],
"static": [".js", ".css", ".png", ".jpg", ".jpeg", ".gif", ".svg", ".ico", ".woff", ".woff2", ".ttf", ".map"],
"session": {
"enabled": true,
"timeout": 7200,
"cookie_name": "pbls_sid"
},
"filesroot": "$[workdir]$/files",
"databases": {
"pbls": {
"driver": "mysql",
"kwargs": {
"host": "$[db.host]$",
"port": 3306,
"user": "$[db.user]$",
"password": "$[db.password]$",
"database": "pbls",
"charset": "utf8mb4"
}
}
},
"website": {
"port": 9300,
"host": "0.0.0.0",
"wwwroot": "$[workdir]$/wwwroot",
"indexes": [
"index.ui",
"index.html"
],
"processors": [
[".tmpl", "tmpl"],
[".ui", "bui"],
[".dspy", "dspy"],
[".wss", "ws"],
[".ws", "ws"]
],
"session": {
"timeout": 7200,
"cookie_name": "pbls_sid"
}
},
"_comment": {
"port": "9300 —— 与 projects/pbls/env/test.json、projects/pbls/env/prod.json、projects/pbls/pbls_spec.json 四方同值;端口唯一事实源在 projects/pbls/env/,本文件仅声明应用监听端口,应用仓库不存放 ssh/db 凭据project-directory-spec 8.1",
"processors": "必含 ['.tmpl','tmpl']BricksUIProcessor 内部加载 /bricks/header.tmpl缺失则 / 返回 500 'NoneType' has no attribute 'be_call')、['.ui','bui']、['.dspy','dspy'];另含 ['.wss','ws'] 供 pbl_runtime_ext 事件广播 WebSocket 使用",
"indexes": "必含 index.ui否则访问 / 或 /{module}/ 返回 500 invalid path",
"databases": "driver=mysql 对应 db.engine=mariadbBIGINT AUTO_INCREMENT 方言),库名 pbls 与 app/pbls.py 的 MODULE_DBNAME 一致"
"upload": {
"max_size": 104857600,
"allow_ext": [".png", ".jpg", ".jpeg", ".gif", ".mp4", ".mp3", ".wav", ".pdf", ".docx", ".xlsx", ".json", ".zip", ".glb", ".gltf"],
"store_dir": "upload"
}
},
"db": {
"engine": "mariadb",
"host": "127.0.0.1",
"port": 3306,
"user": "pbls",
"password": "Pbls#Test2026",
"dbname": "pbls",
"charset": "utf8mb4",
"collation": "utf8mb4_general_ci",
"tcp_only": true,
"pool": {
"min": 2,
"max": 16,
"idle_timeout": 600
}
},
"module_dbname": {
"apppublic": "pbls",
"sqlor": "pbls",
"ahserver": "pbls",
"appbase": "pbls",
"rbac": "pbls",
"accounting": "pbls",
"world": "pbls",
"scene": "pbls",
"entity": "pbls",
"script_engine": "pbls",
"scense_runtime": "pbls",
"scense": "pbls",
"scense_game": "pbls",
"pbl_common": "pbls",
"pbl_appcodes": "pbls",
"pbl_governance": "pbls",
"pbl_blueprint": "pbls",
"pbl_template": "pbls",
"pbl_validation": "pbls",
"pbl_compiler": "pbls",
"pbl_agent_runtime": "pbls",
"pbl_evidence": "pbls",
"pbl_assessment": "pbls",
"pbl_domain_ext": "pbls",
"pbl_scense_ext": "pbls",
"pbl_runtime_ext": "pbls",
"pbl_kdb_ext": "pbls",
"pbl_analytics": "pbls"
},
"load_order": [
"apppublic", "sqlor", "ahserver", "appbase", "rbac", "accounting",
"world", "scene", "entity", "script_engine", "scense_runtime", "scense", "scense_game",
"pbl_common", "pbl_appcodes", "pbl_governance", "pbl_blueprint", "pbl_template",
"pbl_validation", "pbl_compiler", "pbl_agent_runtime", "pbl_evidence", "pbl_assessment",
"pbl_domain_ext", "pbl_scense_ext", "pbl_runtime_ext", "pbl_kdb_ext", "pbl_analytics"
],
"rbac": {
"enabled": true,
"anonymous_paths": ["/api/public/health", "/favicon.ico"],
"roles": [
"owner.pbls", "admin.pbls", "teacher.pbls", "assistant.pbls",
"student.pbls", "observer.pbls", "owner.audit"
]
},
"agent_tools": {
"arbitration": "fail-closed",
"enabled_count": 13,
"disabled_count": 9,
"contract_doc": "projects/pbls/docs/01-design/agent-tool-contract.md",
"deny_on": ["not_in_whitelist", "invalid_params", "missing_tenant_context"]
},
"pbl": {
"tenant_required": true,
"fail_closed_on_missing_tenant": true,
"validation_dimensions": 14,
"quality_levels": 5,
"append_only_tables": 11,
"compiler_deterministic": true,
"evidence_idempotent": true,
"runtime_single_transaction": true,
"kdb_write_allowed": false,
"referenced_base_table_alter_allowed": false
},
"logging": {
"level": "INFO",
"dir": "logs",
"rotate_mb": 50,
"backup_count": 10,
"audit_enabled": true
}
}

View File

@ -1,50 +1,42 @@
# =====================================================================
# pbls 应用依赖清单PBL Agent OS Phase 0/1
# 平台基础依赖web-application-spec「Required Dependencies」硬要求
# 核心apppublic / sqlor / ahserver
# 数据库 Web 应用appbase / rbac
# 前端渲染bricks_for_python.ui → bui processor缺它 / 返回 500
# DB 驱动db.engine = mariadbprojects/pbls/env/test.json 唯一事实源)
# → PyMySQL + cryptographycaching_sha2/rsa 握手需要)+ DBUtils连接池
# 禁止flask / fastapi / django / uvicorn / gunicorn应用入口只允许 ahserver
# =====================================================================
# PBL Agent OS 验证原型Phase 0/1—— 应用依赖声明
# 平台基础依赖ahserver / sqlor / apppublic / appbase / rbac由机构私有源提供
# 通过 --index-url 指向内网 pypi缺失时 build.sh 会 fail-fast 报错而非静默跳过。
--extra-index-url http://10.20.30.41:8081/repository/pypi-hosted/simple
--trusted-host 10.20.30.41
# ---- 平台核心(必装,顺序即安装顺序)----
git+https://git.opencomputing.cn/yumoqing/apppublic
git+https://git.opencomputing.cn/yumoqing/sqlor
git+https://git.opencomputing.cn/yumoqing/ahserver
# ---- 平台基础框架(必需,硬门禁 6.5----
ahserver>=1.4.0
sqlor>=1.3.0
apppublic>=1.2.0
appbase>=1.3.0
rbac>=1.2.0
pybricks>=1.1.0
accounting>=1.0.0
# ---- 数据库 Web 应用基础模块(必装)----
git+https://git.opencomputing.cn/yumoqing/appbase
git+https://git.opencomputing.cn/yumoqing/rbac
# ---- DB 驱动mariadb 方言,显式 TCP禁 socket----
PyMySQL>=1.1.0
mysqlclient>=2.2.0
SQLAlchemy>=2.0.0
# ---- 前端框架(.ui / .tmpl 渲染,必装)----
git+https://git.opencomputing.cn/yumoqing/bricks_for_python
git+https://git.opencomputing.cn/yumoqing/bricks
# ---- 业务模块(本项目新建 15 个 pbl_*,本地路径安装)----
# 由 build.sh 以 pip install -e modules/{模块} 方式安装,不发布到公共源
# pbl_common / pbl_appcodes / pbl_governance / pbl_blueprint / pbl_template
# pbl_validation / pbl_compiler / pbl_agent_runtime / pbl_evidence / pbl_assessment
# pbl_domain_ext / pbl_scense_ext / pbl_runtime_ext / pbl_kdb_ext / pbl_analytics
# ---- DDL / CRUD 生成工具build.sh 建表与 CRUD 生成用)----
xls2ddl
# ---- DB 驱动与连接池mariadb 方言)----
PyMySQL>=1.0.2
cryptography>=3.4.8
DBUtils>=3.0.2
# ---- 运行时通用依赖 ----
# ---- 通用运行时依赖 ----
requests>=2.31.0
python-dateutil>=2.8.2
pytz>=2021.3
requests>=2.27.1
six>=1.16.0
pytz>=2024.1
jsonschema>=4.21.0
PyYAML>=6.0.1
hashlib-additional>=1.0.1 ; python_version < "3.0"
# =====================================================================
# 本项目业务模块modules/pbl_*,由 build.sh 以 pip install -e 安装,
# 不走 PyPI故不在此声明版本清单见 projects/pbls/pbls_spec.json
# 的 load_order共 15 个 pbl_* 模块 + 8 个引用模块):
# pbl_common / pbl_appcodes / pbl_blueprint / pbl_validation /
# pbl_compiler / pbl_agent_runtime / pbl_evidence / pbl_assessment /
# pbl_kdb_ext / pbl_domain_ext / pbl_scense_ext / pbl_runtime_ext /
# pbl_template / pbl_analytics / pbl_governance
# 引用模块(写保护,只挂载不改):
# world / scene / entity / scense / scense_runtime / script_engine /
# kdb / world_snapshot
# =====================================================================
# ---- 前端/模板处理website.processors: .tmpl/.ui/.dspy----
Mako>=1.3.0
Jinja2>=3.1.0
# ---- 部署与自检 ----
psutil>=5.9.0
setuptools>=68.0.0
wheel>=0.42.0

View File

@ -1 +1,893 @@
41,021B commit=3 token 6 TIMESTAMP MySQL 7 FOREIGN KEY675 COMMENTdatetimeTIMESTAMPdatetime CREATE TABLE=38bigint NOT NULL AUTO_INCREMENT=38ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci=38`tenant_id`=113BIGSERIAL|SERIAL|nextval|FOREIGN KEY|REFERENCES|ENUM(|TIMESTAMP =0
-- =====================================================================
-- PBL Agent OS 验证原型Phase 0/1—— 36 表可执行 DDL
-- 方言mariadbInnoDB + utf8mb4/utf8mb4_general_ci
-- 规则id BIGINT NOT NULL AUTO_INCREMENT 物理主键 + xxx_code VARCHAR(32) 业务主键(唯一索引)
-- tenant_id VARCHAR(32) NOT NULL 为第一业务列,所有索引以 tenant_id 打头
-- 禁止 FOREIGN KEY / 禁止 ENUM / 禁止原生 TIMESTAMP用 DATETIME
-- append-only 表无 update_time、无物理删除11 张,见文末清单)
-- 权威来源projects/pbls/docs/01-design/data-model.md
-- 执行apps/pbls/build.sh -> mysql --protocol=TCP -h127.0.0.1 -P3306 pbls < pbls_tables.sql
-- =====================================================================
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
-- =====================================================================
-- 模块 pbl_governance3 表)
-- =====================================================================
-- 1. pbl_tenant 租户主表
CREATE TABLE IF NOT EXISTS pbl_tenant (
id BIGINT NOT NULL AUTO_INCREMENT,
tenant_code VARCHAR(32) NOT NULL COMMENT '租户业务主键',
tenant_id VARCHAR(32) NOT NULL COMMENT '租户ID第一业务列',
tenant_name VARCHAR(128) NOT NULL COMMENT '租户名称',
org_code VARCHAR(32) DEFAULT NULL COMMENT '所属机构编码rbac 侧只读引用)',
status VARCHAR(16) NOT NULL DEFAULT 'active' COMMENT '状态active/suspended/closedappcodes_kv: pbl_tenant_status',
quota_bp INT NOT NULL DEFAULT 100 COMMENT '蓝图配额',
quota_stu INT NOT NULL DEFAULT 500 COMMENT '学生席位配额',
remark VARCHAR(512) DEFAULT NULL COMMENT '备注',
create_by VARCHAR(32) DEFAULT NULL COMMENT '创建人',
create_time DATETIME DEFAULT NULL COMMENT '创建时间',
update_by VARCHAR(32) DEFAULT NULL COMMENT '更新人',
update_time DATETIME DEFAULT NULL COMMENT '更新时间',
PRIMARY KEY (id),
UNIQUE KEY uk_pbl_tenant_code (tenant_code),
KEY idx_pbl_tenant_tid_status (tenant_id, status),
KEY idx_pbl_tenant_tid_org (tenant_id, org_code)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='PBL 租户主表';
-- 2. pbl_role_binding 租户内角色绑定(复用 rbac不改 rbac 基表)
CREATE TABLE IF NOT EXISTS pbl_role_binding (
id BIGINT NOT NULL AUTO_INCREMENT,
binding_code VARCHAR(32) NOT NULL COMMENT '绑定业务主键',
tenant_id VARCHAR(32) NOT NULL COMMENT '租户ID',
user_code VARCHAR(32) NOT NULL COMMENT '用户编码rbac 只读引用)',
role_code VARCHAR(32) NOT NULL COMMENT '角色编码teacher/assistant/student/observer/adminappcodes_kv: pbl_role',
scope_type VARCHAR(16) NOT NULL DEFAULT 'tenant' COMMENT '作用域类型tenant/blueprint/class/team',
scope_code VARCHAR(32) DEFAULT NULL COMMENT '作用域对象编码',
status VARCHAR(16) NOT NULL DEFAULT 'active' COMMENT '状态active/revoked',
effective_from DATETIME DEFAULT NULL COMMENT '生效起',
effective_to DATETIME DEFAULT NULL COMMENT '生效止',
create_by VARCHAR(32) DEFAULT NULL,
create_time DATETIME DEFAULT NULL,
update_by VARCHAR(32) DEFAULT NULL,
update_time DATETIME DEFAULT NULL,
PRIMARY KEY (id),
UNIQUE KEY uk_pbl_role_binding_code (binding_code),
KEY idx_pbl_role_binding_tid_user (tenant_id, user_code, status),
KEY idx_pbl_role_binding_tid_scope (tenant_id, scope_type, scope_code),
KEY idx_pbl_role_binding_tid_role (tenant_id, role_code)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='PBL 租户角色绑定';
-- 3. pbl_audit_log 审计日志append-only
CREATE TABLE IF NOT EXISTS pbl_audit_log (
id BIGINT NOT NULL AUTO_INCREMENT,
audit_code VARCHAR(32) NOT NULL COMMENT '审计业务主键',
tenant_id VARCHAR(32) NOT NULL COMMENT '租户ID',
actor_type VARCHAR(16) NOT NULL DEFAULT 'user' COMMENT '主体类型user/agent/system',
actor_code VARCHAR(32) DEFAULT NULL COMMENT '主体编码',
action_code VARCHAR(64) NOT NULL COMMENT '动作编码appcodes_kv: pbl_audit_action',
object_type VARCHAR(32) DEFAULT NULL COMMENT '对象类型',
object_code VARCHAR(32) DEFAULT NULL COMMENT '对象编码',
result VARCHAR(16) NOT NULL DEFAULT 'success' COMMENT '结果success/denied/error',
detail TEXT DEFAULT NULL COMMENT '详情 JSON',
trace_id VARCHAR(64) DEFAULT NULL COMMENT '链路追踪ID',
client_ip VARCHAR(64) DEFAULT NULL COMMENT '来源IP',
create_time DATETIME DEFAULT NULL COMMENT '发生时间append-only无 update_time',
PRIMARY KEY (id),
UNIQUE KEY uk_pbl_audit_code (audit_code),
KEY idx_pbl_audit_tid_time (tenant_id, create_time),
KEY idx_pbl_audit_tid_obj (tenant_id, object_type, object_code),
KEY idx_pbl_audit_tid_actor (tenant_id, actor_type, actor_code),
KEY idx_pbl_audit_tid_trace (tenant_id, trace_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='PBL 审计日志append-only';
-- =====================================================================
-- 模块 pbl_blueprint11 表M1a
-- =====================================================================
-- 4. pbl_blueprint 蓝图聚合根
CREATE TABLE IF NOT EXISTS pbl_blueprint (
id BIGINT NOT NULL AUTO_INCREMENT,
bp_code VARCHAR(32) NOT NULL COMMENT '蓝图业务主键',
tenant_id VARCHAR(32) NOT NULL COMMENT '租户ID',
bp_name VARCHAR(128) NOT NULL COMMENT '蓝图名称',
subject_code VARCHAR(32) DEFAULT NULL COMMENT '学科编码appcodes_kv: pbl_subject',
grade_code VARCHAR(32) DEFAULT NULL COMMENT '学段编码appcodes_kv: pbl_grade',
driving_q TEXT DEFAULT NULL COMMENT '驱动性问题',
summary VARCHAR(1024) DEFAULT NULL COMMENT '蓝图摘要',
duration_hours INT NOT NULL DEFAULT 0 COMMENT '总课时(小时)',
team_size_min INT NOT NULL DEFAULT 1 COMMENT '最小团队人数',
team_size_max INT NOT NULL DEFAULT 6 COMMENT '最大团队人数',
cur_version INT NOT NULL DEFAULT 1 COMMENT '当前版本号(乐观锁)',
quality_level VARCHAR(16) NOT NULL DEFAULT 'L0_draft' COMMENT '质量等级 L0~L4appcodes_kv: pbl_quality_level',
status VARCHAR(16) NOT NULL DEFAULT 'draft' COMMENT '状态draft/validating/validated/compiling/published/archivedappcodes_kv: pbl_bp_status',
source_type VARCHAR(16) NOT NULL DEFAULT 'manual' COMMENT '来源manual/template/fork/agent',
source_code VARCHAR(32) DEFAULT NULL COMMENT '来源对象编码(模板/父蓝图)',
owner_code VARCHAR(32) DEFAULT NULL COMMENT '归属教师',
lock_holder VARCHAR(32) DEFAULT NULL COMMENT '当前编辑锁持有者',
lock_expire DATETIME DEFAULT NULL COMMENT '编辑锁过期时间',
extra TEXT DEFAULT NULL COMMENT '扩展 JSON',
create_by VARCHAR(32) DEFAULT NULL,
create_time DATETIME DEFAULT NULL,
update_by VARCHAR(32) DEFAULT NULL,
update_time DATETIME DEFAULT NULL,
PRIMARY KEY (id),
UNIQUE KEY uk_pbl_blueprint_code (bp_code),
KEY idx_pbl_bp_tid_status (tenant_id, status),
KEY idx_pbl_bp_tid_owner (tenant_id, owner_code),
KEY idx_pbl_bp_tid_subject (tenant_id, subject_code, grade_code),
KEY idx_pbl_bp_tid_quality (tenant_id, quality_level),
KEY idx_pbl_bp_tid_source (tenant_id, source_type, source_code)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='PBL 蓝图聚合根';
-- 5. pbl_blueprint_version 版本快照 + change_deltaappend-only
CREATE TABLE IF NOT EXISTS pbl_blueprint_version (
id BIGINT NOT NULL AUTO_INCREMENT,
version_code VARCHAR(32) NOT NULL COMMENT '版本业务主键',
tenant_id VARCHAR(32) NOT NULL COMMENT '租户ID',
bp_code VARCHAR(32) NOT NULL COMMENT '蓝图编码',
version_no INT NOT NULL COMMENT '版本号(单调递增)',
snapshot LONGTEXT DEFAULT NULL COMMENT '蓝图全量快照 JSON',
change_delta LONGTEXT DEFAULT NULL COMMENT '相对上一版本的差异 JSON可回放',
checksum VARCHAR(64) DEFAULT NULL COMMENT '快照 sha256',
reason VARCHAR(512) DEFAULT NULL COMMENT '变更原因',
created_by VARCHAR(32) DEFAULT NULL COMMENT '提交人',
create_time DATETIME DEFAULT NULL COMMENT '提交时间append-only无 update_time',
PRIMARY KEY (id),
UNIQUE KEY uk_pbl_bp_version_code (version_code),
UNIQUE KEY uk_pbl_bp_version_no (tenant_id, bp_code, version_no),
KEY idx_pbl_bp_version_tid_bp (tenant_id, bp_code, create_time),
KEY idx_pbl_bp_version_tid_ck (tenant_id, checksum)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='PBL 蓝图版本快照append-only';
-- 6. pbl_blueprint_lock 编辑锁
CREATE TABLE IF NOT EXISTS pbl_blueprint_lock (
id BIGINT NOT NULL AUTO_INCREMENT,
lock_code VARCHAR(32) NOT NULL COMMENT '锁业务主键',
tenant_id VARCHAR(32) NOT NULL COMMENT '租户ID',
bp_code VARCHAR(32) NOT NULL COMMENT '蓝图编码',
holder_code VARCHAR(32) NOT NULL COMMENT '持有者',
session_id VARCHAR(64) DEFAULT NULL COMMENT '会话ID',
lock_state VARCHAR(16) NOT NULL DEFAULT 'held' COMMENT '锁状态held/released/expired/forced',
acquired_at DATETIME DEFAULT NULL COMMENT '获取时间',
expire_at DATETIME DEFAULT NULL COMMENT '过期时间',
released_at DATETIME DEFAULT NULL COMMENT '释放时间',
version_no INT NOT NULL DEFAULT 0 COMMENT '加锁时版本号',
create_time DATETIME DEFAULT NULL,
update_time DATETIME DEFAULT NULL,
PRIMARY KEY (id),
UNIQUE KEY uk_pbl_bp_lock_code (lock_code),
UNIQUE KEY uk_pbl_bp_lock_active (tenant_id, bp_code, lock_state),
KEY idx_pbl_bp_lock_tid_holder (tenant_id, holder_code),
KEY idx_pbl_bp_lock_tid_expire (tenant_id, expire_at)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='PBL 蓝图编辑锁';
-- 7. pbl_subobject 7 类子对象泛化主表
CREATE TABLE IF NOT EXISTS pbl_subobject (
id BIGINT NOT NULL AUTO_INCREMENT,
obj_code VARCHAR(32) NOT NULL COMMENT '子对象业务主键',
tenant_id VARCHAR(32) NOT NULL COMMENT '租户ID',
bp_code VARCHAR(32) NOT NULL COMMENT '所属蓝图',
obj_type VARCHAR(32) NOT NULL COMMENT '子对象类型objective/stage/task/artifact_spec/rubric_ref/resource_ref/assessment_planappcodes_kv: pbl_subobj_type',
parent_code VARCHAR(32) DEFAULT NULL COMMENT '父子对象编码(树形)',
obj_name VARCHAR(128) NOT NULL COMMENT '名称',
obj_summary VARCHAR(1024) DEFAULT NULL COMMENT '摘要',
sort_no INT NOT NULL DEFAULT 0 COMMENT '同级排序',
payload LONGTEXT DEFAULT NULL COMMENT '类型化载荷 JSON泛化契约',
schema_ver VARCHAR(16) NOT NULL DEFAULT 'v1' COMMENT '载荷 schema 版本',
status VARCHAR(16) NOT NULL DEFAULT 'active' COMMENT '状态active/disabled/deleted',
version_no INT NOT NULL DEFAULT 1 COMMENT '乐观锁版本号',
create_by VARCHAR(32) DEFAULT NULL,
create_time DATETIME DEFAULT NULL,
update_by VARCHAR(32) DEFAULT NULL,
update_time DATETIME DEFAULT NULL,
PRIMARY KEY (id),
UNIQUE KEY uk_pbl_subobject_code (obj_code),
KEY idx_pbl_subobj_tid_bp_type (tenant_id, bp_code, obj_type, sort_no),
KEY idx_pbl_subobj_tid_parent (tenant_id, parent_code),
KEY idx_pbl_subobj_tid_status (tenant_id, status)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='PBL 蓝图 7 类子对象泛化主表';
-- 8. pbl_subobject_attr 子对象泛化属性KV
CREATE TABLE IF NOT EXISTS pbl_subobject_attr (
id BIGINT NOT NULL AUTO_INCREMENT,
attr_code VARCHAR(32) NOT NULL COMMENT '属性业务主键',
tenant_id VARCHAR(32) NOT NULL COMMENT '租户ID',
obj_code VARCHAR(32) NOT NULL COMMENT '子对象编码',
attr_key VARCHAR(64) NOT NULL COMMENT '属性键',
attr_value TEXT DEFAULT NULL COMMENT '属性值',
value_type VARCHAR(16) NOT NULL DEFAULT 'string' COMMENT '值类型string/int/float/bool/json/date',
required_flag TINYINT NOT NULL DEFAULT 0 COMMENT '是否必填 0否1是',
sort_no INT NOT NULL DEFAULT 0 COMMENT '排序',
create_time DATETIME DEFAULT NULL,
update_time DATETIME DEFAULT NULL,
PRIMARY KEY (id),
UNIQUE KEY uk_pbl_subobj_attr_code (attr_code),
UNIQUE KEY uk_pbl_subobj_attr_key (tenant_id, obj_code, attr_key),
KEY idx_pbl_subobj_attr_tid_obj (tenant_id, obj_code, sort_no)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='PBL 子对象泛化属性 KV';
-- 9. pbl_subobject_rel 子对象间关系
CREATE TABLE IF NOT EXISTS pbl_subobject_rel (
id BIGINT NOT NULL AUTO_INCREMENT,
rel_code VARCHAR(32) NOT NULL COMMENT '关系业务主键',
tenant_id VARCHAR(32) NOT NULL COMMENT '租户ID',
bp_code VARCHAR(32) NOT NULL COMMENT '所属蓝图',
src_obj_code VARCHAR(32) NOT NULL COMMENT '源子对象',
dst_obj_code VARCHAR(32) NOT NULL COMMENT '目标子对象',
rel_type VARCHAR(32) NOT NULL COMMENT '关系类型depends_on/produces/assesses/references/containsappcodes_kv: pbl_rel_type',
weight DECIMAL(6,3) NOT NULL DEFAULT 1.000 COMMENT '关系权重',
remark VARCHAR(512) DEFAULT NULL COMMENT '备注',
create_by VARCHAR(32) DEFAULT NULL,
create_time DATETIME DEFAULT NULL,
update_time DATETIME DEFAULT NULL,
PRIMARY KEY (id),
UNIQUE KEY uk_pbl_subobj_rel_code (rel_code),
UNIQUE KEY uk_pbl_subobj_rel_triple (tenant_id, src_obj_code, dst_obj_code, rel_type),
KEY idx_pbl_subobj_rel_tid_bp (tenant_id, bp_code, rel_type),
KEY idx_pbl_subobj_rel_tid_dst (tenant_id, dst_obj_code)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='PBL 子对象关系';
-- 10. pbl_subobject_asset 子对象资产引用(只读引用平台资产,不落资产本体)
CREATE TABLE IF NOT EXISTS pbl_subobject_asset (
id BIGINT NOT NULL AUTO_INCREMENT,
asset_code VARCHAR(32) NOT NULL COMMENT '资产引用业务主键',
tenant_id VARCHAR(32) NOT NULL COMMENT '租户ID',
obj_code VARCHAR(32) NOT NULL COMMENT '子对象编码',
asset_kind VARCHAR(32) NOT NULL COMMENT '资产种类image/model/audio/video/doc/urlappcodes_kv: pbl_asset_kind',
asset_uri VARCHAR(512) DEFAULT NULL COMMENT '资产 URI',
asset_name VARCHAR(128) DEFAULT NULL COMMENT '资产名称',
mime_type VARCHAR(64) DEFAULT NULL COMMENT 'MIME',
size_bytes BIGINT NOT NULL DEFAULT 0 COMMENT '字节数',
checksum VARCHAR(64) DEFAULT NULL COMMENT 'sha256',
license_code VARCHAR(32) DEFAULT NULL COMMENT '许可编码',
sort_no INT NOT NULL DEFAULT 0 COMMENT '排序',
create_by VARCHAR(32) DEFAULT NULL,
create_time DATETIME DEFAULT NULL,
update_time DATETIME DEFAULT NULL,
PRIMARY KEY (id),
UNIQUE KEY uk_pbl_subobj_asset_code (asset_code),
KEY idx_pbl_subobj_asset_tid_obj (tenant_id, obj_code, sort_no),
KEY idx_pbl_subobj_asset_tid_kind (tenant_id, asset_kind)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='PBL 子对象资产引用';
-- 11. pbl_subobject_ref 子对象对复用域对象的只读引用world/scene/entity/script
CREATE TABLE IF NOT EXISTS pbl_subobject_ref (
id BIGINT NOT NULL AUTO_INCREMENT,
ref_code VARCHAR(32) NOT NULL COMMENT '引用业务主键',
tenant_id VARCHAR(32) NOT NULL COMMENT '租户ID',
obj_code VARCHAR(32) NOT NULL COMMENT '子对象编码',
ref_module VARCHAR(32) NOT NULL COMMENT '被引用模块world/scene/entity/script_engine/scense/scense_game',
ref_table VARCHAR(64) NOT NULL COMMENT '被引用表名',
ref_id BIGINT DEFAULT NULL COMMENT '被引用行 id',
ref_biz_code VARCHAR(64) DEFAULT NULL COMMENT '被引用业务编码',
ref_mode VARCHAR(16) NOT NULL DEFAULT 'readonly' COMMENT '引用模式readonlyPhase 0/1 唯一合法值)',
snapshot_json TEXT DEFAULT NULL COMMENT '引用时只读快照(不改基表)',
create_by VARCHAR(32) DEFAULT NULL,
create_time DATETIME DEFAULT NULL,
update_time DATETIME DEFAULT NULL,
PRIMARY KEY (id),
UNIQUE KEY uk_pbl_subobj_ref_code (ref_code),
KEY idx_pbl_subobj_ref_tid_obj (tenant_id, obj_code),
KEY idx_pbl_subobj_ref_tid_mod (tenant_id, ref_module, ref_table, ref_biz_code)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='PBL 子对象对复用域只读引用';
-- 12. pbl_subobject_review 子对象评审意见append-only
CREATE TABLE IF NOT EXISTS pbl_subobject_review (
id BIGINT NOT NULL AUTO_INCREMENT,
review_code VARCHAR(32) NOT NULL COMMENT '评审业务主键',
tenant_id VARCHAR(32) NOT NULL COMMENT '租户ID',
bp_code VARCHAR(32) NOT NULL COMMENT '蓝图编码',
obj_code VARCHAR(32) DEFAULT NULL COMMENT '子对象编码(空=蓝图级)',
reviewer_type VARCHAR(16) NOT NULL DEFAULT 'user' COMMENT '评审主体user/agent_critic/agent_designer',
reviewer_code VARCHAR(32) DEFAULT NULL COMMENT '评审主体编码',
verdict VARCHAR(16) NOT NULL DEFAULT 'comment' COMMENT '结论pass/comment/revise/reject',
score DECIMAL(6,2) DEFAULT NULL COMMENT '评分',
comment TEXT DEFAULT NULL COMMENT '意见正文',
create_time DATETIME DEFAULT NULL COMMENT '评审时间append-only无 update_time',
PRIMARY KEY (id),
UNIQUE KEY uk_pbl_subobj_review_code (review_code),
KEY idx_pbl_subobj_review_tid_bp (tenant_id, bp_code, create_time),
KEY idx_pbl_subobj_review_tid_obj (tenant_id, obj_code)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='PBL 子对象评审意见append-only';
-- 13. pbl_blueprint_tag 蓝图标签
CREATE TABLE IF NOT EXISTS pbl_blueprint_tag (
id BIGINT NOT NULL AUTO_INCREMENT,
tag_code VARCHAR(32) NOT NULL COMMENT '标签业务主键',
tenant_id VARCHAR(32) NOT NULL COMMENT '租户ID',
bp_code VARCHAR(32) NOT NULL COMMENT '蓝图编码',
tag_key VARCHAR(64) NOT NULL COMMENT '标签键',
tag_value VARCHAR(128) DEFAULT NULL COMMENT '标签值',
create_time DATETIME DEFAULT NULL,
update_time DATETIME DEFAULT NULL,
PRIMARY KEY (id),
UNIQUE KEY uk_pbl_bp_tag_code (tag_code),
UNIQUE KEY uk_pbl_bp_tag_kv (tenant_id, bp_code, tag_key),
KEY idx_pbl_bp_tag_tid_key (tenant_id, tag_key, tag_value)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='PBL 蓝图标签';
-- 14. pbl_blueprint_publish 发布记录append-only
CREATE TABLE IF NOT EXISTS pbl_blueprint_publish (
id BIGINT NOT NULL AUTO_INCREMENT,
publish_code VARCHAR(32) NOT NULL COMMENT '发布业务主键',
tenant_id VARCHAR(32) NOT NULL COMMENT '租户ID',
bp_code VARCHAR(32) NOT NULL COMMENT '蓝图编码',
version_no INT NOT NULL COMMENT '发布版本号',
gd_code VARCHAR(32) DEFAULT NULL COMMENT '关联 Game Definition 编码',
channel VARCHAR(32) NOT NULL DEFAULT 'class' COMMENT '发布渠道class/school/public',
target_code VARCHAR(32) DEFAULT NULL COMMENT '目标对象(班级编码)',
publish_state VARCHAR(16) NOT NULL DEFAULT 'published' COMMENT '状态published/revoked',
published_by VARCHAR(32) DEFAULT NULL COMMENT '发布人',
create_time DATETIME DEFAULT NULL COMMENT '发布时间append-only无 update_time',
PRIMARY KEY (id),
UNIQUE KEY uk_pbl_bp_publish_code (publish_code),
KEY idx_pbl_bp_publish_tid_bp (tenant_id, bp_code, create_time),
KEY idx_pbl_bp_publish_tid_target (tenant_id, channel, target_code)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='PBL 蓝图发布记录append-only';
-- =====================================================================
-- 模块 pbl_template2 表M1b
-- =====================================================================
-- 15. pbl_template 模板主表(含离线兜底模板)
CREATE TABLE IF NOT EXISTS pbl_template (
id BIGINT NOT NULL AUTO_INCREMENT,
tpl_code VARCHAR(32) NOT NULL COMMENT '模板业务主键',
tenant_id VARCHAR(32) NOT NULL COMMENT '租户ID__system__ 表示平台内置)',
tpl_name VARCHAR(128) NOT NULL COMMENT '模板名称',
tpl_kind VARCHAR(32) NOT NULL DEFAULT 'blueprint' COMMENT '模板种类blueprint/subobject/rubric',
subject_code VARCHAR(32) DEFAULT NULL COMMENT '适用学科',
grade_code VARCHAR(32) DEFAULT NULL COMMENT '适用学段',
offline_flag TINYINT NOT NULL DEFAULT 0 COMMENT '是否离线兜底模板 0否1是',
body LONGTEXT DEFAULT NULL COMMENT '模板正文 JSON含子对象树',
id_prefix_rule VARCHAR(64) DEFAULT NULL COMMENT '实例化 ID 重映射前缀规则',
version_no INT NOT NULL DEFAULT 1 COMMENT '模板版本',
status VARCHAR(16) NOT NULL DEFAULT 'active' COMMENT '状态active/disabled',
create_by VARCHAR(32) DEFAULT NULL,
create_time DATETIME DEFAULT NULL,
update_by VARCHAR(32) DEFAULT NULL,
update_time DATETIME DEFAULT NULL,
PRIMARY KEY (id),
UNIQUE KEY uk_pbl_template_code (tpl_code),
KEY idx_pbl_template_tid_kind (tenant_id, tpl_kind, status),
KEY idx_pbl_template_tid_subj (tenant_id, subject_code, grade_code),
KEY idx_pbl_template_tid_offline (tenant_id, offline_flag)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='PBL 模板主表';
-- 16. pbl_template_item 模板条目(实例化 ID 重映射映射表)
CREATE TABLE IF NOT EXISTS pbl_template_item (
id BIGINT NOT NULL AUTO_INCREMENT,
item_code VARCHAR(32) NOT NULL COMMENT '条目业务主键',
tenant_id VARCHAR(32) NOT NULL COMMENT '租户ID',
tpl_code VARCHAR(32) NOT NULL COMMENT '模板编码',
tpl_obj_key VARCHAR(64) NOT NULL COMMENT '模板内占位键(如 __OBJ_1__',
obj_type VARCHAR(32) NOT NULL COMMENT '子对象类型',
parent_key VARCHAR(64) DEFAULT NULL COMMENT '父占位键',
payload LONGTEXT DEFAULT NULL COMMENT '条目载荷 JSON',
sort_no INT NOT NULL DEFAULT 0 COMMENT '排序',
create_time DATETIME DEFAULT NULL,
update_time DATETIME DEFAULT NULL,
PRIMARY KEY (id),
UNIQUE KEY uk_pbl_template_item_code (item_code),
UNIQUE KEY uk_pbl_template_item_key (tenant_id, tpl_code, tpl_obj_key),
KEY idx_pbl_template_item_tid_tpl (tenant_id, tpl_code, sort_no)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='PBL 模板条目';
-- =====================================================================
-- 模块 pbl_validation3 表M214 维 + 5 级质量状态)
-- =====================================================================
-- 17. pbl_validation_ruleset 校验规则集
CREATE TABLE IF NOT EXISTS pbl_validation_ruleset (
id BIGINT NOT NULL AUTO_INCREMENT,
ruleset_code VARCHAR(32) NOT NULL COMMENT '规则集业务主键',
tenant_id VARCHAR(32) NOT NULL COMMENT '租户ID',
ruleset_name VARCHAR(128) NOT NULL COMMENT '规则集名称',
dim_code VARCHAR(32) NOT NULL COMMENT '维度编码 D01~D14appcodes_kv: pbl_valid_dim',
dim_name VARCHAR(64) NOT NULL COMMENT '维度名称',
rule_expr TEXT DEFAULT NULL COMMENT '规则表达式 JSON确定性可执行',
severity VARCHAR(16) NOT NULL DEFAULT 'error' COMMENT '严重度blocker/error/warning/info',
weight DECIMAL(6,3) NOT NULL DEFAULT 1.000 COMMENT '维度权重',
level_effect VARCHAR(16) DEFAULT NULL COMMENT '对质量等级的影响downgrade/gate/none',
enabled TINYINT NOT NULL DEFAULT 1 COMMENT '是否启用 0否1是',
sort_no INT NOT NULL DEFAULT 0 COMMENT '维度排序',
create_by VARCHAR(32) DEFAULT NULL,
create_time DATETIME DEFAULT NULL,
update_by VARCHAR(32) DEFAULT NULL,
update_time DATETIME DEFAULT NULL,
PRIMARY KEY (id),
UNIQUE KEY uk_pbl_valid_ruleset_code (ruleset_code),
KEY idx_pbl_valid_ruleset_tid_dim (tenant_id, dim_code, enabled),
KEY idx_pbl_valid_ruleset_tid_sort (tenant_id, sort_no)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='PBL 14 维校验规则集';
-- 18. pbl_validation_run 校验执行批次
CREATE TABLE IF NOT EXISTS pbl_validation_run (
id BIGINT NOT NULL AUTO_INCREMENT,
run_code VARCHAR(32) NOT NULL COMMENT '执行批次业务主键',
tenant_id VARCHAR(32) NOT NULL COMMENT '租户ID',
bp_code VARCHAR(32) NOT NULL COMMENT '蓝图编码',
version_no INT NOT NULL DEFAULT 1 COMMENT '被校验版本号',
ruleset_ver VARCHAR(32) DEFAULT NULL COMMENT '规则集版本',
trigger_type VARCHAR(16) NOT NULL DEFAULT 'manual' COMMENT '触发manual/auto/agent/pre_compile',
run_state VARCHAR(16) NOT NULL DEFAULT 'running' COMMENT '状态running/passed/failed/error',
dims_total INT NOT NULL DEFAULT 14 COMMENT '维度总数',
dims_passed INT NOT NULL DEFAULT 0 COMMENT '通过维度数',
blocker_count INT NOT NULL DEFAULT 0 COMMENT 'blocker 数',
error_count INT NOT NULL DEFAULT 0 COMMENT 'error 数',
warning_count INT NOT NULL DEFAULT 0 COMMENT 'warning 数',
score DECIMAL(6,2) DEFAULT NULL COMMENT '加权得分',
quality_level VARCHAR(16) DEFAULT NULL COMMENT '产出质量等级 L0~L4',
started_at DATETIME DEFAULT NULL COMMENT '开始时间',
finished_at DATETIME DEFAULT NULL COMMENT '结束时间',
create_by VARCHAR(32) DEFAULT NULL,
create_time DATETIME DEFAULT NULL,
update_time DATETIME DEFAULT NULL,
PRIMARY KEY (id),
UNIQUE KEY uk_pbl_valid_run_code (run_code),
KEY idx_pbl_valid_run_tid_bp (tenant_id, bp_code, create_time),
KEY idx_pbl_valid_run_tid_state (tenant_id, run_state),
KEY idx_pbl_valid_run_tid_level (tenant_id, quality_level)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='PBL 校验执行批次';
-- 19. pbl_validation_finding 校验发现明细append-only 留痕)
CREATE TABLE IF NOT EXISTS pbl_validation_finding (
id BIGINT NOT NULL AUTO_INCREMENT,
finding_code VARCHAR(32) NOT NULL COMMENT '发现业务主键',
tenant_id VARCHAR(32) NOT NULL COMMENT '租户ID',
run_code VARCHAR(32) NOT NULL COMMENT '执行批次编码',
bp_code VARCHAR(32) NOT NULL COMMENT '蓝图编码',
dim_code VARCHAR(32) NOT NULL COMMENT '维度编码',
obj_code VARCHAR(32) DEFAULT NULL COMMENT '命中子对象',
severity VARCHAR(16) NOT NULL DEFAULT 'error' COMMENT '严重度',
finding_msg VARCHAR(1024) DEFAULT NULL COMMENT '问题描述',
suggestion VARCHAR(1024) DEFAULT NULL COMMENT '修复建议',
evidence_json TEXT DEFAULT NULL COMMENT '证据 JSON',
create_time DATETIME DEFAULT NULL COMMENT '产生时间append-only无 update_time',
PRIMARY KEY (id),
UNIQUE KEY uk_pbl_valid_finding_code (finding_code),
KEY idx_pbl_valid_finding_tid_run (tenant_id, run_code, dim_code),
KEY idx_pbl_valid_finding_tid_bp (tenant_id, bp_code, create_time),
KEY idx_pbl_valid_finding_tid_obj (tenant_id, obj_code)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='PBL 校验发现明细append-only';
-- =====================================================================
-- 模块 pbl_compiler4 表M3a/M3b确定性编译 + Game Definition
-- =====================================================================
-- 20. pbl_compile_job 编译作业
CREATE TABLE IF NOT EXISTS pbl_compile_job (
id BIGINT NOT NULL AUTO_INCREMENT,
job_code VARCHAR(32) NOT NULL COMMENT '作业业务主键',
tenant_id VARCHAR(32) NOT NULL COMMENT '租户ID',
bp_code VARCHAR(32) NOT NULL COMMENT '蓝图编码',
version_no INT NOT NULL COMMENT '被编译版本号',
run_code VARCHAR(32) DEFAULT NULL COMMENT '前置校验批次(必须 passed',
compiler_ver VARCHAR(32) NOT NULL DEFAULT 'v1' COMMENT '编译器版本',
job_state VARCHAR(16) NOT NULL DEFAULT 'queued' COMMENT '状态queued/running/success/failed/cancelled',
input_checksum VARCHAR(64) DEFAULT NULL COMMENT '输入快照 sha256确定性依据',
output_checksum VARCHAR(64) DEFAULT NULL COMMENT '输出 Game Definition sha256',
gd_code VARCHAR(32) DEFAULT NULL COMMENT '产出 Game Definition 编码',
error_msg VARCHAR(1024) DEFAULT NULL COMMENT '错误信息',
started_at DATETIME DEFAULT NULL,
finished_at DATETIME DEFAULT NULL,
create_by VARCHAR(32) DEFAULT NULL,
create_time DATETIME DEFAULT NULL,
update_time DATETIME DEFAULT NULL,
PRIMARY KEY (id),
UNIQUE KEY uk_pbl_compile_job_code (job_code),
KEY idx_pbl_compile_job_tid_bp (tenant_id, bp_code, create_time),
KEY idx_pbl_compile_job_tid_state (tenant_id, job_state),
KEY idx_pbl_compile_job_tid_ick (tenant_id, input_checksum)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='PBL 编译作业';
-- 21. pbl_compile_artifact 编译中间产物
CREATE TABLE IF NOT EXISTS pbl_compile_artifact (
id BIGINT NOT NULL AUTO_INCREMENT,
artifact_code VARCHAR(32) NOT NULL COMMENT '产物业务主键',
tenant_id VARCHAR(32) NOT NULL COMMENT '租户ID',
job_code VARCHAR(32) NOT NULL COMMENT '编译作业编码',
stage_code VARCHAR(32) NOT NULL COMMENT '编译阶段normalize/resolve/link/optimize/emit',
artifact_kind VARCHAR(32) NOT NULL COMMENT '产物种类node_set/edge_set/rule_set/asset_map/gd_draft',
body LONGTEXT DEFAULT NULL COMMENT '产物正文 JSON',
checksum VARCHAR(64) DEFAULT NULL COMMENT 'sha256',
sort_no INT NOT NULL DEFAULT 0 COMMENT '阶段排序',
create_time DATETIME DEFAULT NULL,
update_time DATETIME DEFAULT NULL,
PRIMARY KEY (id),
UNIQUE KEY uk_pbl_compile_artifact_code (artifact_code),
KEY idx_pbl_compile_artifact_tid_job (tenant_id, job_code, sort_no),
KEY idx_pbl_compile_artifact_tid_kind (tenant_id, artifact_kind)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='PBL 编译中间产物';
-- 22. pbl_game_definition Game Definition编译最终产出
CREATE TABLE IF NOT EXISTS pbl_game_definition (
id BIGINT NOT NULL AUTO_INCREMENT,
gd_code VARCHAR(32) NOT NULL COMMENT 'Game Definition 业务主键',
tenant_id VARCHAR(32) NOT NULL COMMENT '租户ID',
bp_code VARCHAR(32) NOT NULL COMMENT '来源蓝图',
version_no INT NOT NULL COMMENT '来源蓝图版本',
gd_version INT NOT NULL DEFAULT 1 COMMENT 'GD 自身版本',
schema_ver VARCHAR(16) NOT NULL DEFAULT 'gd-v1' COMMENT 'GD schema 版本',
body LONGTEXT DEFAULT NULL COMMENT 'Game Definition 全文 JSONschema 校验通过)',
checksum VARCHAR(64) DEFAULT NULL COMMENT 'sha256同输入同输出',
world_ref VARCHAR(64) DEFAULT NULL COMMENT '引用世界编码(只读)',
scene_ref VARCHAR(64) DEFAULT NULL COMMENT '引用场景编码(只读)',
script_ref VARCHAR(64) DEFAULT NULL COMMENT '引用脚本编码(只读)',
gd_state VARCHAR(16) NOT NULL DEFAULT 'draft' COMMENT '状态draft/validated/published/archived',
create_by VARCHAR(32) DEFAULT NULL,
create_time DATETIME DEFAULT NULL,
update_by VARCHAR(32) DEFAULT NULL,
update_time DATETIME DEFAULT NULL,
PRIMARY KEY (id),
UNIQUE KEY uk_pbl_gd_code (gd_code),
UNIQUE KEY uk_pbl_gd_bp_ver (tenant_id, bp_code, version_no, gd_version),
KEY idx_pbl_gd_tid_state (tenant_id, gd_state),
KEY idx_pbl_gd_tid_ck (tenant_id, checksum),
KEY idx_pbl_gd_tid_world (tenant_id, world_ref, scene_ref)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='PBL Game Definition';
-- 23. pbl_compile_log 编译日志append-only
CREATE TABLE IF NOT EXISTS pbl_compile_log (
id BIGINT NOT NULL AUTO_INCREMENT,
log_code VARCHAR(32) NOT NULL COMMENT '日志业务主键',
tenant_id VARCHAR(32) NOT NULL COMMENT '租户ID',
job_code VARCHAR(32) NOT NULL COMMENT '编译作业编码',
stage_code VARCHAR(32) DEFAULT NULL COMMENT '阶段',
log_level VARCHAR(16) NOT NULL DEFAULT 'info' COMMENT '级别debug/info/warn/error',
log_msg VARCHAR(2048) DEFAULT NULL COMMENT '日志正文',
context_json TEXT DEFAULT NULL COMMENT '上下文 JSON',
seq_no BIGINT NOT NULL DEFAULT 0 COMMENT '作业内单调序号',
create_time DATETIME DEFAULT NULL COMMENT '记录时间append-only无 update_time',
PRIMARY KEY (id),
UNIQUE KEY uk_pbl_compile_log_code (log_code),
KEY idx_pbl_compile_log_tid_job (tenant_id, job_code, seq_no),
KEY idx_pbl_compile_log_tid_level (tenant_id, log_level, create_time)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='PBL 编译日志append-only';
-- =====================================================================
-- 模块 pbl_agent_runtime4 表M4a/M4bDesigner/Critic + fail-closed 裁决)
-- =====================================================================
-- 24. pbl_agent_session Agent 会话
CREATE TABLE IF NOT EXISTS pbl_agent_session (
id BIGINT NOT NULL AUTO_INCREMENT,
session_code VARCHAR(32) NOT NULL COMMENT '会话业务主键',
tenant_id VARCHAR(32) NOT NULL COMMENT '租户ID',
bp_code VARCHAR(32) DEFAULT NULL COMMENT '关联蓝图',
agent_role VARCHAR(32) NOT NULL COMMENT 'Agent 角色designer/criticappcodes_kv: pbl_agent_role',
model_name VARCHAR(64) DEFAULT NULL COMMENT '使用的平台模型注册名',
session_state VARCHAR(16) NOT NULL DEFAULT 'active' COMMENT '状态active/paused/closed/error',
owner_code VARCHAR(32) DEFAULT NULL COMMENT '发起用户',
turn_count INT NOT NULL DEFAULT 0 COMMENT '轮次数',
tool_call_count INT NOT NULL DEFAULT 0 COMMENT '工具调用总数',
tool_deny_count INT NOT NULL DEFAULT 0 COMMENT '被拒绝调用数',
context_json LONGTEXT DEFAULT NULL COMMENT '会话上下文 JSON',
started_at DATETIME DEFAULT NULL,
closed_at DATETIME DEFAULT NULL,
create_time DATETIME DEFAULT NULL,
update_time DATETIME DEFAULT NULL,
PRIMARY KEY (id),
UNIQUE KEY uk_pbl_agent_session_code (session_code),
KEY idx_pbl_agent_session_tid_bp (tenant_id, bp_code, session_state),
KEY idx_pbl_agent_session_tid_role (tenant_id, agent_role),
KEY idx_pbl_agent_session_tid_owner (tenant_id, owner_code)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='PBL Agent 会话';
-- 25. pbl_agent_message Agent 消息append-only
CREATE TABLE IF NOT EXISTS pbl_agent_message (
id BIGINT NOT NULL AUTO_INCREMENT,
msg_code VARCHAR(32) NOT NULL COMMENT '消息业务主键',
tenant_id VARCHAR(32) NOT NULL COMMENT '租户ID',
session_code VARCHAR(32) NOT NULL COMMENT '会话编码',
turn_no INT NOT NULL DEFAULT 0 COMMENT '轮次号',
role VARCHAR(16) NOT NULL COMMENT '角色system/user/assistant/tool',
content LONGTEXT DEFAULT NULL COMMENT '消息正文',
token_in INT NOT NULL DEFAULT 0 COMMENT '输入 token',
token_out INT NOT NULL DEFAULT 0 COMMENT '输出 token',
latency_ms INT NOT NULL DEFAULT 0 COMMENT '耗时毫秒',
create_time DATETIME DEFAULT NULL COMMENT '产生时间append-only无 update_time',
PRIMARY KEY (id),
UNIQUE KEY uk_pbl_agent_msg_code (msg_code),
KEY idx_pbl_agent_msg_tid_sess (tenant_id, session_code, turn_no),
KEY idx_pbl_agent_msg_tid_time (tenant_id, create_time)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='PBL Agent 消息append-only';
-- 26. pbl_agent_tool_call 工具调用记录append-only
CREATE TABLE IF NOT EXISTS pbl_agent_tool_call (
id BIGINT NOT NULL AUTO_INCREMENT,
call_code VARCHAR(32) NOT NULL COMMENT '调用业务主键',
tenant_id VARCHAR(32) NOT NULL COMMENT '租户ID',
session_code VARCHAR(32) NOT NULL COMMENT '会话编码',
turn_no INT NOT NULL DEFAULT 0 COMMENT '轮次号',
tool_name VARCHAR(64) NOT NULL COMMENT '工具名13 启用 / 9 禁用白名单外)',
tool_state VARCHAR(16) NOT NULL DEFAULT 'pending' COMMENT '状态pending/allowed/executed/denied/error',
params_json LONGTEXT DEFAULT NULL COMMENT '入参 JSON',
result_json LONGTEXT DEFAULT NULL COMMENT '返回 JSON',
latency_ms INT NOT NULL DEFAULT 0 COMMENT '耗时毫秒',
create_time DATETIME DEFAULT NULL COMMENT '调用时间append-only无 update_time',
PRIMARY KEY (id),
UNIQUE KEY uk_pbl_agent_call_code (call_code),
KEY idx_pbl_agent_call_tid_sess (tenant_id, session_code, turn_no),
KEY idx_pbl_agent_call_tid_tool (tenant_id, tool_name, tool_state),
KEY idx_pbl_agent_call_tid_time (tenant_id, create_time)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='PBL Agent 工具调用append-only';
-- 27. pbl_agent_arbitration fail-closed 裁决记录append-only
CREATE TABLE IF NOT EXISTS pbl_agent_arbitration (
id BIGINT NOT NULL AUTO_INCREMENT,
arb_code VARCHAR(32) NOT NULL COMMENT '裁决业务主键',
tenant_id VARCHAR(32) NOT NULL COMMENT '租户ID',
session_code VARCHAR(32) DEFAULT NULL COMMENT '会话编码',
call_code VARCHAR(32) DEFAULT NULL COMMENT '关联调用编码',
tool_name VARCHAR(64) NOT NULL COMMENT '被裁决工具名',
decision VARCHAR(16) NOT NULL DEFAULT 'deny' COMMENT '裁决allow/deny默认 denyfail-closed',
deny_reason VARCHAR(32) NOT NULL DEFAULT 'not_in_whitelist' COMMENT '拒绝原因not_in_whitelist/invalid_params/missing_tenant_context/write_protected/quota_exceeded',
rule_ref VARCHAR(64) DEFAULT NULL COMMENT '命中规则引用',
detail_json TEXT DEFAULT NULL COMMENT '裁决详情 JSON',
arbiter VARCHAR(32) NOT NULL DEFAULT 'system' COMMENT '裁决者',
create_time DATETIME DEFAULT NULL COMMENT '裁决时间append-only无 update_time',
PRIMARY KEY (id),
UNIQUE KEY uk_pbl_agent_arb_code (arb_code),
KEY idx_pbl_agent_arb_tid_tool (tenant_id, tool_name, decision),
KEY idx_pbl_agent_arb_tid_sess (tenant_id, session_code, create_time),
KEY idx_pbl_agent_arb_tid_reason (tenant_id, deny_reason)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='PBL Agent fail-closed 裁决记录append-only';
-- =====================================================================
-- 模块 pbl_evidence4 表M5a/M5b产出物采集 + 证据幂等)
-- =====================================================================
-- 28. pbl_artifact 学生产出物
CREATE TABLE IF NOT EXISTS pbl_artifact (
id BIGINT NOT NULL AUTO_INCREMENT,
artifact_code VARCHAR(32) NOT NULL COMMENT '产出物业务主键',
tenant_id VARCHAR(32) NOT NULL COMMENT '租户ID',
bp_code VARCHAR(32) NOT NULL COMMENT '蓝图编码',
session_code VARCHAR(32) DEFAULT NULL COMMENT '运行会话编码',
team_code VARCHAR(32) DEFAULT NULL COMMENT '团队编码',
obj_code VARCHAR(32) DEFAULT NULL COMMENT '对应产出物规格子对象',
artifact_name VARCHAR(128) NOT NULL COMMENT '产出物名称',
artifact_kind VARCHAR(32) NOT NULL COMMENT '种类doc/image/model/audio/video/code/log/chatappcodes_kv: pbl_artifact_kind',
storage_uri VARCHAR(512) DEFAULT NULL COMMENT '存储 URI',
mime_type VARCHAR(64) DEFAULT NULL COMMENT 'MIME',
size_bytes BIGINT NOT NULL DEFAULT 0 COMMENT '字节数',
checksum VARCHAR(64) DEFAULT NULL COMMENT 'sha256',
content_text LONGTEXT DEFAULT NULL COMMENT '文本类正文(可索引)',
status VARCHAR(16) NOT NULL DEFAULT 'active' COMMENT '状态active/archived/deleted',
create_by VARCHAR(32) DEFAULT NULL,
create_time DATETIME DEFAULT NULL,
update_time DATETIME DEFAULT NULL,
PRIMARY KEY (id),
UNIQUE KEY uk_pbl_artifact_code (artifact_code),
KEY idx_pbl_artifact_tid_bp (tenant_id, bp_code, artifact_kind),
KEY idx_pbl_artifact_tid_team (tenant_id, team_code),
KEY idx_pbl_artifact_tid_sess (tenant_id, session_code),
KEY idx_pbl_artifact_tid_ck (tenant_id, checksum)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='PBL 学生产出物';
-- 29. pbl_evidence 证据主表
CREATE TABLE IF NOT EXISTS pbl_evidence (
id BIGINT NOT NULL AUTO_INCREMENT,
evidence_code VARCHAR(32) NOT NULL COMMENT '证据业务主键',
tenant_id VARCHAR(32) NOT NULL COMMENT '租户ID',
bp_code VARCHAR(32) NOT NULL COMMENT '蓝图编码',
artifact_code VARCHAR(32) DEFAULT NULL COMMENT '关联产出物',
obj_code VARCHAR(32) DEFAULT NULL COMMENT '关联子对象(学习目标/任务)',
team_code VARCHAR(32) DEFAULT NULL COMMENT '团队编码',
student_code VARCHAR(32) DEFAULT NULL COMMENT '学生编码',
evidence_type VARCHAR(32) NOT NULL COMMENT '证据类型artifact/event/dialogue/state_snapshot/metricappcodes_kv: pbl_evidence_type',
idem_key VARCHAR(128) NOT NULL COMMENT '幂等键tenant+bp+type+source+hash',
payload LONGTEXT DEFAULT NULL COMMENT '证据载荷 JSON',
occurred_at DATETIME DEFAULT NULL COMMENT '证据发生时间',
trust_level VARCHAR(16) NOT NULL DEFAULT 'normal' COMMENT '可信度high/normal/low',
anonymized TINYINT NOT NULL DEFAULT 0 COMMENT '是否已匿名化 0否1是',
status VARCHAR(16) NOT NULL DEFAULT 'active' COMMENT '状态active/invalidated',
create_by VARCHAR(32) DEFAULT NULL,
create_time DATETIME DEFAULT NULL,
update_time DATETIME DEFAULT NULL,
PRIMARY KEY (id),
UNIQUE KEY uk_pbl_evidence_code (evidence_code),
UNIQUE KEY uk_pbl_evidence_idem (tenant_id, idem_key),
KEY idx_pbl_evidence_tid_bp (tenant_id, bp_code, evidence_type),
KEY idx_pbl_evidence_tid_team (tenant_id, team_code, student_code),
KEY idx_pbl_evidence_tid_obj (tenant_id, obj_code),
KEY idx_pbl_evidence_tid_time (tenant_id, occurred_at)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='PBL 证据主表(幂等键唯一)';
-- 30. pbl_evidence_idem 证据幂等提交台账append-only
CREATE TABLE IF NOT EXISTS pbl_evidence_idem (
id BIGINT NOT NULL AUTO_INCREMENT,
idem_code VARCHAR(32) NOT NULL COMMENT '幂等台账业务主键',
tenant_id VARCHAR(32) NOT NULL COMMENT '租户ID',
idem_key VARCHAR(128) NOT NULL COMMENT '幂等键',
evidence_code VARCHAR(32) DEFAULT NULL COMMENT '首次落库证据编码',
submit_count INT NOT NULL DEFAULT 1 COMMENT '累计提交次数(重复提交只增此计数,不新增证据行)',
last_payload_hash VARCHAR(64) DEFAULT NULL COMMENT '最近一次载荷 hash',
conflict_flag TINYINT NOT NULL DEFAULT 0 COMMENT '是否载荷冲突 0否1是',
source_channel VARCHAR(32) DEFAULT NULL COMMENT '来源渠道runtime/manual/agent/import',
create_time DATETIME DEFAULT NULL COMMENT '首次提交时间append-only无 update_time',
PRIMARY KEY (id),
UNIQUE KEY uk_pbl_evidence_idem_code (idem_code),
UNIQUE KEY uk_pbl_evidence_idem_key (tenant_id, idem_key),
KEY idx_pbl_evidence_idem_tid_time (tenant_id, create_time),
KEY idx_pbl_evidence_idem_tid_conf (tenant_id, conflict_flag)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='PBL 证据幂等台账append-only';
-- 31. pbl_evidence_binding 证据与复用域对象绑定(零改表关联)
CREATE TABLE IF NOT EXISTS pbl_evidence_binding (
id BIGINT NOT NULL AUTO_INCREMENT,
bind_code VARCHAR(32) NOT NULL COMMENT '绑定业务主键',
tenant_id VARCHAR(32) NOT NULL COMMENT '租户ID',
evidence_code VARCHAR(32) NOT NULL COMMENT '证据编码',
ref_module VARCHAR(32) NOT NULL COMMENT '复用域模块world/scene/entity/script_engine/scense_runtime/scense/scense_game',
ref_table VARCHAR(64) NOT NULL COMMENT '复用域表名',
ref_id BIGINT DEFAULT NULL COMMENT '复用域行 id',
ref_biz_code VARCHAR(64) DEFAULT NULL COMMENT '复用域业务编码',
bind_role VARCHAR(32) NOT NULL DEFAULT 'source' COMMENT '绑定角色source/target/context',
create_time DATETIME DEFAULT NULL,
update_time DATETIME DEFAULT NULL,
PRIMARY KEY (id),
UNIQUE KEY uk_pbl_evidence_binding_code (bind_code),
KEY idx_pbl_evidence_binding_tid_ev (tenant_id, evidence_code),
KEY idx_pbl_evidence_binding_tid_ref (tenant_id, ref_module, ref_table, ref_biz_code)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='PBL 证据与复用域绑定(零改表)';
-- =====================================================================
-- 模块 pbl_assessment3 表M6Rubric 加权评估与报告)
-- =====================================================================
-- 32. pbl_rubric 量规主表
CREATE TABLE IF NOT EXISTS pbl_rubric (
id BIGINT NOT NULL AUTO_INCREMENT,
rubric_code VARCHAR(32) NOT NULL COMMENT '量规业务主键',
tenant_id VARCHAR(32) NOT NULL COMMENT '租户ID',
bp_code VARCHAR(32) DEFAULT NULL COMMENT '关联蓝图(空=通用量规)',
rubric_name VARCHAR(128) NOT NULL COMMENT '量规名称',
level_count INT NOT NULL DEFAULT 5 COMMENT '等级数(默认 5 级)',
total_weight DECIMAL(8,3) NOT NULL DEFAULT 100.000 COMMENT '总权重',
pass_score DECIMAL(6,2) NOT NULL DEFAULT 60.00 COMMENT '及格分',
grade_rule TEXT DEFAULT NULL COMMENT '等级映射规则 JSON',
is_default TINYINT NOT NULL DEFAULT 0 COMMENT '是否默认量规 0否1是',
version_no INT NOT NULL DEFAULT 1 COMMENT '版本',
status VARCHAR(16) NOT NULL DEFAULT 'active' COMMENT '状态active/disabled',
create_by VARCHAR(32) DEFAULT NULL,
create_time DATETIME DEFAULT NULL,
update_by VARCHAR(32) DEFAULT NULL,
update_time DATETIME DEFAULT NULL,
PRIMARY KEY (id),
UNIQUE KEY uk_pbl_rubric_code (rubric_code),
KEY idx_pbl_rubric_tid_bp (tenant_id, bp_code, status),
KEY idx_pbl_rubric_tid_default (tenant_id, is_default)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='PBL 量规主表';
-- 33. pbl_rubric_criterion 量规评价维度条目
CREATE TABLE IF NOT EXISTS pbl_rubric_criterion (
id BIGINT NOT NULL AUTO_INCREMENT,
crit_code VARCHAR(32) NOT NULL COMMENT '条目业务主键',
tenant_id VARCHAR(32) NOT NULL COMMENT '租户ID',
rubric_code VARCHAR(32) NOT NULL COMMENT '量规编码',
obj_code VARCHAR(32) DEFAULT NULL COMMENT '关联学习目标子对象',
crit_name VARCHAR(128) NOT NULL COMMENT '维度名称',
crit_desc VARCHAR(1024) DEFAULT NULL COMMENT '维度说明',
weight DECIMAL(6,3) NOT NULL DEFAULT 1.000 COMMENT '权重',
level_desc TEXT DEFAULT NULL COMMENT '各等级描述 JSONlevel -> desc',
max_score DECIMAL(6,2) NOT NULL DEFAULT 5.00 COMMENT '最高分',
evidence_required TINYINT NOT NULL DEFAULT 1 COMMENT '是否必须有证据支撑 0否1是',
sort_no INT NOT NULL DEFAULT 0 COMMENT '排序',
create_time DATETIME DEFAULT NULL,
update_time DATETIME DEFAULT NULL,
PRIMARY KEY (id),
UNIQUE KEY uk_pbl_rubric_crit_code (crit_code),
KEY idx_pbl_rubric_crit_tid_rub (tenant_id, rubric_code, sort_no),
KEY idx_pbl_rubric_crit_tid_obj (tenant_id, obj_code)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='PBL 量规评价维度';
-- 34. pbl_assessment_report 评估报告
CREATE TABLE IF NOT EXISTS pbl_assessment_report (
id BIGINT NOT NULL AUTO_INCREMENT,
report_code VARCHAR(32) NOT NULL COMMENT '报告业务主键',
tenant_id VARCHAR(32) NOT NULL COMMENT '租户ID',
bp_code VARCHAR(32) NOT NULL COMMENT '蓝图编码',
rubric_code VARCHAR(32) NOT NULL COMMENT '量规编码',
team_code VARCHAR(32) DEFAULT NULL COMMENT '团队编码',
student_code VARCHAR(32) DEFAULT NULL COMMENT '学生编码(团队报告时为空)',
scope_type VARCHAR(16) NOT NULL DEFAULT 'team' COMMENT '范围team/student/blueprint',
score_total DECIMAL(6,2) NOT NULL DEFAULT 0.00 COMMENT '加权总分(可复算)',
grade_code VARCHAR(16) DEFAULT NULL COMMENT '等级 A/B/C/D/E',
detail_json LONGTEXT DEFAULT NULL COMMENT '逐维度得分明细 JSON含证据引用',
evidence_count INT NOT NULL DEFAULT 0 COMMENT '引用证据数',
missing_evidence_count INT NOT NULL DEFAULT 0 COMMENT '缺证据维度数',
assessor_type VARCHAR(16) NOT NULL DEFAULT 'agent' COMMENT '评估者agent/user/mixed',
assessor_code VARCHAR(32) DEFAULT NULL COMMENT '评估者编码',
report_state VARCHAR(16) NOT NULL DEFAULT 'draft' COMMENT '状态draft/published/archived',
calc_checksum VARCHAR(64) DEFAULT NULL COMMENT '复算校验 sha256',
create_by VARCHAR(32) DEFAULT NULL,
create_time DATETIME DEFAULT NULL,
update_by VARCHAR(32) DEFAULT NULL,
update_time DATETIME DEFAULT NULL,
PRIMARY KEY (id),
UNIQUE KEY uk_pbl_assess_report_code (report_code),
KEY idx_pbl_assess_report_tid_bp (tenant_id, bp_code, scope_type),
KEY idx_pbl_assess_report_tid_team (tenant_id, team_code, student_code),
KEY idx_pbl_assess_report_tid_state (tenant_id, report_state),
KEY idx_pbl_assess_report_tid_grade (tenant_id, grade_code)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='PBL 评估报告';
-- =====================================================================
-- 模块 pbl_domain_ext1 表M8world/scene/entity 租户·班级·团队关联,不改基表)
-- =====================================================================
-- 35. pbl_domain_binding 复用域对象绑定(零改表唯一关联落点)
CREATE TABLE IF NOT EXISTS pbl_domain_binding (
id BIGINT NOT NULL AUTO_INCREMENT,
bind_code VARCHAR(32) NOT NULL COMMENT '绑定业务主键',
tenant_id VARCHAR(32) NOT NULL COMMENT '租户ID',
bind_kind VARCHAR(32) NOT NULL COMMENT '绑定种类tenant_world/class_scene/team_entity/bp_script/session_worldappcodes_kv: pbl_bind_kind',
class_code VARCHAR(32) DEFAULT NULL COMMENT '班级编码',
team_code VARCHAR(32) DEFAULT NULL COMMENT '团队编码',
bp_code VARCHAR(32) DEFAULT NULL COMMENT '蓝图编码',
session_code VARCHAR(32) DEFAULT NULL COMMENT '运行会话编码',
ref_module VARCHAR(32) NOT NULL COMMENT '复用域模块world/scene/entity/script_engine/scense_runtime/scense/scense_game',
ref_table VARCHAR(64) NOT NULL COMMENT '复用域表名',
ref_id BIGINT DEFAULT NULL COMMENT '复用域行 id',
ref_biz_code VARCHAR(64) DEFAULT NULL COMMENT '复用域业务编码',
access_mode VARCHAR(16) NOT NULL DEFAULT 'readonly' COMMENT '访问模式readonlyPhase 0/1 唯一合法值,写保护)',
bind_state VARCHAR(16) NOT NULL DEFAULT 'active' COMMENT '状态active/released',
extra_json TEXT DEFAULT NULL COMMENT '扩展 JSON',
create_by VARCHAR(32) DEFAULT NULL,
create_time DATETIME DEFAULT NULL,
update_by VARCHAR(32) DEFAULT NULL,
update_time DATETIME DEFAULT NULL,
PRIMARY KEY (id),
UNIQUE KEY uk_pbl_domain_binding_code (bind_code),
UNIQUE KEY uk_pbl_domain_binding_ref (tenant_id, bind_kind, ref_module, ref_table, ref_biz_code),
KEY idx_pbl_domain_binding_tid_class (tenant_id, class_code, team_code),
KEY idx_pbl_domain_binding_tid_bp (tenant_id, bp_code),
KEY idx_pbl_domain_binding_tid_sess (tenant_id, session_code),
KEY idx_pbl_domain_binding_tid_ref (tenant_id, ref_module, ref_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='PBL 复用域绑定(零改表)';
-- =====================================================================
-- 模块 pbl_analytics1 表M10分析看板快照append-only
-- =====================================================================
-- 36. pbl_analytics_snapshot 分析快照append-only
CREATE TABLE IF NOT EXISTS pbl_analytics_snapshot (
id BIGINT NOT NULL AUTO_INCREMENT,
snap_code VARCHAR(32) NOT NULL COMMENT '快照业务主键',
tenant_id VARCHAR(32) NOT NULL COMMENT '租户ID',
metric_group VARCHAR(32) NOT NULL COMMENT '指标组blueprint/validation/compile/runtime/evidence/assessmentappcodes_kv: pbl_metric_group',
scope_type VARCHAR(16) NOT NULL DEFAULT 'tenant' COMMENT '范围tenant/class/team/blueprint',
scope_code VARCHAR(32) DEFAULT NULL COMMENT '范围对象编码',
period_key VARCHAR(16) NOT NULL COMMENT '周期键2026-09 / 2026-W38 / 2026-09-15',
metrics_json LONGTEXT DEFAULT NULL COMMENT '指标 JSON计数/均值/分布)',
anonymized TINYINT NOT NULL DEFAULT 1 COMMENT '是否匿名聚合 0否1是KDB 侧强制 1',
sample_size INT NOT NULL DEFAULT 0 COMMENT '样本量',
computed_at DATETIME DEFAULT NULL COMMENT '计算时间',
create_time DATETIME DEFAULT NULL COMMENT '入库时间append-only无 update_time',
PRIMARY KEY (id),
UNIQUE KEY uk_pbl_analytics_snap_code (snap_code),
UNIQUE KEY uk_pbl_analytics_snap_dim (tenant_id, metric_group, scope_type, scope_code, period_key),
KEY idx_pbl_analytics_snap_tid_group (tenant_id, metric_group, period_key),
KEY idx_pbl_analytics_snap_tid_scope (tenant_id, scope_type, scope_code)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci COMMENT='PBL 分析看板快照append-only';
SET FOREIGN_KEY_CHECKS = 1;
-- =====================================================================
-- 契约自检(供 build.sh / QC grep 核验)
-- 表总数36pbl_governance 3 + pbl_blueprint 11 + pbl_template 2 + pbl_validation 3
-- + pbl_compiler 4 + pbl_agent_runtime 4 + pbl_evidence 4 + pbl_assessment 3
-- + pbl_domain_ext 1 + pbl_analytics 1 = 36
-- append-only 表11无 update_time
-- pbl_audit_log / pbl_blueprint_version / pbl_subobject_review / pbl_blueprint_publish
-- pbl_validation_finding / pbl_compile_log / pbl_agent_message / pbl_agent_tool_call
-- pbl_agent_arbitration / pbl_evidence_idem / pbl_analytics_snapshot
-- 零命中项mariadb 方言硬约束):
-- FOREIGN KEY / REFERENCES / ENUM( / SERIAL / BIGSERIAL / nextval / TIMESTAMP
-- 全部索引以 tenant_id 打头;每表 id BIGINT NOT NULL AUTO_INCREMENT + xxx_code 唯一业务主键。
-- =====================================================================