Hacktoberfest 2026: những issue maintainer đã đánh dấu cho tháng Mười, đang mở và phù hợp người mới. Xem issue Hacktoberfest

Job history: expose sealed-plan and approval/result evidence

Đang mở
#166 0 bình luận 0 reaction 0 người được giao Xem trên GitHub

Maintainer thường phản hồi trong vòng 1 ngày

Chưa có ai nhận issue này.

Đánh giá

Độ khó
4/5
Thời gian dự kiến
3-5 ngày
Mức phù hợp với người mới
48/100
Loại issue
Tính năng
Độ rõ ràng
Đặc tả rõ ràng
Mức độ hoạt động
Sôi nổi
Công nghệ
go
Lĩnh vực
cli, devops

Hướng nghiên cứu

Bắt đầu với cmd/ob/job.go và cmd/ob/schedule.go để lần theo các mẫu đầu ra của lệnh và finite_envelope, sau đó đọc internal/journal/journal.go, internal/journal/job_result.go và internal/engine/job.go để xem dữ liệu lần chạy job được ghi lại. Theo dõi JobRunRequest và bản ghi bắt đầu job, bao gồm cả việc lưu giữ thông qua PruneCandidates. Hoàn thành khi ob job history cung cấp các kết quả và siêu dữ liệu được chỉ định cho từng job, xử lý các lần chạy chưa hoàn tất và ghi lại những lần kích hoạt theo lịch nào vẫn còn trong ob schedule history.

Do mô hình lập chỉ mục viết ra từ nội dung của issue.

Mô tả

enhancement

Current scope (v2026.10.1-alpha)

The missing per-job read surface is implemented by #191: ob job history merges timer/operator records and sealed attached journal records, and ob job logs reads exact host-supervised run logs. CLI help explicitly describes retention bounds and the absence of separate retained logs for attached sealed runs. ReleaseID and DataEffect are now structured job-start journal fields.

This issue remains open for the provenance/evidence work in the original proposal:

  • Persist the exact sealed job plan digest; journal.Record and JobRunRequest still do not carry it.
  • Expose data effect, approval class/identity, migration-backup authorization, and normalized job-result evidence in the per-job read model where retained evidence exists. JobHistoryRecord currently omits them.
  • Keep unavailable historical evidence explicit; do not reconstruct an approval or plan identity from unrelated digests.
  • Preserve retention-bounded semantics and cover older records and mixed timer/operator history.

The current read-surface regression run passed, including TestJobHistoryMergesTimerAndOperatorStoresByOperation. This is an evidence-enrichment ticket now, not a request to add an absent command.

Original proposal and historical context

The problem

The two job-execution paths have inverted read surfaces: the lower-risk one is
well instrumented and the higher-risk one is not.

A scheduled job has a full per-job read surface:

  • ob schedule history <job> — the newest run records, newest first
  • ob schedule logs <job> [run] — the output of one exact activation
  • ob schedule list — timer state, next elapse, last trigger

A sealed manual job — the path that exists precisely because the job
declares data_effect: migration or destructive — has neither. ob job
carries exactly two subcommands, plan and run (cmd/ob/job.go:57). After
running one, the only way to see what happened is ob audit, which is
journal-wide and unfiltered: one row per invocation across every operation
kind, with -n as the sole control (cmd/ob/commands.go:219). There is no way
to ask "what has catalog-refresh done, and when."

So the job whose failure matters most is the one an operator can least easily
review after the fact.

It is worse than a clean split between the two paths, because a single job can
land on both. Only deploy_lock: pinned forces data_effect: none
(internal/app/validate.go:450); a scheduled job on the default exclusive
lock may declare migration or destructive, and its timer fires it on cron
like any other. What scheduleRun refuses is the operator-initiated run of
such a job (internal/engine/schedule_run.go:57), redirecting it to
ob job plan and ob job run. So that job's unattended firings are visible in
ob schedule history, its hand-triggered runs are not visible anywhere
job-scoped, and nothing shows both in one place — for exactly the jobs where
the interleaving matters most.

Proposed change

Add ob job history <job> — and, if it falls out cheaply, ob job logs <job>
— mirroring the ob schedule equivalents.

This is mostly a read over data that already exists, but not entirely — see
"What is missing" below.
Every job run is already journaled through the canonical writer, and
JobResultEvidence (internal/journal/job_result.go:8) already records the
normalized, redaction-safe result per invocation:

type JobResultEvidence struct {
    SchemaVersion   string
    Changed         bool
    Provider        string
    BeforeRevisions []string
    AfterRevisions  []string
    Digest          string
}

It hangs off the journal record as job_result
(internal/journal/journal.go:68), and the start record already carries the
operator, timestamp, git SHA, approval class, approved-by, and the migration
backup mode with its override operator and reason
(internal/journal/journal.go:152-178).

What is missing

