You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Found by Neutral's ship-risk shadow gate on PR #1004 (record: #1004 (comment), classified high e4).
The gap
PR #1004 makes CommandRegistry.register copy the registration with a spread before validating and storing it. A spread carries own enumerable properties only, so the runtime now narrows what it accepts. The gate measured a base-vs-head differential and found three shapes went from working to throwing, and two semantics from live to snapshotted:
That narrowing is deliberate and correct, and the gate confirmed zero in-repo reliance on any of it across all 248 .register( sites (the only such uses are the PR's own negative tests).
The problem is that the published types do not say so.hypaware-plugin-kernel-types.d.ts ships in package.json#files for hypaware@1.25.0, so CommandRegistry.register is a third-party plugin API. A plugin author writing:
classMyCommandimplementsCommandRegistration{name='my cmd'summary='...'usage='...'run(){/* ... */}// on the prototype}
compiles clean against the shipped .d.ts (tsc --strict exits 0) and then throws at runtime. PR #1004 states the rule in a JSDoc comment, which is prose a compiler cannot enforce.
Blast radius is bounded but not nil: src/core/runtime/loader.js:108 catches per plugin and logs plugin.activate_failed, so the kernel and other plugins keep running. The failing plugin simply does not load.
Options
Tighten the type so the compiler rejects what the runtime rejects. Most durable, but needs care: expressing "own enumerable properties only" in TypeScript is awkward, and an over-tight type could reject shapes that do still work.
Both. Option 2 is cheap and should probably happen regardless of whether option 1 is judged practical.
Worth deciding before the next published release, since the failure mode for a third-party plugin author is a plugin that silently does not load with only a log line to go on.
Backlink
Deferred from PR #1004 at head 20dd24cb6d6c95aaa15adc0125f9eb95e111dae9.
Correction (later tick): this issue originally named 1.26.0 as the release to note this in. That was wrong. 850fee36 published v1.26.0 without PR #1004, so the narrowing described above is not in 1.26.0 and will first ship in whatever release carries #1004. The hypaware@1.25.0 reference above is still accurate for where the published .d.ts stands today.
Found by Neutral's ship-risk shadow gate on PR #1004 (record: #1004 (comment), classified
high e4).The gap
PR #1004 makes
CommandRegistry.registercopy the registration with a spread before validating and storing it. A spread carries own enumerable properties only, so the runtime now narrows what it accepts. The gate measured a base-vs-head differential and found three shapes went from working to throwing, and two semantics from live to snapshotted:class MyCommandwithrun()on the prototyperunintact)missing run()Object.create(proto)registrationrunThat narrowing is deliberate and correct, and the gate confirmed zero in-repo reliance on any of it across all 248
.register(sites (the only such uses are the PR's own negative tests).The problem is that the published types do not say so.
hypaware-plugin-kernel-types.d.tsships inpackage.json#filesforhypaware@1.25.0, soCommandRegistry.registeris a third-party plugin API. A plugin author writing:compiles clean against the shipped
.d.ts(tsc --strictexits 0) and then throws at runtime. PR #1004 states the rule in a JSDoc comment, which is prose a compiler cannot enforce.Blast radius is bounded but not nil:
src/core/runtime/loader.js:108catches per plugin and logsplugin.activate_failed, so the kernel and other plugins keep running. The failing plugin simply does not load.Options
Worth deciding before the next published release, since the failure mode for a third-party plugin author is a plugin that silently does not load with only a log line to go on.
Backlink
Deferred from PR #1004 at head
20dd24cb6d6c95aaa15adc0125f9eb95e111dae9.Correction (later tick): this issue originally named 1.26.0 as the release to note this in. That was wrong.
850fee36published v1.26.0 without PR #1004, so the narrowing described above is not in 1.26.0 and will first ship in whatever release carries #1004. Thehypaware@1.25.0reference above is still accurate for where the published.d.tsstands today.