Skip to content

Commit 02e19a7

Browse files
huangyiireneclaude
andauthored
docs(core): repair four copy-fails in PHASE2_IMPLEMENTATION.md (#18712)
Fixes #18620 Clause-②: no `packages/core/PHASE2_IMPLEMENTATION.md` carried four copy-fails that the edit boundary of PR #18615 (the seven retired key spellings) deliberately left alone. Triage refused to split the card, so all four land here in one sweep of one file. `packages/spec` was read-only for this work: the schemas were read to learn the right spelling, never edited. Every reading below was re-taken on this branch's head. The card's line numbers moved after PR #18615 landed, so each anchor was located by content. ## The four items are NOT one species Exactly one of them is a silently dropped key. The other three are a compile failure and stale prose. ### 1. `blockedHosts` — a key the runtime silently drops, in a security example The sandbox example wrote `blockedHosts`. `SandboxConfigSchema` (`packages/spec/src/kernel/plugin-security-advanced.zod.ts:392`) declares `deniedHosts`, and `sandbox-runtime.ts:261-262` reads `config.network.deniedHosts`. The `network` object is a plain `z.object`, not `.strict()`, and there is no `retiredKey` tombstone for `blockedHosts` — so the parse succeeds and the key is stripped with no diagnostic at all. Measured against the schema source, the documented block beside a positive control: ``` --- DOCUMENTED blockedHosts --- success: true parsed network keys: ["mode","allowedHosts","maxConnections"] network.deniedHosts: undefined --- CONTROL deniedHosts --- success: true parsed network keys: ["mode","allowedHosts","deniedHosts","maxConnections"] network.deniedHosts: ["malicious.com"] ``` A reader who copied that block got a sandbox that did not deny the host it named, and was told nothing. `blockedHosts` occurred exactly once repo-wide before this PR (that documentation line) and occurs zero times after it. The Features bullet above the block said "allowed/blocked hosts" and now says "allowed/denied hosts", matching the filesystem bullet beside it. Species: a silently dropped key. This is the only one of the four. ### 2. `kernel.logger` — a compile failure by member visibility, not a dropped key The `Integration with Kernel` block passed `kernel.logger` to five constructors. `ObjectKernel` declares `private logger: ObjectLogger` (`packages/core/src/kernel.ts:107`), `KernelBase` declares `protected logger: Logger` (`packages/core/src/kernel-base.ts:36`), and neither class has a public getter. The block never compiled, so nothing about it ever reached a runtime that could drop anything. Measured with `tsc --noEmit --strict`, the documented line against the repaired one: ``` documented: exit 2 error TS2341: Property 'logger' is private and only accessible within class 'ObjectKernel'. repaired: exit 0, no output ``` The repair builds the `ObjectLogger` those five constructors take with `createLogger` — already exported from `@objectstack/core` through the `logger.js` barrel — from the same config the kernel is given, rather than reaching into the kernel. The whole repaired block is what the exit-0 run above typechecked. Species: an example that fails when copied, by member visibility. No metadata key is involved. ### 3. Prose advertising a capability no runtime delivers The intro claimed "auto-recovery" and the Features list claimed "Auto-restart with backoff strategies (fixed, linear, exponential)". `packages/core/src/health-monitor.ts:160` states the opposite in as many words: "Monitors plugin health status. It REPORTS; it does not act on what it finds." The three keys that once configured a restart were retired under ADR-0049 and deleted from this file's examples by PR #18615, which is how the prose became conspicuous. The intro now says the monitor reports and that acting on a report belongs to the host, and the untrue Features bullet is replaced by the true integration point the example already demonstrates — polling `getHealthStatus` and `getHealthReport`. The adjacent bullets were checked rather than assumed: the `recovering` status is real and asserted by `health-monitor.test.ts`, so that bullet stands. Species: stale prose, Prime Directive #10. No key. ### 4. Three observations in the same file - `MICROKERNEL_IMPROVEMENT_PLAN.md` was linked from the References section. Repo-wide the name occurred once — that link — and no such file exists at the repo root or anywhere else, while its sibling `ARCHITECTURE.md` does. The dead link is removed. - `npm test` in a pnpm workspace is now `pnpm --filter @objectstack/core test`, which is what the package's own `test` script answers to. The three test files the section lists all exist. - "File watching integration points" was listed as a hot-reload feature. `HotReloadConfig.watchPatterns` was retired in #12428 because no watcher was ever constructed, and this file's own body already tells the reader that file watching is the host's job. The bullet is folded into the debounce bullet, which now names `scheduleReload` and says the host runs the watcher. Species: stale prose and one dead reference. No keys. ## Changeset: measured, not guessed `packages/core/PHASE2_IMPLEMENTATION.md` sits at a package root, outside every fast-track path, so whether it ships is a property of `@objectstack/core`'s `files[]`, which is `["dist", "README.md", "CHANGELOG.md"]`. The reading, taken after a real build of `@objectstack/core` and its dependency closure: - `npm pack --dry-run --json` in `packages/core` lists 16 tarball entries. The non-`dist/` entries are `CHANGELOG.md`, `LICENSE`, `README.md` and `package.json`. `PHASE2_IMPLEMENTATION.md` is not among them. - Grepping the published paths (`dist`, `README.md`, `CHANGELOG.md`, `package.json`, `LICENSE`) for symbols unique to this diff: `PHASE2_IMPLEMENTATION` 0 files, `MICROKERNEL_IMPROVEMENT_PLAN` 0 files, `Auto-restart with backoff strategies` 0 files, `blockedHosts` 0 files. - Positive control on the same grep: `PluginSandboxRuntime` hits 4 published files (`dist/index.cjs`, `dist/index.js`, `dist/index.d.cts`, `dist/index.d.ts`), so the grep was capable of finding something. Verdict forced by that reading: this diff publishes nothing from any released package, so it takes `skip-changeset` rather than a patch changeset. `Clause-②: no` stands after the diff was written: the schema is untouched, no accept set moves, and no surface is published. `scripts/pm/check-widening-tells.mjs --declaration no` exits 0 on this diff but reports it NOT MEASURED — no declared surface covers a Markdown file — so that exit is recorded as evidence about no surface rather than as a clearance. ## Verification - Gate families derived with `node scripts/pm/dispatch-gates.mjs --commands --repo objectstack-ai/objectstack` from the tool's own change set: 39 families. 37 exited 0. Reconciled with `--ran` carrying every exit code: 39 derived, 37 run, 2 NOT MEASURED, 0 UNRUN. - The 2 NOT MEASURED are `check:dual-build-cjs-loads` and `check:lean-entry-closure`, both exit 3 PREREQUISITE NOT MET: they load built output for every package in the tree and 74 or more packages have no `dist/`. A whole-tree `pnpm build` is CI's run, not this card's; declared as a narrowing rather than reported as a pass. - `pnpm --filter @objectstack/core typecheck` exit 0 (three legs: `tsc --noEmit`, `tsconfig.examples.json`, `check:test-typecheck`). - `pnpm --filter @objectstack/core test` exit 0 — 51 test files, 1316 tests passed. - `pnpm --filter '@objectstack/core...' build` exit 0 (core plus its dependency closure), run before every gate and measurement that reads `dist/`. - `pnpm lint` narrowed to a measurement rather than skipped. ESLint's universe read from `eslint.config.mjs` itself: every config block's `files` is a `{ts,tsx,mts,cts,js,jsx,mjs,cjs}` glob and no block names Markdown. ESLint's own count over the changed file, from `--format json`: 1 result, 0 errors, and the one message is "File ignored because no matching configuration was supplied." Invariance over untouched files: the config enables no type-aware linting anywhere — no `parserOptions.project`, no typed rules, as the config's own recorded measurement at line 328 states — so this diff cannot move any other file's verdict. - `pnpm check:nul-bytes` exit 0, plus a direct control-character scan of the changed file, which found none. - All heavy runs went through `scripts/pm/os-verify-lock.sh` with a stable slot; every verdict above is read from its `VERDICT command-exit` line. Measurements taken at `b6606cdc2d`, which is the only commit on this branch. ## Acceptance notes - The `## References` section still links `[Protocol Definitions](../spec/src/system/)`, while the Phase 2 components this file documents are Kernel-domain schemas under `packages/spec/src/kernel/`. The link resolves to a directory that exists, so it is not dead and nothing fails when copied — a documentation nit, none of the three filable classes. Noted, not filed. No PR and no person is queued on this file today, so there is no carrier for it beyond the next sweep of the document. - `needs:contract-review` is the dispatching seat's label. This PR neither hangs it, removes it, nor waits on it; its presence and the `--pair` exit code are reported to the seat as readings. --- _Generated by [Claude Code](https://claude.ai/code/session_01CqmCgU5RGDoJYhHUMVp2af)_ Co-authored-by: Claude <noreply@anthropic.com>
1 parent df1b275 commit 02e19a7

1 file changed

Lines changed: 19 additions & 13 deletions

File tree

‎packages/core/PHASE2_IMPLEMENTATION.md‎

Lines changed: 19 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,14 @@ Phase 2 implements the core runtime features for advanced plugin lifecycle manag
1010

1111
### 1. Health Monitor (`health-monitor.ts`)
1212

13-
The Health Monitor provides real-time health checking and auto-recovery for plugins.
13+
The Health Monitor provides real-time health checking for plugins. It REPORTS what it
14+
finds; acting on a report — restarting, replacing or quarantining a plugin — belongs to
15+
the host that owns the plugin's lifetime.
1416

1517
**Features:**
1618
- Configurable health check intervals
1719
- Automatic failure detection with thresholds
18-
- Auto-restart with backoff strategies (fixed, linear, exponential)
20+
- Status and report polling (`getHealthStatus` / `getHealthReport`) for the host to act on
1921
- Health status tracking (healthy, degraded, unhealthy, failed, recovering, unknown)
2022
- Metrics collection (uptime, memory, CPU, connections, error rate)
2123

@@ -52,8 +54,7 @@ The Hot Reload Manager enables zero-downtime plugin updates with state preservat
5254

5355
**Features:**
5456
- State preservation strategies (memory, disk, distributed, none)
55-
- File watching integration points
56-
- Debounced reload scheduling
57+
- Debounced reload scheduling (`scheduleReload`) — the host runs the watcher
5758
- Graceful shutdown with configurable timeout
5859
- Before/after reload hooks
5960
- State checksum verification
@@ -213,7 +214,7 @@ The Sandbox Runtime provides isolated execution environments with resource limit
213214
**Features:**
214215
- Multiple isolation levels (none, minimal, standard, strict, paranoid)
215216
- File system access control (allowed/denied paths)
216-
- Network access control (allowed/blocked hosts)
217+
- Network access control (allowed/denied hosts)
217218
- Process spawning control
218219
- Environment variable access control
219220
- Resource limit enforcement (memory, CPU, connections)
@@ -238,7 +239,7 @@ const context = sandbox.createSandbox('my-plugin', {
238239
network: {
239240
mode: 'restricted',
240241
allowedHosts: ['api.example.com'],
241-
blockedHosts: ['malicious.com'],
242+
deniedHosts: ['malicious.com'],
242243
maxConnections: 10,
243244
},
244245
process: {
@@ -312,6 +313,7 @@ These components are designed to integrate with the existing ObjectKernel:
312313
```typescript
313314
import {
314315
ObjectKernel,
316+
createLogger,
315317
PluginHealthMonitor,
316318
HotReloadManager,
317319
DependencyResolver,
@@ -321,12 +323,17 @@ import {
321323

322324
const kernel = new ObjectKernel({ logger: { level: 'info' } });
323325

326+
// The kernel's own logger is private and has no public getter, so build the
327+
// `ObjectLogger` these five constructors take from the same config rather than
328+
// reaching into the kernel.
329+
const logger = createLogger({ level: 'info' });
330+
324331
// Initialize Phase 2 components
325-
const healthMonitor = new PluginHealthMonitor(kernel.logger);
326-
const hotReload = new HotReloadManager(kernel.logger);
327-
const depResolver = new DependencyResolver(kernel.logger);
328-
const permManager = new PluginPermissionManager(kernel.logger);
329-
const sandbox = new PluginSandboxRuntime(kernel.logger);
332+
const healthMonitor = new PluginHealthMonitor(logger);
333+
const hotReload = new HotReloadManager(logger);
334+
const depResolver = new DependencyResolver(logger);
335+
const permManager = new PluginPermissionManager(logger);
336+
const sandbox = new PluginSandboxRuntime(logger);
330337

331338
// Register plugins with enhanced features
332339
// ... plugin registration code ...
@@ -346,7 +353,7 @@ Comprehensive unit tests are provided for all components:
346353
Run tests with:
347354

348355
```bash
349-
npm test
356+
pnpm --filter @objectstack/core test
350357
```
351358

352359
## Performance Considerations
@@ -376,6 +383,5 @@ Phase 3 and beyond will add:
376383

377384
## References
378385

379-
- [MICROKERNEL_IMPROVEMENT_PLAN.md](../../MICROKERNEL_IMPROVEMENT_PLAN.md)
380386
- [ARCHITECTURE.md](../../ARCHITECTURE.md)
381387
- [Protocol Definitions](../spec/src/system/)

0 commit comments

Comments
 (0)