Three fields a review row wants are not journaled today, so this needs a
small write change before the read command:

  • Plan digest. Neither JobPlan.PlanDigest
    (internal/onebox/job_plan.go:45) nor Operation.PlanDigest
    (internal/onebox/operation_types.go:194) ever reaches a Record. The
    journal carries only ApprovalDigest — the grant's digest over a struct that
    contains the plan digest, so it is not recoverable from it. This matters
    most for the interactive ob job run <id> path, which writes neither a plan
    nor a grant to disk (cmd/ob/job.go:223-244): the journal is that run's only
    durable record.
  • Release. Present only as free text, Detail: "release=" + current
    (internal/engine/job.go:85). Parseable, but fragile.
  • Data effect at run time. Not journaled. A break-glass review wants it.

Suggested: add ReleaseID, PlanDigest and DataEffect to journal.Record,
set them in the job start record, and thread PlanDigest through
JobRunRequest. Keep the existing Detail: "release=" for older readers.

Note also that journal.Summarize will not do the reduction — Started,
Operator, StartedAt and Finished are all gated on Phase == "deploy"
(internal/journal/journal.go:485-506) — so this needs a small job-specific
reducer rather than reuse.

Retention

PruneCandidates (internal/journal/journal.go:315-351) puts job_run
journals in a single "auxiliary" window shared with exec, schedule-run,
schedule-pause and service-apply, sized RetainReleases*2 (default 5, so
10 — internal/engine/deploy.go:572, internal/app/defaults.go:25-26), pruned
on every deploy. So a burst of ob exec can evict the break-glass job run
somebody wanted to review, and ob job history would silently have nothing to
show. Either the command's help text states this plainly, or PruneCandidates
grows per-OperationKind windows. Worth deciding with the command rather than
after it. (ob schedule history is unaffected — its depth is journald's.)

New command, not an ob audit --job filter

Settling the alternative this issue originally left open: a new sibling
command, for four reasons.

  1. auditRows deliberately flattens to eleven generic fields
    (internal/engine/audit.go:104-116). Service, JobResult,
    ApprovalClass, MigrationBackup and the release do not survive it. A
    --job filter means adding those to AuditRecord — empty on every non-job
    row — plus a job-specific branch. That is a job reader living inside
    audit's name.
  2. ob audit is documented and cross-referenced as the who-did-what
    invocation table, and is the next command for operation_failed and
    cancelled. Widening its shape has blast radius; a sibling has none.
  3. ob audit reads N+1 round trips, one cat per journal
    (internal/engine/audit.go:66-81). A job reader can use journal.Journals
    in one round trip and skip every id without the -job_run- infix that
    newOperationID embeds (internal/onebox/service.go:60), never parsing a
    deploy journal at all.
  4. Symmetry with ob schedule history (cmd/ob/schedule.go:86-126), same
    finite_envelope output class.
Row shape

Suggested columns, mirroring ob schedule history where the fields allow it:
STARTED OUTCOME DURATION OPERATOR RELEASE EFFECT APPROVAL BACKUP CHANGED OPERATION. Outcome is succeeded | failed | incomplete — a start with no
finish is a crashed run and should say so rather than vanish. The help text
should also say that timer firings of a job which also declares a schedule
live in ob schedule history, not here.

One naming note: ob schedule history's help calls an ob schedule run a
"manual run" (cmd/ob/schedule.go:89), while the code and docs use "manual
job" for when: manual. ob job history should avoid the phrase.

Current workaround

ob audit -n <large> and read past every unrelated record, or
ob audit --output json and filter the journal client-side. Neither is a
per-job view, and both require the operator to know the journal's shape.

Worse: ob audit does not currently render sealed job runs correctly — it
reports them as action job, outcome deployed, with no job name — so the
documented fallback does not actually tell you which job ran. Filed separately;
that bug stands regardless of this issue.

Scope and safety

No change to the one-application, one-host scope. Read-only: no lock, no
fence, nothing written, in line with ob status, ob audit and the
ob schedule read commands. Redaction is already handled upstream —
JobResultEvidence is normalized and redaction-safe by construction, so this
surfaces existing evidence rather than widening what is recorded.

Related: #164 covers the interactive approval prompt on the same ob job path.

Ngôn ngữ chính
Go
Star
3
Fork
0
Merge trung bình
2 giờ 46 phút
Pull request đã merge (30 ngày)
38

Chuẩn bị môi trường

Bắt đầu từ đâu

  1. Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
  2. Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
  3. Fork repository và làm thay đổi trên một nhánh.
  4. Mở pull request có tham chiếu số hiệu của issue.

Issue khác của labstack/onebox

Tất cả issue của labstack/onebox

Issue tương tự

Thêm issue về Go

Nhận issue mới trong hộp thư của bạn

Bản tóm tắt ngắn những issue GitHub phù hợp với người mới.