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
12 changes: 12 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,18 @@ The dashboard's **What's New** rail reads this file at request time
entries. Keep entries terse — one line per item under each version
date, grouped by `Added` / `Changed` / `Fixed` / `Removed`.

## [2026-07-16] — v0.27.1 · Truthful delivery evidence

### Changed

- **Delivery identity separates the agent from its operator.** Compact and expanded cards distinguish execution identity, invocation, connector, runtime, and human ownership while explaining connection confidence on hover or keyboard focus.
- **Issue evidence and activity stay compact without hiding history.** Delivery and GitHub disclosures share a clear interaction pattern, repeated adjacent activity is grouped, and operators can expand capped history on demand.

### Fixed

- **GitHub and completion state remain internally consistent.** Native implementation, closing, related, and release-containment relations render distinctly; merged pull requests no longer retain pending or unknown merge metadata.
- **Compact GitHub references link as one unit.** Shared Markdown surfaces recognize `owner/repository#number` before Forge issue keys instead of splitting hyphenated owners at the slash.

## [2026-07-16] — v0.27.0 · Personal work and canonical delivery

### Added
Expand Down
81 changes: 81 additions & 0 deletions DEVLOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,54 @@

> Append-only session log. Read at session start. Update at session end.

## 2026-07-16 — Truthful Delivery provenance and GitHub relations

AXI-117 audited production Ready to Close, Delivery, and native GitHub cards,
then separated actor, invocation, connector, runtime, implementation PR, and
release-containment facts. Browser claims now persist as manual UI actions and
MCP claims persist as Forge MCP; connector identity comes only from the MCP
initialize `clientInfo`, while runtime attribution requires an output-producing
managed run. Compact Delivery cards expose the full evidence on demand without
guessing Codex Desktop or a runtime from agent identity.

GitHub webhook matching now derives one native relation per issue/resource:
`IMPLEMENTS`, `FIXES`, `RELEASES`, or `RELATES_TO`. The migration reclassifies
release assembly PRs, removes legacy duplicate relations deterministically, and
enforces the singular relation invariant. Generic URL recovery and repository
identity canonicalization preserve a stronger existing relation, while explicit
relinks remain operator-controlled. Imported `SOURCE` identity is preserved
ahead of derived PR relations so later imports cannot duplicate the Forge issue;
explicit downgrades dismiss stale Ready-to-Close requests when no implementation
PR remains. Grouped references such as `Fixes AXI-1, AXI-2` retain the keyword
across the full clause. Duplicate-resource canonicalization also preserves
`SOURCE`, while imported source PRs retain their mapped status synchronization.
Both service canonicalization and migration-time release reclassification
dismiss stale completion requests when they remove the last implementation
relation, with migration cleanup ordered after legacy relation dedupe. Bare URLs
are consumed before compact GitHub and issue-reference tokens so paths containing
`CODENAME-11/Forge#56` or `AXI-123` remain fully clickable. Imported `SOURCE`
PRs participate in failed-check status rules while related/release links do not.
Terminal PR synchronization clears
stale mergeability and suppresses pending-check contradictions, while merged
implementation evidence continues reconciliation until its final checks
aggregate is trusted and still participates in completion readiness. Passing
completion evidence and READY state now use the semantic success token.
PR lifecycle and failed-check status automation is limited to implementation
relations, so related mentions and release-containment links remain contextual.

Verification passed lint (existing warnings only), typecheck, a production
Next build, 1,399 Vitest tests with one intentional skip, focused relation and
provenance coverage, and the AXI-117 Playwright issue journey. The full
single-worker browser run passed 51 journeys before Chromium exited while
opening an unrelated Mission Control context; both affected Mission Control
tests passed immediately in isolation, covering all 53 journeys.

Release review follow-up applied all 119 migrations to a clean isolated local
Postgres database and passed nine focused relation/persistence regressions,
including SOURCE preservation, grouped relation derivation, and audited stale
completion-request dismissal. The production-snapshot development database was
not used for migration or test execution.

## 2026-07-16 — v0.26.1 released, deployed, and verified

Merged release PR #60 and tagged exact `main` commit
Expand Down Expand Up @@ -13755,3 +13803,36 @@ activity provenance.

The immutable tag will be cut only from the merged release commit, then
deployed through the clean-checkout production path and verified live.

---

