<!-- task=m-iop-agent-cli-runtime/21+13,17,20_project_log_sink plan=1 tag=REVIEW_API -->

# Project Log Sink Evidence and Exactly-Once Rework

## For the Implementing Agent

Filling every implementation-owned section in `CODE_REVIEW-cloud-G10.md` is mandatory. Implement the checklist, run every verification command, paste actual notes and stdout/stderr into the review file, keep both active Markdown files in place, and report ready for review; only the code-review skill finalizes the task. If blocked, record only the exact blocker, attempted commands/output, and resume conditions in implementation-owned evidence fields. Do not ask the user, call user-input tools, create control-plane stop files, classify the next state, archive logs, or write `complete.log`.

## Background

The first implementation passed its package checks but did not exercise the production `agenttask.EventSink` evidence path or the S12 archive invariant it claimed. This follow-up makes exact manager state enrichment, durable replay deduplication, task-scoped archives, and the archived WORK_LOG projection one end-to-end boundary.

## Archive Evidence Snapshot

- Current pair to archive during review finalization:
  - `agent-task/m-iop-agent-cli-runtime/21+13,17,20_project_log_sink/plan_local_G08_0.log`
  - `agent-task/m-iop-agent-cli-runtime/21+13,17,20_project_log_sink/code_review_cloud_G08_0.log`
- Prior verdict: `FAIL`.
- Required findings:
  - `EmitWithLocators` was test-only; production `Emit` discarded exact manager locators and synthesized route/state identities.
  - `TestS12LoopParallelArchiveMatrix` used separate project/workspace stores and no archive failure hooks; the archive timeline remained the legacy projection.
  - append was not idempotent by durable event identity, so replay before or after archive could duplicate records and archive ordinals; raw `Detail` leaked into the persisted `RecordID`.
  - the standalone contract used `project-log-sink` instead of `project-logs` and omitted exact S12 test paths.
- Fresh reviewer verification passed formatting, focused/full tests, race, vet, and `git diff --check`, but those commands did not repair the production-path evidence gaps.
- Roadmap carryover remains `project-logs`; no completion may be reported until the follow-up passes.

## Roadmap Targets

- Milestone: `agent-roadmap/phase/automation-runtime-bridge/milestones/iop-agent-cli-runtime.md`
- Milestone link: [Milestone document](agent-roadmap/phase/automation-runtime-bridge/milestones/iop-agent-cli-runtime.md)
- Task ids:
  - `project-logs`: project-local event/log plus WORK_LOG loop/attempt/locator and exactly-once archive lifecycle
- Completion mode: check-on-pass

## Analysis

### Files Read

- `agent-ops/rules/project/rules.md`
- `agent-ops/rules/private/rules.md`
- `agent-ops/rules/common/rules-roadmap.md`
- `agent-ops/rules/common/rules-agent-spec.md`
- `agent-ops/rules/project/domain/agent/rules.md`
- `agent-ops/rules/project/domain/testing/rules.md`
- `agent-ops/rules/project/domain/platform-common/rules.md`
- `agent-test/local/rules.md`
- `agent-roadmap/current.md`
- `agent-roadmap/phase/automation-runtime-bridge/PHASE.md`
- `agent-roadmap/phase/automation-runtime-bridge/milestones/iop-agent-cli-runtime.md`
- `agent-roadmap/sdd/automation-runtime-bridge/iop-agent-cli-runtime/SDD.md`
- `agent-spec/index.md`
- `agent-contract/index.md`
- `agent-contract/inner/agent-runtime.md`
- `agent-contract/inner/iop-agent-cli-runtime.md`
- `packages/go/agenttask/ports.go`
- `packages/go/agenttask/types.go`
- `packages/go/agenttask/manager.go`
- `packages/go/agenttask/workflow.go`
- `packages/go/agenttask/reconcile.go`
- `packages/go/agenttask/dispatch.go`
- `packages/go/agenttask/review.go`
- `packages/go/agenttask/integration_queue.go`
- `packages/go/agenttask/manager_integration_test.go`
- `packages/go/agenttask/integration_queue_test.go`
- `packages/go/agenttask/state_machine_test.go`
- `apps/agent/internal/projectlog/record.go`
- `apps/agent/internal/projectlog/record_test.go`
- `apps/agent/internal/projectlog/store.go`
- `apps/agent/internal/projectlog/store_test.go`
- `apps/agent/internal/projectlog/sink.go`
- `apps/agent/internal/projectlog/sink_test.go`
- `agent-task/m-iop-agent-cli-runtime/21+13,17,20_project_log_sink/PLAN-local-G08.md`
- `agent-task/m-iop-agent-cli-runtime/21+13,17,20_project_log_sink/CODE_REVIEW-cloud-G08.md`
- `agent-task/archive/2026/07/m-iop-agent-cli-runtime/13_agent_domain/complete.log`
- `agent-task/archive/2026/07/m-iop-agent-cli-runtime/17+13_project_log_records/complete.log`
- `agent-task/archive/2026/07/m-iop-agent-cli-runtime/20+13,17_project_log_journal/complete.log`

