Skip to content
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,11 @@ Add `--read-only` to remove tools that permit local writes or execution. See
[Scalable MCP workflows](docs/mcp-scalable-workflows.md) for the tool sequence,
coverage model, partial-result recovery, and side-effect boundaries.

GitHub users are stored as first-class actors. Live discovery records identity
only; profile, social-account, organization, pinned-item, repository, and
contribution facts are synchronized independently. See the
[actor corpus](docs/actor-corpus.md) for the data and freshness model.

## Side-effect boundaries

GitContribute separates corpus reads, GitHub reads, local writes, process
Expand All @@ -268,6 +273,7 @@ See [Architecture](docs/architecture.md) for the complete boundary definitions.

- [Onboarding and configuration](docs/onboarding.md)
- [Scalable MCP workflows](docs/mcp-scalable-workflows.md)
- [Actor corpus](docs/actor-corpus.md)
- [Architecture and side-effect boundaries](docs/architecture.md)
- [Operational runbooks](docs/runbooks.md)
- [Security policy](SECURITY.md)
Expand Down
64 changes: 64 additions & 0 deletions docs/actor-corpus.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
# Actor corpus

GitContribute treats a GitHub account as an actor with independently acquired
facts. This avoids the common failure mode where a user-search result is
mistaken for a hydrated profile or a missing page is mistaken for an empty
relationship.

## Identity and profile

`actors` stores the current provider identity. Its product key is
`github:node:<node_id>` when GitHub supplies a node ID, otherwise the fallback
is `github:login:<normalized_login>`. `actor_aliases` records every observed
login and points it at the same actor, allowing exact reads by current or old
login. Search results write identity observations only.

`actor_profiles` is the current complete profile projection. GitHub fields
such as name, bio, company, location, website, public email, hireability,
followers, following, public repository count, and public gist count are
nullable. Null means “not present in this observation”; it is not converted to
an empty string, zero, or false. `actor_observations` retains the raw profile or
facet payload with acquisition provenance.

## Independently refreshable facets

| Facet | Projection | Acquisition primitive | Important bounds |
| --- | --- | --- | --- |
| profile | `actor_profiles` | `github.sync_users` | 100 exact users |
| social accounts | `actor_social_accounts` | `github.sync_user_social_accounts` | pages, items/user, total requests |
| organizations | `actor_organization_memberships` | `github.sync_user_organizations` | cursor pages, items/user, total requests |
| pinned items | `actor_pinned_items` | `github.sync_user_pinned_items` | 1–6 items/user |
| repositories | `actor_repository_affiliations` | `github.sync_user_repositories` | explicit owned, affiliated, or contributed relationship |
| contributions | period/day/item/total tables | `github.sync_user_contributions` | explicit RFC 3339 interval of at most one year, optionally scoped by organization node ID |

Repository affiliation is not collapsed into a single boolean. The stored
relationship explains why a repository is associated with an actor. A
contribution item records its source kind, occurrence time, optional
repository, provider target identity and URL, restricted flag, and count.
Restricted activity that GitHub cannot disclose remains an aggregate rather
than a fabricated item. Contribution observations use `viewer` authorization
scope because token-visible restricted and private activity is not a public fact.

## Freshness and replacement

Every facet observation carries `observed_at`, `source_updated_at`,
`authorization_scope`, and `complete`. Current projections use
`(source_updated_at, observation_sequence)` ordering. Complete child snapshots
replace atomically. Paginated or truncated reads are stored as observations
but do not replace a previous complete child set.

Corpus reads never contact GitHub. They return coverage alongside facts so an
agent can decide whether the observation is fresh enough for its task. The
server does not encode a universal freshness threshold: profile discovery,
review cleanup, and historical research have different tolerances.

## Query composition

`corpus.search_actors` filters and sorts profile facts. Exact identities use
`corpus.get_actors`; larger child payloads use actor facet resource URIs.
`corpus.search_contributions` composes actor, repository, kind, source, time,
organization scope, sort, and pagination filters. An empty organization scope
selects global contribution periods; an exact node ID selects that organization's
periods. Cursors bind those filters, so they cannot be
reused against a different query. All query pages bind to a corpus snapshot
token and missing coverage remains unknown.
7 changes: 3 additions & 4 deletions docs/agent-tool-evaluation.md
Original file line number Diff line number Diff line change
Expand Up @@ -86,10 +86,9 @@ contracts include:
- preserving semantic references across concise and detailed responses;
- returning stable, duplicate-free pagination;
- avoiding poll suggestions for terminal jobs.
- comparing `workflow.mine_repository_fix_patterns` with manual
search/select/hydrate loops on a repository where closed PR headers have
unknown merge state; score confirmed merged, closed-unmerged, superseded,
open, and unknown outcomes separately.
- comparing bounded atomic search/select/hydrate loops on a repository where
closed PR headers have unknown merge state; score confirmed merged,
closed-unmerged, superseded, open, and unknown outcomes separately.

Run the focused suite with:

Expand Down
18 changes: 18 additions & 0 deletions docs/architecture.md
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,24 @@ The corpus separates source history from convenient current state:
- **Facet coverage** records whether a facet fetch completed and the source
revision it represents.

