Skip to content

v0.9.0 compliance: full upgrade against core/go reference#6

Open
Snider wants to merge 1 commit intomainfrom
dev
Open

v0.9.0 compliance: full upgrade against core/go reference#6
Snider wants to merge 1 commit intomainfrom
dev

Conversation

@Snider
Copy link
Copy Markdown
Contributor

@Snider Snider commented Apr 28, 2026

Brings this repo to verdict: COMPLIANT against the v0.9.0 audit.

🤖 Generated with Claude Code + Codex
Co-Authored-By: Codex noreply@openai.com
Co-Authored-By: Virgil virgil@lethean.io

Summary by CodeRabbit

Release Notes

  • New Features

    • Added comprehensive test coverage for analytics computation, session management, transcript parsing, and video rendering workflows.
  • Bug Fixes

    • Improved error handling for file operations with proper logging of failures.
  • Chores

    • Consolidated and simplified internal dependency management for streamlined maintenance.

bash /tmp/v090/audit.sh . → verdict: COMPLIANT (all 7 dimensions zero).

Co-authored-by: Codex <noreply@openai.com>
Co-Authored-By: Virgil <virgil@lethean.io>
@sonarqubecloud
Copy link
Copy Markdown

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 28, 2026

📝 Walkthrough

Walkthrough

The pull request consolidates dependencies by migrating from separate submodules (dappco.re/go/core, dappco.re/go/core/log) to a single umbrella module (dappco.re/go v0.9.0). All import paths across the codebase are updated accordingly, error handling for file operations is improved, and extensive new test coverage is added.

Changes

