Skip to content

Commit 4bb4868

Browse files
authored
Merge pull request #123 from operatorstack/codex/deltawire-supervisory-control
DeltaWire supervisory generation control
2 parents fc0e4c4 + c83f147 commit 4bb4868

28 files changed

Lines changed: 3262 additions & 23 deletions
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
name: DeltaWire supervisory control
2+
3+
on:
4+
push:
5+
branches: [codex/deltawire-supervisory-control]
6+
paths:
7+
- "labs/20-deltawire/**"
8+
- ".github/workflows/deltawire-supervision.yml"
9+
pull_request:
10+
paths:
11+
- "labs/20-deltawire/**"
12+
- ".github/workflows/deltawire-supervision.yml"
13+
14+
permissions:
15+
contents: read
16+
17+
jobs:
18+
validate-supervisor:
19+
runs-on: ubuntu-latest
20+
steps:
21+
- uses: actions/checkout@v7
22+
with:
23+
fetch-depth: 0
24+
- uses: actions/setup-go@v7
25+
with:
26+
go-version-file: labs/20-deltawire/go.mod
27+
- uses: actions/setup-python@v6
28+
with:
29+
python-version: "3.12"
30+
- name: Validate synthesized supervisor and deterministic framework corpus
31+
run: bash labs/20-deltawire/scripts/validate-supervision.sh
32+
- name: Validate complete DeltaWire lab
33+
run: bash labs/20-deltawire/scripts/validate.sh
34+
- name: Confirm no live provider boundary
35+
run: |
36+
forbidden_harbor='harbor[[:space:]]+'"run"
37+
forbidden_uvx='uvx.*har'"bor"
38+
forbidden_campaign='campaign.*--'"live"
39+
! grep -E "$forbidden_harbor|$forbidden_uvx|$forbidden_campaign" .github/workflows/deltawire-supervision.yml
40+
git diff --check

.github/workflows/deltawire-v7.yml

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,13 @@ jobs:
3131
- uses: astral-sh/setup-uv@v7
3232
- name: Build and stage the frozen Linux binary
3333
run: |
34-
cd labs/20-deltawire
34+
frozen_tree="$RUNNER_TEMP/deltawire-v7-terminal-evidence"
35+
git worktree add --detach "$frozen_tree" deltawire-v7-terminal-evidence
36+
cd "$frozen_tree/labs/20-deltawire"
37+
GOWORK=off CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -trimpath -buildvcs=false -o "$RUNNER_TEMP/deltawire-linux-amd64" ./cmd/deltawire
38+
cd "$GITHUB_WORKSPACE/labs/20-deltawire"
3539
mkdir -p eval/.generated eval/pairs/range-large-v7-r1/environment/.generated
36-
GOWORK=off CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -trimpath -buildvcs=false -o eval/.generated/deltawire-linux-amd64 ./cmd/deltawire
40+
cp "$RUNNER_TEMP/deltawire-linux-amd64" eval/.generated/deltawire-linux-amd64
3741
cp eval/.generated/deltawire-linux-amd64 eval/pairs/range-large-v7-r1/environment/.generated/deltawire
3842
test "$(sha256sum eval/.generated/deltawire-linux-amd64 | cut -d' ' -f1)" = e5198d15000e093a2a28e57ad4a093dde8f66bcab21462549ddf9114064c25f4
3943
- name: Validate skill examples using the actual Linux binary

.github/workflows/deltawire-v8.yml

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,13 @@ jobs:
3030
python-version: "3.12"
3131
- name: Stage the frozen Linux binary
3232
run: |
33-
cd labs/20-deltawire
33+
frozen_tree="$RUNNER_TEMP/deltawire-v7-terminal-evidence"
34+
git worktree add --detach "$frozen_tree" deltawire-v7-terminal-evidence
35+
cd "$frozen_tree/labs/20-deltawire"
36+
GOWORK=off CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -trimpath -buildvcs=false -o "$RUNNER_TEMP/deltawire-linux-amd64" ./cmd/deltawire
37+
cd "$GITHUB_WORKSPACE/labs/20-deltawire"
3438
mkdir -p eval/.generated
35-
GOWORK=off CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -trimpath -buildvcs=false -o eval/.generated/deltawire-linux-amd64 ./cmd/deltawire
39+
cp "$RUNNER_TEMP/deltawire-linux-amd64" eval/.generated/deltawire-linux-amd64
3640
test "$(sha256sum eval/.generated/deltawire-linux-amd64 | cut -d' ' -f1)" = e5198d15000e093a2a28e57ad4a093dde8f66bcab21462549ddf9114064c25f4
3741
cd ../..
3842
python3 labs/20-deltawire/eval/scripts/v8/generate_tasks.py

go.work.sum

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
22
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
33
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
4+
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
45
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

