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
Jump to file
Failed to load files.
Loading
Diff view
Diff view
90 changes: 0 additions & 90 deletions .github/ISSUE_TEMPLATE/pilot-result.yml

This file was deleted.

44 changes: 0 additions & 44 deletions .github/ISSUE_TEMPLATE/team-adoption.yml

This file was deleted.

3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1 +1,4 @@
node_modules/

# Local codex working state — not for tracking
.codex/
5 changes: 1 addition & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -137,10 +137,7 @@ ScopeTrail is intentionally small right now. If a warning is noisy, open a
[false-positive report](https://github.com/Conalh/ScopeTrail/issues/new?template=false-positive.yml).
If your team uses another agent config surface, open a
[missing-surface request](https://github.com/Conalh/ScopeTrail/issues/new?template=missing-surface.yml).
If you are evaluating ScopeTrail for a team or many repositories, open a
[team-adoption signal](https://github.com/Conalh/ScopeTrail/issues/new?template=team-adoption.yml).
Those reports are the validation path for any paid team layer; hosted SaaS is intentionally deferred until the free Action shows repeated team-level pain.
To help validate that demand, pilot ScopeTrail with `fail-on: none` and report results in the [active pilot issue](https://github.com/Conalh/ScopeTrail/issues/18) or the [pilot result form](https://github.com/Conalh/ScopeTrail/issues/new?template=pilot-result.yml).
If you're piloting ScopeTrail across multiple repositories, the [pilot guide](docs/PILOT.md) walks through running it on a real repo, and PR-level feedback is welcome on the [active pilot issue](https://github.com/Conalh/ScopeTrail/issues/18).

## Development

Expand Down
2 changes: 1 addition & 1 deletion dist/report.js
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ function renderMarkdown(report) {
return `${lines.join('\n').trimEnd()}\n`;
}
function appendPilotFeedback(lines) {
lines.push('', '## Pilot feedback', '', 'Trying ScopeTrail in advisory mode? Report whether this run was useful, noisy, or missing an agent config surface:', '', 'https://github.com/Conalh/ScopeTrail/issues/new?template=pilot-result.yml');
lines.push('', '## Feedback', '', 'Trying ScopeTrail in advisory mode? Report false positives or missing config surfaces:', '', 'https://github.com/Conalh/ScopeTrail/issues/new/choose');
}
function renderText(report) {
const lines = [`ScopeTrail permission drift: ${report.rating.toUpperCase()}`];
Expand Down
10 changes: 3 additions & 7 deletions docs/PILOT.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Pilot Guide

Use this guide to try ScopeTrail in an external repository before any paid team-layer work exists.
Use this guide to try ScopeTrail in an external repository and share feedback on how the Action behaves on real config.

## Install

Expand Down Expand Up @@ -46,11 +46,7 @@ Report pilot results in the active pilot issue:

https://github.com/Conalh/ScopeTrail/issues/18

Or open a structured pilot result:

https://github.com/Conalh/ScopeTrail/issues/new?template=pilot-result.yml

Use this format:
Or open a new issue with this format:

```md
Pilot source: external repo / team / solo repo
Expand All @@ -74,4 +70,4 @@ Being listed in the outreach queue does not count as validation evidence. A repo

## Boundary

ScopeTrail is a free local-only CLI and GitHub Action today. The paid team layer remains unbuilt until external pilot evidence shows repeated team-level pain that the single-repo Action cannot manage well.
ScopeTrail is a free local-only CLI and GitHub Action. It reads the checked-out repository, uploads nothing by default, and starts advisory with `fail-on: none`.
29 changes: 0 additions & 29 deletions docs/TEAM_VALIDATION.md

This file was deleted.

2 changes: 1 addition & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
{
"name": "scopetrail",
"version": "0.1.11",
Expand All @@ -11,7 +11,7 @@
"test": "node --test"
},
"dependencies": {
"agent-gov-core": "github:Conalh/agent-gov-core#v0.1.1"
"agent-gov-core": "github:Conalh/agent-gov-core#v0.1.2"

Check warning on line 14 in package.json

View workflow job for this annotation

GitHub Actions / scope-review

TaskBound low scope creep

Changed dependency agent-gov-core from github:Conalh/agent-gov-core#v0.1.1 to github:Conalh/agent-gov-core#v0.1.2. Recommendation: Review whether the version change is in scope for the task.
},
"devDependencies": {
"@types/node": "^24.0.0",
Expand Down
6 changes: 3 additions & 3 deletions src/report.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,11 +83,11 @@ function renderMarkdown(report: DriftReport): string {
function appendPilotFeedback(lines: string[]): void {
lines.push(
'',
'## Pilot feedback',
'## Feedback',
'',
'Trying ScopeTrail in advisory mode? Report whether this run was useful, noisy, or missing an agent config surface:',
'Trying ScopeTrail in advisory mode? Report false positives or missing config surfaces:',
'',
'https://github.com/Conalh/ScopeTrail/issues/new?template=pilot-result.yml'
'https://github.com/Conalh/ScopeTrail/issues/new/choose'
);
}

Expand Down
6 changes: 3 additions & 3 deletions test/cli-output.test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -49,9 +49,9 @@ test('CLI emits Markdown permission drift report', async () => {
assert.match(stdout, /stripe-admin/);
assert.match(stdout, /Bash\(npm \*\)/);
assert.match(stdout, /PreToolUse/);
assert.match(stdout, /## Pilot feedback/);
assert.match(stdout, /issues\/new\?template=pilot-result\.yml/);
assert.match(stdout, /useful, noisy, or missing an agent config surface/i);
assert.match(stdout, /## Feedback/);
assert.match(stdout, /issues\/new\/choose/);
assert.match(stdout, /false positives or missing config surfaces/i);
});

test('CLI emits GitHub warning annotations for permission drift findings', async () => {
Expand Down
32 changes: 0 additions & 32 deletions test/issue-template.test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -25,35 +25,3 @@ test('issue templates collect detector feedback signals', async () => {
assert.match(missingSurface, /label:\s*Affected scope/);
assert.match(missingSurface, /id:\s*review-surface/);
});

test('team adoption issue template collects paid-layer validation signals without promising SaaS', async () => {
const teamAdoption = await readIssueTemplate('team-adoption.yml');

assert.match(teamAdoption, /labels:\s*\["validation", "team-adoption"\]/);
assert.match(teamAdoption, /id:\s*repository-count/);
assert.match(teamAdoption, /label:\s*Repository count/);
assert.match(teamAdoption, /id:\s*agent-tools/);
assert.match(teamAdoption, /id:\s*permission-owner/);
assert.match(teamAdoption, /id:\s*trust-criteria/);
assert.match(teamAdoption, /id:\s*paid-workflow-pain/);
assert.match(teamAdoption, /product validation/i);
assert.doesNotMatch(teamAdoption, /SaaS is available/i);
});

test('pilot result issue template collects auditable external validation evidence', async () => {
const pilotResult = await readIssueTemplate('pilot-result.yml');

assert.match(pilotResult, /labels:\s*\["validation", "pilot-result"\]/);
assert.match(pilotResult, /id:\s*pilot-source/);
assert.match(pilotResult, /id:\s*repository-count/);
assert.match(pilotResult, /id:\s*agent-tools/);
assert.match(pilotResult, /id:\s*install-status/);
assert.match(pilotResult, /id:\s*useful-findings/);
assert.match(pilotResult, /id:\s*noisy-findings/);
assert.match(pilotResult, /id:\s*missing-surfaces/);
assert.match(pilotResult, /id:\s*team-workflow-requested/);
assert.match(pilotResult, /id:\s*would-keep-installed/);
assert.match(pilotResult, /product validation/i);
assert.match(pilotResult, /paid team layer is not available yet/i);
assert.doesNotMatch(pilotResult, /SaaS is available/i);
});
31 changes: 2 additions & 29 deletions test/public-docs.test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,12 @@ async function readProjectFile(...parts) {
return readFile(join(packageRoot, ...parts), 'utf8');
}

test('README links trust, adoption, and team validation docs from the public Action surface', async () => {
test('README links trust, adoption, and pilot docs from the public Action surface', async () => {
const readme = await readProjectFile('README.md');

assert.match(readme, /\[Trust and permissions\]\(docs\/TRUST\.md\)/);
assert.match(readme, /\[Adoption checklist\]\(docs\/ADOPTION\.md\)/);
assert.match(readme, /\[Team-layer validation\]\(docs\/TEAM_VALIDATION\.md\)/);
assert.match(readme, /\[Pilot guide\]\(docs\/PILOT\.md\)/);
assert.match(readme, /install with `fail-on: none`/i);
assert.match(readme, /runs the committed `dist\/` runtime/i);
assert.match(readme, /runs `npm ci --omit=dev` inside the ScopeTrail Action directory/i);
Expand Down Expand Up @@ -65,29 +65,6 @@ test('adoption checklist defines advisory-first rollout and feedback path', asyn
assert.match(adoption, /raise `fail-on`/i);
});

test('team validation doc keeps SaaS deferred behind evidence gates', async () => {
const validation = await readProjectFile('docs', 'TEAM_VALIDATION.md');

assert.match(validation, /paid team layer is a hypothesis/i);
assert.match(validation, /Do not build hosted SaaS/i);
assert.match(validation, /At least 3 external repositories/i);
assert.match(validation, /At least 2 independent users/i);
assert.match(validation, /At least 2 independent feedback items/i);
assert.match(validation, /cross-repo visibility/i);
assert.match(validation, /exception workflow/i);
});

test('public docs link the pilot issue as the active validation funnel', async () => {
const readme = await readProjectFile('README.md');
const validation = await readProjectFile('docs', 'TEAM_VALIDATION.md');
const pilotIssueUrl = 'https://github.com/Conalh/ScopeTrail/issues/18';

assert.match(readme, /Pilot ScopeTrail/i);
assert.match(readme, new RegExp(pilotIssueUrl.replaceAll('/', '\\/')));
assert.match(validation, /active pilot issue/i);
assert.match(validation, new RegExp(pilotIssueUrl.replaceAll('/', '\\/')));
});

test('pilot guide gives external maintainers a complete advisory trial path', async () => {
const readme = await readProjectFile('README.md');
const adoption = await readProjectFile('docs', 'ADOPTION.md');
Expand All @@ -101,9 +78,5 @@ test('pilot guide gives external maintainers a complete advisory trial path', as
assert.match(pilot, /fail-on:\s*none/);
assert.match(pilot, /3-5 pull requests/i);
assert.match(pilot, /https:\/\/github\.com\/Conalh\/ScopeTrail\/issues\/18/);
assert.match(pilot, /https:\/\/github\.com\/Conalh\/ScopeTrail\/issues\/21/);
assert.match(pilot, /issues\/new\?template=pilot-result\.yml/);
assert.match(pilot, /does not count as validation evidence/i);
assert.match(pilot, /cross-repo visibility/i);
assert.match(readme, /pilot-result\.yml/);
});