Commit dd13efe
feat(inspect+dogfood): broader inspect --json + canonical bundle lock-down (#104)
* feat(inspect+dogfood): broader inspect --json + canonical bundle lock-down
Strand A — `inspect --json` extensions (additive over the schema-locked
envelope):
- New optional `host: { cliVersion, rpcSocketPath }` on `InspectResult`,
populated only in live-host mode. Answers "is the running host the
version I think it is?" and "which socket is `inspect` talking to when
`--home` is non-default?"
- New optional `rendererRuntime.{profile, booted, bootInFlight}`,
populated only in live-host mode. Answers "has the renderer actually
attached?" and "is a boot or restart currently in flight?" — the most
common "screenshot hung" report turns out to be pre-boot.
- New optional `eventLogBytes` populated in both live and offline-replay
modes via a new `statEventLogBytes()` sibling to
`countEventLogEntries()`. Answers "does this session's event log look
truncated?" from the persisted bundle.
- `HostRendererManager` gains read-only `isBooted()`, `isBootInFlight()`,
and `getCurrentProfileName()` getters wrapping existing private state.
- `loadPackageMetadata()` extracted from `cli/commands/version.ts` to
`src/util/packageMetadata.ts` so the host can reuse it without
layering inverted into `cli/`.
Strand B — canonical proof-bundle lock-down:
- New `CanonicalBundleManifestSchema` in
`src/tools/bundleManifestSchema.ts` requires `sha256` and `bytes` on
every artifact entry — that's the drift detector.
- `src/tools/validate-bundle.ts` gains `--profile canonical` with eight
rules (manifest exists + parses, artifacts present + bytes match +
sha256 match, commands.sh/reproduce.sh present, command-status.tsv
clean when `result: pass`, notes.md or README.md present) plus a
`checkCatalogParity()` helper that confirms every `dogfood/<name>/`
path in `dogfood/CATALOG.md` resolves to a real directory.
- New `src/tools/validate-canonical-bundles.ts` validates the four
bundles named in `RELEASE.md` in parallel
(`20260326-week9-release-readiness`, `20260325-week8-contract-locks`,
`run-command`, `agent-uses-agent-tty`) plus the CATALOG parity check.
- Two missing canonical manifests authored
(`dogfood/run-command/manifest.json`,
`dogfood/agent-uses-agent-tty/manifest.json`). The two existing
manifests (`week9-release-readiness`, `week8-contract-locks`) gain
`sha256` + `bytes` per artifact — documentation normalization of
already-present evidence, not a rewrite.
- New `scripts/seed-canonical-manifest.mjs` streaming-hash helper for
authoring future canonical manifests.
- Wired into `mise run validate-bundles`, `npm run
validate-bundle:canonical`, and a new step in the `linux-static` CI
job.
Change-Id: I5277df8a9f2e2d917bbb87b40b1d88cfe3c99be9
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Signed-off-by: Thomas Kosiewski <tk@coder.com>
* test: relax live-host rendererRuntime assertions to objectContaining
The new optional `booted` and `bootInFlight` fields on
`rendererRuntime` now appear in live-host inspect envelopes, which
broke two strict `.toEqual` assertions in the integration and e2e
suites. Relax both to `expect.objectContaining` so the contract on the
three pre-existing fields stays pinned while the additive extensions
pass through.
The offline-replay assertion in `hello-prompt.test.ts` stays strict
because offline-replay mode deliberately suppresses the renderer
extensions.
Change-Id: If3adc54ea74e94e986ebefc653e2f09f1fb64755
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Signed-off-by: Thomas Kosiewski <tk@coder.com>
* test(validate-bundle): unit coverage for canonical profile + statEventLogBytes
Addresses Netero P2 [DEREM-1] and P3 [DEREM-2].
DEREM-1: `runCanonicalChecks`, `checkCatalogParity`, and the
`CanonicalBundleManifestSchema` now have branch coverage in
`test/unit/tools/validate-bundle.test.ts`:
- happy path with notes.md + commands.sh
- alternate notes (README.md) and alternate script (reproduce.sh)
- manifest.json missing
- manifest.json not valid JSON
- manifest.json fails CanonicalBundleManifestSchema
- artifact missing on disk
- artifact byte size disagrees with manifest
- artifact sha256 disagrees with manifest
- neither commands.sh nor reproduce.sh present
- neither notes.md nor README.md present
- command-status.tsv absent on pass (skip)
- command-status.tsv with failing row on pass (fail)
- command-status.tsv with no header on pass (fail)
- checkCatalogParity: all resolve, missing dir, glob-skip,
deduplication
DEREM-2: `statEventLogBytes` gets dedicated tests in
`test/unit/host/eventLog.test.ts` covering missing-file
(ENOENT→undefined), empty file, populated file, empty-path
rejection, and non-ENOENT rethrow (forced via ENOTDIR by stat'ing
through a regular file).
Change-Id: I0b903aa4542e0fc320496a5ce4043fc1dc906e7c
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Signed-off-by: Thomas Kosiewski <tk@coder.com>
* fix(validate-bundle+host): round-2 review fixes
Addresses Netero/Hisoka/Mafuuu/Meruem/Bisky/Robin/Leorio/Gon/Pariston
findings in DEREM-4 through DEREM-19.
DEREM-4: artifact paths from manifest.json are now containment-checked
against the bundle root via `isPathWithinBundle`; entries that resolve
outside (e.g. `../../.git/config`) push into a new `escapedArtifacts`
bucket that fails `artifacts-present`.
DEREM-5: `artifacts-bytes-match` and `artifacts-sha256-match` now
report the count of artifacts they actually evaluated, e.g. "7 of 10
artifact sha256 digests match the manifest (3 skipped)." Skipped
artifacts (missing, escaped, stat errors, size mismatch) no longer
inflate the "all match" message.
DEREM-6: `isBootInFlight` now has a test that observes the `true`
state during an awaited boot via `createDeferred` and
`bootImplementation`, mirroring the lazily-boots pattern already used
in the file. The previous test only asserted `false` three times.
DEREM-7: `isDirectExecution` extracted to `src/util/isDirectExecution.ts`
with an `importMetaUrl: string` parameter. The three identical copies
in `validate-bundle.ts`, `review-bundle.ts`, and
`validate-canonical-bundles.ts` now import from the util.
DEREM-8: `manifest-exists` byte-count message now reports
`Buffer.byteLength(manifestText, 'utf8')` instead of
`manifestText.length` (UTF-16 code units mislabeled as "bytes").
DEREM-9: stat() errors on canonical artifacts and CATALOG entries are
now distinguished: ENOENT continues to bucket into "missing"; other
errors (EACCES, EIO) propagate or bucket into a new `statErrors`
list so operators see the real cause instead of "Missing: X" when X
exists but is unreadable.
DEREM-10: `validateCanonicalBundles` now wraps each per-bundle
`validateBundle` call in try/catch and synthesizes a
`validation-error` check on crash, matching `runValidateBundleCli`.
A single bundle crash no longer swallows diagnostics from the other
three. Catalog parity also wraps in try/catch.
DEREM-11: host startup no longer crashes if `package.json` is
unreadable. `loadPackageMetadata` is now lazy and memoized per host
process with a `.catch(() => undefined)` fallback; the inspect RPC
omits `cliVersion` instead of throwing, matching its optional schema
contract.
DEREM-12: command-status.tsv "fail" scan now locates the status
column by header name (`status`, case-insensitive) with a column-1
fallback for legacy layouts; cells containing "fail" in other
columns (e.g. a notes column) no longer trigger false positives.
DEREM-13: new test for non-`pass` canonical bundles confirming that
the `command-status-tsv-clean-if-pass` check is absent (not just
passing).
DEREM-14: `commands-sh-exists` check renamed to
`reproduce-script-exists` (and the local `hasCommandsSh` →
`hasReproduceScript`) to match the rule that either `commands.sh` or
`reproduce.sh` satisfies it.
DEREM-15: `InspectHostInfo` (command-first) renamed to `HostInfo` to
match `HostInspectResult`'s entity-first pattern. The exported public
field in `InspectResult` is already `host`, so this also tightens
type-to-field alignment.
DEREM-18, DEREM-19: doc comments added to `statEventLogBytes` and
`bundleManifestSchema.ts` documenting the ENOENT contract and the
canonical-bundle scope respectively.
DEREM-22: the new inspect-extension tests now assert on the human-
readable `lines` output (Host CLI Version, RPC Socket, Event Log
Bytes, renderer extras suffix), not just the JSON `result`.
Change-Id: I81fc1bd41f4552259598b9ebcb04877e1c38cf40
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Signed-off-by: Thomas Kosiewski <tk@coder.com>
* fix(round-3): decouple host fields, tighten canonical checks, dedupe
DEREM-24: HostInfo.cliVersion is now optional. `rpcSocketPath` (which
the host always knows) surfaces independently when `loadPackageMetadata`
fails. Human output omits the Host CLI Version line in that case rather
than dropping the entire `host` block.
DEREM-25: artifacts-bytes-match and artifacts-sha256-match are no longer
vacuously `ok: true` when every artifact was skipped. Both checks now
require a positive `bytesCheckedCount`/`hashedCount` and report
"No artifacts available to verify" with the skipped count when zero
were evaluated.
DEREM-26: hashFile replaced with a three-line `pipeline(createReadStream,
hash)` from `node:stream/promises`. The Node 24+ runtime handles error
propagation and stream destruction structurally, so the manual Promise
wrapper is unnecessary.
DEREM-27: hasErrorCode extracted to `src/util/hasErrorCode.ts`. The
three in-scope copies in `src/cli/commands/gc.ts`, `src/host/lifecycle.ts`,
and `src/tools/validate-bundle.ts` now import from the util; the private
`NodeError` shim in each file is removed.
DEREM-28: InspectResultSchema gains inline comments documenting when
`host` and `eventLogBytes` are populated; RendererRuntimeSummarySchema
documents the live-mode-only nature of `profile`, `booted`, and
`bootInFlight`. Automation consumers can now distinguish offline-replay,
old-host, and error from the schema alone.
DEREM-29: RendererRuntimeSummarySchema.profile now has `.min(1)` so the
consumer schema matches the producer-side constraint in
`HostInspectResultSchema.rendererProfile`.
Change-Id: I2839a0fa7c81b71af2f4950da609ab395cabaa80
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Signed-off-by: Thomas Kosiewski <tk@coder.com>
* fix(round-4): atomic renderer snapshot + isFile rethrow
DEREM-23 (re-raise): the inspect RPC handler now reads `state.snapshot()`,
`getCurrentProfileName()`, `isBooted()`, and `isBootInFlight()` in a single
synchronous tick before the `await getPackageMetadata()`. The previous
ordering let concurrent RPC handlers mutate renderer state and the session
snapshot between the reads, producing a result that did not correspond
to any real point in time. Switching to local-var capture closes that
window without taking the renderer manager's lifecycle lock.
DEREM-31: `isFile` now rethrows non-ENOENT stat errors instead of
swallowing them as "not present", matching the DEREM-9 discipline used
for canonical artifact stats. EACCES or EIO on commands.sh / notes.md /
command-status.tsv now propagates with the original error so operators
see the real cause.
Change-Id: Iba753e8177d3772de2ad41831c44347570107fc6
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Signed-off-by: Thomas Kosiewski <tk@coder.com>
* fix(round-5): sweep ENOENT, dedupe isWithinRoot, orchestrator tests
DEREM-35: statEventLogBytes and countEventLogEntries now use the shared
hasErrorCode util instead of duplicated inline ENOENT checks.
DEREM-36: TSV failing-row scan lowercases the status cell before
comparing to 'fail' so 'FAIL' and 'Fail' are detected, matching the
case-insensitive header lookup.
DEREM-37: validateCanonicalBundles orchestrator gains a 5-case unit
test suite (happy path, per-bundle ok:false, per-bundle crash via
synthesizeCrashResult, catalog mismatch, catalog parity throw). The
DEREM-10 isolation guarantee is now structurally tested.
DEREM-38: isWithinRoot extracted to src/util/isWithinRoot.ts and
shared by validate-bundle.ts (formerly isPathWithinBundle) and
review-bundle.ts (formerly its own isWithinRoot).
DEREM-39: doc comment on validate-canonical-bundles.ts no longer
falsely cites RELEASE.md for agent-uses-agent-tty; that bundle is the
evergreen agent demo, locked here for drift protection on the same
schema as the three release-signoff bundles.
DEREM-33, DEREM-34: removed em-dashes from PR-touched doc and test
comments.
DEREM-40: local hasNotes renamed to hasNotesOrReadme, matching the
DEREM-14 hasReproduceScript fix.
DEREM-41, DEREM-42, DEREM-43: doc comments added to loadPackageMetadata,
checkCatalogParity, and each new optional field on HostInspectResultSchema.
Change-Id: I458a66294d2747048edb9c6f8f8b10a8979ddd80
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Signed-off-by: Thomas Kosiewski <tk@coder.com>
* fix(round-6): sweep miss in DEREM-39/33 from round 5
DEREM-46: bundleManifestSchema.ts doc comment also falsely claimed all
four canonical bundles are 'named in RELEASE.md'. The DEREM-39 fix in
14db634 corrected the same wording in validate-canonical-bundles.ts but
missed this sibling. Now mirrors the three-release-signoff + one
evergreen-demo distinction.
DEREM-45: em-dash in the checkCatalogParity doc comment introduced in
14db634 (the same commit that fixed DEREM-33 and DEREM-34 elsewhere).
Replaced with a semicolon.
Change-Id: Icaac8482eb8caf6f0bcf9c6e0ac55f7d8ace0d40
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Signed-off-by: Thomas Kosiewski <tk@coder.com>
* test(inspect): cover DEREM-24 branch where cliVersion is absent
DEREM-50: new test 'surfaces host.rpcSocketPath even when cliVersion is
unavailable' exercises the DEREM-24 fix (host gated only on
rpcSocketPath). Asserts host.cliVersion === undefined, host.rpcSocketPath
populates, and the 'RPC Socket:' line appears while 'Host CLI Version:'
does not. If a future change re-couples the two fields, this test breaks.
Change-Id: I760f5f69766e6b6f382bc85cd0af4d6cdded1642
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Signed-off-by: Thomas Kosiewski <tk@coder.com>
---------
Signed-off-by: Thomas Kosiewski <tk@coder.com>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>1 parent 0624b8f commit dd13efe
35 files changed
Lines changed: 2433 additions & 166 deletions
File tree
- .github/workflows
- dogfood
- 20260325-week8-contract-locks
- 20260326-week9-release-readiness
- agent-uses-agent-tty
- run-command
- scripts
- src
- cli/commands
- host
- protocol
- renderer
- tools
- util
- test
- e2e
- integration
- unit
- commands
- host
- tools
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
52 | 52 | | |
53 | 53 | | |
54 | 54 | | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
55 | 58 | | |
56 | 59 | | |
57 | 60 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
14 | 14 | | |
15 | 15 | | |
16 | 16 | | |
17 | | - | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
18 | 20 | | |
19 | 21 | | |
20 | 22 | | |
21 | | - | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
22 | 26 | | |
23 | 27 | | |
24 | 28 | | |
25 | | - | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
26 | 32 | | |
27 | 33 | | |
28 | 34 | | |
29 | | - | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
30 | 38 | | |
31 | 39 | | |
32 | 40 | | |
33 | | - | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
34 | 44 | | |
35 | 45 | | |
36 | 46 | | |
37 | | - | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
38 | 50 | | |
39 | 51 | | |
40 | 52 | | |
41 | | - | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
42 | 56 | | |
43 | 57 | | |
44 | 58 | | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
23 | 23 | | |
24 | 24 | | |
25 | 25 | | |
26 | | - | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
27 | 29 | | |
28 | 30 | | |
29 | 31 | | |
30 | | - | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
31 | 35 | | |
32 | 36 | | |
33 | 37 | | |
34 | | - | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
35 | 41 | | |
36 | 42 | | |
37 | 43 | | |
38 | | - | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
39 | 47 | | |
40 | 48 | | |
41 | 49 | | |
42 | | - | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
43 | 53 | | |
44 | 54 | | |
45 | 55 | | |
46 | | - | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
47 | 59 | | |
48 | 60 | | |
49 | 61 | | |
50 | | - | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
51 | 65 | | |
52 | 66 | | |
53 | 67 | | |
54 | | - | |
| 68 | + | |
| 69 | + | |
| 70 | + | |
55 | 71 | | |
56 | 72 | | |
57 | 73 | | |
58 | | - | |
| 74 | + | |
| 75 | + | |
| 76 | + | |
59 | 77 | | |
60 | 78 | | |
61 | 79 | | |
62 | | - | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
63 | 83 | | |
64 | 84 | | |
65 | 85 | | |
66 | | - | |
| 86 | + | |
| 87 | + | |
| 88 | + | |
67 | 89 | | |
68 | 90 | | |
69 | 91 | | |
70 | | - | |
| 92 | + | |
| 93 | + | |
| 94 | + | |
71 | 95 | | |
72 | 96 | | |
73 | 97 | | |
74 | | - | |
| 98 | + | |
| 99 | + | |
| 100 | + | |
75 | 101 | | |
76 | 102 | | |
77 | 103 | | |
78 | | - | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
79 | 107 | | |
80 | 108 | | |
81 | 109 | | |
82 | | - | |
| 110 | + | |
| 111 | + | |
| 112 | + | |
83 | 113 | | |
84 | 114 | | |
85 | 115 | | |
86 | | - | |
| 116 | + | |
| 117 | + | |
| 118 | + | |
87 | 119 | | |
88 | 120 | | |
89 | 121 | | |
90 | | - | |
| 122 | + | |
| 123 | + | |
| 124 | + | |
91 | 125 | | |
92 | 126 | | |
93 | 127 | | |
94 | | - | |
| 128 | + | |
| 129 | + | |
| 130 | + | |
95 | 131 | | |
96 | 132 | | |
97 | 133 | | |
98 | | - | |
| 134 | + | |
| 135 | + | |
| 136 | + | |
99 | 137 | | |
100 | 138 | | |
101 | 139 | | |
102 | | - | |
| 140 | + | |
| 141 | + | |
| 142 | + | |
103 | 143 | | |
104 | 144 | | |
105 | 145 | | |
106 | | - | |
| 146 | + | |
| 147 | + | |
| 148 | + | |
107 | 149 | | |
108 | 150 | | |
109 | 151 | | |
110 | | - | |
| 152 | + | |
| 153 | + | |
| 154 | + | |
111 | 155 | | |
112 | 156 | | |
113 | 157 | | |
114 | | - | |
| 158 | + | |
| 159 | + | |
| 160 | + | |
115 | 161 | | |
116 | 162 | | |
117 | 163 | | |
0 commit comments