0084 — One Company knowledge base per company: the only store Clara, Settings and ingest use
- Status: Accepted 2026-11-05. Written at decision time, before the first slice, as ADR-0004 requires.
- Date: 2026-11-05
- Deciders: Gera, 2026-11-04 brief ("we really should just have one… every entry should be only FREE FORM… rip out a lot of the Settings page… the Settings page would look at their company brain to pre-fill it… we're updating that company brain daily") and 2026-11-05 decisions: the name is "Company knowledge base", the new and only way ("pull everything in together, delete anything outdated, inherit this"); ingest is rebranded as the Company knowledge base, the one source of truth, and its spreadsheet grid is the right staff view; customers get no full knowledge-base UI for now ("too overwhelming") but one Settings tab, "Knowledge base · Ask", a chat where they ask and correct; "one source is enough": any single source nobody contradicts is stated as fact, disagreeing sources become one question per building, and leases follow the same rule; Fede need not be looped in; building starts when the plan passes its critics, with one combined localhost preview before any UI PR. Fede's 2026-10-07 private-information ruling and his 2026-09-29 fee-source rule are kept and narrowed only where this ADR says, on Gera's decision.
- Systems: company-knowledge-base (new row; propflowai: the
brain.<topic>/brain_suggested.<topic>rows on the company and building nodes, the one fenced readerreadBrain/forClara, the one writerwriteBrainEntry, the Settings tab "Knowledge base · Ask" on the existing Ask Clara chat door, the internal railPOST/GET /api/internal/brain/entries, thebrain_digestpath); propflow-ingest (re-scoped: the Company knowledge base's own app and learning engine; the web app becomes kb.propflowai.co, its grid reads and writes propflowai's rows through the rail, its ledger is the evidence behind each entry; the repo and the row key keep the name as code identifiers); agent-smith (the daily question list as Slack cards). It changes how Clara, Settings, ingest and AppFolio's unit fields relate: one store, one reader, one writer, two views. - Relation: the plan is
plan-decided.md(published at docs.propflowai.co as the Company knowledge base plan, 2026-11); propflowai ADR-0156 records the in-repo mechanics; propflowai ADR-0144 §6 gives the migration shape and is amended for one additive backfill; propflowai ADR-0080 (the voice snapshot) stands. No earlier agentflow ADR covers this area (grep 2026-11-05); SYSTEMS.md's citation of "ADR-0059" for propflow-ingest was wrong (ADR-0059 is the Smith runtime-clone refresh; ingest's 2026-10-15 decision was never written here) and is corrected to this one.
1. The problem
A company's facts live in three places that disagree: the typed Settings answers and free-form sections on the company and
building nodes (ATTACH#setting#knowledge.*), the legacy building record (PROP#/KNOWLEDGE, where Camellia's twelve
sections and fee schedule live and the Settings page showed blank on 2026-11-03), and ingest's sheet, which proposes into a
page few people open. The Situs application fee reads $45 on the listing, $40 in charges, $48 and $31 in marketing text,
"no application fee" from a staff reply, and $45 or $31 on AppFolio's own unit fields, and Clara picked one. Typed forms
refuse the way people describe policy; three UIs carry four names for the same thing; the lease package carries a snapshot
figure nobody re-reads.
2. The decision
- One store. A company's facts are
brain.<topic>rows on its company and building nodes in propflowai's table, one free-form sentence per topic with an envelope (where it came from and its original source class, who confirmed it and their role, whether Clara may say it, which readers may see it, the fair-housing stamp, derived numbers), resolved building over company; open questions and suggestions sit on their own row (brain_suggested.<topic>) that Clara never reads. Each topic declares where it may live, how it inherits, its audience, its reader scope, its safety class, its legacy readers and writers, and whether it may be written yet. The product name is Company knowledge base; it is the only name. There is no second copy anywhere: ingest'sROW#keeps evidence (where found, source, seen, agreement, conflicts, attempts) and no fact. - One reader, one writer. Everything renter-facing (Clara's prompt, her pricing and lease tools, the call snapshot, the
tour and key-pickup texts, the lease-answers block, the lease package and packet) reads through
readBrain; every writer (the Ask tab's tool, the kb grid's doors, the CLI twin, the review and intake forms, document upload, staff teaching, the fee crons, property creation, the ingest rail, the backfill) goes throughwriteBrainEntry, which runs the private-information gate on every write; the five storage doors refuse any other write to a field a writable topic owns. - Two views, no cards. Customers see and correct the knowledge base through one Settings tab, "Knowledge base ·
Ask": the existing Ask Clara chat door with two tools (read entries with their sources, as the signed-in user's role may see them; set an entry). A manager's
correction (
mayConfirmMoney: property manager, org admin, the four team labels of the 2026-08-19 ruling) applies at once with Undo and pins the value; anyone else's is one more source: a fact if nothing disagrees, a question if something does. The private-information gate and the fair-housing screen run on that tool as they run on the teach rail. The Settings pages Fees, Policies (Knowledge & policies), Knowledge, the building editor and the Knowledge-intake routes are deleted in the PR that ships the tab, and are not replaced by cards. Propflow staff see every entry as a row in the grid at kb.propflowai.co (today's ingest app, renamed; same Cloudflare Pages project, custom domain,ingest.propflowai.coredirects, the Access app renamed), whose Value and Status columns read propflowai's rows through the rail and whose teach/answer/promote/hand-off doors write through it; a staffer's edit isconfirmedonly on behalf of a named customer manager. - Settings keeps only what makes the product act. Who to call and in what order, hours and holidays (typed), modes, calendars, connections, recipients, sender timing, how Clara talks, renewal engine terms, and a typed home for vendor access instructions. The two that are also facts (escalation/on-call, calendar/hours) are pre-filled from the knowledge base while unset; once saved, a later knowledge-base change arrives as a one-tap question; who gets paged never changes without a person. Phones, links and aliases are the property record.
- Ingest is the knowledge base's engine. It reads every channel daily and writes through the rail and one function,
acceptRule, shared with the fee crons and property creation: the best source we hold wins when nothing we hold for that unit or building disagrees; a disagreement is one question per building in a capped daily list on thebrain_digestpath, under the mode model (unset is held; a founder sets it per company, and "Live" is what each company is set to at its rollout), recorded on /conversations; staff words and our own read-backs are evidence, never a vote; nothing from a meeting or internal email becomes what Clara says without a person; learned writes from ingest are gated per company by that same path's mode, the one switch on daily learning (no company list in code, no environment flag). Amended 2026-11-05 from propflowai ADR-0156's review: this replaced "Live by default" and "a code list that is deleted at the end"; a code list of company ids fails propflowai's customer-identifier fence, and a merge never turns a feature on at a real company. - Money, under "one source is enough", for Clara and for leases. Clara states a fee as plain fact whenever one source we
hold says it and nothing else we hold for that unit or building disagrees (a manager's word, AppFolio's per-unit
ApplicationFee/DefaultDepositwhere set and non-zero, a listing, the charges ledger, a document, a staff statement that passes the one-off and fair-housing checks). When records for a building disagree, Clara quotes the better figure with where it was seen, inside the fee line and in renter words, for 14 days after the team is asked, then reads it as not on file with the existing silent hand-off. A value amayConfirmMoneyperson confirmed (a Propflow administrator only on behalf of a named customer manager; never a machine) is never replaced by a later machine value without a question. There is no re-ask on age. A lease follows the same rule: the package-review approve and the paperwork rungs re-read every money figure at write time and write any uncontested figure whatever its source; a contested figure holds the lease ("not ready", both figures named) until the building's question is answered or a manager picks one on approval; the deposit on the lease is the deposit Clara quotes, from one function; a lease ledger records every figure written and its source. - Numbers for code are derived, never typed. Deposit tiers, fee × applicants, proration, hours for booking, the emergency
list are extracted from the sentence by a parser (an LLM only in the background and never for life-safety); an unclear
sentence falls to today's safe path. Hours, holidays, the renewal engine and the on-call chain stay typed. The 2026-10-17
"numbers only from typed values" ruling survives for settings keys and is retired for knowledge; the 2026-10-22 "building
evidence reaches Clara only after the customer saves" ruling is replaced by
acceptRule. - The knowledge base never holds contact data. Every write runs Fede's private-information gate with a mode per writer; four named topics are operational (used for routing, never said) with zero contact data, a narrowing of "knowledge base is public" recorded here on Gera's decision; machine writes redact. Fede's 09-29 fee rule gains one clause (a fee line that carries where it was posted is quoted with that mark) and otherwise stands.
- Migration never makes Clara worse. One reader projects the old rows until the backfill; a census of the assembled prompt, tools, snapshot and lease paperwork per building and reader role, attached to every PR from a read-only prod run, must show no unexpected difference; under "one source is enough" the only render change is a contested figure becoming a sourced quote plus a question (Situs: 7 buildings; Yale: 1; Camellia and Western Slope: none); a topic becomes writable only after every reader and every legacy writer moved; the backfill is one additive prod write on Gera's per-step approval; the removal lane finishes in the same effort.
- The drive. Building starts when the plan passes its critics: the ADR PRs and the store first; one combined localhost
preview of every screen (the Ask tab, the kb.propflowai.co grid, the stripped Settings) is shown to Gera before any UI PR
is split; parts are vertical, ≤~300 lines, off
origin/main, driven to merge; every prod write and every per-company rollout is Gera's go; Fede is not looped in.
3. What this does not do
- It does not put Clara's behaviour in the knowledge base: her rules, the emergency floor, fair-housing law and jurisdiction caps stay in code; Fede's Internal notes stay a staff-only drawer ("Team notes") behind their wall.
- It does not give customers a knowledge-base page, cards, tabs or boxes; the chat is the whole customer surface for now.
- It does not copy live PMS records in: units, rent, availability, tenants, work orders, charges and balances stay read-through; AppFolio's per-unit fee fields are synced into the mirror and read as one source, never duplicated as entries.
- It adds no hold gate to Clara's closed check registry: the money rule is enforced at the reader, plus one observe-only
registered check (the registry's "count only goes down" rule is honoured by adding
observe, neverhold). - It does not change the
pms-knowledge-baserepo (AppFolio help articles for Clara's PMS answers), which is a different thing.
4. What this replaces and retires (inventory, per ADR-0004)
- Stores folded in, then deleted after the backfill and a green week: the legacy building knowledge fields
(
PROP#/KNOWLEDGEsections, fee schedule, lease policy, hours, holidays), the typed topic answers and free sections (knowledge.<topic>,knowledge.section.<id>,pets.policy,fees.<slot>,application_fee,screening_policy,fair_housing_text,retention.days), the collected fact slots; the fact half of ingest'sROW#(value/status); orphaned rows stay unread. - UI removed, not replaced: Settings › Knowledge & policies, Fees & deposits, Company knowledge, the building knowledge editor, the Knowledge intake routes, the setup-intake fact screens, the dev "brain" page, the staff-only found-value hints and ingest history card (their content becomes the source line in an Ask answer and the evidence columns in the grid).
- UI inherited and renamed: ingest.propflowai.co → kb.propflowai.co, "Company knowledge base"; its grid, questions, find/run requests, replay, audits, documents, registry, tree and compare pages stay; its accept/edit doors write through the rail.
- Code retired: the legacy readers (
loadCoreTopics,loadOrgKnowledgeSectionsSafe, the knowledge fields ofgetPropertyKnowledge,resolvePricingFactView,statedByTopicOf,OLDER_BUILDING_RECORDS, the raw lease-policy read), the typed write routes and validators (specValueSchema, the fee branches of the knowledge PATCH and the policies PUT, pet apply-to-all, the core-topic and custom-policy routes), the two fee pre-fill crons as direct writers, the one-off knowledge scripts,mayConfirmFeesas a money authority, the approve route's snapshot-only deposit, ingest's newest-wins on required rows and its dotfile company list. - Design records superseded (kept for history with a banner): company-brain-design-2026-10 (its Public half; the Internal half stays live as the Team-notes design), company-brain-plan-2026-11, knowledge-source-of-truth-2026-11, knowledge-base-redesign-2026-08-26, knowledge-page-evolution-2026-08-18, home-knowledge-model, knowledge-layer-2026-08-29, knowledge-at-scale-2026-08-29, knowledge-grounding-architecture, the knowledge-coverage pages, property-brain-prototype, situs-property-brain; ingest's README "placeholder names" note (Gera has named them).
- Names removed from every screen: "Knowledge & policies", "Knowledge intake", "Company knowledge", "Fees & deposits", "Company brain", "Internal notes" (→ "Team notes"), "Ingest", "intake sheet", "policy registry", "pre-fill", "found values".
- Fencing: a drift test runs the end-state grep in CI from the removal part on; the reader ban by directory and type; the
five-door storage guard; a contract test that the grid's value equals the Ask tab's answer on a TEST company and that no
ROW#write carries a fact; planted tests (operational never rendered; a suggestion never rendered; a personal cell redacted or refused; a prose emergency still pages; a contested fee is a sourced quote, never a bare figure; an approve with a contested figure is held with both figures named; a non-manager's chat correction lands as one more source); the census manifest; the bench pack, including the chat door, as a merge gate.
5. Signals (SYSTEMS.md)
company-knowledge-base(new row): "census parity attached to every lane PR"; "no company over 70% of the knowledge budget"; "nightly sweep ran"; "G-BRAIN1 logged N unbacked figures / 0 unexplained"; "no open question older than N days at a rolled-out company"; "grid value equals tab answer on the TEST company"; "end-state grep green on main" (from the removal part).propflow-ingest(re-scoped: the Company knowledge base's app and engine at kb.propflowai.co): "every live company ran today"; "a rail write landed in 36 h"; "kb.propflowai.co answered and ingest.propflowai.co redirected";propflow-ingest-find-workerunchanged;propflow-ingest-auditand the coverage % read facts from the rail from the evidence-only cutover.- A row that is unknown never renders healthy (ADR-0004's liveness clause).
6. Consequences
One store with one name and two views. A company whose facts lived only on the old building record (Camellia) shows them without a company tier. A listing never silently outranks a manager, and a disagreement between records becomes one question instead of a guess, and holds the lease it would have touched. A lease and a quote come from one value. Customers get one chat instead of three pages; staff keep the grid they already use. Clara's prompt has a ceiling. Nobody fills a form twice, and nobody is asked to confirm what we already pulled. The costs: about 41 small PRs across two repos over several weeks, three prod data moves on Gera's per-step approval (hours, the ingest rows becoming evidence-only, the backfill), AppFolio's per-unit fee fields synced into the mirror, a domain and an Access app renamed, a removal lane that must finish before the effort closes, and one accepted risk under "one source is enough": a lone wrong figure is stated as fact, and may reach a lease, until a second record arrives or a manager corrects it; the weekly lease ledger diff is the net under that.