Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
14 changes: 14 additions & 0 deletions docs/_memory/glossary.md
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,20 @@ Default write scope is declared per agent in `memory.scope`.

## Autonomy

### Background role

A named daemon-owned responsibility routed through the closed `[roles]` roster: `coordinator`,
`dream`, `checkpoint_summary`, `memory_extractor`, `auto_title`, or `memory_controller`. Empty
session-role agents resolve either to a virtual builtin (`coordinator` or `dreaming-curator`) or to
the invoking context (`memory_extractor` and `auto_title`); the memory controller is an in-process
model call and has no agent identity.

`[roles]` owns routing β€” enabled state, agent/provider/model/reasoning selection, ordered fallbacks,
and the small amount of policy inseparable from coordinator sessions or controller calls. The
owning subsystem keeps its operational policy, gates, scoring, cadence, and prompts. Background
roles do not replace or govern Loop DSL model defaults, `TaskExecutionProfile`, or automation
resources.

### `task_run`

The single durable work-queue row. Carries `claim_token`, `lease_until`, `heartbeat_at`, the owning `session_id`, and the execution's immutable resolved Network participation snapshot. A `run_kind = "network_wake"` row is taskless and identifies the wake, owner execution, and target session explicitly. **Never duplicated by a parallel queue.**
Expand Down
6 changes: 4 additions & 2 deletions docs/qa/_seeds/final-qa/_children/05-memory-soul.md
Original file line number Diff line number Diff line change
Expand Up @@ -190,9 +190,11 @@ For consolidation scenarios that need a fast cycle:
[memory]
enabled = true

[memory.dream]
[roles.dream]
enabled = true
agent = "claude-code"

[memory.dream]
min_hours = 0.001 # β‰ˆ 3.6s; only acceptable in QA scenarios
min_sessions = 1 # MEM-04 raises to 5 to cover the sessions gate
check_interval = "2s"
Expand Down Expand Up @@ -1365,7 +1367,7 @@ risk: low
live: true
provider: real-openclaw
preconditions:
- `[memory.dream]` config with `agent="openclaw"`.
- `[roles.dream]` config with `agent="openclaw"`.
- Same seeds as MEM-16.
code_refs:
- /Users/pedronauck/Dev/compozy/agh/internal/memory/consolidation/runtime.go:250
Expand Down
43 changes: 43 additions & 0 deletions docs/qa/bugs/BUG-20260724-bundle-agent-snapshot-loss.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# BUG-20260724-bundle-agent-snapshot-loss: Installed bundle profiles silently lose packaged agents

- **Status:** verified
- **Impact (user-side):** Functional
- **Severity:** High Β· **Priority:** P1
- **Persona Affected:** Ada
- **Journey Step:** J-32 reserved-name bundle materialization probe
- **Scenarios:** RT-reserved-builtin-agent-names
- **Found:** 2026-07-24 Β· **Report:** docs/qa/reports/2026-07-24-agent-roles.md

## Summary

A locally installed extension loaded a bundle profile that packaged `agents/coordinator/AGENT.md`, but the public bundle service received an empty agent list. Preview showed no resources and activation succeeded as an empty profile, bypassing both normal agent materialization and reserved-name validation.

## Reproduction

- **Charter:** CH-reserved-builtin-name-sweep Β· **Tour:** Garbage Tour
- **Environment:** desktop / wifi-fast / en-US, isolated `devtool-oss-launch` lab

1. Install an extension whose bundle profile contains `[[profiles.agents]] path = "agents/coordinator"`.
2. Preview or activate the profile through the daemon.
3. Inspect the activation inventory and agent catalog.

**Expected:** The complete packaged agent reaches bundle validation, which rejects the reserved identity before any write.
**Actual:** The profile snapshot contains zero agents; an empty activation succeeds and materializes no agent.

## Evidence

- `reserved-bundle-{extension-install,catalog-before-activate,preview-current}.json` in the run's `qa-artifacts/qa` directory.
- The accidental empty activation `act_16b6f8f030a6fd9a` was immediately deactivated; `reserved-bundle-empty-activation-deactivate.json` proves cleanup.

## Fix

