Skip to content
Merged
16 changes: 16 additions & 0 deletions .llm/harness/debt/arch-debt.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,22 @@ Seeded from `docs/architecture/doctrine/10-codebase-verdict-and-handoff.md` on 2
track packages with `Refactor`, `Restructure`, or `Rewrite` doctrine verdicts. `Keep` and `Defer`
verdicts are not seeded here.

## packages/cli — PLUGIN-USERLAND-SOURCE-COPY

- **Reason:** Maintainer/local `plugin add` copied full first-party plugin source into generated
userland by default, and the public/prod path needed a regression lock proving it never copies
source.
- **Owner:** CLI plugin copy flag gate.
- **Target:** PR #133.
- **Linked plan:** `.llm/tmp/run/fix-cli-plugin-copy-flag-gate--copy-gate/plan.md`
- **Created:** 2026-06-26
- **Status:** closed 2026-06-26 — local maintainer copy is now explicitly flag-gated with
`--no-copy-source` as the opt-out while preserving runtime e2e's default first-party behavior;
public `netscript plugin add` remains hardcoded to JSR stub generation and has a no-copy
regression test.
- **Gate:** plugin-add unit tests, `packages/cli` publish dry-run, `scaffold.plugins`, and
`scaffold.runtime`.

## packages/runtime-config — doctrine verdict Refactor

- **Reason:** Split single-file `mod.ts`; add subpaths if exports grow.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# Commits — fix-cli-plugin-copy-flag-gate--copy-gate

- 983b299a: fix(cli): gate local plugin source copy opt-out
- ae08da94: test(cli): lock public plugin add no-copy path
- a2f68d9c: chore(harness): record plugin copy e2e closure
- 1174f3c0: chore(harness): update plugin copy commit ledger
- 863bd591: chore(harness): clarify runtime aspire evidence
- 49901e2b: merge origin/main into fix/cli-plugin-copy-flag-gate (resolve add-plugin_test.ts)
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# Context Pack — fix-cli-plugin-copy-flag-gate--copy-gate

## Status

Implementation complete through S3 on branch `fix/cli-plugin-copy-flag-gate`.

## Decisions

- D1 was flipped after drift: maintainer/local official source copy remains default-on.
- `--no-copy-source` is the single opt-out flag for thin local-import stubs.
- Public/prod `netscript plugin add` remains JSR-only and does not expose copy-mode flags.

## Landed Slices

- S1: local `--no-copy-source` plumbing and gate.
- S2: public prod no-copy regression lock and import-boundary test.
- S3: e2e confirmation and `PLUGIN-USERLAND-SOURCE-COPY` debt closure.

## Validation Summary

- Scoped package check: pass, 0 findings.
- Plugin-add units: pass, 2 suites / 8 steps.
- `packages/cli` publish dry-run: pass with existing dynamic-import warnings.
- `scaffold.plugins`: pass, 11 passed / 0 failed.
- `scaffold.runtime`: first attempt failed `behavior.workers-executions` after AppHost instability;
clean rerun passed, 47 passed / 0 failed.

## PR

- PR: https://github.com/rickylabs/netscript/pull/133
- Draft remains appropriate until final evaluator pass.
67 changes: 67 additions & 0 deletions .llm/tmp/run/fix-cli-plugin-copy-flag-gate--copy-gate/drift.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
# Drift — fix-cli-plugin-copy-flag-gate--copy-gate

## 2026-06-26 — significant — default-off local copy conflicts with runtime e2e expectations

While preparing S1, the implementation agent found downstream gate coupling that makes the locked
default-off decision unsafe to apply silently.

Evidence:

- `packages/cli/e2e/src/application/gates/scaffold/runtime-gates.ts` waits for and calls the full
first-party worker/saga/trigger/auth HTTP surfaces, including `/api/v1/workers/jobs`,
`/api/v1/workers/tasks`, `/api/v1/sagas/sagas`, `/api/v1/webhooks/inbound/generic`, and auth
session routes.
- `packages/cli/e2e/src/application/gates/scaffold/database-gates.ts` type-checks generated
workspaces including `./workers`, `./sagas`, and `./triggers`.
- `packages/cli/src/kernel/assets/registry-generator-fixture.ts` discovers and reads root copied
official plugin sample/runtime directories such as `workers/jobs`, `sagas`, and `triggers`.
- The thin-stub branch in `packages/cli/src/kernel/adapters/plugin/scaffolder.ts` generates only a
starter `plugins/<name>/` workspace with generic router/service/sample stubs. It does not create
the root `workers`, `sagas`, or `triggers` implementation workspaces and does not provide the full
behavior endpoints asserted by `scaffold.runtime`.

