Commit Graph

3 Commits

Author SHA1 Message Date
rob thijssen
6545d1980b feat(data): add the initial schema and migrations
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
2026-08-07 18:47:16 +03:00
rob thijssen
c49b531bcd feat(config): load and validate configuration in every binary
The invariants in CLAUDE.md were tested functions nobody called. There was no
config type at all: --config was accepted and ignored by all three binaries,
figment was an unused dependency, and the 124-line config.toml.tmpl was
aspirational. assert_not_anthropic could not run at startup because nothing read
the provider it checks.

Add tireless_core::config, validated on construction so a Config in hand is a
checked one, and tireless_agent::preflight, called by the worker at startup and
by `tireless preflight` on demand — the same function, so the two cannot
disagree. Move the Anthropic guard to tireless_core::policy where validate() can
reach it; tireless_agent::opencode re-exports it so the documented path resolves.

Also make /v1/ready honest. It returned "ok" unconditionally while its own doc
comment promised dependency checks, so the deploy probe greened on a process
that could do nothing. It now reports per-dependency state, with unwired ones
saying not_implemented rather than ok.

Tests parse the shipped template rather than a fixture, so template and code
cannot drift apart silently.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013TxK1CWPkFXqdcXMJ4hVe6
2026-08-07 15:36:25 +03:00
rob thijssen
4e42f87576 feat(tireless): scaffold workspace, dashboard and staged design plan
Some checks failed
deploy / build (push) Has been cancelled
deploy / deploy (push) Has been cancelled
Autonomous issue-to-PR driver for Claude Code and OpenCode, structured per
lair/architecture generic.md.

Workspace: entities/core/data/agent library crates plus api, worker and cli
binaries. Two pieces of real logic land with tests — lane routing (cc for
judgement, oc for specification) and the limit governor.

Constraints encoded as code rather than comments:
- agents are spawned as vendor binaries; tireless never calls a provider API
- ANTHROPIC_API_KEY is never set by tireless, only passed through
- assert_not_anthropic refuses to start an OpenCode lane pointed at Anthropic
- every run passes the governor; provider rate-limit signals win over our own
  accounting

Deployment assets target bob.hanzalova.internal:23296 (registered in
port-allocations.md), fronted by hanzalova at tireless.internal.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01DHhHtohxcdk1PL3tfnYJdH
2026-08-02 12:46:42 +03:00