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
7 changes: 7 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,13 @@ jobs:
proof_gh_path="$(python -c 'import shutil; print(shutil.which("gh") or "", end="")')"
python agent_docs/evidence/prove-effective-loading.py --app 'dist/app/skillview${{ matrix.ext }}' --gh "$proof_gh_path" --output dist/effective-loading-app-proof.json
python agent_docs/evidence/prove-effective-loading.py --app 'dist/ext/gh-skillview${{ matrix.ext }}' --gh "$proof_gh_path" --output dist/effective-loading-extension-proof.json
- name: Prove external cleanup suppression without payload mutations
shell: bash
env:
GH_TOKEN: ${{ github.token }}
run: |
python agent_docs/evidence/prove-cleanup-suppression.py --app 'dist/app/skillview${{ matrix.ext }}' --output dist/suppression-app-proof.json
python agent_docs/evidence/prove-cleanup-suppression.py --app 'dist/ext/gh-skillview${{ matrix.ext }}' --output dist/suppression-extension-proof.json
- name: Prove native backup evidence and unchanged installed copies
shell: bash
run: |
Expand Down
10 changes: 10 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -673,6 +673,16 @@ the terminal, with both a full-screen TUI and scriptable CLI commands.

## Progressive disclosure

- Ordinary Cleanup Ignore and CLI `ignore` write only the private sibling
`SkillView/preferences` store; never write or silently remove legacy
`.skillview-ignore` payload markers. Keep suppression observations transient
(`JsonIgnore`) so old maintenance journal/hash inputs remain unchanged. Unknown
source writes must compare reviewed, freshly inventoried, and execution-time
native object/generation evidence, then bind the complete bounded payload.
Charge failed captures against the aggregate inventory byte budget. Preference
diagnostics are independent from physical-provider inventory coverage. Keep
cleanup confirmation dialogs on the event-loop thread before worker admission.

- Product updates use `TuiServices.SavedUpdates`, carrying physical targets
rather than names alone. Keep `--dir` rooted at the verified containing skills
directory and gh noninteractive confirmation separate from target selection.
Expand Down
41,021 changes: 41,021 additions & 0 deletions agent_docs/evidence/maintenance-batch-13-final.json

Large diffs are not rendered by default.

1,577 changes: 1,577 additions & 0 deletions agent_docs/evidence/maintenance-batch-14-checkpoint.json

Large diffs are not rendered by default.

149 changes: 149 additions & 0 deletions agent_docs/evidence/prove-cleanup-suppression.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
"""Verify external cleanup preferences using disposable actual-gh installations."""
import argparse
import hashlib
import json
import os
from pathlib import Path
import shutil
import stat
import subprocess
import tempfile

parser = argparse.ArgumentParser()
parser.add_argument('--app', required=True, type=Path)
parser.add_argument('--gh', action='append', type=Path)
parser.add_argument('--output', required=True, type=Path)
args = parser.parse_args()
app = args.app.resolve()
results = []
gh_paths = args.gh or [Path(shutil.which('gh') or 'gh')]
auth = os.environ.get('GH_TOKEN') or os.environ.get('GITHUB_TOKEN')
if not auth:
auth = subprocess.run([str(gh_paths[-1]), 'auth', 'token'], capture_output=True, text=True, check=True).stdout.strip()


def manifest(paths):
result = []
for payload in paths:
for path in [payload, *sorted(payload.rglob('*'))]:
info = path.lstat()
kind = 'link' if path.is_symlink() else 'directory' if path.is_dir() else 'file'
data = os.readlink(path).encode() if kind == 'link' else path.read_bytes() if kind == 'file' else b''
result.append((str(path), kind, info.st_dev, info.st_ino, info.st_ctime_ns,
stat.S_IMODE(info.st_mode), hashlib.sha256(data).hexdigest()))
return result


for gh_path in gh_paths:
gh = gh_path.resolve()
with tempfile.TemporaryDirectory(prefix='skillview-suppression-proof-') as temporary:
root = Path(temporary).resolve()
home = root / 'home'
home.mkdir()
env = {key: value for key, value in os.environ.items()
if not key.startswith(('GIT_', 'SKILLVIEW_', 'GH_', 'GITHUB_', 'CLAUDE_', 'CODEX_', 'PI_'))}
env.update(HOME=str(home), USERPROFILE=str(home), GH_TOKEN=auth,
GH_EXTENSION='1', GH_PATH=str(gh), GH_CONFIG_DIR=str(root / 'gh-config'),
SKILLVIEW_STATE_HOME=str(root / 'state'), XDG_CONFIG_HOME=str(root / 'config'),
XDG_STATE_HOME=str(root / 'xdg-state'), XDG_DATA_HOME=str(root / 'data'),
XDG_CACHE_HOME=str(root / 'cache'), APPDATA=str(root / 'appdata'),
LOCALAPPDATA=str(root / 'localappdata'), CLAUDE_CONFIG_DIR=str(home / '.claude'),
PI_CODING_AGENT_DIR=str(home / '.pi' / 'agent'), GH_TELEMETRY='false',
GH_NO_UPDATE_NOTIFIER='1', GH_NO_EXTENSION_UPDATE_NOTIFIER='1', GIT_CONFIG_COUNT='0')
commands = []

def run(command, expected=0):
command = [str(item) for item in command]
process = subprocess.run(command, env=env, cwd=root, capture_output=True, text=True, timeout=180)
assert process.returncode == expected, (command, process.returncode, process.stdout, process.stderr)
commands.append({'argv': command, 'exitCode': process.returncode})
return process.stdout

source = root / 'source' / 'demo'
source.mkdir(parents=True)
source.joinpath('SKILL.md').write_text('---\nname: demo\ndescription: Local authored fixture\n---\nPrivate instructions.\n')
source.joinpath('extra.txt').write_text('Keep all extra files and modes.\n')
skills = home / '.agents' / 'skills'
run([gh, 'skill', 'install', '--from-local', '--dir', skills, '--', source.parent, 'demo'])
run([gh, 'skill', 'install', '--dir', skills, '--', 'cli/cli', 'skills/gh-skill'])
owned = skills / 'gh-skill'
peer = skills / 'same-name'
unknown = skills / 'unknown'
for destination in [peer, unknown]:
destination.mkdir()
destination.joinpath('SKILL.md').write_text('---\nname: gh-skill\ndescription: Ownerless fixture\n---\nAuthored local instructions.\n')
alias = root / 'agent-demo'
alias.symlink_to(owned, target_is_directory=True)
registry = home / '.agents' / '.skill-lock.json'
registry_before = registry.read_bytes()
payloads = [owned, skills / 'demo', peer, unknown]
before = manifest(payloads)

def product(*arguments, expected=0):
return json.loads(run([app, '--scan-root', skills, *arguments, '--json'], expected))

def row(document, path):
return next(value for value in document['skills'] if os.path.samefile(value['resolvedPath'], path))

