Quiblo wiki

How this was built

Working with agents on this codebase

The practical half: what gets written down, what belongs in CI instead, and the failure modes to expect.

# One document comes first, always

Every contributor and every agent asked to work on this codebase is given the frozen scope before anything else. It states what Quiblo is in one sentence, what it is explicitly not, the architectural invariants, and the amendments that have changed any of it.

The reason is narrow and practical: an agent asked to add a feature will add it wherever it fits, and "where it fits" is a question about architecture that a prompt cannot answer. The non-goals do more work than the goals — no bundled content, no accounts, no telemetry, no backend — because they are the decisions most likely to be helpfully undone by somebody trying to be useful.

That document is also the reason this page exists: it has been wrong once. Its header pointed at a repository that is not this one, for a week, while being the first thing every new contributor read.

# If it can fail in CI, it belongs in CI

The rule that survived contact with reality. Anything relying on a person or an agent remembering is a rule that is already unenforced — so the conventions this project actually holds are the ones a build can fail on:

  • no provider URL, credential or playlist anywhere in the repository — a grep, on every change, including changes that only touch prose;
  • a licence header on every source file;
  • no core module importing UI code;
  • no domain enum name used as display text, since one reached the screen as VOD;
  • every workflow file parses — including the ones the current run is not using;
  • every shipped third-party component is listed in the app's own licence screen;
  • a compiler warning fails the build.

Each of those exists because something got through. The enum-name rule is the clearest: a grep cannot tell display text from a cache key, so the few legitimate uses carry a comment saying so. That is a deliberate small annoyance — it is the one place where writing that expression is a decision rather than a reflex.

# Measure it, do not argue about it

The most expensive mistake in this project's history was a screen that shook, and the expensive part was four rounds of plausible reasoning about why. The habit that replaced it: when something moves, jitters or takes too long, build the instrument before proposing the cause.

On the JVM that means stepping the clock frame by frame and reading a position out of the scrolling container itself. Two things make such a harness lie, and both were hit here:

  • The wrong geometry. A first attempt guessed a viewport 48dp taller than the real panel; the header fitted, the bug vanished, and the test went green against code the television was failing. A harness at the wrong size is not a weaker instrument, it is a lying one.
  • A cache replaying old output. A census of compiler warnings reported six. The same command with the build cache disabled reported twenty-four — cached task results are replayed without their warnings. Four times under is enough to reach the wrong conclusion, and it did: the six looked like one trivial migration, and the twenty-four included a deprecated encryption library holding user credentials.

The general form: before believing a measurement, ask what it would say if the thing being measured never ran at all.

# A green test is a claim about the harness

Two fixes on the television were signed off on the JVM, published, and rejected the same day by the panel. Both had corrected a real, measured mechanism — and in both the reported symptom outlived the mechanism it was blamed on.

A mechanism is not a symptom. Work that stops when the measured cause is fixed, rather than when the screen looks right, produces exactly that: a confident fix, a green harness, and an unchanged television. The acceptance criteria here are written against symptoms for this reason.

The practice that came out of it is one line in a test's own documentation: run a new harness against the code the device rejected before trusting it. One of the tests in this repository says, in its own comments, that it passes against the broken version too — so it is a guard on a property, not a reproduction of the fault, and a green run is not allowed to mean more than that.

# Notes for an agent are a running cost, not a filing cabinet

An agent reads its notes on every session, so a note is not free the way a document is free. Ours grew to 22,000 tokens across 28 files, of which the index alone — loaded every time, whatever the task — was 1,084.

Three habits caused it, and all three are the obvious thing to do:

  • Writing status into notes. Which gate is open, what shipped last week — all of it true, all of it stale within days, and all of it already in the repository. Notes should point at the file, not copy it.
  • Appending instead of splitting. One file grew to seven facts because each new lesson was added to the end of the nearest one. Recall loads the whole file, so asking about one trap paid for all seven.
  • Writing the index like prose. Its only job is to help decide whether to open a file. A sentence per entry is a paragraph nobody needed.

Compacting on those three rules cut the two worst files by about 70% and the always-loaded index by a third, without deleting a single lesson — everything removed was either status or a copy of something in the repository.

The rule that came out of it: a note earns its place by being something the repository does not already say. Anything else is a second copy to keep true, and the copy that matters least is the one that will be kept up to date.

# What transfers, and what does not

Transfers. Decide the architecture before the agent needs it. Write the non-goals down. Put every convention you actually care about into the build. Prefer tests that assert a property over tests that assert a value. Keep a record of what has not been verified, because that list is the one that goes stale silently.

Does not transfer. The device. A television with a remote, in a room, watched by a person, found faults that nothing on this page would have caught — and the one that took longest was solved by an observation from the sofa. If your project has a physical target, no amount of harness replaces owning one.

Still unanswered. What this cost, in tokens and in sessions, is being collected as aggregates rather than estimated from memory — and that page will exist when the numbers do, not before. Every figure on this wiki comes from something a reader can check, and that includes the ones about ourselves.