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
6 changes: 3 additions & 3 deletions bench/cdeb/ACTIVE-STUDY.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"active_study_id": "cdeb-fresh-v4",
"last_terminal_study_id": "cdeb-fresh-v3r1",
"active_study_id": "cdeb-fresh-v5",
"last_terminal_study_id": "cdeb-fresh-v4",
"status": "active",
"reason": "cdeb-fresh-v4 is a Stage 0 corpus-feasibility study under a new study id, new preregistration and a new estimand. cdeb-fresh-v3 and cdeb-fresh-v3r1 remain invalidated terminal studies holding no measured data; neither may be resumed, and neither may be named here.",
"reason": "cdeb-fresh-v5 is a Stage 0 authority-and-corpus-feasibility study under a new study id, a new preregistration and a new admission model. cdeb-fresh-v3 and cdeb-fresh-v3r1 are invalidated; cdeb-fresh-v4 reached stage0-hold. None of the three may be resumed or named here, and none holds measured data.",
"successor_requires_new_study_id": true
}
14 changes: 11 additions & 3 deletions bench/cdeb/active-study.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,20 @@ export interface ActiveStudyDeclaration {
}

/**
* The phase a study writes into its own STATUS.json when it ends. A study that
* The phases a study writes into its own STATUS.json when it ends. A study that
* declares itself terminal cannot be named active, however the declaration is
* edited -- the refusal reads the study's own record rather than a list of
* names kept somewhere else, which would drift the first time a study ended
* without anyone remembering to update it.
*
* `stage0-hold` joins `invalidated` because a study that reached HOLD is just as
* finished as one that was invalidated: it holds a published verdict and a
* successor requirement, and running anything against it would attribute the
* result to a study that already ended.
*/
export const TERMINAL_STUDY_PHASES = ["invalidated", "stage0-hold"] as const;

/** Retained for callers that predate the plural form. */
export const TERMINAL_STUDY_PHASE = "invalidated";

const isRecord = (value: unknown): value is Record<string, unknown> =>
Expand Down Expand Up @@ -84,8 +92,8 @@ export const assertStudyNotTerminal = (studyRoot: string, expectedStudyId: strin
if (status.study_id !== expectedStudyId) {
throw new Error(`Active study ${expectedStudyId} resolves to a directory whose STATUS.json declares ${status.study_id}`);
}
if (status.phase === TERMINAL_STUDY_PHASE) {
throw new Error(`Refused terminal study ${expectedStudyId} as the active study: its phase is ${TERMINAL_STUDY_PHASE}`);
if ((TERMINAL_STUDY_PHASES as readonly string[]).includes(status.phase)) {
throw new Error(`Refused terminal study ${expectedStudyId} as the active study: its phase is ${status.phase}`);
}
};

Expand Down
6 changes: 4 additions & 2 deletions bench/cdeb/studies/cdeb-fresh-v4/STATUS.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
{
"study_id": "cdeb-fresh-v4",
"phase": "stage0-corpus-feasibility",
"phase": "stage0-hold",
"measured_run_allowed": false,
"updated_at": "2026-08-21T22:17:48Z"
"updated_at": "2026-08-22T01:30:00Z",
"successor_required": true,
"verdict": "HOLD"
}
194 changes: 194 additions & 0 deletions bench/cdeb/studies/cdeb-fresh-v5/STAGE0-PREREGISTRATION.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,194 @@
---
document_id: cdeb-fresh-v5-stage0-preregistration
study_id: cdeb-fresh-v5
phase: stage0-authority-corpus-feasibility
measured_run_allowed: false
authority: COMMITLORE_CDEB_FRESH_V5_FINAL_AGENT_PROMPT_2026-08-22.md
predecessors: [cdeb-fresh-v3, cdeb-fresh-v3r1, cdeb-fresh-v4]
owner_testimony: disabled
registered_at: 2026-08-22T01:30:00Z
---

# CDEB-Fresh v5 — Stage 0 preregistration

Registered before any v5 qualification count exists.

Stage 0 asks one question:

> Can a corpus be built in which the **policy authority is the natural, pre-study
> CommitLore record itself**, and can that policy be delivered by the shipping
> path before a relevant mutation?

It does not run an agent, assign an arm, or record an outcome. At the end
`measured_run_allowed` is still `false` and there are still zero measured
product-effect rows.

## 1. The construct, and what changed from v4

> **A naturally recorded, pre-study CommitLore decision is itself a repository
> recorded-policy artifact.**

v4 required the same ruling to be recoverable from prose with the record
removed. That excluded 190 of 241 decisions — and it excluded precisely the case
the product exists for: a judgment recorded once, which the current code does not
explain. Requiring a decision to be written down twice measures redundancy, not
delivery.

So the independent-prose gate is **removed**, not renamed. Independent
corroboration becomes metadata (§3). No gate below may require a decision to be
documented outside its record; a gate that does is the v4 gate returning under
another name.

## 2. Why this is not a circular benchmark

```text
policy source a pre-study natural record, frozen before the study
treatment automatic delivery of that policy before a relevant mutation
control the same task and agent, decision payload suppressed
outcome does the final tree implement a functionally viable approach
the policy ruled out?
```

The outcome is read from the final code tree. It is **not** whether the agent
cited a `Record-Id`, repeated the record's wording, or stated the reason — those
would let the treatment satisfy the measurement merely by being delivered.

## 3. Authority tiers

**A0 — Natural Recorded Authority.** Primary admission. Requires: pre-cutoff,
present in the frozen snapshot, ordinary-development origin, not
benchmark-authored, not reconstructed or backfilled, explicit ruled-out
behaviour, explicit reason, recoverable scope, recoverable lifecycle, authorized
repository. A duplicate prose source is **not** required. A valid `Record-Id` is
**not** required.

**A1 — Independently Corroborated.** A0 plus independent support in a pull
request, issue, ADR, ordinary prose, design document, code comment or test
rationale. Recorded as `independent_corroboration` and `authority_strength`.
Its absence excludes nothing.

**A2 — Owner Attested.** Disabled. `A2 collected = 0`. Nothing in this stage
waits on owner testimony, and no testimony is added to any v4 failure.

## 4. Gates

A candidate is qualified only if every gate passes. Each failure records a code
from §5 and stops evaluation of that candidate.

**G1 — Natural Recorded Authority.** §3's A0 conditions, from immutable
evidence.

**G2 — Semantic decidability.** Two fresh reviewers, blind to each other, read
the frozen record and each state what policy it defines: ruled-out behaviour,
reason, scope, lifecycle, violation boundary, compliance boundary. They are
**not** asked whether the decision appears anywhere else. Disagreement goes to a
third blind vote. Still ambiguous → `record-ambiguous`. No lexical-overlap floor
is used as an admission gate, in this or any other form.

**G3 — Hidden rationale.** Without the record, is the rejection already obvious
from the current code, a neutral task and the obvious tests? If yes, exclude.
The rationale is **not** required to be documented elsewhere.

**G4 — Functionally viable wrong path.** Both classes must be possible: a
compliant implementation that passes functionally and complies, and a revival
that passes functionally and violates. A revival that fails functional tests is
an ordinary bug and out of scope.

**G5 — Deterministic oracle feasibility.** Could a future final tree be judged
for revival without reading the arm, the delivery log, the agent transcript or
any record citation? Preference order: runtime behaviour probe, AST or
structured parse, public API or CLI behaviour, semantic structural predicate.
Keyword-only oracles are acceptable only where the policy is genuinely lexical.

**G6 — Shipping content delivery.** At the frozen release, before the first
mutation: ruling visible, reason visible, scope correct, lifecycle current, not
stale-as-current, and the injector demonstrably ran. `Record-Id` presence is
metadata and never gates.

**G7 — Bounded realistic task.** A plausible maintenance task inside a normal
tool and time budget. Benchmark-only toy edits are rejected.

**G8 — Leakage safety.** No task prompt carrying the ruling or reason, no
exposure of a known bad implementation, no equivalence to a prior CDEB task, no
public artifact that supplies the answer. **The record existing in Git is not
leakage — it is the treatment content.**

## 5. Exclusion codes

```text
post-cutoff benchmark-authored
backfilled-or-reconstructed reason-not-explicit
scope-unresolvable lifecycle-unresolvable
record-ambiguous reason-obvious-from-code
wrong-path-not-functionally-viable
oracle-not-deterministic shipping-content-not-observable
task-not-bounded leakage-risk
prior-benchmark-task-equivalent
```

`missing-record-id` and `insufficient-provenance` are **not** codes here and must
not become codes.

## 6. Task-author firewall

A task author may see the base tree, a neutral maintenance need, functional
acceptance criteria and the allowed scope. A task author may **not** see the
record, the ruled-out behaviour, the reason, the decision anchor, the gold, a
known bad patch, or any reviewer interpretation. This firewall is the core of
v5's anti-circularity and is checked executably where practical.

## 7. GO / HOLD

Registered before the census runs, taken unchanged from the owner's decision:

```text
eligible repository final A0-qualified >= 8

GO requires all of:
eligible repositories >= 3
total final A0-qualified >= 36
delivery observability demonstrated for identified and id-less decisions
where each is present
no unresolved integrity blocker
Otherwise HOLD.
```

After Stage 0: 4 pass → four-repository set; 3 pass → three-repository set;
≤2 pass → HOLD. Repository selection completes before any treatment outcome
exists, and selecting repositories after seeing an ON/OFF result is forbidden.

**36 is a feasibility floor, not a sample size.** It reserves at least 12
candidates for a pilot and leaves at least 24 distinct candidates for a possible
confirmatory study. The final N comes from a separately frozen power analysis
after the pilot.

Thresholds do not move after counts appear. On HOLD: no threshold relaxation, no
synthetic records, no post-hoc repository cherry-picking, no owner testimony.

## 8. Disclosure — what was already visible

v4's counts are public and known to this document's author: 241 decisions
(gitseed 104, agent-operator-score 59, logic-pro-mcp 43, agent-control-plane 35),
143 identified and 98 id-less, 154 of 207 delivered. Those are pre-gate counts
and v4 qualification outcomes under a discarded rule; none is imported, and no
threshold here is calibrated against them. The disclosure exists so a reader can
judge the thresholds knowing what their author knew.

## 9. Forbidden in Stage 0

```text
pilot runs ON/OFF agent runs randomization
outcome rows effect sizes significance tests
README metrics product claims owner testimony
importing any v4 qualification row, reviewer verdict or correspondence score
```

## 10. Termination

Stage 0 ends with a report and stops, GO or HOLD. A successor requires a new
confirmatory PRD, a new preregistration, a fixed repository set and separate
owner approval.

```text
CDEB-FRESH V5 STAGE 0 COMPLETE — PRODUCT-EFFECT MEASUREMENT NOT STARTED
```
6 changes: 6 additions & 0 deletions bench/cdeb/studies/cdeb-fresh-v5/STATUS.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"study_id": "cdeb-fresh-v5",
"phase": "stage0-authority-corpus-feasibility",
"measured_run_allowed": false,
"updated_at": "2026-08-22T01:30:00Z"
}
55 changes: 55 additions & 0 deletions bench/cdeb/studies/cdeb-fresh-v5/authority-policy.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
{
"schema_version": 1,
"study_id": "cdeb-fresh-v5",
"registered_at": "2026-08-22T01:30:00Z",
"construct": "A naturally recorded, pre-study CommitLore decision is itself a repository recorded-policy artifact.",
"why_this_replaces_v4": "v4 admitted a candidate only when the same ruling could be recovered from prose with the record removed. That excluded 190 of 241 decisions, and it excluded exactly the case the product exists for: a judgment recorded once, in the record, that the current code does not explain. Requiring the decision to be documented twice makes the benchmark measure redundancy rather than delivery.",
"tiers": {
"A0": {
"name": "Natural Recorded Authority",
"role": "primary admission",
"required": [
"created before the study cutoff",
"record bytes present in the frozen snapshot",
"arose in ordinary development",
"not benchmark-authored",
"not reconstructed or backfilled",
"explicit ruled-out behaviour",
"explicit reason",
"scope recoverable",
"lifecycle recoverable",
"authorized repository"
],
"not_required": [
"a duplicate prose source",
"a valid Record-Id",
"independent corroboration"
]
},
"A1": {
"name": "Independently Corroborated",
"role": "evidence-strength metadata only",
"definition": "A0 plus independent support in a pull request, issue, ADR, ordinary prose, design document, code comment or test rationale",
"on_absence": "independent_corroboration is false, authority remains A0, and the candidate is not excluded"
},
"A2": {
"name": "Owner Attested",
"role": "disabled for v5",
"collected": 0,
"why": "v4's counts are already public, so testimony added now could be aimed at specific candidates. The owner disabled it, and nothing in this stage may wait on it."
}
},
"anti_circularity": {
"policy_source": "pre-study natural CommitLore record",
"treatment": "automatic delivery of that policy before a relevant mutation",
"control": "the same task and agent with the model-visible decision payload suppressed",
"outcome": "whether the final code tree implements a functionally viable approach the policy ruled out",
"forbidden_outcomes": [
"whether the agent mentioned a Record-Id",
"whether the agent repeated the record's wording",
"whether the agent stated the reason"
],
"why_it_holds": "the policy source is frozen before the study and the outcome is read from the final tree, so nothing the treatment says can satisfy the measurement by being said."
},
"forbidden_reintroduction": "No gate in this study may require a decision to be documented outside its record. A gate that does so under another name is the v4 gate returning, whatever it is called."
}
1 change: 1 addition & 0 deletions bench/cdeb/studies/cdeb-fresh-v5/deviations.jsonl
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"deviation_id": "CDEB-V5-SNAPSHOT-REUSE-OVER-RESNAPSHOT", "recorded_at": "2026-08-22T01:30:00Z", "kind": "named-deviation-from-default-preference", "basis": {"instruction": "the Stage 0 prompt prefers fresh v5 snapshots and permits reuse where materially safer, documented", "adopted": "reuse the sealed bundles frozen at 2026-08-20T22:08:19Z; the v5 study cutoff is that instant", "measurement": {"gitseed": {"new_commits_since_freeze": 0, "new_ruled_out_lines": 0}, "agent-operator-score": {"new_commits_since_freeze": 90, "new_ruled_out_lines": 0}, "logic-pro-mcp": {"new_commits_since_freeze": 72, "new_ruled_out_lines": 0}, "agent-control-plane": {"new_commits_since_freeze": 5, "new_ruled_out_lines": 14, "window": "2026-08-21T06:46 .. 2026-08-21T18:38"}}, "what_a_fresh_snapshot_would_add": "14 decisions, all of them in agent-control-plane, all authored on 2026-08-21 \u2014 inside the window in which v4's corpus shortfall was known. The other two moved repositories contributed 0 decisions across 162 commits, so a fresh snapshot would import the contaminated set and nothing else.", "content_assessment": "the 14 read as ordinary development \u2014 SQLite DDL migration, retry-rule semantics, a permit brand type, vitest signal handling \u2014 with nothing about CDEB in them. They are probably natural. They cannot be shown to be natural mechanically, and their timing cannot be undone."}, "closed_alternatives": ["re-snapshotting and admitting the 14, which adds candidates authored during the study to the repository sitting nearest the eligibility floor", "re-snapshotting and excluding the 14 by date, which is the same corpus as reuse with more moving parts and a cutoff that has to be defended anyway", "asking the owner to attest that the 14 are natural, which is owner testimony and is disabled"], "measured_data_exists": false, "reason": "The direction of this choice is against GO: it takes the smaller, older corpus and gives up the only candidates a fresh snapshot would have added, in the repository where they would have counted most. If v5 still reaches GO the result is stronger for it; if v5 holds, the 14 are reported by name and count so the owner can order a deliberate re-snapshot rather than have one smuggled in here."}
Empty file.
21 changes: 21 additions & 0 deletions bench/cdeb/studies/cdeb-fresh-v5/study.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
"study_id": "cdeb-fresh-v5",
"schema_version": 1,
"phase": "stage0-authority-corpus-feasibility",
"measured_run_allowed": false,
"construct": "A naturally recorded, pre-study CommitLore decision is itself a repository recorded-policy artifact.",
"primary_admission_authority": "A0",
"owner_testimony": "disabled",
"record_id_required": false,
"independent_corroboration_required": false,
"predecessors": ["cdeb-fresh-v3", "cdeb-fresh-v3r1", "cdeb-fresh-v4"],
"predecessor_status": "v3 and v3r1 invalidated; v4 stage0-hold. None resumable, no measured data in any.",
"predecessor_artifact_reuse": "infrastructure code only, after verification; no qualification outcome, reviewer verdict, task, gold, oracle, trajectory or result row",
"product_release_tag": "v1.2.0",
"product_release_commit": "90a8b212e1db70cccf69fbf48415b9c036b2d854",
"product_dist_sha256": "318e16612206ae0aa3732033127b2937276ce2f142872c33a91ec04a33133b91",
"study_cutoff": "2026-08-20T22:08:19Z",
"stage0_survey_repositories": ["gitseed", "agent-operator-score", "logic-pro-mcp", "agent-control-plane"],
"fixed_repository_set": null,
"created_at": "2026-08-22T01:30:00Z"
}
9 changes: 6 additions & 3 deletions test/cdeb-terminal-hardening.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -123,9 +123,12 @@ describe('CDEB terminal hardening', () => {
const successor = readFileSync(join(STUDY, 'SUCCESSOR.md'), 'utf8');
expect(prd).toContain('status: terminal-preserved');
expect(prd).toContain('must not be used to resume `cdeb-fresh-v3r1`');
expect(active).toMatchObject({ last_terminal_study_id: 'cdeb-fresh-v3r1', successor_requires_new_study_id: true });
expect(active.active_study_id).not.toBe('cdeb-fresh-v3r1');
expect(active.active_study_id).not.toBe('cdeb-fresh-v3');
expect(active).toMatchObject({ successor_requires_new_study_id: true });
// Whichever study holds the slot, no ended one may: the declaration names a
// successor and the resolver refuses the rest from their own status files.
for (const ended of ['cdeb-fresh-v3', 'cdeb-fresh-v3r1', 'cdeb-fresh-v4']) {
expect(active.active_study_id).not.toBe(ended);
}
expect(status).toMatchObject({ phase: 'invalidated', measured_run_allowed: false });
expect(successor).toContain('new study id');
expect(successor).toContain('new preregistration');
Expand Down
9 changes: 6 additions & 3 deletions test/cdeb-v4-stage0-governance.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,11 +76,14 @@ describe('CDEB v4 Stage 0 governance', () => {
expect(() => resolveActiveStudyRoot(unknownStatus)).toThrow(/Invalid active-study declaration/);
});

it('resolves cdeb-fresh-v4 as the active study with the measured run still shut', () => {
expect(resolveActiveStudyRoot(CDEB_ROOT)).toBe(V4);
it('has handed the active slot on and cannot take it back', () => {
// v4 reached HOLD and a successor now holds the slot. What has to stay true
// is not that v4 is active -- it is that v4 can never be active again while
// its own status says it ended.
expect(resolveActiveStudyRoot(CDEB_ROOT)).not.toBe(V4);
const status = readJson(join(V4, 'STATUS.json'));
const study = readJson(join(V4, 'study.json'));
expect(status).toMatchObject({ study_id: 'cdeb-fresh-v4', phase: 'stage0-corpus-feasibility', measured_run_allowed: false });
expect(status).toMatchObject({ study_id: 'cdeb-fresh-v4', phase: 'stage0-hold', measured_run_allowed: false, verdict: 'HOLD' });
expect(study).toMatchObject({ study_id: 'cdeb-fresh-v4', measured_run_allowed: false, record_id_required: false });
expect(study.predecessor_artifact_reuse).toBe('none');
expect(() => assertMeasuredRunAuthorized(V4)).toThrow(/measured_run_allowed is not true/);
Expand Down
Loading
Loading