Skip to content

A hermetic smoke writes a real-shape OpenClaw session file (#555 item 1) - #558

Open
philcunliffe wants to merge 6 commits into
masterfrom
fix/issue-555
Open

A hermetic smoke writes a real-shape OpenClaw session file (#555 item 1)#558
philcunliffe wants to merge 6 commits into
masterfrom
fix/issue-555

Conversation

@philcunliffe

@philcunliffe philcunliffe commented Jul 31, 2026

Copy link
Copy Markdown
Contributor

Follow-up to PR #552. Actions item 1 only of issue #555; item 2 is deliberately not actioned (see below).

What landed

hypaware-core/smoke/flows/backfill_openclaw_fixture.js, the missing sibling of
backfill_codex_fixture.js / backfill_claude_fixture.js. It:

  • boots @hypaware/ai-gateway + @hypaware/openclaw against a tmp HYP_HOME
  • stages a session file under the fake HOME's .openclaw/agents/<agentId>/sessions/<sessionId>.jsonl
    with a type: "session" v3 header and two type: "message" records in the verified two-level
    shape
    : the record line states only id/message/parentId/timestamp/type, and
    role, content, model, provider, api, stopReason, usage are nested under message
  • asserts the staged shape itself before asserting anything downstream of it, so a future edit
    cannot quietly flatten the fixture back into something the pre-OpenClaw backfill reads message fields one level too high, projecting 0 rows #552 reader would also pass
  • drives hyp backfill openclaw through dispatch / createCommandRegistry, mirroring the Codex flow
  • asserts the user-visible result: non-zero rows in ai_gateway_messages (the literal OpenClaw backfill projects 0 rows from real session files: message fields are read at the top level but OpenClaw nests them under 'message' #543
    regression, which reported status: ok with rows_written: 0), carrying the record lines'
    native message_ids, the envelope's content_text and model, and
    provider = anthropic / conversation_source = openclaw / client_name = openclaw
  • asserts the internal telemetry the Codex/Claude flows assert: a backfill.provider_finish span
    and a backfill.finish log under the run's dev_run_id with matching row counts, a
    backfill.write span for ai_gateway_messages, plus the provider's own
    openclaw.backfill.session_projected log with identity_source = native
  • asserts idempotency: a second run under a fresh run id writes zero new rows and the query
    still returns exactly two

hypaware-core/smoke/lib/openclaw_session_fixture.js holds the fixture writer
(openclawMessageLine / writeOpenclawSessionFixture), mirroring
test/plugins/openclaw-backfill.test.js's messageLine() and
test/plugins/openclaw-settlement.test.js's sessionFileLine() rather than inventing a shape.

Flows are resolved by filename by hypaware-core/smoke/lib/harness.js, so registering the flow is
the file itself; there is no separate index list to edit. No LLP changed: this is a test-coverage
gap, not a design change (no LLP in the 0157-0162 set states a smoke inventory).

Mutation-test evidence

The fix here is the test, so it has to be shown to have teeth. The two-level handling in
hypaware-core/plugins-workspace/openclaw/src/session_file.js was temporarily reverted to the
pre-#552 behavior (read every message field off the record line):

 function openclawMessageEnvelope(row) {
-  return isPlainObject(row.message) ? row.message : row
+  return row
 }

Under mutation, the new smoke FAILS with #543's exact signature (status: ok, rows_written: 0):

$ npm run smoke -- backfill_openclaw_fixture
> node ./hypaware-core/smoke/index.js backfill_openclaw_fixture

smoke backfill_openclaw_fixture: FAIL
backfill run 1: openclaw provider ok and wrote NON-ZERO rows (#543 reported ok with 0)
  value={
  "provider": "openclaw",
  "plugin": "@hypaware/openclaw",
  "datasets": [
    "ai_gateway_messages"
  ],
  "status": "ok",
  "items_seen": 0,
  "sessions_seen": 0,
  "rows_written": 0,
  "rows_skipped": 0
}
  smoke=backfill_openclaw_fixture dev_run_id=smoke-backfill_openclaw_fixture-2026-07-31T23-29-42-811Z-20779

Restored (git checkout -- hypaware-core/plugins-workspace/openclaw/src/session_file.js;
git status clean of the mutation), and it passes again:

$ git status --short
?? hypaware-core/smoke/flows/backfill_openclaw_fixture.js
?? hypaware-core/smoke/lib/openclaw_session_fixture.js

$ npm run smoke -- backfill_openclaw_fixture
> node ./hypaware-core/smoke/index.js backfill_openclaw_fixture

smoke backfill_openclaw_fixture: ok (dev_run_id=smoke-backfill_openclaw_fixture-2026-07-31T23-29-48-481Z-20919)

So the smoke would have caught #543.

Other checks in the worktree: npm test 3281 pass / 0 fail / 1 skipped; npm run typecheck clean;
npm run build:types clean.

Item 2 was deliberately NOT actioned

Issue #555 item 2 (the timestamp / id precedence asymmetry in session_file.js, where
timestamp resolves envelope-first via messageField while id resolves line-first) is left
exactly as merged. Quoting the issue's own reasoning:

Round 2 review pinned this with a dedicated test
(test/plugins/openclaw-session-file.test.js: 'the envelope wins for timestamp, the record line wins for id') and could construct no failure from the asymmetry itself: both consumers
(backfill.js, settle.js) read through the one shared reader, so they cannot disagree with each
other about which value wins. It was left pinned rather than changed, specifically to avoid a
behavior change with no evidence behind it in a final review round.

The issue asks to revisit it only "if a future change ever gives backfill.js and settle.js (or a
third consumer) independent access to the raw record for timestamp or id rather than going
through the shared reader." This PR adds no such consumer. The issue's "Non-issues (do not action)"
section was likewise left untouched.

Base branch note

This PR is stacked on fix/issue-543 (PR #552), not on master. PR #552 is still open and
unmerged, so on master the OpenClaw reader still takes message fields off the record line and this
smoke cannot pass there by construction. LLP 0173 records the same finding for its own T12: the
fixture "genuinely cannot be built correctly against the current tree." GitHub will retarget this
PR's base to master automatically when #552 merges. Merge #552 first.

Coordination with integration/openclaw-two-lane-capture (LLP 0173, task T12)

T12 on that branch also plans a backfill_openclaw_fixture, extended with a quiesce-window
dimension (mtime-based skipping of recently-touched session files) and a two-lane dedupe
assertion. T12 is currently blocked and explicitly held until #552 merges, which is the same
blocker this PR has.

This flow is written so T12 extends rather than replaces it:

  • the fixture writer is factored out into smoke/lib/openclaw_session_fixture.js, importable by a
    second flow rather than private to this one
  • writeOpenclawSessionFixture takes an optional caller-chosen mtimeMs (applied via fs.utimes),
    which is precisely the "controllable-mtime agents/<id>/sessions/ tree" T12 calls for. Nothing in
    this flow uses it; it is there so T12 does not have to fork the helper
  • header, records, agentId, and sessionId are all parameterizable, so a quiesce case can
    stage a second session file under the same agents root
  • naming is left open for a sibling flow (e.g. sweep_openclaw_quiesce) rather than claiming the
    generic name for this one case

Backlink for whoever merges: LLP 0173 task T12 ("the hermetic smoke gap", Section 9),
llp/0173-openclaw-two-lane-capture.plan.md on integration/openclaw-two-lane-capture.

Fixes #555

test and others added 5 commits July 31, 2026 22:00
A real OpenClaw v3 `type: "message"` record states only `id`, `parentId`,
`timestamp`, and `type` on the record line: `role`, `content`, `model`,
`provider`, `api`, `stopReason`, and `usage` are all nested under `message`.
The LLP 0158 reader read them off the record line, so every field came back
absent, every record resolved to `provider: unknown`, the backfill allowlist
excluded all of them, and `hyp status` reported `backfill @hypaware/openclaw
[done] (0 rows)` for a session it had failed to read. The settlement enricher
was broken the same way one seam later (`record.role`/`record.content`), so a
real session settled nothing either.

The reader now owns the envelope address: fields are read from the nested
`message` object, falling back to the record line for a record that nests
none, and `role`/`content` are normalized fields rather than something each
consumer picks out of the raw record. Both consumers read them off the
normalized message, so neither can drift a level again.

Fixtures across the three OpenClaw suites now write the real two-level shape
through one helper each; the old flat fixtures asserted an envelope OpenClaw
never writes, which is why the suite stayed green through the bug.

LLP 0158 records the verified record shape, the envelope read rule, and the
path-faithful-fixture consequence.

Co-Authored-By: Claude <noreply@anthropic.com>
… is the line's

Follow-up to the #543 envelope fix, from review of PR #552.

- `messageField` fell back on key *absence*, not value *usability*, so a
  present-but-unusable nested value permanently masked a good record-line
  one. A nested `provider: "  "` beside a line-level `provider: "anthropic"`
  resolved the record to `unknown` and the allowlist excluded it fail-closed;
  a nested `timestamp` that did not parse dropped `message_created_at`, which
  re-dates the row to session start, defeats the `--since` window (a
  timestamp-less item is kept unconditionally) and puts the settlement
  ordinal match outside every window so the turn never dedupes. Rule 3's
  present-value test now runs at both levels before the fallback decides.
- `id` is now read line-first, envelope-fallback. LLP 0158 verified message
  identity on the record line; envelope-first meant a future OpenClaw that
  copied the provider's own id into the nested message would silently repoint
  every `message_id` and `part_id`, so committed rows would stop deduping
  against new ones and the history would double with nothing raised.
- The OPENCLAW_HOME relocation fixture still wrote the invented flat shape,
  bypassing `messageLine`, so it passed with the envelope read reverted. It
  now goes through the helper, and the shape pin carries `idempotencyKey` so
  it matches the live key list the same file documents.
- Say which LEVEL `record` is: `parentId` is on the line, `idempotencyKey`
  and `toolCallId` are at `record.message`. The old wording invited the very
  read #543 was.
- LLP 0158 gains rules 6 and 7 for the two behaviors above, and the stale
  "no live OpenClaw install was reachable" note on `usageAttributes` is
  reconciled with the spelling this work verified.

Co-Authored-By: Claude <noreply@anthropic.com>
…xception

Three follow-ups to the round-1 fixes, all in the same family the round-1
findings were: a new behavior that no test pins, and docs that state a rule
the code does not follow.

- `statedValue`, the `content` present-value test the guard-order fix
  introduced, was entirely unpinned: replacing it with the identity function
  left the whole suite green while a nulled-out nested `content` suppressed a
  usable record-line value and landed `content: null` on the message. Pinned
  in both directions (line supplies it; absent when neither level does).
- `types.d.ts` still stated the blanket envelope-first rule over `id`, which
  the same commit made line-first (LLP 0158 rule 7), and over `content`,
  whose test refuses only `null`. The published declaration is what a package
  consumer reads, so it now names both exceptions.
- LLP 0158 rule 6 claimed a blank or wrong-typed nested value can never
  suppress the line. True of the string fields, false of `content`: a nested
  `content: "   "` or `content: 42` does suppress it. The rule now says what
  "reads as absent" is per field.

Also extends the non-object-`message` test with the `null` case, the one
input where the plain-object guard is the difference between reading the
record line and throwing out of the whole file read.

Co-Authored-By: Claude <noreply@anthropic.com>
#543 shipped green because tier 2 never touched an OpenClaw session file
in any shape. Codex and Claude each have a hermetic flow that stages a
real-shape transcript and drives `hyp backfill` against it; OpenClaw had
no analog, so the only gate that could catch the two-level nesting bug
was the manual acceptance smoke.

Adds `backfill_openclaw_fixture`, mirroring `backfill_codex_fixture.js`
and `backfill_claude_fixture.js`: boots `@hypaware/ai-gateway` +
`@hypaware/openclaw` against a tmp HYP_HOME, stages a v3 session file
under the fake HOME's `.openclaw/agents/<agentId>/sessions/<id>.jsonl`,
drives `hyp backfill openclaw`, and asserts non-zero `ai_gateway_messages`
rows with native record-line ids, envelope content, `provider=anthropic`,
`conversation_source=openclaw`, the `backfill.provider_finish` /
`backfill.write` spans and the `backfill.finish` log under the run's
`dev_run_id`, and a zero-new-rows idempotent rerun.

The fixture writer lives in `smoke/lib/openclaw_session_fixture.js` so no
flow can invent a flatter, friendlier record shape, and takes a
caller-chosen `mtimeMs` so the scheduled-sweep quiesce work (LLP 0173
T12) can extend it rather than replace it.

Co-Authored-By: Claude <noreply@anthropic.com>
openclawMessageLine's JSDoc claimed writing `timestamp` at both levels
"makes the envelope-first read of it observable," but the implementation
copied the same destructured binding to both levels, so they were
byte-identical and no assertion could tell envelope-first from line-first
precedence. Add an optional `messageTimestamp` field that overrides the
nested `message.timestamp` only, keeping the no-arg default (same value at
both levels) unchanged since a real session file does write it that way.
backfill_openclaw_fixture.js now stages the assistant record with a
distinct envelope timestamp and asserts the projected row's
`message_created_at` carries the envelope value, genuinely exercising the
LLP 0158 / #555 envelope-first precedence.

Also strengthen the run-2 idempotency assertion, which checked only
`status === 'ok' && rows_written === 0` under a comment claiming "all
part_ids already present" but never pinned that the session was actually
re-read. A whole-file skip (e.g. the mtime-based quiesce-window skip LLP
0173 T12 will add, using the `mtimeMs` hook this PR introduced) would
report the same zero rows_written and pass identically. Require
`items_seen >= 1 && rows_skipped >= 1` too, so the predicate pins the
dedupe mechanism the comment describes instead of being satisfied
vacuously by a skip.

Co-Authored-By: Claude <noreply@anthropic.com>
@philcunliffe

Copy link
Copy Markdown
Contributor Author

Review round 1 (head 98ff30c)

Verdict: findings (2 minor, both fixed at af73aa2). No blockers. codex is not
available on this host, so this was a single-family review (code-review), not a dual review.

The PR adds the missing hermetic smoke that would have caught #543, plus a factored-out
fixture writer. Both findings are the same class of problem: an assertion that reads as a
gate but could not actually fail.

Finding 1 (minor) - hypaware-core/smoke/lib/openclaw_session_fixture.js:35

JSDoc claimed the fixture makes the envelope-first timestamp read observable; it could not.
The doc block said writing timestamp at both levels is "what makes the envelope-first read of
it observable", but the implementation copied the same destructured timestamp binding to
both the record line and the nested message. The two levels were byte-identical, so no
assertion could distinguish envelope-first from line-first precedence. The flow also asserted
nothing about timestamps at all. The one field LLP 0158 and issue #555 single out as
non-obvious was the one field the fixture provably did not exercise, while the comment
asserted the opposite.

Fixed (af73aa2): openclawMessageLine now takes an optional messageTimestamp that
overrides the nested message.timestamp only. The flow stages an assistant record with a
distinct line timestamp (...10:00:02Z) and envelope timestamp (...10:00:09Z), asserts the
two differ in the fixture, and asserts the projected row's message_created_at carries the
envelope value. Default behavior with no messageTimestamp is unchanged, since a real
session file does carry the same value at both levels.

Finding 2 (minor) - hypaware-core/smoke/flows/backfill_openclaw_fixture.js:260

The idempotency assertion would have gone silently vacuous. Run 2 checked only
status === 'ok' && rows_written === 0 under a comment claiming "all part_ids already
present". It does dedupe for real today (measured run-2 result: items_seen: 1, sessions_seen: 0, rows_written: 0, rows_skipped: 1, i.e. the provider re-yielded the exchange
and materializeItem returned zero rows). But a run that skipped the file entirely would
yield items_seen: 0, rows_written: 0 and pass identically. That is not hypothetical here:
the mtimeMs hook this PR deliberately adds exists so LLP 0173 task T12 can add
mtime-based quiesce-window skipping to this same fixture, which is precisely the change that
would hollow out this gate without failing it.

Fixed (af73aa2): the run-2 predicate now also requires items_seen >= 1 && rows_skipped >= 1,
pinning the part_id-dedupe mechanism the comment claims. Field names were verified against
src/core/commands/backfill.js.

Teeth check (re-run after the fixes)

The smoke is a regression gate, so the decisive question is whether it still fails when the
bug returns. Mutating openclawMessageEnvelope in
hypaware-core/plugins-workspace/openclaw/src/session_file.js to return row (the pre-#552
flat read) makes the smoke fail on its first assertion, reproducing #543's exact signature:

backfill run 1: openclaw provider ok and wrote NON-ZERO rows (#543 reported ok with 0)
value={"provider":"openclaw", ..., "status":"ok","items_seen":0,"sessions_seen":0,"rows_written":0,"rows_skipped":0}

Restored, the smoke passes. Checks at af73aa2: npm test 3281 pass / 0 fail (1 pre-existing
skip), npm run typecheck clean, target smoke green. CI at the new head is the authority.

Deliberately not raised

The head has moved to af73aa2, so the next tick reviews that head as round 2.

Round-2 review nits on the tier-2 gate added for #543. Both are in the
`session_projected` telemetry assertion, and this file exists purely as a
regression gate, so assertion precision is its whole job.

The filter matched on the log body alone, the only one of the four
telemetry assertions not constrained to the run. Two records exist: the
idempotency rerun dispatches with a fresh `DEV_RUN_ID`, and the plugin
logger stamps it, so run 2 emits its own `session_projected` under
`<dev_run_id>-rerun`. Reading `projected[0]` was correct only because
emission order happens to put run 1 first, which is ordering rather than
identity. Constrain it to `harness.devRunId` and this session's native
`session_id`, matching what the three sibling filters already do.

The `identity_source === 'native'` conjunct could never be false: the
plugin hardcodes the string at `session_projected`'s single emission
site, so the conjunct held whenever the log existed at all, while the
comment read as though it separated a native-identity path from a
fallback one. Drop it, and state what the assertion does pin: that the
projection was reached, for this session, with both messages. The
identity claim now sits where it can genuinely vary - `session_id` on
the log, alongside the record lines' `message_id`s already asserted on
the rows.

No behavior change. Both round-2 mutations still fail the smoke: a flat
`openclawMessageEnvelope` reproduces #543's `status: ok` /
`rows_written: 0` on the first behavioral assertion, and swapping
`messageField`'s envelope/line order for `timestamp` fails the
envelope-precedence assertion with the record-line 10:00:02 value.

Co-Authored-By: Claude <noreply@anthropic.com>
@philcunliffe

Copy link
Copy Markdown
Contributor Author

Review round 2 (head af73aa2)

Verdict: findings (2 nits, both fixed at 3f8dc01). No blockers, no majors.
Single-family review (code-review); codex is not available on this host.

This round re-reviewed the whole head with particular attention to whether round 1's two
fixes were correct and complete. They are. Both new findings are about assertion precision
in the same telemetry block, which matters here because this file exists purely as a
regression gate.

Teeth check: PASS (two independent mutations)

The decisive question for this PR is whether the smoke actually fails when the bug returns.
Two separate mutations were applied to
hypaware-core/plugins-workspace/openclaw/src/session_file.js, each reverted with
git checkout -- and re-verified green afterwards:

(A) Revert the two-level read (openclawMessageEnvelope to return row). The smoke fails
fast on its first behavioral assertion, reproducing #543's exact signature:

backfill run 1: openclaw provider ok and wrote NON-ZERO rows (#543 reported ok with 0)
value={"provider":"openclaw","status":"ok","items_seen":0,"sessions_seen":0,"rows_written":0,"rows_skipped":0}

(B) Isolate round 1's fix (flip messageField(envelope, row, 'timestamp', ...) to
messageField(row, envelope, ...), line-first for that one field only). Every earlier
assertion still passes and the smoke fails precisely on the new assertion, with
message_created_at showing the record-line value 2026-05-20T10:00:02.000Z instead of the
envelope value ...10:00:09.000Z. This confirms the envelope-precedence assertion pins what
it claims and is not passing for an unrelated reason.

expect.that throws on first failure, so the flow is fail-fast and no later assertion can
mask an earlier one.

Finding 1 (nit) - hypaware-core/smoke/flows/backfill_openclaw_fixture.js:347

The session_projected filter depended on emission order rather than identity. It matched
on l.body alone and then read projected[0], while its three sibling telemetry assertions
all pin dev_run_id. Because the idempotency rerun deliberately sets a fresh DEV_RUN_ID,
two matching records exist (run 1, and run 2 with a -rerun suffix). Not vacuous today,
since emission order puts run 1 first, but it was the one place a run-2 record could satisfy a
run-1 claim.

Fixed (3f8dc01): the filter now also requires
l.attributes?.[Attr.DEV_RUN_ID] === harness.devRunId && l.attributes?.session_id === sessionId.
Both attributes were empirically confirmed present on the log before being relied on.

Finding 2 (nit) - hypaware-core/smoke/flows/backfill_openclaw_fixture.js:353

identity_source === 'native' was a tautological conjunct. The value is a hardcoded string
literal at the single emission site (plugins-workspace/openclaw/src/backfill.js:317), so it can
never be false when the log exists, yet the surrounding comment read as though the assertion
distinguished a native-identity path from a fallback one.

Fixed (3f8dc01): the conjunct is dropped and the comment rewritten to state what is
actually pinned. The identity claim moved onto the filter as session_id, where it genuinely
can be false. The row assertions already pin native message_ids, so no change was needed there.

Checks at 3f8dc01

npm run smoke -- backfill_openclaw_fixture ok; npm test 3281 pass / 0 fail (1 pre-existing
skip); npm run typecheck clean. Both mutations re-run after the fixes and still fail as above,
so the gate survived the edit. CI at the new head is the authority.

Caveat for the human, not a finding and not introduced by this PR

.github/workflows/ci.yml runs only npm i, npm run typecheck, and npm test. No smoke
flow runs in CI
, including this one and its backfill_codex_fixture / backfill_claude_fixture
siblings. Issue #555 frames the missing smoke as the reason #543 shipped green, but a smoke CI
never executes would not have stopped it either. This PR still closes the stated coverage gap and
the flow is correct; whether the hermetic tier should gate CI is a repo-level tiering decision,
deliberately left to the maintainer.

Deliberately not raised

This is the second and final review round under the 2-round cap. The head has moved to
3f8dc01; the next tick triages rather than reviewing again.

@philcunliffe

Copy link
Copy Markdown
Contributor Author

The review fix-loop reached its 2-round cap, so this landed on the triage rung (LLP 0017).

I independently re-verified all four findings raised across both review rounds against the
committed tree at 3f8dc01 (the current head), reading the code rather than trusting the
review comments' prose:

  • R1-1 (hypaware-core/smoke/lib/openclaw_session_fixture.js): openclawMessageLine now
    takes an optional messageTimestamp that overrides only the nested message.timestamp
    (lines 45-51). The flow (hypaware-core/smoke/flows/backfill_openclaw_fixture.js) stages a
    record with distinct line (10:00:02Z) and envelope (10:00:09Z) timestamps, asserts they
    differ in the fixture (line 149), and asserts the projected message_created_at carries the
    envelope value (line 263). Fixed.
  • R1-2 (same flow file, idempotency assertion): the run-2 predicate now requires
    v.status === 'ok' && v.rows_written === 0 && v.items_seen >= 1 && v.rows_skipped >= 1
    (lines 292-297), no longer vacuous under a whole-file skip. Fixed.
  • R2-1 (session_projected log filter): now pins both
    l.attributes?.[Attr.DEV_RUN_ID] === harness.devRunId and l.attributes?.session_id === sessionId
    (lines 349-356), rather than relying on emission order between the two dev_run_ids in play.
    Fixed.
  • R2-2 (identity_source === 'native' tautology): the conjunct is gone; identity_source
    no longer appears in any assertion, only in the explanatory comment noting why it was dropped.
    The identity claim moved onto the filter's session_id check. Fixed.

I also re-ran npm run smoke -- backfill_openclaw_fixture in an isolated worktree at this head:
it passes.

Zero unresolved findings remain. Per the task's guidance, an issue enumerating nothing would be
noise, so no follow-up issue was opened. Out-of-scope items (the deliberate fix/issue-543 base
branch, the timestamp/id asymmetry #555 explicitly defers, and #555's "Non-issues" list) were
left untouched, as instructed by both review rounds and issue #555 itself.

Judgement: this PR can ship safely.

@philcunliffe philcunliffe added the neutral:approved neutral reviewed this and holds it for a maintainer merge (own or adopted PR; LLP 0025/0030) label Aug 1, 2026
@philcunliffe
philcunliffe marked this pull request as ready for review August 1, 2026 02:10
Base automatically changed from fix/issue-543 to master August 2, 2026 02:00
@philcunliffe

Copy link
Copy Markdown
Contributor Author

⚠️ Merge-order conflict: #558 and #570 both create the same file

Both open PRs add hypaware-core/smoke/flows/backfill_openclaw_fixture.js, and neither is
on master yet. Whichever merges first, the second will conflict on that path.

PR Why it adds the file What its version does
#558 Fixes issue #555 (no hermetic smoke ever wrote a real-shape OpenClaw session file, which is why #543 shipped green) Plain fixture smoke: real two-level envelope shape, non-zero rows, telemetry assertions, idempotency. Mutation-tested: reverting openclawMessageEnvelope to a flat read reproduces #543's signature and fails the smoke. Also adds hypaware-core/smoke/lib/openclaw_session_fixture.js.
#570 Task T12 of LLP 0173, the openclaw-two-lane-capture change set Adds the Lane B dimensions the change set needs: quiesce-window behaviour (a file inside the window is skipped, outside it is captured) and a zero-duplicate assertion across both capture lanes.

They were written to different specs and neither is a superset of the other, so I have not
picked a winner or merged them.
That is a design call about what the smoke tier should
assert, and it is yours.

How this happened

When #558 was written I asked its author to factor the fixture writer out and make mtimeMs
caller-controllable specifically so T12 could extend it rather than replace it. T12 was then
implemented from LLP 0173's own task spec, independently, and produced its own version. The
two efforts never saw each other because they ran on branch-disjoint workers, which is the
same isolation that lets them run in parallel.

Options

  1. Merge OpenClaw two-lane capture (LLP 0172/0173): Lane A attach, Lane B sweep, json_path revival #570 first, then reconcile A hermetic smoke writes a real-shape OpenClaw session file (#555 item 1) #558 onto it — keeps the richer two-lane version, and
    A hermetic smoke writes a real-shape OpenClaw session file (#555 item 1) #558's distinctive value (the mutation-tested regression gate for OpenClaw backfill projects 0 rows from real session files: message fields are read at the top level but OpenClaw nests them under 'message' #543) gets folded in.
  2. Merge A hermetic smoke writes a real-shape OpenClaw session file (#555 item 1) #558 first, then reconcile OpenClaw two-lane capture (LLP 0172/0173): Lane A attach, Lane B sweep, json_path revival #570 onto it — keeps the mutation-tested gate as the
    base, and T12's quiesce/dedupe cases get added on top.
  3. Tell me which to keep and I will reconcile the other onto it and re-verify from CI.

Say which on either thread and I will carry it out on the next tick. Until then both PRs stay
held.

Related: #552 was squash-merged, so #558's branch still carries the original pre-squash
commits. GitHub still reports it MERGEABLE against master, so this is informational only,
but it is why #558's diff looks wider than its own changes.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

neutral:approved neutral reviewed this and holds it for a maintainer merge (own or adopted PR; LLP 0025/0030)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant