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
7 changes: 7 additions & 0 deletions .buildkite/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,13 @@
Buildkite runs repository checks on pull requests and the default branch.
Pull-request builds also run changed-code Fallow, package inspection, and
exact-head product validation.
OS-neutral gates run on the included `macos-medium` M4 queue. Each Git-using
step fails closed unless Git is at least 2.50.1 and below 3.0.0 and the exact
bundle, ancestry, and commit-resolution capabilities used by Tabellio pass.
The gate records the actual Git version, architecture, and OS as hosted
evidence; CI does not build or download an architecture-specific Git artifact.
Linux queues are reserved for an explicit published-artifact compatibility
contract and are not used by this pipeline.
The product-validation step exports the Git validation ref as a portable bundle
instead of treating an internal `.git` ref as a workspace artifact.

Expand Down
15 changes: 5 additions & 10 deletions .buildkite/pipeline.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,22 +3,20 @@ env:
NO_COLOR: "1"

agents:
queue: "linux-small"
queue: "macos-medium"

steps:
- label: ":git: Git 2.50.1"
- label: ":git: Supported Git"
key: "git-toolchain"
command: "bash .buildkite/scripts/build-modern-git.sh"
if: build.pull_request.id != null || build.env("TABELLIO_BUILD_CONTEXT") == "preflight" || build.branch == pipeline.default_branch
timeout_in_minutes: 15
command: "bash .buildkite/scripts/verify-git-toolchain.sh"
timeout_in_minutes: 2
artifact_paths:
- ".artifacts/toolchain/git-2.50.1-linux-amd64.tar.gz"
- "tabellio-git-toolchain.json"

- label: ":test_tube: Repository check"
key: "repository-check"
command: "bash .buildkite/scripts/tests.sh"
depends_on: "git-toolchain"
if: build.pull_request.id != null || build.env("TABELLIO_BUILD_CONTEXT") == "preflight" || build.branch == pipeline.default_branch
timeout_in_minutes: 10
artifact_paths:
- "tabellio-pr-evidence.json"
Expand All @@ -30,7 +28,6 @@ steps:
key: "fallow"
command: "bash .buildkite/scripts/fallow.sh"
depends_on: "git-toolchain"
if: build.pull_request.id != null || build.env("TABELLIO_BUILD_CONTEXT") == "preflight" || build.branch == pipeline.default_branch
timeout_in_minutes: 10
artifact_paths:
- "fallow-audit.json"
Expand All @@ -41,7 +38,6 @@ steps:
- label: ":package: Package dry-run"
key: "package"
command: "bash .buildkite/scripts/package.sh"
if: build.pull_request.id != null || build.env("TABELLIO_BUILD_CONTEXT") == "preflight" || build.branch == pipeline.default_branch
timeout_in_minutes: 10
artifact_paths:
- "package-dry-run.json"
Expand All @@ -53,7 +49,6 @@ steps:
key: "product-validation"
command: "bash .buildkite/scripts/product-validation.sh"
Comment thread
hudsonaikins marked this conversation as resolved.
depends_on: "git-toolchain"
if: build.pull_request.id != null || build.env("TABELLIO_BUILD_CONTEXT") == "preflight" || build.branch == pipeline.default_branch
timeout_in_minutes: 50
artifact_paths:
- "tabellio-validation-result.json"
Expand Down
74 changes: 0 additions & 74 deletions .buildkite/scripts/build-modern-git.sh

This file was deleted.

2 changes: 1 addition & 1 deletion .buildkite/scripts/fallow.sh
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#!/usr/bin/env bash
set -euo pipefail

. .buildkite/scripts/use-modern-git.sh
. .buildkite/scripts/verify-git-toolchain.sh

build_context="${TABELLIO_BUILD_CONTEXT:-provider}"
if [[ "${BUILDKITE_PULL_REQUEST:-false}" == "false" && "$build_context" != "preflight" ]]; then
Expand Down
6 changes: 3 additions & 3 deletions .buildkite/scripts/product-validation.sh
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,11 @@ if [[ "$pull_request" == "false" && "$pipeline_branch" == "$default_branch" ]];
default_branch_build=true
fi
if [[ "$pull_request" == "false" && "$build_context" != "preflight" && "$default_branch_build" != "true" ]]; then
printf '%s\n' "Buildkite product validation requires a pull request, default-branch build, or explicit preflight build." >&2
exit 2
printf '%s\n' '{"decision":"not_required","reason":"product validation runs on pull requests, the default branch, or explicit preflight builds."}' > tabellio-validation-result.json
exit 0
fi

. .buildkite/scripts/use-modern-git.sh
. .buildkite/scripts/verify-git-toolchain.sh
Comment thread
hudsonaikins marked this conversation as resolved.

candidate="${BUILDKITE_COMMIT:-HEAD}"
base_branch="${BUILDKITE_PULL_REQUEST_BASE_BRANCH:-${TABELLIO_BASE_BRANCH:-main}}"
Expand Down
2 changes: 1 addition & 1 deletion .buildkite/scripts/tests.sh
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#!/usr/bin/env bash
set -euo pipefail

