INB-33: provision second self-hosted Gitea Actions runner #2

Closed
Ghost wants to merge 4 commits from inb-33-gitea-runner-2 into main

Summary

Adds a second self-hosted Gitea Actions runner (inboxos-runner-2) with the same label set as inboxos-runner-1 so the live-pipeline cron and historical-pipeline workflow_dispatch can run in parallel on the same host. Removes the single-runner contention that was leaving historical runs queued indefinitely while the every-5-min live pipeline was in flight.

Changes

  • docker/docker-compose.yml - new gitea-runner-2 service + gitea-runner-2-data named volume; mirrors gitea-runner configuration.
  • .env.example - new GITEA_RUNNER_REGISTRATION_TOKEN_2 placeholder.
  • docs/gitea-actions.md - new section 2a registration walkthrough, updated topology + rollback table.
  • pipelines/README.md - operational note that two runners are registered.
  • No workflow files changed; workflows continue to target ubuntu-latest/self-hosted, Gitea load-balances.

Deploy steps (post-merge, on host)

  1. Gitea Site Admin -> Actions -> Runners -> Create new runner; copy token.
  2. Append GITEA_RUNNER_REGISTRATION_TOKEN_2= to .env on the host.
  3. docker compose -f docker/docker-compose.yml up -d gitea-runner-2
  4. Verify two online runners via the runners API.
  5. Dispatch historical-pipeline.yml while live cron is in flight; expect ~30s start.

Resolves INB-33. Unblocks INB-7.

## Summary Adds a second self-hosted Gitea Actions runner (inboxos-runner-2) with the same label set as inboxos-runner-1 so the live-pipeline cron and historical-pipeline workflow_dispatch can run in parallel on the same host. Removes the single-runner contention that was leaving historical runs queued indefinitely while the every-5-min live pipeline was in flight. ## Changes - docker/docker-compose.yml - new gitea-runner-2 service + gitea-runner-2-data named volume; mirrors gitea-runner configuration. - .env.example - new GITEA_RUNNER_REGISTRATION_TOKEN_2 placeholder. - docs/gitea-actions.md - new section 2a registration walkthrough, updated topology + rollback table. - pipelines/README.md - operational note that two runners are registered. - No workflow files changed; workflows continue to target ubuntu-latest/self-hosted, Gitea load-balances. ## Deploy steps (post-merge, on host) 1. Gitea Site Admin -> Actions -> Runners -> Create new runner; copy token. 2. Append GITEA_RUNNER_REGISTRATION_TOKEN_2=<token> to .env on the host. 3. docker compose -f docker/docker-compose.yml up -d gitea-runner-2 4. Verify two online runners via the runners API. 5. Dispatch historical-pipeline.yml while live cron is in flight; expect ~30s start. Resolves INB-33. Unblocks INB-7.
Ghost added 2 commits 2026-06-08 01:12:04 +00:00
inb-21: drop model-escalation chain; pin single gemma4:e4b model; add PR CI
InboxOS — PR CI / Fast offline tests (pull_request) Successful in 28s
InboxOS — PR CI / 100MB historical e2e (pull_request) Failing after 15s
InboxOS — PR CI / Live Ollama extract smoke (pull_request) Successful in 51s
3eba1acd66
INB-21 board decision: the pipeline makes a single LLM call per
step, with the model pinned via INBOXOS_LLM_MODEL /
INBOXOS_LLM_MODEL_EXTRACT (default gemma4:e4b for both). There is
no model-escalation chain. Transient HTTP / JSON failures are
retried by tenacity in llm_run_command (3 attempts, exponential
backoff); a permanent failure dead-letters the message and the
next scheduled run retries from the same checkpoint.

Changes
-------
* pipelines/common.py
  - LLMConfig: drop model_chain field and the
    INBOXOS_LLM_MODEL_CHAIN env-var loader; drop
    model_chain_for_command.
  - Drop ollama_run_command_with_chain and llm_run_command_with_chain.
  - Update docstring to spell out the single-model contract and
    the retry policy.

* pipelines/historical_pipeline.py
  - classify() and extract_for_module() now call llm_run_command
    directly (no chain).
  - main() summary log no longer includes the chain field.

* pipelines/live_pipeline.py
  - extract_for_module() now calls llm_run_command directly.
  - Drop the now-unused llm_run_command_with_chain import.

* .gitea/workflows/{live,historical}-pipeline.yml
  - Drop INBOXOS_LLM_MODEL_CHAIN from the env block.
  - Refresh the header comments to describe the single-model
    contract.

* pipelines/_tests/smoke_inb21_extract.py
  - Now asserts the model is gemma4:e4b (the INB-21 default),
    not the previous lfm2.5:8b / gemma4:12b split.
  - Calls llm_run_command directly (no chain wrapper).

* pipelines/_tests/test_live_pipeline_offline.py
  - Default cfg now uses gemma4:e4b for both classify and
    extract; the per-step routing test asserts the new defaults.
  - Drop the fake_chain install in _install_fakes; drop the
    lp.llm_run_command_with_chain patch.