### SDD Criteria

- SDD: `agent-roadmap/sdd/automation-runtime-bridge/iop-agent-cli-runtime/SDD.md`
- Status: approved; implementation lock: released.
- Targeted Acceptance Scenario: `S12`.
- Milestone Task id: `project-logs`.
- Evidence Map requirement: WORK_LOG loop/attempt/locator evidence, a dynamic parallel frontier, and archive reconciliation with stable identities and exactly-once terminal cleanup.
- These rows require the implementation checklist to use production `Emit`, exact durable state evidence, 11 retry/follow-up pairs, a same-project parallel work unit, task-scoped archives, all archive crash phases, replay deduplication, and decoded archived WORK_LOG assertions. The final verification therefore includes fresh focused, full, and race runs.

### Verification Context

- No separate verification handoff was supplied.
- Repository-native evidence came from the Go package layout, the project testing rule, the approved SDD, both inner contracts, existing projectlog crash-window tests, and the first review's actual outputs.
- Fresh reviewer commands already executed successfully:

```text
test -z "$(gofmt -d apps/agent/internal/projectlog/*.go)"
go test -count=1 ./apps/agent/internal/projectlog -run 'TestSink|TestTimeline|TestS12LoopParallelArchiveMatrix'
go test -count=1 ./apps/agent/internal/projectlog
go test -count=1 -race ./apps/agent/internal/projectlog ./packages/go/agentstate
go vet ./apps/agent/internal/projectlog
git diff --check
```

- Tool preflight: `/config/.local/bin/go`, `go1.26.2 linux/arm64`, `GOROOT=/config/opt/go`.
- Preconditions: run from `/config/workspace/iop-s0`; preserve unrelated dirty-worktree changes; do not read unrelated archive content.
- Constraints: local verification only, no external runner, provider, daemon, or network dependency. Fresh execution is required with `-count=1`; cached results are not acceptable.
- Gap: the package has no standalone host composition call site yet, so the production boundary is proven through the real `Sink.Emit` plus an `agenttask.StateStore` evidence resolver, not through a daemon process.
- Confidence: high for the local package and contract boundary; the named S12 fixture is the required completion oracle.

### Test Coverage Gaps

- Existing sink tests cover event-type mapping and redaction, but use empty event ids and the test-only `EmitWithLocators`; they do not cover exact durable-state enrichment, missing evidence, opaque ids, or conflicting replay.
- Existing record tests reject absent state/selection revisions and therefore encode the current placeholder-fabrication pressure; they need exact optional-evidence boundary cases.
- Existing store tests cover CAS and archive crash phases separately, but not durable `RecordID` deduplication retained after prune or task-scoped journals under one project/workspace.
- Existing S12 coverage uses two projects, has no injected archive failure phase, treats dispatch ordinal as loop ordinal, and does not decode the archived full WORK_LOG.
- Existing contracts state event-id replay idempotency, but the standalone evidence row and exact test/source paths are inconsistent.

