All checks were successful
deploy / deploy (push) Successful in 5m35s
Closes #2. Three tables mirroring tireless-entities, plus the sqlx compile-time-checking decision the rest of stage 1 inherits. RUNTIME QUERIES, NOT `query!`. No .sqlx metadata, no DATABASE_URL to build. lairball, the other house project on this cluster, does the same. The deciding argument is specific to tireless: compile-time checking makes a database a build dependency, and this crate is meant to be modified by a 27B model working unattended. A build that fails without a database it cannot provision is one that model cannot fix, and its documented failure mode is to improvise. The cost is named in store.rs — a malformed query is caught by a test, not by cargo. Enums are text with a check constraint, not Postgres enum types: adding a JobKind variant should be a migration, not an ALTER TYPE holding a lock. Unit tests assert every serde variant appears in the schema, so adding a variant without a migration fails the build rather than the first job of that kind. That surfaced a spelling that would have been permanent: `rename_all = "snake_case"` turns Forge::GitHub into `git_hub`, across the database, the JSON API and the generated TypeScript. Renamed to `github` now, while nothing is persisted and GitHub support is still disabled. The live-issue index is PARTIAL, and both directions of getting it wrong are silent. A plain unique constraint on (forge, owner, repo, number) would forbid re-running a terminal job, and would forbid the discovery lane outright, since discovery recurs against one tracking issue on a cooldown. Partial on the non-terminal states gives at most one live job per issue and unlimited history. The claim index orders by created_at alone and leaves kind as a filter, because the claim takes LIMIT 1 and can stop at the first match. Leading with kind sorts every pending row on every claim: measured at 720 buffers versus 4, and the gap grows with the backlog rather than staying fixed. INCLUDE (kind) was measured too and dropped — FOR UPDATE visits the heap regardless. Verified against Postgres 18, the same major as the house cluster: migrations apply to an empty database and are a no-op on the second run; all eight constraints reject what they should and admit what they should; and two concurrent claimers of one pending job produce exactly one winner, with the loser skipping rather than blocking. Those live tests are #[ignore]d, not skipped on a missing variable, so a green `cargo test` never implies the schema was exercised. CLAUDE.md says how to run them and that an applied migration must never be edited. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013TxK1CWPkFXqdcXMJ4hVe6
115 lines
5.3 KiB
Markdown
115 lines
5.3 KiB
Markdown
# tireless — agent instructions
|
|
|
|
Read [`doc/plan/design.md`](doc/plan/design.md) before making changes. It carries
|
|
the constraints, the staged plan, and the reasoning behind decisions that look
|
|
arbitrary in isolation.
|
|
|
|
House conventions live in [`~/git/architecture`](https://git.lair.cafe/lair/architecture)
|
|
(`generic.md` is the baseline). This project's deliberate deviations are listed
|
|
at the bottom of `readme.md`.
|
|
|
|
**tireless works on tireless.** This repo is its own first subject, so changes
|
|
here are both the product and the test of it. If you are an agent working from a
|
|
tireless-authored issue, design.md §10 says what that implies — in particular,
|
|
that some areas of this repo are constraint-bearing and are routed deliberately.
|
|
|
|
## Invariants — do not "clean these up"
|
|
|
|
These are terms-of-service and safety constraints expressed as code. Each has
|
|
tests. If one seems redundant, read design.md §3 before touching it.
|
|
|
|
1. **Never construct a request to a model provider.** Agents are spawned as the
|
|
vendor's own binary and authenticate themselves. Adding an HTTP client that
|
|
talks to `api.anthropic.com` would break the arrangement that lets a
|
|
subscription back this app.
|
|
|
|
2. **Never read or forward agent credentials.** `has_credentials()` stats
|
|
`~/.claude.json` and nothing more. Do not parse it, copy it, or pass its
|
|
contents anywhere.
|
|
|
|
3. **Never set `ANTHROPIC_API_KEY`.** It reaches Claude Code only if an operator
|
|
put it in the unit environment. Its presence selects pay-as-you-go; its
|
|
absence selects the subscription. That choice is the operator's.
|
|
|
|
4. **Never point the OpenCode lane at Anthropic.** `assert_not_anthropic` is
|
|
checked at startup against both provider id and base URL. Local gateways that
|
|
merely serve an Anthropic-compatible surface (helexa cortex) are fine and are
|
|
tested for.
|
|
|
|
5. **Never let a lane run unbounded.** Every agent invocation passes through
|
|
`tireless_core::budget::Governor`. Provider rate-limit signals are checked
|
|
first and are authoritative.
|
|
|
|
6. **Postgres is the authority on claims, not forge labels.** Labels are a
|
|
best-effort mirror. Do not make a decision by reading a label that could be
|
|
made by reading the database.
|
|
|
|
7. **Never use `--system-prompt` for Claude Code; append instead.** Replacing
|
|
Claude Code's default discards the tool-use scaffolding that makes it a
|
|
coding agent. `SYSTEM_PROMPT_FLAG` is `--append-system-prompt` for this
|
|
reason.
|
|
|
|
8. **The four prompts in `prompt/` are one set — edit them together.**
|
|
`plan.cc.md` emits the structure `implement.oc.md` consumes and
|
|
`tireless_core::plan::validate` enforces. Changing one alone breaks the
|
|
handoff silently, as a bad pull request rather than an error. Bump
|
|
`contract-version:` in all four plus `SYSTEM_PROMPT_CONTRACT_VERSION`
|
|
together; `PromptSet::load` refuses a mismatched set.
|
|
|
|
9. **A plan is validated, not trusted.** Never enqueue implementation work from
|
|
a plan that has not passed `plan::validate`. The `Acceptance` (runnable
|
|
stopping condition) and `Out of scope` (boundary) requirements exist because
|
|
a small model needs them; do not relax them because a plan looks fine to a
|
|
human reader.
|
|
|
|
10. **Admission is inherited, never invented.** tireless may apply the opt-in
|
|
label only to an issue descended from one a human opted in.
|
|
`may_opt_in(JobKind::Discover)` is `false` and must stay false: it is the
|
|
only thing standing between "proposes work" and "generates its own work
|
|
indefinitely". See design.md §2.5. This is not a policy to relax once the
|
|
system is trusted — the failure it prevents is unbounded, not merely wrong.
|
|
|
|
11. **Every constraint above is reachable from a binary's startup path.** A
|
|
guard that exists as a tested function nobody calls is not a guard. If you
|
|
add one, wire it into `Config::validate` or `tireless_agent::preflight::run`
|
|
so it cannot be bypassed by a caller that forgot.
|
|
|
|
## Quality gate
|
|
|
|
Before considering a change complete:
|
|
|
|
```sh
|
|
cargo fmt --all
|
|
cargo clippy --all-targets --all-features -- -D warnings
|
|
cargo test --workspace
|
|
cd dashboard && npm run lint && npm run build
|
|
```
|
|
|
|
This exact block is what a plan targeting this repo should use as its runnable
|
|
`Acceptance` (design.md §10.3).
|
|
|
|
**Touching `crates/tireless-data/migrations/` or any SQL also means running the
|
|
database tests**, which the gate above deliberately skips — CI has no Postgres,
|
|
so they are `#[ignore]`d rather than silently passing:
|
|
|
|
```sh
|
|
podman run -d --name pg -e POSTGRES_PASSWORD=test -e POSTGRES_DB=tireless_test \
|
|
-p 55432:5432 docker.io/library/postgres:18-alpine
|
|
export TIRELESS_TEST_DATABASE_URL=postgres://postgres:test@127.0.0.1:55432/tireless_test
|
|
cargo test -p tireless-data -- --ignored
|
|
```
|
|
|
|
Queries are checked at runtime, not compile time — there is no `.sqlx` offline
|
|
metadata and no `DATABASE_URL` needed to build. `store.rs` says why. The
|
|
consequence is that these tests are the only thing standing between a malformed
|
|
query and production.
|
|
|
|
**Never edit an applied migration.** sqlx records a checksum per version, so an
|
|
edit makes every deployed database refuse to start. Add a new numbered file.
|
|
|
|
## Commits
|
|
|
|
Conventional Commits (`type(scope): subject`), imperative, under ~70 chars.
|
|
Commit autonomously when the work is a coherent, complete unit; hold off when
|
|
follow-ups on the same topic are likely. See `generic.md` §12.
|