Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 39 additions & 0 deletions docs/1.architecture/3.helm-sync-python.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
---
title: Python Helm Sync Planning
description: Describes the pure Python parsing, routing, rendering, and planning slice under development.
icon: 'i-heroicons-cpu-chip'
tags: ['helm', 'python', 'architecture']
---

## Overview

The `python/helm_sync` package is the first migration slice for Helm's board reconciliation logic.
It ports backlog parsing, configuration validation, local-home union, project routing, desired-card rendering, and fieldwise planning into immutable Python records.
The existing Bash entry points remain the production path while later migration slices add state and execution.

`BoardRef` is the complete route key and contains an owner plus a positive Project number.
Project routing uses the registered project identity from local homes and falls back to the configured default board.
The planner receives a fresh board snapshot, desired cards, and a previously read state snapshot.
It makes no network calls and performs no filesystem writes.

## Usage

Run the fixture-only parity suite with:

```bash
bin/fm-test-run.sh tests/fm-helm-sync-python.test.sh
```

The test harness sources the production jq functions from `bin/fm-helm-lib.sh` and compares parser, renderer, and planner output byte-for-byte.
Planner fixtures use only `fixture-owner` and boards `999` and `1000`.

## API Reference

See [the Python Helm API reference](../2.api/3.helm-sync-python.md) for the public module functions and domain records.

## Notes

This slice does not read or write Helm state, call GitHub Projects, execute plan actions, or provide a CLI.
Those capabilities belong to later migration steps and must keep the current shell implementation active until their parity is proven.

The planner also does not yet reconcile board cards that are missing or captain-deleted: it only plans cards whose task id is present in both the desired set and the current board snapshot. The production jq planner's retention, tombstone, and moved-card handling (`bin/fm-helm-lib.sh`) is deliberately deferred to the follow-up state/executor migration slice, not ported here.
340 changes: 340 additions & 0 deletions docs/2.api/3.helm-sync-python.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,340 @@
---
title: Python Helm Sync API
description: Reference for the pure Python Helm parsing, routing, rendering, and planning functions.
icon: 'i-heroicons-code-bracket'
tags: ['helm', 'python', 'api']
---

## Overview

`python/helm_sync` exposes immutable domain records and pure functions for the first Helm migration slice.
The package is available from the repository root with `PYTHONPATH=python`.

## Usage

```python
from pathlib import Path

from helm_sync.backlog import parse_backlog
from helm_sync.desired import render_cards
from helm_sync.model import BoardRef, Owner, ProjectNumber

records = parse_backlog(Path("data/backlog.md").read_text(encoding="utf-8"))
default_board = BoardRef(Owner("fixture-owner"), ProjectNumber(999))
```

`render_cards` also needs the registered project names, routing map, and task IDs whose main-home reports exist.
`plan_board` consumes an already-read `BoardSnapshot`, desired cards, and `SyncState`.

## API Reference

### `BoardRef(owner, number)`

Identifies a board by a validated owner login and positive Project number.

### `Owner`

Brands a validated GitHub owner login.

### `ProjectNumber`

Brands a positive Project number.

### `TaskId`

Brands a backlog task identifier.

### `HomeId`

Brands a local-home identifier.

### `ItemId`

Brands a board item identifier.

### `OptionId`

Brands a single-select option identifier.

### `ProjectName`

Brands a registered project identity.

### `StatusName`

Brands a Helm Status display value.

### `KindName`

Brands a Helm Kind display value.

### `PriorityName`

Brands a Helm Priority display value.

### `ReportPath`

Brands a report path included in a rendered card body.

### `Signature`

Brands a normalized board snapshot signature.

### `InputHash`

Brands a digest of effective sync inputs.

### `Fingerprint`

Brands a serialized divergence fingerprint.

### `FieldName`

Restricts a Helm field name to the literal union `Status | Priority | Project | Kind`.

### `HomeRef(id, path, main=False)`

Identifies a local home and its filesystem root.

### `BacklogRecord(order, state, structured, ...)`