### Symbol References

- `NewSink` call sites: `apps/agent/internal/projectlog/sink_test.go:31`, `apps/agent/internal/projectlog/sink_test.go:98`, and `apps/agent/internal/projectlog/store_test.go:1453,1462,1581`.
- `EmitWithLocators` call sites: `apps/agent/internal/projectlog/sink_test.go:143` and `apps/agent/internal/projectlog/store_test.go:1498,1553,1610,1638`.
- Remove `EmitWithLocators`; update every listed call site to `Emit` backed by exact durable state evidence.
- No external production call site currently constructs `NewSink`, so changing its constructor is contained to this package and its tests.

### Split Judgment

The invariant is indivisible: a deterministic manager event must resolve to one exact task record, deduplicate across CAS/archive/restart, and produce one task-scoped archived WORK_LOG under every crash phase. Splitting schema, sink, store, or S12 verification would again permit test-only evidence to pass without the runtime archive path.

Split predecessors are satisfied:

- `13_agent_domain`: `agent-task/archive/2026/07/m-iop-agent-cli-runtime/13_agent_domain/complete.log`
- `17+13_project_log_records`: `agent-task/archive/2026/07/m-iop-agent-cli-runtime/17+13_project_log_records/complete.log`
- `20+13,17_project_log_journal`: `agent-task/archive/2026/07/m-iop-agent-cli-runtime/20+13,17_project_log_journal/complete.log`

### Scope Rationale

Do not change `agenttask.Event`, manager transition/event call sites, provider adapters, UI, Python task orchestration, roadmap files, or unrelated active tasks. Exact enrichment is a standalone host responsibility and can be resolved from the shared `agenttask.StateStore` revision and `WorkRecord`; unavailable route decision fields must remain absent. Do not add a daemon composition layer that does not yet exist.

### Final Routing

- evaluation_mode: `isolated-reassessment`
- finalizer: `finalize-task-policy.sh pair`
- build closures: scope/context/verification/evidence/ownership/decision all `true`
- build scores: scope `2`, state `2`, blast `2`, evidence `2`, verification `2`; grade `G10`
- build base/final route: `grade-boundary` / `grade-boundary`, lane `cloud`, filename `PLAN-cloud-G10.md`
- review closures: scope/context/verification/evidence/ownership/decision all `true`
- review scores: scope `2`, state `2`, blast `2`, evidence `2`, verification `2`; grade `G10`
- review route: `official-review`, lane `cloud`, adapter `codex`, model `gpt-5.6-sol`, reasoning `xhigh`, filename `CODE_REVIEW-cloud-G10.md`
- large_indivisible_context: `false`
- positive loop risks: `temporal_state`, `concurrent_consistency`, `boundary_contract`, `variant_product` (count `4`)
- recovery signals: `review_rework_count=1`, `evidence_integrity_failure=true`
- capability-gap evidence: none

## Implementation Checklist

- [ ] Resolve production `Sink.Emit` from exact durable task evidence, remove placeholder identity synthesis, and use bounded opaque record ids.
- [ ] Partition task journals under one project/workspace, make append/archive replay idempotent across restart, and archive the full WORK_LOG projection.
- [ ] Rebuild the named S12 matrix through production `Emit` and align both contracts with exact source, test, command, and `project-logs` evidence.
- [ ] Run the focused, full, race, vet, formatting, contract, and diff verification commands exactly as written.
- [ ] Fill implementation-owned sections in CODE_REVIEW-*-G??.md with actual implementation notes and verification output.

### [REVIEW_API-1] Make Production Event Projection Evidence-Exact

#### Problem

`apps/agent/internal/projectlog/sink.go:35-60` gives exact locators only to the test-only `EmitWithLocators` path. `mapEventToRecord` at lines 137-180 persists a raw or fabricated event id, conflates dispatch with loop ordinal, derives state revisions from workflow revisions, and invents route identities. `apps/agent/internal/projectlog/record.go:123-139,303-333` then requires synthesized state and selection fields instead of allowing unavailable evidence to remain absent.

#### Solution

Require `NewSink` to receive an evidence resolver backed by `agenttask.StateStore`. For work events, load the exact manager revision and `WorkRecord`, copy attempt/dispatch/target/change-set/integration/blocker fields, and sort/copy process, session, overlay, change-set, and completion locators. Fail closed on project/work/attempt identity drift. Project events may omit work evidence.

Remove `EmitWithLocators`. Map only supplied or resolved evidence: do not infer state from event type, do not use workflow revision as state revision, and do not fabricate route fields. Permit optional state revision and optional selection-specific route fields while strictly validating every present value. Derive `RecordID` only from a required manager `EventID` using SHA-256; never persist raw `Detail` inside an identity.

Before (`apps/agent/internal/projectlog/sink.go:35-60`):

```go
func (s *Sink) Emit(ctx context.Context, event agenttask.Event) error {
	rec, err := mapEventToRecord(event, s.store.projectID, s.store.workspaceID)
	// ...
	_, err = s.store.AppendRecord(ctx, rec)
	return err
}

func (s *Sink) EmitWithLocators(
	ctx context.Context,
	event agenttask.Event,
	locators []agenttask.LocatorRecord,
) error
```

After:

```go
import (
	"context"
	"crypto/sha256"
	"encoding/hex"
	"sort"
)

type EventEvidenceResolver interface {
	ResolveEventEvidence(context.Context, agenttask.Event) (EventEvidence, error)
}

func (s *Sink) Emit(ctx context.Context, event agenttask.Event) error {
	evidence, err := s.evidence.ResolveEventEvidence(ctx, event)
	if err != nil {
		return err
	}
	record, err := mapEventToRecord(event, evidence, s.store.projectID, s.store.workspaceID)
	if err != nil {
		return err
	}
	return s.store.AppendEventRecord(ctx, record)
}

func opaqueRecordID(eventID string) (string, error) {
	if eventID == "" {
		return "", ErrMissingEventID
	}
	sum := sha256.Sum256([]byte(eventID))
	return "evt-sha256-" + hex.EncodeToString(sum[:]), nil
}
```

Before (`apps/agent/internal/projectlog/record.go:123-139,311-330`):

```go
if r.State == "" {
	if r.StateRevision != "" {
		return fmt.Errorf("%w: StateRevision requires State", ErrInvalidIdentity)
	}
} else {
	if err := validateIdentity("StateRevision", string(r.StateRevision), true); err != nil {
		return err
	}
}

{"RouteStatus.SelectionRevision", route.SelectionRevision},
// ...
if route.ReasonCode == "" {
	return fmt.Errorf("%w: invalid route reason code", ErrInvalidIdentity)
}
```

After:

```go
if r.StateRevision != "" {
	if r.State == "" {
		return fmt.Errorf("%w: StateRevision requires State", ErrInvalidIdentity)
	}
	if err := validateIdentity("StateRevision", string(r.StateRevision), true); err != nil {
		return err
	}
}
// Core target fields remain required when RouteStatus exists.
// SelectionRevision and ReasonCode are validated only when present.
```

#### Modified Files and Checklist

- [ ] `apps/agent/internal/projectlog/sink.go` — add exact state-backed evidence resolution, opaque ids, and production-only emission.
- [ ] `apps/agent/internal/projectlog/sink_test.go` — replace helper injection and cover exact, absent, drifted, redacted, and replayed evidence.
- [ ] `apps/agent/internal/projectlog/record.go` — represent exact attempt/change-set/integration evidence and permit unavailable revisions without placeholders.
- [ ] `apps/agent/internal/projectlog/record_test.go` — update validation matrices for exact-present versus absent evidence.

