forge issue view and pr view: print created, updated, closed, and merged timestamps #204

Merged
vnprc merged 3 commits from agent/forge-view-timestamps into master 2026-09-11 21:27:59 +01:00
Member

forge issue view and forge pr view now print when an item was created and last updated, plus when it was closed and, for pull requests, whether and when it was merged. forge pr snapshot carries the same facts as JSON fields. Nothing else in forge changes: the header labels are realigned into one column and every other line, the body, and the comment blocks are byte-identical. The proof is the exact-output tests for open, closed, and merged items and the snapshot rejection cases; the machines that run forge are unaffected until their allod-tools pin moves. If a date reads wrong, revert this one commit pair; no state is written anywhere.

What changes

  • issue view: Created: and Updated: after Author:, and Closed: when the issue is closed. Dates are the first ten characters of the API timestamp, the YYYY-MM-DD form the comment lines already use.
  • pr view: the same three lines, then Merged: yes YYYY-MM-DD or Merged: no, printed only for a closed pull request. The pr view label column widens from 8 to 10 characters so Created: fits; issue view already had room.
  • pr snapshot: pull_request gains state, created_at, updated_at, closed_at (null until closed), merged, and merged_at (null until merged), carrying the API's full RFC 3339 timestamps. schema_version stays 1: the change is additive and the one consumer, pr-explain, validates named fields and ignores extra keys. The snapshot fails closed on a malformed timestamp, a state other than open or closed, merged disagreeing with merged_at, closed_at on an open PR, or merged on a PR that is not closed.
  • A missing timestamp renders as null, the same stand-in every other missing header field already prints.

Risk

R1. Read-only output formatting and an additive JSON schema. Worst credible failure after the tests pass is a script that pinned pr view's old two-space label alignment; pr view output was never a documented interface and pr snapshot is the machine-readable one. Rollback is a revert.

Validation

  • gofmt -l . empty; go vet and go test ./... green untagged and with site, secret, and site,secret, run by the overseer in the branch worktree after the final commit.
  • New exact-output tests: open and closed issue; open, closed-unmerged, and merged PR. New snapshot tests: the fields for open, closed, and merged PRs; each rejection above; a guard proving each pre-existing malformed fixture fails only on its named defect (those fixtures gained the valid new fields so the older validators still run).
  • Cross-family review after the first commit: one reviewer found the merged-but-open gap and the fixture weakness, both fixed in the second commit; the other read every hunk and reported nothing.

Closes allod/tools#194

`forge issue view` and `forge pr view` now print when an item was created and last updated, plus when it was closed and, for pull requests, whether and when it was merged. `forge pr snapshot` carries the same facts as JSON fields. Nothing else in `forge` changes: the header labels are realigned into one column and every other line, the body, and the comment blocks are byte-identical. The proof is the exact-output tests for open, closed, and merged items and the snapshot rejection cases; the machines that run `forge` are unaffected until their `allod-tools` pin moves. If a date reads wrong, revert this one commit pair; no state is written anywhere. ## What changes - `issue view`: `Created:` and `Updated:` after `Author:`, and `Closed:` when the issue is closed. Dates are the first ten characters of the API timestamp, the `YYYY-MM-DD` form the comment lines already use. - `pr view`: the same three lines, then `Merged: yes YYYY-MM-DD` or `Merged: no`, printed only for a closed pull request. The `pr view` label column widens from 8 to 10 characters so `Created:` fits; `issue view` already had room. - `pr snapshot`: `pull_request` gains `state`, `created_at`, `updated_at`, `closed_at` (null until closed), `merged`, and `merged_at` (null until merged), carrying the API's full RFC 3339 timestamps. `schema_version` stays 1: the change is additive and the one consumer, `pr-explain`, validates named fields and ignores extra keys. The snapshot fails closed on a malformed timestamp, a `state` other than `open` or `closed`, `merged` disagreeing with `merged_at`, `closed_at` on an open PR, or `merged` on a PR that is not closed. - A missing timestamp renders as `null`, the same stand-in every other missing header field already prints. ## Risk R1. Read-only output formatting and an additive JSON schema. Worst credible failure after the tests pass is a script that pinned `pr view`'s old two-space label alignment; `pr view` output was never a documented interface and `pr snapshot` is the machine-readable one. Rollback is a revert. ## Validation - `gofmt -l .` empty; `go vet` and `go test ./...` green untagged and with `site`, `secret`, and `site,secret`, run by the overseer in the branch worktree after the final commit. - New exact-output tests: open and closed issue; open, closed-unmerged, and merged PR. New snapshot tests: the fields for open, closed, and merged PRs; each rejection above; a guard proving each pre-existing malformed fixture fails only on its named defect (those fixtures gained the valid new fields so the older validators still run). - Cross-family review after the first commit: one reviewer found the merged-but-open gap and the fixture weakness, both fixed in the second commit; the other read every hunk and reported nothing. Closes allod/tools#194
issue view and pr view gain Created:/Updated: header lines (and Closed:
when the item is closed), so an issue or pull request's age is readable
without depending on comment activity. pr view also gains a Merged: yes
<date>/no line for closed pull requests. Dates are the API timestamp's
first 10 codepoints, the same slice comment lines already use; a missing
or null timestamp renders as the literal "null", matching how every other
header field already handles a missing value. pr view's header column
widens to fit the new Created:/Updated: labels, so every line in both
commands stays aligned.

