Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
eb9f253
feat: implement packet 23 normalized log follow
Microck Aug 2, 2026
4c01b28
fix: close T8 candidate review findings
Microck Aug 2, 2026
5b20e59
test: align T8 broad validation fixtures
Microck Aug 2, 2026
e38113d
fix: resolve T8 review and platform gate findings
Microck Aug 2, 2026
a2e9275
test: align T8 review proof with packet contracts
Microck Aug 2, 2026
e4d5e74
fix(cli): keep follow and artifact errors typed
Microck Aug 2, 2026
0af7fc8
fix(cli): type all follow identity failures
Microck Aug 2, 2026
591fa10
fix(host): keep retained artifacts coherent
Microck Aug 2, 2026
4f7750f
fix(cli): quote log recovery host aliases
Microck Aug 2, 2026
283b781
fix(cli): preserve JSON log follow recovery
Microck Aug 2, 2026
14c9e7c
test(host): align log retention observation
Microck Aug 2, 2026
8eac9d0
fix(logs): close external review findings
Microck Aug 2, 2026
1ab5605
fix(logs): retry dropped session validation bodies
Microck Aug 2, 2026
1302680
fix(logs): bind reconnect scope and interrupts
Microck Aug 2, 2026
f0c3924
fix(logs): make follow I/O interruptible
Microck Aug 2, 2026
2071e77
fix(logs): reject unrepresentable since ranges
Microck Aug 2, 2026
87a1d5f
fix(logs): bind normalized cursor contracts
Microck Aug 2, 2026
ad4320e
fix(logs): validate response request scope
Microck Aug 2, 2026
de3f958
fix(logs): bind responses to complete query
Microck Aug 2, 2026
dde8e73
fix(logs): enforce response boundary contracts
Microck Aug 2, 2026
3ac3782
fix(ci): gate Unix-only deadline imports
Microck Aug 2, 2026
a703989
fix(logs): type initial follow identity failures
Microck Aug 2, 2026
823526a
fix(logs): paginate finite cursor reads
Microck Aug 2, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 26 additions & 26 deletions .facts

Large diffs are not rendered by default.

21 changes: 21 additions & 0 deletions .spec-gaps.md
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,27 @@ Resolution: User configuration and named profiles use `log_verbosity = "off" | "
- Packet/facts: source packet 22, `ju3` / L1798
- Decision: Canonical SQLite, sidecars, attachments, recovery data, Operator Logs, and recordings remain on the Host. Ordinary run, status, log, and setup operations never copy Host storage to a Controller or service. Only an explicit Operator export command may copy a redacted artifact, diagnostic, or recording to its operator-selected destination. Document this boundary and prove ordinary read paths have no export or write side effect. The task-artifact exception is exactly GAP-046.

### GAP-050: Log follow transport and reconnect contract

- Status: resolved
- Packet/facts: source packet 23, `6b0`, `vrh`, `2mv`, `3w2`, `95q`, `nr7`, `r6y`, `vm3`, `lgn`, `4m1`, `gpk`, `c4sw`, `pcj`, `5ff`, `1wg`, `dww`, and `1db`
- Decision: Keep authenticated `GET /v1/logs` as the only normalized Log read route. Follow mode emits the requested initial finite result, stores the returned high-water Log Cursor, then polls forward from the last delivered cursor. A successful empty forward page means the command remains attached and waits 250 milliseconds; it is not a stream interruption. Each later page continues the same human line stream or newline-delimited `satelle.logs.entry.v1` JSON stream. Reconnect notices and errors use stderr only. Ctrl-C is terminal exit 130 and never consumes reconnect budget.
- Reconnect: Only Host reachability, daemon reachability, SSH bootstrap availability, and connection-level remote execution failures are transient. Recreate the transport for each attempt, query forward from the last delivered Log Cursor, and never use a timestamp or Satelle Event replay. Authentication, authorization, TLS trust, cursor, configuration, storage, and public-contract failures are terminal. One interruption owns a 60-second monotonic budget and an exponential delay starting at 250 milliseconds and capped at 5 seconds. Apply bounded 20 percent symmetric jitter to each delay without exceeding the 5-second cap. The tenth interruption or an expired per-interruption budget returns `logs-follow-reconnect-exhausted` with the last delivered cursor and an exact rerun command. `--no-reconnect` reports the cursor on stderr and returns the original terminal transport error without a retry.
Comment thread
coderabbitai[bot] marked this conversation as resolved.
- Identity and scope: The selected Host binding's expected Host Identity is the immutable follow identity. Each successful HTTP response is already identity-pinned by the transport. Before the initial read and after transport recreation, a requested Session selector must also resolve through an authenticated Session read on that same Host. A changed Host Identity or a Session that is absent from the reconnected Host returns `logs-follow-identity-changed` before any resumed entry is emitted.

### GAP-051: SQLite Log Entry retention policy

- Status: resolved
- Packet/facts: source packet 23, `z0p`
- Decision: Add Operator-owned `sqlite_log_retention = "7d"` to Host and Profile configuration. Reuse packet 22's `RetentionDuration` grammar and 7-day through 365-day bounds. The default is 7 days. A user-selected user-owned Profile overrides the user Host value; project configuration cannot set destructive retention. Resolve one duration at runtime and inject it into SQLite Log pruning. Keep it independent from `session_metadata_retention` and `operator_log_retained_files`. Persist it in service launch configuration, hard-cut the Windows service schema to the next version, and do not migrate older service configurations.

### GAP-052: Normalized Log Entry and diagnostic vocabulary

- Status: resolved
- Packet/facts: source packet 23, `727`, `j3h`, `ool`, and `05u`
- Decision: Keep `satelle.logs.entry.v1` as one closed normalized record. Every entry contains its durable cursor, timestamp, source, severity, exact Host Identity, typed event, structured subject, fixed event-derived message, and redaction marker. The structured subject carries the optional Session and Turn identities plus lifecycle revisions; no arbitrary payload map is added. SQLite remains authoritative and the rotating plain-text Operator Log File mirrors only committed entries.
- Vocabulary: Add typed events for native readiness summary, provider smoke-test summary, and structured execution failure. Readiness and provider summary entries correlate by Turn subject with the private durable result references already accepted and stored at admission; they do not duplicate those references or include probe payloads, credentials, prompts, screenshots, or provider bodies. Turn lifecycle commits use `codex_adapter` for normalized Codex state summaries; daemon-owned admission, stop, restart, and store events remain `host_daemon` or `storage`. Structured failures use the existing redacted terminal summary and revisions, not raw protocol errors. No full Satelle Event stream or recording surface is introduced.

### GAP-021 - Installer-managed standalone Codex contract (RESOLVED)

Resolution: PR 06 owns fail-closed runtime admission of an existing managed Codex installation; the later setup-install and Codex-update packets own acquisition, update, and receipt creation. The acquisition contract uses the official OpenAI standalone Codex `0.144.0` full package from release tag `rust-v0.144.0`, mapping native Host targets to `aarch64-apple-darwin`, `x86_64-apple-darwin`, `aarch64-pc-windows-msvc`, or `x86_64-pc-windows-msvc`. The selected `codex-package-<target>.tar.gz` must match `codex-package_SHA256SUMS` before the official versioned installer runs. The accepted package root is an immutable installer-owned directory under `<codex_home>/packages/standalone/releases`; mutable `current` links or junctions and visible-bin shims are never execution identities. Satelle atomically writes its owner-only `codex-install-receipt.json` under the resolved Satelle state root only after post-install verification. The receipt records schema version, manager, Codex version, target, release tag, exact artifact URL and SHA-256, Codex home, immutable package root, immutable binary path and SHA-256, and installation time. Installation and receipt creation are separate ordered ledger actions, not one atomic transaction. If receipt creation or post-verification fails, the installed package remains untrusted; setup or repair may adopt it only after repeating complete package, metadata, target, binary-digest, and version verification. Readiness fails closed when the receipt is absent or drifts from package metadata, binary bytes, `codex --version`, or the app-server capability handshake. The Host launches only the immutable receipt-recorded binary and sets the receipt-recorded `CODEX_HOME` only on Codex child processes; it ignores npm packages, mutable aliases, shims, and `PATH`.
Expand Down
7 changes: 5 additions & 2 deletions crates/satelle-cli/src/error-output.rs
Original file line number Diff line number Diff line change
Expand Up @@ -344,7 +344,8 @@ fn error_contract(code: ErrorCode) -> ErrorContract {
},
ErrorCode::HostUnreachable
| ErrorCode::HostDaemonUnreachable
| ErrorCode::DirectDaemonUnreachable => ErrorContract {
| ErrorCode::DirectDaemonUnreachable
| ErrorCode::LogsFollowReconnectExhausted => ErrorContract {
category: ErrorCategory::RemoteExecution,
retryable: true,
outcome: "The Host could not be reached.",
Expand Down Expand Up @@ -414,6 +415,7 @@ fn error_contract(code: ErrorCode) -> ErrorContract {
| ErrorCode::OutputModeConflict
| ErrorCode::LogTailLimitExceeded
| ErrorCode::LogPositionConflict
| ErrorCode::LogsTargetRequired
| ErrorCode::ConcurrencyLimitExceeded
| ErrorCode::ConcurrencyWithoutRemoteUpdate
| ErrorCode::ComponentSelectionConflict
Expand Down Expand Up @@ -462,7 +464,8 @@ fn error_contract(code: ErrorCode) -> ErrorContract {
| ErrorCode::CertificateExpired
| ErrorCode::TlsVersionUnsupported
| ErrorCode::TlsHandshakeFailed
| ErrorCode::HostIdentityMismatch => ErrorContract {
| ErrorCode::HostIdentityMismatch
| ErrorCode::LogsFollowIdentityChanged => ErrorContract {
category: ErrorCategory::RemoteExecution,
retryable: false,
outcome: "The Host identity or secure connection was not accepted.",
Expand Down
Loading
Loading