Holds one parsed structured or unstructured backlog row, including metadata, notes, and optional home provenance.

### `DesiredCard(task, home, board, title, body, status, kind, project, priority, priority_n, ...)`

Holds the canonical title, body, status, kind, project, priority, report, and route for one backlog task.

### `CardSnapshot(item, content, fields, task=None)`

Captures one current board item.
DraftContent and IssueContent are separate variants so the planner can preserve Issue text.

### `DraftContent(node_id, title, body)`

Represents editable text content for a draft card.

### `IssueContent(node_id, title, body)`

Represents Issue text that the planner preserves.

### `CardContent`

Unites the `DraftContent` and `IssueContent` variants used by `CardSnapshot`.

### `FieldValue(name, value, option_id=None)`

Represents one selected field value on a card.

### `BoardField(id, name, options)`

Describes one board field and its available single-select options.

### `BoardSnapshot(board, cards, fields)`

Captures the current cards and schema for one board.

### `CardBaseline(task, item, board, node_id, is_issue, status_option, priority_option, title, body, ...)`

Stores the last acknowledged synchronized values for one card.

### `DispatchMarker(task, item, option, fingerprint)`

Identifies a previously recorded dispatch request.

### `DeletedCardTombstone(task, item)`

Prevents automatic recreation of a card after a captain deletion.

### `DivergenceKey(kind, task, item, fingerprint)`

Identifies one fingerprinted field divergence.

### `SyncState(cards, dispatches, tombstones, divergences, poll_signatures, ...)`

Provides the immutable state snapshot consumed by a pure board planner.

### `FieldWrite(field_id, name, value, option_id)`

Describes one proposed single-select field update.

### `WakeRequest(key, payload)`

Describes one keyed wake requested by a reconciliation decision.

### `DivergenceChange(kind, action, item, fingerprint)`

Describes a divergence fingerprint to keep or remove.

### `CreateDraft(task, desired, field_writes, baseline, acknowledge, fingerprint, divergence_changes, note)`

Describes creation of one draft card and its initial field values, including any unsupported-repository note marker transition.

### `UpdateDraft(task, item, draft_issue_id, title, body, field_writes, expected, baseline, acknowledge, ...)`

Describes a guarded draft text or field update with its expected snapshot and acknowledgement.

### `UpdateIssueFields(task, item, field_writes, expected, baseline, acknowledge, ...)`

Describes guarded field updates that preserve an Issue's title and body.

### `CloseMissingCard(task, item, field_write, expected, acknowledge)`

Describes closing a previously synchronized card that is no longer in the desired set.

### `RecordDispatchRequest(task, item, option, fingerprint)`

Describes recording a new captain dispatch request.

### `ClearDispatchRequest(task)`

Describes removing an obsolete dispatch request.

### `WritePriorityToBacklog(task, home_path, priority)`

Describes writing a valid captain Priority edit into its owning backlog.

### `HoldDeletedTask(task, home_path, reason)`

Describes a captain hold created after deletion of a live task's card.

### `KeepDeletedTombstone(task, item)`

Describes retaining a deleted-card tombstone.

### `RaiseWake(task, wake)`

Describes one keyed wake action.

### `RememberDivergence(key)`

Describes recording a divergence fingerprint.

### `ForgetDivergence(kind, task, item)`

Describes removing obsolete divergence memory.

### `NoChange(task, item, baseline, expected, ...)`

Carries the baseline advancement authorized by a decision that needs no board write.

### `BoardPlan(board, actions, snapshot_signature)`

Groups typed reconciliation actions for one board snapshot.

### `PlanAction`

Unites the immutable actions accepted in a `BoardPlan`.

### `BoardWork(board, cards)`

Groups desired cards routed to one complete board identity.

### `PlanError`

Reports a planner snapshot or schema that cannot be reconciled safely.

### `SettingsError`

Reports invalid or unsafe enabled Helm configuration.

### `FleetInputError`

Reports malformed local-home or backlog input.

### `Disabled`

Represents an absent opt-in configuration file.

### `HelmSettings`

