bvandeusenandClaude Opus 5 04775c3496
CI & Build / Python lint (push) Successful in 8s
CI & Build / Plugin hooks (push) Successful in 15s
CI & Build / TypeScript typecheck (push) Successful in 54s
CI & Build / integration (push) Successful in 1m2s
CI & Build / Python tests (push) Successful in 1m40s
CI & Build / Build & push image (push) Successful in 26s
fix(drafter): the base rate counted a dataclass and an async service unit as comparable things (#4208)
A CORRECTION TO THIS ISSUE'S OWN PLAN, first, because the plan was wrong in
a way that would have cost the acceptance case.

#4208 recommended widening `kind` past `css | sym` to carry the form, calling
the denominator the deeper win and a migration the price. Two things:

1. THE MIGRATION IS NOT NEEDED. The issue says density "is computed from
   stored rows and `shape_form` only runs on read". `canon_density` does
   `select(CodeShape)...scalars().all()` and filters to the directory in
   PYTHON; `signature` is a stored column; `canon_form(siblings, ...)` on the
   next line already derives form from those rows. Bucketing the denominator
   costs a list comprehension.

2. WIDENING `kind` WOULD BREAK MILESTONE #2793's ACCEPTANCE CASE. If `kind`
   separated `fn` from `async-fn`, density would bucket them apart — which
   does silence #4204's four `def` helpers, as claimed. Apply it to a
   hand-rolled SYNC `confirmDanger` in a directory where an async confirm
   helper is canon: the canon leaves the candidate's denominator, nothing
   dominates, no flag. That is the flag the milestone exists to produce, and
   it is the same inversion the first form gate made, one layer down.

So option 1 is not expensive-but-right, it is wrong; and option 2 (compare
meaning) is not the interim, it is the only lever. `confirmDanger` beside an
async confirm helper and `is_registered` beside a service unit are identical
at every structural level — same family, same form contradiction, same
density. They differ only in whether the candidate does the canon's JOB, and
no signature carries that.

WHAT THIS SHIPS is the part that is right and provable: an honest
denominator. `comparable_siblings` narrows the count to rows whose family
does not contradict the candidate's, using `families_conflict` — the same
predicate the gate uses, so the count and the verdict cannot drift into
disagreeing about what comparable means. "372 judged siblings" stops counting
a dataclass, a constant and an async service unit as three comparable things.

NARROWED BY FAMILY, NOT FORM, for the reason above: `fn` beside `async-fn`
stays a fair question. An unreadable sibling STAYS COUNTED — dropping it
would shrink `judged`, raise the share, and fire the check more on the
directories it can read least. Every unknown-form decision in this module
goes that way.

Density is now per candidate rather than per kind, cached on (kind, form).

TWO BUGS THIS CHANGE HAD, both caught before CI and both pinned:

- I passed a FAMILY where `families_conflict` reads a FORM, so
  `shape_family("callable")` returned "" and the narrowing was a silent
  no-op that still read as applied. The regression guard deliberately uses a
  callable: `type` is both a form and a family name, so testing with it
  proves nothing and the bug hides.
- My new `_Row` in the test file shadowed the one already there — same
  fields, different `snippet_id` default — silently breaking three passing
  `canon_form` tests. Reused the existing class. A duplicate definition
  quietly changing a neighbour's meaning is this file's own subject.

The residue test's docstring said separating the four needs "widen `kind` or
a comparison of meaning". Corrected: they are not alternatives.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01821k5B3Ysecp9fNYs92Kuy
2026-09-21 01:33:45 -04:00

Fabled Scribe

A self-hosted work system-of-record for software projects, built to be driven by Claude Code. Notes, tasks, issues, projects, milestones, rules, and stored processes — reachable from Claude via a built-in MCP endpoint and a bundled Claude Code plugin, with a clean web UI for humans. No in-app LLM; Claude is the sole assistant.

Features

Notes and tasks with a Markdown editor, sub-tasks, milestones, issues, and kanban project workspaces. Stored processes, an engineering rulebook system (with an inception step that decides what each project inherits), and semantic search with proactive knowledge-injection into Claude's context. A knowledge graph, per-user/group sharing, and a built-in MCP server (/mcp) plus a bundled Claude Code plugin so Claude can record and recall your work directly.

Quick Start

Prerequisites: Docker and Docker Compose. No GPU or local model needed — Claude is the sole assistant, reached over MCP.

Download docker-compose.quickstart.yml from this repo, then:

# Optional but recommended — set a secret key
export SECRET_KEY=your-random-secret-here

docker compose -f docker-compose.quickstart.yml up -d

Open http://localhost:5000. The first user to register becomes admin. To connect Claude, create an API key under Settings → API Keys and install the Claude Code plugin — see API Keys & MCP.

Development: To build from source, see Development.

Documentation

Doc Contents
Architecture Stack, design decisions, data models, key services
Configuration Environment variables, Docker Compose, production setup, security
Features Detailed feature breakdown and keyboard shortcuts
Development Dev workflow, CI/CD, migrations, release process
API Keys & MCP API key management and Fable MCP install guide
SSO / OAuth OIDC setup for Authentik, Keycloak, and other providers
API Reference All REST API endpoints

License

This project is privately maintained.

S
Description
No description provided
Readme
19 MiB
Languages
Python 77.1%
Vue 16%
TypeScript 3.1%
Shell 2.6%
CSS 0.9%
Other 0.2%