Cohort / File(s) Summary
Module dependency consolidation
go.mod
Removes separate requirements for dappco.re/go/core and dappco.re/go/core/log, replacing them with a single dappco.re/go v0.9.0 dependency.
Core import path migration (production)
analytics.go, core_helpers.go, html.go, search.go, video.go, parser.go, parser_other.go, parser_unix.go
Updates core and/or coreerr package imports from dappco.re/go/core and dappco.re/go/core/log to dappco.re/go.
Error handling improvements
parser.go, tests/cli/session/main.go
Deferred file-close operations now capture and log errors via coreerr.Warn instead of silently discarding them; temporary directory cleanup now checks error status before proceeding.
Core import path migration (tests)
bench_test.go, conventions_test.go, html_test.go, parser_test.go, test_helpers_test.go, video_test.go
Updates core package imports to dappco.re/go and adjusts banned-import test paths accordingly.
Test assertion enhancements
parser_test.go, video_test.go
Strengthens test coverage with additional assertions: intermediate variables in extraction tests, length-based checks in truncation scenarios, substring/prefix matching, and output capture validations.
New test suites
ax7_test.go, ax7_unix_test.go
Comprehensive test coverage for analytics computation, session management, filesystem workflows, search functionality, HTML/MP4 output rendering, transcript parsing, and Unix file-descriptor operations (noFollowFile).
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 45.59% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately reflects the main change: updating dependencies from separate core/log subpackages to the unified dappco.re/go v0.9.0 module across the entire codebase.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@ax7_test.go`:
- Around line 13-537: All tests prefixed with TestAX7_* should be renamed to
follow TestFunctionName_Context_Good/Bad/Ugly using the actual API symbols under
test (e.g. rename TestAX7_Analyse_Good/Bad/Ugly → TestAnalyse_SingleToolUse_Good
/ TestAnalyse_NilSession_Bad / TestAnalyse_InputOutputTokens_Ugly), and
similarly for FormatAnalytics, Session.EventsSeq, Session.IsExpired,
ListSessions, ListSessionsSeq, PruneSessions, FetchSession, ParseTranscript,
ParseTranscriptReader, Search, SearchSeq, RenderHTML, RenderMP4 and rawJSON's
UnmarshalJSON/MarshalJSON tests; update each test function name to include the
function/class under test (Analyse, FormatAnalytics, EventsSeq, IsExpired,
ListSessions, ListSessionsSeq, PruneSessions, FetchSession, ParseTranscript,
ParseTranscriptReader, Search, SearchSeq, RenderHTML, RenderMP4,
rawJSON.UnmarshalJSON, rawJSON.MarshalJSON) plus a concise context and suffix
_Good/_Bad/_Ugly so the test names follow the repository convention and still
map to the same test bodies.
- Line 148: The tests reference a non-existent Session.ID field; update all
assertions and literals to use the correct SessionID field defined on the
Session struct. Replace uses like sessions[0].ID with sessions[0].SessionID and
any Session{ID: "..."} composite literals with Session{SessionID: "..."}, e.g.,
in AssertEqual calls and Session constructors (occurrences around AssertEqual,
Session literals at the listed lines). Ensure all test references (sessions,
AssertEqual) consistently use SessionID so the code compiles against parser.go's
Session struct.

In `@parser_other.go`:
- Line 9: Update the import alias for the core error package: replace the import
coreerr "dappco.re/go" with coreerr "dappco.re/go/core/log" in parser_other.go
and make the identical change in parser_unix.go and parser.go so all calls like
coreerr.E(op, msg, err) resolve to the mandated package; search for the import
lines in each file and update the string literal only, leaving the alias
(coreerr) and all existing usages unchanged.

In `@parser.go`:
- Around line 11-12: The file imports the same package twice as both `core` and
`coreerr`; remove the duplicate import and consolidate to a single alias (keep
`core`) in the import block, then replace all uses of `coreerr.E` and
`coreerr.Warn` with `core.E` and `core.Warn` respectively so the code
consistently uses the single import alias (search for symbols `coreerr.E`,
`coreerr.Warn`, and the import lines `core "dappco.re/go"` / `coreerr
"dappco.re/go"` to update).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 29ee6f72-4173-4eb6-bd79-1996c7f77cad

📥 Commits

Reviewing files that changed from the base of the PR and between a4ef7ff and e661e27.

⛔ Files ignored due to path filters (1)
  • go.sum is excluded by !**/*.sum
📒 Files selected for processing (18)
  • analytics.go
  • ax7_test.go
  • ax7_unix_test.go
  • bench_test.go
  • conventions_test.go
  • core_helpers.go
  • go.mod
  • html.go
  • html_test.go
  • parser.go
  • parser_other.go
  • parser_test.go
  • parser_unix.go
  • search.go
  • test_helpers_test.go
  • tests/cli/session/main.go
  • video.go
  • video_test.go

Comment thread ax7_test.go
Comment on lines +13 to +537
func TestAX7_Analyse_Good(t *T) {
sess := &Session{Events: []Event{{Type: "tool_use", Tool: "Bash", Duration: 2 * time.Second, Success: true}}}
a := Analyse(sess)

AssertEqual(t, 1, a.EventCount)
AssertEqual(t, 1.0, a.SuccessRate)
AssertEqual(t, 2*time.Second, a.AvgLatency["Bash"])
}

func TestAX7_Analyse_Bad(t *T) {
a := Analyse(nil)

AssertNotNil(t, a)
AssertEqual(t, 0, a.EventCount)
AssertEmpty(t, a.ToolCounts)
}

func TestAX7_Analyse_Ugly(t *T) {
sess := &Session{Events: []Event{{Type: "tool_use", Tool: "Read", Input: "abcd", Output: "abcdefgh", Success: false}}}
a := Analyse(sess)

AssertEqual(t, 1, a.EventCount)
AssertEqual(t, 0.0, a.SuccessRate)
AssertEqual(t, 1, a.EstimatedInputTokens)
AssertEqual(t, 2, a.EstimatedOutputTokens)
}

// --- FormatAnalytics ---

func TestAX7_FormatAnalytics_Good(t *T) {
a := &SessionAnalytics{
Duration: 2 * time.Minute,
ActiveTime: 30 * time.Second,
EventCount: 3,
SuccessRate: 1,
ToolCounts: map[string]int{"Bash": 1},
ErrorCounts: map[string]int{},
AvgLatency: map[string]time.Duration{"Bash": time.Second},
MaxLatency: map[string]time.Duration{"Bash": time.Second},
}
output := FormatAnalytics(a)

AssertContains(t, output, "Session Analytics")
AssertContains(t, output, "100.0%")
AssertContains(t, output, "Bash")
}

func TestAX7_FormatAnalytics_Bad(t *T) {
var a *SessionAnalytics

AssertPanics(t, func() {
_ = FormatAnalytics(a)
})
AssertNil(t, a)
}

func TestAX7_FormatAnalytics_Ugly(t *T) {
a := &SessionAnalytics{}
output := FormatAnalytics(a)

AssertContains(t, output, "0.0%")
AssertNotContains(t, output, "Tool Breakdown")
AssertContains(t, output, "Events:")
}

// --- Session.EventsSeq ---

func TestAX7_Session_EventsSeq_Good(t *T) {
sess := &Session{Events: []Event{{Type: "user", Input: "hello"}, {Type: "assistant", Input: "hi"}}}
var got []string
for evt := range sess.EventsSeq() {
got = append(got, evt.Type)
}

AssertEqual(t, []string{"user", "assistant"}, got)
AssertLen(t, sess.Events, 2)
}

func TestAX7_Session_EventsSeq_Bad(t *T) {
sess := &Session{}
var got []Event
for evt := range sess.EventsSeq() {
got = append(got, evt)
}

AssertEmpty(t, got)
AssertEmpty(t, sess.Events)
}

func TestAX7_Session_EventsSeq_Ugly(t *T) {
sess := &Session{Events: []Event{{Type: ""}}}
var got []Event
for evt := range sess.EventsSeq() {
got = append(got, evt)
}

AssertLen(t, got, 1)
AssertEqual(t, "", got[0].Type)
}

// --- Session.IsExpired ---

func TestAX7_Session_IsExpired_Good(t *T) {
sess := &Session{EndTime: time.Now().Add(-2 * time.Hour)}
expired := sess.IsExpired(time.Hour)

AssertTrue(t, expired)
AssertFalse(t, sess.EndTime.IsZero())
}

func TestAX7_Session_IsExpired_Bad(t *T) {
sess := &Session{}
expired := sess.IsExpired(time.Hour)

AssertFalse(t, expired)
AssertTrue(t, sess.EndTime.IsZero())
}

func TestAX7_Session_IsExpired_Ugly(t *T) {
sess := &Session{EndTime: time.Now().Add(time.Hour)}
expired := sess.IsExpired(time.Nanosecond)

AssertFalse(t, expired)
AssertTrue(t, sess.EndTime.After(time.Now()))
}

// --- ListSessions ---

func TestAX7_ListSessions_Good(t *T) {
dir := t.TempDir()
writeJSONL(t, dir, "alpha.jsonl", userTextEntry(ts(0), "hello"))
sessions, err := ListSessions(dir)

RequireNoError(t, err)
AssertLen(t, sessions, 1)
AssertEqual(t, "alpha", sessions[0].ID)
}

func TestAX7_ListSessions_Bad(t *T) {
dir := t.TempDir()
sessions, err := ListSessions(dir)

RequireNoError(t, err)
AssertEmpty(t, sessions)
AssertLen(t, sessions, 0)
}

func TestAX7_ListSessions_Ugly(t *T) {
dir := t.TempDir()
writeResult := hostFS.Write(Path(dir, "notes.txt"), "not a transcript")
RequireTrue(t, writeResult.OK)
sessions, err := ListSessions(dir)

RequireNoError(t, err)
AssertEmpty(t, sessions)
AssertTrue(t, writeResult.OK)
}

// --- ListSessionsSeq ---

func TestAX7_ListSessionsSeq_Good(t *T) {
dir := t.TempDir()
writeJSONL(t, dir, "alpha.jsonl", userTextEntry(ts(0), "hello"))
var sessions []Session
for sess := range ListSessionsSeq(dir) {
sessions = append(sessions, sess)
}

AssertLen(t, sessions, 1)
AssertEqual(t, "alpha", sessions[0].ID)
}

func TestAX7_ListSessionsSeq_Bad(t *T) {
var sessions []Session
for sess := range ListSessionsSeq(Path(t.TempDir(), "missing")) {
sessions = append(sessions, sess)
}

AssertEmpty(t, sessions)
AssertLen(t, sessions, 0)
}

func TestAX7_ListSessionsSeq_Ugly(t *T) {
dir := t.TempDir()
writeJSONL(t, dir, "alpha.jsonl", userTextEntry(ts(0), "alpha"))
writeJSONL(t, dir, "bravo.jsonl", userTextEntry(ts(1), "bravo"))
var first Session
for sess := range ListSessionsSeq(dir) {
first = sess
break
}

AssertNotEqual(t, "", first.ID)
AssertTrue(t, first.StartTime.After(time.Time{}))
}

// --- PruneSessions ---

func TestAX7_PruneSessions_Good(t *T) {
dir := t.TempDir()
oldPath := writeJSONL(t, dir, "old.jsonl", userTextEntry(ts(0), "old"))
oldTime := time.Now().Add(-2 * time.Hour)
RequireNoError(t, setFileTimes(oldPath, oldTime, oldTime))
deleted, err := PruneSessions(dir, time.Hour)

RequireNoError(t, err)
AssertEqual(t, 1, deleted)
AssertFalse(t, hostFS.Stat(oldPath).OK)
}

func TestAX7_PruneSessions_Bad(t *T) {
dir := t.TempDir()
recentPath := writeJSONL(t, dir, "recent.jsonl", userTextEntry(ts(0), "recent"))
deleted, err := PruneSessions(dir, time.Hour)

RequireNoError(t, err)
AssertEqual(t, 0, deleted)
AssertTrue(t, hostFS.Stat(recentPath).OK)
}

func TestAX7_PruneSessions_Ugly(t *T) {
dir := t.TempDir()
writeJSONL(t, dir, "now.jsonl", userTextEntry(ts(0), "now"))
deleted, err := PruneSessions(dir, -time.Nanosecond)

RequireNoError(t, err)
AssertEqual(t, 1, deleted)
sessions, err := ListSessions(dir)
RequireNoError(t, err)
AssertEmpty(t, sessions)
}

// --- FetchSession ---

func TestAX7_FetchSession_Good(t *T) {
dir := t.TempDir()
writeJSONL(t, dir, "alpha.jsonl", userTextEntry(ts(0), "hello"))
sess, stats, err := FetchSession(dir, "alpha")

RequireNoError(t, err)
AssertEqual(t, "alpha", sess.ID)
AssertEqual(t, 1, stats.TotalLines)
}

func TestAX7_FetchSession_Bad(t *T) {
dir := t.TempDir()
sess, stats, err := FetchSession(dir, "missing")

AssertError(t, err)
AssertNil(t, sess)
AssertNil(t, stats)
}

func TestAX7_FetchSession_Ugly(t *T) {
dir := t.TempDir()
sess, stats, err := FetchSession(dir, "../outside")

AssertError(t, err)
AssertNil(t, sess)
AssertNil(t, stats)
AssertContains(t, err.Error(), "invalid session id")
}

// --- ParseTranscript ---

func TestAX7_ParseTranscript_Good(t *T) {
dir := t.TempDir()
filePath := writeJSONL(t, dir, "alpha.jsonl", userTextEntry(ts(0), "hello"))
sess, stats, err := ParseTranscript(filePath)

RequireNoError(t, err)
AssertEqual(t, "alpha", sess.ID)
AssertEqual(t, 1, stats.TotalLines)
}

func TestAX7_ParseTranscript_Bad(t *T) {
sess, stats, err := ParseTranscript(Path(t.TempDir(), "missing.jsonl"))

AssertError(t, err)
AssertNil(t, sess)
AssertNil(t, stats)
}

func TestAX7_ParseTranscript_Ugly(t *T) {
dir := t.TempDir()
filePath := writeJSONL(t, dir, "mixed.jsonl", "{bad json", userTextEntry(ts(0), "good"))
sess, stats, err := ParseTranscript(filePath)

RequireNoError(t, err)
AssertLen(t, sess.Events, 1)
AssertEqual(t, 1, stats.SkippedLines)
}

// --- ParseTranscriptReader ---

func TestAX7_ParseTranscriptReader_Good(t *T) {
reader := bytes.NewBufferString(userTextEntry(ts(0), "hello") + "\n")
sess, stats, err := ParseTranscriptReader(reader, "reader")

RequireNoError(t, err)
AssertEqual(t, "reader", sess.ID)
AssertEqual(t, 1, stats.TotalLines)
}

func TestAX7_ParseTranscriptReader_Bad(t *T) {
reader := bytes.NewBufferString("{bad json\n")
sess, stats, err := ParseTranscriptReader(reader, "bad")

RequireNoError(t, err)
AssertNotNil(t, sess)
AssertEqual(t, 1, stats.SkippedLines)
}

func TestAX7_ParseTranscriptReader_Ugly(t *T) {
reader := bytes.NewBufferString("")
sess, stats, err := ParseTranscriptReader(reader, "")

RequireNoError(t, err)
AssertEqual(t, "", sess.ID)
AssertEqual(t, 0, stats.TotalLines)
}

// --- Search ---

func TestAX7_Search_Good(t *T) {
dir := t.TempDir()
writeJSONL(t, dir, "alpha.jsonl", toolUseEntry(ts(0), "Bash", "t1", map[string]any{"command": "go test"}), toolResultEntry(ts(1), "t1", "PASS", false))
results, err := Search(dir, "go test")

RequireNoError(t, err)
AssertLen(t, results, 1)
AssertEqual(t, "alpha", results[0].SessionID)
}

func TestAX7_Search_Bad(t *T) {
dir := t.TempDir()
results, err := Search(dir, "missing")

RequireNoError(t, err)
AssertEmpty(t, results)
AssertLen(t, results, 0)
}

func TestAX7_Search_Ugly(t *T) {
dir := t.TempDir()
writeJSONL(t, dir, "alpha.jsonl", toolUseEntry(ts(0), "Bash", "t1", map[string]any{"command": ""}), toolResultEntry(ts(1), "t1", "needle in output", false))
results, err := Search(dir, "NEEDLE")

RequireNoError(t, err)
AssertLen(t, results, 1)
AssertContains(t, results[0].Match, "needle")
}

// --- SearchSeq ---

func TestAX7_SearchSeq_Good(t *T) {
dir := t.TempDir()
writeJSONL(t, dir, "alpha.jsonl", toolUseEntry(ts(0), "Bash", "t1", map[string]any{"command": "go vet"}), toolResultEntry(ts(1), "t1", "ok", false))
var results []SearchResult
for result := range SearchSeq(dir, "go vet") {
results = append(results, result)
}

AssertLen(t, results, 1)
AssertEqual(t, "Bash", results[0].Tool)
}

func TestAX7_SearchSeq_Bad(t *T) {
var results []SearchResult
for result := range SearchSeq(t.TempDir(), "absent") {
results = append(results, result)
}

AssertEmpty(t, results)
AssertLen(t, results, 0)
}

func TestAX7_SearchSeq_Ugly(t *T) {
dir := t.TempDir()
writeJSONL(t, dir, "alpha.jsonl", toolUseEntry(ts(0), "Bash", "t1", map[string]any{"command": "go test"}), toolResultEntry(ts(1), "t1", "ok", false))
var first SearchResult
for result := range SearchSeq(dir, "") {
first = result
break
}

AssertEqual(t, "alpha", first.SessionID)
AssertEqual(t, "Bash", first.Tool)
}

// --- RenderHTML ---

func TestAX7_RenderHTML_Good(t *T) {
dir := t.TempDir()
outputPath := Path(dir, "session.html")
sess := &Session{ID: "alpha-session", StartTime: time.Date(2026, 2, 20, 10, 0, 0, 0, time.UTC), EndTime: time.Date(2026, 2, 20, 10, 0, 1, 0, time.UTC), Events: []Event{{Type: "tool_use", Tool: "Bash", Input: "echo ok", Output: "ok", Success: true}}}
err := RenderHTML(sess, outputPath)

RequireNoError(t, err)
readResult := hostFS.Read(outputPath)
AssertTrue(t, readResult.OK)
AssertContains(t, readResult.Value.(string), "alpha-s")
}

func TestAX7_RenderHTML_Bad(t *T) {
sess := &Session{ID: "bad"}
err := RenderHTML(sess, Path(t.TempDir(), "missing", "session.html"))

AssertError(t, err)
AssertContains(t, err.Error(), "parent directory")
}

func TestAX7_RenderHTML_Ugly(t *T) {
dir := t.TempDir()
outputPath := Path(dir, "escaped.html")
sess := &Session{ID: "ugly", Events: []Event{{Type: "tool_use", Tool: "Bash", Input: `<script>bad()</script>`, Output: `<script>bad()</script>`, Success: true}}}
err := RenderHTML(sess, outputPath)

RequireNoError(t, err)
html := hostFS.Read(outputPath).Value.(string)
AssertNotContains(t, html, "<script>bad")
AssertContains(t, html, "&lt;script&gt;")
}

// --- RenderMP4 ---

func TestAX7_RenderMP4_Good(t *T) {
dir := t.TempDir()
vhsPath := Path(dir, "vhs")
writeResult := hostFS.WriteMode(vhsPath, "#!/bin/sh\nexit 0\n", 0o755)
RequireTrue(t, writeResult.OK)
previousCore := hostCore
c := New()
c.Action("process.run", func(_ Context, opts Options) Result {
AssertEqual(t, vhsPath, opts.String("command"))
return Ok("rendered")
})
hostCore = c
defer func() { hostCore = previousCore }()
t.Setenv("PATH", dir)
err := RenderMP4(&Session{ID: "alpha", StartTime: time.Date(2026, 2, 20, 10, 0, 0, 0, time.UTC)}, Path(dir, "out.mp4"))

AssertNoError(t, err)
AssertTrue(t, hostFS.Stat(vhsPath).OK)
}

func TestAX7_RenderMP4_Bad(t *T) {
dir := t.TempDir()
t.Setenv("PATH", dir)
err := RenderMP4(&Session{ID: "missing-vhs"}, Path(dir, "out.mp4"))

AssertError(t, err)
AssertContains(t, err.Error(), "vhs not installed")
}

func TestAX7_RenderMP4_Ugly(t *T) {
dir := t.TempDir()
vhsPath := Path(dir, "vhs")
writeResult := hostFS.WriteMode(vhsPath, "#!/bin/sh\nexit 7\n", 0o755)
RequireTrue(t, writeResult.OK)
previousCore := hostCore
c := New()
c.Action("process.run", func(_ Context, _ Options) Result {
return Fail(NewError("render failed"))
})
hostCore = c
defer func() { hostCore = previousCore }()
t.Setenv("PATH", dir)
err := RenderMP4(&Session{ID: "failing-vhs"}, Path(dir, "out.mp4"))

AssertError(t, err)
AssertContains(t, err.Error(), "vhs render")
}

// --- rawJSON JSON methods ---

func TestAX7_JSON_UnmarshalJSON_Good(t *T) {
var raw rawJSON
err := raw.UnmarshalJSON([]byte(`{"agent":"codex"}`))

RequireNoError(t, err)
AssertEqual(t, `{"agent":"codex"}`, string(raw))
}

func TestAX7_JSON_UnmarshalJSON_Bad(t *T) {
var raw *rawJSON
err := raw.UnmarshalJSON([]byte(`{}`))

AssertError(t, err)
AssertContains(t, err.Error(), "nil receiver")
}

func TestAX7_JSON_UnmarshalJSON_Ugly(t *T) {
raw := rawJSON(`previous-value`)
err := raw.UnmarshalJSON([]byte(`[1]`))

RequireNoError(t, err)
AssertEqual(t, `[1]`, string(raw))
AssertLen(t, raw, 3)
}

func TestAX7_JSON_MarshalJSON_Good(t *T) {
raw := rawJSON(`{"agent":"codex"}`)
got, err := raw.MarshalJSON()

RequireNoError(t, err)
AssertEqual(t, `{"agent":"codex"}`, string(got))
}

func TestAX7_JSON_MarshalJSON_Bad(t *T) {
var raw rawJSON
got, err := raw.MarshalJSON()

RequireNoError(t, err)
AssertEqual(t, "null", string(got))
}

func TestAX7_JSON_MarshalJSON_Ugly(t *T) {
raw := rawJSON{}
got, err := raw.MarshalJSON()

RequireNoError(t, err)
AssertEqual(t, "", string(got))
AssertLen(t, got, 0)
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Rename TestAX7_* to the required TestFunctionName_Context_Good/Bad/Ugly form.

The current names hide the symbol under test and miss the repository’s mandated convention. Please rename these to the actual API names, e.g. TestAnalyse_SingleToolUse_Good, TestRenderHTML_EscapesScript_Ugly, etc. As per coding guidelines, **/*_test.go: Test naming convention in Go: TestFunctionName_Context_Good/Bad/Ugly (happy path / expected errors / extreme edge cases).

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@ax7_test.go` around lines 13 - 537, All tests prefixed with TestAX7_* should
be renamed to follow TestFunctionName_Context_Good/Bad/Ugly using the actual API
symbols under test (e.g. rename TestAX7_Analyse_Good/Bad/Ugly →
TestAnalyse_SingleToolUse_Good / TestAnalyse_NilSession_Bad /
TestAnalyse_InputOutputTokens_Ugly), and similarly for FormatAnalytics,
Session.EventsSeq, Session.IsExpired, ListSessions, ListSessionsSeq,
PruneSessions, FetchSession, ParseTranscript, ParseTranscriptReader, Search,
SearchSeq, RenderHTML, RenderMP4 and rawJSON's UnmarshalJSON/MarshalJSON tests;
update each test function name to include the function/class under test
(Analyse, FormatAnalytics, EventsSeq, IsExpired, ListSessions, ListSessionsSeq,
PruneSessions, FetchSession, ParseTranscript, ParseTranscriptReader, Search,
SearchSeq, RenderHTML, RenderMP4, rawJSON.UnmarshalJSON, rawJSON.MarshalJSON)
plus a concise context and suffix _Good/_Bad/_Ugly so the test names follow the
repository convention and still map to the same test bodies.

