follow-through 0.2.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- follow_through-0.2.0/LICENSE +21 -0
- follow_through-0.2.0/PKG-INFO +580 -0
- follow_through-0.2.0/README.md +536 -0
- follow_through-0.2.0/follow_through/__init__.py +15 -0
- follow_through-0.2.0/follow_through/cli.py +165 -0
- follow_through-0.2.0/follow_through/cues.py +687 -0
- follow_through-0.2.0/follow_through/extract.py +935 -0
- follow_through-0.2.0/follow_through/hinglish.py +309 -0
- follow_through-0.2.0/follow_through/ledger.py +141 -0
- follow_through-0.2.0/follow_through/models.py +131 -0
- follow_through-0.2.0/follow_through/report.py +199 -0
- follow_through-0.2.0/follow_through.egg-info/PKG-INFO +580 -0
- follow_through-0.2.0/follow_through.egg-info/SOURCES.txt +25 -0
- follow_through-0.2.0/follow_through.egg-info/dependency_links.txt +1 -0
- follow_through-0.2.0/follow_through.egg-info/entry_points.txt +2 -0
- follow_through-0.2.0/follow_through.egg-info/top_level.txt +1 -0
- follow_through-0.2.0/pyproject.toml +35 -0
- follow_through-0.2.0/setup.cfg +4 -0
- follow_through-0.2.0/tests/test_cli.py +140 -0
- follow_through-0.2.0/tests/test_corpus_defects.py +995 -0
- follow_through-0.2.0/tests/test_example.py +160 -0
- follow_through-0.2.0/tests/test_extract.py +463 -0
- follow_through-0.2.0/tests/test_hinglish.py +311 -0
- follow_through-0.2.0/tests/test_ledger.py +191 -0
- follow_through-0.2.0/tests/test_offline.py +303 -0
- follow_through-0.2.0/tests/test_report.py +168 -0
- follow_through-0.2.0/tests/test_version.py +53 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Waiga Arya
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,580 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: follow-through
|
|
3
|
+
Version: 0.2.0
|
|
4
|
+
Summary: Find the commitments in a transcript and track them until they are closed. Runs entirely on your machine.
|
|
5
|
+
Author: Waiga Arya
|
|
6
|
+
License: MIT License
|
|
7
|
+
|
|
8
|
+
Copyright (c) 2026 Waiga Arya
|
|
9
|
+
|
|
10
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
11
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
12
|
+
in the Software without restriction, including without limitation the rights
|
|
13
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
14
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
15
|
+
furnished to do so, subject to the following conditions:
|
|
16
|
+
|
|
17
|
+
The above copyright notice and this permission notice shall be included in all
|
|
18
|
+
copies or substantial portions of the Software.
|
|
19
|
+
|
|
20
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
21
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
22
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
23
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
24
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
25
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
26
|
+
SOFTWARE.
|
|
27
|
+
|
|
28
|
+
Project-URL: Homepage, https://github.com/Waiga/follow-through
|
|
29
|
+
Project-URL: Issues, https://github.com/Waiga/follow-through/issues
|
|
30
|
+
Keywords: transcripts,meetings,commitments,accountability,cli,offline
|
|
31
|
+
Classifier: Development Status :: 3 - Alpha
|
|
32
|
+
Classifier: Environment :: Console
|
|
33
|
+
Classifier: Intended Audience :: End Users/Desktop
|
|
34
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
35
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
36
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
37
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
38
|
+
Classifier: Topic :: Office/Business
|
|
39
|
+
Classifier: Topic :: Text Processing :: Linguistic
|
|
40
|
+
Requires-Python: >=3.11
|
|
41
|
+
Description-Content-Type: text/markdown
|
|
42
|
+
License-File: LICENSE
|
|
43
|
+
Dynamic: license-file
|
|
44
|
+
|
|
45
|
+
# Follow Through
|
|
46
|
+
|
|
47
|
+
People commit to things out loud. In a meeting, on a call, in a voice note. The
|
|
48
|
+
commitment is real; the record is not. It sits inside a transcript nobody reads
|
|
49
|
+
again, and a week later nobody can say what was promised, by whom, or whether it
|
|
50
|
+
happened.
|
|
51
|
+
|
|
52
|
+
Transcription is already solved. Almost every meeting tool emits text. What is
|
|
53
|
+
missing is the step after: turning that text into a list of obligations you can
|
|
54
|
+
actually close.
|
|
55
|
+
|
|
56
|
+
Follow Through is a command-line tool that reads a transcript, finds the
|
|
57
|
+
statements that commit someone to a future action, and tracks each one until you
|
|
58
|
+
say it is done.
|
|
59
|
+
|
|
60
|
+
It reads English and Hinglish — Hindi spoken in Roman script, which is what
|
|
61
|
+
transcription tools return for most of India. That is not a bonus feature.
|
|
62
|
+
English-only rules do not degrade gracefully on a Hindi conversation: they
|
|
63
|
+
return nothing at all, while reporting nothing wrong.
|
|
64
|
+
|
|
65
|
+
The Hinglish rules were added after the English-only version missed the
|
|
66
|
+
commitments in one real Hindi-English meeting transcript, where every promise
|
|
67
|
+
looked like "main hi follow up dalta hu". That is a single private transcript,
|
|
68
|
+
scored by the person who wrote the rules. It explains why the module exists; it
|
|
69
|
+
is not evidence that it works. The Hinglish rules have never been measured
|
|
70
|
+
against any public corpus, no such corpus is known to me, and the Hinglish
|
|
71
|
+
example in this repository is invented.
|
|
72
|
+
|
|
73
|
+
It runs entirely on your machine. No account, no API key, no network call. Your
|
|
74
|
+
transcripts are never uploaded anywhere.
|
|
75
|
+
|
|
76
|
+
That is enforced, not just promised. `tests/test_offline.py` reads this package's
|
|
77
|
+
own source on every run and fails if any module imports something that can reach
|
|
78
|
+
the network, names one of the `os` functions that starts another program —
|
|
79
|
+
however it is spelled, including behind an alias, an aliased import, or a string
|
|
80
|
+
passed to `getattr` — or reaches for `__import__`, `eval` or `exec`. Each
|
|
81
|
+
detector has its own test proving it can fail, and one test smuggles a working
|
|
82
|
+
exfiltration path in to confirm it is caught.
|
|
83
|
+
|
|
84
|
+
Being precise about what that is: it is a static read of this package's source, on
|
|
85
|
+
a package that declares no dependencies. It is a guard against drift, not a
|
|
86
|
+
sandbox. It does not run the code and it cannot vouch for your Python
|
|
87
|
+
installation. What it does is make the offline promise expensive to break by
|
|
88
|
+
accident and impossible to break in the obvious ways without a test turning red.
|
|
89
|
+
|
|
90
|
+
## Install
|
|
91
|
+
|
|
92
|
+
Follow Through needs Python 3.11 or newer and has no dependencies.
|
|
93
|
+
|
|
94
|
+
```bash
|
|
95
|
+
python3 -m pip install --no-deps .
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
## Use it
|
|
99
|
+
|
|
100
|
+
Start with a transcript. Any plain text file works — exported meeting notes, a
|
|
101
|
+
transcription, or something you typed yourself.
|
|
102
|
+
|
|
103
|
+
```bash
|
|
104
|
+
follow-through extract examples/weekly-sync.txt
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
```
|
|
108
|
+
8a6295803ccc Sam by Friday I'll send the signed lease to finance by Friday.
|
|
109
|
+
35a117fe08a0 owner not stated no stated deadline Can you also share the insurance certificate?
|
|
110
|
+
ab66f295b196 Jordan by October 3 Jordan will pull the carrier rates by October 3.
|
|
111
|
+
1f0e51f8120a Jordan in 3 days I'll have a first cut ready in 3 days.
|
|
112
|
+
4312edaecc56 owner not stated no stated deadline We'll need to decide on the second shift before the move.
|
|
113
|
+
4095a62ef115 Jordan tonight Let me draft the shift plan tonight.
|
|
114
|
+
694cf1f34f39 owner not stated no stated deadline Please confirm the headcount with HR.
|
|
115
|
+
37f8c8a83e0d Alex today I'll update the risk register today.
|
|
116
|
+
0bc8f26c2cae O'Brien next week O'Brien will countersign the lease next week.
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
Five other lines in that transcript were left out on purpose: two hypotheticals,
|
|
120
|
+
one thing already done, one "maybe", and a "let me know". Each of them contains a
|
|
121
|
+
phrase the tool otherwise treats as a commitment.
|
|
122
|
+
|
|
123
|
+
`extract` records nothing. When the list looks right, keep it:
|
|
124
|
+
|
|
125
|
+
```bash
|
|
126
|
+
follow-through track examples/weekly-sync.txt
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
That writes a ledger to `.follow-through/ledger.json`. Run it again over the same
|
|
130
|
+
file after it has grown and only the new commitments are added — nothing is
|
|
131
|
+
duplicated, and nothing you have already closed comes back.
|
|
132
|
+
|
|
133
|
+
A commitment is identified by its wording, its owner, and the file it came from.
|
|
134
|
+
The file matters: people promise the same thing, in the same words, every week.
|
|
135
|
+
If last week's transcript and this week's were treated as one, the second promise
|
|
136
|
+
would silently match the first one you closed and disappear.
|
|
137
|
+
|
|
138
|
+
The file is recorded as the path you gave, shortened, not as an absolute path —
|
|
139
|
+
otherwise the same transcript would produce different ids on different machines.
|
|
140
|
+
One consequence worth knowing: if two directories each hold a `standup.txt` and
|
|
141
|
+
both are tracked from inside themselves into one shared ledger, both record
|
|
142
|
+
`standup.txt` and merge. Run `track` from a common parent and the paths differ,
|
|
143
|
+
so they stay separate.
|
|
144
|
+
|
|
145
|
+
See what is still open, close something, and write a report:
|
|
146
|
+
|
|
147
|
+
```bash
|
|
148
|
+
follow-through list
|
|
149
|
+
follow-through close 8a62 --note "lease countersigned and filed"
|
|
150
|
+
follow-through report
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
`report` writes Markdown and HTML to `reports/`. Open commitments are grouped by
|
|
154
|
+
person, with the unattributed ones in their own visible group — those are the
|
|
155
|
+
ones that actually go missing.
|
|
156
|
+
|
|
157
|
+
A worked example of the finished report is in
|
|
158
|
+
[`examples/expected-report.md`](examples/expected-report.md).
|
|
159
|
+
|
|
160
|
+
## Hinglish
|
|
161
|
+
|
|
162
|
+
The same command, on [`examples/weekly-sync-hinglish.txt`](examples/weekly-sync-hinglish.txt):
|
|
163
|
+
|
|
164
|
+
```
|
|
165
|
+
30c32ccddb01 Neha kal tak Main signed copy finance ko kal tak bhej dungi.
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
Hindi puts two things in different places from English, and both matter.
|
|
169
|
+
|
|
170
|
+
**Who is committing is in the verb ending, not in a pronoun.** `-unga` / `-ungi`
|
|
171
|
+
is "I will", `-enge` is "we will", `-ega` / `-egi` after a name is "she will" or
|
|
172
|
+
"he will" — which is how work actually gets handed to someone in a Hindi meeting.
|
|
173
|
+
The rules match the ending, so verbs nobody thought to list are still caught.
|
|
174
|
+
|
|
175
|
+
**When it is due is at the end of the phrase.** `kal` is "tomorrow"; `kal tak` is
|
|
176
|
+
"by tomorrow". Only the second one sets a deadline, and only the second one
|
|
177
|
+
overrules the filler list.
|
|
178
|
+
|
|
179
|
+
**The Hindi rules only run on Hindi sentences.** Roman script hides the
|
|
180
|
+
difference between a Hindi verb and an ordinary English word: `fungi` ends like
|
|
181
|
+
`karungi`, `Ortega` like `karega`, `karo` is a syrup and `bolo` is a tie. Applied
|
|
182
|
+
to everything, these rules invented commitments in English sentences and invented
|
|
183
|
+
people to own them.
|
|
184
|
+
|
|
185
|
+
So a sentence has to look like Hindi first. Either it contains a Hindi function
|
|
186
|
+
word — `hai`, `ko`, `kar`, `nahi` — or it contains an unmistakably Hindi verb: a
|
|
187
|
+
**lowercase** word ending `-ega`, `-egi`, `-enge`, `-unga`, `-ungi`. The
|
|
188
|
+
lowercase part is what does the work. Hindi verbs are not capitalised in the
|
|
189
|
+
middle of a sentence, and the English words that share those endings are proper
|
|
190
|
+
nouns: Ortega, Vega, Omega, Noriega. That one distinction separates
|
|
191
|
+
"Amazon listing Farhan update karega" from "Maria Ortega raised the issue"
|
|
192
|
+
without needing a dictionary of either language.
|
|
193
|
+
|
|
194
|
+
Transliteration is not standardised — people write `hu` and `hoon`, `kar dunga`
|
|
195
|
+
and `kardunga`. The common spellings are covered and the list will always be
|
|
196
|
+
incomplete. Adding to it is the single most useful contribution anyone can make,
|
|
197
|
+
and the rules are plain data in
|
|
198
|
+
[`follow_through/hinglish.py`](follow_through/hinglish.py).
|
|
199
|
+
|
|
200
|
+
## What it will not do
|
|
201
|
+
|
|
202
|
+
This list is the design, not a disclaimer.
|
|
203
|
+
|
|
204
|
+
- **It will not find every commitment.** It matches patterns in text. Something
|
|
205
|
+
phrased unusually will be missed, and some of what it finds will not really be
|
|
206
|
+
a commitment. Every report says so.
|
|
207
|
+
- **It will not guess who owns something.** If the transcript does not say, the
|
|
208
|
+
owner stays `unknown`. It will not attribute a line to whoever was talking
|
|
209
|
+
most, and it will not turn `From:` or `TODO:` into an owner. "We'll decide on
|
|
210
|
+
Friday" commits a room, not whoever said "we", so that stays `unknown` too.
|
|
211
|
+
An owner is whoever the text names, which may be a team — "Legal will review
|
|
212
|
+
the contract" records Legal, because that is who was named.
|
|
213
|
+
- **It will not guess a deadline.** No timing phrase means no deadline. It records
|
|
214
|
+
the phrase the speaker actually used — `by Friday`, `in 3 days` — as text, and
|
|
215
|
+
never converts it to a calendar date, because that would mean assuming when the
|
|
216
|
+
conversation happened.
|
|
217
|
+
- **It will not decide that something was done.** Only you close an entry, and a
|
|
218
|
+
reason is required when you do.
|
|
219
|
+
- **It will not score anyone.** There is no reliability metric and no leaderboard.
|
|
220
|
+
- **It will not send anything anywhere.**
|
|
221
|
+
|
|
222
|
+
One rule sits underneath all of these: absence of evidence is reported as
|
|
223
|
+
unknown, never as a confirmed no.
|
|
224
|
+
|
|
225
|
+
### Deliberate trade-offs
|
|
226
|
+
|
|
227
|
+
These are choices, not oversights. Each one loses something real, and each one
|
|
228
|
+
was measured against 1,067 real meeting records before it was made.
|
|
229
|
+
|
|
230
|
+
- **A conditional is not a commitment.** "If we extend the last call, we will
|
|
231
|
+
need to ask people to check the model" is rejected, and so is the genuine
|
|
232
|
+
undertaking that sometimes follows one. On the corpus most sentences of this
|
|
233
|
+
shape were conditions rather than promises, so the exclusion stays.
|
|
234
|
+
- **A bare third-party future is only kept when it states a limit.** "A revised
|
|
235
|
+
draft will be posted by Friday" is recorded with no owner. "The routers will
|
|
236
|
+
have the whole table" is not recorded at all, because in a technical meeting
|
|
237
|
+
"will" is more often a prediction than a promise.
|
|
238
|
+
- **An acronym never owns a commitment.** "TCPCL will wait for review" records
|
|
239
|
+
nothing. That also means "IESG will publish it" records nothing. A protocol,
|
|
240
|
+
a document and a working-group short name all look identical to a part
|
|
241
|
+
number, and naming one as the person responsible is exactly the invention
|
|
242
|
+
this tool exists not to make. Write the owner as a word — `Legal`, `Chairs` —
|
|
243
|
+
and it is recorded.
|
|
244
|
+
- **"I can" counts only at the start of a clause, and only unhedged.** "I can
|
|
245
|
+
write the text" is an offer. "It is nice to have this as I can just mirror it
|
|
246
|
+
in my code" is not, and "I could possibly reach out" is not either.
|
|
247
|
+
- **An exclusion applies to the whole sentence.** "I sent the draft last week
|
|
248
|
+
and I'll post the update by Friday" is rejected because of its first half.
|
|
249
|
+
Splitting a sentence into clauses reliably is a bigger change than this tool
|
|
250
|
+
is, and rejecting too much is the safer failure.
|
|
251
|
+
- **A bare institution or a country is still recorded as an owner.** "China will
|
|
252
|
+
continue to expand its fleet" records China, and it is a forecast rather than
|
|
253
|
+
anything anybody in the room can be held to. The article rule above catches
|
|
254
|
+
"the Committee" and "the Department"; it cannot catch "China" or "Congress",
|
|
255
|
+
because a bare capitalised proper noun naming a state has exactly the same
|
|
256
|
+
shape as a surname. Separating them needs a gazetteer or a part-of-speech
|
|
257
|
+
tagger, and this package carries no dependencies. It is a limit of the tool in
|
|
258
|
+
this genre, written down here rather than half-filtered.
|
|
259
|
+
- **Ambiguous narration is kept rather than dropped.** "Let me go to Mr
|
|
260
|
+
Pugliaresi" is floor management; "I will go to the vendor and get a quote" is
|
|
261
|
+
work, and one sentence does not separate them. So verbs like *go to*, *move
|
|
262
|
+
on* and *turn to* are only treated as narration after "let me" or "let us", or
|
|
263
|
+
when they address somebody by title. Everywhere else the false positive is
|
|
264
|
+
kept, because losing a commitment is the worse error.
|
|
265
|
+
- **A document under forty lines is never measured for wrapping.** Below that
|
|
266
|
+
the percentile is just the longest line again, which is the statistic that
|
|
267
|
+
failed, so short files keep the cautious rule and a wrapped one may still be
|
|
268
|
+
read in fragments. This is the shape of the tool's own examples, which is
|
|
269
|
+
worth saying: the fixtures in this repository are too short to exercise the
|
|
270
|
+
measurement, and that is exactly how the defect in it survived a test suite.
|
|
271
|
+
- **The orthography test needs the evidence to be in the file.** "Due to visa
|
|
272
|
+
rules, we would not comment" is refused in a transcript that says "due to"
|
|
273
|
+
somewhere in lower case, which any real one does many times over. In a file of
|
|
274
|
+
a few lines that happens to use the word only once, and capitalised, there is
|
|
275
|
+
nothing to contradict it and the line is recorded. The test gets stronger the
|
|
276
|
+
longer the document is, which is the opposite of the usual failure and worth
|
|
277
|
+
knowing.
|
|
278
|
+
- **An unmarked action item can lose its owner to the orthography test.**
|
|
279
|
+
"Chairs to schedule an interim", with no bullet and no deadline, in a document
|
|
280
|
+
that also writes "the chairs" in lower case, is dropped. Put a bullet in front
|
|
281
|
+
of it or a date inside it and it is kept. The test removes 630 findings on a
|
|
282
|
+
real corpus that were the preposition frame wearing a capital letter; this is
|
|
283
|
+
what it costs, and it costs it only to single-word owners that are also
|
|
284
|
+
ordinary English words.
|
|
285
|
+
- **One sentence yields one owner.** "Carsten, Jim and Christian volunteered to
|
|
286
|
+
review" records Christian, the name nearest the verb. It records a real
|
|
287
|
+
person, and it under-reports the other two.
|
|
288
|
+
|
|
289
|
+
## How it decides
|
|
290
|
+
|
|
291
|
+
The rules are ordinary regular expressions, kept together as data in
|
|
292
|
+
[`follow_through/cues.py`](follow_through/cues.py) so you can read and extend
|
|
293
|
+
them without touching any logic. There is no model involved.
|
|
294
|
+
|
|
295
|
+
A sentence becomes a candidate when it contains someone undertaking to do
|
|
296
|
+
something (`I'll`, `we will`, `let me`, `let's`, `I can write`), handing work to
|
|
297
|
+
somebody else (`please send`, `Priya will`, `Mark agreed to`), or writing it down
|
|
298
|
+
as an action item (`Mark to post the revised draft`, `Ask the WG to adopt it`).
|
|
299
|
+
It is rejected when it is hypothetical, negated, tentative, or already in the
|
|
300
|
+
past — `if I get time`, `I don't think I'll`, `I might`, `I already sent`,
|
|
301
|
+
`Mozilla will not implement`.
|
|
302
|
+
|
|
303
|
+
Contractions require their apostrophe, straight or typographic. This reads like
|
|
304
|
+
a detail and is not one: `we'?ll` also matches the ordinary word "well", and on
|
|
305
|
+
1,067 real transcripts that single optional character produced 36.7% of
|
|
306
|
+
everything the tool reported.
|
|
307
|
+
|
|
308
|
+
A question is only an assignment when it asks for something. "Could you post
|
|
309
|
+
that to the list?" is a request; "Can you explain the difference between the two
|
|
310
|
+
modes?" is a question at a microphone, and recording it as an obligation was the
|
|
311
|
+
tool's second largest source of noise.
|
|
312
|
+
|
|
313
|
+
Nothing quoted is read as a commitment. A scribe writing down what somebody else
|
|
314
|
+
said is reporting, not recording a promise, and a negated future — "X will not
|
|
315
|
+
do Y" — is refused in every person.
|
|
316
|
+
|
|
317
|
+
Four shapes carry a commitment without any of the words above, and all four are
|
|
318
|
+
read:
|
|
319
|
+
|
|
320
|
+
- **Committing in so many words.** "Will you commit to working with my office?"
|
|
321
|
+
and the answer, "I certainly can commit to working with you." The verb is the
|
|
322
|
+
cue. So is an expectation put on the record — "I hope you will consult with
|
|
323
|
+
the public".
|
|
324
|
+
- **A subject the scribe dropped.** "Fangwei: will move the model to that
|
|
325
|
+
format." The label already said who, so the sentence does not. Only read
|
|
326
|
+
where a label is present, and only for an act: "will be sending the text" is
|
|
327
|
+
an undertaking, "will be discussed on the list" has no agent in it and "will
|
|
328
|
+
need more review" is a state.
|
|
329
|
+
- **Reported speech.** "Jankowicz says she will abide by it." Minutes are
|
|
330
|
+
written afterwards, so this is their ordinary voice. The name in front of the
|
|
331
|
+
reporting verb is the person committing.
|
|
332
|
+
- **A note-style action item.** "Mark to post the revised draft."
|
|
333
|
+
|
|
334
|
+
That last one is also the most dangerous cue in the tool, because English uses
|
|
335
|
+
the same shape for something else entirely: "According to this scheme", "Due to
|
|
336
|
+
visa rules", "Thanks to the Chair". Three tests keep them apart, and none of
|
|
337
|
+
them is a list of prepositions.
|
|
338
|
+
|
|
339
|
+
The word after `to` has to be able to begin an infinitive. A bare verb does; a
|
|
340
|
+
determiner or a pronoun does not, and that makes the `to` a preposition. `be` is
|
|
341
|
+
allowed, because "Mirja to be the responsible AD" is a real assignment.
|
|
342
|
+
|
|
343
|
+
The head must not be a word this document also writes in lower case. A capital
|
|
344
|
+
at the start of a sentence carries no information — the capital is the sentence.
|
|
345
|
+
When the same file says "due to" and "want to" in lower case elsewhere, the
|
|
346
|
+
capital was punctuation. A name never gets that contradiction, and every word of
|
|
347
|
+
a name has to be contradicted before the head is refused, so "Mark Nottingham"
|
|
348
|
+
survives a document that also contains the verb "mark".
|
|
349
|
+
|
|
350
|
+
A bullet in front of the line, or a deadline inside it, overrides that last
|
|
351
|
+
test. Either is independent evidence that a scribe was writing an item.
|
|
352
|
+
|
|
353
|
+
Against all of that runs one more filter: a first-person undertaking whose verb
|
|
354
|
+
is an act of speech inside the meeting is narration, not a commitment. Yielding,
|
|
355
|
+
recognising, backing up, refreshing your memory and going to the next witness do
|
|
356
|
+
not outlive the room.
|
|
357
|
+
|
|
358
|
+
Owners come from speaker labels. `Alex:`, `[00:14] Sam Okafor:`,
|
|
359
|
+
`Tony Li (TL):`, `Suresh Krishnan, Kaloom:`, `ekr:` and `<mnot>` are all read as
|
|
360
|
+
people; a real transcript uses every one of those shapes. A first-person
|
|
361
|
+
undertaking belongs to whoever is speaking. A named assignment belongs to the
|
|
362
|
+
person named. A collective undertaking belongs to nobody. When two of these
|
|
363
|
+
appear in one sentence the owner is genuinely unclear, so it is left unknown.
|
|
364
|
+
|
|
365
|
+
A heading ends the current speaker's turn, including when it sits alone on its
|
|
366
|
+
line — `Action items:` with nothing after it. A pasted mail quote (`> ...`) ends
|
|
367
|
+
it too: those are somebody else's words.
|
|
368
|
+
|
|
369
|
+
Filler is treated differently from a hypothetical. "I might look at it" and
|
|
370
|
+
"we'll never get this done" are rejected outright, whatever else the sentence
|
|
371
|
+
says. "Let me know if that works" is rejected only because nothing was promised
|
|
372
|
+
by when — "Let me know the vendor's answer by Friday" is kept.
|
|
373
|
+
|
|
374
|
+
What counts for that second rule is a phrase that names when work is due: `by
|
|
375
|
+
Friday`, `before Monday`, `within two days`, `end of week`, `on Thursday`.
|
|
376
|
+
Merely mentioning a time does not, or "can you hear me today?" would be recorded
|
|
377
|
+
as a commitment.
|
|
378
|
+
|
|
379
|
+
The filler patterns match whole utterances rather than openings, because "let me
|
|
380
|
+
start by welcoming everyone" and "let me start the migration" begin identically
|
|
381
|
+
and only one of them is noise.
|
|
382
|
+
|
|
383
|
+
Three details worth knowing, because they are where this could surprise you.
|
|
384
|
+
|
|
385
|
+
A speaker label applies to the lines that follow it until the next label. That is
|
|
386
|
+
how transcripts work, but it does mean an unlabelled line is attributed to
|
|
387
|
+
whoever spoke last. A structural label such as `Notes:` ends that turn rather
|
|
388
|
+
than continuing it.
|
|
389
|
+
|
|
390
|
+
A word is treated as a name when it is capitalised and is not an ordinary English
|
|
391
|
+
word. That is a filter, not name detection. It rejects `From:`, `TODO:` and
|
|
392
|
+
`Actually`; it cannot tell an unusual name from an unusual noun, so a heading it
|
|
393
|
+
has never heard of will read as a speaker. There is a test that says so.
|
|
394
|
+
|
|
395
|
+
An owner is not necessarily a person. Whoever the sentence names is recorded —
|
|
396
|
+
unless an article stands in front of the name. English does not put one in front
|
|
397
|
+
of a person: "Priya will send the deck" names somebody, "The Committee will hold
|
|
398
|
+
a hearing" and "our Chairs will decide" name a thing and a role. That single test
|
|
399
|
+
replaces a list of institutions, and on a real corpus the institutions arrived
|
|
400
|
+
almost entirely wearing "the".
|
|
401
|
+
|
|
402
|
+
Transcripts are usually hard-wrapped at seventy or eighty columns, so a sentence
|
|
403
|
+
routinely spans two lines. Read one line at a time, nearly half of what the tool
|
|
404
|
+
found on raw wrapped files was cut off, and the deadline was normally in the half
|
|
405
|
+
it threw away.
|
|
406
|
+
|
|
407
|
+
So the file is measured first. A hard-wrapped file has a ceiling: nearly every
|
|
408
|
+
line stops just short of one column, and the few that pass it are a URL, a table
|
|
409
|
+
row or a rule of equals signs. That ceiling is read off the 95th percentile of
|
|
410
|
+
the line lengths, never off the longest line — the longest line is the outlier
|
|
411
|
+
the ceiling has to be measured in spite of. A file needs at least forty lines
|
|
412
|
+
before the percentile can exclude anything, and a quarter of its lines have to
|
|
413
|
+
sit in the band just under the ceiling; otherwise it is note-style minutes,
|
|
414
|
+
where joining bullets into each other would be worse than not joining prose.
|
|
415
|
+
|
|
416
|
+
In a file measured as wrapped, a line that stops short of the ceiling without
|
|
417
|
+
punctuation is joined to the one below it whatever case that line starts in.
|
|
418
|
+
Everywhere else the join only happens when the next line begins in lower case,
|
|
419
|
+
which is the cautious rule. The cautious rule on its own was not enough:
|
|
420
|
+
political testimony is full of proper nouns, so continuations begin with a
|
|
421
|
+
capital constantly, and half-sentences like "Venezuelans to speak their minds
|
|
422
|
+
has crumbled" were left looking like action items because they began a line.
|
|
423
|
+
|
|
424
|
+
Every entry keeps the quoted sentence, the file and line it came from, and which
|
|
425
|
+
rules fired. You can always check the tool's work against the source. The line
|
|
426
|
+
number is the line the sentence started on, counted the way an editor counts:
|
|
427
|
+
a page break inside an old plain-text transcript is not a new line.
|
|
428
|
+
|
|
429
|
+
## Your data
|
|
430
|
+
|
|
431
|
+
- Everything stays in the directory you run it in.
|
|
432
|
+
- File paths are shortened before they are recorded: relative to the directory
|
|
433
|
+
you ran in when the file is below it, otherwise written with `~` in place of
|
|
434
|
+
your home directory. A file outside both is recorded in full, because by then
|
|
435
|
+
there is nothing left to hide.
|
|
436
|
+
- `.gitignore` already excludes `transcripts/`, ledgers, and reports, so your own
|
|
437
|
+
material does not end up in a commit by accident.
|
|
438
|
+
- The examples in this repository are invented. Lumen Freight does not exist, and
|
|
439
|
+
neither do Alex, Sam, or Jordan.
|
|
440
|
+
|
|
441
|
+
## Tests
|
|
442
|
+
|
|
443
|
+
```bash
|
|
444
|
+
python3 -m unittest discover -s tests -t . -v
|
|
445
|
+
```
|
|
446
|
+
|
|
447
|
+
## Contributing
|
|
448
|
+
|
|
449
|
+
Bounded, useful tasks are listed in [ROADMAP.md](ROADMAP.md), and
|
|
450
|
+
[CONTRIBUTING.md](CONTRIBUTING.md) explains how the project is reviewed. New cue
|
|
451
|
+
patterns are especially welcome — they are data, they are easy to test, and every
|
|
452
|
+
one of them makes the tool find something it used to miss.
|
|
453
|
+
|
|
454
|
+
## Honest status
|
|
455
|
+
|
|
456
|
+
Version 0.2. The behaviour described here is covered by tests that run on every
|
|
457
|
+
change, and the example above is checked in and compared against real output, so
|
|
458
|
+
the documentation cannot drift away from the code.
|
|
459
|
+
|
|
460
|
+
What it has not had is users. If it misses things in your transcripts, that is
|
|
461
|
+
the most useful thing you could tell me, and an issue is welcome.
|
|
462
|
+
|
|
463
|
+
## Against real documents
|
|
464
|
+
|
|
465
|
+
Everything above says what the tool is meant to do. This section says what it
|
|
466
|
+
did when it was pointed at documents nobody involved with it had written.
|
|
467
|
+
|
|
468
|
+
**How this was measured.** Which 6,320 documents, how they were selected, which
|
|
469
|
+
of the four measurement passes each figure below belongs to, and the complete
|
|
470
|
+
800-sentence labelled set with its labels:
|
|
471
|
+
[`docs/corpus-manifest.md`](docs/corpus-manifest.md). Its opening section carries
|
|
472
|
+
the full account of how the 800 labels were produced, including the dispatch-by-
|
|
473
|
+
dispatch record.
|
|
474
|
+
|
|
475
|
+
### The corpus
|
|
476
|
+
|
|
477
|
+
6,320 real meeting records, 184 MB: 5,733 IETF working-group minutes spanning
|
|
478
|
+
IETF 65 in 2006 to IETF 126 in 2026, and 587 United States congressional hearing
|
|
479
|
+
transcripts from seven years between 2016 and 2024 (2017 and 2020 were not
|
|
480
|
+
sampled). Both are public records, neither was written for this tool, and no
|
|
481
|
+
example in this repository came from either.
|
|
482
|
+
|
|
483
|
+
### How it was scored
|
|
484
|
+
|
|
485
|
+
A tool must not be allowed to grade itself, so two measures it did not produce.
|
|
486
|
+
One of them is weaker than that phrasing suggests, and the weakness is stated below
|
|
487
|
+
rather than left for the reader to discover.
|
|
488
|
+
|
|
489
|
+
**The scribes' own answers.** Many IETF minutes carry an "Action items" block a
|
|
490
|
+
human wrote during the meeting. The tool never sees that block; it reads the
|
|
491
|
+
discussion, and the block says what a person present thought was agreed.
|
|
492
|
+
|
|
493
|
+
**A blind labelling, by a model rather than by people.** 800 sentences were drawn
|
|
494
|
+
uniformly at random from a population defined without reference to this tool's
|
|
495
|
+
rules: any sentence in the corpus containing a marker from a fixed list of ordinary
|
|
496
|
+
English future and obligation words. Each was marked a commitment or not by an
|
|
497
|
+
isolated language model instance, five in total: four labelling 200 sentences each,
|
|
498
|
+
and a fifth re-labelling one block of 200 to measure agreement. The fifth agreed
|
|
499
|
+
with the first on 197 of 200, Cohen's kappa 0.92.
|
|
500
|
+
|
|
501
|
+
No person labelled any of the 800 sentences. The isolation was real — each
|
|
502
|
+
instance started fresh, was given the task from linguistic criteria alone, and was
|
|
503
|
+
instructed not to read this tool's source and not to look for its answers, so no
|
|
504
|
+
labeller could have copied it. But the labels come from the same model family that
|
|
505
|
+
wrote the tool being graded, which satisfies "a tool must not grade itself" less
|
|
506
|
+
completely than human annotation would. And the kappa is not human
|
|
507
|
+
inter-annotator agreement: it is two runs of one model on one prompt, so read it
|
|
508
|
+
as rubric stability rather than as evidence that two people would mark these
|
|
509
|
+
sentences the same way. The scribes' own answers above do not have this problem,
|
|
510
|
+
and they are the measure to weight.
|
|
511
|
+
|
|
512
|
+
### What it did
|
|
513
|
+
|
|
514
|
+
| | v0.1 | v0.2 |
|
|
515
|
+
|---|---|---|
|
|
516
|
+
| precision, 800 blind labels | 0.131 | 0.348 |
|
|
517
|
+
| recall, 800 blind labels | 0.432 | 0.605 |
|
|
518
|
+
| recall, whole pipeline over whole documents | 0.318 | 0.455 |
|
|
519
|
+
| action items the scribes marked and it missed | 1,598 of 1,760 | 1,249 of 1,760 |
|
|
520
|
+
| findings quoted cut off mid-sentence | 62.6% | 11.7% |
|
|
521
|
+
| findings carrying a deadline | 1.5% | 3.7% |
|
|
522
|
+
| hard-wrapped files correctly detected as wrapped | 24% | 84% |
|
|
523
|
+
| total findings over the corpus | 90,529 | 63,540 |
|
|
524
|
+
|
|
525
|
+
Four rounds of fixes sit behind that, and `tests/test_corpus_defects.py` is
|
|
526
|
+
their regression suite: 88 tests whose fixtures are real corpus sentences rather
|
|
527
|
+
than invented ones.
|
|
528
|
+
|
|
529
|
+
The largest single defect was one optional apostrophe. `\bwe'?ll\b` matches the
|
|
530
|
+
ordinary word **well**, and `\bi'?ll\b` matches **ill** — 31,599 findings, more
|
|
531
|
+
than a third of everything the tool reported, came from that alone. It is now 96.
|
|
532
|
+
|
|
533
|
+
The worst was a quoted slogan recorded as an open obligation owned by the group
|
|
534
|
+
the slogan named. Two guards close it, and neither is a list of words.
|
|
535
|
+
|
|
536
|
+
Two of the four rounds existed to fix something an earlier round had introduced.
|
|
537
|
+
The cue added to catch `Mark to post the draft` also fired on the ordinary
|
|
538
|
+
English preposition, so a report carried owners called According, Deferring and
|
|
539
|
+
Due — 5.5% of all findings, now 1.8%. The line-rejoiner added to fix that
|
|
540
|
+
measured a file's width from its longest line, so one URL or table row hid the
|
|
541
|
+
wrap column and it missed 76% of the hard-wrapped files it existed for,
|
|
542
|
+
including the transcript it had been written from. Both were caught by measuring
|
|
543
|
+
again rather than by reading the summary of the fix. A synthetic fixture passes
|
|
544
|
+
because whoever wrote it wrote it clean; only real files disagree with you.
|
|
545
|
+
|
|
546
|
+
### What this establishes, and what it does not
|
|
547
|
+
|
|
548
|
+
It establishes that the tool survives real input. 6,320 documents, zero crashes,
|
|
549
|
+
zero timeouts, about a seventh of a second each.
|
|
550
|
+
|
|
551
|
+
It establishes that every defect class listed above is real, because each one was
|
|
552
|
+
found in a document somebody actually published.
|
|
553
|
+
|
|
554
|
+
**It does not establish that this tool is good at reading your meetings.**
|
|
555
|
+
Standards-body minutes and parliamentary hearings are two genres it was not
|
|
556
|
+
designed for, in which most sentences containing "will" are prediction,
|
|
557
|
+
procedure or rhetoric rather than promise. These are numbers from hostile
|
|
558
|
+
ground, not a description of ordinary use. No measurement on ordinary business
|
|
559
|
+
meeting transcripts exists, because no public corpus of them does — and a
|
|
560
|
+
precision of 0.348 is not a good score by any reading.
|
|
561
|
+
|
|
562
|
+
Three further limits, stated rather than buried. Both corpora are hard-wrapped
|
|
563
|
+
at about seventy columns, so two thirds of the sampled sentences are cut
|
|
564
|
+
mid-line; that is what the tool sees too, but it is harsher than
|
|
565
|
+
one-sentence-per-line input. The whole corpus is English, so nothing in this
|
|
566
|
+
section says anything at all about the Hinglish rules. And 71% of what human
|
|
567
|
+
scribes wrote down as an action item is still missed: on written minutes this
|
|
568
|
+
tool finds under a third of what a person in the room recorded.
|
|
569
|
+
|
|
570
|
+
Follow Through was built with AI assistance, under human direction and reviewed
|
|
571
|
+
before release.
|
|
572
|
+
|
|
573
|
+
## Licence
|
|
574
|
+
|
|
575
|
+
MIT. See [LICENSE](LICENSE).
|
|
576
|
+
|
|
577
|
+
## Author
|
|
578
|
+
|
|
579
|
+
[Waiga Arya](https://www.linkedin.com/in/waigaarya/), Director of Business Strategy and
|
|
580
|
+
Innovation at Sadaway Pvt. Ltd. These tools were built for my own operating problems first.
|