Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Make add/add-wizard and update manifest-aware for aw.yml package installs#34008

Merged
pelikhan merged 9 commits into
mainfrom
copilot/fix-aw-json-manifest-support
May 22, 2026
Merged

Make add/add-wizard and update manifest-aware for aw.yml package installs#34008
pelikhan merged 9 commits into
mainfrom
copilot/fix-aw-json-manifest-support

Conversation

Copy link
Copy Markdown
Contributor

Copilot AI commented May 22, 2026

Workflows installed from aw.yml manifests were tracked as per-file sources, so update could not reason at manifest scope. This change moves source tracking to the manifest address (repo/repo/folder + ref) and updates workflows as a manifest-managed set.

  • Manifest-scoped source tracking

    • For workflows resolved via repository package manifests, source now points to the manifest location (not individual workflow files).
    • Applies to both add and add-wizard paths through shared source-string generation.
  • Filename-keyed manifest safety

    • Enforces unique markdown workflow filenames within a single manifest package, even across different folders.
    • Rejects ambiguous manifests early with a targeted validation error.
  • Manifest-aware update orchestration

    • Detects manifest-backed workflows from source.
    • Groups workflows by manifest source and reconciles each group against the latest manifest:
      • update existing workflows still listed
      • add newly listed workflows
      • remove workflows no longer listed by the manifest
  • Source-normalized merge/modification behavior

    • Normalizes source during local-modification comparison/merge paths so manifest-managed workflows don’t appear modified purely because source format changed.
  • Coverage additions

    • Adds focused tests for manifest source generation/parsing, duplicate filename detection, and grouped manifest update behavior (update/add/remove).
# before (per-file source)
source: owner/repo/workflows/triage.md@<sha>

# after (manifest source)
source: owner/repo@<sha>
# or
source: owner/repo/packages/repo-assist@<sha>

Copilot AI changed the title Fix aw manifest support in add/add-wizard/update workflows Make add/add-wizard and update manifest-aware for aw.yml package installs May 22, 2026
Copilot AI requested a review from pelikhan May 22, 2026 13:34
@pelikhan pelikhan marked this pull request as ready for review May 22, 2026 13:34
Copilot AI review requested due to automatic review settings May 22, 2026 13:34
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR makes workflow install/update behavior “manifest-aware” for repository packages defined by aw.yml, so workflows installed from a manifest are tracked and updated as a manifest-managed set rather than as individual file sources.

Changes:

  • Switches source: tracking for manifest-installed workflows to point at the manifest address (owner/repo[@ref] or owner/repo/<packagePath>[@ref]), via shared source-string generation and parsing.
  • Adds validation to reject aw.yml manifests that contain duplicate workflow filenames (even across different folders).
  • Updates update to detect manifest-backed workflows, group them by manifest source, and reconcile each group (update existing, add new, remove no-longer-listed).
Show a summary per file
File Description
pkg/cli/update_workflows.go Groups workflows by manifest source and dispatches group updates.
pkg/cli/update_merge.go Normalizes source during local-modification detection to avoid false diffs.
pkg/cli/update_manifest.go Implements manifest-group update orchestration (update/add/remove).
pkg/cli/update_manifest_test.go Adds unit coverage for grouped manifest update behavior.
pkg/cli/spec.go Adds FromRepositoryManifest and emits manifest-scoped source strings.
pkg/cli/spec_manifest_source_test.go Adds tests for manifest source generation/parsing.
pkg/cli/add_workflow_resolution.go Marks resolved package workflows as manifest-derived and preserves package path.
pkg/cli/add_package_manifest.go Validates unique markdown workflow filenames within a manifest.
pkg/cli/add_package_manifest_test.go Tests duplicate-filename manifest rejection.

Copilot's findings

Tip

Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

  • Files reviewed: 9/9 changed files
  • Comments generated: 2