- **Root cause:** `cloneBundleSpecs` copied channels, jobs, triggers, and bridges but omitted `BundleProfile.Agents`. Bundle services consume the Manager snapshot rather than the mutable installed object.
- **Fix:** Extension snapshots now deep-clone every packaged agent plus Soul and Heartbeat sidecars.
- **Fix commit:** `c841d7e06428c28e4e1b4ba8c17bccb4a103eea1`
- **Regression test:** `internal/extension/manager_test.go` β€” `TestManagerCloneExtensionReturnsIsolatedSnapshot` proves agents survive and mutable fields do not alias the installed extension.

## Verification

- After rebuild and restart, the same fixture reached reserved-name validation before preview or activation.
- No activation or agent catalog residue remained after the valid probe.
- The extension `-race` suite passed 789 tests; repository lint passed.
42 changes: 42 additions & 0 deletions docs/qa/bugs/BUG-20260724-coordinator-config-list-path.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# BUG-20260724-coordinator-config-list-path: Coordinator enabled state is published under a path operators cannot use

- **Status:** verified
- **Impact (user-side):** Friction
- **Severity:** Medium Β· **Priority:** P2
- **Persona Affected:** Dora
- **Journey Step:** J-route-background-work baseline inspection, step 1
- **Scenarios:** MS-background-role-routing
- **Found:** 2026-07-24 Β· **Report:** docs/qa/reports/2026-07-24-agent-roles.md

## Summary

Dora listed effective configuration before changing a background role and saw the coordinator toggle as `roles.coordinator.roleconfig.enabled`. That path is not part of the public `[roles]` contract and cannot be used with `agh config set`; the supported path is `roles.coordinator.enabled`.

## Reproduction

- **Charter:** CH-background-role-routing-scopes Β· **Tour:** Feature Tour
- **Environment:** desktop / wifi-fast / en-US, isolated `devtool-oss-launch` lab

1. Start the isolated daemon with pristine role defaults.
2. Run `agh config list -o json`.
3. Inspect the entries beginning with `roles.coordinator`.

**Expected:** The coordinator toggle is listed as `roles.coordinator.enabled`.
**Actual:** The list contains `roles.coordinator.roleconfig.enabled` and omits the canonical enabled path.

## Evidence

- `/Users/pedronauck/dev/qa-labs/agh-agent-roles-devtool-oss-launch-20260724-094737-758561-lab/qa-artifacts/qa/config-list-roles.json`
- Independent write-path check: `agh config set roles.coordinator.max_children 6` resolves the canonical coordinator branch and returns its bounded validation error, while the published `roleconfig` segment is absent from the supported registry.

## Fix

- **Root cause:** The redacted config projector treated every exported struct field as a named TOML node. Go's anonymous `RoleConfig` field is flattened by the TOML contract, but the projector lowercased its Go type name to `roleconfig` and inserted a segment that does not exist in the file or validated write registry.
- **Fix:** Anonymous untagged TOML struct fields are now merged into their parent projection while explicit outer fields retain precedence.
- **Fix commit:** `69b2099f3cada66395ced4c8ae862b21b5ebc996`
- **Regression test:** `internal/cli/config_test.go` β€” `TestConfigRenderingAndMutationHelpers/Should flatten anonymous TOML fields into canonical parent paths` failed on the invalid `roleconfig` segment before the fix and passes after it.

## Verification

- **Retested:** 2026-07-24, Dora / J-route-background-work baseline from a freshly rebuilt and restarted isolated daemon Β· **Report:** docs/qa/reports/2026-07-24-agent-roles.md
- **Result:** `agh config list -o json` returns `roles.coordinator.enabled`; `agh config get roles.coordinator.enabled -o json` returns `false`; the invalid `roles.coordinator.roleconfig.enabled` path is absent. Package `-race` and repository lint gates pass.
42 changes: 42 additions & 0 deletions docs/qa/bugs/BUG-20260724-inherited-role-provider-resolution.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# BUG-20260724-inherited-role-provider-resolution: Model-only inherited roles omit the invoking provider

