Skip to content

feat(engine): kernel slog capture + cog_tail_kernel_log#28

Merged
chazmaniandinkle merged 5 commits intocogos-dev:mainfrom
chazmaniandinkle:feat/kernel-slog-api
Apr 21, 2026
Merged

feat(engine): kernel slog capture + cog_tail_kernel_log#28
chazmaniandinkle merged 5 commits intocogos-dev:mainfrom
chazmaniandinkle:feat/kernel-slog-api

Conversation

@chazmaniandinkle
Copy link
Copy Markdown
Contributor

Summary

Kernel diagnostic-log surface — closes the follow-up gap Agent Q surfaced during trace-search design. Two-part implementation: (a) capture (in-process file sink via tee handler) + (b) surface (MCP tool + HTTP route). Per Agent U's design (`agent-U-kernel-slog-design.cog.md`).

Three observability surfaces now locked into distinct lanes:

Surface Content PR
Ledger hash-chained events #11
Traces client metabolites (turn_metrics, attention) #17
Kernel slog operator diagnostic text this PR

What landed

  • `internal/engine/log_capture.go` (130 LOC) — `teeHandler` fanning each `slog.Record` to the existing text-on-stderr handler AND a new `slog.NewJSONHandler` writing to `/.cog/run/kernel.log.jsonl`. `upgradeLoggerWithFileSink(cfg)` entry point.
  • `internal/engine/kernel_log_query.go` (397 LOC) — `QueryKernelLog` with level/substring/since/limit filters; 1 MiB bufio-tail scan. Byte-compat response shape with `QueryLedger` / `QueryTraces`.
  • `cog_tail_kernel_log` MCP tool (justified against `cog_read_stderr` / `cog_tail_slog` per Agent U §4.1 — both rejected as implementation leaks).
  • `GET /v1/kernel-log` HTTP route — additive; does not reshape `/v1/proprioceptive` or `/v1/traces`.
  • Three call-site updates (`cli.go:runServe`, `experiment.go:runExperimentRun`, `benchmark.go:runBenchCmd`) — clean 3-line additions after each `LoadConfig` call. The existing `setupLogger()` at `cli.go:117-124` stays untouched as the pre-config stderr-only fallback.
  • `Config.KernelLogPath` field (`kernel_log_path` YAML key) — default when empty; follows the `DigestPaths` precedent.

Backwards-compat on stderr preserved

`TestUpgradeLoggerStderrStillReceivesOutput` is the §8.4 regression guard. Service managers that capture stderr (your `/Library/LaunchAgents/com.cogos.kernel.plist` pointing `StandardErrorPath` at `/.cog/var/logs/serve.log`) continue to work unchanged. The new JSON file sink is additive.

Rotation policy

Deferred to v1.5 per Agent U §3.3 and design landing-plan §"Follow-ups" #1. v1 uses `O_APPEND` with unbounded growth; rotation policies land separately when the first workspace crosses 100 MB. Documented inline in `log_capture.go` package comment.

Test plan

  • 12 top-level tests / 19 with sub-tests — all pass `-race -short -count=1`
  • `TestTeeHandlerWritesToBothSinks`, `TestTeeHandlerWithAttrsAndWithGroupFanOut`, `TestTeeHandlerEnabledIsOR`, `TestUpgradeLoggerWithFileSinkCreatesJSONLFile`, `TestUpgradeLoggerHonorsOverridePath`, `TestUpgradeLoggerStderrStillReceivesOutput`, `TestUpgradeLoggerFailsOpenGracefully`
  • Query tests: empty, newest-first, level/substring/since filters, limit/truncated, malformed-line skip, attr extraction, validation (5 sub-cases), HTTP + MCP roundtrip
  • `go test ./... -short -race -count=1` — green
  • `go build ./...` + `go vet ./...` — silent
  • Zero deletions, purely additive

Scaffolded-infra note for cogos#22

`readLastJSONLEntries` (serve.go:939-976), `QueryLedger` (PR #11), `QueryTraces` (PR #17), and `QueryKernelLog` (this PR) all do 1-MiB-bufio JSONL-tail-with-filter. A shared `scanJSONLTailWithFilter(path, matchFn, limit)` primitive could replace three similar scans once all land. Deliberately NOT centralised in this PR — my scan has different filter semantics (substring pre-filter before JSON parse, typed time/level extraction); a shared helper mid-PR would either bloat or leak. Logged for the #22 audit to decide.

Stdlib only

No new deps in `go.mod`. `slog.NewJSONHandler` is stdlib (Go 1.21+).

Design reference

`cog://mem/semantic/surveys/2026-04-21-consolidation/agent-U-kernel-slog-design.cog.md`

Closes the follow-up gap Agent Q surfaced during trace-search implementation:
ledger (hash-chained events) and traces (client metabolites) were already
exposed as MCP tools, but kernel diagnostic text (slog) remained unreachable
from any API. This change adds the third observability surface per Agent U's
kernel-slog-api design.

Two parts:

(a) Capture — a teeHandler fans the default slog output to both stderr
    (text, backwards-compat-locked for service managers) and a JSONL file
    at <workspace>/.cog/run/kernel.log.jsonl (structured, API-reachable).
    Installed via upgradeLoggerWithFileSink(cfg) after LoadConfig at the
    three setupLogger call sites (cli.go:runServe, experiment.go, benchmark.go);
    the existing setupLogger() stays as the pre-config stderr-only fallback.
    Best-effort — open failure logs a warning and leaves the stderr-only
    default in place. No rotation in v1 (defer to v1.5 per Agent U §3.3).

(b) Surface — GET /v1/kernel-log HTTP route + cog_tail_kernel_log MCP tool,
    both backed by QueryKernelLog. Filter grammar mirrors the Agent L /
    Agent Q query shape: limit + level + substring + since/until. Reuses the
    1 MiB bufio + JSONL scan primitive from handleProprioceptive. Newest-first
    ordering; malformed lines skipped silently; missing file returns
    exists=false rather than 404. Does NOT reshape /v1/proprioceptive
    (byte-locked) or /v1/traces.

Tool name "cog_tail_kernel_log" deliberately avoids cog_read_stderr
(implementation leak — sink is the JSONL file, not raw stderr) and
cog_tail_slog (couples API to the Go stdlib). Config.KernelLogPath
supports workspace-level override via kernel.yaml:kernel_log_path.

Stdlib-only. No new deps. 12 new tests (tee fan-out, WithAttrs/WithGroup
propagation, stderr compat regression guard, graceful open failure, empty
file, filter by level/substring/since, limit + truncated, malformed line
tolerance, attr extraction, query validation, HTTP handler, MCP roundtrip).

Refs: agent-U-kernel-slog-design.cog.md, agent-Q-logs-search-design §8.7.
# Conflicts:
#	internal/engine/mcp_server.go
#	internal/engine/serve.go
# Conflicts:
#	internal/engine/mcp_server.go
#	internal/engine/serve.go
@chazmaniandinkle chazmaniandinkle merged commit eec2568 into cogos-dev:main Apr 21, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant