@sema-agent/server 7.43.0 → 7.44.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/USAGE.md +18 -0
- package/dist/adoption/plan.js +31 -192
- package/dist/adoption/quiesce.js +3 -86
- package/dist/adoption/runner.js +3 -140
- package/dist/adoption/sql.js +0 -74
- package/dist/adoption/wire.js +0 -80
- package/dist/approval-ask-machine.js +0 -75
- package/dist/approval-card.js +0 -323
- package/dist/approval-deny-reasons.js +0 -42
- package/dist/approval-hmac.js +0 -35
- package/dist/approval-reconciler.js +8 -166
- package/dist/approval.js +4 -67
- package/dist/audit.js +1 -44
- package/dist/auth-bridge.js +4 -47
- package/dist/auth-keys.js +0 -23
- package/dist/bake-runner/main.js +4 -65
- package/dist/bake-runner/protocol.js +3 -58
- package/dist/bake-runner/runner.js +5 -91
- package/dist/bench/l8/artifact.js +2 -61
- package/dist/bench/l8/escape.js +0 -25
- package/dist/bench/l8/index.js +0 -14
- package/dist/bench/l8/probes.js +0 -60
- package/dist/bench/l8/run-probes.js +2 -45
- package/dist/bench/s1/arms.js +14 -189
- package/dist/bench/s1/live-deps.js +11 -253
- package/dist/bench/s1/oracle.js +1 -36
- package/dist/bench/s1/repair-oracle-adapter.js +0 -30
- package/dist/bench/s1/reviewer.js +0 -34
- package/dist/bench/s1/row.js +0 -62
- package/dist/bench/s1/run-firm.js +4 -70
- package/dist/bench/s1/runner-ctx.js +0 -40
- package/dist/bench/s1/tasks.js +0 -115
- package/dist/boot/adoption.js +0 -20
- package/dist/boot/budget-tracing.js +3 -55
- package/dist/boot/config-center.js +43 -551
- package/dist/boot/coordinators.js +1 -69
- package/dist/boot/crash-last.js +0 -18
- package/dist/boot/deferred-sandbox-path-env.js +3 -119
- package/dist/boot/execution-env.js +5 -171
- package/dist/boot/governance-seams.js +0 -92
- package/dist/boot/leader.js +0 -69
- package/dist/boot/limit-sync.js +0 -2
- package/dist/boot/memory-boundary.js +3 -91
- package/dist/boot/org-memory.js +1 -25
- package/dist/boot/parked-revive-gate.js +0 -150
- package/dist/boot/permission-rules-audit.js +1 -56
- package/dist/boot/reapers.js +15 -273
- package/dist/boot/resolve-spec.js +9 -768
- package/dist/boot/retention-lane.js +4 -87
- package/dist/boot/runner-deps.js +3 -297
- package/dist/boot/runtime-caps.js +0 -40
- package/dist/boot/session-faces.js +2 -133
- package/dist/boot/shutdown.js +9 -83
- package/dist/boot/side-query-lane.js +2 -137
- package/dist/boot/stores.js +15 -215
- package/dist/boot/task-list-lane.js +0 -18
- package/dist/boot/webfetch-summarize-lane.js +0 -47
- package/dist/boot/workflow-orchestration.js +3 -99
- package/dist/boot-reclaim.js +0 -20
- package/dist/bounded-session-map.js +0 -19
- package/dist/brain.js +2 -139
- package/dist/budget.js +9 -244
- package/dist/capabilities/builtin-tools.js +0 -3
- package/dist/capabilities/center-plugins.js +6 -51
- package/dist/capabilities/center-prompts.js +6 -71
- package/dist/capabilities/code-review-council.js +7 -40
- package/dist/capabilities/collab-workflows.js +1 -44
- package/dist/capabilities/hands-lane.js +0 -65
- package/dist/capabilities/memory-notice.js +0 -70
- package/dist/capabilities/prompt.js +0 -14
- package/dist/capabilities/prompts/code-review.js +0 -14
- package/dist/capabilities/prompts/identity.js +0 -6
- package/dist/capabilities/prompts/team.js +0 -4
- package/dist/capabilities/repo-tools.js +0 -34
- package/dist/capabilities/sandbox-file-send.js +3 -92
- package/dist/capabilities/scenarios.d.ts +0 -1
- package/dist/capabilities/scenarios.js +18 -279
- package/dist/capabilities/select-environment-tool.js +0 -32
- package/dist/capabilities/send-user-file-tool.js +2 -66
- package/dist/capabilities/skills.d.ts +1 -2
- package/dist/capabilities/skills.js +3 -21
- package/dist/capabilities/team.d.ts +3 -11
- package/dist/capabilities/team.js +3 -51
- package/dist/capabilities/tool-defer.js +0 -3
- package/dist/config-center/apply-effective.js +15 -330
- package/dist/config-center/apply-ledger.js +5 -38
- package/dist/config-center/facade.js +0 -41
- package/dist/config-center/hot-keys-registry.js +0 -20
- package/dist/config-center/http-client.js +2 -125
- package/dist/config-center/mcp-revocation.js +2 -34
- package/dist/config-center/read-face.js +0 -59
- package/dist/config-center/restart-signal.js +1 -85
- package/dist/config-center/skills-mcp.d.ts +1 -1
- package/dist/config-center/skills-mcp.js +9 -76
- package/dist/config-center/stage-limits.js +8 -35
- package/dist/config-invariants.js +0 -16
- package/dist/config-lkg.js +0 -42
- package/dist/config-provider.js +3 -186
- package/dist/config-types.js +0 -5
- package/dist/config.js +107 -1145
- package/dist/degenerate-instrument.js +3 -67
- package/dist/deployment-governance.js +0 -124
- package/dist/digest-form.js +0 -12
- package/dist/elicitation.js +3 -86
- package/dist/env-facts.js +7 -75
- package/dist/fleet/fleet-bus.js +34 -507
- package/dist/fleet/fleet-reconciler.js +9 -149
- package/dist/fleet/fleet-terminal-window.js +10 -178
- package/dist/fleet/subagent-tail-bus.js +3 -72
- package/dist/fleet-client.js +10 -70
- package/dist/fleet-lease.js +5 -79
- package/dist/git-api-kind.js +0 -3
- package/dist/governance-ask-marks.js +2 -78
- package/dist/hooks/branch-transcript.js +0 -74
- package/dist/hooks/cc-agent-hook-prompt.js +0 -29
- package/dist/hooks/cc-stop-prompt.js +1 -46
- package/dist/hooks/hook-llm.js +1 -53
- package/dist/hooks/hook-runner.js +20 -414
- package/dist/http/active-run-conflict.js +4 -129
- package/dist/http/cursor-fingerprint.d.ts +5 -0
- package/dist/http/cursor-fingerprint.js +5 -0
- package/dist/http/idempotency.js +0 -37
- package/dist/http/principal-gate.js +3 -40
- package/dist/http/route-ctx.js +0 -9
- package/dist/http/routes/a2a-serve.js +7 -319
- package/dist/http/routes/admin-config-refresh.js +0 -4
- package/dist/http/routes/admin-drain.js +0 -10
- package/dist/http/routes/adoption.js +1 -29
- package/dist/http/routes/agents-roster.js +1 -47
- package/dist/http/routes/approvals-assistant.js +32 -395
- package/dist/http/routes/attachments.js +4 -22
- package/dist/http/routes/capabilities.js +3 -420
- package/dist/http/routes/diagnostics.js +1 -81
- package/dist/http/routes/fleet.js +9 -185
- package/dist/http/routes/images.js +14 -239
- package/dist/http/routes/leader.js +0 -13
- package/dist/http/routes/memory-bundle.js +1 -61
- package/dist/http/routes/memory-policy.js +9 -99
- package/dist/http/routes/notify-wake.js +3 -37
- package/dist/http/routes/observability.js +2 -19
- package/dist/http/routes/retention-ops.js +2 -34
- package/dist/http/routes/rules.js +1 -93
- package/dist/http/routes/runs.js +64 -873
- package/dist/http/routes/session-sync.js +19 -258
- package/dist/http/routes/sessions-list.js +17 -43
- package/dist/http/routes/sessions.js +34 -226
- package/dist/http/routes/shared-memory.js +5 -36
- package/dist/http/routes/side-query.js +1 -87
- package/dist/http/routes/tasks.js +52 -722
- package/dist/http/routes/trace-usage.js +32 -195
- package/dist/http/routes/workflows.js +19 -195
- package/dist/http/run-meta.js +0 -6
- package/dist/http/send.js +0 -32
- package/dist/http/server.js +92 -1597
- package/dist/http/sse-lifecycle.js +2 -13
- package/dist/http/sse-log.js +3 -48
- package/dist/http/tar.js +5 -21
- package/dist/http/verify-rounds.js +0 -5
- package/dist/http/wire-gate.js +0 -9
- package/dist/http/workspace-content.js +0 -10
- package/dist/images/bake-validate.js +1 -70
- package/dist/images/manifest.js +1 -6
- package/dist/index.js +0 -21
- package/dist/key-resolver.js +2 -17
- package/dist/leader/diffout.js +1 -20
- package/dist/leader/diffup.js +0 -47
- package/dist/leader/endpoint.js +2 -57
- package/dist/leader/fanout.js +3 -45
- package/dist/leader/grader-env-factory.js +3 -72
- package/dist/leader/leader.js +5 -156
- package/dist/leader/merge.js +8 -115
- package/dist/leader/planner.js +3 -54
- package/dist/leader/repair-oracle.js +1 -60
- package/dist/leader/repair-wire.js +2 -79
- package/dist/leader/wire.js +8 -307
- package/dist/lsp/e2b-bridge.js +4 -64
- package/dist/lsp/e2b-manager.js +6 -94
- package/dist/lsp/lsp-frames.js +0 -12
- package/dist/lsp/manager.js +4 -96
- package/dist/lsp/ws-transport.js +5 -55
- package/dist/lsp-evict.js +1 -15
- package/dist/main.js +57 -765
- package/dist/memory-bundle-engine.js +0 -55
- package/dist/memory-export.js +0 -4
- package/dist/memory-posture.js +1 -15
- package/dist/memory-scope.js +11 -148
- package/dist/memory-sync-client.js +2 -44
- package/dist/memory-sync.js +1 -80
- package/dist/model-select.js +3 -80
- package/dist/observability/cost-quota.js +1 -17
- package/dist/observability/cost-taxonomy.js +0 -34
- package/dist/observability/fail-open.js +7 -86
- package/dist/observability/logger.js +0 -6
- package/dist/observability/metrics.js +0 -94
- package/dist/observability/otel-exporter.js +3 -13
- package/dist/observability/principal-context.js +0 -9
- package/dist/observability/prompt-manifest.js +1 -37
- package/dist/observability/rate-limit.js +0 -4
- package/dist/observability/secret-env-scrub.js +2 -56
- package/dist/observability/tool-trace.js +1 -70
- package/dist/orchestration/hardened-vm-runner.js +4 -118
- package/dist/orchestration/hardened-vm-worker-runner.js +1 -26
- package/dist/orchestration/hardened-vm-worker.js +0 -27
- package/dist/orchestration/subagent-steer.js +1 -45
- package/dist/orchestration/workflow-agent-steer.js +1 -80
- package/dist/orchestration/workflow-completion-inbox.js +32 -285
- package/dist/orchestration/workflow-notify-journal.js +16 -259
- package/dist/org-memory-admission.js +3 -47
- package/dist/parent-watch.js +2 -48
- package/dist/parked-decide.js +1 -109
- package/dist/per-task-image.js +0 -57
- package/dist/plan-cache-probe.js +3 -27
- package/dist/plugins/adoption-log-sql.js +2 -119
- package/dist/plugins/approval-ask-store-memory.js +3 -38
- package/dist/plugins/approval-ask-store-sql.js +6 -188
- package/dist/plugins/approval-exemption-store.js +2 -28
- package/dist/plugins/background-agent-store-sql.js +4 -105
- package/dist/plugins/background-shell-support.js +14 -122
- package/dist/plugins/blob-backend.js +6 -169
- package/dist/plugins/breaker-state-sql.js +8 -46
- package/dist/plugins/caching-session-store.js +4 -106
- package/dist/plugins/checkpoint-store-sql.js +18 -505
- package/dist/plugins/e2b-orphan-reclaim.js +0 -45
- package/dist/plugins/file-outcome-sink.js +0 -9
- package/dist/plugins/file-resume-anchor-store.js +4 -43
- package/dist/plugins/file-run-store.js +26 -364
- package/dist/plugins/file-snapshot-store-sql.js +10 -181
- package/dist/plugins/fork-routing-session-store.js +8 -111
- package/dist/plugins/host-platform.js +2 -91
- package/dist/plugins/image-bake-store-sql.js +7 -250
- package/dist/plugins/image-index-sql.js +4 -123
- package/dist/plugins/k8s-bg-scripts.js +4 -88
- package/dist/plugins/k8s-exec-protocol.js +0 -41
- package/dist/plugins/leader-run-store-sql.js +0 -101
- package/dist/plugins/local-checkpoint-store.js +8 -128
- package/dist/plugins/local-session-store.js +34 -296
- package/dist/plugins/local-task-attachment-store.js +2 -16
- package/dist/plugins/mailbox-store-sql.js +8 -65
- package/dist/plugins/memory-embedder-fingerprint.js +5 -166
- package/dist/plugins/memory-embedder.js +4 -70
- package/dist/plugins/memory-engine-pg.js +6 -170
- package/dist/plugins/memory-engine-tidb.js +7 -155
- package/dist/plugins/memory-engine-vector-util.js +0 -10
- package/dist/plugins/memory-key-guards.js +0 -34
- package/dist/plugins/memory-origin-law.js +0 -187
- package/dist/plugins/memory-resume-anchor-store.js +0 -17
- package/dist/plugins/memory-run-store.js +12 -89
- package/dist/plugins/memory-session-policy-store.js +0 -17
- package/dist/plugins/memory-sync-store-pg.js +4 -49
- package/dist/plugins/memory-sync-store-tidb.js +3 -35
- package/dist/plugins/outcome-ledger-sql.js +3 -97
- package/dist/plugins/permission-rule-store-file.js +5 -133
- package/dist/plugins/permission-rule-store-sql.d.ts +3 -0
- package/dist/plugins/permission-rule-store-sql.js +50 -307
- package/dist/plugins/pg-cost-quota.js +0 -7
- package/dist/plugins/pg-pool.js +0 -92
- package/dist/plugins/pg-rate-limiter.js +2 -13
- package/dist/plugins/pg-safe-json.js +4 -40
- package/dist/plugins/pg-session-storage.js +25 -189
- package/dist/plugins/posix-shell-fs.js +1 -31
- package/dist/plugins/remote-env-adb.js +12 -101
- package/dist/plugins/remote-env-e2b.js +40 -371
- package/dist/plugins/remote-env-file-error.js +0 -37
- package/dist/plugins/remote-env-host.js +63 -483
- package/dist/plugins/remote-env-k8s.js +32 -326
- package/dist/plugins/remote-env-local-docker.js +24 -157
- package/dist/plugins/remote-env-ssh.js +20 -128
- package/dist/plugins/remote-scratchpad.js +2 -32
- package/dist/plugins/remote-shell.js +1 -32
- package/dist/plugins/resume-anchor-store-sql.js +0 -11
- package/dist/plugins/retention-lane-store-sql.js +0 -108
- package/dist/plugins/retention-store-sql.js +4 -383
- package/dist/plugins/roster-store-sql.js +0 -55
- package/dist/plugins/run-store-sql.js +14 -251
- package/dist/plugins/s3-presign.js +2 -49
- package/dist/plugins/scheduler-support.js +3 -80
- package/dist/plugins/send-file-ledger.js +4 -53
- package/dist/plugins/send-user-file.js +4 -94
- package/dist/plugins/session-placement.js +1 -89
- package/dist/plugins/session-policy-store-sql.js +3 -81
- package/dist/plugins/session-store.js +0 -57
- package/dist/plugins/shared-memory-store-sql.js +4 -167
- package/dist/plugins/sql-driver.js +0 -17
- package/dist/plugins/sql-errors.js +0 -7
- package/dist/plugins/sql-escape.js +0 -8
- package/dist/plugins/sql-row-helpers.js +0 -25
- package/dist/plugins/store-backend.js +42 -222
- package/dist/plugins/store-contracts.js +2 -46
- package/dist/plugins/task-attachment-store.js +3 -49
- package/dist/plugins/task-list-store-sql.js +0 -79
- package/dist/plugins/tidb-cost-quota.js +1 -4
- package/dist/plugins/tidb-pool.js +1 -207
- package/dist/plugins/tidb-rate-limiter.js +3 -9
- package/dist/plugins/tidb-session-storage.js +4 -70
- package/dist/plugins/tidb-session-store.js +19 -341
- package/dist/plugins/tool-result-store-sql.js +4 -179
- package/dist/plugins/usage-window-store-sql.js +0 -8
- package/dist/plugins/web-search.js +10 -132
- package/dist/plugins/workflow-journal-store-sql.js +2 -58
- package/dist/plugins/workflow-run-store-sql.js +6 -91
- package/dist/plugins/worktree-isolation.js +6 -126
- package/dist/plugins/write-behind-counter.js +16 -75
- package/dist/principal-jwt.js +5 -60
- package/dist/project-memory.js +15 -146
- package/dist/prompts-domain-validate.js +1 -51
- package/dist/question.js +2 -111
- package/dist/resource-suspend.js +0 -18
- package/dist/router/route-orchestration.js +0 -77
- package/dist/rules-consent.d.ts +44 -5
- package/dist/rules-consent.js +75 -215
- package/dist/run-local.js +14 -381
- package/dist/runs.js +29 -617
- package/dist/runtime-caps-resolver.js +6 -132
- package/dist/runtime-governance.js +1 -232
- package/dist/sandbox-pkg-source.js +0 -37
- package/dist/sealed-key.js +3 -68
- package/dist/security.js +6 -291
- package/dist/session-leaf-bus.js +0 -32
- package/dist/session-sync-content.js +1 -69
- package/dist/session-sync-kernel.js +3 -60
- package/dist/session-sync.js +3 -66
- package/dist/session-titler.js +7 -41
- package/dist/session-watch.js +9 -73
- package/dist/shared-memory-scope-authorizer.js +0 -18
- package/dist/sighup-idle.js +1 -12
- package/dist/spec-fields.js +4 -143
- package/dist/store-live-probe.js +3 -49
- package/dist/task-a2a.js +1 -126
- package/dist/task-cwd.js +1 -103
- package/dist/task-mcp.js +1 -89
- package/dist/task-settings.js +10 -300
- package/dist/task-workflow.js +8 -75
- package/dist/tool-approval.d.ts +28 -1
- package/dist/tool-approval.js +70 -1430
- package/dist/trace/artifacts.js +5 -20
- package/dist/trace/engine-notice-wire.js +6 -138
- package/dist/trace/ledger-sink.js +7 -96
- package/dist/trace/project.js +4 -448
- package/dist/trace/redact.js +9 -77
- package/dist/turn-activity.js +1 -27
- package/dist/usage-analytics.js +4 -34
- package/dist/wall-clock-jump-guard.js +1 -68
- package/package.json +3 -3
- package/dist/capabilities/scenario-alias.d.ts +0 -27
- package/dist/capabilities/scenario-alias.js +0 -61
|
@@ -1,7 +1,4 @@
|
|
|
1
1
|
export const TASK_ATTACHMENT_TABLE = "task_attachment";
|
|
2
|
-
/** 物化相对路径(确定性,notice 与真实写盘共用一份推导——两处各算一遍会漂):按 listBySession 序
|
|
3
|
-
* (created_at_ms, id)分配 `attachments/<name>`;同名撞车时后者前缀 id 头 8 位。名字在上传时已
|
|
4
|
-
* 消毒为安全 basename([A-Za-z0-9._-]),拼接后仍是安全相对路径。 */
|
|
5
2
|
export function materializedRelPaths(atts) {
|
|
6
3
|
const used = new Set();
|
|
7
4
|
const out = new Map();
|
|
@@ -26,9 +23,6 @@ function rowToRecord(r) {
|
|
|
26
23
|
...(r.bound_at_ms !== null && r.bound_at_ms !== undefined ? { boundAtMs: Number(r.bound_at_ms) } : {}),
|
|
27
24
|
};
|
|
28
25
|
}
|
|
29
|
-
/** 半场②(提交时绑定 + objective 告知)的可测核。fresh 腿硬验证(未知/他人 id → throw(mapTo400));
|
|
30
|
-
* resume 腿降级(warn+跳过——4xx 会砖存量 task;记录不可变 ⇒ 在场行的 notice 字节恒稳)。
|
|
31
|
-
* notice 路径从**绑定后的全 session 集**推导(与物化共用 materializedRelPaths),只罗列本次引用的文件。 */
|
|
32
26
|
export async function bindAttachmentsForTask(opts) {
|
|
33
27
|
const found = [];
|
|
34
28
|
for (const id of opts.ids) {
|
|
@@ -47,8 +41,6 @@ export async function bindAttachmentsForTask(opts) {
|
|
|
47
41
|
const lines = found.map((r) => `- ${paths.get(r.id) ?? `attachments/${r.name}`} (${r.mime}, ${r.sizeBytes} bytes)`);
|
|
48
42
|
return { notice: `[attachments] ${found.length} uploaded file(s) are available in the \`attachments/\` directory of your working directory:\n${lines.join("\n")}` };
|
|
49
43
|
}
|
|
50
|
-
/** 半场③(env 建立时物化)的可测核。**fail-loud**:objective 已宣告文件在场,静默缺文件=模型按幻影
|
|
51
|
-
* 文件行动,比 env 建立失败更糟 ⇒ 任一写失败即 throw。幂等:重建沙箱/resume 重写同路径同字节。 */
|
|
52
44
|
export async function materializeAttachmentsInto(env, store, sessionId) {
|
|
53
45
|
const atts = await store.listBySession(sessionId);
|
|
54
46
|
if (atts.length === 0)
|
|
@@ -102,7 +94,6 @@ export async function ensurePgTaskAttachmentSchema(q) {
|
|
|
102
94
|
await q(`CREATE INDEX IF NOT EXISTS idx_att_session ON ${TASK_ATTACHMENT_TABLE} (session_id)`);
|
|
103
95
|
await q(`CREATE INDEX IF NOT EXISTS idx_att_unbound ON ${TASK_ATTACHMENT_TABLE} (created_at_ms)`);
|
|
104
96
|
}
|
|
105
|
-
/** bytes → 4 MiB 块序列(共享切块器,两方言 + 完整性校验共用)。 */
|
|
106
97
|
export class TiDBTaskAttachmentStore {
|
|
107
98
|
pool;
|
|
108
99
|
bytes;
|
|
@@ -111,8 +102,6 @@ export class TiDBTaskAttachmentStore {
|
|
|
111
102
|
this.bytes = bytes;
|
|
112
103
|
}
|
|
113
104
|
async put(rec) {
|
|
114
|
-
// 次序=bytes 先、meta 后:meta 行在场 ⇒ 对象在场(读侧无半态)。对象键=sha256(去重;
|
|
115
|
-
// MinioBlobBackend putBlob 幂等,重复内容=同键重放)。半途崩溃只留无 meta 的对象——经 API 不可达。
|
|
116
105
|
await this.bytes.putBlob(rec.sha256, rec.content);
|
|
117
106
|
await this.pool.execute(`INSERT INTO ${TASK_ATTACHMENT_TABLE} (${COLS}) VALUES (?,?,?,?,?,?,?,?,?)`, [rec.id, rec.owner, rec.name, rec.mime, rec.sha256, rec.sizeBytes, rec.sessionId ?? null, rec.createdAtMs, rec.boundAtMs ?? null]);
|
|
118
107
|
}
|
|
@@ -121,15 +110,12 @@ export class TiDBTaskAttachmentStore {
|
|
|
121
110
|
return rows.length ? rowToRecord(rows[0]) : null;
|
|
122
111
|
}
|
|
123
112
|
async getContent(owner, id) {
|
|
124
|
-
const meta = await this.get(owner, id);
|
|
113
|
+
const meta = await this.get(owner, id);
|
|
125
114
|
if (!meta)
|
|
126
115
|
return null;
|
|
127
|
-
const b = await this.bytes.getBlob(meta.sha256);
|
|
116
|
+
const b = await this.bytes.getBlob(meta.sha256);
|
|
128
117
|
return b && b.byteLength === meta.sizeBytes ? b : null;
|
|
129
118
|
}
|
|
130
|
-
/** 零引用对象删除(best-effort):meta 已删后,sha 仍被其他行引用则对象保留(跨行去重共享)。
|
|
131
|
-
* 失败只吞不抛——E21 purge 不被对象存储抖动卡死(blob-backend 异步删裁定同旨);无 meta 的对象
|
|
132
|
-
* 经 API 不可达,彻底清收敛记 follow-up。 */
|
|
133
119
|
async deleteBytesIfUnreferenced(shas) {
|
|
134
120
|
for (const sha of new Set(shas)) {
|
|
135
121
|
try {
|
|
@@ -138,7 +124,6 @@ export class TiDBTaskAttachmentStore {
|
|
|
138
124
|
await this.bytes.deleteBlobs([sha]);
|
|
139
125
|
}
|
|
140
126
|
catch {
|
|
141
|
-
/* best-effort(见上) */
|
|
142
127
|
}
|
|
143
128
|
}
|
|
144
129
|
}
|
|
@@ -174,17 +159,10 @@ export class TiDBTaskAttachmentStore {
|
|
|
174
159
|
await this.deleteBytesIfUnreferenced(rows.map((r) => r.sha256));
|
|
175
160
|
return res.affectedRows ?? 0;
|
|
176
161
|
}
|
|
177
|
-
/** D-1 孤儿对象彻底 GC(clay 拍 2026-07-28):对象存储列举 × meta 行对账。判据保守三层:
|
|
178
|
-
* ①只删**真列举到**且 ②零 meta 行引用 且 ③LastModified 过 grace 的对象(上传先行窗口:对象先落、
|
|
179
|
-
* meta 行后写——grace 护住 put 竞态,宁漏勿误删,下轮再收);列举失败=整轮 throw(调用方 catch,
|
|
180
|
-
* 「列不出来」绝不当「没有孤儿」)。 */
|
|
181
162
|
async sweepOrphanObjects(graceMs, nowMs = Date.now()) {
|
|
182
163
|
const lister = this.bytes;
|
|
183
164
|
if (typeof lister.listObjects !== "function")
|
|
184
|
-
return 0;
|
|
185
|
-
// 🔴 复审 F2:**边列举边消费**——grace 判据是「对象年龄」不是「孤儿性」,稳态下整个存量语料
|
|
186
|
-
// (凡超过 grace)都会先进候选集;攒满再分批 ⇒ 内存与语料同阶(20 万对象实测堆 Δ58MB,百万级
|
|
187
|
-
// ≈290MB,且每 tick 每副本各一份)。改成满 200 就消费,峰值降到 O(200)。
|
|
165
|
+
return 0;
|
|
188
166
|
let removed = 0;
|
|
189
167
|
let batch = [];
|
|
190
168
|
const flush = async () => {
|
|
@@ -192,11 +170,6 @@ export class TiDBTaskAttachmentStore {
|
|
|
192
170
|
return;
|
|
193
171
|
const referenced = await this.referencedShas(batch);
|
|
194
172
|
const orphans = batch.filter((h) => !referenced.has(h));
|
|
195
|
-
// 🔴 复审 B-F1(数据安全):**删前逐对象复查**。grace 只在列举时刻判过一次,而
|
|
196
|
-
// 「referencedShas 判零引用 → deleteBlobs」之间落地的同 sha 上传(内容去重 ⇒ 同 key)会让
|
|
197
|
-
// meta 行在场而对象被本轮删掉 = 永久丢字节(getContent 恒 null、物化 fail-loud)。put 会 PUT
|
|
198
|
-
// 同键刷新 LastModified,所以删前再 HEAD 一次即可识别;窗口压到 HEAD→DELETE 毫秒级。
|
|
199
|
-
// 无 headObject 面 ⇒ 保守**不删**(宁留孤儿不误删)。
|
|
200
173
|
const safe = await this.filterStillOrphan(orphans, graceMs, nowMs);
|
|
201
174
|
if (safe.length > 0)
|
|
202
175
|
removed += await this.bytes.deleteBlobs(safe);
|
|
@@ -212,7 +185,6 @@ export class TiDBTaskAttachmentStore {
|
|
|
212
185
|
await flush();
|
|
213
186
|
return removed;
|
|
214
187
|
}
|
|
215
|
-
/** sweep 的引用对账半场:批内 sha 中仍有 meta 行的子集(单 IN 查询;DISTINCT 免重复行膨胀)。 */
|
|
216
188
|
async referencedShas(shas) {
|
|
217
189
|
if (shas.length === 0)
|
|
218
190
|
return new Set();
|
|
@@ -220,8 +192,6 @@ export class TiDBTaskAttachmentStore {
|
|
|
220
192
|
const [rows] = await this.pool.query(`SELECT DISTINCT sha256 FROM ${TASK_ATTACHMENT_TABLE} WHERE sha256 IN (${ph})`, shas);
|
|
221
193
|
return new Set(rows.map((r) => String(r.sha256)));
|
|
222
194
|
}
|
|
223
|
-
/** 删前复查(复审 B-F1):只保留「HEAD 仍在 且 LastModified 仍过 grace」的 hash。无 headObject
|
|
224
|
-
* 面 ⇒ 返回空集(保守不删);HEAD 抛错 ⇒ 该对象本轮跳过(下轮再收)。 */
|
|
225
195
|
async filterStillOrphan(hashes, graceMs, nowMs) {
|
|
226
196
|
if (hashes.length === 0)
|
|
227
197
|
return [];
|
|
@@ -236,7 +206,6 @@ export class TiDBTaskAttachmentStore {
|
|
|
236
206
|
out.push(h);
|
|
237
207
|
}
|
|
238
208
|
catch {
|
|
239
|
-
/* 复查失败=本轮跳过(宁漏勿误删) */
|
|
240
209
|
}
|
|
241
210
|
}
|
|
242
211
|
return out;
|
|
@@ -250,7 +219,6 @@ export class PgTaskAttachmentStore {
|
|
|
250
219
|
this.bytes = bytes;
|
|
251
220
|
}
|
|
252
221
|
async put(rec) {
|
|
253
|
-
// bytes 先、meta 后(TiDB 同姿,注同)
|
|
254
222
|
await this.bytes.putBlob(rec.sha256, rec.content);
|
|
255
223
|
await this.q(`INSERT INTO ${TASK_ATTACHMENT_TABLE} (${COLS}) VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9)`, [rec.id, rec.owner, rec.name, rec.mime, rec.sha256, rec.sizeBytes, rec.sessionId ?? null, rec.createdAtMs, rec.boundAtMs ?? null]);
|
|
256
224
|
}
|
|
@@ -273,14 +241,12 @@ export class PgTaskAttachmentStore {
|
|
|
273
241
|
await this.bytes.deleteBlobs([sha]);
|
|
274
242
|
}
|
|
275
243
|
catch {
|
|
276
|
-
/* best-effort(TiDB 同注) */
|
|
277
244
|
}
|
|
278
245
|
}
|
|
279
246
|
}
|
|
280
247
|
async bind(owner, ids, sessionId, boundAtMs) {
|
|
281
248
|
if (ids.length === 0)
|
|
282
249
|
return 0;
|
|
283
|
-
// PgQueryFn 有意无 rowCount(pg-query.ts 契约)⇒ RETURNING id 数行
|
|
284
250
|
const res = await this.q(`UPDATE ${TASK_ATTACHMENT_TABLE} SET session_id = $1, bound_at_ms = $2 WHERE owner = $3 AND id = ANY($4::varchar[]) RETURNING id`, [sessionId, boundAtMs, owner, ids]);
|
|
285
251
|
return res.rows.length;
|
|
286
252
|
}
|
|
@@ -305,14 +271,10 @@ export class PgTaskAttachmentStore {
|
|
|
305
271
|
await this.deleteBytesIfUnreferenced(res.rows.map((r) => r.sha256));
|
|
306
272
|
return res.rows.length;
|
|
307
273
|
}
|
|
308
|
-
/** D-1 孤儿对象彻底 GC —— twin of the TiDB store(判据三层同注:真列举/零引用/过 grace)。 */
|
|
309
274
|
async sweepOrphanObjects(graceMs, nowMs = Date.now()) {
|
|
310
275
|
const lister = this.bytes;
|
|
311
276
|
if (typeof lister.listObjects !== "function")
|
|
312
277
|
return 0;
|
|
313
|
-
// 🔴 复审 F2:**边列举边消费**——grace 判据是「对象年龄」不是「孤儿性」,稳态下整个存量语料
|
|
314
|
-
// (凡超过 grace)都会先进候选集;攒满再分批 ⇒ 内存与语料同阶(20 万对象实测堆 Δ58MB,百万级
|
|
315
|
-
// ≈290MB,且每 tick 每副本各一份)。改成满 200 就消费,峰值降到 O(200)。
|
|
316
278
|
let removed = 0;
|
|
317
279
|
let batch = [];
|
|
318
280
|
const flush = async () => {
|
|
@@ -320,11 +282,6 @@ export class PgTaskAttachmentStore {
|
|
|
320
282
|
return;
|
|
321
283
|
const referenced = await this.referencedShas(batch);
|
|
322
284
|
const orphans = batch.filter((h) => !referenced.has(h));
|
|
323
|
-
// 🔴 复审 B-F1(数据安全):**删前逐对象复查**。grace 只在列举时刻判过一次,而
|
|
324
|
-
// 「referencedShas 判零引用 → deleteBlobs」之间落地的同 sha 上传(内容去重 ⇒ 同 key)会让
|
|
325
|
-
// meta 行在场而对象被本轮删掉 = 永久丢字节(getContent 恒 null、物化 fail-loud)。put 会 PUT
|
|
326
|
-
// 同键刷新 LastModified,所以删前再 HEAD 一次即可识别;窗口压到 HEAD→DELETE 毫秒级。
|
|
327
|
-
// 无 headObject 面 ⇒ 保守**不删**(宁留孤儿不误删)。
|
|
328
285
|
const safe = await this.filterStillOrphan(orphans, graceMs, nowMs);
|
|
329
286
|
if (safe.length > 0)
|
|
330
287
|
removed += await this.bytes.deleteBlobs(safe);
|
|
@@ -347,8 +304,6 @@ export class PgTaskAttachmentStore {
|
|
|
347
304
|
const r = await this.q(`SELECT DISTINCT sha256 FROM ${TASK_ATTACHMENT_TABLE} WHERE sha256 IN (${ph})`, shas);
|
|
348
305
|
return new Set(r.rows.map((row) => String(row.sha256)));
|
|
349
306
|
}
|
|
350
|
-
/** 删前复查(复审 B-F1):只保留「HEAD 仍在 且 LastModified 仍过 grace」的 hash。无 headObject
|
|
351
|
-
* 面 ⇒ 返回空集(保守不删);HEAD 抛错 ⇒ 该对象本轮跳过(下轮再收)。 */
|
|
352
307
|
async filterStillOrphan(hashes, graceMs, nowMs) {
|
|
353
308
|
if (hashes.length === 0)
|
|
354
309
|
return [];
|
|
@@ -363,7 +318,6 @@ export class PgTaskAttachmentStore {
|
|
|
363
318
|
out.push(h);
|
|
364
319
|
}
|
|
365
320
|
catch {
|
|
366
|
-
/* 复查失败=本轮跳过(宁漏勿误删) */
|
|
367
321
|
}
|
|
368
322
|
}
|
|
369
323
|
return out;
|
|
@@ -1,62 +1,13 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* TaskListStore SQL twins(design/151 S3c server pg 半场,[1530] 提货单②)——core 团队共享任务
|
|
3
|
-
* 清单(TaskCreate/TaskUpdate/TaskList 工具族)的 TiDB/PG 双方言实现。挂载缝 = S3c 行为车定
|
|
4
|
-
* (createTaskListTools(store) 已收 store 参数);本文件先就绪 store 半场。
|
|
5
|
-
*
|
|
6
|
-
* 语义真源 = core file 实现(dist/stores/file/task-list-store.js,durable 对 durable)+ [1530] 定谳:
|
|
7
|
-
* 1. **`mutate` 必须后端事务原子**(接口 JSDoc codex S4 F2 句):read-modify-write 全序列进一个
|
|
8
|
-
* 事务;分区锁 = meta 行 `SELECT … FOR UPDATE`(天然 advisory lock,同清单 mutate 串行)。
|
|
9
|
-
* 2. **nextId 只增不回退、与分配同事务**(删最高 id 不复用):`task_list_meta` 单行携 `next_id`,
|
|
10
|
-
* **永不从存量 MAX 派生**。
|
|
11
|
-
* 3. metadata = JSON 列(`assertJsonMetadata` 在 set 面拦,file/memory 同形);id 任意 string
|
|
12
|
-
* (工具层走 allocateId 产数字串,接口不排除外部 id)。
|
|
13
|
-
*
|
|
14
|
-
* `list` 序:两个 core 参照本就不同(memory=Map 纯插入序;file=JS 对象序 = integer-like 键数字
|
|
15
|
-
* 升序、其余按插入序殿后)——SQL twin 对齐 **file 形**(durable 参照):`id_num` 物化列(canonical
|
|
16
|
-
* array-index 形才非 NULL)数字升序,非数字 id 按 `sort_seq`(插入序)殿后。set 覆盖已有 id 保位
|
|
17
|
-
* (sort_seq 不变)= 两参照一致的保位语义。`sort_seq` 从 **meta 行计数器同事务分配**(复审 F6:
|
|
18
|
-
* TiDB AUTO_INCREMENT 按 tidb-server 分段缓存,跨节点不单调——「插入序」在多网关部署下会倒序;
|
|
19
|
-
* meta 计数器 = allocateId 同姿势,真单调;覆盖写浪费一个号,单调性无损)。
|
|
20
|
-
*
|
|
21
|
-
* 分区键 `listKey` = 构造参数(file 形的 root 目录对位):谁的清单由挂载点决定(per-team 组装,
|
|
22
|
-
* S3c 行为车),store 层只管字节隔离(VARBINARY / COLLATE "C",roster F2 案)。PG unstorable
|
|
23
|
-
* bytes([1439]):item 正文(subject/description/metadata)= 内容面 lossy(pgSafeJsonStringify,
|
|
24
|
-
* U+FFFD);**身份键 listKey/id 拒绝式**(清洗形变 = 行与查询键错位)。TiDB verbatim。
|
|
25
|
-
*/
|
|
26
1
|
import { createHash } from "node:crypto";
|
|
27
|
-
// assertJsonMetadata:core 1.374 起包根导出([1531]§一3——私拷镜像即换,DURABLE_AGENT_HANDLE_RE 同姿势)。
|
|
28
2
|
import { assertJsonMetadata } from "@sema-agent/core";
|
|
29
3
|
import { pgHasUnstorable, pgSafeJsonStringify, PgUnstorableError } from "./pg-safe-json.js";
|
|
30
4
|
export const TASK_LIST_META_TABLE = "task_list_meta";
|
|
31
5
|
export const TASK_LIST_ITEM_TABLE = "task_list_item";
|
|
32
|
-
/**
|
|
33
|
-
* #318 `sessionId ↦ 本表的身份键`:`session:<可读前缀>-<sha256(sessionId) 前 16 位>`。
|
|
34
|
-
*
|
|
35
|
-
* 🔴 为什么不直接把 sessionId 当 listKey:sessionId 是**调用方可自报**的不透明串(提交门
|
|
36
|
-
* `http/server.ts` 只卡 ≤64 **字符** —— [#15] 刻意的宽松提交契约,不卡字节数也不卡字符集)。
|
|
37
|
-
* 而本文件的身份键是字节面严格的:{@link assertListKeyBytes} 对 >190 字节当场拒(TiDB
|
|
38
|
-
* `INSERT IGNORE` 静默截断案),PG twin 对孤代理/NUL 走 {@link PgUnstorableError} 拒。直接透传
|
|
39
|
-
* 的话,一个 64 字符全四字节 emoji 的会话(256 字节)会让**整条请求**在场景装配处 500 —— 而那条腿
|
|
40
|
-
* 只是待办清单。派生一个恒可存的键把这一整类失败模式消掉(既不是 fail-open 也不是 fail-loud,是让
|
|
41
|
-
* 那条臂不存在)。
|
|
42
|
-
*
|
|
43
|
-
* 判据:确定性(同 sessionId 跨副本/跨重启恒同键)、字节安全(纯 ASCII,≤ 8+24+1+16 = 49 字节)、
|
|
44
|
-
* 抗碰撞(摘要取**全串**,可读前缀只为运维肉眼对账)。
|
|
45
|
-
*
|
|
46
|
-
* `session:` 是**命名空间**位:design/147 §6 D2 的团队共享清单将来若按 team 分区,两族键同表不撞。
|
|
47
|
-
* 同族先例 = `env-facts.ts` 的 `scratchpadSessionSegment`(文件名面)——刻意**不**复用彼此的实现:
|
|
48
|
-
* 一个键空间改了算法不该把另一个键空间的存量行全孤儿化。
|
|
49
|
-
*
|
|
50
|
-
* 🔴 属主在**本文件**(而不是消费它的 boot 车道):留存腿(`retention-store-sql.ts`)按同一派生式
|
|
51
|
-
* 批量删本表的行,两个消费点必须读同一个函数 —— 键派生有两份就是「在线删除删得掉、留存腿删不掉」。
|
|
52
|
-
*/
|
|
53
6
|
export function taskListKeyFor(sessionId) {
|
|
54
7
|
const readable = sessionId.replace(/[^A-Za-z0-9_-]/g, "_").slice(0, 24);
|
|
55
8
|
const digest = createHash("sha256").update(sessionId).digest("hex").slice(0, 16);
|
|
56
9
|
return `session:${readable.length > 0 ? readable : "_"}-${digest}`;
|
|
57
10
|
}
|
|
58
|
-
/** JS 对象 integer-like(array-index)键判別——file 参照的遍历序里数字升序的那一族:canonical
|
|
59
|
-
* 十进制、0 ≤ n < 2^32-1。"01"/"1e3"/负数/超界 = 普通串键(插入序殿后)。 */
|
|
60
11
|
function arrayIndexOf(id) {
|
|
61
12
|
if (!/^(0|[1-9][0-9]*)$/.test(id))
|
|
62
13
|
return null;
|
|
@@ -66,16 +17,12 @@ function arrayIndexOf(id) {
|
|
|
66
17
|
function parseItem(v) {
|
|
67
18
|
return JSON.parse(String(v));
|
|
68
19
|
}
|
|
69
|
-
/** 键长守卫(mailbox twin F5 同案):TiDB `INSERT IGNORE` 对超 190 字节键静默截断——截断 listKey
|
|
70
|
-
* 与全长查询参数字节比对恒 miss(mutate 拿不到分区锁 = 无锁运行)。构造点一次拒清。item 的 id
|
|
71
|
-
* 列超长走非 IGNORE 语句 = 两方言原生 fail-loud,无需前置守卫。 */
|
|
72
20
|
function assertListKeyBytes(listKey) {
|
|
73
21
|
if (Buffer.byteLength(listKey, "utf8") > 190) {
|
|
74
22
|
throw new Error(`TaskListStore: listKey exceeds the 190-byte key column (refusing — a truncated key would desync from its byte-exact lookups)`);
|
|
75
23
|
}
|
|
76
24
|
}
|
|
77
25
|
export async function ensureTiDBTaskListSchema(pool) {
|
|
78
|
-
// next_sort = sort_seq 计数器(F6:不用 AUTO_INCREMENT——TiDB 分段缓存跨节点不单调)。
|
|
79
26
|
await pool.query(`CREATE TABLE IF NOT EXISTS ${TASK_LIST_META_TABLE} (
|
|
80
27
|
list_key VARBINARY(190) NOT NULL,
|
|
81
28
|
next_id BIGINT NOT NULL,
|
|
@@ -107,14 +54,11 @@ export async function ensurePgTaskListSchema(q) {
|
|
|
107
54
|
PRIMARY KEY (list_key, id)
|
|
108
55
|
)`);
|
|
109
56
|
}
|
|
110
|
-
/** meta 行 ensure(ensure-first 形:先幂等 INSERT 再 FOR UPDATE——「无行 FOR UPDATE + INSERT」的
|
|
111
|
-
* 经典并发死锁/dup 撞车形整个消掉;mutate 已持 meta 行锁时重入 = 同事务无害)。 */
|
|
112
57
|
async function ensureMeta(exec, dialect, listKey) {
|
|
113
58
|
await exec(dialect === "tidb"
|
|
114
59
|
? `INSERT IGNORE INTO ${TASK_LIST_META_TABLE} (list_key, next_id, next_sort) VALUES (?, 1, 1)`
|
|
115
60
|
: `INSERT INTO ${TASK_LIST_META_TABLE} (list_key, next_id, next_sort) VALUES ($1, 1, 1) ON CONFLICT (list_key) DO NOTHING`, [listKey]);
|
|
116
61
|
}
|
|
117
|
-
/** 事务内的 nextId 分配(定谳 2:与分配同事务、永不 MAX 派生)。 */
|
|
118
62
|
async function allocateOn(exec, dialect, listKey) {
|
|
119
63
|
await ensureMeta(exec, dialect, listKey);
|
|
120
64
|
const rows = await exec(dialect === "tidb"
|
|
@@ -126,8 +70,6 @@ async function allocateOn(exec, dialect, listKey) {
|
|
|
126
70
|
: `UPDATE ${TASK_LIST_META_TABLE} SET next_id = $1 WHERE list_key = $2`, [id + 1, listKey]);
|
|
127
71
|
return String(id);
|
|
128
72
|
}
|
|
129
|
-
/** 事务内的 set(F6:sort_seq 从 meta 计数器分配,与写同事务——meta 行锁顺带把同清单写串行;
|
|
130
|
-
* 覆盖写时 ON DUPLICATE/CONFLICT 不动 sort_seq(保位),浪费的号只增不回,单调性无损)。 */
|
|
131
73
|
async function setOn(exec, dialect, listKey, id, itemJson) {
|
|
132
74
|
await ensureMeta(exec, dialect, listKey);
|
|
133
75
|
const rows = await exec(dialect === "tidb"
|
|
@@ -143,17 +85,6 @@ async function setOn(exec, dialect, listKey, id, itemJson) {
|
|
|
143
85
|
? `UPDATE ${TASK_LIST_META_TABLE} SET next_sort = ? WHERE list_key = ?`
|
|
144
86
|
: `UPDATE ${TASK_LIST_META_TABLE} SET next_sort = $1 WHERE list_key = $2`, [sort + 1, listKey]);
|
|
145
87
|
}
|
|
146
|
-
/**
|
|
147
|
-
* 整份清单删除(#318 / E21 会话删除级联;codex R1-[high] 验真后加)。
|
|
148
|
-
*
|
|
149
|
-
* 语义 = 「这个 listKey 的清单**不存在过**」:item 行 + meta 行(高水位 `next_id` / 插入序
|
|
150
|
-
* `next_sort`)一并抹掉。⚠️ **meta 行必须一起删**:留着它,同一个 listKey 被重新登记后
|
|
151
|
-
* (会话 id 由调用方自选、删除后可被别人 `register`)新主的第一条任务会从旧主的高水位续号 ——
|
|
152
|
-
* 那是一条跨化身的信息泄漏(「上一位在这里建过 47 条」)。
|
|
153
|
-
*
|
|
154
|
-
* 事务内先对 meta 行 `FOR UPDATE`(与 `mutate` 同一把分区锁)⇒ 与并发的清单写串行,不会删到
|
|
155
|
-
* 一半被插回新行。meta 行不在(从未写过任何任务)= 无锁可拿,DELETE 命中 0 行,幂等。
|
|
156
|
-
*/
|
|
157
88
|
export async function deleteTiDBTaskList(pool, listKey) {
|
|
158
89
|
assertListKeyBytes(listKey);
|
|
159
90
|
const c = await pool.getConnection();
|
|
@@ -172,7 +103,6 @@ export async function deleteTiDBTaskList(pool, listKey) {
|
|
|
172
103
|
c.release();
|
|
173
104
|
}
|
|
174
105
|
}
|
|
175
|
-
/** {@link deleteTiDBTaskList} 的 PG 孪生(同语义、同事务姿势)。 */
|
|
176
106
|
export async function deletePgTaskList(pool, listKey) {
|
|
177
107
|
if (pgHasUnstorable(listKey))
|
|
178
108
|
throw new PgUnstorableError("task-list listKey");
|
|
@@ -215,9 +145,6 @@ export function createTiDBTaskListStore(pool, listKey) {
|
|
|
215
145
|
const [rows] = (await q.query(sql, params));
|
|
216
146
|
return rows;
|
|
217
147
|
};
|
|
218
|
-
// mutate 事务内的读必须**当前读**(FOR UPDATE):TiDB 悲观事务的普通 SELECT 按 start_ts 快照读
|
|
219
|
-
// (事务开始时点)——分区锁串行后普通读仍看见开锁前的旧值,read-modify-write 静默丢更新(真双库
|
|
220
|
-
// 套件抓获:8 并发 increment 终值 1)。MySQL 的快照点(首次快照读)不同但同修;顶层单语句无此臂。
|
|
221
148
|
const build = (q, inTx) => ({
|
|
222
149
|
get: async (id) => {
|
|
223
150
|
const [rows] = (await q.query(`SELECT item_json FROM ${TASK_LIST_ITEM_TABLE} WHERE list_key = ? AND id = ?${inTx ? " FOR UPDATE" : ""}`, [listKey, id]));
|
|
@@ -242,7 +169,6 @@ export function createTiDBTaskListStore(pool, listKey) {
|
|
|
242
169
|
? {}
|
|
243
170
|
: {
|
|
244
171
|
mutate: (fn) => tx(async (c) => {
|
|
245
|
-
// 分区锁(定谳 1):ensure + FOR UPDATE——同 listKey 的并发 mutate 在此串行。
|
|
246
172
|
await ensureMeta(execOn(c), "tidb", listKey);
|
|
247
173
|
await c.query(`SELECT next_id FROM ${TASK_LIST_META_TABLE} WHERE list_key = ? FOR UPDATE`, [listKey]);
|
|
248
174
|
return fn(build(c, true));
|
|
@@ -275,17 +201,12 @@ export function createPgTaskListStore(pool, listKey) {
|
|
|
275
201
|
const res = await q.query(sql, params);
|
|
276
202
|
return res.rows;
|
|
277
203
|
};
|
|
278
|
-
// 事务内当前读(TiDB 侧同注——PG READ COMMITTED 语句级快照本已看见锁前提交,FOR UPDATE 统一
|
|
279
|
-
// 双方言姿势,顺带把行锁真拿住)。
|
|
280
204
|
const build = (q, inTx) => ({
|
|
281
205
|
get: async (id) => {
|
|
282
206
|
const { rows } = await q.query(`SELECT item_json FROM ${TASK_LIST_ITEM_TABLE} WHERE list_key = $1 AND id = $2${inTx ? " FOR UPDATE" : ""}`, [listKey, id]);
|
|
283
207
|
return rows.length > 0 ? parseItem(rows[0].item_json) : undefined;
|
|
284
208
|
},
|
|
285
209
|
set: async (id, item) => {
|
|
286
|
-
// 身份/引用键拒绝式(复审 F8):行键 id 之外,blob 内的 item.id/owner(工具层 ifOwnerIs 守卫
|
|
287
|
-
// 的比对对象)与 blocks/blockedBy(id 引用)清洗形变会与真实键错位——同落拒绝层;正文
|
|
288
|
-
// (subject/description/metadata)维持内容面 lossy。
|
|
289
210
|
if (pgHasUnstorable(id) ||
|
|
290
211
|
pgHasUnstorable(item.id) ||
|
|
291
212
|
(item.owner !== undefined && pgHasUnstorable(item.owner)) ||
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { WriteBehindCounter } from "./write-behind-counter.js";
|
|
2
2
|
export class TiDBCostQuota {
|
|
3
3
|
counter;
|
|
4
|
-
/** #322:限额=比较参数(行里只有花费);窗长换代经 counter.setWindowMs(桶键语义见那里)。 */
|
|
5
4
|
limitMicroUsd;
|
|
6
5
|
refreshRequested = false;
|
|
7
6
|
refreshIntervalMs;
|
|
@@ -23,7 +22,6 @@ export class TiDBCostQuota {
|
|
|
23
22
|
this.counter.stop();
|
|
24
23
|
}
|
|
25
24
|
check(scopeKey) {
|
|
26
|
-
// 关断哨兵:零 counter 访问、零 SQL(恒构造的代价必须是 0)。
|
|
27
25
|
if (this.limitMicroUsd <= 0)
|
|
28
26
|
return { allowed: true, usedMicroUsd: 0, limitMicroUsd: 0, retryAfterSec: 0 };
|
|
29
27
|
const used = this.counter.used(scopeKey);
|
|
@@ -32,10 +30,9 @@ export class TiDBCostQuota {
|
|
|
32
30
|
}
|
|
33
31
|
add(scopeKey, micro) {
|
|
34
32
|
if (this.limitMicroUsd <= 0)
|
|
35
|
-
return;
|
|
33
|
+
return;
|
|
36
34
|
this.counter.addLocal(scopeKey, micro);
|
|
37
35
|
}
|
|
38
|
-
// write-behind lifecycle (delegated; exposed for the reaper/tests)
|
|
39
36
|
flush() {
|
|
40
37
|
return this.counter.flush();
|
|
41
38
|
}
|