Purpose: recover Vlad's evidence-backed work and meetings into a review queue, without duplicating work already recorded in Clockify. Keep unrelated overlapping activity visible with an explicit warning. The recurring cycle publishes pending/unposted proposals; Clockify writes require approval of the specific review entries.
This repository is the canonical implementation. The collector lives only in
scripts/clockify_sync_collect.py; the top-level clockify_sync_collect.py is
a compatibility wrapper.
The source audit and process-level failure inventory are recorded in
clockify-description-failure-taxonomy.md.
Vlad authorized the recurring reconciliation workflow without additional
per-run approval prompts. Collect relevant private work evidence, analyze it
through the approved deepseek-v4.1-flash:cloud route, reconcile against
Clockify read-only, and publish missing proposals as pending/unposted in the
existing monthly review tabs. This includes recovery runs and newly recovered
evidence, not only unchanged cache hits. See the
standing authorization.
Do not interpret this as approval to post time to Clockify, change inference destinations, or deploy code. Those actions retain their separate boundaries.
cd /Users/blackthorne/Work/automation-clockify-sync
python3 scripts/clockify_review_run.py \
--period-manifest /absolute/private/path/period-manifest.json \
--routing /absolute/private/path/routing.json \
--corrections /absolute/private/path/review-corrections.jsonl \
--acceptance-ledger /absolute/private/path/review-acceptance.jsonlThe orchestration command defaults to --review-mode shadow_all and runs the
complete process:
- collect full cross-machine session events, commands, commit-backed artifacts, existing Clockify entries, Multica issue context, and hydrated Fathom records;
- write and validate an immutable, content-addressed evidence ledger;
- classify noise and reconstruct atomic semantic accomplishments with a tiered analyzer;
- use an independent Flash review to select a configured project/task and render Caveman descriptions targeting 8–14 words, while local code verifies taxonomy membership and structural safety;
- allocate evidence-backed active effort without gap filling, overnight bridging, or silent trimming; preserve complete meetings and unrelated simultaneous work with explicit overlap warnings;
- validate quality and ingest stable review identities; shadow evaluation exposes the full denominator, while repeated runs emit only actionable deltas. Exceptions-only operation is not activated until its measured gates pass.
For month-scale recovery, scripts/clockify_portfolio_review.py adds a bounded
second pass over already reviewed, successfully allocated activities. It groups
only one project/day portfolio at a time and asks the pinned Flash model to turn
message-level commands, checks, fixes, tests, and follow-ups into invoice-worthy
accomplishments. A separate Flash call then validates client/project level, task
type, effort, consolidation boundary, and Caveman wording against the same raw
evidence. The stage retains the original non-overlapping allocation segments,
never fills gaps, writes progress to portfolio-status.json, and stores both
model decisions in an append-only cache. scripts/clockify_portfolio_quality.py
performs only structural/integrity checks and identifies rows requiring another
semantic repair; it does not replace the Flash validator with local semantics.
It prints the absolute path to autopilot-result.json. Lower-level commands
remain available for targeted diagnosis. Calendly recordings are first-class,
read-only meeting evidence; scheduled events without a recording are retained
only as scheduled_without_recording exclusions and never supply billable time.
To place reviewed Claude outcomes within observed same-session human windows,
set "session_timing_pool_sources": ["codex_sessions", "claude_bursts"] in the
routing snapshot. Placement remains estimated: assistant runtime is not human
attention, gaps are not filled, and outcomes share the available pool. Keep the
placement and overlap warnings visible for review. Omitting this setting keeps
the historical Codex-only recipe; replay uses the saved routing, not live config.
Fresh Clockify collection includes entries that started before the requested period but overlap it. Only relevant rows are persisted; pagination is based on the original response size. Older sealed checkpoints retain their exact request contract and are replayed explicitly, never silently reused as fresh coverage.
Grouped review entries need one client-facing summary covering all included
issues, not concatenated child descriptions. Keep the original child wording,
evidence and exact time segments separately; changing a parent summary must not
change its identity, duration, routing or approval. Prepared publication accepts
an explicit reviewed group_summaries map bound to the exact parent and ordered
children. For fresh recurring deliveries, the cycle synthesizes groups with
distinct child descriptions using the current pinned Flash route and existing
analyzer cache. A separate semantic review sees every child; rejected summaries
get one targeted repair. Only prepared client-facing wording and project context
are transmitted, not raw evidence. Missing or unaccepted summaries cannot fall
back to concatenation. Identical wording needs no inference. The accepted summary
is frozen in the existing publication binding; retries and historical bindings
replay offline without changing child wording, time, approvals or IDs. Direct
historical callers of the pure adapter retain their previous default behavior.
Google Sheet publication is a separate post-review stage. Collection, analysis, quality checks and replay do not publish. The recurring review cycle can invoke publication after source quality and immutable replay pass, using the explicit Sheet-write setting and the standing authorization for its named destination. An operator can use the same stage directly for an authorized review package:
python3 scripts/clockify_sheet_publish.py \
--spreadsheet-id <approved-spreadsheet-id> \
--sheet-title "August 2026 review" \
--template-title Proposals \
--proposals /absolute/path/to/source-run/proposals.json \
--quality-report /absolute/path/to/source-run/quality_report.json \
--replay-integrity /absolute/path/to/replay-run/replay-integrity.json \
--run-id <source-run-id> \
--enable-writeWithout --enable-write, the command validates the artifacts and emits a
no-write preview. The write path verifies the proposal count, quality status,
replay status, replay/source identity, and unique stable activity-segment IDs.
It creates the named month tab from the hidden Proposals template when
needed, displays duration as integer minutes, and appends only new stable IDs.
For existing IDs it updates machine-owned evidence fields while preserving the
human-owned Disposition, Review Status, and Review Notes cells. It never
calls Clockify. Later intervals in the same month use the same command and tab;
already published stable IDs are not duplicated.
clockify_review_cycle.py --config <config> --adopt-historical-request <request>
can import a completed historical slice without collecting, inferring or
publishing again. It requires the genuine collector checkpoint, sealed exact
replay, and completed publisher/readback receipt for the same source and rows.
It does not turn a preview or a subset publication into full delivery. A stale
checkpoint remains a gap; never edit its digest to make it match newer files.
Saved receipts and posted-row captures are trusted local connector/operator evidence, not remote signatures. Use actual verified captures, never fabricate a publication result from expected row hashes. A posted-work credit also needs an exact existing Clockify match and the same evidence-backed accomplishment; mere temporal overlap is not credit. Later genuine captures can preserve historical proof without reconstructing an unavailable original run.
The scheduled autopilot does not invoke the production poster. After a board- approved portfolio has a clean repair, passing quality report, and passing immutable replay, an operator can validate or execute that exact digest:
python3 scripts/clockify_post_approved_portfolio.py \
/absolute/path/to/portfolio-repair.json \
--quality-report /absolute/path/to/portfolio-quality.json \
--replay-integrity /absolute/path/to/replay-integrity.json \
--routing /absolute/path/to/routing.json \
--receipt /absolute/path/to/private-receipt.json \
--approval-receipt <board-approval-id> \
--approval-events /absolute/path/to/approval-events.jsonl \
--post-events /absolute/path/to/post-events.jsonl \
--period-manifest /absolute/path/to/period-manifest.json \
--expected-portfolio-sha256 <approved-sha256> \
--executeOmit --execute for a read-only preflight. Execution validates one unexpired
approval ledger entry before credentials are loaded, binding the exact portfolio,
quality, replay, routing, correction, coverage, residual-exception, target, and
period evidence. Its append-only post-event ledger writes planned before a
POST and one terminal result only after exact live readback; a mutable receipt
is compatibility output, never execution history. Ambiguous responses and
interrupted plans are resolved through fresh exact readback and are never
blindly reposted. The final compatibility receipt includes a full-period live
readback digest.
Outputs:
runs/<run-id>/evidence/evidence-ledger.json: immutable evidence and completeness manifest;runs/<run-id>/semantic-analysis.json: cited atomic activities, omissions, analyzer provenance, and the reversible content-addressed evidence-bundle manifest used for local member expansion;runs/<run-id>/work-accounting-result.json: semantic, allocation, canonical meeting, and exception contract;runs/<run-id>/allocation-report.json: strict allocation and contested time;runs/<run-id>/fathom-reconciliation.json: legacy-named, canonical meeting disposition for every recording-backed meeting;runs/<run-id>/review-learning-cases.json: generalized, sanitized correction cases derived from the integrity-checked decision log;runs/<run-id>/review-regression-cases.json: exact local-only expectations bound to reviewed evidence; these are never sent to a model;runs/<run-id>/review-regression-results.json: pass/fail evidence showing whether previously corrected behavior was actually learned;runs/<replay-run-id>/replay-integrity.json: digest-bound proof that a distinct replay reused the byte-identical ledger and analyzer versions;runs/<run-id>/proposals.json: final semantic allocation candidates;runs/<run-id>/legacy-*.json: collector-only diagnostic candidates, never reviewable output and never carried into durable state;runs/<run-id>/quality_report.json: read-only quality findings;runs/<run-id>/review-snapshot.json: actionable delta against durable state;runs/<run-id>/autopilot-result.json: deterministic action contract;runs/<run-id>/autopilot-summary.md: compact new/changed or coverage summary;runs/<run-id>/review-current.csv: stable-ID export of the complete active review for local inspection or an explicitly approved Sheet patch;runs/<portfolio-run-id>/portfolio-review.csv: locally consolidated, invoice-reviewable activities with their original allocation segments;runs/<portfolio-run-id>/portfolio-status.json: model/revision-bound progress for resumable desktop execution;runs/<portfolio-run-id>/portfolio-quality.json: overlap, provenance, forbidden-content, duration, and semantic-repair findings;state/review-items.json: mutable local review state, intentionally ignored by Git;state/review-corrections.jsonl: immutable evidence-bound approve, skip, and modify decisions, intentionally ignored by Git.state/review-acceptance.jsonl: integrity-linked shadow/guarded period evidence controlling exceptions-only eligibility, intentionally ignored by Git.
The period coordinator keeps its manifest and append-only event history at the
operator-selected local period paths; neither belongs in evidence output or a
public report. A period uses half-open UTC intervals. Source debt is therefore
one exact (source, since, until, slice) identity: completing an adjacent or
broader interval never clears it. Retryable failures retain a sanitized receipt
(identity digests, class, retryability, and time only); credentials, cursors,
and raw evidence are never retained.
Each completed slice retains completion-bundle.json, which verifies all
downstream artifacts before a backlog/debt entry may be reused. The bounded
runner defaults to a 2,700-second slice timeout, a 7,200-second backlog total,
and a 30-second termination grace; environment configuration may tighten or
extend those documented budgets. A replay binds the normalized period/revision
and event digest, routing snapshot, correction and acceptance journals,
canonical meeting reconciliation, and ordered completion-bundle identities.
Missing, extra, reordered, or drifted bundles fail closed. Portfolio replay
sealing now requires --period-manifest, --corrections, and --acceptance
in addition to its existing inputs; this is intentionally pre-release
backward-incompatible. Publication remains deferred to its separate approved
gate and is never performed by collection or replay.
Every fresh review run requires a period manifest and snapshots that exact manifest together with routing, corrections, and acceptance inputs into each run directory before accounting. Downstream accounting consumes the snapshots, not the mutable source paths. Replays reject caller overrides and consume only the source run's complete snapshot set. Missing, unsafe, or conflicting files fail before semantic accounting.
Interrupted accounting can use clockify_review_run.py --resume-from with the
existing source run and explicit state/cache paths. It never recollects or
replaces the four snapshots. Completed sources are adopted only after their
completion bundle verifies. An explicitly authorized --repair-from instead
creates a distinct derived run, retaining the source and its receipts unchanged;
validated cache decisions are reused and only missing decisions may use the
approved cloud route. Repairs still require separate immutable replay before
Sheet publication, and neither command posts to Clockify.
A newly opened period's input manifest cannot contain its own future output. For this bootstrap case, replay binds the completed source bundle separately, verifies its exact interval and artifacts, and leaves both manifest snapshots byte-identical. A missing, drifted, or different-period bundle still fails closed.
Flash analysis and a separate Flash reviewer own semantic classification,
project/task recommendations, consolidation boundaries, effort judgment, and
human-readable wording. Deterministic code owns evidence identity, exact taxonomy
membership, non-overlapping placement, review identity, integrity, and safety; it
does not discard a plausible activity through a grammar-only semantic validator.
Raw evidence may overlap; proposed and existing Clockify allocations may not.
Each activity carries minimum, recommended, and maximum active-effort estimates,
with the recommended estimate normalized to five-minute timesheet granularity.
Deterministic code derives a conservative minimum/maximum safety band of roughly
two-thirds to four-thirds around that estimate, rounded outward to five minutes.
When every cited item has a complete observed interval, their interval union is
only an effort ceiling: the largest conservative band that fits below that
ceiling is used, and timing confidence is normalized to medium. The interval
is never treated as proof that all observed wall time was active work. Raw
low-timing model output still triggers the configured fallback or a visible
exception; normalization cannot silently turn it into an accepted proposal.
Action rendering normalizes capitalization and removes only a redundant trailing
verification verb for the same accomplishment; other compound actions still fail.
Allocation prioritizes semantic confidence and direct human-attention signals,
then places only the recommended demand inside observed spans of the cited
semantic workstream. Unrelated evidence elsewhere that day cannot widen that
placement envelope.
If capacity falls below the evidence-backed minimum, token allocations are
rolled back completely. When recommended demand still cannot fit, the process
emits contested_time with the full unmet demand instead of shrinking or
discarding the work. Unused capacity stays explicit and empty time remains empty.
The analyzer receives deterministic noise filtering before semantic work begins. System messages, tool transport, heartbeats, session-control commands, pure standing-by or approval-waiting messages, polling updates, and injected wrappers are excluded. Substantive accomplishments that merely mention words such as "heartbeat", "approval", or "polling" remain eligible. For explicit conversational evidence, a non-meeting accomplishment must cite a user instruction and an assistant result from the same session. User-only requests and assistant-only status/autonomous output fail the semantic contract and must be omitted or surfaced as exceptions. Meetings remain independently eligible through their fixed Fathom evidence contract.
The primary analyzer must pass a minimal live probe and its structured response
contract. A sealed contract rejection receives exactly one content-addressed
repair request containing only its allowlisted failure category and narrow
corrective guidance; raw rejected output is never copied into that request or
cache record. Probe, authentication, non-retryable HTTP, and malformed-response
failures are not retried and block the run. A connection loss or retryable HTTP
status (408, 425, 429, or 5xx) is sealed; after the same pinned route
passes a fresh evidence-free probe, it receives up to three distinct
content-addressed recovery requests. Exhausted request-specific transport
recovery becomes an evidence-bound exception; it never invents a proposal and
does not abort unrelated workstreams.
A timed-out extraction request is sealed in
the local cache and bisected only at a safe context or complete-turn boundary;
the identical timed-out body is never sent again. If repair still fails, a
configured stronger fallback receives the safe category and handles the bounded
chunk. A sealed semantic-contract rejection may also enter the deterministic
partition recovery below even when the primary is the only qualified route. Conflicting or
low-confidence claims that remain unresolved become explicit exceptions, never
proposals.
The required primary is the deepseek-v4.1-flash:cloud alias. Every live
run must additionally pin the full revision reported by the host's current
manifest so the scorecard, analyzer cache, semantic run, and replay cannot
silently mix model releases if the alias moves later. The current Precision
rollout binds revision
e04da138d31e0c9468e982e1ae9503d06cb7e170caa16a90c17d931c4aa140f8.
The retired deepseek-v4-flash:cloud and deepseek-v4-flash:0731-cloud tags
remain accepted only with their historical revision for already sealed decisions. The exact model tag
is part of each cache route identity, so an in-progress sealed run must retain
the tag it started with rather than migrating accepted decisions to an alias.
The active release must pass the v17 synthetic route gate.
deepseek-v4-pro:cloud is not an approved route for this process.
An explicit retry of a review rejected for missing or conflicting citations uses a separate request identity. It may preserve only whole, uncontested rows; all evidence in conflicting rows and all uncited evidence become an explicit locally derived manual-review exception, without assigned effort. It never chooses a conflicting owner or trims a semantic claim. Other validation errors still reject the result. The validated derived response is sealed in the cache so replay produces the same activities and unresolved evidence without another inference call; existing sealed runs are never rewritten.
Analyzer requests retain the fail-closed 1,450,000-byte hard ceiling. Normal
extraction uses a 250,000-byte and 250-event operational target with four
deterministically ordered workers so a large-context route does not receive an
unnecessarily broad semantic partition. A single event may exceed the target but
never the hard ceiling; it is never clipped. When every configured qualified
route rejects or times out on one bounded extraction chunk, deterministic recovery bisects only at
source-context or conversation-turn boundaries. This includes a single qualified
primary with no fallback. A user instruction always stays with its following
assistant/tool result. A single indivisible turn rejected by every configured
route becomes one local analyzer_failure exception with a failure digest; an
indivisible transport timeout receives exactly one content-addressed recovery
series of at most three requests on the same route with distinct seeds and
timeout markers. The identical timed-out body is never resent. Exhaustion
becomes one analyzer_failure exception covering the complete indivisible
evidence unit.
If every configured qualified route rejects repeated-workstream synthesis,
including a single primary with no fallback, those otherwise valid but potentially
duplicative claims become one analyzer_synthesis_failure exception. A synthesis
transport failure receives the same sealed, probe-gated recovery bound; exhaustion
keeps the whole candidate workstream out of proposals as one visible exception.
Synthesis candidates require the same normalized project, workstream, and
concrete object; generic model labels alone cannot combine unrelated activities.
No rejected activity can become a proposal.
Within each operational chunk, contiguous evidence from one stable session, repository, issue, or meeting context is represented as a content-addressed local bundle. The provider receives only request-local bundle references, ordered redacted members, and inclusive numeric ranges. It never receives the original ledger IDs or context identifiers. Models may split one bundle into multiple atomic accomplishments by returning disjoint member ranges. Local code expands those ranges to the original immutable evidence IDs and then enforces complete exactly-once coverage before computing activity identities.
Validated analyzer decisions are stored in the append-only local
analyzer-cache-v2.jsonl beside the durable review state. Cache keys bind the endpoint, model, prompt/schema
versions, and complete request-body digest without storing request prose. Both
accepted responses, contract-rejected primary decisions, and extraction timeout
decisions are sealed, so an
immutable replay cannot randomly switch provider wording or fallback routing.
Every cache hit is revalidated; replayed decisions do not require another live
provider probe. Concurrent or stale writers are locked and conflicting decisions
fail closed instead of replacing or interleaving cache records.
The rendered_description field is required on semantic activities and starts
as null; deterministic routing and rendering populate it only for activities
that can become proposals. Analyzer wording is never trusted as final text. The
Caveman renderer regenerates it from prefix, action, object, and bounded outcome,
then quality checks require proposal description to match it exactly.
Recording eligibility requires a valid recorded meeting window and either Vlad as recorder, organizer, or attendee. Recordings shorter than five minutes require a transcript. A title-only record remains an exception; it cannot support an invented outcome. Existing Clockify time reconciles a meeting only with reciprocal overlap of at least 80%; partial conflicts remain explicit fixed-block exceptions.
Fathom and Calendly recordings are deduplicated by meeting-dedup/v1 before
accounting. Shared provider, event, or join identities require agreeing start
and end instants; the fallback requires the same normalized non-Vlad
participant set and each boundary within five minutes. Missing participants,
multiple candidates, or timing disagreement are explicit exceptions, never a
merged or averaged duration. A duplicate pair is one canonical meeting and
every source recording must be cited by that meeting's review allocation.
Multi-project meeting allocations are accepted only when timestamped semantic
evidence partitions the full recorded interval. Human approval or a percentage
share cannot replace a timestamped boundary.
routing.json.member_identities is copied into, and therefore bound by, each
immutable evidence-ledger manifest. That bound identity set controls recording
eligibility and the identities removed before participant-window fallback
matching; a later routing change cannot alter a previously collected period.
Recollect a period to apply an identity change.
When present, duration_seconds and second-precision start/end bounds are
authoritative for a recording, proposal, review row, and its allocation
segments. duration_minutes remains a display and legacy-compatibility field;
minute-only historical artifacts remain readable, while an artifact that
supplies exact seconds is checked against its exact bounds.
Review corrections are immutable and bound to stable activity plus evidence
identity. Only sanitized general rules reach the analyzer. Exact replacement
values remain local-only regression cases. A reappearing skip is removed from
every segment; a mismatching or missing reviewed activity produces one deduplicated
correction_regression exception and no reviewable allocation. A split
correction records the expected child count and an exact, non-overlapping
partition of the parent evidence; replay fails visibly if a child is missing or
evidence is lost, duplicated, or repartitioned.
The immutable ledger is local-only. Private agent/session, meeting, or issue prose is denied to every analyzer transport by default. A minimal route probe contains no evidence and remains safe to run while the gate is closed. Sending the semantic projection requires a separate runtime decision:
export CLOCKIFY_ANALYZER_PRIVATE_TEXT_APPROVED=approvedDo not persist or enable that value merely because a route probe succeeded; setting it authorizes redacted private prose to leave the local machine for the configured analyzer endpoint. When explicitly enabled, cloud requests receive only a strict semantic projection: opaque bundle references, numeric member ranges and spans, redacted user/assistant text, structured Fathom summary/action-item/transcript text, safe commit subjects, and artifact basenames. Tool-call inputs, tool-result bodies, credentials, emails, URLs, absolute paths, and hashes never cross that boundary. Safe text is not clipped; an individually oversized projected event blocks analysis.
Repository commits and changed-file lists remain immutable ledger evidence, but they are corroborative-only until deterministically bound to a human session or issue workstream. Observing a repository from a session CWD does not prove that Vlad authored every commit in its July history: fetched upstream, dependency-bot, and autonomous-agent commits must never become standalone Clockify activities.
Fathom collection queries records created from one day before the requested window through its end, then filters locally by recording or scheduled occurrence overlap. Live July validation showed Fathom records were created between 9 minutes and 5.7 hours after their meetings; the lead covers the boundary without crawling thousands of unrelated historical records. The inventory records the creation-search window, occurrence filter, pagination count, and completeness. HTTP 429 responses use one bounded collection-wide retry budget; exhaustion records sanitized page/cursor and retry provenance and fails closed. Multica issue evidence is fully paginated and then bounded to issue activity in the requested accounting window.
Canonical remote session exports attest the exact collector-script SHA-256 before their evidence can be called complete. Git worktrees must also match the coordinator Git SHA with no tracked changes; the Desktop non-Git archive is identified explicitly and accepted only when its collector-script digest matches. Month-scale canonical exports use a bounded, configurable timeout and never turn a timeout or attestation mismatch into legacy metadata evidence.
A currently running Clockify entry is represented as an existing fixed block only through the earlier of the collection snapshot and the requested end. Its temporary boundary remains explicit provenance. If any running entry cannot be bounded safely, Clockify coverage stays partial and accounting fails closed.
The collector keeps private, local checkpoints for paginated source responses
so an interrupted recovery can resume without repeating already committed
pages. The default root is the private repository state directory
state/collector-checkpoints. A service may set an explicit private root with
CLOCKIFY_COLLECTOR_CHECKPOINT_ROOT=/absolute/private/state/collector-checkpoints.
Keep the live directory private and mode-restricted; checkpoint contents are
recovery evidence, not review artifacts, and must not be shared with an
analyzer or client.
Collection windows are split oldest-first into slices of at most two local calendar days. Each completed slice is recorded independently, so its validated report is immediately available for review even if a later slice fails. A subsequent run retries the oldest incomplete slice first. A source or slice failure preserves its incomplete checkpoint and fails closed: it never deletes recovery state, fabricates a result, or marks an incomplete slice as complete. Cleanup is never automatic during collection.
After review, an operator may remove only completed checkpoints older than a UTC date boundary by passing an explicit absolute root:
python3 scripts/clockify_sync_collect.py cleanup-checkpoints \
--completed-before YYYY-MM-DD \
--checkpoint-root /absolute/private/state/collector-checkpointsThe command refuses relative, missing, or non-directory roots, and reports aggregate counts plus checkpoint identity digests only. It never prints page filenames, payloads, cursors, or credentials. Incomplete and corrupt checkpoints are preserved for fail-closed recovery and are not removed by this command.
state/source-coverage.json retains per-peer coverage debt. If MacBook or
desktop collection is unavailable, the current run still analyzes complete
Precision and central evidence, and records the missed interval instead of
treating it as zero work. The next scheduled run expands its whole collection
window to the earliest debt date, which also expands Clockify and Fathom fixed
blocks for safe deduplication and allocation. Successful recollection clears a
source only when the expanded window reaches that source's original debt date;
retry exhaustion never erases debt.
review-snapshot.json categorizes items as new, changed,
carried_pending, or resolved_disappeared. A zero-candidate run never closes
pending work. Source failures remain visible as coverage warnings.
autopilot-result.json uses one of six actions:
no_comment: healthy coverage and no actionable delta;review_delta: one or more new or changed review items;review_exceptions: an accepted exceptions-only run has active ambiguous rows;review_batch: an accepted exceptions-only run has a new/changed clean batch and no new/changed exception;coverage_warning: incomplete evidence, whether or not candidates exist;blocked: quality identity/provenance failed and durable state was not updated.
The compact summary never reproduces carried_pending row content.
shadow_all is the default and remains the only usable mode today. It presents
the full active denominator, including ambiguous rows. Every active item must
receive an evidence-bound approve, skip, or modify decision before a
period can support promotion.
exceptions_only is fail-closed. It may be requested only with an acceptance
ledger whose status reports exceptions_only_eligible: true:
python3 scripts/clockify_review_run.py \
--review-mode exceptions_only \
--period-manifest /absolute/private/path/period-manifest.json \
--routing /absolute/private/path/routing.json \
--corrections /absolute/private/path/review-corrections.jsonl \
--acceptance-ledger state/review-acceptance.jsonlEligibility requires one complete shadow_baseline period with at least 90%
unchanged approvals, followed by two distinct, later, consecutive guarded
periods with at least 95%. Each period must have complete sources, passing
quality, a stable second replay (0 new / 0 changed), complete dispositions
for the full denominator (ambiguous rows included), assessments for every
skip/modify decision, and zero critical routing, description-truth, meeting,
or allocation errors. Every analyzer route used in a period must also have a
passing digest-bound evaluation scorecard.
Record and inspect those integrity-linked local periods with:
python3 scripts/review_acceptance.py record \
--run-dir /absolute/path/to/first-run \
--replay-run-dir /absolute/path/to/replay-run \
--decisions state/review-corrections.jsonl \
--critical-assessments /absolute/path/to/assessments.json \
--analyzer-scorecard /absolute/path/to/analyzer-scorecard.json \
--stage shadow_baseline \
--ledger state/review-acceptance.jsonl
python3 scripts/review_acceptance.py status \
--ledger state/review-acceptance.jsonlAn acceptance replay must not recollect live sources. Run the first shadow pass
with isolated validation state and all four exact reconciliation inputs, then
point --replay-from at its absolute run directory. Replay accepts no caller
override for the period manifest, routing, corrections, or acceptance ledger;
it consumes only the source run's snapshots:
python3 scripts/clockify_review_run.py \
--since 2026-07-01 --until 2026-08-03 \
--state state/validation/july-baseline/review-items.json \
--period-manifest /absolute/private/path/period-manifest.json \
--routing /absolute/private/path/routing.json \
--corrections state/validation/july-baseline/review-corrections.jsonl \
--acceptance-ledger state/validation/july-baseline/review-acceptance.jsonl
python3 scripts/clockify_review_run.py \
--replay-from /absolute/path/to/runs/<first-run-id> \
--state state/validation/july-baseline/review-items.jsonThe replay command creates a distinct run, copies the evidence ledger
byte-for-byte, reruns deterministic accounting through the same validated
analyzer-decision cache, and fails before durable-state ingestion if the ledger
identity, semantic evidence digest, evidence-bundle manifest, analyzer route/version, or sealed cache
decision differs. Its replay-integrity.json is required alongside replay
0 new / 0 changed; running the ordinary collector twice is not replay proof.
In exceptions_only, clean pending rows are represented by one
content-addressed clean_batch count and ID; active ambiguous rows remain
fully detailed only when new or changed. The machine contract retains the
stable row IDs behind the batch digest so an explicit board approval of that
exact batch can be verified without printing every clean description. The
digest binds each stable review ID, revision, and evidence fingerprint, so any
changed member produces a different batch ID. Neither
mode writes to Clockify.
A route probe only proves that the selected transport can return minimal JSON. Before private-text approval, run the live synthetic evaluator. It probes the route, submits five fixed non-private cases twice, and writes both a capture and a digest-bound scorecard:
python3 scripts/analyzer_live_evaluation.py \
--tier primary \
--capture-output state/validation/analyzer/primary-capture.json \
--scorecard-output state/validation/analyzer/primary-scorecard.jsonThe built-in cases cover one atomic accomplishment, a required split, duplicate
evidence merging, a title-only meeting, and waiting noise. The command accepts
no evidence or prose input, so CLOCKIFY_ANALYZER_PRIVATE_TEXT_APPROVED remains
closed. Run it separately with --tier fallback if a fallback is configured.
The capture uses the versioned analyzer-evaluation input contract; the scorecard
contains no captured prose.
The transport-free evaluator remains available for inspecting or re-evaluating an existing capture:
python3 scripts/analyzer_evaluation.py \
--input /absolute/path/to/synthetic-capture.json \
--output /absolute/path/to/analyzer-scorecard.jsonThe live harness validates each replay through the same bounded production
contract-repair and partition-recovery path used by real analysis; exhausted
leaves remain failures rather than being hidden by the harness. The offline
evaluator then checks complete corpus coverage, fixed expected activity,
exception, and omission dispositions, production schema/citation and atomicity
rules, concrete accomplishment concepts, and renderer/forbidden-description
compliance. Adjacent repeated words are rejected. Replay stability
compares the review-relevant decision—disposition, partitions, lifecycle,
effort, and confidence—rather than arbitrary rationale prose.
For waiting-only evidence, planned and noise are equivalent omission
lifecycles because neither creates a review row; activity boundaries and
exception kinds remain exact.
The append-only validated decision cache owns exact output replay and is separately integrity
checked. Long immutable ledger IDs never rely on model copying: local code
expands disjoint bundle-member ranges before schema and citation validation. Prefix validation
uses a neutral placeholder because deterministic routing owns the final prefix.
If every configured qualified route rejects or times out on a bounded extraction partition, the analyzer bisects its
evidence at the nearest context or complete conversation-turn boundary and
analyzes each child through the same route set, cancellation gate, and sealed cache.
It never retries the identical parent request.
Recovery never separates user intent from its following assistant result. It is
bounded at an indivisible turn, singleton evidence, or depth four, records every
child route decision, and cannot rejoin normal cross-chunk synthesis unless every
evidence ID is classified exactly once.
A passing synthetic
route scorecard proves contract fitness, not July semantic accuracy; the latter
still requires full-denominator human dispositions and the measured acceptance
thresholds. Neither a probe nor a passing synthetic scorecard authorizes
private-text egress.
Month-scale accounting and scheduled reviews run under an available host user service, not an SSH
foreground process or a Codex/terminal session.
scripts/clockify_accounting_runner.py holds a nonblocking
single-instance lock, resumes the append-only analyzer cache, and atomically
writes runner-status.json with only lifecycle metadata. It never serializes
the analyzer environment or credentials. Accounting artifacts are atomically
published before the validated work-accounting-result.json completion marker;
the runner trusts that marker only when the complete required artifact set is
present. A completed result is idempotent and will not be recomputed.
Before starting, the runner also requires the approved Flash model and release
revision. A nonempty cache is sealed to exactly one model tag; changing an
in-progress explicit-tag run to the generic alias, or presenting a mixed-model
cache, fails closed before any provider request. The safe model and revision are
recorded in lifecycle status so host drift can be audited without exposing a key.
The reviewed unit is ops/systemd/clockify-work-accounting.service. Its
clockify_autopilot_runner.py entrypoint runs the complete review process,
writes compact durable status, and returns exit 75 only for incomplete source
peer coverage. Complete Precision and central evidence still produces review
proposals plus a coverage_warning. systemd then recollects after one hour, bounded by
CLOCKIFY_AUTOPILOT_MAX_COVERAGE_RETRIES; configuration and integrity exit 2
still fail closed without looping. After retry exhaustion, durable source debt
remains and the next primary schedule tries the expanded interval again. Install it
as ~/.config/systemd/user/clockify-work-accounting.service, create the private
mode-0600 environment file from
ops/systemd/clockify-work-accounting.env.example, and enable user lingering on
Precision so the unit survives SSH/Mac/desktop disconnection and Precision
reboot. The
unit clears all inherited fallback-route variables so this validation can use
only the approved pinned Flash route. It restarts unexpected crashes, but
RestartPreventExitStatus=2 prevents a known fail-closed configuration,
authentication, integrity, or route error from looping indefinitely. Logs remain
in the Precision user journal.
Deterministic slice paths are not release identities. The review coordinator
rejects a structurally valid completion bundle whose bound runtime differs from
the active release. A historical bundle with actionable peer gaps is retained
only as an immutable recovery parent: canonical coverage creates exact source
debt, while replay and publication remain blocked. Exact recovery creates a
current-runtime derived run, reuses compatible complete provider evidence via a
digest-bound source-adoption.json, and recollects only the requested
sessions/<peer> or repositories/<peer> facet. Stable record identities make
repeated merges idempotent; compatibility, snapshot, adoption, or lineage drift
fails closed.
Exhausted exact debt uses a bounded metadata-only peer probe (ssh ... true,
with no activity evidence) to observe health epochs. Offline-to-online
reactivates that debt once. Repeated offline or online observations do not reset
its budget, and runtime change alone is not treated as source recovery. An
exhausted generic runner/unclassified record is likewise not retried under an
unchanged runtime. When a new runtime can validate its immutable historical
bundle, one classification pass replaces the generic record with exact peer
debts; subsequent cycles recover those exact sources rather than rerunning the
full provider.
Set CLOCKIFY_ANALYZER_PRIMARY_REASONING_EFFORT=none for the current Flash
alias. Ollama otherwise enables a reasoning stream that can spend minutes on a
small contract request. The setting remains model inference, is bound to new
cache route identities, reuses accepted legacy decisions from the same model
revision, and deliberately retries legacy rejections and timeouts.
Set CLOCKIFY_HTTP_TIMEOUT_SECONDS to control only read-only Clockify
collection requests. It defaults to 30 seconds and accepts base-10 integers
from 5 through 120, inclusive. Empty, non-integer, or out-of-range values
fail before a Clockify request; Fathom, SSH, canonical-export, and analyzer
timeouts are unaffected. The systemd and launchd environment examples set the
documented default explicitly.
Calendly configuration is separate from the accounting runner: by default the
collector reads ~/.config/serenichron/calendly.env (or the mode-0600 path in
CALENDLY_ENV_FILE). That file supplies a read-only recording endpoint through
CALENDLY_RECORDINGS_URL, its gateway token, and
CALENDLY_GATEWAY_READ_ONLY=true; values are intentionally not shown here. An
incomplete recording pagination result, missing recording capability, or a
non-read-only configuration is a visible capability gap: the Calendly source
remains incomplete and complete source coverage cannot pass. The collector may
record scheduled events as scheduled_without_recording, but they never create
duration evidence or a Clockify proposal.
Use scripts/calendly_collector.py preflight with --since, --until, and
--output to validate the configured read-only gateway and canonical interval
without making a network request. collect takes the same arguments plus a
required --checkpoint-root; it resumes or creates a checkpointed collection
and emits recordings only after pagination is complete. Any unavailable or
partial result has complete: false and no partial recording output.
For a bounded operator-requested review that cannot wait for gateway setup,
clockify_sync_collect.py run --calendly-optional records Calendly as explicitly
excluded and does not contact the gateway. The default remains required and
fail-closed; the override does not change scheduled autopilot configuration.
Portfolio quality reports canonical recording_coverage while preserving the
read-only fathom_coverage alias for historical artifacts. New replay seals
bind the canonical reconciliation digest, deduplication version and tolerance,
and timestamped-split digest. Older Fathom-only seals remain readable and are
verified against the immutable fields they originally contained.
When the desktop is unavailable, macOS can run the same guarded runner through
ops/launchd/com.serenichron.clockify-work-accounting.plist and
ops/launchd/clockify-work-accounting.sh. The wrapper reads the same private
mode-0600 environment contract, clears every fallback route, restarts unexpected
crashes, and maps the runner's intentional exit 2 to a clean launchd exit so a
known authorization, integrity, configuration, or route block cannot create a
restart loop. Install or load this agent only under separate approval; keeping
the reviewed files in the repository does not activate it.
These reduce model calls, request bytes, Clockify paging and repeated child runs without changing sealed decisions. Each one leaves historical replays byte-identical.
- Review partition normalization (on for the ledger pipeline cache):
a fresh semantic-review response whose only defect is partition
bookkeeping is repaired locally (
review_partition_normalization_v1) instead of spending model repair calls. Contested rows and unassigned members go to oneanalyzer_review_partial_quarantineexception without effort, and only when that routes at most 25% of members; otherwise the usual repair path runs. Sealed decisions replay unchanged. - Trimmed projection (routing
"semantic_projection_contract": "clockify-semantic-projection/v2"): diff hunks and fenced code blocks become line-count markers, and user bodies over 4,000 characters keep a head and tail excerpt. Every member is still sent. Requests declare the contract, so unmarked runs keep their historical request bytes. - Bounded Clockify overlap read (routing
"clockify_bounded_overlap": true): fresh collection starts seven days before the window (clockify-overlap-pagination/v3) instead of paging all history. It would miss an entry that began more than seven days before the window and still overlaps it, so the complete v2 scan stays the default. - Cycle circuit breaker (config
circuit_breaker_failures, default 2;circuit_breaker_cooldown_hours, default 72): a failed slice whose rerun inputs are unchanged is skipped after repeated identical failures, then probed once per cooldown. A new release, config, routing, corrections, acceptance, source or replay closes it immediately. A cycle with nothing else to do reportscircuit_openand exits 75. - Per-call diagnostics: live analyzer calls append numeric-only
records (route, mode, body digest and bytes, latency, outcome, token
usage) to
<analyzer-cache>.call-diagnostics.jsonl, mode0600. The file is not part of the sealed cache or any snapshot.
scripts/efficiency_measurement.py reproduces the offline before/after
numbers from sealed artifacts only (partitions, cache-rejections,
projection RUN..., clockify-overlap, circuit-breaker JOURNAL).
Fresh, configured Clockify collections retain full native checkpoint pages in
evidence/clockify-native-checkpoint/, separately from the sanitized semantic
ledger. The report binds their hash, exact target and period; derivation copies
only the verified bytes. These are original collection snapshots, not fresh GETs
or historical POST receipts, and they do not by themselves authorize credits or
Clockify writes. Historical runs without this optional proof remain readable.
Accounting can consume audited verified_posted_credit schema 2 records from
the frozen corrections snapshot. Each record identifies exactly which current
proposals are already covered by approved native posts: one accomplishment,
a disjoint aggregate, or aliases of one fully recorded meeting. Accounting
checks the prior entries against that run's preserved native collection and
keeps unrelated work visible. Missing or mismatched proof does not hide time.
Repair may append effective credits without replacing parent corrections or
reusing a prior entry; replay reads only sealed facts and copied snapshots.
This does not automatically discover equivalences or authorize Clockify writes.
New cycle-generated review bindings also retain original proposal/ledger handles
and the cycle's private post-proof destination. Pass that original binding to
clockify_native_sheet_post.py plan --review-batches; approved execution then
saves a clockify-native-credit-input/v1 packet automatically after exact
Clockify readback. A retry after a packet-write interruption reuses the confirmed
posting events, without another POST. Aliases and ordinary session work do not
become original recording proofs.
Fresh recurring slices select those local packets against their sealed Clockify checkpoint and exact provider recording identities. They freeze even an empty selection before replay; later history/configuration changes cannot replace it. Only proved interval intersections are credited, preserving exact residual seconds. Different proposed versus posted project/tag routing remains a full review proposal with its overlap warning and explicit local routing debt, not a silent client reclassification. Source recovery archives the old selection and creates a new one for the replacement source. Legacy bindings and deliveries remain unchanged; existing off-path posting receipts require a finite verified bootstrap inventory, not an archive scan. This local code is not evidence that an installed autopilot has been deployed or restored.
Native posting accepts explicit source-accounted declarations through
--source-adoptions. The clockify-source-accounted-adoptions/v1 schema keeps
its historical readback-digest requirement without fallback. Explicitly choosing
clockify-source-accounted-adoptions/v2 instead verifies each prior entry once
against the plan's captured live snapshot: unique ID, exact workspace/user,
approved payload and duration. The sealed credit records
verification_basis: current_live_snapshot, a new readback_digest, and the
separate historical_readback_digest; the original confirmed digest is not
claimed reproduced. Every credited entry must pass fresh direct GET verification
before any create. Both versions require original source, native plan, approval,
and confirmed event artifacts plus explicit one-to-one equivalence; shared
sources alone never collapse independent accomplishments. Execution/replay uses
approved sealed facts without reopening the originals. Legacy entries lacking
the original native plan and approval remain unsupported.
- Collector, quality, and review-state steps do not write to Clockify.
- Missing analyzer configuration, incomplete required central or Precision evidence, invalid correction logs, title-only meetings, and contract failures block or become explicit exceptions; they never become invented work.
- Missing non-coordinator peer evidence becomes durable coverage debt and a warning; it does not suppress proposals supported by complete sources.
- EmblemStudio work uses the applicable Serenichron project and task type, with
ES —instead of the ordinarySC —description prefix. - Private semantic prose cannot reach a configured analyzer unless
CLOCKIFY_ANALYZER_PRIVATE_TEXT_APPROVED=approvedis explicitly present at runtime; route-probe success is not privacy approval. - A blocked accounting stage still writes its local action contract and exits nonzero so schedulers cannot mistake it for a healthy run.
- The quality command never updates Google Sheets or any other external system.
- The Sheet publisher requires an explicit
--enable-write, a passing quality report, a passing immutable replay for the same source run, and a separately approved workbook/interval. It preserves human decision cells by stable ID. - Clockify posting requires an explicit board decision for each stable review item.
- Approval-gated portfolio posting uses
CLOCKIFY_POST_HTTP_TIMEOUT_SECONDS, which defaults to45seconds and accepts the same inclusive5through120base-10 integer range. Invalid values fail before Clockify access. The setting changes only request waiting time: it does not authorize--execute, select a portfolio, or weaken digest, quality, idempotency, reconciliation, or receipt gates. - Sheet synchronization, Multica issue mutation, schedule changes, deployment, and fleet rollout are separate guarded actions.
- Do not claim a fix is live until the runtime path and Git SHA are read back on every collector host.
python3 -m unittest discover -s tests -v
python3 -m py_compile \
clockify_sync_collect.py \
scripts/evidence_ledger.py \
scripts/semantic_analyzer.py \
scripts/work_allocator.py \
scripts/caveman_renderer.py \
scripts/work_accounting_pipeline.py \
scripts/review_corrections.py \
scripts/review_acceptance.py \
scripts/analyzer_evaluation.py \
scripts/analyzer_live_evaluation.py \
scripts/clockify_accounting_runner.py \
scripts/clockify_sync_collect.py \
scripts/clockify_sync_quality.py \
scripts/clockify_review_state.py \
scripts/clockify_review_run.py
git diff --checkThe approval-gated production sequence and exact live IDs are documented in
clockify-review-rollout.md. Re-read live state
before using it; the snapshot is intentionally not treated as current truth.
The requirement-by-requirement distinction between local proof and missing live
acceptance evidence is tracked in
clockify-process-acceptance.md.
tests/test_publication_end_to_end.py drives the immutable coordinator event
ledger, consumed Clockify posting approval and receipt, exact API/shared-report
readback, ECB currency conversion, publication gate, receipt store, and finance
adapter ordering with synthetic fixtures. It never uses a production transport:
only the report/Slack boundary is a recording fake.
tests/fixtures/reconciliation/publication-routine/manifest.json proves a
two-day, two-slice routine period. Publication is legal only after the exact
post receipt is bound to both fresh readbacks, the prepared contract has a
separate approval, the report is read back, and Slack is upserted. Re-running a
published period returns its persisted receipt without another report update or
Slack message.
tests/fixtures/reconciliation/publication-backlog/manifest.json carries a
Calendly-only recording, a Fathom/Calendly duplicate, transient missing-slice
coverage debt, an approved Desktop limitation, an ambiguous POST recovery,
USD/EUR native buckets, retained correction revision, and report-success then
Slack-failure retry. Calendly may be excluded only for a bounded historical
recovery explicitly recorded in coverage; future autopilot coverage treats it
as a first-class required source.
Publication state is fail-closed: publication_deferred means preparation or
authorization evidence is absent; publication_incomplete means a delivery
attempt retained the verified report receipt but needs a Slack retry; and
published requires the bound report and Slack receipts. ECB quotes use the
latest eligible EUR-base quote, convert every native bucket to USD with
half-up cent rounding, and are rejected when older than four calendar days.