Comment on lines +189 to +199
baseContent, err := downloadWorkflowContentFn(ctx, repo, currentPath, currentRef, opts.Verbose)
if err != nil {
merge = false
} else {
currentContent, err := os.ReadFile(wf.Path)
if err != nil {
return fmt.Errorf("failed to read current workflow: %w", err)
}
newSourceSpec := sourceSpecWithRef(&SourceSpec{Repo: repo, Path: latestPath}, latestRef)
mergedContent, conflicts, mergeErr := MergeWorkflowContent(string(baseContent), string(currentContent), string(newContent), sourceSpecCurrent, newSourceSpec, wf.Path, opts.Verbose)
if mergeErr != nil {
Comment thread pkg/cli/update_workflows.go Outdated
Comment on lines +75 to +82
if repoSpec, ok, err := parseManifestSourceSpec(wf.SourceSpec); err != nil {
errMsg := err.Error()
if repoSpec != nil {
errMsg = fmt.Sprintf("%s (%s)", errMsg, repositoryPackageIdentifier(repoSpec.RepoSlug, repoSpec.PackagePath))
}
failedUpdates = append(failedUpdates, updateFailure{
Name: wf.Name,
Error: errMsg,
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 22, 2026

🧠 Matt Pocock Skills Reviewer has completed the skills-based review. ✅

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 22, 2026

🧪 Test Quality Sentinel completed test quality analysis.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 22, 2026

Design Decision Gate 🏗️ completed the design decision gate check.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 22, 2026

PR Code Quality Reviewer completed the code quality review.

Copy link
Copy Markdown
Contributor

@github-actions github-actions Bot left a comment

Choose a reason for hiding this comment

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

Code Review Summary

I've reviewed this PR for manifest-aware workflow management. The implementation is solid overall with good test coverage. Found 4 issues requiring attention before merge:

📋 Issue breakdown (4 total)

Correctness issues (3):

  1. Empty workflow filenames silently ignored in validation
  2. Hardcoded "main" branch assumption (should query actual default branch)
  3. Unreachable error context branch in update_workflows.go (flagged by previous reviewer)

Maintainability issues (1):
4. Double TrimSpace() call on source spec (minor performance waste)

Already flagged by previous reviewer:

  • Source normalization issue in MergeWorkflowContent (line 199, update_manifest.go)
  • Unreachable error context in parseManifestSourceSpec handling (line 82, update_workflows.go)
✅ What's done well
  • Excellent test coverage: New tests cover manifest source generation, parsing, duplicate detection, and add/update/remove operations
  • Clear separation of concerns: Manifest-specific logic cleanly separated into update_manifest.go
  • Thorough error handling: Most error paths are properly handled with descriptive messages
  • Good use of existing patterns: Follows established conventions for validation and error messages

Recommendation

Please address the correctness issues (especially the hardcoded "main" branch assumption and empty filename handling) before merging. The maintainability issue is minor but worth fixing while touching the code.

🔎 Code quality review by PR Code Quality Reviewer · ● 1.3M

Comments that could not be inline-anchored

pkg/cli/add_package_manifest.go:406

Empty workflow filenames silently ignored: When a manifest entry has an empty filename after trimming (e.g., &quot; .md&quot; or &quot;folder/.md&quot;), the validation silently skips it without error, potentially allowing malformed manifest entries to pass through.

<details>
<summary>💡 Suggested fix</summary>

if key == &quot;&quot; {
    return fmt.Errorf(&quot;invalid Agentic Workflow manifest %q: workflow filename cannot be empty or whitespace-only: %q&quot;, manifestPath, installPath)
}

This ensures all `.m…

pkg/cli/update_manifest.go:285

Hardcoded default ref assumption: When repoSpec.Version is empty, the code assumes &quot;main&quot; as the default branch, which may not match the repository's actual default branch (could be master, develop, etc.).

<details>
<summary>💡 Suggested fix</summary>

currentRef := repoSpec.Version
if currentRef == &quot;&quot; {
    defaultBranch, err := getRepositoryPackageDefaultBranch(repoSpec.RepoSlug, &quot;&quot;)
    if err != nil {
        for _, wf := range grouped {
            failures = append(fail</details>

<details><summary>pkg/cli/update_manifest.go:356</summary>

**Potential panic from empty grouped slice**: When adding new workflows from the manifest, `targetDir` is derived from `grouped[0].Path`, but this assumes `grouped` is non-empty. If all workflows in the manifest are new (no existing workflows), this will panic with an index out of range error.

&lt;details&gt;
&lt;summary&gt;💡 Suggested fix&lt;/summary&gt;

```go
// Determine target directory from existing workflows or use a sensible default
targetDir := &quot;.&quot;
if len(grouped) &gt; 0 {
    targetDir = filepath.Dir(gr…

</details>

<details><summary>pkg/cli/update_workflows.go:86</summary>

**Double TrimSpace potentially wasteful**: The source spec is trimmed twice — once in `parseManifestSourceSpec()` (line 232 of update_manifest.go) and again when used as the map key here. The second trim is redundant since `parseManifestSourceSpec` already trims the input.

&lt;details&gt;
&lt;summary&gt;💡 Suggested fix&lt;/summary&gt;

```go
manifestGroups[wf.SourceSpec] = append(manifestGroups[wf.SourceSpec], wf)

Since the source is already trimmed during parsing, the map key doesn't need additional trim…

@github-actions
Copy link
Copy Markdown
Contributor

🏗️ Design Decision Gate — ADR Required

This PR makes significant changes to core business logic (+583 lines under pkg/cli/) but does not have a linked Architecture Decision Record (ADR).

📄 Draft ADR committed: docs/adr/34008-manifest-scoped-source-tracking-and-update.md — review and complete it before merging.

🔒 This PR cannot merge until an ADR is linked in the PR body.

📋 What to do next
  1. Review the draft ADR committed to your branch — it was generated from the PR diff and captures: (a) moving source tracking to the manifest address, (b) manifest-scoped update orchestration (add/update/remove), (c) duplicate-filename validation, and (d) source-normalized local-modification comparison.
  2. Complete the missing sections — add context the AI couldn't infer (deciders, original motivation, prior incidents), refine the decision rationale, and confirm the alternatives reflect what was actually considered.
  3. Commit the finalized ADR to docs/adr/ on your branch.
  4. Reference the ADR in this PR body by adding a line such as:

    ADR: ADR-34008: Manifest-Scoped Source Tracking and Manifest-Aware Update Orchestration

Once an ADR is linked in the PR body, this gate will re-run and verify the implementation matches the decision.

❓ Why ADRs Matter

"AI made me procrastinate on key design decisions. Because refactoring was cheap, I could always say 'I'll deal with this later.' Deferring decisions corroded my ability to think clearly."

ADRs create a searchable, permanent record of why the codebase looks the way it does. Future contributors (and your future self) will thank you.

This PR introduces a dual interpretation of the source frontmatter field (per-file path vs. manifest address) and a new deletion side effect during update — both are exactly the kind of decisions that deserve to be recorded explicitly.

📋 Michael Nygard ADR Format Reference

An ADR must contain these four sections to be considered complete:

  • Context — What is the problem? What forces are at play?
  • Decision — What did you decide? Why?
  • Alternatives Considered — What else could have been done?
  • Consequences — What are the trade-offs (positive and negative)?

All ADRs are stored in docs/adr/ as Markdown files numbered by PR number (e.g., 34008-*.md for PR #34008).

🏗️ ADR gate enforced by Design Decision Gate 🏗️ · ● 6M ·

Copy link
Copy Markdown
Contributor

@github-actions github-actions Bot left a comment

Choose a reason for hiding this comment

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

Skills-Based Review 🧠

Applied /tdd and /zoom-out — requesting changes on test coverage gaps and error handling.

📋 Key Themes & Recommendations

Test Coverage Gaps (/tdd)

  1. Missing edge cases: Empty manifest handling, case-insensitive duplicate detection, partial package resolution failures
  2. Incomplete assertions: Lock file cleanup not verified in removal tests
  3. Error recovery paths: Network failures and partial manifest resolution need coverage

Architecture & Design (/zoom-out)

  1. ✅ Strong architectural fit: Manifest-scoped source tracking is the right abstraction level — it aligns with how users think about package updates
  2. ✅ Clean separation: Manifest vs. direct workflow routing is well-designed and maintainable
  3. ⚠️ Silent error suppression: Source normalization errors are ignored, which could hide frontmatter issues during local modification detection

Positive Highlights

  • Comprehensive happy-path tests: TestUpdateManifestWorkflowGroup_AddsUpdatesRemoves covers the core update/add/remove flow
  • Early validation: Duplicate filename detection happens before any downloads
  • Backward compatibility: Existing direct workflow specs continue working unchanged
  • Isolated logic: New manifest update behavior is cleanly separated in update_manifest.go

Priority fixes:

  1. Add error handling/logging for source normalization failures (comment on update_merge.go:75)
  2. Add test coverage for edge cases: empty manifests, case-insensitive duplicates, partial failures
  3. Strengthen existing test assertions to verify lock file cleanup

The core design is solid — these are refinements to make the implementation more robust. 🚀

🧠 Reviewed using Matt Pocock's skills by Matt Pocock Skills Reviewer · ● 1.1M

Comment thread pkg/cli/update_merge.go

// Normalize again after processing
sourceResolvedNormalized := stringutil.NormalizeWhitespace(sourceResolved)
if normalized, normalizeErr := UpdateFieldInFrontmatter(sourceResolvedNormalized, "source", "__gh_aw_source__"); normalizeErr == nil {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

[/zoom-out] Silent error suppression during source normalization could hide frontmatter issues.

💡 Impact & Suggested Fix

If UpdateFieldInFrontmatter fails (e.g., malformed YAML), the comparison proceeds with unnormalized source values, potentially reporting false positives for local modifications.

Suggested approach (option 1 - log and continue):

if normalized, normalizeErr := UpdateFieldInFrontmatter(sourceResolvedNormalized, "source", "__gh_aw_source__"); normalizeErr == nil {
    sourceResolvedNormalized = normalized
} else {
    updateLog.Printf("Warning: failed to normalize source field: %v", normalizeErr)
}

Option 2 - fail fast if normalization is critical:

normalized, err := UpdateFieldInFrontmatter(sourceResolvedNormalized, "source", "__gh_aw_source__")
if err != nil {
    return false, fmt.Errorf("failed to normalize source field: %w", err)
}
sourceResolvedNormalized = normalized

This prevents silent logic errors when frontmatter is malformed.

return nil, nil
}

_, err := resolveRepositoryPackage(&RepoSpec{RepoSlug: "owner/repo"}, "")
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

[/tdd] Missing test case: case-insensitive duplicate detection.

💡 Suggested edge case test

The duplicate detection in validateUniqueManifestWorkflowFilenames uses strings.ToLower() for case-insensitive comparison, but this test only checks exact duplicates (triage.md in different folders).

Add a test for case variants:

t.Run("rejects case-insensitive duplicate filenames", func(t *testing.T) {
    downloadPackageFileFromGitHubForHost = func(owner, repo, path, ref, host string) ([]byte, error) {
        switch path {
        case "aw.yml":
            return []byte(`name: Case Duplicates
files:
  - workflows/triage.md
  - workflows/Triage.md
`), nil
        case "README.md":
            return []byte("# Case Duplicates\n"), nil
        default:
            return nil, createRepositoryPackageNotFoundError(path)
        }
    }

    _, err := resolveRepositoryPackage(&RepoSpec{RepoSlug: "owner/repo"}, "")
    require.Error(t, err)
    assert.Contains(t, err.Error(), "duplicate workflow filename")
})

This ensures the case-insensitive logic works correctly and prevents platform-specific filename collisions.

if len(successes) != 3 {
t.Fatalf("expected 3 successful operations, got %d", len(successes))
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

[/tdd] Test doesn't verify .lock.yml file cleanup.

💡 Strengthen test assertion

The test verifies that removed.md is deleted, but removeManifestManagedWorkflow also removes the corresponding .lock.yml file. The test should verify both:

if _, err := os.Stat(removedPath); !os.IsNotExist(err) {
    t.Fatalf("expected removed workflow to be deleted, got err=%v", err)
}
removedLockPath := filepath.Join(tmpDir, "removed.lock.yml")
if _, err := os.Stat(removedLockPath); !os.IsNotExist(err) {
    t.Fatalf("expected removed lock file to be deleted, got err=%v", err)
}

Also create the lock file in test setup:

if err := os.WriteFile(removedLockPath, []byte("# lock file\n"), 0o644); err != nil {
    t.Fatalf("write removed lock: %v", err)
}

This ensures the cleanup logic works end-to-end.

Version: currentRef,
}, "")
if err != nil {
for _, wf := range grouped {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

[/tdd] Missing test: partial package resolution failure.

💡 Edge case that needs coverage

When resolveRepositoryPackage fails for currentPkg but succeeds for latestPkg (or vice versa), all workflows in the group fail. This error recovery path isn't tested.

Suggested test scenario:

t.Run("handles partial package resolution failure", func(t *testing.T) {
    downloadPackageFileFromGitHubForHost = func(owner, repo, path, ref, host string) ([]byte, error) {
        if ref == "v1.0.0" && path == "aw.yml" {
            return nil, errors.New("network timeout") // Simulate failure
        }
        if ref == "v2.0.0" && path == "aw.yml" {
            return []byte("name: Test\nfiles:\n  - workflows/test.md\n"), nil
        }
        return nil, createRepositoryPackageNotFoundError(path)
    }

    successes, failures := updateManifestWorkflowGroup(...)
    require.Empty(t, successes)
    require.NotEmpty(t, failures)
    assert.Contains(t, failures[0].Error, "failed to resolve current manifest package")
})

This validates the error propagation behavior when one of the two package fetches fails.

}
return successes, failures
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

[/tdd] Missing test: empty manifest in latest version.

💡 Boundary condition test

What happens when the latest manifest has zero workflows? The current test doesn't cover this scenario.

Suggested test:

t.Run("removes all workflows when latest manifest is empty", func(t *testing.T) {
    downloadPackageFileFromGitHubForHost = func(owner, repo, path, ref, host string) ([]byte, error) {
        switch path {
        case "aw.yml":
            if ref == "v1.0.0" {
                return []byte("name: Test\nfiles:\n  - workflows/old.md\n"), nil
            }
            if ref == "v2.0.0" {
                return []byte("name: Test\nfiles: []\n"), nil // Empty manifest
            }
        case "README.md":
            return []byte("# Test\n"), nil
        }
        return nil, createRepositoryPackageNotFoundError(path)
    }

    tmpDir := testutil.TempDir(t, "empty-manifest-*")
    oldPath := filepath.Join(tmpDir, "old.md")
    os.WriteFile(oldPath, []byte("---\nsource: owner/[email protected]\n---\n"), 0o644)

    successes, failures := updateManifestWorkflowGroup(context.Background(), "owner/[email protected]", []*workflowWithSource{
        {Name: "old", Path: oldPath, SourceSpec: "owner/[email protected]"},
    }, UpdateWorkflowsOptions{NoCompile: true, DisableSecurityScanner: true})

    require.Empty(t, failures)
    require.Len(t, successes, 1)
    _, err := os.Stat(oldPath)
    assert.True(t, os.IsNotExist(err), "workflow should be removed when manifest becomes empty")
})

This ensures graceful handling when a package stops declaring workflows.

Comment thread pkg/cli/spec.go
return ""
}

if workflow.FromRepositoryManifest {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

[/zoom-out] Good architectural decision: manifest source format.

✅ Why this design works well

Using owner/repo/packages/repo-assist@ref as the manifest source (instead of individual file paths) is the right abstraction level:

  1. Semantic clarity: The source field now represents the unit of versioning — the manifest package, not individual files
  2. Update efficiency: All workflows from the same manifest update as a group with a single API call
  3. Conflict reduction: Source normalization (lines 75-79 in update_merge.go) prevents false "local modification" detection when migrating from file-level to manifest-level sources

This aligns well with how users think about package updates: "update the repo-assist package" rather than "update 5 individual workflows."

// Update each workflow
manifestGroups := make(map[string][]*workflowWithSource)
var directWorkflows []*workflowWithSource
for _, wf := range workflows {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

[/zoom-out] Clean separation: manifest vs. direct workflows.

✅ Good design pattern

The separation logic here is clear and maintainable:

  1. Parse once, route correctly: parseManifestSourceSpec determines whether a workflow is manifest-backed
  2. Group for efficiency: Manifest workflows get batched by source for atomic updates
  3. Preserve existing behavior: Direct workflows continue through the original update path

This design avoids a common anti-pattern where manifest and direct workflows would be intermixed in a single update loop with complex conditionals.

Minor suggestion: Consider extracting the grouping logic into a helper function if this pattern repeats elsewhere:

func groupWorkflowsBySource(workflows []*workflowWithSource) (map[string][]*workflowWithSource, []*workflowWithSource, []updateFailure)

@github-actions
Copy link
Copy Markdown
Contributor

🧪 Test Quality Sentinel Report

Test Quality Score: 90/100 — Excellent

Analyzed 5 test(s): 5 design tests, 0 implementation tests, 0 guideline violations. Minor improvements recommended.

📊 Metrics & Test Classification (5 tests analyzed)
Metric Value
New/modified tests analyzed 5
✅ Design tests (behavioral contracts) 5 (100%)
⚠️ Implementation tests (low value) 0 (0%)
Tests with error/edge cases 5 (100%)
Duplicate test clusters 0
Test inflation detected Yes (1 file)
�� Coding-guideline violations 0

Test Classification Details

Test File Classification Notes
TestResolveRepositoryPackage (subtest) pkg/cli/add_package_manifest_test.go:665 ✅ Design Tests duplicate filename rejection
TestBuildSourceStringWithCommitSHA_ManifestSource pkg/cli/spec_manifest_source_test.go:7 ✅ Design Tests source string format with package path
TestBuildSourceStringWithCommitSHA_ManifestSourceRoot pkg/cli/spec_manifest_source_test.go:25 ✅ Design Tests source string format without package path
TestParseManifestSourceSpec pkg/cli/spec_manifest_source_test.go:42 ✅ Design Table-driven parser test (3 scenarios)
TestUpdateManifestWorkflowGroup_AddsUpdatesRemoves pkg/cli/update_manifest_test.go:18 ✅ Design Comprehensive integration test

Language Support

Tests analyzed:

  • 🐹 Go (*_test.go): 5 tests — all with required //go:build !integration build tags
⚠️ Minor Issues — Non-Blocking (2 observations)

⚠️ Missing Assertion Messages — spec_manifest_source_test.go

Issue: All three tests use t.Fatalf("expected %q, got %q", want, got) without additional descriptive context.

Guideline: Tests should include descriptive messages that explain what failed in domain terms, not just the mismatch.

Example improvement:

// Current
t.Fatalf("expected %q, got %q", want, got)

// Better
t.Fatalf("source string format for manifest package with subdirectory: expected %q, got %q", want, got)

Impact: Minor — error messages are functional but could be more helpful for debugging.


⚠️ Test Inflation — spec_manifest_source_test.go (3.43:1 ratio)

Observation: 72 lines of test code for 21 lines of production code (spec.go +14, add_workflow_resolution.go +7).

Analysis: While this exceeds the 2:1 guideline, the inflation is justified in this case:

  • All 3 tests are high-value behavioral tests covering critical parsing/formatting logic
  • Table-driven test with 3 edge case scenarios
  • No code duplication or unnecessary complexity

Verdict: Acceptable — the ratio reflects thorough edge case coverage, not test bloat.

Verdict

Check passed. 0% of new tests are implementation tests (threshold: 30%). All tests enforce behavioral contracts with proper error coverage.

📖 Understanding Test Classifications

Design Tests (High Value) verify what the system does:

  • Assert on observable outputs, return values, or state changes
  • Cover error paths and boundary conditions
  • Would catch a behavioral regression if deleted
  • Remain valid even after internal refactoring

Implementation Tests (Low Value) verify how the system does it:

  • Assert on internal function calls (mocking internals)
  • Only test the happy path with typical inputs
  • Break during legitimate refactoring even when behavior is correct
  • Give false assurance: they pass even when the system is wrong

Goal: Shift toward tests that describe the system's behavioral contract — the promises it makes to its users and collaborators.

🧪 Test quality analysis by Test Quality Sentinel · ● 1.3M ·

Copy link
Copy Markdown
Contributor

@github-actions github-actions Bot left a comment

Choose a reason for hiding this comment

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

✅ Test Quality Sentinel: 90/100. Excellent test quality — all 5 new tests are design tests that enforce behavioral contracts with comprehensive error coverage.

@pelikhan
Copy link
Copy Markdown
Collaborator

@copilot review all comments

@pelikhan
Copy link
Copy Markdown
Collaborator

@copilot add integration test that adds githubnext/agentic-ops v-1, then call update

Copy link
Copy Markdown
Contributor Author

Copilot AI commented May 22, 2026

@copilot review all comments

Handled. I reviewed and addressed the actionable review threads in commit 28f8344 (merge source normalization for manifest-managed workflows + removal of unreachable manifest parse error branch), with targeted tests and validation rerun.

Copy link
Copy Markdown
Contributor Author

Copilot AI commented May 22, 2026

@copilot add integration test that adds githubnext/agentic-ops v-1, then call update

Added in eb05f5e: integration test TestUpdateCommand_AfterManifestAddIntegration in pkg/cli/update_integration_test.go that runs add githubnext/agentic-ops@v-1 and then update.

@pelikhan pelikhan merged commit 9926de8 into main May 22, 2026
@pelikhan pelikhan deleted the copilot/fix-aw-json-manifest-support branch May 22, 2026 16:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants