VERDICT: FINDINGS
Final adversarial review completed against draft PR #280 head 3a1fc1eae2572f2c240ba20e4848318e581595d3. The principal implementation is correctly wired and its normal, duplicate-version, pnpm, valid-workspace-symlink, transport, and runtime-log paths are proven. One fail-closed edge remains incorrect and prevents comprehensive satisfaction.
packages/deploy/src/bundle.ts asks esbuild to bundle the persona handler and externalizes only Node builtins plus @agentworkforce/runtime and @agentworkforce/runtime/raw. Consequently, third-party and transitive package source that reaches the output is frozen into agent.bundle.mjs. The staged package.json, however, is built independently from esbuild's resolved graph and contains only the separately installed external runtime version. Neither BundleResult, the generated runner, sandbox upload, cloud request, runner.started, nor the deployments-list JSON surface carries an inventory of the package code actually inlined into the artifact.
This creates two distinct facts that the baseline conflates or omits:
dependencies.@agentworkforce/runtimedescribes code intentionally external toagent.bundle.mjsand installed at execution time.- Bundled-package attribution must describe package-owned inputs that contributed bytes to the actual esbuild output, including transitives and possibly multiple versions of the same package name.
An author dependency range or the repository lockfile alone cannot prove either fact for an already-staged artifact. Restarting the runner cannot change inlined bytes, and publishing a newer upstream dependency cannot propagate without a new resolution and bundle.
- Requested/imported is not actually bundled. Metafile inputs that are fully tree-shaken, external imports, or packages used only by the external runtime must not be reported as inlined code. Evidence should be tied to the output contribution (
bytesInOutput > 0or an equally strong graph fact), not topackage.jsondeclarations. - Direct is not complete. The manifest must include transitive package inputs that contribute code, not only the persona's direct dependencies or a hard-coded
@relayfile/*allowlist. - One name does not imply one version. Nested dependency graphs can bundle two versions of the same package. A name-to-single-version object risks false attribution or last-write-wins nondeterminism; the schema and logs must preserve distinct
(name, version)identities. - Filesystem path is not operator evidence. pnpm's content-addressed
.pnpmlayout, symlinked workspaces, nestednode_modules, scoped packages, conditional exports, and realpath-vs-symlink paths must resolve to the package manifest that owns each bundled input. Absolute source paths, pnpm store paths, user names, temp roots, and symlink targets must never enter generated metadata or logs. - Nearest manifest is not automatically the owner. An upward package.json search must stop at defensible package boundaries and verify a valid name/version; it must not accidentally attribute persona-local source to the workspace root, a parent application, or a neighboring package.
- Workspace version can overclaim provenance. A workspace package's
package.jsonversion may label unpublished or locally modified source. If workspace packages are inventoried, the field must remain explicitly a resolved package version, not a claim that the bytes equal the published npm artifact. - Missing metadata must not become a lie. Package-owned bundled code whose manifest is absent, unreadable, invalid, or has no name/version needs a deterministic, tested policy (fail closed or explicit unresolved evidence). Silently omitting it while describing the list as complete is unsafe.
- Object traversal order is not a contract. Manifest and log ordering must be explicitly sorted and stable across identical builds, platforms, symlink layouts, and repeated runs.
- An auxiliary file can go stale or disappear. The stager deliberately leaves auxiliary files from prior runs untouched; sandbox upload currently names exactly four files; cloud upload serializes only runner, agent, and package JSON. Any sibling manifest must be overwritten, represented in
BundleResult, uploaded in every mode, and protected from stale residue. Embedding metadata in the already-uploaded package JSON avoids some, but not all, stale-artifact risks. - Runtime logging must describe this artifact.
runner.startedmust receive immutable metadata from the staged artifact/runner, not re-resolve the current filesystem or read the author project at cold start. It must remain structured, deterministic, bounded, and free of paths, environment values, tokens, source-map contents, or other secrets. - Presence in a staged file is not fleet queryability.
--bundle-outmakes local package JSON queryable, but deployed fleet queryability requires cloud persistence/response wiring or another supported JSON surface. If cloud changes are outside this repository/iteration, that limitation must be explicit rather than implied complete. - Unit mocks can erase the defect. Tests that replace
BundleStager, feed a hand-written package JSON, or assert only a mocked cloud POST do not prove the real esbuild graph. Required proof must stage a real bundle from a realistic installed/package layout, inspect the emitted JS and metadata together, exercise transitive and workspace/symlink cases, and show the runtime's actualrunner.startedrecord.
- Review base and HEAD before implementation:
533b9669bcad1f06e31c8fa6644f7228e12fc510;git diff origin/main...HEADwas empty. - Issue #279 states that a deployed artifact inlines
@relayfile/relay-helpersand@relayfile/adapter-core, while generated package JSON pins only@agentworkforce/runtime. - Baseline
packages/deploy/src/bundle.tscalls esbuild withoutmetafile: true, writes onlyagent.bundle.mjs,runner.mjs,persona.json, andpackage.json, and resolves only the external runtime version. - Baseline
packages/runtime/src/runner.tslogsrunner.startedwith persona, workspace, schedules, triggers, and integrations only. - Baseline sandbox upload enumerates exactly those four staged files. Baseline cloud upload includes runner source, agent source, and parsed package JSON; deployments-list parsing exposes no bundle inventory.
- Lockfile evidence illustrates why graph attribution matters: the workspace contains both
@relayfile/adapter-core@0.5.1and transitive@relayfile/adapter-core@0.5.6; a single version inferred from a direct declaration would be false for some bundle graphs.
The main path is end-to-end wired:
- esbuild emits a metafile and the stager selects only input entries with
bytesInOutput > 0foragent.bundle.mjs. - Valid package owners become a deterministic array of distinct
(name, version)pairs. Deduplication uses the full pair, so@relayfile/adapter-core@0.5.1and@relayfile/adapter-core@0.5.6coexist. - The generated
package.jsonretains the exact external@agentworkforce/runtimepin and embeds the path-freebundleManifestas the sole persisted source of truth. - The generated runner reads that exact object from its adjacent package JSON and passes it to
startRunner;runner.startedemits it unchanged. - Sandbox transport uploads the package JSON and cloud transport places the parsed package JSON under
bundle.packageJson. Local operators can query a staged artifact withjq .bundleManifest <bundle-dir>/package.json.
Fleet-wide deployments list --json queryability still depends on cloud persistence/response work and is explicitly not claimed. That limitation is acceptable under the iteration's “artifact or supported JSON surface” acceptance wording, but it remains an operational follow-up.
The missing-metadata workspace-symlink path breaks the otherwise correct build step: logical dependency identity is erased by realpath() before ownership is determined, allowing bundled dependency bytes to be silently omitted from the manifest.
- Severity: HIGH
- File:
packages/deploy/src/bundle.ts(findPackageOwnership,findPackageOwnershipFromDirectory, and theentryOwnerexclusion inbuildBundleManifest) - Issue: Ownership discovery immediately realpaths each esbuild input. For a logical
node_modules/missing-workspacesymlink whose target is inside the author project and lackspackage.json, the search walks from the real target into the author project's package manifest. That owner equalsentryOwner, so the contributing dependency input is skipped. The bundle contains the dependency bytes whilebundleManifest.packagesis empty. A target beneath a different ancestor package can analogously be falsely attributed to that ancestor. This contradicts the implementation report's fail-closed claim and acceptance focus #5. - Deterministic reproduction: Create an author project with
{name:"author-project",version:"1.0.0"}, symlinknode_modules/missing-workspacetopackages/missing-workspace, omit a package manifest at the target, import its exported marker from the agent, and stage with the real builtbundleStager. Observed output at pushed head:{"stage":"SUCCEEDED","manifest":{"schemaVersion":1,"packages":[]},"bundleContainsMarker":true,"leaksPath":false}. - Exact fix: Preserve the logical esbuild input path alongside its realpath. Detect and retain the logical
node_modulespackage boundary before dereferencing symlinks; require that dependency boundary/target to supply its own valid package name and version, and never walk above that package root into the consumer or an unrelated ancestor. Continue using real roots for deduplication/cache identity and keep all failure messages path-free. - Required test: Add a real
bundleStager/esbuild regression with an author-project package manifest and anode_modulesworkspace symlink to an in-project target that has code but nopackage.json. Assert staging rejects, the error contains a stable inferred dependency label but no temp/absolute path, and the same fixture succeeds with the correct(name, version)only after a valid target manifest is added. Add the analogous protection against attribution to a different valid ancestor package.
- Exact review target: local
HEAD, branch remote, and PR #280headRefOidall resolved to3a1fc1eae2572f2c240ba20e4848318e581595d3; base was533b9669bcad1f06e31c8fa6644f7228e12fc510. - Scope diff contains only the two iteration artifacts, README/changelogs, deploy bundle/tests/transport tests, and runtime runner/tests. The reviewer artifact is the only additional untracked file.
pnpm --filter @agentworkforce/deploy test: 230 passed, 0 failed. These include real esbuild fixtures for output-only attribution, unused declaration exclusion, deterministic sorting, valid workspace and pnpm symlinks, versionless metadata rejection, and simultaneous@relayfile/adapter-core@0.5.1plus@0.5.6representation.node --test packages/runtime/dist/runner.test.js: 13 passed, 0 failed.git diff --check: passed.- Real repository graph probe using
packages/delivery/src/index.ts: emitted@relayfile/adapter-core@0.5.6,@relayfile/adapter-linear@0.4.6,@relayfile/relay-helpers@0.4.7, and@relayfile/sdk@0.7.40; retained runtime4.1.26; left no external@relayfile/*imports; serialized no working-directory path. - Actual generated-runner probe: staged a real
shadow-probe@7.8.9package, executed generatedrunner.mjs, observed exit 0, and confirmed byte-for-byte JSON parity betweenpackage.json.bundleManifestand the structuredrunner.started.bundleManifest; stdout/artifact metadata contained no temp root. - Adversarial missing-metadata workspace-symlink probe reproduced WF279-SHADOW-001 exactly as documented above.
- PR #280 remained draft. CI
checkwas in progress at review time. CodeRabbit's draft-skip notice is informational only and provides no substantive review evidence.
workforce#279: draft PR #280 delivered at3a1fc1e; main wiring is complete, but WF279-SHADOW-001 requires repair and regression proof.relayfile-adapters#248: deferred dependency-only context; no changes authorized in this iteration.cloud#2678: deferred; no changes authorized in this iteration.
- Until WF279-SHADOW-001 is fixed, a workspace-linked dependency with absent metadata can ship bundled bytes with no corresponding manifest entry or can inherit an unrelated ancestor identity.
- The manifest records a workspace package's declared resolved version, not proof that locally modified bytes match the published artifact; README correctly states this limitation.
- Fleet-wide version queries remain unavailable until the cloud service persists and returns
bundle.packageJson.bundleManifest; this workforce iteration provides artifact and startup-log queryability only. - CI completion was not yet available at the review timestamp and must be rechecked before any readiness decision.