# The tick — the project's heartbeat ``` Type: knowledge ``` A **tick** is a single, bounded act of stewardship that every agent performs at session start (and that autonomous sessions perform on a loop). Ticks are how a corpus-driven project stays alive without a human driving every step: we pump ticks at one subject slice at a time, and each tick either makes the design corpus more precise or surfaces the thing preventing that. ## Taking a tick 0. **Brief, then work the queues in order.** Run `tools/tick-brief.sh` for the whole intake picture in one shot: recent commits, activity, project status, decision labels, the findings queue, and the stalest coverage rows. Then take the first queue that has work: 1. **Harvest** — a `decision-made` issue. Cameron already decided; converting his answer into law/spec motion is the highest value per tick. Convert, close, done. 2. **Findings queue** — a recorded surplus finding in the [tick ledger](tick-ledger.md). Verify it is still true (the code or corpus may have moved since it was recorded), then act on it. 3. **Fresh audit** — only when both queues are empty. Pick the stalest slice from the ledger's coverage table (or a slice the ledger has never seen). Fresh discovery is the fallback, not the default. 1. For a fresh audit: read the [corpus map](../overview.md) and the chosen coherent subject slice: its relevant `Type: law`, owning `Type: spec`, declared dependencies, and nearby `Type: knowledge` pages. Start from the spec's checked `Design:` anchors; they identify the binding clauses the system claims to realize. A missing, misleading, or duplicate-owner reference is itself a contradiction. 2. Find **one** thing to act on — the highest-severity one you can see: - a **violation**: the code does not do what the binding corpus says; - a **contradiction**: current corpus pages disagree; - a **question**: the corpus is ambiguous or silent where the code needs it to speak; - a **bug**: the code disagrees with itself or with reality; - an **insecurity**: something unsafe in code, tooling, or process. 3. Act on it, per the table below. One **act** per tick — bounded beats exhaustive, because ticks repeat. Surplus findings you saw but did not act on are not dropped: record each as one line in the ledger's findings queue. Discovery is the expensive phase of a tick; paid-for findings must not evaporate. 4. Leave a trace: update the slice's row in the [coverage ledger](tick-ledger.md) — a **clean verdict is a trace** — plus the commit(s), the issue, or the spec marker. A tick that changed nothing and recorded nothing did not happen. ## What each finding demands | Finding | Action | |---|---| | **Violation** | Fix the code toward the owning law/spec page. If the code is right, amend that page deliberately with a defense. Never let them drift silently. | | **Contradiction** | File a Tangled issue quoting both pages, use the issue body standard below, and label it `decision-required`. Do not silently pick a side unless one reading is obviously a typo. If it blocks work, add an `[OPEN]` marker to the owning binding page. | | **Question** | If it is small and answerable within existing intent, make the owning page more precise with a defense. If directional or a taste call, file a `decision-required` issue and add an `[OPEN]` marker to the owning page. | | **Bug** | Fix it, add a regression test, commit with a defense. | | **Insecurity** | Fix or remove it. Never ship the insecure path because it was convenient. Defense in the commit. | ## The defense rule Every commit that changes behavior carries a **defense** in its commit message: a short paragraph stating which corpus clause justifies the change — or, when the commit amends that clause, why the amendment is right. Format: ``` Defense: wiki/mechanics/detection.md specifies per-observer suspicion; the single global heat pool violated it. This implements the observer split without changing the tuned pacing. ``` No defense, no behavior change. The point is that the design corpus becomes much more precise over time: every change either cites the law or improves it. ## Filing issues (Tangled CLI) The CLI is `tang` (source at `~/code/tangled-cli`, Cameron's fork — disconnected from the markbennett.ca upstream). The global binary is a symlink to `~/code/tangled-cli/dist/index.js`. ```bash tang context # verify repo resolution tang issue list tang issue create "Question: ..." -F body.md tang label add issue decision-required # waiting on Cameron tang issue view 1 tang issue edit 1 -F body.md # rewrite if an issue is not answerable tang label add issue decision-made # Cameron answered; harvest next ``` - **Auth is one-time per machine and human-only**: `tang auth login` (browser OAuth). If commands fail with "Not authenticated", stop and ask the user to log in rather than working around it. - Issue titles: prefix with the finding type — `Contradiction:`, `Question:`, `Violation:` — so the issue list reads as the project's open questions. The rest of the title is the decision itself ("four origins or five?"), not a topic label ("chargen thoughts"). ### Issue body standard (binding) Every Tangled issue filed for Cameron is a **decision packet**, not a status dump or agent diary. He must be able to open any issue and answer it in under two minutes without reading the surrounding session. **Required sections, in this order:** 1. **`## Question`** — one concrete question. Prefer a numbered multiple-choice list (`1.` / `2.` / `3.` … plus `Something else (say what)`). Never leave the ask buried in a paragraph of context. 2. **`## Why this is open`** — short analysis: what the docs/code currently say, what conflict or gap forces a human call, and what is already decided (so he does not re-litigate settled ground). Quote file paths; keep it to a few sentences. 3. **`## Options`** — 2–4 real alternatives with one honest trade-off line each (which pillar/clause it serves or strains). Tables are fine. 4. **`## Recommendation`** — one marked pick and a one-line reason. Turns the issue into a yes/no override, not an essay question. 5. **`## What your answer unlocks`** — the mechanical next step (which binding wiki page to amend, which ROADMAP item unblocks, when to close the issue). **Hard rejects (do not file, or rewrite before leaving):** - A body that is only narrative / session notes with no singular question. - A question that cannot be answered without opening other files first. - Multiple unrelated decisions packed into one issue (split them). - Jargon-dense prose that restates the wiki instead of asking for a call. If you find an existing open issue that fails this standard, rewrite it with `tang issue edit` before doing other harvest work on it. An unanswerable issue is process debt, same species as a stale `[OPEN]` marker. ### Decision labels (binding) Two custom Tangled labels track whether an issue still needs Cameron: | Label | Meaning | Who applies it | |---|---|---| | **`decision-required`** | Open ask waiting on Cameron. Body must already meet the issue standard above. | Agent, when filing or refreshing a human decision | | **`decision-made`** | Cameron has answered (in the issue thread, chat, or decision history). Ready for harvest into law/spec/ROADMAP motion, then close. | Agent, as soon as the answer is recorded — or Cameron | Rules: - Every newly filed Question/Contradiction issue that needs a human call gets `decision-required` in the same turn as `tang issue create`. - The two labels are mutually exclusive: applying one removes the other (`tang label add` does this swap automatically). - Harvest prioritizes `decision-made` first (convert + close), then unlabeled / stale open issues, and leaves `decision-required` alone except to rewrite incomprehensible bodies. - Do not close a `decision-required` issue just because it is old. Do not leave an answered issue on `decision-required` — flip it to `decision-made` (or convert and close in the same harvest). ```bash tang label defs tang label list issue 1 tang label add issue 1 decision-required tang label add issue 1 decision-made # also clears decision-required tang label remove issue 1 decision-made ``` ## Tick etiquette - **Metered resources are not tick fuel.** Anything that spends a shared, capped resource (API generation quotas, paid credits) is session work to do with Cameron present, not autonomous-tick work — unless the remaining capacity is known and generous. An autonomous tick that drains a shared quota blocks the human's own use of it. - **User-gated means quiet.** When every open item waits on an action only the human can take (account access, billing, a browser login), say so once, lengthen the loop interval, and retry only the cheap checks. Do not convert "blocked" into invented work. - Highest severity first; insecurity and violations outrank questions. - Do not hoard **acts**: one per tick, then end the tick. Surplus findings go into the [ledger's findings queue](tick-ledger.md) as one-liners so the next tick (or the next agent) starts from them instead of rediscovering. - If a tick finds genuinely nothing, record the clean verdict in the coverage ledger, say so in one line, and stop — do not invent work. A clean row is durable value: it steers later ticks toward staler slices. Three quiet ticks in a row on stalest-first slices means the audited corpus and code agree; that is success, not failure. - **Recurrence promotes to the gate.** A mechanical finding class seen twice (a quoted code path that no longer exists, a stale constant, a broken structural reference) becomes a `tools/corpus_engine.py` checker instead of a third tick. Model attention is for semantic drift; the gate owns everything a script can verify. If implementing the checker exceeds the tick, queue it as a finding. - Significant ticks get a line in `wiki/log/DEVLOG.md`; routine ones are traced by their commits/issues alone.