## 2026-07-16 — Delivery agent and operator identity

Refined the issue Delivery card so execution identity and human ownership are
not collapsed into one ambiguous Actor label. Registered agents now remain the
primary identity with their operator shown as supporting context. Manual work
shows the operator explicitly, while legacy Codex Desktop, MCP, dispatch, and
scheduled sessions without a registered agent connection are labeled as
unverified instead of being falsely attributed to the credential owner.

Expanded Delivery evidence now lists Agent and Operator independently alongside
invocation, connector, and runtime facts. The agent transport documentation and
the issue-flow Playwright contract were updated to preserve the distinction.
Connection state now uses a semantic status badge with a hover/focus explanation,
and the evidence disclosure uses a bordered control and rotating chevron so its
interactivity is visible without adding density to the collapsed card.
GitHub PR state now follows the same semantic badge and explanatory tooltip
pattern, while GitHub evidence uses the same recognizable disclosure control.
The issue claim card now separates owner identity, active state, expiry, and the
release action into a clearer compact hierarchy.
The issue Activity rail now groups only adjacent equivalent events, preserving
audit order while reducing repeated metadata noise. It shows eight recent
groups by default and provides an explicit event-counted show-more/show-less
control for the remaining history.
The shared Markdown renderer now recognizes compact GitHub
`owner/repository#number` references before Forge issue keys, preventing
hyphenated owners from becoming partial links in issue comments, Command
Center decisions, and every other shared rich-text surface.
Prepared the reviewed change as patch release `v0.27.1`; the immutable tag is
cut only after the release-ready commit lands on `main` with all required CI
checks green.
8 changes: 6 additions & 2 deletions docs/agents/providers-and-transports.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,9 @@ There are two independent axes:
runtime) or **Streaming/Completions** (Forge). Orthogonal to tier; see
[Chat & Dispatch Engines](./engines.md).

There are also four deliberately separate identities in the execution record:
There are also five deliberately separate identities in the execution record:

- **Operator** — the human who owns or manages the delivery lease or credential.
- **Agent profile / binding** — who is acting and what it may do in the
workspace.
- **Agent connection** — the concrete managed runtime, MCP client, webhook, or
Expand All @@ -24,7 +25,10 @@ There are also four deliberately separate identities in the execution record:

An API key authenticates a caller; it is not the execution identity. Forge
snapshots the connection on runs and work sessions so key rotation or later
profile relinking cannot rewrite historical attribution.
profile relinking cannot rewrite historical attribution. Delivery surfaces
therefore show Agent and Operator separately; legacy clients without a
registered agent connection are labeled unverified instead of attributing the
agent's work to the credential owner.

## Connection-aware liveness

Expand Down
33 changes: 22 additions & 11 deletions docs/engineering/work-management.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,21 +29,28 @@ connection is primary; additional connections must explicitly join as a
contributor or reviewer, or receive an audited handoff before changing the
branch or advancing delivery state.

Delivery provenance records separate facts: actor/profile, invocation source,
connector/transport, and execution runtime. MCP client identity comes from the
negotiated MCP `clientInfo`; missing identity is displayed as an unidentified
client rather than guessed as Codex Desktop or CLI. A runtime is shown only
when an output-producing `AgentRun` carries both a runtime connection and an
external run id. Direct MCP or UI work does not imply runtime execution.

## Project branch contract

Branch topology is project configuration, not an Axiom-wide constant. Every
maintained repository declares these seven facts in `AGENTS.md` or
`RELEASE.md`:

| Fact | Meaning |
| --- | --- |
| Integration branch | Normal feature/fix PR target |
| Release branch | Durable released-code history |
| Tag source | Branch/commit from which immutable release tags are cut |
| Staging source | Exact branch SHA or tag deployed to staging |
| Production source | Exact tag/SHA accepted by production |
| Hotfix base | Ref used to begin an emergency fix |
| Back-merge target | Branches that must receive the hotfix afterward |
| Fact | Meaning |
| ------------------ | ------------------------------------------------------- |
| Integration branch | Normal feature/fix PR target |
| Release branch | Durable released-code history |
| Tag source | Branch/commit from which immutable release tags are cut |
| Staging source | Exact branch SHA or tag deployed to staging |
| Production source | Exact tag/SHA accepted by production |
| Hotfix base | Ref used to begin an emergency fix |
| Back-merge target | Branches that must receive the hotfix afterward |

