aboutsummaryrefslogtreecommitdiff
path: root/docs/decisions
diff options
context:
space:
mode:
authorCraig Jennings <c@cjennings.net>2026-04-30 07:55:28 -0500
committerCraig Jennings <c@cjennings.net>2026-04-30 07:55:28 -0500
commitb0d722d1a985326fb38e4e7fea237b9c4a2adcfd (patch)
tree47793265082155fe8ddacfc09d5990d7760de15a /docs/decisions
parent9e90517a98785c450cd13cd940bd1787a4771529 (diff)
downloadgloss-b0d722d1a985326fb38e4e7fea237b9c4a2adcfd.tar.gz
gloss-b0d722d1a985326fb38e4e7fea237b9c4a2adcfd.zip
docs: record four ADRs for gloss design decisions
The four decisions called out in the brainstorm now have their own files under docs/decisions/, each with Context / Decision / Consequences / Alternatives Considered. - 0001 — storage path default: respects org-directory if set, falls back to user-emacs-directory. - 0002 — auto-fetch on local miss: silent fall-through, network failures surface via the regular error rollup. No y/n prompt for v1. - 0003 — drill direction: every entry exports as twosided. One card per entry, both directions over time, no per-entry override. - 0004 — HTML strip strategy: libxml-parse-html-region. Plain text only, no italic/bold preservation. Online fetch disabled package-wide for the session if libxml is missing. The "Open Questions" section in the design doc is now "Decisions Recorded" with links into the ADRs.
Diffstat (limited to 'docs/decisions')
-rw-r--r--docs/decisions/0001-storage-path-default.org55
-rw-r--r--docs/decisions/0002-auto-fetch-on-local-miss.org51
-rw-r--r--docs/decisions/0003-drill-direction.org49
-rw-r--r--docs/decisions/0004-html-strip-strategy.org54
4 files changed, 209 insertions, 0 deletions
diff --git a/docs/decisions/0001-storage-path-default.org b/docs/decisions/0001-storage-path-default.org
new file mode 100644
index 0000000..539cba7
--- /dev/null
+++ b/docs/decisions/0001-storage-path-default.org
@@ -0,0 +1,55 @@
+#+TITLE: ADR-1: Storage path default
+#+DATE: 2026-04-30
+#+STATUS: Accepted
+
+* Context
+
+The glossary is a single org file. The package needs a default location
+that integrates with the user's existing org workflow when one exists,
+and falls back gracefully otherwise. The choice is visible to users via
+the =gloss-file= defcustom and to the file system as the path that gets
+auto-created on first save.
+
+* Decision
+
+Default =gloss-file= to:
+
+#+begin_src emacs-lisp
+(expand-file-name "gloss.org" (or org-directory user-emacs-directory))
+#+end_src
+
+If =org-directory= is set, the glossary lives next to the user's other
+org files. If it isn't, the glossary lives under =user-emacs-directory=
+(typically =~/.emacs.d/=).
+
+* Consequences
+
+*Positive.*
+
+- Users with an established =org-directory= get the glossary in their
+ org tree without configuration.
+- Users without =org-directory= still get a sensible default path that
+ doesn't require a directory tree to exist.
+- The path is writable on every supported platform without privilege.
+
+*Negative.*
+
+- =user-emacs-directory= isn't intended for user data — it's
+ configuration. Users who care will set =gloss-file= explicitly.
+- A user who later sets =org-directory= won't see the glossary move.
+ =gloss-file= is captured at defcustom evaluation time, not on each
+ call. This is documented in the README troubleshooting section.
+
+* Alternatives Considered
+
+*Hardcoded path* — e.g. =~/.gloss.org= or =~/gloss.org=. Rejected:
+ignores the org-directory convention; doesn't respect user
+preferences for where data lives.
+
+*XDG_DATA_HOME* — e.g. =~/.local/share/gloss/gloss.org=. Rejected:
+correct in spirit but adds a layer the user doesn't otherwise see in
+their org workflow. The whole point is "this is one of your org
+files."
+
+*Package-data dir* — e.g. inside the gloss package's install location.
+Rejected: data shouldn't live with code; survives reinstalls poorly.
diff --git a/docs/decisions/0002-auto-fetch-on-local-miss.org b/docs/decisions/0002-auto-fetch-on-local-miss.org
new file mode 100644
index 0000000..399d520
--- /dev/null
+++ b/docs/decisions/0002-auto-fetch-on-local-miss.org
@@ -0,0 +1,51 @@
+#+TITLE: ADR-2: Auto-fetch on local miss
+#+DATE: 2026-04-30
+#+STATUS: Accepted
+
+* Context
+
+When the user runs =gloss-lookup= on a term that isn't in the local
+cache, the package can either prompt before going online or fall
+through silently. The trade-off is between explicit consent (no
+surprise network calls) and frictionless typical use.
+
+* Decision
+
+Silent fall-through. On a cache miss, =gloss-lookup= calls the online
+fetcher without asking. Network failures surface clearly via the
+error rollup (see ADR on the error taxonomy in the design doc).
+
+If a user wants a strict offline mode, they can wrap =gloss-lookup= or
+unbind =gloss-fetch-sources= to nil. v1 does not ship a defcustom toggle.
+
+* Consequences
+
+*Positive.*
+
+- The common case (term not in glossary, want a definition) takes
+ one keystroke (=C-h g g=) instead of two.
+- The user-facing message on a network failure is the same shape as
+ any other failure mode — there's no special "you would have hit
+ the network" affordance to explain.
+
+*Negative.*
+
+- A user on a metered connection or in a restricted environment
+ might prefer an explicit prompt. v1 doesn't accommodate that.
+- A typo on the term means a wasted network call. The cost is small
+ (one HTTP request to Wiktionary) and the failure is fast.
+
+* Alternatives Considered
+
+*y/n prompt before fetch.* Rejected: the answer would be "yes" 99%
+of the time, and the prompt becomes friction the user trains
+themselves to ignore. The 1% offline case is better handled by
+detecting the failure than by pre-asking permission.
+
+*Defcustom =gloss-auto-fetch=.* Rejected for v1: adds a knob with no
+clear default. If shakedown reveals a real need, adding the knob in
+v1.1 is straightforward — silent fall-through is the harder default
+to walk back.
+
+*Hard-fail offline.* Rejected: turns "not in glossary" into a fatal
+error, which is the wrong shape for what should be a soft fall-through.
diff --git a/docs/decisions/0003-drill-direction.org b/docs/decisions/0003-drill-direction.org
new file mode 100644
index 0000000..90073aa
--- /dev/null
+++ b/docs/decisions/0003-drill-direction.org
@@ -0,0 +1,49 @@
+#+TITLE: ADR-3: Drill direction
+#+DATE: 2026-04-30
+#+STATUS: Accepted
+
+* Context
+
+=gloss-drill-export-all= tags every entry for =org-drill=. The card
+type controls which direction(s) the drill quizzes — term-to-definition
+(recognition), definition-to-term (recall), or both.
+
+* Decision
+
+Set =:DRILL_CARD_TYPE: twosided= on every exported entry.
+=org-drill='s twosided card type alternates direction on consecutive
+visits, so a single entry quizzes both directions over time.
+
+No per-entry override in v1. Every entry exports as twosided.
+
+* Consequences
+
+*Positive.*
+
+- Tests both recognition and recall over time without doubling the
+ deck size — one entry, both directions, alternated by =org-drill='s
+ scheduler.
+- No per-entry decision burden during =gloss-add= or
+ =gloss-drill-export=.
+
+*Negative.*
+
+- Some terms make more sense one-directional. A user who saved
+ "SBIR" → "Small Business Innovation Research" probably wants
+ recognition only (acronym → expansion), not recall (expansion →
+ acronym). v1 doesn't accommodate this.
+- A future v2 may want a per-entry =:DRILL_CARD_TYPE:= override or a
+ defcustom for the default. Both are additive changes.
+
+* Alternatives Considered
+
+*=:DRILL_CARD_TYPE: simple= (term → definition only).* Rejected:
+half the value of the cards, and the user can always skip-back
+during drill if they don't want the reverse direction.
+
+*Two cards per entry, one each direction.* Rejected: doubles the
+deck size; adds maintenance burden when an entry is edited (now
+two cards diverge).
+
+*Cloze cards.* Rejected: needs a marked deletion in the body, which
+fights the "save once, drill forever" promise.
diff --git a/docs/decisions/0004-html-strip-strategy.org b/docs/decisions/0004-html-strip-strategy.org
new file mode 100644
index 0000000..4ec7293
--- /dev/null
+++ b/docs/decisions/0004-html-strip-strategy.org
@@ -0,0 +1,54 @@
+#+TITLE: ADR-4: HTML strip strategy
+#+DATE: 2026-04-30
+#+STATUS: Accepted
+
+* Context
+
+Wiktionary's REST API returns definition text with HTML markup —
+=<span>= wrappers, =<a>= anchors, transclusion markers, occasional
+inline =<i>= and =<b>=. The package needs plain text in the saved
+glossary entry. The strip strategy must be robust on real responses
+(not toy inputs) and shouldn't add a heavyweight dependency.
+
+* Decision
+
+Strip via =libxml-parse-html-region=. Take the parsed tree, recurse
+through it collecting text nodes, drop everything else. No
+preservation of inline formatting (italic, bold, links).
+
+If the running Emacs wasn't built with libxml2, online fetching is
+disabled package-wide for the session with a one-shot user-error.
+Manual =gloss-add= still works without libxml.
+
+* Consequences
+
+*Positive.*
+
+- Robust on edge cases — nested tags, malformed HTML, unusual
+ attributes. The libxml parser handles all of these.
+- libxml2 is standard on Linux and macOS; ships with most Emacs
+ builds. The "missing libxml" path is real but rare.
+- ~30 lines of strip code. Maintainable.
+
+*Negative.*
+
+- Loses italic/bold/link formatting from definitions. The saved
+ entry is plain text only. v1 trades fidelity for simplicity.
+- A user on a barebones Emacs build (no libxml2) loses online
+ fetching entirely. The error message tells them why and what to
+ do, but it's still a hit.
+
+* Alternatives Considered
+
+*Regex strip* — pattern-replace =<[^>]+>= and known HTML entities.
+Rejected: misses entities the regex didn't anticipate, breaks on
+attributes containing =>=, fights when tags are malformed. Looks
+simpler but rots fast.
+
+*Preserve markdown-style inline formatting* — italic → =/.../=, bold
+→ =*...*=. Rejected for v1: scope creep on a personal package.
+Defensible v1.1 if requested.
+
+*=shr-render-region=.* Rejected: shr is a renderer, not a stripper.
+It produces text-with-faces meant for display, not text for
+storage. Wrong shape for the use case.