. .buildkite/scripts/use-modern-git.sh
. .buildkite/scripts/verify-git-toolchain.sh
npm run check
node scripts/write-tabellio-evidence-envelope.mjs --out tabellio-pr-evidence.json
node scripts/check-tabellio-evidence-envelope.mjs --evidence tabellio-pr-evidence.json
Expand Down
17 changes: 0 additions & 17 deletions .buildkite/scripts/use-modern-git.sh

This file was deleted.

62 changes: 62 additions & 0 deletions .buildkite/scripts/verify-git-toolchain.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
#!/usr/bin/env bash
set -euo pipefail

minimum_version="2.50.1"
maximum_version="3.0.0"

version_number() {
local version="$1"
if [[ ! "$version" =~ ^([0-9]+)\.([0-9]+)\.([0-9]+)$ ]]; then
printf 'Tabellio CI requires a semantic Git version; found %s.\n' "$version" >&2
return 1
fi
printf '%09d%09d%09d\n' "${BASH_REMATCH[1]}" "${BASH_REMATCH[2]}" "${BASH_REMATCH[3]}"
}

check_supported_version() {
local version="$1"
local actual minimum maximum
actual="$(version_number "$version")" || return 1
minimum="$(version_number "$minimum_version")"
maximum="$(version_number "$maximum_version")"
if [[ "$actual" < "$minimum" || "$actual" > "$maximum" || "$actual" == "$maximum" ]]; then
printf 'Tabellio CI requires Git >=%s and <%s; found %s.\n' \
"$minimum_version" "$maximum_version" "$version" >&2
return 1
fi
}

if [[ "${1:-}" == "--check-version" ]]; then
[[ "$#" == 2 ]] || {
printf '%s\n' "usage: verify-git-toolchain.sh --check-version <version>" >&2
exit 2
}
check_supported_version "$2"
exit
fi

actual_version="$(git version | awk '{ print $3 }')"
check_supported_version "$actual_version"

head_commit="$(git rev-parse --verify 'HEAD^{commit}')"
git merge-base --is-ancestor "$head_commit" "$head_commit"

(
temporary_dir="$(mktemp -d)"
trap 'rm -rf "$temporary_dir"' EXIT
git bundle create "$temporary_dir/capability.bundle" --all
git bundle verify "$temporary_dir/capability.bundle" >/dev/null
)

architecture="$(uname -m)"
operating_system="$(uname -s)"
evidence_path="${TABELLIO_GIT_EVIDENCE_PATH:-tabellio-git-toolchain.json}"
if [[ ! "$architecture" =~ ^[A-Za-z0-9._-]+$ || ! "$operating_system" =~ ^[A-Za-z0-9._-]+$ ]]; then
printf '%s\n' "Tabellio CI could not record a portable architecture/OS identity." >&2
exit 1
fi

printf '{"schemaVersion":"tabellio-git-toolchain/v0.1","gitVersion":"%s","architecture":"%s","os":"%s","capabilities":["bundle-create-verify","merge-base-is-ancestor","rev-parse-commit"]}\n' \
"$actual_version" "$architecture" "$operating_system" > "$evidence_path"
printf 'Git %s supported on %s/%s; required capabilities passed.\n' \
"$actual_version" "$operating_system" "$architecture"
24 changes: 24 additions & 0 deletions .tabellio/validators.json
Original file line number Diff line number Diff line change
Expand Up @@ -348,6 +348,30 @@
"metrics": [{"name": "baseline_integration_security_pass", "unit": "boolean", "passValue": 1, "failValue": 0}],
"cost": {"telemetry": "available", "usd": 0, "modelCalls": 0, "toolCalls": 0},
"summary": "Packaged artifact completeness and private-evidence boundaries"
},
"wave-admission-schema": {
"commands": [["node", "--test", "--test-name-pattern", "^schema accepts", "tests/wave-admission.test.mjs"]],
"metrics": [{"name": "wave_admission_schema_pass", "unit": "boolean", "passValue": 1, "failValue": 0}],
"cost": {"telemetry": "available", "usd": 0, "modelCalls": 0, "toolCalls": 0},
"summary": "Wave manifest structure and bounded identity contract"
},
"wave-admission-semantic": {
"commands": [["node", "--test", "--test-name-pattern", "^negative matrix", "tests/wave-admission.test.mjs"]],
"metrics": [{"name": "wave_admission_negative_pass", "unit": "boolean", "passValue": 1, "failValue": 0}],
"cost": {"telemetry": "available", "usd": 0, "modelCalls": 0, "toolCalls": 0},
"summary": "Stable fail-closed admission reasons"
},
"wave-admission-workflow": {
"commands": [["node", "--test", "--test-name-pattern", "workflow accepts|CLI renders", "tests/wave-admission.test.mjs"]],
"metrics": [{"name": "wave_admission_workflow_pass", "unit": "boolean", "passValue": 1, "failValue": 0}],
"cost": {"telemetry": "available", "usd": 0, "modelCalls": 0, "toolCalls": 0},
"summary": "Three-repository admission and rejection demo"
},
"wave-admission-security": {
"commands": [["node", "--test", "--test-name-pattern", "^security rejects", "tests/wave-admission.test.mjs"]],
"metrics": [{"name": "wave_admission_security_pass", "unit": "boolean", "passValue": 1, "failValue": 0}],
"cost": {"telemetry": "available", "usd": 0, "modelCalls": 0, "toolCalls": 0},
"summary": "Repository path safety and no-external-action boundary"
}
}
}
50 changes: 50 additions & 0 deletions docs/wave-admission.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
# Wave Admission

