Skip to content

V1.2.0 dev - refactoring, bugfixes, performance - #43

Draft
tobixen wants to merge 24 commits into
masterfrom
v1.2.0-dev
Draft

V1.2.0 dev - refactoring, bugfixes, performance#43
tobixen wants to merge 24 commits into
masterfrom
v1.2.0-dev

Conversation

@tobixen

@tobixen tobixen commented Jun 15, 2026

Copy link
Copy Markdown
Member

I was almost able to run a full code review using Claude Fable on this project before the model was yanked - two subagents was killed mid-flight, I had to let Opus take over. Anyway, a lot of issues were found. I've looked through all of them and had the AI fix up most of them. So v1.1.2 is mostly about refactoring, performance tuning and bugfixes.

Except, two minor features that I forgot committing a year ago or so has been included. One of them is a quite niche feature only used by my own workflow - in interactive mode it's possible to start time-tracking using the Timewarrior tool. The other is a command line option to change the delimiter (default is newline) in the list mode. (I did need it for something, but I don't remember what - but by combining --separator and --template it's possible to do things like getting a comma-separated list of UIDs from the tool).

Be aware that this heavy round of refactoring gives a risk of new bugs introduced.

The very most of the work here was done by Claude Opus, some with Claude Sonnet. I have to do quite some manual QA on this before removing the "draft"-status.

tobixen and others added 24 commits June 11, 2026 17:40
The config handling code in plann was adopted by the caldav library a
while back, but plann kept its own copy.  Drop the duplicates:

- read_config, config_section and expand_config_section in
  plann/config.py now come from caldav.config (read_config through a
  thin wrapper preserving plann's log-and-continue behaviour on a
  broken config file)
- find_calendars delegates connection parameter extraction and the
  calendar lookup to caldav.config.extract_conn_params_from_section
  and caldav.get_calendars

This also fixes a crash (KeyError: 'url') for config sections that
carry a `features` server profile but no caldav_url - the caldav
library derives the URL from the profile's auto-connect hints (since
v2.2.1)

prompt: I have this configuration in ~/.config/calendar.conf: [ecloud
section with caldav_pass, caldav_user, features but no URL].  The URL
should not be needed [...] This is also reproducible by using plann:
KeyError: 'url'

followup-prompt: It's needed to fix the bug in the caldav library
obviously, but plann also needs some refactoring, it should trust the
caldav library to do things right instead of carrying a separate code
path for this logic.

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
find_calendars attached the section's extra config to the calendar
objects as `extra_params` (sourced from a `caldav_extra_params` key),
while add_time_tracking read `obj.parent.extra_config` - so a
`"extra_config": {"time_tracking": [...]}` config section never had
any effect.  Attach it as `extra_config`, always (defaulting to an
empty dict), sourced from the unprefixed `extra_config` key.

Also port two more time tracking fixes from the archived development
branch (commit 8c9e742):

- accept "timewarrior" and "Timewarrior" in addition to "timew" (the
  error message told the user to configure `timewarrior`, which was
  not accepted)
- don't pop the categories off the icalendar component when exporting
  to timewarrior

prompt: time tracking hacks have been working.  Please ensure they
will still work.

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
Salvage the two genuinely-novel ideas from the archived/development
branch (commit "what's this?"); the rest of that branch had already been
reimplemented on master (config delegation, time tracking).

* `list --separator=...` joins listed items with a configurable string
  (defaults to a newline), threaded through `_list`.
* The interactive edit prompt now advertises the `start` command and
  re-prompts afterwards so a follow-up command can be given for the same
  task.  `command_edit` already handled `start`; it just wasn't reachable
  from the menu.

