App-FuguBench

 view release on metacpan or  search on metacpan

t/fugubench/traces.t  view on Meta::CPAN

# Two more sessions of the checkout, each one with a panel launch and
# then the writes of a scratch path. Session 8 holds the two files that
# .gitignore covers, one path relative and one path absolute inside
# the checkout, and the edits column must take neither one.
# Session 9 holds three near misses, and it must take every one: the
# name must start a path segment, and a scratchpad must end the path
# (TRACE-PANEL-3).
_write(
	"$main/88888888-8888.jsonl",
	_record( 'req_p1', [ 1, 2, 3 ], 4,
		_tool( 'Agent', description => 'Panel review member 1' ) )
	    . _record( 'req_p2', [ 1, 2, 3 ], 4,
		_tool( 'Write', file_path => 'SCRATCHPAD-1.md' ),
		_tool( 'Write', file_path => "$checkout/SCRATCHPAD-2.md" ) )
);
_write(
	"$main/99999999-9999.jsonl",
	_record( 'req_n1', [ 1, 2, 3 ], 4,
		_tool( 'Agent', description => 'Panel review member 1' ) )
	    . _record( 'req_n2', [ 1, 2, 3 ], 4,
		_tool( 'Write', file_path => 'myscratch/x.md' ),
		_tool( 'Write', file_path => 'NOTSCRATCHPAD.md' ),
		_tool( 'Write', file_path => 'SCRATCHPAD-3.md.bak' ) )
);

# Three sessions of the checkout boundary, each one with a panel
# launch and then one write. The edits column counts a repository file
# of the measured checkout only (TRACE-PANEL-3). Session B writes a
# file inside the checkout, which is one. Session C writes the memory
# file of a session, under a .claude/projects/ path of the operator
# HOME in shape, which is none. Session D writes a file of a sibling
# checkout, which is none, as the directory match rejects the sibling.
_write(
	"$main/bbbbbbbb-bbbb.jsonl",
	_record( 'req_b1', [ 1, 2, 3 ], 4,
		_tool( 'Agent', description => 'Panel review member 1' ) )
	    . _record( 'req_b2', [ 1, 2, 3 ], 4,
		_tool( 'Write', file_path => "$checkout/spec/workspace.md" ) )
);
_write(
	"$main/cccccccc-cccc.jsonl",
	_record( 'req_c1', [ 1, 2, 3 ], 4,
		_tool( 'Agent', description => 'Panel review member 1' ) )
	    . _record(
		'req_c2',
		[ 1, 2, 3 ],
		4,
		_tool(
			'Write',
			file_path => "$root/.claude/projects"
			    . '/-x-Work-FuguBSD/memory/session-rules.md'
		)
	    )
);
_write(
	"$main/dddddddd-dddd.jsonl",
	_record( 'req_d1', [ 1, 2, 3 ], 4,
		_tool( 'Agent', description => 'Panel review member 1' ) )
	    . _record( 'req_d2', [ 1, 2, 3 ], 4,
		_tool( 'Write',
			file_path => "$checkout-backup/spec/workspace.md" ) )
);

# One session of the panel of an early campaign, before the org pack
# shipped a reviewer agent. The launch carries a catch-all type, which
# names no role, so the description decides and the launch is a round.
_write(
	"$main/aaaaaaaa-aaaa.jsonl",
	_record( 'req_c1', [ 1, 2, 3 ], 4,
		_tool(
			'Agent',
			subagent_type => 'general-purpose',
			description   => 'Panel review member 1'
		) )
);

# One worktree of the checkout, one project clone in it, and one
# sibling checkout that the match must reject.
_write( "$root/fixture--claude-worktrees-w1/22222222-2222.jsonl",
	_session('w') );
_write( "$root/fixture-backup/33333333-3333.jsonl",           _session('b') );
_write( "$root/fixture-Projects-Tooling/44444444-4444.jsonl", _session('p') );

my ( $code, $out ) = _traces( $cwd, $root, 'fixture' );
is( $code, 0, 'traces exits zero' );

my ($row) = grep { /^11111111\b/ } split /\n/, $out;
ok( $row, 'the main session gets a row' ) or diag $out;
my @field = split q{ }, $row // q{};

is( $field[1], '2026-09-09T09:59', 'the start time is the first record' );
is( $field[2], 3,                  'the record count is a request count' );
is( $field[3], 3330,    'the peak reads the last record of a request' );
is( $field[4], 140,     'the output reads the last record of a request' );
is( $field[5], 1,       'a panel launch is a round, a fixer is not' );
is( $field[6], 2,
	'an edit before the launch, and a write under scratch/, do not count' );
is( $field[7], 12765, 'the sub-agent input counts one time' );
is( $field[8], 26,    'the sub-agent output counts one time' );
is( $field[9], 888,   'rev-peak takes the panel member, not the fixer' );

like( $out, qr/^22222222/m, 'a worktree of the checkout joins' );
like( $out, qr/^44444444/m, 'a project clone joins' );
unlike( $out, qr/^33333333/m, 'a sibling checkout stays out' );

unlike( $out, qr/^77777777/m, 'a session with no request gets no row' );

my @pad  = split q{ }, ( grep { /^88888888\b/ } split /\n/, $out )[0] // q{};
my @near = split q{ }, ( grep { /^99999999\b/ } split /\n/, $out )[0] // q{};
is( $pad[6], 0, 'a SCRATCHPAD*.md write is not an edit' ) or diag $out;
is( $near[6], 3, 'a near miss of the scratch pattern is an edit' )
    or diag $out;

my @in   = split q{ }, ( grep { /^bbbbbbbb\b/ } split /\n/, $out )[0] // q{};
my @home = split q{ }, ( grep { /^cccccccc\b/ } split /\n/, $out )[0] // q{};
my @sib  = split q{ }, ( grep { /^dddddddd\b/ } split /\n/, $out )[0] // q{};
is( $in[6], 1, 'a write inside the checkout is an edit' ) or diag $out;
is( $home[6], 0, 'a write to the operator HOME is not an edit' )
    or diag $out;
is( $sib[6], 0, 'a write to a sibling checkout is not an edit' )
    or diag $out;

my @cat = split q{ }, ( grep { /^aaaaaaaa\b/ } split /\n/, $out )[0] // q{};
is( $cat[5], 1, 'a catch-all agent type falls back to the description' )
    or diag $out;

my ( $none_code, $none_out ) = _traces( $cwd, $root, 'absent' );
is( $none_code, 0, 'a name with no trace directory exits zero' );
like( $none_out, qr/^no session of absent$/m, 'and it reports none' );

# Without --name, the verb derives the name from the checkout root,
# cut at the last .claude/worktrees/ marker (TRACE-NAME-1). The -C
# directory sits under two markers, and it holds a .toolingrc of its
# own, so it is the checkout root. The last marker names the inner
# checkout, and the first one names the outer checkout, whose trace
# directory must stay out.
my $nest = tempdir( CLEANUP => 1 );
my $deep = "$nest/.claude/worktrees/a/.claude/worktrees/b";
_write( "$deep/.toolingrc", q{} );

my $outer = abs_path($nest)                       =~ s/[^A-Za-z0-9-]/-/gr;



( run in 0.948 second using v1.01-cache-2.11-cpan-5e09290becf )