Skip to content

feat: add phabfive export, a task written as a spec - #625

Open
holmboe wants to merge 1 commit into
spec-kind-editfrom
export-manifest
Open

holmboe wants to merge 1 commit into
spec-kind-editfrom
export-manifest

Conversation

@holmboe

@holmboe holmboe commented Nov 12, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Third of three stacked pull requests. Based on #624; review only the last commit, and retarget to main once that one is merged.

What show prints is for a person: Status: Resolved, Visible To: All Users, no tags and no subscribers. None of it can be typed back in. phabfive export writes the same task in the spelling a spec takes:

$ phabfive export T123 > task.yaml
$ $EDITOR task.yaml
$ phabfive apply -f task.yaml --dry-run
$ phabfive apply -f task.yaml
  • The output is a kind: edit spec: status by its key, priority by its keyword, a project by its #hashtag, a user by username, a policy by its keyword. Lists are sorted.
  • An unchanged export applies as no change. That invariant is what the e2e tests pin.
  • --as create writes a create spec instead, for a new task like the old one. It drops the identity, the stamp, and the parents, subtasks and commits: a copy is not the same node in the graph.
  • Monograms and links are arguments, or piped in: bare monograms, or what a search prints as yaml, json or jsonl.
  • YAML by default, on a terminal too. --format=json and jsonl are honoured, terminal formats are refused. -o FILE writes a file.
  • Each task is stamped with modified:, and the file says interpolate: false.
  • The YAML is parsed back before it is printed, and falls back to JSON if it would not round-trip, so the text in the file is the text in the task.

Tasks only. The library half is phabfive.export (export_spec, dump_spec), data only. Pastes, projects and repositories can follow the same way; a passphrase cannot be edited through Conduit at all.

Behaviour worth a look in review

  • Left out of an export, because a spec cannot spell them: the column of a task on several workboards, a priority outside the stock table, and the "Subscribers" and "Task Author" policies. An absent key is left alone, so nothing is lost on apply.
  • The column follows a retag. A task on one board is exported with its column:. Changing only projects: to another board's project then places the task in the same-named column there, or is refused as unknown-column; removing its only board project is refused. The refusals say to remove column:, and the guide has a section on it. The alternative is not to export column: by default.
  • A spec has no key for points, custom fields, the subtype, comments or the author, so an export does not carry them.

Test plan

  • tests/test_export.py: the output validates on the offline layer and against the JSON Schema, text survives dump and load byte for byte (trailing newline or none, trailing spaces, CRLF, yes, 123, {{ x }}), and the command's arguments, stdin forms and formats.
  • tests/e2e/test_export_edit.py against a local Phorge stable: an export applied unchanged changes nothing and does not move the modified time, an edited export sends the difference once, a task changed since the export is not overwritten without --force, a create export makes a task whose own export matches the original, and a search piped into an export.
  • make test-e2e on stable: 167 passed, 2 skipped.
  • Full unit suite, ruff, ruff format, mypy, scripts/gen_spec_docs.py --check and mkdocs build --strict.
  • phabricator-stable was not run locally; the ci:phabricator-stable label ran it here, and it passes.

🤖 Generated with Claude Code

What `show` prints is for a person - `Status: Resolved`, `Visible To: All
Users`, no tags and no subscribers - and cannot be typed back in.
`phabfive export T123` writes the same task in the spelling a spec takes:
a status by its key, a project by its hashtag, a policy by its keyword.
The file is a `kind: edit` spec, so `phabfive apply -f` sends whatever is
changed in it, and an unchanged export applies as no change.

- `--as create` writes a create spec instead, for a new task like the old
  one, without the identity, the stamp and the relations
- Monograms are arguments or piped in from a search
- Each task is stamped with `modified:`, so a change to a task somebody
  else has touched since is refused as `stale`
- The file says `interpolate: false`, and the YAML is parsed back before
  it is printed, so the text in the file is the text in the task
- Left out, because a spec cannot spell them: the column of a task on
  several workboards, a priority outside the stock table, and the
  "Subscribers" and "Task Author" policies. An absent key is left alone

Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
@holmboe holmboe added ci:phorge-stable Test Phorge stable in the Kubernetes deploy check ci:phabricator-stable Test Phabricator stable, as Phacility left it, in the Kubernetes deploy check labels Nov 12, 2026

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ci:phabricator-stable Test Phabricator stable, as Phacility left it, in the Kubernetes deploy check ci:phorge-stable Test Phorge stable in the Kubernetes deploy check

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant