test: address Codex review of property tests (PR 3)

- llm: generator now emits finish chunks (the finish-defaults property was
  vacuously green); add a property asserting streaming and one-shot assembly
  agree on usage and finish
- agent-loop: assert the synchronous burst batches into exactly one turn; add
  a mixed-schedule property (send/settle interleavings); recordStatus returns
  its disposer; per-run timeouts so a hang loses no seed
- session: randomize the noise/message interleaving (was a fixed alternation)
- tools: exclude non-finite doubles from generated numeric args (JSON-real)
This commit is contained in:
Tianyi Cui
2026-06-14 00:24:23 +08:00
parent 2f6d3b8539
commit 7b07b70750
4 changed files with 91 additions and 23 deletions

View File

@@ -74,19 +74,24 @@ describe('Session properties', () => {
}))
})
it('non-message events never affect derived history', () => {
it('non-message events never affect derived history (any interleaving)', () => {
fc.assert(fc.property(
fc.array(messageEventArb, { maxLength: 12 }),
fc.array(nonMessageEventArb, { maxLength: 12 }),
(messages, noise) => {
// The same message events, with and without interleaved noise, derive
// the same history (noise is inserted at arbitrary positions).
// An arbitrary merge of the two streams that PRESERVES each stream's
// relative order (a random interleaving, not a fixed alternation).
fc.infiniteStream(fc.boolean()),
(messages, noise, pick) => {
const clean = build(messages).deriveMessages()
const interleaved: Appendable[] = []
const maxLen = Math.max(messages.length, noise.length)
for (let i = 0; i < maxLen; i++) {
if (i < noise.length) interleaved.push(noise[i]!)
if (i < messages.length) interleaved.push(messages[i]!)
let mi = 0
let ni = 0
const picker = pick[Symbol.iterator]()
while (mi < messages.length || ni < noise.length) {
// take from noise when chosen and available, else from messages
const takeNoise = ni < noise.length && (mi >= messages.length || picker.next().value === true)
if (takeNoise) { interleaved.push(noise[ni]!); ni++ }
else { interleaved.push(messages[mi]!); mi++ }
}
const withNoise = build(interleaved).deriveMessages()
expect(withNoise).toEqual(clean)