mirror of
https://github.com/QwenLM/qwen-code.git
synced 2026-11-07 06:19:43 -10:00
refactor(managed-agent): align shared MySQL schema conventions (#16143)
* docs(managed-agent): document database tables and columns * refactor(managed-agent): align shared MySQL schema conventions
This commit is contained in:
1 parent
6fe83a8245
commit
b1cd4ac0c6
150 files changed
+2457
-1750
No files matched your search
@@ -0,0 +1,94 @@
|
||||
# Managed schema conventions
|
||||
|
||||
[English](2026-11-02-managed-schema-conventions.md) | [简体中文](2026-11-02-managed-schema-conventions.zh-CN.md)
|
||||
|
||||
## Scope
|
||||
|
||||
Align the shared pre-release V1 database baseline with the MySQL conventions in
|
||||
Alibaba's Java Development Manual (Huangshan edition). Server and Broker must
|
||||
continue to initialize and validate the same catalog on MySQL 8.4 and H2.
|
||||
Physical deletion and retention policies are outside this change.
|
||||
|
||||
Reference: the MySQL chapter, printed pages 32–35, in the
|
||||
[official Huangshan manual](<https://github.com/alibaba/p3c/blob/6c59c8c36ecd8722c712d5685b8c3822c1c8b030/Java开发手册(黄山版).pdf>).
|
||||
|
||||
## Decisions
|
||||
|
||||
- Give every table an unsigned auto-increment, unique `id`. Use it as the primary
|
||||
key except on `ma_session` and `ma_tenant_guard`, which retain their original
|
||||
business primary keys `(tenant_id, session_id)` and `(tenant_key, guard_domain)`.
|
||||
These two tables coordinate existing records through upserts. With `id` as
|
||||
their clustered primary key, native MySQL captured `PRIMARY` supremum locks
|
||||
blocking unrelated Sessions, tenants and guard domains during acquisition.
|
||||
Keep their business clustering and a separate unique `id` index to preserve
|
||||
the existing creation and locking-read protocol. The other 36 tables keep `id`
|
||||
primary keys and unique business keys. Business identities, tenant scoping,
|
||||
idempotency, and fencing continue to use the original business keys.
|
||||
- Keep the existing `gmt_create` and `gmt_modified` names and all
|
||||
epoch-millisecond timestamp fields. Application clocks, lease deadlines, and
|
||||
ordered pagination depend on the current timestamp contracts.
|
||||
Do not add duplicate timestamps. Database row IDs are excluded from domain
|
||||
projections and CSI evidence.
|
||||
- Use `is_` names and unsigned tiny integers for boolean columns. Keep nullable
|
||||
flags nullable and generated flags generated. Update SQL consumers and boolean
|
||||
row decoding together; serialized API and journal payload names stay intact.
|
||||
Range checks retain the 0/1 domain on both engines without H2's connection-bound
|
||||
optimization of constant `IN` lists.
|
||||
- Use unsigned integer declarations for nonnegative counters, versions,
|
||||
generations, sizes, and ordinals. Validate signedness for every integer type on
|
||||
MySQL. H2 ignores unsigned storage ranges, so native MySQL evidence remains
|
||||
required. Retain the nonnegative CHECK constraints for H2. MySQL and MariaDB
|
||||
require `STRICT_TRANS_TABLES` or `STRICT_ALL_TABLES` in global and session
|
||||
`sql_mode` to reject ordinary out-of-range unsigned writes instead of clamping
|
||||
them; `IGNORE` writes can downgrade these errors to warnings.
|
||||
- Name ordinary indexes with `idx_` and unique constraints with `uk_`. MySQL
|
||||
always exposes the primary index as `PRIMARY`; the DDL gives its constraint a
|
||||
table-specific `pk_` name where supported.
|
||||
- Remove database foreign keys. Existing application admission, ownership, and
|
||||
transaction checks continue to govern related writes. Preserve all former
|
||||
parent and child identity indexes and business uniqueness constraints.
|
||||
- Store fixed-width SHA-256 strings in `CHAR`. Keep shared receipt and operation
|
||||
digest columns variable-width when their namespaces store different digest
|
||||
formats.
|
||||
- Keep full indexes for short discriminator strings: their complete values are
|
||||
needed by covering and ordered queries, and shortening them loses information.
|
||||
Use a bounded prefix for the longer host identity lookup. MySQL executable
|
||||
comments express its prefix while H2 uses the full-column equivalent.
|
||||
|
||||
## Catalog validation
|
||||
|
||||
The canonical resource remains V1. Existing development catalogs must be
|
||||
recreated; no repair, migration, or history rewrite is introduced. Validation
|
||||
must reject missing row IDs, incorrect primary or business keys, missing
|
||||
auto-increment behavior, changed integer types or signedness, and changed index
|
||||
prefixes. It must continue rejecting legacy, partial, and foreign catalogs.
|
||||
Shared Server/Broker admission and validation refuse non-strict MySQL or MariaDB
|
||||
before schema writes. The database defaults and every application connection
|
||||
must retain strict mode during operation; the startup check does not enforce
|
||||
later administrative or connection-mode changes, and does not change SQL modes.
|
||||
|
||||
## Verification and acceptance
|
||||
|
||||
- Exercise Broker and Flyway initialization, repeated validation, row ID
|
||||
generation on fresh H2 and disposable MySQL 8.4 databases.
|
||||
- Independently verify all 38 generated IDs are unique, both coordination tables
|
||||
retain their ordered business primary keys, and the other 36 retain `id`
|
||||
primary keys. Native concurrency checks must preserve same-key exclusion,
|
||||
independent guard domains/tenants/Sessions, concurrent first creation,
|
||||
committed migration-fence visibility, SSH overlap arbitration, publication
|
||||
ordering and bounded lifecycle completion. Existing failures remain unresolved
|
||||
until the corrected revision passes the required native gates.
|
||||
- Verify that duplicate business identities still fail, flags retain their
|
||||
values and nullability, and representative Server/Broker stores still read and
|
||||
write the renamed columns.
|
||||
- Check snapshot/projection contracts, schema drift rejection, and relevant
|
||||
queue, publication, scheduling, Workspace and Runtime consumers.
|
||||
- Reject non-strict global or session modes before initialization or validation,
|
||||
and verify ordinary negative unsigned writes fail under both supported strict modes on
|
||||
MySQL without changing the server's global settings in the test.
|
||||
- Run focused local Maven checks within the module's shared validation budget;
|
||||
report full-suite and native-process gaps for CI.
|
||||
|
||||
Acceptance remains pending until the checks above and the required CI gates
|
||||
pass. Changing row layout, removing foreign keys, and updating CSI field names
|
||||
requires a fresh development installation under the existing pre-release policy.
|
||||
@@ -0,0 +1,65 @@
|
||||
# Managed 数据库规约
|
||||
|
||||
[English](2026-11-02-managed-schema-conventions.md) | [简体中文](2026-11-02-managed-schema-conventions.zh-CN.md)
|
||||
|
||||
## 范围
|
||||
|
||||
按照《阿里巴巴 Java 开发手册(黄山版)》的 MySQL 规约整理共享的发布前 V1 数据库基线。
|
||||
Server 和 Broker 必须继续在 MySQL 8.4 与 H2 上初始化和校验同一套数据库。
|
||||
物理删除及保留期策略不在本次修改范围内。
|
||||
|
||||
参考来源为[官方黄山版手册](<https://github.com/alibaba/p3c/blob/6c59c8c36ecd8722c712d5685b8c3822c1c8b030/Java开发手册(黄山版).pdf>)
|
||||
中印刷页码 32–35 页的 MySQL 章节。
|
||||
|
||||
## 决策
|
||||
|
||||
- 每张表增加无符号、自增且唯一的 `id`,除 `ma_session` 和 `ma_tenant_guard` 外均用作主键。
|
||||
这两张表保留原业务主键 `(tenant_id, session_id)` 和 `(tenant_key, guard_domain)`。
|
||||
两表通过 upsert 协调已有记录;以 `id` 作为聚簇主键时,原生 MySQL 已捕获取锁过程中的
|
||||
`PRIMARY` supremum 锁,阻塞了无关 Session、租户及锁域。
|
||||
保留业务聚簇和单独的 `id` 唯一索引,以保留现有首次创建及加锁读取协议。
|
||||
其余 36 张表继续使用 `id` 主键和业务唯一键。
|
||||
业务身份、租户范围、幂等及防止旧执行者写入的检查继续使用原业务键。
|
||||
- 沿用现有 `gmt_create`、`gmt_modified` 命名及所有毫秒时间字段。
|
||||
应用时钟、租约截止时间及有序分页依赖现有时间戳约定。不新增重复时间字段。
|
||||
数据库生成的行 ID 不进入领域投影和 CSI 证据。
|
||||
- 布尔字段采用 `is_` 命名及无符号微整型。保留可空标志的可空性、派生标志的计算方式。
|
||||
同步调整 SQL 消费者和行数据的布尔解码;序列化 API 及日志载荷的字段名保持原样。
|
||||
用范围检查在两种数据库上保留 0/1 值域,避免 H2 对常量 `IN` 列表的优化依赖初始化连接。
|
||||
- 非负计数、版本、代次、大小及序号使用无符号整数声明。
|
||||
MySQL 校验覆盖所有整数类型的符号属性。H2 忽略无符号存储范围,因此仍需真实 MySQL 验证。
|
||||
保留非负 CHECK 约束用于 H2。MySQL 和 MariaDB 的全局及会话 `sql_mode` 必须包含
|
||||
`STRICT_TRANS_TABLES` 或 `STRICT_ALL_TABLES`,让普通的越界无符号写入被拒绝,而不是被截断;
|
||||
`IGNORE` 写入仍可能把这类错误降级为警告。
|
||||
- 普通索引使用 `idx_` 前缀,唯一约束使用 `uk_` 前缀。
|
||||
MySQL 始终将主键索引显示为 `PRIMARY`;DDL 在支持时为主键约束声明表内唯一的 `pk_` 名称。
|
||||
- 移除数据库外键。现有应用准入、所有权及事务检查继续控制关联写入。
|
||||
保留原父子身份索引和业务唯一约束。
|
||||
- 固定宽度 SHA-256 字符串使用 `CHAR`。多个命名空间存储不同摘要格式的共享回执和操作摘要列,
|
||||
继续使用变长类型。
|
||||
- 短判别字符串保留完整索引:覆盖查询和有序查询需要完整值,截短会丢失信息。
|
||||
较长的主机身份查询使用有界前缀。通过 MySQL 可执行注释声明前缀,H2 使用对应完整列索引。
|
||||
|
||||
## 数据库校验
|
||||
|
||||
标准资源继续使用 V1。已有开发数据库需要重建,不引入修复、升级迁移或历史改写。
|
||||
校验必须拒绝缺失的行 ID、错误的主键或业务唯一键、缺少自增行为、错误的整数类型或符号属性,
|
||||
以及变化的索引前缀。继续拒绝旧版、不完整及包含其他业务对象的数据库。
|
||||
Server/Broker 共享准入和校验入口,在写入结构前拒绝非严格模式的 MySQL 或 MariaDB。
|
||||
运行期间数据库默认值及每个应用连接都必须保持严格模式;启动检查不控制之后的管理员或连接模式变更,
|
||||
也不会修改 SQL 模式。
|
||||
|
||||
## 验证与验收
|
||||
|
||||
- 在新建 H2 和临时 MySQL 8.4 数据库上验证 Broker、Flyway 初始化、重复校验、行 ID 生成行为。
|
||||
- 独立验证全部 38 张表生成的 ID 均唯一,两张协调表保留顺序正确的业务主键,其余 36 张表保留 `id` 主键。
|
||||
原生并发检查须验证同键互斥、不同锁域/租户/Session 互不阻塞、并发首次创建、等待后可见已提交迁移栅栏、
|
||||
SSH 目录重叠仲裁、发布锁顺序及有界生命周期完成。修复版本通过必需原生门禁前,原失败仍保留为未解决。
|
||||
- 验证重复业务身份仍被拒绝,标志值及可空性保持一致,代表性的 Server/Broker 存储仍能读写更名后的列。
|
||||
- 检查快照和投影约定、结构偏移拒绝行为,以及相关队列、发布、调度、Workspace 和 Runtime 消费者。
|
||||
- 在初始化或校验前拒绝非严格的全局或会话模式;在 MySQL 的两种严格模式下验证普通负数无符号写入被拒绝,
|
||||
测试不修改服务器全局设置。
|
||||
- 在模块共享验证预算内运行针对性的本地 Maven 检查;将全量测试及原生进程验证缺口交给 CI 并明确记录。
|
||||
|
||||
上述检查及必需 CI 门禁通过前,验收仍待完成。
|
||||
行结构变化、移除外键及 CSI 字段名调整,遵循现有发布前策略,需要全新安装开发环境。
|
||||
@@ -0,0 +1,65 @@
|
||||
/**
|
||||
* @license
|
||||
* Copyright 2026 Qwen Team
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
import { describe, expect, it } from 'vitest';
|
||||
import { projectEvents } from './hosted-sse-observer.js';
|
||||
|
||||
describe.each([
|
||||
{
|
||||
surface: 'public',
|
||||
expected: {
|
||||
schema_version: 1,
|
||||
projection_version: 1,
|
||||
sequence: 7,
|
||||
event_id: 'event',
|
||||
session_id: 'session',
|
||||
turn_id: 'turn',
|
||||
type: 'turn.completed',
|
||||
created_at: 1_700_000_000,
|
||||
data: { status: 'completed' },
|
||||
},
|
||||
},
|
||||
{
|
||||
surface: 'web',
|
||||
expected: {
|
||||
schemaVersion: 1,
|
||||
projectionVersion: 1,
|
||||
sequence: 7,
|
||||
eventId: 'event',
|
||||
sessionId: 'session',
|
||||
turnId: 'turn',
|
||||
type: 'turn.completed',
|
||||
createdAt: 1_700_000_000_123,
|
||||
data: { status: 'completed' },
|
||||
},
|
||||
},
|
||||
])('projectEvents ($surface)', ({ surface, expected }) => {
|
||||
it.each([
|
||||
[false, false],
|
||||
[0, false],
|
||||
[true, true],
|
||||
[1, true],
|
||||
])('projects the canonical SQL terminal flag %s', (flag, terminal) => {
|
||||
const rows = [
|
||||
{
|
||||
schema_version: 1,
|
||||
projection_version: 1,
|
||||
sequence_id: 7,
|
||||
event_id: 'event',
|
||||
session_id: 'session',
|
||||
turn_id: 'turn',
|
||||
item_id: null,
|
||||
content_part_id: null,
|
||||
event_type: 'turn.completed',
|
||||
gmt_create: 1_700_000_000_123,
|
||||
data_json: '{"status":"completed"}',
|
||||
is_terminal: flag,
|
||||
},
|
||||
];
|
||||
|
||||
expect(projectEvents(rows, surface)).toEqual([{ ...expected, terminal }]);
|
||||
});
|
||||
});
|
||||
@@ -191,7 +191,7 @@ export function projectEvents(
|
||||
? Math.floor(Number(row['gmt_create']) / 1000)
|
||||
: row['gmt_create'],
|
||||
data: JSON.parse(String(row['data_json'])),
|
||||
terminal: Boolean(row['terminal']),
|
||||
terminal: Boolean(row['is_terminal']),
|
||||
};
|
||||
return Object.fromEntries(
|
||||
Object.entries(fields)
|
||||
|
||||
+1
-1
@@ -99,7 +99,7 @@
|
||||
"test:integration:sandbox:docker": "cross-env QWEN_SANDBOX=docker npm run build:sandbox && QWEN_SANDBOX=docker vitest run --root ./integration-tests",
|
||||
"test:integration:sandbox:podman": "cross-env QWEN_SANDBOX=podman vitest run --root ./integration-tests",
|
||||
"test:integration:hosted:sandbox:none": "cross-env QWEN_SANDBOX=false vitest run --root ./integration-tests --config ./vitest.hosted.config.ts",
|
||||
"test:integration:no-ak:sandbox:none": "cross-env QWEN_SANDBOX=false vitest run --root ./integration-tests --poolOptions.forks.maxForks 2 ./fake-openai-server.test.ts ./test-helper.test.ts ./chat-transcript-contract.test.ts ./skill-hooks-invocation-parity.test.ts ./skill-hooks-resume.test.ts ./qwen-live-m4-acp-call.test.ts ./qwen-live-m4-acp-permission.test.ts ./qwen-live-m4-acp-steering.test.ts ./qwen-live-m4-acp-multibackend.test.ts ./qwen-live-m1-call.test.ts ./qwen-live-m2-inject.test.ts ./qwen-live-m2-permission.test.ts ./qwen-live-m2-steering.test.ts ./cli/_prompt-latency-policy.test.ts ./cli/agent-loop-parity.test.ts ./cli/acp-agent-loop-parity.test.ts ./cli/hosted-harness-process.test.ts ./cli/daemon-invocation-context.test.ts ./cli/headless-workflow-skill.test.ts ./cli/workflow-ancestor-discovery.test.ts ./cli/daemon-workflow-ancestor-trust.test.ts ./cli/workflow-intent.test.ts ./cli/workflow-mode.test.ts ./cli/acp-workflow-mode.test.ts ./cli/daemon-workflow-intent.test.ts ./cli/daemon-workflow-mode.test.ts ./cli/list_directory.test.ts ./cli/tool-hook-context.test.ts ./cli/tool-hook-updated-input.test.ts ./cli/qwen-serve-routes.test.ts ./cli/qwen-serve-session-cd.test.ts ./cli/qwen-serve-streaming.test.ts ./cli/qwen-serve-standalone-concurrency.test.ts ./interactive/workflow-completion.test.ts ./interactive/workflow-intent.test.ts ./interactive/workflow-mode.test.ts ./interactive/mods-tool-middleware.test.ts ./interactive/statusline-parity.test.ts ./interactive/tui-editor-parity.test.ts ./interactive/tui-input-ownership.test.ts ./sdk-typescript/abort-and-lifecycle.test.ts ./sdk-typescript/permission-control.test.ts ./sdk-typescript/sdk-mcp-server.test.ts ./sdk-typescript/subagents.test.ts ./sdk-typescript/system-control.test.ts ./sdk-typescript/tool-control.test.ts ./sdk-typescript/workflow-intent.test.ts ./sdk-typescript/workflow-mode.test.ts",
|
||||
"test:integration:no-ak:sandbox:none": "cross-env QWEN_SANDBOX=false vitest run --root ./integration-tests --poolOptions.forks.maxForks 2 ./fake-openai-server.test.ts ./test-helper.test.ts ./chat-transcript-contract.test.ts ./skill-hooks-invocation-parity.test.ts ./skill-hooks-resume.test.ts ./qwen-live-m4-acp-call.test.ts ./qwen-live-m4-acp-permission.test.ts ./qwen-live-m4-acp-steering.test.ts ./qwen-live-m4-acp-multibackend.test.ts ./qwen-live-m1-call.test.ts ./qwen-live-m2-inject.test.ts ./qwen-live-m2-permission.test.ts ./qwen-live-m2-steering.test.ts ./cli/_prompt-latency-policy.test.ts ./cli/agent-loop-parity.test.ts ./cli/acp-agent-loop-parity.test.ts ./cli/hosted-harness-process.test.ts ./cli/daemon-invocation-context.test.ts ./cli/headless-workflow-skill.test.ts ./cli/workflow-ancestor-discovery.test.ts ./cli/daemon-workflow-ancestor-trust.test.ts ./cli/workflow-intent.test.ts ./cli/workflow-mode.test.ts ./cli/acp-workflow-mode.test.ts ./cli/daemon-workflow-intent.test.ts ./cli/daemon-workflow-mode.test.ts ./cli/list_directory.test.ts ./cli/tool-hook-context.test.ts ./cli/tool-hook-updated-input.test.ts ./cli/qwen-serve-routes.test.ts ./cli/qwen-serve-session-cd.test.ts ./cli/qwen-serve-streaming.test.ts ./cli/qwen-serve-standalone-concurrency.test.ts ./helpers/hosted-sse-observer.test.ts ./interactive/workflow-completion.test.ts ./interactive/workflow-intent.test.ts ./interactive/workflow-mode.test.ts ./interactive/mods-tool-middleware.test.ts ./interactive/statusline-parity.test.ts ./interactive/tui-editor-parity.test.ts ./interactive/tui-input-ownership.test.ts ./sdk-typescript/abort-and-lifecycle.test.ts ./sdk-typescript/permission-control.test.ts ./sdk-typescript/sdk-mcp-server.test.ts ./sdk-typescript/subagents.test.ts ./sdk-typescript/system-control.test.ts ./sdk-typescript/tool-control.test.ts ./sdk-typescript/workflow-intent.test.ts ./sdk-typescript/workflow-mode.test.ts",
|
||||
"test:integration:sdk:sandbox:none": "cross-env QWEN_SANDBOX=false vitest run --root ./integration-tests --poolOptions.forks.maxForks 2 sdk-typescript",
|
||||
"test:integration:sdk:sandbox:docker": "cross-env QWEN_SANDBOX=docker npm run build:sandbox && QWEN_SANDBOX=docker vitest run --root ./integration-tests --poolOptions.forks.maxForks 2 sdk-typescript",
|
||||
"test:sdk:python": "python3 -m pytest -c packages/sdk-python/pyproject.toml packages/sdk-python/tests -q",
|
||||
|
||||
@@ -332,7 +332,16 @@ reclaim anything. If the database check fails, capacity remains skipped.
|
||||
MySQL is the supported database family; full integration CI uses MySQL 8.4.
|
||||
MariaDB no longer has a CI lane or an ongoing compatibility guarantee.
|
||||
Existing dialect handling remains in place; this change does not reject
|
||||
connections that previously worked or introduce a catalog migration.
|
||||
MariaDB solely by product name or introduce a catalog migration.
|
||||
|
||||
MySQL and MariaDB require `STRICT_TRANS_TABLES` or `STRICT_ALL_TABLES` in both
|
||||
global and session `sql_mode`. Schema admission and validation reject non-strict
|
||||
connections before schema writes. Strict mode prevents ordinary writes to unsigned
|
||||
counters from silently clamping negative values to zero; `IGNORE` writes can
|
||||
downgrade these errors to warnings. Configure the database defaults and
|
||||
every application connection to retain strict mode throughout operation; a
|
||||
startup check does not police later administrative or connection-mode changes.
|
||||
The application does not change the server's SQL mode.
|
||||
|
||||
Run the packaged CLI with `qwen serve --profile hosted-harness` as a separate
|
||||
process (the credentialed launch is spelled out in the Full WebShell
|
||||
|
||||
+2
-2
@@ -47,7 +47,7 @@ final class AgentEventJournal {
|
||||
result.getString("turn_id"),
|
||||
result.getString("event_type"),
|
||||
storeRows.readMap(result.getString("data_json")),
|
||||
result.getBoolean("terminal"),
|
||||
result.getBoolean("is_terminal"),
|
||||
result.getString("source_key"),
|
||||
result.getLong("gmt_create"),
|
||||
result.getInt("schema_version"),
|
||||
@@ -58,7 +58,7 @@ final class AgentEventJournal {
|
||||
|
||||
static final String INSERT_EVENT = "INSERT INTO ma_public_event"
|
||||
+ " (tenant_id, session_id, sequence_id, event_id, turn_id,"
|
||||
+ " event_type, data_json, terminal, source_key, gmt_create,"
|
||||
+ " event_type, data_json, is_terminal, source_key, gmt_create,"
|
||||
+ " schema_version, projection_version, item_id, content_part_id)"
|
||||
+ " VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
|
||||
|
||||
|
||||
+3
-3
@@ -678,14 +678,14 @@ final class AgentExecutionOperations {
|
||||
+ " <= ? AND EXISTS (SELECT 1 FROM ma_session private_scope"
|
||||
+ " WHERE private_scope.tenant_id = ma_operation.tenant_id AND"
|
||||
+ " private_scope.session_id = ma_operation.session_id AND"
|
||||
+ " private_scope.csi_guard = FALSE) ORDER BY available_at"
|
||||
+ " private_scope.is_csi_guard = FALSE) ORDER BY available_at"
|
||||
+ " LIMIT ?",
|
||||
lifecycleOperations.operationTargetMapper,
|
||||
now,
|
||||
limit));
|
||||
if (targets.size() < limit) {
|
||||
targets.addAll(jdbc.query(
|
||||
"SELECT tenant_id, session_id, operation_id FROM ma_operation WHERE operation_kind = 'TASK_CANCEL' AND delivery_state = 'LEASED' AND claim_until < " + ManagedSchemaTime.SQL_NOW + " AND EXISTS (SELECT 1 FROM ma_session private_scope WHERE private_scope.tenant_id = ma_operation.tenant_id AND private_scope.session_id = ma_operation.session_id AND private_scope.csi_guard = FALSE) ORDER BY claim_until LIMIT ?",
|
||||
"SELECT tenant_id, session_id, operation_id FROM ma_operation WHERE operation_kind = 'TASK_CANCEL' AND delivery_state = 'LEASED' AND claim_until < " + ManagedSchemaTime.SQL_NOW + " AND EXISTS (SELECT 1 FROM ma_session private_scope WHERE private_scope.tenant_id = ma_operation.tenant_id AND private_scope.session_id = ma_operation.session_id AND private_scope.is_csi_guard = FALSE) ORDER BY claim_until LIMIT ?",
|
||||
lifecycleOperations.operationTargetMapper, limit - targets.size()));
|
||||
}
|
||||
return List.copyOf(targets);
|
||||
@@ -700,7 +700,7 @@ final class AgentExecutionOperations {
|
||||
+ " 'RECOVERY_BLOCKED' AND available_at <= ? AND delivery_state = 'BLOCKED'"
|
||||
+ " AND EXISTS (SELECT 1 FROM ma_session s WHERE s.tenant_id ="
|
||||
+ " ma_operation.tenant_id AND s.session_id = ma_operation.session_id AND"
|
||||
+ " s.csi_guard = FALSE) ORDER BY available_at LIMIT ?",
|
||||
+ " s.is_csi_guard = FALSE) ORDER BY available_at LIMIT ?",
|
||||
(result, row) -> new ParkedOperation(result.getString("tenant_id"),
|
||||
result.getString("session_id"), result.getString("operation_id"),
|
||||
result.getString("operation_kind")),
|
||||
|
||||
+2
-2
@@ -584,7 +584,7 @@ final class AgentLifecycleOperations {
|
||||
+ " 'BLOCKED') AND available_at <= ? AND EXISTS (SELECT 1 FROM"
|
||||
+ " ma_session private_scope WHERE private_scope.tenant_id ="
|
||||
+ " ma_operation.tenant_id AND private_scope.session_id ="
|
||||
+ " ma_operation.session_id AND private_scope.csi_guard ="
|
||||
+ " ma_operation.session_id AND private_scope.is_csi_guard ="
|
||||
+ " FALSE) ORDER BY available_at LIMIT ?",
|
||||
operationTargetMapper,
|
||||
now,
|
||||
@@ -592,7 +592,7 @@ final class AgentLifecycleOperations {
|
||||
if (targets.size() < limit) {
|
||||
targets.addAll(
|
||||
jdbc.query(
|
||||
"SELECT tenant_id, session_id, operation_id FROM ma_operation WHERE operation_kind IN ('CLOSE', 'ARCHIVE', 'DELETE', 'CWD_CHANGE') AND state = 'RUNNING' AND delivery_state = 'LEASED' AND claim_until < " + ManagedSchemaTime.SQL_NOW + " AND EXISTS (SELECT 1 FROM ma_session private_scope WHERE private_scope.tenant_id = ma_operation.tenant_id AND private_scope.session_id = ma_operation.session_id AND private_scope.csi_guard = FALSE) ORDER BY claim_until LIMIT ?",
|
||||
"SELECT tenant_id, session_id, operation_id FROM ma_operation WHERE operation_kind IN ('CLOSE', 'ARCHIVE', 'DELETE', 'CWD_CHANGE') AND state = 'RUNNING' AND delivery_state = 'LEASED' AND claim_until < " + ManagedSchemaTime.SQL_NOW + " AND EXISTS (SELECT 1 FROM ma_session private_scope WHERE private_scope.tenant_id = ma_operation.tenant_id AND private_scope.session_id = ma_operation.session_id AND private_scope.is_csi_guard = FALSE) ORDER BY claim_until LIMIT ?",
|
||||
operationTargetMapper,
|
||||
limit - targets.size()));
|
||||
}
|
||||
|
||||
+3
-3
@@ -78,7 +78,7 @@ final class AgentMessageProjection {
|
||||
String cursor, int limit, boolean backward, long afterSequence) {
|
||||
storeRows.requireSession(tenantId, sessionId);
|
||||
ManagedLegacySessionGuard.requireLegacyMutation(Boolean.TRUE.equals(jdbc.queryForObject(
|
||||
"SELECT csi_guard FROM ma_session WHERE tenant_id = ? AND session_id = ?",
|
||||
"SELECT is_csi_guard FROM ma_session WHERE tenant_id = ? AND session_id = ?",
|
||||
Boolean.class, tenantId, sessionId)));
|
||||
if (limit < 1 || limit > 100) {
|
||||
throw new ManagedAgentException(400, "invalid_limit",
|
||||
@@ -293,7 +293,7 @@ final class AgentMessageProjection {
|
||||
+ " AND s.covered_sequence > s.replay_floor_sequence"
|
||||
+ " AND EXISTS (SELECT 1 FROM ma_session private_scope WHERE"
|
||||
+ " private_scope.tenant_id = s.tenant_id AND private_scope.session_id = s.session_id"
|
||||
+ " AND private_scope.csi_guard = FALSE)"
|
||||
+ " AND private_scope.is_csi_guard = FALSE)"
|
||||
+ " AND NOT EXISTS (SELECT 1 FROM ma_turn t JOIN ma_public_event e ON"
|
||||
+ " e.tenant_id = t.tenant_id AND e.session_id = t.session_id AND e.turn_id = t.turn_id"
|
||||
+ " WHERE t.tenant_id = s.tenant_id AND t.session_id = s.session_id"
|
||||
@@ -339,7 +339,7 @@ final class AgentMessageProjection {
|
||||
|
||||
List<MaterializationTarget> findMaterializationTargets(int limit) {
|
||||
return jdbc.query(
|
||||
"SELECT s.tenant_id, s.session_id FROM ma_session s JOIN ma_event_stream p ON p.tenant_id = s.tenant_id AND p.session_id = s.session_id AND p.stream_kind = 'SESSION' AND p.stream_id = X'' WHERE s.session_kind = 'PUBLIC' AND s.csi_guard = FALSE AND s.retired_at IS NULL AND s.status <> 'DELETED' AND p.projection_pending = TRUE ORDER BY p.gmt_modified ASC LIMIT ?",
|
||||
"SELECT s.tenant_id, s.session_id FROM ma_session s JOIN ma_event_stream p ON p.tenant_id = s.tenant_id AND p.session_id = s.session_id AND p.stream_kind = 'SESSION' AND p.stream_id = X'' WHERE s.session_kind = 'PUBLIC' AND s.is_csi_guard = FALSE AND s.retired_at IS NULL AND s.status <> 'DELETED' AND p.is_projection_pending = TRUE ORDER BY p.gmt_modified ASC LIMIT ?",
|
||||
(result, row) ->
|
||||
new MaterializationTarget(
|
||||
result.getString("tenant_id"), result.getString("session_id")),
|
||||
|
||||
+2
-2
@@ -520,7 +520,7 @@ final class AgentSessionAdmissions {
|
||||
// paused before this call is about to mint the Session anyway.
|
||||
// The row lock serializes that verdict against this read, so a
|
||||
// settled record refuses the mint inside its own transaction —
|
||||
// addressed by the parent's launch row's own primary key, which
|
||||
// addressed by the parent's launch row's unique business key, which
|
||||
// is the same key the idempotent admission derives, so the
|
||||
// locking read never becomes a cross-tenant table scan under
|
||||
// REPEATABLE READ.
|
||||
@@ -843,7 +843,7 @@ final class AgentSessionAdmissions {
|
||||
+ " context_revision, workspace_config_ref,"
|
||||
+ " workspace_policy_ref, tool_profile,"
|
||||
+ " creator_actor_key, owner_actor_key, runtime_request_key, approval_mode,"
|
||||
+ " plan_enabled, selected_approval_mode, approval_revision, model_id, model_revision) VALUES"
|
||||
+ " is_plan_enabled, selected_approval_mode, approval_revision, model_id, model_revision) VALUES"
|
||||
+ " (?, ?, ?, ?, ?, ?, 'ACTIVE', ?, ?, ?, ?, ?, ?, ?,"
|
||||
+ " ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
|
||||
tenantId, sessionId, agentId, pin.revision(), pin.digest(),
|
||||
|
||||
+7
-7
@@ -86,7 +86,7 @@ final class AgentSessionCommands {
|
||||
// The replay probe must not lock: a FOR UPDATE read that misses
|
||||
// next-key-locks a gap of the tenant-shared command index, and
|
||||
// concurrent admissions holding such gap locks deadlock when they
|
||||
// all try to insert into the same gap. The PRIMARY KEY deduplicates
|
||||
// all try to insert into the same gap. The unique business key deduplicates
|
||||
// racing inserts instead, and the service replays on
|
||||
// DuplicateKeyException.
|
||||
Optional<CommandRecord> existing = findCommand(tenantId, operation,
|
||||
@@ -451,15 +451,15 @@ final class AgentSessionCommands {
|
||||
String unanswered = "(state = 'RUNNING' AND phase = 'SUBMITTED' AND claim_until <= "
|
||||
+ ManagedSchemaTime.SQL_NOW + ")";
|
||||
for (Map<String, Object> row : jdbc.queryForList(
|
||||
"SELECT operation_key, tenant_id, session_id, idempotency_key FROM ma_operation WHERE operation_kind = 'RENAME' AND " + unanswered + " AND EXISTS (SELECT 1 FROM ma_session private_scope WHERE private_scope.tenant_id = ma_operation.tenant_id AND private_scope.session_id = ma_operation.session_id AND private_scope.csi_guard = FALSE) LIMIT 100")) {
|
||||
"SELECT operation_key, tenant_id, session_id, idempotency_key FROM ma_operation WHERE operation_kind = 'RENAME' AND " + unanswered + " AND EXISTS (SELECT 1 FROM ma_session private_scope WHERE private_scope.tenant_id = ma_operation.tenant_id AND private_scope.session_id = ma_operation.session_id AND private_scope.is_csi_guard = FALSE) LIMIT 100")) {
|
||||
parkRename(row, unanswered);
|
||||
}
|
||||
jdbc.update(
|
||||
"UPDATE ma_operation SET state = 'PENDING', delivery_state = 'PENDING', phase = 'ADMITTED', available_at = ?, claim_owner = NULL, claim_until = NULL, gmt_modified = ? WHERE operation_kind = 'RENAME' AND state = 'RUNNING' AND phase = 'PREPARING' AND claim_until <= " + ManagedSchemaTime.SQL_NOW + " AND EXISTS (SELECT 1 FROM ma_session private_scope WHERE private_scope.tenant_id = ma_operation.tenant_id AND private_scope.session_id = ma_operation.session_id AND private_scope.csi_guard = FALSE) LIMIT 100",
|
||||
"UPDATE ma_operation SET state = 'PENDING', delivery_state = 'PENDING', phase = 'ADMITTED', available_at = ?, claim_owner = NULL, claim_until = NULL, gmt_modified = ? WHERE operation_kind = 'RENAME' AND state = 'RUNNING' AND phase = 'PREPARING' AND claim_until <= " + ManagedSchemaTime.SQL_NOW + " AND EXISTS (SELECT 1 FROM ma_session private_scope WHERE private_scope.tenant_id = ma_operation.tenant_id AND private_scope.session_id = ma_operation.session_id AND private_scope.is_csi_guard = FALSE) LIMIT 100",
|
||||
now,
|
||||
now);
|
||||
return jdbc.query(
|
||||
"SELECT " + ManagedSchemaProjection.OPERATION.columns() + " FROM ma_operation WHERE operation_kind = 'RENAME' AND delivery_state = 'PENDING' AND state = 'PENDING' AND available_at <= ? AND EXISTS (SELECT 1 FROM ma_session private_scope WHERE private_scope.tenant_id = ma_operation.tenant_id AND private_scope.session_id = ma_operation.session_id AND private_scope.csi_guard = FALSE) ORDER BY available_at LIMIT 100",
|
||||
"SELECT " + ManagedSchemaProjection.OPERATION.columns() + " FROM ma_operation WHERE operation_kind = 'RENAME' AND delivery_state = 'PENDING' AND state = 'PENDING' AND available_at <= ? AND EXISTS (SELECT 1 FROM ma_session private_scope WHERE private_scope.tenant_id = ma_operation.tenant_id AND private_scope.session_id = ma_operation.session_id AND private_scope.is_csi_guard = FALSE) ORDER BY available_at LIMIT 100",
|
||||
this::renameDelivery,
|
||||
now);
|
||||
}
|
||||
@@ -862,7 +862,7 @@ final class AgentSessionCommands {
|
||||
// to a (kind, state) index whose range holds every Session's pending
|
||||
// rows, and two Sessions' settles then deadlock. H2 skips the hint.
|
||||
for (String operationKey : jdbc.queryForList("SELECT operation_key"
|
||||
+ " FROM ma_operation /*! FORCE INDEX (uq_ma_operation_identity) */"
|
||||
+ " FROM ma_operation /*! FORCE INDEX (uk_ma_operation_identity) */"
|
||||
+ " WHERE scope_key = ? AND"
|
||||
+ " operation_kind = ? AND target_key = ? AND state ="
|
||||
+ " 'PENDING' FOR UPDATE",
|
||||
@@ -929,7 +929,7 @@ final class AgentSessionCommands {
|
||||
String payloadDigest, long now) {
|
||||
jdbc.update("INSERT INTO ma_turn (tenant_id, session_id,"
|
||||
+ " turn_id, prompt_id, input_json, payload_digest,"
|
||||
+ " status, gmt_create, gmt_modified, model_id, model_revision, approval_mode, approval_revision, plan_enabled, permission_rules_json) SELECT"
|
||||
+ " status, gmt_create, gmt_modified, model_id, model_revision, approval_mode, approval_revision, is_plan_enabled, permission_rules_json) SELECT"
|
||||
+ " ?, ?, ?, ?, ?, ?, 'ACCEPTED', ?, ?, model_id,"
|
||||
+ " CASE WHEN model_id IS NULL THEN NULL ELSE model_revision END,"
|
||||
+ " CASE WHEN ((agent_id=? AND agent_definition_digest IS NULL)"
|
||||
@@ -946,7 +946,7 @@ final class AgentSessionCommands {
|
||||
+ " OR (agent_id<>? AND agent_definition_digest IS NOT NULL))"
|
||||
+ " AND workspace_id IS NOT NULL AND tool_profile IN ('hosted-workspace-files/1',"
|
||||
+ " 'hosted-workspace-shell/1','hosted-workspace-files/3')"
|
||||
+ " THEN plan_enabled ELSE NULL END,"
|
||||
+ " THEN is_plan_enabled ELSE NULL END,"
|
||||
+ " CASE WHEN ((agent_id=? AND agent_definition_digest IS NULL)"
|
||||
+ " OR (agent_id<>? AND agent_definition_digest IS NOT NULL))"
|
||||
+ " AND workspace_id IS NOT NULL AND tool_profile IN ('hosted-workspace-files/1',"
|
||||
|
||||
+5
-5
@@ -302,7 +302,7 @@ final class AgentSessionPolicies {
|
||||
if (initial.get("operationId").equals(body.path("command").path("operationId").asText())) {
|
||||
boolean beforeModel = jdbc.queryForObject("SELECT COUNT(*) FROM ma_turn WHERE tenant_id=? AND session_id=?", Integer.class,
|
||||
tenantId, sessionId) <= 1
|
||||
&& jdbc.queryForList("SELECT turn_id FROM ma_turn WHERE tenant_id=? AND session_id=? AND submission_attempted=TRUE LIMIT 1 FOR UPDATE",
|
||||
&& jdbc.queryForList("SELECT turn_id FROM ma_turn WHERE tenant_id=? AND session_id=? AND is_submission_attempted=TRUE LIMIT 1 FOR UPDATE",
|
||||
tenantId, sessionId).isEmpty();
|
||||
if (!beforeModel || !isBootstrapRevision(body)
|
||||
|| !objectMapper.valueToTree(initial).equals(body.path("command"))) {
|
||||
@@ -324,7 +324,7 @@ final class AgentSessionPolicies {
|
||||
JsonNode command = childExtensionBootstrapCommand(child, lineage);
|
||||
boolean onlyInitialTurn = jdbc.queryForObject("SELECT COUNT(*) FROM ma_turn WHERE tenant_id=? AND session_id=?", Integer.class,
|
||||
child.tenantId(), child.sessionId()) <= 1
|
||||
&& jdbc.queryForList("SELECT turn_id FROM ma_turn WHERE tenant_id=? AND session_id=? AND submission_attempted=TRUE LIMIT 1 FOR UPDATE",
|
||||
&& jdbc.queryForList("SELECT turn_id FROM ma_turn WHERE tenant_id=? AND session_id=? AND is_submission_attempted=TRUE LIMIT 1 FOR UPDATE",
|
||||
child.tenantId(), child.sessionId()).isEmpty();
|
||||
if (!onlyInitialTurn || !isBootstrapRevision(body) || !command.equals(body.path("command"))) {
|
||||
throw new ManagedAgentException(409, "child_launch_snapshot_invalid", "Child extension bootstrap conflicts with its launch snapshot");
|
||||
@@ -365,7 +365,7 @@ final class AgentSessionPolicies {
|
||||
String sessionId = session.sessionId();
|
||||
// The journal may already have a consistent-read snapshot; these reads must observe the
|
||||
// Plan/Turn admission that won the same Session row before this settings commit.
|
||||
if (Boolean.TRUE.equals(jdbc.queryForObject("SELECT plan_enabled FROM ma_session WHERE tenant_id=? AND session_id=? FOR UPDATE",
|
||||
if (Boolean.TRUE.equals(jdbc.queryForObject("SELECT is_plan_enabled FROM ma_session WHERE tenant_id=? AND session_id=? FOR UPDATE",
|
||||
Boolean.class, tenantId, sessionId))) {
|
||||
throw new ManagedAgentException(409, "unsupported_feature", "Disable Plan mode before managing MCP servers.");
|
||||
}
|
||||
@@ -642,7 +642,7 @@ final class AgentSessionPolicies {
|
||||
throw new ManagedAgentException(409, "unsupported_feature", "Permission rules are unavailable");
|
||||
}
|
||||
boolean planMode = requestedPlanMode == null
|
||||
? Boolean.TRUE.equals(jdbc.queryForObject("SELECT plan_enabled FROM ma_session WHERE tenant_id=? AND session_id=?",
|
||||
? Boolean.TRUE.equals(jdbc.queryForObject("SELECT is_plan_enabled FROM ma_session WHERE tenant_id=? AND session_id=?",
|
||||
Boolean.class, tenantId, sessionId)) : requestedPlanMode;
|
||||
if (planMode && (!planModeSupported || !supportsPlanMode(session))) {
|
||||
throw new ManagedAgentException(409, "unsupported_feature", "Plan mode is unavailable");
|
||||
@@ -663,7 +663,7 @@ final class AgentSessionPolicies {
|
||||
}
|
||||
long revision = current + 1;
|
||||
long now = clock.millis();
|
||||
jdbc.update("UPDATE ma_session SET selected_approval_mode = ?, approval_revision = ?, plan_enabled = ?, permission_rules_json = ?, gmt_modified = ?,"
|
||||
jdbc.update("UPDATE ma_session SET selected_approval_mode = ?, approval_revision = ?, is_plan_enabled = ?, permission_rules_json = ?, gmt_modified = ?,"
|
||||
+ " version = version + 1 WHERE tenant_id = ? AND session_id = ? AND approval_revision = ?",
|
||||
mode, revision, planMode, rules == null ? null : storeRows.writeJson(rules), now, tenantId, sessionId, current);
|
||||
ManagedReceipts.insert(jdbc, namespace, tenantId, scopeKind, scope, key, digest,
|
||||
|
||||
+5
-5
@@ -163,7 +163,7 @@ final class AgentSessionQueries {
|
||||
row.getString("session_id"),
|
||||
row.getString("parent_session_id"),
|
||||
row.getString("workspace_id"),
|
||||
(Long) row.getObject("workspace_generation"),
|
||||
row.getObject("workspace_generation", Long.class),
|
||||
row.getString("workspace_storage_id"),
|
||||
row.getBoolean("creator_can_execute")),
|
||||
arguments.toArray());
|
||||
@@ -426,10 +426,10 @@ final class AgentSessionQueries {
|
||||
args.addAll(sessionIds);
|
||||
Map<String, WebShellApprovalSelection> result = new HashMap<>();
|
||||
jdbc.query("SELECT session_id, COALESCE(selected_approval_mode, approval_mode) AS mode,"
|
||||
+ " approval_revision, plan_enabled, permission_rules_json FROM ma_session WHERE tenant_id=? AND session_id IN ("
|
||||
+ " approval_revision, is_plan_enabled, permission_rules_json FROM ma_session WHERE tenant_id=? AND session_id IN ("
|
||||
+ AgentStoreRows.placeholders(sessionIds.size()) + ") AND session_kind='PUBLIC'",
|
||||
row -> { result.put(row.getString("session_id"), new WebShellApprovalSelection(
|
||||
row.getString("mode"), row.getLong("approval_revision"), row.getBoolean("plan_enabled"),
|
||||
row.getString("mode"), row.getLong("approval_revision"), row.getBoolean("is_plan_enabled"),
|
||||
storeRows.readPermissionRules(row.getString("permission_rules_json")))); }, args.toArray());
|
||||
return result;
|
||||
}
|
||||
@@ -449,7 +449,7 @@ final class AgentSessionQueries {
|
||||
|
||||
WebShellApprovalSelection findTurnApprovalSelection(String tenantId, String sessionId,
|
||||
String promptId) {
|
||||
var rows = jdbc.query("SELECT t.approval_mode, t.approval_revision, t.plan_enabled, t.permission_rules_json,"
|
||||
var rows = jdbc.query("SELECT t.approval_mode, t.approval_revision, t.is_plan_enabled, t.permission_rules_json,"
|
||||
+ " s.approval_revision AS selected_revision, s.agent_id, s.agent_definition_digest,"
|
||||
+ " s.workspace_id, s.tool_profile FROM ma_turn t JOIN ma_session s"
|
||||
+ " ON s.tenant_id=t.tenant_id AND s.session_id=t.session_id"
|
||||
@@ -468,7 +468,7 @@ final class AgentSessionQueries {
|
||||
}
|
||||
// Legacy prompt replays must preserve the original absence of a selection.
|
||||
return mode == null ? null : new WebShellApprovalSelection(mode, row.getLong("approval_revision"),
|
||||
row.getBoolean("plan_enabled"), storeRows.readPermissionRules(row.getString("permission_rules_json")));
|
||||
row.getBoolean("is_plan_enabled"), storeRows.readPermissionRules(row.getString("permission_rules_json")));
|
||||
}, tenantId, sessionId, promptId);
|
||||
if (rows.size() != 1) {
|
||||
throw new ManagedAgentException(409, "turn_not_found", "The Turn was not found");
|
||||
|
||||
+2
-2
@@ -63,7 +63,7 @@ final class AgentStoreRows {
|
||||
readInput(result.getString("input_json")),
|
||||
result.getString("payload_digest"),
|
||||
result.getString("status"),
|
||||
result.getBoolean("submission_attempted"),
|
||||
result.getBoolean("is_submission_attempted"),
|
||||
result.getString("harness_event_epoch"),
|
||||
nullableLong(result, "harness_last_event_id"),
|
||||
result.getString("dispatch_owner"),
|
||||
@@ -208,7 +208,7 @@ final class AgentStoreRows {
|
||||
+ " ? AND ma_session.session_id = ? FOR UPDATE",
|
||||
(rows, rowNumber) -> {
|
||||
if (legacyMutation) {
|
||||
ManagedLegacySessionGuard.requireLegacyMutation(rows.getBoolean("csi_guard"));
|
||||
ManagedLegacySessionGuard.requireLegacyMutation(rows.getBoolean("is_csi_guard"));
|
||||
}
|
||||
// H2 can retain pre-wait outer-join values after locking the Session.
|
||||
// Read its stream only after acquiring that lock.
|
||||
|
||||
+9
-9
@@ -54,7 +54,7 @@ final class AgentTurnExecution {
|
||||
// Harness park enters only the coordinator's read-only observation
|
||||
// branch; cancellation still uses the normal dispatch lane.
|
||||
return jdbc.query(
|
||||
"SELECT tenant_id, session_id, turn_id FROM ma_turn WHERE status IN ('ACCEPTED', 'RUNNING', 'CANCELLING') AND (dispatch_lease_until IS NULL OR dispatch_lease_until < ?) AND (retry_after IS NULL OR retry_after <= ?) AND (status = 'CANCELLING' OR error_code IS NULL OR error_code NOT IN ('" + AgentStateStore.WORKFLOW_RECOVERY_BLOCKED + "', '" + AgentStateStore.RUNTIME_RECOVERY_BLOCKED + "')) AND (status = 'CANCELLING' OR NOT EXISTS (SELECT 1 FROM ma_session_worktree w WHERE w.tenant_id = ma_turn.tenant_id AND w.session_id = ma_turn.session_id AND w.state <> 'READY')) AND EXISTS (SELECT 1 FROM ma_session private_scope WHERE private_scope.tenant_id = ma_turn.tenant_id AND private_scope.session_id = ma_turn.session_id AND private_scope.csi_guard = FALSE) ORDER BY gmt_modified ASC LIMIT ?",
|
||||
"SELECT tenant_id, session_id, turn_id FROM ma_turn WHERE status IN ('ACCEPTED', 'RUNNING', 'CANCELLING') AND (dispatch_lease_until IS NULL OR dispatch_lease_until < ?) AND (retry_after IS NULL OR retry_after <= ?) AND (status = 'CANCELLING' OR error_code IS NULL OR error_code NOT IN ('" + AgentStateStore.WORKFLOW_RECOVERY_BLOCKED + "', '" + AgentStateStore.RUNTIME_RECOVERY_BLOCKED + "')) AND (status = 'CANCELLING' OR NOT EXISTS (SELECT 1 FROM ma_session_worktree w WHERE w.tenant_id = ma_turn.tenant_id AND w.session_id = ma_turn.session_id AND w.state <> 'READY')) AND EXISTS (SELECT 1 FROM ma_session private_scope WHERE private_scope.tenant_id = ma_turn.tenant_id AND private_scope.session_id = ma_turn.session_id AND private_scope.is_csi_guard = FALSE) ORDER BY gmt_modified ASC LIMIT ?",
|
||||
(result, row) -> new DispatchTarget(
|
||||
result.getString("tenant_id"),
|
||||
result.getString("session_id"),
|
||||
@@ -68,7 +68,7 @@ final class AgentTurnExecution {
|
||||
return jdbc.query(
|
||||
"SELECT tenant_id, session_id, turn_id FROM ma_turn WHERE status IN ('ACCEPTED', 'RUNNING') AND error_code = '"
|
||||
+ AgentStateStore.RUNTIME_RECOVERY_BLOCKED
|
||||
+ "' AND (dispatch_lease_until IS NULL OR dispatch_lease_until < ?) AND (retry_after IS NULL OR retry_after <= ?) AND EXISTS (SELECT 1 FROM ma_session private_scope WHERE private_scope.tenant_id = ma_turn.tenant_id AND private_scope.session_id = ma_turn.session_id AND private_scope.csi_guard = FALSE) ORDER BY retry_after ASC, gmt_modified ASC LIMIT ?",
|
||||
+ "' AND (dispatch_lease_until IS NULL OR dispatch_lease_until < ?) AND (retry_after IS NULL OR retry_after <= ?) AND EXISTS (SELECT 1 FROM ma_session private_scope WHERE private_scope.tenant_id = ma_turn.tenant_id AND private_scope.session_id = ma_turn.session_id AND private_scope.is_csi_guard = FALSE) ORDER BY retry_after ASC, gmt_modified ASC LIMIT ?",
|
||||
(result, row) -> new DispatchTarget(
|
||||
result.getString("tenant_id"),
|
||||
result.getString("session_id"),
|
||||
@@ -146,7 +146,7 @@ final class AgentTurnExecution {
|
||||
return jdbc.update("UPDATE ma_turn SET error_code = ?, error_message = ?,"
|
||||
+ " gmt_modified = ?, version = version + 1 WHERE tenant_id = ?"
|
||||
+ " AND session_id = ? AND turn_id = ? AND dispatch_owner = ?"
|
||||
+ " AND dispatch_lease_until >= ? AND submission_attempted = TRUE"
|
||||
+ " AND dispatch_lease_until >= ? AND is_submission_attempted = TRUE"
|
||||
+ " AND status IN ('ACCEPTED', 'RUNNING')",
|
||||
AgentStateStore.RUNTIME_RECOVERY_BLOCKED, diagnostic, now,
|
||||
tenantId, sessionId, turnId, owner, now) == 1;
|
||||
@@ -274,7 +274,7 @@ final class AgentTurnExecution {
|
||||
storeRows.requireLegacyMutation(tenantId, sessionId);
|
||||
long now = clock.millis();
|
||||
int updated = jdbc.update("UPDATE ma_turn SET"
|
||||
+ " submission_attempted = TRUE, gmt_modified = ?,"
|
||||
+ " is_submission_attempted = TRUE, gmt_modified = ?,"
|
||||
+ " version = version + 1 WHERE tenant_id = ? AND"
|
||||
+ " session_id = ? AND turn_id = ? AND"
|
||||
+ " dispatch_owner = ? AND dispatch_lease_until"
|
||||
@@ -298,11 +298,11 @@ final class AgentTurnExecution {
|
||||
storeRows.requireLegacyMutation(tenantId, sessionId);
|
||||
long now = clock.millis();
|
||||
int updated = jdbc.update("UPDATE ma_turn SET"
|
||||
+ " submission_attempted = FALSE, gmt_modified = ?,"
|
||||
+ " is_submission_attempted = FALSE, gmt_modified = ?,"
|
||||
+ " version = version + 1 WHERE tenant_id = ? AND"
|
||||
+ " session_id = ? AND turn_id = ? AND"
|
||||
+ " dispatch_owner = ? AND dispatch_lease_until"
|
||||
+ " >= ? AND submission_attempted = TRUE AND"
|
||||
+ " >= ? AND is_submission_attempted = TRUE AND"
|
||||
+ " harness_event_epoch IS NULL AND status IN"
|
||||
+ " ('ACCEPTED','RUNNING','CANCELLING')",
|
||||
now, tenantId, sessionId, turnId, owner, now);
|
||||
@@ -744,7 +744,7 @@ final class AgentTurnExecution {
|
||||
+ " version + 1 WHERE tenant_id = ? AND"
|
||||
+ " session_id = ? AND turn_id = ? AND"
|
||||
+ " dispatch_owner = ? AND dispatch_lease_until >= ?"
|
||||
+ " AND submission_attempted = FALSE",
|
||||
+ " AND is_submission_attempted = FALSE",
|
||||
now, now, tenantId, sessionId, turnId, owner, now);
|
||||
if (updated != 1) {
|
||||
return;
|
||||
@@ -768,12 +768,12 @@ final class AgentTurnExecution {
|
||||
long now = clock.millis();
|
||||
String message = "The Session worktree could not be prepared.";
|
||||
List<String> turns = jdbc.queryForList("SELECT turn_id FROM ma_turn WHERE tenant_id = ? AND session_id = ?"
|
||||
+ " AND status = 'ACCEPTED' AND submission_attempted = FALSE FOR UPDATE", String.class, tenantId, sessionId);
|
||||
+ " AND status = 'ACCEPTED' AND is_submission_attempted = FALSE FOR UPDATE", String.class, tenantId, sessionId);
|
||||
for (String turnId : turns) {
|
||||
jdbc.update("UPDATE ma_turn SET status = 'FAILED', error_code = ?, error_message = ?, completed_at = ?,"
|
||||
+ " gmt_modified = ?, dispatch_owner = NULL, dispatch_lease_until = NULL, version = version + 1"
|
||||
+ " WHERE tenant_id = ? AND session_id = ? AND turn_id = ? AND status = 'ACCEPTED'"
|
||||
+ " AND submission_attempted = FALSE", code, message, now, now, tenantId, sessionId, turnId);
|
||||
+ " AND is_submission_attempted = FALSE", code, message, now, now, tenantId, sessionId, turnId);
|
||||
eventJournal.appendEvent(tenantId, sessionId, turnId, "turn.failed", Map.of("code", code, "message", message), true, null, now);
|
||||
sessionCommands.settleTurnCommands(tenantId, sessionId, turnId, now);
|
||||
}
|
||||
|
||||
+7
-7
@@ -75,8 +75,8 @@ public class AutomationLedgerStore
|
||||
result.getString("timezone"),
|
||||
result.getString("session_mode"),
|
||||
result.getString("overlap"), result.getString("catch_up"),
|
||||
(Long) result.getObject("catch_up_limit"),
|
||||
result.getBoolean("enabled"), result.getString("state"),
|
||||
result.getObject("catch_up_limit", Long.class),
|
||||
result.getBoolean("is_enabled"), result.getString("state"),
|
||||
result.getString("blocked_reason"),
|
||||
result.getLong("armed_at"),
|
||||
result.getObject("watermark_slot", Long.class),
|
||||
@@ -252,7 +252,7 @@ public class AutomationLedgerStore
|
||||
+ " workspace_id, actor_id, record_revision,"
|
||||
+ " definition_revision, definition_digest, goal,"
|
||||
+ " cron, timezone, session_mode, overlap, catch_up,"
|
||||
+ " catch_up_limit, enabled, state, blocked_reason,"
|
||||
+ " catch_up_limit, is_enabled, state, blocked_reason,"
|
||||
+ " armed_at, watermark_slot, lease_owner,"
|
||||
+ " lease_until, fence, gmt_create, gmt_modified,"
|
||||
+ " gate)"
|
||||
@@ -286,7 +286,7 @@ public class AutomationLedgerStore
|
||||
+ " record_revision = ?, definition_revision = ?,"
|
||||
+ " definition_digest = ?, goal = ?, cron = ?,"
|
||||
+ " timezone = ?, session_mode = ?, overlap = ?,"
|
||||
+ " catch_up = ?, catch_up_limit = ?, enabled = ?,"
|
||||
+ " catch_up = ?, catch_up_limit = ?, is_enabled = ?,"
|
||||
+ " state = ?, blocked_reason = NULL, armed_at = ?,"
|
||||
+ " gmt_modified = ?, gate = ?, gate_last_outcome = ?,"
|
||||
+ " gate_last_at = ?, gate_quiet_since_delivery = ?,"
|
||||
@@ -388,7 +388,7 @@ public class AutomationLedgerStore
|
||||
/** Live, enabled, unblocked definitions whose lease is free or expired. */
|
||||
public List<ScheduleRow> findArmed(long now, int limit) {
|
||||
return jdbc.query("SELECT " + ManagedSchemaProjection.SCHEDULE.columns() + " FROM ma_schedule"
|
||||
+ " WHERE state = ? AND enabled = TRUE"
|
||||
+ " WHERE state = ? AND is_enabled = TRUE"
|
||||
+ " AND blocked_reason IS NULL"
|
||||
+ " AND (lease_until IS NULL OR lease_until < ?)"
|
||||
+ " ORDER BY gmt_modified, schedule_id LIMIT ?", SCHEDULE,
|
||||
@@ -479,7 +479,7 @@ public class AutomationLedgerStore
|
||||
/**
|
||||
* Records one occurrence decision under the writer's lease unless one exists: the row is
|
||||
* selected from the definition row the owner holds, so a writer whose lease another claim has
|
||||
* taken inserts nothing, and the primary key keeps the first decision of a slot. Answers the row
|
||||
* taken inserts nothing, and the unique business key keeps the first decision of a slot. Answers the row
|
||||
* now held — the one written, or the earlier decision — or empty when another claim has taken
|
||||
* the lease and no decision exists.
|
||||
*/
|
||||
@@ -730,7 +730,7 @@ public class AutomationLedgerStore
|
||||
}
|
||||
|
||||
/**
|
||||
* Claims (tenant, key) for one request before any side effect: the primary key arbitrates, so
|
||||
* Claims (tenant, key) for one request before any side effect: the unique business key arbitrates, so
|
||||
* only one concurrent or retried caller owns the identity; the row's empty result marks it
|
||||
* unanswered. A claim whose requester dies mid-flight stays durable, which is what lets a
|
||||
* different request under the same key conflict instead of repeating the side effect.
|
||||
|
||||
+1
-1
@@ -258,7 +258,7 @@ public class ChannelInstanceStore
|
||||
// The ordering index can scan all completed deliveries before finding a due row.
|
||||
return jdbc.query("SELECT session_id, record_id, revision,"
|
||||
+ " delivery_state, record_resource_id"
|
||||
+ " FROM ma_session_record USE INDEX (ix_ma_record_session_delivery)"
|
||||
+ " FROM ma_session_record USE INDEX (idx_ma_record_session_delivery)"
|
||||
+ " WHERE record_kind = 'DOMAIN' AND session_scope_key = ?"
|
||||
+ " AND domain = 'channel_delivery'"
|
||||
+ " AND delivery_state IN ('planned', 'partial')"
|
||||
|
||||
+3
-3
@@ -139,7 +139,7 @@ public class ChildResultRelayStore
|
||||
* write would otherwise leave the stale snapshot behind a row the
|
||||
* correction could not see yet. The parent's consuming revision
|
||||
* updates that same record row first, so the two commits serialize.
|
||||
* The lookup names the record's primary key; matching only the
|
||||
* The lookup names the record's unique business key; matching only the
|
||||
* session scope would make MySQL lock every row the scan touches. */
|
||||
private String lockedDeliveryState(String tenantId,
|
||||
String parentSessionId, String childRunId) {
|
||||
@@ -626,7 +626,7 @@ public class ChildResultRelayStore
|
||||
String order) {
|
||||
List<TurnLine> rows = jdbc.query(
|
||||
"SELECT turn_id, status, completed_at, error_code,"
|
||||
+ " submission_attempted, harness_event_epoch"
|
||||
+ " is_submission_attempted, harness_event_epoch"
|
||||
+ " FROM ma_turn"
|
||||
+ " WHERE tenant_id = ? AND session_id = ?"
|
||||
+ " ORDER BY gmt_create " + order + ", turn_id "
|
||||
@@ -635,7 +635,7 @@ public class ChildResultRelayStore
|
||||
result.getString("status"),
|
||||
result.getObject("completed_at", Long.class),
|
||||
result.getString("error_code"),
|
||||
result.getBoolean("submission_attempted"),
|
||||
result.getBoolean("is_submission_attempted"),
|
||||
result.getString("harness_event_epoch")),
|
||||
tenantId, sessionId);
|
||||
return rows.isEmpty() ? null : rows.getFirst();
|
||||
|
||||
+2
-2
@@ -110,9 +110,9 @@ public final class ExternalStorageRegistrationStore implements ExternalStorageRe
|
||||
* Reads one tenant-bound registration for the external Workspace profile.
|
||||
*
|
||||
* <p>Read-only by construction: no lock, no write, no idempotency record. The
|
||||
* lookup uses the same primary key the write path inserts
|
||||
* lookup uses the same unique business key the write path inserts
|
||||
* ({@link JdbcRuntimeBindingRepository#storageAliasKey}), joins the owner row
|
||||
* on the owner's primary key, and admits only a {@code REGISTERED} row. It
|
||||
* on the owner's unique business key, and admits only a {@code REGISTERED} row. It
|
||||
* then enforces exactly these fields: the decoded record's alias id equals the
|
||||
* requested alias, its identity owner key equals the stored physical key, its
|
||||
* revision equals the stored {@code registration_revision}, and its mount root
|
||||
|
||||
+2
-2
@@ -41,7 +41,7 @@ public class HarnessPlacementStore
|
||||
|
||||
public boolean hasUnreleasedOwnership(String instance, String boot) {
|
||||
return !jdbc.query("SELECT m.session_id FROM ma_session m WHERE m.harness_instance_id = ?"
|
||||
+ " AND m.harness_owner_boot_id = ? AND m.resource_gc_completed = FALSE"
|
||||
+ " AND m.harness_owner_boot_id = ? AND m.is_resource_gc_completed = FALSE"
|
||||
+ " AND m.harness_placement_state <> 'RELEASED'"
|
||||
+ " AND (m.status NOT IN ('CLOSED', 'ARCHIVED', 'DELETED') OR EXISTS ("
|
||||
+ " SELECT 1 FROM ma_session_head h WHERE h.tenant_id = m.tenant_id AND h.session_id = m.session_id"
|
||||
@@ -227,7 +227,7 @@ public class HarnessPlacementStore
|
||||
case ARCHIVE -> "ARCHIVING";
|
||||
default -> "CLOSING";
|
||||
};
|
||||
var admission = jdbc.query("SELECT status, session_kind, workspace_id, csi_guard FROM ma_session"
|
||||
var admission = jdbc.query("SELECT status, session_kind, workspace_id, is_csi_guard FROM ma_session"
|
||||
+ " WHERE tenant_id = ? AND session_id = ? FOR UPDATE", (row, index) ->
|
||||
pendingStatus.equals(row.getString(1))
|
||||
&& ("PUBLIC".equals(row.getString(2)) || row.getString(3) != null)
|
||||
|
||||
+1
-1
@@ -24,7 +24,7 @@ public class JdbcSessionRecoveryRepository implements SessionRecoveryRepository
|
||||
@Override
|
||||
public long nonInitialTurns(String tenantId, String sessionId) {
|
||||
return jdbc.queryForObject("SELECT COUNT(*) FROM ma_turn WHERE tenant_id = ? AND session_id = ?"
|
||||
+ " AND (status <> 'CANCELLED' OR submission_attempted = TRUE OR harness_event_epoch IS NOT NULL)",
|
||||
+ " AND (status <> 'CANCELLED' OR is_submission_attempted = TRUE OR harness_event_epoch IS NOT NULL)",
|
||||
Long.class, tenantId, sessionId);
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -350,7 +350,7 @@ final class JournalCommit {
|
||||
continuation, head, request.writerId(), request.writerGeneration(), writerToken);
|
||||
jdbc.update("UPDATE ma_session_head SET"
|
||||
+ " journal_revision = ?, committed_sequence = ?,"
|
||||
+ " wake_pending = wake_pending OR ?,"
|
||||
+ " is_wake_pending = is_wake_pending OR ?,"
|
||||
+ " wake_head_revision = CASE WHEN wake_head_revision = ? THEN ? ELSE wake_head_revision END,"
|
||||
+ " cleanup_head_revision = CASE WHEN cleanup_head_revision = ? THEN ? ELSE cleanup_head_revision END,"
|
||||
+ " last_commit_digest = ?, activation_epoch = ?,"
|
||||
|
||||
+4
-4
@@ -308,9 +308,9 @@ final class JournalFencing {
|
||||
.isConnectionTransactional(target, jdbc.getDataSource())) {
|
||||
var privatePins =
|
||||
jdbc.query(
|
||||
"SELECT csi_guard FROM ma_session WHERE tenant_id ="
|
||||
+ " ? AND session_id = ? AND csi_guard = TRUE",
|
||||
(row, index) -> row.getBoolean("csi_guard"),
|
||||
"SELECT is_csi_guard FROM ma_session WHERE tenant_id ="
|
||||
+ " ? AND session_id = ? AND is_csi_guard = TRUE",
|
||||
(row, index) -> row.getBoolean("is_csi_guard"),
|
||||
tenantId,
|
||||
sessionId);
|
||||
if (!privatePins.isEmpty()) {
|
||||
@@ -325,7 +325,7 @@ final class JournalFencing {
|
||||
// range locks: taking them on every writer path
|
||||
// would couple per-turn traffic of unrelated
|
||||
// Sessions again (#13800). The root is locked
|
||||
// first, by primary key once it exists, so its pin
|
||||
// first, by unique business key once it exists, so its pin
|
||||
// is read as committed now even under an older
|
||||
// REPEATABLE READ snapshot, no gap is taken that
|
||||
// another tenant's first writer inserts into, and
|
||||
|
||||
+2
-2
@@ -107,8 +107,8 @@ final class JournalResourceReads {
|
||||
JournalStoreRows.validateStableId(resourceId, "resourceId");
|
||||
var guarded =
|
||||
jdbc.queryForList(
|
||||
"SELECT csi_guard FROM ma_session"
|
||||
+ " WHERE tenant_id = ? AND session_id = ? AND csi_guard = TRUE",
|
||||
"SELECT is_csi_guard FROM ma_session"
|
||||
+ " WHERE tenant_id = ? AND session_id = ? AND is_csi_guard = TRUE",
|
||||
tenantId,
|
||||
sessionId);
|
||||
if (guarded.isEmpty()) {
|
||||
|
||||
+2
-2
@@ -449,7 +449,7 @@ final class JournalStoreRows {
|
||||
+ " p.publication_id WHERE p.tenant_id = ? AND p.workspace_id = ?"
|
||||
+ " AND p.session_id = ? AND p.admission_resource_id = ? AND"
|
||||
+ " p.producer_phase IN ('FINISHED', 'REFERENCED') AND"
|
||||
+ " p.quarantined = FALSE AND o.slot_key = X'61646d697373696f6e'"
|
||||
+ " p.is_quarantined = FALSE AND o.slot_key = X'61646d697373696f6e'"
|
||||
+ " AND o.capture_state = 'VERIFIED' AND o.resource_id = ? AND"
|
||||
+ " o.capture_object_key = ? AND o.sha256 = ? AND o.byte_length ="
|
||||
+ " ?",
|
||||
@@ -488,7 +488,7 @@ final class JournalStoreRows {
|
||||
if ("managed-tool-outcome".equals(resource.kind())) {
|
||||
Long quarantined = jdbc.queryForObject("SELECT COUNT(*) FROM ma_output_capture"
|
||||
+ " WHERE tenant_id = ? AND workspace_id = ? AND session_id = ?"
|
||||
+ " AND admission_resource_id = ? AND quarantined = TRUE",
|
||||
+ " AND admission_resource_id = ? AND is_quarantined = TRUE",
|
||||
Long.class, resource.tenantId(), resource.workspaceId(),
|
||||
resource.sessionId(), resource.resourceId());
|
||||
if (quarantined != null && quarantined > 0) {
|
||||
|
||||
+4
-4
@@ -11,10 +11,10 @@ import org.springframework.transaction.support.TransactionSynchronizationManager
|
||||
import java.util.Map;
|
||||
|
||||
final class LocalStorageOwners {
|
||||
static final String SESSION_AUTHORITY_SQL = "SELECT 1 FROM ma_session WHERE tenant_id = ? AND workspace_storage_id = ? AND resource_gc_completed = FALSE LIMIT 1";
|
||||
static final String SESSION_AUTHORITY_SQL = "SELECT 1 FROM ma_session WHERE tenant_id = ? AND workspace_storage_id = ? AND is_resource_gc_completed = FALSE LIMIT 1";
|
||||
static final String RUNTIME_AUTHORITY_SQL = "SELECT 1 FROM ma_runtime_binding WHERE storage_alias_key = ?"
|
||||
+ " AND (binding_state NOT IN ('FAILED', 'RELEASED')"
|
||||
+ " OR (binding_state = 'FAILED' AND provision_seeded = TRUE)) LIMIT 1";
|
||||
+ " OR (binding_state = 'FAILED' AND is_provision_seeded = TRUE)) LIMIT 1";
|
||||
static final String OPERATION_AUTHORITY_SQL = "SELECT 1 FROM ma_operation WHERE storage_key = ?"
|
||||
+ " AND ((operation_kind IN ('WORKSPACE_RECOVERY', 'WORKSPACE_OPERATOR_RECOVERY', 'STORAGE_MIGRATION')"
|
||||
+ " AND state IN ('CAPTURING', 'VERIFYING', 'PREPARED', 'ATTESTED', 'RETIRING', 'RETIRED', 'PREPARING', 'INVALIDATED'))"
|
||||
@@ -23,10 +23,10 @@ final class LocalStorageOwners {
|
||||
+ String.join("', '", ChildWorkspaceStore.PREPARING, ChildWorkspaceStore.READY, ChildWorkspaceStore.MERGING,
|
||||
ChildWorkspaceStore.APPLYING, ChildWorkspaceStore.APPLIED, ChildWorkspaceStore.DISCARDING,
|
||||
ChildWorkspaceStore.CONFLICTED, ChildWorkspaceStore.BLOCKED, ChildWorkspaceStore.FAILED) + "'))) LIMIT 1";
|
||||
static final String HEAD_AUTHORITY_SQL = "SELECT /*! STRAIGHT_JOIN */ 1 FROM ma_session s USE INDEX (ix_ma_session_storage_scope)"
|
||||
static final String HEAD_AUTHORITY_SQL = "SELECT /*! STRAIGHT_JOIN */ 1 FROM ma_session s USE INDEX (idx_ma_session_storage_scope)"
|
||||
+ " JOIN ma_session_head h ON h.tenant_key = s.tenant_key AND h.harness_key = s.session_key"
|
||||
+ " JOIN ma_workspace w ON w.tenant_id = s.tenant_id AND w.workspace_id = h.workspace_id"
|
||||
+ " WHERE s.tenant_id = ? AND s.workspace_storage_id IS NULL AND s.resource_gc_completed = FALSE"
|
||||
+ " WHERE s.tenant_id = ? AND s.workspace_storage_id IS NULL AND s.is_resource_gc_completed = FALSE"
|
||||
+ " AND h.tenant_key = ? AND h.head_kind = 'MANAGED_SESSION' AND w.tenant_id = ? AND w.storage_id = ? LIMIT 1";
|
||||
|
||||
private LocalStorageOwners() {
|
||||
|
||||
+4
-4
@@ -311,10 +311,10 @@ public class ManagedActionStore
|
||||
&& continuation.path("calls").get(0).path("call").path("callId").equals(options.path("functionCallId"))
|
||||
&& continuation.path("calls").get(0).path("inputRef").equals(options.path("inputRef"))
|
||||
&& continuation.path("calls").get(0).path("actionId").asText().equals(id));
|
||||
jdbc.update("UPDATE ma_session SET plan_enabled=FALSE, approval_revision=approval_revision+1,"
|
||||
+ " version=version+1, gmt_modified=? WHERE tenant_id=? AND session_id=? AND plan_enabled=TRUE"
|
||||
jdbc.update("UPDATE ma_session SET is_plan_enabled=FALSE, approval_revision=approval_revision+1,"
|
||||
+ " version=version+1, gmt_modified=? WHERE tenant_id=? AND session_id=? AND is_plan_enabled=TRUE"
|
||||
+ " AND EXISTS (SELECT 1 FROM ma_turn WHERE tenant_id=? AND session_id=?"
|
||||
+ " AND prompt_id=? AND plan_enabled=TRUE AND status IN ('ACCEPTED','RUNNING'))",
|
||||
+ " AND prompt_id=? AND is_plan_enabled=TRUE AND status IN ('ACCEPTED','RUNNING'))",
|
||||
event.path("occurredAt").asLong(), tenantId, sessionId, tenantId, sessionId,
|
||||
options.path("turnId").asText());
|
||||
}
|
||||
@@ -384,7 +384,7 @@ public class ManagedActionStore
|
||||
return options.path("v").asInt() == 3 && options.path("toolName").asText().equals("exit_plan_mode")
|
||||
&& jdbc.queryForObject("SELECT COUNT(*) FROM ma_turn t JOIN ma_session s ON s.tenant_id=t.tenant_id"
|
||||
+ " AND s.session_id=t.session_id WHERE t.tenant_id=? AND t.session_id=? AND t.prompt_id=?"
|
||||
+ " AND t.plan_enabled=TRUE AND s.session_kind='PUBLIC' AND s.parent_session_id IS NULL",
|
||||
+ " AND t.is_plan_enabled=TRUE AND s.session_kind='PUBLIC' AND s.parent_session_id IS NULL",
|
||||
Integer.class, tenantId, sessionId, options.path("turnId").asText()) == 1;
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -109,7 +109,7 @@ public final class ManagedExtensionAgentLaunch {
|
||||
+ " AND s.last_generation=b.runtime_generation WHERE b.binding_id=? AND b.runtime_generation=?"
|
||||
+ " AND b.tenant_id=? AND b.workspace_id=? AND b.workspace_generation=? AND b.storage_id=?"
|
||||
+ " AND b.isolation_class='session' AND b.isolation_key=? AND b.binding_state='READY'"
|
||||
+ " AND b.drain_requested=FALSE AND b.runtime_instance_id IS NOT NULL AND b.runtime_lease_id IS NOT NULL FOR UPDATE",
|
||||
+ " AND b.is_drain_requested=FALSE AND b.runtime_instance_id IS NOT NULL AND b.runtime_lease_id IS NOT NULL FOR UPDATE",
|
||||
String.class, runtime.path("bindingId").asText(), selectedGeneration, parent.tenantId(),
|
||||
parent.workspace().getWorkspaceId(), Long.toString(parent.workspace().getWorkspaceGeneration()),
|
||||
parent.workspace().getStorageId(), parent.sessionId());
|
||||
|
||||
+3
-3
@@ -19,14 +19,14 @@ final class ManagedLegacySessionGuard {
|
||||
connection.getMetaData().getDatabaseProductName();
|
||||
String index =
|
||||
"MySQL".equals(product) || "MariaDB".equals(product)
|
||||
? " FORCE INDEX (ma_session_csi_guard_idx)"
|
||||
? " FORCE INDEX (idx_ma_session_csi_guard)"
|
||||
: "";
|
||||
try (var statement =
|
||||
connection.prepareStatement(
|
||||
"SELECT csi_guard FROM ma_session"
|
||||
"SELECT is_csi_guard FROM ma_session"
|
||||
+ index
|
||||
+ " WHERE tenant_id = ? AND session_id"
|
||||
+ " = ? AND csi_guard = TRUE FOR"
|
||||
+ " = ? AND is_csi_guard = TRUE FOR"
|
||||
+ " UPDATE")) {
|
||||
statement.setQueryTimeout(10);
|
||||
statement.setBytes(
|
||||
|
||||
+2
-2
@@ -36,7 +36,7 @@ final class ManagedProjectionResourceCollector {
|
||||
boolean runOnce() {
|
||||
boolean changed = false;
|
||||
var candidates = jdbc.queryForList(
|
||||
"SELECT resource_key, tenant_id, session_id FROM ma_resource WHERE retention_until <= " + ManagedSchemaTime.SQL_NOW + " AND NOT EXISTS (SELECT 1 FROM ma_session s WHERE s.tenant_id = ma_resource.tenant_id AND s.session_id = ma_resource.session_id AND s.csi_guard = TRUE) ORDER BY retention_until, resource_key LIMIT "
|
||||
"SELECT resource_key, tenant_id, session_id FROM ma_resource WHERE retention_until <= " + ManagedSchemaTime.SQL_NOW + " AND NOT EXISTS (SELECT 1 FROM ma_session s WHERE s.tenant_id = ma_resource.tenant_id AND s.session_id = ma_resource.session_id AND s.is_csi_guard = TRUE) ORDER BY retention_until, resource_key LIMIT "
|
||||
+ BATCH);
|
||||
for (var candidate : candidates) {
|
||||
changed |= Boolean.TRUE.equals(ManagedSessionStore.skipContended(transactions,
|
||||
@@ -88,7 +88,7 @@ final class ManagedProjectionResourceCollector {
|
||||
ToolPublicationRetentionStore.hash(tenant), ToolPublicationRetentionStore.hash(session), tenant, session).isEmpty();
|
||||
protectedBody |= !jdbc.queryForList(
|
||||
"SELECT session_id FROM ma_session WHERE tenant_id = ? AND"
|
||||
+ " session_id = ? AND recovery_protected = TRUE",
|
||||
+ " session_id = ? AND is_recovery_protected = TRUE",
|
||||
tenant, session).isEmpty();
|
||||
protectedBody |= !jdbc.queryForList(
|
||||
"SELECT lease_id FROM ma_read_lease WHERE tenant_key = ? AND"
|
||||
|
||||
+3
-3
@@ -37,7 +37,7 @@ final class ManagedReceipts {
|
||||
List<Receipt> rows =
|
||||
jdbc.query(
|
||||
"SELECT tenant_id, scope_id, idempotency_key, request_digest, session_id,"
|
||||
+ " turn_id, state, session_status_before, actor_id, workspace_bound, gmt_create,"
|
||||
+ " turn_id, state, session_status_before, actor_id, is_workspace_bound, gmt_create,"
|
||||
+ " gmt_modified, operation, result_json, result_operation_key FROM ma_request_receipt WHERE receipt_key = ? AND namespace = ?"
|
||||
+ " AND tenant_key = ? AND scope_key = ?"
|
||||
+ (lock ? " FOR UPDATE" : ""),
|
||||
@@ -51,7 +51,7 @@ final class ManagedReceipts {
|
||||
row.getString("state"),
|
||||
row.getString("session_status_before"),
|
||||
row.getBytes("actor_id"),
|
||||
row.getObject("workspace_bound", Boolean.class),
|
||||
row.getObject("is_workspace_bound", Boolean.class),
|
||||
row.getLong("gmt_create"), row.getLong("gmt_modified"),
|
||||
row.getString("operation"), row.getString("result_json"),
|
||||
row.getString("result_operation_key")),
|
||||
@@ -92,7 +92,7 @@ final class ManagedReceipts {
|
||||
"INSERT INTO ma_request_receipt (receipt_key, namespace, tenant_key, tenant_id,"
|
||||
+ " scope_kind, scope_key, scope_id, idempotency_key, idempotency_digest,"
|
||||
+ " request_digest, operation, actor_id, session_id, turn_id, state,"
|
||||
+ " session_status_before, workspace_bound, gmt_create, gmt_modified) VALUES (?,"
|
||||
+ " session_status_before, is_workspace_bound, gmt_create, gmt_modified) VALUES (?,"
|
||||
+ " ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)",
|
||||
ManagedSchemaKeys.receiptKey(namespace, tenant, scopeKind, scopeId, key),
|
||||
namespace.name(),
|
||||
|
||||
+1
-1
@@ -26,7 +26,7 @@ public final class ManagedRuntimeRetentionGuard implements JdbcRuntimeRetention.
|
||||
&& exists(
|
||||
connection,
|
||||
"SELECT 1 FROM ma_session WHERE tenant_id = ? AND session_id = ?"
|
||||
+ " AND csi_guard = TRUE LIMIT 1 FOR UPDATE",
|
||||
+ " AND is_csi_guard = TRUE LIMIT 1 FOR UPDATE",
|
||||
identity(request.getScope().getTenantId()),
|
||||
identity(request.getIsolationKey()))
|
||||
|| exists(
|
||||
|
||||
+3
-3
@@ -210,7 +210,7 @@ final class ManagedSessionRetirementStore {
|
||||
}
|
||||
var roots =
|
||||
jdbc.queryForList(
|
||||
"SELECT retired_at, retirement_generation, recovery_protected FROM"
|
||||
"SELECT retired_at, retirement_generation, is_recovery_protected FROM"
|
||||
+ " ma_session WHERE tenant_id = ? AND session_id = ? FOR UPDATE",
|
||||
tenant,
|
||||
session);
|
||||
@@ -218,7 +218,7 @@ final class ManagedSessionRetirementStore {
|
||||
|| roots.getFirst().get("retired_at") == null
|
||||
|| ToolPublicationRetentionStore.number(roots.getFirst(), "retirement_generation")
|
||||
< 1
|
||||
|| ToolPublicationRetentionStore.flag(roots.getFirst(), "recovery_protected")) {
|
||||
|| ToolPublicationRetentionStore.flag(roots.getFirst(), "is_recovery_protected")) {
|
||||
throw new IllegalStateException("Session retirement is incomplete");
|
||||
}
|
||||
var heads =
|
||||
@@ -276,7 +276,7 @@ final class ManagedSessionRetirementStore {
|
||||
throw new IllegalStateException("Session collection is not settled");
|
||||
}
|
||||
if (jdbc.update(
|
||||
"UPDATE ma_session SET gmt_modified = " + ManagedSchemaTime.SQL_NOW + ", resource_gc_completed = TRUE WHERE tenant_id = ? AND session_id = ? AND retired_at IS NOT NULL",
|
||||
"UPDATE ma_session SET gmt_modified = " + ManagedSchemaTime.SQL_NOW + ", is_resource_gc_completed = TRUE WHERE tenant_id = ? AND session_id = ? AND retired_at IS NOT NULL",
|
||||
tenant,
|
||||
session)
|
||||
!= 1) {
|
||||
|
||||
+8
-8
@@ -84,8 +84,8 @@ public class ManagedTaskEventStore
|
||||
public EventPage read(String tenantId, String sessionId, String taskId, long after, int limit) {
|
||||
List<TaskEvent> events = jdbc.query("SELECT sequence_id AS event_sequence, event_type,"
|
||||
+ " gmt_create AS occurred_at, schema_version, projection_version, state, runtime_state,"
|
||||
+ " text, truncated, artifact_id, capture_id, output_stream_id AS stream_id,"
|
||||
+ " first_ordinal, end_ordinal, archived FROM ma_public_event WHERE tenant_id = ?"
|
||||
+ " text, is_truncated, artifact_id, capture_id, output_stream_id AS stream_id,"
|
||||
+ " first_ordinal, end_ordinal, is_archived FROM ma_public_event WHERE tenant_id = ?"
|
||||
+ " AND session_id = ? AND stream_kind = 'TASK' AND stream_id = ?"
|
||||
+ " AND sequence_id > ? ORDER BY sequence_id LIMIT ?",
|
||||
ManagedTaskEventStore::eventRow, tenantId, sessionId, taskId, after, limit + 1);
|
||||
@@ -139,7 +139,7 @@ public class ManagedTaskEventStore
|
||||
ranges.toString(), occurredAt, tenantId, sessionId, taskId);
|
||||
}
|
||||
jdbc.update("INSERT INTO ma_public_event (tenant_id,session_id,stream_kind,stream_id,sequence_id,"
|
||||
+ "event_id,event_type,gmt_create,schema_version,projection_version,text,truncated,capture_id,"
|
||||
+ "event_id,event_type,gmt_create,schema_version,projection_version,text,is_truncated,capture_id,"
|
||||
+ "output_stream_id,first_ordinal,end_ordinal) VALUES (?,?,'TASK',?,?,?,'output',?,?,?,?,?,?,?,?,?)",
|
||||
tenantId, sessionId, taskId, sequence, eventId(tenantId, sessionId, taskId, sequence),
|
||||
occurredAt, SCHEMA_VERSION, PROJECTION_VERSION, text, truncated,
|
||||
@@ -178,9 +178,9 @@ public class ManagedTaskEventStore
|
||||
public int markOutputArchived(String tenantId, String sessionId, String taskId, long throughSequence) {
|
||||
return transaction(() -> {
|
||||
lockStream(tenantId, sessionId, taskId, 0);
|
||||
return jdbc.update("UPDATE ma_public_event SET archived = TRUE WHERE tenant_id = ? AND session_id = ?"
|
||||
return jdbc.update("UPDATE ma_public_event SET is_archived = TRUE WHERE tenant_id = ? AND session_id = ?"
|
||||
+ " AND stream_kind = 'TASK' AND stream_id = ? AND event_type = 'output'"
|
||||
+ " AND archived = FALSE AND sequence_id <= ?",
|
||||
+ " AND is_archived = FALSE AND sequence_id <= ?",
|
||||
tenantId, sessionId, taskId, throughSequence);
|
||||
});
|
||||
}
|
||||
@@ -243,7 +243,7 @@ public class ManagedTaskEventStore
|
||||
|
||||
private Long oldestUnarchived(String tenantId, String sessionId, String taskId) {
|
||||
return jdbc.queryForObject("SELECT MIN(sequence_id) FROM ma_public_event WHERE tenant_id = ? AND session_id = ?"
|
||||
+ " AND stream_kind = 'TASK' AND stream_id = ? AND event_type = 'output' AND archived = FALSE",
|
||||
+ " AND stream_kind = 'TASK' AND stream_id = ? AND event_type = 'output' AND is_archived = FALSE",
|
||||
Long.class, tenantId, sessionId, taskId);
|
||||
}
|
||||
|
||||
@@ -378,8 +378,8 @@ public class ManagedTaskEventStore
|
||||
return new TaskEvent(result.getLong("event_sequence"), result.getString("event_type"),
|
||||
result.getLong("occurred_at"), result.getInt("schema_version"), result.getInt("projection_version"),
|
||||
result.getString("state"), result.getString("runtime_state"), result.getString("text"),
|
||||
result.getObject("truncated", Boolean.class), result.getString("artifact_id"),
|
||||
result.getObject("is_truncated", Boolean.class), result.getString("artifact_id"),
|
||||
result.getString("capture_id"), result.getString("stream_id"), result.getObject("first_ordinal", Long.class),
|
||||
result.getObject("end_ordinal", Long.class), result.getBoolean("archived"));
|
||||
result.getObject("end_ordinal", Long.class), result.getBoolean("is_archived"));
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -119,7 +119,7 @@ public class ManagedToolResultProjector {
|
||||
private Projection resolve(Source source, ToolPublicationRetentionStore.ReadLease lease, Runnable guard) throws IOException {
|
||||
guard.run();
|
||||
store.verifySource(source);
|
||||
var candidates = jdbc.query("SELECT " + ManagedSchemaProjection.OUTPUT_CAPTURE.columns("p") + ", CASE WHEN quarantined THEN 1 ELSE 0 END AS quarantine_mark FROM ma_output_capture p WHERE scope_key = ? AND tenant_id = ?"
|
||||
var candidates = jdbc.query("SELECT " + ManagedSchemaProjection.OUTPUT_CAPTURE.columns("p") + ", CASE WHEN is_quarantined THEN 1 ELSE 0 END AS quarantine_mark FROM ma_output_capture p WHERE scope_key = ? AND tenant_id = ?"
|
||||
+ " AND workspace_id = ? AND session_id = ? AND execution_key = ?",
|
||||
(schemaRow, schemaIndex) -> com.alibaba.qwen.code.runtimebroker.managedschema.ManagedSchemaRows.read(schemaRow),
|
||||
ToolPublicationDataStore.scope(source.sessionKey()),
|
||||
|
||||
+2
-2
@@ -119,7 +119,7 @@ public class ManagedToolResultStore
|
||||
+ " (SELECT 1 FROM ma_session s WHERE"
|
||||
+ " s.tenant_id = ma_operation.tenant_id"
|
||||
+ " AND s.session_id ="
|
||||
+ " ma_operation.session_id AND s.csi_guard"
|
||||
+ " ma_operation.session_id AND s.is_csi_guard"
|
||||
+ " = TRUE) AND state = ? AND "
|
||||
+ due
|
||||
+ " <= "
|
||||
@@ -472,7 +472,7 @@ public class ManagedToolResultStore
|
||||
var rows =
|
||||
jdbc.query(
|
||||
"SELECT state, producer_phase, binding_digest, admission_resource_id,"
|
||||
+ " receipt_sequence, receipt_revision, CASE WHEN quarantined THEN 1"
|
||||
+ " receipt_sequence, receipt_revision, CASE WHEN is_quarantined THEN 1"
|
||||
+ " ELSE 0 END AS quarantine_mark FROM ma_output_capture WHERE"
|
||||
+ " scope_key = ? AND tenant_id = ? AND workspace_id = ? AND session_id"
|
||||
+ " = ? AND publication_id = ? FOR UPDATE",
|
||||
|
||||
+7
-7
@@ -102,7 +102,7 @@ public class ManagedUserMessageStore
|
||||
String input = "edit".equals(command.action()) ? encode(agents.userMessageInput(command.input())) : null;
|
||||
if (input == null && snapshot(tenant, session).messages().stream()
|
||||
.anyMatch(message -> message.id().equals(command.messageId()) && "recovery_blocked".equals(message.state()))) {
|
||||
jdbc.update("UPDATE ma_user_message_queue SET paused = TRUE WHERE tenant_id = ? AND session_id = ?", tenant, session);
|
||||
jdbc.update("UPDATE ma_user_message_queue SET is_paused = TRUE WHERE tenant_id = ? AND session_id = ?", tenant, session);
|
||||
}
|
||||
// Keep a blocked claim's identity so a late durable receipt can still settle it.
|
||||
int changed = input == null
|
||||
@@ -126,7 +126,7 @@ public class ManagedUserMessageStore
|
||||
throw conflict("user_message_recovery_blocked");
|
||||
}
|
||||
String turn = latestTurn(tenant, session).get("turnId");
|
||||
jdbc.update("UPDATE ma_user_message_queue SET paused = FALSE, resumed_turn_id = ? WHERE tenant_id = ? AND session_id = ?",
|
||||
jdbc.update("UPDATE ma_user_message_queue SET is_paused = FALSE, resumed_turn_id = ? WHERE tenant_id = ? AND session_id = ?",
|
||||
turn, tenant, session);
|
||||
}
|
||||
default -> throw refusal("invalid_request", "Unknown user message action.");
|
||||
@@ -160,7 +160,7 @@ public class ManagedUserMessageStore
|
||||
if (mismatches != null && mismatches > 0) {
|
||||
jdbc.update("UPDATE ma_user_message SET state = 'recovery_blocked' WHERE tenant_id = ? AND session_id = ? AND state = 'queued'",
|
||||
tenant, session);
|
||||
jdbc.update("UPDATE ma_user_message_queue SET paused = TRUE WHERE tenant_id = ? AND session_id = ?", tenant, session);
|
||||
jdbc.update("UPDATE ma_user_message_queue SET is_paused = TRUE WHERE tenant_id = ? AND session_id = ?", tenant, session);
|
||||
return List.of();
|
||||
}
|
||||
jdbc.update("UPDATE ma_user_message SET state = 'claimed', turn_id = ?, prompt_id = ? WHERE tenant_id = ?"
|
||||
@@ -173,7 +173,7 @@ public class ManagedUserMessageStore
|
||||
return jdbc.query("SELECT DISTINCT m.tenant_id, m.session_id, q.last_dispatch_at FROM ma_user_message m JOIN ma_session s"
|
||||
+ " ON s.tenant_id = m.tenant_id AND s.session_id = m.session_id JOIN ma_user_message_queue q"
|
||||
+ " ON q.tenant_id = m.tenant_id AND q.session_id = m.session_id WHERE s.status = 'ACTIVE'"
|
||||
+ " AND q.paused = FALSE AND m.state = 'queued' AND NOT EXISTS (SELECT 1 FROM ma_turn t"
|
||||
+ " AND q.is_paused = FALSE AND m.state = 'queued' AND NOT EXISTS (SELECT 1 FROM ma_turn t"
|
||||
+ " WHERE t.tenant_id = m.tenant_id AND t.session_id = m.session_id AND t.status IN ('ACCEPTED', 'RUNNING', 'CANCELLING', 'RECOVERY_BLOCKED'))"
|
||||
+ " AND NOT EXISTS (SELECT 1 FROM ma_user_message blocked WHERE blocked.tenant_id = m.tenant_id"
|
||||
+ " AND blocked.session_id = m.session_id AND blocked.state IN ('claimed', 'recovery_blocked'))"
|
||||
@@ -209,7 +209,7 @@ public class ManagedUserMessageStore
|
||||
+ " AND state = 'queued' AND COALESCE(context_revision, -1) <> COALESCE(?, -1)", Integer.class, tenant, session, context);
|
||||
if (mismatches != null && mismatches > 0) {
|
||||
jdbc.update("UPDATE ma_user_message SET state = 'recovery_blocked' WHERE tenant_id = ? AND session_id = ? AND state = 'queued'", tenant, session);
|
||||
jdbc.update("UPDATE ma_user_message_queue SET paused = TRUE WHERE tenant_id = ? AND session_id = ?", tenant, session);
|
||||
jdbc.update("UPDATE ma_user_message_queue SET is_paused = TRUE WHERE tenant_id = ? AND session_id = ?", tenant, session);
|
||||
return;
|
||||
}
|
||||
Message first = snapshot.messages().getFirst();
|
||||
@@ -270,7 +270,7 @@ public class ManagedUserMessageStore
|
||||
String resumed = jdbc.queryForObject("SELECT resumed_turn_id FROM ma_user_message_queue WHERE tenant_id = ? AND session_id = ?",
|
||||
String.class, tenant, session);
|
||||
if (!Objects.equals(resumed, turn.get("turnId"))) {
|
||||
jdbc.update("UPDATE ma_user_message_queue SET paused = TRUE WHERE tenant_id = ? AND session_id = ?", tenant, session);
|
||||
jdbc.update("UPDATE ma_user_message_queue SET is_paused = TRUE WHERE tenant_id = ? AND session_id = ?", tenant, session);
|
||||
}
|
||||
}
|
||||
jdbc.update("UPDATE ma_user_message SET state = 'recovery_blocked' WHERE tenant_id = ? AND session_id = ? AND state = 'claimed'"
|
||||
@@ -279,7 +279,7 @@ public class ManagedUserMessageStore
|
||||
}
|
||||
|
||||
private Snapshot snapshot(String tenant, String session) {
|
||||
boolean paused = Boolean.TRUE.equals(jdbc.queryForObject("SELECT paused FROM ma_user_message_queue"
|
||||
boolean paused = Boolean.TRUE.equals(jdbc.queryForObject("SELECT is_paused FROM ma_user_message_queue"
|
||||
+ " WHERE tenant_id = ? AND session_id = ?", Boolean.class, tenant, session));
|
||||
List<Message> messages = read(tenant, session, "state IN ('queued', 'claimed', 'recovery_blocked')");
|
||||
return new Snapshot(paused || messages.stream().anyMatch(message -> "recovery_blocked".equals(message.state())), messages);
|
||||
|
||||
+1
-1
@@ -85,7 +85,7 @@ public final class ResidentWorkspaces extends com.alibaba.qwen.code.managedagent
|
||||
+ " AND b.canonical_cwd = ? AND b.storage_id = ? AND b.capability_digest = ?"
|
||||
+ " AND b.isolation_class = 'workspace' AND b.isolation_key IS NULL"
|
||||
+ " AND b.provisioner_kind = 'kubernetes-workspace' AND b.binding_state = 'READY'"
|
||||
+ " AND b.drain_requested = FALSE AND b.resource_handle_json IS NOT NULL"
|
||||
+ " AND b.is_drain_requested = FALSE AND b.resource_handle_json IS NOT NULL"
|
||||
+ " AND b.provision_seed_ciphertext IS NOT NULL AND b.attestation_generation > 0 FOR UPDATE",
|
||||
(row, index) -> new Original(row.getString(1), row.getLong(2), row.getString(3)), request(binding).requestKey(), tenantId,
|
||||
binding.getWorkspaceId(), Long.toString(binding.getWorkspaceGeneration()), selected.registration().mountRoot(),
|
||||
|
||||
+5
-5
@@ -36,7 +36,7 @@ public final class SessionResourceCollectionCollector {
|
||||
+ " AND object_version_id IS NULL AND encryption_key_id IS NULL AND"
|
||||
+ " deletion_operation_key IS NULL AND NOT EXISTS (SELECT 1 FROM ma_resource_ref f"
|
||||
+ " WHERE f.resource_key = ma_resource.resource_key) THEN 1 ELSE 0 END AS"
|
||||
+ " collectible FROM ma_resource USE INDEX (ix_ma_resource_scope_page) WHERE"
|
||||
+ " collectible FROM ma_resource USE INDEX (idx_ma_resource_scope_page) WHERE"
|
||||
+ " session_scope_key = ? AND resource_key > ? ORDER BY resource_key LIMIT "
|
||||
+ (PAGE_ROWS + 1);
|
||||
private final JdbcTemplate jdbc;
|
||||
@@ -138,7 +138,7 @@ public final class SessionResourceCollectionCollector {
|
||||
var rows =
|
||||
jdbc.query(
|
||||
"SELECT s.tenant_id, s.session_id, s.session_scope_key FROM ma_session s"
|
||||
+ " WHERE s.csi_guard = FALSE AND s.retired_at <= ? AND NOT EXISTS"
|
||||
+ " WHERE s.is_csi_guard = FALSE AND s.retired_at <= ? AND NOT EXISTS"
|
||||
+ " (SELECT 1 FROM ma_operation o WHERE o.operation_kind ="
|
||||
+ " 'SESSION_RESOURCE_GC' AND o.scope_key = s.session_scope_key AND"
|
||||
+ " o.target_key = s.session_scope_key LIMIT 1) ORDER BY s.retired_at"
|
||||
@@ -181,7 +181,7 @@ public final class SessionResourceCollectionCollector {
|
||||
Claim claim() {
|
||||
long time = ToolPublicationRetentionStore.now(jdbc);
|
||||
var candidates = jdbc.query(
|
||||
"SELECT scope_key, tenant_id, session_id FROM ma_operation WHERE operation_kind = 'SESSION_RESOURCE_GC' AND NOT EXISTS (SELECT 1 FROM ma_session s WHERE s.tenant_id = ma_operation.tenant_id AND s.session_id = ma_operation.session_id AND s.csi_guard = TRUE) AND state <> 'SUCCEEDED' AND available_at >= 0 AND available_at <= ? AND (claim_owner = ? OR claim_until IS NULL OR claim_until <= ?) ORDER BY available_at, operation_key LIMIT 32",
|
||||
"SELECT scope_key, tenant_id, session_id FROM ma_operation WHERE operation_kind = 'SESSION_RESOURCE_GC' AND NOT EXISTS (SELECT 1 FROM ma_session s WHERE s.tenant_id = ma_operation.tenant_id AND s.session_id = ma_operation.session_id AND s.is_csi_guard = TRUE) AND state <> 'SUCCEEDED' AND available_at >= 0 AND available_at <= ? AND (claim_owner = ? OR claim_until IS NULL OR claim_until <= ?) ORDER BY available_at, operation_key LIMIT 32",
|
||||
(row, index) -> ManagedSchemaRows.read(row), time, owner, time);
|
||||
for (var candidate : candidates) {
|
||||
Claim claim =
|
||||
@@ -289,7 +289,7 @@ public final class SessionResourceCollectionCollector {
|
||||
private String blocker(String tenant, String session, long now, java.util.Map<String, Object> head) {
|
||||
var roots =
|
||||
jdbc.query(
|
||||
"SELECT retired_at, recovery_protected FROM ma_session WHERE tenant_key = ?"
|
||||
"SELECT retired_at, is_recovery_protected FROM ma_session WHERE tenant_key = ?"
|
||||
+ " AND session_key = ? AND retired_at IS NOT NULL",
|
||||
(schemaRow, schemaIndex) -> ManagedSchemaRows.read(schemaRow),
|
||||
ToolPublicationRetentionStore.hash(tenant),
|
||||
@@ -297,7 +297,7 @@ public final class SessionResourceCollectionCollector {
|
||||
if (roots.isEmpty()) {
|
||||
return "session_not_retired";
|
||||
}
|
||||
if (ToolPublicationRetentionStore.flag(roots.getFirst(), "recovery_protected")) {
|
||||
if (ToolPublicationRetentionStore.flag(roots.getFirst(), "is_recovery_protected")) {
|
||||
return "recovery_protected";
|
||||
}
|
||||
if (ToolPublicationRetentionStore.number(roots.getFirst(), "retired_at")
|
||||
|
||||
+1
-1
@@ -202,7 +202,7 @@ public class SessionWorktreeStore
|
||||
public List<String[]> failedInitialSessions() {
|
||||
return jdbc.query("SELECT DISTINCT w.tenant_id, w.session_id, w.failure_code FROM ma_session_worktree w"
|
||||
+ " JOIN ma_turn t ON t.tenant_id = w.tenant_id AND t.session_id = w.session_id"
|
||||
+ " WHERE w.state IN ('FAILED','BLOCKED') AND t.status = 'ACCEPTED' AND t.submission_attempted = FALSE LIMIT 20",
|
||||
+ " WHERE w.state IN ('FAILED','BLOCKED') AND t.status = 'ACCEPTED' AND t.is_submission_attempted = FALSE LIMIT 20",
|
||||
(result, index) -> new String[] {result.getString("tenant_id"), result.getString("session_id"), result.getString("failure_code")});
|
||||
}
|
||||
|
||||
|
||||
+5
-5
@@ -129,11 +129,11 @@ public final class ToolPublicationAdmissionStore {
|
||||
String suffix = locked ? " FOR UPDATE" : "";
|
||||
var publication = jdbc.query("SELECT scope_key, publication_id, tenant_id, workspace_id, session_id, producer_phase,"
|
||||
+ " admission_resource_id, receipt_sequence, receipt_revision,"
|
||||
+ " CASE WHEN quarantined THEN 1 ELSE 0 END AS quarantined"
|
||||
+ " CASE WHEN is_quarantined THEN 1 ELSE 0 END AS is_quarantined"
|
||||
+ " FROM ma_output_capture WHERE scope_key = ? AND publication_id = ?" + suffix, (schemaRow, schemaIndex) -> ManagedSchemaRows.read(schemaRow), scope(key), id).getFirst();
|
||||
require(scope(key).equals(publication.get("scope_key")) && id.equals(publication.get("publication_id"))
|
||||
&& "REFERENCED".equals(publication.get("producer_phase"))
|
||||
&& ((Number) publication.get("quarantined")).intValue() == 0
|
||||
&& ((Number) publication.get("is_quarantined")).intValue() == 0
|
||||
&& text(key, "tenantId").equals(publication.get("tenant_id"))
|
||||
&& text(key, "workspaceId").equals(publication.get("workspace_id"))
|
||||
&& text(key, "sessionId").equals(publication.get("session_id"))
|
||||
@@ -374,7 +374,7 @@ public final class ToolPublicationAdmissionStore {
|
||||
sessions.lockPublicationWriter(text(key, "tenantId"), text(key, "workspaceId"),
|
||||
text(key, "sessionId"), request.writerId(), request.writerGeneration(), writerToken);
|
||||
Map<String, Object> publication = jdbc.query("SELECT producer_phase, binding_json, binding_digest,"
|
||||
+ " CASE WHEN quarantined THEN 1 ELSE 0 END AS quarantined, admission_resource_id,"
|
||||
+ " CASE WHEN is_quarantined THEN 1 ELSE 0 END AS is_quarantined, admission_resource_id,"
|
||||
+ " receipt_sequence, receipt_revision, finish_digest, terminal_resource_id"
|
||||
+ " FROM ma_output_capture WHERE scope_key = ? AND publication_id = ? AND tenant_id = ?"
|
||||
+ " AND workspace_id = ? AND session_id = ? FOR UPDATE", (schemaRow, schemaIndex) -> ManagedSchemaRows.read(schemaRow), scope, publicationId,
|
||||
@@ -382,7 +382,7 @@ public final class ToolPublicationAdmissionStore {
|
||||
ToolPublicationStore.requireLockedBinding(publication, finished.path("binding"));
|
||||
require(resourceId.equals(publication.get("admission_resource_id"))
|
||||
&& candidate.get("terminal_resource_id").equals(publication.get("terminal_resource_id"))
|
||||
&& ((Number) publication.get("quarantined")).intValue() == 0,
|
||||
&& ((Number) publication.get("is_quarantined")).intValue() == 0,
|
||||
"Admission root changed");
|
||||
var object = jdbc.query("SELECT capture_state AS state, sha256, byte_length, capture_object_key AS object_key"
|
||||
+ " FROM ma_resource WHERE scope_key = ? AND publication_id = ?"
|
||||
@@ -410,7 +410,7 @@ public final class ToolPublicationAdmissionStore {
|
||||
}
|
||||
var receipt = sessions.commit(text(key, "tenantId"), text(key, "sessionId"),
|
||||
writerToken, request, authority);
|
||||
jdbc.update("UPDATE ma_output_capture SET gmt_modified = " + ManagedSchemaTime.SQL_NOW + ", producer_phase = 'REFERENCED', admission_held_bytes = admission_used_bytes, receipt_sequence = ?, receipt_revision = ?, accepted_complete = ? WHERE scope_key = ? AND publication_id = ?",
|
||||
jdbc.update("UPDATE ma_output_capture SET gmt_modified = " + ManagedSchemaTime.SQL_NOW + ", producer_phase = 'REFERENCED', admission_held_bytes = admission_used_bytes, receipt_sequence = ?, receipt_revision = ?, is_accepted_complete = ? WHERE scope_key = ? AND publication_id = ?",
|
||||
request.lastSequence(), receipt.journalRevision(),
|
||||
"committed".equals(outcome.path("decision").asText())
|
||||
&& "complete".equals(outcome.path("envelope").path("capture").path("captureStatus").asText()),
|
||||
|
||||
+4
-4
@@ -126,8 +126,8 @@ public final class ToolPublicationCollector {
|
||||
+ " c.session_id FROM ma_output_capture c WHERE c.retention_state ="
|
||||
+ " 'RETIRING' AND NOT EXISTS (SELECT 1 FROM ma_session s WHERE"
|
||||
+ " s.tenant_id = c.tenant_id AND s.session_id = c.session_id AND"
|
||||
+ " s.csi_guard = TRUE) AND NOT EXISTS (SELECT 1 FROM ma_operation o"
|
||||
+ " USE INDEX (ix_ma_operation_publication) WHERE o.scope_key ="
|
||||
+ " s.is_csi_guard = TRUE) AND NOT EXISTS (SELECT 1 FROM ma_operation o"
|
||||
+ " USE INDEX (idx_ma_operation_publication) WHERE o.scope_key ="
|
||||
+ " c.scope_key AND o.publication_id = c.publication_id AND"
|
||||
+ " o.operation_kind = 'CAPTURE_GC' LIMIT 1) LIMIT 32",
|
||||
(row, index) -> ManagedSchemaRows.read(row));
|
||||
@@ -206,7 +206,7 @@ public final class ToolPublicationCollector {
|
||||
long time = ToolPublicationRetentionStore.now(jdbc);
|
||||
var candidates =
|
||||
jdbc.query(
|
||||
"SELECT scope_key, publication_id, tenant_id, session_id FROM ma_operation WHERE operation_kind = 'CAPTURE_GC' AND NOT EXISTS (SELECT 1 FROM ma_session s WHERE s.tenant_id = ma_operation.tenant_id AND s.session_id = ma_operation.session_id AND s.csi_guard = TRUE) AND state <> 'SUCCEEDED' AND available_at >= 0 AND available_at <= ? AND (claim_owner = ? OR claim_until IS NULL OR claim_until <= ?) ORDER BY available_at, operation_key LIMIT 32",
|
||||
"SELECT scope_key, publication_id, tenant_id, session_id FROM ma_operation WHERE operation_kind = 'CAPTURE_GC' AND NOT EXISTS (SELECT 1 FROM ma_session s WHERE s.tenant_id = ma_operation.tenant_id AND s.session_id = ma_operation.session_id AND s.is_csi_guard = TRUE) AND state <> 'SUCCEEDED' AND available_at >= 0 AND available_at <= ? AND (claim_owner = ? OR claim_until IS NULL OR claim_until <= ?) ORDER BY available_at, operation_key LIMIT 32",
|
||||
(row, index) -> ManagedSchemaRows.read(row),
|
||||
time,
|
||||
owner,
|
||||
@@ -333,7 +333,7 @@ public final class ToolPublicationCollector {
|
||||
|
||||
private boolean sessionCollectionPending(String tenant, String session) {
|
||||
return !Boolean.TRUE.equals(jdbc.queryForObject(
|
||||
"SELECT resource_gc_completed FROM ma_session WHERE tenant_id = ? AND session_id"
|
||||
"SELECT is_resource_gc_completed FROM ma_session WHERE tenant_id = ? AND session_id"
|
||||
+ " = ?", Boolean.class, tenant, session));
|
||||
}
|
||||
|
||||
|
||||
+31
-31
@@ -163,10 +163,10 @@ public final class ToolPublicationDataStore {
|
||||
capture.set(field, manifest.path(field));
|
||||
}
|
||||
var publication = jdbc.query("SELECT producer_phase, admission_resource_id,"
|
||||
+ " CASE WHEN quarantined THEN 1 ELSE 0 END AS quarantined FROM ma_output_capture"
|
||||
+ " CASE WHEN is_quarantined THEN 1 ELSE 0 END AS is_quarantined FROM ma_output_capture"
|
||||
+ " WHERE scope_key = ? AND publication_id = ?", (schemaRow, schemaIndex) -> ManagedSchemaRows.read(schemaRow), scope(key), publicationId).getFirst();
|
||||
require("REFERENCED".equals(publication.get("producer_phase"))
|
||||
&& ((Number) publication.get("quarantined")).intValue() == 0,
|
||||
&& ((Number) publication.get("is_quarantined")).intValue() == 0,
|
||||
"Original publication receipt is unavailable");
|
||||
String admissionId = (String) publication.get("admission_resource_id");
|
||||
byte[] bytes = readResource(key, publicationId, admissionId);
|
||||
@@ -355,7 +355,7 @@ public final class ToolPublicationDataStore {
|
||||
+ " AND publication_id = ? AND slot_key = ? AND operation_id = ? AND capture_state = 'CANDIDATE'",
|
||||
bytes, scope, publicationId, slot, operationId);
|
||||
}
|
||||
jdbc.update("UPDATE ma_operation SET gmt_modified = " + ManagedSchemaTime.SQL_NOW + ", verification_ready = TRUE, verification_next_at = ?, claim_owner = NULL, claim_until = NULL WHERE operation_kind IN ('OUTPUT_UPLOAD', 'OUTPUT_VERIFY', 'OUTPUT_FINISH') AND scope_key = ? AND publication_id = ? AND operation_id = ?",
|
||||
jdbc.update("UPDATE ma_operation SET gmt_modified = " + ManagedSchemaTime.SQL_NOW + ", is_verification_ready = TRUE, verification_next_at = ?, claim_owner = NULL, claim_until = NULL WHERE operation_kind IN ('OUTPUT_UPLOAD', 'OUTPUT_VERIFY', 'OUTPUT_FINISH') AND scope_key = ? AND publication_id = ? AND operation_id = ?",
|
||||
now(), scope, publicationId, operationId);
|
||||
});
|
||||
verificationWakeup.run();
|
||||
@@ -367,7 +367,7 @@ public final class ToolPublicationDataStore {
|
||||
}
|
||||
|
||||
boolean verifyNextOperation() {
|
||||
var candidates = jdbc.query("SELECT scope_key, publication_id, operation_id, claim_generation, verification_request_json FROM ma_operation WHERE operation_kind IN ('OUTPUT_UPLOAD', 'OUTPUT_VERIFY', 'OUTPUT_FINISH') AND execution_mode = 'ASYNC' AND state = 'PENDING' AND verification_ready = TRUE AND verification_next_at <= " + ManagedSchemaTime.SQL_NOW + " ORDER BY verification_next_at, scope_key, publication_id, operation_id LIMIT 32", (schemaRow, schemaIndex) -> ManagedSchemaRows.read(schemaRow));
|
||||
var candidates = jdbc.query("SELECT scope_key, publication_id, operation_id, claim_generation, verification_request_json FROM ma_operation WHERE operation_kind IN ('OUTPUT_UPLOAD', 'OUTPUT_VERIFY', 'OUTPUT_FINISH') AND execution_mode = 'ASYNC' AND state = 'PENDING' AND is_verification_ready = TRUE AND verification_next_at <= " + ManagedSchemaTime.SQL_NOW + " ORDER BY verification_next_at, scope_key, publication_id, operation_id LIMIT 32", (schemaRow, schemaIndex) -> ManagedSchemaRows.read(schemaRow));
|
||||
boolean processed = false;
|
||||
for (var candidate : candidates) {
|
||||
String scope = (String) candidate.get("scope_key");
|
||||
@@ -841,7 +841,7 @@ public final class ToolPublicationDataStore {
|
||||
require(operationId != null && operationId.matches("[a-z0-9_-]{1,128}"),
|
||||
"Invalid publication operation ID");
|
||||
String scope = scope(key);
|
||||
var rows = jdbc.query("SELECT o.state, o.result_json, o.failure_status, o.failure_code, CASE WHEN o.execution_mode = 'ASYNC' AND o.verification_ready THEN 1 ELSE 0 END AS ready, COALESCE(o.recovery_deadline, o.deadline) AS deadline, CASE WHEN o.claim_owner IS NULL OR o.claim_until < " + ManagedSchemaTime.SQL_NOW + " THEN 1 ELSE 0 END AS retryable, p.tenant_id, p.token_hash, p.workspace_id, p.session_id FROM ma_operation o JOIN ma_output_capture p ON p.scope_key = o.scope_key AND p.publication_id = o.publication_id WHERE o.operation_kind IN ('OUTPUT_UPLOAD', 'OUTPUT_VERIFY', 'OUTPUT_FINISH') AND o.scope_key = ? AND o.publication_id = ? AND o.operation_id = ?",
|
||||
var rows = jdbc.query("SELECT o.state, o.result_json, o.failure_status, o.failure_code, CASE WHEN o.execution_mode = 'ASYNC' AND o.is_verification_ready THEN 1 ELSE 0 END AS ready, COALESCE(o.recovery_deadline, o.deadline) AS deadline, CASE WHEN o.claim_owner IS NULL OR o.claim_until < " + ManagedSchemaTime.SQL_NOW + " THEN 1 ELSE 0 END AS retryable, p.tenant_id, p.token_hash, p.workspace_id, p.session_id FROM ma_operation o JOIN ma_output_capture p ON p.scope_key = o.scope_key AND p.publication_id = o.publication_id WHERE o.operation_kind IN ('OUTPUT_UPLOAD', 'OUTPUT_VERIFY', 'OUTPUT_FINISH') AND o.scope_key = ? AND o.publication_id = ? AND o.operation_id = ?",
|
||||
(r, n) -> {
|
||||
Map<String, Object> row = new HashMap<>();
|
||||
for (String field : List.of("state", "tenant_id", "workspace_id", "session_id", "token_hash",
|
||||
@@ -892,10 +892,10 @@ public final class ToolPublicationDataStore {
|
||||
transactions.executeWithoutResult(status -> {
|
||||
var authorization = authorizeClaim(key, scope, publicationId, token);
|
||||
var publication = jdbc.query("SELECT producer_phase, finish_operation_id,"
|
||||
+ " finish_predecessor_id, CASE WHEN quarantined THEN 1 ELSE 0 END AS quarantined"
|
||||
+ " finish_predecessor_id, CASE WHEN is_quarantined THEN 1 ELSE 0 END AS is_quarantined"
|
||||
+ " FROM ma_output_capture WHERE scope_key = ? AND publication_id = ?", (schemaRow, schemaIndex) -> ManagedSchemaRows.read(schemaRow),
|
||||
scope, publicationId).getFirst();
|
||||
require(((Number) publication.get("quarantined")).intValue() == 0,
|
||||
require(((Number) publication.get("is_quarantined")).intValue() == 0,
|
||||
"Publication is quarantined");
|
||||
List<Operation> rows = operation(scope, publicationId, operationId, true);
|
||||
require(rows.size() == 1, "Publication operation is missing");
|
||||
@@ -1063,7 +1063,7 @@ public final class ToolPublicationDataStore {
|
||||
private JsonNode finishedInternal(JsonNode key, String publicationId) {
|
||||
String scope = scope(key);
|
||||
var publications = jdbc.query("SELECT producer_phase,"
|
||||
+ " CASE WHEN quarantined THEN 1 ELSE 0 END AS quarantined, binding_json,"
|
||||
+ " CASE WHEN is_quarantined THEN 1 ELSE 0 END AS is_quarantined, binding_json,"
|
||||
+ " terminal_resource_id, finish_operation_id FROM ma_output_capture"
|
||||
+ " WHERE scope_key = ? AND publication_id = ? AND tenant_id = ?"
|
||||
+ " AND workspace_id = ? AND session_id = ?", (schemaRow, schemaIndex) -> ManagedSchemaRows.read(schemaRow), scope, publicationId,
|
||||
@@ -1074,7 +1074,7 @@ public final class ToolPublicationDataStore {
|
||||
require("FINISHED".equals(publication.get("producer_phase"))
|
||||
|| "REFERENCED".equals(publication.get("producer_phase")),
|
||||
"Publication has no finished result");
|
||||
require(((Number) publication.get("quarantined")).intValue() == 0,
|
||||
require(((Number) publication.get("is_quarantined")).intValue() == 0,
|
||||
"Finished publication is quarantined");
|
||||
String resourceId = (String) publication.get("terminal_resource_id");
|
||||
Resource terminal = catalogResource(key, publicationId, resourceId);
|
||||
@@ -1121,7 +1121,7 @@ public final class ToolPublicationDataStore {
|
||||
sessions.lockPublicationWriter(text(key, "tenantId"), text(key, "workspaceId"),
|
||||
text(key, "sessionId"), writerId, writerGeneration, writerToken);
|
||||
var publication = jdbc.query("SELECT producer_phase, binding_json, binding_digest,"
|
||||
+ " CASE WHEN quarantined THEN 1 ELSE 0 END AS quarantined,"
|
||||
+ " CASE WHEN is_quarantined THEN 1 ELSE 0 END AS is_quarantined,"
|
||||
+ " admission_bytes, admission_used_bytes,"
|
||||
+ " admission_resource_id, terminal_resource_id FROM ma_output_capture"
|
||||
+ " WHERE scope_key = ? AND publication_id = ? AND tenant_id = ?"
|
||||
@@ -1131,7 +1131,7 @@ public final class ToolPublicationDataStore {
|
||||
require("FINISHED".equals(publication.get("producer_phase"))
|
||||
|| "REFERENCED".equals(publication.get("producer_phase")),
|
||||
"Publication is not finished");
|
||||
require(((Number) publication.get("quarantined")).intValue() == 0,
|
||||
require(((Number) publication.get("is_quarantined")).intValue() == 0,
|
||||
"Publication is quarantined");
|
||||
require(original.path("terminal").path("resourceId").asText()
|
||||
.equals(publication.get("terminal_resource_id")),
|
||||
@@ -1181,13 +1181,13 @@ public final class ToolPublicationDataStore {
|
||||
sessions.lockPublicationWriter(text(key, "tenantId"), text(key, "workspaceId"),
|
||||
text(key, "sessionId"), writerId, writerGeneration, writerToken);
|
||||
var publication = jdbc.query("SELECT producer_phase, terminal_resource_id, binding_json, binding_digest,"
|
||||
+ " CASE WHEN quarantined THEN 1 ELSE 0 END AS quarantined"
|
||||
+ " CASE WHEN is_quarantined THEN 1 ELSE 0 END AS is_quarantined"
|
||||
+ " FROM ma_output_capture WHERE scope_key = ? AND publication_id = ? AND tenant_id = ?"
|
||||
+ " AND workspace_id = ? AND session_id = ? FOR UPDATE", (schemaRow, schemaIndex) -> ManagedSchemaRows.read(schemaRow), scope, publicationId,
|
||||
text(key, "tenantId"), text(key, "workspaceId"), text(key, "sessionId")).getFirst();
|
||||
ToolPublicationStore.requireLockedBinding(publication, original.path("binding"));
|
||||
require("FINISHED".equals(publication.get("producer_phase"))
|
||||
&& ((Number) publication.get("quarantined")).intValue() == 0
|
||||
&& ((Number) publication.get("is_quarantined")).intValue() == 0
|
||||
&& original.path("terminal").path("resourceId").asText()
|
||||
.equals(publication.get("terminal_resource_id")), "Admission publication changed");
|
||||
Stored row = stored(scope, publicationId, "admission", true).get(0);
|
||||
@@ -1285,11 +1285,11 @@ public final class ToolPublicationDataStore {
|
||||
return new FinishClaim(0, null, terminal.objectKey(), terminal.resourceId(), binding, receipt);
|
||||
}
|
||||
Map<String, Object> row = jdbc.query("SELECT producer_phase, active_operation_id,"
|
||||
+ " CASE WHEN quarantined THEN 1 ELSE 0 END AS quarantined,"
|
||||
+ " CASE WHEN is_quarantined THEN 1 ELSE 0 END AS is_quarantined,"
|
||||
+ " finish_operation_id, finish_predecessor_id, finish_digest, producer_bytes,"
|
||||
+ " producer_used_bytes FROM ma_output_capture WHERE scope_key = ?"
|
||||
+ " AND publication_id = ?", (schemaRow, schemaIndex) -> ManagedSchemaRows.read(schemaRow), scope, publicationId).getFirst();
|
||||
require(((Number) row.get("quarantined")).intValue() == 0,
|
||||
require(((Number) row.get("is_quarantined")).intValue() == 0,
|
||||
"Publication is quarantined");
|
||||
String phase = (String) row.get("producer_phase");
|
||||
require("OPEN".equals(phase) || "FINISHING".equals(phase) || "FINISHED".equals(phase),
|
||||
@@ -1367,7 +1367,7 @@ public final class ToolPublicationDataStore {
|
||||
List<Operation> current = operation(scope, publicationId, operationId, true);
|
||||
requireOperationClaim(current, claim.epoch(), now());
|
||||
Map<String, Object> publication = jdbc.query("SELECT producer_phase,"
|
||||
+ " CASE WHEN quarantined THEN 1 ELSE 0 END AS quarantined, finish_operation_id,"
|
||||
+ " CASE WHEN is_quarantined THEN 1 ELSE 0 END AS is_quarantined, finish_operation_id,"
|
||||
+ " finish_predecessor_id, finish_digest, active_operation_id, capture_used_bytes,"
|
||||
+ " producer_used_bytes FROM ma_output_capture WHERE scope_key = ?"
|
||||
+ " AND publication_id = ?", (schemaRow, schemaIndex) -> ManagedSchemaRows.read(schemaRow), scope, publicationId).getFirst();
|
||||
@@ -1375,7 +1375,7 @@ public final class ToolPublicationDataStore {
|
||||
&& operationId.equals(publication.get("finish_operation_id"))
|
||||
&& digest.equals(publication.get("finish_digest"))
|
||||
&& publication.get("active_operation_id") == null
|
||||
&& ((Number) publication.get("quarantined")).intValue() == 0,
|
||||
&& ((Number) publication.get("is_quarantined")).intValue() == 0,
|
||||
"Finish barrier changed");
|
||||
if (claim.predecessor() != null) {
|
||||
List<Operation> previous = operation(scope, publicationId, claim.predecessor(), true);
|
||||
@@ -1502,10 +1502,10 @@ public final class ToolPublicationDataStore {
|
||||
return new ScanClaim(0, exactSucceededReplay(scope, publicationId, operationId, slot, requestDigest));
|
||||
}
|
||||
var phase = jdbc.query("SELECT producer_phase, finish_predecessor_id,"
|
||||
+ " CASE WHEN quarantined THEN 1 ELSE 0 END AS quarantined"
|
||||
+ " CASE WHEN is_quarantined THEN 1 ELSE 0 END AS is_quarantined"
|
||||
+ " FROM ma_output_capture WHERE scope_key = ? AND publication_id = ?", (schemaRow, schemaIndex) -> ManagedSchemaRows.read(schemaRow),
|
||||
scope, publicationId).getFirst();
|
||||
require(((Number) phase.get("quarantined")).intValue() == 0,
|
||||
require(((Number) phase.get("is_quarantined")).intValue() == 0,
|
||||
"Publication is quarantined");
|
||||
require("OPEN".equals(phase.get("producer_phase"))
|
||||
|| "FINISHING".equals(phase.get("producer_phase"))
|
||||
@@ -1677,7 +1677,7 @@ public final class ToolPublicationDataStore {
|
||||
requireOperationClaim(rows, epoch, current);
|
||||
long until = Math.min(rows.get(0).deadline().getTime(),
|
||||
current.getTime() + claimTimeout.toMillis());
|
||||
jdbc.update("UPDATE ma_operation SET gmt_modified = " + ManagedSchemaTime.SQL_NOW + ", claim_until = ?, verification_next_at = CASE WHEN execution_mode = 'ASYNC' AND verification_ready THEN ? ELSE verification_next_at END WHERE operation_kind IN ('OUTPUT_UPLOAD', 'OUTPUT_VERIFY', 'OUTPUT_FINISH') AND scope_key = ? AND publication_id = ? AND operation_id = ?",
|
||||
jdbc.update("UPDATE ma_operation SET gmt_modified = " + ManagedSchemaTime.SQL_NOW + ", claim_until = ?, verification_next_at = CASE WHEN execution_mode = 'ASYNC' AND is_verification_ready THEN ? ELSE verification_next_at END WHERE operation_kind IN ('OUTPUT_UPLOAD', 'OUTPUT_VERIFY', 'OUTPUT_FINISH') AND scope_key = ? AND publication_id = ? AND operation_id = ?",
|
||||
new Timestamp(until), new Timestamp(until), scope, publicationId, operationId);
|
||||
});
|
||||
next = System.nanoTime() + interval;
|
||||
@@ -1707,7 +1707,7 @@ public final class ToolPublicationDataStore {
|
||||
transactions.executeWithoutResult(status -> {
|
||||
retention.lockRetainedPublication(scope, publicationId);
|
||||
requireVerificationClaim(scope, publicationId);
|
||||
jdbc.update("UPDATE ma_output_capture SET gmt_modified = " + ManagedSchemaTime.SQL_NOW + ", quarantined = TRUE WHERE scope_key = ? AND publication_id = ?", scope, publicationId);
|
||||
jdbc.update("UPDATE ma_output_capture SET gmt_modified = " + ManagedSchemaTime.SQL_NOW + ", is_quarantined = TRUE WHERE scope_key = ? AND publication_id = ?", scope, publicationId);
|
||||
jdbc.update("UPDATE ma_resource SET capture_state = 'QUARANTINED'"
|
||||
+ " WHERE scope_key = ? AND publication_id = ?"
|
||||
+ " AND slot_key = ? AND capture_state = 'VERIFIED'", scope, publicationId, slot);
|
||||
@@ -1798,10 +1798,10 @@ public final class ToolPublicationDataStore {
|
||||
return new Candidate(saved.objectKey(), saved.resourceId(), 0, replay);
|
||||
}
|
||||
var phase = jdbc.query("SELECT producer_phase, finish_predecessor_id,"
|
||||
+ " CASE WHEN quarantined THEN 1 ELSE 0 END AS quarantined"
|
||||
+ " CASE WHEN is_quarantined THEN 1 ELSE 0 END AS is_quarantined"
|
||||
+ " FROM ma_output_capture WHERE scope_key = ? AND publication_id = ?", (schemaRow, schemaIndex) -> ManagedSchemaRows.read(schemaRow),
|
||||
scope, publicationId).getFirst();
|
||||
require(((Number) phase.get("quarantined")).intValue() == 0,
|
||||
require(((Number) phase.get("is_quarantined")).intValue() == 0,
|
||||
"Publication is quarantined");
|
||||
require("OPEN".equals(phase.get("producer_phase"))
|
||||
|| "FINISHING".equals(phase.get("producer_phase"))
|
||||
@@ -1954,12 +1954,12 @@ public final class ToolPublicationDataStore {
|
||||
private JsonNode exactSucceededReplay(String scope, String publicationId, String operationId,
|
||||
String slot, String requestDigest) {
|
||||
var publication = jdbc.query("SELECT producer_phase, finish_operation_id,"
|
||||
+ " terminal_resource_id, CASE WHEN quarantined THEN 1 ELSE 0 END AS quarantined"
|
||||
+ " terminal_resource_id, CASE WHEN is_quarantined THEN 1 ELSE 0 END AS is_quarantined"
|
||||
+ " FROM ma_output_capture WHERE scope_key = ? AND publication_id = ?", (schemaRow, schemaIndex) -> ManagedSchemaRows.read(schemaRow),
|
||||
scope, publicationId).getFirst();
|
||||
require(("FINISHED".equals(publication.get("producer_phase"))
|
||||
|| "REFERENCED".equals(publication.get("producer_phase")))
|
||||
&& ((Number) publication.get("quarantined")).intValue() == 0,
|
||||
&& ((Number) publication.get("is_quarantined")).intValue() == 0,
|
||||
"Original publication is not finished");
|
||||
List<Operation> prior = operation(scope, publicationId, operationId, true);
|
||||
require(prior.size() == 1 && "SUCCEEDED".equals(prior.get(0).state())
|
||||
@@ -2131,14 +2131,14 @@ public final class ToolPublicationDataStore {
|
||||
|
||||
private List<Operation> operation(String scope, String publicationId, String operationId, boolean locked) {
|
||||
return jdbc.query("SELECT request_digest, slot_key, state, claim_generation, claim_until, execution_mode,"
|
||||
+ " verification_ready,"
|
||||
+ " is_verification_ready,"
|
||||
+ " COALESCE(recovery_deadline, deadline) AS deadline"
|
||||
+ " FROM ma_operation WHERE operation_kind IN ('OUTPUT_UPLOAD', 'OUTPUT_VERIFY', 'OUTPUT_FINISH') AND scope_key = ? AND publication_id = ?"
|
||||
+ " AND operation_id = ?" + (locked ? " FOR UPDATE" : ""),
|
||||
(r, n) -> new Operation(r.getString("request_digest"), r.getString("slot_key"),
|
||||
r.getString("state"), r.getLong("claim_generation"), ManagedSchemaTime.timestamp(r, "claim_until"),
|
||||
ManagedSchemaTime.timestamp(r, "deadline"), "ASYNC".equals(r.getString("execution_mode")),
|
||||
r.getBoolean("verification_ready")), scope, publicationId, operationId);
|
||||
r.getBoolean("is_verification_ready")), scope, publicationId, operationId);
|
||||
}
|
||||
|
||||
private void verify(String scope, String publicationId, String objectKey, long length, String digest) {
|
||||
@@ -2292,7 +2292,7 @@ public final class ToolPublicationDataStore {
|
||||
arguments.add(ToolPublicationRetentionStore.hash(text(key, "sessionId")));
|
||||
arguments.addAll(ids);
|
||||
var rows = jdbc.query("SELECT publication_id, producer_phase, admission_resource_id,"
|
||||
+ " receipt_revision, receipt_sequence, CASE WHEN quarantined THEN 1 ELSE 0 END AS quarantined"
|
||||
+ " receipt_revision, receipt_sequence, CASE WHEN is_quarantined THEN 1 ELSE 0 END AS is_quarantined"
|
||||
+ " FROM ma_output_capture WHERE scope_key = ?"
|
||||
+ " AND tenant_id = ? AND workspace_id = ? AND session_id = ?"
|
||||
+ " AND NOT EXISTS (SELECT 1 FROM ma_session r"
|
||||
@@ -2306,7 +2306,7 @@ public final class ToolPublicationDataStore {
|
||||
|
||||
static boolean referenced(Map<String, Object> row, JsonNode outcomeRef, long revision, long sequence) {
|
||||
return row != null && "REFERENCED".equals(row.get("producer_phase"))
|
||||
&& row.get("quarantined") instanceof Number mark && mark.intValue() == 0
|
||||
&& row.get("is_quarantined") instanceof Number mark && mark.intValue() == 0
|
||||
&& outcomeRef != null && outcomeRef.path("resourceId").isTextual()
|
||||
&& outcomeRef.path("resourceId").asText().equals(row.get("admission_resource_id"))
|
||||
&& row.get("receipt_revision") instanceof Number r && r.longValue() == revision
|
||||
@@ -2318,7 +2318,7 @@ public final class ToolPublicationDataStore {
|
||||
guard.run();
|
||||
String scope = scope(key);
|
||||
var publications = jdbc.query("SELECT binding_json, producer_phase,"
|
||||
+ " CASE WHEN quarantined THEN 1 ELSE 0 END AS quarantined FROM ma_output_capture"
|
||||
+ " CASE WHEN is_quarantined THEN 1 ELSE 0 END AS is_quarantined FROM ma_output_capture"
|
||||
+ " WHERE scope_key = ? AND publication_id = ? AND tenant_id = ?"
|
||||
+ " AND workspace_id = ? AND session_id = ?", (schemaRow, schemaIndex) -> ManagedSchemaRows.read(schemaRow), scope, publicationId,
|
||||
text(key, "tenantId"), text(key, "workspaceId"), text(key, "sessionId"));
|
||||
@@ -2328,7 +2328,7 @@ public final class ToolPublicationDataStore {
|
||||
require(!requireFinished || "FINISHED".equals(publication.get("producer_phase"))
|
||||
|| "REFERENCED".equals(publication.get("producer_phase")),
|
||||
"Publication is not finished");
|
||||
require(((Number) publication.get("quarantined")).intValue() == 0,
|
||||
require(((Number) publication.get("is_quarantined")).intValue() == 0,
|
||||
"Publication is quarantined");
|
||||
JsonNode binding = ToolPublicationContract.readJson(
|
||||
((String) publication.get("binding_json")).getBytes(StandardCharsets.UTF_8));
|
||||
|
||||
+10
-10
@@ -115,11 +115,11 @@ public final class ToolPublicationRetentionStore implements com.alibaba.qwen.cod
|
||||
boundedParameters(jdbc, timeoutSeconds, tenant, session, hash(tenant), hash(session),
|
||||
com.alibaba.qwen.code.managedagent.repository.ManagedSessionStore.sessionScopeKey(tenant, session), time, time));
|
||||
return jdbc.query(
|
||||
"SELECT tenant_id, session_id, csi_guard FROM ma_session WHERE tenant_id = ? AND"
|
||||
"SELECT tenant_id, session_id, is_csi_guard FROM ma_session WHERE tenant_id = ? AND"
|
||||
+ " session_id = ? FOR UPDATE",
|
||||
boundedParameters(jdbc, timeoutSeconds, tenant, session),
|
||||
(row, index) -> {
|
||||
boolean guarded = row.getBoolean("csi_guard");
|
||||
boolean guarded = row.getBoolean("is_csi_guard");
|
||||
if (legacyMutation) {
|
||||
ManagedLegacySessionGuard.requireLegacyMutation(guarded);
|
||||
}
|
||||
@@ -225,7 +225,7 @@ public final class ToolPublicationRetentionStore implements com.alibaba.qwen.cod
|
||||
}
|
||||
jdbc.update(
|
||||
"UPDATE ma_session SET gmt_modified = " + ManagedSchemaTime.SQL_NOW + ", retirement_operation_id = ?, retirement_generation ="
|
||||
+ " retirement_generation + 1, retired_at = ?, recovery_protected = ? WHERE"
|
||||
+ " retirement_generation + 1, retired_at = ?, is_recovery_protected = ? WHERE"
|
||||
+ " tenant_key = ? AND session_key = ? AND retired_at IS NULL",
|
||||
operation,
|
||||
time,
|
||||
@@ -292,7 +292,7 @@ public final class ToolPublicationRetentionStore implements com.alibaba.qwen.cod
|
||||
String publication = (String) row.get("publication_id");
|
||||
lockRetainedPublication(scope, publication);
|
||||
jdbc.update(
|
||||
"UPDATE ma_output_capture SET gmt_modified = " + ManagedSchemaTime.SQL_NOW + ", quarantined = TRUE WHERE scope_key = ?"
|
||||
"UPDATE ma_output_capture SET gmt_modified = " + ManagedSchemaTime.SQL_NOW + ", is_quarantined = TRUE WHERE scope_key = ?"
|
||||
+ " AND publication_id = ?",
|
||||
scope,
|
||||
publication);
|
||||
@@ -668,7 +668,7 @@ public final class ToolPublicationRetentionStore implements com.alibaba.qwen.cod
|
||||
.query(
|
||||
"SELECT scope_key, publication_id, tenant_id, session_id,"
|
||||
+ " capture_used_bytes, producer_used_bytes, admission_used_bytes,"
|
||||
+ " write_evidence, quarantined, accepted_complete, producer_phase FROM"
|
||||
+ " is_write_evidence, is_quarantined, is_accepted_complete, producer_phase FROM"
|
||||
+ " ma_output_capture WHERE retention_state = 'RETIRING' ORDER BY"
|
||||
+ " scope_key, publication_id LIMIT 100",
|
||||
(schemaRow, schemaIndex) -> ManagedSchemaRows.read(schemaRow))
|
||||
@@ -686,7 +686,7 @@ public final class ToolPublicationRetentionStore implements com.alibaba.qwen.cod
|
||||
+ number(row, "admission_used_bytes");
|
||||
var roots =
|
||||
jdbc.query(
|
||||
"SELECT retired_at, recovery_protected FROM ma_session WHERE tenant_key = ?"
|
||||
"SELECT retired_at, is_recovery_protected FROM ma_session WHERE tenant_key = ?"
|
||||
+ " AND session_key = ? AND retired_at IS NOT NULL",
|
||||
(schemaRow, schemaIndex) -> ManagedSchemaRows.read(schemaRow),
|
||||
hash(tenant),
|
||||
@@ -694,16 +694,16 @@ public final class ToolPublicationRetentionStore implements com.alibaba.qwen.cod
|
||||
String blocker;
|
||||
if (roots.isEmpty()) {
|
||||
blocker = "session_not_retired";
|
||||
} else if (flag(roots.getFirst(), "recovery_protected")) {
|
||||
} else if (flag(roots.getFirst(), "is_recovery_protected")) {
|
||||
blocker = "recovery_protected";
|
||||
} else if (number(roots.getFirst(), "retired_at") > now(jdbc) - grace.toMillis()) {
|
||||
blocker = "grace_period";
|
||||
} else if (!flag(row, "write_evidence")) {
|
||||
} else if (!flag(row, "is_write_evidence")) {
|
||||
blocker = "legacy_write_evidence_missing";
|
||||
} else if (flag(row, "quarantined")) {
|
||||
} else if (flag(row, "is_quarantined")) {
|
||||
blocker = "quarantined";
|
||||
} else if (!"REFERENCED".equals(row.get("producer_phase"))
|
||||
|| !flag(row, "accepted_complete")) {
|
||||
|| !flag(row, "is_accepted_complete")) {
|
||||
blocker = "not_accepted_complete";
|
||||
} else if (count(
|
||||
"SELECT COUNT(*) FROM ma_read_lease WHERE tenant_key = ? AND session_key ="
|
||||
|
||||
+6
-6
@@ -242,12 +242,12 @@ public final class ToolPublicationStore {
|
||||
var current = jdbc.query(
|
||||
"SELECT token_hash, state, expires_at, binding_digest,"
|
||||
+ " binding_json, tenant_id, workspace_id, session_id, CASE"
|
||||
+ " WHEN quarantined THEN 1 ELSE 0 END AS quarantined FROM"
|
||||
+ " WHEN is_quarantined THEN 1 ELSE 0 END AS is_quarantined FROM"
|
||||
+ " ma_output_capture WHERE scope_key = ? AND publication_id ="
|
||||
+ " ? FOR UPDATE", (schemaRow, schemaIndex) -> ManagedSchemaRows.read(schemaRow),
|
||||
scope, publicationId).getFirst();
|
||||
long nowEpoch = ToolPublicationRetentionStore.now(jdbc);
|
||||
require(((Number) current.get("quarantined")).intValue() == 0, "Publication is quarantined");
|
||||
require(((Number) current.get("is_quarantined")).intValue() == 0, "Publication is quarantined");
|
||||
if (access != Access.SETTLE) {
|
||||
require(equalHash(suppliedHash, (String) current.get("token_hash"))
|
||||
&& "OPEN".equals(current.get("state")) && current.get("expires_at") != null,
|
||||
@@ -411,7 +411,7 @@ public final class ToolPublicationStore {
|
||||
+ " session_id, publication_id, execution_key, capture_id, binding_json,"
|
||||
+ " binding_digest, token_hash, state, expires_at, capture_bytes,"
|
||||
+ " producer_bytes, admission_bytes, capture_held_bytes,"
|
||||
+ " producer_held_bytes, admission_held_bytes, write_evidence) VALUES (?,"
|
||||
+ " producer_held_bytes, admission_held_bytes, is_write_evidence) VALUES (?,"
|
||||
+ " ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, 'OPEN', ?, ?, ?, ?, ?, ?, ?, TRUE)",
|
||||
scope, tenantKey, tenant, workspace, session, id, hash(text(candidate, "executionCallId")),
|
||||
text(candidate, "captureId"), candidate.toString(), digest, tokenHash, expires, bytes,
|
||||
@@ -878,13 +878,13 @@ public final class ToolPublicationStore {
|
||||
require(sameResult, "Original settled Broker result conflicts with terminal result");
|
||||
JsonNode terminal = finished.path("terminal");
|
||||
var publication = jdbc.query("SELECT producer_phase, finish_operation_id, finish_digest,"
|
||||
+ " terminal_resource_id, CASE WHEN quarantined THEN 1 ELSE 0"
|
||||
+ " END AS quarantined FROM ma_output_capture WHERE scope_key ="
|
||||
+ " terminal_resource_id, CASE WHEN is_quarantined THEN 1 ELSE 0"
|
||||
+ " END AS is_quarantined FROM ma_output_capture WHERE scope_key ="
|
||||
+ " ? AND publication_id = ? FOR UPDATE", (schemaRow, schemaIndex) -> ManagedSchemaRows.read(schemaRow),
|
||||
scope, publicationId).getFirst();
|
||||
require(("FINISHED".equals(publication.get("producer_phase"))
|
||||
|| "REFERENCED".equals(publication.get("producer_phase")))
|
||||
&& ((Number) publication.get("quarantined")).intValue() == 0
|
||||
&& ((Number) publication.get("is_quarantined")).intValue() == 0
|
||||
&& text(finished, "finishOperationId").equals(publication.get("finish_operation_id"))
|
||||
&& text(terminal, "resourceId").equals(publication.get("terminal_resource_id"))
|
||||
&& text(terminal, "digest").equals(publication.get("finish_digest")),
|
||||
|
||||
+8
-8
@@ -66,11 +66,11 @@ public class WakeRecoveryStore
|
||||
+ " h.committed_sequence, h.compacted_through_revision, s.parent_session_id,"
|
||||
+ " s.parent_child_run_id FROM ma_session_head h JOIN ma_session s ON"
|
||||
+ " s.tenant_id = h.tenant_id AND s.session_id = h.session_id WHERE"
|
||||
+ " h.head_kind = 'MANAGED_SESSION' AND h.wake_scan_pending = TRUE"
|
||||
+ " h.head_kind = 'MANAGED_SESSION' AND h.is_wake_scan_pending = TRUE"
|
||||
+ " AND h.compacted_through_revision = 0"
|
||||
+ " AND h.wake_pending = ? AND h.wake_retry_at <= " + ManagedSchemaTime.SQL_NOW + " AND" + UNOWNED
|
||||
+ " AND h.is_wake_pending = ? AND h.wake_retry_at <= " + ManagedSchemaTime.SQL_NOW + " AND" + UNOWNED
|
||||
+ " AND s.session_kind = 'PUBLIC' AND s.status = 'ACTIVE'"
|
||||
+ " AND s.retired_at IS NULL AND s.csi_guard = FALSE"
|
||||
+ " AND s.retired_at IS NULL AND s.is_csi_guard = FALSE"
|
||||
+ " AND h.workspace_id = COALESCE(s.workspace_id, ?)"
|
||||
+ " ORDER BY h.wake_retry_at, h.tenant_key, h.harness_key LIMIT ?",
|
||||
(row, index) -> new Candidate(row.getString("tenant_id"), row.getString("workspace_id"),
|
||||
@@ -87,7 +87,7 @@ public class WakeRecoveryStore
|
||||
// subquery would first lock the head, then wait for a shared Session lock.
|
||||
var session = jdbc.queryForList("SELECT session_id FROM ma_session WHERE tenant_id = ?"
|
||||
+ " AND session_id = ? AND session_kind = 'PUBLIC' AND status = 'ACTIVE'"
|
||||
+ " AND retired_at IS NULL AND csi_guard = FALSE"
|
||||
+ " AND retired_at IS NULL AND is_csi_guard = FALSE"
|
||||
+ " AND (workspace_id IS NULL OR workspace_id = ?) FOR UPDATE",
|
||||
String.class, candidate.tenantId(), candidate.sessionId(), candidate.workspaceId());
|
||||
if (session.isEmpty() || ManagedConfigStore.blocked(jdbc, candidate.tenantId(), candidate.sessionId())) {
|
||||
@@ -98,7 +98,7 @@ public class WakeRecoveryStore
|
||||
+ " AND h.session_id = ? AND h.workspace_id = ?"
|
||||
+ " AND h.head_kind = 'MANAGED_SESSION' AND h.journal_revision = ?"
|
||||
+ " AND h.compacted_through_revision = 0"
|
||||
+ " AND h.wake_scan_pending = TRUE AND h.wake_retry_at <= " + ManagedSchemaTime.SQL_NOW + " AND" + UNOWNED,
|
||||
+ " AND h.is_wake_scan_pending = TRUE AND h.wake_retry_at <= " + ManagedSchemaTime.SQL_NOW + " AND" + UNOWNED,
|
||||
ManagedSchemaKeys.key(candidate.tenantId()),
|
||||
ManagedSchemaKeys.key(candidate.sessionId()), candidate.tenantId(), candidate.sessionId(),
|
||||
candidate.workspaceId(), candidate.journalRevision()) == 1;
|
||||
@@ -231,9 +231,9 @@ public class WakeRecoveryStore
|
||||
+ " WHERE h.tenant_key = ? AND h.harness_key = ? AND h.tenant_id = ?"
|
||||
+ " AND h.session_id = ? AND h.workspace_id = ? AND h.head_kind = 'MANAGED_SESSION'"
|
||||
+ " AND h.journal_revision = ? AND h.committed_sequence = ?"
|
||||
+ " AND h.compacted_through_revision = 0 AND h.wake_scan_pending = TRUE AND" + UNOWNED
|
||||
+ " AND h.compacted_through_revision = 0 AND h.is_wake_scan_pending = TRUE AND" + UNOWNED
|
||||
+ " AND s.session_kind = 'PUBLIC' AND s.status = 'ACTIVE'"
|
||||
+ " AND s.retired_at IS NULL AND s.csi_guard = FALSE"
|
||||
+ " AND s.retired_at IS NULL AND s.is_csi_guard = FALSE"
|
||||
+ " AND (s.workspace_id IS NULL OR s.workspace_id = ?)",
|
||||
Long.class, ManagedSchemaKeys.key(candidate.tenantId()), ManagedSchemaKeys.key(candidate.sessionId()),
|
||||
candidate.tenantId(), candidate.sessionId(), candidate.workspaceId(), candidate.journalRevision(),
|
||||
@@ -242,7 +242,7 @@ public class WakeRecoveryStore
|
||||
|
||||
/** Only a full prefix at this exact revision may clear the hint. */
|
||||
public boolean recordPending(Candidate candidate, boolean pending) {
|
||||
return jdbc.update("UPDATE ma_session_head SET wake_pending = ?, wake_head_revision = ?"
|
||||
return jdbc.update("UPDATE ma_session_head SET is_wake_pending = ?, wake_head_revision = ?"
|
||||
+ " WHERE tenant_key = ? AND harness_key = ? AND tenant_id = ?"
|
||||
+ " AND session_id = ? AND workspace_id = ? AND journal_revision = ?"
|
||||
+ " AND compacted_through_revision = 0",
|
||||
|
||||
+1
-1
@@ -78,7 +78,7 @@ final class WorkspaceCsiApplicationImage {
|
||||
put(headDelta, "wake_head_revision", revision);
|
||||
wakeRevision = revision;
|
||||
}
|
||||
put(headDelta, "wake_scan_pending", Boolean.TRUE.equals(head.bool("wake_pending"))
|
||||
put(headDelta, "is_wake_scan_pending", Boolean.TRUE.equals(head.bool("is_wake_pending"))
|
||||
|| wakeRevision == null || wakeRevision != revision);
|
||||
put(headDelta, "committed_sequence", request.path("lastSequence").longValue());
|
||||
put(headDelta, "last_commit_digest", text(request, "commitDigest"));
|
||||
|
||||
+41
-37
@@ -69,7 +69,7 @@ final class WorkspaceCsiApplicationInventory {
|
||||
.enable(DeserializationFeature.FAIL_ON_TRAILING_TOKENS);
|
||||
private static final List<Declaration> CATALOGUE = List.of(
|
||||
declaration("ma_agent_definition", "tenant_id,agent_id,revision",
|
||||
"tenant_id:VARBINARY,agent_id:VARBINARY,revision:BIGINT,digest:VARCHAR,definition_json:LONGTEXT,"
|
||||
"tenant_id:VARBINARY,agent_id:VARBINARY,revision:BIGINT,digest:CHAR,definition_json:LONGTEXT,"
|
||||
+ "gmt_create:BIGINT"),
|
||||
declaration("ma_artifact", "artifact_id",
|
||||
"artifact_id:VARBINARY,result_id:VARBINARY,scope_key:CHAR,descriptor_json:MEDIUMTEXT,"
|
||||
@@ -95,7 +95,7 @@ final class WorkspaceCsiApplicationInventory {
|
||||
"tenant_id:VARBINARY,session_id:VARBINARY,stream_kind:VARCHAR,stream_id:VARBINARY,last_sequence:BIGINT,"
|
||||
+ "replay_floor_sequence:BIGINT,covered_sequence:BIGINT,wake_covered_sequence:BIGINT,"
|
||||
+ "projection_version:INT,"
|
||||
+ "artifact_refs_resource_key:CHAR,output_ranges_json:LONGTEXT,projection_pending:BOOLEAN,"
|
||||
+ "artifact_refs_resource_key:CHAR,output_ranges_json:LONGTEXT,is_projection_pending:BOOLEAN,"
|
||||
+ "gmt_modified:BIGINT"),
|
||||
declaration("ma_extension_operation", "operation_key",
|
||||
"operation_key:CHAR,scope_key:CHAR,tenant_id:VARBINARY,workspace_id:VARBINARY,actor_key:CHAR,"
|
||||
@@ -125,7 +125,7 @@ final class WorkspaceCsiApplicationInventory {
|
||||
+ "session_status_before:VARCHAR,receipt_id:VARBINARY,claim_owner:VARBINARY,claim_generation:BIGINT,"
|
||||
+ "claim_until:BIGINT,available_at:BIGINT,attempt_count:INT,budget_exempt_attempt:INT,deadline:BIGINT,"
|
||||
+ "recovery_deadline:BIGINT,execution_mode:VARCHAR,verification_request_json:LONGTEXT,"
|
||||
+ "verification_ready:BOOLEAN,verification_next_at:BIGINT,publication_id:VARBINARY,"
|
||||
+ "is_verification_ready:BOOLEAN,verification_next_at:BIGINT,publication_id:VARBINARY,"
|
||||
+ "publication_command_id:VARBINARY,slot_key:VARBINARY,execution_key:CHAR,item_id:VARBINARY,"
|
||||
+ "policy_version:VARBINARY,failure_status:INT,failure_code:VARCHAR,gmt_create:BIGINT,gmt_modified:BIGINT,"
|
||||
+ "completed_at:BIGINT,progress_format:VARCHAR,progress_version:BIGINT,progress_stage:VARCHAR,"
|
||||
@@ -141,28 +141,28 @@ final class WorkspaceCsiApplicationInventory {
|
||||
"scope_key:CHAR,tenant_key:CHAR,tenant_id:VARBINARY,workspace_id:VARBINARY,session_id:VARBINARY,"
|
||||
+ "publication_id:VARBINARY,execution_key:CHAR,capture_id:VARBINARY,binding_json:MEDIUMTEXT,"
|
||||
+ "binding_digest:CHAR,token_hash:CHAR,state:VARCHAR,expires_at:BIGINT,capture_bytes:BIGINT,"
|
||||
+ "producer_bytes:BIGINT,admission_bytes:BIGINT,producer_phase:VARCHAR,quarantined:BOOLEAN,"
|
||||
+ "producer_bytes:BIGINT,admission_bytes:BIGINT,producer_phase:VARCHAR,is_quarantined:BOOLEAN,"
|
||||
+ "active_operation_id:VARBINARY,finish_operation_id:VARBINARY,finish_predecessor_id:VARBINARY,"
|
||||
+ "finish_digest:CHAR,terminal_resource_id:VARBINARY,admission_resource_id:VARBINARY,"
|
||||
+ "receipt_sequence:BIGINT,receipt_revision:BIGINT,capture_held_bytes:BIGINT,producer_held_bytes:BIGINT,"
|
||||
+ "admission_held_bytes:BIGINT,capture_used_bytes:BIGINT,producer_used_bytes:BIGINT,"
|
||||
+ "admission_used_bytes:BIGINT,retention_state:VARCHAR,write_evidence:BOOLEAN,accepted_complete:BOOLEAN,"
|
||||
+ "admission_used_bytes:BIGINT,retention_state:VARCHAR,is_write_evidence:BOOLEAN,is_accepted_complete:BOOLEAN,"
|
||||
+ "collected_at:BIGINT,collected_bytes:BIGINT,released_held_bytes:BIGINT,manifest_resource_key:CHAR,"
|
||||
+ "manifest_sha256:CHAR,seal_manifest_resource_key:CHAR,seal_manifest_sha256:CHAR,gmt_create:BIGINT,"
|
||||
+ "gmt_modified:BIGINT"),
|
||||
declaration("ma_public_event", "tenant_id,session_id,stream_kind,stream_id,sequence_id",
|
||||
"tenant_id:VARBINARY,session_id:VARBINARY,sequence_id:BIGINT,event_id:VARBINARY,turn_id:VARBINARY,"
|
||||
+ "event_type:VARCHAR,data_json:LONGTEXT,terminal:BOOLEAN,source_key:VARBINARY,gmt_create:BIGINT,"
|
||||
+ "event_type:VARCHAR,data_json:LONGTEXT,is_terminal:BOOLEAN,source_key:VARBINARY,gmt_create:BIGINT,"
|
||||
+ "schema_version:INT,projection_version:INT,item_id:VARBINARY,content_part_id:VARBINARY,"
|
||||
+ "stream_kind:VARCHAR,stream_id:VARBINARY,state:VARCHAR,runtime_state:VARCHAR,text:LONGTEXT,"
|
||||
+ "truncated:BOOLEAN,artifact_id:VARBINARY,capture_id:VARBINARY,output_stream_id:VARBINARY,"
|
||||
+ "first_ordinal:BIGINT,end_ordinal:BIGINT,archived:BOOLEAN"),
|
||||
+ "is_truncated:BOOLEAN,artifact_id:VARBINARY,capture_id:VARBINARY,output_stream_id:VARBINARY,"
|
||||
+ "first_ordinal:BIGINT,end_ordinal:BIGINT,is_archived:BOOLEAN"),
|
||||
declaration("ma_read_lease", "lease_id",
|
||||
"lease_id:VARBINARY,tenant_key:CHAR,session_key:CHAR,retirement_generation:BIGINT,expires_at:BIGINT"),
|
||||
declaration("ma_request_receipt", "receipt_key",
|
||||
"receipt_key:CHAR,namespace:VARCHAR,tenant_key:CHAR,tenant_id:VARBINARY,scope_kind:VARCHAR,"
|
||||
+ "scope_key:CHAR,scope_id:VARBINARY,idempotency_key:VARBINARY,idempotency_digest:CHAR,"
|
||||
+ "request_digest:VARCHAR,actor_id:VARBINARY,operation:VARCHAR,state:VARCHAR,workspace_bound:BOOLEAN,"
|
||||
+ "request_digest:VARCHAR,actor_id:VARBINARY,operation:VARCHAR,state:VARCHAR,is_workspace_bound:BOOLEAN,"
|
||||
+ "session_id:VARBINARY,turn_id:VARBINARY,agent_id:VARBINARY,agent_revision:BIGINT,schedule_id:VARBINARY,"
|
||||
+ "channel_id:VARBINARY,account_generation:BIGINT,semantic_revision:BIGINT,action_id:VARBINARY,"
|
||||
+ "action_version:BIGINT,decision_scope_key:CHAR,mutation_attempt_sequence:BIGINT,"
|
||||
@@ -185,11 +185,11 @@ final class WorkspaceCsiApplicationInventory {
|
||||
+ "workspace_generation:VARBINARY,canonical_cwd:VARCHAR,capability_digest:VARBINARY,"
|
||||
+ "isolation_class:VARCHAR,isolation_key:VARBINARY,provisioner_kind:VARCHAR,storage_id:VARBINARY,"
|
||||
+ "storage_alias_key:CHAR,runtime_generation:BIGINT,binding_state:VARCHAR,provision_request_id:VARBINARY,"
|
||||
+ "provision_seed_ciphertext:LONGTEXT,provision_seeded:BOOLEAN,credential_key_id:VARBINARY,"
|
||||
+ "provision_seed_ciphertext:LONGTEXT,is_provision_seeded:BOOLEAN,credential_key_id:VARBINARY,"
|
||||
+ "resource_handle_version:INT,resource_handle_json:LONGTEXT,loss_evidence_json:LONGTEXT,"
|
||||
+ "stop_evidence_json:LONGTEXT,runtime_instance_id:VARBINARY,runtime_endpoint:VARCHAR,"
|
||||
+ "runtime_lease_id:VARBINARY,runtime_epoch:BIGINT,runtime_credential_ciphertext:LONGTEXT,"
|
||||
+ "runtime_credential_key_id:VARBINARY,attestation_generation:BIGINT,drain_requested:BOOLEAN,"
|
||||
+ "runtime_credential_key_id:VARBINARY,attestation_generation:BIGINT,is_drain_requested:BOOLEAN,"
|
||||
+ "operation_owner:VARBINARY,operation_lease_until:BIGINT,operation_generation:BIGINT,"
|
||||
+ "record_version:BIGINT,last_health_at:BIGINT,last_reconciled_at:BIGINT,last_active_at:BIGINT,"
|
||||
+ "drain_receipt_json:LONGTEXT,first_activation_journal_revision:BIGINT"),
|
||||
@@ -198,7 +198,7 @@ final class WorkspaceCsiApplicationInventory {
|
||||
+ "workspace_generation:VARBINARY,canonical_cwd:VARCHAR,capability_digest:VARBINARY,"
|
||||
+ "isolation_class:VARCHAR,harness_session_id:VARBINARY,turn_kind:VARCHAR,binding_id:VARBINARY,"
|
||||
+ "runtime_generation:BIGINT,session_state:VARCHAR,record_version:BIGINT,last_active_at:BIGINT,"
|
||||
+ "execution_storage_key:CHAR,execution_exclusive:BOOLEAN"),
|
||||
+ "execution_storage_key:CHAR,is_execution_exclusive:BOOLEAN"),
|
||||
declaration("ma_runtime_slot", "request_key",
|
||||
"request_key:CHAR,tenant_id:VARBINARY,workspace_id:VARBINARY,workspace_generation:VARBINARY,"
|
||||
+ "canonical_cwd:VARCHAR,capability_digest:VARBINARY,isolation_class:VARCHAR,isolation_key:VARBINARY,"
|
||||
@@ -207,7 +207,7 @@ final class WorkspaceCsiApplicationInventory {
|
||||
"tenant_id:VARBINARY,schedule_id:VARBINARY,session_id:VARBINARY,workspace_id:VARBINARY,"
|
||||
+ "actor_id:VARBINARY,record_revision:BIGINT,definition_revision:BIGINT,definition_digest:CHAR,"
|
||||
+ "goal:VARCHAR,cron:VARCHAR,timezone:VARCHAR,session_mode:VARCHAR,overlap:VARCHAR,catch_up:VARCHAR,"
|
||||
+ "catch_up_limit:BIGINT,enabled:BOOLEAN,state:VARCHAR,blocked_reason:VARCHAR,armed_at:BIGINT,"
|
||||
+ "catch_up_limit:BIGINT,is_enabled:BOOLEAN,state:VARCHAR,blocked_reason:VARCHAR,armed_at:BIGINT,"
|
||||
+ "watermark_slot:BIGINT,lease_owner:VARBINARY,lease_until:BIGINT,fence:BIGINT,gmt_create:BIGINT,"
|
||||
+ "gmt_modified:BIGINT,gate:VARCHAR,gate_last_outcome:VARCHAR,gate_last_at:BIGINT,"
|
||||
+ "gate_quiet_since_delivery:INT,gate_failures:INT,gate_last_error:VARCHAR"),
|
||||
@@ -226,14 +226,14 @@ final class WorkspaceCsiApplicationInventory {
|
||||
+ "approval_mode:VARCHAR,tool_profile:VARCHAR,"
|
||||
+ "creator_actor_key:VARBINARY,owner_actor_key:VARBINARY,parent_session_id:VARBINARY,"
|
||||
+ "root_session_id:VARBINARY,parent_child_run_id:VARBINARY,child_depth:INT,"
|
||||
+ "agent_definition_digest:VARCHAR,session_kind:VARCHAR,tenant_key:CHAR,session_key:CHAR,"
|
||||
+ "agent_definition_digest:CHAR,session_kind:VARCHAR,tenant_key:CHAR,session_key:CHAR,"
|
||||
+ "session_scope_key:CHAR,title_revision:BIGINT,retirement_operation_id:VARBINARY,"
|
||||
+ "retirement_generation:BIGINT,retired_at:BIGINT,recovery_protected:BOOLEAN,"
|
||||
+ "resource_gc_completed:BOOLEAN,runtime_request_key:CHAR,csi_guard:BOOLEAN,"
|
||||
+ "retirement_generation:BIGINT,retired_at:BIGINT,is_recovery_protected:BOOLEAN,"
|
||||
+ "is_resource_gc_completed:BOOLEAN,runtime_request_key:CHAR,is_csi_guard:BOOLEAN,"
|
||||
+ "model_id:VARBINARY,model_revision:BIGINT,"
|
||||
+ "model_config_digest:VARCHAR,model_config_key_id:VARCHAR,model_config_ciphertext:LONGTEXT,"
|
||||
+ "selected_approval_mode:VARCHAR,approval_revision:BIGINT,"
|
||||
+ "plan_enabled:BOOLEAN,permission_rules_json:LONGTEXT,public_child_agents_version:INT,harness_instance_id:VARBINARY,harness_owner_boot_id:VARBINARY,"
|
||||
+ "is_plan_enabled:BOOLEAN,permission_rules_json:LONGTEXT,public_child_agents_version:INT,harness_instance_id:VARBINARY,harness_owner_boot_id:VARBINARY,"
|
||||
+ "harness_placement_epoch:BIGINT,harness_placement_state:VARCHAR"),
|
||||
declaration("ma_session_head", "tenant_key,harness_key",
|
||||
"tenant_id:VARBINARY,workspace_id:VARBINARY,session_id:VARBINARY,storage_version:INT,state:VARCHAR,"
|
||||
@@ -244,8 +244,8 @@ final class WorkspaceCsiApplicationInventory {
|
||||
+ "activation_id:VARBINARY,activation_phase:VARCHAR,activation_event_epoch:BIGINT,"
|
||||
+ "activation_expires_at:BIGINT,activation_head_revision:BIGINT,tenant_key:CHAR,harness_key:CHAR,"
|
||||
+ "harness_session_id:VARBINARY,head_kind:VARCHAR,phase:VARCHAR,operation_id:VARBINARY,"
|
||||
+ "claim_generation:BIGINT,claim_lease_until:BIGINT,wake_pending:BOOLEAN,wake_head_revision:BIGINT,"
|
||||
+ "wake_retry_at:BIGINT,wake_scan_pending:BOOLEAN,cleanup_head_revision:BIGINT"),
|
||||
+ "claim_generation:BIGINT,claim_lease_until:BIGINT,is_wake_pending:BOOLEAN,wake_head_revision:BIGINT,"
|
||||
+ "wake_retry_at:BIGINT,is_wake_scan_pending:BOOLEAN,cleanup_head_revision:BIGINT"),
|
||||
declaration("ma_session_journal_tx", "tenant_id,session_id,journal_revision",
|
||||
"tenant_id:VARBINARY,workspace_id:VARBINARY,session_id:VARBINARY,journal_revision:BIGINT,"
|
||||
+ "command_key_hash:CHAR,transaction_id:VARBINARY,operation:LONGTEXT,command_id:VARBINARY,"
|
||||
@@ -289,27 +289,27 @@ final class WorkspaceCsiApplicationInventory {
|
||||
+ "idempotency_key:VARBINARY,binding_id:VARBINARY,runtime_generation:BIGINT,harness_session_id:VARBINARY,"
|
||||
+ "runtime_session_id:VARBINARY,runtime_session_key:CHAR,turn_id:VARBINARY,tool_call_id:VARBINARY,"
|
||||
+ "request_digest:VARCHAR,reference_json:LONGTEXT,execution_state:VARCHAR,execution_status:VARCHAR,"
|
||||
+ "result_json:LONGTEXT,last_sequence:BIGINT,cancel_requested:BOOLEAN,dispatch_owner:VARBINARY,"
|
||||
+ "result_json:LONGTEXT,last_sequence:BIGINT,is_cancel_requested:BOOLEAN,dispatch_owner:VARBINARY,"
|
||||
+ "dispatch_lease_until:BIGINT,dispatch_generation:BIGINT,record_version:BIGINT,settled_at:BIGINT,"
|
||||
+ "abandoned_at:BIGINT,loss_evidence_id:VARBINARY,authorized_dispatch_generation:BIGINT,"
|
||||
+ "authorized_binding_version:BIGINT,native_authorization_json:LONGTEXT"),
|
||||
declaration("ma_turn", "tenant_id,session_id,turn_id",
|
||||
"tenant_id:VARBINARY,session_id:VARBINARY,turn_id:VARBINARY,prompt_id:VARBINARY,input_json:LONGTEXT,"
|
||||
+ "payload_digest:VARCHAR,status:VARCHAR,submission_attempted:BOOLEAN,harness_event_epoch:VARBINARY,"
|
||||
+ "payload_digest:CHAR,status:VARCHAR,is_submission_attempted:BOOLEAN,harness_event_epoch:VARBINARY,"
|
||||
+ "harness_last_event_id:BIGINT,dispatch_owner:VARBINARY,dispatch_lease_until:BIGINT,error_code:VARCHAR,"
|
||||
+ "error_message:VARCHAR,gmt_create:BIGINT,gmt_modified:BIGINT,completed_at:BIGINT,version:BIGINT,"
|
||||
+ "retry_count:INT,consecutive_failures:INT,budget_exempt_failures:INT,retry_after:BIGINT,"
|
||||
+ "model_id:VARBINARY,model_revision:BIGINT,approval_mode:VARCHAR,approval_revision:BIGINT,"
|
||||
+ "plan_enabled:BOOLEAN,permission_rules_json:LONGTEXT"),
|
||||
+ "is_plan_enabled:BOOLEAN,permission_rules_json:LONGTEXT"),
|
||||
declaration("ma_user_message", "tenant_id,session_id,message_id",
|
||||
"tenant_id:VARBINARY,session_id:VARBINARY,message_id:VARBINARY,sequence_number:BIGINT,"
|
||||
+ "revision:BIGINT,actor_id:VARBINARY,input_json:LONGTEXT,state:VARCHAR,context_revision:BIGINT,"
|
||||
+ "turn_id:VARBINARY,prompt_id:VARBINARY,consumed_sequence:BIGINT"),
|
||||
declaration("ma_user_message_command", "tenant_id,session_id,command_key",
|
||||
"tenant_id:VARBINARY,session_id:VARBINARY,command_key:CHAR,actor_id:VARBINARY,"
|
||||
+ "request_digest:VARCHAR,result_json:LONGTEXT"),
|
||||
+ "request_digest:CHAR,result_json:LONGTEXT"),
|
||||
declaration("ma_user_message_queue", "tenant_id,session_id",
|
||||
"tenant_id:VARBINARY,session_id:VARBINARY,paused:BOOLEAN,resumed_turn_id:VARBINARY,"
|
||||
"tenant_id:VARBINARY,session_id:VARBINARY,is_paused:BOOLEAN,resumed_turn_id:VARBINARY,"
|
||||
+ "next_sequence:BIGINT,last_dispatch_at:BIGINT"),
|
||||
declaration("ma_workspace", "tenant_id,workspace_id",
|
||||
"tenant_id:VARBINARY,workspace_id:VARBINARY,workspace_generation:BIGINT,storage_id:VARBINARY,"
|
||||
@@ -941,7 +941,7 @@ final class WorkspaceCsiApplicationInventory {
|
||||
&& hash(utf8(initial.toString())).equals(row.text("request_digest"))
|
||||
&& Objects.equals(read.number("started_at"), row.number("gmt_create"))
|
||||
&& row.number("gmt_modified") != null && row.number("gmt_modified") >= read.number("started_at"));
|
||||
for (String field : List.of("actor_id", "workspace_bound", "turn_id", "agent_id", "agent_revision", "schedule_id",
|
||||
for (String field : List.of("actor_id", "is_workspace_bound", "turn_id", "agent_id", "agent_revision", "schedule_id",
|
||||
"channel_id", "account_generation", "semantic_revision", "action_id", "action_version", "decision_scope_key",
|
||||
"mutation_attempt_sequence", "session_status_before", "result_operation_key")) {
|
||||
requireEncoded(row.cell(field).isNull());
|
||||
@@ -1984,7 +1984,11 @@ final class WorkspaceCsiApplicationInventory {
|
||||
}
|
||||
|
||||
private static boolean schema(ResultSetMetaData metadata, Declaration declaration) throws SQLException {
|
||||
if (metadata.getColumnCount() != declaration.columns().size()) {
|
||||
int identity = declaration.columns().size() + 1;
|
||||
if (metadata.getColumnCount() != identity
|
||||
|| !"id".equalsIgnoreCase(metadata.getColumnName(identity))
|
||||
|| metadata.getColumnType(identity) != Types.BIGINT
|
||||
|| !metadata.isAutoIncrement(identity)) {
|
||||
return false;
|
||||
}
|
||||
for (int index = 0; index < declaration.columns().size(); index++) {
|
||||
@@ -2379,7 +2383,7 @@ final class WorkspaceCsiApplicationInventory {
|
||||
return false;
|
||||
}
|
||||
if (namespace == com.alibaba.qwen.code.runtimebroker.schema.ManagedSchemaContract.ReceiptNamespace.SESSION_CREATE_MODE) {
|
||||
Boolean bound = row.bool("workspace_bound");
|
||||
Boolean bound = row.bool("is_workspace_bound");
|
||||
return scopeKind == com.alibaba.qwen.code.runtimebroker.schema.ManagedSchemaContract.ReceiptScope.TENANT
|
||||
&& ownerTenant.equals(scopeId) && bound != null && "RESERVED".equals(row.text("state"))
|
||||
&& row.cell("session_id").isNull() && row.cell("turn_id").isNull() && row.cell("actor_id").isNull()
|
||||
@@ -2387,7 +2391,7 @@ final class WorkspaceCsiApplicationInventory {
|
||||
}
|
||||
if (namespace != com.alibaba.qwen.code.runtimebroker.schema.ManagedSchemaContract.ReceiptNamespace.SESSION_CREATE_ACTOR
|
||||
|| scopeKind != com.alibaba.qwen.code.runtimebroker.schema.ManagedSchemaContract.ReceiptScope.ACTOR
|
||||
|| !Boolean.TRUE.equals(row.bool("workspace_bound")) || !"COMPLETED".equals(row.text("state"))
|
||||
|| !Boolean.TRUE.equals(row.bool("is_workspace_bound")) || !"COMPLETED".equals(row.text("state"))
|
||||
|| row.binary("actor_id") == null || !ManagedReceipts.actorScope(row.binary("actor_id")).equals(scopeId)
|
||||
|| !otherSession(ownerTenant, null, row.text("session_id"))) {
|
||||
return false;
|
||||
@@ -2411,7 +2415,7 @@ final class WorkspaceCsiApplicationInventory {
|
||||
|| !row.text("idempotency_key").matches("[\\x21-\\x7e]{1,128}")) {
|
||||
return false;
|
||||
}
|
||||
for (String field : List.of("workspace_bound", "session_id", "turn_id", "agent_id", "agent_revision",
|
||||
for (String field : List.of("is_workspace_bound", "session_id", "turn_id", "agent_id", "agent_revision",
|
||||
"schedule_id", "channel_id", "account_generation", "semantic_revision", "action_id", "action_version",
|
||||
"decision_scope_key", "mutation_attempt_sequence", "session_status_before", "result_operation_key")) {
|
||||
if (!row.cell(field).isNull()) {
|
||||
@@ -2849,7 +2853,7 @@ final class WorkspaceCsiApplicationInventory {
|
||||
&& row.cell("model_config_digest").isNull() && row.cell("model_config_key_id").isNull()
|
||||
&& row.cell("model_config_ciphertext").isNull()
|
||||
&& row.cell("selected_approval_mode").isNull() && Objects.equals(0L, row.number("approval_revision"))
|
||||
&& Boolean.FALSE.equals(row.bool("plan_enabled")) && row.cell("permission_rules_json").isNull()
|
||||
&& Boolean.FALSE.equals(row.bool("is_plan_enabled")) && row.cell("permission_rules_json").isNull()
|
||||
&& Objects.equals(0L, row.number("public_child_agents_version"))
|
||||
&& row.cell("harness_instance_id").isNull() && row.cell("harness_owner_boot_id").isNull()
|
||||
&& Objects.equals(0L, row.number("harness_placement_epoch"))
|
||||
@@ -2862,7 +2866,7 @@ final class WorkspaceCsiApplicationInventory {
|
||||
&& CsiFilesRetirementProfile.CONFIG_REF.equals(row.text("workspace_config_ref"))
|
||||
&& CsiFilesRetirementProfile.POLICY_REF.equals(row.text("workspace_policy_ref"))
|
||||
&& row.number("context_revision") != null && row.number("context_revision") > 0
|
||||
&& "qwen-code".equals(row.text("agent_id")) && Boolean.TRUE.equals(row.bool("csi_guard"))
|
||||
&& "qwen-code".equals(row.text("agent_id")) && Boolean.TRUE.equals(row.bool("is_csi_guard"))
|
||||
&& row.cell("parent_session_id").isNull() && row.cell("root_session_id").isNull()
|
||||
&& row.cell("parent_child_run_id").isNull() && row.cell("child_depth").isNull()
|
||||
&& row.binary("creator_actor_key") != null
|
||||
@@ -2872,7 +2876,7 @@ final class WorkspaceCsiApplicationInventory {
|
||||
&& "PUBLIC".equals(row.text("session_kind"))
|
||||
&& Objects.equals(0L, row.number("retirement_generation"))
|
||||
&& row.cell("retired_at").isNull() && row.cell("retirement_operation_id").isNull()
|
||||
&& Boolean.FALSE.equals(row.bool("recovery_protected")) && Boolean.FALSE.equals(row.bool("resource_gc_completed"))
|
||||
&& Boolean.FALSE.equals(row.bool("is_recovery_protected")) && Boolean.FALSE.equals(row.bool("is_resource_gc_completed"))
|
||||
&& Objects.equals(0L, row.number("harness_last_event_id"))
|
||||
&& row.cell("harness_boot_id").isNull() && row.cell("harness_event_epoch").isNull()
|
||||
&& Objects.equals(row.number("gmt_create"), row.number("gmt_modified")));
|
||||
@@ -2885,7 +2889,7 @@ final class WorkspaceCsiApplicationInventory {
|
||||
JsonNode data = parse(row.text("data_json"));
|
||||
Row parent = originalRow("ma_session");
|
||||
expect(table, row, rawSession(row) && "SESSION".equals(row.text("stream_kind")) && "".equals(row.text("stream_id")) && "session.created".equals(row.text("event_type"))
|
||||
&& row.cell("turn_id").isNull() && row.cell("source_key").isNull() && Boolean.FALSE.equals(row.bool("terminal"))
|
||||
&& row.cell("turn_id").isNull() && row.cell("source_key").isNull() && Boolean.FALSE.equals(row.bool("is_terminal"))
|
||||
&& Objects.equals(1L, row.number("sequence_id")) && data != null && data.isObject()
|
||||
&& data.size() == 1 && session.equals(data.path("sessionId").textValue())
|
||||
&& parent != null && Objects.equals(parent.number("gmt_create"), row.number("gmt_create"))
|
||||
@@ -2952,14 +2956,14 @@ final class WorkspaceCsiApplicationInventory {
|
||||
case "ma_runtime_binding" -> expect(table, row, request(row)
|
||||
&& original.bindingId().equals(row.text("binding_id")) && has("Bscope", row.text("scope_key"))
|
||||
&& Objects.equals(original.generation(), row.number("runtime_generation"))
|
||||
&& "DRAINING".equals(row.text("binding_state")) && Boolean.TRUE.equals(row.bool("drain_requested"))
|
||||
&& "DRAINING".equals(row.text("binding_state")) && Boolean.TRUE.equals(row.bool("is_drain_requested"))
|
||||
&& intent.runtimeInstanceId().equals(row.text("runtime_instance_id"))
|
||||
&& intent.leaseId().equals(row.text("runtime_lease_id")) && Objects.equals(intent.epoch(), row.number("runtime_epoch"))
|
||||
&& matches(parse(row.text("resource_handle_json")), parse(intent.resourceHandleJson()))
|
||||
&& Objects.equals(intent.resourceHandleVersion().longValue(), row.number("resource_handle_version"))
|
||||
&& Objects.equals(intent.attestationGeneration(), row.number("attestation_generation")));
|
||||
case "ma_runtime_session" -> expect(table, row, scope(row)
|
||||
&& row.cell("execution_storage_key").isNull() && Boolean.FALSE.equals(row.bool("execution_exclusive"))
|
||||
&& row.cell("execution_storage_key").isNull() && Boolean.FALSE.equals(row.bool("is_execution_exclusive"))
|
||||
&& original.bindingId().equals(row.text("binding_id")) && session.equals(row.text("runtime_session_id"))
|
||||
&& session.equals(row.text("harness_session_id")) && "bootstrap".equals(row.text("turn_kind"))
|
||||
&& Objects.equals(original.generation(), row.number("runtime_generation"))
|
||||
@@ -3019,7 +3023,7 @@ final class WorkspaceCsiApplicationInventory {
|
||||
&& Objects.equals(0L, row.number("covered_sequence")) && Objects.equals(0L, row.number("replay_floor_sequence"))
|
||||
&& row.cell("wake_covered_sequence").isNull() && row.cell("artifact_refs_resource_key").isNull()
|
||||
&& row.cell("output_ranges_json").isNull() && Objects.equals(1L, row.number("projection_version"))
|
||||
&& Boolean.TRUE.equals(row.bool("projection_pending")) && parent != null
|
||||
&& Boolean.TRUE.equals(row.bool("is_projection_pending")) && parent != null
|
||||
&& Objects.equals(parent.number("gmt_create"), row.number("gmt_modified")));
|
||||
}
|
||||
case "ma_request_receipt" -> {
|
||||
@@ -3044,7 +3048,7 @@ final class WorkspaceCsiApplicationInventory {
|
||||
&& ManagedReceipts.scope(tenant, scopeId).equals(row.text("scope_key"))
|
||||
&& com.alibaba.qwen.code.runtimebroker.schema.ManagedSchemaKeys.key(idempotency).equals(row.text("idempotency_digest"))
|
||||
&& row.cell("turn_id").isNull() && row.cell("operation").isNull() && row.cell("session_status_before").isNull()
|
||||
&& Boolean.TRUE.equals(row.bool("workspace_bound")) && row.text("request_digest") != null);
|
||||
&& Boolean.TRUE.equals(row.bool("is_workspace_bound")) && row.text("request_digest") != null);
|
||||
if (namespace == com.alibaba.qwen.code.runtimebroker.schema.ManagedSchemaContract.ReceiptNamespace.SESSION_CREATE_MODE) {
|
||||
expect(table, row, scopeKind == com.alibaba.qwen.code.runtimebroker.schema.ManagedSchemaContract.ReceiptScope.TENANT
|
||||
&& tenant.equals(scopeId) && has("creation", idempotency) && row.cell("session_id").isNull()
|
||||
|
||||
+2
-2
@@ -121,7 +121,7 @@ public final class WorkspaceCsiCheckpointSnapshotStore {
|
||||
"SELECT " + ManagedSchemaProjection.OUTPUT_CAPTURE.columns() + " FROM ma_output_capture WHERE scope_key = ? AND publication_id = ?",
|
||||
publicationScope, publicationId);
|
||||
scope(publication, key);
|
||||
require("REFERENCED".equals(publication.get("producer_phase")) && !flag(publication, "quarantined"));
|
||||
require("REFERENCED".equals(publication.get("producer_phase")) && !flag(publication, "is_quarantined"));
|
||||
JsonNode binding = ToolPublicationContract.parseBytes("binding",
|
||||
text(publication, "binding_json").getBytes(StandardCharsets.UTF_8));
|
||||
require(binding.path("sessionKey").equals(key) && publicationId.equals(binding.path("publicationId").asText())
|
||||
@@ -339,7 +339,7 @@ public final class WorkspaceCsiCheckpointSnapshotStore {
|
||||
"SELECT " + ManagedSchemaProjection.RUNTIME_SESSION.columns() + " FROM ma_runtime_session WHERE scope_key = ? AND runtime_session_id = ?",
|
||||
scopeHash(runtime.getRequest().getScope()), ref.path("sessionId").asText());
|
||||
require(runtime.getRequest().getScope().equals(scope(session))
|
||||
&& session.get("execution_storage_key") == null && Boolean.FALSE.equals(session.get("execution_exclusive"))
|
||||
&& session.get("execution_storage_key") == null && !flag(session, "is_execution_exclusive")
|
||||
&& runtime.getBindingId().equals(session.get("binding_id"))
|
||||
&& runtime.getGeneration() == rawNumber(session, "runtime_generation")
|
||||
&& binding.path("sessionKey").path("sessionId").asText().equals(session.get("harness_session_id")));
|
||||
|
||||
+17
-17
@@ -82,10 +82,10 @@ public class WorkspaceExecutionStore
|
||||
+ " JOIN ma_runtime_slot slot ON slot.active_binding_id = b.binding_id AND slot.request_key = b.request_key"
|
||||
+ " JOIN ma_storage_owner o ON o.binding_id = b.binding_id AND o.runtime_generation = b.runtime_generation"
|
||||
+ " WHERE rs.binding_id = ? AND rs.runtime_generation = ? AND rs.runtime_session_id = ?"
|
||||
+ " AND rs.execution_storage_key IS NULL AND rs.execution_exclusive = FALSE"
|
||||
+ " AND rs.execution_storage_key IS NULL AND rs.is_execution_exclusive = FALSE"
|
||||
+ " AND rs.harness_session_id = ? AND rs.session_state IN (" + (releasing
|
||||
? "'ACQUIRING', 'READY', 'RELEASING', 'RELEASED'" : "'ACQUIRING', 'READY'") + ")"
|
||||
+ " AND b.request_key = ? AND b.binding_state = 'READY' AND b.drain_requested = FALSE"
|
||||
+ " AND b.request_key = ? AND b.binding_state = 'READY' AND b.is_drain_requested = FALSE"
|
||||
+ " AND o.storage_key = ? AND o.storage_kind = 'CSI' AND o.csi_phase = 'RESERVED'"
|
||||
+ " AND o.csi_registration_key = ? AND o.csi_registration_revision = ?"
|
||||
+ " AND o.csi_provision_request_id = b.provision_request_id AND o.holder_key IS NULL"
|
||||
@@ -172,7 +172,7 @@ public class WorkspaceExecutionStore
|
||||
if (turnId == null || dispatchOwner == null
|
||||
|| jdbc.queryForObject("SELECT COUNT(*) FROM ma_turn WHERE tenant_id = ?"
|
||||
+ " AND session_id = ? AND turn_id = ? AND status = 'RUNNING'"
|
||||
+ " AND submission_attempted = TRUE AND harness_event_epoch IS NOT NULL"
|
||||
+ " AND is_submission_attempted = TRUE AND harness_event_epoch IS NOT NULL"
|
||||
+ " AND dispatch_owner = ? AND dispatch_lease_until >= " + ManagedSchemaTime.SQL_NOW,
|
||||
Long.class, session.tenantId(), session.sessionId(), turnId, dispatchOwner) != 1) {
|
||||
throw com.alibaba.qwen.code.managedagent.repository.WorkspaceExecutionStore.unavailable();
|
||||
@@ -261,7 +261,7 @@ public class WorkspaceExecutionStore
|
||||
+ (cancellation
|
||||
? " JOIN ma_turn t ON t.tenant_id = s.tenant_id"
|
||||
+ " AND t.session_id = s.session_id AND t.status = 'CANCELLING'"
|
||||
+ " AND (t.submission_attempted = TRUE OR t.harness_event_epoch IS NOT NULL)"
|
||||
+ " AND (t.is_submission_attempted = TRUE OR t.harness_event_epoch IS NOT NULL)"
|
||||
: committedStop ? ""
|
||||
: " JOIN ma_workspace r ON r.tenant_id = s.tenant_id"
|
||||
+ " AND r.workspace_id = s.workspace_id"
|
||||
@@ -387,12 +387,12 @@ public class WorkspaceExecutionStore
|
||||
WorkspaceStorageKindGuard.requireExecutionAlias(jdbc, binding.getTenantId(), binding.getStorageId());
|
||||
String key = storageKey(binding);
|
||||
WorkspaceMigrationAdmission.requireOpen(jdbc, binding.getTenantId(), binding.getStorageId());
|
||||
List<Boolean> live = jdbc.query("SELECT binding_id, runtime_generation, binding_state, drain_requested,"
|
||||
List<Boolean> live = jdbc.query("SELECT binding_id, runtime_generation, binding_state, is_drain_requested,"
|
||||
+ " tenant_id, workspace_id, workspace_generation, storage_id FROM ma_runtime_binding"
|
||||
+ " WHERE binding_id = ? FOR UPDATE", (row, index) ->
|
||||
session.getBindingId().equals(row.getString("binding_id"))
|
||||
&& session.getRuntimeGeneration() == row.getLong("runtime_generation")
|
||||
&& "READY".equals(row.getString("binding_state")) && !row.getBoolean("drain_requested")
|
||||
&& "READY".equals(row.getString("binding_state")) && !row.getBoolean("is_drain_requested")
|
||||
&& binding.getTenantId().equals(row.getString("tenant_id"))
|
||||
&& binding.getWorkspaceId().equals(row.getString("workspace_id"))
|
||||
&& Long.toString(binding.getWorkspaceGeneration()).equals(row.getString("workspace_generation"))
|
||||
@@ -430,10 +430,10 @@ public class WorkspaceExecutionStore
|
||||
throw busy();
|
||||
}
|
||||
var members = WorkspaceOperations.rows(jdbc, "SELECT runtime_session_id,"
|
||||
+ " binding_id, runtime_generation, execution_exclusive FROM ma_runtime_session"
|
||||
+ " binding_id, runtime_generation, is_execution_exclusive FROM ma_runtime_session"
|
||||
+ " WHERE execution_storage_key = ? FOR UPDATE", key);
|
||||
for (var member : members) {
|
||||
if (Boolean.TRUE.equals(member.get("execution_exclusive")) && !sameMember(member, session)) {
|
||||
if (Boolean.TRUE.equals(member.get("is_execution_exclusive")) && !sameMember(member, session)) {
|
||||
throw busy();
|
||||
}
|
||||
}
|
||||
@@ -470,9 +470,9 @@ public class WorkspaceExecutionStore
|
||||
throw com.alibaba.qwen.code.managedagent.repository.WorkspaceExecutionStore.unavailable();
|
||||
}
|
||||
var members = WorkspaceOperations.rows(jdbc, "SELECT binding_id, runtime_generation, runtime_session_id,"
|
||||
+ " execution_exclusive FROM ma_runtime_session WHERE execution_storage_key = ? FOR UPDATE", key);
|
||||
+ " is_execution_exclusive FROM ma_runtime_session WHERE execution_storage_key = ? FOR UPDATE", key);
|
||||
for (var member : members) {
|
||||
if (sameMember(member, session) && Boolean.TRUE.equals(member.get("execution_exclusive"))) {
|
||||
if (sameMember(member, session) && Boolean.TRUE.equals(member.get("is_execution_exclusive"))) {
|
||||
throw new RuntimeBrokerException(409, "workspace_rewind_recovery_required",
|
||||
"An earlier Workspace rewind has an unconfirmed outcome.", false);
|
||||
}
|
||||
@@ -480,7 +480,7 @@ public class WorkspaceExecutionStore
|
||||
if (members.stream().anyMatch(member -> !sameMember(member, session))) {
|
||||
return false;
|
||||
}
|
||||
return jdbc.update("UPDATE ma_runtime_session SET execution_exclusive = TRUE WHERE binding_id = ?"
|
||||
return jdbc.update("UPDATE ma_runtime_session SET is_execution_exclusive = TRUE WHERE binding_id = ?"
|
||||
+ " AND runtime_generation = ? AND runtime_session_id = ? AND execution_storage_key = ?",
|
||||
session.getBindingId(), session.getRuntimeGeneration(), session.getRuntimeSessionId(), key) == 1;
|
||||
}));
|
||||
@@ -490,7 +490,7 @@ public class WorkspaceExecutionStore
|
||||
transaction.executeWithoutResult(status -> {
|
||||
WorkspaceStorageKindGuard.lockDomain(jdbc, binding.getTenantId());
|
||||
String key = storageKey(binding);
|
||||
jdbc.update("UPDATE ma_runtime_session SET execution_exclusive = FALSE WHERE binding_id = ?"
|
||||
jdbc.update("UPDATE ma_runtime_session SET is_execution_exclusive = FALSE WHERE binding_id = ?"
|
||||
+ " AND runtime_generation = ? AND runtime_session_id = ? AND execution_storage_key = ?",
|
||||
session.getBindingId(), session.getRuntimeGeneration(), session.getRuntimeSessionId(), key);
|
||||
});
|
||||
@@ -499,7 +499,7 @@ public class WorkspaceExecutionStore
|
||||
public boolean hasExclusiveClaim(RuntimeSessionRecord session) {
|
||||
return !jdbc.queryForList("SELECT runtime_session_id FROM ma_runtime_session WHERE binding_id = ?"
|
||||
+ " AND runtime_generation = ? AND runtime_session_id = ? AND execution_storage_key IS NOT NULL"
|
||||
+ " AND execution_exclusive = TRUE", String.class, session.getBindingId(), session.getRuntimeGeneration(),
|
||||
+ " AND is_execution_exclusive = TRUE", String.class, session.getBindingId(), session.getRuntimeGeneration(),
|
||||
session.getRuntimeSessionId()).isEmpty();
|
||||
}
|
||||
|
||||
@@ -564,7 +564,7 @@ public class WorkspaceExecutionStore
|
||||
if (live.size() != 1 || !live.getFirst()) {
|
||||
throw com.alibaba.qwen.code.managedagent.repository.WorkspaceExecutionStore.unavailable();
|
||||
}
|
||||
jdbc.update("UPDATE ma_runtime_session SET execution_storage_key = NULL, execution_exclusive = FALSE"
|
||||
jdbc.update("UPDATE ma_runtime_session SET execution_storage_key = NULL, is_execution_exclusive = FALSE"
|
||||
+ " WHERE execution_storage_key = ? AND binding_id = ? AND runtime_generation = ?"
|
||||
+ " AND runtime_session_id = ? AND harness_session_id = ?", key, session.getBindingId(),
|
||||
session.getRuntimeGeneration(), session.getRuntimeSessionId(), session.getSession().getHarnessSessionId());
|
||||
@@ -660,11 +660,11 @@ public class WorkspaceExecutionStore
|
||||
|| HarnessOwnership.sharesRuntimeSessions(saved.getRequest()))) {
|
||||
return false;
|
||||
}
|
||||
var claims = jdbc.query("SELECT binding_state, drain_requested, operation_owner, operation_generation,"
|
||||
var claims = jdbc.query("SELECT binding_state, is_drain_requested, operation_owner, operation_generation,"
|
||||
+ " operation_lease_until, tenant_id, storage_id, UNIX_TIMESTAMP() AS db_seconds,"
|
||||
+ " EXTRACT(MICROSECOND FROM CURRENT_TIMESTAMP(6)) AS db_micros FROM ma_runtime_binding"
|
||||
+ " WHERE binding_id = ? AND runtime_generation = ?", (row, index) ->
|
||||
saved.getState().name().equals(row.getString("binding_state")) && row.getBoolean("drain_requested")
|
||||
saved.getState().name().equals(row.getString("binding_state")) && row.getBoolean("is_drain_requested")
|
||||
&& saved.getOperationOwner().equals(row.getString("operation_owner"))
|
||||
&& saved.getOperationGeneration() == row.getLong("operation_generation")
|
||||
&& ManagedSchemaTime.timestamp(row, "operation_lease_until") != null
|
||||
@@ -744,7 +744,7 @@ public class WorkspaceExecutionStore
|
||||
saved.getGeneration(), saved.getOperationOwner(), saved.getOperationGeneration()) != 1) {
|
||||
throw com.alibaba.qwen.code.managedagent.repository.WorkspaceExecutionStore.unavailable();
|
||||
}
|
||||
jdbc.update("UPDATE ma_runtime_session SET execution_storage_key = NULL, execution_exclusive = FALSE"
|
||||
jdbc.update("UPDATE ma_runtime_session SET execution_storage_key = NULL, is_execution_exclusive = FALSE"
|
||||
+ " WHERE binding_id = ? AND runtime_generation = ? AND execution_storage_key = ?",
|
||||
saved.getBindingId(), saved.getGeneration(), key);
|
||||
});
|
||||
|
||||
+1
-1
@@ -132,7 +132,7 @@ public final class WorkspaceOperatorRecoveryStore {
|
||||
"blocked_execution_call_id", blockedCapture.callId(), "operator_id", operator,
|
||||
"reason", reason, "prepared_at", Instant.now().toString()));
|
||||
if (jdbc.update("UPDATE ma_runtime_binding SET binding_state = ?,"
|
||||
+ " drain_requested = TRUE, operation_owner = NULL, operation_lease_until = NULL,"
|
||||
+ " is_drain_requested = TRUE, operation_owner = NULL, operation_lease_until = NULL,"
|
||||
+ " operation_generation = operation_generation + 1, record_version = record_version + 1"
|
||||
+ " WHERE binding_id = ? AND runtime_generation = ? AND record_version = ?",
|
||||
saved.getState() == RuntimeBindingRecord.State.LOST ? "LOST" : "OPERATOR_RECOVERY",
|
||||
|
||||
+4
-4
@@ -160,11 +160,11 @@ public class WorkspaceProfileLifecycleVerifier {
|
||||
verifyNotStartedPublication(operation, execution);
|
||||
} else {
|
||||
var rows = jdbc.queryForList("SELECT producer_phase, admission_resource_id, receipt_sequence, receipt_revision,"
|
||||
+ " CASE WHEN quarantined THEN 1 ELSE 0 END AS quarantined FROM ma_output_capture"
|
||||
+ " CASE WHEN is_quarantined THEN 1 ELSE 0 END AS is_quarantined FROM ma_output_capture"
|
||||
+ " WHERE tenant_id = ? AND session_id = ? AND publication_id = ? FOR UPDATE",
|
||||
operation.tenantId(), operation.sessionId(), execution.getReference().get("publicationId"));
|
||||
if (rows.size() != 1 || !"REFERENCED".equals(rows.getFirst().get("producer_phase"))
|
||||
|| ((Number) rows.getFirst().get("quarantined")).intValue() != 0
|
||||
|| ((Number) rows.getFirst().get("is_quarantined")).intValue() != 0
|
||||
|| !source.outcomeRef().path("resourceId").asText().equals(rows.getFirst().get("admission_resource_id"))
|
||||
|| source.receiptSequence() != ((Number) rows.getFirst().get("receipt_sequence")).longValue()
|
||||
|| source.journalRevision() != ((Number) rows.getFirst().get("receipt_revision")).longValue()) {
|
||||
@@ -313,12 +313,12 @@ public class WorkspaceProfileLifecycleVerifier {
|
||||
|
||||
private void verifyNotStartedPublication(OperationRecord operation, ToolExecutionRecord execution) {
|
||||
var rows = jdbc.queryForList("SELECT state, producer_phase, terminal_resource_id, binding_json, binding_digest,"
|
||||
+ " CASE WHEN quarantined THEN 1 ELSE 0 END AS quarantined"
|
||||
+ " CASE WHEN is_quarantined THEN 1 ELSE 0 END AS is_quarantined"
|
||||
+ " FROM ma_output_capture WHERE tenant_id = ? AND session_id = ? AND publication_id = ? FOR UPDATE",
|
||||
operation.tenantId(), operation.sessionId(), execution.getReference().get("publicationId"));
|
||||
if (rows.size() != 1 || !"NOT_STARTED".equals(rows.getFirst().get("state"))
|
||||
|| !"OPEN".equals(rows.getFirst().get("producer_phase"))
|
||||
|| ((Number) rows.getFirst().get("quarantined")).intValue() != 0
|
||||
|| ((Number) rows.getFirst().get("is_quarantined")).intValue() != 0
|
||||
|| rows.getFirst().get("terminal_resource_id") != null) {
|
||||
unsettled();
|
||||
}
|
||||
|
||||
+2
-2
@@ -100,7 +100,7 @@ final class WorkspaceRecoveryReader {
|
||||
&& row.get("object_version_id") == null && row.get("encryption_key_id") == null,
|
||||
"resource_layout_unsupported");
|
||||
bytes = (byte[]) row.get("inline_bytes");
|
||||
var references = jdbc.queryForList("SELECT resource_key FROM ma_resource_ref USE INDEX (ix_ma_ref_resource)"
|
||||
var references = jdbc.queryForList("SELECT resource_key FROM ma_resource_ref USE INDEX (idx_ma_ref_resource)"
|
||||
+ " WHERE resource_key = ? AND session_scope_key = ? AND owner_kind IN ('JOURNAL','SESSION_RECORD')"
|
||||
+ " AND tenant_id = ? AND workspace_id = ? AND session_id = ? AND resource_id = ?"
|
||||
+ " AND journal_revision <= ? LIMIT 1", String.class, resourceKey, sessionScope,
|
||||
@@ -298,7 +298,7 @@ final class WorkspaceRecoveryReader {
|
||||
check(rows.size() == 1, "publication_scope_conflict");
|
||||
var row = rows.getFirst();
|
||||
check(!"DELETING".equals(row.get("retention_state")), "source_drift");
|
||||
check("REFERENCED".equals(row.get("producer_phase")) && Boolean.FALSE.equals(row.get("quarantined"))
|
||||
check("REFERENCED".equals(row.get("producer_phase")) && Boolean.FALSE.equals(row.get("is_quarantined"))
|
||||
&& row.get("receipt_revision") instanceof Number && row.get("receipt_sequence") instanceof Number
|
||||
&& number(row, "receipt_revision") > 0 && number(row, "receipt_revision") <= head.path("journalRevision").asLong()
|
||||
&& number(row, "receipt_sequence") > 0 && number(row, "receipt_sequence") <= head.path("committedSequence").asLong(),
|
||||
|
||||
+2
-2
@@ -641,7 +641,7 @@ public final class WorkspaceRecoveryStore implements com.alibaba.qwen.code.manag
|
||||
+ " AND retention_state = 'DELETING' LIMIT 1" + currentRead, String.class, captureScope).isEmpty(), "source_drift");
|
||||
}
|
||||
var retirements = WorkspaceOperations.rows(jdbc, "SELECT tenant_id, session_id, retirement_operation_id AS operation_id,"
|
||||
+ " retirement_generation AS generation, retired_at, recovery_protected FROM ma_session"
|
||||
+ " retirement_generation AS generation, retired_at, is_recovery_protected FROM ma_session"
|
||||
+ " WHERE tenant_id = ? AND session_id = ? AND retirement_generation > 0", tenant, session);
|
||||
check(retirements.size() <= 1, "source_drift");
|
||||
source.putNull("retirement");
|
||||
@@ -652,7 +652,7 @@ public final class WorkspaceRecoveryStore implements com.alibaba.qwen.code.manag
|
||||
&& ((Number) row.get("deleted_at")).longValue() > 0
|
||||
&& ((Number) retirement.get("generation")).longValue() == 1
|
||||
&& ((Number) retirement.get("retired_at")).longValue() > 0
|
||||
&& !ToolPublicationRetentionStore.flag(retirement, "recovery_protected"), "source_drift");
|
||||
&& !ToolPublicationRetentionStore.flag(retirement, "is_recovery_protected"), "source_drift");
|
||||
JsonNode retiredHead = source.path("head");
|
||||
check(retiredHead.isNull() || "DELETED".equals(retiredHead.path("state").asText())
|
||||
&& retiredHead.path("latestCheckpointResourceId").isNull()
|
||||
|
||||
+61
-43
@@ -22,16 +22,16 @@ final class ManagedSchemaCatalog {
|
||||
private static final Pattern COLUMN =
|
||||
Pattern.compile(
|
||||
"(?m)^ ([a-z0-9_]+)"
|
||||
+ " (VARBINARY|VARCHAR|CHAR|BIGINT|INT|BOOLEAN|DATETIME|LONGTEXT|MEDIUMTEXT|MEDIUMBLOB|LONGBLOB)(?:\\((\\d+)\\))?([^\\n"
|
||||
+ " (VARBINARY|VARCHAR|CHAR|BIGINT|INT|TINYINT|BOOLEAN|DATETIME|LONGTEXT|MEDIUMTEXT|MEDIUMBLOB|LONGBLOB)(?:\\((\\d+)\\))?([^\\n"
|
||||
+ "]*)");
|
||||
private static final Pattern PRIMARY = Pattern.compile("PRIMARY KEY \\(([^)]+)\\)");
|
||||
private static final Pattern UNIQUE = Pattern.compile("UNIQUE(?: KEY [a-z_]+)? \\(([^)]+)\\)");
|
||||
private static final Pattern CHECK = Pattern.compile("CONSTRAINT ([a-z_]+) CHECK");
|
||||
private static final Pattern INDEX =
|
||||
Pattern.compile("CREATE (UNIQUE )?INDEX ([a-z_]+) ON (ma_[a-z_]+) \\(([^)]+)\\)");
|
||||
Pattern.compile("CREATE (UNIQUE )?INDEX ([a-z_]+) ON (ma_[a-z_]+) \\(([^;]+)\\);");
|
||||
private static final Pattern INLINE_INDEX = Pattern.compile("INDEX ([a-z_]+)\\s*\\(([^)]+)\\)");
|
||||
private static final Pattern FOREIGN =
|
||||
Pattern.compile("FOREIGN KEY \\(([^)]+)\\)\\s*REFERENCES (ma_[a-z_]+) \\(([^)]+)\\)");
|
||||
private static final Pattern INDEX_PREFIX =
|
||||
Pattern.compile(" /\\*!50000 \\((\\d+)\\) \\*/");
|
||||
|
||||
private ManagedSchemaCatalog() {}
|
||||
|
||||
@@ -45,6 +45,14 @@ final class ManagedSchemaCatalog {
|
||||
throw new SQLException("Managed schema requires a dedicated application catalog;"
|
||||
+ " system or missing catalog refused before DDL: " + name);
|
||||
}
|
||||
try (var statement = connection.prepareStatement("SELECT @@GLOBAL.sql_mode, @@SESSION.sql_mode");
|
||||
var result = statement.executeQuery()) {
|
||||
if (!result.next() || !strictSqlMode(result.getString(1)) || !strictSqlMode(result.getString(2))) {
|
||||
throw new SQLException("Managed schema requires strict SQL mode"
|
||||
+ " (STRICT_TRANS_TABLES or STRICT_ALL_TABLES) globally and for the current session;"
|
||||
+ " refused before DDL");
|
||||
}
|
||||
}
|
||||
if (isMariaDb(connection)) {
|
||||
try (var statement = connection.prepareStatement(
|
||||
"SELECT @@GLOBAL.check_constraint_checks, @@SESSION.check_constraint_checks");
|
||||
@@ -58,6 +66,16 @@ final class ManagedSchemaCatalog {
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean strictSqlMode(String modes) {
|
||||
for (String mode : modes.split(",")) {
|
||||
if ("STRICT_TRANS_TABLES".equalsIgnoreCase(mode.trim())
|
||||
|| "STRICT_ALL_TABLES".equalsIgnoreCase(mode.trim())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private static boolean isMariaDb(Connection connection) throws SQLException {
|
||||
var metadata = connection.getMetaData();
|
||||
String version = metadata.getDatabaseProductVersion();
|
||||
@@ -137,7 +155,7 @@ final class ManagedSchemaCatalog {
|
||||
validateGeneratedColumns(connection, name, body);
|
||||
validateKeys(connection, name, body, ddl);
|
||||
validateChecks(connection, name, body);
|
||||
validateForeignKeys(connection, name, body, ddl);
|
||||
validateForeignKeys(connection, name);
|
||||
}
|
||||
if (!declared.equals(ManagedSchemaContract.TABLES)) {
|
||||
throw new SQLException(
|
||||
@@ -152,6 +170,7 @@ final class ManagedSchemaCatalog {
|
||||
Map<String, Boolean> unsigned = new HashMap<>();
|
||||
Map<String, String> names = new HashMap<>();
|
||||
Map<String, Boolean> required = new HashMap<>();
|
||||
Map<String, Boolean> automatic = new HashMap<>();
|
||||
try (var result =
|
||||
connection
|
||||
.getMetaData()
|
||||
@@ -167,6 +186,8 @@ final class ManagedSchemaCatalog {
|
||||
required.put(
|
||||
lower(result.getString("COLUMN_NAME")),
|
||||
result.getInt("NULLABLE") == DatabaseMetaData.columnNoNulls);
|
||||
automatic.put(lower(result.getString("COLUMN_NAME")),
|
||||
"YES".equals(result.getString("IS_AUTOINCREMENT")));
|
||||
}
|
||||
}
|
||||
boolean nativeDatabase = "MySQL".equals(connection.getMetaData().getDatabaseProductName())
|
||||
@@ -203,10 +224,13 @@ final class ManagedSchemaCatalog {
|
||||
if (!compatibleType(column.group(2), types.get(key))) {
|
||||
throw new SQLException("Managed schema column type differs: " + name + "." + key);
|
||||
}
|
||||
if (nativeDatabase && "BIGINT".equals(column.group(2))
|
||||
if (nativeDatabase && Set.of("BIGINT", "INT", "TINYINT").contains(column.group(2))
|
||||
&& column.group(4).contains("UNSIGNED") != Boolean.TRUE.equals(unsigned.get(key))) {
|
||||
throw new SQLException("Managed schema integer signedness differs: " + name + "." + key);
|
||||
}
|
||||
if (column.group(4).contains("AUTO_INCREMENT") != automatic.get(key)) {
|
||||
throw new SQLException("Managed schema identity generation differs: " + name + "." + key);
|
||||
}
|
||||
if (Set.of("LONGTEXT", "MEDIUMTEXT", "MEDIUMBLOB", "LONGBLOB").contains(column.group(2))
|
||||
&& actual.get(key) < 1_048_576) {
|
||||
throw new SQLException("Managed schema body capacity differs: " + name + "." + key);
|
||||
@@ -315,6 +339,7 @@ final class ManagedSchemaCatalog {
|
||||
|| index.group(1) != null && !uniqueIndexes.contains(index.group(2))) {
|
||||
throw new SQLException("Managed schema index differs: " + index.group(2));
|
||||
}
|
||||
validateIndexPrefix(connection, name, index.group(2), index.group(4));
|
||||
}
|
||||
}
|
||||
var inline = INLINE_INDEX.matcher(body);
|
||||
@@ -327,44 +352,36 @@ final class ManagedSchemaCatalog {
|
||||
}
|
||||
}
|
||||
|
||||
private static void validateForeignKeys(
|
||||
Connection connection, String name, String body, String ddl) throws SQLException {
|
||||
Map<String, Map<Integer, String>> actual = new HashMap<>();
|
||||
try (var result =
|
||||
connection
|
||||
.getMetaData()
|
||||
.getImportedKeys(
|
||||
connection.getCatalog(),
|
||||
connection.getSchema(),
|
||||
storedName(connection, name))) {
|
||||
while (result.next()) {
|
||||
String key = lower(result.getString("FK_NAME"));
|
||||
actual.computeIfAbsent(key, ignored -> new java.util.TreeMap<>())
|
||||
.put(
|
||||
result.getInt("KEY_SEQ"),
|
||||
lower(result.getString("FKCOLUMN_NAME"))
|
||||
+ ":"
|
||||
+ lower(result.getString("PKTABLE_NAME"))
|
||||
+ ":"
|
||||
+ lower(result.getString("PKCOLUMN_NAME")));
|
||||
private static void validateIndexPrefix(Connection connection, String table,
|
||||
String index, String declaration) throws SQLException {
|
||||
if (!"MySQL".equals(connection.getMetaData().getDatabaseProductName())
|
||||
&& !isMariaDb(connection)) {
|
||||
return;
|
||||
}
|
||||
String[] fields = declaration.split(",");
|
||||
try (var statement = connection.prepareStatement(
|
||||
"SELECT SEQ_IN_INDEX, SUB_PART FROM INFORMATION_SCHEMA.STATISTICS"
|
||||
+ " WHERE TABLE_SCHEMA = ? AND TABLE_NAME = ? AND INDEX_NAME = ?")) {
|
||||
statement.setString(1, schema(connection));
|
||||
statement.setString(2, table);
|
||||
statement.setString(3, index);
|
||||
try (var rows = statement.executeQuery()) {
|
||||
while (rows.next()) {
|
||||
var prefix = INDEX_PREFIX.matcher(fields[rows.getInt(1) - 1]);
|
||||
Integer expected = prefix.find() ? Integer.valueOf(prefix.group(1)) : null;
|
||||
if (!java.util.Objects.equals(expected, rows.getObject(2, Integer.class))) {
|
||||
throw new SQLException("Managed schema index prefix differs: " + index);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
var alters = Pattern.compile("ALTER TABLE " + name + " ([^;]+);").matcher(ddl);
|
||||
String declarations = body;
|
||||
while (alters.find()) {
|
||||
declarations += "\n" + alters.group(1);
|
||||
}
|
||||
var foreign = FOREIGN.matcher(declarations);
|
||||
while (foreign.find()) {
|
||||
List<String> local = columns(foreign.group(1));
|
||||
List<String> remote = columns(foreign.group(3));
|
||||
List<String> expected = new ArrayList<>();
|
||||
for (int index = 0; index < local.size(); index++) {
|
||||
expected.add(local.get(index) + ":" + foreign.group(2) + ":" + remote.get(index));
|
||||
}
|
||||
if (actual.values().stream()
|
||||
.noneMatch(key -> new ArrayList<>(key.values()).equals(expected))) {
|
||||
throw new SQLException("Managed schema foreign key is missing: " + name + local);
|
||||
}
|
||||
|
||||
private static void validateForeignKeys(Connection connection, String name) throws SQLException {
|
||||
try (var keys = connection.getMetaData().getImportedKeys(
|
||||
connection.getCatalog(), connection.getSchema(), storedName(connection, name))) {
|
||||
if (keys.next()) {
|
||||
throw new SQLException("Managed schema must not contain foreign keys: " + name);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -376,6 +393,7 @@ final class ManagedSchemaCatalog {
|
||||
case "CHAR" -> type == java.sql.Types.CHAR;
|
||||
case "BIGINT" -> type == java.sql.Types.BIGINT;
|
||||
case "INT" -> type == java.sql.Types.INTEGER;
|
||||
case "TINYINT" -> type == java.sql.Types.TINYINT;
|
||||
case "BOOLEAN" ->
|
||||
type == java.sql.Types.BOOLEAN
|
||||
|| type == java.sql.Types.BIT
|
||||
@@ -594,7 +612,7 @@ final class ManagedSchemaCatalog {
|
||||
}
|
||||
|
||||
private static List<String> columns(String value) {
|
||||
return java.util.Arrays.stream(value.split(","))
|
||||
return java.util.Arrays.stream(INDEX_PREFIX.matcher(value).replaceAll("").split(","))
|
||||
.map(String::trim)
|
||||
.map(ManagedSchemaCatalog::lower)
|
||||
.toList();
|
||||
|
||||
+20
-20
@@ -23,7 +23,7 @@ public enum ManagedSchemaProjection {
|
||||
"tenant_id, session_id, stream_kind, stream_id, last_sequence, "
|
||||
+ "replay_floor_sequence, covered_sequence, wake_covered_sequence, projection_version, "
|
||||
+ "artifact_refs_resource_key, "
|
||||
+ "output_ranges_json, projection_pending, gmt_modified"),
|
||||
+ "output_ranges_json, is_projection_pending, gmt_modified"),
|
||||
MESSAGE(
|
||||
"tenant_id, session_id, item_id, turn_id, item_type, item_role, item_status, "
|
||||
+ "attributes_json, first_sequence, last_sequence, gmt_create, gmt_modified, revision, "
|
||||
@@ -38,7 +38,7 @@ public enum ManagedSchemaProjection {
|
||||
+ "payload_version, request_json, result_json, state, phase, admission_stage, "
|
||||
+ "delivery_state, session_status_before, receipt_id, claim_owner, claim_generation, "
|
||||
+ "claim_until, available_at, attempt_count, budget_exempt_attempt, deadline, "
|
||||
+ "recovery_deadline, execution_mode, verification_request_json, verification_ready, "
|
||||
+ "recovery_deadline, execution_mode, verification_request_json, is_verification_ready, "
|
||||
+ "verification_next_at, publication_id, publication_command_id, slot_key, "
|
||||
+ "execution_key, item_id, policy_version, failure_status, failure_code, gmt_create, "
|
||||
+ "gmt_modified, completed_at, progress_format, progress_version, progress_stage, "
|
||||
@@ -52,22 +52,22 @@ public enum ManagedSchemaProjection {
|
||||
"scope_key, tenant_key, tenant_id, workspace_id, session_id, publication_id, "
|
||||
+ "execution_key, capture_id, binding_json, binding_digest, token_hash, state, "
|
||||
+ "expires_at, capture_bytes, producer_bytes, admission_bytes, producer_phase, "
|
||||
+ "quarantined, active_operation_id, finish_operation_id, finish_predecessor_id, "
|
||||
+ "is_quarantined, active_operation_id, finish_operation_id, finish_predecessor_id, "
|
||||
+ "finish_digest, terminal_resource_id, admission_resource_id, receipt_sequence, "
|
||||
+ "receipt_revision, capture_held_bytes, producer_held_bytes, admission_held_bytes, "
|
||||
+ "capture_used_bytes, producer_used_bytes, admission_used_bytes, retention_state, "
|
||||
+ "write_evidence, accepted_complete, collected_at, collected_bytes, "
|
||||
+ "is_write_evidence, is_accepted_complete, collected_at, collected_bytes, "
|
||||
+ "released_held_bytes, manifest_resource_key, manifest_sha256, "
|
||||
+ "seal_manifest_resource_key, seal_manifest_sha256, gmt_create, gmt_modified"),
|
||||
PUBLIC_EVENT(
|
||||
"tenant_id, session_id, sequence_id, event_id, turn_id, event_type, data_json, "
|
||||
+ "terminal, source_key, gmt_create, schema_version, projection_version, item_id, "
|
||||
+ "content_part_id, stream_kind, stream_id, state, runtime_state, text, truncated, "
|
||||
+ "artifact_id, capture_id, output_stream_id, first_ordinal, end_ordinal, archived"),
|
||||
+ "is_terminal, source_key, gmt_create, schema_version, projection_version, item_id, "
|
||||
+ "content_part_id, stream_kind, stream_id, state, runtime_state, text, is_truncated, "
|
||||
+ "artifact_id, capture_id, output_stream_id, first_ordinal, end_ordinal, is_archived"),
|
||||
REQUEST_RECEIPT(
|
||||
"receipt_key, namespace, tenant_key, tenant_id, scope_kind, scope_key, scope_id, "
|
||||
+ "idempotency_key, idempotency_digest, request_digest, actor_id, operation, state, "
|
||||
+ "workspace_bound, session_id, turn_id, agent_id, agent_revision, schedule_id, "
|
||||
+ "is_workspace_bound, session_id, turn_id, agent_id, agent_revision, schedule_id, "
|
||||
+ "channel_id, account_generation, semantic_revision, action_id, action_version, "
|
||||
+ "decision_scope_key, mutation_attempt_sequence, session_status_before, "
|
||||
+ "result_operation_key, result_json, gmt_create, gmt_modified"),
|
||||
@@ -85,11 +85,11 @@ public enum ManagedSchemaProjection {
|
||||
"binding_id, request_key, scope_key, tenant_id, workspace_id, workspace_generation, "
|
||||
+ "canonical_cwd, capability_digest, isolation_class, isolation_key, provisioner_kind, "
|
||||
+ "storage_id, storage_alias_key, runtime_generation, binding_state, "
|
||||
+ "provision_request_id, provision_seed_ciphertext, provision_seeded, "
|
||||
+ "provision_request_id, provision_seed_ciphertext, is_provision_seeded, "
|
||||
+ "credential_key_id, resource_handle_version, resource_handle_json, "
|
||||
+ "loss_evidence_json, stop_evidence_json, runtime_instance_id, runtime_endpoint, "
|
||||
+ "runtime_lease_id, runtime_epoch, runtime_credential_ciphertext, "
|
||||
+ "runtime_credential_key_id, attestation_generation, drain_requested, "
|
||||
+ "runtime_credential_key_id, attestation_generation, is_drain_requested, "
|
||||
+ "operation_owner, operation_lease_until, operation_generation, record_version, "
|
||||
+ "last_health_at, last_reconciled_at, last_active_at, drain_receipt_json, "
|
||||
+ "first_activation_journal_revision"),
|
||||
@@ -97,7 +97,7 @@ public enum ManagedSchemaProjection {
|
||||
"scope_key, runtime_session_id, tenant_id, workspace_id, workspace_generation, "
|
||||
+ "canonical_cwd, capability_digest, isolation_class, harness_session_id, turn_kind, "
|
||||
+ "binding_id, runtime_generation, session_state, record_version, last_active_at, "
|
||||
+ "execution_storage_key, execution_exclusive"),
|
||||
+ "execution_storage_key, is_execution_exclusive"),
|
||||
RUNTIME_SLOT(
|
||||
"request_key, tenant_id, workspace_id, workspace_generation, canonical_cwd, "
|
||||
+ "capability_digest, isolation_class, isolation_key, provisioner_kind, storage_id, "
|
||||
@@ -105,7 +105,7 @@ public enum ManagedSchemaProjection {
|
||||
SCHEDULE(
|
||||
"tenant_id, schedule_id, session_id, workspace_id, actor_id, record_revision, "
|
||||
+ "definition_revision, definition_digest, goal, cron, timezone, session_mode, "
|
||||
+ "overlap, catch_up, catch_up_limit, enabled, state, blocked_reason, armed_at, "
|
||||
+ "overlap, catch_up, catch_up_limit, is_enabled, state, blocked_reason, armed_at, "
|
||||
+ "watermark_slot, lease_owner, lease_until, fence, gmt_create, gmt_modified, "
|
||||
+ "gate, gate_last_outcome, gate_last_at, gate_quiet_since_delivery, "
|
||||
+ "gate_failures, gate_last_error"),
|
||||
@@ -122,10 +122,10 @@ public enum ManagedSchemaProjection {
|
||||
+ "tool_profile, creator_actor_key, owner_actor_key, parent_session_id, "
|
||||
+ "root_session_id, parent_child_run_id, child_depth, agent_definition_digest, "
|
||||
+ "session_kind, tenant_key, session_key, session_scope_key, title_revision, "
|
||||
+ "retirement_operation_id, retirement_generation, retired_at, recovery_protected, "
|
||||
+ "resource_gc_completed, runtime_request_key, csi_guard, model_id, model_revision, "
|
||||
+ "retirement_operation_id, retirement_generation, retired_at, is_recovery_protected, "
|
||||
+ "is_resource_gc_completed, runtime_request_key, is_csi_guard, model_id, model_revision, "
|
||||
+ "model_config_digest, model_config_key_id, model_config_ciphertext, "
|
||||
+ "selected_approval_mode, approval_revision, plan_enabled, permission_rules_json, public_child_agents_version, harness_instance_id, "
|
||||
+ "selected_approval_mode, approval_revision, is_plan_enabled, permission_rules_json, public_child_agents_version, harness_instance_id, "
|
||||
+ "harness_owner_boot_id, harness_placement_epoch, harness_placement_state"),
|
||||
SESSION_HEAD(
|
||||
"tenant_id, workspace_id, session_id, storage_version, state, writer_generation, "
|
||||
@@ -135,8 +135,8 @@ public enum ManagedSchemaProjection {
|
||||
+ "recovery_detail_code, gmt_create, gmt_modified, activation_id, "
|
||||
+ "activation_phase, activation_event_epoch, activation_expires_at, "
|
||||
+ "activation_head_revision, tenant_key, harness_key, harness_session_id, head_kind, "
|
||||
+ "phase, operation_id, claim_generation, claim_lease_until, wake_pending, "
|
||||
+ "wake_head_revision, wake_retry_at, wake_scan_pending, cleanup_head_revision"),
|
||||
+ "phase, operation_id, claim_generation, claim_lease_until, is_wake_pending, "
|
||||
+ "wake_head_revision, wake_retry_at, is_wake_scan_pending, cleanup_head_revision"),
|
||||
SESSION_JOURNAL_TX(
|
||||
"tenant_id, workspace_id, session_id, journal_revision, command_key_hash, "
|
||||
+ "transaction_id, operation, command_id, content_digest, first_sequence, "
|
||||
@@ -168,17 +168,17 @@ public enum ManagedSchemaProjection {
|
||||
"execution_call_id_hash, execution_call_id, idempotency_key_hash, idempotency_key, "
|
||||
+ "binding_id, runtime_generation, harness_session_id, runtime_session_id, "
|
||||
+ "runtime_session_key, turn_id, tool_call_id, request_digest, reference_json, "
|
||||
+ "execution_state, execution_status, result_json, last_sequence, cancel_requested, "
|
||||
+ "execution_state, execution_status, result_json, last_sequence, is_cancel_requested, "
|
||||
+ "dispatch_owner, dispatch_lease_until, dispatch_generation, record_version, "
|
||||
+ "settled_at, abandoned_at, loss_evidence_id, authorized_dispatch_generation, "
|
||||
+ "authorized_binding_version, native_authorization_json"),
|
||||
TURN(
|
||||
"tenant_id, session_id, turn_id, prompt_id, input_json, payload_digest, status, "
|
||||
+ "submission_attempted, harness_event_epoch, harness_last_event_id, dispatch_owner, "
|
||||
+ "is_submission_attempted, harness_event_epoch, harness_last_event_id, dispatch_owner, "
|
||||
+ "dispatch_lease_until, error_code, error_message, gmt_create, gmt_modified, "
|
||||
+ "completed_at, version, retry_count, consecutive_failures, "
|
||||
+ "budget_exempt_failures, retry_after, model_id, model_revision, "
|
||||
+ "approval_mode, approval_revision, plan_enabled, permission_rules_json");
|
||||
+ "approval_mode, approval_revision, is_plan_enabled, permission_rules_json");
|
||||
|
||||
private final String columns;
|
||||
|
||||
|
||||
+24
-7
@@ -15,12 +15,29 @@ import java.util.Set;
|
||||
/** Reads raw SQL rows while decoding only declared UTF-8 identity columns. */
|
||||
public final class ManagedSchemaRows {
|
||||
private static final Set<String> BOOLEANS = Set.of(
|
||||
"recovery_protected", "resource_gc_completed", "submission_attempted",
|
||||
"projection_pending", "terminal", "truncated",
|
||||
"archived", "quarantined", "write_evidence", "accepted_complete",
|
||||
"workspace_bound", "verification_ready", "is_default", "provision_seeded",
|
||||
"drain_requested", "cancel_requested", "enabled", "csi_guard",
|
||||
"execution_exclusive");
|
||||
"is_accepted_complete",
|
||||
"is_archived",
|
||||
"is_cancel_requested",
|
||||
"is_csi_guard",
|
||||
"is_default",
|
||||
"is_drain_requested",
|
||||
"is_enabled",
|
||||
"is_execution_exclusive",
|
||||
"is_paused",
|
||||
"is_plan_enabled",
|
||||
"is_projection_pending",
|
||||
"is_provision_seeded",
|
||||
"is_quarantined",
|
||||
"is_recovery_protected",
|
||||
"is_resource_gc_completed",
|
||||
"is_submission_attempted",
|
||||
"is_terminal",
|
||||
"is_truncated",
|
||||
"is_verification_ready",
|
||||
"is_wake_pending",
|
||||
"is_wake_scan_pending",
|
||||
"is_workspace_bound",
|
||||
"is_write_evidence");
|
||||
private static final Set<String> IDENTITIES =
|
||||
Set.of(
|
||||
"tenant_id",
|
||||
@@ -144,7 +161,7 @@ public final class ManagedSchemaRows {
|
||||
} else if (value instanceof java.time.LocalDateTime timestamp) {
|
||||
value = java.sql.Timestamp.valueOf(timestamp);
|
||||
}
|
||||
if ("csi_guard".equals(label) && value instanceof Number number) {
|
||||
if ("is_csi_guard".equals(label) && value instanceof Number number) {
|
||||
value = number.longValue() != 0;
|
||||
}
|
||||
row.put(label, value);
|
||||
|
||||
+5
-5
@@ -61,7 +61,7 @@ public final class JdbcCsiFilesRetirementGuard {
|
||||
throw unavailable();
|
||||
}
|
||||
var original = new Original(request(row), com.alibaba.qwen.code.runtimebroker.managedschema.ManagedSchemaRows.identity(row, "binding_id"), row.getLong("runtime_generation"),
|
||||
RuntimeBindingRecord.State.valueOf(row.getString("binding_state")), row.getBoolean("drain_requested"),
|
||||
RuntimeBindingRecord.State.valueOf(row.getString("binding_state")), row.getBoolean("is_drain_requested"),
|
||||
row.getLong("record_version"), row.getObject("first_activation_journal_revision", Long.class));
|
||||
if (!binding.getBindingId().equals(original.bindingId()) || !binding.getRequest().equals(original.request())
|
||||
|| binding.getGeneration() != original.generation() || binding.getState() != original.state()
|
||||
@@ -339,7 +339,7 @@ public final class JdbcCsiFilesRetirementGuard {
|
||||
.identity(rows, "binding_id"),
|
||||
rows.getLong("runtime_generation"),
|
||||
RuntimeBindingRecord.State.valueOf(rows.getString("binding_state")),
|
||||
rows.getBoolean("drain_requested"), rows.getLong("record_version"),
|
||||
rows.getBoolean("is_drain_requested"), rows.getLong("record_version"),
|
||||
rows.getObject("first_activation_journal_revision", Long.class));
|
||||
if (bindings.size() < 2 || isProfile(original.request().getScope())
|
||||
&& bindings.stream().noneMatch(binding ->
|
||||
@@ -421,12 +421,12 @@ public final class JdbcCsiFilesRetirementGuard {
|
||||
}
|
||||
|
||||
private static Pin readPin(Connection connection, String tenantId, String sessionId) throws SQLException {
|
||||
// By primary key: on an existing root this locks that record alone.
|
||||
// Through ma_session_csi_guard_idx, an unpinned root left a gap lock
|
||||
// By unique business key: on an existing root this locks that record alone.
|
||||
// Through idx_ma_session_csi_guard, an unpinned root left a gap lock
|
||||
// that spans other tenants' keys, so their first writers could not
|
||||
// insert their own roots (#13996).
|
||||
try (PreparedStatement statement = statement(connection,
|
||||
"SELECT csi_guard FROM ma_session WHERE tenant_id = ? AND session_id = ? FOR"
|
||||
"SELECT is_csi_guard FROM ma_session WHERE tenant_id = ? AND session_id = ? FOR"
|
||||
+ " UPDATE")) {
|
||||
JdbcRepositorySupport.setIdentity(statement, 1, tenantId);
|
||||
JdbcRepositorySupport.setIdentity(statement, 2, sessionId);
|
||||
|
||||
+4
-4
@@ -78,7 +78,7 @@ public final class JdbcRuntimeBindingRepository
|
||||
"runtime_credential_ciphertext",
|
||||
"runtime_credential_key_id",
|
||||
"attestation_generation",
|
||||
"drain_requested",
|
||||
"is_drain_requested",
|
||||
"operation_owner",
|
||||
"operation_lease_until",
|
||||
"operation_generation",
|
||||
@@ -202,7 +202,7 @@ public final class JdbcRuntimeBindingRepository
|
||||
}
|
||||
}
|
||||
try (var clear = connection.prepareStatement("UPDATE ma_runtime_session SET execution_storage_key = NULL,"
|
||||
+ " execution_exclusive = FALSE WHERE execution_storage_key = ? AND binding_id = ?"
|
||||
+ " is_execution_exclusive = FALSE WHERE execution_storage_key = ? AND binding_id = ?"
|
||||
+ " AND runtime_generation = ? AND runtime_session_id = ?")) {
|
||||
clear.setString(1, key);
|
||||
JdbcRepositorySupport.setIdentity(clear, 2, session.getBindingId());
|
||||
@@ -2334,7 +2334,7 @@ public final class JdbcRuntimeBindingRepository
|
||||
"UPDATE ma_runtime_binding SET binding_state = ?, resource_handle_version = ?,"
|
||||
+ " resource_handle_json = ?, runtime_instance_id = ?, runtime_endpoint = ?,"
|
||||
+ " runtime_lease_id = ?, runtime_epoch = ?, runtime_credential_ciphertext = ?,"
|
||||
+ " runtime_credential_key_id = ?, attestation_generation = ?, drain_requested"
|
||||
+ " runtime_credential_key_id = ?, attestation_generation = ?, is_drain_requested"
|
||||
+ " = ?, operation_owner = ?, operation_lease_until = ?, operation_generation ="
|
||||
+ " ?, record_version = ?, last_health_at = ?, last_reconciled_at = ?,"
|
||||
+ " last_active_at = ?, loss_evidence_json = ?, stop_evidence_json = ?,"
|
||||
@@ -2496,7 +2496,7 @@ public final class JdbcRuntimeBindingRepository
|
||||
RuntimeBindingRecord.State.valueOf(
|
||||
result.getString("binding_state")),
|
||||
lease, handle, result.getLong("attestation_generation"),
|
||||
result.getBoolean("drain_requested"),
|
||||
result.getBoolean("is_drain_requested"),
|
||||
result.getString("operation_owner"),
|
||||
JdbcRepositorySupport.getInstant(result,
|
||||
"operation_lease_until"),
|
||||
|
||||
+1
-1
@@ -72,7 +72,7 @@ public final class JdbcRuntimeSessionRepository
|
||||
JdbcRepositorySupport.setIdentity(statement, 1, original.request().getScope().getTenantId());
|
||||
JdbcRepositorySupport.setIdentity(statement, 2, original.request().getIsolationKey());
|
||||
try (var row = statement.executeQuery()) {
|
||||
if (!row.next() || !row.getBoolean("csi_guard")) {
|
||||
if (!row.next() || !row.getBoolean("is_csi_guard")) {
|
||||
throw new IllegalArgumentException("Original managed Session is required");
|
||||
}
|
||||
context = new com.alibaba.qwen.code.runtimebroker.managedworkspace.ContextBinding(com.alibaba.qwen.code.runtimebroker.managedschema.ManagedSchemaRows.identity(row, "tenant_id"),
|
||||
|
||||
+3
-3
@@ -37,7 +37,7 @@ public final class JdbcToolExecutionRepository
|
||||
"runtime_session_id", "runtime_session_key", "turn_id",
|
||||
"tool_call_id", "request_digest", "reference_json",
|
||||
"execution_state", "execution_status", "result_json",
|
||||
"last_sequence", "cancel_requested", "dispatch_owner",
|
||||
"last_sequence", "is_cancel_requested", "dispatch_owner",
|
||||
"dispatch_lease_until", "dispatch_generation", "record_version",
|
||||
"settled_at", "abandoned_at", "loss_evidence_id",
|
||||
"authorized_dispatch_generation", "authorized_binding_version");
|
||||
@@ -1082,7 +1082,7 @@ public final class JdbcToolExecutionRepository
|
||||
ToolExecutionRecord record) throws SQLException {
|
||||
String sql = "UPDATE ma_tool_execution SET execution_state = ?, "
|
||||
+ "execution_status = ?, result_json = ?, "
|
||||
+ "last_sequence = ?, cancel_requested = ?, "
|
||||
+ "last_sequence = ?, is_cancel_requested = ?, "
|
||||
+ "dispatch_owner = ?, dispatch_lease_until = ?, "
|
||||
+ "dispatch_generation = ?, record_version = ?, "
|
||||
+ "settled_at = ?, abandoned_at = ?, loss_evidence_id = ?, "
|
||||
@@ -1183,7 +1183,7 @@ public final class JdbcToolExecutionRepository
|
||||
result.getString("execution_status"),
|
||||
fromJson(result.getString("result_json")),
|
||||
result.getLong("last_sequence"),
|
||||
result.getBoolean("cancel_requested"),
|
||||
result.getBoolean("is_cancel_requested"),
|
||||
result.getString("dispatch_owner"),
|
||||
JdbcRepositorySupport.getInstant(result,
|
||||
"dispatch_lease_until"),
|
||||
|
||||
+1144
-1052
File diff suppressed because it is too large.
Load diff
+2
-2
@@ -688,7 +688,7 @@ class ChildResultRelayStoreTest {
|
||||
TENANT, session);
|
||||
jdbc.update("INSERT INTO ma_turn (tenant_id, session_id,"
|
||||
+ " turn_id, prompt_id, input_json, payload_digest,"
|
||||
+ " status, submission_attempted, gmt_create,"
|
||||
+ " status, is_submission_attempted, gmt_create,"
|
||||
+ " gmt_modified, completed_at, version)"
|
||||
+ " VALUES (?, ?, 'turn-1', 'prompt-1', '[]', 'd',"
|
||||
+ " 'COMPLETED', TRUE, 1, 2, 2, 1)", TENANT, session);
|
||||
@@ -702,7 +702,7 @@ class ChildResultRelayStoreTest {
|
||||
// never dispatch proof (R23's cascade producer).
|
||||
jdbc.update("INSERT INTO ma_turn (tenant_id, session_id,"
|
||||
+ " turn_id, prompt_id, input_json, payload_digest,"
|
||||
+ " status, submission_attempted, gmt_create,"
|
||||
+ " status, is_submission_attempted, gmt_create,"
|
||||
+ " gmt_modified, completed_at, version)"
|
||||
+ " VALUES (?, ?, 'turn-pre', 'prompt-2', '[]', 'd',"
|
||||
+ " 'FAILED', FALSE, 3, 4, 4, 1)",
|
||||
|
||||
+1
-1
@@ -958,7 +958,7 @@ class EventTransportBrokerGate {
|
||||
private EventRecord storedPublicEvent(String session, long sequence,
|
||||
String type) {
|
||||
EventRecord event = publicEvent(session, sequence, type);
|
||||
jdbc.update("INSERT INTO ma_public_event (tenant_id, session_id, sequence_id, event_id, turn_id, event_type, data_json, terminal, source_key, gmt_create) VALUES (?, ?, ?, ?, ?, ?, '{}', FALSE, NULL, ?)", TENANT, session, sequence,
|
||||
jdbc.update("INSERT INTO ma_public_event (tenant_id, session_id, sequence_id, event_id, turn_id, event_type, data_json, is_terminal, source_key, gmt_create) VALUES (?, ?, ?, ?, ?, ?, '{}', FALSE, NULL, ?)", TENANT, session, sequence,
|
||||
event.eventId(), event.turnId(), type, event.createdAt());
|
||||
jdbc.update("UPDATE ma_event_stream SET last_sequence = ? WHERE"
|
||||
+ " tenant_id = ? AND session_id = ? AND stream_kind ="
|
||||
|
||||
+1
-1
@@ -498,7 +498,7 @@ class HostedHookMessageDisplayReloadIT {
|
||||
+ destination.toAbsolutePath());
|
||||
json.writeValue(destination.resolve("events.json").toFile(),
|
||||
jdbc.queryForList("SELECT session_id, turn_id,"
|
||||
+ " event_type, terminal FROM ma_public_event"
|
||||
+ " event_type, is_terminal FROM ma_public_event"
|
||||
+ " WHERE tenant_id = ? ORDER BY sequence_id",
|
||||
tenant));
|
||||
json.writeValue(destination.resolve("model-requests.json")
|
||||
|
||||
+3
-3
@@ -517,7 +517,7 @@ class HostedHookStreamGapIT {
|
||||
+ " CAST(turn_id AS CHAR) AS turn_id,"
|
||||
+ " CAST(item_id AS CHAR) AS item_id,"
|
||||
+ " CAST(content_part_id AS CHAR) AS content_part_id,"
|
||||
+ " event_type, gmt_create, data_json, terminal"
|
||||
+ " event_type, gmt_create, data_json, is_terminal"
|
||||
+ " FROM ma_public_event WHERE tenant_id = ? AND"
|
||||
+ " session_id = ? AND stream_kind = 'SESSION' AND"
|
||||
+ " stream_id = X'' ORDER BY sequence_id", tenant, session);
|
||||
@@ -543,7 +543,7 @@ class HostedHookStreamGapIT {
|
||||
fields.put("type", row.get("event_type"));
|
||||
fields.put("created_at", web ? millis : millis / 1000);
|
||||
fields.put("data", json.readTree(row.get("data_json").toString()));
|
||||
Object terminal = row.get("terminal");
|
||||
Object terminal = row.get("is_terminal");
|
||||
fields.put("terminal", terminal instanceof Boolean flag ? flag
|
||||
: ((Number) terminal).intValue() != 0);
|
||||
ObjectNode node = json.createObjectNode();
|
||||
@@ -799,7 +799,7 @@ class HostedHookStreamGapIT {
|
||||
.toList());
|
||||
json.writeValue(destination.resolve("events.json").toFile(),
|
||||
jdbc.queryForList("SELECT session_id, turn_id,"
|
||||
+ " event_type, terminal FROM ma_public_event"
|
||||
+ " event_type, is_terminal FROM ma_public_event"
|
||||
+ " WHERE tenant_id = ? ORDER BY sequence_id",
|
||||
tenant));
|
||||
json.writeValue(destination.resolve("model-requests.json")
|
||||
|
||||
+3
-3
@@ -657,7 +657,7 @@ class HostedMcpStreamGapIT {
|
||||
+ " CAST(turn_id AS CHAR) AS turn_id,"
|
||||
+ " CAST(item_id AS CHAR) AS item_id,"
|
||||
+ " CAST(content_part_id AS CHAR) AS content_part_id,"
|
||||
+ " event_type, gmt_create, data_json, terminal"
|
||||
+ " event_type, gmt_create, data_json, is_terminal"
|
||||
+ " FROM ma_public_event WHERE tenant_id = ? AND"
|
||||
+ " session_id = ? AND stream_kind = 'SESSION' AND"
|
||||
+ " stream_id = X'' ORDER BY sequence_id", tenant, session);
|
||||
@@ -683,7 +683,7 @@ class HostedMcpStreamGapIT {
|
||||
fields.put("type", row.get("event_type"));
|
||||
fields.put("created_at", web ? millis : millis / 1000);
|
||||
fields.put("data", json.readTree(row.get("data_json").toString()));
|
||||
Object terminal = row.get("terminal");
|
||||
Object terminal = row.get("is_terminal");
|
||||
fields.put("terminal", terminal instanceof Boolean flag ? flag
|
||||
: ((Number) terminal).intValue() != 0);
|
||||
ObjectNode node = json.createObjectNode();
|
||||
@@ -922,7 +922,7 @@ class HostedMcpStreamGapIT {
|
||||
.toList());
|
||||
json.writeValue(destination.resolve("events.json").toFile(),
|
||||
jdbc.queryForList("SELECT session_id, turn_id,"
|
||||
+ " event_type, terminal FROM ma_public_event"
|
||||
+ " event_type, is_terminal FROM ma_public_event"
|
||||
+ " WHERE tenant_id = ? ORDER BY sequence_id",
|
||||
tenant));
|
||||
json.writeValue(destination.resolve("model-requests.json")
|
||||
|
||||
+1
-1
@@ -198,7 +198,7 @@ final class HostedMonitorRunProbe implements AutoCloseable {
|
||||
+ " binding_state, runtime_generation,"
|
||||
+ " loss_evidence_json IS NOT NULL AS loss_evidence,"
|
||||
+ " stop_evidence_json IS NOT NULL AS stop_evidence,"
|
||||
+ " drain_requested FROM ma_runtime_binding WHERE"
|
||||
+ " is_drain_requested FROM ma_runtime_binding WHERE"
|
||||
+ " tenant_id = ? AND isolation_key = ? ORDER BY"
|
||||
+ " runtime_generation", tenant, sessionId);
|
||||
var slots = new java.util.ArrayList<Map<String, Object>>();
|
||||
|
||||
+12
-1
@@ -11,6 +11,7 @@ import org.junit.jupiter.params.provider.ValueSource;
|
||||
import java.sql.Connection;
|
||||
import java.sql.DatabaseMetaData;
|
||||
import java.sql.DriverManager;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Statement;
|
||||
@@ -86,12 +87,20 @@ class HostedMySqlIsolationExtensionTest {
|
||||
throws Throwable {
|
||||
var connection = mock(Connection.class);
|
||||
var metadata = mock(DatabaseMetaData.class);
|
||||
var modeQuery = mock(PreparedStatement.class);
|
||||
var modes = mock(ResultSet.class);
|
||||
var tables = mock(Statement.class);
|
||||
var cleanup = mock(Statement.class);
|
||||
var rows = mock(ResultSet.class);
|
||||
when(connection.getMetaData()).thenReturn(metadata);
|
||||
when(metadata.getDatabaseProductName()).thenReturn("MySQL");
|
||||
when(connection.getCatalog()).thenReturn("hosted_isolation_test");
|
||||
when(connection.prepareStatement("SELECT @@GLOBAL.sql_mode, @@SESSION.sql_mode"))
|
||||
.thenReturn(modeQuery);
|
||||
when(modeQuery.executeQuery()).thenReturn(modes);
|
||||
when(modes.next()).thenReturn(true, false);
|
||||
when(modes.getString(1)).thenReturn("STRICT_TRANS_TABLES");
|
||||
when(modes.getString(2)).thenReturn("STRICT_TRANS_TABLES");
|
||||
when(connection.createStatement()).thenReturn(tables, cleanup);
|
||||
when(tables.executeQuery(anyString())).thenReturn(rows);
|
||||
when(rows.next()).thenReturn(true, true, false);
|
||||
@@ -130,7 +139,9 @@ class HostedMySqlIsolationExtensionTest {
|
||||
}
|
||||
});
|
||||
|
||||
var order = inOrder(rows, tables, cleanup, connection);
|
||||
var order = inOrder(modes, modeQuery, rows, tables, cleanup, connection);
|
||||
order.verify(modes).close();
|
||||
order.verify(modeQuery).close();
|
||||
order.verify(rows).close();
|
||||
order.verify(tables).close();
|
||||
order.verify(cleanup).execute("SET FOREIGN_KEY_CHECKS = 0");
|
||||
|
||||
+2
-2
@@ -673,7 +673,7 @@ class HostedProcessCrashIT {
|
||||
.containsEntry("runtime_session_id", execution.get("runtime_session_id"))
|
||||
.containsEntry("binding_id", execution.get("binding_id"))
|
||||
.containsEntry("runtime_generation", execution.get("runtime_generation"))
|
||||
.containsEntry("session_state", "READY").containsEntry("execution_exclusive", false);
|
||||
.containsEntry("session_state", "READY").containsEntry("is_execution_exclusive", false);
|
||||
assertThat(((Number) member.get("runtime_generation")).longValue()).isEqualTo(1);
|
||||
assertThat(jdbc.queryForObject("SELECT COUNT(*) FROM ma_runtime_binding b"
|
||||
+ " JOIN ma_runtime_session rs ON rs.binding_id=b.binding_id AND rs.runtime_generation=b.runtime_generation"
|
||||
@@ -682,7 +682,7 @@ class HostedProcessCrashIT {
|
||||
+ " WHERE rs.scope_key=? AND rs.runtime_session_id=? AND b.scope_key=rs.scope_key"
|
||||
+ " AND b.tenant_id=rs.tenant_id AND b.workspace_id=rs.workspace_id AND b.workspace_generation=rs.workspace_generation"
|
||||
+ " AND b.canonical_cwd=rs.canonical_cwd AND b.capability_digest=rs.capability_digest AND b.isolation_class=rs.isolation_class"
|
||||
+ " AND b.provisioner_kind='local-process' AND b.binding_state='READY' AND b.drain_requested=FALSE"
|
||||
+ " AND b.provisioner_kind='local-process' AND b.binding_state='READY' AND b.is_drain_requested=FALSE"
|
||||
+ " AND s.workspace_id=b.workspace_id AND s.workspace_generation=b.workspace_generation AND s.workspace_storage_id=b.storage_id"
|
||||
+ " AND st.physical_key=rs.execution_storage_key AND st.registration_state='REGISTERED' AND st.storage_kind='LOCAL'"
|
||||
+ " AND st.registration_revision>0 AND s.workspace_config_ref=? AND s.workspace_policy_ref=? AND s.context_config_ref=?",
|
||||
|
||||
+2
-2
@@ -246,7 +246,7 @@ final class HostedProviderMediaProbe implements AutoCloseable {
|
||||
tenant, storageId);
|
||||
assertThat(physical).isNotBlank();
|
||||
var member = jdbc.queryForMap("SELECT binding_id, runtime_generation, session_state,"
|
||||
+ " execution_storage_key, execution_exclusive FROM ma_runtime_session"
|
||||
+ " execution_storage_key, is_execution_exclusive FROM ma_runtime_session"
|
||||
+ " WHERE tenant_id = ? AND harness_session_id = ? AND runtime_session_id = ?",
|
||||
tenant, harness, runtimeId);
|
||||
boolean released = phase.equals("released") || phase.equals("restarted");
|
||||
@@ -254,7 +254,7 @@ final class HostedProviderMediaProbe implements AutoCloseable {
|
||||
assertThat(member.get("runtime_generation")).as("original runtime generation").isEqualTo(row.get("runtime_generation"));
|
||||
assertThat(member.get("execution_storage_key")).as("physical execution membership")
|
||||
.isEqualTo(released ? null : physical);
|
||||
assertThat(member.get("execution_exclusive")).as("shared execution membership").isEqualTo(false);
|
||||
assertThat(member.get("is_execution_exclusive")).as("shared execution membership").isEqualTo(false);
|
||||
assertThat(member.get("session_state")).isEqualTo(released ? "RELEASED" : "READY");
|
||||
if (phase.equals("restarted")) {
|
||||
assertThat(restarted).isNotNull();
|
||||
|
||||
+3
-3
@@ -131,7 +131,7 @@ class HostedProviderMediaProbeTest {
|
||||
jdbc.update("INSERT INTO ma_tool_execution (execution_call_id_hash, execution_call_id,"
|
||||
+ " idempotency_key_hash, idempotency_key, binding_id, runtime_generation, harness_session_id,"
|
||||
+ " runtime_session_id, runtime_session_key, turn_id, tool_call_id, request_digest,"
|
||||
+ " reference_json, execution_state, last_sequence, cancel_requested, dispatch_generation,"
|
||||
+ " reference_json, execution_state, last_sequence, is_cancel_requested, dispatch_generation,"
|
||||
+ " record_version) VALUES (?, 'execute', ?, 'key', 'binding', 1, 'harness', 'runtime', ?,"
|
||||
+ " 'turn', 'call', 'digest', ?, 'PREPARED', 0, FALSE, 0, 1)",
|
||||
"b".repeat(64), "c".repeat(64), "d".repeat(64), reference.toString());
|
||||
@@ -170,10 +170,10 @@ class HostedProviderMediaProbeTest {
|
||||
jdbc.update("UPDATE ma_runtime_session SET binding_id='binding', runtime_generation=2");
|
||||
assertThatThrownBy(() -> ReflectionTestUtils.invokeMethod(probe, "check", session, "prepared", fields))
|
||||
.isInstanceOf(AssertionError.class).hasMessageContaining("original runtime generation");
|
||||
jdbc.update("UPDATE ma_runtime_session SET runtime_generation=1, execution_exclusive=TRUE");
|
||||
jdbc.update("UPDATE ma_runtime_session SET runtime_generation=1, is_execution_exclusive=TRUE");
|
||||
assertThatThrownBy(() -> ReflectionTestUtils.invokeMethod(probe, "check", session, "prepared", fields))
|
||||
.isInstanceOf(AssertionError.class).hasMessageContaining("shared execution membership");
|
||||
jdbc.update("UPDATE ma_runtime_session SET execution_exclusive=FALSE");
|
||||
jdbc.update("UPDATE ma_runtime_session SET is_execution_exclusive=FALSE");
|
||||
jdbc.update("UPDATE ma_tool_execution SET execution_state='SETTLED', execution_status='success',"
|
||||
+ " dispatch_generation=1, result_json='{}'");
|
||||
ReflectionTestUtils.setField(probe, "dispatches", Map.of("runtime", 1));
|
||||
|
||||
+1
-1
@@ -1202,7 +1202,7 @@ class HostedPublicWorkspaceIT {
|
||||
JsonNode events = request("GET", "/v1/agents/sessions/" + session + "/events", null, null, "actor", 200);
|
||||
assertThat(events.toString()).contains("G0_DONE");
|
||||
assertThat(jdbc.queryForObject("SELECT COUNT(*) FROM ma_public_event"
|
||||
+ " WHERE tenant_id = ? AND session_id = ? AND terminal = TRUE", Integer.class, tenant, session))
|
||||
+ " WHERE tenant_id = ? AND session_id = ? AND is_terminal = TRUE", Integer.class, tenant, session))
|
||||
.isEqualTo(1);
|
||||
int requests = modelRequests.size();
|
||||
long executions = jdbc.queryForObject("SELECT COUNT(*) FROM ma_tool_execution WHERE harness_session_id = ?",
|
||||
|
||||
+3
-3
@@ -1491,7 +1491,7 @@ class HostedSessionRelayFaultGatesIT {
|
||||
+ " CAST(turn_id AS CHAR) AS turn_id,"
|
||||
+ " CAST(item_id AS CHAR) AS item_id,"
|
||||
+ " CAST(content_part_id AS CHAR) AS content_part_id,"
|
||||
+ " event_type, gmt_create, data_json, terminal"
|
||||
+ " event_type, gmt_create, data_json, is_terminal"
|
||||
+ " FROM ma_public_event WHERE tenant_id = ? AND"
|
||||
+ " session_id = ? AND stream_kind = 'SESSION' AND"
|
||||
+ " stream_id = X'' ORDER BY sequence_id",
|
||||
@@ -1517,7 +1517,7 @@ class HostedSessionRelayFaultGatesIT {
|
||||
fields.put("type", row.get("event_type"));
|
||||
fields.put("created_at", web ? created : created / 1000);
|
||||
fields.put("data", json.readTree(row.get("data_json").toString()));
|
||||
Object terminal = row.get("terminal");
|
||||
Object terminal = row.get("is_terminal");
|
||||
fields.put("terminal", terminal instanceof Boolean flag ? flag
|
||||
: ((Number) terminal).intValue() != 0);
|
||||
ObjectNode node = json.createObjectNode();
|
||||
@@ -1536,7 +1536,7 @@ class HostedSessionRelayFaultGatesIT {
|
||||
"SELECT COUNT(*) FROM ma_public_event"
|
||||
+ " WHERE tenant_id = ? AND"
|
||||
+ " session_id = ? AND turn_id = ?"
|
||||
+ " AND terminal",
|
||||
+ " AND is_terminal",
|
||||
Integer.class, tenant, session, turn))
|
||||
.isEqualTo(1));
|
||||
}
|
||||
|
||||
+4
-4
@@ -442,14 +442,14 @@ class HostedShellLifecycleRecoveryIT {
|
||||
/** The durable blocker the collectors persisted; survives a lost Spring log. */
|
||||
private Map<String, Object> collectionState() {
|
||||
var state = new LinkedHashMap<String, Object>();
|
||||
state.put("capture", jdbc.queryForList("SELECT retention_state, collected_at, write_evidence,"
|
||||
+ " accepted_complete, quarantined, producer_phase FROM ma_output_capture"
|
||||
state.put("capture", jdbc.queryForList("SELECT retention_state, collected_at, is_write_evidence,"
|
||||
+ " is_accepted_complete, is_quarantined, producer_phase FROM ma_output_capture"
|
||||
+ " WHERE tenant_id = ? AND session_id = ?", tenant, session));
|
||||
state.put("operations", jdbc.queryForList("SELECT operation_kind, state, phase, failure_code,"
|
||||
+ " available_at FROM ma_operation WHERE operation_kind IN ('CAPTURE_GC',"
|
||||
+ " 'SESSION_RESOURCE_GC') AND tenant_id = ? AND session_id = ?", tenant, session));
|
||||
state.put("retirement", jdbc.queryForList("SELECT retired_at, recovery_protected,"
|
||||
+ " resource_gc_completed FROM ma_session WHERE tenant_id = ? AND session_id = ?",
|
||||
state.put("retirement", jdbc.queryForList("SELECT retired_at, is_recovery_protected,"
|
||||
+ " is_resource_gc_completed FROM ma_session WHERE tenant_id = ? AND session_id = ?",
|
||||
tenant, session));
|
||||
state.put("liveReadLeases", jdbc.queryForObject("SELECT COUNT(*) FROM ma_read_lease"
|
||||
+ " WHERE tenant_key = ? AND session_key = ? AND expires_at > ?", Long.class,
|
||||
|
||||
+2
-2
@@ -136,7 +136,7 @@ final class HostedSseGapProbe implements AutoCloseable {
|
||||
}
|
||||
assertThat(execution.get("execution_call_id")).isEqualTo(executionId);
|
||||
String storage = "storage-0";
|
||||
var member = jdbc.queryForMap("SELECT m.execution_storage_key, m.execution_exclusive, s.physical_key"
|
||||
var member = jdbc.queryForMap("SELECT m.execution_storage_key, m.is_execution_exclusive, s.physical_key"
|
||||
+ " FROM ma_runtime_session m JOIN ma_storage s ON s.tenant_id = m.tenant_id"
|
||||
+ " WHERE s.alias_key = ? AND s.tenant_id = ? AND s.storage_id = ?"
|
||||
+ " AND m.harness_session_id = ? AND m.binding_id = ?"
|
||||
@@ -145,7 +145,7 @@ final class HostedSseGapProbe implements AutoCloseable {
|
||||
tenant, storage, session, execution.get("binding_id"), execution.get("runtime_generation"), promptId);
|
||||
assertThat(member.get("physical_key")).isNotNull();
|
||||
assertThat(member.get("execution_storage_key")).isEqualTo(finished ? null : member.get("physical_key"));
|
||||
assertThat(member.get("execution_exclusive")).isEqualTo(false);
|
||||
assertThat(member.get("is_execution_exclusive")).isEqualTo(false);
|
||||
assertThat(execution.get("turn_id")).isEqualTo(promptId);
|
||||
assertThat(execution.get("runtime_session_id")).isEqualTo(promptId);
|
||||
assertThat(execution.get("execution_state")).isEqualTo(finished ? "SETTLED" : "EXECUTING");
|
||||
|
||||
+3
-3
@@ -1127,7 +1127,7 @@ class HostedWorkflowRelayFaultGatesIT {
|
||||
+ " CAST(turn_id AS CHAR) AS turn_id,"
|
||||
+ " CAST(item_id AS CHAR) AS item_id,"
|
||||
+ " CAST(content_part_id AS CHAR) AS content_part_id,"
|
||||
+ " event_type, gmt_create, data_json, terminal"
|
||||
+ " event_type, gmt_create, data_json, is_terminal"
|
||||
+ " FROM ma_public_event WHERE tenant_id = ? AND"
|
||||
+ " session_id = ? AND stream_kind = 'SESSION' AND"
|
||||
+ " stream_id = X'' ORDER BY sequence_id",
|
||||
@@ -1153,7 +1153,7 @@ class HostedWorkflowRelayFaultGatesIT {
|
||||
fields.put("type", row.get("event_type"));
|
||||
fields.put("created_at", web ? created : created / 1000);
|
||||
fields.put("data", json.readTree(row.get("data_json").toString()));
|
||||
Object terminal = row.get("terminal");
|
||||
Object terminal = row.get("is_terminal");
|
||||
fields.put("terminal", terminal instanceof Boolean flag ? flag
|
||||
: ((Number) terminal).intValue() != 0);
|
||||
ObjectNode node = json.createObjectNode();
|
||||
@@ -1172,7 +1172,7 @@ class HostedWorkflowRelayFaultGatesIT {
|
||||
"SELECT COUNT(*) FROM ma_public_event"
|
||||
+ " WHERE tenant_id = ? AND"
|
||||
+ " session_id = ? AND turn_id = ?"
|
||||
+ " AND terminal",
|
||||
+ " AND is_terminal",
|
||||
Integer.class, tenant, session, turn))
|
||||
.isEqualTo(1));
|
||||
}
|
||||
|
||||
+3
-3
@@ -525,7 +525,7 @@ class HostedWorkspaceToolTurnIT {
|
||||
.isEqualTo("中文😀é\\ud800");
|
||||
for (String sessionId : List.of(sessions.get(index).get("sessionId").toString(), secondarySessionId)) {
|
||||
var publications = jdbc.queryForList("SELECT state, producer_phase,"
|
||||
+ " CASE WHEN accepted_complete THEN 1 ELSE 0 END AS complete"
|
||||
+ " CASE WHEN is_accepted_complete THEN 1 ELSE 0 END AS complete"
|
||||
+ " FROM ma_output_capture WHERE tenant_id = ? AND session_id = ?", tenant, sessionId);
|
||||
if (cases.contains("o2")) {
|
||||
assertThat(publications).hasSize(1);
|
||||
@@ -684,7 +684,7 @@ class HostedWorkspaceToolTurnIT {
|
||||
tenant, storageId);
|
||||
assertThat(physical).isNotBlank();
|
||||
Map<String, Object> member = jdbc.queryForMap("SELECT binding_id, runtime_generation, runtime_session_id,"
|
||||
+ " session_state, execution_storage_key, execution_exclusive FROM ma_runtime_session"
|
||||
+ " session_state, execution_storage_key, is_execution_exclusive FROM ma_runtime_session"
|
||||
+ " WHERE tenant_id = ? AND harness_session_id = ? AND runtime_session_id = ?",
|
||||
tenant, session.get("sessionId"), report.path("promptId").asText());
|
||||
boolean released = storeFaults ? fault.equals("turn-reply") : List.of("prepare", "start", "release").contains(fault);
|
||||
@@ -698,7 +698,7 @@ class HostedWorkspaceToolTurnIT {
|
||||
boolean retained = !storeFaults && fault.equals("prepare-twice");
|
||||
assertThat(member.get("execution_storage_key")).as(fault + " execution membership")
|
||||
.isEqualTo(retained ? physical : null);
|
||||
assertThat(member.get("execution_exclusive")).isEqualTo(false);
|
||||
assertThat(member.get("is_execution_exclusive")).isEqualTo(false);
|
||||
if (retained) {
|
||||
assertThat(member.get("binding_id")).isEqualTo(executions.getFirst().get("binding_id"));
|
||||
assertThat(member.get("runtime_generation")).isEqualTo(executions.getFirst().get("runtime_generation"));
|
||||
|
||||
+2
-2
@@ -111,11 +111,11 @@ class ManagedAgentDefinitionAdmissionTest {
|
||||
assertThatThrownBy(() -> transactions.execute(status -> selected.requireMcpManagement(tenant, "stranger", id, null)))
|
||||
.isInstanceOfSatisfying(ManagedAgentException.class,
|
||||
error -> assertThat(error.getCode()).isEqualTo("session_not_found"));
|
||||
jdbc.update("UPDATE ma_session SET plan_enabled=TRUE, selected_approval_mode='default', approval_revision=1 WHERE tenant_id=? AND session_id=?", tenant, id);
|
||||
jdbc.update("UPDATE ma_session SET is_plan_enabled=TRUE, selected_approval_mode='default', approval_revision=1 WHERE tenant_id=? AND session_id=?", tenant, id);
|
||||
assertThatThrownBy(() -> transactions.execute(status -> selected.requireMcpManagement(tenant, "actor", id, "operation")))
|
||||
.isInstanceOfSatisfying(ManagedAgentException.class,
|
||||
error -> assertThat(error.getCode()).isEqualTo("unsupported_feature"));
|
||||
jdbc.update("UPDATE ma_session SET plan_enabled=FALSE WHERE tenant_id=? AND session_id=?", tenant, id);
|
||||
jdbc.update("UPDATE ma_session SET is_plan_enabled=FALSE WHERE tenant_id=? AND session_id=?", tenant, id);
|
||||
jdbc.update("INSERT INTO ma_turn (tenant_id, session_id, turn_id, prompt_id, input_json, payload_digest, status, gmt_create, gmt_modified)"
|
||||
+ " VALUES (?, ?, 'turn', 'prompt', '[]', 'digest', 'RUNNING', 1, 1)", tenant, id);
|
||||
var readable = transactions.execute(status -> selected.requireMcpManagement(tenant, "actor", id, null));
|
||||
|
||||
+5
-5
@@ -1087,7 +1087,7 @@ class ManagedAgentMySqlIT {
|
||||
scopeKey,
|
||||
sha256("command-7")))
|
||||
.extracting(row -> row.get("key"))
|
||||
.containsExactly("ix_ma_record_operation");
|
||||
.containsExactly("idx_ma_record_operation");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -1932,19 +1932,19 @@ class ManagedAgentMySqlIT {
|
||||
for (Object[] lookup :
|
||||
List.of(
|
||||
new Object[] {
|
||||
"uq_ma_hook_once", "hook_once_key_hash = ?", sha256("once-7")
|
||||
"uk_ma_hook_once", "hook_once_key_hash = ?", sha256("once-7")
|
||||
},
|
||||
new Object[] {
|
||||
"uq_ma_hook_occurrence",
|
||||
"uk_ma_hook_occurrence",
|
||||
"hook_occurrence_hash = ? AND hook_ordinal = ?",
|
||||
sha256("occurrence-7"),
|
||||
1
|
||||
},
|
||||
new Object[] {
|
||||
"uq_ma_hook_occurrence", "hook_occurrence_hash = ?", sha256("occurrence-7")
|
||||
"uk_ma_hook_occurrence", "hook_occurrence_hash = ?", sha256("occurrence-7")
|
||||
},
|
||||
new Object[] {
|
||||
"ix_ma_hook_definition",
|
||||
"idx_ma_hook_definition",
|
||||
"hook_definition_hash = ?",
|
||||
sha256("catalog-1\u00001")
|
||||
})) {
|
||||
|
||||
+3
-3
@@ -483,10 +483,10 @@ class ManagedApprovalChangeTest {
|
||||
var created = transaction().execute(status -> service.createWorkspaceSession(tenant, "actor", "legacy-create",
|
||||
definition.agentId(), null, null, null, input, new WorkspaceSelection("ws", ".")));
|
||||
session = created.sessionId();
|
||||
jdbc.update("UPDATE ma_turn SET status='COMPLETED',approval_mode=NULL,approval_revision=NULL,plan_enabled=NULL WHERE tenant_id=? AND session_id=?",
|
||||
jdbc.update("UPDATE ma_turn SET status='COMPLETED',approval_mode=NULL,approval_revision=NULL,is_plan_enabled=NULL WHERE tenant_id=? AND session_id=?",
|
||||
tenant, session);
|
||||
var submitted = transaction().execute(status -> service.submitTurn(tenant, "actor", "legacy-submit", session, input));
|
||||
jdbc.update("UPDATE ma_turn SET status='COMPLETED',approval_mode=NULL,approval_revision=NULL,plan_enabled=NULL WHERE tenant_id=? AND session_id=?",
|
||||
jdbc.update("UPDATE ma_turn SET status='COMPLETED',approval_mode=NULL,approval_revision=NULL,is_plan_enabled=NULL WHERE tenant_id=? AND session_id=?",
|
||||
tenant, session);
|
||||
change("actor", "new-policy", "yolo", 0);
|
||||
assertThat(transaction().execute(status -> service.createWorkspaceSession(tenant, "actor", "legacy-create",
|
||||
@@ -508,7 +508,7 @@ class ManagedApprovalChangeTest {
|
||||
var admitted = transaction().execute(status -> store.insertTurnCommand(tenant, "SUBMIT_TURN", "legacy", "legacy-digest",
|
||||
session, input, SubmitHarnessTurn.computePayloadDigest(input)));
|
||||
var turn = store.findTurn(tenant, session, admitted.turnId()).orElseThrow();
|
||||
jdbc.update("UPDATE ma_turn SET approval_mode=NULL, approval_revision=NULL, plan_enabled=NULL, status='COMPLETED'"
|
||||
jdbc.update("UPDATE ma_turn SET approval_mode=NULL, approval_revision=NULL, is_plan_enabled=NULL, status='COMPLETED'"
|
||||
+ " WHERE tenant_id=? AND turn_id=?", tenant, admitted.turnId());
|
||||
assertThat(store.findTurnApprovalSelection(tenant, session, turn.promptId()))
|
||||
.isNull();
|
||||
|
||||
+2
-2
@@ -674,13 +674,13 @@ class ManagedArtifactApiIntegrationTest {
|
||||
.andExpect(jsonPath("$.access.can_read_content").value(false));
|
||||
mvc.perform(asReader(get(ROOT + "/artifacts"))).andExpect(status().isOk()).andExpect(header().string("Cache-Control", "private, no-store"))
|
||||
.andExpect(jsonPath("$.data").isEmpty());
|
||||
assertThat(fixture.jdbc().queryForObject("SELECT quarantined FROM ma_output_capture", Boolean.class))
|
||||
assertThat(fixture.jdbc().queryForObject("SELECT is_quarantined FROM ma_output_capture", Boolean.class))
|
||||
.isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
void deletionAndQuarantineHideContentWithoutChangingExecutionFacts() throws Exception {
|
||||
fixture.jdbc().update("UPDATE ma_output_capture SET quarantined = TRUE WHERE publication_id = X'7075622d31'");
|
||||
fixture.jdbc().update("UPDATE ma_output_capture SET is_quarantined = TRUE WHERE publication_id = X'7075622d31'");
|
||||
mvc.perform(asReader(get(ROOT + "/artifacts/" + stdout.path("id").asText())))
|
||||
.andExpect(status().isOk()).andExpect(jsonPath("$.artifact.availability").value("unavailable"))
|
||||
.andExpect(jsonPath("$.access.can_read_content").value(false));
|
||||
|
||||
+1
-1
@@ -214,7 +214,7 @@ class ManagedHookAdmissionIndexTest {
|
||||
event -> {
|
||||
assertThat(event.getLevel()).isEqualTo(Level.WARN);
|
||||
assertThat(event.getThrowableProxy().getMessage())
|
||||
.containsIgnoringCase("uq_ma_hook_once");
|
||||
.containsIgnoringCase("uk_ma_hook_once");
|
||||
});
|
||||
assertThat(
|
||||
jdbc.queryForObject(
|
||||
|
||||
+3
-3
@@ -121,7 +121,7 @@ class ManagedMcpSettingsStoreTest {
|
||||
new TransactionTemplate(transactionManager).executeWithoutResult(status -> {
|
||||
jdbc.queryForObject("SELECT session_id FROM ma_session WHERE tenant_id=? AND session_id=? FOR UPDATE",
|
||||
String.class, "tenant", id);
|
||||
jdbc.update("UPDATE ma_session SET plan_enabled=TRUE, selected_approval_mode='default', approval_revision=1"
|
||||
jdbc.update("UPDATE ma_session SET is_plan_enabled=TRUE, selected_approval_mode='default', approval_revision=1"
|
||||
+ " WHERE tenant_id=? AND session_id=?", "tenant", id);
|
||||
pending.set(executor.submit(() -> {
|
||||
started.countDown();
|
||||
@@ -149,12 +149,12 @@ class ManagedMcpSettingsStoreTest {
|
||||
ObjectNode first = settings(1, "enabled", null);
|
||||
var request = journal.requestOrdinary(first.path("operationId").asText(), "config_install", first,
|
||||
event -> {}, records -> records, 0);
|
||||
jdbc.update("UPDATE ma_session SET plan_enabled=TRUE, selected_approval_mode='default', approval_revision=1"
|
||||
jdbc.update("UPDATE ma_session SET is_plan_enabled=TRUE, selected_approval_mode='default', approval_revision=1"
|
||||
+ " WHERE tenant_id=? AND session_id=?", "tenant", id);
|
||||
assertThatThrownBy(() -> journal.commit(request)).isInstanceOfSatisfying(ManagedAgentException.class,
|
||||
error -> assertThat(error.getCode()).isEqualTo("unsupported_feature"));
|
||||
assertThat(ManagedMcpSettings.find(jdbc, "tenant", id)).isNull();
|
||||
jdbc.update("UPDATE ma_session SET plan_enabled=FALSE WHERE tenant_id=? AND session_id=?", "tenant", id);
|
||||
jdbc.update("UPDATE ma_session SET is_plan_enabled=FALSE WHERE tenant_id=? AND session_id=?", "tenant", id);
|
||||
jdbc.update("INSERT INTO ma_turn (tenant_id, session_id, turn_id, prompt_id, input_json, payload_digest, status, gmt_create, gmt_modified)"
|
||||
+ " VALUES (?, ?, 'turn', ?, '[]', 'digest', 'ACCEPTED', 1, 1)", "tenant", id, UUID.randomUUID().toString());
|
||||
assertThatThrownBy(() -> journal.commit(request)).isInstanceOfSatisfying(ManagedAgentException.class,
|
||||
|
||||
+3
-3
@@ -126,7 +126,7 @@ class ManagedRuntimeRetentionRaceTest {
|
||||
fixture.retire();
|
||||
fixture.jdbc.update("UPDATE ma_storage_owner SET holder_key = NULL, binding_id = NULL,"
|
||||
+ " runtime_generation = NULL, runtime_session_id = NULL");
|
||||
fixture.jdbc.update("UPDATE ma_runtime_session SET execution_storage_key = NULL, execution_exclusive = FALSE");
|
||||
fixture.jdbc.update("UPDATE ma_runtime_session SET execution_storage_key = NULL, is_execution_exclusive = FALSE");
|
||||
var locked = new CountDownLatch(1);
|
||||
var release = new CountDownLatch(1);
|
||||
var first = new AtomicBoolean(true);
|
||||
@@ -272,7 +272,7 @@ class ManagedRuntimeRetentionRaceTest {
|
||||
"handleKind", binding.getResourceHandle().getKind(), "handleVersion", binding.getResourceHandle().getVersion(),
|
||||
"handle", JSON.valueToTree(binding.getResourceHandle().getValue()).toString(), "stoppedAt", OLD.toString())).toString() : null;
|
||||
// Age a completed lifecycle; production writers above still perform every reference admission check.
|
||||
jdbc.update("UPDATE ma_runtime_binding SET binding_state = 'RELEASED', last_active_at = ?, drain_requested = TRUE,"
|
||||
jdbc.update("UPDATE ma_runtime_binding SET binding_state = 'RELEASED', last_active_at = ?, is_drain_requested = TRUE,"
|
||||
+ " drain_receipt_json = ?, operation_owner = NULL, operation_lease_until = NULL", Timestamp.from(OLD), receipt);
|
||||
jdbc.update("UPDATE ma_runtime_slot SET active_binding_id = NULL");
|
||||
jdbc.update("UPDATE ma_runtime_session SET session_state = 'RELEASED', last_active_at = ?", Timestamp.from(OLD));
|
||||
@@ -281,7 +281,7 @@ class ManagedRuntimeRetentionRaceTest {
|
||||
if (reference == Reference.OPERATOR || reference == Reference.CSI_RETIREMENT) {
|
||||
jdbc.update("UPDATE ma_storage_owner SET holder_key = NULL, binding_id = NULL,"
|
||||
+ " runtime_generation = NULL, runtime_session_id = NULL");
|
||||
jdbc.update("UPDATE ma_runtime_session SET execution_storage_key = NULL, execution_exclusive = FALSE");
|
||||
jdbc.update("UPDATE ma_runtime_session SET execution_storage_key = NULL, is_execution_exclusive = FALSE");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+12
-12
@@ -136,8 +136,8 @@ class ManagedSchemaJournalAtomicityTest {
|
||||
@ValueSource(booleans = {false, true})
|
||||
void wakeHintCommitsAndRollsBackWithItsAcceptedInput(boolean knownPrefix) throws Exception {
|
||||
assertThat(jdbc.queryForObject("SELECT wake_head_revision FROM ma_session_head", Long.class)).isEqualTo(1);
|
||||
assertThat(jdbc.queryForObject("SELECT wake_scan_pending FROM ma_session_head", Boolean.class)).isFalse();
|
||||
jdbc.update("UPDATE ma_session_head SET wake_pending = FALSE, wake_head_revision = ?", knownPrefix ? 1L : null);
|
||||
assertThat(jdbc.queryForObject("SELECT is_wake_scan_pending FROM ma_session_head", Boolean.class)).isFalse();
|
||||
jdbc.update("UPDATE ma_session_head SET is_wake_pending = FALSE, wake_head_revision = ?", knownPrefix ? 1L : null);
|
||||
var monitor = ManagedExtensionProjectionContractTest.fixtures()
|
||||
.required("monitorChainCases").get(0).required("revisions").get(0).required("monitorRun");
|
||||
var prepared = journal.request("wake-admit", monitor, 1_000);
|
||||
@@ -150,45 +150,45 @@ class ManagedSchemaJournalAtomicityTest {
|
||||
var request = journal.requestDomainWithInput("wake-admit", "monitor_run", monitor, closure, "wake-turn", input);
|
||||
assertThatThrownBy(() -> transactions.executeWithoutResult(status -> {
|
||||
journal.commit(request);
|
||||
assertThat(jdbc.queryForObject("SELECT wake_pending FROM ma_session_head", Boolean.class)).isTrue();
|
||||
assertThat(jdbc.queryForObject("SELECT is_wake_pending FROM ma_session_head", Boolean.class)).isTrue();
|
||||
assertThat(jdbc.queryForObject("SELECT wake_head_revision FROM ma_session_head", Long.class))
|
||||
.isEqualTo(knownPrefix ? 2L : null);
|
||||
assertThat(jdbc.queryForObject("SELECT wake_scan_pending FROM ma_session_head", Boolean.class)).isTrue();
|
||||
assertThat(jdbc.queryForObject("SELECT is_wake_scan_pending FROM ma_session_head", Boolean.class)).isTrue();
|
||||
throw new SimulatedCrash();
|
||||
})).isInstanceOf(SimulatedCrash.class);
|
||||
assertThat(jdbc.queryForObject("SELECT wake_pending FROM ma_session_head", Boolean.class)).isFalse();
|
||||
assertThat(jdbc.queryForObject("SELECT is_wake_pending FROM ma_session_head", Boolean.class)).isFalse();
|
||||
assertThat(jdbc.queryForObject("SELECT wake_head_revision FROM ma_session_head", Long.class))
|
||||
.isEqualTo(knownPrefix ? 1L : null);
|
||||
transactions.executeWithoutResult(status -> journal.commit(request));
|
||||
assertThat(jdbc.queryForObject("SELECT wake_pending FROM ma_session_head", Boolean.class)).isTrue();
|
||||
assertThat(jdbc.queryForObject("SELECT is_wake_pending FROM ma_session_head", Boolean.class)).isTrue();
|
||||
assertThat(jdbc.queryForObject("SELECT wake_head_revision FROM ma_session_head", Long.class))
|
||||
.isEqualTo(knownPrefix ? 2L : null);
|
||||
journal.committed(request);
|
||||
|
||||
// A legacy admission did not maintain the hint; an unrelated modern
|
||||
// commit must not mark that unexamined prefix as current.
|
||||
jdbc.update("UPDATE ma_session_head SET wake_pending = FALSE, wake_head_revision = 1");
|
||||
jdbc.update("UPDATE ma_session_head SET is_wake_pending = FALSE, wake_head_revision = 1");
|
||||
var next = ManagedExtensionProjectionContractTest.fixtures()
|
||||
.required("monitorChainCases").get(0).required("revisions").get(1);
|
||||
var ordinary = journal.request("ordinary-update", next.required("monitorRun"),
|
||||
next.required("occurredAt").longValue());
|
||||
transactions.executeWithoutResult(status -> journal.commit(ordinary));
|
||||
assertThat(jdbc.queryForObject("SELECT journal_revision FROM ma_session_head", Long.class)).isEqualTo(3);
|
||||
assertThat(jdbc.queryForObject("SELECT wake_pending FROM ma_session_head", Boolean.class)).isFalse();
|
||||
assertThat(jdbc.queryForObject("SELECT is_wake_pending FROM ma_session_head", Boolean.class)).isFalse();
|
||||
assertThat(jdbc.queryForObject("SELECT wake_head_revision FROM ma_session_head", Long.class)).isEqualTo(1);
|
||||
assertThat(jdbc.queryForObject("SELECT wake_scan_pending FROM ma_session_head", Boolean.class)).isTrue();
|
||||
assertThat(jdbc.queryForObject("SELECT is_wake_scan_pending FROM ma_session_head", Boolean.class)).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
void anOrdinaryCommitPreservesAnAlreadyPendingWake() throws Exception {
|
||||
jdbc.update("UPDATE ma_session_head SET wake_pending = TRUE, wake_head_revision = 1");
|
||||
jdbc.update("UPDATE ma_session_head SET is_wake_pending = TRUE, wake_head_revision = 1");
|
||||
var monitor = ManagedExtensionProjectionContractTest.fixtures()
|
||||
.required("monitorChainCases").get(0).required("revisions").get(0).required("monitorRun");
|
||||
var ordinary = journal.request("ordinary-update", monitor, 1_000);
|
||||
transactions.executeWithoutResult(status -> journal.commit(ordinary));
|
||||
assertThat(jdbc.queryForObject("SELECT wake_pending FROM ma_session_head", Boolean.class)).isTrue();
|
||||
assertThat(jdbc.queryForObject("SELECT is_wake_pending FROM ma_session_head", Boolean.class)).isTrue();
|
||||
assertThat(jdbc.queryForObject("SELECT wake_head_revision FROM ma_session_head", Long.class)).isEqualTo(2);
|
||||
assertThat(jdbc.queryForObject("SELECT wake_scan_pending FROM ma_session_head", Boolean.class)).isTrue();
|
||||
assertThat(jdbc.queryForObject("SELECT is_wake_scan_pending FROM ma_session_head", Boolean.class)).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
+32
@@ -1,5 +1,6 @@
|
||||
package com.alibaba.qwen.code.managedagent;
|
||||
|
||||
import org.springframework.dao.DataAccessException;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
|
||||
/** InnoDB lock-wait and deadlock observations shared by the MySQL witnesses (#13800). */
|
||||
@@ -21,6 +22,37 @@ public final class MySqlLockProbe {
|
||||
return waits == null ? 0 : waits;
|
||||
}
|
||||
|
||||
/** Capture before releasing test holders so a failed witness retains its lock graph. */
|
||||
public static String describeLockWaits(JdbcTemplate jdbc, String schema) {
|
||||
try {
|
||||
return "InnoDB lock waits for " + schema + ": " + jdbc.queryForList(
|
||||
"SELECT requested.ENGINE_TRANSACTION_ID AS waiting_transaction,"
|
||||
+ " waiting_trx.trx_query AS waiting_sql,"
|
||||
+ " held.ENGINE_TRANSACTION_ID AS blocking_transaction,"
|
||||
+ " blocking_trx.trx_query AS blocking_sql,"
|
||||
+ " requested.OBJECT_NAME AS table_name,"
|
||||
+ " requested.INDEX_NAME AS requested_index,"
|
||||
+ " requested.LOCK_TYPE AS requested_type,"
|
||||
+ " requested.LOCK_MODE AS requested_mode,"
|
||||
+ " requested.LOCK_DATA AS requested_data,"
|
||||
+ " held.INDEX_NAME AS blocking_index, held.LOCK_TYPE AS blocking_type,"
|
||||
+ " held.LOCK_MODE AS blocking_mode, held.LOCK_DATA AS blocking_data"
|
||||
+ " FROM performance_schema.data_lock_waits waits"
|
||||
+ " JOIN performance_schema.data_locks requested ON requested.ENGINE = waits.ENGINE"
|
||||
+ " AND requested.ENGINE_LOCK_ID = waits.REQUESTING_ENGINE_LOCK_ID"
|
||||
+ " JOIN performance_schema.data_locks held ON held.ENGINE = waits.ENGINE"
|
||||
+ " AND held.ENGINE_LOCK_ID = waits.BLOCKING_ENGINE_LOCK_ID"
|
||||
+ " LEFT JOIN information_schema.INNODB_TRX waiting_trx"
|
||||
+ " ON waiting_trx.trx_id = waits.REQUESTING_ENGINE_TRANSACTION_ID"
|
||||
+ " LEFT JOIN information_schema.INNODB_TRX blocking_trx"
|
||||
+ " ON blocking_trx.trx_id = waits.BLOCKING_ENGINE_TRANSACTION_ID"
|
||||
+ " WHERE requested.OBJECT_SCHEMA = ? AND held.OBJECT_SCHEMA = ?",
|
||||
schema, schema);
|
||||
} catch (DataAccessException error) {
|
||||
return "InnoDB lock snapshot unavailable for " + schema + ": " + error;
|
||||
}
|
||||
}
|
||||
|
||||
/** Waits up to ~9 s until at least {@code expected} transactions of {@code schema} queue. */
|
||||
public static void awaitLockWaits(JdbcTemplate jdbc, String schema, int expected, String what)
|
||||
throws InterruptedException {
|
||||
|
||||
+1
-1
@@ -1421,7 +1421,7 @@ public class SurfaceAdmissionAcceptanceTest {
|
||||
+ " schedule_id, session_id, workspace_id, actor_id,"
|
||||
+ " record_revision, definition_revision, definition_digest,"
|
||||
+ " goal, cron, timezone, session_mode, overlap, catch_up,"
|
||||
+ " catch_up_limit, enabled, state, blocked_reason, armed_at,"
|
||||
+ " catch_up_limit, is_enabled, state, blocked_reason, armed_at,"
|
||||
+ " watermark_slot, lease_owner, lease_until, fence,"
|
||||
+ " gmt_create, gmt_modified) VALUES (?, ?, ?, 'ws', ?, 1, 1, ?,"
|
||||
+ " 'probe', '0 2 * * *', 'UTC', 'persistent', 'skip', 'none',"
|
||||
|
||||
+2
-1
@@ -506,7 +506,8 @@ class ToolPublicationLockOrderMySqlIT {
|
||||
}
|
||||
assertThat(waiting).as("Publication waits for the placement owner").isPositive();
|
||||
assertThat(source.subjectPlacementLocks.get())
|
||||
.as("Placement precedes retention in the contending transaction")
|
||||
.as(() -> "Placement precedes retention in the contending transaction; "
|
||||
+ MySqlLockProbe.describeLockWaits(admin, schema))
|
||||
.containsExactly("placement");
|
||||
source.releaseOwner.countDown();
|
||||
owner.get(30, TimeUnit.SECONDS);
|
||||
|
||||
+10
-10
@@ -1019,7 +1019,7 @@ class ToolPublicationStoreTest {
|
||||
objects.get(objectKey)[0] = 'z';
|
||||
assertThatThrownBy(() -> sessions.readResource("tenant-1", "workspace-1", "session-1",
|
||||
admission.path("resourceId").asText(), WRITER_TOKEN)).hasMessageContaining("verification");
|
||||
assertThat(jdbc.queryForObject("SELECT quarantined FROM ma_output_capture"
|
||||
assertThat(jdbc.queryForObject("SELECT is_quarantined FROM ma_output_capture"
|
||||
+ " WHERE publication_id = X'7075622d31'", Boolean.class)).isTrue();
|
||||
assertThatThrownBy(() -> sessions.readResource("tenant-1", "workspace-1", "session-1",
|
||||
admission.path("resourceId").asText(), WRITER_TOKEN)).hasMessageContaining("verification");
|
||||
@@ -1272,7 +1272,7 @@ class ToolPublicationStoreTest {
|
||||
if (!large) {
|
||||
if (quarantineBeforeProjection) {
|
||||
jdbc.update(
|
||||
"UPDATE ma_output_capture SET quarantined = TRUE WHERE publication_id ="
|
||||
"UPDATE ma_output_capture SET is_quarantined = TRUE WHERE publication_id ="
|
||||
+ " X'7075622d31'");
|
||||
}
|
||||
JsonNode projected = projectPublicReceipt(data);
|
||||
@@ -1354,7 +1354,7 @@ class ToolPublicationStoreTest {
|
||||
try (var stream = apiReader.open(artifact)) {
|
||||
assertThat(stream.readNBytes(2)).isEqualTo("ab".getBytes(StandardCharsets.UTF_8));
|
||||
jdbc.update(
|
||||
"UPDATE ma_output_capture SET quarantined = TRUE WHERE publication_id ="
|
||||
"UPDATE ma_output_capture SET is_quarantined = TRUE WHERE publication_id ="
|
||||
+ " X'7075622d31'");
|
||||
byte[] target = new byte[] {'?'};
|
||||
assertThatThrownBy(() -> stream.read(target)).hasMessageContaining("receipt is unavailable");
|
||||
@@ -1440,7 +1440,7 @@ class ToolPublicationStoreTest {
|
||||
.hasMessageContaining("digest changed");
|
||||
assertThat(jdbc.queryForObject("SELECT capture_state FROM ma_resource"
|
||||
+ " WHERE slot_key = X'7365676d656e743a7374646f75743a31'", String.class)).isEqualTo("QUARANTINED");
|
||||
assertThat(jdbc.queryForObject("SELECT quarantined FROM ma_output_capture"
|
||||
assertThat(jdbc.queryForObject("SELECT is_quarantined FROM ma_output_capture"
|
||||
+ " WHERE publication_id = X'7075622d31'", Boolean.class)).isFalse();
|
||||
assertThat(data.prefix(key, "pub-1", PUBLICATION_TOKEN, "good-prefix", "stdout")
|
||||
.path("byteLength").asLong()).isEqualTo(3);
|
||||
@@ -2535,10 +2535,10 @@ class ToolPublicationStoreTest {
|
||||
jdbc.update("INSERT INTO ma_output_capture (scope_key, tenant_key, tenant_id, workspace_id, session_id,"
|
||||
+ " publication_id, execution_key, capture_id, binding_json, binding_digest, token_hash, state,"
|
||||
+ " expires_at, capture_bytes, producer_bytes, admission_bytes, capture_held_bytes,"
|
||||
+ " producer_held_bytes, admission_held_bytes, write_evidence) SELECT scope_key, tenant_key,"
|
||||
+ " producer_held_bytes, admission_held_bytes, is_write_evidence) SELECT scope_key, tenant_key,"
|
||||
+ " tenant_id, workspace_id, session_id, ?, ?, ?, binding_json, binding_digest, token_hash, state,"
|
||||
+ " expires_at, capture_bytes, producer_bytes, admission_bytes, capture_held_bytes,"
|
||||
+ " producer_held_bytes, admission_held_bytes, write_evidence FROM ma_output_capture"
|
||||
+ " producer_held_bytes, admission_held_bytes, is_write_evidence FROM ma_output_capture"
|
||||
+ " WHERE publication_id = ?", to.getBytes(StandardCharsets.UTF_8), digest(to),
|
||||
to.getBytes(StandardCharsets.UTF_8), from.getBytes(StandardCharsets.UTF_8));
|
||||
}
|
||||
@@ -3081,12 +3081,12 @@ class ToolPublicationStoreTest {
|
||||
void acceptedProducerEvidenceFeedsRetirementEligibility() {
|
||||
var fixture = apiFixture();
|
||||
assertThat(fixture.jdbc().queryForObject(
|
||||
"SELECT write_evidence AND accepted_complete FROM"
|
||||
"SELECT is_write_evidence AND is_accepted_complete FROM"
|
||||
+ " ma_output_capture",
|
||||
Boolean.class)).isTrue();
|
||||
fixture.jdbc().update(
|
||||
"UPDATE ma_session SET retirement_operation_id = X'64656c6574652d31',"
|
||||
+ " retirement_generation = 1, retired_at = 1, recovery_protected ="
|
||||
+ " retirement_generation = 1, retired_at = 1, is_recovery_protected ="
|
||||
+ " FALSE WHERE tenant_id = X'74656e616e742d31' AND session_id ="
|
||||
+ " X'73657373696f6e2d31'");
|
||||
fixture.jdbc().update("UPDATE ma_output_capture SET retention_state = 'RETIRING'");
|
||||
@@ -3247,7 +3247,7 @@ class ToolPublicationStoreTest {
|
||||
var claim = fixture.results().claim().orElseThrow();
|
||||
fixture.jdbc().update(
|
||||
"UPDATE ma_session SET retirement_operation_id = X'64656c6574652d31',"
|
||||
+ " retirement_generation = 1, retired_at = 1, recovery_protected ="
|
||||
+ " retirement_generation = 1, retired_at = 1, is_recovery_protected ="
|
||||
+ " FALSE WHERE tenant_id = X'74656e616e742d31' AND session_id ="
|
||||
+ " X'73657373696f6e2d31'");
|
||||
var projection = new ManagedToolResultStore.Projection(JSON.createObjectNode(), "pub-1",
|
||||
@@ -3346,7 +3346,7 @@ class ToolPublicationStoreTest {
|
||||
var calls = new java.util.concurrent.atomic.AtomicInteger();
|
||||
org.mockito.Mockito.doAnswer(call -> {
|
||||
if (calls.incrementAndGet() == 2) {
|
||||
fixture.jdbc().update("UPDATE ma_output_capture SET quarantined=TRUE");
|
||||
fixture.jdbc().update("UPDATE ma_output_capture SET is_quarantined=TRUE");
|
||||
}
|
||||
return fixture.policy().version();
|
||||
}).when(policy).version();
|
||||
|
||||
+2
-2
@@ -194,7 +194,7 @@ class WorkspaceSessionRetentionMySqlIT {
|
||||
var claimed = deleteClaim(store, tenant, session);
|
||||
jdbc.update("DELETE FROM ma_workspace_access");
|
||||
assertThat(transaction(() -> store.completeOperation(tenant, session, claimed.operationId(), "delete-worker", claimed.claimGeneration(), false))).isTrue();
|
||||
assertThat(jdbc.queryForObject("SELECT recovery_protected FROM ma_session WHERE retirement_generation > 0", Boolean.class)).isTrue();
|
||||
assertThat(jdbc.queryForObject("SELECT is_recovery_protected FROM ma_session WHERE retirement_generation > 0", Boolean.class)).isTrue();
|
||||
var retention = new ToolPublicationRetentionStore(jdbc, new DataSourceTransactionManager(source));
|
||||
assertThat(retention.observe(Duration.ZERO)).singleElement().extracting(ToolPublicationRetentionStore.Candidate::blocker).isEqualTo("recovery_protected");
|
||||
assertThatThrownBy(() -> transaction(() -> com.alibaba.qwen.code.managedagent.VerificationFixtures.managedSessionStore(jdbc).acquireWriter(tenant, session, TOKEN,
|
||||
@@ -495,7 +495,7 @@ class WorkspaceSessionRetentionMySqlIT {
|
||||
String key = "b".repeat(64);
|
||||
jdbc.update("INSERT INTO ma_output_capture (scope_key, tenant_key, tenant_id, workspace_id, session_id,"
|
||||
+ " publication_id, execution_key, capture_id, binding_json, binding_digest, token_hash, state,"
|
||||
+ " capture_bytes, producer_bytes, admission_bytes, producer_phase, write_evidence, accepted_complete,"
|
||||
+ " capture_bytes, producer_bytes, admission_bytes, producer_phase, is_write_evidence, is_accepted_complete,"
|
||||
+ " capture_held_bytes, producer_held_bytes, admission_held_bytes, capture_used_bytes)"
|
||||
+ " VALUES (?, ?, ?, 'workspace', ?, 'pub-1', ?, 'capture-1', '{}', ?, ?, 'FENCED',"
|
||||
+ " 1000, 1000, 1000, 'REFERENCED', TRUE, TRUE, 1000, 1000, 1000, 123)",
|
||||
|
||||
+1
-1
@@ -67,7 +67,7 @@ class AutomationScannerConcurrencyMySqlIT {
|
||||
+ " session_id, workspace_id, actor_id,"
|
||||
+ " record_revision, definition_revision,"
|
||||
+ " definition_digest, goal, cron, timezone,"
|
||||
+ " session_mode, overlap, catch_up, enabled, state,"
|
||||
+ " session_mode, overlap, catch_up, is_enabled, state,"
|
||||
+ " armed_at, gmt_create, gmt_modified)"
|
||||
+ " VALUES (?, ?, ?, 'workspace', 'actor', 1, 1,"
|
||||
+ " 'digest', 'Goal', '* * * * *', 'UTC', 'default',"
|
||||
|
||||
+2
-2
@@ -45,7 +45,7 @@ class ManagedSchemaConfigurationTest {
|
||||
assertThat(sessionListColumns(source)).containsExactly("tenant_id", "gmt_create", "session_id");
|
||||
assertThat(jdbc.queryForMap("SELECT " + ManagedSchemaProjection.SESSION.columns() + " FROM ma_session"))
|
||||
.isEqualTo(session)
|
||||
.containsEntry("csi_guard", false)
|
||||
.containsEntry("is_csi_guard", false)
|
||||
.containsEntry("runtime_request_key", null)
|
||||
.containsEntry("model_id", null)
|
||||
.containsEntry("model_revision", 0L)
|
||||
@@ -103,7 +103,7 @@ class ManagedSchemaConfigurationTest {
|
||||
.getIndexInfo(null, null, "ma_session", false, false)) {
|
||||
var columns = new ArrayList<String>();
|
||||
while (rows.next()) {
|
||||
if ("ix_ma_session_list".equalsIgnoreCase(rows.getString("INDEX_NAME"))) {
|
||||
if ("idx_ma_session_list".equalsIgnoreCase(rows.getString("INDEX_NAME"))) {
|
||||
columns.add(rows.getString("COLUMN_NAME").toLowerCase(java.util.Locale.ROOT));
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -132,7 +132,7 @@ public class EventTransportConsumerSqlTest {
|
||||
"SELECT " + ManagedSchemaProjection.SESSION_HEAD.columns() + " FROM ma_session_head WHERE tenant_id = ? AND session_id = ?",
|
||||
TENANT,
|
||||
session);
|
||||
assertThat(sessionBefore.get("csi_guard")).isEqualTo(true);
|
||||
assertThat(sessionBefore.get("is_csi_guard")).isEqualTo(true);
|
||||
|
||||
deliver(wake(session, WORKSPACE, 3));
|
||||
assertThat(wakeWatermark(session)).isNull();
|
||||
@@ -436,7 +436,7 @@ public class EventTransportConsumerSqlTest {
|
||||
private void event(String session, long sequence, String type) {
|
||||
jdbc.update("INSERT INTO ma_public_event (tenant_id, session_id,"
|
||||
+ " sequence_id, event_id, turn_id, event_type, data_json,"
|
||||
+ " terminal, source_key, gmt_create) VALUES (?, ?, ?, ?,"
|
||||
+ " is_terminal, source_key, gmt_create) VALUES (?, ?, ?, ?,"
|
||||
+ " NULL, ?, '{}', FALSE, NULL, ?)",
|
||||
TENANT, session, sequence, "evt-" + UUID.randomUUID(), type,
|
||||
1_760_000_000_000L + sequence);
|
||||
|
||||
+2
-2
@@ -460,7 +460,7 @@ class WorkspaceCsiSessionMainTest {
|
||||
void retainedRequestPinStillRefusesAfterAConflictingProfileChange() {
|
||||
var original = create(request("retained-pin"));
|
||||
jdbc.update("UPDATE ma_session SET tool_profile = 'hosted-workspace-files/1'");
|
||||
assertThat(jdbc.queryForObject("SELECT csi_guard FROM ma_session", Boolean.class)).isTrue();
|
||||
assertThat(jdbc.queryForObject("SELECT is_csi_guard FROM ma_session", Boolean.class)).isTrue();
|
||||
var before = allTables();
|
||||
assertPrivateRefusal(() -> new TransactionTemplate(manager).executeWithoutResult(status ->
|
||||
store().appendPublicEventIfAbsent("tenant", original.sessionId(), null, "session.environment",
|
||||
@@ -516,7 +516,7 @@ class WorkspaceCsiSessionMainTest {
|
||||
var privateTurn = new java.util.LinkedHashMap<>(ordinaryTurn);
|
||||
privateTurn.put("session_id", jdbc.queryForObject(
|
||||
"SELECT session_id FROM ma_session"
|
||||
+ " WHERE csi_guard = TRUE ORDER BY session_id LIMIT 1", String.class));
|
||||
+ " WHERE is_csi_guard = TRUE ORDER BY session_id LIMIT 1", String.class));
|
||||
privateTurn.put("turn_id", "private-legacy-turn");
|
||||
privateTurn.put("prompt_id", UUID.randomUUID().toString());
|
||||
privateTurn.put("gmt_modified", 0L);
|
||||
|
||||
+1
-1
@@ -58,7 +58,7 @@ class AgentLockContractTest extends RecoverySettlementStoreTest {
|
||||
trace.assertSessionBeforeTurn(TENANT, sessionId);
|
||||
trace.assertOneTransaction(TENANT, sessionId);
|
||||
var locks = trace.successful(TENANT, sessionId).stream()
|
||||
.filter(event -> event.sql().contains("for update") && !event.sql().contains("csi_guard = true"))
|
||||
.filter(event -> event.sql().contains("for update") && !event.sql().contains("is_csi_guard = true"))
|
||||
.map(event -> event.root() ? "root" : event.turn() ? "turn" : "stream").toList();
|
||||
assertThat(locks.subList(0, 3)).containsExactly("root", "stream", "turn");
|
||||
assertThat(trace.events()).anyMatch(event -> event.phase() == StoreLockTrace.Phase.COMMIT);
|
||||
|
||||
+1
-1
@@ -53,7 +53,7 @@ class ConsolidatedTaskEventStoreTest {
|
||||
jdbc.update("INSERT INTO ma_event_stream (tenant_id,session_id,stream_kind,stream_id,last_sequence,gmt_modified)"
|
||||
+ " VALUES ('tenant','session','SESSION','',1,0)");
|
||||
jdbc.update("INSERT INTO ma_public_event (tenant_id,session_id,stream_kind,stream_id,sequence_id,event_id,"
|
||||
+ "event_type,data_json,terminal,gmt_create) VALUES ('tenant','session','SESSION','',1,'session-event',"
|
||||
+ "event_type,data_json,is_terminal,gmt_create) VALUES ('tenant','session','SESSION','',1,'session-event',"
|
||||
+ "'session.updated','{}',FALSE,1)");
|
||||
assertThat(events.expireThrough("tenant", "session", "task", 2)).isEqualTo(2);
|
||||
assertThat(events.read("tenant", "session", "task", 0, 100).events()).isEmpty();
|
||||
|
||||
+1
-1
@@ -66,7 +66,7 @@ final class ExecutedQueryPlan {
|
||||
counts.add(0d);
|
||||
JsonNode pages = node.path("r_engine_stats").path("pages_accessed");
|
||||
if ("const".equals(node.path("access_type").asText())
|
||||
&& "PRIMARY".equals(node.path("key").asText())
|
||||
&& node.path("key").isTextual() && !node.path("key").asText().isBlank()
|
||||
&& pages.isIntegralNumber() && pages.canConvertToLong() && pages.asLong() > 0) {
|
||||
preExecutionPages.add(pages.asLong());
|
||||
}
|
||||
|
||||
+3
-3
@@ -70,16 +70,16 @@ class ExecutedQueryPlanTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
void requiresActualPrimaryConstPageEvidence() {
|
||||
void requiresActualConstIndexPageEvidence() {
|
||||
for (String access : new String[] {"ref", "const"}) {
|
||||
for (String key : new String[] {"another", "PRIMARY"}) {
|
||||
for (String key : new String[] {"", "uk_ma_resource_business_key", "PRIMARY"}) {
|
||||
for (String pages : new String[] {"null", "0", "\"2\"", "2"}) {
|
||||
var plan = ExecutedQueryPlan.mariaDb("{\"table\":{\"table_name\":\"r\","
|
||||
+ "\"access_type\":\"" + access + "\",\"key\":\"" + key + "\","
|
||||
+ "\"r_rows\":null,\"r_loops\":0,\"r_engine_stats\":{\"pages_accessed\":" + pages + "}}}");
|
||||
assertThat(plan.scannedRows()).isZero();
|
||||
assertThat(plan.preExecutionPageReads()).isEqualTo(
|
||||
access.equals("const") && key.equals("PRIMARY") && pages.equals("2") ? 2 : 0);
|
||||
access.equals("const") && !key.isBlank() && pages.equals("2") ? 2 : 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Loaded 100 of 150 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user