Comment thread ax7_test.go

RequireNoError(t, err)
AssertLen(t, sessions, 1)
AssertEqual(t, "alpha", sessions[0].ID)
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Use SessionID; ID is not a field on Session.

parser.go:42-65 defines the struct with SessionID, so every sess.ID assertion and Session{ID: ...} literal here is a compile-time breakage.

Suggested fix
- AssertEqual(t, "alpha", sessions[0].ID)
+ AssertEqual(t, "alpha", sessions[0].SessionID)

- sess := &Session{ID: "alpha-session", StartTime: time.Date(2026, 2, 20, 10, 0, 0, 0, time.UTC), EndTime: time.Date(2026, 2, 20, 10, 0, 1, 0, time.UTC), Events: []Event{{Type: "tool_use", Tool: "Bash", Input: "echo ok", Output: "ok", Success: true}}}
+ sess := &Session{SessionID: "alpha-session", StartTime: time.Date(2026, 2, 20, 10, 0, 0, 0, time.UTC), EndTime: time.Date(2026, 2, 20, 10, 0, 1, 0, time.UTC), Events: []Event{{Type: "tool_use", Tool: "Bash", Input: "echo ok", Output: "ok", Success: true}}}

Also applies to: 182-182, 205-205, 253-253, 284-284, 331-331, 408-408, 418-418, 453-453, 462-462, 481-481

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@ax7_test.go` at line 148, The tests reference a non-existent Session.ID
field; update all assertions and literals to use the correct SessionID field
defined on the Session struct. Replace uses like sessions[0].ID with
sessions[0].SessionID and any Session{ID: "..."} composite literals with
Session{SessionID: "..."}, e.g., in AssertEqual calls and Session constructors
(occurrences around AssertEqual, Session literals at the listed lines). Ensure
all test references (sessions, AssertEqual) consistently use SessionID so the
code compiles against parser.go's Session struct.

Comment thread parser_other.go
"io" // Note: intrinsic — keeps the platform stub signature aligned with the Unix io.ReadCloser implementation; no core equivalent

coreerr "dappco.re/go/core/log"
coreerr "dappco.re/go"
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify all non-test Go files use the mandated coreerr import path.
fd -e go | rg -n --no-heading 'coreerr\s+"dappco\.re/go"' 
fd -e go | rg -n --no-heading 'coreerr\s+"dappco\.re/go/core/log"'

Repository: dAppCore/go-session

Length of output: 45


🏁 Script executed:

fd -name "parser_other.go"

Repository: dAppCore/go-session

Length of output: 294


🏁 Script executed:

fd "parser_other.go"

Repository: dAppCore/go-session

Length of output: 79


🏁 Script executed:

cat -n parser_other.go | head -20

Repository: dAppCore/go-session

Length of output: 885


🏁 Script executed:

rg 'coreerr\s+"' --type go

Repository: dAppCore/go-session

Length of output: 176


🏁 Script executed:

cat go.mod

Repository: dAppCore/go-session

Length of output: 131


Update all coreerr imports to use the mandated path.

The import in parser_other.go line 9 (and identically in parser_unix.go and parser.go) must be changed from dappco.re/go to dappco.re/go/core/log to comply with the error-handling guidelines requiring all coreerr.E(op, msg, err) calls to source from dappco.re/go/core/log.

🔧 Proposed fix
 import (
 	"io" // Note: intrinsic — keeps the platform stub signature aligned with the Unix io.ReadCloser implementation; no core equivalent
 
-	coreerr "dappco.re/go"
+	coreerr "dappco.re/go/core/log"
 )

This change is required in all three files: parser_other.go, parser_unix.go, and parser.go.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
coreerr "dappco.re/go"
import (
"io" // Note: intrinsic — keeps the platform stub signature aligned with the Unix io.ReadCloser implementation; no core equivalent
coreerr "dappco.re/go/core/log"
)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@parser_other.go` at line 9, Update the import alias for the core error
package: replace the import coreerr "dappco.re/go" with coreerr
"dappco.re/go/core/log" in parser_other.go and make the identical change in
parser_unix.go and parser.go so all calls like coreerr.E(op, msg, err) resolve
to the mandated package; search for the import lines in each file and update the
string literal only, leaving the alias (coreerr) and all existing usages
unchanged.

