v3 knowledge refresh: teach the published SDK 3.0.0 surface + three drift gates (fn-165) - #2
v3 knowledge refresh: teach the published SDK 3.0.0 surface + three drift gates (fn-165)#2acebytes wants to merge 20 commits into
Conversation
…te + CI - reference/plugin-api/: byte-verbatim mirror of the published @appos.space/plugin-types@3.0.0 tarball's 9 dist/*.d.ts (maps dropped); generated INDEX.md records version, dist.integrity sha512, per-file sha256, and the regeneration command; old single-file plugin-api.d.ts (2950-line 2.4.0-fn50 snapshot) deleted - scripts/check-sdk-freshness.sh: check mode (registry dist.integrity vs committed .sdk-integrity pin + tarball-byte sha512 + per-file byte-equality + INDEX consistency; exits 0 today) and --update regeneration mode - scripts/verify-knowledge.mjs: ts-fence type-check against the pinned SDK + exported-name-set diff (mirror vs installed) + stale-identifier denylist + count-string consistency; three-tier scan matrix (teaching full scan / migration guide fences-only / compiled/** excluded); currently RED (184 findings) over the unrefreshed corpus BY DESIGN — proves the F1 drift class is detected before fn-165.2/.3 refresh content - package.json + package-lock.json: exact pins (typescript 5.9.3; @appos.space/plugin-types, plugin-utils, view-builders all 3.0.0) - .github/workflows/verify.yml: first CI for this repo (npm ci + both gates on PR/push; commented slot for fn-165.4 check-compiled-freshness) - README: knowledge-verification section + duplicate-clone retirement note Task: fn-165-ship-the-9-wave-plugin-ecosystem-sdk.1
Codex impl-review round 1 Major: check mode derived the version solely from .sdk-integrity, so bumping the devDependency + lockfile without --update kept verifying the OLD tarball while verify-knowledge type-checked the NEW installed package. Check mode now fails (exit 1) unless package.json's devDependency is EXACTLY the pinned version and the package-lock.json entry carries the same version + integrity — the mirror check and the fence type-check are guaranteed to reference the same artifact. Mutation-tested both directions; clean tree still exits 0. Task: fn-165-ship-the-9-wave-plugin-ecosystem-sdk.1
Codex impl-review round 3 Major: --update mutated the committed mirror/INDEX/ pin with unguarded rm/cp/redirects under set -uo (no -e) and an unconditional success exit, so an I/O failure could leave partial artifacts while printing UPDATED. Update mode now builds everything in a staging dir with every write guarded, byte-verifies the staged mirror against the tarball, then swaps into place with guarded moves — any failure exits 2 before/without trusting the result, and a mid-swap failure leaves a state check mode flags loudly. Round-trip verified byte-stable (regenerate over committed tree = zero diff); check mode still exit 0. Task: fn-165-ship-the-9-wave-plugin-ecosystem-sdk.1
…efresh to SDK 3.0.0 - new-plugin: scaffold pins ^3.0.0 x3; extensions[] example with fn-163 dual-registration + removal-marker note; landmine names 3.0.0; webview fence captures registration-token strings per 3.0.0 types - validate: minHostVersion blocklist extends to 3.0.0; schema anchor moves main -> pinned v3.0.0 tag (rationale rewritten; v2.4.0 tag stays the counter-example); 0.0.0 host-version symptom+cause note; core-plugin scope-lookup + extensions[] cross-check in the permission audit - build: entry-point fence self-contained (compiles under the F1 gate) - plugin-architect: canonical-scope model replaces the memorized 34-count; repertoire covers all 43 namespaces incl. the 21 core-plugin namespaces - viewdescriptor-builder: handler fence compiles (no ambient activate); 'No HTML' rule explicitly scoped to ViewDescriptor rendering mode; ViewDescriptor imported from the SDK, never hand-rolled - webview-panel-builder + webview-panels skill: token-return reality documented (3.0.0 types string; 1.0.0 host returns undefined at runtime; auto-teardown on unload); fences compile or take sanctioned no-verify (multi-file fragment, untyped window.twopanez); name: frontmatter added to both aux skills - marketplace.json: 3.0.0 at BOTH version sites; description drops stale counts; claude plugin validate --strict passes from repo root - README/CLAUDE: What's-new-in-v3.0, corrected layout trees, compiled/ provenance (Desktop compile-factory-context.sh), root-CLAUDE.md-not- plugin-context note verify-knowledge.mjs: 0 findings under these files (88 remain under skills/appos-plugin-dev/** = fn-165.2's scope) Task: fn-165-ship-the-9-wave-plugin-ecosystem-sdk.3
…igration guide - SKILL.md: name: frontmatter, 3.0.0 surface (43 namespaces), references wired early with mirror grep hints, actions quickstart (exec-context), body under 500 lines (enumerations moved to reference/) - extension-api.md: full 43-namespace reference (21 core-plugin namespaces incl. quirks), verbatim actions.register signature, extensions[] + fn-163 dual-registration caveat, catalog bundle layout, 135-scope permission model + 5 deprecated aliases, plugin-utils ActionHandler disambiguation, stale-tarball-README note - patterns.md: fences made gate-clean (imports + declare stubs, js fences for webview .js); NEW patterns: exec-context action, extensions[] dual registration, notifications.emit, scheduler job lifecycle - NEW reference/migration-2.x-to-3.0.md: six break classes (rename rule, no ambient globals, exec-context handlers, token returns, interface->type TS2352 w/ ytdlp example, ^3.0.0 pins + stale README); before-fences ts no-verify, after-fences type-checked - window.twopanez / --twopanez-* / install path / 17 ViewDescriptor types unchanged (live host contract) - verify-knowledge.mjs: ZERO findings under skills/appos-plugin-dev/** (whole-repo exit stays 1 until fn-165.3 lands — remaining findings are all in .3-scope files) Task: fn-165-ship-the-9-wave-plugin-ecosystem-sdk.2
…token contract
- §21: webview messages are semantic intents ('show-version'); command +
argv HARDCODED per intent in plugin code — never forwarded from
window.twopanez input into ctx.shell.execute (injection-shaped bridge
removed); unknown message types dropped; app.js send updated; key
points call the rule out
- §6 + §21: capture onWebPanelMessage/onWebPanelRequest tokens and
document the REAL host contract — no handler-unregister API exists;
ctx.ui.unregister takes slot-based contribution ids only; the disposed
flag is the actual disposal mechanism
Task: fn-165-ship-the-9-wave-plugin-ecosystem-sdk.2
…r tokens) migration guide §4 + TL;DR, SKILL.md webview/constraints, extension-api WebView section: registerWebPanel returns a DISPOSABLE slot id (ctx.ui.unregister); onWebPanelMessage/onWebPanelRequest return handler tokens with NO unregister path — disposed-flag guard + host cleanup is the disposal mechanism. Consistent everywhere with patterns.md §6/§21. Task: fn-165-ship-the-9-wave-plugin-ecosystem-sdk.2
Shared disposed flag guards both webview handlers AND the async showVersion intent body; guard-flip disposer pushed after the panel disposer so reverse drain flips it first. Matches §6 / SKILL.md / migration §4 lifecycle teaching. Task: fn-165-ship-the-9-wave-plugin-ecosystem-sdk.2
…ate + webview fence harmonization - compiled/: plugin-factory-context.md regenerated from the v3-knowledge- refresh sources by AppOS-Desktop's fixed compile-factory-context.sh (byte-identical to the Desktop bundled copy); cli-chat-system-prompt.md re-synced from its Desktop-owned source; new manifest.json pins compiled artifact + dev-plugin source hashes (ownership-split, overlap fields byte-equal with the Desktop manifest) - scripts/check-compiled-freshness.sh: dev-plugin-only two-direction gate (source changed without regen / compiled artifact edited directly; both failure modes mutation-tested), wired into verify.yml's fn-165.4 slot and package.json scripts.check - webview-panels/SKILL.md: the ts no-verify shape sketch upgraded to the canonical TwopanezBridge ambient-block convention (authoritative copy: reference/extension-api.md); future-revision note retired; webview-panel-builder.md:144 stays no-verify (multi-file fragment) Task: fn-165-ship-the-9-wave-plugin-ecosystem-sdk.4 (AppOS-Desktop)
…requires X's) GNU mktemp on the Linux CI runner rejects 'mktemp -d -t sdk-freshness' (too few X's); an explicit path template works on both GNU and BSD. Task: fn-165.5
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: a7dd40ba9a
ℹ️ 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".
- patterns: disposed-flag teardown replaces unregister(undefined-token) disposer (P1); per-variant WebView message validation; honest pipeShellToWebPanel broadcast contract (x2 sites); menubar rollback on init failure; worked example aligned - migration guide: token capture for type-compat, teardown via disposed-flag/host cleanup - new-plugin: actions.definition extension-point id; honest fn-163 cold-start metadata framing - verify-knowledge: CommonMark tilde-fence support (fixture-proven) - compiled artifacts + manifest regenerated (168,537 B, gates green)
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: ab5f813540
ℹ️ 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".
- plugin-architect: manifest actions.definition = catalog metadata until fn-163 (last cold-start attribution site) - check-sdk-freshness: INDEX.md rows must match mirror set one-to-one (extra/missing/duplicate all fail; mutation-tested) - verify-knowledge: dependency/global tsc diagnostics now fail the gate (false-green proven + fixed; mutation-tested) - find -maxdepth claim: not addressed — empirically verified BSD-compatible (documented primary, path-first order)
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 7a5c4d170d
ℹ️ 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".
- SKILL.md: token-disposer guidance replaced with disposed-flag/host-cleanup contract at BOTH surviving sites (P1); sibling skills verified clean - extension-api.md: legacy-alias claim corrected (only network.fetch host-normalized); migration guide gains replace-dead-scope-names guidance - verify-knowledge: EOF-unclosed fences now compiled per CommonMark (fixture-proven) - check-compiled-freshness: manifest validated as JSON before hash loop (mutation-proven) - compiled artifacts + manifests regenerated (169,662 B)
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 1180a7d93e
ℹ️ 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".
- README: manifest actions.definition = catalog metadata (canonical fn-163 framing; README+CLAUDE swept, only site) - vault secrecy claim precise: raw material transits JS once at store(), no read-back after (SKILL.md + extension-api.md ctx.vault paragraph found in sweep) - check-compiled-freshness: hash entries now emitted from the parsed JSON object (single source of truth; duplicate-key divergence mutation-proven) - compiled artifacts + manifests regenerated (169,927 B)
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 7d4b6c85d0
ℹ️ 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".
- validate: legacy-alias post-check after schema validation (4 dead aliases = ERROR w/ canonical replacements; network.fetch tolerated-but-rename) + 3 audit-table rows fixed; extensions[] cross-check uses per-EP scope lookup instead of mechanical *.register suffix (verified examples incl. surfaces.contribute.* and entities.computedField.provide) - verify-knowledge: CommonMark blockquote-container fence support (depth-tracked prefix, no lazy continuation, fixture-proven; corpus unchanged)
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 02f6d4194e
ℹ️ 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".
- extension-api: WebPanel disposal claim split per verified host divergence (P1; conceptual corpus sweep — sole surviving prose site); Disposal paragraph aligned with migration guide + patterns §6 - verify-knowledge: list-marker fence containers (generalized r5 container mechanism to blockquote+list token sequences; bypass probe-confirmed, fixture-proven); hyphenated N-scope/N-namespace count patterns (mutation-proven) - compiled artifacts + manifests regenerated
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 5289d97283
ℹ️ 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".
- check-compiled-freshness: generator-derived set-equality for manifest source AND artifact keys (reviewer repro mutation-proven; same-shape artifacts hole closed)
- verify-knowledge: fence indentation bounded to CommonMark {0,3} per container level (false-green reproduced then fixed; tab-led fence lines correctly rejected)
- check-sdk-freshness: INDEX surface counts fully derived via shared surface_line() helper + new Gate 5c validates the INDEX line against re-derived truth (mutation-proven)
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 6e613a0253
ℹ️ 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".
- plugin-architect: legacy-alias claim split per canonical table; dead webview scope dropped from output template; third surface found+fixed in webview-panel-builder checklist (template-focused sweep) - verify-knowledge: CommonMark §2.2 column-based list-container stripping (tab expansion + partial-tab re-emission; both false-green modes reproduced then fixture-proven) - check-compiled-freshness: strict root-object + schema===1 discriminator gate (generator already writes schema:1; mutation-proven 4 directions)
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 663d813e94
ℹ️ 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".
- verify-knowledge: track list-container state across continuation lines (CommonMark blockquote/list stack + lazy continuation) so col>=4 fences inside list items are no longer silently skipped - verify-knowledge: compile each fence in an isolated ts.Program over a shared memoized CompilerHost so declare-global/ambient declarations cannot leak between teaching examples (0.6s -> 0.9s for 63 fences) - new-plugin.md: scaffold emits only canonical ui.webPanel; dead webview alias removed from both scaffold-instruction sites (validator kept) - check-sdk-freshness.sh: --update pre-flight mirrors check-mode Gate 0 (explicit version must match package.json + lockfile; reject exit 2 before any fetch) so successful updates can't desync the toolchain - README/CLAUDE.md: document npm run check as the canonical local CI reproduction (includes the compiled-freshness gate) - SKILL.md (appos-plugin-dev + webview-panels): remove nonexistent shell termination API; document in-flight cancellation as unavailable in SDK 3.0.0; compiled factory context + manifest regenerated
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: b2e8a3ab38
ℹ️ 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".
| | `ctx.lifecycle` | Dependency status notifications | (none) | | ||
| | `registerFromCommand(commandId, metadata)` | Projects an existing `ctx.commands` command into the action catalog | `actions.register` | | ||
| | `invoke(id, input, source?)` | Invokes through the full pipeline; resolves to an `ActionReceipt` | `actions.invoke` (+ `actions.invoke.agent` for source `"agent"`) | | ||
| | `all()` | Lists merged executable + manifest-declared actions | `actions.list` | |
There was a problem hiding this comment.
Stop promising manifest-only results from all()
On the shipped host while fn-163 remains unresolved, all() cannot list manifest-declared actions because those contributions never reach discovery; this directly contradicts the caveat at lines 413-418. A plugin using all() to inspect an unbound manifest action or handle its expected ACTION_NOT_FOUND state will instead see no entry. Fresh evidence beyond the earlier discovery comments is that this method table and the following manifest-only guarantee remain after the other action guidance was corrected.
Useful? React with 👍 / 👎.
| const ctxBody = core.match(/export interface PluginContext \{([\s\S]*?)\n\}/); | ||
| if (!ctxBody) throw new Error(`PluginContext not found in ${dtsDir}/core.d.ts`); | ||
| const members = [...ctxBody[1].matchAll(/readonly (\w+):/g)].map((m) => m[1]); | ||
| const scalars = members.filter((n) => ["pluginId", "pluginVersion", "hostVersion"].includes(n)); |
There was a problem hiding this comment.
Derive metadata scalars instead of whitelisting three names
When a future SDK adds another readonly metadata scalar to PluginContext, this whitelist classifies it as an API namespace, leaving metadataScalars unchanged and incrementing namespaces. Both INDEX generation and count verification consume this same incorrect deriveCounts() result, so the regenerated index and gate agree and remain green while advertising wrong surface counts. Fresh evidence beyond the earlier generated-count comment is that the new dynamic surface_line() still ultimately depends on this fixed three-name classification.
Useful? React with 👍 / 👎.
|
|
||
| # Swap into place (guarded; a failure here exits non-zero and the committed | ||
| # tree is left for check mode to flag rather than being trusted). | ||
| rm -rf "$MIRROR_DIR" || { echo "[check-sdk-freshness] ERROR could not remove old mirror $MIRROR_DIR" >&2; exit 2; } |
There was a problem hiding this comment.
Preserve the old mirror until replacement succeeds
When the following mv fails, this command has already permanently deleted the existing mirror; the failure branch itself acknowledges that the repository is left with no mirror, and a later failure moving the pin similarly leaves the new mirror paired with the old integrity metadata. This defeats the stage-then-swap protection precisely for filesystem failures during installation, so keep the old directory as a rollback target and install the staged directory before removing that backup.
Useful? React with 👍 / 👎.
| ## The bridge (`window.twopanez`) | ||
|
|
||
| The host injects `window.twopanez` at document start, before any module runs. Its shape: | ||
| The host injects `window.twopanez` at document start, before any module runs. The published `@appos.space/plugin-types` package does not type it (WebView code is a separate compilation world), so ship this local ambient declaration alongside your webview sources (authoritative copy: `appos-plugin-dev/reference/extension-api.md` § "WebView-side bridge (`window.twopanez`)"): |
There was a problem hiding this comment.
Include the WebView declaration in the typecheck project
When a user follows the canonical scaffold, placing this file at webview/twopanez.d.ts provides no typing: commands/new-plugin.md configures TypeScript with include: ["src/**/*.ts"], while the generated WebView sources are .js, so neither this declaration nor the code using window.twopanez participates in npm run typecheck. Misspelled bridge methods therefore remain unchecked despite this guidance; add a WebView TypeScript/checkJs project or otherwise include the declaration and WebView sources in the scaffolded typecheck.
Useful? React with 👍 / 👎.
| - **`grid`** — `columns` (default 3), `spacing` (default 8) | ||
| - **`remoteImage`** — `url` (file:// only in v1), `width`, `height`, | ||
| `cornerRadius`, `maxDimension` (default 512) | ||
| - **`textField`** — `placeholder`, `value`, `action` (fires on submit) |
There was a problem hiding this comment.
Use the published textField property name
When an author follows this property list to initialize an editable field, value is not part of SDK 3.0.0's TextFieldDescriptor; reference/plugin-api/views.d.ts defines the property as text. Typed inline descriptors therefore fail excess-property checking, while loosely constructed JSON reaches the host without the intended initial text. Teach text here so generated ViewDescriptor panels match the published contract.
Useful? React with 👍 / 👎.
v3 knowledge refresh — every teaching surface now teaches SDK 3.0.0 (fn-165.1–.5)
This PR is the dev-plugin half of the fn-165 knowledge refresh. Every surface the App Builder / CLI Chat / Claude Code consumes now teaches the published
@appos.space/plugin-types@3.0.0surface (43 namespaces, 135 canonical permission scopes,ActionExecutionContexthandler contract,extensions[]manifests, catalog bundle layout) instead of the 22-namespace 2.4.x surface — and future drift is detectable by construction via three CI gates.Landing order: this PR merges FIRST, then the AppOS-Desktop branch (
fn-165-ship-the-9-wave-plugin-ecosystem-sdk). The Desktop-bundled compiled artifacts were regenerated FROM this branch's sources and are byte-identical tocompiled/plugin-factory-context.mdhere (sha256747e5096f5d908b790ad1d8d2cf30c93f46eb6bbf0a310f58491f35313c76bb2). Merge is user-gated — do not merge on my account.End-state report: what was stale → what is refreshed
reference/plugin-api.d.ts@version 2.4.0-fn50, 22 namespacesreference/plugin-api/— the published 3.0.0 tarball's 9dist/*.d.tsmodules mirrored byte-verbatim, plus a generatedINDEX.mdrecording version, npmdist.integrity(sha512), per-file sha256, and the regeneration commandskills/appos-plugin-dev/SKILL.mdctx.actions.register(def, (exec) => ...)exec-context contract,extensions[]with the fn-163 caveat, catalog bundle layoutreference/extension-api.mdgetDependencyStatus/recheckDependenciesis gone (both host-wired)reference/patterns.mdreference/migration-2.x-to-3.0.mdregisterWebPaneltoken return, no-ambient-globals,interface→typeforexec.inputassertion targets, citing the ytdlp case). The sole sanctioned home for pre-3.0 identifiersskills/viewdescriptor-authoring/SKILL.md,skills/webview-panels/SKILL.mdTwopanezBridgeblock)agents/{plugin-architect, viewdescriptor-builder, webview-panel-builder}.mdcommands/{new-plugin, validate, deploy, build}.md^2.4.0scaffold pinsvalidate.mdblocklist extended to flagminHostVersion: "3.0.0"confusion (host is1.0.0)compiled/plugin-factory-context.mdcompiled/cli-chat-system-prompt.md.claude-plugin/marketplace.jsonmetadata.versionandplugins[0].version— deliberately aligned with the SDK major it teachesREADME.md,CLAUDE.mdGates added (drift detectable by construction)
scripts/check-sdk-freshness.sh— verifies the recorded npmdist.integrityagainst the registry and every mirroredplugin-api/*.d.tsfile byte-equal to the published tarball. Green:@appos.space/plugin-types@3.0.0, 9 files byte-equal.scripts/verify-knowledge.mjs— extractstsfences from all teaching markdown and type-checks them against the pinned 3.0.0 package (grep was prototyped and produced a false pass; type-checking is the gate), plus exported-name-set diff, stale-identifier denylist, and count-string consistency. Three-tier scan matrix: teaching sources full-scan; migration guide fences-only (denylist-exempt);compiled/**excluded (validated via manifests instead). Green: 16 files scanned, 63 fences compiled, 6 sanctionedno-verifyopt-outs (5 migration-guide "before" fences + 1 multi-file fragment inagents/webview-panel-builder.md).scripts/check-compiled-freshness.sh— ownership-split manifest check: recomputes dev-plugin-owned source hashes AND compiled-artifact hashes againstcompiled/manifest.json; a source edit without regen and a hand-edit of a compiled artifact both fail. Green: 2 artifacts, 12 sources fresh..github/workflows/verify.yml— runs all three vianpm run checkon PR (npm ci, committed lockfile, TypeScript pinned exactly).E2EFactoryContextResourceTestspins the bundled resources AND the generator script's own hash against the Desktop manifest;compile-factory-context.sh --checkregenerates into a temp dir and byte-compares both repos' artifacts.Decisions taken
dist.integrity) is the reference and every bundled copy is a generated artifact. Syncing from the plugin-sdk working tree or the host d.ts was rejected (that is exactly how the forks happened).extensions[]taught WITH the fn-163 caveat. Manifest-declarative action definitions currently never reachDiscoveryStore(open bug fn-163); the knowledge teaches the runtime dual-registration workaround marked "remove when fn-163 lands". Back-link recorded on fn-163.packages/plugin-types/README.mdis immutable; the knowledge carries a "trust the d.ts" note and the source fix rides a plugin-sdk PR so the next release carries it.window.twopanez/--twopanez-*stay. Verified live host contract (PluginWebViewBridge.swift:81,145-160); renaming them in docs would break every generated plugin.appos-plugin-dev-skill.md(Desktop-bundled builder skill) is HAND-MAINTAINED-but-gated: ownership comment in the file, sha256 pinned in the Desktop manifest, stale-identifier scan inE2EFactoryContextResourceTests.Proof the gates earn their keep (gate-era catch)
During fn-165.4's codex review r1, the Desktop-bundled builder skill was caught teaching
context.ui.openWebViewfor plugin WebView panels (it is for external URLs only) — fixed toregisterWebPanel+showPaneTab(Desktop commit353742922) with the manifest re-pinned. A wrong-API teaching defect caught and hash-locked in the same wave that built the gate.What remains (recorded follow-ups, none block this PR)
--plugin-dirresolver (probes rootplugin.jsonbut marketplace layout has.claude-plugin/plugin.json; dev fallbacks omit the canonical clone; resolved dir must beplugins/appos-dev). Evidence appended to that task; NOT fixed here.registerWebPanel(PluginContextBridge.swift:5997) andonWebPanelMessage(:6262) returnundefinedat runtime while SDK 3.0.0 types them as returning registration-token strings. The docs' honest divergence note is the interim contract; token-based disposal for WebView panels does not work until the host is fixed.*Namespacevs*API, 267 vs 177 types) — separate fn-150-class follow-up.^2.4.0pins +interface→typeatsrc/actions/register-actions.ts:216) — documented as the migration-guide example, not executed.executableSha256policy for brew-installed binaries.Verification (local @ a7dd40b)
npm run check— all three gates green (freshness + verify-knowledge + freshness:compiled)claude plugin validate --strict .— Validation passed (CLI 2.1.205)grep -rn "com.twopanez/plugins" plugins/— 0 hitsswift test --parallel --filter 'E2E'exit 0 (143 tests) andcompile-factory-context.sh --checkclean, recorded on the Desktop brancha7dd40b;ac52447adds one CI-only portability fix (GNU mktemp template incheck-sdk-freshness.sh) after the first PR run failed on the Linux runner. Theverifyworkflow is green on this PR.