Repository navigation
feat(052): lose the recording, never the shell (US3) - #282
Merged
Merged
Conversation
The rule the whole feature is subordinate to. The adapter now sits in preexec
on every command of an engagement, holding the shell's descriptors, so every
way it can fail is a way the operator's shell can fail -- in the middle of work
that may not be repeatable. Unrecorded is bad; a wedged prompt, a lost reverse
shell or a command reporting someone else's exit status is worse.
T036, FR-009: with RedLog unreachable the commands already ran. Silently,
which is the bug -- an operator whose RedLog crashed two hours ago has been
working unrecorded with no way to know. They are now told, once, on the way
in, and told again only if it comes back and goes away. A warning on every
prompt is one an operator learns to read past, and then the one that matters
is read past too.
The startup banner said "command metadata will be logged" and offered
redlog-run as the way to get output. Both stopped being true at T020, so the
zsh adapter now announces "commands and their output" and bash announces
"commands" -- a banner that overstates what is recorded is worse than none,
because an operator who believes the output is in the record stops checking.
T037 turned out to be a characterisation test: killing the relay underneath a
running command already leaves the shell alive and already reports the
command's own status to both the shell and the record. That is the T020 design
working, and it is now pinned.
T038, FR-029: the relay declines the shapes it cannot hold, before the command
runs rather than noticing afterwards.
cat log | less relayed on `cat`, the pager's stdout becomes a pipe and
it stops being a pager. Any native or pty stage anywhere
in a pipeline stands the whole line down.
nmap | tee f not a hazard, and worth capturing: the last stage still
writes to the terminal, which is what the relay holds.
nmap -oN f > out stdout is already pointed elsewhere, so two processes are
not started to watch an empty descriptor. The record says
`redirected` either way (FR-008).
One test needed a note of its own: `pkill -f` matches full command lines, so a
command that kills its own relay matches itself and reports 143 -- which looks
exactly like the bug being tested for. And RedLog cannot be made unreachable
by omitting the credential files on this machine, because under WSL the
adapter deliberately falls back to the Windows profile's .redlog, which is a
real install.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
T039, FR-010. The dangerous outcome is not a missing command. It is a command from engagement A filed under engagement B -- a lie in a document a client reads, written by the tool whose whole job is to be believable. A terminal is pinned to the project it was opened against; when the operator switches project in RedLog the terminal stops, says why, and cannot be talked back into recording. `redlog start` is not the way around the guarantee; the safe answer is a new terminal (research.md D5). Detected by watching the active identity file's mtime with the zstat builtin, so the common case -- nothing changed -- costs a stat and no process. Only a changed mtime pays for the relay call. The session_end row lands in whichever project is open now, which is where someone wondering why the terminal went quiet will be looking, and names the engagement whose work stopped explicitly rather than letting the attribution speak for it. T040. The spool and the replay both existed. What the payload did not carry was WHEN: a command run at 02:00 with RedLog closed arrived claiming 09:00, the moment the operator next opened the project. A record whose times are the times someone read it is not a record of the engagement (Domain Invariant #8). One field -- source_timestamp on every event the adapter sends. insertEvent already validates it and hashes the rejection, so a wrong unit is refused rather than dragging the row to 1970. Two self-inflicted failures the suite caught, both worth the note: - The payload builder is a double-quoted shell string. A comment written with backticks around a function name RAN it; the follow-up comment quoting the resulting error message ended the string early and truncated the builder, so no event was sent at all. Prose punctuation is executable in there. - shell-adapter-boundaries holds the line that paths into the RedLog directory are transport, not lifecycle. The identity file is now named by shell-common; the zsh adapter only watches what it is handed. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
Important
This repository does not receive automatic reviews because it has fewer than 10 stars. ⚙️ Run configuration
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
guan4tou2
added a commit
that referenced
this pull request
Oct 8, 2026
feat(052): lose the recording, never the shell (US3)
guan4tou2
added a commit
that referenced
this pull request
Oct 8, 2026
feat(052): lose the recording, never the shell (US3)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What changed
Spec 052's US3: the rule the whole feature is subordinate to. An audit logger
may lose the recording, and may never take the shell with it.
This is not a defensive extra. The adapter now sits in
preexecon everycommand of an engagement, holding the shell's descriptors — so every way it can
fail is a way the operator's shell can fail, in the middle of work that may not
be repeatable. Unrecorded is bad. A wedged prompt, a lost reverse shell, or a
command that reports someone else's exit status is worse.
Why
Silence was the bug, not the fallback (T036, FR-009)
With RedLog unreachable the commands already ran — silently. An operator whose
RedLog crashed two hours ago has been working unrecorded with no way to know.
They are told now, once, on the way in, and again only if RedLog comes back
and goes away. A warning on every prompt is one an operator learns to read
past, and then the one that matters is read past too.
The startup banner said "command metadata will be logged" and offered
redlog-runas the way to get output. Both stopped being true at T020, so zshnow announces "commands and their output" and bash announces "commands". A
banner that overstates what is recorded is worse than none: an operator who
believes the output is in the record stops checking.
T037 turned out to be a characterisation test
All three assertions passed on the first run. Killing the relay underneath a
running command already leaves the shell alive and already reports the
command's own status to both the shell and the record — that is T020's design
working. It is now pinned rather than assumed.
The shapes the relay has to decline (T038, FR-029)
Four of the six already stood down. The two that did not:
cat log | lesscat, and then the pager's stdout is a pipe instead of a terminal — it stops being a pager. Anynativeorptystage anywhere in the line stands the whole thing down.nmap | tee fnmap -oN f > outredirectedeither way (FR-008).A command from engagement A must never be filed under B (T039, FR-010)
The dangerous outcome is not a missing command. It is a lie in a document a
client reads, written by the tool whose whole job is to be believable. A
terminal is pinned to the project it was opened against; when the operator
switches project the terminal stops, says why, and cannot be talked back into
recording —
redlog startis not the way around the guarantee, and the safeanswer is a new terminal (research.md D5).
Detected by watching the active identity file's mtime with the
zstatbuiltin,so the common case — nothing changed — costs a stat and no process.
The spool carried everything except when (T040)
The spool and the replay both existed. The payload did not carry a time, so a
command run at 02:00 with RedLog closed arrived claiming 09:00 — the moment the
operator next opened the project. A record whose times are the times someone
read it is not a record of the engagement (Domain Invariant #8).
One field:
source_timestampon every event the adapter sends.insertEventalready validates it and hashes the rejection, so a wrong unit is refused
rather than dragging the row to 1970.
Found while building, fixed here
is executable in there. A comment written with backticks around a function
name ran it; the follow-up comment quoting the resulting error message
ended the string early and truncated the builder, so no event was sent at
all. Both were caught by the suite within one run of each other.
shell-adapter-boundariesholds a real line. Paths into the RedLogdirectory are transport, not lifecycle. The identity file is now named by
shell-common.sh; the zsh adapter only watches what it is handed.pkill -fmatches full commandlines, so a command that kills its own relay matches itself and reports
143 — which looks exactly like the bug being tested for. And RedLog cannot
be made unreachable by omitting the credential files on a developer machine,
because under WSL the adapter deliberately falls back to the Windows
profile's
.redlog, which is a real install.Verification
npm run typechecknpm run verify:specsnpm run verify:architecturenpm run verify:i18nnpm test— 3140 passed, 25 skippednpm run buildgit show --statand carry only their ownpaths (CLAUDE.md §Branches, the shared index)
Tasks T036–T040 of 47; Phase 5 (US3) complete, 40 of 47 done. What is left is
Phase 6: docs (T041/T042), the e2e install journey (T043), the SC measurements
(T045),
verification.md(T046), the final gate round (T047) — and T044,which is not something CI can do: the
nc→Ctrl-Z→stty raw -echo→fgupgrade on a real Kali VM. The spec is explicit that a run which cannot dothat is not a verified feature, whatever the unit suite says.
🤖 Generated with Claude Code