~bigbes/sr-ht-spec

fe913656 — bigbes 27 days ago
feat(authn): unified-login identity, agent token validation, provenance trailers

Cookie identity is fail-open to anonymous: a missing, tampered or
foreign-key cookie yields no user rather than an error, so anonymous
browsing never breaks on a bad cookie.

Agent tokens are the opposite. A bad bearer is a permanent 401, a store
outage a transient 503, and revoked rows are returned so operators can
distinguish a killed token from one that never existed.

TokenStore is declared here rather than imported from db/, so the two
packages can be built in parallel and service/ wires them together.
ba61af74 — bigbes 27 days ago
docs: correct the core-go dependency pin

The doc repeated dolt.sr.ht's README claim that core-go is wired via a
replace directive to the instance fork. Neither sibling's go.mod contains
one; both require sourcecraft.dev/bigbes/sr-ht-core directly at
dd418a200152, which is the module path the fork declares from that commit
onward. A replace against the older c2c2f38 is rejected outright, since
its go.mod still declared git.sr.ht/~sircmpwn/core-go.
33a3deaf — Eugene Blikh 27 days ago
feat: foundation — go.mod with every dependency, and the core/ domain

Phase 1 foundation commit. Two things, so that later parallel waves write
disjoint directories and never touch go.mod:

  - go.mod / go.sum carrying every external dependency the whole module will
    need (go-git, bleve, goldmark, chi, lib/pq, yaml.v3, the MCP SDK, brant,
    auxilia, testify, and the sr-ht-core fork). Populated by building a
    throwaway blank-import file, which is then deleted; `go mod tidy` runs
    once, at the very end of the build-out.
  - core/, the pure domain: owner/space names, safe relative paths, the
    globally-unique document ID grammar, frontmatter parsing and schema
    validation, `.spec.yml` policy with auto_merge glob matching, and the
    proposal state machine. Standard library plus yaml.v3, nothing else.

Two design invariants are enforced here rather than documented and hoped for:
"approved" is not a status (it is a property of the branch a document is
reachable from), and the proposal machine has exactly open/merged/rejected.
A per-space `.spec.yml` cannot reintroduce either.

Note on the sr-ht-core pin: the design calls for a `replace` onto
git.srht.bigb.es/~bigbes/core-go at c2c2f38, but that commit's go.mod still
declares `module git.sr.ht/~sircmpwn/core-go`, so Go rejects the replacement.
Both siblings pin the later dd418a20 under the canonical path with no
replace; this does the same.
a7336236 — bigbes 27 days ago
docs: add repo layout, schema, implementation plan and verification

Extends the design with the sections the sibling services carry: package
tree with a strict downward dependency rule, the Postgres schema, a
wave-based implementation plan, an end-to-end verification checklist and
the open risks.

Work is dispatched per the parallel-implementer convention: foundation
commit carries every external dependency and the core package, then
siblings importing it write disjoint directories in parallel. Phase 0
runs the prose-diff spike first because it is the assumption with no
fallback.

Projects and comments are deliberately absent from the schema: a project
is a saved filter that is speculative before there are spaces to filter,
and comment anchoring should be settled against a built review UI rather
than committed to a schema first.
12e043e2 — bigbes 27 days ago
docs: settle the seven questions raised by review

- Read contract keeps pinned ?rev= and the approved/draft split. The
  review UI needs blob->render at arbitrary revs regardless, so pinning is
  nearly free and makes X-Agent-Base auditable.
- Materialized checkout dropped. One read path over git objects for
  approved head, pinned revs and proposal branches alike, which removes
  atomic swap, rev stamps, a cache directory and two crash-repair rows.
  Cost is bounded: vault.Scan touches the filesystem twice and
  vault.FromPages already accepts pre-loaded pages.
- Volume is tens of documents a day, so warren's batch index rebuild is
  absorbed unchanged and incremental indexing is explicitly not built.
- One agent token plus mandatory provenance. The refs rule is the boundary
  that bounds damage; per-space scoping defers to a column and a filter.
- Human pushes are validated too, with a skip-validation push option. The
  risk is a typo corrupting the global ID registry, not malice.
- External corpora left unspecified; global IDs are the only forward
  compatibility needed.
- Name confirmed as spec.sr.ht.
f0dcfb4d — bigbes 27 days ago
docs: confirm browser review, and make the link the entry point

Review happens in a browser, so the prose differ stays in v1 and remains
the Phase 0 gate.

The link, not the inbox, is the normal way in: you are usually already
talking to an agent when it proposes, so every write response must carry
the proposal URL for the agent to surface. Proposal URLs are stable past
merge or rejection. The inbox demotes to a backstop for unattended work,
sharing a page with the policy-merged digest, which is invisible for the
same reason.
1e7e4b1e — bigbes 27 days ago
docs: correct errors found by independent review

Two claims were plainly wrong and load-bearing:

- post-receive cannot reject a push; its exit status is ignored once refs
  have moved. Validation and the refs rule move to the update hook. The
  hooks are also not 'zero service code': bleve is single-writer and the
  daemon holds the index, so both hooks RPC into the daemon, and push
  fails closed when it is unreachable.
- hut builds endpoints from per-service origins, never from api.sr.ht, so
  federation buys it nothing and 'one endpoint, one token' is hollow. The
  decision is now a read schema at our own /query; federation is a free
  config line rather than a motivation.

Also resolves an internal contradiction: the doc argued for a single
shared index and then specified one bleve index per project. Now one
global index with projects as query-time filters, and globally unique
document IDs, which removes the per-project collision hole.

Further corrections: merge staleness keyed by document ID rather than
path, deletion and rename made human-push-only, approval expressed as a
property of the branch rather than frontmatter, the proposal state machine
collapsed to open/merged/rejected for a single reviewer, If-Match pinned
to the approved head, and a new consistency section covering crash repair,
the reconciler, per-space mutexes and unix ownership.

Records warren's index as a batch full rebuild rather than incremental,
and the eight questions from review that still need answers.
fc499243 — bigbes 27 days ago
docs: fold in scope, audience, cadence and edit-path decisions

Four confirmed answers reshape the design rather than just the backlog:

- Agent-authored specs only. Read-only mounts leave v1; the meta-project
  now unifies owned spaces. The store is a fresh silo, so it is empty
  until filled, which reorders the phases.
- Single-user. Visibility levels, approver lists, approval counts and
  request-changes cycles drop. Authorization relocates rather than
  disappearing: it is about scoping agents, not separating humans.
- Bimodal cadence. Records approval as human or policy so auto-merged
  notes are not laundered as reviewed, and adds a digest so the firehose
  half stays visible.
- Human edits via clone and push. Adds the git remote as a v1 requirement
  and drops the web editor. Humans push to the approved branch, agents may
  only write proposals/*; SSH plus a post-receive hook needs no service
  code and validates every write path.

Also records mixed ru/en search analyzers as an unresolved question that
determines whether search is usable at all.
72f58940 — bigbes 27 days ago
docs: federate the read side into api.sr.ht from Phase 2

Reverses the earlier no-federation call. The deciding arguments are one
endpoint plus one meta PAT for agents already querying git/todo/builds,
hut ergonomics, and core-go/webhooks being GraphQL-native so Phase 5
pulls gqlgen in regardless. The dolt precedent does not generalize: its
API is a chunk-store protocol, whereas documents and proposals are an
ordinary CRUD graph.

Mutations stay on REST + MCP. If-Match optimistic concurrency is an HTTP
idiom with well-defined 409 semantics, and a federated type is a consumed
contract, so the unsettled proposal types stay out of the gateway.

Also records that federation is not cross-service search: thistle merges
schemas and routes fields, so the meta-project still needs our own index.
c945f382 — bigbes 27 days ago
docs: add SourceHut integration section to the spec.sr.ht design

Records the config-driven wiring (Recipe B: pure Go, chrome copied from
compare.sr.ht), the canonical [spec.sr.ht] keys, and the shared keys read
in place.

Documents why skipping GraphQL federation is safe: api.sr.ht federates
every .sr.ht config section with no allow-list, but updateSchema skips
services that fail to serve /query, and the refresh is SIGHUP-driven
rather than a ticker.
be096fc6 — bigbes 27 days ago
docs: design proposal for spec.sr.ht

Reviewable document storage for the self-hosted SourceHut instance: bots
propose, humans review and curate, bots consume the approved text.

Records the four confirmed decisions (proposal-first review gate, own bare
git repos, absorb warren's read plane, thin full-loop v1) and the projects
model that gives cross-space unified search.