Impact:

The plan's S3 says to update `scaffold.plugins`/`scaffold.runtime` expectations while still running
the full runtime suite green. Under the current scaffold implementation, simply flipping local
official plugin add to default thin stubs would make the runtime suite stop validating the actual
first-party plugin behavior it currently asserts.

Required decision before implementation:

1. Keep copy default-on for maintainer/runtime e2e and add `--no-copy-source` as the opt-out, or
2. Keep D1 default-off but also implement a replacement runtime reader/scaffold path that preserves
the full first-party behavior gates without vendoring source.

No implementation files were changed before this drift was recorded.

## 2026-06-26 — resolution — D1 flipped to default-on with `--no-copy-source`

Supervisor decision after reviewing the drift: flip plan decision D1. Maintainer/local official
plugin source copy remains default-on, preserving today's vendored-source behavior and keeping
`scaffold.plugins` / `scaffold.runtime` validating the real first-party plugin implementations. The
new flag is a single opt-out, `--no-copy-source`, with help text "Generate a thin local-import stub
instead of copying the official plugin source tree."

Rationale:

- Runtime-gate coupling makes default-off a separate, larger reader-rework program.
- The user's requirement was that maintainer copy be optional and behind a flag; an opt-out flag
satisfies that requirement without changing the maintainer default.
- The user's primary prod/JSR no-copy guarantee remains satisfied by leaving the public path
hardcoded to `importMode: 'jsr'` and adding a regression lock.
- Default-off plus a replacement runtime reader/scaffold path can be requested later as its own
scoped task.

## 2026-06-26 — minor — parallel scaffold runtime run contended on Aspire control-plane port

During S3 validation, the first `scaffold.runtime` attempt reached the workers behavior gates and
then failed `behavior.workers-executions` with `Connection refused` after the generated AppHost was
no longer running. A follow-up rerun with a unique suite name also hit
`https://127.0.0.1:18891` already in use while another scaffold runtime suite was active.

The user noted this may have come from a parallel thread using `aspire stop` and asked to check the
CLI docs / parallel mode. Aspire and CLI help confirmed the e2e runtime path already launches
Aspire with `--isolated`; that isolates generated resources, but Aspire's control-plane port can
still collide when another suite is active. After the parallel run released `18891`, a raw
`scaffold.runtime` rerun from the WSL ext4 worktree passed with `passed=47 failed=0`.
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
use harness

# Codex Implementation Brief — gate maintainer plugin-source copy behind a flag + lock prod no-copy

You are the daemon-attached WSL Codex implementation agent for run
`fix-cli-plugin-copy-flag-gate--copy-gate`, branch `fix/cli-plugin-copy-flag-gate`
(off `origin/main` @ alpha.4). The supervisor (Claude) authored `research.md` and `plan.md` in
`.llm/tmp/run/fix-cli-plugin-copy-flag-gate--copy-gate/`. PLAN-EVAL is waived (user self-reviews the
PR). Read `research.md` and `plan.md` first — they are the contract and carry the exact file:line
anchors. Do not restate; implement.

## SKILL

Read and apply, in order, before any code:
- `.agents/skills/netscript-harness/SKILL.md` — run loop, commit-per-slice, artifacts.
- `.agents/skills/netscript-cli/SKILL.md` — CLI command/option plumbing, scaffold internals, local vs
public feature split, plugin add flow.
- `.agents/skills/netscript-doctrine/SKILL.md` — public-surface gates; this is a behavior/flag change,
not a surface change — keep it that way.
- `.agents/skills/netscript-tools/SKILL.md` — scoped check/lint/fmt wrappers, raw git verification.
- `.agents/skills/netscript-deno-toolchain/SKILL.md` — `deno doc`, `publish:dry-run`, lock hygiene.
- `.agents/skills/netscript-pr/SKILL.md` — branch/PR/comment conventions.
- `.agents/skills/codex-wsl-remote/SKILL.md` — native worktree rule; run full e2e from this WSL ext4
worktree, never `/mnt/c`.

