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
77 changes: 77 additions & 0 deletions CONTEXT.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
# jcode Cloud domain context

This glossary records the product language shared by the control plane, Runner,
Console, and design documents. It is intentionally small: implementation detail
belongs next to the implementation and accepted decisions belong in
`docs/02-decision-log.md`.

## Core terms

- **Work Item** — durable team work. A jtype Card remains the truth for Kanban
work; a provider Pull Request remains the truth for review work. Cloud does not
create a second issue system.
- **Trigger** — the fact that requests execution: Manual, JType transition, SCM
event/comment, Cron occurrence, or scoped API call. Trigger implementations
differ, but all must produce the same bounded trigger facts before dispatch.
- **Workflow Definition** — an editable, versioned authoring artifact that binds
a trigger shape, Agent Profile, requirements, timeout, typed outputs, and prompt.
Ship-R1 has code-owned built-in definitions; repository/UI authoring arrives in
Ship-R2. A definition is compiled into a Run-specific Workflow Contract.
- **Agent Profile** — a versioned role contract describing how an agent should
behave and which capabilities it requires. Built-in roles are Developer,
Reviewer, Product Manager, and Architect; a Custom profile may refine the
instructions and requirements. A profile is not a human identity and does not
grant authorization.
- **LLM Selection** — the resolved provider/model/effort projection frozen for a
Run. Ship-R1 does not introduce a separate LLM Profile resource; that remains
distinct from Agent Profile and Runner Profile even when selected from current
Project/model settings.
- **Workflow Contract** — the immutable, schema-versioned execution contract
compiled for one Run from a Workflow Definition revision, bounded trigger
facts, an Agent Profile revision, Service policy, LLM Selection, typed delivery
outputs, and verification rules. Editing a profile or Automation never mutates
an existing Run's contract.
- **Run Readiness** — a server-side evaluation of a proposed Workflow Contract
against model, repository, Plugin, Runner, persistence, and delivery
capabilities. Ship-R1 keeps existing dispatch prerequisites and records the
resolved contract; Ship-R2 exposes the shared preview/create evaluator. A
failed check never silently selects another profile or output.
- **Run** — one execution truth in Cloud: lifecycle, transcript, artifacts,
result, delivery, usage, and frozen Workflow Contract.
- **Run SCM Grant** — the immutable repository and provider authorization facts
for a Run: installation/grant revision, provider configuration revision,
repository identity, clone route, default branch, and acting provider identity.
Clone, push, Pull Request, and review writeback consume the same grant.
- **Review Revision Pair** — the provider-verified base/head commit SHAs frozen on
a Review Run. The Review Plan may additionally record the computed merge-base;
revision facts are not authorization and therefore are not part of SCM Grant.
- **Runner Profile** — an operator-owned manifest for a Runner image digest and
its executable/tool/network/persistence capabilities. It is infrastructure,
not an Agent persona.
- **Review Plan** — a deterministic plan pinned to base/head commits, with a
changed-hunk index, bounded review units, rules revision, and input coverage
ledger. Ship-R1 coverage proves what entered the reviewer, not what the model
semantically considered.
- **Typed Output** — an allowlisted intent produced by a Run and externalized by
a control-plane adapter, such as `provider_review` or `create_pull_request`.
Agent tool permission never grants an output absent from the contract.
- **Delivery** — the control-plane-owned publication of a Run result. Pull
Request delivery is lifecycle-aware by default: a one-shot success is Ready;
a long session may use Draft only as an intermediate state. Cloud never
approves or merges automatically.
- **Workspace Checkpoint** — an append-only reference to a stable Run workspace
state. A PVC is a cache and resume substrate, not the checkpoint truth.

## Invariants

