Skip to content

session/replaytest: add multi-backend replay consistency harness#2272

Open
ltyfulan9 wants to merge 4 commits into
trpc-group:mainfrom
ltyfulan9:feat/replay-consistency-harness
Open

session/replaytest: add multi-backend replay consistency harness#2272
ltyfulan9 wants to merge 4 commits into
trpc-group:mainfrom
ltyfulan9:feat/replay-consistency-harness

Conversation

@ltyfulan9

Copy link
Copy Markdown

Summary

  • add a reusable replay consistency harness for Session and Memory backends
  • cover 11 deterministic replay cases, fault injection, concurrent ordering,
    normalization, strict allowed differences, and validated JSON reports
  • provide InMemory and real SQLite backend implementations
  • add an optional oracle-free consensus mode for three or more independent
    backends

Consensus behavior

Consensus mode compares every successful backend pair without assuming that a
named reference implementation is correct. It reports a backend as an outlier
only when exactly one backend disagrees with all others while the remaining
backends agree with each other.

Two-backend disagreements remain ambiguous. Failed or unsupported backends are
excluded from the semantic matrix while retaining explicit execution evidence.

Verification

  • go test ./session/replaytest
  • go test -race ./session/replaytest
  • go test ./session/replaytest -count=20
  • go vet ./session/replaytest
  • go test ./session/...
  • SQLite module: go test ./...
  • SQLite module: go test -race ./...

Closes #2001

@coderabbitai

coderabbitai Bot commented Jul 20, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 9d2e370a-4940-4665-b30c-5de727cb3f37

📥 Commits

Reviewing files that changed from the base of the PR and between 583e908 and 13f7fda.

📒 Files selected for processing (2)
  • session/replaytest/quality_test.go
  • session/replaytest/replaytest_test.go
🚧 Files skipped from review as they are similar to previous changes (1)
  • session/replaytest/quality_test.go

📝 Walkthrough

English

Overview

Adds a reusable session/replaytest harness to verify semantic replay consistency across Session/Memory/Summary/state/Track backends. It defines a deterministic test “matrix” (11 scenarios), runs the same typed steps against multiple backends, normalizes backend-specific identifiers/timestamps/ordering artifacts, injects deterministic faults, and computes structured semantic diffs. It supports both a reference-oracle comparison mode and an oracle-free “consensus” mode for classifying an outlier when ≥3 comparable backends disagree, and emits validated JSON reports with precise diff locators (case, backend pair, session, event index/summary filter key/track name/memory id, and JSON-pointer paths). Includes an InMemory backend adapter plus a CGO-based SQLite integration module with a lightweight matrix test.

Public API and compatibility

New exported Go API surface (new package; no existing APIs changed):

  • Core runner/comparison/reporting
    • type Runner struct{ ... }
    • func (r Runner) Run(ctx context.Context, cases []Case, backends []Backend) (Report, error)
    • func Replay(ctx context.Context, replayCase Case, backend Backend) (Snapshot, error)
    • func Compare(caseName string, baseline, actual Snapshot, allowed []AllowedDiff) ([]Diff, error)
    • func InjectFault(input Snapshot, kind FaultKind) (Snapshot, error)
    • func WriteReport(writer io.Writer, report Report) error
    • func (r Report) IsClean() bool
    • func (r Report) Validate() error
  • Backends and harness fixtures
    • func InMemoryBackend() Backend
    • type DeterministicSummarizer struct{}
      • func (*DeterministicSummarizer) ShouldSummarize(...) bool
      • func (*DeterministicSummarizer) Summarize(...) (string, error)
      • func (*DeterministicSummarizer) SetPrompt(string)
      • func (*DeterministicSummarizer) SetModel(model.Model)
      • func (*DeterministicSummarizer) Metadata() map[string]any
    • func PublicCases() []Case
    • func FullCapabilities() Capabilities
  • Public model types (used for adapters/extension points and report schema)
    • Capabilities: type Capability, type Capabilities, exported capability constants
    • Test definition: type Case, step definitions (type Step, type StepKind, type StateInput, type MemoryInput, type SummaryInput, type TrackInput, type EventInput, type StateScope, etc.)
    • Snapshot/diff: type Snapshot, type Diff, allowed-diff rules (type AllowedDiff, type AllowedRule and constants)
    • Consensus: type ComparisonMode, verdict/types (type ConsensusVerdict, type ConsensusResult, type PairComparison)
    • Reports/faults: type Report, type CaseResult, type FaultKind and exported fault constants

Questions to review:

  • Which of the above types/constants truly need to be exported vs kept internal (especially the large report/diff/allowed-rule model).
  • Whether naming/semantics of capabilities, consensus verdicts, and allowed-diff path rules are stable enough for long-term adapter compatibility.
  • Whether DeterministicSummarizer is intended to be a supported public fixture (and thus should be documented/stabilized) or should be unexported.
  • JSON report schema stability and forward/backward compatibility expectations.

Behavioral and operational risks

  • Normalization risk: Semantic equivalence relies on normalization rules (logical event ids, timestamp presence markers, stable causal/global ordering behavior, memory sorting, summary boundary handling). Too-aggressive normalization or incorrect volatility classification could hide real backend regressions.
  • Consensus correctness risk: Consensus/outlier classification depends on comparable backends and exclusion evidence. If comparable-backend requirements are misapplied or evidence is incomplete/incorrect, an actual outlier could be misclassified or an ambiguity may become an outlier.
  • Allowed-diff masking risk: Over-broad allowed-diff path globs/backend pair matching or numeric tolerance rules may reduce the signal of true differences; malformed allowed-diff rules must be strictly rejected.
  • Concurrency/ordering artifacts: Concurrent branch interleaving is intentionally treated specially (branch-local causal ordering vs global interleaving). Bugs in event grouping or locator derivation could produce misleading diffs.
  • Operational/CI risk: SQLite coverage lives in a separate session/replaytest/sqlite module and depends on CGO + a C compiler; it may be skipped in some CI environments.
  • Maintenance risk: The package introduces a sizable public API and a strict JSON report validator; schema or rule changes will require careful coordination with any external consumers.

Recommended validation

Run (as applicable to your environment):

go test ./session/replaytest/...
go test -race ./session/replaytest/...
go test -count=10 ./session/replaytest/...
go vet ./session/replaytest/...

go test ./...

# SQLite integration (CGO required)
cd session/replaytest/sqlite
CGO_ENABLED=1 go test ./

Specifically verify:

  • All public cases pass on InMemory and produce a clean report where expected.
  • Each FaultKind injection reliably produces blocking diffs with correct locators (event index / summary filter key / track name / memory id / JSON-pointer path).
  • Compare allowed-diff matching works for wildcards and unordered backend-pair rules, and rejects malformed allowed-diff inputs.
  • Consensus mode classification and consensus evidence/exclusion behavior match expectations (including ambiguous/insufficient-backend cases).
  • Report.Validate() and WriteReport() reject malformed/incorrect counters and that JSON round-trip encoding remains stable.

中文

变更概览

新增可复用的 session/replaytest 语义回放一致性测试框架,用于验证不同后端(Session/Memory/Summary/状态/Track)在“语义可见”行为上的一致性。框架定义 11 个确定性测试场景:同一组强类型步骤会在多个后端上执行;随后通过归一化处理后端差异(如逻辑ID、时间戳、排序/并发工件),进行结构化语义差异对比;并支持确定性故障注入。对比模式包含:参考后端(reference oracle)模式与无 oracle 的“共识(consensus)”模式(当 ≥3 个可比较后端出现不一致时,用于识别 outlier)。最终输出带精确定位信息(case/后端对/session/event index/summary filter key/track 名/memory id/json-pointer 路径)的 JSON 报告,并提供校验。包含 InMemory 后端适配实现,以及依赖 CGO 的 SQLite 集成模块(轻量级矩阵测试)。

公共 API 与兼容性

新增一个规模较大的“新包”公共 Go API(未改动既有 API):

  • 核心运行/比较/报告
    • type Runner struct{ ... }
    • func (r Runner) Run(ctx context.Context, cases []Case, backends []Backend) (Report, error)
    • func Replay(ctx context.Context, replayCase Case, backend Backend) (Snapshot, error)
    • func Compare(caseName string, baseline, actual Snapshot, allowed []AllowedDiff) ([]Diff, error)
    • func InjectFault(input Snapshot, kind FaultKind) (Snapshot, error)
    • func WriteReport(writer io.Writer, report Report) error
    • func (r Report) IsClean() bool
    • func (r Report) Validate() error
  • 后端与测试夹具
    • func InMemoryBackend() Backend
    • type DeterministicSummarizer struct{}
      • func (*DeterministicSummarizer) ShouldSummarize(...) bool
      • func (*DeterministicSummarizer) Summarize(...) (string, error)
      • func (*DeterministicSummarizer) SetPrompt(string)
      • func (*DeterministicSummarizer) SetModel(model.Model)
      • func (*DeterministicSummarizer) Metadata() map[string]any
    • func PublicCases() []Case
    • func FullCapabilities() Capabilities
  • 公共数据模型(适配器/扩展点与报告 Schema)
    • 能力系统:type Capabilitytype Capabilities 以及导出的能力常量
    • 测试用例与步骤:type Casetype Steptype StepKindtype StateInputtype MemoryInputtype SummaryInputtype TrackInputtype EventInputtype StateScope
    • Snapshot/差异:type Snapshottype Diff、允许差异规则 type AllowedDiff/type AllowedRule 及常量
    • 共识:type ComparisonModetype ConsensusVerdicttype ConsensusResulttype PairComparison
    • 报告/故障:type Reporttype CaseResulttype FaultKind 及导出的故障常量