pr snapshot carries the same underlying fields (state, created_at,
updated_at, closed_at, merged, merged_at) as RFC 3339 strings, validated
the way every other snapshot field is: a malformed timestamp, or merge/
close metadata that contradicts itself, fails snapshot validation instead
of reaching a consumer.

Refs allod/tools#194
projectPRSnapshot validated the merged/merged_at pair and closed_at
against an open state, but not merged against state itself: a response
with state "open", closed_at null, merged true, and a valid merged_at
passed, so pr snapshot could emit a merged-but-open pull request.
Forgejo always closes a pull request it merges, so add that rule
alongside the existing two. pr view already prints Merged only when
state is closed, so its output needs no change.

Fixed the malformed-response test fixtures (cases 42, 44-46, 48-50):
they predate the state/timestamp/merged fields and were failing the new
state check before ever reaching the object-ID, ref, repository, or
clone-URL validator each is named for. Added valid state/timestamp/merge
metadata to each so it again fails only on its own named defect, plus a
guard test that repairs case 42's one named defect and confirms the
result passes -- proving no other defect was hiding in the fixture. Added
a rejection case for the new merged-requires-closed rule.

Refs allod/tools#194
Three gaps between what the snapshot does and what the pull request body
claims about it.

A pull request the API calls closed but gives no close date was accepted
and emitted, although closed_at is documented as null only until the pull
request is closed and the snapshot is documented as failing closed on
contradictory close and merge fields. The projector now rejects that pair
next to the existing rejection of a close date on an open pull request,
and the comment names both directions.

The rejection table had no case for a state outside open and closed, so
nothing exercised the validator that accepts only those two. A fixture
carrying "state":"draft" now covers it, alongside a fixture for the closed
pull request with no close date.

The guard proving a malformed fixture fails only on its named defect
covered a single fixture, and two of the older fixtures still lacked the
state, timestamp, and merge fields the newer validators require: those
bodies failed before reaching the check their names claim to exercise, and
the table reported them caught anyway. Every fixture now carries valid new
fields, and the fixtures live in one table that records each body's single
defect and the repair for it. The guard walks that table and requires each
repaired body to become a passing snapshot, so no case can pass for a
reason other than its own.

Refs allod/tools#194
vnprc approved these changes 2026-09-11 21:27:53 +01:00
vnprc merged commit 5076eaca1b into master 2026-09-11 21:27:59 +01:00
vnprc deleted branch agent/forge-view-timestamps 2026-09-11 21:28:00 +01:00
Sign in to join this conversation.
No description provided.