Compare commits

..

13 Commits

Author SHA1 Message Date
Codex 3fb54b662f docs: refresh planner priorities for 4351
Harness (E2E) / Harnesses (mock LLM) (push) Waiting to run
Harness (E2E) / Provider harnesses (live LLM conformance) (push) Waiting to run
Lint / golangci-lint (push) Waiting to run
Run Tests / Unit Tests (push) Waiting to run
Run Tests / Etcd Integration Tests (push) Waiting to run
2026-07-08 12:43:57 +00:00
Asim Aslam 415e95c0f1 test agent startup resume checkpoints (#4350)
Co-authored-by: Codex <codex@openai.com>
2026-07-08 13:20:15 +01:00
Asim Aslam 36c42d0cfa docs: refresh planner priorities for 4345 (#4346)
Co-authored-by: Codex <codex@openai.com>
2026-07-08 12:50:35 +01:00
Asim Aslam 459dff8e7a ci: add first-agent CLI wayfinding target (#4344)
Co-authored-by: Codex <codex@openai.com>
2026-07-08 12:26:26 +01:00
Asim Aslam 6c74ae0f9c docs: refresh planner priorities for 4340 (#4342)
Co-authored-by: Codex <codex@openai.com>
2026-07-08 11:55:34 +01:00
Asim Aslam 224e107f1c Stabilize plan-delegate notify recovery (#4339)
Co-authored-by: Codex <codex@openai.com>
2026-07-08 11:28:41 +01:00
Asim Aslam e0b9f1323f docs: refresh planner priorities for 4335 (#4337)
Co-authored-by: Codex <codex@openai.com>
2026-07-08 11:00:58 +01:00
Asim Aslam 35d3d99428 Fail agent-flow on missing onboarding side effects (#4334)
Co-authored-by: Codex <codex@openai.com>
2026-07-08 10:30:24 +01:00
Asim Aslam 656c0ce9d6 docs: refresh planner priorities for 4331 (#4332)
Co-authored-by: Codex <codex@openai.com>
2026-07-08 10:05:26 +01:00
Asim Aslam 7734f5605d Verify zero-to-hero deploy dry-run (#4330)
Co-authored-by: Codex <codex@openai.com>
2026-07-08 09:26:45 +01:00
Asim Aslam affd61e69b docs: refresh coherence changelog (#4326)
Co-authored-by: Codex <codex@openai.com>
2026-07-08 08:57:36 +01:00
Asim Aslam 171da77817 docs: refresh planner priorities for 4319 (#4320)
Co-authored-by: Codex <codex@openai.com>
2026-07-08 08:03:31 +01:00
Asim Aslam 83a6b2004a Propagate provider HTTP retry signals (#4318)
Co-authored-by: Codex <codex@openai.com>
2026-07-08 06:43:28 +01:00
11 changed files with 279 additions and 20 deletions
+2 -3
View File
@@ -21,9 +21,8 @@ changes, architectural rewrites. Those go to the human.
## Work queue (ranked)
1. **Propagate cancellation and retry signals through provider model calls** ([#4273](https://github.com/micro/go-micro/issues/4273)) — The live AtlasCloud tool-call reporting defect closed with #4313, leaving provider-boundary resilience as the highest-value Now-phase hardening seam. Keep the increment focused on cancellation/deadline/retry behavior across model calls, with fakes/tests and no public API or architecture changes.
2. **CI-verify zero-to-hero deploy dry-run path** ([#4309](https://github.com/micro/go-micro/issues/4309)) — Developer adoption remains the current goal, and the docs now have a strong no-secret first-agent path; the next adoption gap is making sure the documented scaffold → run → chat → inspect → deploy dry-run lifecycle is continuously verified through the deploy boundary, not just described. This keeps the 0→hero contract honest alongside internal resilience work.
3. **Trace agent RunInfo in OpenTelemetry spans** ([#4315](https://github.com/micro/go-micro/issues/4315)) — After the Now-phase resilience and getting-started contract gaps, the highest Next-phase operability gap is connecting existing run metadata to traces so real agent runs can be debugged across steps, tool calls, delegation, failures, services, and flows without inventing a new surface.
1. **Stabilize AtlasCloud agent conformance marker retry** ([#4348](https://github.com/micro/go-micro/issues/4348)) — The durable-agent checkpoint issue has shipped, so the highest-value open Now-phase gap is the live provider conformance failure found in Harness (E2E): AtlasCloud completes the tool/delegate path but can omit the required conformance marker after retry. Fixing this protects the cross-provider promise behind first-agent trust without broad API or architecture change.
2. **Trace agent RunInfo in OpenTelemetry spans** ([#4315](https://github.com/micro/go-micro/issues/4315)) — After the live conformance regression is stable, the highest Next-phase operability gap is connecting existing run metadata to traces so real agent runs can be debugged across steps, tool calls, delegation, failures, services, and flows without inventing a new surface.
_Seeded by Claude Code from the roadmap + open issues; thereafter maintained by the
architecture-review pass._
+25
View File
@@ -16,12 +16,37 @@ next version when it ships.
## [Unreleased]
### Added
- **Provider HTTP retry signals** — provider failures now preserve HTTP status and `Retry-After` details so retry classification and backoff can respond to rate limits and unavailable providers. (`ai/`)
### Fixed
- **Stream fallback memory** — unsupported streaming attempts no longer leave stale duplicate user turns before fallback paths continue with non-streaming agent calls. (`agent/`)
- **Function-style text tool calls** — agent fallback parsing now recognizes provider replies that render tools as function-style calls, including nested JSON arguments. (`agent/`)
- **Plan/delegate notify recovery** — plan-delegate recovery now waits for recovered notify side effects and routes retries through the communications agent that owns the notification. (`internal/harness/`)
### Documentation
- **First-agent docs wayfinding guard** — the local harness now includes a focused no-network check for first-agent and 0→hero docs links. (`Makefile`, `internal/harness/`)
---
## [6.3.18] - July 2026
### Added
- **StreamAsk close cancellation** — agent streaming calls now cancel promptly when their runner closes, avoiding orphaned stream work. (`agent/`)
- **Agent resume pending helper** — agent durability now has a focused helper for resuming pending checkpointed runs. (`agent/`)
- **Agent tool retry tracing** — agent traces now include tool retry attempts for easier debugging of retry/fallback behavior. (`agent/`)
- **Shared-broker universe harness** — the universe harness now runs against the shared broker path, improving coverage of the same runtime wiring used by services, agents, and workflows. (`internal/harness/`)
### Fixed
- **Plan/delegate retry idempotency** — agent retries now preserve side-effect and notification dedupe across conformance retry paths, including completion and owner-notification edge cases. (`agent/`, `internal/harness/`)
- **AtlasCloud text tool calls** — AtlasCloud fallback handling now recovers more text-rendered tool calls from OpenAI-compatible responses. (`ai/atlascloud/`, `agent/`)
- **OpenAI-compatible text tool calls** — OpenAI-compatible providers now recover text-rendered tool calls more reliably. (`agent/`)
- **AtlasCloud multi-step follow-ups** — AtlasCloud tool fallback handling now continues multi-step tool follow-up paths more reliably. (`ai/atlascloud/`, `agent/`)
### Documentation
- **Agent debugging quickcheck** — docs now include a focused quickcheck path for first-agent debugging. (`internal/website/docs/`)
- **Website first-agent examples map** — website docs now link the maintained examples wayfinding map for the first-agent route. (`internal/website/docs/`)
- **Examples wayfinding index** — examples docs now provide a central map for first-agent, support, and interop examples. (`examples/`, `internal/website/docs/`)
---
+11 -3
View File
@@ -8,7 +8,7 @@ LDFLAGS = -X $(GIT_IMPORT).BuildDate=$(BUILD_DATE) -X $(GIT_IMPORT).GitCommit=$(
# GORELEASER_DOCKER_IMAGE = ghcr.io/goreleaser/goreleaser-cross:v1.25.7
GORELEASER_DOCKER_IMAGE = ghcr.io/goreleaser/goreleaser:latest
.PHONY: test test-race test-coverage harness docs-wayfinding install-smoke provider-conformance-mock provider-conformance lint fmt install-tools proto clean help gorelease-dry-run gorelease-dry-run-docker
.PHONY: test test-race test-coverage harness cli-wayfinding docs-wayfinding install-smoke provider-conformance-mock provider-conformance lint fmt install-tools proto clean help gorelease-dry-run gorelease-dry-run-docker
# Default target
help:
@@ -19,6 +19,7 @@ help:
@echo " make test-coverage - Run tests with coverage"
@echo " make lint - Run linter"
@echo " make harness - Run deterministic getting-started and end-to-end harnesses"
@echo " make cli-wayfinding - Verify installed first-agent CLI wayfinding commands"
@echo " make docs-wayfinding - Verify first-agent docs wayfinding links resolve locally"
@echo " make install-smoke - Verify the local install.sh and first-run CLI smoke path"
@echo " make provider-conformance-mock - Run cross-provider harness with deterministic mock provider"
@@ -50,13 +51,20 @@ test-coverage:
# This mirrors the default CI path so local dogfooding catches scaffold,
# run/chat/inspect, and 0→hero regressions before a PR is opened.
harness:
$(MAKE) docs-wayfinding
$(MAKE) install-smoke
$(MAKE) cli-wayfinding
go test ./cmd/micro/cli/new -run TestZeroToOne -count=1
./internal/harness/zero-to-hero-ci/run.sh
go run ./internal/harness/agent-flow
$(MAKE) provider-conformance-mock
# Verify the installed CLI keeps the first-agent on-ramp commands discoverable.
# This guards the no-secret commands README/docs recommend (`micro agent demo`,
# `micro examples`, and `micro zero-to-hero`) as a CI contract.
cli-wayfinding:
go test ./cmd/micro -run 'TestFirstAgentWalkthroughCLIBoundaries|TestExamplesWayfinding' -count=1
$(MAKE) docs-wayfinding
$(MAKE) install-smoke
# Verify the README and website first-agent/0→hero wayfinding links resolve to
# maintained local docs and examples. This is a focused no-network guard for the
# developer-adoption on-ramp.
+65
View File
@@ -397,6 +397,71 @@ func TestResumeFailedCheckpointAfterFreshAgentRestart(t *testing.T) {
}
}
func TestResumePendingAfterFreshAgentRestartDoesNotReplayCompletedTool(t *testing.T) {
ctx := context.Background()
st := store.NewMemoryStore()
cp := flow.StoreCheckpoint(st, "startup-resume-agent")
toolRuns := 0
failFirst := true
fakeGen = func(ctx context.Context, opts ai.Options, req *ai.Request) (*ai.Response, error) {
if opts.ToolHandler != nil {
res := opts.ToolHandler(ctx, ai.ToolCall{ID: "call-1", Name: "external.allocate", Input: map[string]any{"cluster": "blue"}})
if res.Content != "allocated" {
t.Fatalf("tool result = %q, want allocated", res.Content)
}
}
if failFirst {
failFirst = false
return nil, errors.New("process stopped before final response")
}
return &ai.Response{Reply: "startup recovery complete"}, nil
}
defer func() { fakeGen = nil }()
newAgent := func() *agentImpl {
return newTestAgent(Name("startup-resume-agent"), WithStore(st), WithCheckpoint(cp),
WithTool("external.allocate", "allocate capacity once", nil, func(context.Context, map[string]any) (string, error) {
toolRuns++
return "allocated", nil
}))
}
first := newAgent()
_, err := first.Ask(ctx, "allocate blue capacity")
if err == nil {
t.Fatal("Ask succeeded, want simulated process stop")
}
if toolRuns != 1 {
t.Fatalf("tool executions after failed Ask = %d, want 1", toolRuns)
}
restarted := newAgent()
failedRun, err := ResumePending(ctx, restarted)
if err != nil {
t.Fatalf("ResumePending after restart: failedRun=%q err=%v", failedRun, err)
}
if failedRun != "" {
t.Fatalf("failed run = %q, want none", failedRun)
}
if toolRuns != 1 {
t.Fatalf("tool executions after ResumePending = %d, want completed tool not replayed", toolRuns)
}
runs, err := Pending(ctx, restarted)
if err != nil {
t.Fatalf("Pending after ResumePending: %v", err)
}
if len(runs) != 0 {
t.Fatalf("Pending after ResumePending = %#v, want none", runs)
}
summaries, err := ListRunSummaries(st, "startup-resume-agent")
if err != nil {
t.Fatalf("ListRunSummaries after ResumePending: %v", err)
}
if len(summaries) != 1 || summaries[0].Status != "done" || summaries[0].Checkpoint != "done" {
t.Fatalf("summary after ResumePending = %#v, want one done run", summaries)
}
}
func TestResumeFailedCheckpointDoesNotDuplicateCompactedMemory(t *testing.T) {
ctx := context.Background()
st := store.NewMemoryStore()
+29 -10
View File
@@ -178,6 +178,24 @@ func waitFor(reg registry.Registry, name string) {
}
}
func waitForOnboardingSideEffects(ctx context.Context, wsSvc *WorkspaceService, ntSvc *NotifyService) error {
ticker := time.NewTicker(50 * time.Millisecond)
defer ticker.Stop()
for {
workspaces, notifications := wsSvc.count(), ntSvc.count()
if workspaces >= 1 && notifications >= 1 {
return nil
}
select {
case <-ctx.Done():
return fmt.Errorf("agent-flow missing required onboarding side effects before timeout: workspaces=%d/1 notifications=%d/1", workspaces, notifications)
case <-ticker.C:
}
}
}
func main() {
provider := flag.String("provider", "mock", "LLM provider: mock (default), anthropic, openai, ...")
flag.Parse()
@@ -257,20 +275,21 @@ func main() {
os.Exit(1)
}
// Wait for the agent to finish acting.
deadline := time.Now().Add(30 * time.Second)
for time.Now().Before(deadline) {
if ntSvc.count() >= 1 && wsSvc.count() >= 1 {
break
}
time.Sleep(50 * time.Millisecond)
}
// Wait for the agent to finish acting, and fail the harness if the
// provider returns a successful reply without the required service side
// effects. The 0→hero/provider conformance path must not print success
// unless the services → agent → workflow contract actually happened.
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
err := waitForOnboardingSideEffects(ctx, wsSvc, ntSvc)
cancel()
fmt.Printf("\n\033[1mresult:\033[0m workspaces created=%d, notifications sent=%d\n", wsSvc.count(), ntSvc.count())
if rs := f.Results(); len(rs) > 0 {
fmt.Printf("flow reply: %s\n", rs[len(rs)-1].Reply)
}
if wsSvc.count() >= 1 && ntSvc.count() >= 1 {
fmt.Println("\n\033[32m✓ the agent onboarded the user — triggered by an event, not a prompt\033[0m")
if err != nil {
fmt.Printf("\n\033[31m✗ %v\033[0m\n", err)
os.Exit(1)
}
fmt.Println("\n\033[32m✓ the agent onboarded the user — triggered by an event, not a prompt\033[0m")
}
+36
View File
@@ -1,6 +1,8 @@
package main
import (
"context"
"strings"
"testing"
"time"
@@ -99,3 +101,37 @@ func TestEventTriggersAgentNoPrompt(t *testing.T) {
t.Errorf("flow recorded no result for the event")
}
}
func TestWaitForOnboardingSideEffectsFailsWhenMissing(t *testing.T) {
wsSvc := new(WorkspaceService)
ntSvc := new(NotifyService)
ctx, cancel := context.WithTimeout(context.Background(), time.Millisecond)
defer cancel()
err := waitForOnboardingSideEffects(ctx, wsSvc, ntSvc)
if err == nil {
t.Fatal("waitForOnboardingSideEffects returned nil, want missing side effects error")
}
if got := err.Error(); !strings.Contains(got, "workspaces=0/1") || !strings.Contains(got, "notifications=0/1") {
t.Fatalf("waitForOnboardingSideEffects error %q does not report missing side effects", got)
}
}
func TestWaitForOnboardingSideEffectsPassesWhenComplete(t *testing.T) {
wsSvc := new(WorkspaceService)
ntSvc := new(NotifyService)
if err := wsSvc.Create(context.Background(), &CreateRequest{Owner: "alice@acme.com"}, &CreateResponse{}); err != nil {
t.Fatalf("create workspace: %v", err)
}
if err := ntSvc.Send(context.Background(), &SendRequest{To: "alice@acme.com", Message: "Welcome"}, &SendResponse{}); err != nil {
t.Fatalf("send notification: %v", err)
}
ctx, cancel := context.WithTimeout(context.Background(), time.Second)
defer cancel()
if err := waitForOnboardingSideEffects(ctx, wsSvc, ntSvc); err != nil {
t.Fatalf("waitForOnboardingSideEffects returned %v, want nil", err)
}
}
+13 -2
View File
@@ -482,7 +482,7 @@ func runPlanDelegate(provider string) error {
f := flow.New("zero-to-hero",
flow.Steps(
flow.Step{Name: "conductor", Run: planDelegateConductorStep(conductor)},
flow.Step{Name: "conductor", Run: planDelegateConductorStep(conductor, taskSvc, notifySvc)},
flow.Step{Name: "require-notify", Run: requireDelegatedNotifyStep(taskSvc, notifySvc, func(ctx context.Context) error {
_, err := comms.Ask(ctx, "Send exactly one owner readiness notification now with this exact task: "+delegatedNotifyTask+" Use the notify service and do not answer until the notification has been sent.")
return err
@@ -521,11 +521,15 @@ func runPlanDelegate(provider string) error {
return nil
}
func planDelegateConductorStep(conductor agent.Agent) flow.StepFunc {
func planDelegateConductorStep(conductor agent.Agent, taskSvc *TaskService, notifySvc *NotifyService) flow.StepFunc {
return func(ctx context.Context, in flow.State) (flow.State, error) {
prompt := "Create three launch tasks (Design, Build, Ship), then make sure owner@acme.com is notified: " + in.String()
rsp, err := conductor.Ask(ctx, prompt)
if err != nil {
if isUnfinishedPlanError(err) && taskSvc != nil && notifySvc != nil && taskSvc.count() == 3 && notifySvc.count() == 0 {
fmt.Printf("\n\033[33mwarning:\033[0m conductor stopped with unfinished delegation after creating tasks; continuing to require-notify recovery: %v\n", err)
return in, nil
}
return in, err
}
if rsp != nil && rsp.Reply != "" {
@@ -535,6 +539,13 @@ func planDelegateConductorStep(conductor agent.Agent) flow.StepFunc {
}
}
func isUnfinishedPlanError(err error) bool {
if err == nil {
return false
}
return strings.Contains(strings.ToLower(err.Error()), "unfinished plan steps")
}
func requireDelegatedNotifyStep(taskSvc *TaskService, notifySvc *NotifyService, recoverMissingNotify func(context.Context) error) flow.StepFunc {
return func(ctx context.Context, in flow.State) (flow.State, error) {
tasks := taskSvc.count()
@@ -301,6 +301,45 @@ func TestPlanDelegateExecutionRejectsClaimedCompletionWithoutNotify(t *testing.T
}
}
type failingAgent struct {
err error
}
func (a failingAgent) Name() string { return "failing" }
func (a failingAgent) Init(...agent.Option) {}
func (a failingAgent) Options() agent.Options { return agent.Options{} }
func (a failingAgent) Ask(context.Context, string) (*agent.Response, error) { return nil, a.err }
func (a failingAgent) Stream(context.Context, string) (ai.Stream, error) { return nil, a.err }
func (a failingAgent) Run() error { return nil }
func (a failingAgent) Stop() error { return nil }
func (a failingAgent) String() string { return "failing" }
func TestPlanDelegateConductorAllowsNotifyRecoveryAfterUnfinishedDelegation(t *testing.T) {
taskSvc := new(TaskService)
for _, title := range []string{"Design", "Build", "Ship"} {
var rsp AddResponse
if err := taskSvc.Add(context.Background(), &AddRequest{Title: title}, &rsp); err != nil {
t.Fatalf("Add(%q): %v", title, err)
}
}
notifySvc := new(NotifyService)
step := planDelegateConductorStep(failingAgent{err: errors.New("agent run abc has unfinished plan steps: Delegate readiness notification to comms agent")}, taskSvc, notifySvc)
if _, err := step(context.Background(), flow.State{}); err != nil {
t.Fatalf("planDelegateConductorStep returned %v, want require-notify recovery to run", err)
}
}
func TestPlanDelegateConductorKeepsUnfinishedTaskFailureActionable(t *testing.T) {
step := planDelegateConductorStep(failingAgent{err: errors.New("agent run abc has unfinished plan steps: Create Build task")}, new(TaskService), new(NotifyService))
err := func() error { _, err := step(context.Background(), flow.State{}); return err }()
if err == nil {
t.Fatal("planDelegateConductorStep returned nil, want unfinished task error")
}
if got := err.Error(); !strings.Contains(got, "Create Build task") {
t.Fatalf("error = %q, want original unfinished task detail", got)
}
}
func TestPlanDelegateExecutionRecoversMissingNotifyOnce(t *testing.T) {
taskSvc := new(TaskService)
for _, title := range []string{"Design", "Build", "Ship"} {
@@ -62,6 +62,62 @@ func TestZeroToHeroReferenceDocs(t *testing.T) {
}
}
func TestZeroToHeroDeployDryRunCommandSmoke(t *testing.T) {
root := filepath.Clean(filepath.Join("..", "..", ".."))
absRoot, err := filepath.Abs(root)
if err != nil {
t.Fatalf("resolve repository root: %v", err)
}
bin := filepath.Join(t.TempDir(), "micro")
build := exec.Command("go", "build", "-o", bin, "./cmd/micro")
build.Dir = absRoot
if out, err := build.CombinedOutput(); err != nil {
t.Fatalf("build micro CLI for deploy dry-run smoke: %v\n%s", err, out)
}
workspace := t.TempDir()
writeFile(t, filepath.Join(workspace, "micro.mu"), `service api
path ./api
deploy prod
ssh deploy@prod.example.com
path /srv/micro
`)
if err := os.Mkdir(filepath.Join(workspace, "api"), 0o755); err != nil {
t.Fatalf("create service dir: %v", err)
}
cmd := exec.Command(bin, "deploy", "--dry-run", "prod")
cmd.Dir = workspace
cmd.Env = append(os.Environ(), "MICRO_CONFIG_FILE="+filepath.Join(workspace, "micro.mu"))
out, err := cmd.CombinedOutput()
if err != nil {
t.Fatalf("documented deploy dry-run command failed: %v\n%s", err, out)
}
got := string(out)
for _, want := range []string{
"micro deploy --dry-run",
"Target",
"deploy@prod.example.com",
"Remote path",
"/srv/micro",
"Services",
"api",
"No SSH, rsync, systemd, or remote deployment was performed.",
} {
if !strings.Contains(got, want) {
t.Fatalf("deploy dry-run output missing %q:\n%s", want, got)
}
}
guide := readFile(t, filepath.Join(absRoot, "internal", "website", "docs", "guides", "zero-to-hero.md"))
if !strings.Contains(guide, "micro deploy --dry-run prod") {
t.Fatal("0→hero guide must document the same deploy dry-run command covered by CI")
}
}
func TestGuidesNavigationLeadsWithDoing(t *testing.T) {
root := filepath.Clean(filepath.Join("..", "..", ".."))
nav := readFile(t, filepath.Join(root, "internal", "website", "_data", "navigation.yml"))
+1 -1
View File
@@ -9,7 +9,7 @@ cd "$ROOT"
go test ./cmd/micro/cli/new -run TestZeroToOne -count=1
go test ./cmd/micro -run 'TestFirstAgentWalkthroughCLIBoundaries|TestZeroToHeroCLIBoundaries' -count=1
go test ./cmd/micro/cli/deploy -run TestDeployDryRun -count=1
go test ./internal/harness/zero-to-hero-ci -run 'TestNoSecretFirstAgentTranscript|TestNoSecretFirstAgentDebuggingSmoke|TestZeroToHeroReferenceDocs|TestYourFirstAgentTutorialSmoke' -count=1
go test ./internal/harness/zero-to-hero-ci -run 'TestNoSecretFirstAgentTranscript|TestNoSecretFirstAgentDebuggingSmoke|TestZeroToHeroReferenceDocs|TestZeroToHeroDeployDryRunCommandSmoke|TestYourFirstAgentTutorialSmoke' -count=1
# Deterministic no-secret reference scenarios. These use the real Go Micro
# runtime and mock only the LLM provider. The support example is the maintained
+2 -1
View File
@@ -23,7 +23,7 @@ cloud credentials?"
| Run | `micro run` remains the local development entry point. | `go test ./cmd/micro -run TestZeroToHeroCLIBoundaries -count=1` |
| Chat | `micro chat` remains the interactive agent entry point. | `go test ./cmd/micro -run TestZeroToHeroCLIBoundaries -count=1` |
| Inspect | `micro inspect agent <name>`, `micro agent history <name>`, `micro inspect flow <flow>`, and `micro flow runs <flow>` remain discoverable for run history; the no-secret debugging smoke seeds durable agent history and runs the documented inspect/history commands without provider keys. | `go test ./internal/harness/zero-to-hero-ci -run TestNoSecretFirstAgentDebuggingSmoke -count=1` |
| Deploy | `micro deploy --dry-run` resolves deploy targets without touching remote infrastructure. | `go test ./cmd/micro/cli/deploy -run TestDeployDryRun -count=1` |
| Deploy | `micro deploy --dry-run prod` resolves the documented deploy target without touching remote infrastructure. | `go test ./internal/harness/zero-to-hero-ci -run TestZeroToHeroDeployDryRunCommandSmoke -count=1` |
| Smallest first agent | `examples/first-agent` runs one service-backed agent with a deterministic mock model and no provider key. | `go test ./examples/first-agent -run TestRunFirstAgent -count=1` |
| Runtime reference app | `examples/support` runs typed services, an agent using those services as tools, an event-driven flow handoff, and an approval gate with only the model mocked. | `go test ./examples/support -run 'TestRunSupportMockSmoke|TestZeroToHeroReadmeDocumentsLifecycle' -count=1` |
| Runtime harnesses | Real services, agents, durable flows, store-backed history, delegation, and A2A run with only the model mocked. | `./internal/harness/zero-to-hero-ci/run.sh` and `make provider-conformance-mock` |
@@ -84,6 +84,7 @@ go test ./cmd/micro -run TestFirstAgentWalkthroughCLIBoundaries -count=1
# CLI inner-loop commands: run, chat, inspect, flow runs, deploy --dry-run.
go test ./cmd/micro -run TestZeroToHeroCLIBoundaries -count=1
go test ./cmd/micro/cli/deploy -run TestDeployDryRun -count=1
go test ./internal/harness/zero-to-hero-ci -run TestZeroToHeroDeployDryRunCommandSmoke -count=1
# Smallest no-secret service-backed first agent.
go test ./examples/first-agent -run TestRunFirstAgent -count=1