- **Status:** verified
- **Impact (user-side):** Functional
- **Severity:** High Β· **Priority:** P1
- **Persona Affected:** Dora; Ada
- **Journey Step:** J-route-background-work, live Settings save β†’ next auto-title invocation
- **Scenarios:** MS-background-role-routing; MS-background-role-fallback; MS-settings-roles-panel
- **Found:** 2026-07-24 Β· **Report:** docs/qa/reports/2026-07-24-agent-roles.md

## Summary

A valid model-only override on the inherited `auto_title` or `memory_extractor` role left the effective provider empty. Session creation rejected the primary route before acceptance, so auto-title either failed or used a configured fallback even though the invoking agent had a valid provider.

## Reproduction

- **Charters:** CH-background-role-routing-scopes, CH-role-fallback-boundary, CH-settings-roles-live-truth
- **Environment:** desktop / wifi-fast / en-US, isolated `devtool-oss-launch` lab

1. Configure `roles.auto_title.enabled = true`, `model = "gpt-5.6-luna"`, and no role-level provider.
2. Start a `general` session on provider `codex` and complete its first turn.
3. Inspect the generated title, hidden auto-title child, and `role.fallback.used` logs.

**Expected:** The inherited role resolves `codex` from the invoking agent, starts the hidden child on `codex/gpt-5.6-luna`, and needs no fallback.
**Actual:** The primary creation spec contains `provider = ""` with `model = "gpt-5.6-luna"`; validation rejects it before acceptance and advances to the fallback when one is configured.

## Evidence

- Before: `ui-live-auto-title-session.json`, `ui-live-fallback-{cli,http}.json` in the run's `qa-artifacts/qa` directory.
- After: `inherit-provider-fix-{session-create,auto-title-child,parent-after-title,fallback-events,visible-sessions,session-stop}.json` in the same directory.

## Fix

- **Root cause:** `RoleResolver.resolveEffective` returned immediately for an inherited role before reading invocation correlation or resolving the invoking agent's provider chain.
- **Fix:** In invocation context, inherited roles now resolve the correlated agent and apply the documented agent-provider β†’ default-provider chain while preserving the role's explicit model override. Projection reads without invocation context remain honestly unresolved.
- **Fix commit:** `a9a8fcad63f4354505e4c9a0701a6d0f559cc991`
- **Regression test:** `internal/daemon/role_resolver_test.go` β€” `TestRoleResolver/Should resolve inherited role overrides through the invoking agent provider chain` covers both an explicit invoking-agent provider and an invoking agent that inherits `defaults.provider`.

## Verification

- The focused regression failed red for both roles before the fix, then passed in four parallel cases; the complete daemon package passed 1,399 `-race` tests and repository lint passed with zero issues.
- A rebuilt/restarted daemon created hidden child `sess-afc891322e1060b8` as `general/codex/gpt-5.6-luna`, completed it, generated the parent title `inherited provider probe complete`, emitted zero `role.fallback.used` events, and kept the child out of the public session list.
44 changes: 44 additions & 0 deletions docs/qa/bugs/BUG-20260724-memory-extractor-agent-tier.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# BUG-20260724-memory-extractor-agent-tier: Extractor emits agent tier metadata outside agent scope

- **Status:** verified
- **Impact (user-side):** Functional
- **Severity:** High Β· **Priority:** P1
- **Persona Affected:** Dora
- **Journey Step:** J-digest-sessions-into-memory, extractor harvest
- **Scenarios:** MS-011
- **Found:** 2026-07-24 Β· **Report:** docs/qa/reports/2026-07-24-agent-roles.md

## Summary

The default Memory extractor produced a durable global candidate with `agent_tier = "global"`. Agent tier is valid only for agent-scoped memories, so the controller rejected the candidate and moved it to the extractor DLQ.

## Reproduction

- **Charter:** CH-dream-pipeline-canary Β· **Tour:** Feature Tour
- **Environment:** desktop / wifi-fast / en-US, isolated `devtool-oss-launch` lab

1. Run a normal provider-backed session while the default memory extractor is enabled.
2. Let the extractor return a global or workspace JSONL candidate with a non-empty `agent_tier`.
3. Drain the extractor and inspect `agh memory extractor list-pending -o json`.

**Expected:** The extractor boundary returns a contract-valid candidate; `agent_tier` is empty outside `scope = "agent"`.
**Actual:** The controller rejects the candidate with `memory controller: candidate frontmatter: agent tier requires agent scope` and records a DLQ item.