Wave admission answers one question before parallel implementation starts:
which lanes are safe to pull now?

The manifest binds each lane to explicit Plane, repository, task, base-commit,
owned-surface, dependency, WIP, and integration-owner evidence. Admission is a
pure local decision. It does not start tasks, update Plane, call providers,
merge, deploy, or release.

## Contract

Use `tabellio-wave-manifest/v0.1` from
`schemas/wave-manifest.v0.1.schema.json`.

A lane is rejected when:

| Code | Meaning |
| --- | --- |
| `LANE_NOT_READY` | Plane state is not exactly `Ready`. |
| `WIP_LIMIT_EXCEEDED` | Existing plus requested WIP exceeds manifest limit, capped at three. |
| `DEPENDENCY_INCOMPLETE` | Declared dependency is not complete. |
| `MAPPING_MISSING` | Plane, repository, and task mapping cannot be resolved. |
| `SURFACE_OVERLAP` | Two lanes claim intersecting surfaces in one repository. |
| `STALE_BASE` | Planned and observed base commits differ. |
| `INTEGRATOR_MISSING` | Final integration owner does not resolve to a mapping. |
| `SURFACE_INVALID` | Owned surface is not a safe repository-relative path or `/**` prefix. |
| `DUPLICATE_IDENTITY` | Mapping, task, lane, or story identity is duplicated. |

Reason ordering and wording are deterministic.

## Demo

```bash
node scripts/tabellio-wave-admit.mjs \
--manifest examples/tabellio-wave/accepted-three-repository.json

node scripts/tabellio-wave-admit.mjs \
--manifest examples/tabellio-wave/rejected-overlap-dependency.json
```

First command accepts three independent Ready lanes. Second rejects overlapping
Tabellio surfaces and an incomplete dependency with stable reason codes.

## Boundary

Manifest is snapshot evidence supplied by operator or coordinator. Admission
does not query Plane or Git, and cannot infer links from names or timing.
Callers must build mappings from authoritative identifiers and refresh observed
base commits before each admission decision.
47 changes: 47 additions & 0 deletions examples/tabellio-wave/accepted-three-repository.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
{
"schemaVersion": "tabellio-wave-manifest/v0.1",
"id": "intb-282-accepted-demo",
"capturedAt": "2026-07-31T18:00:00Z",
"wip": {"limit": 3, "started": 0},
"finalIntegrator": {"mappingId": "tabellio", "owner": "Tabellio repository owner"},
"mappings": [
{"id": "tabellio", "planeProject": "INTB", "repository": "IntelIP/Tabellio", "taskId": "task-tabellio"},
{"id": "contexenda", "planeProject": "CTX", "repository": "IntelIP/Contexenda", "taskId": "task-contexenda"},
{"id": "vaticor", "planeProject": "VATI", "repository": "IntelIP/vaticor", "taskId": "task-vaticor"}
],
"lanes": [
{
"id": "wave-admission",
"mappingId": "tabellio",
"storyId": "INTB-282",
"state": "Ready",
"baseCommit": "1111111111111111111111111111111111111111",
"observedBaseCommit": "1111111111111111111111111111111111111111",
"ownedSurfaces": ["schemas/wave-manifest.v0.1.schema.json", "scripts/lib/wave-admission.mjs"],
"dependencies": [],
"wipSlots": 1
},
{
"id": "docx-fixtures",
"mappingId": "contexenda",
"storyId": "CTX-25",
"state": "Ready",
"baseCommit": "2222222222222222222222222222222222222222",
"observedBaseCommit": "2222222222222222222222222222222222222222",
"ownedSurfaces": ["tests/fixtures/docx/**"],
"dependencies": [{"storyId": "CTX-24", "status": "completed"}],
"wipSlots": 1
},
{
"id": "paper-eval",
"mappingId": "vaticor",
"storyId": "VATI-12",
"state": "Ready",
"baseCommit": "3333333333333333333333333333333333333333",
"observedBaseCommit": "3333333333333333333333333333333333333333",
"ownedSurfaces": ["evals/paper/**"],
"dependencies": [],
"wipSlots": 1
}
]
}
Loading
Loading