Holds the validated default board, dispatch Status option, and source path returned by `load_settings`.

### `SettingsResult`

Unites `Disabled` and `HelmSettings`, the two possible results of `load_settings`.

### `parse_owner(value: object) -> Owner`

Validates and brands a GitHub owner login at a configuration or routing boundary.

### `parse_project_number(value: object) -> ProjectNumber`

Validates and brands a positive Project number.

### `parse_task_id(value: object) -> TaskId`

Validates and brands a backlog task identifier.

### `parse_home_id(value: object) -> HomeId`

Validates and brands a local-home identifier.

### `parse_item_id(value: object) -> ItemId`

Validates and brands a single-line board item identifier.

### `parse_backlog(text: str) -> tuple[BacklogRecord, ...]`

Parses backlog headings, structured rows, metadata, body lines, URLs, and unstructured rows.
The output matches `fm_helm_backlog_parse_program`.

### `record_to_dict(record: BacklogRecord) -> dict[str, object]`

Converts a parsed record to the JSON-compatible shape emitted by the jq parser.

### `load_settings(home: Path) -> Disabled | HelmSettings`

Reads `config/helm.json`.
Returns `Disabled` when that opt-in file is absent and raises `SettingsError` when a present file is invalid or unsafe.

### `settings_from_mapping(raw: object, config_path: Path) -> HelmSettings`

Validates already-decoded configuration data at the JSON boundary.

### `discover_local_homes(main_home: Path, registry_path: Path) -> tuple[HomeRef, ...]`

Returns the main home and valid local homes in registry order.
Remote, malformed, and relative-path entries are skipped.

### `parse_home_backlog(home: HomeRef) -> tuple[BacklogRecord, ...]`

Reads, parses, validates, and tags one local home's backlog.

### `load_fleet(homes: tuple[HomeRef, ...]) -> tuple[BacklogRecord, ...]`

Parses each local backlog once and rejects invalid rows and duplicate task IDs across homes.

### `registered_projects(homes: tuple[HomeRef, ...]) -> tuple[str, ...]`

Returns unique project names in first-seen home and file order.

### `project_for_repo(repo: str | None, registered: Sequence[str]) -> str | None`

Resolves a backlog repository value to its registered project identity.

### `board_for_project(project, route_map, default_board) -> BoardRef`

Returns a valid active or migrating project route, or the configured default board.

### `route_cards(cards, default_board, retention_board=None) -> tuple[BoardWork, ...]`

Groups desired cards by complete board identity.
Orders the optional retention board first, then the default, then remaining boards by owner and number.

### `render_card(record, registered_projects, route_map, default_board, report_ids=frozenset()) -> DesiredCard`

Renders one structured backlog record into its canonical desired card.

### `render_cards(records, registered_projects, route_map, default_board, report_ids=frozenset()) -> tuple[DesiredCard, ...]`

Renders an ordered backlog union once into desired cards.

### `plan_board(snapshot, desired, state, force=False, dispatch_status="In flight", epoch="0") -> BoardPlan`

Computes a pure fieldwise plan from a fresh board snapshot.
The three-way comparison preserves captain edits, applies backlog edits that do not conflict, records convergence, and retains prior baselines for conflicting fields.

## Notes

The planner returns typed actions, including `CreateDraft`, `UpdateDraft`, `UpdateIssueFields`, and `NoChange`.
The package has no state adapter, GraphQL client, executor, or command-line entry point in this migration slice.
8 changes: 8 additions & 0 deletions docs/documentation-audiences.json
Original file line number Diff line number Diff line change
Expand Up @@ -444,6 +444,14 @@
"path": "docs/1.architecture/helm-project-routing.md",
"audience": "maintainer-architecture"
},
{
"path": "docs/1.architecture/3.helm-sync-python.md",
"audience": "maintainer-architecture"
},
{
"path": "docs/2.api/3.helm-sync-python.md",
"audience": "maintainer-architecture"
},
{
"path": "docs/2.api/guides/helm-project-routing.md",
"audience": "operator-current"
Expand Down
Loading
Loading