initial = product('list', '--allow-hidden-dirs')
assert not initial['preferenceDiagnostics'] and not initial['partial'], initial
assert not (root / 'state' / 'SkillView' / 'preferences').exists(), 'Read created preferences'
assert row(initial, owned)['ownerRecords'], 'Actual gh owner was not captured'
assert row(initial, skills / 'demo')['sourceIdentity']['provider'] == 'local'
assert os.path.samefile(row(initial, skills / 'demo')['localSourcePath'], source)
checks = []
for target, selector, mode in [(owned, alias, 'source'), (skills / 'demo', skills / 'demo', 'source'), (unknown, unknown, 'object')]:
saved = product('ignore', '--path', selector)
assert saved['succeeded'] and saved['changed'] and saved['cleanupSuppression']['external'], saved
assert saved['cleanupSuppression']['bindingMode'] == mode, saved
repeated = product('ignore', '--path', target)
assert not repeated['changed'], repeated
listing = product('list', '--allow-hidden-dirs')
observed = row(listing, target)
assert observed['ignored'] and observed['cleanupSuppression']['external'], observed
assert not observed['cleanupSuppression']['legacyMarker'], observed
assert not row(listing, peer)['ignored'], listing
assert manifest(payloads) == before and registry.read_bytes() == registry_before
cleared = product('ignore', '--install-id', observed['installationId'], '--clear')
assert cleared['changed'] and not cleared['cleanupSuppression']['external'], cleared
assert not cleared['cleanupSuppression']['legacyMarker'], cleared
assert not row(product('list', '--allow-hidden-dirs'), target)['ignored']
assert manifest(payloads) == before and registry.read_bytes() == registry_before
checks.append({'path': str(target), 'bindingMode': saved['cleanupSuppression']['bindingMode'],
'restartObserved': True, 'payloadAndRegistryUnchanged': True})
assert all(not (target / '.skillview-ignore').exists() for target in payloads)
product('ignore', '--path', unknown)
unknown.joinpath('SKILL.md').write_text('---\nname: demo\ndescription: Replacement content\n---\nChanged in place.\n')
expired = row(product('list', '--allow-hidden-dirs'), unknown)['cleanupSuppression']
assert not expired['external'] and expired['state'] == 'inactive', expired
product('ignore', '--path', unknown, '--clear')
# Legacy marker is recognized but never silently deleted by clear-external.
unknown.joinpath('.skillview-ignore').write_bytes(b'')
legacy_before = manifest([unknown])
product('ignore', '--path', unknown)
legacy_clear = product('ignore', '--path', unknown, '--clear')
assert legacy_clear['cleanupSuppression']['legacyMarker'] and not legacy_clear['cleanupSuppression']['external']
assert manifest([unknown]) == legacy_before
# A separate state home cannot inherit this home's suppression.
product('ignore', '--path', owned)
env['SKILLVIEW_STATE_HOME'] = str(root / 'other-state')
assert not row(product('list', '--allow-hidden-dirs'), owned)['ignored']
env['SKILLVIEW_STATE_HOME'] = str(root / 'state')
assert row(product('list', '--allow-hidden-dirs'), owned)['ignored']
product('ignore', '--path', owned, '--clear')
preferences = root / 'state' / 'SkillView' / 'preferences'
records = sorted(preferences.glob('*.json'))
assert records, preferences
records[-1].write_text('{truncated')
damaged = product('list', '--allow-hidden-dirs')
assert damaged['preferenceDiagnostics'] and not damaged['partial'] and not row(damaged, owned)['cleanupSuppression']['external'], damaged
assert registry.read_bytes() == registry_before
results.append({'ghVersion': run([gh, '--version']).splitlines()[0], 'app': str(app),
'checks': checks, 'aliasResolved': True, 'unknownInPlaceEditExpires': True,
'legacyPreserved': True, 'alternateStateIsolated': True,
'corruptClearDoesNotReviveSuppression': True, 'commands': commands})
args.output.parent.mkdir(parents=True, exist_ok=True)
args.output.write_text(json.dumps({'schemaVersion': 1, 'status': 'passed',
'app': {'path': str(app), 'sha256': hashlib.sha256(app.read_bytes()).hexdigest()},
'results': results}, indent=2) + '\n')
print(json.dumps({'results': len(results), 'commands': sum(len(item['commands']) for item in results)}))
17 changes: 10 additions & 7 deletions agent_docs/maintenance-acceptance.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"schemaVersion": 1,
"sourceAudit": "maintenance-audit.json",
"sourceAuditSha256": "da78b199ef143ce02d23754a1652616bf597b3f6e0c3c5be0cc2c34056d964d4",
"verifiedMainCommit": "351224b3e058166073370caafcba225bce12d7e9",
"verifiedMainCommit": "6233f6a39105c472130e726c425da7ecf5acb632",
"objective": "Implement all 21 findings in reviewable, verified and merged batches. No finding is complete solely because its protective foundations exist.",
"items": [
{
Expand Down Expand Up @@ -106,8 +106,8 @@
"title": "Protect local changes before update or force repair",
"priority": "P0",
"status": "incomplete",
"implementedEvidenceSummary": "Local changes refused by routine updates; raw backups; quarantine/undo; saved recorded and ownerless/shared-gh newer-revision replacement retaining original/displaced native objects, with reviewed owner/payload recovery",
"remaining": "Source and other manager owner transitions; additional reviewed local-change dispositions; external suppression state; complete original acceptance audit",
"implementedEvidenceSummary": "Local changes refused by routine updates; raw backups; quarantine/undo; saved recorded and ownerless/shared-gh newer-revision replacement retaining original/displaced native objects, with reviewed owner/payload recovery; external cleanup suppression for verified physical installations without payload-marker writes",
"remaining": "Source and other manager owner transitions; additional reviewed local-change dispositions; remaining suppression kinds and damaged/stale preference recovery; complete original acceptance audit",
"acceptance": "Changed tracked file, extra file, deletion, pin, shared symlink target and unchanged upstream tree SHA are all covered. No overwrite without an explicit disposition of local changes. Verified rollback restores extras and exclusions. Preserve the observed doc/runtime disagreement in compatibility tests.",
"evidenceLedger": "maintenance-implementation.md",
"finalAcceptanceProven": false
Expand Down Expand Up @@ -156,12 +156,15 @@
"id": "M12",
"title": "Explain what each agent can actually load",
"priority": "P1",
"status": "incomplete",
"implementedEvidenceSummary": "Basic validity and placement evidence",
"remaining": "Versioned effective-loading analysis and observed-versus-expected agent views",
"status": "complete",
"implementedEvidenceSummary": "Versioned conditional local loading analysis for selected agent/profile/project/CWD/version, frozen physical subjects and all candidates; cited agent-specific selection/coexistence, policy and invocation dimensions, explicit unavailable native inventory and unknown sessions; shared CLI/TUI rendering with bounded owned capture",
"remaining": null,
"acceptance": "Explain why a skill is unavailable and which copy is selected or which names coexist. Disabled, broken and incompatible states outrank a generic symlink badge. Do not apply the generic client guide\u2019s project-over-user advice as a universal rule for every agent.",
"evidenceLedger": "maintenance-implementation.md",
"finalAcceptanceProven": false
"finalAcceptanceProven": true,
"finalAcceptanceEvidence": "evidence/maintenance-batch-13-final.json",
"verifiedCommit": "6233f6a39105c472130e726c425da7ecf5acb632",
"mergedPullRequest": 63
},
{
"id": "M13",
Expand Down
14 changes: 12 additions & 2 deletions agent_docs/maintenance-effective-loading.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@

PR #61 merged at `351224b3e058166073370caafcba225bce12d7e9`. This
reviewed design starts the next implementation batch. Close the complete original
M12 change and acceptance, retaining M08/M09/M13-M21 obligations. Implementation
is in review; final acceptance remains pending.
M12 change and acceptance, retaining M08/M09/M13-M21 obligations. Implementation and final acceptance are complete; historical checkpoints below
retain their original pending status.

Use M10 contextual inventory + M11 frozen subjects. Add an analysis result for
one selected agent, profile, working project and client version, retaining every
Expand Down Expand Up @@ -177,3 +177,13 @@ are selected under their local tier rules. Invalid Codex absolute paths become
unknown policy without dropping other candidates. Shared payload/frontmatter
models and persisted journal formats remain unchanged. The native product proof
includes both rejected Gemini forms alongside a valid competing user skill.


Final M12 acceptance: PR #63 merged at `6233f6a39105c472130e726c425da7ecf5acb632` after final-head
verification and review. The merged tree matches `bedba13fc1c1c16449122187aa2ade8f253c1c40`.
`evidence/maintenance-batch-13-final.json` records source hashes, all platform and
actual gh contracts, both local native hosts, four-RID artifact binding, old-native
recovery compatibility and reviewed findings. Native AI-client inventory remains
unavailable with explicit reasons and active sessions remain unknown. Product
fixture version labels do not claim AI-client conformance. Whole-goal acceptance
is nine of 21, with the full remaining original audit retained.
Loading
Loading