* pipelines/_tests/test_historical_pipeline_offline.py
  - Drop test_process_escalation_recovers_on_second_model (chain
    is gone).
  - _install_fakes now patches llm_run_command instead of
    llm_run_command_with_chain; the 100MB e2e uses the same
    single-model fake.

* .gitea/workflows/ci-pr.yml (new)
  - PR-only gate. Three jobs: fast-tests (gitea_request,
    mbox_stream, live_pipeline_offline, historical fast subset),
    e2e-100mb (the slow historical end-to-end against a
    synthetic 100MB mbox), and live-llm-smoke (real Ollama
    against the Substack input from run #674). Triggers on
    pull_request targeting main + workflow_dispatch for manual
    reruns. live-llm-smoke is no-op when OLLAMA_BASE_URL is
    unset so fork PRs without infra access stay unblocked.

Operational contract (per CEO directive, 2026-06-07)
----------------------------------------------------
Run fast tests locally, commit, push, open a PR, wait for the
ci-pr workflow to go green, then merge. The 100MB e2e and live
Ollama smoke no longer run on a developer workstation.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
inb-33: add gitea-runner-2 for live+historical parallelism
InboxOS — PR CI / Fast offline tests (pull_request) Successful in 29s
InboxOS — PR CI / 100MB historical e2e (pull_request) Failing after 15s
InboxOS — PR CI / Live Ollama extract smoke (pull_request) Successful in 42s
2395571843
Adds a second self-hosted Gitea Actions runner (inboxos-runner-2)
to docker/docker-compose.yml with the same label set
(self-hosted,linux,x64,gitea-runner:docker) so the live-pipeline
cron and historical-pipeline workflow_dispatch can execute in
parallel on the same host. Removes the single-runner contention
that was leaving historical runs queued indefinitely while the
5-minute live pipeline was in progress.

- docker/docker-compose.yml: new gitea-runner-2 service + named
  volume gitea-runner-2-data; mirrors gitea-runner config.
- .env.example: new GITEA_RUNNER_REGISTRATION_TOKEN_2 placeholder.
- docs/gitea-actions.md: §2a registration steps, updated topology
  diagram, updated rollback table.
- pipelines/README.md: operational note that two runners are
  registered.

No workflow files changed: workflows continue to target
ubuntu-latest/self-hosted; Gitea load-balances between the two
runners.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
Ghost added 2 commits 2026-06-08 02:33:45 +00:00
Lifts the historical Papra attachment uploader into common.py and adds
a pure policy function + dry-run gate, so the live and historical
pipelines can audit Papra write decisions on real traffic before the
first real write goes out.

- common.py: PapraConfig, PapraTarget, PapraDecision, papra_decide,
  papra_write_attachment, papra_write_body, content-hash and HTML-strip
  helpers. Dry-run defaults to True; honors PAPRA_DRY_RUN env. Pure
  decide() is unit-testable without HTTP. Write helpers never raise;
  failures are logged as papra_write_failed.
- live_pipeline.py: wires papra_decide + papra_write_* into
  process_one_message after the NocoDB UPSERTs. Emits papra_decision
  per message even on the skip path.
- historical_pipeline.py: replaces inline upload_attachments_to_papra
  with the shared helper, keeps attachment behavior intact, and adds
  the post-classification body-write pass.
- .gitea/workflows/{live,historical}-pipeline.yml: export
  PAPRA_BASE_URL / API_TOKEN / ORG_ID / DRY_RUN (default 'true') and
  the body-write / metadata-only module lists.
- tests: 13/13 new test_papra_decide_offline.py + 14/14
  test_live_pipeline_offline.py + 7/7 per-message historical tests
  (the unchanged-shape 100MB e2e test is not re-run this commit).
- docs/papra-write-policy.md: policy, env vars, dry-run flag, audit
  recipe, future papra_index note.

No real Papra HTTP request is made during the dry-run smoke.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
inb-35: add operations runbook and top-level README
InboxOS — PR CI / Fast offline tests (pull_request) Successful in 28s
InboxOS — PR CI / 100MB historical e2e (pull_request) Failing after 15s
InboxOS — PR CI / Live Ollama extract smoke (pull_request) Successful in 42s
985b67a361
- docs/operations-runbook.md: 8-section runbook (system overview,
  service inventory, workflow ops, observability, failure modes,
  security, cost, glossary) so a new operator can recover from
  common failures without re-deriving the architecture.
- README.md: top-level entry point that links to the runbook as
  the day-1 incident-response reference.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
Ghost closed this pull request 2026-06-08 07:26:20 +00:00
Some checks are pending
InboxOS — PR CI / Fast offline tests (pull_request) Successful in 28s
InboxOS — PR CI / 100MB historical e2e (pull_request) Failing after 15s
InboxOS — PR CI / Live Ollama extract smoke (pull_request) Successful in 42s

Pull request closed

Sign in to join this conversation.
No Reviewers
No Label
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: coreci/inboxos-v1#2