## Evidence

- `/Users/pedronauck/dev/qa-labs/agh-agent-roles-devtool-oss-launch-20260724-094737-758561-lab/qa-artifacts/qa/archive/20260724T112506.161087000Z-20260724T112506.009718000Z-257.jsonl.processing.json`
- `/Users/pedronauck/dev/qa-labs/agh-agent-roles-devtool-oss-launch-20260724-094737-758561-lab/qa-artifacts/qa/memory-extractor-status-after-source.json`

## Fix

- **Root cause:** The extractor prompt presented `agent_tier` as a universal field, and `candidateFromExtractedLine` preserved it for every scope even though Memory v2 permits it only for agent scope.
- **Fix:** The prompt now makes `agent_tier` conditional, while the untrusted-output adapter strips it from global and workspace candidates before controller submission.
- **Fix commit:** `b6f7408439a68b9e5225b1b086770b4e37347e58`
- **Regression test:** `internal/daemon/memory_runtime_test.go` β€” `TestCollectMemoryExtractorOutput` covers both workspace and global candidates carrying an inapplicable tier.

## Verification

- **Retested:** 2026-07-24 from a rebuilt and restarted isolated daemon.
- A fresh provider-backed session produced two workspace memories; drain returned `remaining = 0`, no new DLQ record appeared, and health returned `status = "ok"` with two workspace files.
- Evidence: `memory-pipeline-retest-{drain,extractor-status,list,health}.json` under the run's `qa-artifacts/qa` directory.
- Scoped `-race` gates passed 1,396 daemon tests and 32 memory-prompt tests; repository lint passed.
44 changes: 44 additions & 0 deletions docs/qa/bugs/BUG-20260724-reserved-bundle-error-mapping.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# BUG-20260724-reserved-bundle-error-mapping: Reserved bundle agents return internal errors

- **Status:** verified
- **Impact (user-side):** Friction
- **Severity:** Medium Β· **Priority:** P2
- **Persona Affected:** Ada; agent operators
- **Journey Step:** J-32 reserved-name bundle materialization probe
- **Scenarios:** RT-reserved-builtin-agent-names
- **Found:** 2026-07-24 Β· **Report:** docs/qa/reports/2026-07-24-agent-roles.md

## Summary

Once a packaged `coordinator` reached bundle validation, the domain returned the correct `ErrAgentNameReserved` sentinel and wrote nothing. HTTP and UDS nevertheless classified it as 500, and the native adapter collapsed it to `tool_backend_failed` rather than the public `agent_name_reserved` code.

## Reproduction

- **Charter:** CH-reserved-builtin-name-sweep Β· **Tour:** Garbage Tour
- **Environment:** desktop / wifi-fast / en-US, isolated `devtool-oss-launch` lab

1. Activate a bundle profile that packages an agent named `coordinator`.
2. Repeat through HTTP, UDS/CLI, and `agh__bundles_activate`.
3. Inspect status, diagnostic code, and post-attempt activation/catalog state.

**Expected:** HTTP and UDS return 422, CLI exits with its diagnostic exit class, native returns `agent_name_reserved`, and no state changes.
**Actual:** HTTP and UDS return 500; native classifies the same validation error as a backend failure.

## Evidence

- Before: `reserved-bundle-{http,uds,cli}-valid-probe.*` in the run's `qa-artifacts/qa` directory.
- After: `reserved-bundle-{http,uds,cli}-fixed-probe.*` and `native-bundle-capable-session-history.json`.

## Fix

- **Root cause:** `StatusForBundleError` did not classify `ErrAgentNameReserved`, and the native bundle adapter relied only on the resulting generic HTTP status mapping.
- **Fix:** Bundle API mapping now returns 422 for the sentinel; the native adapter preserves `ErrorCodeAgentNameReserved` with invalid-input/schema semantics.
- **Fix commit:** `a1c966c01b40ae37372e4431704703acd92e679a`
- **Regression tests:** `TestStatusForBundleErrorAndChannelHelpers/agent name reserved` and `TestDaemonNativeTools/Should preserve the reserved agent code from bundle activation`.

## Verification

