Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 7 additions & 4 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ Python ≥3.12, uv, pytest, ruff. `ty` is available as a **non-gating** type che
uv run --no-project --with 'google-cloud-storage>=2,<4' python scripts/sync_wheelhouse.py
```

Auth is ADC: on the VM the SA key at `GOOGLE_APPLICATION_CREDENTIALS` (`/etc/replicator/co-pypi-reader.json`), in CI a keyless WIF token. Pin the current minor — `>=0.7.7,<0.8`. The **patch** floor is load-bearing, not tidiness: the change-bus payloads are `extra="ignore"`, so on an older wheel a model constructed with fields it does not have yet succeeds and silently discards them. Raise the floor with every co-core feature the code starts depending on, or a version skew publishes facts that look right and carry nothing (#10). The 0.7.7 floor is the exception that fails *loudly* — `AsyncBusTailReader` and `FetchPolicyState` do not exist below it, so a skew is an ImportError rather than a silent discard (#19).
Auth is ADC: on the VM the SA key at `GOOGLE_APPLICATION_CREDENTIALS` (`/etc/replicator/co-pypi-reader.json`), in CI a keyless WIF token. Pin the current minor — `>=0.8.0,<0.9`. The **patch** floor is load-bearing, not tidiness: the change-bus payloads are `extra="ignore"`, so on an older wheel a model constructed with fields it does not have yet succeeds and silently discards them. Raise the floor with every co-core feature the code starts depending on, or a version skew publishes facts that look right and carry nothing (#10). The 0.8.0 floor fails *loudly* instead: `info_source_id` is required on all three payloads, so a skew is a ValidationError at construction rather than a silent discard (#19, #28).

<!-- BEGIN socraticode-policy -->
## Code Exploration Policy
Expand Down Expand Up @@ -115,9 +115,12 @@ Every variable the service reads, with the reasoning behind each default:

Replicator is a **consumer** first. Follow the conventions co-core and the archiver producer established:

- **At-least-once ⇒ idempotent.** The command dedupes on `command_id`, the fact on
`content_fingerprint`, and `fetch_failed` on neither — storage identity and
correlation identity are not interchangeable.
- **At-least-once ⇒ idempotent.** The command dedupes on `command_id`; both facts
are keyed per *occurrence* (`content_fingerprint:command_id`,
`command_id:occurred_at`), so nothing an issuer waits on can collapse — storage
identity and correlation identity are not interchangeable. `info_source_id`
rides both and is **echoed, never read**: the `tests/test_boundaries.py`
carve-out is one field wide, and widening it edits the charter (#28).
- **Store, then publish — never the reverse.** A fact pointing at bytes that are
not there is unrepairable by the consumer; stored bytes with no fact repair
themselves on the reclaim.
Expand Down
11 changes: 6 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,9 @@ The founding design lives in
first — it is the normative issuer contract and its permanent home, with the refusal list, failure
taxonomy and trust posture in its companion
[`content-fetch-issuer-reference.md`](docs/contracts/content-fetch-issuer-reference.md).
Publish through co-core's `to_wire`, never hand-rolled fields; and because the wire carries no
domain identity, correlation is entirely the issuer's job. Most ways of getting either wrong fail
silently.
Publish through co-core's `to_wire`, never hand-rolled fields. The wire carries one domain key —
`info_source_id`, echoed onto both facts and read by nothing here — but correlation is still
entirely the issuer's job, on `command_id`. Most ways of getting either wrong fail silently.

## Shape

Expand Down Expand Up @@ -107,14 +107,15 @@ see [docs/DEPLOYMENT.md](docs/DEPLOYMENT.md) for what each one is and why.
Nothing in the cluster issues `content.fetch` commands until the Watcher cutover, so
`scripts/seed_fetch.py` is the issuer. The target is never defaulted — `--redis-url` and
`--topic` are both required, and db 0 + `content.fetch` (the one pair the running worker
consumes, and therefore actually fetches over the network) additionally needs `--production`:
consumes, and therefore actually fetches over the network) additionally needs `--production`
**and** a real `--info-source-id`, since the facts it publishes echo that value cluster-wide:

```bash
# Fetches the local /health app — a target we control, so the smoke test costs
# nobody else a request. Start it first (see Dev server below).
uv run python -m scripts.seed_fetch \
--redis-url redis://localhost:6379/0 --topic content.fetch \
--production --watch http://localhost:8041/health
--production --info-source-id isrc-01J9ZK7Q --watch http://localhost:8041/health
```

`--watch` tails the fact stream until each command has an outcome — a `blob_available`, or a
Expand Down
Loading
Loading