Skip to content

fix(core): PHASE2_IMPLEMENTATION.md imports from the root barrel, not an undeclared subpath - #16205

Merged
zhuangjianguo merged 1 commit into
mainfrom
claude/issue-15931-phase2-doc-root-barrel-import
Sep 6, 2026
Merged

zhuangjianguo merged 1 commit into
mainfrom
claude/issue-15931-phase2-doc-root-barrel-import

Conversation

@claude

@claude claude Bot commented Sep 6, 2026

Copy link
Copy Markdown
Contributor

Fixes #15931

Route (2) of the two the card names, as ruled at dispatch: repoint the document at the root barrel. packages/core/package.json is untouched — no ./security exports entry, no files change. Widening the published surface to make a document true stays the maintainer's call and this PR does not foreclose it.

The defect, measured live at this head

packages/core/PHASE2_IMPLEMENTATION.md sections 4 and 5 told readers to write from '@objectstack/core/security'. That subpath is declared in no exports entry, so it is refused outright rather than merely untyped:

REFUSED: ERR_PACKAGE_PATH_NOT_EXPORTED - Package subpath './security' is not defined
         by "exports" in packages/core/package.json
CONTROL: import('@objectstack/core/logger') -> RESOLVED, exports: ObjectLogger,createLogger

The control fires on the same command and scope, so the refusal is a reading and not a broken probe. exports keys re-derived on this tree: exactly ['.', './logger'], no wildcard. files: ['dist','README.md','CHANGELOG.md'].

The repair, and the proof it is true

Both lines now name @objectstack/core. Both classes are exported from the root barrel via export * from './security/index.js' in packages/core/src/index.ts, and the repaired specifier was checked against the built root entry rather than against the source:

surface PluginPermissionManager PluginSandboxRuntime control: PluginSecurityScanner (retired) control: PluginHealthMonitor
dist/index.d.ts (the . types target) declare class @ 1577 declare class @ 1680 0 occurrences present
dist/index.cjs (the . require target) function function undefined function

Both controls fire in the direction they should, so neither column is a vacuous read.

Counted, not eyeballed

Occurrences of the bad specifier over the whole document before editing: 2, at lines 161 and 219 — the card's arithmetic holds and its line numbers are exact, not stale. Firing control on the same command and file: @objectstack/core without the /security tail counted 5. After the edit: 0 bad, and the two repaired lines join the four that already named the root barrel.

Repo-wide, the import-statement shape from '@objectstack/core/security' existed in exactly these 2 places plus one prose row in docs/qa/platform-checklist/FOLLOW-UPS.md that describes this very defect (control on the same command and scope: the same shape on the real ./logger subpath returns 2 files). The other 14 files carrying the string carry it as prose, changelog history, or a @module tag — none is an import instruction. Every from '@objectstack/...' specifier in this document was swept: only two distinct ones exist, @objectstack/core (now 6) and the repaired subpath (now 0).

Two prose notes that this PR makes stale — flagged, deliberately not edited

Both describe the residue as still present, and both stop being true when this lands. They are named here rather than fixed, because neither repair is mechanically pinned and one of them sits in a test file whose suite this diff otherwise does not touch:

  • docs/qa/platform-checklist/FOLLOW-UPS.md — "sections 4 and 5 still tell readers to import … from '@objectstack/core/security' … Deliberately left".
  • packages/core/src/security/security-scanner-retirement.pin.test.ts — a comment reading "PHASE2_IMPLEMENTATION.md sections 4 and 5 still teach it; filed separately". No assertion in that file reads the document, so nothing there goes red.

Contract and publishing

Clause-②: no — re-derived from this diff, not predicted. The diff is one markdown file that reaches no published artefact: untouched text from the document appears in 0 files under packages/core/dist/, while three firing controls on the same command and scope reach 6, 6 and 4 dist files — the third taken from a source comment, which proves sourcemap sourcesContent was inside the compared set and the zero is not a scope artefact. npm pack --dry-run over packages/core lists 16 files; PHASE2_IMPLEMENTATION.md is not among them, while the controls README.md and dist/index.d.ts are. No accept set moves, no exported symbol moves.

No changeset, skip-changeset label instead — measured by that same npm pack reading rather than assumed: this diff publishes nothing from any released package.

Gates

All 36 families derived by node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack (derived from the real change set, not from a hand-written list) were run, 36/36 green, on the final commit 9b833a084 against a clean tree — exit codes captured by redirect-then-read, never through a pipe. The family was not narrowed for being markdown: check:system-context-census and the other anchor/census families were run in full, and separately no PHASE2_IMPLEMENTATION.md:LINE anchor exists anywhere in the tree (0 hits, with a firing control proving 45 files under docs/ do carry PATH:LINE anchors). The diff changes no line count regardless: 375 lines before and after.

Two of the 36 first returned PREREQUISITE NOT MET (exit 3, which is not a red and not a pass); a full pnpm build — 72/72 tasks — was run under the shared verify lock and both were re-run to a real green: check:dual-build-cjs-loads over 103 entries / 66 packages / 619 CJS files, and check:dts-closure over 72 built packages with @objectstack/core in the swept set.

check:published-readme-exports was also run to a real green over its full population — 60 published documents across 79 workspace packages — and confirms the card's account of why no gate saw this: PHASE2_IMPLEMENTATION.md is not one of the 60, because packages/core does not publish it.


Generated by Claude Code

… an undeclared subpath

`packages/core/PHASE2_IMPLEMENTATION.md` sections 4 and 5 told readers to write
`import { … } from '@objectstack/core/security'`. `packages/core/package.json`
declares exactly two `exports` entries, `.` and `./logger`, with no `./security`
and no wildcard, so that specifier resolves for no consumer of the published
package. Measured live at this head:

  ERR_PACKAGE_PATH_NOT_EXPORTED - Package subpath './security' is not defined
  by "exports" in packages/core/package.json

with `@objectstack/core/logger` resolving on the same command as the control.

Both classes are real and both are exported from the ROOT barrel, reached by
`export * from './security/index.js'` in `packages/core/src/index.ts`. So the
symbols exist and only the path is wrong. Both lines now name `@objectstack/core`.
Verified against the built root entry that the repaired specifier is true:
`PluginPermissionManager` and `PluginSandboxRuntime` are both declared in
`dist/index.d.ts` and both load from `dist/index.cjs`, with the retired
`PluginSecurityScanner` absent as the negative control and `PluginHealthMonitor`
present as the positive one.

No contract change: `packages/core/package.json` is untouched. Adding a
`./security` entry would widen the published surface on no evidence of demand
and remains the maintainer's call.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ARYe3yQTQCUFm5qPYNgKaJ
@claude claude Bot added the skip-changeset PR has no user-facing published change; bypasses the changeset gate label Sep 6, 2026
@github-actions

github-actions Bot commented Sep 6, 2026

Copy link
Copy Markdown
Contributor

📓 Docs Drift Check

⚠️ 1 changed file(s) yielded no anchor (packages/core/PHASE2_IMPLEMENTATION.md), so the pages documenting them are NOT COVERED by this run — this is not a clean bill of health for those files. Nothing else in this diff resolved to a documentable surface (no symbol, route or SDK anchor derived from 1 changed package(s)).

What this run could not see
  • 1 changed file(s) yielded no anchor (packages/core/PHASE2_IMPLEMENTATION.md) — pages documenting those are invisible to this run
  • a page that states a rule by its inputs shares no identifier with the emitter that implements the rule, so an emitter-only diff cannot list it — not on this run and not on any run. Measured on fix(driver-sql): emit varchar(maxLength) for a text field a declared index keys on #11430: content/docs/protocol/objectql/types.mdx documents the text-family column mapping by the ObjectQL type names it maps FROM (text / textarea / html) while the diff changed createColumn; it went unlisted, and it was the page that diff falsified, in four places. No shared token exists to detect this on, so a rule your change carries has to be re-read by hand in the pages that restate it.

Coarse fallback — 24 page(s) merely mention a changed package (the pre-#9192 predicate, kept for the deliberately-wide backstop): node scripts/docs-audit/affected-docs.mjs --json 159dbad233cf84476c2c552c2a962bed1d4b5172 → packageMentionDocs.

@claude

claude Bot commented Sep 6, 2026

Copy link
Copy Markdown
Contributor Author

Backlinks for the two things this PR reports but does not change, both filed unassigned and ungraded:


Generated by Claude Code

@zhuangjianguo
zhuangjianguo marked this pull request as ready for review September 6, 2026 07:02
@zhuangjianguo
zhuangjianguo added this pull request to the merge queue Sep 6, 2026
Merged via the queue into main with commit e270ebb Sep 6, 2026
39 checks passed
@zhuangjianguo
zhuangjianguo deleted the claude/issue-15931-phase2-doc-root-barrel-import branch September 6, 2026 07:31
akarma-synetal pushed a commit to akarma-synetal/framework that referenced this pull request Sep 9, 2026
…nding choice (objectstack-ai#16909)

`docs/qa/platform-checklist/FOLLOW-UPS.md` § 7a stated in the present tense that
`PHASE2_IMPLEMENTATION.md` sections 4 and 5 "still tell readers to `import … from
'@objectstack/core/security'`", and that the choice between the two available repairs
was "Deliberately left ... not a lane's call".

Measured on `origin/main`: that specifier occurs 0 times in
`packages/core/PHASE2_IMPLEMENTATION.md` (firing control in the same run:
`@objectstack/core` occurs 7 times in the same file), and both section 4 and section 5
now import from the root barrel. PR objectstack-ai#16205 (commit e270ebb) repointed them.

So both halves were stale: the residue is gone, and the choice was made — the repair
taken is the one that does NOT widen the published contract, which is the fact a
tracking ledger owes its next reader. `packages/core/package.json` still declares
exactly `.` and `./logger`, re-measured here. The "filed separately" half stays and now
names its filing, objectstack-ai#15931.


Claude-Session: https://claude.ai/code/session_01ADLdAs2pVcH17h9tZKWMBg

Co-authored-by: Claude <noreply@anthropic.com>
akarma-synetal pushed a commit to akarma-synetal/framework that referenced this pull request Sep 28, 2026
…ATION.md (objectstack-ai#18615)

Fixes objectstack-ai#18000

Clause-②: no

Both `registerPlugin` examples in
`packages/core/PHASE2_IMPLEMENTATION.md` failed when
copied verbatim: seven keys across them are spellings that
`@objectstack/spec` and
`@objectstack/core` both refuse today. Every replacement spelling comes
from the key's own
`retiredKey()` prescription — none was invented, and no key was deleted
to make a block parse.

## What changed (line numbers on the dispatch base `d93400f42e`)

| line | was | now | why |
|:--|:--|:--|:--|
| 31 | `interval: 30000` | `intervalMs: 30000` | renamed in
`@objectstack/spec` 17 (objectstack-ai#17780) |
| 32 | `timeout: 5000` | `timeoutMs: 5000` | renamed in
`@objectstack/spec` 17 (objectstack-ai#17780) |
| 35 | `autoRestart: true` | deleted | removed in 18 (objectstack-ai#12032, ADR-0049)
— nothing ever restarted a plugin |
| 36 | `maxRestartAttempts: 3` | deleted | removed in 18 (objectstack-ai#12032) — it
capped a restart that never happened |
| 37 | `restartBackoff: 'exponential'` | deleted | removed in 18
(objectstack-ai#12032) — it delayed a restart that never happened |
| 70 | `watchPatterns` | deleted | removed in 18 (objectstack-ai#12428, ADR-0049) — no
watcher was ever constructed |
| 71 | `debounceDelay: 1000` | `debounceDelayMs: 1000` | renamed in
`@objectstack/spec` 17 (objectstack-ai#17780) |

Each deletion is followed by the affordance its own prescription names,
so the block still
answers the question the deleted key was asked: poll `getHealthStatus()`
/ `getHealthReport()`
for the restart trio (the monitor reports, it does not act), and run
your own watcher and call
`hotReload.scheduleReload('my-plugin', reloadFn)` for `watchPatterns`.

## Verification

**R1 — re-taken on the dispatch base, not inherited.** `git grep -c` per
key against that one
file at `d93400f42e`: `autoRestart` 1 · `maxRestartAttempts` 1 ·
`restartBackoff` 1 ·
`watchPatterns` 1 · `interval` 3 · `timeout` 2 · `debounceDelay` 1 —
identical to the dispatch's
reading. Dark control: a fabricated key returns 0 in the same file with
the same instrument.

**R2 — resolved by occurrence, not by count.** `interval` 3 = prose
`:16`
("Configurable health check intervals"), the example `:31`, prose
`:348`. `timeout` 2 = the
example `:32`, prose `:56` ("Graceful shutdown with configurable
timeout") — `shutdownTimeout`
does not match the lower-case spelling, which is why the count is 2 and
not 3. Only `:31` and
`:32` were retired-key occurrences; the three prose lines are untouched.
⚠️ The same bare counts
survive this fix for a *different* reason — `intervalMs` /
`debounceDelayMs` contain the old
words as substrings, and the three deleted keys are now named in the
replacement comments — so
after this PR a bare count is still not a verdict. The verdict
instrument is key POSITION inside
a fenced block: retired keys in key position, before 7, after 0.

**R3 — measured per key; the dispatch had not verified it.** One-shot
probe (throwaway, not
committed) against both refusal channels: the spec tombstone
(`PluginHealthCheckSchema` /
`HotReloadConfigSchema` `safeParse`) and the `@objectstack/core` runtime
door
(`PluginHealthMonitor.registerPlugin` /
`HotReloadManager.registerPlugin`, which call
`assertNoRetiredKeys` before storing anything).

| key | spec refuses | core refuses | prescription carried |
|:--|:--|:--|:--|
| `interval` | yes | yes | rename to `intervalMs` |
| `timeout` | yes | yes | rename to `timeoutMs` |
| `autoRestart` | yes | yes | delete the key |
| `maxRestartAttempts` | yes | yes | delete the key |
| `restartBackoff` | yes | yes | delete the key |
| `watchPatterns` | yes | yes | delete the key |
| `debounceDelay` | yes | yes | rename to `debounceDelayMs` |
| `fabricatedDarkControlKey` (dark control) | **no** | **no** | — |

So all seven are genuinely retired, none is merely "accepted and
ignored", and the instrument
discriminates. Whole-block readings: the health block as it stood
refuses first at `autoRestart`
(`[HealthMonitor] Plugin 'my-plugin': 'autoRestart' was removed from
PluginHealthCheck in
@objectstack/spec 18 …`), the hot-reload block refuses first at
`watchPatterns`; **both repaired
blocks parse clean and register clean on both channels**.

An earlier run of that probe reported `core.refused=true` for *every*
case including the dark
control — a stub logger with no `child()`. The dark control is what
caught it; the readings above
are from the corrected run.

## Gates

> **Corrected after review** (os-dev seat,
`session_01CqmCgU5RGDoJYhHUMVp2af`). This section first
> read **35 run / 4 NOT MEASURED**. That was a real reading, but of the
EARLIER of two runs of the
> same 39 commands — the one taken at `e7da59e475` before a build
existed. The reading for the head
> this PR points at is **37 run / 2 NOT MEASURED**, which is what the
report comment on objectstack-ai#18000
> carries. Numbers below corrected from the recorded exit codes; the
cause is stated rather than
> patched over, because it decides whether the count is stable (it is
not — it is a function of
> build state).

Derived at this head from the real changed path, then reconciled:
`node scripts/pm/dispatch-gates.mjs --repo objectstack-ai/objectstack
--commands` ⇒ 39 families;
`--ran` with a recorded exit code per line ⇒ **39 derived, 37 run, 2 NOT
MEASURED, 0 UNRUN**
(derivation taken from tree `45caf2a451`). Every exit code was written
to disk before anything was
read, one file per command.

NOT MEASURED (both exited **3**, the prerequisite-refusal code, not a
finding):
`check:dual-build-cjs-loads` and `check:lean-entry-closure` — both LOAD
built entry points for
every package that declares an exports map, so the three-package closure
build in this worktree
was not enough to satisfy them. A markdown file that no build reads and
no `files[]` ships cannot
move them; CI runs them on a fully built tree.

**Why the two runs disagree, in one mechanism.** Between them I ran
`pnpm --filter '@objectstack/core^...' build`, which created `dist/` for
exactly three packages
(`spec`, `types`, `metadata-core`). Three families read the filesystem
rather than the diff and
flipped with it, none of them because of anything in this PR:

| family | run 1 (`e7da59e475`, nothing built) | run 2 (`45caf2a451`, 3
packages built) |
|:--|:--|:--|
| `check:dts-closure` | exit 3 — PREREQUISITE NOT MET, no package has a
`dist/` | exit 0 — "3 built package(s) swept — 39/39 declared
declaration file(s) present" |
| `check:sourcemap-no-sources-content` | exit 3 — same refusal | exit 0
— "3 built package(s) swept — 52 map(s), none embed source text" |
| `check:cross-package-test-inputs` | exit 0 | exit 1 — names
`packages/cli/test/init-created-files-summary.e2e.test.ts` walking into
`packages/spec/dist/`, a radius no declared glob reaches |

The first two are recorded as **run** above because on this head they
were measured. The third is
recorded as **exit 0**, the verdict in the tree state CI runs it in:
`lint.yml`'s "Cross-package
test inputs" step has no build ahead of it. Two-leg proof that build
state is the whole cause —
parking `packages/spec/dist` away and re-running gives exit 0 ("29
package(s) read outside
themselves, all declared"); restoring it was verified by file count (216
= 216) and a clean
`git status`. That blind spot — a gate that can only SEE the undeclared
walk radius in a built
tree, run by CI in an unbuilt one — is handed to the PM as a finding of
its own, not repaired here.

⚠️ So neither count is meaningful without its tree state: in CI's
unbuilt lint job those first two
families will refuse with exit 3 again, exactly as run 1 recorded. What
is stable is that no
family's verdict moves with this diff.

Package-scoped, after `pnpm --filter '@objectstack/core^...' build` (the
closure build the first
test run turned out to need — it failed on `Cannot find package
'@objectstack/spec/system'`,
a prerequisite miss, not a red):

- `pnpm --filter @objectstack/core test` — **51 files / 1316 tests
passed**, exit 0
- `pnpm --filter @objectstack/core typecheck` — exit 0 (`tsc --noEmit`,
the examples project, and
  `check:test-typecheck`)

No test in the tree reads this document: `git grep` for
`PHASE2_IMPLEMENTATION` outside the file
itself returns five hits, all of them comments. Repo-wide scans (`pnpm
lint` and the rest) are
CI's.

## Changeset: none, deliberately

`packages/core/package.json` `files` is `['dist', 'README.md',
'CHANGELOG.md']`, and
`packages/core/tsup.config.ts` builds only `src/index.ts` and
`src/logger.ts` — no step copies
markdown into `dist/`. So this document reaches contributors reading the
repo and never an
installer: nothing published moves, which is the `skip-changeset`
criterion. Positive control on
the instrument: `README.md` **is** in that `files` list, so the list
does discriminate.
`Clause-②: no` — no authorable surface widens or narrows here.

## Acceptance notes

Everything below was found by the whole-file sweep the card asked for,
measured, and
**deliberately left out of this diff** under the dispatch's edit
boundary (fix what is stale for
the same reason — a retired spelling inside a copy-pasteable example;
anything stale for another
reason is reported, not edited).

**1. objectstack-ai#16208 — its two sites are NOT in this file, and one of them is
already repaired.** The
dispatch describes objectstack-ai#16208 as an open, held card "against sections 4 and
5 of this same document".
Measured at `d93400f42e`: the two sites objectstack-ai#16208's own body names are in
*other* files, and this
document is only their SUBJECT.

- `packages/core/PHASE2_IMPLEMENTATION.md` contains **zero** occurrences
of `core/security`.
Sections 4 and 5 import from the root barrel (`import {
PluginPermissionManager } from
'@objectstack/core';` at `:161`, `import { PluginSandboxRuntime } from
'@objectstack/core';`
  at `:219`) — PR objectstack-ai#16205's repair, still in place.
- Site 1, `docs/qa/platform-checklist/FOLLOW-UPS.md:196-205`: **already
repaired**. It now reads
"What SURVIVED that removal in the same document, **and how it was
closed**" and describes the
  subpath teaching in the past tense, naming objectstack-ai#15931 and PR objectstack-ai#16205.
- Site 2,
`packages/core/src/security/security-scanner-retirement.pin.test.ts:46-48`:
**still
stale**. The header comment still says "`PHASE2_IMPLEMENTATION.md`
sections 4 and 5 still teach
  it" — false at this base, by the first bullet.

So this PR touches no line objectstack-ai#16208 owns, there is no edit conflict
between the two cards, and
objectstack-ai#16208 is now a one-file, one-comment card. Its state is the PM's call,
not this seat's. Its
restart condition (any commit touching that pin test file since
`5abca1792e`) was NOT evaluated
here: this checkout is shallow, and a windowed history answer from a
truncated history is exactly
the false reading that condition must not be decided on.

**2. `blockedHosts` at `:235` (`:241` after this diff) — different
class, left in place.** The
sandbox example writes `blockedHosts: ['malicious.com']`.
`SandboxConfigSchema`
(`packages/spec/src/kernel/plugin-security-advanced.zod.ts:390-396`)
declares `deniedHosts`, and
`packages/core/src/security/sandbox-runtime.ts:261` reads
`config.network.deniedHosts`. This is
**not** a retired spelling — there is no tombstone, and `blockedHosts`
occurs exactly once in the
entire repository, in this document. Measured consequence: `safeParse`
**succeeds** and the key is
silently dropped (parsed network keys come back as `mode`,
`allowedHosts`, `maxConnections`; no
`deniedHosts` appears). A reader copying that block gets a sandbox that
does not block the host it
names — a silent strip, not the loud refusal the seven keys give.
TypeScript catches it as an
excess property; anything that reaches the parse does not. **Recommend
filing** (class (a): the
example fails when copied, with a named repro) — one-word repair,
`blockedHosts` ⇒ `deniedHosts`.
Dedupe words: `blockedHosts`, `deniedHosts`, `SandboxConfigSchema`,
`PHASE2_IMPLEMENTATION`,
`sandbox example`.

**3. `kernel.logger` at `:319-323` (`:325-329` after this diff) —
different class, left in
place.** The Integration block does `new
PluginHealthMonitor(kernel.logger)` for five classes.
`ObjectKernel` declares `private logger: ObjectLogger`
(`packages/core/src/kernel.ts:107`) and
`ObjectKernelBase` declares `protected logger: Logger`
(`packages/core/src/kernel-base.ts:36`) — no public getter. Copying that
block into TypeScript
does not compile. Not a key spelling and not a retired key, so out of
this diff's boundary.
Dedupe words: `kernel.logger`, `private logger`, `ObjectKernel`,
`Integration with Kernel`,
`PHASE2_IMPLEMENTATION`.

**4. Two prose claims falsified by the same objectstack-ai#12032 retirement — left in
place, and the tension is
deliberate.** `:13` ("real-time health checking and **auto-recovery**")
and `:18`
("**Auto-restart** with backoff strategies (fixed, linear,
exponential)") advertise the capability
whose three keys this PR deletes. They are true of no runtime:
`packages/core/src/health-monitor.ts` states "It REPORTS; it does not
act on what it finds", and
the tombstone records that `attemptRestart` called `destroy()` and
stopped. They are prose, not a
retired spelling inside an example, so the boundary keeps them out of
this diff — which does leave
the document advertising at `:18` a capability its example no longer
configures. Flagged rather
than smuggled: this is Prime Directive objectstack-ai#10's "advertise a capability the
runtime doesn't deliver",
worth a card of its own. Dedupe words: `auto-recovery`, `Auto-restart
with backoff`,
`PHASE2_IMPLEMENTATION`, `objectstack-ai#12032`, `health monitor features`.

**5. Observations, not filings.** `:373` links
`[MICROKERNEL_IMPROVEMENT_PLAN.md](../../MICROKERNEL_IMPROVEMENT_PLAN.md)`
and no such file exists at the repo root (`ARCHITECTURE.md`, the sibling
link, does). `:343` says
to run tests with `npm test` in a pnpm workspace. `:55` lists "File
watching integration points"
as a hot-reload feature, which after objectstack-ai#12428 is true only of
`scheduleReload`.

**6. Same-name tombstones on other defs are NOT defects here.**
Cross-checking every key in every
fenced block against the spelling KEY-colon-`retiredKey(` repo-wide
turns up `enabled`, `actions`, `fields`,
`mode`, and `interval` / `timeout` again — all on unrelated schemas
(`metadata-loader.zod.ts`,
`manifest.zod.ts`, `ui/component.zod.ts`, `api/router.zod.ts`, …). The
keys in this document are
judged against the def they are actually passed to, so those collisions
are noise. Within the four
schemas these examples really use, the tombstoned set is exactly the
seven repaired above.


---
_Generated by [Claude Code](https://claude.ai/code)_

Co-authored-by: Claude <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation size/xs skip-changeset PR has no user-facing published change; bypasses the changeset gate

Projects

None yet

Development

Successfully merging this pull request may close these issues.

core: PHASE2_IMPLEMENTATION.md teaches @objectstack/core/security, a subpath the package exports in no entry

2 participants