Skip to content

Commit a550746

Browse files
phodalcodex
andcommitted
feat(harness): merge harness-as-code platform
Merge feat/harness-as-code-package into the current main branch, bringing the executable Harness DSL, comparison and execution contracts, Harness UI, Harness Studio, and their specs and evidence adapters together. Resolve the Inspector Workbench overlap by preserving mainline privacy labels and family markers alongside stable grouped-run ids and notebook layout. Normalize the remaining lockfile registry URL. Validated with npm run check, 4 Playwright Chromium flows, and root preview health and canvas-module smoke checks. Co-authored-by: Codex (GPT 5.6 Sol) <codex@openai.com>
2 parents 5032774 + c9b59e5 commit a550746

215 files changed

Lines changed: 40133 additions & 677 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/ci.yml

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,26 @@ jobs:
3838
- run: npm ci
3939
- name: Run Vitest
4040
run: npm run test:ci
41+
- name: Verify Harness DSL generated sources
42+
run: npm run harness:generated
43+
- name: Build Harness DSL package
44+
run: npm run harness:build
45+
- name: Test Harness DSL package
46+
run: npm run harness:test
47+
- name: Build Harness UI package
48+
run: npm run harness-ui:build
49+
- name: Test Harness UI package
50+
run: npm run harness-ui:test
51+
- name: Build Harness Studio package
52+
run: npm run harness-studio:build
53+
- name: Test Harness Studio package
54+
run: npm run harness-studio:test
55+
- name: Install Chromium for Harness Studio browser test
56+
if: ${{ matrix.os == 'ubuntu-latest' && matrix.node == '22.20.0' }}
57+
run: npx playwright install --with-deps chromium
58+
- name: Test Harness Studio browser interaction
59+
if: ${{ matrix.os == 'ubuntu-latest' && matrix.node == '22.20.0' }}
60+
run: npm run harness-studio:test:browser
4161
- name: Upload JUnit test results
4262
if: ${{ always() }}
4363
uses: actions/upload-artifact@v7

.github/workflows/release.yml

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,17 @@ name: Publish npm
22

33
on:
44
workflow_dispatch:
5+
inputs:
6+
package:
7+
description: Package to publish
8+
required: true
9+
default: better-harness
10+
type: choice
11+
options:
12+
- better-harness
13+
- harness
14+
- harness-ui
15+
- harness-studio
516

617
permissions:
718
contents: read
@@ -20,8 +31,14 @@ jobs:
2031
registry-url: https://registry.npmjs.org
2132
package-manager-cache: false
2233
- run: npm ci
23-
- run: npm test
24-
- run: npm run pack:verify
25-
- run: npm publish --access public
34+
- run: npm run check
35+
- name: Publish Better Harness
36+
if: ${{ inputs.package == 'better-harness' }}
37+
run: npm publish --access public
38+
env:
39+
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
40+
- name: Publish selected Harness workspace
41+
if: ${{ inputs.package != 'better-harness' }}
42+
run: npm publish --workspace "@qoder-ai/${{ inputs.package }}" --access public
2643
env:
2744
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,4 +18,6 @@ skills/**/.plugin-eval/
1818
assets/wasm
1919
dev/terminal-demo/*.cast
2020
/.codex/better-harness/
21+
/harness-readme-compare-evidence/
22+
/harness-qoder-profile-evidence/
2123
design-qa.md

docs/ARCHITECTURE.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,14 @@ the target journey, contract, evidence, governance, and DX-measurement system.
2121
supplied copy, but they do not compose or translate it; host UIs render the
2222
persisted semantic copy instead of rebuilding it from structural metadata.
2323
- Keep host evidence adapters separate from packaging, and keep all automation cross-platform.
24+
- Keep Harness as Code dependencies directed `core <- adapters <- devtools`:
25+
the package root owns browser-safe grammar, IR, revision, and resolution;
26+
source locking, host execution, compare execution, and highlighting are
27+
explicit subpath boundaries. UI protocol layers accept injected executors.
28+
- Bridge persisted Harness runs into Inspector through the `harness-run`
29+
session adapter. Harness owns revision and receipt schemas; session-analysis
30+
owns `NormalizedToolActivityV1`; the bridge is one-way and never merges the
31+
two contracts. See [ADR-0003](adrs/harness-run-evidence-bridge.md).
2432
- Keep stable host identity, display, home-option, and support-slice metadata in
2533
`scripts/host-support/`. Executable adapter imports and construction remain in
2634
capability-local registries; do not introduce a global host service locator.

docs/adrs/README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,10 @@ deprecated.
1313
| --- | --- | --- | --- | --- |
1414
| `ADR-0001` | [AI-Optimized Directory Structure](directory-structure.md) | Proposed | 2026-07-16 | Directory ownership, artifact routing, migration gates, and target-directory activation |
1515
| `ADR-0002` | [Developer Experience System](developer-experience-system.md) | Proposed | 2026-07-31 | Journeys, federated contracts, projections, native evidence, governance, support, and DX measurement |
16+
| `ADR-0003` | [Harness Run Evidence Bridge](harness-run-evidence-bridge.md) | Proposed | 2026-08-15 | Harness revision and run evidence ingestion into the Inspector normalization chain |
17+
| `ADR-0004` | [Harness Checkpoint Experiment Compare](harness-checkpoint-experiment-compare.md) | Proposed | 2026-08-17 | Checkpoint-anchored mixed-origin experiments, derived treatment axes, per-contrast verdicts, and the Studio experiment lifecycle |
18+
| `ADR-0005` | [Checkpoint-backed Compare Sources and Materialization](checkpoint-backed-compare-sources.md) | Proposed | 2026-08-17 | Source-neutral checkpoint discovery, request provenance, adapter projections, and per-lane materialization |
19+
| `ADR-0006` | [Session Notebook Trace and Outcome Projection](session-notebook-evidence-projection.md) | Proposed | 2026-08-18 | Ordered Turn evidence, response availability, evidence-bounded outcomes, and session-scoped patch requirements |
1620

1721
## Lifecycle
1822

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
# Checkpoint-backed Compare Sources and Materialization
2+
3+
## Traceability
4+
5+
- ADR ID: `ADR-0005`
6+
- Status: Proposed
7+
- Decision date: 2026-08-17
8+
- Related ADR: [Harness Checkpoint Experiment Compare](harness-checkpoint-experiment-compare.md)
9+
- Implementation spec: [Checkpoint-anchored multi-lane harness
10+
experiments](../specs/2026-08-17-harness-studio-checkpoint-compare.md)
11+
12+
## Context
13+
14+
The first Harness Studio experiment runner uses a
15+
`session-execution-plan-v1` checkpoint. That plan happens to identify a Git
16+
repository, commit, tree, and agent-session position, and its current
17+
materializer creates detached Git worktrees. Those facts are sufficient for the
18+
first executable adapter, but they are not the product boundary.
19+
20+
Compare must also be able to start from other resources that retain historical
21+
state. A presentation can have a versioned PPTX checkpoint and isolated file
22+
copies; a document, design, notebook, or remote workspace can expose different
23+
revision locators and materialization mechanisms. Naming the product or its
24+
browser contract `git-backed` would leak the first adapter into every future
25+
source and force non-Git histories to pretend to be repositories.
26+
27+
The experiment layer also needs to keep three facts distinct:
28+
29+
- the immutable checkpoint shared by the experiment;
30+
- the user request that fresh lanes execute, whether imported from history or
31+
entered for a new comparison;
32+
- the runtime-owned isolated materialization created for each fresh lane.
33+
34+
## Decision
35+
36+
- **Harness Studio Compare is checkpoint-backed.** A Compare locks one
37+
checkpoint and one request before execution. Git is the first checkpoint
38+
source adapter, not the product identity or a required field in the generic
39+
Studio model.
40+
- **`checkpointRef` remains opaque and authoritative.** The experiment manifest
41+
continues to store the checkpoint plan reference and digest. It does not copy
42+
repository, document, revision, slide, session, or worktree fields. The
43+
checkpoint-owning adapter validates and interprets the referenced bytes.
44+
- **Source adapters project a generic descriptor for Studio.** A validated
45+
adapter may expose display-oriented `adapter`, `resource`, `revision`,
46+
optional `history`, and `materialization` facts. Labels and values belong to
47+
the adapter: the Git adapter can say `Repository`, `Commit`, `Session
48+
position`, and `Detached worktree`; a PPTX adapter can say `Presentation`,
49+
`Version`, `Edit history`, and `Isolated document copy`. Studio renders the
50+
descriptor and does not branch on those labels or require Git-shaped fields.
51+
- **The descriptor is a projection, not a second checkpoint.** It is derived
52+
from a validated checkpoint for selection and preflight UX. Evidence and
53+
execution continue to cite the checkpoint digest and adapter receipts rather
54+
than trusting browser-authored display values.
55+
- **Discovery, lock, and materialization are separate phases.** A source adapter
56+
may browse projects or document histories and resolve a mutable selection
57+
into an immutable checkpoint. Locking creates no sandbox, worktree, document
58+
copy, or result ref. Only execution invokes the adapter's materializer for
59+
each fresh lane.
60+
- **Materialization is capability-based.** An adapter describes whether it can
61+
create isolated copies, replay an observed history, preserve a result, and
62+
clean up. The current Git adapter materializes a detached worktree at the
63+
locked commit. A future PPTX adapter may copy a versioned file plus required
64+
sidecars into an isolated directory. Neither mechanism changes what a
65+
checkpoint means.
66+
- **Request provenance is independent of checkpoint provenance.** Historical
67+
Replay locks the exact imported user request and its source locator; New
68+
Request Compare locks newly entered request bytes. Editing an imported
69+
historical request creates a new request identity instead of silently
70+
rewriting the historical episode.
71+
- **Studio follows `Draft -> Lock -> Materialize -> Execute -> Evaluate`.** The
72+
mutable Builder selects a scenario, checkpoint source, request source, and
73+
variants. Lock produces the existing experiment/checkpoint references and a
74+
comparability preview. The compact Workbench starts after lock and retains the
75+
source identity while it streams ACP and result evidence.
76+
- **Comparison semantics remain those of ADR-0004.** Every fresh lane starts
77+
from a materialization of the same checkpoint; observed history is contextual
78+
unless its identity is complete; treatment axes and verdict strength remain
79+
derived from evidence.
80+
81+
## First Adapter Boundary
82+
83+
The first implementation projects `session-execution-plan-v1` as:
84+
85+
| Generic field | Git adapter value |
86+
| --- | --- |
87+
| Adapter | Git + agent session |
88+
| Resource | Repository display name |
89+
| Revision | Base commit, with tree as secondary identity |
90+
| History | Session id and selected entry |
91+
| Materialization | One detached worktree per fresh trial, created on Run |
92+
93+
The projection deliberately does not become `GitCheckpointSourceV1` in the
94+
browser. Provider-specific validation, absolute paths, Git commands, locks, and
95+
cleanup stay in the Node adapter and runner.
96+
97+
## Consequences
98+
99+
Studio can explain the real Git/worktree plan today without making Git a
100+
permanent product dependency. Future versioned resources can join by supplying
101+
the same descriptor and lifecycle capabilities, while their canonical
102+
checkpoint formats remain adapter-owned. The extra boundary requires an
103+
adapter registry, explicit unsupported-checkpoint errors, and tests proving the
104+
browser UI contains no Git-specific branching. A generic projection cannot by
105+
itself guarantee that two historical environments are reproducible; checkpoint
106+
completeness and runtime receipts remain required evidence.
107+
108+
## Rejected Alternatives
109+
110+
- **Call the product Git-backed.** Rejected because it makes repository
111+
vocabulary part of product identity and excludes versioned non-code
112+
resources.
113+
- **Add a universal checkpoint object containing every source field.** Rejected
114+
because optional Git, PPTX, document, design, and remote-workspace fields
115+
would duplicate adapter contracts and weaken validation.
116+
- **Create one checkpoint per lane.** Rejected because it removes the shared
117+
starting condition. Lanes receive separate materializations of one checkpoint.
118+
- **Create worktrees or file copies while the Builder is edited.** Rejected
119+
because mutable selection is not execution authority and abandoned drafts
120+
would leak resources.
Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
# Harness Checkpoint Experiment Compare
2+
3+
## Traceability
4+
5+
- ADR ID: `ADR-0004`
6+
- Status: Proposed
7+
- Decision date: 2026-08-17
8+
- Related specs: [Harness Coding Compare](../specs/2026-08-15-harness-coding-compare.md),
9+
[Session Checkpoint Executor PoC](../specs/2026-08-16-session-checkpoint-executor-poc.md),
10+
[Harness UI Studio](../specs/2026-08-15-harness-ui-studio.md)
11+
- Implementation spec: [Checkpoint-anchored multi-lane harness
12+
experiments](../specs/2026-08-17-harness-studio-checkpoint-compare.md)
13+
- Source abstraction: [Checkpoint-backed Compare Sources and
14+
Materialization](checkpoint-backed-compare-sources.md)
15+
16+
## Context
17+
18+
Two evidence systems exist today and neither can express a mixed-origin,
19+
multi-lane experiment:
20+
21+
- `harness-compare.v1` freezes a fixture, runs exactly two variants
22+
(`baseline`/`candidate`) serially against a synthetic Git repository, and
23+
derives a single verdict. The manifest carries one global `runtime.model`,
24+
so per-lane model variation is inexpressible, and the treatment axis is
25+
limited to `harness | runtime-profile`.
26+
- The session executor owns the checkpoint contract
27+
(`session-execution-plan-v1`): base commit and tree plus session file
28+
digest, entry id, and branch digest. Execution results land on
29+
`refs/better-harness/session-executions` namespaced refs and never switch
30+
the user's branch.
31+
32+
Studio users want to pick a checkpoint, replay the observed historical
33+
trajectory, run two fresh agents (different harness or different model) from
34+
the same checkpoint in parallel, and compare the three trajectories side by
35+
side. The first executable adapter resolves a Git commit and materializes
36+
detached worktrees, but ADR-0005 keeps those mechanics out of the generic
37+
product contract. The temptation is to add a "sandbox checkpoint" type, copy
38+
source-specific fields into a new experiment schema, or let a single global
39+
verdict summarize a three-lane view. Each of those blurs provenance or
40+
fabricates attribution.
41+
42+
## Decision
43+
44+
- **One checkpoint definition per adapter.** The current session-executor plan
45+
is the first checkpoint contract. Future source adapters may own other
46+
versioned checkpoint formats under ADR-0005. A sandbox is a materialization
47+
of the referenced checkpoint for one lane's execution, never a new checkpoint
48+
type. Experiment documents hold a `checkpointRef` (path plus digest) and never
49+
copy or reinterpret checkpoint fields.
50+
- **The `.harness` grammar does not change.** The upgrade lives entirely in
51+
the experiment and compare layer. `harness-compare.v1` remains the frozen
52+
fixture, two-variant path; it is not extended to cover checkpoints.
53+
- **New `harness-experiment.v1` manifest.** The version starts at v1; no
54+
prior experiment schema exists. It declares one shared task (prompt hash,
55+
grader) and N lanes. A lane has `origin: "observed"` (a recorded trajectory
56+
reference plus its starting checkpoint digest; no sandbox is created) or
57+
`origin: "execute"` (a harness id plus a per-lane runtime profile and model;
58+
a sandbox is materialized from the shared checkpoint). The host, the visible
59+
tool set, and the run policy are shared across lanes rather than per-lane, so
60+
a lane cannot move the host and confound every contrast at once.
61+
- **Treatment axes are derived, never author-declared.** A contrast names
62+
only the lanes it compares. The runner computes the axis by diffing the
63+
lanes' harness id, runtime profile, and model. Exactly one differing axis
64+
(`harness`, `runtime-profile`, or `model` — extending the existing
65+
taxonomy) permits an attribution verdict; more than one yields
66+
`multi-axis`, which is descriptive only and can never produce a harness
67+
accept/reject.
68+
- **The statistical evidence bar is preserved.** Execute lanes carry a trial
69+
count, and per-contrast verdicts are decided by the existing matched-pair
70+
decision policy, including the two-matched-pair floor. A contrast whose
71+
lanes ran once each is attributable in principle but reports
72+
`insufficient_evidence`, never a promotion; the experiment schema is not a
73+
bypass for the compare evidence bar.
74+
- **An identically configured pair is descriptive, not invalid.** Where
75+
`harness-compare.v1` rejects a manifest whose variants move nothing, an
76+
experiment accepts it and reports `no-axis-moved`. Two identical lanes from
77+
one checkpoint measure run-to-run variance, which is the noise floor every
78+
other contrast is read against.
79+
- **Checkpoint completeness is a gate, not an assumption.** A checkpoint
80+
anchors a commit and tree, not the untracked files or dirty state the
81+
historical trajectory may have started from. Materialization records a
82+
completeness receipt: either a clean-tree assertion or a captured
83+
dirty-state patch applied to every fresh lane. Without it, fresh lanes may
84+
not claim to share the historical lane's starting condition.
85+
- **Observed lanes are contextual evidence by default.** A historical
86+
trajectory participates in an attribution verdict only when its runtime,
87+
model, harness revision, environment receipts, and task identity (prompt
88+
and prior session context) all match the fresh lanes. Absent any of those
89+
— and the prompt almost never matches — it is displayed as context in a
90+
descriptive contrast. Grades are optional on observed lanes.
91+
- **Execution discipline for parallel lanes.** All lanes pass preflight
92+
(checkpoint digest, base commit/tree, session digest) before any lane
93+
starts. Worktree materialization is serialized to avoid Git lock
94+
contention; execution then runs in parallel with `Promise.allSettled`, so
95+
one lane's failure never discards another lane's evidence. Every event
96+
carries `experimentId`, `laneId`, and `runId`. Each lane persists its own
97+
`HarnessRevision`, runtime/model receipt, sandbox receipt, trajectory,
98+
patch, and grade. Results stay on namespaced refs; adopting a result is a
99+
later explicit action.
100+
- **Studio hosts experiments, not one global verdict.** The stateless
101+
run-per-request `/agui` endpoint is insufficient. Studio gains a
102+
server-side experiment registry (create an experiment, subscribe to
103+
per-lane event streams, cancel), persists evidence per experiment
104+
directory, previews which axes a configuration moves before running, and
105+
renders one verdict per contrast. A three-lane view never shows a single
106+
aggregate verdict.
107+
- **Tool-chain correlation is explicit evidence, not a similarity score.**
108+
Studio normalizes each ACP-derived tool call into tool name, resource target,
109+
and canonical arguments, then aligns lane sequences one-to-one and in order.
110+
The UI labels a counterpart `exact`, `same-resource`, `same-tool`, or `none`
111+
and shows the neighbouring calls around it. This makes a shared file read and
112+
a shared Read → Edit → Test path visible without presenting fuzzy similarity
113+
as provenance or causal proof.
114+
115+
## Consequences
116+
117+
Mixed-origin comparison becomes expressible without expanding the core
118+
`.harness` DSL or forking the checkpoint contract. The compare aggregate
119+
taxonomy gains a `model` axis and per-contrast decisions; consumers of
120+
`harness-compare-result.v1` are unaffected because `harness-compare.v1`
121+
remains frozen. Observed trajectories gain a principled, limited role:
122+
context by default, baseline only under full identity. The cost is a second
123+
manifest schema to maintain, a Studio server that now holds run state, and
124+
the obligation to keep the derived-axis rule and evidence floor enforced in
125+
the runner rather than trusted from the document. Implementation still
126+
requires the dated spec, acceptance scenarios, and test evidence mandated by
127+
`AGENTS.md`.

0 commit comments

Comments
 (0)