onetaskgraph-github-projects 0.2.11

A onetaskgraph source over GitHub Projects.
Documentation

A stateless onetaskgraph source over one GitHub Projects v2 board.

A board is a container of projects, not a project. Its own title, shortDescription and readme are never read as an item's fields and are never written: nothing in this source can rename the board a user configured.

A project is an issue and its tasks are that issue's sub-issues. GitHub's schema decides that: Issue exposes parent, subIssues and subIssuesSummary, and DraftIssue exposes none of them. Creating an issue needs a repositoryId, and a board has none, so [GitHubProjectsConfig::repository] names the one repository this source creates its project and task issues in; a write without it is refused naming the field.

Telling a project from a task. A board issue is a project when either it has sub-issues or it carries [ItemKind::METADATA_KEY]; otherwise it is a task. A sub-issue is always a task, whatever it carries. The marker is sufficient and never necessary: it is what makes an empty project — the state a project copy passes through between creating the project and filing its first task — readable as a project, while the sub-issue arm lets a person author a project on the board by hand with no knowledge of this product's metadata at all. Pull requests are neither a project nor a task and are ignored.

Where metadata lives. Short typed things go to typed fields and native relations: status to the board's Status single-select and the issue's own state, the copy origin to a source-owned onetaskgraph.origin text field, and dependencies to blockedBy and to sub-issue links. Unbounded caller JSON goes in a trailing <!-- onetaskgraph.metadata ... --> comment at the end of the issue body — the same encoding docs/metadata.md settles for Linear, not a second one. A ProjectV2 text field is length-bounded and shortDescription is capped at 300 characters, which is why neither can hold a caller's own prose.

Status. status_mapping is per-instance configuration from a status category to null, a board Status option name, or a closed state of completed or not-planned. Nothing here ever calls updateProjectV2Field: that mutation's singleSelectOptions overwrites a field's option set, so no addition is additive and a mistake destroys every item's status. A status this board cannot represent is a refusal naming the status and the instance instead.

done closes the issue by default because GitHub derives subIssuesSummary.completed and the board's own Sub-issues progress field from closed sub-issues: a plan whose finished tasks were only moved to a "Done" column would read 0% complete forever.

Required checks use only the local fixture server; the ignored credentialed lane verifies the current schema, creates and reads back one uniquely named issue, then deletes every matching project item and verifies that no residue remains.

That lane writes only to the board GH_PROJECTS_OWNER and GH_PROJECTS_NUMBER name, and only into the repository GH_PROJECTS_REPOSITORY names, and skips — as it does without GH_PROJECTS_TOKEN — when any of them is absent. Requiring both to be nominated is what keeps a credentialed write lane off a board and a repository nobody nominated; it never asks GitHub which project was updated most recently. Before it starts, the lane also clears any item titled the way it titles its own artifacts, which is self-healing after an interrupted run: a process killed between its write and its cleanup leaves an artifact the next run removes.