prompt: Please add the --separator feature and reproduce the interactive 'start' in the current branch.

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Fixes from docs/code-review-2026-06-12.md (bug #13 on hold, #6/#7/#8 via relativedelta):

- cli.py: fix --startnow/--track missing leading dashes (#1)
- cli.py: fix all(isinstance(...)) guard in add-time-tracking (#9)
- cli.py: add type=int to --limit on check-due command (#11)
- cli.py: stop double-prefixing lookahead with '+' in dismiss_panic (#15)
- commands.py: fix discarded children result, undefined 'parents', and
  icalendar_comp typo in --no-pinned-tasks Todo branch (#2)
- interactive.py: fix inverted condition in interactive_split_task
  postpone prompt (#5)
- lib.py: dedent return in _relationship_text so all relation types
  are shown, not just the first (#3)
- lib.py: apply filter to first object too in _list(ics=True) (#4)
- lib.py: fix icalendar_component_UID attribute access in error log (#12)
- lib.py: wrap scalar time_tracking string in list before iterating (#14)
- panic_planning.py: guard get_dtend() result for None/date before
  comparing with aware datetime (#10)
- timespec.py: fix year constant (1314000 → 31536000), use
  dateutil.relativedelta for year arithmetic (handles date vs datetime
  and Feb-29), accumulate diff across loop iterations (#6, #7, #8)
- pyproject.toml: add python-dateutil as explicit dependency

Regression tests for the timespec fixes are in tests/test_timespec.py:
without them the parse_add_dur table exercised none of #6/#7/#8 (`1y`
came out as ~15 days, `1h30m` as 30 minutes, and a plain date or a
Feb-29 base raised).

prompt: look into docs/code-review-2026-06-12.md and start fixing things
followup-prompt: do it as suggested (re: using dateutil.relativedelta for year branch)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- C1: delete stale _interactive_edit from commands.py; import canonical
  version from interactive.py which has the 'start' time-tracking command
  and re-prompts after it — the stale copy lacked both
- C2: extract _pdb_edit(obj) in interactive.py; replace duplicated
  5-line pdb setup block in commands.py and command_edit with a single call
- C3: interactive_split_task used inline summary fallback that duplicated
  _summary; replace with _summary(obj)
- C4: delete get_obj closure in _set_relations_from_text_list; use
  _get_obj_from_line (which handles comment stripping and edge cases
  more robustly); also guard against None return when appending children

prompt: Deal with "duplication and drift"

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…uage tests

Export DURATION_UNITS / DURATION_TOKEN_RE / DURATION_RE / is_duration() from
timespec.py and use them in the four sites that previously each hard-coded the
[smhdwy] unit set (parse_add_dur, _parse_timespec, commands.__select,
interactive._command_line_edit).  Adding a new unit (e.g. months) is now a
one-line change.  Marks C5 fixed in docs/code-review-2026-06-12.md.

Add explicit tests that natural-language dates ("yesterday", "in 2 days") are
accepted, including through parse_timespec(), plus a TestDurationGrammar class.

Also remove a pre-existing unused command_edit import in commands.py so
`ruff check plann/` is clean.

Note: date parsing already delegates to dateparser (commit 0ea94fb); the
compact [smhdwy] duration grammar stays local because dateparser parses dates,
not durations (relativedelta handles the calendar arithmetic).

prompt: In many other scripts and apps I've made, I'm using the dateparser library to parse dates. There is an ongoing code review under docs/code-review-2026-06-12 that comments about bugs and issues with the date parsing. Please have a look if we can use dateparser instead of local parsing. Also, fix the issues if they will still be relevant after introducing dateparser.
followup-prompt: but make explicit test that dates like "yesterday" is accepted, and also check the "Duration grammar in four places" from the code review, it's marked as not fixed
followup-prompt: ruff errors should be fixed even if they are pre-existing

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
C6: centralise component-type detection. Add _component_type() and
_caldav_objclass() to lib.py and replace the scattered 'BEGIN:VEVENT' in
obj.data raw-string sniffing (panic_planning.py, interactive.py,
commands.py, cli.py). The old approach also matched the substring inside a
description/summary body; the helpers parse the component name instead.

C10: _editor() now uses shutil.which() instead of a hand-rolled PATH search,
and raises a clear FileNotFoundError when no editor is found instead of
leaving a non-executable fallback bound.

D1: remove unreachable `raise NotImplementedError` at end of _parse_timespec.

D2: `command_edit` checked `'with family'` twice; the second was meant to be
`'with parent'` so `postpone 1d with parent` silently did nothing.

prompt: continue picking items from docs/code-review-2026-06-12.md

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The plural-vs-singular category special-casing was spread across several sites
(_process_set_arg, _set_something, _add_category, the cli option generator and
_set_task_attribs).  Introduce a single lib.COMMA_LIST_ATTRS registry plus
helpers (_is_comma_list_attr / _comma_list_canonical / _comma_list_is_plural /
_comma_list_tokens / _add_comma_list / _set_comma_list) and have the edit path
delegate to them.

Generalised to RESOURCES while there: edit now exposes --add-category,
--add-categories, --add-resource and --add-resources (plural splits on comma,
singular keeps it literal), and --set-resources now splits on comma like
--set-categories always has.  --set-category is kept for backwards
compatibility but flagged deprecated in its --help (it appends, which the name
does not convey).

The select-by --category (substring) / --categories (exact) distinction is
intentional - it maps to the caldav library's search semantics - and is left
untouched.

Also fixes the assert-less no-op checks in test_add_set_category and gives
test_plann_cli.py its first real tests.

prompt: Now go back to the original plann C7
followup-prompt: (earlier decisions) comma-lists only for categories+resources; expose both singular and plural for add/set so the user need not guess; keep the --add-category comma-literal quirk; no --set-resource; --set-category deprecated in --help only

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
C8 flagged interactive_config for hardcoding a config-key list that had
diverged from what the caldav reader actually consumes. While fixing it,
discovered the function was dead code: orphaned during the argparse->click
migration (it still expected an argparse `args` namespace and had no caller).

- Re-wire as a `plann configure` click subcommand; refactor the function to
  take explicit (config, config_file, config_section, allow_use) params.
- Derive the connection prompt keys from caldav.config.CONNKEYS with an
  assertion that they map to real connection parameters, so the writer can
  no longer silently drift from the reader.
- Fix `ssl_verify_cert` -> `caldav_ssl_verify_cert` (the bare key was silently
  dropped by caldav's extractor), add `features`, `calendar_name` and
  `extra_config.time_tracking`, drop never-read `language`/`timezone`.
- Strengthen the runtime "here be dragons / under-tested" disclaimer.
- Tests: round-trip the written connection keys through the caldav extractor
  and assert the configure command is registered.

prompt: docs/code-review-2026-06-12.md - deal with C8.
followup-prompt: re-wire, fix, but make sure to print out a disclaimer that
the interactive configuration is under-tested and that there may be dragons.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…1, E1)

C11: _split_vcals scanned the raw string by hand at a fixed 14-char offset,
assuming LF line endings - so concatenated VCALENDAR streams using the
RFC 5545 canonical CRLF endings split into nothing.  Delegate to
icalendar.Calendar.from_ical(ical, multiple=True), which handles CRLF and
line folding.  Implemented the previously-stubbed test_split_vcals plus a
CRLF regression test.

E1: the cli() group ran find_calendars() unconditionally, so even
`plann <subcommand> --help` connected to every configured calendar.  Wrap
discovery in a _LazyCalendars list-like that resolves on first use, and fold
the command-line + config-file discovery into a single _discover_calendars().

prompt: Continue with C-11 and E-1

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
… E2)

The '{...}' sort-key branch built a fresh Template(skey) inside the sort key
function, so it was recompiled on every comparison (O(n log n) times) instead
of once per sort key.  Extract the sort-key logic into _sort_key_function,
compiling the template once; this also removes the closure-in-loop pattern and
is independently testable.

prompt: Fix E2

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
`list --top-down`/`--bottom-up` walks the parent/child graph and re-fetched
the same task from the server once per edge: _relships_by_type fetched every
relative via get_object_by_uid, and the _list recursion re-ran that for each
node, so a parent was fetched anew for every child - ~N×R round-trips.

Add a per-traversal _RelativeCache that memoizes object-by-UID lookups and
the per-object relationship scan.  _relships_by_type now parses the related
UIDs locally (get_relatives(fetch_objects=False), no network) and resolves
them through the cache; the cache is threaded through the _list recursion.

This is caching, not opt-in: the relationship scan is still always done for
the hierarchical view (it's needed to build the tree), just without the
redundant fetches.

prompt: E3.  Making it "opt-in" doesn't sound like a fix, I think it's needed
to know about relationships when doing a "top down" hierarchical task list.
Please consider and come with suggestions

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
_set_task_attribs ran a fresh server select for each of category/due/priority/
duration (plus another to list categories in use) - ~5 round-trips, each
re-fetching the task list, even though the code already re-filtered the
results client-side.

Fetch the pending todos once and filter client-side per attribute using the
icalendar_searcher library's `undef` operator - the same semantics caldav
uses for the server-side no_<x> search.  The category branch reuses the same
fetch.  5 round-trips collapse to 1.

Side benefit: on servers that do not honour the no_<x> filter, the previous
code applied the server-side limit before client-side filtering and so could
miss tasks; filtering the full fetch finds them.

icalendar_searcher is declared as an explicit dependency (it was already
present transitively via caldav).

prompt: E4 - there is the library icalendar_searcher (an implicit dependency
already as it's used by caldav) that can do client-side filtering of
icalendar data

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The code review suggested stopping the per-calendar UID lookup at the first
hit.  That would silently drop the case where the same UID exists in more
than one calendar (e.g. a copied event/task), which --uid deliberately
collects.  The U×C lookups are inherent to "find this UID in any calendar"
(there is no batch-by-UID query).  Document the intent in the code so it is
not "optimised" into a bug, and record the rationale in the review table.

prompt: I'm not sure if E5 is something that should be "fixed".  the fix is
basically to stop iterating over calendars as soon as a matching object is
found?  Now, what if the object exists in several calendars with the same uid?

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
`plann select --uid=asdf delete` previously produced no output at all,
whether or not the UID matched anything.  delete now names each item as
it is deleted and prints "No items selected for deletion" on an empty
selection, so the two cases are distinguishable.

Ref #42

prompt: Work on issue #42

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Generalises the issue #42 feedback gap beyond delete: a --uid that is
not found in any calendar is no longer silently ignored.  By default
__select now warns (to stderr) naming the missing uid(s).
--abort-on-missing-uid still takes precedence; --no-warn-on-missing-uid
restores the old fully-silent behaviour.

Ref #42

prompt: let's make a more general solution: introduce --warn-on-missing-uid/--no-warn-on-missing-uid (or something like that) with warn being the default

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
…ures)

The v1.2.0-dev test suite (tests/test_lib.py::test_features_without_url)
depends on caldav resolving the connection URL from `auto-connect.url`
features when no caldav_url is given.  Released caldav 3.2.1 returns None
for that, so CI failed on every Python version.  Bump the floor to 3.3.0,
which carries the feature.  CI install will stay red until caldav 3.3.0
is published; that release will precede the plann release.

prompt: there are breakages with the github runners, please investigate.
followup-prompt: Create a dependency on caldav 3.3.0 and ignore the dependency breakage. I will ensure to release caldav 3.3.0 before plann is released.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
CI workflow (.github/workflows/linkcheck.yml):
Two link-check runs (push + the matching pull_request) fired within a
couple of seconds, both queried for an open report issue, both found
none, and both created one - producing duplicate "Link Checker Report"
issues (e.g. github.com//issues/44 and /45).
- Restrict issue create/close to the default branch (schedule, push to
  master, manual dispatch); PR and feature-branch runs only surface the
  lychee output in the job log.  This removes the noise source and, since
  only master-ref runs touch issues, the race itself.
- Add a concurrency group keyed on the ref to serialise same-ref runs.
- Fold any pre-existing duplicate open issues into the oldest one, and
  close all open report issues (not just the first) when links are healthy.
- More resilience: --timeout 30, --max-retries 6, --retry-wait-time 2.

Local pre-commit hook (.pre-commit-config.yaml):
The hook was silently dead - `types: [markdown, rst]` is an AND, so it
required a file to be both markdown and rst at once, matching nothing;
and the lychee-docker image for the pinned rev was never published.  That
is why the broken doc links below were only ever caught by CI, not locally.
Replace it with the canonical block shared across my projects: the
auto-installing `id: lychee` (no docker), latest rev lychee-v0.24.2, a
whole-tree scan (args end in '.', pass_filenames: false) so all file types
are checked rather than only md/rst, run at the pre-push stage.

lychee only auto-discovers a non-dot `lychee.toml`, so rename .lychee.toml
-> lychee.toml; the hook then needs no --config, and the CI workflow points
at the new name.  Gitignore the .lycheecache the hook writes locally.

Doc fixes: the docs/CALENDAR_SERVER_RECOMMENDATIONS.md references in
USER_GUIDE.md and TASK_MANAGEMENT.md were missing the leading C (and the
docs/ prefix) - genuinely broken links the checker was flagging.

prompt: lychee is set up in an annoying way, it's creating new issues on every run if lychee fails. Please make the lychee setup more robust (more caching, more retries, don't create new issues if there already exists open issues, etc)
followup-prompt: fix tingbok and icalendar-searcher too. Things should be as similar as possible on all three projects, so lychee should run latest version, it should check all files (not only *.rst / *.md) and it should run from pre-commit before pushing.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
docs/panic_algorithm.md has sat untracked in the working tree for years.
It is the original rubber-duck design sketch for the panic planner and is
the only prose description of what plann/panic_planning.py is trying to
do, so it belongs in the repository rather than in one working copy.

Committed verbatim as the historical record.  Two things in it do not
match the implementation and are deliberately left alone rather than
silently edited:

- the slack formula reads `task_duration*(24-hours_per_day)/241` with an
  unbalanced backtick; timeline_suggestion() in panic_planning.py divides
  by hours_per_day, not by 24 or 241
- the notes describe an end time defaulting to "in 30 days" and a priority
  loop 1..9; the implementation takes timeline_end and hours_per_day as
  parameters with no such defaults spelled out

Prompt: /review-and-push create a pull request from this branch [review-and-push skill; the branch already had draft PR #43, so the skill ran its full review procedure over the branch instead of opening a new PR]
Followup-Prompt: (answer to a clarifying question) Look through and commit [= docs/panic_algorithm.md, the untracked file found while taking stock]

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Postponing a task that has parents could drop the user straight into pdb:

    import inspect
    stack_depth = len(inspect.stack())
    if stack_depth > 13:
        breakpoint()

This is item #13 of docs/code-review-2026-06-12.md, the one correctness
bug from that review left on hold.  It is reachable in normal use - the
guard sits in the recursive "postpone the parent too" path, entered from
`interactive check-due` and `dismiss-panic`, and a plain `edit --postpone`
already sits at ~12 frames, so a couple of levels of recursion crosses the
threshold.  With no tty attached it does not even look like a debugger,
just a hang.

The stack-depth probe was a debugging aid for the recursion, not a
feature; drop the whole block.  Marked fixed in the review document, and
covered by a test asserting the function stays free of breakpoint() and
inspect.stack().

Prompt: /review-and-push create a pull request from this branch [review-and-push skill; the branch already had draft PR #43, so the skill ran its full review procedure over the branch instead of opening a new PR]
Followup-Prompt: (answer to a clarifying question) A1-A5 plus CHANGELOG and the timespec tests [= fix all five confirmed bugs from the clean-context code review, add the missing CHANGELOG entries, and add regression tests for the timespec fixes]

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The bulk of the correctness fixes on this branch never reached the
CHANGELOG: the commits that made them (76d4e21, eaeb5fc) touched no
CHANGELOG.md at all, so the Unreleased "Fixed" section listed six items
for what is closer to twenty.  Every bug added here was present in the
released v1.1.1, so the "nothing introduced and fixed since the last
release" rule does not exempt them - a user upgrading from v1.1.1 gets
these fixes and had no way to see that from the changelog.

Deliberately *not* listed, by that same rule: the regressions found in
the code review of this branch and fixed within it (the `add ical` split
returning parsed objects rather than ical text, PRIORITY:0 tasks being
skipped by set-task-attribs, a blank line in the relations editor
orphaning children, and `start` tracebacking without time tracking
configured).  Those were introduced and fixed between releases.

Also corrects two claims in entries that were already there:

- the `--add-categories`/`--add-category` entry concluded "so you do not
  have to remember whether to use singular or plural", which contradicts
  its own premise - the two forms deliberately behave differently, so the
  user does have to know which was typed.  Reworded to state the split
  rule and stop there.
- the same entry said the plural forms "split the value on comma"
  unconditionally; _comma_list_tokens only splits when a lone value
  contains a comma.  The docstring was already accurate, the changelog
  was not.

Plus a typo in the review document ("pin the middle" -> "in the middle")
and a missing f-prefix on a SUMMARY line in a test helper, which put the
literal text "event {uid}" into every generated VCALENDAR.

Prompt: /review-and-push create a pull request from this branch [review-and-push skill; the branch already had draft PR #43, so the skill ran its full review procedure over the branch instead of opening a new PR]
Followup-Prompt: (answer to a clarifying question) A1-A5 plus CHANGELOG and the timespec tests [= fix all five confirmed bugs from the clean-context code review, add the missing CHANGELOG entries, and add regression tests for the timespec fixes]

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Adds docs/ROADMAP.md: a 156-hour (EUR 7800) plan across five phases,
following the style of the calendaring-client roadmap.  Each item names
a deliverable and links to a GitHub issue; the issues are the source of
truth for task-level detail, so the roadmap carries only the big
picture - why the hours are distributed as they are, what depends on
what, what gets released when, and what is deliberately not funded.

Fourteen issues were filed for the funded tasks that had none:
#48
#49
#50
#51
#52
#53
#54
#55
#56
#57
#58
#59
#60
#61

Pre-existing issues covered by the plan:
#13
#25
#26
#47

The five original task buckets were redefined, reordered and
reprioritized against the code, the open issues and the design
documents.  Quality became the largest bucket (54h, 35%).  The
migration to calendaring-client moved ahead of the time-tracking work,
which now depends on it, and grew as the configuration and
time-tracking logic was moved out of plann and into the library.
Milestone reporting shrank correspondingly - the report is an export
format over an aggregated task list rather than a feature of its own.

The bucket list for the NLnet system, with the EUR cost per bucket
summing to 7800, is maintained out of tree and is not committed.

Prompt: I want a roadmap with estimates, including all github issues and visions from documentation.  Read more instructions from tmp-estimates
Followup-Prompt: (answers to clarifying questions) redefine and reallocate the task buckets freely; milestone reporting is a plann feature rather than project admin; route each issue through emacsclient individually
Followup-Prompt: `>` is to be used for quotes, so it may be appropriate to use it for the prompt, but not for anything else
Followup-Prompt: See issue-1-2.md, I moved the preamble to the footer and shortened it.  Please do the same change in all the other issue gate documents
Followup-Prompt: I do see a problem here - the issues on GitHub is duplicating information from the roadmap.  I think it's important to have one source of truth.  Since I'm working on the github issues now, it's probably best to keep the details in the github issues and make the roadmap more condensed (focus on the big picture rather than the details in the roadmap?)
Followup-Prompt: Issue 1.3 probably needs some rethinking - check my latest edit, perhaps the logic actually belongs in the calendaring-client package
Followup-Prompt: 3.2 is now also in my browser.  Both 3.1 and 3.2 now depends on the migration to calendaring-cli (sic), hence the roadmap (and roadmap bullet point numbers in the issues) needs to be rewritten.
Followup-Prompt: For 4-1, most of the work should now be done in the calendaring-client.
Followup-Prompt: issue 4.3 probably needs some rethinking.  This should be a quite trivial export option of some existing task list?
Followup-Prompt: TODO-markers in the temp-file should be removed, as it's no longer TODO
Followup-Prompt: Fixup the ROADMAP.  Now that every feature has a github issue, we should not duplicate things in the ROADMAP.

Followup-Prompt: As for the work being in limbo between the calendarling-client (sic) and the plann projects, it's still possible to reproject the calendaring-client library, even including to move hours from the plann project to the calendaring-client project

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Two things plann used to own turned out to belong in the
calendaring-client library rather than in a command-line tool: the
configuration/credential handling and the iCalendar representation of
"time spent".  The configuration half was already funded there; the
time-tracking half was not, and plann depends on the API existing.

The work moved, so the money moves with it.  The plann grant drops from
156 h (7800 EUR) to 144 h (7200 EUR), and the calendaring-client MoU
gains a "Time-tracking model and API" item of the same size.  The total
across the two grants is unchanged.

The 12 hours come off the two buckets that had grown when the
time-tracking work shrank - QA (54 h -> 48 h) and the migration
(22 h -> 16 h) - rather than off any bucket funding plann's own
deliverables.  Both are back at their original sizes.

Ref #49
Ref #54

Prompt: Here is the current MoU-text for the calendaring-client - please adjust and write a new file: (...) [the NLnet MoU task list for the sibling project; the adjusted list was written to an untracked file in that repo]
Followup-Prompt: Please fix the plann/tmp-estimates file

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
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