Compare commits
39
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
30d3296043 | ||
|
|
3578709896 | ||
|
|
f9df94377b | ||
|
|
78c1477198 | ||
|
|
d928a1968a | ||
|
|
027aed1eeb | ||
|
|
26d5529280 | ||
|
|
6fdbd34bab | ||
|
|
52bf0302c6 | ||
|
|
841437fa06 | ||
|
|
9c9a0024d4 | ||
|
|
a6c2d4459c | ||
|
|
da45fa3fb0 | ||
|
|
db0f229285 | ||
|
|
a77c947cd4 | ||
|
|
9a84b3de34 | ||
|
|
7b8c75e571 | ||
|
|
a08672b31e | ||
|
|
6015bcbf6f | ||
|
|
a5b4502c72 | ||
|
|
39c0c5f8be | ||
|
|
1b31e78be5 | ||
|
|
c5e496e715 | ||
|
|
050cbc8fee | ||
|
|
a6afbfaa9d | ||
|
|
0ee27eb523 | ||
|
|
3b62a8940c | ||
|
|
04eb50e2b4 | ||
|
|
7f2e47ca38 | ||
|
|
aa035b828c | ||
|
|
b3315ead52 | ||
|
|
64adb998cf | ||
|
|
ed7efc58b7 | ||
|
|
cf3333d607 | ||
|
|
a375daead7 | ||
|
|
a5a0e0c6be | ||
|
|
9e8e20b3b5 | ||
|
|
3dfe3dbe53 | ||
|
|
37083fc92a |
@@ -0,0 +1,117 @@
|
||||
---
|
||||
name: diagnose
|
||||
description: Disciplined diagnosis loop for hard bugs and performance regressions. Reproduce → minimise → hypothesise → instrument → fix → regression-test. Use when user says "diagnose this" / "debug this", reports a bug, says something is broken/throwing/failing, or describes a performance regression.
|
||||
---
|
||||
|
||||
# Diagnose
|
||||
|
||||
A discipline for hard bugs. Skip phases only when explicitly justified.
|
||||
|
||||
When exploring the codebase, use the project's domain glossary to get a clear mental model of the relevant modules, and check ADRs in the area you're touching.
|
||||
|
||||
## Phase 1 — Build a feedback loop
|
||||
|
||||
**This is the skill.** Everything else is mechanical. If you have a fast, deterministic, agent-runnable pass/fail signal for the bug, you will find the cause — bisection, hypothesis-testing, and instrumentation all just consume that signal. If you don't have one, no amount of staring at code will save you.
|
||||
|
||||
Spend disproportionate effort here. **Be aggressive. Be creative. Refuse to give up.**
|
||||
|
||||
### Ways to construct one — try them in roughly this order
|
||||
|
||||
1. **Failing test** at whatever seam reaches the bug — unit, integration, e2e.
|
||||
2. **Curl / HTTP script** against a running dev server.
|
||||
3. **CLI invocation** with a fixture input, diffing stdout against a known-good snapshot.
|
||||
4. **Headless browser script** (Playwright / Puppeteer) — drives the UI, asserts on DOM/console/network.
|
||||
5. **Replay a captured trace.** Save a real network request / payload / event log to disk; replay it through the code path in isolation.
|
||||
6. **Throwaway harness.** Spin up a minimal subset of the system (one service, mocked deps) that exercises the bug code path with a single function call.
|
||||
7. **Property / fuzz loop.** If the bug is "sometimes wrong output", run 1000 random inputs and look for the failure mode.
|
||||
8. **Bisection harness.** If the bug appeared between two known states (commit, dataset, version), automate "boot at state X, check, repeat" so you can `git bisect run` it.
|
||||
9. **Differential loop.** Run the same input through old-version vs new-version (or two configs) and diff outputs.
|
||||
10. **HITL bash script.** Last resort. If a human must click, drive _them_ with `scripts/hitl-loop.template.sh` so the loop is still structured. Captured output feeds back to you.
|
||||
|
||||
Build the right feedback loop, and the bug is 90% fixed.
|
||||
|
||||
### Iterate on the loop itself
|
||||
|
||||
Treat the loop as a product. Once you have _a_ loop, ask:
|
||||
|
||||
- Can I make it faster? (Cache setup, skip unrelated init, narrow the test scope.)
|
||||
- Can I make the signal sharper? (Assert on the specific symptom, not "didn't crash".)
|
||||
- Can I make it more deterministic? (Pin time, seed RNG, isolate filesystem, freeze network.)
|
||||
|
||||
A 30-second flaky loop is barely better than no loop. A 2-second deterministic loop is a debugging superpower.
|
||||
|
||||
### Non-deterministic bugs
|
||||
|
||||
The goal is not a clean repro but a **higher reproduction rate**. Loop the trigger 100×, parallelise, add stress, narrow timing windows, inject sleeps. A 50%-flake bug is debuggable; 1% is not — keep raising the rate until it's debuggable.
|
||||
|
||||
### When you genuinely cannot build a loop
|
||||
|
||||
Stop and say so explicitly. List what you tried. Ask the user for: (a) access to whatever environment reproduces it, (b) a captured artifact (HAR file, log dump, core dump, screen recording with timestamps), or (c) permission to add temporary production instrumentation. Do **not** proceed to hypothesise without a loop.
|
||||
|
||||
Do not proceed to Phase 2 until you have a loop you believe in.
|
||||
|
||||
## Phase 2 — Reproduce
|
||||
|
||||
Run the loop. Watch the bug appear.
|
||||
|
||||
Confirm:
|
||||
|
||||
- [ ] The loop produces the failure mode the **user** described — not a different failure that happens to be nearby. Wrong bug = wrong fix.
|
||||
- [ ] The failure is reproducible across multiple runs (or, for non-deterministic bugs, reproducible at a high enough rate to debug against).
|
||||
- [ ] You have captured the exact symptom (error message, wrong output, slow timing) so later phases can verify the fix actually addresses it.
|
||||
|
||||
Do not proceed until you reproduce the bug.
|
||||
|
||||
## Phase 3 — Hypothesise
|
||||
|
||||
Generate **3–5 ranked hypotheses** before testing any of them. Single-hypothesis generation anchors on the first plausible idea.
|
||||
|
||||
Each hypothesis must be **falsifiable**: state the prediction it makes.
|
||||
|
||||
> Format: "If <X> is the cause, then <changing Y> will make the bug disappear / <changing Z> will make it worse."
|
||||
|
||||
If you cannot state the prediction, the hypothesis is a vibe — discard or sharpen it.
|
||||
|
||||
**Show the ranked list to the user before testing.** They often have domain knowledge that re-ranks instantly ("we just deployed a change to #3"), or know hypotheses they've already ruled out. Cheap checkpoint, big time saver. Don't block on it — proceed with your ranking if the user is AFK.
|
||||
|
||||
## Phase 4 — Instrument
|
||||
|
||||
Each probe must map to a specific prediction from Phase 3. **Change one variable at a time.**
|
||||
|
||||
Tool preference:
|
||||
|
||||
1. **Debugger / REPL inspection** if the env supports it. One breakpoint beats ten logs.
|
||||
2. **Targeted logs** at the boundaries that distinguish hypotheses.
|
||||
3. Never "log everything and grep".
|
||||
|
||||
**Tag every debug log** with a unique prefix, e.g. `[DEBUG-a4f2]`. Cleanup at the end becomes a single grep. Untagged logs survive; tagged logs die.
|
||||
|
||||
**Perf branch.** For performance regressions, logs are usually wrong. Instead: establish a baseline measurement (timing harness, `performance.now()`, profiler, query plan), then bisect. Measure first, fix second.
|
||||
|
||||
## Phase 5 — Fix + regression test
|
||||
|
||||
Write the regression test **before the fix** — but only if there is a **correct seam** for it.
|
||||
|
||||
A correct seam is one where the test exercises the **real bug pattern** as it occurs at the call site. If the only available seam is too shallow (single-caller test when the bug needs multiple callers, unit test that can't replicate the chain that triggered the bug), a regression test there gives false confidence.
|
||||
|
||||
**If no correct seam exists, that itself is the finding.** Note it. The codebase architecture is preventing the bug from being locked down. Flag this for the next phase.
|
||||
|
||||
If a correct seam exists:
|
||||
|
||||
1. Turn the minimised repro into a failing test at that seam.
|
||||
2. Watch it fail.
|
||||
3. Apply the fix.
|
||||
4. Watch it pass.
|
||||
5. Re-run the Phase 1 feedback loop against the original (un-minimised) scenario.
|
||||
|
||||
## Phase 6 — Cleanup + post-mortem
|
||||
|
||||
Required before declaring done:
|
||||
|
||||
- [ ] Original repro no longer reproduces (re-run the Phase 1 loop)
|
||||
- [ ] Regression test passes (or absence of seam is documented)
|
||||
- [ ] All `[DEBUG-...]` instrumentation removed (`grep` the prefix)
|
||||
- [ ] Throwaway prototypes deleted (or moved to a clearly-marked debug location)
|
||||
- [ ] The hypothesis that turned out correct is stated in the commit / PR message — so the next debugger learns
|
||||
|
||||
**Then ask: what would have prevented this bug?** If the answer involves architectural change (no good test seam, tangled callers, hidden coupling) hand off to the `/improve-codebase-architecture` skill with the specifics. Make the recommendation **after** the fix is in, not before — you have more information now than when you started.
|
||||
@@ -0,0 +1,47 @@
|
||||
# ADR Format
|
||||
|
||||
ADRs live in `docs/adr/` and use sequential numbering: `0001-slug.md`, `0002-slug.md`, etc.
|
||||
|
||||
Create the `docs/adr/` directory lazily — only when the first ADR is needed.
|
||||
|
||||
## Template
|
||||
|
||||
```md
|
||||
# {Short title of the decision}
|
||||
|
||||
{1-3 sentences: what's the context, what did we decide, and why.}
|
||||
```
|
||||
|
||||
That's it. An ADR can be a single paragraph. The value is in recording *that* a decision was made and *why* — not in filling out sections.
|
||||
|
||||
## Optional sections
|
||||
|
||||
Only include these when they add genuine value. Most ADRs won't need them.
|
||||
|
||||
- **Status** frontmatter (`proposed | accepted | deprecated | superseded by ADR-NNNN`) — useful when decisions are revisited
|
||||
- **Considered Options** — only when the rejected alternatives are worth remembering
|
||||
- **Consequences** — only when non-obvious downstream effects need to be called out
|
||||
|
||||
## Numbering
|
||||
|
||||
Scan `docs/adr/` for the highest existing number and increment by one.
|
||||
|
||||
## When to offer an ADR
|
||||
|
||||
All three of these must be true:
|
||||
|
||||
1. **Hard to reverse** — the cost of changing your mind later is meaningful
|
||||
2. **Surprising without context** — a future reader will look at the code and wonder "why on earth did they do it this way?"
|
||||
3. **The result of a real trade-off** — there were genuine alternatives and you picked one for specific reasons
|
||||
|
||||
If a decision is easy to reverse, skip it — you'll just reverse it. If it's not surprising, nobody will wonder why. If there was no real alternative, there's nothing to record beyond "we did the obvious thing."
|
||||
|
||||
### What qualifies
|
||||
|
||||
- **Architectural shape.** "We're using a monorepo." "The write model is event-sourced, the read model is projected into Postgres."
|
||||
- **Integration patterns between contexts.** "Ordering and Billing communicate via domain events, not synchronous HTTP."
|
||||
- **Technology choices that carry lock-in.** Database, message bus, auth provider, deployment target. Not every library — just the ones that would take a quarter to swap out.
|
||||
- **Boundary and scope decisions.** "Customer data is owned by the Customer context; other contexts reference it by ID only." The explicit no-s are as valuable as the yes-s.
|
||||
- **Deliberate deviations from the obvious path.** "We're using manual SQL instead of an ORM because X." Anything where a reasonable reader would assume the opposite. These stop the next engineer from "fixing" something that was deliberate.
|
||||
- **Constraints not visible in the code.** "We can't use AWS because of compliance requirements." "Response times must be under 200ms because of the partner API contract."
|
||||
- **Rejected alternatives when the rejection is non-obvious.** If you considered GraphQL and picked REST for subtle reasons, record it — otherwise someone will suggest GraphQL again in six months.
|
||||
@@ -0,0 +1,77 @@
|
||||
# CONTEXT.md Format
|
||||
|
||||
## Structure
|
||||
|
||||
```md
|
||||
# {Context Name}
|
||||
|
||||
{One or two sentence description of what this context is and why it exists.}
|
||||
|
||||
## Language
|
||||
|
||||
**Order**:
|
||||
{A concise description of the term}
|
||||
_Avoid_: Purchase, transaction
|
||||
|
||||
**Invoice**:
|
||||
A request for payment sent to a customer after delivery.
|
||||
_Avoid_: Bill, payment request
|
||||
|
||||
**Customer**:
|
||||
A person or organization that places orders.
|
||||
_Avoid_: Client, buyer, account
|
||||
|
||||
## Relationships
|
||||
|
||||
- An **Order** produces one or more **Invoices**
|
||||
- An **Invoice** belongs to exactly one **Customer**
|
||||
|
||||
## Example dialogue
|
||||
|
||||
> **Dev:** "When a **Customer** places an **Order**, do we create the **Invoice** immediately?"
|
||||
> **Domain expert:** "No — an **Invoice** is only generated once a **Fulfillment** is confirmed."
|
||||
|
||||
## Flagged ambiguities
|
||||
|
||||
- "account" was used to mean both **Customer** and **User** — resolved: these are distinct concepts.
|
||||
```
|
||||
|
||||
## Rules
|
||||
|
||||
- **Be opinionated.** When multiple words exist for the same concept, pick the best one and list the others as aliases to avoid.
|
||||
- **Flag conflicts explicitly.** If a term is used ambiguously, call it out in "Flagged ambiguities" with a clear resolution.
|
||||
- **Keep definitions tight.** One sentence max. Define what it IS, not what it does.
|
||||
- **Show relationships.** Use bold term names and express cardinality where obvious.
|
||||
- **Only include terms specific to this project's context.** General programming concepts (timeouts, error types, utility patterns) don't belong even if the project uses them extensively. Before adding a term, ask: is this a concept unique to this context, or a general programming concept? Only the former belongs.
|
||||
- **Group terms under subheadings** when natural clusters emerge. If all terms belong to a single cohesive area, a flat list is fine.
|
||||
- **Write an example dialogue.** A conversation between a dev and a domain expert that demonstrates how the terms interact naturally and clarifies boundaries between related concepts.
|
||||
|
||||
## Single vs multi-context repos
|
||||
|
||||
**Single context (most repos):** One `CONTEXT.md` at the repo root.
|
||||
|
||||
**Multiple contexts:** A `CONTEXT-MAP.md` at the repo root lists the contexts, where they live, and how they relate to each other:
|
||||
|
||||
```md
|
||||
# Context Map
|
||||
|
||||
## Contexts
|
||||
|
||||
- [Ordering](./src/ordering/CONTEXT.md) — receives and tracks customer orders
|
||||
- [Billing](./src/billing/CONTEXT.md) — generates invoices and processes payments
|
||||
- [Fulfillment](./src/fulfillment/CONTEXT.md) — manages warehouse picking and shipping
|
||||
|
||||
## Relationships
|
||||
|
||||
- **Ordering → Fulfillment**: Ordering emits `OrderPlaced` events; Fulfillment consumes them to start picking
|
||||
- **Fulfillment → Billing**: Fulfillment emits `ShipmentDispatched` events; Billing consumes them to generate invoices
|
||||
- **Ordering ↔ Billing**: Shared types for `CustomerId` and `Money`
|
||||
```
|
||||
|
||||
The skill infers which structure applies:
|
||||
|
||||
- If `CONTEXT-MAP.md` exists, read it to find contexts
|
||||
- If only a root `CONTEXT.md` exists, single context
|
||||
- If neither exists, create a root `CONTEXT.md` lazily when the first term is resolved
|
||||
|
||||
When multiple contexts exist, infer which one the current topic relates to. If unclear, ask.
|
||||
@@ -0,0 +1,88 @@
|
||||
---
|
||||
name: grill-with-docs
|
||||
description: Grilling session that challenges your plan against the existing domain model, sharpens terminology, and updates documentation (CONTEXT.md, ADRs) inline as decisions crystallise. Use when user wants to stress-test a plan against their project's language and documented decisions.
|
||||
---
|
||||
|
||||
<what-to-do>
|
||||
|
||||
Interview me relentlessly about every aspect of this plan until we reach a shared understanding. Walk down each branch of the design tree, resolving dependencies between decisions one-by-one. For each question, provide your recommended answer.
|
||||
|
||||
Ask the questions one at a time, waiting for feedback on each question before continuing.
|
||||
|
||||
If a question can be answered by exploring the codebase, explore the codebase instead.
|
||||
|
||||
</what-to-do>
|
||||
|
||||
<supporting-info>
|
||||
|
||||
## Domain awareness
|
||||
|
||||
During codebase exploration, also look for existing documentation:
|
||||
|
||||
### File structure
|
||||
|
||||
Most repos have a single context:
|
||||
|
||||
```
|
||||
/
|
||||
├── CONTEXT.md
|
||||
├── docs/
|
||||
│ └── adr/
|
||||
│ ├── 0001-event-sourced-orders.md
|
||||
│ └── 0002-postgres-for-write-model.md
|
||||
└── src/
|
||||
```
|
||||
|
||||
If a `CONTEXT-MAP.md` exists at the root, the repo has multiple contexts. The map points to where each one lives:
|
||||
|
||||
```
|
||||
/
|
||||
├── CONTEXT-MAP.md
|
||||
├── docs/
|
||||
│ └── adr/ ← system-wide decisions
|
||||
├── src/
|
||||
│ ├── ordering/
|
||||
│ │ ├── CONTEXT.md
|
||||
│ │ └── docs/adr/ ← context-specific decisions
|
||||
│ └── billing/
|
||||
│ ├── CONTEXT.md
|
||||
│ └── docs/adr/
|
||||
```
|
||||
|
||||
Create files lazily — only when you have something to write. If no `CONTEXT.md` exists, create one when the first term is resolved. If no `docs/adr/` exists, create it when the first ADR is needed.
|
||||
|
||||
## During the session
|
||||
|
||||
### Challenge against the glossary
|
||||
|
||||
When the user uses a term that conflicts with the existing language in `CONTEXT.md`, call it out immediately. "Your glossary defines 'cancellation' as X, but you seem to mean Y — which is it?"
|
||||
|
||||
### Sharpen fuzzy language
|
||||
|
||||
When the user uses vague or overloaded terms, propose a precise canonical term. "You're saying 'account' — do you mean the Customer or the User? Those are different things."
|
||||
|
||||
### Discuss concrete scenarios
|
||||
|
||||
When domain relationships are being discussed, stress-test them with specific scenarios. Invent scenarios that probe edge cases and force the user to be precise about the boundaries between concepts.
|
||||
|
||||
### Cross-reference with code
|
||||
|
||||
When the user states how something works, check whether the code agrees. If you find a contradiction, surface it: "Your code cancels entire Orders, but you just said partial cancellation is possible — which is right?"
|
||||
|
||||
### Update CONTEXT.md inline
|
||||
|
||||
When a term is resolved, update `CONTEXT.md` right there. Don't batch these up — capture them as they happen. Use the format in [CONTEXT-FORMAT.md](./CONTEXT-FORMAT.md).
|
||||
|
||||
`CONTEXT.md` should be totally devoid of implementation details. Do not treat `CONTEXT.md` as a spec, a scratch pad, or a repository for implementation decisions. It is a glossary and nothing else.
|
||||
|
||||
### Offer ADRs sparingly
|
||||
|
||||
Only offer to create an ADR when all three are true:
|
||||
|
||||
1. **Hard to reverse** — the cost of changing your mind later is meaningful
|
||||
2. **Surprising without context** — a future reader will wonder "why did they do it this way?"
|
||||
3. **The result of a real trade-off** — there were genuine alternatives and you picked one for specific reasons
|
||||
|
||||
If any of the three is missing, skip the ADR. Use the format in [ADR-FORMAT.md](./ADR-FORMAT.md).
|
||||
|
||||
</supporting-info>
|
||||
@@ -0,0 +1,109 @@
|
||||
---
|
||||
name: tdd
|
||||
description: Test-driven development with red-green-refactor loop. Use when user wants to build features or fix bugs using TDD, mentions "red-green-refactor", wants integration tests, or asks for test-first development.
|
||||
---
|
||||
|
||||
# Test-Driven Development
|
||||
|
||||
## Philosophy
|
||||
|
||||
**Core principle**: Tests should verify behavior through public interfaces, not implementation details. Code can change entirely; tests shouldn't.
|
||||
|
||||
**Good tests** are integration-style: they exercise real code paths through public APIs. They describe _what_ the system does, not _how_ it does it. A good test reads like a specification - "user can checkout with valid cart" tells you exactly what capability exists. These tests survive refactors because they don't care about internal structure.
|
||||
|
||||
**Bad tests** are coupled to implementation. They mock internal collaborators, test private methods, or verify through external means (like querying a database directly instead of using the interface). The warning sign: your test breaks when you refactor, but behavior hasn't changed. If you rename an internal function and tests fail, those tests were testing implementation, not behavior.
|
||||
|
||||
See [tests.md](tests.md) for examples and [mocking.md](mocking.md) for mocking guidelines.
|
||||
|
||||
## Anti-Pattern: Horizontal Slices
|
||||
|
||||
**DO NOT write all tests first, then all implementation.** This is "horizontal slicing" - treating RED as "write all tests" and GREEN as "write all code."
|
||||
|
||||
This produces **crap tests**:
|
||||
|
||||
- Tests written in bulk test _imagined_ behavior, not _actual_ behavior
|
||||
- You end up testing the _shape_ of things (data structures, function signatures) rather than user-facing behavior
|
||||
- Tests become insensitive to real changes - they pass when behavior breaks, fail when behavior is fine
|
||||
- You outrun your headlights, committing to test structure before understanding the implementation
|
||||
|
||||
**Correct approach**: Vertical slices via tracer bullets. One test → one implementation → repeat. Each test responds to what you learned from the previous cycle. Because you just wrote the code, you know exactly what behavior matters and how to verify it.
|
||||
|
||||
```
|
||||
WRONG (horizontal):
|
||||
RED: test1, test2, test3, test4, test5
|
||||
GREEN: impl1, impl2, impl3, impl4, impl5
|
||||
|
||||
RIGHT (vertical):
|
||||
RED→GREEN: test1→impl1
|
||||
RED→GREEN: test2→impl2
|
||||
RED→GREEN: test3→impl3
|
||||
...
|
||||
```
|
||||
|
||||
## Workflow
|
||||
|
||||
### 1. Planning
|
||||
|
||||
When exploring the codebase, use the project's domain glossary so that test names and interface vocabulary match the project's language, and respect ADRs in the area you're touching.
|
||||
|
||||
Before writing any code:
|
||||
|
||||
- [ ] Confirm with user what interface changes are needed
|
||||
- [ ] Confirm with user which behaviors to test (prioritize)
|
||||
- [ ] Identify opportunities for [deep modules](deep-modules.md) (small interface, deep implementation)
|
||||
- [ ] Design interfaces for [testability](interface-design.md)
|
||||
- [ ] List the behaviors to test (not implementation steps)
|
||||
- [ ] Get user approval on the plan
|
||||
|
||||
Ask: "What should the public interface look like? Which behaviors are most important to test?"
|
||||
|
||||
**You can't test everything.** Confirm with the user exactly which behaviors matter most. Focus testing effort on critical paths and complex logic, not every possible edge case.
|
||||
|
||||
### 2. Tracer Bullet
|
||||
|
||||
Write ONE test that confirms ONE thing about the system:
|
||||
|
||||
```
|
||||
RED: Write test for first behavior → test fails
|
||||
GREEN: Write minimal code to pass → test passes
|
||||
```
|
||||
|
||||
This is your tracer bullet - proves the path works end-to-end.
|
||||
|
||||
### 3. Incremental Loop
|
||||
|
||||
For each remaining behavior:
|
||||
|
||||
```
|
||||
RED: Write next test → fails
|
||||
GREEN: Minimal code to pass → passes
|
||||
```
|
||||
|
||||
Rules:
|
||||
|
||||
- One test at a time
|
||||
- Only enough code to pass current test
|
||||
- Don't anticipate future tests
|
||||
- Keep tests focused on observable behavior
|
||||
|
||||
### 4. Refactor
|
||||
|
||||
After all tests pass, look for [refactor candidates](refactoring.md):
|
||||
|
||||
- [ ] Extract duplication
|
||||
- [ ] Deepen modules (move complexity behind simple interfaces)
|
||||
- [ ] Apply SOLID principles where natural
|
||||
- [ ] Consider what new code reveals about existing code
|
||||
- [ ] Run tests after each refactor step
|
||||
|
||||
**Never refactor while RED.** Get to GREEN first.
|
||||
|
||||
## Checklist Per Cycle
|
||||
|
||||
```
|
||||
[ ] Test describes behavior, not implementation
|
||||
[ ] Test uses public interface only
|
||||
[ ] Test would survive internal refactor
|
||||
[ ] Code is minimal for this test
|
||||
[ ] No speculative features added
|
||||
```
|
||||
@@ -0,0 +1,33 @@
|
||||
# Deep Modules
|
||||
|
||||
From "A Philosophy of Software Design":
|
||||
|
||||
**Deep module** = small interface + lots of implementation
|
||||
|
||||
```
|
||||
┌─────────────────────┐
|
||||
│ Small Interface │ ← Few methods, simple params
|
||||
├─────────────────────┤
|
||||
│ │
|
||||
│ │
|
||||
│ Deep Implementation│ ← Complex logic hidden
|
||||
│ │
|
||||
│ │
|
||||
└─────────────────────┘
|
||||
```
|
||||
|
||||
**Shallow module** = large interface + little implementation (avoid)
|
||||
|
||||
```
|
||||
┌─────────────────────────────────┐
|
||||
│ Large Interface │ ← Many methods, complex params
|
||||
├─────────────────────────────────┤
|
||||
│ Thin Implementation │ ← Just passes through
|
||||
└─────────────────────────────────┘
|
||||
```
|
||||
|
||||
When designing interfaces, ask:
|
||||
|
||||
- Can I reduce the number of methods?
|
||||
- Can I simplify the parameters?
|
||||
- Can I hide more complexity inside?
|
||||
@@ -0,0 +1,31 @@
|
||||
# Interface Design for Testability
|
||||
|
||||
Good interfaces make testing natural:
|
||||
|
||||
1. **Accept dependencies, don't create them**
|
||||
|
||||
```typescript
|
||||
// Testable
|
||||
function processOrder(order, paymentGateway) {}
|
||||
|
||||
// Hard to test
|
||||
function processOrder(order) {
|
||||
const gateway = new StripeGateway();
|
||||
}
|
||||
```
|
||||
|
||||
2. **Return results, don't produce side effects**
|
||||
|
||||
```typescript
|
||||
// Testable
|
||||
function calculateDiscount(cart): Discount {}
|
||||
|
||||
// Hard to test
|
||||
function applyDiscount(cart): void {
|
||||
cart.total -= discount;
|
||||
}
|
||||
```
|
||||
|
||||
3. **Small surface area**
|
||||
- Fewer methods = fewer tests needed
|
||||
- Fewer params = simpler test setup
|
||||
@@ -0,0 +1,59 @@
|
||||
# When to Mock
|
||||
|
||||
Mock at **system boundaries** only:
|
||||
|
||||
- External APIs (payment, email, etc.)
|
||||
- Databases (sometimes - prefer test DB)
|
||||
- Time/randomness
|
||||
- File system (sometimes)
|
||||
|
||||
Don't mock:
|
||||
|
||||
- Your own classes/modules
|
||||
- Internal collaborators
|
||||
- Anything you control
|
||||
|
||||
## Designing for Mockability
|
||||
|
||||
At system boundaries, design interfaces that are easy to mock:
|
||||
|
||||
**1. Use dependency injection**
|
||||
|
||||
Pass external dependencies in rather than creating them internally:
|
||||
|
||||
```typescript
|
||||
// Easy to mock
|
||||
function processPayment(order, paymentClient) {
|
||||
return paymentClient.charge(order.total);
|
||||
}
|
||||
|
||||
// Hard to mock
|
||||
function processPayment(order) {
|
||||
const client = new StripeClient(process.env.STRIPE_KEY);
|
||||
return client.charge(order.total);
|
||||
}
|
||||
```
|
||||
|
||||
**2. Prefer SDK-style interfaces over generic fetchers**
|
||||
|
||||
Create specific functions for each external operation instead of one generic function with conditional logic:
|
||||
|
||||
```typescript
|
||||
// GOOD: Each function is independently mockable
|
||||
const api = {
|
||||
getUser: (id) => fetch(`/users/${id}`),
|
||||
getOrders: (userId) => fetch(`/users/${userId}/orders`),
|
||||
createOrder: (data) => fetch('/orders', { method: 'POST', body: data }),
|
||||
};
|
||||
|
||||
// BAD: Mocking requires conditional logic inside the mock
|
||||
const api = {
|
||||
fetch: (endpoint, options) => fetch(endpoint, options),
|
||||
};
|
||||
```
|
||||
|
||||
The SDK approach means:
|
||||
- Each mock returns one specific shape
|
||||
- No conditional logic in test setup
|
||||
- Easier to see which endpoints a test exercises
|
||||
- Type safety per endpoint
|
||||
@@ -0,0 +1,10 @@
|
||||
# Refactor Candidates
|
||||
|
||||
After TDD cycle, look for:
|
||||
|
||||
- **Duplication** → Extract function/class
|
||||
- **Long methods** → Break into private helpers (keep tests on public interface)
|
||||
- **Shallow modules** → Combine or deepen
|
||||
- **Feature envy** → Move logic to where data lives
|
||||
- **Primitive obsession** → Introduce value objects
|
||||
- **Existing code** the new code reveals as problematic
|
||||
@@ -0,0 +1,61 @@
|
||||
# Good and Bad Tests
|
||||
|
||||
## Good Tests
|
||||
|
||||
**Integration-style**: Test through real interfaces, not mocks of internal parts.
|
||||
|
||||
```typescript
|
||||
// GOOD: Tests observable behavior
|
||||
test("user can checkout with valid cart", async () => {
|
||||
const cart = createCart();
|
||||
cart.add(product);
|
||||
const result = await checkout(cart, paymentMethod);
|
||||
expect(result.status).toBe("confirmed");
|
||||
});
|
||||
```
|
||||
|
||||
Characteristics:
|
||||
|
||||
- Tests behavior users/callers care about
|
||||
- Uses public API only
|
||||
- Survives internal refactors
|
||||
- Describes WHAT, not HOW
|
||||
- One logical assertion per test
|
||||
|
||||
## Bad Tests
|
||||
|
||||
**Implementation-detail tests**: Coupled to internal structure.
|
||||
|
||||
```typescript
|
||||
// BAD: Tests implementation details
|
||||
test("checkout calls paymentService.process", async () => {
|
||||
const mockPayment = jest.mock(paymentService);
|
||||
await checkout(cart, payment);
|
||||
expect(mockPayment.process).toHaveBeenCalledWith(cart.total);
|
||||
});
|
||||
```
|
||||
|
||||
Red flags:
|
||||
|
||||
- Mocking internal collaborators
|
||||
- Testing private methods
|
||||
- Asserting on call counts/order
|
||||
- Test breaks when refactoring without behavior change
|
||||
- Test name describes HOW not WHAT
|
||||
- Verifying through external means instead of interface
|
||||
|
||||
```typescript
|
||||
// BAD: Bypasses interface to verify
|
||||
test("createUser saves to database", async () => {
|
||||
await createUser({ name: "Alice" });
|
||||
const row = await db.query("SELECT * FROM users WHERE name = ?", ["Alice"]);
|
||||
expect(row).toBeDefined();
|
||||
});
|
||||
|
||||
// GOOD: Verifies through interface
|
||||
test("createUser makes user retrievable", async () => {
|
||||
const user = await createUser({ name: "Alice" });
|
||||
const retrieved = await getUser(user.id);
|
||||
expect(retrieved.name).toBe("Alice");
|
||||
});
|
||||
```
|
||||
@@ -0,0 +1,76 @@
|
||||
---
|
||||
name: to-prd
|
||||
description: Turn the current conversation context into a PRD and publish it to the project issue tracker. Use when user wants to create a PRD from the current context.
|
||||
---
|
||||
|
||||
This skill takes the current conversation context and codebase understanding and produces a PRD. Do NOT interview the user — just synthesize what you already know.
|
||||
|
||||
The issue tracker and triage label vocabulary should have been provided to you — run `/setup-matt-pocock-skills` if not.
|
||||
|
||||
## Process
|
||||
|
||||
1. Explore the repo to understand the current state of the codebase, if you haven't already. Use the project's domain glossary vocabulary throughout the PRD, and respect any ADRs in the area you're touching.
|
||||
|
||||
2. Sketch out the major modules you will need to build or modify to complete the implementation. Actively look for opportunities to extract deep modules that can be tested in isolation.
|
||||
|
||||
A deep module (as opposed to a shallow module) is one which encapsulates a lot of functionality in a simple, testable interface which rarely changes.
|
||||
|
||||
Check with the user that these modules match their expectations. Check with the user which modules they want tests written for.
|
||||
|
||||
3. Write the PRD using the template below, then publish it to the project issue tracker. Apply the `ready-for-agent` triage label - no need for additional triage.
|
||||
|
||||
<prd-template>
|
||||
|
||||
## Problem Statement
|
||||
|
||||
The problem that the user is facing, from the user's perspective.
|
||||
|
||||
## Solution
|
||||
|
||||
The solution to the problem, from the user's perspective.
|
||||
|
||||
## User Stories
|
||||
|
||||
A LONG, numbered list of user stories. Each user story should be in the format of:
|
||||
|
||||
1. As an <actor>, I want a <feature>, so that <benefit>
|
||||
|
||||
<user-story-example>
|
||||
1. As a mobile bank customer, I want to see balance on my accounts, so that I can make better informed decisions about my spending
|
||||
</user-story-example>
|
||||
|
||||
This list of user stories should be extremely extensive and cover all aspects of the feature.
|
||||
|
||||
## Implementation Decisions
|
||||
|
||||
A list of implementation decisions that were made. This can include:
|
||||
|
||||
- The modules that will be built/modified
|
||||
- The interfaces of those modules that will be modified
|
||||
- Technical clarifications from the developer
|
||||
- Architectural decisions
|
||||
- Schema changes
|
||||
- API contracts
|
||||
- Specific interactions
|
||||
|
||||
Do NOT include specific file paths or code snippets. They may end up being outdated very quickly.
|
||||
|
||||
Exception: if a prototype produced a snippet that encodes a decision more precisely than prose can (state machine, reducer, schema, type shape), inline it within the relevant decision and note briefly that it came from a prototype. Trim to the decision-rich parts — not a working demo, just the important bits.
|
||||
|
||||
## Testing Decisions
|
||||
|
||||
A list of testing decisions that were made. Include:
|
||||
|
||||
- A description of what makes a good test (only test external behavior, not implementation details)
|
||||
- Which modules will be tested
|
||||
- Prior art for the tests (i.e. similar types of tests in the codebase)
|
||||
|
||||
## Out of Scope
|
||||
|
||||
A description of the things that are out of scope for this PRD.
|
||||
|
||||
## Further Notes
|
||||
|
||||
Any further notes about the feature.
|
||||
|
||||
</prd-template>
|
||||
@@ -0,0 +1,7 @@
|
||||
---
|
||||
name: zoom-out
|
||||
description: Tell the agent to zoom out and give broader context or a higher-level perspective. Use when you're unfamiliar with a section of code or need to understand how it fits into the bigger picture.
|
||||
disable-model-invocation: true
|
||||
---
|
||||
|
||||
I don't know this area of code well. Go up a layer of abstraction. Give me a map of all the relevant modules and callers, using the project's domain glossary vocabulary.
|
||||
@@ -0,0 +1,13 @@
|
||||
root = true
|
||||
|
||||
[*]
|
||||
charset = utf-8
|
||||
end_of_line = crlf
|
||||
insert_final_newline = true
|
||||
trim_trailing_whitespace = true
|
||||
|
||||
[*.md]
|
||||
trim_trailing_whitespace = false
|
||||
|
||||
[*.{java,xml,yml,yaml,properties,json,sql,txt,ps1}]
|
||||
charset = utf-8
|
||||
@@ -49,7 +49,6 @@ uploads/
|
||||
|
||||
### Temp Scripts ###
|
||||
*.sh
|
||||
*.py
|
||||
|
||||
### docker
|
||||
/volumes
|
||||
|
||||
@@ -1,43 +1,107 @@
|
||||
<!-- gitnexus:start -->
|
||||
# GitNexus — Code Intelligence
|
||||
# CLAUDE.md
|
||||
|
||||
## Defaults
|
||||
|
||||
- Reply in **Chinese** unless I explicitly ask for English.
|
||||
- No emojis.
|
||||
- Do not truncate important outputs (logs, diffs, stack traces, commands, or critical reasoning that affects
|
||||
safety/correctness).
|
||||
|
||||
## Refactor policy (legacy code)
|
||||
|
||||
- When existing code is a "big ball of mud" (hard to maintain, clearly bad design,
|
||||
full of hacks), prefer a **clean, full refactor** over stacking more patches
|
||||
on top of it.
|
||||
- A refactor may completely replace internal structure
|
||||
(functions, modules, classes, data flow).
|
||||
- By default, try to preserve externally observable behaviour.
|
||||
If you intentionally change behaviour or protocols, you MUST:
|
||||
- Call out clearly that this is a **behaviour/protocol change**.
|
||||
- Explain why the change is necessary and which code paths/consumers are affected.
|
||||
- Update or add tests to cover the new behaviour.
|
||||
|
||||
## Before touching code (mandatory)
|
||||
|
||||
Find reuse opportunities + Trace the call/dependency chain and impact radius:
|
||||
|
||||
- Use semantic code search first via `codebase-retrieval` tool.
|
||||
- Confirm understanding with LSP: `goToDefinition`, `findReferences`.
|
||||
- Use Grep/Glob for verifying and understanding additional code snippets.
|
||||
|
||||
## Red lines
|
||||
|
||||
- No copy-paste duplication.
|
||||
- Do not break existing externally observable behaviour **unless**:
|
||||
- It is part of a deliberate refactor as described in the refactor policy, and
|
||||
- You clearly document the behavioural change and its impact.
|
||||
- Do not proceed with a known-wrong approach.
|
||||
- Critical paths must have explicit error handling.
|
||||
- Never implement "blindly": always confirm understanding via code reading + references.
|
||||
|
||||
## Task sizing
|
||||
|
||||
- **Simple**
|
||||
- Criteria — single file, clear requirement, < 20 lines changed,
|
||||
clearly local impact.
|
||||
- Handling — after doing the "Before touching code" steps
|
||||
(research + impact analysis + internal three-question checklist),
|
||||
you may execute directly with minimal explanation.
|
||||
- A very short context line is enough;
|
||||
a full breakdown of the checklist is not required.
|
||||
|
||||
- **Medium**
|
||||
- Criteria — 2–5 files, or requires some research, or impact is not obviously local.
|
||||
- Handling — write a short plan (bullet points) → then implement.
|
||||
- Briefly surface the checklist result in the reply
|
||||
(1–3 short lines describing real issue, key reuse, and main impact).
|
||||
|
||||
- **Complex**
|
||||
- Criteria — architecture changes, multiple modules, high uncertainty or risk.
|
||||
- Handling — follow this workflow:
|
||||
1. **RESEARCH**: inspect code and facts only (no proposals yet).
|
||||
2. **PLAN**: present options + tradeoffs + recommendation;
|
||||
use `AskUserQuestion` actively to align with the user;
|
||||
wait for user's confirmation.
|
||||
3. **EXECUTE**: implement exactly the approved plan.
|
||||
4. **REVIEW**: self-check (tests, edge cases, cleanup).
|
||||
|
||||
## Git
|
||||
|
||||
- Do not commit unless I explicitly ask.
|
||||
- Do not push unless I explicitly ask.
|
||||
- Before writing a commit message, glance at a few recent commits and match the repo's style:
|
||||
- `git log -n 5 --oneline`
|
||||
- If there is no obvious existing style, use this default format:
|
||||
- `<type>(<scope>): <description>`
|
||||
- Before any commit: run `git diff` and confirm the exact scope of changes.
|
||||
- Never force-push to `main` / `master` unless the user approves.
|
||||
- Do not add attribution lines in commit messages.
|
||||
|
||||
## Security
|
||||
|
||||
- Never hardcode secrets (keys/passwords/tokens).
|
||||
- Never commit `.env` files or any credentials.
|
||||
- Validate user input at trust boundaries (APIs, CLIs, external data sources).
|
||||
|
||||
## Quality & cleanup
|
||||
|
||||
- Prefer clarity and simplicity first (KISS); apply DRY to remove obvious
|
||||
copy-paste duplication when it does not hurt readability.
|
||||
- If you change a function signature, update **all** call sites.
|
||||
- After changes:
|
||||
- Remove temporary files.
|
||||
- Remove dead/commented-out code.
|
||||
- Remove unused imports.
|
||||
- Remove debug logging that is no longer needed.
|
||||
- Run the smallest meaningful verification (lint/test/build) for the parts you touched.
|
||||
|
||||
## Windows / PowerShell (if used)
|
||||
|
||||
- PowerShell does not support `&&`; use `;` to chain commands.
|
||||
- Quote paths that contain spaces or non-ASCII characters.
|
||||
|
||||
## Baisc Infos
|
||||
|
||||
Unless directly relevant to the user's current question, you should avoid proactively mentioning, illustrating, or
|
||||
trailing off into the following information in 99% of cases:
|
||||
|
||||
This project is indexed by GitNexus as **SuperBizAgent-java** (7988 symbols, 12713 relationships, 297 execution flows). Use the GitNexus MCP tools to understand code, assess impact, and navigate safely.
|
||||
|
||||
> If any GitNexus tool warns the index is stale, run `npx gitnexus analyze` in terminal first.
|
||||
|
||||
## Always Do
|
||||
|
||||
- **MUST run impact analysis before editing any symbol.** Before modifying a function, class, or method, run `gitnexus_impact({target: "symbolName", direction: "upstream"})` and report the blast radius (direct callers, affected processes, risk level) to the user.
|
||||
- **MUST run `gitnexus_detect_changes()` before committing** to verify your changes only affect expected symbols and execution flows.
|
||||
- **MUST warn the user** if impact analysis returns HIGH or CRITICAL risk before proceeding with edits.
|
||||
- When exploring unfamiliar code, use `gitnexus_query({query: "concept"})` to find execution flows instead of grepping. It returns process-grouped results ranked by relevance.
|
||||
- When you need full context on a specific symbol — callers, callees, which execution flows it participates in — use `gitnexus_context({name: "symbolName"})`.
|
||||
|
||||
## Never Do
|
||||
|
||||
- NEVER edit a function, class, or method without first running `gitnexus_impact` on it.
|
||||
- NEVER ignore HIGH or CRITICAL risk warnings from impact analysis.
|
||||
- NEVER rename symbols with find-and-replace — use `gitnexus_rename` which understands the call graph.
|
||||
- NEVER commit changes without running `gitnexus_detect_changes()` to check affected scope.
|
||||
|
||||
## Resources
|
||||
|
||||
| Resource | Use for |
|
||||
|----------|---------|
|
||||
| `gitnexus://repo/SuperBizAgent-java/context` | Codebase overview, check index freshness |
|
||||
| `gitnexus://repo/SuperBizAgent-java/clusters` | All functional areas |
|
||||
| `gitnexus://repo/SuperBizAgent-java/processes` | All execution flows |
|
||||
| `gitnexus://repo/SuperBizAgent-java/process/{name}` | Step-by-step execution trace |
|
||||
|
||||
## CLI
|
||||
|
||||
| Task | Read this skill file |
|
||||
|------|---------------------|
|
||||
| Understand architecture / "How does X work?" | `.claude/skills/gitnexus/gitnexus-exploring/SKILL.md` |
|
||||
| Blast radius / "What breaks if I change X?" | `.claude/skills/gitnexus/gitnexus-impact-analysis/SKILL.md` |
|
||||
| Trace bugs / "Why is X failing?" | `.claude/skills/gitnexus/gitnexus-debugging/SKILL.md` |
|
||||
| Rename / extract / split / refactor | `.claude/skills/gitnexus/gitnexus-refactoring/SKILL.md` |
|
||||
| Tools, resources, schema reference | `.claude/skills/gitnexus/gitnexus-guide/SKILL.md` |
|
||||
| Index, status, clean, wiki CLI commands | `.claude/skills/gitnexus/gitnexus-cli/SKILL.md` |
|
||||
|
||||
<!-- gitnexus:end -->
|
||||
|
||||
@@ -111,47 +111,3 @@ trailing off into the following information in 99% of cases:
|
||||
- 文档目录结构:
|
||||
- 不要将文档放到用户目录(如 `C:\Users\EDY\.claude\`)中
|
||||
|
||||
|
||||
<!-- gitnexus:start -->
|
||||
# GitNexus — Code Intelligence
|
||||
|
||||
This project is indexed by GitNexus as **SuperBizAgent-java** (7988 symbols, 12713 relationships, 297 execution flows). Use the GitNexus MCP tools to understand code, assess impact, and navigate safely.
|
||||
|
||||
> If any GitNexus tool warns the index is stale, run `npx gitnexus analyze` in terminal first.
|
||||
|
||||
## Always Do
|
||||
|
||||
- **MUST run impact analysis before editing any symbol.** Before modifying a function, class, or method, run `gitnexus_impact({target: "symbolName", direction: "upstream"})` and report the blast radius (direct callers, affected processes, risk level) to the user.
|
||||
- **MUST run `gitnexus_detect_changes()` before committing** to verify your changes only affect expected symbols and execution flows.
|
||||
- **MUST warn the user** if impact analysis returns HIGH or CRITICAL risk before proceeding with edits.
|
||||
- When exploring unfamiliar code, use `gitnexus_query({query: "concept"})` to find execution flows instead of grepping. It returns process-grouped results ranked by relevance.
|
||||
- When you need full context on a specific symbol — callers, callees, which execution flows it participates in — use `gitnexus_context({name: "symbolName"})`.
|
||||
|
||||
## Never Do
|
||||
|
||||
- NEVER edit a function, class, or method without first running `gitnexus_impact` on it.
|
||||
- NEVER ignore HIGH or CRITICAL risk warnings from impact analysis.
|
||||
- NEVER rename symbols with find-and-replace — use `gitnexus_rename` which understands the call graph.
|
||||
- NEVER commit changes without running `gitnexus_detect_changes()` to check affected scope.
|
||||
|
||||
## Resources
|
||||
|
||||
| Resource | Use for |
|
||||
|----------|---------|
|
||||
| `gitnexus://repo/SuperBizAgent-java/context` | Codebase overview, check index freshness |
|
||||
| `gitnexus://repo/SuperBizAgent-java/clusters` | All functional areas |
|
||||
| `gitnexus://repo/SuperBizAgent-java/processes` | All execution flows |
|
||||
| `gitnexus://repo/SuperBizAgent-java/process/{name}` | Step-by-step execution trace |
|
||||
|
||||
## CLI
|
||||
|
||||
| Task | Read this skill file |
|
||||
|------|---------------------|
|
||||
| Understand architecture / "How does X work?" | `.claude/skills/gitnexus/gitnexus-exploring/SKILL.md` |
|
||||
| Blast radius / "What breaks if I change X?" | `.claude/skills/gitnexus/gitnexus-impact-analysis/SKILL.md` |
|
||||
| Trace bugs / "Why is X failing?" | `.claude/skills/gitnexus/gitnexus-debugging/SKILL.md` |
|
||||
| Rename / extract / split / refactor | `.claude/skills/gitnexus/gitnexus-refactoring/SKILL.md` |
|
||||
| Tools, resources, schema reference | `.claude/skills/gitnexus/gitnexus-guide/SKILL.md` |
|
||||
| Index, status, clean, wiki CLI commands | `.claude/skills/gitnexus/gitnexus-cli/SKILL.md` |
|
||||
|
||||
<!-- gitnexus:end -->
|
||||
|
||||
@@ -72,9 +72,10 @@
|
||||
|
||||
### SessionContext
|
||||
- 定义:会话上下文数据类,存储在 Redis 中的会话数据
|
||||
- 包含字段:sessionId、userId、businessId、traceId、status、toolCalls、TTL
|
||||
- 包含字段:sessionId、userId、businessId、traceId、status、toolCalls、messageHistory、TTL
|
||||
- 序列化方式:JSON(GenericJackson2JsonRedisSerializer)
|
||||
- 使用场景:多轮对话上下文管理、工具调用历史追踪
|
||||
- 边界:messageHistory 是热路径对话历史缓存,用于下一轮 prompt 上下文;长期审计的问题和答案应落到 Diagnosis Run,而不是依赖 Redis TTL 内的上下文正文。
|
||||
|
||||
### ToolCall
|
||||
- 定义:工具调用记录数据类,追踪 Agent 使用的工具及其结果
|
||||
@@ -87,6 +88,21 @@
|
||||
- 核心方法:createSession、getSession、updateSession、deleteSession、refreshSession、addToolCall
|
||||
- 使用场景:分布式会话管理、Agent 状态维护
|
||||
|
||||
### Chat Session
|
||||
- 定义:一次多轮对话上下文,由 `sessionId` 唯一标识。
|
||||
- 使用场景:保存用户连续对话的上下文窗口、会话状态和最近活跃时间。
|
||||
- 边界:Chat Session 不代表一次诊断执行;同一个 Chat Session 可以包含多次 Diagnosis Run。
|
||||
|
||||
### Diagnosis Run
|
||||
- 定义:一次独立诊断执行,由 `runId` 唯一标识,属于一个 Chat Session。
|
||||
- 使用场景:保存某一轮诊断的 query、answer、status、耗时、token、反馈和自评估结果。
|
||||
- 边界:Diagnosis Run 是 Trace、Feedback 和 Evidence score 的绑定对象;多轮对话中的每次 `/api/chat` 或 `/api/ai_ops` 执行都应创建新的 Diagnosis Run。
|
||||
|
||||
### Diagnosis Trace
|
||||
- 定义:一次 Diagnosis Run 的可回放执行轨迹,由 run 主记录、AgentStep 和 ToolInvocation 聚合形成。
|
||||
- 使用场景:Trace API、Trace UI、Verifier 审计、评测 fixture 和人工排查。
|
||||
- 边界:Diagnosis Trace 是聚合视图,不要求单独的 trace 主表;当前 trace 明细由 `agent_step` 和 `tool_invocation` 表承载。
|
||||
|
||||
### Flyway
|
||||
- 定义:数据库版本迁移工具,管理 SQL 脚本的版本化执行
|
||||
- 配置:spring.flyway.enabled=true, baseline-on-migrate=true
|
||||
@@ -105,4 +121,49 @@
|
||||
- 枚举类型在数据库中存储为 VARCHAR,JPA 使用 `@Enumerated(EnumType.STRING)` + `columnDefinition = "VARCHAR"`
|
||||
- JPA ddl-auto 使用 `validate` 模式,表结构修改必须通过 Flyway 迁移脚本
|
||||
- Redis 会话 TTL 由调用方指定,不同场景使用不同过期时间(短诊断 5 分钟,长会话 1 小时)
|
||||
- Repository 查询方法遵循 Spring Data JPA 命名约定,复杂查询使用 `@Query`
|
||||
- Repository 查询方法遵循 Spring Data JPA 命名约定,复杂查询使用 `@Query`
|
||||
|
||||
## Diagnosis Playbook Skills
|
||||
|
||||
### Diagnosis Playbook Skill
|
||||
- 定义:项目内可版本化的诊断流程包,存放在 `src/main/resources/skills/{skill-name}/SKILL.md`。
|
||||
- 使用场景:把高频故障诊断流程从大 prompt / 知识库文档中抽出,形成可审查、可复用、可按需加载的 playbook。
|
||||
- 边界:skill 只定义排查 workflow、证据顺序、停止条件、低置信度行为和报告规则;事实性知识仍放在 `knowledge_base/`,事实证据仍来自 evidence tools。
|
||||
|
||||
### SkillRegistry
|
||||
- 定义:Spring AI Alibaba Agent Framework 的 skill 元数据和正文读取入口。本项目使用 `ClasspathSkillRegistry` 从 classpath `skills/` 加载 skill。
|
||||
- 使用场景:统一提供 skill `name` / `description` 元数据,并支撑 Executor 通过官方 `read_skill` 读取完整 `SKILL.md`。
|
||||
- 当前约束:`SkillConfig.SingleSkillRegistry` 临时只暴露 active skill `diagnose-mysql-connection-pool`,用于验证单 skill 流程和避免一次性注入全部 skill。
|
||||
|
||||
### PlannerSkillMetadataHook
|
||||
- 定义:项目本地 hook,只向 Planner 注入结构化 `skill_catalog` 元数据。
|
||||
- 使用场景:Planner 根据 skill `name` / `description` 选择 `selected_skill`,输出 `selection_reason` 和执行计划。
|
||||
- 边界:Planner 不暴露官方 `read_skill` 工具,不读取完整 `SKILL.md`;Planner 只能选择 skill,不能执行 skill。
|
||||
|
||||
### SkillsAgentHook
|
||||
- 定义:Spring AI Alibaba 官方 skill hook,会同时注入官方 Skills System prompt,并暴露 `read_skill` 工具。
|
||||
- 使用场景:只挂到 Executor 和 single-agent Chat;Executor 根据 `planner_plan.selected_skill` 读取完整 playbook 后再调用证据工具。
|
||||
- 边界:不要挂到 Planner,否则 Planner 会获得 `read_skill` 工具并可能读取完整 skill;Verifier 也不能挂该 hook。
|
||||
|
||||
### read_skill
|
||||
- 定义:官方 skill 读取工具,参数为 `skill_name`,返回对应 `SKILL.md` 正文。
|
||||
- 使用场景:Executor 在执行场景化诊断前读取 Planner 选中的 playbook。
|
||||
- 边界:`read_skill` 是流程指导工具,不是事实证据工具;不应作为诊断事实写入 `tool_invocation` 证据链。
|
||||
|
||||
### Evidence Tools
|
||||
- 定义:产生可验证诊断事实的工具集合,包括 `lookup_knowledge`、`query_logs`、`query_metrics`、告警/Prometheus 工具等。
|
||||
- 使用场景:Executor 按 skill workflow 调用 evidence tools 收集事实,`tool_invocation` 记录这些事实证据。
|
||||
- 边界:最终诊断结论必须被 evidence tools 支撑,不能仅由 skill 正文支撑。
|
||||
|
||||
### Verifier Skill Isolation
|
||||
- 定义:Chat Verifier 与 skill 系统隔离,只校验 Executor 答案和 `tool_trace_summary`。
|
||||
- 使用场景:防止 Verifier 把 playbook 指令当作事实证据;Verifier 只判断已有证据是否支持结论。
|
||||
- 边界:Verifier 不接收 `skill_catalog`,不暴露 `read_skill`,不读取 `SKILL.md`。
|
||||
|
||||
## Diagnosis Playbook Business Rules
|
||||
|
||||
- Planner 只看 skill metadata,输出 `selected_skill`、`selection_reason` 和 plan。
|
||||
- Executor 才能调用 `read_skill(selected_skill)`,并且读取 skill 后仍必须调用 evidence tools。
|
||||
- Skill 正文不得替代 `lookup_knowledge`、日志、指标或告警数据。
|
||||
- Verifier 只基于 `tool_trace_summary` 校验事实,不基于 skill 正文校验事实。
|
||||
- 当前阶段保留单 active skill 白名单:`diagnose-mysql-connection-pool`。
|
||||
|
||||
+31
-20
@@ -2,23 +2,34 @@
|
||||
|
||||
## 项目
|
||||
|
||||
| 日期 | slug | 领域 | 关键词 | 状态 |
|
||||
|---|---|---|---|---|
|
||||
| 2026-07-05 | diagnosis-playbook-skills | Agent Skill/Playbook | read_skill, diagnosis playbook, progressive disclosure, payment timeout, MySQL pool, Redis timeout | openspec/changes/diagnosis-playbook-skills | implemented |
|
||||
| 2026-07-05 | mvp-demo-interview-runbook | MVP Demo/Interview | Plan C, payment timeout, runbook, trace checklist, demo script | openspec/changes/archive/2026-07-05-mvp-demo-interview-runbook | archived |
|
||||
| 2026-07-05 | diagnosis-eval-baseline-diff | Agent 评测/回归 Diff | baseline diff, regression detection, evidence coverage, cost signal, markdown report | openspec/changes/archive/2026-07-05-diagnosis-eval-baseline-diff | archived |
|
||||
| 2026-07-04 | expand-diagnosis-eval-fixtures | Agent 评测/回归 Baseline | fixture coverage, baseline report, redis timeout, slow response, jvm memory risk | openspec/changes/archive/2026-07-05-expand-diagnosis-eval-fixtures | archived |
|
||||
| 2026-07-04 | diagnosis-eval-harness | Agent 评测/回归 Harness | fixed cases, trace validation, evidence coverage, verdict distribution, markdown report | openspec/changes/archive/2026-07-04-diagnosis-eval-harness | archived |
|
||||
| 2026-07-04 | evidence-trace-hardening | 证据链/降级契约/离线验证 | ToolInvocationRecorder, ToolTraceSummaryService, lookup_knowledge, query_logs, query_metrics, LOW_CONFID, REJECT | openspec/changes/archive/2026-07-04-evidence-trace-hardening | archived |
|
||||
| 2026-07-03 | mvp-demo-trace-acceptance | MVP Demo/trace/acceptance | mvp-demo, trace API, diagnosis_session, agent_step, tool_invocation, feedback | openspec/changes/archive/2026-07-03-mvp-demo-trace-acceptance | archived |
|
||||
| 2026-07-04 | aiops-traceable-diagnosis-entry | AIOps/trace/alert diagnosis | ai_ops, SSE, alert input, sessionId, diagnosis_session, trace API | openspec/changes/archive/2026-07-04-aiops-traceable-diagnosis-entry | archived |
|
||||
| 2026-07-04 | aiops-alert-scope-control | AIOps/scope/prompt control | payload mode, auto-discovery mode, queryPrometheusAlerts, HighCPUUsage | openspec/changes/archive/2026-07-04-aiops-alert-scope-control | archived |
|
||||
| 2026-05-29 | chatmodel-abstraction | 解耦/多模型路由 | ChatModel, EmbeddingModel, DeepSeek, BGE-M3, SiliconFlow, Spring AI | archived |
|
||||
| 2026-06-23 | phase1-infrastructure | 基础设施/文档管理 | MySQL, Redis, Milvus, Flyway, JPA, 向量检索, 类别过滤 | archived |
|
||||
| 2026-06-24 | lookup-knowledge-integration | 知识库检索 | L0精确匹配, L1语义检索, frontmatter, 混合检索 | archived |
|
||||
| 2026-06-25 | doc-management-ui | 前端开发/文档管理 | 文档管理页面, CRUD, 状态监控, 纯静态页面, API集成 | archived |
|
||||
| 2026-06-26 | session-storage | 会话存储/可观测 | diagnosis_session, agent_step, tool_invocation, token追踪, 多Agent路由 | openspec/changes/session-storage | archived |
|
||||
| 2026-06-29 | confidence-feedback | 质量评估/反馈机制 | evidence_score, selfEvaluation, feedback, useful, not_useful, case_library, BAD_CASE, tool_invocation规则引擎, 反馈按钮, sessionId回传 | openspec/changes/confidence-feedback | archived |
|
||||
| 2026-06-30 | session-dedup-knowledge-map | 去重/知识图谱 | RetrievedDocTracker, KnowledgeDomainService, knowledge_domain, covers, whenToRetrieve, Planner注入, ISS-001 | openspec/changes/archive/2026-06-30-session-dedup-knowledge-map | archived |
|
||||
| 2026-07-01 | executor-action-memory-relevance | 检索质量/行动记忆 | relevanceLevel, completenessHint, Min-Max归一化, RetrievedDocTracker域级记录, Executor检索约束, ISS-002 | openspec/changes/archive/2026-07-01-executor-action-memory-relevance | archived |
|
||||
| 2026-07-02 | chat-verifier-agent | Chat质量门禁/可追溯验证 | Verifier, groundedness_score, facts_checked, evidence_refs, tool_trace_summary, self_evaluation | openspec/changes/archive/2026-07-03-chat-verifier-agent | archived |
|
||||
| 日期 | slug | 说明 | 领域 | 关键词 | 关联 OpenSpec | 状态 |
|
||||
|---|---|---|---|---|---|---|
|
||||
| 2026-07-10 | session-run-trace-isolation | 拆分会话态和运行态,引入 runId 隔离 Trace、Feedback、AIOps 和 demo 链路。 | Trace/session/run isolation | chat_session, diagnosis_run, runId, trace exact run, feedback fallback, AIOps SSE metadata, baseline drift | openspec/changes/archive/2026-07-10-session-run-trace-isolation | archived |
|
||||
| 2026-07-09 | interview-demo-quality-audit | 增加面试演示前置质量审计,覆盖 prompt、Gatekeeper 和评测基线。 | Agent eval/demo/Prompt audit | interview demo preflight, prompt_audit, gatekeeper rules, diagnosis baseline, 12 fixtures | openspec/changes/archive/2026-07-09-interview-demo-quality-audit | archived |
|
||||
| 2026-07-08 | executor-composer-final-answer | 引入 Composer 生成最终回答,只使用 Verifier 允许的结论材料。 | Chat quality gate/evidence attribution | chat_composer, final answer, allowed_claims, allowed_hypotheses, safe fallback, composer_output | openspec/changes/archive/2026-07-08-executor-composer-final-answer | archived |
|
||||
| 2026-07-08 | diagnosis-eval-demo-gatekeeper-closure | 收敛诊断评测、稳定 demo 场景和 Gatekeeper 审计元数据。 | Agent eval/demo/Gatekeeper | diagnosis eval matrix, stable demo scenarios, Gatekeeper rule set version, audit metadata | openspec/changes/archive/2026-07-08-diagnosis-eval-demo-gatekeeper-closure | archived |
|
||||
| 2026-07-08 | verifier-evidence-reference-fidelity | 强化 Verifier 对 evidence_refs、raw_path 和 no_evidence 的保真校验。 | Chat质量门禁/证据归因 | evidence_refs, raw_path, Gatekeeper severity, verifier evidence excerpt, HikariCP mock, no_evidence | openspec/changes/archive/2026-07-08-verifier-evidence-reference-fidelity | archived |
|
||||
| 2026-07-07 | executor-evidence-output-contract | 设计 Executor 结构化证据输出,解决证据归因幻觉和 LOW_CONFID 问题。 | Chat质量门禁/证据归因 | Executor structured output, evidence bindings, Verifier structured claims, LOW_CONFID, hallucination | openspec/changes/archive/2026-07-07-executor-evidence-output-contract | archived |
|
||||
| 2026-07-07 | executor-v2-output-contract | 将 Executor 输出升级为 V2 契约,移除面向用户的最终回答字段。 | Chat质量门禁/证据归因 | executor_evidence_v2, user_facing_answer removal, diagnosis_summary removal, structured renderer | openspec/changes/archive/2026-07-07-executor-v2-output-contract | archived |
|
||||
| 2026-07-07 | executor-gatekeeper-hook | 在 Executor 与 Verifier 之间接入 Gatekeeper,校验证据绑定来源。 | Chat质量门禁/证据归因 | Gatekeeper, verifier payload, source_invocation_ids, tool_name match, self_evaluation | openspec/changes/archive/2026-07-07-executor-gatekeeper-hook | archived |
|
||||
| 2026-07-07 | executor-verifier-claim-checks | 增加 Verifier claim_checks 和事实校验兼容逻辑。 | Chat质量门禁/证据归因 | Verifier claim_checks, facts_checked compatibility, effective verdict guardrail, malformed output downgrade | openspec/changes/archive/2026-07-07-executor-verifier-claim-checks | archived |
|
||||
| 2026-07-06 | rag-eval-pipeline-closure | 建立 RAG 评测闭环,加入 fixture、快照和 baseline diff。 | RAG/评测/回归闭环 | lookupResult fixture, LookupKnowledgeTool snapshot, evidenceBlocks, contextPack, retrievalTrace, rerankTrace, baseline diff, fallback case | devflow/projects/2026-07-06-rag-eval-pipeline-closure | archived |
|
||||
| 2026-07-06 | modular-rag-pipeline | 将 lookup_knowledge 改造成模块化 RAG 管线,补齐证据块和检索追踪。 | RAG/Agent工具/证据链 | modular RAG, lookup_knowledge, evidenceBlocks, contextPack, rerank, retrievalTrace, L0 hint, unfiltered retry | openspec/changes/archive/2026-07-06-modular-rag-pipeline | archived |
|
||||
| 2026-07-05 | diagnosis-playbook-skills | 增加诊断 Playbook Skill,沉淀支付超时、MySQL 池、Redis 超时等套路。 | Agent Skill/Playbook | read_skill, diagnosis playbook, progressive disclosure, payment timeout, MySQL pool, Redis timeout | openspec/changes/diagnosis-playbook-skills | implemented |
|
||||
| 2026-07-05 | mvp-demo-interview-runbook | 准备可复现的 MVP 面试演示包、运行手册和 Trace 检查清单。 | MVP Demo/Interview | Plan C, payment timeout, runbook, trace checklist, demo script | openspec/changes/archive/2026-07-05-mvp-demo-interview-runbook | archived |
|
||||
| 2026-07-05 | diagnosis-eval-baseline-diff | 增加诊断评测 baseline diff,用于判断回归和证据覆盖变化。 | Agent 评测/回归 Diff | baseline diff, regression detection, evidence coverage, cost signal, markdown report | openspec/changes/archive/2026-07-05-diagnosis-eval-baseline-diff | archived |
|
||||
| 2026-07-04 | expand-diagnosis-eval-fixtures | 扩充诊断评测 fixture,覆盖 Redis、慢响应和 JVM 内存风险。 | Agent 评测/回归 Baseline | fixture coverage, baseline report, redis timeout, slow response, jvm memory risk | openspec/changes/archive/2026-07-05-expand-diagnosis-eval-fixtures | archived |
|
||||
| 2026-07-04 | diagnosis-eval-harness | 建立固定诊断评测 Harness,输出 trace、证据覆盖和 verdict 分布。 | Agent 评测/回归 Harness | fixed cases, trace validation, evidence coverage, verdict distribution, markdown report | openspec/changes/archive/2026-07-04-diagnosis-eval-harness | archived |
|
||||
| 2026-07-04 | evidence-trace-hardening | 强化工具调用证据链、降级契约和离线验证能力。 | 证据链/降级契约/离线验证 | ToolInvocationRecorder, ToolTraceSummaryService, lookup_knowledge, query_logs, query_metrics, LOW_CONFID, REJECT | openspec/changes/archive/2026-07-04-evidence-trace-hardening | archived |
|
||||
| 2026-07-04 | aiops-traceable-diagnosis-entry | 增加可追踪的 AIOps 告警诊断入口,打通 sessionId 和 Trace API。 | AIOps/trace/alert diagnosis | ai_ops, SSE, alert input, sessionId, diagnosis_session, trace API | openspec/changes/archive/2026-07-04-aiops-traceable-diagnosis-entry | archived |
|
||||
| 2026-07-04 | aiops-alert-scope-control | 收敛 AIOps 告警诊断范围,区分 payload 定向和自动发现模式。 | AIOps/scope/prompt control | payload mode, auto-discovery mode, queryPrometheusAlerts, HighCPUUsage | openspec/changes/archive/2026-07-04-aiops-alert-scope-control | archived |
|
||||
| 2026-07-03 | mvp-demo-trace-acceptance | 增加 MVP demo 的 Trace 验收,覆盖会话、步骤、工具和反馈链路。 | MVP Demo/trace/acceptance | mvp-demo, trace API, diagnosis_session, agent_step, tool_invocation, feedback | openspec/changes/archive/2026-07-03-mvp-demo-trace-acceptance | archived |
|
||||
| 2026-07-02 | chat-verifier-agent | 增加 Chat Verifier Agent,用 groundedness 和 evidence_refs 校验回答。 | Chat质量门禁/可追溯验证 | Verifier, groundedness_score, facts_checked, evidence_refs, tool_trace_summary, self_evaluation | openspec/changes/archive/2026-07-03-chat-verifier-agent | archived |
|
||||
| 2026-07-01 | executor-action-memory-relevance | 增加行动记忆和相关性信号,约束 Executor 重复检索。 | 检索质量/行动记忆 | relevanceLevel, completenessHint, Min-Max归一化, RetrievedDocTracker域级记录, Executor检索约束, ISS-002 | openspec/changes/archive/2026-07-01-executor-action-memory-relevance | archived |
|
||||
| 2026-06-30 | session-dedup-knowledge-map | 引入会话级去重和知识域地图,减少重复召回。 | 去重/知识图谱 | RetrievedDocTracker, KnowledgeDomainService, knowledge_domain, covers, whenToRetrieve, Planner注入, ISS-001 | openspec/changes/archive/2026-06-30-session-dedup-knowledge-map | archived |
|
||||
| 2026-06-29 | confidence-feedback | 建立质量评估和用户反馈机制,并把有用反馈沉淀为案例。 | 质量评估/反馈机制 | evidence_score, selfEvaluation, feedback, useful, not_useful, case_library, BAD_CASE, tool_invocation规则引擎, 反馈按钮, sessionId回传 | openspec/changes/confidence-feedback | archived |
|
||||
| 2026-06-26 | session-storage | 建立通用会话存储,记录 session、agent step 和 tool invocation。 | 会话存储/可观测 | diagnosis_session, agent_step, tool_invocation, token追踪, 多Agent路由 | openspec/changes/session-storage | archived |
|
||||
| 2026-06-25 | doc-management-ui | 实现文档管理页面,支持文档 CRUD、状态监控和 API 集成。 | 前端开发/文档管理 | 文档管理页面, CRUD, 状态监控, 纯静态页面, API集成 | - | archived |
|
||||
| 2026-06-24 | lookup-knowledge-integration | 接入知识库检索,支持 L0 精确匹配和 L1 语义检索。 | 知识库检索 | L0精确匹配, L1语义检索, frontmatter, 混合检索 | - | archived |
|
||||
| 2026-06-23 | phase1-infrastructure | 搭建第一阶段基础设施,包括 MySQL、Redis、Milvus、Flyway 和 JPA。 | 基础设施/文档管理 | MySQL, Redis, Milvus, Flyway, JPA, 向量检索, 类别过滤 | - | archived |
|
||||
| 2026-05-29 | chatmodel-abstraction | 抽象 ChatModel 和 EmbeddingModel,支持多模型路由。 | 解耦/多模型路由 | ChatModel, EmbeddingModel, DeepSeek, BGE-M3, SiliconFlow, Spring AI | - | archived |
|
||||
|
||||
@@ -48,7 +48,7 @@
|
||||
|
||||
## 遗留问题
|
||||
|
||||
ISS-002:Executor 无约束重复调用 `lookup_knowledge`(单会话 20+ 次),knowledge map 和检索约束只注入了 Planner 未注入 Executor。详见 `mvp/issues/ISS-002-executor-unconstrained-lookup.md`。
|
||||
ISS-002:Executor 无约束重复调用 `lookup_knowledge`(单会话 20+ 次),knowledge map 和检索约束只注入了 Planner 未注入 Executor。详见 `mvp/issues/archived/ISS-002-executor-unconstrained-lookup.md`。
|
||||
|
||||
## 已知限制
|
||||
|
||||
|
||||
@@ -9,8 +9,8 @@
|
||||
## Context
|
||||
|
||||
- `devflow/index.md` was checked. Relevant history includes `session-storage`, `confidence-feedback`, `executor-action-memory-relevance`, and `chat-verifier-agent`.
|
||||
- `mvp/notes/agent-engineering-decisions.md` already recommends the next phase as "可复现 MVP Demo", including `mvp-demo` profile, fixed diagnosis case, one-click request, and `GET /api/diagnosis/{sessionId}/trace`.
|
||||
- `mvp/issues/ISS-003-mvp-design-implementation-review.md` identifies test stability, session traceability, verifier evidence chain, upload path, and SupervisorAgent consistency as recent MVP concerns. Security cleanup is intentionally deferred by user decision.
|
||||
- `mvp/archive/2026-07-09-doc-cleanup/notes/agent-engineering-decisions.md` already recommends the next phase as "可复现 MVP Demo", including `mvp-demo` profile, fixed diagnosis case, one-click request, and `GET /api/diagnosis/{sessionId}/trace`.
|
||||
- `mvp/issues/active/ISS-003-mvp-design-implementation-review.md` identifies test stability, session traceability, verifier evidence chain, upload path, and SupervisorAgent consistency as recent MVP concerns. Security cleanup is intentionally deferred by user decision.
|
||||
|
||||
## Question Pool
|
||||
|
||||
|
||||
@@ -0,0 +1,101 @@
|
||||
# Modular RAG Pipeline — Acceptance
|
||||
|
||||
## 验收状态
|
||||
|
||||
状态:通过,OpenSpec 已归档。
|
||||
|
||||
任务完成:
|
||||
|
||||
- OpenSpec tasks:31/31 完成。
|
||||
- Review 后新增去重边界修复和回归测试。
|
||||
- OpenSpec archive:`openspec/changes/archive/2026-07-06-modular-rag-pipeline`。
|
||||
|
||||
## 静态验证
|
||||
|
||||
```powershell
|
||||
openspec validate modular-rag-pipeline --strict
|
||||
```
|
||||
|
||||
结果:
|
||||
|
||||
```text
|
||||
Change 'modular-rag-pipeline' is valid
|
||||
```
|
||||
|
||||
```powershell
|
||||
git diff --check
|
||||
```
|
||||
|
||||
结果:
|
||||
|
||||
```text
|
||||
PASS
|
||||
```
|
||||
|
||||
说明:仅出现 Windows LF/CRLF warning,无 whitespace error。
|
||||
|
||||
## 脚本验证
|
||||
|
||||
```powershell
|
||||
mvn -q -DskipTests compile
|
||||
```
|
||||
|
||||
结果:PASS。
|
||||
|
||||
```powershell
|
||||
mvn -q "-Dtest=LookupKnowledgeToolTest,ToolInvocationRecorderTest" test
|
||||
```
|
||||
|
||||
结果:PASS。
|
||||
|
||||
覆盖:
|
||||
|
||||
- filtered L1 成功不 retry。
|
||||
- filtered L1 低质量触发 raw unfiltered retry。
|
||||
- filtered L1 无 evidence 触发 raw unfiltered retry。
|
||||
- L0 hint 不作为 standalone fact evidence。
|
||||
- 无 L0 hint 时直接 unfiltered vector search。
|
||||
- rerank 使用 hint match 并记录 trace。
|
||||
- context pack 保留 source/title/breadcrumb/hit reasons。
|
||||
- evidence blocks 按 source 去重。
|
||||
- session dedup 不再返回可消费 evidence/context。
|
||||
- recorder 记录 retrieval trace、rerank trace、context pack summary 和 evidence summaries。
|
||||
|
||||
```powershell
|
||||
$env:MILVUS_TOKEN = <application.yml 中的 milvus.token>; mvn -q test
|
||||
```
|
||||
|
||||
结果:PASS。
|
||||
|
||||
说明:
|
||||
|
||||
- `MilvusConnectionTest` 需要 `MILVUS_TOKEN` 环境变量,直接读 `System.getenv`,不会自动读 `application.yml`。
|
||||
- 注入该环境变量后完整测试通过。
|
||||
|
||||
## 实现验收
|
||||
|
||||
已验证行为:
|
||||
|
||||
- `LookupKnowledgeTool` 已变为 pipeline orchestrator。
|
||||
- `LookupResult` 新契约包含 `evidenceBlocks`、`contextPack`、`retrievalTrace`、`rerankTrace`。
|
||||
- 旧 `primary/supplement` 字段和 DTO 已删除。
|
||||
- `ToolInvocationRecorder` 不再依赖 `result.getPrimary()`。
|
||||
- filtered retrieval 失败时会记录 `filtered_vector_no_evidence` 或 `filtered_vector_low_quality`。
|
||||
- no-evidence 情况返回 `found=false` 且保留 retrieval trace。
|
||||
- session dedup 情况返回 `found=false` 且 evidence/context 为空。
|
||||
|
||||
## 未验证项
|
||||
|
||||
人工 Demo 未执行:
|
||||
|
||||
- 还没有通过真实 Chat/AIOps 会话观察 Agent 是否稳定按 `contextPack.packedText` 和 `evidenceBlocks` 引用证据。
|
||||
|
||||
风险:
|
||||
|
||||
- 工具 JSON 契约是 L4 breaking change,prompt 已更新,但真实对话行为仍建议做一次端到端 demo。
|
||||
|
||||
## 后续建议
|
||||
|
||||
- 增加一组 RAG eval cases,固定 query、期望 evidence source、期望 fallback path。
|
||||
- 将 `MilvusConnectionTest` 改成 Spring 配置驱动或 integration profile,避免配置源混用。
|
||||
- 后续可在评测数据足够后再考虑 model-based rerank 或 hybrid retrieval。
|
||||
@@ -0,0 +1,54 @@
|
||||
# Modular RAG Pipeline — Brief
|
||||
|
||||
## 背景
|
||||
|
||||
`lookup_knowledge` 已经能返回知识库证据,但实现集中在 `LookupKnowledgeTool` 内部:L0 查询分析、L1 向量召回、相关性归一化、证据组装、会话去重和 trace 入库耦合在一起。
|
||||
|
||||
旧返回契约 `primary/supplement` 也延续了“L0 是主结果、L1 是补充”的语义,和当前设计目标不一致。新的目标是让 L0 只作为 query understanding / filter / rerank / trace 信号,让 L1 向量检索成为事实证据来源。
|
||||
|
||||
## 目标
|
||||
|
||||
- 将 `lookup_knowledge` 改造成模块化 RAG pipeline。
|
||||
- 保留显式 Agent tool 边界,不改工具名和 query 参数。
|
||||
- L0 只提供领域、关键词、实体、category filter 和 trace hint。
|
||||
- L1 filtered vector retrieval 失败或低质量时,降级为 raw query unfiltered L1 retry。
|
||||
- 输出 evidence-first contract:`evidenceBlocks`、`contextPack`、`retrievalTrace`、`rerankTrace`。
|
||||
- 保持 `tool_invocation` 表结构稳定,把新 trace 写入 `retrieval_details` JSON。
|
||||
|
||||
## 范围
|
||||
|
||||
已完成:
|
||||
|
||||
- 新增 pipeline DTO:`KnowledgeQuery`、`RetrievedEvidenceCandidate`、`ContextPack`、`RetrievalTrace`、`RerankTrace`、`EvidencePostprocessResult`。
|
||||
- 新增 pipeline service:`KnowledgeQueryTransformer`、`KnowledgeDocumentRetriever`、`KnowledgeEvidencePostProcessor`、`KnowledgeContextPacker`、`LookupResultAssembler`。
|
||||
- 重构 `LookupKnowledgeTool` 为薄 orchestration 层。
|
||||
- 迁移 `LookupResult`,删除 `primary/supplement` 字段和 `PrimaryResult` / `SupplementResult` 类。
|
||||
- 更新 `ToolInvocationRecorder`,记录 query transform、retrieval trace、context pack summary、rerank trace、fallback reason 和 evidence summaries。
|
||||
- 更新 executor prompt 和 RAG 架构文档。
|
||||
- 补充 lookup、recorder、fallback、rerank、context pack、session dedup 测试。
|
||||
|
||||
非目标:
|
||||
|
||||
- 不引入 implicit Advisor。
|
||||
- 不引入 cross-encoder、BM25、RRF、Elasticsearch、OpenSearch。
|
||||
- 不改文档上传、chunk、embedding 写入、Milvus schema。
|
||||
- 不改变 Agent 何时调用 `lookup_knowledge`。
|
||||
|
||||
## 关联 OpenSpec
|
||||
|
||||
- `openspec/changes/archive/2026-07-06-modular-rag-pipeline`
|
||||
|
||||
## 接口影响
|
||||
|
||||
级别:L4 breaking interface。
|
||||
|
||||
原因:
|
||||
|
||||
- 删除旧 `LookupResult.primary` / `LookupResult.supplement`。
|
||||
- `lookup_knowledge` tool JSON 输出形状变化。
|
||||
|
||||
缓解:
|
||||
|
||||
- 工具名和输入参数保持不变。
|
||||
- in-repo 消费方、测试和 prompt 同步迁移。
|
||||
- `tool_invocation` 表结构不变。
|
||||
@@ -0,0 +1,72 @@
|
||||
# Modular RAG Pipeline — Decisions
|
||||
|
||||
## D1: `lookup_knowledge` 保持显式工具
|
||||
|
||||
不把知识检索做成隐式 Advisor。Agent 仍显式调用 `lookup_knowledge(query)`,这样 trace、Verifier、Eval 都能看到工具调用边界。
|
||||
|
||||
## D2: L0 只做 query understanding
|
||||
|
||||
L0 产出:
|
||||
|
||||
- `domainHints`
|
||||
- `matchedKeywords`
|
||||
- `entities`
|
||||
- `categoryFilter`
|
||||
- `l0Titles`
|
||||
- `l0MatchCount`
|
||||
|
||||
L0 不再直接转成 fact evidence。L0 hint 可以影响 filter、rerank、trace,但不能在 L1 失败时冒充知识证据。
|
||||
|
||||
## D3: MVP 降级策略采用 unfiltered L1 retry
|
||||
|
||||
流程:
|
||||
|
||||
```text
|
||||
filtered L1 with L0 category filter
|
||||
-> empty / no final evidence / below reference threshold
|
||||
-> raw query unfiltered L1 retry
|
||||
-> still no evidence => no_evidence
|
||||
```
|
||||
|
||||
取舍:
|
||||
|
||||
- 简单、可解释、适合 MVP。
|
||||
- 避免引入 BM25/RRF/multi-query/cross-encoder 的复杂度。
|
||||
- 代价是低质量场景多一次向量查询,已通过 trace 记录 attempt duration。
|
||||
|
||||
## D4: 删除 `primary/supplement`
|
||||
|
||||
这是一次 L4 breaking interface change。
|
||||
|
||||
删除原因:
|
||||
|
||||
- `primary/supplement` 绑定旧语义:L0 primary、L1 supplement。
|
||||
- 新设计中事实证据来自 `evidenceBlocks/contextPack`。
|
||||
|
||||
迁移结果:
|
||||
|
||||
- `LookupResult` 暴露 evidence-first 字段。
|
||||
- `PrimaryResult` / `SupplementResult` 已删除。
|
||||
- 生产代码和测试不再引用 `getPrimary()` / `getSupplement()`。
|
||||
|
||||
## D5: Trace 表结构保持稳定
|
||||
|
||||
`tool_invocation` 表不新增列。新增信息写入 `retrieval_details` JSON:
|
||||
|
||||
- `query_transform`
|
||||
- `retrieval_trace`
|
||||
- `context_pack_summary`
|
||||
- `rerank_trace`
|
||||
- `fallback_reason`
|
||||
- `evidence_blocks`
|
||||
|
||||
原因:当前 trace、Verifier、Eval 已经以 `tool_invocation` 为证据入口,JSON details 足够承载 RAG 细节,避免 schema churn。
|
||||
|
||||
## D6: 会话去重不返回可消费证据
|
||||
|
||||
Review 后修正:
|
||||
|
||||
- dedup result 的 `found=false` 必须和 evidence/context 语义一致。
|
||||
- 返回消息说明文档已检索过。
|
||||
- 不再返回 `evidenceBlocks/contextPack`,避免 Agent 重复使用同一证据。
|
||||
- 保留 `retrievalTrace` 和 `retrievedDomainsThisSession` 便于可观测。
|
||||
@@ -0,0 +1,56 @@
|
||||
# Modular RAG Pipeline — Evidence
|
||||
|
||||
## 代码证据
|
||||
|
||||
关键入口:
|
||||
|
||||
- `src/main/java/com/superbiz/agent/tool/LookupKnowledgeTool.java`
|
||||
- `src/main/java/com/superbiz/agent/service/ToolInvocationRecorder.java`
|
||||
- `src/main/java/com/superbiz/agent/dto/LookupResult.java`
|
||||
|
||||
新增模块:
|
||||
|
||||
- `KnowledgeQueryTransformer`:复用 `KnowledgeIndexService.analyzeQuery`,把 L0 转成 query hints 和可选 `categoryFilter`。
|
||||
- `KnowledgeDocumentRetriever`:封装 `VectorSearchService.searchSimilarDocuments(query, topK, category)`,统一 filtered / unfiltered attempt。
|
||||
- `KnowledgeEvidencePostProcessor`:归一化 L2、创建 evidence blocks、source dedup、规则 rerank、输出 `RerankTrace`。
|
||||
- `KnowledgeContextPacker`:按字符预算打包 evidence,保留 source/title/breadcrumb/hit reasons。
|
||||
- `LookupResultAssembler`:统一组装 evidence-first result、no-evidence result、session dedup result。
|
||||
|
||||
## 设计证据
|
||||
|
||||
已有文档约束:
|
||||
|
||||
- `mvp/architecture/rag-architecture.md`:RAG 应表达为可解释 pipeline,而不是一坨工具逻辑。
|
||||
- `mvp/architecture/retrieval-observability.md`:L0 是 hint/explainability 层,L1 是语义检索主路径。
|
||||
- `devflow/glossary/CONTEXT.md`:`lookup_knowledge` 是显式 Agent evidence tool,`tool_invocation` 是 trace / verifier / eval 的证据来源。
|
||||
|
||||
OpenSpec 对齐:
|
||||
|
||||
- `openspec/changes/modular-rag-pipeline/proposal.md`
|
||||
- `openspec/changes/modular-rag-pipeline/design.md`
|
||||
- `openspec/changes/modular-rag-pipeline/specs/rag-knowledge-retrieval/spec.md`
|
||||
- `openspec/changes/modular-rag-pipeline/tasks.md`
|
||||
|
||||
## 用户确认
|
||||
|
||||
- 一次到位做模块化 RAG,而不是只做小补丁。
|
||||
- L0 不再作为事实证据兜底。
|
||||
- filtered L1 不准时,MVP 降级为 raw query unfiltered L1 retry。
|
||||
- 可以新增字段,并删除旧字段以换取后续流程清晰。
|
||||
|
||||
## Review 发现
|
||||
|
||||
Review 中发现一个非阻塞但应修复的问题:
|
||||
|
||||
- 会话去重命中时,返回 `found=false` 但仍带 `evidenceBlocks/contextPack`,可能导致 Agent 重复消费同一份证据。
|
||||
|
||||
修复:
|
||||
|
||||
- `LookupResultAssembler.deduped` 清空可消费 evidence/context,只保留 message、trace、relevance hint 和 session domain memory。
|
||||
- 新增 `LookupKnowledgeToolTest.sessionDedupDoesNotReturnConsumableEvidenceAgain`。
|
||||
|
||||
## 非阻塞观察
|
||||
|
||||
- `MilvusConnectionTest` 仍直接依赖 `MILVUS_TOKEN` 环境变量;主配置中已有 token,但测试不读 Spring 配置。
|
||||
- 测试日志仍有 ANTLR 版本 warning,不影响测试通过。
|
||||
- 控制台在部分命令输出中仍会出现中文编码显示问题,但源码按 UTF-8 读取时关键用户提示文本正常。
|
||||
@@ -0,0 +1,78 @@
|
||||
# Acceptance: rag-eval-pipeline-closure
|
||||
|
||||
## Status
|
||||
|
||||
Archived.
|
||||
|
||||
## Acceptance Criteria
|
||||
|
||||
| Item | Status | Notes |
|
||||
|---|---|---|
|
||||
| Modular fixture support | Done | Evaluator reads `lookupResult.evidenceBlocks/contextPack/retrievalTrace/rerankTrace`. |
|
||||
| LookupResult-only contract | Done | Evaluator fails fixtures that do not expose `lookupResult`. |
|
||||
| Golden modular assertions | Done | Cases assert selected attempt, accepted fallback reason, evidence status, context sources, and rerank top source. |
|
||||
| Fallback coverage | Done | Added `chat-l0-filter-fallback` for filtered low-quality/no-evidence to unfiltered retry. |
|
||||
| Real tool snapshot generation | Done | Added `RagLookupSnapshotGeneratorTest` and `generate_rag_lookup_snapshots.ps1`, defaulting to Spring AI VectorStore mode. |
|
||||
| Seed docs import/reindex | Done | Added canonical seed docs, `RagEvalSeedImporterTest`, and `prepare_rag_eval_seed.ps1`. |
|
||||
| Eval metadata isolation | Done | Added `kb_scope` metadata and `retrieval.kb-scope` filtering for L0 and L1. |
|
||||
| Frontmatter body split | Done | Upload chunking embeds Markdown body, while frontmatter feeds metadata and L0. |
|
||||
| Baseline diff | Done | `--compare-to` writes JSON/Markdown diff and exits non-zero on regression. |
|
||||
| Documentation | Done | Updated RAG eval README and added `mvp/architecture/rag-eval-closure.md`. |
|
||||
|
||||
## Verification
|
||||
|
||||
```powershell
|
||||
python scripts\eval_rag_retrieval.py
|
||||
```
|
||||
|
||||
Result: passed. 7 cases, passRate=1.0, recall@5=1.0.
|
||||
|
||||
```powershell
|
||||
mvn -q "-Dtest=RagLookupSnapshotGeneratorTest" test
|
||||
```
|
||||
|
||||
Result: passed. The snapshot generator stays disabled unless `rag.snapshot.enabled=true` is provided.
|
||||
|
||||
```powershell
|
||||
mvn -q "-Dtest=RagLookupSnapshotGeneratorTest" "-Drag.snapshot.enabled=true" "-Drag.snapshot.fixtures=<temp-fixtures>" "-Drag.snapshot.retrievedAt=2026-07-06T00:00:00Z" "-Dretrieval.kb-scope=rag-eval" "-Dretrieval.vector-store.mode=spring" test
|
||||
python scripts\eval_rag_retrieval.py --fixtures <temp-fixtures> --json-report <temp-current.json> --markdown-report <temp-current.md>
|
||||
```
|
||||
|
||||
Result: passed. Spring AI VectorStore live snapshot produced 7 cases, passRate=1.0, recall@5=1.0. The fallback case used `selectedAttempt=UNFILTERED_VECTOR_RETRY` and `fallbackReason=filtered_vector_no_evidence`; the expected source `rag-l0-filter-fallback` remained rank 1.
|
||||
|
||||
```powershell
|
||||
python scripts\eval_rag_retrieval.py --json-report <temp-current.json> --markdown-report <temp-current.md> --compare-to eval\rag-retrieval\reports\baseline.json --diff-json-report <temp-diff.json> --diff-markdown-report <temp-diff.md>
|
||||
```
|
||||
|
||||
Result: passed. regressions=0.
|
||||
|
||||
```powershell
|
||||
mvn -q "-Dtest=FrontmatterParserTest,VectorIndexServiceTest,VectorSearchServiceTest,DocumentManagementServiceTest,RagLookupSnapshotGeneratorTest,RagEvalSeedImporterTest" test
|
||||
```
|
||||
|
||||
Result: passed. The seed importer and snapshot generator remain disabled unless their system properties are explicitly enabled.
|
||||
|
||||
```powershell
|
||||
$null = [scriptblock]::Create((Get-Content -Raw scripts\prepare_rag_eval_seed.ps1))
|
||||
$null = [scriptblock]::Create((Get-Content -Raw scripts\generate_rag_lookup_snapshots.ps1))
|
||||
```
|
||||
|
||||
Result: PowerShell syntax OK.
|
||||
|
||||
```powershell
|
||||
.\scripts\prepare_rag_eval_seed.ps1
|
||||
```
|
||||
|
||||
Result: passed. Seed docs were imported through `DocumentManagementService` and reindexed into the configured runtime DB/vector stack.
|
||||
|
||||
```powershell
|
||||
.\scripts\generate_rag_lookup_snapshots.ps1 -Fixtures <temp-fixtures> -RetrievedAt 2026-07-06T00:00:00Z -SkipEval
|
||||
```
|
||||
|
||||
Result: passed after defaulting the script to `retrieval.vector-store.mode=spring`. The script generated live fixtures through the real `LookupKnowledgeTool` and then the offline evaluator reported 7 cases, passRate=1.0, recall@5=1.0.
|
||||
|
||||
```powershell
|
||||
git diff --check
|
||||
```
|
||||
|
||||
Result: no whitespace errors. Git reported only LF/CRLF conversion warnings.
|
||||
@@ -0,0 +1,21 @@
|
||||
# Brief: rag-eval-pipeline-closure
|
||||
|
||||
## Background
|
||||
|
||||
The modular RAG pipeline now returns `LookupResult` with `evidenceBlocks`, `contextPack`, `retrievalTrace`, and `rerankTrace`. The RAG retrieval baseline must validate that full contract, so it can detect regressions in fallback behavior, context packing, or rerank trace.
|
||||
|
||||
## Goals
|
||||
|
||||
1. Reuse the existing offline RAG retrieval baseline.
|
||||
2. Extend it to support modular `LookupResult` fixtures.
|
||||
3. Add golden assertions for selected attempt, fallback reason, evidence status, context sources, and rerank top source.
|
||||
4. Add a RAG baseline diff path for regression detection.
|
||||
5. Add a snapshot generator that calls the real `LookupKnowledgeTool`.
|
||||
6. Document how RAG baseline and diagnosis baseline form a quality loop.
|
||||
|
||||
## Non-Goals
|
||||
|
||||
- No new production API.
|
||||
- No LLM-as-judge scoring.
|
||||
- No production API behavior changes.
|
||||
- No replacement for diagnosis eval.
|
||||
@@ -0,0 +1,57 @@
|
||||
# Decisions: rag-eval-pipeline-closure
|
||||
|
||||
## D1. Reuse the existing evaluator
|
||||
|
||||
Decision: extend `scripts/eval_rag_retrieval.py` instead of creating a second evaluator.
|
||||
|
||||
Reason: the old evaluator already owns golden cases, fixtures, hit-level classification, and Markdown/JSON reports. Extending it keeps one RAG baseline path.
|
||||
|
||||
## D2. Use LookupResult as the only fixture contract
|
||||
|
||||
Decision: support `lookupResult` only.
|
||||
|
||||
Reason: the MVP has moved to evidence-first RAG. Keeping an older fixture contract would weaken the baseline and let incomplete fixtures bypass context packing, retrieval trace, and rerank checks.
|
||||
|
||||
## D3. Make modular assertions opt-in per case
|
||||
|
||||
Decision: use fields such as `expectedSelectedAttempt`, `expectedFallbackReason`/`expectedFallbackReasons`, `expectedEvidenceStatus`, `expectedContextSources`, and `expectedRerankTopSource`.
|
||||
|
||||
Reason: golden cases can be strict where the pipeline path matters without forcing every historical case to assert every new field.
|
||||
|
||||
## D4. Diff remains deterministic
|
||||
|
||||
Decision: RAG diff compares report fields only and does not call live services or models.
|
||||
|
||||
Reason: this keeps it suitable for local regression checks and CI-style gates.
|
||||
|
||||
## D5. Isolate live eval docs with kb_scope
|
||||
|
||||
Decision: add `kb_scope` metadata and use `rag-eval` for canonical eval seed documents.
|
||||
|
||||
Reason: local production documents are not stable enough for golden retrieval expectations. Scope isolation lets real `LookupKnowledgeTool` snapshots use the same MySQL/Milvus stack while avoiding accidental matches from unrelated local data.
|
||||
|
||||
Default runtime keeps `retrieval.kb-scope` empty so legacy documents without `kb_scope` remain searchable. Eval scripts pass `-Dretrieval.kb-scope=rag-eval`. The same scope applies to L0 query hints and L1 vector retrieval.
|
||||
|
||||
## D6. Import seed docs through the real upload pipeline
|
||||
|
||||
Decision: seed docs are imported by `RagEvalSeedImporterTest` through `DocumentManagementService.uploadDocument`.
|
||||
|
||||
Reason: this updates DB metadata, L0 index state, local knowledge files, and Milvus chunks in the same way as normal document ingestion. A direct Milvus-only seed would make the live eval less representative.
|
||||
|
||||
## D7. Strip frontmatter before chunk embedding
|
||||
|
||||
Decision: uploaded Markdown frontmatter feeds metadata/L0 but is stripped before chunking and embedding.
|
||||
|
||||
Reason: frontmatter is a control plane, not evidence text. Keeping it in chunks lets L0-only keywords artificially improve vector similarity, especially for fallback decoy cases.
|
||||
|
||||
## D8. Treat retry behavior as the stable fallback contract
|
||||
|
||||
Decision: the fallback golden case accepts both `filtered_vector_low_quality` and `filtered_vector_no_evidence`, while still requiring `selectedAttempt=UNFILTERED_VECTOR_RETRY`, expected evidence source, context packing, and rerank top source.
|
||||
|
||||
Reason: Spring AI VectorStore and the Milvus SDK can differ on whether an over-filtered first pass returns a weak candidate or no candidate. The MVP contract is that the retriever skips only the L0 category filter, keeps `kb_scope`, retries the original query, and returns the correct evidence.
|
||||
|
||||
## D9. Default live snapshots to Spring AI VectorStore
|
||||
|
||||
Decision: `generate_rag_lookup_snapshots.ps1` defaults to `retrieval.vector-store.mode=spring`.
|
||||
|
||||
Reason: Spring AI VectorStore is the current framework path for the project and should be the default live verification route. SDK mode remains available through `-VectorStoreMode sdk` for comparison.
|
||||
@@ -0,0 +1,87 @@
|
||||
# Evidence: rag-eval-pipeline-closure
|
||||
|
||||
## Changed Assets
|
||||
|
||||
- `scripts/eval_rag_retrieval.py`
|
||||
- `eval/rag-retrieval/cases/golden-cases.json`
|
||||
- `eval/rag-retrieval/fixtures/*.json`
|
||||
- `eval/rag-retrieval/reports/baseline.json`
|
||||
- `eval/rag-retrieval/reports/baseline.md`
|
||||
- `eval/rag-retrieval/README.md`
|
||||
- `mvp/architecture/rag-eval-closure.md`
|
||||
- `src/test/java/com/superbiz/agent/eval/RagLookupSnapshotGeneratorTest.java`
|
||||
- `src/test/java/com/superbiz/agent/eval/RagEvalSeedImporterTest.java`
|
||||
- `scripts/generate_rag_lookup_snapshots.ps1`
|
||||
- `scripts/prepare_rag_eval_seed.ps1`
|
||||
- `eval/rag-retrieval/seed-docs/*.md`
|
||||
- `src/main/java/com/superbiz/agent/dto/Frontmatter.java`
|
||||
- `src/main/java/com/superbiz/agent/dto/KnowledgeEntry.java`
|
||||
- `src/main/java/com/superbiz/agent/service/FrontmatterParser.java`
|
||||
- `src/main/java/com/superbiz/agent/service/KnowledgeIndexService.java`
|
||||
- `src/main/java/com/superbiz/agent/service/DocumentManagementService.java`
|
||||
- `src/main/java/com/superbiz/agent/service/VectorIndexService.java`
|
||||
- `src/main/java/com/superbiz/agent/service/VectorSearchService.java`
|
||||
- `src/main/java/com/superbiz/agent/service/SpringAiVectorStoreSidecarService.java`
|
||||
- `src/main/resources/application.yml`
|
||||
|
||||
## Baseline Result
|
||||
|
||||
```text
|
||||
Evaluated 7 cases: passRate=1.0, recall@5=1.0, failed=0
|
||||
```
|
||||
|
||||
## Regression Signals
|
||||
|
||||
The evaluator now fails on:
|
||||
|
||||
- missing expected source
|
||||
- missing breadcrumb or evidence keyword
|
||||
- non-`lookupResult` fixture
|
||||
- selected attempt mismatch
|
||||
- fallback reason mismatch
|
||||
- fallback reason outside accepted values
|
||||
- evidence status mismatch
|
||||
- missing context source
|
||||
- rerank top source mismatch
|
||||
|
||||
The snapshot generator now provides:
|
||||
|
||||
- real `LookupKnowledgeTool` invocation
|
||||
- one fixture per golden case
|
||||
- explicit opt-in through `rag.snapshot.enabled=true`
|
||||
- optional post-generation baseline evaluation
|
||||
- scoped retrieval through `retrieval.kb-scope=rag-eval`
|
||||
- Spring AI VectorStore by default through `retrieval.vector-store.mode=spring`
|
||||
- scoped L0 hints through the same `retrieval.kb-scope`
|
||||
|
||||
The seed importer now provides:
|
||||
|
||||
- canonical eval docs under `eval/rag-retrieval/seed-docs`
|
||||
- real `DocumentManagementService` import/reindex
|
||||
- stable `source`/`docId` metadata
|
||||
- `kb_scope=rag-eval` isolation from local non-eval documents
|
||||
- frontmatter stripping before chunk embedding
|
||||
- an over-filter decoy seed doc for fallback-path evaluation
|
||||
|
||||
The diff now detects:
|
||||
|
||||
- aggregate pass/recall regression
|
||||
- case pass regression
|
||||
- hit-level regression
|
||||
- first-rank regression
|
||||
- selected attempt/fallback/evidence/rerank changes
|
||||
|
||||
## Final Spring Live Snapshot
|
||||
|
||||
```text
|
||||
.\scripts\generate_rag_lookup_snapshots.ps1 -Fixtures <temp-fixtures> -RetrievedAt 2026-07-06T00:00:00Z
|
||||
Evaluated 7 cases: passRate=1.0, recall@5=1.0, failed=0
|
||||
```
|
||||
|
||||
Key fallback trace:
|
||||
|
||||
```text
|
||||
selectedAttempt=UNFILTERED_VECTOR_RETRY
|
||||
fallbackReason=filtered_vector_no_evidence
|
||||
rerankTopSource=rag-l0-filter-fallback
|
||||
```
|
||||
@@ -0,0 +1,16 @@
|
||||
# Acceptance: executor-evidence-output-contract
|
||||
|
||||
## Draft Acceptance
|
||||
|
||||
- [x] Issue exists: `mvp/issues/active/executor-evidence-attribution-hallucination.md`.
|
||||
- [x] OpenSpec change artifacts exist.
|
||||
- [x] devflow tracking files exist.
|
||||
- [x] OpenSpec validation passes.
|
||||
- [x] Implementation updates Chat Executor prompt.
|
||||
- [x] Implementation passes structured Executor output to Verifier.
|
||||
- [x] Verifier prefers structured claims and still falls back safely.
|
||||
- [x] Focused tests cover parsing, payload assembly, and unsupported confirmed claims.
|
||||
|
||||
## Notes
|
||||
|
||||
This project is currently in proposal/design stage. Runtime code is intentionally not changed yet.
|
||||
@@ -0,0 +1,23 @@
|
||||
# Brief: executor-evidence-output-contract
|
||||
|
||||
## Summary
|
||||
|
||||
Executor currently returns natural-language diagnosis answers that may mix confirmed evidence, runbook guidance, historical patterns, and unsupported inference. Verifier catches many unsupported facts, but only after extracting claims from prose.
|
||||
|
||||
This project defines a structured Executor evidence-attribution contract and updates the Verifier input/verification path to consume it.
|
||||
|
||||
## Goal
|
||||
|
||||
Make Chat Executor output machine-checkable so confirmed claims are explicitly bound to current-session evidence, while hypotheses and evidence gaps remain visibly separate.
|
||||
|
||||
## Scope
|
||||
|
||||
- Chat Executor prompt contract.
|
||||
- Executor structured output parsing.
|
||||
- Verifier payload extension.
|
||||
- Chat Verifier prompt behavior.
|
||||
- Focused tests/eval fixtures.
|
||||
|
||||
## Related OpenSpec
|
||||
|
||||
`openspec/changes/executor-evidence-output-contract/`
|
||||
@@ -0,0 +1,71 @@
|
||||
# Decisions: executor-evidence-output-contract
|
||||
|
||||
## sm-flow Progress
|
||||
|
||||
### Clarify
|
||||
|
||||
Entry summary: recent Chat diagnosis sessions are `LOW_CONFID` because Executor presents unsupported or weakly supported details as confirmed facts after successful tool calls.
|
||||
|
||||
Slug: `executor-evidence-output-contract`
|
||||
|
||||
Scale: standard. This affects prompts, verifier input assembly, parsing behavior, and tests, but does not require a database schema change.
|
||||
|
||||
### Context
|
||||
|
||||
Relevant history:
|
||||
|
||||
- `executor-action-memory-relevance`: Executor already has retrieval quality constraints and should avoid repeated `lookup_knowledge`.
|
||||
- `chat-verifier-agent`: Verifier should not see intermediate reasoning; it receives explicit `original_query`, `executor_final_answer`, `tool_trace_summary`, and `retry_context`.
|
||||
- `evidence-trace-hardening`: evidence-bearing tools persist stable traces and no-evidence semantics.
|
||||
- `modular-rag-pipeline`: `lookup_knowledge` exposes evidence blocks and context packs; L0 hints are not fact evidence.
|
||||
|
||||
Current code shape:
|
||||
|
||||
- `src/main/resources/prompts/chat-executor-prompt.md` is the Chat Executor prompt.
|
||||
- `src/main/resources/prompts/executor-prompt.md` is for the AiOps flow and is not the target of this Chat change.
|
||||
- `VerifierInputHook` currently builds a payload with `original_query`, `executor_final_answer`, `tool_trace_summary`, and `retry_context`.
|
||||
- Verifier prompt currently extracts facts from `executor_final_answer`.
|
||||
|
||||
### Grill
|
||||
|
||||
Question: Should Executor output only JSON or JSON plus readable answer?
|
||||
|
||||
Decision: use one JSON object containing both machine fields and `user_facing_answer`. This avoids losing a readable Chinese answer while giving Verifier structured claims.
|
||||
|
||||
Question: Should evidence binding use `chunk_id`?
|
||||
|
||||
Decision: no. Use generic binding fields because `query_logs` and `query_metrics` do not naturally expose RAG chunks.
|
||||
|
||||
Question: Should Verifier trust Executor-provided claims completely?
|
||||
|
||||
Decision: no. Verifier should verify structured claims first, then scan `user_facing_answer` for extra confirmed-sounding facts omitted from `claims`.
|
||||
|
||||
Question: What happens when Executor JSON is malformed?
|
||||
|
||||
Decision: preserve raw final answer, mark parse failure, and fall back to existing natural-language verification.
|
||||
|
||||
### Specify
|
||||
|
||||
OpenSpec artifacts:
|
||||
|
||||
- `proposal.md`: why and scope
|
||||
- `design.md`: contract, verifier behavior, risks
|
||||
- `specs/chat-verifier-agent/spec.md`: modified and added requirements
|
||||
- `tasks.md`: implementation checklist
|
||||
|
||||
### Audit
|
||||
|
||||
Cross-artifact alignment:
|
||||
|
||||
- Issue describes evidence attribution hallucination.
|
||||
- Proposal scopes the fix to Executor output and Verifier consumption.
|
||||
- Design preserves existing verifier isolation.
|
||||
- Spec adds observable behavior without changing database schema.
|
||||
- Tasks remain implementation-oriented and unchecked.
|
||||
|
||||
Interface impact:
|
||||
|
||||
- Prompt/output contract: L2 internal Agent contract change.
|
||||
- Verifier payload: L2 internal structured input extension.
|
||||
- Database schema: no change.
|
||||
- External HTTP API: no intended change.
|
||||
@@ -0,0 +1,17 @@
|
||||
# Evidence: executor-evidence-output-contract
|
||||
|
||||
## Repository Evidence
|
||||
|
||||
- `chat-executor-prompt.md` currently requires using real tool data but does not require a structured evidence-attribution output.
|
||||
- `chat-verifier-prompt.md` currently extracts facts from `executor_final_answer` prose and compares them with `tool_trace_summary`.
|
||||
- `VerifierInputHook` currently provides `original_query`, `executor_final_answer`, `tool_trace_summary`, and `retry_context`.
|
||||
- `openspec/specs/chat-verifier-agent/spec.md` already requires explicit verifier inputs, auditable evidence refs, fixed verdicts, and low-confidence handling.
|
||||
- `openspec/specs/evidence-trace-hardening/spec.md` already distinguishes failed, no-hit, deduped, and successful evidence-tool traces.
|
||||
|
||||
## Runtime Evidence From Recent Sessions
|
||||
|
||||
Recent MySQL inspection showed repeated `LOW_CONFID` verifier results with many `no_evidence` facts. Typical unsupported claims included OOM, Full GC frequency, specific slow SQL timings, lock waits, and service-specific timeout details that were not supported by current-session tool traces.
|
||||
|
||||
## Design Evidence
|
||||
|
||||
This change preserves the previous design that Verifier should not inspect intermediate reasoning. The new structured output is still final Executor output, not hidden chain-of-thought.
|
||||
@@ -0,0 +1,48 @@
|
||||
# Acceptance: executor-gatekeeper-hook
|
||||
|
||||
## Implementation Result
|
||||
|
||||
Completed stage two of Executor Structured Output V2.
|
||||
|
||||
- Added `ExecutorGatekeeperService`.
|
||||
- Added initial `schema.executor_v2` and `evidence.invocation_ref` rules.
|
||||
- Added `gatekeeper_result` to Verifier payload.
|
||||
- Stored `gatekeeper_result` in `VerifierContextHolder`.
|
||||
- Persisted `gatekeeper_result` under `diagnosis_session.self_evaluation.verifier_evaluation`.
|
||||
- Updated Verifier prompt so Gatekeeper fail must not produce PASS.
|
||||
- Added focused tests for schema failure, valid pass, fabricated invocation ids, tool name mismatch, hook payload, and persistence.
|
||||
|
||||
## Static Verification
|
||||
|
||||
- `cmd /c openspec validate executor-gatekeeper-hook`
|
||||
- Result: passed.
|
||||
- Coverage: OpenSpec change validity.
|
||||
|
||||
## Script Verification
|
||||
|
||||
- `mvn "-Dtest=ExecutorGatekeeperServiceTest,VerifierInputHookTest,ChatServiceSequentialAgentTest" test`
|
||||
- Result: passed.
|
||||
- Coverage: 23 focused tests for Gatekeeper service, hook integration, and ChatService persistence.
|
||||
|
||||
## Browser / Manual Verification
|
||||
|
||||
Not run. This stage changes backend validation and audit behavior only.
|
||||
|
||||
## Unverified
|
||||
|
||||
- Full live application run with a real LLM.
|
||||
- MySQL trace inspection after a real chat session.
|
||||
- Excerpt similarity or phrase/utilization rules.
|
||||
|
||||
Reason: This phase intentionally covers deterministic schema and invocation-reference validation. Full live verification is better after Verifier V2 and Composer are implemented.
|
||||
|
||||
## Remaining Work
|
||||
|
||||
- Phase three: Verifier V2 `claim_checks`.
|
||||
- Phase four: Composer final-answer generation.
|
||||
- Phase five: eval fixtures and full audit closure.
|
||||
|
||||
## Archive Status
|
||||
|
||||
Devflow archive files created for stage two. OpenSpec archive is expected before moving to stage three.
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
# Brief: executor-gatekeeper-hook
|
||||
|
||||
## Background
|
||||
|
||||
Stage one of Executor Structured Output V2 changed Chat Executor output to `executor_evidence_v2`, removing final-expression fields from Executor. That made the output structured, but it did not yet prevent deterministic evidence attribution failures such as fabricated invocation ids, removed fields, empty evidence bindings, or mismatched tool names.
|
||||
|
||||
## Goal
|
||||
|
||||
Add a deterministic Gatekeeper between Executor output parsing and Verifier model execution.
|
||||
|
||||
The Gatekeeper should:
|
||||
|
||||
- Validate the initial Executor V2 schema.
|
||||
- Validate `claims[].evidence_bindings[].source_invocation_ids` against current-session `tool_invocation` rows.
|
||||
- Validate evidence binding `tool_name` against the persisted invocation tool name.
|
||||
- Expose a small `gatekeeper_result` to Verifier and audit persistence.
|
||||
|
||||
## Scope
|
||||
|
||||
Included:
|
||||
|
||||
- New Gatekeeper validation service.
|
||||
- `schema.executor_v2` initial rule.
|
||||
- `evidence.invocation_ref` initial rule.
|
||||
- `VerifierInputHook` payload integration.
|
||||
- `VerifierContextHolder` storage.
|
||||
- `ChatService` verifier evaluation persistence.
|
||||
- Minimal verifier prompt update.
|
||||
- Focused tests for Gatekeeper, hook payload, fabricated invocation ids, tool name mismatch, and persistence.
|
||||
|
||||
Excluded:
|
||||
|
||||
- No Executor retry on Gatekeeper failure.
|
||||
- No excerpt similarity rule in this phase.
|
||||
- No hallucination phrase or evidence utilization rule in this phase.
|
||||
- No Verifier V2 `claim_checks`.
|
||||
- No Composer.
|
||||
- No database schema changes.
|
||||
|
||||
## OpenSpec
|
||||
|
||||
- Change: `openspec/changes/executor-gatekeeper-hook`
|
||||
- Parent stage: `openspec/changes/archive/2026-07-07-executor-v2-output-contract`
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
# Decisions: executor-gatekeeper-hook
|
||||
|
||||
## Key Decisions
|
||||
|
||||
### Gatekeeper stays in VerifierInputHook
|
||||
|
||||
Decision: Gatekeeper is integrated inside `VerifierInputHook`, after Executor output parsing and before Verifier model execution.
|
||||
|
||||
Reason: The user explicitly chose to keep this version in the Verifier hook and not move validation into Executor hook. This preserves the current workflow orchestration.
|
||||
|
||||
### No retry in this phase
|
||||
|
||||
Decision: Gatekeeper failure does not trigger automatic Executor retry.
|
||||
|
||||
Reason: Retry behavior is intentionally deferred. This phase only validates, exposes, and audits deterministic failures.
|
||||
|
||||
### Initial rule set is intentionally small
|
||||
|
||||
Decision: Stage two implements only `schema.executor_v2` and `evidence.invocation_ref` as hard checks.
|
||||
|
||||
Reason: These rules catch the highest-confidence physical failures with low implementation risk. Excerpt similarity, hallucination phrases, and evidence utilization remain later enhancements.
|
||||
|
||||
### No new database schema
|
||||
|
||||
Decision: Persist `gatekeeper_result` in existing `diagnosis_session.self_evaluation.verifier_evaluation`.
|
||||
|
||||
Reason: The user asked to keep database fields minimal. Existing JSON audit storage is enough for this phase.
|
||||
|
||||
### Internal interface impact
|
||||
|
||||
Decision: This is an L2 internal interface extension.
|
||||
|
||||
Impact:
|
||||
|
||||
- Verifier payload gains `gatekeeper_result`.
|
||||
- `VerifierContextHolder` gains Gatekeeper result storage.
|
||||
- `self_evaluation.verifier_evaluation` gains `gatekeeper_result`.
|
||||
- No external API, DTO, database table, or schema migration changes.
|
||||
|
||||
## Deferred Decisions
|
||||
|
||||
- Whether Gatekeeper should later trigger Executor retry.
|
||||
- Whether `evidence.excerpt_similarity` should be hard fail or warn-only.
|
||||
- Whether hallucination phrase and evidence utilization rules should be config-driven from metadata files.
|
||||
- How Verifier V2 `claim_checks` should enforce Gatekeeper failures in code, beyond prompt instruction.
|
||||
|
||||
## Remaining Risks
|
||||
|
||||
- Verifier prompt compliance is not a deterministic guarantee; stage three should make Gatekeeper fail incompatible with PASS in Verifier V2 behavior.
|
||||
- Excerpt authenticity is not checked in this phase, so real invocation ids can still be paired with misleading excerpt text until a later rule is implemented.
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
# Evidence: executor-gatekeeper-hook
|
||||
|
||||
## Context Evidence
|
||||
|
||||
- `executor-v2-output-contract` established `executor_evidence_v2` and removed Executor final-expression fields.
|
||||
- `VerifierInputHook` is the existing integration point for explicit Verifier payload construction.
|
||||
- `ChatService.persistVerifierEvaluation(...)` is the existing persistence path for verifier audit snapshots.
|
||||
- `ToolInvocationRepository.findBySessionIdOrderByIdAsc(...)` provides the current-session invocation pool used by Gatekeeper.
|
||||
|
||||
## Implementation Evidence
|
||||
|
||||
- `src/main/java/com/superbiz/agent/service/ExecutorGatekeeperService.java`
|
||||
- Implements `schema.executor_v2`.
|
||||
- Implements `evidence.invocation_ref`.
|
||||
- Returns `status`, `failed_rules`, `warnings`, and `errors`.
|
||||
|
||||
- `src/main/java/com/superbiz/agent/hook/VerifierInputHook.java`
|
||||
- Runs Gatekeeper after parsing Executor output and building trace summary.
|
||||
- Adds `gatekeeper_result` to Verifier payload.
|
||||
- Stores `gatekeeper_result` in `VerifierContextHolder`.
|
||||
|
||||
- `src/main/java/com/superbiz/agent/util/VerifierContextHolder.java`
|
||||
- Stores per-request Gatekeeper result for later persistence.
|
||||
|
||||
- `src/main/java/com/superbiz/agent/service/ChatService.java`
|
||||
- Wires `ExecutorGatekeeperService` into verifier hook construction.
|
||||
- Persists `gatekeeper_result` under `diagnosis_session.self_evaluation.verifier_evaluation`.
|
||||
|
||||
- `src/main/resources/prompts/chat-verifier-prompt.md`
|
||||
- Documents `gatekeeper_result` as an input.
|
||||
- States Gatekeeper fail must not produce PASS.
|
||||
|
||||
## Test Evidence
|
||||
|
||||
- `src/test/java/com/superbiz/agent/service/ExecutorGatekeeperServiceTest.java`
|
||||
- Covers schema failure and valid pass behavior.
|
||||
- Covers fabricated invocation ids and tool name mismatch.
|
||||
|
||||
- `src/test/java/com/superbiz/agent/hook/VerifierInputHookTest.java`
|
||||
- Covers Verifier payload containing `gatekeeper_result`.
|
||||
- Covers hook behavior for fabricated invocation ids.
|
||||
|
||||
- `src/test/java/com/superbiz/agent/service/ChatServiceSequentialAgentTest.java`
|
||||
- Covers persistence of `gatekeeper_result` into verifier evaluation.
|
||||
|
||||
## Validation Evidence
|
||||
|
||||
- `mvn "-Dtest=ExecutorGatekeeperServiceTest,VerifierInputHookTest,ChatServiceSequentialAgentTest" test`
|
||||
- Result: passed.
|
||||
- Coverage: 23 focused tests.
|
||||
|
||||
- `cmd /c openspec validate executor-gatekeeper-hook`
|
||||
- Result: passed.
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
# Acceptance: executor-v2-output-contract
|
||||
|
||||
## Implementation Result
|
||||
|
||||
Completed stage one of Executor Structured Output V2.
|
||||
|
||||
- Executor prompt now emits `executor_evidence_v2`.
|
||||
- Executor output no longer includes `diagnosis_summary` or `user_facing_answer`.
|
||||
- ChatService PASS path renders V2 structured output into readable Chinese.
|
||||
- VerifierInputHook remains parse-only and accepts V2 output without final-expression fields.
|
||||
|
||||
## Static Verification
|
||||
|
||||
- `cmd /c openspec validate executor-v2-output-contract`
|
||||
- Result: passed.
|
||||
- Coverage: OpenSpec syntax and change validity.
|
||||
|
||||
## Script Verification
|
||||
|
||||
- `mvn "-Dtest=VerifierInputHookTest,ChatServiceSequentialAgentTest" test`
|
||||
- Result: passed.
|
||||
- Coverage: VerifierInputHook V2 parsing; ChatService PASS rendering for V2; existing sequential workflow tests.
|
||||
|
||||
## Browser / Manual Verification
|
||||
|
||||
Not run. This stage changes backend prompt/runtime contract and unit-level behavior only.
|
||||
|
||||
## Unverified
|
||||
|
||||
- Full live application run with a real LLM.
|
||||
- MySQL trace inspection after a real chat session.
|
||||
|
||||
Reason: Stage one is covered by focused unit tests; live verification is more useful after Gatekeeper and Composer phases.
|
||||
|
||||
## Remaining Work
|
||||
|
||||
- Phase two: Gatekeeper in `VerifierInputHook`.
|
||||
- Phase three: Verifier V2 `claim_checks`.
|
||||
- Phase four: Composer.
|
||||
- Phase five: eval fixtures and full audit closure.
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
# Brief: executor-v2-output-contract
|
||||
|
||||
## Background
|
||||
|
||||
`executor_evidence_v1` still made Chat Executor produce both evidence attribution and final user-facing prose through `diagnosis_summary` and `user_facing_answer`.
|
||||
|
||||
This kept Executor in a "diagnose and narrate" role and left room for unsupported conclusions to appear before later verification and composition stages.
|
||||
|
||||
## Goal
|
||||
|
||||
Narrow Chat Executor output to `executor_evidence_v2`: structured diagnostic material only, with final expression removed from Executor.
|
||||
|
||||
## Scope
|
||||
|
||||
- Update Chat Executor prompt to emit `executor_evidence_v2`.
|
||||
- Remove `diagnosis_summary` and `user_facing_answer` from Executor output.
|
||||
- Keep `claims`, `hypotheses`, `recommended_actions`, `missing_info`, and evidence bindings.
|
||||
- Add temporary ChatService rendering for PASS + V2 output so normal users do not see raw JSON.
|
||||
- Preserve V1 `user_facing_answer` extraction for compatibility.
|
||||
|
||||
## Non-Goals
|
||||
|
||||
- No Gatekeeper implementation.
|
||||
- No Verifier V2 `claim_checks`.
|
||||
- No Composer.
|
||||
- No Planner changes.
|
||||
- No database schema changes.
|
||||
- No evidence tool signature changes.
|
||||
|
||||
## Related OpenSpec
|
||||
|
||||
`openspec/changes/archive/2026-07-07-executor-v2-output-contract/`
|
||||
@@ -0,0 +1,39 @@
|
||||
# Decisions: executor-v2-output-contract
|
||||
|
||||
## Key Decisions
|
||||
|
||||
### Executor V2 removes final-expression fields
|
||||
|
||||
Decision: Chat Executor final output now uses `executor_evidence_v2` and must not include `diagnosis_summary` or `user_facing_answer`.
|
||||
|
||||
Reason: Executor should collect evidence and produce structured diagnostic material, not write final user-facing conclusions.
|
||||
|
||||
### Temporary renderer bridges the gap before Composer
|
||||
|
||||
Decision: `ChatService` renders V2 structured fields into readable Chinese only when Verifier returns `PASS`.
|
||||
|
||||
Reason: Composer is a later phase, but external users must not receive raw JSON during this intermediate stage.
|
||||
|
||||
### V1 compatibility remains
|
||||
|
||||
Decision: Existing V1 `user_facing_answer` extraction remains.
|
||||
|
||||
Reason: It keeps old tests and any lingering V1 output compatible while the staged migration continues.
|
||||
|
||||
### Gatekeeper and Verifier V2 are deferred
|
||||
|
||||
Decision: This phase does not add Gatekeeper or `claim_checks`.
|
||||
|
||||
Reason: The user requested phase-by-phase implementation with archive and commit after each phase. Gatekeeper is phase two.
|
||||
|
||||
## Interface Impact
|
||||
|
||||
- Internal Agent output contract: L4, because fields are removed.
|
||||
- Verifier payload: L2, because raw `executor_final_answer` and parsed `executor_structured_output` remain.
|
||||
- External Chat answer: compatible intent; users still get readable Chinese.
|
||||
|
||||
## Risks
|
||||
|
||||
- The temporary renderer is not a full Composer and should be replaced in the Composer phase.
|
||||
- Verifier prompt still uses V1 `facts_checked`; Verifier V2 is a later phase.
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
# Evidence: executor-v2-output-contract
|
||||
|
||||
## Context Used
|
||||
|
||||
- `devflow/projects/2026-07-07-executor-evidence-output-contract`: V1 evidence-attribution contract kept `user_facing_answer`.
|
||||
- `devflow/projects/2026-07-02-chat-verifier-agent`: Verifier consumes explicit inputs and should not see intermediate reasoning.
|
||||
- `devflow/projects/2026-07-04-evidence-trace-hardening`: evidence summaries and tool invocation references are the evidence foundation.
|
||||
- `mvp/issues/design-notes/executor-structured-output-v2.md`: staged implementation design; stage one is Executor V2 output contract.
|
||||
|
||||
## Code Evidence
|
||||
|
||||
- `src/main/resources/prompts/chat-executor-prompt.md`: V2 contract now uses `answer_version="executor_evidence_v2"` and removes final-expression fields.
|
||||
- `src/main/java/com/superbiz/agent/service/ChatService.java`: PASS path now tries V1 `user_facing_answer`, then renders V2 structured output to readable Chinese.
|
||||
- `src/main/resources/prompts/chat-verifier-prompt.md`: `user_facing_answer` is now described as compatibility-only.
|
||||
- `src/test/java/com/superbiz/agent/hook/VerifierInputHookTest.java`: V2 structured output without `user_facing_answer` parses successfully.
|
||||
- `src/test/java/com/superbiz/agent/service/ChatServiceSequentialAgentTest.java`: PASS + V2 output renders Chinese and does not expose raw JSON.
|
||||
|
||||
## Key Finding
|
||||
|
||||
The previous V1 contract intentionally kept `user_facing_answer`, but the V2 staged design intentionally removes it. This is an internal Agent contract break, mitigated by a temporary renderer until Composer is implemented.
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
# Acceptance
|
||||
|
||||
## Implementation Result
|
||||
|
||||
Implemented stage three of Executor Structured Output V2:
|
||||
|
||||
- Verifier prompt now validates claim derivability rather than scanning final natural-language output.
|
||||
- Verifier output supports `claim_checks`.
|
||||
- `ChatService` derives compatibility `facts_checked` from `claim_checks`.
|
||||
- `ChatService` persists both `claim_checks` and `facts_checked`.
|
||||
- Effective verdict guardrails prevent Gatekeeper failures and malformed structured output from remaining `PASS`.
|
||||
- Verifier logging summarizes `claim_checks`.
|
||||
|
||||
## Static Verification
|
||||
|
||||
- Reviewed `git diff --stat` and changed files are scoped to stage three implementation, tests, OpenSpec/devflow, and the issue handoff document.
|
||||
- `cmd /c openspec validate executor-verifier-claim-checks` passed.
|
||||
- After OpenSpec archive, `cmd /c openspec validate --specs` passed.
|
||||
|
||||
## Script Verification
|
||||
|
||||
Passed:
|
||||
|
||||
```powershell
|
||||
mvn "-Dtest=ExecutorGatekeeperServiceTest,VerifierInputHookTest,ChatServiceSequentialAgentTest" test
|
||||
```
|
||||
|
||||
Coverage:
|
||||
|
||||
- Verifier payload and Gatekeeper hook behavior.
|
||||
- Gatekeeper schema/invocation validation.
|
||||
- `claim_checks` parsing and persistence.
|
||||
- `claim_checks` to `facts_checked` compatibility mapping.
|
||||
- all claim verification mapping classes.
|
||||
- Gatekeeper failure downgrade from model `PASS`.
|
||||
- malformed Executor output downgrade from model `PASS`.
|
||||
|
||||
The targeted Maven test command was re-run after OpenSpec archive and passed.
|
||||
|
||||
## Browser / Manual Verification
|
||||
|
||||
Not run. This stage changes backend prompt, parser, audit, and tests only.
|
||||
|
||||
## OpenSpec Archive Status
|
||||
|
||||
Archived:
|
||||
|
||||
```text
|
||||
openspec/changes/archive/2026-07-07-executor-verifier-claim-checks
|
||||
```
|
||||
|
||||
Archive follow-up: the generated canonical `chat-verifier-agent` spec was reviewed and amended to preserve pre-existing verifier input and Gatekeeper schema scenarios while adding the new claim-check scenarios.
|
||||
|
||||
## Remaining Risks
|
||||
|
||||
- Composer is not implemented in this stage; final PASS rendering still uses the temporary V2 renderer until stage four.
|
||||
- Full eval fixture expansion is deferred to stage five.
|
||||
- Existing Maven warnings about duplicate test dependency and Lombok builder defaults remain outside this stage.
|
||||
@@ -0,0 +1,41 @@
|
||||
# Executor Verifier Claim Checks
|
||||
|
||||
## Background
|
||||
|
||||
Stage one moved Chat Executor to `executor_evidence_v2`, and stage two added deterministic Gatekeeper checks before Verifier. After those stages, Verifier still primarily used the legacy `facts_checked` contract and could still treat `executor_final_answer` as a fact source.
|
||||
|
||||
That left two risks:
|
||||
|
||||
- Verifier could still extract extra confirmed facts from natural-language Executor output.
|
||||
- Downstream audit and retry consumers could not distinguish V2 claim-level verification from legacy fact checks.
|
||||
|
||||
## Goal
|
||||
|
||||
Make Verifier V2 claim-oriented:
|
||||
|
||||
- verify `executor_structured_output.claims` as the primary target;
|
||||
- emit `claim_checks` as the authoritative V2 result;
|
||||
- keep `facts_checked` only as a compatibility projection;
|
||||
- enforce code-side guardrails so Gatekeeper failures or malformed structured output cannot remain effective `PASS`.
|
||||
|
||||
## Scope
|
||||
|
||||
- Updated `chat-verifier-prompt.md` to frame verification as claim derivability.
|
||||
- Extended `ChatService` to parse, normalize, map, and persist `claim_checks`.
|
||||
- Added effective verdict guardrails for Gatekeeper failure and malformed/missing Executor structured output.
|
||||
- Updated verifier logging summaries to count `claim_checks`.
|
||||
- Updated sequential workflow tests to cover claim mapping and downgrade behavior.
|
||||
|
||||
## Non-Goals
|
||||
|
||||
- No Composer integration in this phase.
|
||||
- No final-answer material filtering beyond existing templates and temporary V2 renderer.
|
||||
- No Executor retry behavior change.
|
||||
- No Gatekeeper rule expansion.
|
||||
- No database schema migration.
|
||||
|
||||
## OpenSpec
|
||||
|
||||
- Active change before archive: `openspec/changes/executor-verifier-claim-checks`
|
||||
- Capability: `chat-verifier-agent`
|
||||
- Scale: standard
|
||||
@@ -0,0 +1,57 @@
|
||||
# Decisions
|
||||
|
||||
## Scope Decision
|
||||
|
||||
Stage three is limited to Verifier V2 claim checks. Composer is explicitly deferred to stage four.
|
||||
|
||||
Reason: Composer requires stable verifier output and allowed-material filtering; mixing it into this stage would make rollback and acceptance unclear.
|
||||
|
||||
## Contract Decision
|
||||
|
||||
`claim_checks` is the authoritative V2 verifier output.
|
||||
|
||||
`facts_checked` remains as a compatibility projection generated from `claim_checks` when present.
|
||||
|
||||
Reason: existing low-confidence rendering, retry context, trace output, and evaluation code still depend on `facts_checked`.
|
||||
|
||||
## Mapping Decision
|
||||
|
||||
Claim verification maps to legacy facts as follows:
|
||||
|
||||
| claim verification | legacy facts_checked verification |
|
||||
|---|---|
|
||||
| `direct_observation` | `direct_evidence` |
|
||||
| `reasonable_inference` | `indirect_support` |
|
||||
| `overstated` | `indirect_support` |
|
||||
| `unsupported` | `no_evidence` |
|
||||
| `external_unknown` | `no_evidence` |
|
||||
| `contradicted` | `contradicted` |
|
||||
|
||||
## Guardrail Decision
|
||||
|
||||
Effective verdict is enforced in code:
|
||||
|
||||
- `gatekeeper_result.status=fail` cannot remain `PASS`.
|
||||
- `evidence.invocation_ref` failure downgrades to `REJECT`.
|
||||
- Other Gatekeeper failures downgrade at least to `LOW_CONFID`.
|
||||
- missing/malformed Executor structured output cannot remain `PASS`.
|
||||
|
||||
Reason: prompt compliance is not deterministic enough for safety-critical evidence attribution.
|
||||
|
||||
## Apply Fix Record
|
||||
|
||||
Initial targeted Maven verification failed because older tests expected PASS to return Executor natural-language output or V1 `user_facing_answer`.
|
||||
|
||||
Classification: test drift from the committed OpenSpec, not a design blocker.
|
||||
|
||||
Resolution: update tests to use valid Executor V2 output for PASS paths and assert downgrade behavior for malformed or Gatekeeper-failed outputs.
|
||||
|
||||
## Interface Impact
|
||||
|
||||
L2 internal contract extension:
|
||||
|
||||
- Verifier output gains `claim_checks`.
|
||||
- Existing `facts_checked` remains available.
|
||||
- Persistence JSON gains `claim_checks` under existing `self_evaluation`.
|
||||
|
||||
No external API or database schema changes.
|
||||
@@ -0,0 +1,35 @@
|
||||
# Evidence
|
||||
|
||||
## Relevant History
|
||||
|
||||
- `executor-v2-output-contract`: Executor emits `executor_evidence_v2` and no longer emits final-expression fields.
|
||||
- `executor-gatekeeper-hook`: Gatekeeper validates schema and invocation references before Verifier and persists `gatekeeper_result`.
|
||||
- `chat-verifier-agent`: Existing Verifier used `facts_checked`, low-confidence rendering, retry context, and verifier audit.
|
||||
|
||||
## Code Evidence
|
||||
|
||||
- `src/main/resources/prompts/chat-verifier-prompt.md`: Verifier prompt now makes `executor_structured_output.claims` primary and treats `executor_final_answer` as debug/fallback only.
|
||||
- `src/main/java/com/superbiz/agent/service/ChatService.java`: parses `claim_checks`, maps them to compatibility `facts_checked`, persists both, and applies effective verdict guardrails.
|
||||
- `src/main/java/com/superbiz/agent/hook/AgentLoggingHook.java`: verifier thought summaries now include `claim_checks`.
|
||||
- `src/test/java/com/superbiz/agent/service/ChatServiceSequentialAgentTest.java`: covers claim-check mapping, Gatekeeper downgrade, malformed output downgrade, and V2 PASS paths.
|
||||
|
||||
## Evidence-Driven Conclusions
|
||||
|
||||
- `facts_checked` cannot be removed yet because existing low-confidence templates, retry context, trace tooling, and eval paths still consume it.
|
||||
- Prompt-only prevention is insufficient for Gatekeeper failures; `ChatService` must enforce effective verdict downgrades in code.
|
||||
- No database schema migration is needed because `claim_checks` is persisted inside existing `diagnosis_session.self_evaluation`.
|
||||
- Composer remains stage four and must not be mixed into this stage.
|
||||
|
||||
## Verification Evidence
|
||||
|
||||
Script verification passed:
|
||||
|
||||
```powershell
|
||||
mvn "-Dtest=ExecutorGatekeeperServiceTest,VerifierInputHookTest,ChatServiceSequentialAgentTest" test
|
||||
cmd /c openspec validate executor-verifier-claim-checks
|
||||
```
|
||||
|
||||
Known existing warnings:
|
||||
|
||||
- Maven reports duplicate `spring-boot-starter-test` dependency in `pom.xml`.
|
||||
- Existing Lombok `@Builder` default warnings remain.
|
||||
@@ -0,0 +1,48 @@
|
||||
# diagnosis-eval-demo-gatekeeper-closure Acceptance
|
||||
|
||||
## Static / Structure Verification
|
||||
|
||||
- `cmd /c openspec validate diagnosis-eval-demo-gatekeeper-closure --strict`
|
||||
- Result: passed.
|
||||
- `cmd /c openspec validate --specs`
|
||||
- Result: passed, 10 specs passed.
|
||||
|
||||
## Script Verification
|
||||
|
||||
- `mvn "-Dtest=ExecutorGatekeeperServiceTest,DiagnosisTraceEvaluatorTest,DiagnosisEvalBaselineDiffTest,VerifierInputHookTest" test`
|
||||
- Result: 36 tests, 0 failures, 0 errors.
|
||||
- `mvn "-Dtest=DiagnosisTraceEvaluatorTest,DiagnosisEvalBaselineDiffTest,ExecutorGatekeeperServiceTest,VerifierInputHookTest,ChatServiceSequentialAgentTest,ToolInvocationRecorderTest,QueryLogsToolsTest" test`
|
||||
- Result: 61 tests, 0 failures, 0 errors.
|
||||
- `mvn "-Dtest=ExecutorGatekeeperServiceTest,VerifierInputHookTest" test`
|
||||
- Result after E2E startup fix: 23 tests, 0 failures, 0 errors.
|
||||
|
||||
## Live E2E Verification
|
||||
|
||||
- Start command: `mvn spring-boot:run "-Dspring-boot.run.profiles=mvp-demo"`.
|
||||
- Demo command: `powershell -ExecutionPolicy Bypass -File mvp/demo/scripts/run-payment-timeout-demo.ps1`.
|
||||
- Result: chat, trace, and feedback requests completed successfully.
|
||||
- Output files:
|
||||
- `mvp/demo/output/chat-response.json`
|
||||
- `mvp/demo/output/trace-response.json`
|
||||
- `mvp/demo/output/feedback-response.json`
|
||||
- Trace observations:
|
||||
- `hasVerifierEvaluation=true`
|
||||
- `gatekeeper_result.rule_set_version=gatekeeper-rules-v1`
|
||||
|
||||
## Fixed During Verification
|
||||
|
||||
- E2E startup initially failed because Spring could not instantiate `ExecutorGatekeeperService`.
|
||||
- Root cause: two public constructors and no explicit `@Autowired` constructor.
|
||||
- Fix: annotate the production constructor with `@Autowired`.
|
||||
|
||||
## Residual Risk
|
||||
|
||||
- The live payment-timeout path can still produce `LOW_CONFID` because model-generated evidence bindings may omit some explicit `source_invocation_id` values.
|
||||
- This is not a blocker for this change because deterministic matrix behavior is covered by saved fixtures and baseline evaluation.
|
||||
- Existing Maven warnings remain: duplicate `spring-boot-starter-test` declaration and Lombok `@Builder` default warnings.
|
||||
|
||||
## Archive Status
|
||||
|
||||
- Devflow archive artifacts created.
|
||||
- OpenSpec change archived to `openspec/changes/archive/2026-07-08-diagnosis-eval-demo-gatekeeper-closure`.
|
||||
- Main specs synced by `cmd /c openspec archive diagnosis-eval-demo-gatekeeper-closure --yes`.
|
||||
@@ -0,0 +1,33 @@
|
||||
# diagnosis-eval-demo-gatekeeper-closure Brief
|
||||
|
||||
## Background
|
||||
|
||||
The Chat evidence pipeline already had Executor V2 structured output, deterministic Gatekeeper validation, Verifier claim checks, and Composer final rendering. The missing piece was an interview-ready acceptance story that made the anti-hallucination behavior easy to demonstrate and regress.
|
||||
|
||||
## Goal
|
||||
|
||||
Close the next three interview-readiness gaps together:
|
||||
|
||||
- diagnosis eval fixture matrix
|
||||
- stable demo data set
|
||||
- Gatekeeper rule configuration and audit version
|
||||
|
||||
## Scope
|
||||
|
||||
- Expand `mvp/eval` with matrix-oriented cases, fixtures, and baseline reports.
|
||||
- Add stable demo request payloads and scenario documentation.
|
||||
- Add a lightweight local Gatekeeper rule catalog with `rule_set_version` and rule metadata in `gatekeeper_result`.
|
||||
- Update architecture, demo, and eval docs to describe the current implementation.
|
||||
|
||||
## Non-goals
|
||||
|
||||
- No new public HTTP endpoint.
|
||||
- No new database table.
|
||||
- No Planner `scope_contract`.
|
||||
- No Gatekeeper retry loop.
|
||||
- No remote or dynamic rule execution engine.
|
||||
|
||||
## OpenSpec
|
||||
|
||||
- Change: `openspec/changes/diagnosis-eval-demo-gatekeeper-closure`
|
||||
- Interface impact: L2 internal contract change.
|
||||
@@ -0,0 +1,144 @@
|
||||
# diagnosis-eval-demo-gatekeeper-closure Decisions
|
||||
|
||||
## Clarify
|
||||
|
||||
- Entry summary: implement the next three interview-readiness items together: diagnosis eval fixture matrix, stable demo data set, and Gatekeeper rule configuration/audit version.
|
||||
- Slug: `diagnosis-eval-demo-gatekeeper-closure`
|
||||
- Devflow scale: `standard`
|
||||
- Interface impact: expected L2 internal contract change because `gatekeeper_result` audit JSON will gain rule metadata/version fields.
|
||||
|
||||
## Context
|
||||
|
||||
- `devflow/index.md` used: related entries found for diagnosis eval harness, fixture expansion, MVP demo runbook, Gatekeeper hook, and verifier evidence reference fidelity.
|
||||
- Relevant glossary:
|
||||
- Evidence Tools produce incident facts and must be recorded in `tool_invocation`.
|
||||
- Verifier should not use skills/runbooks as incident evidence.
|
||||
- `tool_invocation.retrieval_details` is the structured evidence/audit home for tool-specific details.
|
||||
- Historical constraints that must enter OpenSpec:
|
||||
- Diagnosis eval is offline and deterministic; no LLM-as-judge.
|
||||
- Demo assets should be runnable, but fixed regression should use saved fixtures.
|
||||
- Gatekeeper remains in the Verifier hook path.
|
||||
- No new database table for Gatekeeper audit; use `self_evaluation.verifier_evaluation.gatekeeper_result`.
|
||||
- `$.no_evidence` is a query no-hit signal, not proof that a problem is impossible.
|
||||
|
||||
## Question Pool
|
||||
|
||||
| ID | Dimension | Mode | Question | Status |
|
||||
|---|---|---|---|---|
|
||||
| Q1 | Terminology | evidence-driven | What names should this change use for the matrix, demo set, and Gatekeeper rule metadata? | Resolved |
|
||||
| Q2 | Boundary | evidence-driven | Should this change alter public APIs, database schema, Planner output, or retry behavior? | Resolved |
|
||||
| Q3 | Acceptance | evidence-driven | Which existing tests and baseline assets define the current acceptance style? | Resolved |
|
||||
| Q4 | Technical | evidence-driven | Where should Gatekeeper rule metadata live with minimal implementation risk? | Pending code research |
|
||||
| Q5 | Scope | user-interview | Should the stable demo set be documentation/payloads only, or should it include live E2E scripts for all scenarios? | Confirmed |
|
||||
|
||||
## Evidence-driven Conclusions
|
||||
|
||||
- Q1 conclusion: use `diagnosis eval matrix`, `stable demo scenarios`, and `Gatekeeper rule set version` as terms.
|
||||
- Q2 conclusion: keep this as an internal contract change. Do not add public endpoints, tables, Planner `scope_contract`, or Gatekeeper retry.
|
||||
- Q3 conclusion: existing `DiagnosisTraceEvaluatorTest`, `ExecutorGatekeeperServiceTest`, `VerifierInputHookTest`, `ToolInvocationRecorderTest`, and `mvp/eval/reports` define the current acceptance style.
|
||||
- Q4 conclusion: Gatekeeper metadata should live behind a small rule catalog loaded by `ExecutorGatekeeperService`; the audit output should include a rule set version and enabled rule metadata summary, without adding tables or remote registry.
|
||||
|
||||
## User-interview Confirmations
|
||||
|
||||
- Q5 confirmed by resumed objective: complete items 1/2/3 with sm-flow, archive, submit, and run end-to-end if necessary.
|
||||
- Implementation interpretation: stable demo scenarios will be fixed request payloads and runbook docs plus deterministic fixture-backed eval. Live E2E remains necessary only for at least one main path or where unit/fixture evidence is insufficient.
|
||||
|
||||
## OpenSpec Backfill
|
||||
|
||||
- Created Draft proposal at `openspec/changes/diagnosis-eval-demo-gatekeeper-closure/proposal.md`.
|
||||
- Context constraints from historical devflow entries were written into the proposal.
|
||||
- Scope confirmation and Gatekeeper catalog placement were written into the proposal/design.
|
||||
|
||||
## Current Checkpoint
|
||||
|
||||
- Discover completed.
|
||||
- No implementation files changed yet.
|
||||
|
||||
## Specify / Alignment
|
||||
|
||||
### Cross-artifact Alignment
|
||||
|
||||
| Check | Status | Notes |
|
||||
|---|---|---|
|
||||
| brief/proposal goals -> proposal | Aligned | Proposal covers eval matrix, stable demo scenarios, and Gatekeeper rule catalog/audit version. |
|
||||
| proposal scope/constraints -> design | Aligned | Design records offline deterministic eval, fixture-backed demo distinction, local rule catalog, and no new table/API. |
|
||||
| design decisions -> specs/tasks | Aligned | Specs cover eval matrix, rule set version validation, demo scenarios, and Gatekeeper rule metadata; tasks cover matching implementation slices. |
|
||||
| specs observable behavior -> tasks | Aligned | Each requirement has an executable task and acceptance check. |
|
||||
|
||||
### Interface Impact
|
||||
|
||||
- Level: L2 internal contract change.
|
||||
- Reason: `gatekeeper_result` internal audit JSON gains `rule_set_version` and rule metadata summary. Eval case/result fields may gain optional rule set checks. No public HTTP API, database schema, or external DTO contract changes.
|
||||
|
||||
## Audit
|
||||
|
||||
Input -> processing -> output chain:
|
||||
|
||||
```text
|
||||
mvp/demo request docs + mvp/eval fixtures
|
||||
-> DiagnosisTraceEvaluator
|
||||
-> baseline reports
|
||||
-> interview/demo evidence
|
||||
|
||||
Gatekeeper rule catalog
|
||||
-> ExecutorGatekeeperService
|
||||
-> VerifierInputHook / ChatService persisted self_evaluation
|
||||
-> Trace and eval audit
|
||||
```
|
||||
|
||||
Architecture risk assessment:
|
||||
|
||||
1. The change is intentionally internal and should not add new public consumers.
|
||||
2. Gatekeeper catalog must stay metadata-only; dynamic rule execution would be a different, riskier architecture.
|
||||
3. Fixture-backed demo scenarios should be documented as deterministic regression artifacts, not live LLM guarantees.
|
||||
4. Baseline report churn is expected and must be committed with case/fixture changes.
|
||||
5. No devflow/OpenSpec conflict found.
|
||||
|
||||
## Commit Gate
|
||||
|
||||
- `cmd /c openspec validate diagnosis-eval-demo-gatekeeper-closure --strict`: passed.
|
||||
- `cmd /c openspec validate --specs`: passed, 10 specs passed.
|
||||
- File completeness:
|
||||
- proposal.md: present.
|
||||
- design.md: present.
|
||||
- specs: present for `diagnosis-eval-harness`, `mvp-demo-trace-acceptance`, `chat-verifier-agent`.
|
||||
- tasks.md: present.
|
||||
- Consistency:
|
||||
- Proposal concepts have corresponding design sections.
|
||||
- Design decisions are reflected in specs/tasks.
|
||||
- Task acceptance checks are verifiable.
|
||||
|
||||
## Current Checkpoint
|
||||
|
||||
- Commit completed.
|
||||
- `.committed` marker created.
|
||||
|
||||
## Apply Verification
|
||||
|
||||
- Focused verification passed:
|
||||
- `mvn "-Dtest=ExecutorGatekeeperServiceTest,DiagnosisTraceEvaluatorTest,DiagnosisEvalBaselineDiffTest,VerifierInputHookTest" test`
|
||||
- Result: 36 tests, 0 failures, 0 errors.
|
||||
- Broader relevant regression passed:
|
||||
- `mvn "-Dtest=DiagnosisTraceEvaluatorTest,DiagnosisEvalBaselineDiffTest,ExecutorGatekeeperServiceTest,VerifierInputHookTest,ChatServiceSequentialAgentTest,ToolInvocationRecorderTest,QueryLogsToolsTest" test`
|
||||
- Result: 61 tests, 0 failures, 0 errors.
|
||||
- E2E startup repro found a Spring bean construction issue:
|
||||
- Command: `mvn spring-boot:run "-Dspring-boot.run.profiles=mvp-demo"`
|
||||
- Failure: `ExecutorGatekeeperService` had two public constructors and no annotated constructor, so Spring attempted a no-arg constructor and failed with `No default constructor found`.
|
||||
- Classification: code deviation from OpenSpec implementation intent, not a spec gap.
|
||||
- Fix: annotate the production constructor with `@Autowired`.
|
||||
- Post-fix focused regression passed:
|
||||
- `mvn "-Dtest=ExecutorGatekeeperServiceTest,VerifierInputHookTest" test`
|
||||
- Result: 23 tests, 0 failures, 0 errors.
|
||||
- Live E2E passed for demo compatibility:
|
||||
- Start: `mvn spring-boot:run "-Dspring-boot.run.profiles=mvp-demo"`
|
||||
- Run: `powershell -ExecutionPolicy Bypass -File mvp/demo/scripts/run-payment-timeout-demo.ps1`
|
||||
- Result: `/api/chat`, `/api/diagnosis/{sessionId}/trace`, and `/api/feedback` completed successfully.
|
||||
- Trace summary included `hasVerifierEvaluation=true`.
|
||||
- Persisted Gatekeeper audit included `rule_set_version=gatekeeper-rules-v1`.
|
||||
- Residual quality note: the live payment-timeout response remained `LOW_CONFID` because some model-produced evidence bindings still lacked explicit `source_invocation_id`; deterministic PASS/LOW_CONFID/REJECT claims are covered by fixture-backed eval.
|
||||
|
||||
## Archive Readiness
|
||||
|
||||
- OpenSpec tasks 1-4 completed.
|
||||
- Verification is recorded in devflow acceptance artifacts.
|
||||
- Remaining known risk: live LLM output is not deterministic and may still produce LOW_CONFID on the payment-timeout path; this is intentionally documented as demo compatibility, not a fixed PASS guarantee.
|
||||
@@ -0,0 +1,22 @@
|
||||
# diagnosis-eval-demo-gatekeeper-closure Evidence
|
||||
|
||||
## Code And Artifact Evidence
|
||||
|
||||
- Gatekeeper rule metadata lives in `src/main/resources/gatekeeper/gatekeeper-rules.json`.
|
||||
- `ExecutorGatekeeperService` loads the local catalog, uses configured threshold parameters, and emits `rule_set_version` plus enabled rule metadata.
|
||||
- `VerifierInputHook` and `ChatService` preserve Gatekeeper audit metadata in fallback/default paths.
|
||||
- `DiagnosisTraceEvaluator` can optionally validate expected Gatekeeper rule set version.
|
||||
- `mvp/eval/cases/diagnosis-cases.json` now includes narrow-scope and no-evidence matrix cases.
|
||||
- `mvp/eval/reports/baseline-report.json` and `.md` were regenerated for the expanded fixed matrix.
|
||||
- `mvp/demo/evidence-pipeline-scenarios.md` documents live vs fixture-backed demo scenarios.
|
||||
|
||||
## Decisions
|
||||
|
||||
- Keep this phase internal: no public API, no DB schema, no Planner output change.
|
||||
- Keep Gatekeeper deterministic Java validation; the catalog is metadata/config only.
|
||||
- Treat live demo as compatibility evidence and fixture-backed eval as deterministic regression evidence.
|
||||
- Persist audit under the existing `self_evaluation.verifier_evaluation.gatekeeper_result` structure.
|
||||
|
||||
## Runtime Finding
|
||||
|
||||
The first Maven E2E startup found a real integration issue: `ExecutorGatekeeperService` had multiple public constructors without an annotated constructor, so Spring could not instantiate the service. The fix was to annotate the production constructor with `@Autowired`.
|
||||
@@ -0,0 +1,57 @@
|
||||
# Acceptance
|
||||
|
||||
## Implementation Result
|
||||
|
||||
Implemented stage four of Executor Structured Output V2:
|
||||
|
||||
- Added `chat_composer` prompt and Agent.
|
||||
- Final answers for PASS, LOW_CONFID, and REJECT now use Composer when Verifier decision is valid.
|
||||
- Composer input is filtered from Verifier decision and Executor structured output.
|
||||
- Unsupported, external-unknown, and contradicted claims are excluded from confirmed final-answer material.
|
||||
- REJECT Composer input has `allowed_hypotheses=[]`.
|
||||
- Malformed Composer output uses deterministic safe fallback.
|
||||
- Fallback does not expose raw Composer JSON, raw Executor JSON, or Executor `user_facing_answer`.
|
||||
- `composer_output` is persisted in verifier audit.
|
||||
|
||||
## Static Verification
|
||||
|
||||
- Reviewed implementation diff for stage-four scope.
|
||||
- `cmd /c openspec validate executor-composer-final-answer` passed.
|
||||
- `cmd /c openspec validate --specs` passed before archive.
|
||||
|
||||
## Script Verification
|
||||
|
||||
Passed:
|
||||
|
||||
```powershell
|
||||
mvn "-Dtest=ChatServiceSequentialAgentTest" test
|
||||
mvn "-Dtest=ExecutorGatekeeperServiceTest,VerifierInputHookTest,ChatServiceSequentialAgentTest" test
|
||||
```
|
||||
|
||||
Coverage:
|
||||
|
||||
- Composer prompt loading and invocation.
|
||||
- valid Composer output as final answer source.
|
||||
- malformed Composer output fallback.
|
||||
- PASS no raw Executor JSON leakage.
|
||||
- LOW_CONFID separation of confirmed material, possible directions, and gaps.
|
||||
- REJECT safe output without raw Executor answer.
|
||||
- Gatekeeper and Verifier stage compatibility.
|
||||
|
||||
## Browser / Manual Verification
|
||||
|
||||
Not run. This stage changes backend prompt, routing, parser, audit, and tests only.
|
||||
|
||||
## OpenSpec Archive Status
|
||||
|
||||
Archived:
|
||||
|
||||
```text
|
||||
openspec/changes/archive/2026-07-08-executor-composer-final-answer
|
||||
```
|
||||
|
||||
## Remaining Risks
|
||||
|
||||
- Stage five still needs broader eval fixture coverage for full evidence-attribution regressions.
|
||||
- Composer prompt quality can be improved after real run traces are collected.
|
||||
- Existing Maven warnings about duplicate test dependency and Lombok builder defaults remain outside this stage.
|
||||
@@ -0,0 +1,54 @@
|
||||
# Executor Composer Final Answer
|
||||
|
||||
## Background
|
||||
|
||||
Stages one to three moved the Chat diagnosis chain to structured Executor output, deterministic Gatekeeper validation, and Verifier `claim_checks`.
|
||||
|
||||
Before this stage, `ChatService` still owned final answer rendering. PASS paths could use a temporary V2 renderer, while LOW_CONFID and REJECT paths used templates. That left final user-facing expression too close to Executor material and made it harder to prove that only Verifier-allowed claims reached the user.
|
||||
|
||||
## Goal
|
||||
|
||||
Add a Composer expression layer after Verifier:
|
||||
|
||||
```text
|
||||
chat_planner
|
||||
-> chat_executor
|
||||
-> VerifierInputHook + Gatekeeper
|
||||
-> chat_verifier
|
||||
-> chat_composer
|
||||
-> final answer
|
||||
```
|
||||
|
||||
Composer produces user-facing answers from filtered material only:
|
||||
|
||||
- `allowed_claims`
|
||||
- `allowed_hypotheses`
|
||||
- `missing_info`
|
||||
- `recommended_actions`
|
||||
- `rationale`
|
||||
|
||||
## Scope
|
||||
|
||||
- Added `chat-composer-prompt.md`.
|
||||
- Added `chat_composer` Agent construction in `ChatService`.
|
||||
- Added Composer input filtering from Verifier decision and Executor structured output.
|
||||
- Replaced PASS temporary V2 renderer usage with Composer-or-safe-fallback rendering.
|
||||
- Routed LOW_CONFID and REJECT final answers through Composer when Verifier output is valid.
|
||||
- Added deterministic fallback for malformed Composer output.
|
||||
- Persisted `composer_output` under `diagnosis_session.self_evaluation.verifier_evaluation`.
|
||||
- Updated sequential workflow tests.
|
||||
|
||||
## Non-Goals
|
||||
|
||||
- No Planner changes.
|
||||
- No Executor retry changes.
|
||||
- No Gatekeeper rule expansion.
|
||||
- No Verifier classification expansion.
|
||||
- No database schema migration.
|
||||
- No stage-five eval fixture expansion.
|
||||
|
||||
## OpenSpec
|
||||
|
||||
- Active change before archive: `openspec/changes/executor-composer-final-answer`
|
||||
- Capabilities: `chat-composer-agent`, `chat-verifier-agent`
|
||||
- Scale: standard
|
||||
@@ -0,0 +1,70 @@
|
||||
# Decisions
|
||||
|
||||
## Scope Decision
|
||||
|
||||
Stage four is limited to Composer final-answer generation and routing.
|
||||
|
||||
Reason: Gatekeeper and Verifier contracts were stabilized in earlier stages; this phase should only close the final-expression path.
|
||||
|
||||
## Composer Responsibility
|
||||
|
||||
Composer is an expression layer, not a diagnosis layer.
|
||||
|
||||
It may rephrase and organize only filtered material. It must not call tools, introduce new facts, rejudge root cause, or read raw Executor/tool output.
|
||||
|
||||
## Filtering Decision
|
||||
|
||||
`ChatService` owns Composer input filtering:
|
||||
|
||||
| Verifier classification | Composer handling |
|
||||
|---|---|
|
||||
| `direct_observation` | `allowed_claims` |
|
||||
| `reasonable_inference` | `allowed_claims`, with bounded wording |
|
||||
| `overstated` | `allowed_hypotheses` or `missing_info` |
|
||||
| `unsupported` | `missing_info` |
|
||||
| `external_unknown` | `missing_info` |
|
||||
| `contradicted` | `missing_info` / REJECT-safe output |
|
||||
|
||||
For REJECT, `allowed_hypotheses` is always empty.
|
||||
|
||||
## Fallback Decision
|
||||
|
||||
Malformed Composer output falls back to deterministic rendering from filtered Composer input.
|
||||
|
||||
Fallback must never expose:
|
||||
|
||||
- raw Composer JSON;
|
||||
- raw Executor JSON;
|
||||
- Executor `user_facing_answer`;
|
||||
- full unscreened tool output.
|
||||
|
||||
## Audit Decision
|
||||
|
||||
No new table is added. Composer output is persisted under:
|
||||
|
||||
```text
|
||||
diagnosis_session.self_evaluation.verifier_evaluation.composer_output
|
||||
```
|
||||
|
||||
The audit snapshot is intentionally compact and stores status plus parsed user-facing fields.
|
||||
|
||||
## Apply Fix Record
|
||||
|
||||
Initial targeted verification exposed test drift:
|
||||
|
||||
- test file had a UTF-8 BOM and failed Java compilation;
|
||||
- scripted chat model did not recognize `COMPOSER_TEST_PROMPT`;
|
||||
- older tests expected three-Agent execution and temporary V2 renderer behavior;
|
||||
- LOW_CONFID assertions required indirect support to disappear instead of appearing as a possible direction.
|
||||
|
||||
Resolution: remove BOM, add Composer script branch, and update assertions to match the committed Composer contract.
|
||||
|
||||
## Interface Impact
|
||||
|
||||
L2 internal behavior change:
|
||||
|
||||
- external Chat API still returns a final answer string;
|
||||
- internal final-answer source changes from Executor/temporary renderer to Composer or safe fallback;
|
||||
- audit JSON gains `composer_output` under existing `self_evaluation`.
|
||||
|
||||
No database schema change.
|
||||
@@ -0,0 +1,36 @@
|
||||
# Evidence
|
||||
|
||||
## Relevant History
|
||||
|
||||
- `executor-v2-output-contract`: Executor emits structured diagnostic material and no final-expression fields.
|
||||
- `executor-gatekeeper-hook`: Gatekeeper validates deterministic evidence failures before Verifier.
|
||||
- `executor-verifier-claim-checks`: Verifier emits `claim_checks` and effective verdict guardrails.
|
||||
|
||||
## Code Evidence
|
||||
|
||||
- `src/main/resources/prompts/chat-composer-prompt.md`: defines Composer as an expression layer with strict JSON output.
|
||||
- `src/main/java/com/superbiz/agent/service/ChatService.java`: loads Composer prompt, invokes `chat_composer`, filters Composer input, parses Composer output, falls back safely, and persists Composer audit.
|
||||
- `src/test/java/com/superbiz/agent/service/ChatServiceSequentialAgentTest.java`: covers Composer invocation, fallback, REJECT/LOW_CONFID behavior, and no raw JSON leakage.
|
||||
|
||||
## Evidence-Driven Conclusions
|
||||
|
||||
- Composer must be after Verifier because Verifier `claim_checks` are the authority for allowed final-answer material.
|
||||
- Composer must not receive raw tool output or full unscreened Executor output because that would re-open the evidence attribution problem.
|
||||
- Verifier malformed/missing output should not invoke Composer because there is no trustworthy decision to filter with.
|
||||
- Fixed fallback remains necessary because Composer is an LLM call with a strict JSON contract and can produce malformed output.
|
||||
|
||||
## Verification Evidence
|
||||
|
||||
Passed:
|
||||
|
||||
```powershell
|
||||
mvn "-Dtest=ChatServiceSequentialAgentTest" test
|
||||
mvn "-Dtest=ExecutorGatekeeperServiceTest,VerifierInputHookTest,ChatServiceSequentialAgentTest" test
|
||||
cmd /c openspec validate executor-composer-final-answer
|
||||
cmd /c openspec validate --specs
|
||||
```
|
||||
|
||||
Known existing warnings:
|
||||
|
||||
- Maven reports duplicate `spring-boot-starter-test` dependency in `pom.xml`.
|
||||
- Existing Lombok `@Builder` default warnings remain.
|
||||
@@ -0,0 +1,52 @@
|
||||
# Acceptance
|
||||
|
||||
## Static Verification
|
||||
|
||||
- `openspec validate verifier-evidence-reference-fidelity --strict`: passed.
|
||||
- `openspec validate --specs`: passed.
|
||||
|
||||
## Script Verification
|
||||
|
||||
- `mvn "-Dtest=ToolInvocationRecorderTest,ExecutorGatekeeperServiceTest,VerifierInputHookTest,QueryLogsToolsTest,ChatServiceSequentialAgentTest" test`
|
||||
- Passed: 38 tests.
|
||||
- `mvn "-Dtest=ExecutorGatekeeperServiceTest" test`
|
||||
- Passed: 9 tests.
|
||||
- `mvn test`
|
||||
- Failed on unrelated environment-gated `MilvusConnectionTest.connect`: `MILVUS_TOKEN` environment variable was not set.
|
||||
- Other executed tests in the run progressed until that single failure; focused tests for this change passed.
|
||||
|
||||
## End-to-End Verification
|
||||
|
||||
The Java service was restarted with `mvn spring-boot:run`; logs were written under `logs/`.
|
||||
|
||||
| Case | Session | Result | Gatekeeper Audit |
|
||||
|---|---|---|---|
|
||||
| HikariCP positive | `iss007-hikari-positive-20260708-1553` | PASS; confirmed order-service HikariCP timeout and pool saturation logs | `pass / none`, checked_bindings=2 |
|
||||
| HikariCP negative | `iss007-hikari-negative-20260708-1555` | LOW_CONFID; no `generic-service`; no false positive for inventory-service | `fail / low_confid` |
|
||||
| HighMemoryUsage positive | `iss007-memory-positive-20260708-1558` | PASS; confirmed HighMemoryUsage 91%, did not confirm memory leak | `pass / none`, checked_bindings=1 |
|
||||
| SlowResponse positive | `iss007-slow-positive-20260708-1600` | PASS; confirmed SlowResponse and slow request logs, no DB pool root cause | `pass / none`, checked_bindings=7 |
|
||||
| Narrow HighCPUUsage | `iss007-narrow-highcpu-20260708-1602` | PASS; only covered payment-service HighCPUUsage | `pass / none`, checked_bindings=1 |
|
||||
|
||||
## Database Audit
|
||||
|
||||
`scripts/query_mysql.py` was used to verify:
|
||||
|
||||
- `diagnosis_session.self_evaluation.verifier_evaluation.verdict`
|
||||
- `gatekeeper_result.status`
|
||||
- `gatekeeper_result.severity`
|
||||
- `gatekeeper_result.checked_bindings`
|
||||
- no-hit HikariCP query rows persist `evidence_status=no_evidence`
|
||||
|
||||
## Remaining Risk
|
||||
|
||||
- Negative no-hit claims still have incomplete precise references when Executor uses `$.logs` for empty arrays. Gatekeeper correctly downgrades to `LOW_CONFID`.
|
||||
- Prompt-only scope control is improved but not a hard contract. A future `scope_contract` may still be needed.
|
||||
- Full test suite requires `MILVUS_TOKEN` to pass `MilvusConnectionTest`.
|
||||
|
||||
## OpenSpec Archive
|
||||
|
||||
- `openspec archive verifier-evidence-reference-fidelity --yes`: succeeded.
|
||||
- Main specs updated:
|
||||
- `openspec/specs/chat-verifier-agent/spec.md`
|
||||
- `openspec/specs/evidence-trace-hardening/spec.md`
|
||||
- Non-blocking warning: proposal did not use OpenSpec's preferred `## Why` / `## What Changes` headers, but archive completed.
|
||||
@@ -0,0 +1,44 @@
|
||||
# Verifier Evidence Reference Fidelity
|
||||
|
||||
## Background
|
||||
|
||||
ISS-007 came from end-to-end diagnosis cases where raw tool output and Executor `evidence_excerpt` contained enough facts, but Verifier still returned `LOW_CONFID` because the verifier-facing summary compressed away key details.
|
||||
|
||||
The affected flow is:
|
||||
|
||||
```text
|
||||
chat_planner
|
||||
-> chat_executor
|
||||
-> VerifierInputHook / Gatekeeper
|
||||
-> chat_verifier
|
||||
-> chat_composer
|
||||
```
|
||||
|
||||
The change hardens the evidence handoff between Executor, Gatekeeper, and Verifier.
|
||||
|
||||
## Goal
|
||||
|
||||
Make Executor cite concrete tool evidence, make Gatekeeper validate that citation with code, and make Verifier judge whether verified evidence can derive the claim.
|
||||
|
||||
## Scope
|
||||
|
||||
- Persist `tool_invocation.retrieval_details.evidence_refs`.
|
||||
- Use `source_invocation_id + raw_path + evidence_excerpt` as the precise evidence binding.
|
||||
- Add Gatekeeper `severity` and checked binding audit.
|
||||
- Keep Gatekeeper in the Verifier hook path.
|
||||
- Keep `tool_trace_summary` as navigation/audit context, not the only evidence source.
|
||||
- Fix HikariCP mock positive/no-hit behavior.
|
||||
- Tighten Executor/Verifier prompts for narrow-scope evidence handling.
|
||||
|
||||
## Non-goals
|
||||
|
||||
- No Planner `scope_contract`.
|
||||
- No new database table.
|
||||
- No full JSONPath engine.
|
||||
- No change to external HTTP API.
|
||||
- No retry rollback from Gatekeeper to Executor in this phase.
|
||||
|
||||
## OpenSpec
|
||||
|
||||
- Change: `openspec/changes/verifier-evidence-reference-fidelity`
|
||||
- Source issue: `mvp/issues/archived/ISS-007-verifier-evidence-summary-fidelity.md`
|
||||
@@ -0,0 +1,54 @@
|
||||
# Decisions
|
||||
|
||||
## Evidence Reference
|
||||
|
||||
Use `source_invocation_id + raw_path + evidence_excerpt` as the precise evidence reference for Executor claim bindings.
|
||||
|
||||
Reason:
|
||||
|
||||
- Invocation ID alone only identifies a tool call, not the evidence inside it.
|
||||
- `raw_path` is enough for the first version when paired with `retrieval_details.evidence_refs`.
|
||||
- `evidence_excerpt` remains the text Verifier reads, but only after Gatekeeper validates it.
|
||||
|
||||
## Raw Path
|
||||
|
||||
Only support stable locators in the first version:
|
||||
|
||||
- `$.alerts[i]`
|
||||
- `$.logs[i]`
|
||||
- `$.evidence_blocks[i]`
|
||||
|
||||
No full JSONPath engine is introduced.
|
||||
|
||||
## Gatekeeper Severity
|
||||
|
||||
Gatekeeper output includes:
|
||||
|
||||
- `status`
|
||||
- `severity`
|
||||
- `checked_bindings`
|
||||
- `failed_rules`
|
||||
- `warnings`
|
||||
- `errors`
|
||||
|
||||
Severity meaning:
|
||||
|
||||
- `none`: precise references passed.
|
||||
- `low_confid`: evidence is missing or incomplete, but not fabricated.
|
||||
- `reject`: fabricated ID, wrong tool, unknown raw path, or mismatched excerpt.
|
||||
|
||||
## Verifier Boundary
|
||||
|
||||
Verifier uses verified claim-local excerpts as primary derivability evidence. `tool_trace_summary` remains available for navigation and audit, but no longer needs to carry every concrete fact.
|
||||
|
||||
## Hook Placement
|
||||
|
||||
Gatekeeper remains in the Verifier input hook path. This version does not retry Executor on Gatekeeper failure.
|
||||
|
||||
## Planner
|
||||
|
||||
Planner is not changed. `scope_contract` remains a later-stage idea. This phase uses prompt constraints to reduce narrow-scope over-expansion.
|
||||
|
||||
## Database
|
||||
|
||||
No new tables. Evidence refs are stored in `tool_invocation.retrieval_details.evidence_refs`; audit is stored in `diagnosis_session.self_evaluation.verifier_evaluation.gatekeeper_result`.
|
||||
@@ -0,0 +1,33 @@
|
||||
# Evidence
|
||||
|
||||
## Existing Context
|
||||
|
||||
- Existing `chat-verifier-agent` spec still used `source_invocation_ids` and `tool_trace_summary` as the main verifier evidence context.
|
||||
- Existing `evidence-trace-hardening` spec already established `tool_invocation.retrieval_details` as the right place for structured tool-specific facts.
|
||||
- Prior devflow projects established that runbook/skill content is guidance, not incident evidence.
|
||||
|
||||
## Code Findings
|
||||
|
||||
- `VerifierInputHook` previously backfilled plural `source_invocation_ids` from `tool_trace_summary` by tool name.
|
||||
- `ExecutorGatekeeperService` previously validated invocation existence and tool name, but not `raw_path` or excerpt authenticity.
|
||||
- `ToolInvocationRecorder` persisted retrieval details but did not generate claim-addressable `evidence_refs`.
|
||||
- `QueryLogsTools` could fall back to `generic-service` placeholder logs on no-hit.
|
||||
|
||||
## Implementation Evidence
|
||||
|
||||
- `ToolInvocationRecorder` now extracts:
|
||||
- `$.alerts[i]` for `query_metrics`
|
||||
- `$.logs[i]` for `query_logs`
|
||||
- `$.evidence_blocks[i]` for `lookup_knowledge`
|
||||
- `ExecutorGatekeeperService` now validates:
|
||||
- invocation existence
|
||||
- tool name
|
||||
- raw path presence
|
||||
- `retrieval_details.evidence_refs`
|
||||
- excerpt similarity/support
|
||||
- `VerifierInputHook` only auto-fills a singular `source_invocation_id` when exactly one candidate exists and never invents `raw_path`.
|
||||
- `QueryLogsTools` returns HikariCP mock logs for `order-service` and returns empty no-hit results for unrelated services.
|
||||
|
||||
## Residual Finding
|
||||
|
||||
The HikariCP negative E2E no longer has generic-service pollution, but the model still issued an extra broad HikariCP query without the service filter and used order-service as context. This is a remaining narrow-scope behavior issue, not a mock evidence pollution issue.
|
||||
@@ -0,0 +1,46 @@
|
||||
# Acceptance
|
||||
|
||||
## Static Verification
|
||||
|
||||
- `openspec validate interview-demo-quality-audit --strict`
|
||||
- Result: passed.
|
||||
- Coverage: OpenSpec proposal/design/spec/tasks consistency.
|
||||
- PowerShell parser/runtime readiness check:
|
||||
- Command: `powershell -NoProfile -ExecutionPolicy Bypass -File mvp/demo/scripts/run-interview-demo-check.ps1 -BaseUrl http://127.0.0.1:1 -OutputDir target/demo-check-syntax`
|
||||
- Result: expected failure with actionable readiness message.
|
||||
- Coverage: script parses under Windows PowerShell and fails before issuing diagnosis requests when service is unreachable.
|
||||
|
||||
## Script Verification
|
||||
|
||||
- `mvn -q "-Dtest=DiagnosisTraceEvaluatorTest" test`
|
||||
- Result: passed.
|
||||
- Coverage: 12/12 fixed eval fixtures, Prompt audit evaluator checks, Gatekeeper rule metadata checks, regenerated baseline reports.
|
||||
- `mvn -q "-Dtest=ChatServiceSequentialAgentTest" test`
|
||||
- Result: passed.
|
||||
- Coverage: Chat verifier evaluation persists `prompt_audit`.
|
||||
- `mvn -q "-Dtest=DiagnosisTraceEvaluatorTest,DiagnosisEvalBaselineDiffTest,ChatServiceSequentialAgentTest,ExecutorGatekeeperServiceTest,VerifierInputHookTest" test`
|
||||
- Result: passed.
|
||||
- Coverage: broader eval, baseline diff, Chat sequential flow, Gatekeeper, and Verifier input hook regression set.
|
||||
- `mvn -q -DskipTests compile`
|
||||
- Result: passed.
|
||||
- Coverage: main source compilation.
|
||||
|
||||
## E2E Verification
|
||||
|
||||
- Started service with:
|
||||
- `mvn spring-boot:run -Dspring-boot.run.profiles=mvp-demo`
|
||||
- Ran:
|
||||
- `powershell -NoProfile -ExecutionPolicy Bypass -File mvp/demo/scripts/run-interview-demo-check.ps1 -BaseUrl http://localhost:9900 -SessionId mvp-demo-interview-quality-audit-001`
|
||||
- Result: passed.
|
||||
- Summary:
|
||||
- `chatSuccess=true`
|
||||
- `verdict=LOW_CONFID`
|
||||
- `gatekeeperStatus=fail`
|
||||
- `gatekeeperRuleSetVersion=gatekeeper-rules-v1`
|
||||
- `promptAuditVersion=chat-prompts-v1`
|
||||
- tools included `lookup_knowledge`, `query_logs`, `query_metrics`, and `get_available_log_topics`
|
||||
- Note: live E2E remains a compatibility check, not the deterministic PASS oracle. The fixed fixture baseline is the regression source of truth.
|
||||
|
||||
## Not Verified
|
||||
|
||||
- Browser UI inspection was not required for this change because the scope is backend trace/eval/demo script documentation, not frontend behavior.
|
||||
@@ -0,0 +1,23 @@
|
||||
# Interview Demo Quality Audit Brief
|
||||
|
||||
## Background
|
||||
|
||||
The MVP already demonstrates traceable Agent diagnosis with Planner, Executor, Gatekeeper, Verifier, Composer, evidence tools, trace persistence, and deterministic eval fixtures. The remaining interview-readiness gap is not a new Agent architecture; it is making the demo easier to run and making prompt/rule changes easier to audit.
|
||||
|
||||
## Goal
|
||||
|
||||
Stabilize the interview demo path, expand fixture-backed evaluation, and persist prompt/Gatekeeper audit metadata so the project can explain and verify Agent behavior during interviews.
|
||||
|
||||
## Scope
|
||||
|
||||
- Add prompt audit metadata to Chat verifier evaluation.
|
||||
- Extend deterministic eval cases and baseline reports.
|
||||
- Add an interview demo preflight/check script.
|
||||
- Update MVP demo and architecture documentation.
|
||||
|
||||
## Non-goals
|
||||
|
||||
- No public API or database schema changes.
|
||||
- No new SubAgent split, MCP migration, process isolation, or AIOps LLM Verifier.
|
||||
- No guarantee that every live LLM run returns PASS.
|
||||
|
||||
@@ -0,0 +1,111 @@
|
||||
# interview-demo-quality-audit Decisions
|
||||
|
||||
## Clarify
|
||||
|
||||
- Entry summary: stabilize the interview demo, expand deterministic eval coverage, and add Prompt/Gatekeeper version audit.
|
||||
- Slug: `interview-demo-quality-audit`.
|
||||
- Devflow scale: `standard`.
|
||||
- Interface impact: L2 internal contract change because `verifier_evaluation` gains `prompt_audit`; no public HTTP API or database schema change.
|
||||
|
||||
## Context
|
||||
|
||||
- `devflow/index.md` used: related entries found for `diagnosis-eval-demo-gatekeeper-closure`, `executor-composer-final-answer`, `verifier-evidence-reference-fidelity`, `mvp-demo-interview-runbook`, and `diagnosis-eval-baseline-diff`.
|
||||
- Relevant glossary:
|
||||
- Evidence Tools produce incident facts and must be recorded in `tool_invocation`.
|
||||
- Verifier should not use skills/runbooks as incident evidence.
|
||||
- Diagnosis Playbook Skill is workflow guidance, not a fact source.
|
||||
- Historical constraints that must enter OpenSpec:
|
||||
- Diagnosis eval is deterministic and fixture-backed; no LLM-as-judge.
|
||||
- Stable demo scenarios are documentation/payloads plus deterministic fixtures; live E2E is a compatibility check, not a guaranteed PASS oracle.
|
||||
- Gatekeeper rule metadata is already metadata-only and should not become dynamic rule execution.
|
||||
- Composer is the final expression layer and must not leak raw Executor JSON.
|
||||
|
||||
## Question Pool
|
||||
|
||||
| ID | Dimension | Mode | Question | Status |
|
||||
|---|---|---|---|---|
|
||||
| Q1 | Terminology | evidence-driven | What should the new audit metadata be called? | Resolved |
|
||||
| Q2 | Boundary | evidence-driven | Does this require public API or schema changes? | Resolved |
|
||||
| Q3 | Acceptance | evidence-driven | Which current assets define deterministic acceptance? | Resolved |
|
||||
| Q4 | Technical | evidence-driven | Where should prompt version metadata live with minimal implementation risk? | Resolved |
|
||||
| Q5 | Scope | user-interview | Should live E2E be mandatory for all scenarios? | Confirmed by objective as conditional |
|
||||
|
||||
## Evidence-driven Conclusions
|
||||
|
||||
- Q1 conclusion: use `prompt_audit` for prompt version metadata and keep existing `gatekeeper_result.rule_set_version`.
|
||||
- Q2 conclusion: keep this as an internal trace/self-evaluation contract change. Do not add endpoints, tables, or new Agent roles.
|
||||
- Q3 conclusion: `DiagnosisTraceEvaluatorTest`, baseline reports, fixed fixtures, and demo scripts define current acceptance style.
|
||||
- Q4 conclusion: add a small Chat prompt audit catalog near `ChatService` prompt loading and persist a compact snapshot with verifier evaluation.
|
||||
- Q5 conclusion: run live E2E with `mvp-demo` profile if dependencies are available; otherwise record the blocker and rely on deterministic eval/unit evidence.
|
||||
|
||||
## Specify / Alignment
|
||||
|
||||
| Check | Status | Notes |
|
||||
|---|---|---|
|
||||
| proposal goals -> proposal | Aligned | Proposal covers demo preflight, eval expansion, prompt audit, and docs. |
|
||||
| proposal scope/constraints -> design | Aligned | Design records no public API/schema changes, prompt audit shape, eval fields, and demo script behavior. |
|
||||
| design decisions -> specs/tasks | Aligned | Specs cover persisted prompt audit, evaluator checks, baseline, and demo script outputs. |
|
||||
| specs observable behavior -> tasks | Aligned | Each requirement has implementation and verification tasks. |
|
||||
|
||||
## Audit
|
||||
|
||||
Input -> processing -> output chain:
|
||||
|
||||
```text
|
||||
prompt resource metadata
|
||||
-> ChatService / PromptAudit snapshot
|
||||
-> verifier_evaluation.prompt_audit
|
||||
-> Trace API / eval fixtures
|
||||
-> DiagnosisTraceEvaluator baseline
|
||||
|
||||
run-interview-demo-check.ps1
|
||||
-> service readiness
|
||||
-> chat / trace / feedback
|
||||
-> mvp/demo/output summary
|
||||
```
|
||||
|
||||
Architecture risk assessment:
|
||||
|
||||
1. The audit shape is intentionally compact and internal; storing full prompt text would create noisy traces and possible sensitive-content risk.
|
||||
2. Eval should assert versions by explicit metadata, not by prompt content hashes that churn during local prompt edits.
|
||||
3. Live demo checks may still be LOW_CONFID because LLM output is not deterministic; deterministic fixtures remain the regression source of truth.
|
||||
4. No devflow/OpenSpec conflict found.
|
||||
|
||||
## Commit Gate
|
||||
|
||||
- `openspec validate interview-demo-quality-audit --strict`: passed.
|
||||
- File completeness:
|
||||
- `proposal.md`: present.
|
||||
- `design.md`: present.
|
||||
- `specs/`: present for `chat-verifier-agent`, `diagnosis-eval-harness`, and `mvp-demo-trace-acceptance`.
|
||||
- `tasks.md`: present.
|
||||
- Consistency:
|
||||
- Proposal goals map to design sections.
|
||||
- Design decisions map to spec requirements and executable tasks.
|
||||
- Task acceptance checks are verifiable.
|
||||
- `.committed` marker created.
|
||||
|
||||
## Current Checkpoint
|
||||
|
||||
- Commit completed.
|
||||
- Apply is authorized by the original objective: "完成后归档提交".
|
||||
|
||||
## Pre-apply Research
|
||||
|
||||
- Capability source: sm-flow built-in apply protocol. `openspec-apply-change` was not invoked directly in this session.
|
||||
- Repository semantic search/LSP note: the requested `codebase-retrieval` and LSP tools were not available in the exposed toolset, so impact analysis used `rg`, direct file reads, OpenSpec/devflow artifacts, and targeted tests.
|
||||
- Reference implementation and reuse:
|
||||
- `ChatService.persistVerifierEvaluation(...)` is the single persistence point for Chat verifier/composer audit data; prompt audit was added there to cover normal, fallback, and degraded Composer paths.
|
||||
- `DiagnosisTraceEvaluator` and `DiagnosisEvalReportWriter` are the deterministic eval extension points; no LLM judge was introduced.
|
||||
- `mvp/demo/scripts/run-payment-timeout-demo.ps1` provided the request/trace/feedback flow reused by the new interview preflight script.
|
||||
- Interface impact remains L2 internal trace contract: `verifier_evaluation.prompt_audit` and eval report fields are added; no public endpoint, table, or request DTO changed.
|
||||
|
||||
## Apply Notes
|
||||
|
||||
- Added compact Chat prompt audit metadata: `chat-prompts-v1`, with planner/executor/verifier/composer prompt versions and resource paths.
|
||||
- Extended diagnosis eval schema, result reporting, baseline fixtures, JSON report, and Markdown report for Prompt audit and Gatekeeper rule metadata.
|
||||
- Added two fixture-backed audit cases:
|
||||
- `prompt-gatekeeper-audit-closure`
|
||||
- `audit-metadata-low-confid`
|
||||
- Added `mvp/demo/scripts/run-interview-demo-check.ps1` to run service readiness, Chat, Trace, feedback, and summary output.
|
||||
- Updated MVP demo/eval/architecture docs to explain `prompt_audit.version`, `gatekeeper_result.rule_set_version`, and deterministic fixture baseline.
|
||||
@@ -0,0 +1,58 @@
|
||||
# Evidence
|
||||
|
||||
## Context Files Read
|
||||
|
||||
- `devflow/index.md`
|
||||
- `devflow/glossary/CONTEXT.md`
|
||||
- `devflow/projects/2026-07-08-diagnosis-eval-demo-gatekeeper-closure/decisions.md`
|
||||
- `devflow/projects/2026-07-08-executor-composer-final-answer/decisions.md`
|
||||
- `mvp/architecture/current-mvp-architecture.md`
|
||||
- `mvp/architecture/agent-orchestration.md`
|
||||
- `mvp/architecture/executor-evidence-pipeline-refactor.md`
|
||||
- `mvp/architecture/harness-quality-gates.md`
|
||||
- `mvp/demo/README.md`
|
||||
- `mvp/demo/ten-minute-interview-demo.md`
|
||||
- `mvp/eval/README.md`
|
||||
- `mvp/eval/cases/diagnosis-cases.json`
|
||||
- `src/main/java/com/superbiz/agent/service/ChatService.java`
|
||||
- `src/main/java/com/superbiz/agent/service/ExecutorGatekeeperService.java`
|
||||
- `src/main/java/com/superbiz/agent/eval/DiagnosisTraceEvaluator.java`
|
||||
- `src/main/resources/gatekeeper/gatekeeper-rules.json`
|
||||
|
||||
## Tooling Note
|
||||
|
||||
The required `codebase-retrieval` and LSP tools were not exposed in this session. Impact analysis used `rg`, direct file reads, existing OpenSpec/devflow artifacts, and targeted tests instead.
|
||||
|
||||
## Implementation Evidence
|
||||
|
||||
- `src/main/java/com/superbiz/agent/service/ChatService.java`
|
||||
- Adds `prompt_audit` under `verifier_evaluation` through the shared `persistVerifierEvaluation(...)` path.
|
||||
- Uses compact metadata only: audit version, prompt names, prompt versions, and resource paths.
|
||||
- `src/main/java/com/superbiz/agent/eval/DiagnosisTraceEvaluator.java`
|
||||
- Adds deterministic checks for `requirePromptAudit`, `expectedPromptAuditVersion`, `expectedPromptVersions`, and `requireGatekeeperRules`.
|
||||
- `src/main/java/com/superbiz/agent/eval/DiagnosisEvalReportWriter.java`
|
||||
- Adds Prompt Audit and Gatekeeper rule count columns to Markdown reports.
|
||||
- `mvp/eval/cases/diagnosis-cases.json`
|
||||
- Expands fixed baseline to 12 fixture-backed cases.
|
||||
- `mvp/eval/fixtures/prompt-gatekeeper-audit-closure-pass.json`
|
||||
- Positive PASS fixture proving Prompt audit and Gatekeeper rule metadata closure.
|
||||
- `mvp/eval/fixtures/audit-metadata-low-confid.json`
|
||||
- LOW_CONFID fixture proving safe answer behavior while audit metadata remains present.
|
||||
- `mvp/demo/scripts/run-interview-demo-check.ps1`
|
||||
- Adds service readiness, Chat, Trace, feedback, and summary output for interview preflight.
|
||||
|
||||
## Verification Evidence
|
||||
|
||||
- OpenSpec:
|
||||
- `openspec validate interview-demo-quality-audit --strict`: passed before archive.
|
||||
- `openspec validate --specs --strict`: 10 specs passed after merging deltas into main specs.
|
||||
- Unit/eval:
|
||||
- `mvn -q "-Dtest=DiagnosisTraceEvaluatorTest" test`: passed.
|
||||
- `mvn -q "-Dtest=ChatServiceSequentialAgentTest" test`: passed.
|
||||
- `mvn -q "-Dtest=DiagnosisTraceEvaluatorTest,DiagnosisEvalBaselineDiffTest,ChatServiceSequentialAgentTest,ExecutorGatekeeperServiceTest,VerifierInputHookTest" test`: passed.
|
||||
- Compile:
|
||||
- `mvn -q -DskipTests compile`: passed.
|
||||
- E2E:
|
||||
- Started `mvn spring-boot:run -Dspring-boot.run.profiles=mvp-demo`.
|
||||
- Ran `mvp/demo/scripts/run-interview-demo-check.ps1` against `http://localhost:9900`.
|
||||
- Summary recorded `chatSuccess=true`, `verdict=LOW_CONFID`, `gatekeeperRuleSetVersion=gatekeeper-rules-v1`, and `promptAuditVersion=chat-prompts-v1`.
|
||||
@@ -0,0 +1,103 @@
|
||||
# Acceptance
|
||||
|
||||
## 实现结果
|
||||
|
||||
- OpenSpec tasks: `42/42` complete。
|
||||
- Phase commits:
|
||||
- `52bf030 feat(trace): add session run isolation schema`
|
||||
- `6fdbd34 docs(openspec): tighten run isolation contract`
|
||||
- `26d5529 feat(trace): isolate chat runs`
|
||||
- `027aed1 feat(trace): add run-scoped trace reads`
|
||||
- `d928a19 feat(trace): bind feedback to runs`
|
||||
- `78c1477 feat(trace): isolate aiops runs`
|
||||
- `f9df943 feat(trace): finish run-aware demo verification`
|
||||
- OpenSpec archive: `openspec/changes/archive/2026-07-10-session-run-trace-isolation`
|
||||
|
||||
## 静态验证
|
||||
|
||||
```powershell
|
||||
node --check src\main\resources\static\app.js
|
||||
node --check src\main\resources\static\trace.js
|
||||
openspec validate session-run-trace-isolation --strict
|
||||
git diff --check -- . ':!devflow/index.md'
|
||||
```
|
||||
|
||||
结果:通过。
|
||||
|
||||
## 脚本验证
|
||||
|
||||
PowerShell demo 脚本解析:
|
||||
|
||||
```powershell
|
||||
$scripts = @(
|
||||
'mvp\demo\scripts\run-payment-timeout-demo.ps1',
|
||||
'mvp\demo\scripts\run-interview-demo-check.ps1'
|
||||
)
|
||||
foreach ($script in $scripts) {
|
||||
[scriptblock]::Create((Get-Content -Raw -Encoding UTF8 $script)) | Out-Null
|
||||
}
|
||||
```
|
||||
|
||||
结果:通过。
|
||||
|
||||
Focused tests:
|
||||
|
||||
```powershell
|
||||
mvn -q "-Dtest=ChatControllerTest,DiagnosisTraceServiceTest,FeedbackControllerTest,FeedbackServiceTest,AiOpsServiceTest" test
|
||||
```
|
||||
|
||||
结果:通过。
|
||||
|
||||
Baseline / regression:
|
||||
|
||||
```powershell
|
||||
mvn -q "-Dtest=DiagnosisTraceEvaluatorTest,DiagnosisEvalBaselineDiffTest" test
|
||||
mvn -q "-Dtest=DiagnosisTraceEvaluatorTest,DiagnosisEvalBaselineDiffTest,ExecutorGatekeeperServiceTest,VerifierInputHookTest,ChatServiceSequentialAgentTest" test
|
||||
```
|
||||
|
||||
结果:通过,无 baseline drift。
|
||||
|
||||
## E2E 验证
|
||||
|
||||
使用 Maven 启动:
|
||||
|
||||
```powershell
|
||||
mvn spring-boot:run -Dspring-boot.run.profiles=mvp-demo
|
||||
```
|
||||
|
||||
E2E 使用同一 `sessionId` 连续两轮 Chat:
|
||||
|
||||
- `sessionId`: `e2e-phase6-chat-codex-20260710-2120`
|
||||
- `run1`: `run-e2a97696-4398-4abc-90e4-28f45c838f92`
|
||||
- `run2`: `run-76ce6a6e-92ab-40c9-800a-eca0c1bb5172`
|
||||
|
||||
验证结果:
|
||||
|
||||
- Chat1 / Chat2 均成功。
|
||||
- run1 exact trace 返回 run1。
|
||||
- run2 exact trace 返回 run2。
|
||||
- session-only latest trace 返回 run2。
|
||||
- DB 中同一 session 有两条 `diagnosis_run`。
|
||||
- step/tool rows 按 `run_id` 隔离,mixed row check 为 0。
|
||||
- `chat_session.message_pair_count = 2`。
|
||||
|
||||
## 日志验证
|
||||
|
||||
检查:
|
||||
|
||||
- `target/e2e/phase6-mvn-20260710-211831.out.log`
|
||||
- `logs/application.log`
|
||||
- `logs/chat.log`
|
||||
|
||||
结果:能找到 E2E `sessionId`、两个 `runId`、Chat execution、run persistence 和 trace lookup 相关日志。
|
||||
|
||||
## 浏览器/人工验证
|
||||
|
||||
未单独进行浏览器点击验证。Trace UI 的本次验收通过静态语法检查、URL/runId 参数代码审查和后端 exact trace E2E 共同覆盖。建议后续手动打开 `trace.html?sessionId=...&runId=...` 做展示层冒烟。
|
||||
|
||||
## 剩余风险 / 后续事项
|
||||
|
||||
- 缺少 `runId` 的 Feedback fallback 是短期兼容路径,客户端全部迁移后可收紧。
|
||||
- `diagnosis_session` 仍保留为历史兼容和回滚表,后续需要观察窗口后再评估约束收紧或归档策略。
|
||||
- `case_library.diagnosis_id` 仍是过渡字段,旧值可能为 `session_id`,新自动值为 `run_id`。
|
||||
- 历史 mixed trace 不能恢复真实多轮边界,只能按 compatibility run 查询。
|
||||
@@ -0,0 +1,41 @@
|
||||
# Session / Run / Trace Isolation
|
||||
|
||||
## 背景
|
||||
|
||||
同一个 `sessionId` 以前同时代表多轮 Chat 上下文和一次持久化诊断 Trace。端到端验证发现,同一 `sessionId` 连续两轮 Chat 时,Redis 多轮上下文是正确的,但 MySQL 中 `diagnosis_session` 会被后一轮覆盖,`agent_step` 和 `tool_invocation` 会按同一个 `session_id` 混在一起。
|
||||
|
||||
这会导致 Trace 回放、Verifier/Evaluation 读数、Feedback 绑定和 `case_library` 来源都可能跨轮污染。
|
||||
|
||||
## 目标
|
||||
|
||||
- 将会话态和运行态拆开:`chat_session` 保存会话元数据,`diagnosis_run` 保存一次诊断运行。
|
||||
- 引入正式 API 字段 `runId`,作为一次可回放诊断执行的边界。
|
||||
- `agent_step` 和 `tool_invocation` 保留原 Trace 明细角色,新增 `run_id` 并按 run 隔离读写。
|
||||
- Trace、Feedback、CaseLibrary、AIOps、demo 脚本和 Trace UI 都支持 run-aware 流程。
|
||||
- 保留旧 `diagnosis_session` 作为历史兼容和回滚表。
|
||||
- 完成 Maven E2E、DB 检查、日志检查和 baseline drift 验证。
|
||||
|
||||
## 范围
|
||||
|
||||
- Flyway/JPA 增加 `chat_session`、`diagnosis_run`,并给 `agent_step`、`tool_invocation` 增加 `run_id`。
|
||||
- Chat 每次有效执行创建一个新的 `diagnosis_run`,响应返回 `sessionId + runId`。
|
||||
- Trace API 支持 latest-run fallback 和 exact-run 查询:`GET /api/diagnosis/{sessionId}/trace?runId=...`。
|
||||
- 新增 run list API:`GET /api/chat/session/{sessionId}/runs`。
|
||||
- Feedback 优先绑定 `runId`,缺省时短期 fallback 到 latest run 并返回 `fallbackToLatestRun=true`。
|
||||
- AIOps 每次有效执行创建并透出 `runId`,SSE 保持 `message` event name 并发送 `type=metadata`。
|
||||
- MVP demo、Trace UI、表文档和架构文档统一为 `chat_session -> diagnosis_run -> trace detail(run_id)`。
|
||||
|
||||
## 非目标
|
||||
|
||||
- 不新增 `diagnosis_trace` 或 `trace_event` 主表。
|
||||
- 不实现完整 run-list UI。
|
||||
- 不删除旧 `diagnosis_session`。
|
||||
- 不改变 Redis 对话历史窗口策略。
|
||||
- 不把完整多轮正文历史持久化到 MySQL。
|
||||
- 不尝试把历史混合 trace 还原成真实多轮边界。
|
||||
|
||||
## 关联
|
||||
|
||||
- OpenSpec: `openspec/changes/archive/2026-07-10-session-run-trace-isolation`
|
||||
- Change slug: `session-run-trace-isolation`
|
||||
- 分档: complex
|
||||
@@ -0,0 +1,48 @@
|
||||
# Decisions
|
||||
|
||||
## 核心决策
|
||||
|
||||
| 决策 | 选择 | 理由 |
|
||||
|---|---|---|
|
||||
| 领域拆分 | 新增 `chat_session` 和 `diagnosis_run` | 会话元数据和一次诊断执行的生命周期不同,继续塞在一张表会导致上下文膨胀和边界混淆 |
|
||||
| Trace 明细 | 复用 `agent_step` / `tool_invocation`,增加 `run_id` | 现有明细表已经能表达 Trace,隔离需要 run key,不需要新事件模型 |
|
||||
| API 身份 | `runId = "run-" + UUID` | 外部 ID 不依赖数据库自增 ID,碰撞风险低 |
|
||||
| Trace 兼容 | 缺少 `runId` 时按 `created_at DESC, id DESC` 解析 latest run | 保留旧客户端兼容性,避免 feedback/eval 更新 `updated_at` 后改变 latest 判定 |
|
||||
| 历史迁移 | 每条旧 `diagnosis_session` 生成一条 compatibility run | 旧混合数据没有真实轮次边界,不能伪造多 run 历史 |
|
||||
| Feedback fallback | 缺少 `runId` 时短期绑定 latest run 并返回 `fallbackToLatestRun=true` | 老客户端可继续工作,同时让歧义可观测 |
|
||||
| Case provenance | 新自动案例写 `case_library.diagnosis_id = run_id` | 保留旧列,文档声明过渡语义 |
|
||||
| AIOps 范围 | 同一个 change 内完成 AIOps run isolation | AIOps 是一等 Trace 入口,不能留下同类混合 trace bug |
|
||||
| 所有权校验 | 服务层校验 run/session ownership,暂不加 DB 外键 | 兼容历史 orphan rows 和回滚窗口 |
|
||||
|
||||
## 用户确认
|
||||
|
||||
- 选择拆 `chat_session` 和 `diagnosis_run`,不只是在旧表加字段。
|
||||
- `chat_session` 第一阶段只保存元数据,不保存完整对话正文。
|
||||
- 完整多轮对话历史继续放在 Redis `SessionContext.messageHistory`。
|
||||
- `runId` 是正式 API 字段。
|
||||
- Trace 缺少 `runId` 时短期默认查 latest run。
|
||||
- Feedback 缺少 `runId` 时短期 fallback,长期可再收紧。
|
||||
- 每次有效 Chat/AIOps 都创建 run。
|
||||
- 不新增 `diagnosis_trace` / `trace_event` 主表。
|
||||
- 旧 `diagnosis_session` 保留用于历史和回滚,新代码不再写新执行态。
|
||||
- demo 脚本和 Trace UI 做最小 `runId` 支持。
|
||||
|
||||
## 接口影响
|
||||
|
||||
级别:L4。
|
||||
|
||||
- 新 API 响应字段:`runId`。
|
||||
- Trace API 新 query 参数:`runId`。
|
||||
- 新 API:`GET /api/chat/session/{sessionId}/runs`。
|
||||
- Feedback request 新增 optional/preferred `runId`。
|
||||
- Feedback response 新增 bound `runId` 和 `fallbackToLatestRun`。
|
||||
- `/api/ai_ops` SSE 保持 event name `message`,新增 `type=metadata` 消息。
|
||||
- DB contract 新增两张表和两个 `run_id` 列。
|
||||
- 旧 `sessionId` only 调用仍兼容,但 fallback 必须可观测。
|
||||
|
||||
## 风险接受
|
||||
|
||||
- 历史混合 trace 无法真实拆分,只能作为 compatibility run。
|
||||
- 上下文传播同时依赖 `RunnableConfig.metadata` 和 `SessionContextHolder`,后续改动必须注意 `sessionId/runId` 同步。
|
||||
- `case_library.diagnosis_id` 在过渡期存在 `session_id` 和 `run_id` 两种语义。
|
||||
- 缺少 `runId` 的 Feedback 仍有歧义,后续客户端迁移完成后可收紧为参数错误。
|
||||
@@ -0,0 +1,76 @@
|
||||
# Evidence
|
||||
|
||||
## 上下文证据
|
||||
|
||||
- `SessionContext.messageHistory` 和 `getMessagePairCount()` 证明 Redis 承载热对话历史;MySQL 只需要长期审计的会话目录和运行记录。
|
||||
- `CaseLibraryService.createFromSession` 原先按 `DiagnosisSession.sessionId` 去重并映射 query/answer,因此 run 隔离后需要新增 `createFromRun`。
|
||||
- 旧 `mvp/architecture/data-model.md` 把 `case_library.diagnosis_id` 解释为 `diagnosis_session.session_id`,本次改为过渡语义:旧数据可能是 `session_id`,新自动案例是 `run_id`。
|
||||
- 既有 Trace OpenSpec 要求 `GET /api/diagnosis/{sessionId}/trace` 是只读端点;latest-run 和 exact-run 查询都必须保持只读。
|
||||
- ISS-010 的 E2E 事实显示同一 `sessionId` 两轮 Chat 会产生 MySQL Trace 混合,是本 change 的直接触发证据。
|
||||
|
||||
## 实现证据
|
||||
|
||||
- Phase 1 增加 `V011__add_session_run_isolation.sql`,创建 `chat_session`、`diagnosis_run`,并为 `agent_step` / `tool_invocation` 增加 nullable `run_id`。
|
||||
- Phase 2 将 Chat 写路径切到 `chat_session + diagnosis_run`,并让 Hook/Tool/Evaluation/Gatekeeper 使用 run-scoped 数据。
|
||||
- Phase 3 将 Trace API 改为 latest-run / exact-run 双模式,并加入 lightweight run summaries。
|
||||
- Phase 4 将 Feedback 和 CaseLibrary 绑定到 run,保留没有 run-backed 数据时的 legacy fallback。
|
||||
- Phase 5 将 AIOps 接入 run isolation,SSE metadata 暴露 `sessionId + runId`。
|
||||
- Phase 6 更新 demo 脚本、Trace UI、MVP 架构文档和表文档,并修正 review 后发现的 session-only 文档残留。
|
||||
|
||||
## E2E 证据
|
||||
|
||||
Maven 启动命令:
|
||||
|
||||
```powershell
|
||||
mvn spring-boot:run -Dspring-boot.run.profiles=mvp-demo
|
||||
```
|
||||
|
||||
日志:
|
||||
|
||||
- `target/e2e/phase6-mvn-20260710-211831.out.log`
|
||||
- `target/e2e/phase6-mvn-20260710-211831.err.log`
|
||||
- `logs/application.log`
|
||||
- `logs/chat.log`
|
||||
|
||||
E2E session:
|
||||
|
||||
- `sessionId`: `e2e-phase6-chat-codex-20260710-2120`
|
||||
- `run1`: `run-e2a97696-4398-4abc-90e4-28f45c838f92`
|
||||
- `run2`: `run-76ce6a6e-92ab-40c9-800a-eca0c1bb5172`
|
||||
|
||||
结果:
|
||||
|
||||
- 两轮 Chat 都成功,并复用同一个 `sessionId`。
|
||||
- 两轮返回不同 `runId`。
|
||||
- run1 exact trace 只返回 run1。
|
||||
- run2 exact trace 只返回 run2。
|
||||
- session-only Trace latest fallback 返回 run2。
|
||||
- `chat_session.message_pair_count = 2`,证明多轮上下文连续。
|
||||
|
||||
## DB 证据
|
||||
|
||||
通过 `scripts/query_mysql.py` 检查:
|
||||
|
||||
- `diagnosis_run` 中该 E2E session 有 2 条 `SUCCESS / CHAT` 运行。
|
||||
- `agent_step` 按 run 分组:run1 `10` 行,run2 `9` 行。
|
||||
- `tool_invocation` 按 run 分组:run1 `14` 行,run2 `8` 行。
|
||||
- mixed row check 为 `0`,没有 NULL 或 unexpected `run_id` 混入该 E2E session。
|
||||
|
||||
## Baseline 证据
|
||||
|
||||
运行:
|
||||
|
||||
```powershell
|
||||
mvn -q "-Dtest=DiagnosisTraceEvaluatorTest,DiagnosisEvalBaselineDiffTest" test
|
||||
mvn -q "-Dtest=DiagnosisTraceEvaluatorTest,DiagnosisEvalBaselineDiffTest,ExecutorGatekeeperServiceTest,VerifierInputHookTest,ChatServiceSequentialAgentTest" test
|
||||
```
|
||||
|
||||
结果:
|
||||
|
||||
- 两组 baseline / regression 命令通过。
|
||||
- baseline harness 使用离线 fixture,不依赖 live DB/session tables。
|
||||
- 未观察到 baseline drift。
|
||||
|
||||
## 工具限制
|
||||
|
||||
AGENTS 要求的 `codebase-retrieval` 和 LSP 工具在本会话不可用。替代验证使用 OpenSpec、`rg`、定向阅读、 focused tests、E2E、DB 查询和日志检查。
|
||||
@@ -12,12 +12,59 @@ post-processing, or Spring AI VectorStore integration.
|
||||
```text
|
||||
eval/rag-retrieval/
|
||||
cases/golden-cases.json Fixed retrieval golden cases
|
||||
fixtures/*.json Saved retrieval candidates for each case
|
||||
seed-docs/*.md Canonical docs imported into the live KB for real-tool eval
|
||||
fixtures/*.json Saved retrieval fixtures for each case
|
||||
reports/baseline.json Machine-readable baseline report
|
||||
reports/baseline.md Human-readable baseline report
|
||||
reports/baseline-diff.* Optional diff reports
|
||||
reports/live-post-reindex.* Optional live acceptance reports
|
||||
```
|
||||
|
||||
## Seed Docs + Import/Reindex
|
||||
|
||||
The live-tool eval uses canonical seed documents so the real
|
||||
`LookupKnowledgeTool` can retrieve stable evidence from MySQL/Milvus instead of
|
||||
whatever ad hoc documents happen to exist in the local knowledge base.
|
||||
|
||||
Seed documents live in:
|
||||
|
||||
```text
|
||||
eval/rag-retrieval/seed-docs/*.md
|
||||
```
|
||||
|
||||
Each seed doc uses frontmatter fields that are propagated into vector metadata:
|
||||
|
||||
```yaml
|
||||
source: mysql-connection-pool
|
||||
breadcrumb: Database > MySQL > Connection Pool
|
||||
kb_scope: rag-eval
|
||||
```
|
||||
|
||||
Import or reindex the seed docs through the real upload pipeline:
|
||||
|
||||
```powershell
|
||||
.\scripts\prepare_rag_eval_seed.ps1
|
||||
```
|
||||
|
||||
The script runs `RagEvalSeedImporterTest` with `rag.seed.enabled=true`. It
|
||||
deletes the existing document with the same `source`/`docId`, uploads the seed
|
||||
doc through `DocumentManagementService`, updates DB metadata and L0, and rebuilds
|
||||
Milvus chunks.
|
||||
|
||||
`kb_scope` isolates eval data:
|
||||
|
||||
- default application config leaves `retrieval.kb-scope` empty, so legacy docs
|
||||
without `kb_scope` remain searchable;
|
||||
- eval scripts pass `-Dretrieval.kb-scope=rag-eval`, so L0 query hints and L1
|
||||
vector retrieval both use only the canonical eval seed docs;
|
||||
- the fallback retry skips only the L0 category filter, not the `kb_scope`
|
||||
boundary.
|
||||
|
||||
Frontmatter is not embedded as chunk content during upload. It feeds metadata,
|
||||
L0, and document enrichment; only the Markdown body is chunked and embedded.
|
||||
This keeps controlled L0 decoys from becoming semantically relevant just because
|
||||
their frontmatter keywords matched the query.
|
||||
|
||||
## Run
|
||||
|
||||
From the repository root:
|
||||
@@ -36,6 +83,106 @@ python scripts/eval_rag_retrieval.py \
|
||||
--markdown-report eval/rag-retrieval/reports/baseline.md
|
||||
```
|
||||
|
||||
## Generate Fixtures From LookupKnowledgeTool
|
||||
|
||||
Use the snapshot generator when fixtures should reflect the real
|
||||
`LookupKnowledgeTool` pipeline:
|
||||
|
||||
```powershell
|
||||
.\scripts\generate_rag_lookup_snapshots.ps1
|
||||
```
|
||||
|
||||
For the intended live loop, run seed import first:
|
||||
|
||||
```powershell
|
||||
.\scripts\prepare_rag_eval_seed.ps1
|
||||
.\scripts\generate_rag_lookup_snapshots.ps1
|
||||
python scripts\eval_rag_retrieval.py
|
||||
```
|
||||
|
||||
The script runs a Spring test harness:
|
||||
|
||||
```text
|
||||
mvn -q -Dtest=RagLookupSnapshotGeneratorTest -Drag.snapshot.enabled=true -Dretrieval.kb-scope=rag-eval -Dretrieval.vector-store.mode=spring test
|
||||
```
|
||||
|
||||
The generator reads `golden-cases.json`, injects the real `LookupKnowledgeTool`
|
||||
bean, calls `lookupKnowledge(query)` for each case, writes
|
||||
`fixtures/{caseId}.json`, and then runs `eval_rag_retrieval.py` unless
|
||||
`-SkipEval` is provided. It defaults to Spring AI VectorStore mode; pass
|
||||
`-VectorStoreMode sdk` only when intentionally comparing the legacy SDK path.
|
||||
|
||||
Custom paths are supported:
|
||||
|
||||
```powershell
|
||||
.\scripts\generate_rag_lookup_snapshots.ps1 `
|
||||
-Cases eval\rag-retrieval\cases\golden-cases.json `
|
||||
-Fixtures eval\rag-retrieval\fixtures `
|
||||
-RetrievedAt 2026-07-06T00:00:00Z
|
||||
```
|
||||
|
||||
The generator is disabled in normal test runs. It only executes when
|
||||
`rag.snapshot.enabled=true` is provided because it writes repository files and
|
||||
depends on the configured runtime retrieval stack.
|
||||
|
||||
If generated fixtures fail the offline baseline, treat that as a real alignment
|
||||
signal: either the golden expectations need to be adjusted to the current
|
||||
knowledge base, or the knowledge base/indexing path needs to be fixed.
|
||||
|
||||
## Modular RAG Contract
|
||||
|
||||
Fixtures must use the current `lookupResult` shape, which mirrors the
|
||||
`lookup_knowledge` output:
|
||||
|
||||
```text
|
||||
lookupResult.evidenceBlocks
|
||||
lookupResult.contextPack
|
||||
lookupResult.retrievalTrace
|
||||
lookupResult.rerankTrace
|
||||
```
|
||||
|
||||
Golden cases can assert both retrieval quality and pipeline behavior:
|
||||
|
||||
- `expectedSources` / `expectedDocIds`
|
||||
- `expectedBreadcrumbs`
|
||||
- `expectedKeywords`
|
||||
- `expectedSelectedAttempt`
|
||||
- `expectedFallbackReason`
|
||||
- `expectedFallbackReasons`
|
||||
- `expectedEvidenceStatus`
|
||||
- `expectedContextSources`
|
||||
- `expectedRerankTopSource`
|
||||
|
||||
This lets the baseline catch regressions such as losing the expected evidence
|
||||
source, skipping context packing, changing the selected retrieval attempt, or
|
||||
breaking the filtered-vector to unfiltered-retry fallback.
|
||||
|
||||
## Baseline Diff
|
||||
|
||||
To compare a freshly generated report against an existing baseline:
|
||||
|
||||
```bash
|
||||
python scripts/eval_rag_retrieval.py \
|
||||
--json-report eval/rag-retrieval/reports/current.json \
|
||||
--markdown-report eval/rag-retrieval/reports/current.md \
|
||||
--compare-to eval/rag-retrieval/reports/baseline.json \
|
||||
--diff-json-report eval/rag-retrieval/reports/baseline-diff.json \
|
||||
--diff-markdown-report eval/rag-retrieval/reports/baseline-diff.md
|
||||
```
|
||||
|
||||
The diff reports aggregate regressions and case-level changes for:
|
||||
|
||||
- pass rate, recall@K, strong hit rate, miss count
|
||||
- pass state
|
||||
- hit level
|
||||
- first expected rank
|
||||
- selected attempt
|
||||
- fallback reason
|
||||
- evidence status
|
||||
- rerank top source
|
||||
|
||||
The command exits non-zero when a case fails or the diff contains a regression.
|
||||
|
||||
## Hit Levels
|
||||
|
||||
- `strong`: expected document is found and breadcrumb or evidence keyword coverage is satisfied.
|
||||
@@ -81,6 +228,6 @@ GET /api/search/similar
|
||||
```
|
||||
|
||||
It writes JSON and Markdown reports with query, topK, result count, top
|
||||
candidates, breadcrumb, score labels, and raw response fields. This is a live
|
||||
results, breadcrumb, score labels, and raw response fields. This is a live
|
||||
smoke check for environment readiness and post-reindex behavior; it does not
|
||||
replace the deterministic offline baseline above.
|
||||
|
||||
@@ -8,8 +8,14 @@
|
||||
"scenario": "chat",
|
||||
"query": "MySQL connection pool is exhausted. How should I diagnose it?",
|
||||
"expectedDocIds": ["mysql-connection-pool"],
|
||||
"expectedSources": ["mysql-connection-pool"],
|
||||
"expectedBreadcrumbs": ["Database > MySQL > Connection Pool"],
|
||||
"expectedKeywords": ["connection pool", "max_connections", "HikariCP"],
|
||||
"expectedSelectedAttempt": "FILTERED_VECTOR",
|
||||
"expectedFallbackReason": null,
|
||||
"expectedEvidenceStatus": "supported",
|
||||
"expectedContextSources": ["mysql-connection-pool"],
|
||||
"expectedRerankTopSource": "mysql-connection-pool",
|
||||
"notes": "Covers precise database troubleshooting retrieval."
|
||||
},
|
||||
{
|
||||
@@ -17,8 +23,14 @@
|
||||
"scenario": "chat",
|
||||
"query": "What is the standard troubleshooting flow for an application incident?",
|
||||
"expectedDocIds": ["incident-diagnosis-flow"],
|
||||
"expectedSources": ["incident-diagnosis-flow"],
|
||||
"expectedBreadcrumbs": ["AIOps > Diagnosis Flow"],
|
||||
"expectedKeywords": ["collect evidence", "verify", "remediation"],
|
||||
"expectedSelectedAttempt": "FILTERED_VECTOR",
|
||||
"expectedFallbackReason": null,
|
||||
"expectedEvidenceStatus": "supported",
|
||||
"expectedContextSources": ["incident-diagnosis-flow"],
|
||||
"expectedRerankTopSource": "incident-diagnosis-flow",
|
||||
"notes": "Covers process-style knowledge where breadcrumb matters."
|
||||
},
|
||||
{
|
||||
@@ -26,8 +38,14 @@
|
||||
"scenario": "aiops",
|
||||
"query": "Alert HighLatency on payment-service with p95 latency above threshold",
|
||||
"expectedDocIds": ["payment-service-latency"],
|
||||
"expectedSources": ["payment-service-latency"],
|
||||
"expectedBreadcrumbs": ["AIOps > Service Alerts > Payment Latency"],
|
||||
"expectedKeywords": ["p95 latency", "payment-service", "downstream dependency"],
|
||||
"expectedSelectedAttempt": "FILTERED_VECTOR",
|
||||
"expectedFallbackReason": null,
|
||||
"expectedEvidenceStatus": "supported",
|
||||
"expectedContextSources": ["payment-service-latency"],
|
||||
"expectedRerankTopSource": "payment-service-latency",
|
||||
"notes": "Covers alert payload terms that should become retrieval hints."
|
||||
},
|
||||
{
|
||||
@@ -35,8 +53,14 @@
|
||||
"scenario": "aiops",
|
||||
"query": "When an AIOps request already includes alert payload, should the agent diagnose unrelated active alerts?",
|
||||
"expectedDocIds": ["aiops-alert-scope-control"],
|
||||
"expectedSources": ["aiops-alert-scope-control"],
|
||||
"expectedBreadcrumbs": ["AIOps > Alert Scope Control"],
|
||||
"expectedKeywords": ["payload", "unrelated active alerts", "scope"],
|
||||
"expectedSelectedAttempt": "FILTERED_VECTOR",
|
||||
"expectedFallbackReason": null,
|
||||
"expectedEvidenceStatus": "supported",
|
||||
"expectedContextSources": ["aiops-alert-scope-control"],
|
||||
"expectedRerankTopSource": "aiops-alert-scope-control",
|
||||
"notes": "Covers scoped alert diagnosis behavior."
|
||||
},
|
||||
{
|
||||
@@ -44,8 +68,14 @@
|
||||
"scenario": "chat",
|
||||
"query": "If a long section is split into multiple chunks, how do we keep retrieval context?",
|
||||
"expectedDocIds": ["rag-chunk-context-reconstruction"],
|
||||
"expectedSources": ["rag-chunk-context-reconstruction"],
|
||||
"expectedBreadcrumbs": ["RAG > Chunking > Context Reconstruction"],
|
||||
"expectedKeywords": ["neighbor chunk", "same section", "breadcrumb"],
|
||||
"expectedSelectedAttempt": "FILTERED_VECTOR",
|
||||
"expectedFallbackReason": null,
|
||||
"expectedEvidenceStatus": "supported",
|
||||
"expectedContextSources": ["rag-chunk-context-reconstruction"],
|
||||
"expectedRerankTopSource": "rag-chunk-context-reconstruction",
|
||||
"notes": "Covers the known RAG refactor issue around context reconstruction."
|
||||
},
|
||||
{
|
||||
@@ -53,9 +83,30 @@
|
||||
"scenario": "chat",
|
||||
"query": "Should L0 keyword matching decide the final retrieval result?",
|
||||
"expectedDocIds": ["rag-l0-domain-entity-hint"],
|
||||
"expectedSources": ["rag-l0-domain-entity-hint"],
|
||||
"expectedBreadcrumbs": ["RAG > L0 > Domain Entity Hint"],
|
||||
"expectedKeywords": ["domain detector", "entity extractor", "metadata filter"],
|
||||
"expectedSelectedAttempt": "FILTERED_VECTOR",
|
||||
"expectedFallbackReason": null,
|
||||
"expectedEvidenceStatus": "supported",
|
||||
"expectedContextSources": ["rag-l0-domain-entity-hint"],
|
||||
"expectedRerankTopSource": "rag-l0-domain-entity-hint",
|
||||
"notes": "Covers the target L0 role after refactor."
|
||||
},
|
||||
{
|
||||
"caseId": "chat-l0-filter-fallback",
|
||||
"scenario": "chat",
|
||||
"query": "RAG query was over-filtered by L0 and filtered vector search returned low quality evidence. What should happen?",
|
||||
"expectedDocIds": ["rag-l0-filter-fallback"],
|
||||
"expectedSources": ["rag-l0-filter-fallback"],
|
||||
"expectedBreadcrumbs": ["RAG > Fallback > Unfiltered Retry"],
|
||||
"expectedKeywords": ["skip the L0 filter", "unfiltered vector retry", "low quality"],
|
||||
"expectedSelectedAttempt": "UNFILTERED_VECTOR_RETRY",
|
||||
"expectedFallbackReasons": ["filtered_vector_low_quality", "filtered_vector_no_evidence"],
|
||||
"expectedEvidenceStatus": "supported",
|
||||
"expectedContextSources": ["rag-l0-filter-fallback"],
|
||||
"expectedRerankTopSource": "rag-l0-filter-fallback",
|
||||
"notes": "Covers the MVP fallback rule: if filtered L1 is low quality, retry raw query without L0 filter."
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -1,25 +1,81 @@
|
||||
{
|
||||
"caseId": "aiops-payment-latency-alert",
|
||||
"query": "Alert HighLatency on payment-service with p95 latency above threshold",
|
||||
"retrievedAt": "2026-07-05T00:00:00Z",
|
||||
"candidates": [
|
||||
{
|
||||
"rank": 1,
|
||||
"docId": "payment-service-latency",
|
||||
"title": "Payment Service Latency Alert Playbook",
|
||||
"breadcrumb": "AIOps > Service Alerts > Payment Latency",
|
||||
"content": "For payment-service p95 latency alerts, check downstream dependency latency, thread pool saturation, gateway retries, and recent deployment changes.",
|
||||
"score": 0.84,
|
||||
"retrievalLayer": "L1"
|
||||
"retrievedAt": "2026-07-06T00:00:00Z",
|
||||
"lookupResult": {
|
||||
"found": true,
|
||||
"evidenceBlocks": [
|
||||
{
|
||||
"source": "payment-service-latency",
|
||||
"title": "Payment Service Latency Alert Playbook",
|
||||
"breadcrumb": "AIOps > Service Alerts > Payment Latency",
|
||||
"retrievalLayer": "L1",
|
||||
"content": "For payment-service p95 latency alerts, check downstream dependency latency, thread pool saturation, gateway retries, and recent deployment changes.",
|
||||
"score": 0.84,
|
||||
"hitReasons": ["domain_match:+0.15", "entity_match:+0.20", "keyword_match:+0.10"]
|
||||
},
|
||||
{
|
||||
"source": "mysql-connection-pool",
|
||||
"title": "MySQL Connection Pool Troubleshooting",
|
||||
"breadcrumb": "Database > MySQL > Connection Pool",
|
||||
"retrievalLayer": "L1",
|
||||
"content": "Database connection pool saturation can increase payment latency when checkout paths wait for connections.",
|
||||
"score": 0.68,
|
||||
"hitReasons": ["keyword_match:+0.10"]
|
||||
}
|
||||
],
|
||||
"contextPack": {
|
||||
"packedText": "[1] Payment Service Latency Alert Playbook\nAIOps > Service Alerts > Payment Latency\nFor payment-service p95 latency alerts, check downstream dependency latency, thread pool saturation, gateway retries, and recent deployment changes.",
|
||||
"strategy": "top_evidence_blocks",
|
||||
"charBudget": 3500,
|
||||
"usedChars": 236,
|
||||
"includedSources": ["payment-service-latency", "mysql-connection-pool"],
|
||||
"omittedSources": []
|
||||
},
|
||||
{
|
||||
"rank": 2,
|
||||
"docId": "mysql-connection-pool",
|
||||
"title": "MySQL Connection Pool Troubleshooting",
|
||||
"breadcrumb": "Database > MySQL > Connection Pool",
|
||||
"content": "Database connection pool saturation can increase payment latency when checkout paths wait for connections.",
|
||||
"score": 0.68,
|
||||
"retrievalLayer": "L1"
|
||||
"retrievalTrace": {
|
||||
"originalQuery": "Alert HighLatency on payment-service with p95 latency above threshold",
|
||||
"rewrittenQuery": "HighLatency payment-service p95 latency alert downstream dependency diagnosis",
|
||||
"categoryFilter": "AIOps",
|
||||
"selectedAttempt": "FILTERED_VECTOR",
|
||||
"fallbackReason": null,
|
||||
"evidenceStatus": "supported",
|
||||
"queryHints": {
|
||||
"domains": ["AIOps"],
|
||||
"matched_keywords": ["p95 latency", "payment-service", "downstream dependency"],
|
||||
"entities": ["payment-service", "HighLatency"],
|
||||
"l0_titles": ["Payment Service Latency Alert Playbook"],
|
||||
"l0_match_count": 1
|
||||
},
|
||||
"attempts": [
|
||||
{
|
||||
"name": "FILTERED_VECTOR",
|
||||
"query": "HighLatency payment-service p95 latency alert downstream dependency diagnosis",
|
||||
"categoryFilter": "AIOps",
|
||||
"candidateCount": 2,
|
||||
"usable": true,
|
||||
"durationMs": 11,
|
||||
"topScore": 0.84,
|
||||
"topSimilarity": 0.84
|
||||
}
|
||||
]
|
||||
},
|
||||
"rerankTrace": {
|
||||
"items": [
|
||||
{
|
||||
"finalRank": 1,
|
||||
"source": "payment-service-latency",
|
||||
"baseScore": 0.84,
|
||||
"finalScore": 1.29,
|
||||
"boostReasons": ["domain_match:+0.15", "entity_match:+0.20", "keyword_match:+0.10"]
|
||||
},
|
||||
{
|
||||
"finalRank": 2,
|
||||
"source": "mysql-connection-pool",
|
||||
"baseScore": 0.68,
|
||||
"finalScore": 0.78,
|
||||
"boostReasons": ["keyword_match:+0.10"]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,16 +1,65 @@
|
||||
{
|
||||
"caseId": "aiops-prometheus-alert-scope",
|
||||
"query": "When an AIOps request already includes alert payload, should the agent diagnose unrelated active alerts?",
|
||||
"retrievedAt": "2026-07-05T00:00:00Z",
|
||||
"candidates": [
|
||||
{
|
||||
"rank": 1,
|
||||
"docId": "aiops-alert-scope-control",
|
||||
"title": "AIOps Alert Scope Control",
|
||||
"breadcrumb": "AIOps > Alert Scope Control",
|
||||
"content": "When payload mode is active, queryPrometheusAlerts can verify the supplied alert, but unrelated active alerts must remain scoped context and should not become full diagnoses.",
|
||||
"score": 0.9,
|
||||
"retrievalLayer": "L0+L1"
|
||||
"retrievedAt": "2026-07-06T00:00:00Z",
|
||||
"lookupResult": {
|
||||
"found": true,
|
||||
"evidenceBlocks": [
|
||||
{
|
||||
"source": "aiops-alert-scope-control",
|
||||
"title": "AIOps Alert Scope Control",
|
||||
"breadcrumb": "AIOps > Alert Scope Control",
|
||||
"retrievalLayer": "L1",
|
||||
"content": "When payload mode is used, diagnose the input alert payload and do not expand unrelated active alerts into the main diagnosis scope.",
|
||||
"score": 0.88,
|
||||
"hitReasons": ["domain_match:+0.15", "keyword_match:+0.10"]
|
||||
}
|
||||
],
|
||||
"contextPack": {
|
||||
"packedText": "[1] AIOps Alert Scope Control\nAIOps > Alert Scope Control\nWhen payload mode is used, diagnose the input alert payload and do not expand unrelated active alerts into the main diagnosis scope.",
|
||||
"strategy": "top_evidence_blocks",
|
||||
"charBudget": 3500,
|
||||
"usedChars": 188,
|
||||
"includedSources": ["aiops-alert-scope-control"],
|
||||
"omittedSources": []
|
||||
},
|
||||
"retrievalTrace": {
|
||||
"originalQuery": "When an AIOps request already includes alert payload, should the agent diagnose unrelated active alerts?",
|
||||
"rewrittenQuery": "AIOps alert payload scope unrelated active alerts diagnosis",
|
||||
"categoryFilter": "AIOps",
|
||||
"selectedAttempt": "FILTERED_VECTOR",
|
||||
"fallbackReason": null,
|
||||
"evidenceStatus": "supported",
|
||||
"queryHints": {
|
||||
"domains": ["AIOps"],
|
||||
"matched_keywords": ["payload", "unrelated active alerts", "scope"],
|
||||
"entities": ["alert payload"],
|
||||
"l0_titles": ["AIOps Alert Scope Control"],
|
||||
"l0_match_count": 1
|
||||
},
|
||||
"attempts": [
|
||||
{
|
||||
"name": "FILTERED_VECTOR",
|
||||
"query": "AIOps alert payload scope unrelated active alerts diagnosis",
|
||||
"categoryFilter": "AIOps",
|
||||
"candidateCount": 1,
|
||||
"usable": true,
|
||||
"durationMs": 8,
|
||||
"topScore": 0.88,
|
||||
"topSimilarity": 0.88
|
||||
}
|
||||
]
|
||||
},
|
||||
"rerankTrace": {
|
||||
"items": [
|
||||
{
|
||||
"finalRank": 1,
|
||||
"source": "aiops-alert-scope-control",
|
||||
"baseScore": 0.88,
|
||||
"finalScore": 1.13,
|
||||
"boostReasons": ["domain_match:+0.15", "keyword_match:+0.10"]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,25 +1,81 @@
|
||||
{
|
||||
"caseId": "chat-diagnosis-flow",
|
||||
"query": "What is the standard troubleshooting flow for an application incident?",
|
||||
"retrievedAt": "2026-07-05T00:00:00Z",
|
||||
"candidates": [
|
||||
{
|
||||
"rank": 1,
|
||||
"docId": "incident-diagnosis-flow",
|
||||
"title": "Incident Diagnosis Flow",
|
||||
"breadcrumb": "AIOps > Diagnosis Flow",
|
||||
"content": "The standard flow is to collect evidence, identify the suspected fault domain, verify the hypothesis, apply remediation, and confirm recovery.",
|
||||
"score": 0.82,
|
||||
"retrievalLayer": "L1"
|
||||
"retrievedAt": "2026-07-06T00:00:00Z",
|
||||
"lookupResult": {
|
||||
"found": true,
|
||||
"evidenceBlocks": [
|
||||
{
|
||||
"source": "incident-diagnosis-flow",
|
||||
"title": "Incident Diagnosis Flow",
|
||||
"breadcrumb": "AIOps > Diagnosis Flow",
|
||||
"retrievalLayer": "L1",
|
||||
"content": "The standard flow is to collect evidence, identify the suspected fault domain, verify the hypothesis, apply remediation, and confirm recovery.",
|
||||
"score": 0.82,
|
||||
"hitReasons": ["domain_match:+0.15", "keyword_match:+0.10"]
|
||||
},
|
||||
{
|
||||
"source": "rag-chunk-context-reconstruction",
|
||||
"title": "RAG Chunk Context Reconstruction",
|
||||
"breadcrumb": "RAG > Chunking > Context Reconstruction",
|
||||
"retrievalLayer": "L1",
|
||||
"content": "Long sections may require neighbor chunk expansion and breadcrumb-aware packing.",
|
||||
"score": 0.55,
|
||||
"hitReasons": []
|
||||
}
|
||||
],
|
||||
"contextPack": {
|
||||
"packedText": "[1] Incident Diagnosis Flow\nAIOps > Diagnosis Flow\nThe standard flow is to collect evidence, identify the suspected fault domain, verify the hypothesis, apply remediation, and confirm recovery.",
|
||||
"strategy": "top_evidence_blocks",
|
||||
"charBudget": 3500,
|
||||
"usedChars": 192,
|
||||
"includedSources": ["incident-diagnosis-flow", "rag-chunk-context-reconstruction"],
|
||||
"omittedSources": []
|
||||
},
|
||||
{
|
||||
"rank": 2,
|
||||
"docId": "rag-chunk-context-reconstruction",
|
||||
"title": "RAG Chunk Context Reconstruction",
|
||||
"breadcrumb": "RAG > Chunking > Context Reconstruction",
|
||||
"content": "Long sections may require neighbor chunk expansion and breadcrumb-aware packing.",
|
||||
"score": 0.55,
|
||||
"retrievalLayer": "L1"
|
||||
"retrievalTrace": {
|
||||
"originalQuery": "What is the standard troubleshooting flow for an application incident?",
|
||||
"rewrittenQuery": "standard application incident troubleshooting flow collect evidence verify remediation",
|
||||
"categoryFilter": "AIOps",
|
||||
"selectedAttempt": "FILTERED_VECTOR",
|
||||
"fallbackReason": null,
|
||||
"evidenceStatus": "supported",
|
||||
"queryHints": {
|
||||
"domains": ["AIOps"],
|
||||
"matched_keywords": ["collect evidence", "verify", "remediation"],
|
||||
"entities": ["application incident"],
|
||||
"l0_titles": ["Incident Diagnosis Flow"],
|
||||
"l0_match_count": 1
|
||||
},
|
||||
"attempts": [
|
||||
{
|
||||
"name": "FILTERED_VECTOR",
|
||||
"query": "standard application incident troubleshooting flow collect evidence verify remediation",
|
||||
"categoryFilter": "AIOps",
|
||||
"candidateCount": 2,
|
||||
"usable": true,
|
||||
"durationMs": 10,
|
||||
"topScore": 0.82,
|
||||
"topSimilarity": 0.82
|
||||
}
|
||||
]
|
||||
},
|
||||
"rerankTrace": {
|
||||
"items": [
|
||||
{
|
||||
"finalRank": 1,
|
||||
"source": "incident-diagnosis-flow",
|
||||
"baseScore": 0.82,
|
||||
"finalScore": 1.07,
|
||||
"boostReasons": ["domain_match:+0.15", "keyword_match:+0.10"]
|
||||
},
|
||||
{
|
||||
"finalRank": 2,
|
||||
"source": "rag-chunk-context-reconstruction",
|
||||
"baseScore": 0.55,
|
||||
"finalScore": 0.55,
|
||||
"boostReasons": []
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,25 +1,81 @@
|
||||
{
|
||||
"caseId": "chat-l0-domain-hint",
|
||||
"query": "Should L0 keyword matching decide the final retrieval result?",
|
||||
"retrievedAt": "2026-07-05T00:00:00Z",
|
||||
"candidates": [
|
||||
{
|
||||
"rank": 1,
|
||||
"docId": "rag-l0-domain-entity-hint",
|
||||
"title": "RAG L0 Domain Entity Hint",
|
||||
"breadcrumb": "RAG > L0 > Domain Entity Hint",
|
||||
"content": "L0 should be retained as a domain detector, entity extractor, metadata filter generator, and explainability signal, not as the final retrieval decision.",
|
||||
"score": 0.88,
|
||||
"retrievalLayer": "L0"
|
||||
"retrievedAt": "2026-07-06T00:00:00Z",
|
||||
"lookupResult": {
|
||||
"found": true,
|
||||
"evidenceBlocks": [
|
||||
{
|
||||
"source": "rag-l0-domain-entity-hint",
|
||||
"title": "RAG L0 Domain Entity Hint",
|
||||
"breadcrumb": "RAG > L0 > Domain Entity Hint",
|
||||
"retrievalLayer": "L1",
|
||||
"content": "L0 should be retained as a domain detector, entity extractor, metadata filter generator, and explainability signal, not as the final retrieval decision.",
|
||||
"score": 0.88,
|
||||
"hitReasons": ["domain_match:+0.15", "keyword_match:+0.10"]
|
||||
},
|
||||
{
|
||||
"source": "rag-l0-l1-fusion-ranking",
|
||||
"title": "RAG L0 L1 Fusion Ranking",
|
||||
"breadcrumb": "RAG > Ranking > Fusion",
|
||||
"retrievalLayer": "L1",
|
||||
"content": "L0 and L1 candidates should eventually be fused rather than handled as an early-return branch.",
|
||||
"score": 0.75,
|
||||
"hitReasons": ["domain_match:+0.15"]
|
||||
}
|
||||
],
|
||||
"contextPack": {
|
||||
"packedText": "[1] RAG L0 Domain Entity Hint\nRAG > L0 > Domain Entity Hint\nL0 should be retained as a domain detector, entity extractor, metadata filter generator, and explainability signal, not as the final retrieval decision.",
|
||||
"strategy": "top_evidence_blocks",
|
||||
"charBudget": 3500,
|
||||
"usedChars": 219,
|
||||
"includedSources": ["rag-l0-domain-entity-hint", "rag-l0-l1-fusion-ranking"],
|
||||
"omittedSources": []
|
||||
},
|
||||
{
|
||||
"rank": 2,
|
||||
"docId": "rag-l0-l1-fusion-ranking",
|
||||
"title": "RAG L0 L1 Fusion Ranking",
|
||||
"breadcrumb": "RAG > Ranking > Fusion",
|
||||
"content": "L0 and L1 candidates should eventually be fused rather than handled as an early-return branch.",
|
||||
"score": 0.75,
|
||||
"retrievalLayer": "L1"
|
||||
"retrievalTrace": {
|
||||
"originalQuery": "Should L0 keyword matching decide the final retrieval result?",
|
||||
"rewrittenQuery": "RAG L0 keyword matching domain entity hint final retrieval decision",
|
||||
"categoryFilter": "RAG",
|
||||
"selectedAttempt": "FILTERED_VECTOR",
|
||||
"fallbackReason": null,
|
||||
"evidenceStatus": "supported",
|
||||
"queryHints": {
|
||||
"domains": ["RAG"],
|
||||
"matched_keywords": ["domain detector", "entity extractor", "metadata filter"],
|
||||
"entities": ["L0"],
|
||||
"l0_titles": ["RAG L0 Domain Entity Hint"],
|
||||
"l0_match_count": 1
|
||||
},
|
||||
"attempts": [
|
||||
{
|
||||
"name": "FILTERED_VECTOR",
|
||||
"query": "RAG L0 keyword matching domain entity hint final retrieval decision",
|
||||
"categoryFilter": "RAG",
|
||||
"candidateCount": 2,
|
||||
"usable": true,
|
||||
"durationMs": 9,
|
||||
"topScore": 0.88,
|
||||
"topSimilarity": 0.88
|
||||
}
|
||||
]
|
||||
},
|
||||
"rerankTrace": {
|
||||
"items": [
|
||||
{
|
||||
"finalRank": 1,
|
||||
"source": "rag-l0-domain-entity-hint",
|
||||
"baseScore": 0.88,
|
||||
"finalScore": 1.13,
|
||||
"boostReasons": ["domain_match:+0.15", "keyword_match:+0.10"]
|
||||
},
|
||||
{
|
||||
"finalRank": 2,
|
||||
"source": "rag-l0-l1-fusion-ranking",
|
||||
"baseScore": 0.75,
|
||||
"finalScore": 0.9,
|
||||
"boostReasons": ["domain_match:+0.15"]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,91 @@
|
||||
{
|
||||
"caseId": "chat-l0-filter-fallback",
|
||||
"query": "RAG query was over-filtered by L0 and filtered vector search returned low quality evidence. What should happen?",
|
||||
"retrievedAt": "2026-07-06T00:00:00Z",
|
||||
"lookupResult": {
|
||||
"found": true,
|
||||
"evidenceBlocks": [
|
||||
{
|
||||
"source": "rag-l0-filter-fallback",
|
||||
"title": "RAG L0 Filter Fallback",
|
||||
"breadcrumb": "RAG > Fallback > Unfiltered Retry",
|
||||
"retrievalLayer": "L1",
|
||||
"content": "When filtered vector retrieval is low quality, skip the L0 filter and run an unfiltered vector retry with the raw query before returning no evidence.",
|
||||
"score": 0.83,
|
||||
"hitReasons": ["domain_match:+0.15", "keyword_match:+0.10"]
|
||||
},
|
||||
{
|
||||
"source": "rag-l0-domain-entity-hint",
|
||||
"title": "RAG L0 Domain Entity Hint",
|
||||
"breadcrumb": "RAG > L0 > Domain Entity Hint",
|
||||
"retrievalLayer": "L1",
|
||||
"content": "L0 supplies hints for metadata filtering and explanation, but it should not be treated as final fact evidence.",
|
||||
"score": 0.66,
|
||||
"hitReasons": ["domain_match:+0.15"]
|
||||
}
|
||||
],
|
||||
"contextPack": {
|
||||
"packedText": "[1] RAG L0 Filter Fallback\nRAG > Fallback > Unfiltered Retry\nWhen filtered vector retrieval is low quality, skip the L0 filter and run an unfiltered vector retry with the raw query before returning no evidence.",
|
||||
"strategy": "top_evidence_blocks",
|
||||
"charBudget": 3500,
|
||||
"usedChars": 214,
|
||||
"includedSources": ["rag-l0-filter-fallback", "rag-l0-domain-entity-hint"],
|
||||
"omittedSources": []
|
||||
},
|
||||
"retrievalTrace": {
|
||||
"originalQuery": "RAG query was over-filtered by L0 and filtered vector search returned low quality evidence. What should happen?",
|
||||
"rewrittenQuery": "RAG L0 filtered vector low quality fallback unfiltered retry",
|
||||
"categoryFilter": "RAG",
|
||||
"selectedAttempt": "UNFILTERED_VECTOR_RETRY",
|
||||
"fallbackReason": "filtered_vector_low_quality",
|
||||
"evidenceStatus": "supported",
|
||||
"queryHints": {
|
||||
"domains": ["RAG"],
|
||||
"matched_keywords": ["L0", "low quality", "unfiltered vector retry"],
|
||||
"entities": ["L0"],
|
||||
"l0_titles": ["RAG L0 Domain Entity Hint"],
|
||||
"l0_match_count": 1
|
||||
},
|
||||
"attempts": [
|
||||
{
|
||||
"name": "FILTERED_VECTOR",
|
||||
"query": "RAG L0 filtered vector low quality fallback unfiltered retry",
|
||||
"categoryFilter": "RAG",
|
||||
"candidateCount": 1,
|
||||
"usable": false,
|
||||
"durationMs": 7,
|
||||
"topScore": 1.35,
|
||||
"topSimilarity": 0.325
|
||||
},
|
||||
{
|
||||
"name": "UNFILTERED_VECTOR_RETRY",
|
||||
"query": "RAG query was over-filtered by L0 and filtered vector search returned low quality evidence. What should happen?",
|
||||
"categoryFilter": null,
|
||||
"candidateCount": 2,
|
||||
"usable": true,
|
||||
"durationMs": 13,
|
||||
"topScore": 0.83,
|
||||
"topSimilarity": 0.83
|
||||
}
|
||||
]
|
||||
},
|
||||
"rerankTrace": {
|
||||
"items": [
|
||||
{
|
||||
"finalRank": 1,
|
||||
"source": "rag-l0-filter-fallback",
|
||||
"baseScore": 0.83,
|
||||
"finalScore": 1.08,
|
||||
"boostReasons": ["domain_match:+0.15", "keyword_match:+0.10"]
|
||||
},
|
||||
{
|
||||
"finalRank": 2,
|
||||
"source": "rag-l0-domain-entity-hint",
|
||||
"baseScore": 0.66,
|
||||
"finalScore": 0.81,
|
||||
"boostReasons": ["domain_match:+0.15"]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,25 +1,81 @@
|
||||
{
|
||||
"caseId": "chat-mysql-connection-pool",
|
||||
"query": "MySQL connection pool is exhausted. How should I diagnose it?",
|
||||
"retrievedAt": "2026-07-05T00:00:00Z",
|
||||
"candidates": [
|
||||
{
|
||||
"rank": 1,
|
||||
"docId": "mysql-connection-pool",
|
||||
"title": "MySQL Connection Pool Troubleshooting",
|
||||
"breadcrumb": "Database > MySQL > Connection Pool",
|
||||
"content": "When the connection pool is exhausted, inspect HikariCP active connections, max_connections, slow SQL, leak detection, and database wait events.",
|
||||
"score": 0.86,
|
||||
"retrievalLayer": "L0+L1"
|
||||
"retrievedAt": "2026-07-06T00:00:00Z",
|
||||
"lookupResult": {
|
||||
"found": true,
|
||||
"evidenceBlocks": [
|
||||
{
|
||||
"source": "mysql-connection-pool",
|
||||
"title": "MySQL Connection Pool Troubleshooting",
|
||||
"breadcrumb": "Database > MySQL > Connection Pool",
|
||||
"retrievalLayer": "L1",
|
||||
"content": "When the connection pool is exhausted, inspect HikariCP active connections, max_connections, slow SQL, leak detection, and database wait events.",
|
||||
"score": 0.86,
|
||||
"hitReasons": ["domain_match:+0.15", "keyword_match:+0.10"]
|
||||
},
|
||||
{
|
||||
"source": "incident-diagnosis-flow",
|
||||
"title": "Incident Diagnosis Flow",
|
||||
"breadcrumb": "AIOps > Diagnosis Flow",
|
||||
"retrievalLayer": "L1",
|
||||
"content": "Collect evidence, compare metrics and logs, then verify remediation before closing the incident.",
|
||||
"score": 0.61,
|
||||
"hitReasons": []
|
||||
}
|
||||
],
|
||||
"contextPack": {
|
||||
"packedText": "[1] MySQL Connection Pool Troubleshooting\nDatabase > MySQL > Connection Pool\nWhen the connection pool is exhausted, inspect HikariCP active connections, max_connections, slow SQL, leak detection, and database wait events.",
|
||||
"strategy": "top_evidence_blocks",
|
||||
"charBudget": 3500,
|
||||
"usedChars": 216,
|
||||
"includedSources": ["mysql-connection-pool", "incident-diagnosis-flow"],
|
||||
"omittedSources": []
|
||||
},
|
||||
{
|
||||
"rank": 2,
|
||||
"docId": "incident-diagnosis-flow",
|
||||
"title": "Incident Diagnosis Flow",
|
||||
"breadcrumb": "AIOps > Diagnosis Flow",
|
||||
"content": "Collect evidence, compare metrics and logs, then verify remediation before closing the incident.",
|
||||
"score": 0.61,
|
||||
"retrievalLayer": "L1"
|
||||
"retrievalTrace": {
|
||||
"originalQuery": "MySQL connection pool is exhausted. How should I diagnose it?",
|
||||
"rewrittenQuery": "MySQL connection pool exhausted HikariCP max_connections diagnosis",
|
||||
"categoryFilter": "Database",
|
||||
"selectedAttempt": "FILTERED_VECTOR",
|
||||
"fallbackReason": null,
|
||||
"evidenceStatus": "supported",
|
||||
"queryHints": {
|
||||
"domains": ["Database", "MySQL"],
|
||||
"matched_keywords": ["connection pool", "HikariCP", "max_connections"],
|
||||
"entities": ["MySQL", "HikariCP"],
|
||||
"l0_titles": ["MySQL Connection Pool Troubleshooting"],
|
||||
"l0_match_count": 1
|
||||
},
|
||||
"attempts": [
|
||||
{
|
||||
"name": "FILTERED_VECTOR",
|
||||
"query": "MySQL connection pool exhausted HikariCP max_connections diagnosis",
|
||||
"categoryFilter": "Database",
|
||||
"candidateCount": 2,
|
||||
"usable": true,
|
||||
"durationMs": 12,
|
||||
"topScore": 0.86,
|
||||
"topSimilarity": 0.86
|
||||
}
|
||||
]
|
||||
},
|
||||
"rerankTrace": {
|
||||
"items": [
|
||||
{
|
||||
"finalRank": 1,
|
||||
"source": "mysql-connection-pool",
|
||||
"baseScore": 0.86,
|
||||
"finalScore": 1.11,
|
||||
"boostReasons": ["domain_match:+0.15", "keyword_match:+0.10"]
|
||||
},
|
||||
{
|
||||
"finalRank": 2,
|
||||
"source": "incident-diagnosis-flow",
|
||||
"baseScore": 0.61,
|
||||
"finalScore": 0.61,
|
||||
"boostReasons": []
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,25 +1,81 @@
|
||||
{
|
||||
"caseId": "chat-rag-chunk-context",
|
||||
"query": "If a long section is split into multiple chunks, how do we keep retrieval context?",
|
||||
"retrievedAt": "2026-07-05T00:00:00Z",
|
||||
"candidates": [
|
||||
{
|
||||
"rank": 1,
|
||||
"docId": "rag-chunk-context-reconstruction",
|
||||
"title": "RAG Chunk Context Reconstruction",
|
||||
"breadcrumb": "RAG > Chunking > Context Reconstruction",
|
||||
"content": "After a chunk hit, expand to neighbor chunk candidates from the same section and preserve breadcrumb metadata in the evidence pack.",
|
||||
"score": 0.79,
|
||||
"retrievalLayer": "L1"
|
||||
"retrievedAt": "2026-07-06T00:00:00Z",
|
||||
"lookupResult": {
|
||||
"found": true,
|
||||
"evidenceBlocks": [
|
||||
{
|
||||
"source": "rag-chunk-context-reconstruction",
|
||||
"title": "RAG Chunk Context Reconstruction",
|
||||
"breadcrumb": "RAG > Chunking > Context Reconstruction",
|
||||
"retrievalLayer": "L1",
|
||||
"content": "After a chunk hit, expand to neighbor chunk candidates from the same section and preserve breadcrumb metadata in the evidence pack.",
|
||||
"score": 0.79,
|
||||
"hitReasons": ["domain_match:+0.15", "keyword_match:+0.10"]
|
||||
},
|
||||
{
|
||||
"source": "rag-breadcrumb-embedding-gap",
|
||||
"title": "RAG Breadcrumb Embedding Gap",
|
||||
"breadcrumb": "RAG > Embedding > Breadcrumb",
|
||||
"retrievalLayer": "L1",
|
||||
"content": "Embedding title and breadcrumb with content helps recover section semantics.",
|
||||
"score": 0.72,
|
||||
"hitReasons": ["domain_match:+0.15"]
|
||||
}
|
||||
],
|
||||
"contextPack": {
|
||||
"packedText": "[1] RAG Chunk Context Reconstruction\nRAG > Chunking > Context Reconstruction\nAfter a chunk hit, expand to neighbor chunk candidates from the same section and preserve breadcrumb metadata in the evidence pack.",
|
||||
"strategy": "top_evidence_blocks",
|
||||
"charBudget": 3500,
|
||||
"usedChars": 203,
|
||||
"includedSources": ["rag-chunk-context-reconstruction", "rag-breadcrumb-embedding-gap"],
|
||||
"omittedSources": []
|
||||
},
|
||||
{
|
||||
"rank": 2,
|
||||
"docId": "rag-breadcrumb-embedding-gap",
|
||||
"title": "RAG Breadcrumb Embedding Gap",
|
||||
"breadcrumb": "RAG > Embedding > Breadcrumb",
|
||||
"content": "Embedding title and breadcrumb with content helps recover section semantics.",
|
||||
"score": 0.72,
|
||||
"retrievalLayer": "L1"
|
||||
"retrievalTrace": {
|
||||
"originalQuery": "If a long section is split into multiple chunks, how do we keep retrieval context?",
|
||||
"rewrittenQuery": "RAG chunk context reconstruction neighbor chunk same section breadcrumb",
|
||||
"categoryFilter": "RAG",
|
||||
"selectedAttempt": "FILTERED_VECTOR",
|
||||
"fallbackReason": null,
|
||||
"evidenceStatus": "supported",
|
||||
"queryHints": {
|
||||
"domains": ["RAG"],
|
||||
"matched_keywords": ["neighbor chunk", "same section", "breadcrumb"],
|
||||
"entities": ["chunk", "breadcrumb"],
|
||||
"l0_titles": ["RAG Chunk Context Reconstruction"],
|
||||
"l0_match_count": 1
|
||||
},
|
||||
"attempts": [
|
||||
{
|
||||
"name": "FILTERED_VECTOR",
|
||||
"query": "RAG chunk context reconstruction neighbor chunk same section breadcrumb",
|
||||
"categoryFilter": "RAG",
|
||||
"candidateCount": 2,
|
||||
"usable": true,
|
||||
"durationMs": 9,
|
||||
"topScore": 0.79,
|
||||
"topSimilarity": 0.79
|
||||
}
|
||||
]
|
||||
},
|
||||
"rerankTrace": {
|
||||
"items": [
|
||||
{
|
||||
"finalRank": 1,
|
||||
"source": "rag-chunk-context-reconstruction",
|
||||
"baseScore": 0.79,
|
||||
"finalScore": 1.04,
|
||||
"boostReasons": ["domain_match:+0.15", "keyword_match:+0.10"]
|
||||
},
|
||||
{
|
||||
"finalRank": 2,
|
||||
"source": "rag-breadcrumb-embedding-gap",
|
||||
"baseScore": 0.72,
|
||||
"finalScore": 0.87,
|
||||
"boostReasons": ["domain_match:+0.15"]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +1,15 @@
|
||||
{
|
||||
"generatedAt": "2026-07-04T17:59:52.172759+00:00",
|
||||
"generatedAt": "2026-07-06T13:37:59.726351+00:00",
|
||||
"caseFile": "eval/rag-retrieval/cases/golden-cases.json",
|
||||
"fixtureDir": "eval/rag-retrieval/fixtures",
|
||||
"aggregate": {
|
||||
"caseCount": 6,
|
||||
"caseCount": 7,
|
||||
"topK": 5,
|
||||
"strongHitCount": 6,
|
||||
"passedCount": 7,
|
||||
"failedCount": 0,
|
||||
"passRate": 1.0,
|
||||
"lookupResultCaseCount": 7,
|
||||
"strongHitCount": 7,
|
||||
"mediumHitCount": 0,
|
||||
"weakHitCount": 0,
|
||||
"missCount": 0,
|
||||
@@ -18,6 +22,7 @@
|
||||
"caseId": "chat-mysql-connection-pool",
|
||||
"scenario": "chat",
|
||||
"query": "MySQL connection pool is exhausted. How should I diagnose it?",
|
||||
"dataShape": "lookupResult",
|
||||
"hitLevel": "strong",
|
||||
"passed": true,
|
||||
"firstExpectedRank": 1,
|
||||
@@ -31,12 +36,22 @@
|
||||
"hikaricp"
|
||||
],
|
||||
"breadcrumbMatched": true,
|
||||
"selectedAttempt": "FILTERED_VECTOR",
|
||||
"fallbackReason": null,
|
||||
"evidenceStatus": "supported",
|
||||
"includedSources": [
|
||||
"mysql-connection-pool",
|
||||
"incident-diagnosis-flow"
|
||||
],
|
||||
"omittedSources": [],
|
||||
"rerankTopSource": "mysql-connection-pool",
|
||||
"failedChecks": []
|
||||
},
|
||||
{
|
||||
"caseId": "chat-diagnosis-flow",
|
||||
"scenario": "chat",
|
||||
"query": "What is the standard troubleshooting flow for an application incident?",
|
||||
"dataShape": "lookupResult",
|
||||
"hitLevel": "strong",
|
||||
"passed": true,
|
||||
"firstExpectedRank": 1,
|
||||
@@ -50,12 +65,22 @@
|
||||
"remediation"
|
||||
],
|
||||
"breadcrumbMatched": true,
|
||||
"selectedAttempt": "FILTERED_VECTOR",
|
||||
"fallbackReason": null,
|
||||
"evidenceStatus": "supported",
|
||||
"includedSources": [
|
||||
"incident-diagnosis-flow",
|
||||
"rag-chunk-context-reconstruction"
|
||||
],
|
||||
"omittedSources": [],
|
||||
"rerankTopSource": "incident-diagnosis-flow",
|
||||
"failedChecks": []
|
||||
},
|
||||
{
|
||||
"caseId": "aiops-payment-latency-alert",
|
||||
"scenario": "aiops",
|
||||
"query": "Alert HighLatency on payment-service with p95 latency above threshold",
|
||||
"dataShape": "lookupResult",
|
||||
"hitLevel": "strong",
|
||||
"passed": true,
|
||||
"firstExpectedRank": 1,
|
||||
@@ -69,12 +94,22 @@
|
||||
"downstream dependency"
|
||||
],
|
||||
"breadcrumbMatched": true,
|
||||
"selectedAttempt": "FILTERED_VECTOR",
|
||||
"fallbackReason": null,
|
||||
"evidenceStatus": "supported",
|
||||
"includedSources": [
|
||||
"payment-service-latency",
|
||||
"mysql-connection-pool"
|
||||
],
|
||||
"omittedSources": [],
|
||||
"rerankTopSource": "payment-service-latency",
|
||||
"failedChecks": []
|
||||
},
|
||||
{
|
||||
"caseId": "aiops-prometheus-alert-scope",
|
||||
"scenario": "aiops",
|
||||
"query": "When an AIOps request already includes alert payload, should the agent diagnose unrelated active alerts?",
|
||||
"dataShape": "lookupResult",
|
||||
"hitLevel": "strong",
|
||||
"passed": true,
|
||||
"firstExpectedRank": 1,
|
||||
@@ -87,12 +122,21 @@
|
||||
"scope"
|
||||
],
|
||||
"breadcrumbMatched": true,
|
||||
"selectedAttempt": "FILTERED_VECTOR",
|
||||
"fallbackReason": null,
|
||||
"evidenceStatus": "supported",
|
||||
"includedSources": [
|
||||
"aiops-alert-scope-control"
|
||||
],
|
||||
"omittedSources": [],
|
||||
"rerankTopSource": "aiops-alert-scope-control",
|
||||
"failedChecks": []
|
||||
},
|
||||
{
|
||||
"caseId": "chat-rag-chunk-context",
|
||||
"scenario": "chat",
|
||||
"query": "If a long section is split into multiple chunks, how do we keep retrieval context?",
|
||||
"dataShape": "lookupResult",
|
||||
"hitLevel": "strong",
|
||||
"passed": true,
|
||||
"firstExpectedRank": 1,
|
||||
@@ -106,12 +150,22 @@
|
||||
"breadcrumb"
|
||||
],
|
||||
"breadcrumbMatched": true,
|
||||
"selectedAttempt": "FILTERED_VECTOR",
|
||||
"fallbackReason": null,
|
||||
"evidenceStatus": "supported",
|
||||
"includedSources": [
|
||||
"rag-chunk-context-reconstruction",
|
||||
"rag-breadcrumb-embedding-gap"
|
||||
],
|
||||
"omittedSources": [],
|
||||
"rerankTopSource": "rag-chunk-context-reconstruction",
|
||||
"failedChecks": []
|
||||
},
|
||||
{
|
||||
"caseId": "chat-l0-domain-hint",
|
||||
"scenario": "chat",
|
||||
"query": "Should L0 keyword matching decide the final retrieval result?",
|
||||
"dataShape": "lookupResult",
|
||||
"hitLevel": "strong",
|
||||
"passed": true,
|
||||
"firstExpectedRank": 1,
|
||||
@@ -125,6 +179,44 @@
|
||||
"metadata filter"
|
||||
],
|
||||
"breadcrumbMatched": true,
|
||||
"selectedAttempt": "FILTERED_VECTOR",
|
||||
"fallbackReason": null,
|
||||
"evidenceStatus": "supported",
|
||||
"includedSources": [
|
||||
"rag-l0-domain-entity-hint",
|
||||
"rag-l0-l1-fusion-ranking"
|
||||
],
|
||||
"omittedSources": [],
|
||||
"rerankTopSource": "rag-l0-domain-entity-hint",
|
||||
"failedChecks": []
|
||||
},
|
||||
{
|
||||
"caseId": "chat-l0-filter-fallback",
|
||||
"scenario": "chat",
|
||||
"query": "RAG query was over-filtered by L0 and filtered vector search returned low quality evidence. What should happen?",
|
||||
"dataShape": "lookupResult",
|
||||
"hitLevel": "strong",
|
||||
"passed": true,
|
||||
"firstExpectedRank": 1,
|
||||
"topCandidates": [
|
||||
"1:rag-l0-filter-fallback",
|
||||
"2:rag-l0-domain-entity-hint"
|
||||
],
|
||||
"matchedKeywords": [
|
||||
"skip the l0 filter",
|
||||
"unfiltered vector retry",
|
||||
"low quality"
|
||||
],
|
||||
"breadcrumbMatched": true,
|
||||
"selectedAttempt": "UNFILTERED_VECTOR_RETRY",
|
||||
"fallbackReason": "filtered_vector_low_quality",
|
||||
"evidenceStatus": "supported",
|
||||
"includedSources": [
|
||||
"rag-l0-filter-fallback",
|
||||
"rag-l0-domain-entity-hint"
|
||||
],
|
||||
"omittedSources": [],
|
||||
"rerankTopSource": "rag-l0-filter-fallback",
|
||||
"failedChecks": []
|
||||
}
|
||||
]
|
||||
|
||||
@@ -1,16 +1,20 @@
|
||||
# RAG Retrieval Baseline
|
||||
|
||||
Generated at: `2026-07-04T17:59:52.172759+00:00`
|
||||
Generated at: `2026-07-06T13:37:59.726351+00:00`
|
||||
|
||||
## Aggregate
|
||||
|
||||
| Metric | Value |
|
||||
|---|---:|
|
||||
| Cases | 6 |
|
||||
| Cases | 7 |
|
||||
| Top K | 5 |
|
||||
| Passed | 7 |
|
||||
| Failed | 0 |
|
||||
| Pass rate | 1.0 |
|
||||
| LookupResult fixtures | 7 |
|
||||
| Recall@K | 1.0 |
|
||||
| Strong hit rate | 1.0 |
|
||||
| Strong hits | 6 |
|
||||
| Strong hits | 7 |
|
||||
| Medium hits | 0 |
|
||||
| Weak hits | 0 |
|
||||
| Misses | 0 |
|
||||
@@ -18,11 +22,12 @@ Generated at: `2026-07-04T17:59:52.172759+00:00`
|
||||
|
||||
## Cases
|
||||
|
||||
| Case | Scenario | Hit | First Expected Rank | Top Candidates | Failed Checks |
|
||||
|---|---|---|---:|---|---|
|
||||
| chat-mysql-connection-pool | chat | strong | 1 | 1:mysql-connection-pool<br>2:incident-diagnosis-flow | |
|
||||
| chat-diagnosis-flow | chat | strong | 1 | 1:incident-diagnosis-flow<br>2:rag-chunk-context-reconstruction | |
|
||||
| aiops-payment-latency-alert | aiops | strong | 1 | 1:payment-service-latency<br>2:mysql-connection-pool | |
|
||||
| aiops-prometheus-alert-scope | aiops | strong | 1 | 1:aiops-alert-scope-control | |
|
||||
| chat-rag-chunk-context | chat | strong | 1 | 1:rag-chunk-context-reconstruction<br>2:rag-breadcrumb-embedding-gap | |
|
||||
| chat-l0-domain-hint | chat | strong | 1 | 1:rag-l0-domain-entity-hint<br>2:rag-l0-l1-fusion-ranking | |
|
||||
| Case | Scenario | Pass | Hit | Attempt | Fallback | Evidence | First Expected Rank | Top Candidates | Failed Checks |
|
||||
|---|---|---|---|---|---|---|---:|---|---|
|
||||
| chat-mysql-connection-pool | chat | true | strong | FILTERED_VECTOR | | supported | 1 | 1:mysql-connection-pool<br>2:incident-diagnosis-flow | |
|
||||
| chat-diagnosis-flow | chat | true | strong | FILTERED_VECTOR | | supported | 1 | 1:incident-diagnosis-flow<br>2:rag-chunk-context-reconstruction | |
|
||||
| aiops-payment-latency-alert | aiops | true | strong | FILTERED_VECTOR | | supported | 1 | 1:payment-service-latency<br>2:mysql-connection-pool | |
|
||||
| aiops-prometheus-alert-scope | aiops | true | strong | FILTERED_VECTOR | | supported | 1 | 1:aiops-alert-scope-control | |
|
||||
| chat-rag-chunk-context | chat | true | strong | FILTERED_VECTOR | | supported | 1 | 1:rag-chunk-context-reconstruction<br>2:rag-breadcrumb-embedding-gap | |
|
||||
| chat-l0-domain-hint | chat | true | strong | FILTERED_VECTOR | | supported | 1 | 1:rag-l0-domain-entity-hint<br>2:rag-l0-l1-fusion-ranking | |
|
||||
| chat-l0-filter-fallback | chat | true | strong | UNFILTERED_VECTOR_RETRY | filtered_vector_low_quality | supported | 1 | 1:rag-l0-filter-fallback<br>2:rag-l0-domain-entity-hint | |
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
---
|
||||
title: AIOps Alert Scope Control
|
||||
keywords: [alert payload, unrelated active alerts, scope control]
|
||||
summary: Keep diagnosis scoped to the request payload and avoid diagnosing unrelated active alerts.
|
||||
category: aiops
|
||||
source: aiops-alert-scope-control
|
||||
breadcrumb: AIOps > Alert Scope Control
|
||||
kb_scope: rag-eval
|
||||
covers: [alert scope, payload, active alerts]
|
||||
when_to_retrieve: Use when an AIOps request includes a concrete alert payload and scope boundaries matter.
|
||||
---
|
||||
|
||||
# AIOps
|
||||
|
||||
## Alert Scope Control
|
||||
|
||||
When an AIOps request already includes an alert payload, the agent should diagnose that payload first.
|
||||
It must not expand the task into unrelated active alerts unless the user asks for broad alert triage.
|
||||
|
||||
Scope rules:
|
||||
|
||||
1. Treat the provided payload as the primary incident boundary.
|
||||
2. Use unrelated active alerts only as correlation evidence when they share service, dependency, time window, or trace context.
|
||||
3. Do not replace the requested alert with a louder but unrelated alert.
|
||||
|
||||
This runbook anchors payload, unrelated active alerts, and scope behavior.
|
||||
@@ -0,0 +1,27 @@
|
||||
---
|
||||
title: Incident Diagnosis Flow
|
||||
keywords: [standard troubleshooting flow, application incident, collect evidence, verify, remediation]
|
||||
summary: Standard flow for diagnosing application incidents with evidence, hypothesis verification, and remediation.
|
||||
category: ops
|
||||
source: incident-diagnosis-flow
|
||||
breadcrumb: AIOps > Diagnosis Flow
|
||||
kb_scope: rag-eval
|
||||
covers: [incident diagnosis, evidence collection, remediation]
|
||||
when_to_retrieve: Use when the user asks for a standard troubleshooting flow or incident diagnosis sequence.
|
||||
---
|
||||
|
||||
# AIOps
|
||||
|
||||
## Diagnosis Flow
|
||||
|
||||
The standard troubleshooting flow is evidence first, hypothesis second, remediation last.
|
||||
|
||||
Recommended sequence:
|
||||
|
||||
1. Collect evidence from alerts, metrics, logs, traces, deployments, and recent configuration changes.
|
||||
2. Define a small hypothesis that explains the observed symptoms.
|
||||
3. Verify the hypothesis with a targeted metric, log query, or reproduction step.
|
||||
4. Choose remediation that directly addresses the verified cause.
|
||||
5. Record the outcome and the evidence used to make the decision.
|
||||
|
||||
Do not skip collect evidence, verify, and remediation ordering during an application incident.
|
||||
@@ -0,0 +1,29 @@
|
||||
---
|
||||
title: MySQL Connection Pool Runbook
|
||||
keywords: [MySQL connection pool, pool exhausted, max_connections, HikariCP]
|
||||
summary: Diagnose exhausted MySQL connection pools and distinguish application leaks from database limits.
|
||||
category: database
|
||||
source: mysql-connection-pool
|
||||
breadcrumb: Database > MySQL > Connection Pool
|
||||
kb_scope: rag-eval
|
||||
covers: [mysql, connection pool, database capacity]
|
||||
when_to_retrieve: Use when MySQL clients report exhausted pools, connection acquisition timeout, max_connections pressure, or HikariCP saturation.
|
||||
---
|
||||
|
||||
# Database
|
||||
|
||||
## MySQL
|
||||
|
||||
### Connection Pool
|
||||
|
||||
When MySQL connection pool is exhausted, first compare application pool usage with database `max_connections`.
|
||||
For HikariCP, check `active`, `idle`, `pending`, and connection acquisition timeout metrics.
|
||||
|
||||
Recommended diagnosis:
|
||||
|
||||
1. Verify whether HikariCP active connections stay near maximum while pending threads grow.
|
||||
2. Check MySQL `Threads_connected`, `Threads_running`, and `max_connections`.
|
||||
3. Inspect slow SQL and long transactions that keep connections checked out.
|
||||
4. If the database is healthy, look for application connection leaks or missing transaction boundaries.
|
||||
|
||||
Use this runbook as evidence for connection pool, max_connections, and HikariCP incidents.
|
||||
@@ -0,0 +1,28 @@
|
||||
---
|
||||
title: Payment Service Latency Alert
|
||||
keywords: [HighLatency, payment-service, p95 latency, downstream dependency]
|
||||
summary: Diagnose payment-service p95 latency alerts and identify downstream dependency bottlenecks.
|
||||
category: aiops
|
||||
source: payment-service-latency
|
||||
breadcrumb: AIOps > Service Alerts > Payment Latency
|
||||
kb_scope: rag-eval
|
||||
covers: [payment-service, latency, downstream dependency]
|
||||
when_to_retrieve: Use when an alert mentions payment-service, HighLatency, or elevated p95 latency.
|
||||
---
|
||||
|
||||
# AIOps
|
||||
|
||||
## Service Alerts
|
||||
|
||||
### Payment Latency
|
||||
|
||||
For `HighLatency` alerts on `payment-service`, treat p95 latency as the primary symptom.
|
||||
|
||||
Diagnosis steps:
|
||||
|
||||
1. Confirm whether p95 latency is isolated to payment-service or shared across upstream callers.
|
||||
2. Compare payment-service latency with downstream dependency latency for gateway, risk, and order services.
|
||||
3. Check connection pool wait time, retry spikes, and timeout rates.
|
||||
4. If downstream dependency latency increased first, classify payment-service as affected rather than root cause.
|
||||
|
||||
The expected evidence terms are p95 latency, payment-service, and downstream dependency.
|
||||
@@ -0,0 +1,28 @@
|
||||
---
|
||||
title: RAG Chunk Context Reconstruction
|
||||
keywords: [split into multiple chunks, retrieval context, neighbor chunk, same section, breadcrumb context]
|
||||
summary: Preserve context when long RAG sections are split into multiple retrievable chunks.
|
||||
category: rag
|
||||
source: rag-chunk-context-reconstruction
|
||||
breadcrumb: RAG > Chunking > Context Reconstruction
|
||||
kb_scope: rag-eval
|
||||
covers: [rag chunking, context packing, breadcrumbs]
|
||||
when_to_retrieve: Use when a retrieval question asks how to preserve context across split chunks.
|
||||
---
|
||||
|
||||
# RAG
|
||||
|
||||
## Chunking
|
||||
|
||||
### Context Reconstruction
|
||||
|
||||
When a long section is split into multiple chunks, retrieval should keep enough local structure for the answer.
|
||||
|
||||
Recommended behavior:
|
||||
|
||||
1. Store the breadcrumb with every chunk.
|
||||
2. Preserve the same section identity across adjacent chunks.
|
||||
3. During context packing, include a neighbor chunk when the selected chunk depends on nearby setup or definitions.
|
||||
4. Prefer concise evidence blocks that show the breadcrumb and the relevant content span.
|
||||
|
||||
The key concepts are neighbor chunk, same section, and breadcrumb.
|
||||
@@ -0,0 +1,29 @@
|
||||
---
|
||||
title: RAG L0 Domain Entity Hint
|
||||
keywords: [L0 keyword matching, final retrieval result, domain detector, entity extractor, metadata filter]
|
||||
summary: Define L0 as a query transformation hint layer instead of final retrieval evidence.
|
||||
category: rag
|
||||
source: rag-l0-domain-entity-hint
|
||||
breadcrumb: RAG > L0 > Domain Entity Hint
|
||||
kb_scope: rag-eval
|
||||
covers: [l0 hint, query transformation, metadata filter]
|
||||
when_to_retrieve: Use when a question asks whether L0 should decide final retrieval or only provide hints.
|
||||
---
|
||||
|
||||
# RAG
|
||||
|
||||
## L0
|
||||
|
||||
### Domain Entity Hint
|
||||
|
||||
L0 keyword matching should not decide the final retrieval result.
|
||||
In the modular RAG pipeline, L0 behaves like a lightweight domain detector and entity extractor.
|
||||
|
||||
The output can provide:
|
||||
|
||||
1. Candidate domain hints.
|
||||
2. Matched entities and keywords.
|
||||
3. An optional metadata filter for the first vector retrieval attempt.
|
||||
|
||||
Final evidence still comes from L1 vector retrieval, post-retrieval normalization, rerank, and context packing.
|
||||
The important terms are domain detector, entity extractor, and metadata filter.
|
||||
@@ -0,0 +1,19 @@
|
||||
---
|
||||
title: RAG L0 Filter Decoy
|
||||
keywords: [over-filtered by L0, filtered vector search, low quality evidence]
|
||||
summary: Decoy document used to force the first filtered retrieval attempt into a low-quality category.
|
||||
category: overfilter-decoy
|
||||
source: rag-l0-filter-decoy
|
||||
breadcrumb: RAG > Fallback > Decoy
|
||||
kb_scope: rag-eval
|
||||
covers: [fallback test decoy]
|
||||
when_to_retrieve: Use only as a controlled eval decoy for over-filter fallback testing.
|
||||
---
|
||||
|
||||
# Release Calendar
|
||||
|
||||
## Approval Window
|
||||
|
||||
This document describes an unrelated release calendar approval window.
|
||||
It intentionally avoids the real fallback instructions so the filtered retrieval
|
||||
attempt is low quality and the retriever must retry without the L0 category filter.
|
||||
@@ -0,0 +1,25 @@
|
||||
---
|
||||
title: RAG L0 Filter Fallback
|
||||
keywords: [golden retry contract, second pass retrieval]
|
||||
summary: Retry the raw query without the L0 category filter when filtered vector evidence is missing or low quality.
|
||||
category: fallback
|
||||
source: rag-l0-filter-fallback
|
||||
breadcrumb: RAG > Fallback > Unfiltered Retry
|
||||
kb_scope: rag-eval
|
||||
covers: [fallback, unfiltered retry, retrieval quality]
|
||||
when_to_retrieve: Use when validating the fallback contract for low-quality filtered vector retrieval.
|
||||
---
|
||||
|
||||
# RAG
|
||||
|
||||
## Fallback
|
||||
|
||||
### Unfiltered Retry
|
||||
|
||||
If the first vector search is over-constrained by an L0 metadata filter and returns low quality evidence,
|
||||
the retriever should skip the L0 filter and run an unfiltered vector retry with the original query.
|
||||
|
||||
The fallback reason should be `filtered_vector_low_quality` when the filtered candidate exists but is below the
|
||||
reference threshold. If there is no usable evidence at all, use `filtered_vector_no_evidence`.
|
||||
|
||||
This document is the expected evidence for skip the L0 filter, unfiltered vector retry, and low quality behavior.
|
||||
@@ -0,0 +1,18 @@
|
||||
# RAG Eval Knowledge Base Mirror
|
||||
|
||||
This folder stores the committed knowledge-base copy of the canonical RAG eval
|
||||
documents.
|
||||
|
||||
The source of truth for the eval importer remains:
|
||||
|
||||
```text
|
||||
eval/rag-retrieval/seed-docs/
|
||||
```
|
||||
|
||||
The documents are kept under `knowledge_base/rag-eval/` so eval/test knowledge
|
||||
does not mix with the normal business knowledge folders such as `api`,
|
||||
`infrastructure`, or `troubleshooting`.
|
||||
|
||||
Each document keeps its original frontmatter `category` and `kb_scope`. The
|
||||
category is still the retrieval category used by L0/L1, while `kb_scope:
|
||||
rag-eval` isolates these documents during eval runs.
|
||||
@@ -0,0 +1,26 @@
|
||||
---
|
||||
title: AIOps Alert Scope Control
|
||||
keywords: [alert payload, unrelated active alerts, scope control]
|
||||
summary: Keep diagnosis scoped to the request payload and avoid diagnosing unrelated active alerts.
|
||||
category: aiops
|
||||
source: aiops-alert-scope-control
|
||||
breadcrumb: AIOps > Alert Scope Control
|
||||
kb_scope: rag-eval
|
||||
covers: [alert scope, payload, active alerts]
|
||||
when_to_retrieve: Use when an AIOps request includes a concrete alert payload and scope boundaries matter.
|
||||
---
|
||||
|
||||
# AIOps
|
||||
|
||||
## Alert Scope Control
|
||||
|
||||
When an AIOps request already includes an alert payload, the agent should diagnose that payload first.
|
||||
It must not expand the task into unrelated active alerts unless the user asks for broad alert triage.
|
||||
|
||||
Scope rules:
|
||||
|
||||
1. Treat the provided payload as the primary incident boundary.
|
||||
2. Use unrelated active alerts only as correlation evidence when they share service, dependency, time window, or trace context.
|
||||
3. Do not replace the requested alert with a louder but unrelated alert.
|
||||
|
||||
This runbook anchors payload, unrelated active alerts, and scope behavior.
|
||||
@@ -0,0 +1,28 @@
|
||||
---
|
||||
title: Payment Service Latency Alert
|
||||
keywords: [HighLatency, payment-service, p95 latency, downstream dependency]
|
||||
summary: Diagnose payment-service p95 latency alerts and identify downstream dependency bottlenecks.
|
||||
category: aiops
|
||||
source: payment-service-latency
|
||||
breadcrumb: AIOps > Service Alerts > Payment Latency
|
||||
kb_scope: rag-eval
|
||||
covers: [payment-service, latency, downstream dependency]
|
||||
when_to_retrieve: Use when an alert mentions payment-service, HighLatency, or elevated p95 latency.
|
||||
---
|
||||
|
||||
# AIOps
|
||||
|
||||
## Service Alerts
|
||||
|
||||
### Payment Latency
|
||||
|
||||
For `HighLatency` alerts on `payment-service`, treat p95 latency as the primary symptom.
|
||||
|
||||
Diagnosis steps:
|
||||
|
||||
1. Confirm whether p95 latency is isolated to payment-service or shared across upstream callers.
|
||||
2. Compare payment-service latency with downstream dependency latency for gateway, risk, and order services.
|
||||
3. Check connection pool wait time, retry spikes, and timeout rates.
|
||||
4. If downstream dependency latency increased first, classify payment-service as affected rather than root cause.
|
||||
|
||||
The expected evidence terms are p95 latency, payment-service, and downstream dependency.
|
||||
@@ -0,0 +1,29 @@
|
||||
---
|
||||
title: MySQL Connection Pool Runbook
|
||||
keywords: [MySQL connection pool, pool exhausted, max_connections, HikariCP]
|
||||
summary: Diagnose exhausted MySQL connection pools and distinguish application leaks from database limits.
|
||||
category: database
|
||||
source: mysql-connection-pool
|
||||
breadcrumb: Database > MySQL > Connection Pool
|
||||
kb_scope: rag-eval
|
||||
covers: [mysql, connection pool, database capacity]
|
||||
when_to_retrieve: Use when MySQL clients report exhausted pools, connection acquisition timeout, max_connections pressure, or HikariCP saturation.
|
||||
---
|
||||
|
||||
# Database
|
||||
|
||||
## MySQL
|
||||
|
||||
### Connection Pool
|
||||
|
||||
When MySQL connection pool is exhausted, first compare application pool usage with database `max_connections`.
|
||||
For HikariCP, check `active`, `idle`, `pending`, and connection acquisition timeout metrics.
|
||||
|
||||
Recommended diagnosis:
|
||||
|
||||
1. Verify whether HikariCP active connections stay near maximum while pending threads grow.
|
||||
2. Check MySQL `Threads_connected`, `Threads_running`, and `max_connections`.
|
||||
3. Inspect slow SQL and long transactions that keep connections checked out.
|
||||
4. If the database is healthy, look for application connection leaks or missing transaction boundaries.
|
||||
|
||||
Use this runbook as evidence for connection pool, max_connections, and HikariCP incidents.
|
||||
@@ -0,0 +1,25 @@
|
||||
---
|
||||
title: RAG L0 Filter Fallback
|
||||
keywords: [golden retry contract, second pass retrieval]
|
||||
summary: Retry the raw query without the L0 category filter when filtered vector evidence is missing or low quality.
|
||||
category: fallback
|
||||
source: rag-l0-filter-fallback
|
||||
breadcrumb: RAG > Fallback > Unfiltered Retry
|
||||
kb_scope: rag-eval
|
||||
covers: [fallback, unfiltered retry, retrieval quality]
|
||||
when_to_retrieve: Use when validating the fallback contract for low-quality filtered vector retrieval.
|
||||
---
|
||||
|
||||
# RAG
|
||||
|
||||
## Fallback
|
||||
|
||||
### Unfiltered Retry
|
||||
|
||||
If the first vector search is over-constrained by an L0 metadata filter and returns low quality evidence,
|
||||
the retriever should skip the L0 filter and run an unfiltered vector retry with the original query.
|
||||
|
||||
The fallback reason should be `filtered_vector_low_quality` when the filtered candidate exists but is below the
|
||||
reference threshold. If there is no usable evidence at all, use `filtered_vector_no_evidence`.
|
||||
|
||||
This document is the expected evidence for skip the L0 filter, unfiltered vector retry, and low quality behavior.
|
||||
@@ -0,0 +1,27 @@
|
||||
---
|
||||
title: Incident Diagnosis Flow
|
||||
keywords: [standard troubleshooting flow, application incident, collect evidence, verify, remediation]
|
||||
summary: Standard flow for diagnosing application incidents with evidence, hypothesis verification, and remediation.
|
||||
category: ops
|
||||
source: incident-diagnosis-flow
|
||||
breadcrumb: AIOps > Diagnosis Flow
|
||||
kb_scope: rag-eval
|
||||
covers: [incident diagnosis, evidence collection, remediation]
|
||||
when_to_retrieve: Use when the user asks for a standard troubleshooting flow or incident diagnosis sequence.
|
||||
---
|
||||
|
||||
# AIOps
|
||||
|
||||
## Diagnosis Flow
|
||||
|
||||
The standard troubleshooting flow is evidence first, hypothesis second, remediation last.
|
||||
|
||||
Recommended sequence:
|
||||
|
||||
1. Collect evidence from alerts, metrics, logs, traces, deployments, and recent configuration changes.
|
||||
2. Define a small hypothesis that explains the observed symptoms.
|
||||
3. Verify the hypothesis with a targeted metric, log query, or reproduction step.
|
||||
4. Choose remediation that directly addresses the verified cause.
|
||||
5. Record the outcome and the evidence used to make the decision.
|
||||
|
||||
Do not skip collect evidence, verify, and remediation ordering during an application incident.
|
||||
@@ -0,0 +1,19 @@
|
||||
---
|
||||
title: RAG L0 Filter Decoy
|
||||
keywords: [over-filtered by L0, filtered vector search, low quality evidence]
|
||||
summary: Decoy document used to force the first filtered retrieval attempt into a low-quality category.
|
||||
category: overfilter-decoy
|
||||
source: rag-l0-filter-decoy
|
||||
breadcrumb: RAG > Fallback > Decoy
|
||||
kb_scope: rag-eval
|
||||
covers: [fallback test decoy]
|
||||
when_to_retrieve: Use only as a controlled eval decoy for over-filter fallback testing.
|
||||
---
|
||||
|
||||
# Release Calendar
|
||||
|
||||
## Approval Window
|
||||
|
||||
This document describes an unrelated release calendar approval window.
|
||||
It intentionally avoids the real fallback instructions so the filtered retrieval
|
||||
attempt is low quality and the retriever must retry without the L0 category filter.
|
||||
@@ -0,0 +1,28 @@
|
||||
---
|
||||
title: RAG Chunk Context Reconstruction
|
||||
keywords: [split into multiple chunks, retrieval context, neighbor chunk, same section, breadcrumb context]
|
||||
summary: Preserve context when long RAG sections are split into multiple retrievable chunks.
|
||||
category: rag
|
||||
source: rag-chunk-context-reconstruction
|
||||
breadcrumb: RAG > Chunking > Context Reconstruction
|
||||
kb_scope: rag-eval
|
||||
covers: [rag chunking, context packing, breadcrumbs]
|
||||
when_to_retrieve: Use when a retrieval question asks how to preserve context across split chunks.
|
||||
---
|
||||
|
||||
# RAG
|
||||
|
||||
## Chunking
|
||||
|
||||
### Context Reconstruction
|
||||
|
||||
When a long section is split into multiple chunks, retrieval should keep enough local structure for the answer.
|
||||
|
||||
Recommended behavior:
|
||||
|
||||
1. Store the breadcrumb with every chunk.
|
||||
2. Preserve the same section identity across adjacent chunks.
|
||||
3. During context packing, include a neighbor chunk when the selected chunk depends on nearby setup or definitions.
|
||||
4. Prefer concise evidence blocks that show the breadcrumb and the relevant content span.
|
||||
|
||||
The key concepts are neighbor chunk, same section, and breadcrumb.
|
||||
@@ -0,0 +1,29 @@
|
||||
---
|
||||
title: RAG L0 Domain Entity Hint
|
||||
keywords: [L0 keyword matching, final retrieval result, domain detector, entity extractor, metadata filter]
|
||||
summary: Define L0 as a query transformation hint layer instead of final retrieval evidence.
|
||||
category: rag
|
||||
source: rag-l0-domain-entity-hint
|
||||
breadcrumb: RAG > L0 > Domain Entity Hint
|
||||
kb_scope: rag-eval
|
||||
covers: [l0 hint, query transformation, metadata filter]
|
||||
when_to_retrieve: Use when a question asks whether L0 should decide final retrieval or only provide hints.
|
||||
---
|
||||
|
||||
# RAG
|
||||
|
||||
## L0
|
||||
|
||||
### Domain Entity Hint
|
||||
|
||||
L0 keyword matching should not decide the final retrieval result.
|
||||
In the modular RAG pipeline, L0 behaves like a lightweight domain detector and entity extractor.
|
||||
|
||||
The output can provide:
|
||||
|
||||
1. Candidate domain hints.
|
||||
2. Matched entities and keywords.
|
||||
3. An optional metadata filter for the first vector retrieval attempt.
|
||||
|
||||
Final evidence still comes from L1 vector retrieval, post-retrieval normalization, rerank, and context packing.
|
||||
The important terms are domain detector, entity extractor, and metadata filter.
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user