Supported shapes include trunk-based (`feature → main → tag`), an integration
train (`feature → dev → release PR → main → tag`), upstream-tracking forks, and
Expand All @@ -57,10 +64,14 @@ integration, scheduled stabilization, or an upstream convention.
- Refresh the work-session heartbeat at meaningful phase changes and after
commits. Mechanical tool traces do not replace a heartbeat or semantic status.
- Push early and open a PR early when overlap is likely.
- Link implementation PRs with Forge's native GitHub relation and kind
`IMPLEMENTS`; never use a generic link attachment for a PR.
- Link implementation PRs with Forge's native GitHub relation: `IMPLEMENTS`
for delivered behavior or `FIXES` for closing/fixing semantics. Bare issue
references are `RELATES_TO`; release assembly PRs use `RELEASES` to mean the
release contains the implementation. Never use a generic link attachment.
- GitHub owns PR state, reviews, checks, mergeability, and merge state. Forge
mirrors those facts into the delivery lifecycle.
- One issue/resource pair has one native relation. Re-linking reclassifies the
relation instead of duplicating status cards.
- Resolve file overlap in the PR. Do not move uncommitted patches between
worktrees or share one worktree between tasks.
- If dispatch discovers an existing primary connection, block a second execute
Expand Down
19 changes: 11 additions & 8 deletions docs/plans/github-support-integration.md
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ model ExternalResourceLink {
workspaceId String
issueId String
externalResourceId String
kind String // SOURCE | IMPLEMENTS | REVIEWS | RELATES_TO
kind String // SOURCE | IMPLEMENTS | FIXES | RELEASES | REVIEWS | RELATES_TO
createdById String?
createdAt DateTime @default(now())

Expand All @@ -154,6 +154,9 @@ Link semantics:

- `SOURCE` - Forge issue was created from this GitHub issue.
- `IMPLEMENTS` - PR is intended to resolve or implement the Forge issue.
- `FIXES` - PR uses explicit fix/close/resolve semantics for the Forge issue.
- `RELEASES` - release assembly PR contains an already-separate implementation.
- `RELATES_TO` - contextual reference without implementation semantics.
- `REVIEWS` - PR/review context requires attention for the Forge issue.
- `RELATES_TO` - soft context link.

Expand Down Expand Up @@ -354,14 +357,14 @@ subscription category.

Expose the same core operator/agent actions through `github.*` MCP tools:

| Tool | Scope | Notes |
| --- | --- | --- |
| `github.parseUrl` | `READ_ISSUES` | Normalize a GitHub URL into repo/type/number. |
| `github.listLinked` | `READ_ISSUES` | Return linked resources for a Forge issue. |
| `github.link` | `WRITE_ISSUES` | Link issue/PR URL to a Forge issue with a relation kind. |
| Tool | Scope | Notes |
| -------------------- | -------------- | ------------------------------------------------------------- |
| `github.parseUrl` | `READ_ISSUES` | Normalize a GitHub URL into repo/type/number. |
| `github.listLinked` | `READ_ISSUES` | Return linked resources for a Forge issue. |
| `github.link` | `WRITE_ISSUES` | Link issue/PR URL to a Forge issue with a relation kind. |
| `github.importIssue` | `WRITE_ISSUES` | Create or return the Forge issue sourced from a GitHub issue. |
| `github.sync` | `WRITE_ISSUES` | Refresh one linked resource and apply mapping policy. |
| `github.search` | `READ_ISSUES` | Search mapped repo issues/PRs for linking/import. |
| `github.sync` | `WRITE_ISSUES` | Refresh one linked resource and apply mapping policy. |
| `github.search` | `READ_ISSUES` | Search mapped repo issues/PRs for linking/import. |

Add linked GitHub resources to `agent.context.bundle({ issueId })`:

Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "forge",
"version": "0.27.0",
"version": "0.27.1",
"private": true,
"description": "Forge — a fast, minimalist, keyboard-driven project management platform with pluggable agents.",
"license": "MIT",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
-- AXI-117: make GitHub relations singular/truthful and expand delivery source
-- vocabulary without conflating invocation, transport, and runtime.

ALTER TYPE "WorkSessionSource" ADD VALUE IF NOT EXISTS 'MCP';
ALTER TYPE "WorkSessionSource" ADD VALUE IF NOT EXISTS 'NATIVE_SESSION';
ALTER TYPE "WorkSessionSource" ADD VALUE IF NOT EXISTS 'ISSUE_DISPATCH';
ALTER TYPE "WorkSessionSource" ADD VALUE IF NOT EXISTS 'SCHEDULED';

-- Release assembly PRs are containment evidence, not implementation PRs.
UPDATE "ExternalResourceLink" link
SET "kind" = 'RELEASES'
Comment thread
Codename-11 marked this conversation as resolved.
FROM "ExternalResource" resource
WHERE link."externalResourceId" = resource."id"
AND link."kind" = 'IMPLEMENTS'
AND resource."resourceType" = 'PULL_REQUEST'
AND (
resource."title" ~* '^\s*release\s+v?[0-9]'
OR COALESCE(resource."metadata" #>> '{head,ref}', '') ~* '(^|/)release([-\/]|$)'
);

-- Older rows could carry multiple semantic kinds for the same issue/resource.
-- Keep one deterministic relation before enforcing the native invariant.
WITH ranked AS (
SELECT "id",
ROW_NUMBER() OVER (
PARTITION BY "issueId", "externalResourceId"
ORDER BY
CASE "kind"
-- SOURCE is the durable identity used to de-duplicate imported
-- GitHub issues/PRs. Derived relations must not erase it.
WHEN 'SOURCE' THEN 0
WHEN 'FIXES' THEN 1
WHEN 'IMPLEMENTS' THEN 2
WHEN 'RELEASES' THEN 3
WHEN 'REVIEWS' THEN 4
ELSE 5
END,
"createdAt" ASC,
"id" ASC
) AS rn
FROM "ExternalResourceLink"
)
DELETE FROM "ExternalResourceLink" link
USING ranked
WHERE link."id" = ranked."id" AND ranked.rn > 1;

-- Reclassification and dedupe can both remove the last implementation link.
-- Any completion request left without implementation PR evidence is stale.
UPDATE "ActionRequest" request
SET
"status" = 'DISMISSED',
"resolvedAt" = NOW(),
"resolution" = 'No linked pull request remains as implementation evidence.'
WHERE request."status" = 'OPEN'
AND request."sourceType" = 'completion-candidate'
AND request."issueId" IS NOT NULL
AND NOT EXISTS (
SELECT 1
FROM "ExternalResourceLink" implementation_link
JOIN "ExternalResource" implementation_resource
ON implementation_resource."id" = implementation_link."externalResourceId"
WHERE implementation_link."issueId" = request."issueId"
AND implementation_link."kind" IN ('IMPLEMENTS', 'FIXES')
AND implementation_resource."resourceType" = 'PULL_REQUEST'
);

DROP INDEX "ExternalResourceLink_issueId_externalResourceId_kind_key";
CREATE UNIQUE INDEX "ExternalResourceLink_issueId_externalResourceId_key"
ON "ExternalResourceLink"("issueId", "externalResourceId");
8 changes: 6 additions & 2 deletions prisma/schema.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -290,6 +290,10 @@ enum WorkSessionSource {
CODEX_DESKTOP
CONTRIBUTOR
MANUAL
MCP
NATIVE_SESSION
ISSUE_DISPATCH
SCHEDULED
}

/// The transport or execution endpoint through which an agent binding acts.
Expand Down Expand Up @@ -2597,7 +2601,7 @@ model ExternalResourceLink {
workspaceId String
issueId String
externalResourceId String
/// SOURCE | IMPLEMENTS | REVIEWS | RELATES_TO.
/// SOURCE | IMPLEMENTS | FIXES | RELEASES | REVIEWS | RELATES_TO.
kind String
createdById String?
createdAt DateTime @default(now())
Expand All @@ -2607,7 +2611,7 @@ model ExternalResourceLink {
externalResource ExternalResource @relation(fields: [externalResourceId], references: [id], onDelete: Cascade)
createdBy User? @relation("ExternalResourceLinkCreator", fields: [createdById], references: [id], onDelete: SetNull)

@@unique([issueId, externalResourceId, kind])
@@unique([issueId, externalResourceId])
@@index([workspaceId, issueId])
@@index([workspaceId, externalResourceId])
@@index([createdById])
Expand Down
Loading
Loading