- CLI/HTTP/UDS returned `agent_name_reserved`; HTTP and UDS returned 422 and named `.agh/bundles/<activation>/agents/coordinator/AGENT.md`.
- A real Codex session invoked `agh__bundles_activate` once and received `agent_name_reserved: Unprocessable Entity`.
- Activation and agent catalogs were byte-stable across every rejected attempt.
- API core passed 1,346 `-race` tests, daemon passed 1,396, and repository lint passed.
39 changes: 39 additions & 0 deletions docs/qa/charters/CH-background-role-routing-scopes.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# CH-background-role-routing-scopes: Routing changes exactly the scope I chose β€” live, bounded, and nowhere else

```yaml
charter:
id: CH-background-role-routing-scopes
mission: "As Dora, drive the whole [roles] write plane β€” global config set, workspace overlay, and the native agh__config_* tools β€” and prove every accepted route becomes live for the next eligible invocation in exactly the chosen scope, every invalid or deleted key is rejected with its exact path, and routed catalog agents still behave as their role."
mode: charter-with-tour
persona:
name: Dora
device: desktop
network: wifi-fast
locale: en-US
journey: J-route-background-work
scenarios: [MS-background-role-routing]
tour: Feature Tour
time_box_minutes: 90
guidance:
must_try:
- "Baseline first: `agh config list -o json` (read the exact roles.* leaves β€” `agh config get` takes one flattened leaf like roles.dream.model, never the roles branch) and `agh roles list -o json` on a fresh home must show the pinned defaults (coordinator off; dream/checkpoint on builtin dreaming-curator; auto_title/extractor inherit; controller haiku@250ms)."
- "Global route: `agh config set roles.dream.model <m>` then trigger a dream (`agh memory dream trigger`) β€” the hidden dream session resolves the routed model with the builtin identity, and the session stays out of fleet/session lists (Invariant 10)."
- "Workspace route: `agh config set --scope workspace --workspace <root> roles.dream.agent <local-curator>` β€” that workspace's next dream runs the catalog agent (AGH role overlay still applied, ADR-003/Invariant 12) while a sibling workspace keeps global routing; survive a fresh config read (Invariant 11)."
- "Live toggle: `roles.auto_title.enabled false` β†’ next session gets no title spawn; re-enable β†’ titles resume, all without daemon restart."
- "Native plane: `agh__config_list` serves the exact roles.* leaves and `agh__config_get roles.auto_title.model` reads one; `agh__config_set roles.auto_title.model` accepted and `agh__config_unset` restores the inherited value; `agh__config_path` proves only the selected global/workspace config file target and scope; every removed path (`memory.dream.agent`, `memory.controller.llm.model`, `session.auto_title_enabled`, `autonomy.coordinator.*`) rejected deterministically by both `agh config set` and `agh__config_set` (Invariant 9)."
- "Rejection quality: `roles.coordinator.max_children 6` names the ≀5 cap (Invariant 8); `roles.dream.timeout` in TOML fails load naming `roles.dream.timeout` (Invariant 7); an old deleted key inside config.toml fails load naming the key; the prior good config stays authoritative after every rejection."
- "Ghost route: `roles.dream.agent ghost` β€” the next invocation fails explicitly (`role_agent_not_found` / role.resolve.error), with no silent builtin fallback (Invariant 4)."
must_avoid:
- "The Settings web panel (CH-settings-roles-live-truth owns it) and fallback chains under failure (CH-role-fallback-boundary owns them)."
- "Editing role policy knobs that stayed subsystem-side (dream cadence/gates, extractor pipeline) β€” the routing-vs-policy split means they are out of mission."
coverage:
surfaces:
- "[roles] via agh config set (global) + --scope workspace --workspace overlay"
- "agh__config_list|get|set|unset roles.* accept + removed-path reject; agh__config_path scope-target proof only"
- "routed invocation evidence (dream, auto_title) incl. hidden-session visibility"
- "docs entry origin: runtime/core/configuration/config-toml [roles] worked example matches observed behavior"
invariants: [4, 7, 8, 9, 10, 11, 12]
adrs: [ADR-002, ADR-003]
```

<!-- The charter is durable and immutable: each run's debrief belongs in that run's dated report. -->
Loading
Loading