Skip to content

Conformance: skill-local scripts ship with their skill and mirror byte-identically #482

Description

@rucka

Story Statement

As a pair maintainer shipping skills that carry their own scripts
I want the skills conformance check to prove that every script a SKILL.md links under ./scripts/ exists beside it in the dataset, and that every dataset skill-local script has a byte-identical installed twin under .claude/skills/<prefixed-skill>/scripts/
So that a skill is portable as one folder and a script edited in one copy but not the other is a red gate, not a runtime surprise

Where: pnpm skills:conformance (packages/knowledge-hub/src/tools/skills-conformance-check.ts) — the value is a new failure class in its report and a PASS on the current corpus.

Epic Context

Parent Epic: Supervised automation #212
Status: Refined
Priority: P1 (Should-Have)

Status Workflow

  • Refined: Story is detailed, estimated, and ready for development
  • In Progress: Story is actively being developed
  • Done: Story delivered and accepted

Classification

risk:green · cost:green · coupling: green

Matrix — per dimension
Dimension Tier Source Note
Service/domain criticality green Criticality Table packages/knowledge-hub is listed Low.
Change/diff risk green story scope One module (skills-conformance-check.ts) + its vitest file; no shared code, no schema, no infra.
Business impact green subdomain class Development Tooling Standards (Generic).
Security relevance green path heuristic Read-only filesystem comparison inside the repo.
Coupling balance green map-contexts (scoped) Consumes the dataset tree and the installed skills tree it already reads.

Acceptance Criteria

Functional Requirements

Given-When-Then Format:

  1. Given a dataset SKILL.md whose body links a script as […](./scripts/<file>) or […](scripts/<file>)
    When skills:conformance runs and that file does not exist in the skill's scripts/ directory
    Then the report carries an error naming the skill's relative path and the missing script path, and the check exits non-zero.

  2. Given a dataset skill-local script dataset/.skills/<category>/<name>/scripts/<file>
    When the installed twin .claude/skills/pair-<category>-<name>/scripts/<file> is missing or differs by one byte
    Then the report carries an error naming both paths (missing vs drifted), and the check exits non-zero.

  3. Given the current corpus (three skills with scripts/: contract-phase, red-seal, p3-verify)
    When skills:conformance runs
    Then it PASSes and its summary line names the new check ("skill-local scripts shipped and mirrored").

Business Rules

  • The dataset copy is canonical; the installed copy is derived. The check reports drift, never repairs it.
  • Only files under a skill's own scripts/ directory are in scope; sub-documents (*.md) stay with the existing mirror guards.
  • A bare/meta skill (next, loop) may own no sub-directory: the bounded flatten (flattenDepth: 2) refuses a depth-1 entry that holds files and a sub-directory, and so does the gate. A meta skill that needs scripts/ must sit at category depth (capability/<name>/scripts/*.claude/skills/pair-capability-<name>/scripts/*). Corrected 2026-09-09 after PR [US-482] feat: skill-local scripts ship with their skill and mirror byte-identically #483's review: the earlier rule described a layout the installer rejects.

Edge Cases and Error Handling

  • Invalid Input: a link target outside scripts/ (e.g. ../other/x.mjs) is out of scope for this check and left to checkLinks.
  • System Errors: an unreadable script file is reported as an error naming the path, never as "identical".
  • Boundary Conditions: an installed twin with no dataset source is ignored (root-only files are not this check's subject, consistent with the SKILL.md mirror guard).
  • Exceptional Scenarios: an empty scripts/ directory is neither an error nor a pass line.

Definition of Done Checklist

Development Completion

  • AC 1–3 implemented in skills-conformance-check.ts and covered by vitest in skills-conformance-check.test.ts (temp-directory fixtures for AC 1–2, real corpus for AC 3)
  • pnpm skills:conformance PASS on the branch; pnpm --filter @pair/knowledge-hub test green
  • No new dependency; format, lint, hygiene green
  • Summary line of the checker lists the new check

Quality Assurance

  • Missing-file and drifted-file cases each fail with the exact paths in the message
  • Regression: every existing conformance test still passes

Deployment and Release

Story Sizing and Sprint Readiness

Refined Story Points

Final Story Points: 2 (S)
Confidence Level: High
Sizing Justification: one pure function (~50 lines) wired into runChecks, three vitest cases; the corpus already satisfies it.

Sprint Capacity Validation

Sprint Fit Assessment: Yes
Development Time Estimate: 0.5 day
Testing Time Estimate: 0.25 day
Total Effort Assessment: Fits within sprint capacity: Yes

Dependencies and Coordination

Story Dependencies

Prerequisite Stories: #479 (the workflow/ category and the skill-local scripts/ folders exist only on feature/US-479-delivery-workflow-to-be) — this story is STACKED on that branch.
Dependent Stories: none.
Shared Components: packages/knowledge-hub/src/tools/skills-conformance-check.ts.

Team Coordination

  • Maintainer: review and merge.

External Dependencies

None.

Validation and Testing Strategy

Acceptance Testing Approach

Testing Methods: vitest unit tests with mkdtemp fixtures for AC 1–2 (dataset + fake root tree); integration assertion on the real corpus for AC 3; pnpm skills:conformance as the end-to-end oracle.
Test Data Requirements: temp directories only.
Environment Requirements: Node 20+, pnpm.

User Validation

Success Metrics: pnpm skills:conformance reports the new check and PASSes; a deliberately drifted copy fails locally.
Rollback Plan: revert the commit; no data or config impact.

Notes

Canary story for the phase-skill delivery engine (US-479 AC 10, ADL 2026-09-09 deterministic-code-canary): small, code-shaped, deterministic Vitest oracles, stacked on feature/US-479-delivery-workflow-to-be.

Technical Analysis

Implementation Approach

Strategy: add checkSkillLocalScripts(skillsDir, installedSkillsDir) to skills-conformance-check.ts returning string[] errors; call it from runChecks after checkEntrypointDepth; extend the PASS summary line. Installed dir = resolve(ROOT, '..', '..', '.claude', 'skills'); installed skill dir name = pair-<category>-<name> for <category>/<name>/SKILL.md, pair-<name> for a bare category skill (same rule as installedArtifactPath in skill-md-mirror.ts).

Design: not required.

Key Components:

  • packages/knowledge-hub/src/tools/skills-conformance-check.ts — new exported function + wiring + summary text.
  • packages/knowledge-hub/src/tools/skills-conformance-check.test.ts — three cases (missing linked script, drifted twin, real corpus PASS).

Technical Risks and Mitigation

Risk Impact Mitigation
Duplicating the naming transform wrong installed path for bare skills reuse the flatten/prefix rule already tested in skill-md-mirror.ts (installedArtifactPath) or mirror its two cases in the tests
Running against a checkout without .claude/skills false "missing twin" errors when the installed skills dir is absent, skip the twin check with one informational line (dataset-only checkouts)

Task Breakdown

  • T-1: RED — vitest cases for AC 1 (missing linked script) and AC 2 (missing / drifted twin) against temp fixtures; confirm they fail before any implementation
  • T-2: GREEN — implement checkSkillLocalScripts and wire it into runChecks + the summary line; AC 3 assertion on the real corpus
  • T-3: pnpm skills:conformance, pnpm --filter @pair/knowledge-hub test, format/lint; PR stacked on feature/US-479-delivery-workflow-to-be

Dependency Graph:

T-1 ──► T-2 ──► T-3

AC Coverage:

AC Tasks
AC 1 T-1, T-2
AC 2 T-1, T-2
AC 3 T-2, T-3

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

risk:greenClassification: low risk tieruser storyWork item representing a user story

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions