diff --git a/.github/workflows/auto-merge.yml b/.github/workflows/auto-merge.yml index fdf9fe483..a28575dad 100644 --- a/.github/workflows/auto-merge.yml +++ b/.github/workflows/auto-merge.yml @@ -1,24 +1,18 @@ -# ============================================================================= -# Auto-merge for Trusted PRs -# ----------------------------------------------------------------------------- -# Tiers: -# 1. Renovate: Auto-approve + auto-merge -# 2. AI Agents (copilot/jules/claude): Auto-merge when CI passes -# 3. CodeRabbit approved: Auto-merge when CI passes -# 4. Governance bot: Auto-merge action version governance PRs -# 5. Owner PRs: Auto-merge when CI passes +# Common tiers (Dependabot, Renovate, AI Agent, CodeRabbit, Owner) delegate +# to the reusable workflow at ANcpLua/renovate-config. The Governance bot +# tier is qyl-specific and stays local. # -# Uses pull_request_target for security (runs in base branch context). -# All merges wait for required status checks before completing. -# ============================================================================= +# Required secrets: +# AUTOMERGE_APP_ID, AUTOMERGE_APP_PRIVATE_KEY +# See https://github.com/ANcpLua/renovate-config#auto-merge-reusable-workflow name: Auto-merge on: pull_request_target: - types: [ opened, synchronize, reopened, ready_for_review ] + types: [opened, synchronize, reopened, ready_for_review] pull_request_review: - types: [ submitted ] + types: [submitted] permissions: contents: write @@ -29,80 +23,9 @@ concurrency: cancel-in-progress: false jobs: - renovate-auto-merge: - name: Renovate auto-merge - runs-on: ubuntu-latest - if: > - github.event.pull_request.user.login == 'renovate[bot]' && - github.event.pull_request.draft == false - - steps: - - name: Auto-approve Renovate PRs - env: - PR_URL: ${{ github.event.pull_request.html_url }} - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: gh pr review --approve "$PR_URL" - - - name: Enable auto-merge for Renovate - env: - PR_URL: ${{ github.event.pull_request.html_url }} - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: gh pr merge --auto --squash "$PR_URL" - - ai-agent-auto-merge: - name: AI Agent auto-merge - runs-on: ubuntu-latest - if: | - (github.actor == 'copilot[bot]' || github.actor == 'jules[bot]' || github.actor == 'claude-code[bot]') && - ( - startsWith(github.event.pull_request.head.ref, 'copilot/') || - startsWith(github.event.pull_request.head.ref, 'jules/') || - startsWith(github.event.pull_request.head.ref, 'claude/') - ) - - steps: - - name: Identify AI agent - id: agent - env: - BRANCH: ${{ github.event.pull_request.head.ref }} - run: | - if [[ "$BRANCH" == copilot/* ]]; then - echo "agent=Copilot" >> "$GITHUB_OUTPUT" - elif [[ "$BRANCH" == jules/* ]]; then - echo "agent=Jules" >> "$GITHUB_OUTPUT" - elif [[ "$BRANCH" == claude/* ]]; then - echo "agent=Claude" >> "$GITHUB_OUTPUT" - fi - - - name: Auto-approve AI agent PRs - env: - PR_URL: ${{ github.event.pull_request.html_url }} - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - AGENT: ${{ steps.agent.outputs.agent }} - run: | - echo "Auto-approving $AGENT PR" - gh pr review --approve "$PR_URL" --body "✅ Auto-approved: $AGENT autonomous fix PR" - - - name: Enable auto-merge for AI agent PRs - env: - PR_URL: ${{ github.event.pull_request.html_url }} - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: gh pr merge --auto --squash "$PR_URL" - - coderabbit-auto-merge: - name: CodeRabbit auto-merge - runs-on: ubuntu-latest - if: | - github.event_name == 'pull_request_review' && - github.event.review.state == 'approved' && - github.event.review.user.login == 'coderabbitai[bot]' - - steps: - - name: Enable auto-merge for CodeRabbit approved PRs - env: - PR_URL: ${{ github.event.pull_request.html_url }} - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: gh pr merge --auto --squash "$PR_URL" + auto-merge: + uses: ANcpLua/renovate-config/.github/workflows/auto-merge-reusable.yml@main + secrets: inherit governance-auto-merge: name: Governance bot auto-merge @@ -111,12 +34,17 @@ jobs: github.event.pull_request.user.login == 'github-actions[bot]' && github.event.pull_request.head.ref == 'chore/action-governance' && github.event.pull_request.draft == false - steps: + - uses: actions/create-github-app-token@67e27a7eb7db372a1c61a7f9bdab8699e9ee57f7 # v2.1.4 + id: app-token + with: + app-id: ${{ secrets.AUTOMERGE_APP_ID }} + private-key: ${{ secrets.AUTOMERGE_APP_PRIVATE_KEY }} + - name: Verify only .github files changed env: PR_URL: ${{ github.event.pull_request.html_url }} - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + GH_TOKEN: ${{ steps.app-token.outputs.token }} run: | set -euo pipefail files=$(gh pr diff "$PR_URL" --name-only) @@ -129,7 +57,7 @@ jobs: - name: Auto-approve governance PR env: PR_URL: ${{ github.event.pull_request.html_url }} - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + GH_TOKEN: ${{ steps.app-token.outputs.token }} run: | gh pr review --approve "$PR_URL" \ --body "✅ Auto-approved: action governance update (scoped to .github/)" @@ -137,19 +65,5 @@ jobs: - name: Enable auto-merge env: PR_URL: ${{ github.event.pull_request.html_url }} - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: gh pr merge --auto --squash "$PR_URL" - - owner-auto-merge: - name: Owner auto-merge - runs-on: ubuntu-latest - if: > - github.event.pull_request.user.login == github.event.repository.owner.login && - github.event.pull_request.draft == false - - steps: - - name: Enable auto-merge for owner PRs - env: - PR_URL: ${{ github.event.pull_request.html_url }} - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + GH_TOKEN: ${{ steps.app-token.outputs.token }} run: gh pr merge --auto --squash "$PR_URL" diff --git a/AGENTS.md b/AGENTS.md index c0c39bcc5..f22a61fc4 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -126,13 +126,14 @@ Endpoint implementations under `services/qyl.collector/**Endpoints.cs` track `co ## HTTP client error handling -In `services/qyl.loom/CollectorClient.cs` and any other `HttpClient`-consuming code, the established pattern: +In `services/qyl.loom/CollectorClient.cs` and any other `HttpClient`-consuming code: -- Before `ReadFromJsonAsync` on a non-success response, check - `Content.Headers.ContentType?.MediaType == "application/json"` and `ContentLength > 0`; otherwise fall back to - `StatusCode`. -- `ReadFromJsonAsync` is wrapped in `try/catch (JsonException)` on non-success paths. -- Failures return a structured DTO. Throwing on expected HTTP error status is the exception, not the rule. +- Default: `response.EnsureSuccessStatusCode()` → `ReadFromJsonAsync(CollectorClientJsonContext.Default., ct)`. + Let unexpected HTTP failures throw; the AOT-friendly `JsonTypeInfo` context is mandatory — never the reflection + overload. +- For endpoints with a documented failure body (e.g. `CreatePullRequestAsync` at `CollectorClient.cs:148-178`), + branch on `IsSuccessStatusCode` and read either the success or failure DTO. Reserve this shape for contracts that + actually define a structured error payload. ## Codegen boundaries @@ -195,9 +196,6 @@ In `services/qyl.mcp/`: For `services/qyl.loom/`, `services/qyl.loom.patterns/`, `services/qyl.mcp/Agents/`. -References worth reading before editing agent/workflow code: `~/.claude/skills/microsoft-agent-framework-qyl/SKILL.md` ( -qyl overlay) and `~/.claude/skills/microsoft-agent-framework/SKILL.md` (core MAF). - Local invariants: - qyl three-builder pattern: `IXxxChatClientBuilder` → `IXxxAgentsBuilder` → workflow. One `Build*Agent()` factory per @@ -214,14 +212,14 @@ Reach for these before hand-rolling. Each row points at a concrete qyl call-site | Layer | Entry point | qyl call-site | |-------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------| -| **Agent — standalone** | `llm.AsAIAgent(new ChatClientAgentOptions { Name, Description, ChatOptions = new() { Instructions } }).AsBuilder().UseQylAgentTelemetry().Build()` | `services/qyl.loom/Autofix/Workflow/Executors/RcaExecutor.cs:35-40` and every sibling executor | -| **Agent — non-streaming** | `await agent.RunAsync(userMessage, cancellationToken: ct)` | `RcaExecutor.cs:42` — the universal shape across Autofix executors and `TriagePipelineService` | -| **Agent — streaming** | `await foreach (var evt in streamingRun.WatchStreamAsync(ct)) { … }` | `services/qyl.loom/Autofix/AutofixAgentService.cs:66-77`, `services/qyl.loom/Exploration/ExplorationOrchestrator.cs:37` | +| **Agent — standalone** | `llm.AsAIAgent(new ChatClientAgentOptions { Name, Description, ChatOptions = new() { Instructions } }).AsBuilder().UseQylAgentTelemetry().Build()` | `services/qyl.loom/Agents/QylLoomAgentsBuilder.cs:82-85` (every `Build*Agent()` factory) | +| **Agent — non-streaming** | `await agent.RunAsync(userMessage, cancellationToken: ct)` | `services/qyl.loom/Autofix/Workflow/Executors/HypothesisExecutor.cs:38-40` — universal shape across Autofix executors | +| **Agent — streaming** | `await foreach (var evt in streamingRun.WatchStreamAsync(ct)) { … }` | `services/qyl.loom/Autofix/LoomAutofixRunner.cs:188`, `services/qyl.loom/Exploration/ExplorationOrchestrator.cs:37` | | **Agent — structured output** | `await agent.RunAsync(prompt)` → `AgentResponse.Result` | When `T` is a `LoomToolEnvelope` verdict (see `services/qyl.mcp/Tools/`) | | **Session** | `agent.CreateSessionAsync()` • `SerializeSessionAsync` / `DeserializeSessionAsync` | When the same agent must preserve context across MCP tool calls — gate on `LoomRunState` | -| **Tools — local** | `AIFunctionFactory.Create(methodInfo, instanceFactory, new AIFunctionFactoryOptions { Name, ... })` | `internal/qyl.instrumentation/Instrumentation/Loom/LoomToolFactoryBridge.cs:99-119` | +| **Tools — local** | `AIFunctionFactory.Create(methodInfo, new AIFunctionFactoryOptions { Name = "qyl.." })` | `services/qyl.loom/Autofix/Workflow/AutofixContextToolFactories.cs:9-15` | | **Workflow — build** | `new WorkflowBuilder(start).AddEdge(a, b).AddFanOutEdge(src, [t1, t2, t3]).WithOutputFrom(last).Build()` | `services/qyl.loom/Autofix/Workflow/AutofixWorkflowFactory.cs:44-51`, `services/qyl.loom/Exploration/Workflow/ExplorationWorkflowFactory.cs:23-28` | -| **Workflow — run** | `InProcessExecution.RunStreamingAsync(workflow, input)` + `run.WatchStreamAsync(ct)` | `AutofixAgentService.cs:66`, `ExplorationOrchestrator.cs:37` | +| **Workflow — run** | `InProcessExecution.RunStreamingAsync(workflow, input)` + `run.WatchStreamAsync(ct)` | `services/qyl.loom/Autofix/LoomAutofixRunner.cs:182-188`, `services/qyl.loom/Exploration/ExplorationOrchestrator.cs:37` | | **Observability** | `IChatClient` decoration (`.WithQylTelemetry` short form or `.UseQylTelemetry` on `ChatClientBuilder` fluent form) **and** `agent.AsBuilder().UseQylAgentTelemetry().Build()` on `AIAgent`. Wrap both layers — wrapping one halves the spans. | All executors + `internal/qyl.instrumentation/Instrumentation/GenAi/GenAiInstrumentation.cs:53,100,141` | ## MAF.Advanced.Patterns — consume, don't duplicate diff --git a/Version.props b/Version.props index 7a40d2333..d63b78efb 100644 --- a/Version.props +++ b/Version.props @@ -32,7 +32,7 @@ 10.1.0 1.3.2 16.3.0 - 0.55.0 + 0.55.2 6.5.1 5.5.1 2.5.0 diff --git a/report.md b/report.md deleted file mode 100644 index 8af632803..000000000 --- a/report.md +++ /dev/null @@ -1,147 +0,0 @@ -# qyl docs ↔ codebase reality check - -- **Generated:** 2026-05-04 19:55–20:00 CEST -- **Branch:** `add-owner-automerge-tier` -- **HEAD:** `f86426d6` (ci(auto-merge): add owner tier) -- **Scope:** `/Users/ancplua/qyl/AGENTS.md` (CLAUDE.md is a symlink to it), `/Users/ancplua/.claude/CLAUDE.md` (global), and the `SKILL.md` files AGENTS.md references -- **Codegen commands actually executed end-to-end:** - `./eng/build.sh GenerateSemconv`, `./eng/semconv/run-weaver.sh`, `./eng/build.sh Generate` - -## TL;DR - -The doc is mostly accurate on **what files exist** and **what the platform looks like**, but inaccurate on several **specific anchors agents are told to follow**: two cited files do not exist, the cited HTTP-client pattern is the opposite of what the file actually does, and the two `SKILL.md` references at the top of the MAF section don't exist on disk. The codegen commands all run and succeed — but `nuke Generate` produces ~26 k lines of TypeScript drift against the committed state, so the "regenerated output ships in the same commit" rule is currently broken for the JS http-client emitter. - ---- - -## 1. Verified working as claimed - -| Claim | Status | -|---|---| -| `CLAUDE.md` is a symlink to `AGENTS.md` | ✓ | -| `qyl.slnx`, `eng/compose.yaml`, `nuget.config` exist where stated | ✓ | -| All 11 generated-codegen paths in the table exist | ✓ | -| All 13 semconv `eng/semconv/model/qyl/*.yaml` files exist | ✓ | -| `QylAttr` (internal) + `QylAttributes` (public) constants classes match documented shape | ✓ | -| `[QylSkill]` / `[QylCapability]` attributes defined; `internal/qyl.mcp.generators/` exists | ✓ | -| `LoomToolEnvelope` non-generic with `Ok(data)` / `Fail(error)` factory methods | ✓ | -| `InvestigationLineage.TryEnter()` exists; depth 3 / spawn 10 enforced via `QYL_AGENT_MAX_DEPTH` / `QYL_AGENT_MAX_SPAWNS` | ✓ | -| `[McpServerTool]` methods are `partial` (sampled `ErrorTools`, `AutofixMcpTools`, `RcaTools`) | ✓ | -| `DuckDbStore` exposes `GetReadConnectionAsync(ct)` + `ExecuteWriteAsync(Func, ct)` | ✓ | -| `.UseQylMcpInstrumentation(...)` called in `QylMcpServerRegistration.cs:78` and `qyl.loom/Program.cs:35` after transport | ✓ | -| `GenAiInstrumentation.cs:53/100/141` cite real `WithQylTelemetry` / `UseQylTelemetry` / `UseQylAgentTelemetry` definitions | ✓ | -| `ExplorationOrchestrator.cs:37`, `AutofixWorkflowFactory.cs:44-51`, `ExplorationWorkflowFactory.cs:23-28` all match | ✓ | -| 17/17 user-facing Nuke targets exist; sub-targets are `.Unlisted()` | ✓ | -| All 23 `MAF.Advanced.Patterns` classes + 5 sibling packages + `QylLoomShowcase` sample exist | ✓ | -| No `dynamic` / `ExpandoObject` / `.Result` / `.Wait()` in business code (one safe `IsCompletedSuccessfully` fast-path in `LspClientWrapper.cs:101`) | ✓ | -| No `DateTime.UtcNow` / `Now` / `DateTimeOffset.UtcNow` in `services/` | ✓ | -| ESLint dashboard rules (`@radix-ui` ban, `asChild`/`Slot` ban, `argsIgnorePattern: '^_'`) all present | ✓ | -| GitHub state: PR #172 merged 2026-04-28, issue #173 open | ✓ | -| `~/framework/` siblings (ANcpLua.Agents, ANcpLua.Analyzers, ANcpLua.NET.Sdk, ANcpLua.Roslyn.Utilities, MAF.Advanced.Patterns) all exist | ✓ | - ---- - -## 2. Wrong / made up - -### 2a. Files that don't exist - -| Cited at | Path | Status | -|---|---|---| -| AGENTS.md:217-218 | `services/qyl.loom/Autofix/Workflow/Executors/RcaExecutor.cs` | **Does not exist.** Directory has Confidence/Context/Fixability/Hypothesis/HypothesisJudge/Report/SelfCritiqueRouter/Solution/StoppingPointGate executors plus a stray `NewFile1.md`, but no `Rca` executor. | -| AGENTS.md:222 | `internal/qyl.instrumentation/Instrumentation/Loom/LoomToolFactoryBridge.cs` | **Does not exist** anywhere under `internal/`. | -| AGENTS.md:198-199 | `~/.claude/skills/microsoft-agent-framework-qyl/SKILL.md` | **Does not exist.** `~/.claude/skills/` contains only `.DS_Store`. | -| AGENTS.md:198-199 | `~/.claude/skills/microsoft-agent-framework/SKILL.md` | **Does not exist.** Same as above. | - -The MAF cheat-sheet rows that point at `RcaExecutor.cs:35-40`, `:42`, and `LoomToolFactoryBridge.cs:99-119` are cargo-culted — agents pointed at those line ranges will land on missing files. - -### 2b. Wrong line ranges - -| Cited at | Claim | Reality | -|---|---|---| -| AGENTS.md:219 | `services/qyl.loom/Autofix/AutofixAgentService.cs:66-77` contains the streaming `await foreach … WatchStreamAsync` loop | File is **only 67 lines total**. The streaming loop is in `services/qyl.loom/Autofix/LoomAutofixRunner.cs:188`. | - -### 2c. Pattern claim inverted from reality - -**AGENTS.md:127-135 — "HTTP client error handling"** claims `services/qyl.loom/CollectorClient.cs` follows a specific pattern: `Content.Headers.ContentType?.MediaType == "application/json"` check, `try/catch (JsonException)` on non-success paths, and "structured DTO failures, throwing on expected HTTP error status is the exception". - -The actual file calls `response.EnsureSuccessStatusCode()` on every call (~20 sites), with no ContentType check and no JsonException wrapping. The pattern the doc describes simply isn't there — either the convention is aspirational and was never adopted, or the file regressed away from it. - -### 2d. Inaccurate but close - -| Cited at | Claim | Reality | -|---|---|---| -| AGENTS.md:260 | `QylTelemetryExtensions` defines `WithQylTelemetry` | `WithQylTelemetry` exists, but in `QylWorkflowExecutionExtensions.cs`, not `QylTelemetryExtensions.cs`. The latter file contains `BeginQylSpan`/`WithQylSpanAsync`/`SetQylOperation`/`SetQylTag`. | -| AGENTS.md:62 | `preview` is enabled | Not set at root. `Directory.Build.props` defers to SDK defaults; individual csprojs declare `latest` or `14`. The "preview features are fair game" assertion isn't actually wired up at the root. | -| AGENTS.md:66 | `FakeChatClient` "lives in `tests/qyl.collector.tests/Instrumentation/`" | Lives in the external `ANcpLua.Agents.Testing` NuGet package. The tests just import it via `using ANcpLua.Agents.Testing.ChatClients;`. | -| AGENTS.md:89 | `Verify` target description (4 sub-checks) | Actually 5 sub-targets — also runs `VerifyGeneratedFilesClean` (the CI gate that flags drifted generated files; relevant to §3 below). | -| AGENTS.md table around line 145 | `GenerateSemconv` referenced in Codegen Boundaries | But **omitted from the Nuke workflow table** at lines 82-100. It exists at `eng/build/BuildPipeline.cs:45-107` and is callable via `./eng/build.sh GenerateSemconv`. | - ---- - -## 3. Codegen commands — actual behavior vs claims - -All three commands ran successfully on this machine. But they don't do exactly what the doc claims, and one of them produces non-trivial drift. - -### `./eng/build.sh GenerateSemconv` — runs in <1 sec - -| Doc claim (line 145) | Reality | -|---|---| -| Generates `packages/Qyl.SemanticConventions/Attributes/Qyl/QylAttributes.g.cs` | ✓ Generates that file. | -| (nothing else listed) | Also regenerates **all** of `packages/Qyl.OpenTelemetry.SemanticConventions.Incubating/Attributes/**` plus `SchemaUrl.g.cs` and `SchemaVersion.g.cs`. | - -Output is deterministic against committed state — zero diff after run. - -### `./eng/semconv/run-weaver.sh` — runs in <1 sec - -| Doc claim (lines 144,146) | Reality | -|---|---| -| Generates `packages/Qyl.OpenTelemetry.SemanticConventions{,Incubating}/Attributes/**` | **Wrong.** This script does **not** write to those paths. (`GenerateSemconv` does — see above.) | -| Generates `packages/Qyl.Telemetry/Conventions/Qyl.g.cs` | ✓ Generates that file. | -| (nothing else listed) | Also generates: `services/qyl.dashboard/src/lib/semconv.ts` (1368 lines), `services/qyl.collector/Storage/promoted-columns.g.sql` (1369 lines), `core/specs/emitters/qyl-semconv-lint/data/otel-attribute-registry.json` (675 attributes), `packages/qyl-client/src/conventions.ts`, `docs/attributes/qyl.attrs.md`. | - -Output is deterministic — zero diff after run. There's also an `ℹ No registry manifest found: …/eng/semconv/model/qyl/manifest.yaml` notice (informational, not blocking). - -### `./eng/build.sh Generate` — runs in ~22 sec - -Pipeline: `GenerateSemconv` → `TypeSpecInstall` → `TypeSpecCompile` (which runs 7 emitters in turn). - -| Doc claim (line 143) | Reality | -|---|---| -| Generates `packages/Qyl.Contracts/Generated/**` | ✓ | -| Generates `packages/qyl-client/src/generated/**` | ✓ but with drift — see below | -| (not listed) | Also writes to `services/qyl.collector/Storage/` (DuckDB emit), `packages/Qyl.Client/Generated/` (HTTP-client csharp emit, `Qyl.Client.slnx`), `packages/qyl-client/schemas/qyl-api` (JSON schemas), and `services/qyl.collector/Generated/` (server csharp + README + docs). | - -**Drift:** running this command from a clean tree produces **49 modified files, 11 629 insertions / 14 792 deletions**. Stripping whitespace (`git diff -w`) still leaves **45 files, 890 insertions / 4 053 deletions** — so it's not just formatting. The drift is concentrated in: - -- `packages/qyl-client/src/generated/**` — biggest delta is `models/internal/serializers.ts` (8 492 lines) and `models/models.ts` (8 495 lines) -- `packages/qyl-client/schemas/qyl-api` -- `services/qyl.collector/Generated/{README.md,docs/emitter.md,docs/usage.md}` (output by `@typespec/http-server-csharp`) - -The C# server output under `services/qyl.collector/Generated/generated/` is **clean** (0 drifted files). So the issue is specific to the JS-side TypeSpec emitters and the http-server emitter's docs. The `@typespec/http-client-csharp` emitter also showed a `⚠` warning during the run. - -**Implication:** AGENTS.md line 150 — "Source change + regenerated output ship in the same commit" — is currently broken. The committed `qyl-client` does not match what the local toolchain produces. Verify's `VerifyGeneratedFilesClean` sub-target (which the doc inaccurately omits) would presumably flag this in CI. - ---- - -## 4. Not checked - -- Whether issue #1 in `Alexander-Nachtmann/MAF.Advanced.Patterns` actually says what AGENTS.md:292 claims (different repo, didn't query). -- Whether commits `12a746f` and `bae3d2e` in MAF.Advanced.Patterns match the consolidation status descriptions on AGENTS.md:20-21 (would need git log in that other repo). -- The `ANcpLua.Agents` → `MAF.Advanced.Patterns` consolidation phases 1-7 — only verified the resulting packages exist, not that the migration commits did exactly what the bullet points say. -- `packages/Qyl.OpenTelemetry.SemanticConventions/Attributes/**` (non-Incubating) — neither command above wrote to this directory in this run, but the directory has 90 generated files committed. Some other path generates them; AGENTS.md:144 attributes them to `run-weaver.sh` which is incorrect (see §3). The actual generator wasn't pinned down in this session. - ---- - -## 5. Working-tree state at end of session - -The codegen-drift modifications were restored before writing this report. The drift was real (recorded in §3) but not kept on disk — to reproduce it: `./eng/build.sh Generate` from a clean tree, then `git diff -w --shortstat HEAD`. Only the pre-existing `M .github/copilot-instructions.md` from session start and the new `report.md` remain. - ---- - -## Recommendations (prioritised) - -1. **Fix the cargo-culted file paths in AGENTS.md** — replace `RcaExecutor.cs` and `LoomToolFactoryBridge.cs` with files that actually exist, or delete those rows. -2. **Either create the two `SKILL.md` files or remove the references** at AGENTS.md:198-199 — agents will follow them and hit nothing. -3. **Decide whether `CollectorClient.cs` should match the documented HTTP-error pattern**, then either rewrite the file or correct the doc. -4. **Run `nuke Generate` and commit the drift** so the committed state matches what local tooling produces — or pin the TypeSpec emitter versions if reproducibility across machines is the issue. -5. **Add `GenerateSemconv` to the Nuke workflow table** at AGENTS.md:82-100; correct the codegen-boundaries table to reflect that `run-weaver.sh` doesn't write to `Qyl.OpenTelemetry.SemanticConventions{,Incubating}/Attributes/**` (and add the outputs it actually produces). -6. **Fix `AutofixAgentService.cs:66-77` line range** to point at the actual streaming-loop file (`LoomAutofixRunner.cs:188`).