建议重点评审问题:

  • 哪些类型/常量是否必须导出(尤其是 report/diff/allowed-rule 这类对象的长期稳定性与对外依赖成本)。
  • 能力(capability)、共识判定(consensus verdict)、允许差异路径规则的命名与语义是否足够“可长期扩展”,并能保证适配器兼容性。
  • DeterministicSummarizer 是否是“面向外部支持的公共夹具”,还是仅内部实现;如对外导出则需补齐文档与稳定性承诺。
  • JSON 报告的 schema 及版本演进策略。

行为与运维风险

  • **归一化风险:**语义等价依赖归一化规则(逻辑事件ID、时间戳 presence 标记、因果/全局排序处理、记忆排序、摘要边界(retained/boundary)处理等)。若归一化过强或“易变字段/稳定字段”划分错误,可能掩盖真实后端回归。
  • **共识正确性风险:**共识(outlier/ambiguous)取决于“可比较后端”与“排除证据”。若证据缺失/不正确或可比较条件不合理,可能误判真实 outlier 或把应当 outlier 的情况判为歧义。
  • **允许差异掩盖风险:**若 allowed-diff 的路径 glob、后端对匹配规则、数值容差规则过宽,可能降低回归发现能力;同时必须严格拒绝畸形 allowed-diff 规则。
  • **并发/排序工件风险:**并发分支交错的处理是有意的(保留分支内因果顺序、忽略全局交错),若事件分组/定位解析有缺陷,可能产生误导性的差异。
  • **运维/CI 风险:**SQLite 测试在 session/replaytest/sqlite 独立模块中,依赖 CGO 与 C 编译器;部分 CI 可能无法运行或需显式启用 CGO。
  • **维护风险:**新增大量公共 API 与严格的报告校验逻辑;规则/Schema 变更会带来较高维护成本。

建议验证

按环境执行:

go test ./session/replaytest/...
go test -race ./session/replaytest/...
go test -count=10 ./session/replaytest/...
go vet ./session/replaytest/...

go test ./...

# SQLite 集成(需要 CGO)
cd session/replaytest/sqlite
CGO_ENABLED=1 go test ./

重点确认:

  • InMemory 通过全部 public case,并在应通过的场景下产生 clean 报告。
  • 每个 FaultKind 注入均能触发阻塞性(blocking)差异,且定位信息准确(event index / summary filter key / track 名 / memory id / JSON-pointer 路径)。
  • Compare 的 allowed-diff 匹配:通配符、无序后端对规则等行为正确;畸形 allowed-diff 输入会被拒绝。
  • 共识模式下:分类结果与排除证据/不足/歧义等规则符合预期。
  • Report.Validate()WriteReport() 能拒绝畸形报告/不一致计数,并且 JSON 往返编码保持 schema 兼容。

Walkthrough

Changes

Replay consistency harness

Layer / File(s) Summary
Replay contracts and public cases
session/replaytest/types.go, cases.go, backend.go, DESIGN.md, README.md
Adds typed backend and case contracts, deterministic services, ten replay scenarios, and semantic comparison documentation.
Replay execution and backend integration
session/replaytest/runner.go, report.go, session/replaytest/sqlite/*
Executes cases across isolated backends, handles capabilities and concurrent branches, emits validated JSON reports, and adds SQLite integration coverage.
Snapshot normalization
session/replaytest/normalize.go
Canonicalizes events, state, memories, summaries, tracks, timestamps, identifiers, and causal ordering.
Semantic comparison and allowed differences
session/replaytest/compare.go, replaytest_test.go, quality_test.go
Adds recursive snapshot comparison, JSON Pointer diffs, locators, numeric tolerance, allowed-diff validation, and report accounting checks.
Consensus classification and validation
session/replaytest/consensus.go, replaytest_test.go, quality_test.go
Adds pairwise consensus verdicts, outlier detection, exclusion evidence, matrix validation, and tamper checks.
Fault injection and validation
session/replaytest/fault.go, tests, testdata
Adds deterministic snapshot faults and coverage for fault detection, lifecycle failures, normalization semantics, and report serialization.

Estimated code review effort: 5 (Critical) | ~120 minutes

Possibly related PRs

Suggested reviewers: winechord

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 6.90% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main change: a multi-backend replay consistency harness.
Description check ✅ Passed The description matches the changeset and covers the harness, consensus mode, backends, and validation work.
Linked Issues check ✅ Passed The PR covers the requested replay harness, 10+ cases, InMemory/SQLite backends, normalization, reports, and tests.
Out of Scope Changes check ✅ Passed The docs, tests, SQLite module, and sample report all support the replay harness; no unrelated changes stand out.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Comment thread session/replaytest/runner.go Outdated
}
close(start)
wg.Wait()
return errors.Join(errs...)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

StepConcurrent leaves e.session stale, so a following summary omits branch events. Reload after successful joins before returning.

中文 StepConcurrent 会让 `e.session` 保持旧状态,因此后续摘要会漏掉分支事件。成功等待所有分支后先重新加载再返回。

Comment thread session/replaytest/sqlite/go.mod Outdated
require (
github.com/mattn/go-sqlite3 v1.14.32
trpc.group/trpc-go/trpc-agent-go v1.6.1-0.20260311094958-7b74ee59e339
trpc.group/trpc-go/trpc-agent-go/memory/sqlite v0.0.0

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The v0.0.0 sibling requirements make this module fail for consumers because dependency replace directives are ignored. Use published sibling versions here.

中文 这些 `v0.0.0` 同级依赖会让消费者构建失败,因为依赖模块中的 replace 会被忽略。这里改用已发布的同级模块版本。

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (1)
session/replaytest/runner.go (1)

29-33: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Document the zero-value contract of Runner's exported fields.

Mode (empty → ComparisonReference), Reference (empty → backends[0].Name in reference mode; must be empty in consensus mode), and Now (nil → time.Now) all carry meaningful default semantics that are currently only discoverable by reading Run. Add per-field Godoc so external consumers can rely on a stable contract.

As per path instructions: "whether defaults, zero values, nil inputs ... are defined where relevant" and "Require exported declaration comments to begin with the declared name and describe the caller-visible contract."

中文

Runner 的导出字段补充零值契约文档。 Mode(空 → ComparisonReference)、Reference(reference 模式下空 → backends[0].Name;consensus 模式下必须为空)、Now(nil → time.Now)都带有重要的默认语义,目前只能通过阅读 Run 才能得知。建议为每个字段添加 Godoc,使外部使用者能依赖稳定契约。

依据 path instructions:需说明默认值/零值/nil 行为,且导出声明注释应以声明名开头并描述调用方可见的契约。

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@session/replaytest/runner.go` around lines 29 - 33, Document each exported
Runner field with Godoc comments beginning with its field name: state that
Mode’s zero value selects ComparisonReference, Reference defaults to
backends[0].Name in reference mode and must be empty in consensus mode, and Now
uses time.Now when nil.

Source: Path instructions

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@session/replaytest/sqlite/factory.go`:
- Around line 89-99: Update openDB to call db.SetMaxOpenConns(1) immediately
after sql.Open succeeds, before db.Ping, so SQLite access uses a single pooled
connection and serializes writers. Preserve the existing error handling and
close behavior.

In `@session/replaytest/sqlite/go.mod`:
- Around line 12-39: Update the go.mod dependency graph so
google.golang.org/grpc resolves to v1.79.3 and go.opentelemetry.io/otel/sdk
resolves to v1.43.0, including any required related module updates. Run go mod
tidy in this module and commit the resulting go.mod/go.sum changes so indirect
dependencies no longer select the vulnerable versions.

---

Nitpick comments:
In `@session/replaytest/runner.go`:
- Around line 29-33: Document each exported Runner field with Godoc comments
beginning with its field name: state that Mode’s zero value selects
ComparisonReference, Reference defaults to backends[0].Name in reference mode
and must be empty in consensus mode, and Now uses time.Now when nil.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: a9ab47d3-0110-4763-b75f-8d5b5ca8f215

📥 Commits

Reviewing files that changed from the base of the PR and between 41d2f05 and 0942c2f.

⛔ Files ignored due to path filters (1)
  • session/replaytest/sqlite/go.sum is excluded by !**/*.sum
📒 Files selected for processing (18)
  • session/replaytest/DESIGN.md
  • session/replaytest/README.md
  • session/replaytest/backend.go
  • session/replaytest/cases.go
  • session/replaytest/compare.go
  • session/replaytest/consensus.go
  • session/replaytest/doc.go
  • session/replaytest/fault.go
  • session/replaytest/normalize.go
  • session/replaytest/replaytest_test.go
  • session/replaytest/report.go
  • session/replaytest/runner.go
  • session/replaytest/sqlite/README.md
  • session/replaytest/sqlite/factory.go
  • session/replaytest/sqlite/go.mod
  • session/replaytest/sqlite/integration_test.go
  • session/replaytest/testdata/session_memory_summary_track_diff_report.json
  • session/replaytest/types.go

