8000 feat(board): owner, team and customers on the plan by kvaps · Pull Request #296 · aenix-io/aeman · GitHub
[go: up one dir, main page]

Skip to content

feat(board): owner, team and customers on the plan - #296

Merged
kvaps merged 31 commits into
mainfrom
feat/owner-team-customer
Nov 6, 2026
Merged

kvaps merged 31 commits into
mainfrom
feat/owner-team-customer

Conversation

@kvaps
@kvaps kvaps commented Nov 6, 2026
Copy link
Copy Markdown
Member

The Roadmap could not say who answers for a plan item, which team does it, or which customer it is for. This adds all three. Spec: docs/design/ownership.md, rows O1-O10.

  • Goals, initiatives and epics get an optional owner (one person, not inherited, puts nothing on day boards) and an optional team. A card's effective team is its own, else the nearest ancestor's; a task's own team wins.
  • The board gets a customer roster (customers/<ulid>.yaml). Any card except project cards can name several customers; effective customers are the card's own plus all ancestors'. Rename and delete reach every card.
  • Roadmap filters Team, Customer and Owner, applied by the server (view=roadmap selectors, MCP list_cards), with ancestors drawn. Owner matches a plan item's owner or a task's assignee and replaces the old client-side assignee filter.
  • Drawer: owner/team picker on plan items, customer chips everywhere, inherited values shown greyed. Roster manager on the Roadmap.
  • API: spec.owner, spec.customers, status.effectiveTeam, status.effectiveCustomers, customer roster routes; matching MCP tools.
  • Storage: new owner:, customers: keys, team: now kept on plan items. No migration, schema stays 3. git-backend.md and plugin-impact.md updated for external writers.

Also fixed on the way: a watch whose buffer overflows no longer drops frames silently. The server ends it with an ERROR frame carrying a 410 Expired status, and the SPA re-lists and re-watches with backoff (G85).