#### Test Strategy

Write/update `TestSinkMapsEveryEventType`, `TestSinkResolvesExactDurableEvidence`, `TestSinkRejectsEvidenceIdentityDrift`, `TestSinkUsesOpaqueStableRecordID`, `TestTimelineProjectionIsStableAndRedacted`, and record validation subtests. Assert production `Emit` retains exact loop/attempt/dispatch/route/locator/blocker/change-set/integration values, omits unavailable values, rejects missing event ids and mismatches, and never exposes raw details in `RecordID`.

#### Verification

```bash
go test -count=1 ./apps/agent/internal/projectlog -run 'TestSink|TestTimeline|TestRecord'
```

Expected: exact durable evidence is mapped through `Emit`; placeholder identities and raw event ids are absent.

### [REVIEW_API-2] Make Task Archive Replay Exactly Once

#### Problem

`apps/agent/internal/projectlog/store.go:42-52,203-244` keeps one project journal and appends every replay, while cleanup removes the only retained event evidence. `encodeTimeline` at lines 854-872 writes a legacy shape without loop, attempt, dispatch, role/result, or locators. Two same-project tasks therefore cannot own independent archive ordinals, and a replayed terminal event can create a second archive.

#### Solution

Route work records to deterministic work-unit scopes below the same project/workspace store; keep project-only events in the project scope. Add `ForWorkUnit`, scoped CAS keys, scoped archive roots, and strict scope identity checks while retaining compatible project-scope operations.

Persist a `SeenRecords` map from opaque `RecordID` to original sequence and canonical record fingerprint. On replay, return the original sequence without append; if the same id has different content, fail closed. Retain this map and `NextSequence` after terminal prune so restart and post-archive replay remain idempotent. Reconciliation must never increment the archive ordinal for a seen terminal event.

Replace the legacy timeline encoder with JSONL `WorkLogEntry` output from `ProjectWorkLog`; archive tests must decode and validate every full entry.

Before (`apps/agent/internal/projectlog/store.go:45-52,221-242`):

```go
type journal struct {
	SchemaVersion  uint32
	ProjectID      agenttask.ProjectID
	WorkspaceID    agenttask.WorkspaceID
	NextSequence   uint64
	ArchiveOrdinal uint64
	Records        []ProjectLogRecord
}

seq := j.NextSequence
rec.Sequence = seq
j.Records = append(j.Records, rec)
j.NextSequence = seq + 1
```

After:

```go
type seenRecord struct {
	Sequence    uint64 `json:"sequence"`
	Fingerprint string `json:"fingerprint"`
}

type journal struct {
	// existing identity and ordinal fields
	WorkUnitID  agenttask.WorkUnitID     `json:"work_unit_id,omitempty"`
	SeenRecords map[string]seenRecord    `json:"seen_records"`
	Records     []ProjectLogRecord       `json:"records"`
}

if seen, ok := j.SeenRecords[record.RecordID]; ok {
	if seen.Fingerprint != recordFingerprint(record) {
		return 0, ErrRecordReplayConflict
	}
	return seen.Sequence, nil
}
```

Before (`apps/agent/internal/projectlog/store.go:854-872`):

```go
func encodeTimeline(records []ProjectLogRecord) ([]byte, error) {
	for _, rec := range records {
		entry := timelineEntry{
			Sequence: rec.Sequence,
			// legacy fields only
		}
		// ...
	}
}
```

After:

```go
func encodeTimeline(records []ProjectLogRecord) ([]byte, error) {
	return encodeWorkLogEntries(ProjectWorkLog(records).Entries)
}
```

#### Modified Files and Checklist

