@@ -67,41 +67,28 @@ BARK is for: storing reports sent to a mailbox in a database.
6767
6868* Principles
6969
70- - *Email-native* :: No account to create, no platform to maintain, no
71- vendor lock-in. Users report bugs and review patches with whatever
72- mail client they already use. The mailing list archive *is* the
73- tracker history — BARK simply indexes it.
74-
75- - *One place* :: [[https://orgmode.org][Org mode]] was born out of the idea that to-do items and
76- free-form notes should be edited in the same space. Similarly, bug
77- reports, patches and feature requests should be handled where users
78- and developers discuss them. It is the tracker's job to filter out
79- the noise and help everyone focus on how they can contribute.
80-
81- - *KISS* :: BARK provides a simple framework for acting on reports, with
82- a fixed vocabulary: =acked=, =owned=, or =closed= for status; =urgency= and
83- =importance= for priority. You cannot invent a custom =WONTFIX-MAYBE=
84- status or manually set a report to P0. This is deliberate: a fixed
85- vocabulary prevents the label proliferation that eventually makes
86- trackers unusable.
87-
88- - *Immutable* :: No web form, no API endpoint, no account. Users report
89- bugs and request features by emailing a list. Maintainers respond by
90- replying to the same thread. As every state change is encoded in an
91- email, the entire tracker state can be reconstructed at any time by
92- re-monitoring the mailbox from scratch. This means no tracker backup
93- to manage and no database migration between BARK versions — the
94- mailbox is the source of truth.
95-
96- - *Low ops* :: BARK exports static HTML, JSON, RSS and Org files. There
97- is no application server to keep running, no database to back up
98- (beyond the mailbox itself), and no user accounts to administer. A
99- cron job and a web server serving static files are all you need.
100-
101- - *Local-first* :: BARK exports to JSON, RSS, Org. Companion tools like
102- =bone= (TUI browser), =gnus-bone.el= (Emacs/Gnus) and =notmuch-bone.el=
103- (Emacs/notmuch) let users consume the data in whatever environment
104- they already live in, rather than forcing a new interface on them.
70+ - *One place* :: Reports and their discussions belong in one source
71+ -- the mailing list, which BARK indexes. The tracker's job is to
72+ filter noise, not to host a separate conversation.
73+
74+ - *Email-native* :: No account, no platform, no vendor lock-in.
75+ Users work in whatever mail client they already use, and the
76+ mailing list archive *is* the tracker history -- BARK simply
77+ indexes it.
78+
79+ - *Immutable* :: Every state change is encoded in an email, so the
80+ whole tracker state can be rebuilt from the mailbox at any time.
81+ No tracker backups to manage, no DB migrations between versions
82+ -- the mailbox is the source of truth.
83+
84+ - *Local-first* :: Companion tools (=bone= TUI, =gnus-bone.el=,
85+ =notmuch-bone.el=) let users consume BARK data from their existing
86+ environment instead of imposing a new interface.
87+
88+ - *KISS* :: Fixed vocabulary, deliberately: =acked=, =owned=, =closed=
89+ for status; =urgency= and =importance= for priority. No custom
90+ =WONTFIX-MAYBE= status, no manual P0 -- this prevents the label
91+ proliferation that eventually breaks trackers.
10592
10693* As a user
10794** Bug, Patch, Request
@@ -169,38 +156,30 @@ maintainers, who can undo anyone's action (see [[#undoing-updates][Undoing updat
169156
170157** Superseding a report
171158
172- If your report turns out to duplicate another one, or if you send a
173- new version of a patch that replaces the previous one, you can mark
174- the old report as superseded by replying to its thread with:
159+ When one report replaces another (a newer patch version, a fresh bug
160+ report capturing the real issue), mark the supersession with either
161+ of two equivalent directives -- they produce the same effect and
162+ differ only by point of view:
175163
176- : Superseded-by: <target-message-id@example.com>
164+ - From the *old* report's thread:
177165
178- Three forms are accepted:
166+ : Superseded-by: <new-message-id@example.com>
179167
180- - =<msg-id@host>= --- the canonical RFC form.
181- - =msg-id@host= --- a bare message-id.
182- - An archive URL where the message-id is the last path segment, e.g.
183- =https://list.orgmode.org/orgmode/msg-id@host/=.
168+ - From the *new* report's thread (works in a reply *and* in the
169+ opening mail of a brand-new bug/patch/request):
184170
185- Source and target must both be bugs, patches, or requests, of the
186- same type.
171+ : Supersedes: <old-message-id@example.com>
187172
188- Symmetric form -- when investigation matures and you file a fresh
189- report that captures the real problem, mark the old one as superseded
190- from the new report's side:
173+ Message-ids accept three forms: =<id@host>=, bare =id@host=, or the
174+ last path segment of an archive URL (e.g.
175+ =https://list.orgmode.org/orgmode/id@host/=). Source and target must
176+ be of the same type (both bugs, both patches, or both requests).
191177
192- : Supersedes: <old-message-id@example.com>
178+ To undo: =Not superseded= (from the closed report's thread) or =Not
179+ superseding= (from the replacement's thread).
193180
194- Both =Superseded-by:= and =Supersedes:= produce the exact same effect
195- (same close, same relation) -- they differ only by point of view.
196- =Supersedes:= works in the opening mail of a new bug/patch/request,
197- not only in replies.
198-
199- To undo: =Not superseded= (from the closed report's thread) or
200- =Not superseding= (from the replacement's thread).
201-
202- See the [[#superseding-a-report-1][maintainer section]] for the full details on what this does
203- and how to undo it.
181+ See the [[#superseding-a-report-1][maintainer section]] for the automatic actions BARK performs
182+ on supersession.
204183
205184** Marking a report as a duplicate
206185
@@ -222,10 +201,9 @@ To cross-reference another report:
222201
223202: Related-to: <other-message-id@example.com>
224203
225- Accepts any pair of reports. Three message-id forms: bracketed
226- (=<msg-id@host>=), bare (=msg-id@host=), or archive URL. Several
227- =Related-to:= lines in one email post several links. Works on
228- closed reports. To undo:
204+ Accepts any pair of reports. Same message-id forms as
205+ =Superseded-by:= (see above). Several =Related-to:= lines in one
206+ email post several links. Works on closed reports. To undo:
229207=Not related-to: <other-message-id@example.com>=.
230208
231209** Resolving a bug or request with a patch
@@ -335,17 +313,8 @@ To remove a per-report expiry:
335313
336314** Superseding a report
337315
338- When a report is made obsolete by another (e.g. a patch resubmitted
339- without version numbers, or a bug report that duplicates a broader
340- one), anyone can mark the old report as superseded by replying to its
341- thread with:
342-
343- : Superseded-by: <target-message-id@example.com>
344-
345- The message-id can be given as =<msg-id@host>=, bare =msg-id@host=, or
346- extracted from an archive URL where it is the last path segment (e.g.
347- =https://list.orgmode.org/orgmode/msg-id@host/=). This does three
348- things automatically:
316+ A =Supersedes:= or =Superseded-by:= directive (see [[#superseding-a-report][the user section]]
317+ for syntax and message-id forms) triggers three automatic actions:
349318
3503191. Poses a =:supersedes= qualified relation (=:rel/from= = the closed
351320 report, =:rel/to= = the replacement) and a symmetric =:related-to=
@@ -354,47 +323,18 @@ things automatically:
3543233. Links the two reports as related (bidirectional, kept on undo).
355324
356325In the index, superseded reports appear struck through (like canceled
357- reports) and display an "S" status flag. The subject tooltip shows the
358- title of the superseding report.
359-
360- To undo:
361-
362- : Not superseded.
363-
364- This retracts the supersede reference, reopens the report, and clears
365- the close-reason. The related link is kept.
366-
367- *** Supersedes (symmetric form, replacement's point of view)
326+ reports) with an "S" status flag; the subject tooltip shows the
327+ replacement's title.
368328
369- After several rounds of investigation, the original mail of a bug or
370- patch often no longer captures the real understanding. Filing a
371- fresh report that supersedes the old one is a natural editorial move ,
372- and BARK supports it from the replacement's side:
329+ Last-write-wins on direction: if a later directive flips the direction
330+ (e.g. =Supersedes: <X>= posed at t1, then =Superseded-by: <X>= posed
331+ at t2 on the same report), the second pose retracts the first ,
332+ reopens the previously-closed report, and applies the new direction.
373333
374- : Supersedes: <old-message-id@example.com>
375-
376- This works both in a reply (the current report becomes the replacement)
377- and in the *opening mail* of a brand-new bug/patch/request -- making
378- the new report the canonical face of the issue.
379-
380- =Supersedes:= and =Superseded-by:= produce the *same* relation and
381- the *same* close on the same pair of reports: the canonical
382- =:supersedes= relation always points from the closed (superseded)
383- report to the replacement. They only differ in point of view.
384-
385- Last-write-wins on direction: if a later directive flips the
386- direction (e.g. =Supersedes: <X>= posed at t1, then
387- =Superseded-by: <X>= posed at t2 on the same report), the second
388- pose retracts the first and reopens the previously-closed report
389- before applying the new direction.
390-
391- To undo from the replacement's side:
392-
393- : Not superseding.
394-
395- This retracts the =:supersedes= relation and reopens the
396- previously-closed target. Same scope as =Not superseded.= (the
397- original setter or a maintainer).
334+ Undo scope: =Not superseded= and =Not superseding= can be issued by
335+ the original setter or by any maintainer. Either retracts the
336+ relation, reopens the closed report, and clears the close-reason; the
337+ =:related-to= link is kept.
398338
399339*** Automatic supersession of patches and diffs
400340
@@ -638,16 +578,10 @@ in turn take precedence over the built-in defaults.
638578
639579*** Syntax mode: =:loose= vs =:strict=
640580
641- The =:command-syntax= key controls whether Bark instructions must be
642- prefixed with =!=. Accepts =:loose= (default) or =:strict=.
643-
644- - =:loose= — every Bark instruction can be written with or without a
645- =!= prefix. Matches prose-style usage on mailing lists.
646- - =:strict= — every Bark instruction MUST start with =!=. Eliminates
647- false positives on common English words like "Done.", "Closed.",
648- "Applied." that appear naturally in conversation.
649-
650- The rule applies uniformly to all Bark instructions:
581+ The =:command-syntax= key (=:loose= default, =:strict= opt-in) controls
582+ whether Bark instructions must be prefixed with =!=. =:strict= eliminates
583+ false positives on common English words like "Done.", "Closed." or
584+ "Applied." that appear naturally in conversation.
651585
652586| Form | Loose | Strict |
653587|------------------+------------------------+------------------------|
@@ -743,63 +677,38 @@ The BARK instance can expose reports as HTML, JSON, Org and RSS.
743677
744678Running =bb export all= generates, for each source:
745679
746- - =index.html= --- the main reports table (filterable, sortable).
747- - =stats .html= --- report statistics and charts .
748- - =docs.html= --- a user-facing documentation page (from =docs-tpl .org=) .
749- - =all .json=, =all.org =, =all.xml= --- full exports in JSON, Org and RSS .
680+ - HTML pages: =index.html= ( reports table), =stats.html= (charts),
681+ =docs .html= (user docs) .
682+ - Full exports: =all.json=, =all .org=, =all.xml= .
683+ - Per-type feeds: =bugs .json=, =patches.xml =, =requests.org=, etc .
750684- =votes.json= --- per-report vote details (see below).
751- - Per-type feeds: =bugs.json=, =patches.xml=, etc.
752- - =patches/= --- a directory with attached and inline patch files.
753- - =text/= --- a directory with =text/plain= and =text/x-log= attachments
754- (e.g. backtraces, log files). Saved under =text/<mid-hash>/=.
755- - =events/= --- a directory with =.ics= calendar files extracted from
756- announcements. Each report's =.ics= attachments are saved under
757- =events/<mid-hash>/=. Combined =events/announcements.ics=,
758- =events/announcements-open.ics= and =events/announcements-closed.ics=
759- aggregate =VEVENT= blocks into subscribable calendar feeds.
760- - =events.json=, =events.org=, =events.xml= --- open announcements that
761- carry an =.ics= attachment or inline =VCALENDAR= content.
762- - =events-closed.json=, =events-closed.org=, =events-closed.xml= ---
763- closed announcements with =.ics= content.
764-
765- RSS feeds contain up to 50 items, most recent first.
766-
767- Export is incremental: only sources modified since the last export are
768- re-generated. Use =bb export all --force= to force a full re-export.
769-
770- You can also export a single format:
771-
772- : bb export json
773- : bb export rss
774- : bb export org
775- : bb export html
776- : bb export stats
777- : bb export text
778- : bb export events
779-
780- Use =-n <source>= to restrict to one source, =-p <N>= to filter by minimum
781- priority, and =-s <N>= to filter by minimum status.
782-
783- Use =--page-size <N>= to paginate the HTML report table (e.g.
784- =bb export --page-size 100=). Pagination is client-side: all data is
785- still exported, but only one page of rows is rendered at a time,
786- improving browser responsiveness on large trackers.
787-
788- Use =--closed-retention <date-or-duration>= to exclude old closed reports
789- from all exports. Accepts an ISO date (=2024-01-01=) or a duration
790- (=1y=, =6m=, =90d=). For instance, =bb export --closed-retention 1y=
791- keeps only reports closed within the last 12 months.
792-
793- Use =--topics-filter <topics>= to export only reports matching given
794- topics (comma-separated, case-insensitive). For instance,
795- =bb export --topics-filter event= exports only reports with topic
796- "event". Use =bb export --topics-filter "event,security"= for
797- multiple topics. The filter can also be set per source in =config.edn=
798- (see below); the CLI flag overrides all config values.
799-
800- =:page-size= and =:closed-retention= are CLI-only flags.
801- =:topics-filter= can also be set per source in =config.edn=; the CLI
802- flag overrides any per-source value.
685+ - =patches/= --- attached and inline patch files.
686+ - =text/<mid-hash>/= --- =text/plain= and =text/x-log= attachments
687+ (backtraces, log files).
688+ - =events/<mid-hash>/= --- =.ics= attachments from announcements;
689+ combined feeds at =events/announcements{,-open,-closed}.ics=
690+ aggregate VEVENT blocks for subscription.
691+ - =events.{json,org,xml}= and =events-closed.{json,org,xml}= ---
692+ open/closed announcements carrying =.ics= or inline VCALENDAR content.
693+
694+ RSS feeds contain up to 50 items, most recent first. Export is
695+ incremental (only sources modified since the last export are
696+ re-generated); use =--force= to bypass.
697+
698+ Single-format export: =bb export {json|rss|org|html|stats|text|events}=.
699+
700+ | Flag | Purpose | Configurable |
701+ |-----------------------+----------------------------------------------------------+--------------|
702+ | =-n <source>= | restrict to one source | -- |
703+ | =-p <N>= | filter by minimum priority | -- |
704+ | =-s <N>= | filter by minimum status | -- |
705+ | =--page-size <N>= | paginate HTML report table (client-side rendering) | CLI only |
706+ | =--closed-retention= | exclude reports closed before given ISO date or duration | CLI only |
707+ | =--topics-filter= | restrict to topics (comma-separated, case-insensitive) | per source |
708+ | =--force= | force a full re-export | CLI only |
709+
710+ Durations accept =Nd=, =Nw=, =Nm=, =Ny= (e.g. =--closed-retention 1y=
711+ keeps reports closed within the last 12 months).
803712
804713** Vote transparency
805714
@@ -1045,17 +954,11 @@ All rules are conjunctive: a report is only expired when *all*
1045954conditions are met. Only =:inactive-after= is required; the others are
1046955optional filters.
1047956
1048- When =:inactive-after= is a duration, it is measured from the date of the
1049- *last email in the thread* (the most recent descendant, or the founding
1050- email if there are no replies). This means any reply — from any
1051- participant — resets the expiry clock.
1052-
1053- When =:inactive-after= is an ISO date, the report expires after that
1054- fixed date regardless of activity.
1055-
1056- When =:inactive-after= is =:deadline=, the report expires when its
1057- deadline date is in the past (reports without a deadline are never
1058- expired by this rule).
957+ | =:inactive-after= value | Trigger |
958+ |-----------------------+----------------------------------------------------------------------|
959+ | Duration (e.g. =30d=) | Last email in the thread is older than the duration (any reply resets) |
960+ | ISO date | The fixed date has passed, regardless of activity |
961+ | =:deadline= | The report's deadline is in the past (no deadline => never expires) |
1059962
1060963The =:max-status= value uses an activity score that only counts acked
1061964and owned (since expiry candidates are always open reports):
@@ -1092,18 +995,16 @@ report has an explicit expiry date, only that date is checked.
1092995 :max-size 1048576} ;; skip emails > 1 MB (optional)
1093996#+end_src
1094997
1095- - =:fetch= — first-run fetch window (no watermark yet). Exactly one of
1096- three disjoint map shapes (strict; no key mixing, empty map rejected):
1097- - ={:limit N}= — fetch the latest N messages (positive integer).
1098- - ={:since "30d"}= — relative duration from now. Accepts =Nd=, =Nw=, =Nm=, =Ny=.
1099- - ={:start "yyyy-MM-dd" :end "yyyy-MM-dd"}= — absolute half-open window
1100- =[start, end)=. Both =:start= and =:end= are optional (at least one
1101- must be present); ISO dates only.
1102- Default when =:fetch= is omitted: ={:limit 50}=. CLI shortcut
1103- (=--fetch=), the scalar is lifted to one of the three map shapes:
1104- - =--fetch 50= → ={:limit 50}=
1105- - =--fetch 30d= → ={:since "30d"}=
1106- - =--fetch 2020-01-01= → ={:start "2020-01-01"}=
998+ - =:fetch= — first-run fetch window (no watermark yet). Exactly one
999+ of three disjoint map shapes (no key mixing, empty map rejected);
1000+ default is ={:limit 50}=:
1001+
1002+ | Config form | CLI shortcut | Meaning |
1003+ |-----------------------------------+-------------------------+-----------------------------------------------------------|
1004+ | ={:limit N}= | =--fetch 50= | Latest N messages (positive integer) |
1005+ | ={:since "Nd"}= | =--fetch 30d= | Relative duration from now (=Nd=, =Nw=, =Nm=, =Ny=) |
1006+ | ={:start "yyyy-MM-dd" :end "..."}= | =--fetch 2020-01-01= | Absolute half-open window =[start, end)=; both keys optional, at least one required |
1007+
11071008- =:max-size= — skip emails larger than N bytes. No limit by default.
11081009
11091010Text content of =.patch=, =.diff=, =.ics=, =text/plain= and =text/x-log=
0 commit comments