GitHub actors are first-class projections rather than denormalized author
strings. A stable provider node ID is the preferred identity; observed logins
are aliases, so a rename does not split one contributor into two profiles.
Profile fields remain nullable because absence may mean undisclosed,
unauthorized, or not acquired. Social accounts, public organizations, pinned
items, repository relationships, and contribution periods are independent
facets with their own observation time, source time, authorization scope, and
completeness. A child table is replaced only after its complete bounded fetch;
an incomplete observation advances coverage without destroying the last
complete projection.

Actor acquisition is deliberately atomic. `github.search_users` stores only
identity observations. Exact `github.sync_users` profile reads and the
`github.sync_user_*` facet tools perform no implicit fan-out into one another.
`corpus.search_actors`, `corpus.get_actors`, `corpus.get_actor_facets`, and
`corpus.search_contributions` are offline and snapshot-bound. See
`docs/actor-corpus.md` for the typed provider-to-SQLite mapping.

An explicit repository-context sync checks a fixed, bounded set of conventional
`CONTRIBUTING.md` and AI-policy paths. Found text is stored as an untrusted
repository-level `contribution_guidance` facet with exact file provenance.
Expand Down
64 changes: 27 additions & 37 deletions docs/mcp-composed-workflows.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,32 +41,31 @@ corpus.get_coverage -> typed exact/repository recovery -> jobs.get
```

Coverage reads are offline and missing coverage is unknown. Synchronization is
always an explicit bounded operation. If `corpus.get_coverage` or
`workflow.prepare_issue_set` returns incomplete coverage, follow its item-level
typed recovery action, preserving exact-thread versus repository scope. Poll
the returned job, perform the offline reread, and reuse its returned
`snapshot_token` for any composed duplicate checks. Use exact resource URIs
only through MCP `resources/read` before attaching receipts or handing evidence
to a draft workflow.
always an explicit bounded operation. If `corpus.get_coverage`, an exact thread
read, or a facet read returns incomplete coverage, follow its item-level typed
recovery action while preserving exact-thread versus repository scope. Poll the
returned job, perform the offline reread, and reuse its returned
`snapshot_token` for composed duplicate checks. Use exact resource URIs only
through MCP `resources/read` before attaching receipts or handing evidence to a
draft workflow.

Canonical MCP composition:

1. Use `workflow.prepare_issue_set` for supplied exact issues. It returns
stored facts, per-thread coverage gaps, related work, merged precedents, and
linkage candidates without network access. When its result is partial,
replay the returned recovery action, poll the job, and retry the same read.
2. For an exact pull request or fields not covered by that aggregate, use
`corpus.get_threads` with `response_format=detailed`.
3. Read repository guidance or a persisted dossier only when the task needs
repository-wide context. Do not treat missing coverage as a negative result.
1. Use `corpus.get_threads` for supplied exact issues or pull requests and
`corpus.get_thread_facets` for selected child coverage.
2. Use `corpus.find_clusters`, `corpus.find_neighbors`, and
`corpus.find_precedents` only for the duplicate or historical evidence the
task needs.
3. Read repository guidance only when the task needs repository-wide context.
Do not treat missing coverage as a negative result.
4. Perform a bounded GitHub sync only when current live state is required or
when returned coverage recovery requests it, wait for its durable job, and
then repeat the relevant offline read.

Decision: **compose**. `workflow.prepare_issue_set` already removes the
error-prone issue fan-out while preserving coverage and provenance. A second
general “research brief” MCP operation would overlap it and the exact-thread
read without demonstrated semantic benefit.
Decision: **compose**. The facts-first catalog removed the aggregate issue-set
operation. Exact reads and bounded duplicate primitives make coverage and
selection visible to the calling agent without granting another workflow tool
authority over the sequence.

## Base and candidate validation comparison

Expand All @@ -88,28 +87,19 @@ loss of comparison semantics that would justify another process-capable tool.
Reconsider only if controlled traces show recurring client mistakes or a
material call/payload reduction that preserves authorization and proof.

## Contribution preflight
## Contribution collision checks

```text
workflow.preflight_contribution
github.search_threads (bounded current work)
github.sync_pull_request_portfolio(selection=authored) -> jobs.get
corpus.search_pull_requests | corpus.find_pull_request_overlaps
workspace.check_merge_conflicts (only after explicit acquisition)
```

Contribution preflight is the narrow exception to the portfolio composition
above. It is a read-only, bounded routing operation for the point before an
opportunity or workspace exists. It resolves the authenticated identity,
searches only the target repository for open authored pull requests, performs
one bounded related issue/PR search, and inspects explicitly supplied local Git
worktree paths without adopting or changing them. The operation returns
`existing_pr` when an authored PR matches a title, branch, commit, or inspected
worktree; it returns `new_work` only when every required live search and local
inspection completed; otherwise it returns `coverage_unknown` with reasons and
the next action needed to retry.

This contract closes the pre-candidate gap without duplicating portfolio
storage or local workflow links. It does not create jobs, write the corpus,
create worktrees, or mutate GitHub. The regression fixtures cover an existing
authored PR with a matching local branch, unavailable identity, and a verified
unrelated candidate.
Decision: **compose**. The catalog no longer exposes a preflight workflow that
decides whether an agent should start work. Agents select the current-work,
portfolio, overlap, or Git comparison facts appropriate to the task. Unknown
discovery or facet coverage prevents a “no competing work” conclusion.

## Unified catalog

Expand Down
Loading
Loading