1. Trigger identity, accountable identity, Agent Profile, Runner Profile, and
provider Bot identity are distinct concepts.
2. Display-only provenance never participates in authorization.
3. A Run executes one frozen Workflow Contract; retries explicitly choose
whether to reuse it or resolve a new revision.
4. Provider credentials never enter the Runner. A Run only receives scoped
source and credential adapters from the control plane.
5. Different trigger implementations may collect different facts, but they may
not bypass platform dispatch prerequisites or invent private dispatch paths.
6. Multi-agent execution is opt-in orchestration over isolated review/work
units. A role profile does not imply multi-agent execution.
66 changes: 66 additions & 0 deletions console/src/api/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -650,6 +650,13 @@ export interface Run {
review_output?: string;
/** When the review comment was posted to the PR (idempotency marker). */
review_posted_at?: string | null;
/** Immutable built-in Workflow + Agent Profile projection resolved at Run creation. */
execution_contract?: WorkflowContract;
/** Server-accepted review input coverage. Private changed-line anchors are never serialized. */
review_plan?: ReviewPlan;
/** Exact provider revisions frozen before a review Run is queued. */
pr_head_sha?: string;
pr_base_sha?: string;
/**
* How the run was triggered (M7 / blueprint §8): the API/console (default,
* absent) or a Gitea PR comment `@jcode …` webhook. A webhook run carries the
Expand Down Expand Up @@ -694,6 +701,65 @@ export interface Run {
provenance?: RunProvenance;
}

export interface WorkflowContract {
schema_version: number;
hash: string;
workflow: { id: string; name: string; revision: number; source: string; definition_hash: string };
profile: { id: string; name: string; role: string; revision: number; instructions: string };
trigger: {
kind: string;
origin?: string;
repository?: string;
object?: string;
action?: string;
ref?: string;
automation_id?: string;
idempotency_key: string;
concurrency_group: string;
};
execution: {
run_kind: RunKind;
llm_selection: { model_id?: string; model_name: string; effort?: string; source: string };
session: boolean;
permission_mode: string;
workspace_access: 'read_only' | 'read_write' | string;
provider_credentials: 'none' | string;
base_ref?: string;
timeout_seconds: number;
timeout_source: string;
};
delivery: { outputs: Array<{ type: string; target?: string; ready_policy?: string }>; merge: 'never' | string };
verification: { mode: string; rules_revision?: string; max_findings?: number; minimum_confidence?: number; required_records?: string[] };
requirements: string[];
resolved_at: string;
}

export interface ReviewPlanFile {
path: string;
status: 'indexed' | 'skipped' | string;
reason?: string;
hunks: number;
changed_lines: number;
}

export interface ReviewPlan {
schema_version: number;
plan_hash: string;
base_sha: string;
head_sha: string;
merge_base_sha: string;
rules_revision: string;
coverage: 'complete' | 'partial' | string;
changed_files: number;
eligible_files: number;
indexed_files: number;
changed_hunks: number;
indexed_hunks: number;
changed_lines: number;
files: ReviewPlanFile[];
created_at: string;
}

export interface ProvenanceActorRef {
kind: 'cloud_user' | 'external_actor' | 'service_principal' | 'automation_principal' | 'provider_bot' | string;
id?: string;
Expand Down
31 changes: 31 additions & 0 deletions console/src/i18n/locales/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2129,6 +2129,37 @@ export default {
resumedFrom: 'Resumed from',
resumedFromLink: 'resumed from {id}',
},
contract: {
title: 'Execution contract',
legacyUnavailable: 'This historical Run predates immutable execution contracts.',
workflow: 'Workflow',
profile: 'Agent profile',
trigger: 'Trigger',
model: 'Model',
timeout: 'Timeout',
delivery: 'Delivery',
verification: 'Verification',
technical: 'Technical contract',
hash: 'Contract hash',
definition: 'Definition',
access: 'Workspace',
requirements: 'Requirements',
},
coverage: {
eyebrow: 'Review input',
title: 'Review coverage',
unavailable: 'Unavailable',
legacyUnavailable: 'Coverage was not recorded for this historical review Run.',
complete: 'Complete',
partial: 'Partial',
files: 'files indexed',
hunks: 'hunks indexed',
lines: 'changed lines',
baseHead: 'Base → head',
mergeBase: 'Merge base',
skipped: '{count} skipped files',
unsupported: 'unsupported',
},
origin: {
fromPrComment: 'from PR comment',
scheduled: 'scheduled',
Expand Down
31 changes: 31 additions & 0 deletions console/src/i18n/locales/zh-Hans.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1963,6 +1963,37 @@ export default {
resumedFrom: '恢复自',
resumedFromLink: '恢复自 {id}',
},
contract: {
title: '执行契约',
legacyUnavailable: '此历史运行早于不可变执行契约功能。',
workflow: '工作流',
profile: 'Agent 配置',
trigger: '触发器',
model: '模型',
timeout: '超时',
delivery: '交付',
verification: '校验',
technical: '技术契约',
hash: '契约哈希',
definition: '定义',
access: '工作区',
requirements: '能力要求',
},
coverage: {
eyebrow: '评审输入',
title: '评审覆盖范围',
unavailable: '不可用',
legacyUnavailable: '此历史评审运行未记录覆盖范围。',
complete: '完整',
partial: '部分',
files: '已索引文件',
hunks: '已索引代码块',
lines: '变更行',
baseHead: '基线 → 提交',
mergeBase: '共同祖先',
skipped: '跳过 {count} 个文件',
unsupported: '不支持',
},
origin: {
fromPrComment: '来自 PR 评论',
scheduled: '定时',
Expand Down
24 changes: 24 additions & 0 deletions console/src/pages/RunDetailPage.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,30 @@
.empty { margin: 0; padding: var(--space-8); border: 1px solid var(--color-border); border-radius: var(--radius-lg); color: var(--color-text-faint); font-size: var(--fs-sm); text-align: center; }
.reviewOutput { padding: var(--space-5); border: 1px solid var(--color-border); border-radius: var(--radius-xl); }
.reviewProgress { display: grid; gap: var(--space-5); }
.reviewCoverage { display: grid; gap: var(--space-4); padding: var(--space-5); border: 1px solid var(--color-border); border-radius: var(--radius-xl); background: var(--color-bg-inset); }
.reviewCoverage header { display: flex; align-items: flex-start; justify-content: space-between; gap: var(--space-4); }
.reviewCoverage header > div { display: grid; gap: 3px; }
.reviewCoverage header span { color: var(--color-text-faint); font-family: var(--font-mono); font-size: 10px; font-weight: var(--fw-semibold); letter-spacing: var(--tracking-label); text-transform: uppercase; }
.reviewCoverage h2 { margin: 0; color: var(--color-text); font-size: var(--fs-sm); }
.reviewCoverage header strong { padding: 3px var(--space-2); border: 1px solid var(--color-border); border-radius: var(--radius-pill); color: var(--color-text-muted); font-family: var(--font-mono); font-size: 10px; text-transform: uppercase; }
.reviewCoverage header strong[data-coverage='complete'] { border-color: color-mix(in srgb, var(--status-succeeded-fg) 35%, var(--color-border)); color: var(--status-succeeded-fg); }
.reviewCoverage header strong[data-coverage='partial'] { border-color: color-mix(in srgb, var(--status-scheduling-fg) 35%, var(--color-border)); color: var(--status-scheduling-fg); }
.reviewCoverage > p { margin: 0; color: var(--color-text-faint); font-size: var(--fs-caption); }
.coverageMetrics { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); border: 1px solid var(--color-border); border-radius: var(--radius-lg); overflow: hidden; }
.coverageMetrics > div { display: grid; gap: 2px; padding: var(--space-3); }
.coverageMetrics > div + div { border-left: 1px solid var(--color-border); }
.coverageMetrics b { color: var(--color-text); font-family: var(--font-mono); font-size: var(--fs-sm); font-weight: var(--fw-medium); }
.coverageMetrics span { color: var(--color-text-faint); font-size: 10px; }
.coverageRevisions { display: grid; gap: var(--space-2); margin: 0; }
.coverageRevisions > div { display: grid; grid-template-columns: 92px minmax(0, 1fr); gap: var(--space-3); }
.coverageRevisions dt { color: var(--color-text-faint); font-size: var(--fs-tiny); }
.coverageRevisions dd { margin: 0; color: var(--color-text-muted); font-size: var(--fs-tiny); overflow-wrap: anywhere; }
.coverageSkipped { color: var(--color-text-faint); font-size: var(--fs-tiny); }
.coverageSkipped summary { width: max-content; cursor: pointer; }
.coverageSkipped ul { display: grid; gap: var(--space-2); margin: var(--space-3) 0 0; padding: 0; list-style: none; }
.coverageSkipped li { display: flex; min-width: 0; justify-content: space-between; gap: var(--space-3); }
.coverageSkipped code { overflow: hidden; color: var(--color-text-muted); text-overflow: ellipsis; white-space: nowrap; }
.coverageSkipped li span { flex: none; }

@media (max-width: 940px) {
.taskLayout { grid-template-columns: minmax(0, 1fr); align-content: start; overflow-y: auto; }
Expand Down
61 changes: 61 additions & 0 deletions console/src/pages/RunDetailPage.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,67 @@ function renderPage(client: ApiClient, seed?: Run) {
}

describe('RunDetailPage — resilient error states', () => {
it('shows the frozen workflow contract and deterministic review coverage', async () => {
const { client, ctl } = makeClient();
const run = baseRun({
kind: 'review',
status: 'succeeded',
finished_at: '2026-07-07T00:05:00Z',
review_output: 'No findings.',
execution_contract: {
schema_version: 1,
hash: 'sha256:contract',
workflow: { id: 'builtin:pull-request-review', name: 'Pull Request Review', revision: 1, source: 'builtin', definition_hash: 'sha256:definition' },
profile: { id: 'builtin:reviewer', name: 'Reviewer', role: 'reviewer', revision: 1, instructions: 'Review exact revisions.' },
trigger: { kind: 'scm', origin: 'automation', idempotency_key: 'delivery-1', concurrency_group: 'svc-1:pull_request:42' },
execution: {
run_kind: 'review',
llm_selection: { model_name: 'glm-5.2', source: 'resolved_run' },
session: false,
permission_mode: 'full_access',
workspace_access: 'read_only',
provider_credentials: 'none',
timeout_seconds: 1800,
timeout_source: 'project_override',
},
delivery: { outputs: [{ type: 'provider_review', target: 'trigger_pr' }], merge: 'never' },
verification: { mode: 'structured_review', rules_revision: 'review-v2', max_findings: 50, minimum_confidence: 80 },
requirements: ['source.read', 'git', 'ripgrep', 'scm.review.write'],
resolved_at: '2026-07-07T00:00:00Z',
},
review_plan: {
schema_version: 1,
plan_hash: 'sha256:plan',
base_sha: '1111111111111111111111111111111111111111',
head_sha: '2222222222222222222222222222222222222222',
merge_base_sha: '1111111111111111111111111111111111111111',
rules_revision: 'review-v2',
coverage: 'partial',
changed_files: 2,
eligible_files: 1,
indexed_files: 1,
changed_hunks: 3,
indexed_hunks: 2,
changed_lines: 17,
files: [
{ path: 'src/main.ts', status: 'indexed', hunks: 2, changed_lines: 17 },
{ path: 'assets/logo.png', status: 'skipped', reason: 'binary', hunks: 1, changed_lines: 0 },
],
created_at: '2026-07-07T00:00:10Z',
},
});
ctl.getRun.mockResolvedValue(run);
renderPage(client, run);

expect(await screen.findByTestId('workflow-contract')).toBeTruthy();
expect(screen.getByText('Pull Request Review v1')).toBeTruthy();
expect(screen.getByText('30m · project_override')).toBeTruthy();
const coverage = screen.getByTestId('review-coverage');
expect(coverage.querySelector('[data-coverage="partial"]')).toBeTruthy();
expect(screen.getByText('1/2')).toBeTruthy();
expect(screen.getByText('17')).toBeTruthy();
});

it('shows captured Run usage in the inspector without merging cost sources', async () => {
const { client, ctl } = makeClient();
const value = baseRun({
Expand Down
Loading
Loading