labs/20-deltawire/GAPS.md

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
# Supervisory generation-control gaps
2+
3+
Status: non-blocking follow-ups to the supervisory-control implementation in PR #123.
4+
5+
The main concept is working: a synthesized supervisor controls compile, stage, verify,
6+
promote, recovery, and abstention; strict YAML compiles to the existing JSON plan IR;
7+
an independent evaluator checks the generated bytes; and tested failures preserve the
8+
previous artifact. The deterministic evaluation and CI require no model calls.
9+
10+
These items are hardening or measurement improvements, not merge blockers.
11+
12+
## Higher-priority hardening
13+
14+
1. **Crash-durable promotion recovery.** Promotion has in-process rollback, but there is
15+
no durable journal spanning a process or machine crash between rename, state, and
16+
final-receipt writes. A future change should add a small write-ahead promotion record
17+
and recovery test matrix.
18+
2. **Stronger replay closure.** Stored receipts recheck the decision chain and released
19+
output. They could additionally bind and revalidate every retained lifecycle artifact,
20+
including the compiled plan, reference output, staged output, and engine state.
21+
3. **Narrow schema TOCTOU exposure.** Freeze schema bytes once and pass that immutable
22+
value through staging and verification rather than reopening the source path at later
23+
phases.
24+
4. **Pre-materialization resource bounds.** Reject obviously oversized finite products
25+
from their cardinality before expanding rows or compiling a plan.
26+
27+
## Lower-priority completeness
28+
29+
5. Preserve exact integer condition comparisons above JavaScript's safe-integer range;
30+
the current condition evaluator uses floating-point numeric comparison.
31+
6. Reject additional ambiguous YAML scalar spellings if interoperability demands a
32+
narrower lexical format.
33+
7. Increase common-mode independence between the compiler and reference evaluator by
34+
splitting any remaining shared low-level expansion helpers.
35+
8. Add an explicit direct-spec order assertion. Full byte comparison already detects
36+
ordering differences, but the source language does not expose order as an assertion.
37+
9. Harden artifact-path handling against concurrent symlink replacement and other
38+
filesystem races beyond the current path and staging checks.
39+
10. Expand the Pareto report with compiled-plan bytes, timing, and mutation-coverage
40+
metrics if those measurements become useful for selecting later AI candidates.
41+
42+
## Explicit boundaries
43+
44+
- The supervisor cannot infer incorrectly approved or unstated intent; external approval
45+
or a task oracle remains necessary.
46+
- The current proof is for the declared finite-state model and tested runtime boundary,
47+
not a claim against arbitrary operating-system, hardware, or privileged-adversary faults.
48+
- The deterministic comparison establishes correctness and interface size only. It does
49+
not establish model-token or cost savings without a later controlled AI evaluation.
50+

labs/20-deltawire/README.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,22 @@
11
# DeltaWire
22

33
In an exploratory 24-run pilot, the DeltaWire treatment used 24.2% fewer aggregate input-plus-output tokens than control. Both arms received full reward under the pilot’s existing verifiers. Semantic oracles, per-run pairing, and treatment-compliance evidence are being hardened before the confirmatory run.
4+
5+
## Supervised direct specifications
6+
7+
`deltawire supervise` accepts a strict, non-executable
8+
`deltawire.direct.v1` YAML specification, compiles it to the existing JSON
9+
plan, renders only in private staging, and independently interprets the direct
10+
specification. The synthesized finite-state supervisor is the sole authority
11+
that can atomically publish matching output:
12+
13+
```text
14+
deltawire supervise --repo . dataset.dw.yaml
15+
deltawire supervise --repo . --dry-run dataset.dw.yaml
16+
```
17+
18+
Failures and declared irregular workloads preserve the previous output and
19+
produce an abstained or failed-safe receipt under
20+
`.deltawire/supervision/runs/`. Existing JSON plan commands remain unchanged.
21+
See [the supervisory boundary](docs/12-supervisory-generation-control.md) for
22+
the state model, hazards, and deterministic framework-admission rules.
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
# DeltaWire supervisory generation control
2+
3+
## Boundary
4+
5+
The agent-facing mechanism proposes a finite dataset specification. It never
6+
owns the final output path. `deltawire supervise` freezes the specification,
7+
compiles it to the unchanged `deltawire.plan.v1` IR, renders in a private
8+
staging repository, and compares that result byte-for-byte with a separately
9+
implemented reference evaluator. Only the synthesized supervisor can enable
10+
atomic promotion.
11+
12+
The finite plant is modeled as a discrete-event system. Synthesis removes
13+
forbidden states, states with unsafe uncontrollable successors, and states that
14+
cannot reach a marked terminal. The resulting policy is maximally permissive
15+
within the declared model: a controllable event is disabled only when it leaves
16+
the safe, nonblocking region.
17+
18+
This proves artifact-release safety relative to an approved specification. It
19+
cannot prove that an approved specification captures an unstated human intent.
20+
That residual risk requires external approval, examples, or a task oracle.
21+
22+
## Modes and safe terminals
23+
24+
- `direct_spec`: parse and normalize the strict YAML proposal.
25+
- `json_ir`: execute the compiled, stable plan-v1 representation.
26+
- `recovery`: retain evidence and expose only safe recovery actions.
27+
- `abstained`: preserve the previous output when no admissible path succeeds.
28+
- `failed_safe`: preserve the previous output after an authority/evidence fault.
29+
30+
`released`, `abstained`, and `failed_safe` are marked terminal states. Unknown,
31+
missing, stale, replayed, or hash-inconsistent evidence can never enable
32+
publication.
33+
34+
## Hazard/control record v1
35+
36+
| Hazard | Prevention | Monitor and isolation | Reconfiguration / safe state | Executable evidence |
37+
| --- | --- | --- | --- | --- |
38+
| Incorrect approved intent | Make invocation approve an exact canonical spec hash | Report the residual-risk boundary; task oracles remain independent | Require a corrected, newly hashed spec | framework corpus and task-family oracles |
39+
| Ambiguous specification | Strict typed YAML; finite domains; mutually exclusive and exhaustive rules | Parser/evaluator diagnostics | abstained | direct-spec rejection tests |
40+
| Contract/schema tampering | Freeze canonical spec and schema hashes before compilation | Recheck hashes in the receipt chain | failed-safe | transition-chain and staging tests |
41+
| Compiler defect | Reference evaluator does not import compiler or DeltaWire engine | Byte comparison plus task oracle | abstained | differential fixtures and mutation tests |
42+
| DeltaWire runtime defect | Keep plan-v1 lifecycle validation and limits | Regeneration/check hash and reference comparison | abstained | lifecycle integration tests |
43+
| Common-mode verifier defect | Separate plan execution, direct evaluator, and evaluation-family oracle | Disagreement is isolated as reference failure | abstained | canonical family corpus |
44+
| Path escape or symlink | Existing safe-path rules and private fixed supervision root | Path resolution and regular-directory checks | failed-safe | store/path tests and CLI integration |
45+
| TOCTOU / partial write | Stage privately; promote by same-filesystem atomic rename | Post-promotion hash | rollback or failed-safe | publication fault injection |
46+
| Stale evidence | Content-addressed run identity and hash-linked transitions | Sequence, prior hash, policy hash, and state replay | failed-safe | receipt replay tests |
47+
| Resource exhaustion | Existing plan/schema/record/output limits; finite ranges only | Preflight counts and byte limits | abstained | limit tests |
48+
| Policy drift | Deterministic synthesized-policy hash in every transition | Replay against the current model | failed-safe | policy determinism tests |
49+
| Missing observation | No event and no transition authority | Release remains disabled | recovery then abstained | exhaustive state/event tests |
50+
| Unauthorized publication | Final path is absent from candidate authority; early promotion enters a forbidden state | Synthesized event policy | deny and preserve output | maximal-permissiveness and early-promotion tests |
51+
| Infrastructure corruption | Boundary failures are distinct from candidate failures | `DW_SUPERVISION_FAULT` and retained receipt | failed-safe | malformed state/evidence tests |
52+
53+
## Strict direct specification v1
54+
55+
The YAML surface supports exactly one primary construction: ordered Cartesian
56+
product, explicit rows, or base-plus-variants. Products may use finite ordered
57+
values or bounded integer ranges. Record templates preserve scalar types for an
58+
exact `${name}` placeholder. Structured rules use only `eq`, `ne`, `lt`, `lte`,
59+
`gt`, `gte`, `in`, `all`, `any`, or `otherwise`; there is no expression or code
60+
execution surface. Exceptions match finite domain or record fields and apply
61+
JSON-pointer `set`/`omit` operations.
62+
63+
Aliases, anchors, custom tags, merge keys, duplicate keys, unknown fields,
64+
non-string mapping keys, multiple documents, excessive nesting, and oversized
65+
specifications are rejected. `applicability: should_abstain` deliberately
66+
selects the safe abstention path.
67+
68+
## Deterministic admission
69+
70+
`eval/supervision/evaluate_frameworks.py` compares strict YAML with a
71+
hand-authored JSON plan on the same semantic cases. It performs no model or
72+
provider call. A framework becomes an AI-evaluation candidate only when all
73+
applicable outputs are exact and deterministic, all supervisory tests pass,
74+
irregular work abstains, and YAML is smaller than JSON on the high-fit range
75+
and matrix cases. This is admission to a later experiment, not a token-savings
76+
claim.
Lines changed: 84 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,86 @@
11
#!/usr/bin/env python3
2-
import argparse,hashlib,json,subprocess
2+
import argparse
3+
import hashlib
4+
import json
5+
import re
6+
import subprocess
37
from pathlib import Path
4-
ROOT=Path(__file__).resolve().parents[5]
5-
def sha(path): return hashlib.sha256(Path(path).read_bytes()).hexdigest()
6-
def main():
7-
parser=argparse.ArgumentParser(); parser.add_argument("--manifest",required=True); args=parser.parse_args(); value=json.loads(Path(args.manifest).read_text()); checks={"schema":value.get("schema_version")=="deltawire-v8-campaign-manifest.v1","not_ready":value.get("READY_FOR_72") is False,"attempt_ceiling":value.get("attempt_ceiling")==26,"image_platform_manifest":str(value.get("image_platform_manifest","")).startswith("sha256:") and len(value.get("image_platform_manifest",""))==71,"schedule":value.get("schedule_sha256")==sha(ROOT/"labs/20-deltawire/eval/campaigns/v8/schedule.json"),"ancestor":subprocess.run(["git","merge-base","--is-ancestor",value.get("infrastructure_commit",""),"HEAD"],cwd=ROOT).returncode==0,"inputs":all((ROOT/path).is_file() and sha(ROOT/path)==expected for path,expected in value.get("input_hashes",{}).items()),"evidence":all((ROOT/path).is_file() and sha(ROOT/path)==expected for path,expected in value.get("evidence_hashes",{}).items())}; report={"schema_version":"deltawire-v8-manifest-verification.v1","status":"pass" if all(checks.values()) else "fail","checks":checks}; print(json.dumps(report,indent=2,sort_keys=True)); raise SystemExit(0 if report["status"]=="pass" else 1)
8-
if __name__=="__main__": main()
8+
9+
10+
ROOT = Path(__file__).resolve().parents[5]
11+
12+
13+
def sha_bytes(value: bytes) -> str:
14+
return hashlib.sha256(value).hexdigest()
15+
16+
17+
def sha_file(path: Path) -> str:
18+
return sha_bytes(path.read_bytes())
19+
20+
21+
def git_blob(commit: str, path: str) -> bytes | None:
22+
result = subprocess.run(
23+
["git", "show", f"{commit}:{path}"],
24+
cwd=ROOT,
25+
check=False,
26+
capture_output=True,
27+
)
28+
return result.stdout if result.returncode == 0 else None
29+
30+
31+
def frozen_hashes_match(commit: str, expected: dict[str, str]) -> bool:
32+
for path, wanted in expected.items():
33+
value = git_blob(commit, path)
34+
if value is None or sha_bytes(value) != wanted:
35+
return False
36+
return True
37+
38+
39+
def live_hashes_match(expected: dict[str, str]) -> bool:
40+
return all(
41+
(ROOT / path).is_file() and sha_file(ROOT / path) == wanted
42+
for path, wanted in expected.items()
43+
)
44+
45+
46+
def main() -> int:
47+
parser = argparse.ArgumentParser()
48+
parser.add_argument("--manifest", required=True)
49+
args = parser.parse_args()
50+
51+
value = json.loads(Path(args.manifest).read_text())
52+
commit = value.get("infrastructure_commit", "")
53+
commit_valid = bool(re.fullmatch(r"[0-9a-f]{40}", commit))
54+
ancestor = (
55+
commit_valid
56+
and subprocess.run(
57+
["git", "merge-base", "--is-ancestor", commit, "HEAD"],
58+
cwd=ROOT,
59+
check=False,
60+
).returncode
61+
== 0
62+
)
63+
schedule = git_blob(commit, "labs/20-deltawire/eval/campaigns/v8/schedule.json") if commit_valid else None
64+
65+
checks = {
66+
"schema": value.get("schema_version") == "deltawire-v8-campaign-manifest.v1",
67+
"not_ready": value.get("READY_FOR_72") is False,
68+
"attempt_ceiling": value.get("attempt_ceiling") == 26,
69+
"image_platform_manifest": str(value.get("image_platform_manifest", "")).startswith("sha256:")
70+
and len(value.get("image_platform_manifest", "")) == 71,
71+
"schedule": schedule is not None and sha_bytes(schedule) == value.get("schedule_sha256"),
72+
"ancestor": ancestor,
73+
"inputs": commit_valid and frozen_hashes_match(commit, value.get("input_hashes", {})),
74+
"evidence": live_hashes_match(value.get("evidence_hashes", {})),
75+
}
76+
report = {
77+
"schema_version": "deltawire-v8-manifest-verification.v1",
78+
"status": "pass" if all(checks.values()) else "fail",
79+
"checks": checks,
80+
}
81+
print(json.dumps(report, indent=2, sort_keys=True))
82+
return 0 if report["status"] == "pass" else 1
83+
84+
85+
if __name__ == "__main__":
86+
raise SystemExit(main())

0 commit comments

Comments
 (0)