- [ ] `apps/agent/internal/projectlog/store.go` — add work-unit scoping, persistent replay fingerprints, conflict handling, and full WORK_LOG archive encoding.
- [ ] `apps/agent/internal/projectlog/store_test.go` — cover scoped CAS/archive isolation, replay before/after prune and restart, conflicts, and decoded WORK_LOG artifacts.
- [ ] `apps/agent/internal/projectlog/sink.go` — route work events to their scoped journal.

#### Test Strategy

Write `TestStoreReplayDeduplicatesBeforeAndAfterArchive`, `TestStoreRejectsConflictingRecordReplay`, `TestStoreScopesParallelWorkArchives`, and archived timeline assertions. Reopen both the state store and projectlog store between phases. Assert one record/ordinal for identical replay, a typed conflict for drift, independent work-unit ordinal `1` under one project/workspace, and a full redacted `WorkLogEntry` timeline.

#### Verification

```bash
go test -count=1 ./apps/agent/internal/projectlog -run 'TestStoreReplay|TestStoreRejectsConflicting|TestStoreScopesParallel|TestArchive'
```

Expected: duplicate events converge before and after archive/restart; scoped archives and full WORK_LOG artifacts remain exact.

### [REVIEW_API-3] Rebuild S12 and Contract Evidence

#### Problem

`apps/agent/internal/projectlog/store_test.go:1436-1649` uses separate project/workspace identities, calls `EmitWithLocators`, and never invokes `WithFailureHook`. `agent-contract/inner/iop-agent-cli-runtime.md:12,43` omits exact tests and names `project-log-sink`, conflicting with the approved SDD and Roadmap id `project-logs`. `agent-contract/inner/agent-runtime.md:61` requires idempotent same-event replay but does not state how the standalone sink binds exact durable state evidence.

#### Solution

Rewrite `TestS12LoopParallelArchiveMatrix` around one project/workspace store and one production sink. Use two work units and state-backed evidence; task A must execute 11 explicit review-failure/follow-up pairs before its terminal attempt while task B advances independently. Recreate state/store/sink instances at selected boundaries and replay identical events before and after archive.

Run the matrix as subtests over `archive_before_lock`, `archive_before_write`, `archive_after_rename`, `archive_before_manifest`, and `archive_before_cleanup`. For each phase, recover with `Reconcile`, assert terminal-only cleanup, one archive ordinal per work unit, no duplicate record or archive after replay, retained locator identity, and decoded redacted WORK_LOG loop/attempt/dispatch/role/result fields.

Update both contracts: bind exact state revision/work evidence to sink projection, list production and test files, record the fresh race command, and use `project-logs`.

Before (`apps/agent/internal/projectlog/store_test.go:1448-1464,1498-1499`):

```go
storeA, err := NewStore(state, archiveRootDir, "proj-loop-A", "ws-loop-A")
sinkA, err := NewSink(storeA)
storeB, err := NewStore(state, archiveRootDir, "proj-loop-B", "ws-loop-B")
sinkB, err := NewSink(storeB)
// ...
if err := sinkB.EmitWithLocators(ctx, evtBStart, locatorsB); err != nil {
```

After:

```go
store, err := NewStore(state, archiveRootDir, "proj-loop", "ws-loop")
sink, err := NewSink(store, durableEvidence)
for _, phase := range archiveFailurePhases {
	t.Run(phase, func(t *testing.T) {
		// Interleave work-A's 11 retry/follow-up pairs with independent work-B,
		// inject the phase, reopen durable stores, reconcile, and replay events.
	})
}
```

Before (`agent-contract/inner/iop-agent-cli-runtime.md:12,43`):

```markdown
- implemented S12 source: `apps/agent/internal/projectlog/sink.go`, `apps/agent/internal/projectlog/store.go`, and `apps/agent/internal/projectlog/record.go`.
| S12 | ... | `project-log-sink` proves ... |
```

After:

```markdown
- implemented S12 source/tests: `apps/agent/internal/projectlog/sink.go`, `store.go`, `record.go`, `sink_test.go`, `store_test.go`, and `record_test.go`.
| S12 | ... | `project-logs` proves ... with `go test -count=1 -race ./apps/agent/internal/projectlog ./packages/go/agentstate`. |
```

#### Modified Files and Checklist

- [ ] `apps/agent/internal/projectlog/store_test.go` — replace the named S12 fixture with the production, same-project, crash-phase matrix.
- [ ] `agent-contract/inner/agent-runtime.md` — clarify exact durable-state enrichment and opaque sink deduplication at the EventSink boundary.
- [ ] `agent-contract/inner/iop-agent-cli-runtime.md` — correct the Roadmap id and record exact production/test/race evidence.
- [ ] `agent-task/m-iop-agent-cli-runtime/21+13,17,20_project_log_sink/CODE_REVIEW-cloud-G10.md` — fill implementation-owned completion, decisions, deviations, and actual command output.

#### Test Strategy

The test is mandatory and remains named `TestS12LoopParallelArchiveMatrix`. It must assert 11 explicit retry/follow-up pairs, independent same-project progress, exact resolver evidence, every archive failure phase, restart convergence, replay deduplication, separate task archive ordinals, and full archived WORK_LOG content under `-race`.

#### Verification

```bash
go test -count=1 -race ./apps/agent/internal/projectlog -run TestS12LoopParallelArchiveMatrix
```

Expected: every crash-phase subtest converges to one terminal archive per work unit with stable evidence and no replay duplicates.

## Dependencies and Execution Order

Implement REVIEW_API-1 before REVIEW_API-2 so scoped journals receive canonical opaque ids and exact evidence. Complete REVIEW_API-2 before rebuilding the S12 fixture and contract evidence in REVIEW_API-3. The three archived predecessor `complete.log` files listed in `Split Judgment` satisfy the directory-encoded dependencies.

## Modified Files Summary

| File | Item |
|------|------|
| `apps/agent/internal/projectlog/sink.go` | REVIEW_API-1, REVIEW_API-2 |
| `apps/agent/internal/projectlog/sink_test.go` | REVIEW_API-1 |
| `apps/agent/internal/projectlog/record.go` | REVIEW_API-1 |
| `apps/agent/internal/projectlog/record_test.go` | REVIEW_API-1 |
| `apps/agent/internal/projectlog/store.go` | REVIEW_API-2 |
| `apps/agent/internal/projectlog/store_test.go` | REVIEW_API-2, REVIEW_API-3 |
| `agent-contract/inner/agent-runtime.md` | REVIEW_API-3 |
| `agent-contract/inner/iop-agent-cli-runtime.md` | REVIEW_API-3 |
| `agent-task/m-iop-agent-cli-runtime/21+13,17,20_project_log_sink/CODE_REVIEW-cloud-G10.md` | REVIEW_API-3 |

## Final Verification

```bash
gofmt -w apps/agent/internal/projectlog/*.go
test -z "$(gofmt -d apps/agent/internal/projectlog/*.go)"
go test -count=1 ./apps/agent/internal/projectlog -run 'TestSink|TestTimeline|TestRecord|TestStoreReplay|TestStoreRejectsConflicting|TestStoreScopesParallel|TestS12LoopParallelArchiveMatrix'
go test -count=1 ./apps/agent/internal/projectlog
go test -count=1 -race ./apps/agent/internal/projectlog ./packages/go/agentstate
go vet ./apps/agent/internal/projectlog
rg --sort path -n 'implemented S12 source|\\| S12 \\|' agent-contract/inner/iop-agent-cli-runtime.md
git diff --check
```

Expected: formatting is clean; fresh focused/full/race tests and vet pass; contract output names exact S12 source/tests and `project-logs`; the worktree has no whitespace errors. After completing all code changes, fill implementation-owned sections in `CODE_REVIEW-*-G??.md`.
