Repository navigation
feat: harden native plugin publishing lifecycle - #11
Conversation
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 9d06f01d25
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
- Start bootstrap with a truly empty changelog - Validate bootstrap and released changelog states separately
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: a1e3dab318
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
- Pin Claude marketplace installs to release tags
Initialization now creates a fresh recipient release history instead of inheriting the template's. It forces every version surface to 0.1.0, empties the Release Please manifest and changelog, renames the release package to the recipient identity, and regenerates the version-bearing Codex hook definition with --plugin-version. The Codex hooks file is now a generated artifact covered by generate:check. Implements U1 (R3, R12; AE1; KTD4).
Centralize plugin payload discovery in a single strict walker that rejects symlinks, special files, and realpath escapes before any copy, returns a deterministic sorted inventory, and copies regular files only with preserved modes. Packaging and distribution proof now derive their expected archive members from that shared inventory and assert exact membership plus byte-for-byte equality against the source, replacing the hand-maintained required-file allowlist. Implements U2 (R8, R9; AE5; KTD2, KTD5).
Canonical metadata validation now enforces the full generated native package contract: strict semver with a 64-character bound, structural HTTPS URL parsing (host required, no embedded credentials, no unsupported characters), control-character and uniqueness rules, and normalized starter-prompt checks. The stricter directory-readiness text subset is named separately and reports the deferred ZIP/assets/identity/ portal/review/approval/publication work as not evaluated, so passing it never implies public-directory submission readiness. Generated Claude manifest and marketplace entry both set defaultEnabled: false as post-inspection defense in depth, with an exported Claude Code 2.1.154 compatibility marker warning that earlier clients ignore it. Contract tests consume the canonical validator and run `claude plugin validate --strict` against the rendered plugin. Implements U9 (R23, R24, R29, R31, R32, R36; KTD12, KTD16).
Release Please now maintains the version PR only (skip-github-release); the workflow itself resolves exactly one merged release-PR candidate bound to github.sha, proving base branch, automation identity, two-parent merge, and an allowed-projection-only diff, then persists that candidate record before proof and reuses it idempotently. Compatibility, metadata, and payload proof run against the pinned candidate SHA even if main advances. The immutable vX.Y.Z tag is created explicitly at the proven SHA and verified against the remote before the GitHub Release is created with --verify-tag --target. Incomplete-publication repair compares each asset before writing: matching assets are left untouched, missing ones added, and mismatches fail closed unless an explicit same-tag human authorization runs under the protected release environment. Release evidence is renamed from provenance to *.checksums.json bound to repository, source commit, immutable tag, version, archive name, size, and SHA-256, and is documented as integrity evidence rather than independent publisher authenticity. Implements U3 (R1-R5, R10, R11, R30; AE2-AE4; KTD1-KTD3, KTD9, KTD17).
Add a release-impact classifier that inspects the base-to-head diff and requires a releasable Conventional Commit title (feat, fix, perf, or a breaking form) whenever installable payload bytes change. Documentation, test, and CI-only changes are exempt, and the recognized Release Please version-only projection (including the node release-type package.json bump) is exempt so the automated release PR is never blocked. Failures name the accepted title classes and the changed payload paths. Implements U4 (R6, R7; AE7; KTD6).
Add a read-only repository-readiness verifier (bun run readiness) that confirms the safeguards this release design depends on: an immutable v* tag ruleset restricting deletions and updates with no bypass, the expected default branch and merge mode, required status checks, Actions permissions, and that no workflow grants repository administration. Each classifier fails closed, treating absent, bypassable, unauthorized, or unqueryable state as not-ready with an exact settings repair hint rather than assuming the repository is safe. Implements U5 (R13, R14; KTD3).
Add a hermetic harness-install proof (bun run prove:harness-install) that
installs the tagged payload into isolated Claude and Codex homes and
verifies both report the same version with cache bytes identical to the
independently resolved tagged inventory. Claude proof exercises user,
project, and local scopes, preserves ${CLAUDE_PLUGIN_DATA} through
--keep-data across upgrade, rollback, and restoration, ignores orphaned
cache directories, and asserts the defaultEnabled and 2.1.154
compatibility boundary. Codex proof takes its evidence from marketplace
and plugin list --json (installed path, version, enabled state,
policies), proves local-cache byte replacement, restores prior ref and
enabled state after an injected failure, and keeps hook trust separate
from plugin enablement. Interactive trust, private Git transport, and
hosted fresh-task cases are skipped with recorded reasons. The proof
writes only to temporary isolated homes and stays out of prove:all so
the CI gate remains non-flaky.
Implements U6 (R15-R20, R25-R29, R33-R35; AE6, AE8-AE10;
KTD2, KTD7, KTD10, KTD13, KTD15, KTD16, KTD18, KTD19).
Hosted public and private Git-repository canaries now run only when the template's publishing machinery changes, classified from the base-to-head diff; recipient payload-only changes stay on hermetic proof alone. Canary authorization binds the real Git transport identity used to push (SSH greeting or HTTPS credential-helper user), failing preflight when it differs from the intended owner even if the active gh account matches. Each qualifying source SHA publishes to a unique immutable refs/heads/candidate/<sha> ref per canary repo, never advancing a shared branch or rewriting history, and the candidate is installed through each native harness and compared to the source SHA. Results make no universal-directory submission claim. Implements U7 (R21, R22; KTD8, KTD11).
Rewrite the README and reviewed-release ADR to describe only proven behavior. Release maintenance is separated from publication: Release Please maintains the version PR, and the workflow binds one candidate commit through proof, immutable tag, and release. Repair names an exact existing tag and distinguishes incomplete-publication repair from a new release. Integrity evidence is renamed from provenance to checksums. Native install, upgrade, rollback, and trust recipes follow the proven ordered flow per host, Codex support is scoped to the CLI and ChatGPT desktop app, and the Git-marketplace path is separated from the deferred OpenAI universal-directory and Anthropic community submissions. Implements U8 (R3-R5, R10, R11, R15-R22, R26-R37; KTD1-KTD10, KTD15-KTD19).
The implementation-ready, adversarially reviewed plan that units U1-U9 were built from.
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: d00e0fbcdb
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
- Accept valid bootstrap release projections - Classify deleted publishing paths - Bind release exemptions to trusted automation identity
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 64b60eaf67
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: fac5e40f17
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
|
@codex review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: cb182a3c5e
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
… Brain (#53) * feat(dev): detect an orphaned development cache and add a dev-mode skill Backport of my-second-brain-plugin #11 (1a192dc). Walks the development cache to a bounded depth and reports dangling links, unreadable paths, and depth-exceeded paths as an orphaned or unverifiable cache, rather than letting an unwalkable tree read as a clean result. Adds the dev-mode skill as the user-facing half of the Development Installation lifecycle already shipped in #50. Vault-specific skills from the originating commit (new-note, new-project, ultragoal) are omitted; only dev-mode is generic. * fix(dev): require an explicit recovery step on every lifecycle error Backport of my-second-brain-plugin #12 (057ab2f). Makes nextAction a required constructor parameter on every ClaudeDevelopmentInstallationError, so no lifecycle failure reaches a caller without naming the step that repairs it. A default here would silently name one command as the recovery for every failure, including that command's own. Bun strips types without checking them, so next-action-contract.test.ts is the enforcement: it scans every construction site, including the helper-fed sites whose first argument is options.code, and rejects a recovery step that is a bare rerun of the failing command. * fix(dev): let check read a profile installed from another checkout Backport of my-second-brain-plugin #13 (312f0f1). The restoration snapshot lives inside the checkout that captured it, so a second checkout never holds one for an installation it did not create. check there now reports the link mismatch it can see rather than refusing for want of a snapshot that was never its to hold. The own-checkout case keeps the opposite, fail-closed contract. The originating fixture hardcoded the plugin name; it now reads the name from plugin.config.json, matching orphan-detection.test.ts, so the mismatch fires under any template plugin identity. --------- Co-authored-by: Nathan Vale <hi@nathanvale.com>
Summary
This PR turns the template's initial release path into a reviewed, fail-closed publishing lifecycle. Recipient plugins start at a clean
v0.1.0, while later releases keep every version surface synchronized.The same candidate commit now flows through deterministic packaging, native installation proof, an immutable tag, GitHub Release publication, and bounded same-tag repair. Repository safeguards and publishing-system canaries expose missing configuration instead of assuming the repository is ready.
Design decisions
Session-settled decisions carried from planning: use reviewed Release Please maintenance, immutable candidate refs, conditional hosted canaries, native harness evidence, and explicit deferred directory-publication boundaries.
Validation
bun run prove:all: 190 passed, 4 skipped, 0 failed.hosted-canary-qualificationenvironment has noCANARY_GH_TOKEN,CANARY_SSH_KNOWN_HOSTS, orCANARY_SSH_PRIVATE_KEYsecrets.Release sequencing
Merge this PR before release PR #10. Keep #10 open so Release Please can rewrite the existing release branch from
v0.2.0to the correct initialv0.1.0.Related: #10
Summary by CodeRabbit
New Features
Bug Fixes
Documentation