## The shape (grounded in research.md)

- PUBLIC `netscript plugin add` = prod/JSR: hardcoded `importMode:'jsr'` (`render-plugin.ts:41,61,89`)
→ `PluginScaffolder.scaffold()` thin stubs only, never `copyPlugin()`. **Already correct — only add
a regression lock.**
- LOCAL `netscript-dev plugin add` = maintainer: `add-local-plugin.ts:189` decides, `:254` calls
`copyPlugin(...)` → `copy-official-plugin.ts:94` → `plugin-file-collector.ts:50` full-source tree
copy into userland `plugins/<dir>/`. **Unconditional today — gate it behind a flag.**

## Non-negotiables

1. **Flag-gate the local copy.** Add `--copy-source` (boolean, default `false`) + explicit
`--no-copy-source` to the **local** add command (`add-local-plugin-command.ts`, after `--samples`).
Thread it through the input/options/dependencies into `add-local-plugin.ts`. Gate the copy decision
(`:189`) and the `copyPlugin(...)` call (`:254`) on it.
2. **Default off = thin-stub local scaffold.** When the flag is false, fall through to the existing
`PluginScaffolder.scaffold()` branch (the same one already used for non-canonical plugin names) but
keep `importMode:'local'` so relative local imports are still produced. Contributors get a runnable
local plugin without a vendored source tree. `--copy-source` restores today's vendored behavior
byte-for-byte.
3. **Prod can never copy.** Do NOT change the public path's `importMode:'jsr'`. Add a regression test
asserting the public `plugin add` produces only the JSR-stub shape and copies NO plugin source
(no verbatim source-only files from the canonical plugin under the scaffolded `plugins/<name>/`).
If feasible, also make `copyPlugin`/`copyOfficialPlugin` structurally unreachable from the public
feature (it already is — assert via a test/import-boundary, do not add a runtime branch).
4. **Public default output byte-identical.** Public path never copied; do not perturb its output.
5. **No public surface/type change.** This is internal flag plumbing; `publish:dry-run` must show no
surface change for `@netscript/cli`.

## Commit slices (commit + push + PR comment + append commits.md after EACH)

- **S1 — flag plumbing + gate.** Add the `--copy-source`/`--no-copy-source` option; thread through
local add input/options/deps; gate `:189`/`:254`; default-off path uses thin-stub local scaffold.
Update `add-local-plugin_test.ts` into two cases (default no-copy local-imports; `--copy-source`
preserves vendored copy). Scoped check/lint/fmt + unit.
- **S2 — prod no-copy regression lock.** Add the public-path test that asserts JSR-stub shape and no
source copy; assert the copy helpers are not reachable from the public command. `publish:dry-run`.
- **S3 — e2e + debt close.** Update `scaffold.plugins`/`scaffold.runtime` gate expectations to the
default-off shape; run both suites; record evidence. Close the `PLUGIN-USERLAND-SOURCE-COPY` debt
entry in `arch-debt.md` (add it then mark resolved in the PR).

## Validation (record evidence in worklog.md per slice; full list in plan.md)

- `run-deno-check.ts --root packages/cli --ext ts,tsx` (`--unstable-kv`)
- scoped lint + fmt (ts,tsx only)
- `deno task test` for the plugin-add units (public + local, both flag states)
- `deno task publish:dry-run` cli (no surface change)
- `deno task e2e:cli run scaffold.plugins --cleanup --format pretty`
- `deno task e2e:cli run scaffold.runtime --cleanup --format pretty` (MERGE BAR — run from this WSL
ext4 worktree, not `/mnt/c`)

## Boundaries

- Do NOT couple in the asset-read import-attribute slice (`fix/cli-jsr-asset-embedding`, #124).
- Do NOT change the public/JSR path's behavior — only add the lock.
- If you find a downstream step that READS the vendored `plugins/<dir>/` files (so default-off breaks
it), STOP, log to `drift.md`, and either keep copy default-on (flip the documented open decision in
plan.md D1) or fix the reader — surface it for the user, do not silently pick.
- Lock hygiene: do not churn root `deno.lock` without need; no `deno cache --reload`.
- Push slice branch via explicit refspec
`git push origin HEAD:refs/heads/fix/cli-plugin-copy-flag-gate`.
- Stage only relevant files by explicit path; never `git add -A`.
Loading
Loading