kvaps added 30 commits November 6, 2026 19:53
A planning card gets an owner (one person, not inherited) and a
team (inherited down, a task's own team wins); goals, initiatives,
epics and tasks get customers from a board roster, added to on the
way down. The Roadmap filters by team, customer and owner on the
server. Project cards keep none of it.

Signed-off-by: Andrei Kvapil <kvapss@gmail.com>
A planning card may now carry an owner, the one person who answers
for it, and a team, the team that carries it out; it is still nobody's
work and places nothing. Any card but a project card may name the
board's customers, kept in a roster on the board. A card's effective
team is its own or its nearest ancestor's, and its effective customers
are its own plus every ancestor's, a review card's being its task's.
Both are computed by the index and never written down the tree.

Signed-off-by: Andrei Kvapil <kvapss@gmail.com>
A card file may now carry owner and customers keys, and the board's
customer roster is customers/<id>.yaml in the primary repository, read
in rank order and merged from the primary alone. The backend can set a
card's owner and customers and add, rename, reorder and delete a
customer; a delete takes the id off every card that names it in the
same commit as the roster file. No schema bump: older readers keep the
new keys as unknown ones.

Signed-off-by: Andrei Kvapil <kvapss@gmail.com>
Own on a goal, an initiative or an epic now sets its team and its
owner, a person needing no team there, instead of being refused, and a
planning card may be given a team or born with a team, an owner and
customers. Any card but a project card may name customers from the
roster, each once; the roster can be added to, renamed, reordered and
deleted from. The storage's support is an interface of its own, so a
backend written before the feature still satisfies Backend, and the
server's cache and rights wrappers implement it.

Signed-off-by: Andrei Kvapil <kvapss@gmail.com>
A card resource now carries its owner and customers as written and its
effective team and customers as computed, and the board resource the
customer roster. The roadmap view takes team, customer and owner
selectors, applied by the server to the listing and the watch alike:
a task matches by its effective team and customers, a planning card
by its own owner and effective values or by any task under it, and
every match comes with its ancestors.

Signed-off-by: Andrei Kvapil <kvapss@gmail.com>
Every ownership gesture a person will have has its route and tool: the
card patch and the create take owner and customers, own on a plan
item sets its team and owner, the roadmap listing takes the team,
customer and owner filters, and the customer roster has add, rename,
reorder and delete routes and the add_customer, rename_customer,
reorder_customers and delete_customer tools. The descriptions explain
the model to an agent: an owner answers for a plan item and is not
inherited, customers are named by id and added to down the tree.

Signed-off-by: Andrei Kvapil <kvapss@gmail.com>
Behaviour-matrix rows O1 to O9 pin the ownership rules, and H3 and H10
are amended where a planning card may now carry a team and an owner.
The API reference describes the roadmap filters, the card fields and
the customer roster's routes and tools, and the storage documents tell
an external writer about the owner and customers keys and the roster
files.

Signed-off-by: Andrei Kvapil <kvapss@gmail.com>
The card model carries a planning card's owner, a card's customers
and the server's effective team and customers; the board carries the
customer roster. The provider patches and creates with the new fields,
keeps the roster through its routes, and the roadmap's queries and
watch take the team, customer and owner filters. ownership.ts works
out the effective team and customers from the cards the board holds,
so an edit to an ancestor shows below at once.

Signed-off-by: Andrei Kvapil <kvapss@gmail.com>
A plan item's drawer and its Roadmap row name its team and owner in
the owner picker, where a person needs no team; every card but a
project card shows its customers, its own as chips it can remove and
the inherited ones grey with where they come from, and a name the
roster lacks is added to it from the field. A task with no team shows
its plan's, grey. The Roadmap's toolbar has Team, Customer and Owner
filters, passed to the server and remembered per viewer, and opens the
customer roster in the dialog the teams and projects use.

Signed-off-by: Andrei Kvapil <kvapss@gmail.com>
A task's effective team and customers are computed from the plan item
above it and no write touches the task, so watchers kept the old ones.
A change to a plan item's team or customers now re-sends the tasks
directly under it, as a rename re-sends their lineage. The matrix rows
name the client's tests for the ownership rules.

Signed-off-by: Andrei Kvapil <kvapss@gmail.com>
The Roadmap's filters were judged together on one card, and no task
has an owner, so owner=ann&team=cozystack missed ann's epic whose only
cozystack work was a task under it. Each filter is now judged on its
own and AND across them: a planning card passes team or customer by
itself or any task under it and owner by its own, and the tasks under
a passing plan item are listed when they pass team and customer.

Signed-off-by: Andrei Kvapil <kvapss@gmail.com>
A card's team and customers are the effective ones of every card
below it, at any depth, so a change to them now re-sends the plan
items, tasks and subtasks under it and their review cards, nearest
level first. A title or date change still reaches the direct tasks
only. A task's customers now reach its review card as well.

Signed-off-by: Andrei Kvapil <kvapss@gmail.com>
A card can come to name a customer the roster no longer holds: an
edit queued before a delete lands after it, or a rebase replays an
edit over the other side's delete. Such an id now names nobody: the
resource leaves it out of the card's customers and effective
customers, no filter matches it, and the next customers edit drops it
instead of refusing the whole list. Only an id new to the card must
be on the roster.

Signed-off-by: Andrei Kvapil <kvapss@gmail.com>
…task

A review card whose task the board does not hold (another team's)
showed no customers at all. It now shows the server's effective
customers, as every other card does when its chain is not loaded.

Signed-off-by: Andrei Kvapil <kvapss@gmail.com>
A planning card keeps its team now, and that team put it on the
lists a team selector narrows: the Team and Backlog watches and MCP
list_cards view=all with a team. Those lists hold tasks, as they did
before planning cards had a team.

Signed-off-by: Andrei Kvapil <kvapss@gmail.com>
A project card has no team (H4), but a stray team key an old file
still carries was served as the team it counts under. The effective
team is now none on a project card, on the server and on the board.

Signed-off-by: Andrei Kvapil <kvapss@gmail.com>
own on a goal, an initiative or an epic with a person alone cleared
the card's team, and a team alone cleared its owner. Each half is now
kept when it is not given; nobody still takes both off, and one half
comes off alone through the update. The owner picker on a plan item
writes the halves that moved through the update for that reason.

Signed-off-by: Andrei Kvapil <kvapss@gmail.com>
A customer's delete takes the id off every card that names it, in
every repository, with the server's credential. A visitor who may
write the roster but not every repository holding such a card was
writing there through the roster; the delete is now refused (403)
and nothing changes.

Signed-off-by: Andrei Kvapil <kvapss@gmail.com>
A card frame cut for a watcher who cannot read an ancestor or the
reviewed task still carried the effective team and customers those
cards gave it. They are now worked out again from the card's own and
what the watcher may read, as the lineage and the due date are.

Signed-off-by: Andrei Kvapil <kvapss@gmail.com>
A team key a planning card's file already carries was ignored and
now takes effect: the card shows it, passes the Roadmap's team
filter and hands it to the tasks under it. Say so, and that boards
with such files want a look before the release.

Signed-off-by: Andrei Kvapil <kvapss@gmail.com>
The hierarchy design and the Roadmap's code comments still said a
planning card has no team and the Roadmap no team filter. The MCP
descriptions of list_cards and update_card team, and of create_card
type, now explain what a team means on the Roadmap and on a plan
item.

Signed-off-by: Andrei Kvapil <kvapss@gmail.com>
The Roadmap's toolbar had two person filters: the server's Owner
filter and the old client-side assignee select. There is one now. A
person in the Owner filter matches a plan item they own, never by
inheritance, and a task or subtask they are assigned to, each drawn
with its ancestors; a plan item also passes by a task under it
assigned to them. Its options are the board's members, the plan
items' owners, the tasks' assignees and the current selection.

Signed-off-by: Andrei Kvapil <kvapss@gmail.com>
A frame that did not fit in a watcher's buffer was dropped without a
word, and the client kept a board missing that change until a
reload. The first such frame now marks the watch overflowed: nothing
more is queued for it, and its writer, woken by a flag rather than a
buffer slot, ends the stream with a Kubernetes-style ERROR frame (a
Status of code 410, reason Expired). The board answers it by
re-listing its view and reopening its watches at once, without a
page reload. The buffer is larger now, but correctness no longer
depends on its size.

Signed-off-by: Andrei Kvapil <kvapss@gmail.com>
G84 is taken by the MCP-behind-a-proxy row on its own branch; give
the overflow rule the next free number so both land cleanly.

Signed-off-by: Andrei Kvapil <kvapss@gmail.com>
The Roadmap's team, customer and owner filters have no client mirror,
yet a watch spared the author the ADDED and DELETED of their own
change while sending the DELETED of the ancestors that came with it:
the author's board kept the card with no chain above it. A watch on a
filtered Roadmap now sends its author the membership changes and
spares only the MODIFIED echo. The drawer stays open on a card that
only left the board's selection.

Signed-off-by: Andrei Kvapil <kvapss@gmail.com>
A board that kept falling behind re-listed in a tight loop, one
re-list per 410. The first 410 is still answered at once; each one
after it from a watch that died young waits longer, 1 s doubling to
30 s with jitter, and a watch that lived 30 s starts over.

Signed-off-by: Andrei Kvapil <kvapss@gmail.com>
A frame cut for a watcher skipped an unreadable ancestor and
inherited from a readable one above it, while the listing on the
watcher's visible board stops at the unreadable one. The frame now
follows the listing: the chain ends at the first ancestor the
watcher cannot read, and a review card takes its task's customers
only when the task is readable. Also bring the send and subtree
fan-out comments in line with the 410 on overflow.

Signed-off-by: Andrei Kvapil <kvapss@gmail.com>
It had been left above offTheTeamList when that was added.

Signed-off-by: Andrei Kvapil <kvapss@gmail.com>
The Owner filter's options came from the filtered listing, so they
shrank to the filter's own answer. They now also keep everyone the
board has shown since it opened. A filter that matches nothing said
the roadmap was empty; it now says nothing matches the filters and
offers to clear them.

Signed-off-by: Andrei Kvapil <kvapss@gmail.com>
A goal, an initiative or an epic passes the owner filter by a task
under it assigned to one of the people chosen, not only by its own
owner.

Signed-off-by: Andrei Kvapil <kvapss@gmail.com>
Comments written after the row was renumbered still said G84, which
main gives to the MCP proxy row.

Signed-off-by: Andrei Kvapil <kvapss@gmail.com>
@kvaps
kvaps merged commit e8a2a03 into main Nov 6, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

0