fix: drop the duplicate **Timestamp** line from audit blocks (2.6.4) - #759
fix: drop the duplicate **Timestamp** line from audit blocks (2.6.4)#759warren830 wants to merge 1 commit into
Conversation
renderAuditBlock writes `**Timestamp**:` itself but did not filter the key out of caller-supplied `fields`, so the three emitters that passed it — `park`, `unpark`, and the `practices-promote` write-failure path — rendered two identically-marked lines in one block. A reader that pairs `**Timestamp**` occurrences with `**Event**` occurrences desynchronises at the first parked workflow and misattributes the time of every later event. Fixed at both layers, as the issue proposes: - render: `EMITTER_OWNED_FIELD_KEYS` skips `Timestamp`/`Event` in the fields loop, so no caller can produce a second line. - callers: the three emitters stop passing the redundant field. `Timestamp` stays out of RESERVED_FIELD_KEYS on purpose — the public `audit append --field Timestamp=...` contract must keep accepting it, and t261 pins that. The value is now dropped at render instead of duplicated. Tests: t111 pins the render-layer contract (caller value gone, emitter line intact, sibling fields undisturbed); t17 pins the file-wide invariant that **Timestamp** count equals block count across park + unpark. Fixes awslabs#715
apackeer
left a comment
There was a problem hiding this comment.
Warren, this PR fixes #715 by filtering emitter-owned audit fields at the shared renderer, removing the three redundant Timestamp caller fields, and regenerating every harness distribution. I reviewed the issue and the implementation against origin/v2; the duplicate structured-event fields are reproducible there, and the code change is narrowly scoped.
Part A - Direction: sound. The problem exists, core/tools/aidlc-audit.ts is the correct harness-neutral enforcement point, and the caller cleanup in core/tools/aidlc-state.ts closes the known sources without changing the public command surface. bun scripts/package.ts --check passes for all seven harnesses.
Part B - Review: request changes.
docs/reference/12-state-machine.md:451is stale after this change. It still says park/unpark carry a caller-suppliedTimestampand rely on the emitter's line being first. The PR now removes those fields and drops public--field Timestamp=...values at render time. Please update this contract paragraph to match the new behavior.
The independent review's three notes do not add blocking findings: the accepted-but-dropped Timestamp value is deliberate and tested, 2.6.4 is the correct current version slot, and append-raw is a pre-existing path outside the structured renderer.
Verification: bun scripts/package.ts --check passed; focused tests passed twice at tests/logs/2026-08-14T08-06-47Z-p2 and tests/logs/2026-08-14T08-08-24Z-p7894, each with 4 files and 202 assertions; git diff --check passed. Version, changelog heading, and README badge are synchronized, and no new numbered test file was introduced.
Part C - UX impact. There are no command, flag, prompt, stage, default, or error changes. New structured audit rows stop duplicating timestamps; audit append --field Timestamp=... remains accepted but now silently ignores the supplied value. Historical audit data remains byte-unchanged and requires no engine migration.
Summary
Audit blocks carried a duplicate
**Timestamp**:line.renderAuditBlockwrites the timestamp itself, but did not filter the key out of caller-suppliedfields, so the three emitters that passed it rendered two identically-marked lines in one block.The consequence is not cosmetic for anything that reads
audit.mdas a whole file: a reader that pairs**Timestamp**occurrences with**Event**occurrences desynchronises at the first parked workflow and misattributes the time of every later event.Fixes #715.
Changes
Fixed at both layers, which is what the issue proposes:
core/tools/aidlc-audit.ts: newEMITTER_OWNED_FIELD_KEYS(Timestamp,Event) is skipped in thefieldsloop, so no caller can produce a second line.core/tools/aidlc-state.ts:park,unpark, and thepractices-promotewrite-failure path stop passing the redundant field. Both local timestamp values are still used forLast Updated/Parked, so nothing else moves.core/knowledge/aidlc-shared/audit-format.md:WORKFLOW_PARKEDfield order corrected toTimestamp, Stage, matching every neighbouring row (the reversed order was an artifact of the buggy emit order).Timestampdeliberately stays out ofRESERVED_FIELD_KEYS. Adding it there is the tempting wrong fix: it would break the publicaudit append --field Timestamp=...contract thatt261-audit-authority-floorpins. The value is now dropped at render instead of refused, so that test stays green — only its stale rationale comment is updated.User experience
The rendered timestamp value is unchanged; only the redundant second line is gone. Existing
audit.mdshards need no migration — the duplicate was redundant rather than wrong, and the first occurrence was always the authoritative one.Checklist
Test Plan
Two new tests, both in files whose
covers:headers already carry the right tokens, so no coverage-registry regeneration:tests/unit/t111.test.ts— render-layer contract: a caller-suppliedTimestampleaves exactly one**Timestamp**and one**Event**in the block, the surviving line is the emitter's, the caller's value is absent entirely, and sibling fields are undisturbed.tests/unit/t17.test.ts— the reporter's actual symptom: acrosspark+unpark, the file-wide**Timestamp**count equals the block count.Verified locally (bun 1.3.11; CI pins 1.3.14):
The suite result is identical to the pre-change baseline on this branch point: the same 2 files fail (
t248-codekb-scope-diff,t255-workspace-sync) with the same 9 assertions, both unrelated to audit rendering (t255's failures are ~5s timeouts on live git remote queries and look environmental here). Total assertions went 6038 → 6040, the two added above. Targeted runst111,t17,t261,t68all pass.Version bumped to 2.6.4 rather than 2.6.3, since #754 and #758 both already claim 2.6.3.
Acknowledgment
By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of the project license.