Skip to content

feat: add API boundary runner, relocate fixtures, and configure CI check#183

Merged
reidbaker merged 5 commits into
flutter:mainfrom
reidbaker:feat/api-boundary-runner-2026-07-16
Jul 17, 2026
Merged

feat: add API boundary runner, relocate fixtures, and configure CI check#183
reidbaker merged 5 commits into
flutter:mainfrom
reidbaker:feat/api-boundary-runner-2026-07-16

Conversation

@reidbaker-agent

@reidbaker-agent reidbaker-agent commented Jul 16, 2026

Copy link
Copy Markdown
Contributor

This work is to prevent mistakes that caused the need for #182 Ensuring that the public api boundary is tested in a way that prevents impossible to use apis.

2 prongs to the fix, one is in the skill used to validate breaking changed against known downstream users. Second is an explicit test for the api boundary in a examples folder.

For good organization I also moved the existing valid and invalid skills into their own directory.

Agent authored description below

Introduces an automated API boundary verification test runner to programmatically validate the linter's public contract under external packaging constraints (preventing any future regressions where unexported classes or parameters slip into the public interface).

  • API Boundary Code Runner: Added a new package at example/api_boundary_runner which imports strictly package:dart_skills_lint/dart_skills_lint.dart (avoiding internal imports) and executes verification logic.
  • Fixture Relocation: Moved all reference fixtures to example/skills/valid and example/skills/invalid, updating all references across READMEs, tests, and configurations.
  • Workflow Automation: Configured .github/workflows/dart_skills_lint_workflow.yaml to build, analyze, format, and run the example code runner across GHA matrix OS platforms.
  • Upgraded downstream validation documentation: Refined [check-downstream-consumers/SKILL.md] to mandate diagnostic API migration checks during PR reviews.

@gemini-code-assist

Copy link
Copy Markdown
Contributor

Warning

Gemini encountered an error creating the review. You can try again by commenting /gemini review.

@reidbaker

Copy link
Copy Markdown
Contributor

/Gemini review

@gemini-code-assist gemini-code-assist Bot left a comment

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.

Code Review

This pull request restructures the example fixtures by moving them under example/skills/ and updates the configuration, documentation, and tests accordingly. It also introduces a new api_boundary_runner tool to validate the public API boundary and adds guidelines for performing diagnostic API migrations. Feedback on the new runner suggests implementing a more robust path resolution mechanism to handle compiled snapshots and replacing direct exit(1) calls with exitCode = 1 and returns to allow proper flushing of output streams.

Comment on lines +19 to +25
final String scriptDir = p.dirname(Platform.script.toFilePath());
final String validSkillPath = p.normalize(
p.absolute(p.join(scriptDir, '..', '..', 'skills', 'valid')),
);
final String invalidSkillPath = p.normalize(
p.absolute(p.join(scriptDir, '..', '..', 'skills', 'invalid')),
);

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.

medium

Relying solely on Platform.script.toFilePath() can fail if the script is executed as a compiled snapshot (e.g., via dart run under certain configurations) or if the scheme is not file. Resolving the path with fallback options based on the current working directory makes the runner much more robust across different execution environments.

  String findPath(String relativeSuffix) {
    final pathsToTry = [
      p.join('example', 'skills', relativeSuffix),
      p.join('..', 'skills', relativeSuffix),
      if (Platform.script.scheme == 'file')
        p.join(p.dirname(Platform.script.toFilePath()), '..', '..', 'skills', relativeSuffix),
    ];
    for (final path in pathsToTry) {
      final absolutePath = p.absolute(path);
      if (Directory(absolutePath).existsSync()) {
        return p.normalize(absolutePath);
      }
    }
    throw StateError('Could not locate skills/$relativeSuffix directory.');
  }

  final String validSkillPath = findPath('valid');
  final String invalidSkillPath = findPath('invalid');

Comment on lines +35 to +38
if (!validResult) {
print('Error: Valid skill fixture failed validation!');
exit(1);
}

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.

medium

Calling exit(1) immediately terminates the Dart VM, which can truncate pending asynchronous operations or stdout/stderr streams. Setting exitCode = 1 and returning from main allows the VM to flush all event queues and terminate cleanly.

Suggested change
if (!validResult) {
print('Error: Valid skill fixture failed validation!');
exit(1);
}
if (!validResult) {
print('Error: Valid skill fixture failed validation!');
exitCode = 1;
return;
}

Comment on lines +49 to +52
if (invalidResult) {
print('Error: Invalid skill fixture unexpectedly passed validation!');
exit(1);
}

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.

medium

Setting exitCode = 1 and returning from main is preferred over calling exit(1) directly, as it allows the Dart VM to flush pending asynchronous stdout/stderr writes before terminating.

Suggested change
if (invalidResult) {
print('Error: Invalid skill fixture unexpectedly passed validation!');
exit(1);
}
if (invalidResult) {
print('Error: Invalid skill fixture unexpectedly passed validation!');
exitCode = 1;
return;
}

@reidbaker
reidbaker self-requested a review July 17, 2026 14:33
@reidbaker
reidbaker merged commit b161bf2 into flutter:main Jul 17, 2026
14 checks passed
@reidbaker
reidbaker deleted the feat/api-boundary-runner-2026-07-16 branch July 17, 2026 15:24
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.

2 participants