Comment thread parser.go
Comment on lines +11 to +12
core "dappco.re/go"
coreerr "dappco.re/go"
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Remove duplicate import of the same package.

Static analysis correctly identifies that dappco.re/go is imported twice with different aliases (core and coreerr). This is redundant and violates import hygiene.

Since the package provides both general utilities (core.Sprintf, core.Contains, etc.) and error handling (coreerr.E, coreerr.Warn), consolidate to a single import and use one alias consistently.

🔧 Proposed fix: use single alias
 import (
 	"io"     // Note: intrinsic — Reader, ReadCloser, and EOF contracts for transcript streams and hostFS handles; no core equivalent
 	"io/fs"  // Note: intrinsic — fs.FileInfo metadata returned from hostFS.Stat; no core equivalent
 	"iter"   // Note: intrinsic — public lazy sequence API for sessions and events; no core equivalent
 	"slices" // Note: intrinsic — iterator collection, sorted keys, and session ordering; no core equivalent
 	"time"   // Note: intrinsic — RFC3339 transcript timestamps and session age calculations; no core equivalent

 	core "dappco.re/go"
-	coreerr "dappco.re/go"
 )

Then replace all coreerr.E with core.E and coreerr.Warn with core.Warn throughout the file.

🧰 Tools
🪛 GitHub Check: SonarCloud Code Analysis

[warning] 12-12: Remove this import; the package is already imported with alias 'core'

See more on https://sonarcloud.io/project/issues?id=dAppCore_go-session&issues=AZ3VO4uI_sfuB3cpLiiH&open=AZ3VO4uI_sfuB3cpLiiH&pullRequest=6

🪛 golangci-lint (2.11.4)

[error] 11-11: ST1019: package "dappco.re/go" is being imported more than once

(staticcheck)


[error] 12-12: ST1019(related information): other import of "dappco.re/go"

(staticcheck)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@parser.go` around lines 11 - 12, The file imports the same package twice as
both `core` and `coreerr`; remove the duplicate import and consolidate to a
single alias (keep `core`) in the import block, then replace all uses of
`coreerr.E` and `coreerr.Warn` with `core.E` and `core.Warn` respectively so the
code consistently uses the single import alias (search for symbols `coreerr.E`,
`coreerr.Warn`, and the import lines `core "dappco.re/go"` / `coreerr
"dappco.re/go"` to update).

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