Comment thread session/replaytest/sqlite/factory.go Outdated
Comment on lines +89 to +99
func openDB(path string) (*sql.DB, error) {
dsn := "file:" + filepath.ToSlash(path) + "?_busy_timeout=5000&_foreign_keys=on"
db, err := sql.Open("sqlite3", dsn)
if err != nil {
return nil, err
}
if err := db.Ping(); err != nil {
return nil, errors.Join(err, db.Close())
}
return db, nil
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🌐 Web query:

mattn go-sqlite3 database/sql concurrent writes SQLITE_BUSY SetMaxOpenConns(1)

💡 Result:

When using mattn/go-sqlite3, the SQLITE_BUSY (database is locked) error typically occurs because SQLite does not support concurrent write transactions to the same database file [1][2]. While Go's database/sql package manages a connection pool that is safe for concurrent use, SQLite's underlying limitations require specific configuration to handle these collisions effectively [1][3]. The most common and effective strategies to mitigate SQLITE_BUSY are: 1. Use Write-Ahead Logging (WAL) Mode: Configure your database connection to use WAL mode by appending _journal_mode=WAL to your connection string [4][5][2]. This allows multiple readers to operate concurrently with a single writer, significantly reducing locking issues [1][4][5]. 2. Limit Write Connections: Since SQLite does not support concurrent writes, it is highly recommended to throttle your write-side connection pool to a single connection using db.SetMaxOpenConns(1) [1][4][5]. This effectively serializes write access at the application level before it reaches the database [6][3]. 3. Implement a Busy Timeout: Append a _busy_timeout parameter to your connection string (e.g.,?_busy_timeout=5000 for a 5000ms timeout) [7][6][8]. This instructs SQLite to automatically retry lock acquisition for the specified duration before returning a SQLITE_BUSY error [6][9][8]. 4. Use Separate Pools for Reads and Writes: A recommended best practice is to maintain two separate sql.DB instances [1][4][2]: - A Read-Write pool: Throttled to SetMaxOpenConns(1), using _txlock=immediate to start transactions with BEGIN IMMEDIATE, which helps avoid deadlocks [1][4][2]. - A Read-Only pool: Configured for concurrent access as needed, using BEGIN DEFERRED [1][2]. Avoid using cache=shared mode, as it is generally discouraged by SQLite maintainers and can complicate concurrency [4][2]. Always ensure your connection string starts with the file: prefix to correctly interpret these parameters [4][2].

Citations:


Serialize SQLite writers with a single connection.

openDB uses the default database/sql pool, so SQLite can open multiple connections here. The parallel concurrent_interleaving case can then hit SQLITE_BUSY/lock contention even with _busy_timeout; cap the pool with db.SetMaxOpenConns(1) (and enable WAL if parallel reads are needed).

中文

将 SQLite 写入串行化,限制为单连接。

openDB 使用默认的 database/sql 连接池,SQLite 可能因此同时打开多个连接。并行的 concurrent_interleaving 用例会更容易遇到 SQLITE_BUSY/锁竞争,即使设置了 _busy_timeout 也可能受影响;建议用 db.SetMaxOpenConns(1) 限制连接池(如果还需要并发读,可再启用 WAL)。

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@session/replaytest/sqlite/factory.go` around lines 89 - 99, Update openDB to
call db.SetMaxOpenConns(1) immediately after sql.Open succeeds, before db.Ping,
so SQLite access uses a single pooled connection and serializes writers.
Preserve the existing error handling and close behavior.

Comment on lines +12 to +39
require (
github.com/cenkalti/backoff/v4 v4.3.0 // indirect
github.com/go-ego/gse v1.0.0 // indirect
github.com/go-logr/logr v1.4.2 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/grpc-ecosystem/grpc-gateway/v2 v2.22.0 // indirect
github.com/vcaesar/cedar v0.20.2 // indirect
go.opentelemetry.io/otel v1.29.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.29.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.29.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.29.0 // indirect
go.opentelemetry.io/otel/metric v1.29.0 // indirect
go.opentelemetry.io/otel/sdk v1.29.0 // indirect
go.opentelemetry.io/otel/trace v1.29.0 // indirect
go.opentelemetry.io/proto/otlp v1.3.1 // indirect
go.uber.org/multierr v1.10.0 // indirect
go.uber.org/zap v1.27.0 // indirect
golang.org/x/net v0.34.0 // indirect
golang.org/x/sys v0.30.0 // indirect
golang.org/x/text v0.21.0 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20240822170219-fc7c04adadcd // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20240822170219-fc7c04adadcd // indirect
google.golang.org/grpc v1.65.0 // indirect
google.golang.org/protobuf v1.34.2 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
trpc.group/trpc-go/trpc-a2a-go v0.2.5 // indirect
)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔒 Security & Privacy | 🔴 Critical | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
gh api graphql -f query='
{
  grpc: securityVulnerabilities(first: 3, ecosystem: GO, package: "google.golang.org/grpc") {
    nodes { advisory { ghsaId summary severity } firstPatchedVersion { identifier } vulnerableVersionRange }
  }
  otel: securityVulnerabilities(first: 3, ecosystem: GO, package: "go.opentelemetry.io/otel/sdk") {
    nodes { advisory { ghsaId summary severity } firstPatchedVersion { identifier } vulnerableVersionRange }
  }
}'

Repository: trpc-group/trpc-agent-go

Length of output: 1430


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf '\n## session/replaytest/sqlite/go.mod\n'
cat -n session/replaytest/sqlite/go.mod

printf '\n## parent go.mod replace/import context\n'
grep -nE 'replace|google.golang.org/grpc|go.opentelemetry.io/otel/sdk' -n go.mod session/replaytest/sqlite/go.mod || true

printf '\n## files mentioning google.golang.org/grpc or go.opentelemetry.io/otel/sdk\n'
rg -n 'google\.golang\.org/grpc|go\.opentelemetry\.io/otel/sdk' -g 'go.mod' -g '!**/vendor/**' .

printf '\n## module tree for nested replaytest module (if any)\n'
find session/replaytest/sqlite -maxdepth 2 -name go.mod -o -name go.sum | sort

Repository: trpc-group/trpc-agent-go

Length of output: 12903


Bump the vulnerable gRPC/OpenTelemetry pins
google.golang.org/grpc v1.65.0 is in a CRITICAL authorization-bypass range, and go.opentelemetry.io/otel/sdk v1.29.0 is in a HIGH PATH-hijack range. Update the parent module graph to grpc v1.79.3 and otel/sdk v1.43.0, then re-run go mod tidy here so these indirect entries stop pulling the vulnerable versions.

🧰 Tools
🪛 OSV Scanner (2.4.0)

[HIGH] 29-29: go.opentelemetry.io/otel/sdk 1.29.0: OpenTelemetry Go SDK Vulnerable to Arbitrary Code Execution via PATH Hijacking in go.opentelemetry.io/otel/sdk

(GO-2026-4394)


[HIGH] 29-29: go.opentelemetry.io/otel/sdk 1.29.0: OpenTelemetry Go SDK Vulnerable to Arbitrary Code Execution via PATH Hijacking

(GHSA-9h8m-3fm2-qjrq)


[HIGH] 29-29: go.opentelemetry.io/otel/sdk 1.29.0: opentelemetry-go: BSD kenv command not using absolute path enables PATH hijacking

(GHSA-hfvc-g4fc-pqhx)


[CRITICAL] 37-37: google.golang.org/grpc 1.65.0: Authorization bypass in gRPC-Go via missing leading slash in :path in google.golang.org/grpc

(GO-2026-4762)


[CRITICAL] 37-37: google.golang.org/grpc 1.65.0: gRPC-Go has an authorization bypass via missing leading slash in :path

(GHSA-p77j-4mvh-x3m3)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@session/replaytest/sqlite/go.mod` around lines 12 - 39, Update the go.mod
dependency graph so google.golang.org/grpc resolves to v1.79.3 and
go.opentelemetry.io/otel/sdk resolves to v1.43.0, including any required related
module updates. Run go mod tidy in this module and commit the resulting
go.mod/go.sum changes so indirect dependencies no longer select the vulnerable
versions.

Source: Linters/SAST tools

@github-actions

github-actions Bot commented Jul 20, 2026

Copy link
Copy Markdown

All contributors have signed the CLA ✍️ ✅
Posted by the CLA Assistant Lite bot.

@ltyfulan9

Copy link
Copy Markdown
Author

I have read the CLA Document and I hereby sign the CLA

@codecov

codecov Bot commented Jul 20, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 89.07692% with 213 lines in your changes missing coverage. Please review.
✅ Project coverage is 89.85183%. Comparing base (0c77741) to head (13f7fda).

Files with missing lines Patch % Lines
session/replaytest/runner.go 81.84818% 63 Missing and 47 partials ⚠️
session/replaytest/compare.go 87.79343% 34 Missing and 18 partials ⚠️
session/replaytest/normalize.go 86.58537% 19 Missing and 14 partials ⚠️
session/replaytest/fault.go 94.90446% 4 Missing and 4 partials ⚠️
session/replaytest/cases.go 98.45560% 2 Missing and 2 partials ⚠️
session/replaytest/consensus.go 97.71429% 2 Missing and 2 partials ⚠️
session/replaytest/report.go 81.81818% 1 Missing and 1 partial ⚠️
Additional details and impacted files
@@                 Coverage Diff                 @@
##                main       #2272         +/-   ##
===================================================
- Coverage   89.85876%   89.85183%   -0.00693%     
===================================================
  Files           1150        1159          +9     
  Lines         203417      205367       +1950     
===================================================
+ Hits          182788      184526       +1738     
- Misses         12914       13039        +125     
- Partials        7715        7802         +87     
Flag Coverage Δ
unittests 89.85183% <89.07692%> (-0.00693%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Add a typed replay matrix covering 11 session, memory, summary, track, concurrency, and recovery scenarios.

Normalize backend-generated values while preserving causal order and semantic timestamps. Keep the CGO-backed SQLite adapter in a nested module and emit validated JSON diff reports.

Fixes trpc-group#2001

RELEASE NOTES: Added a reusable replay consistency harness for session and memory backends.
Compare successful backend snapshots pairwise without assuming a named reference is correct. Report only conclusive single-backend outliers while preserving ambiguous and insufficient outcomes.

Validate pair matrices, exclusion evidence, status accounting, and reserved paths so generated reports remain internally consistent.
@ltyfulan9
ltyfulan9 force-pushed the feat/replay-consistency-harness branch from 0942c2f to 583e908 Compare July 21, 2026 00:30

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

♻️ Duplicate comments (1)
session/replaytest/sqlite/go.mod (1)

20-25: 🔒 Security & Privacy | 🔴 Critical | ⚡ Quick win

Update the vulnerable indirect dependencies before merging.

go.opentelemetry.io/otel/sdk v1.29.0 is affected by a high-severity PATH-hijacking vulnerability, and google.golang.org/grpc v1.65.0 is affected by a critical authorization-bypass vulnerability. Patched versions are OpenTelemetry v1.40.0+ and gRPC v1.79.3+. (github.com)

Please update the OpenTelemetry module family and gRPC dependency, run go mod tidy, and commit the resulting module graph.

中文

合并前请升级存在漏洞的间接依赖。

go.opentelemetry.io/otel/sdk v1.29.0 受高危 PATH 劫持漏洞影响,google.golang.org/grpc v1.65.0 受严重授权绕过漏洞影响。修复版本分别为 OpenTelemetry v1.40.0+ 和 gRPC v1.79.3+。(github.com)

请升级 OpenTelemetry 模块族和 gRPC 依赖,运行 go mod tidy,并提交更新后的模块依赖图。

Also applies to: 35-35

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@session/replaytest/sqlite/go.mod` around lines 20 - 25, Update the
OpenTelemetry module family currently pinned at v1.29.0 to v1.40.0 or newer, and
upgrade google.golang.org/grpc to v1.79.3 or newer wherever it appears in the
module graph. Run go mod tidy afterward and commit the resulting go.mod and
go.sum dependency updates.

Sources: MCP tools, Linters/SAST tools

🧹 Nitpick comments (1)
session/replaytest/normalize.go (1)

168-176: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Hardcoded "tracks" state key vs. session constants — prefer a shared constant.

This block uses the exported session.StateAppPrefix / session.StateUserPrefix constants but hardcodes the literal "tracks" key. If the session package owns a constant for the tracks state key, use it so this filter can't silently drift out of sync when the owning package changes its internal key.

Verify whether session exposes a constant for this key:

#!/bin/bash
rg -nP 'const|var' --type=go session -g '!**/replaytest/**' | rg -i 'track'
rg -nP '"tracks"' --type=go session -g '!**/replaytest/**' -C2
中文

硬编码的 "tracks" 状态键与 session 常量不一致——建议使用共享常量。

此处已使用导出的 session.StateAppPrefix / session.StateUserPrefix 常量,却把 "tracks" 写成字面量。若 session 包已提供对应的 tracks 状态键常量,请改用它,避免上游内部键更名时此过滤逻辑无声失效。

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@session/replaytest/normalize.go` around lines 168 - 176, Update
normalizeState to replace the hardcoded "tracks" comparison with the existing
exported tracks state-key constant from the session package, after verifying its
exact name. Keep the session.StateAppPrefix and session.StateUserPrefix
filtering unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@session/replaytest/quality_test.go`:
- Line 40: Replace the intentionally invalid "memroy" capability with the same
clearly non-typo literal, such as "not-a-capability", at
session/replaytest/quality_test.go lines 40-40 and
session/replaytest/replaytest_test.go lines 94-94, preserving the
unknown-capability test behavior in both sites.

---

Duplicate comments:
In `@session/replaytest/sqlite/go.mod`:
- Around line 20-25: Update the OpenTelemetry module family currently pinned at
v1.29.0 to v1.40.0 or newer, and upgrade google.golang.org/grpc to v1.79.3 or
newer wherever it appears in the module graph. Run go mod tidy afterward and
commit the resulting go.mod and go.sum dependency updates.

---

Nitpick comments:
In `@session/replaytest/normalize.go`:
- Around line 168-176: Update normalizeState to replace the hardcoded "tracks"
comparison with the existing exported tracks state-key constant from the session
package, after verifying its exact name. Keep the session.StateAppPrefix and
session.StateUserPrefix filtering unchanged.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 58eef773-4a29-48ab-bad8-ec2c58ba352e

📥 Commits

Reviewing files that changed from the base of the PR and between 0942c2f and 583e908.

⛔ Files ignored due to path filters (1)
  • session/replaytest/sqlite/go.sum is excluded by !**/*.sum
📒 Files selected for processing (19)
  • session/replaytest/DESIGN.md
  • session/replaytest/README.md
  • session/replaytest/backend.go
  • session/replaytest/cases.go
  • session/replaytest/compare.go
  • session/replaytest/consensus.go
  • session/replaytest/doc.go
  • session/replaytest/fault.go
  • session/replaytest/normalize.go
  • session/replaytest/quality_test.go
  • session/replaytest/replaytest_test.go
  • session/replaytest/report.go
  • session/replaytest/runner.go
  • session/replaytest/sqlite/README.md
  • session/replaytest/sqlite/factory_test.go
  • session/replaytest/sqlite/go.mod
  • session/replaytest/sqlite/integration_test.go
  • session/replaytest/testdata/session_memory_summary_track_diff_report.json
  • session/replaytest/types.go
🚧 Files skipped from review as they are similar to previous changes (11)
  • session/replaytest/doc.go
  • session/replaytest/report.go
  • session/replaytest/sqlite/README.md
  • session/replaytest/README.md
  • session/replaytest/DESIGN.md
  • session/replaytest/sqlite/integration_test.go
  • session/replaytest/testdata/session_memory_summary_track_diff_report.json
  • session/replaytest/backend.go
  • session/replaytest/consensus.go
  • session/replaytest/fault.go
  • session/replaytest/types.go

Comment thread session/replaytest/quality_test.go Outdated
unknownCapabilityBackend := right
unknownCapabilityBackend.Name = "unknown-capability"
unknownCapabilityBackend.Capabilities = FullCapabilities()
unknownCapabilityBackend.Capabilities["memroy"] = true

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Rename the intentional unknown-capability literal to avoid tripping the typos CI check. Both sites use "memroy" as a deliberately-invalid capability, but it is a near-miss of memory and the CI typos check flags it. A clearly non-typo token (e.g. "not-a-capability") keeps the test intent and keeps the gate green.

  • session/replaytest/quality_test.go#L40: change unknownCapabilityBackend.Capabilities["memroy"] = true to a non-typo capability literal.
  • session/replaytest/replaytest_test.go#L94: change Requires: []Capability{CapabilitySession, "memroy"} to the same non-typo literal.
中文

将故意使用的“未知能力”字面量改名,以避免触发 typos CI 检查。 两处都用 "memroy" 作为故意无效的能力,但它与 memory 极为相近,CI 的 typos 检查会将其标记。改成明显不是拼写错误的标记(如 "not-a-capability")既保留测试意图,又能让检查通过。

  • session/replaytest/quality_test.go#L40:将 Capabilities["memroy"] = true 改为非拼写错误的能力字面量。
  • session/replaytest/replaytest_test.go#L94:将 Requires 中的 "memroy" 改为相同的非拼写错误字面量。
🧰 Tools
🪛 GitHub Check: typos

[warning] 40-40:
"memroy" should be "memory".

📍 Affects 2 files
  • session/replaytest/quality_test.go#L40-L40 (this comment)
  • session/replaytest/replaytest_test.go#L94-L94
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@session/replaytest/quality_test.go` at line 40, Replace the intentionally
invalid "memroy" capability with the same clearly non-typo literal, such as
"not-a-capability", at session/replaytest/quality_test.go lines 40-40 and
session/replaytest/replaytest_test.go lines 94-94, preserving the
unknown-capability test behavior in both sites.

Source: Linters/SAST tools

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

构建 Session / Memory 多后端回放一致性测试框架

3 participants