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
18 changes: 16 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,15 @@ All notable changes to Tabellio are recorded here.

## Unreleased

## 0.2.0 - 2026-07-15

### Added

- GitHub-bound exact-commit validation runner with committed argv manifests and no shell execution.
- Bounded SHA-256 output evidence, detached worktree cleanup, and durable results on `refs/tabellio/validations`.
- Local validation results integrated into durable review readiness.
- Git-native JSON ledger on compare-and-swap refs for durable control-plane state.
- Durable review cycles covering GitHub feedback, agent findings, triage, checks, fixes, and readiness.
- Dry-run-first, atomic review-cycle migration from legacy v0.1 identities and PR numbers to GitHub-only v0.2 state.
- Entire-checkpoint-bound fix records with commit remapping across git-spice restacks.
- Approval-gated git-spice submit, update, sync, restack, and merge operations.
- Integrity-bound operation intents, short-lived approvals, one-use receipts, and branch-set race checks.
Expand All @@ -33,7 +34,8 @@ All notable changes to Tabellio are recorded here.

### Fixed

- Removed 15 unused public exports and consolidated provider subprocess handling; inherited Fallow dead-code findings dropped from 49 to 34 without deleting runtime interface methods.
- Removed 15 unused public exports and consolidated provider subprocess handling.
- Classified all 34 reported interface and injected class methods against runtime and test call sites, then added narrow stale-checked Fallow suppressions; unresolved dead-code findings are zero.
- Evidence artifact self-integrity now has an explicit canonical hash scope.
- Handwritten policy validators now require approval booleans, unique action IDs, and non-empty forbidden side effects.
- Runtime context validation now matches schema property boundaries.
Expand All @@ -51,6 +53,18 @@ All notable changes to Tabellio are recorded here.
- Made GitHub `origin` the canonical code store and thin pull-request shell while keeping agent control state external.
- Rejected publication or fetching of review, validation, and Entire control refs through the code-storage remote.

### Removed

- Retired the completed one-time legacy review-cycle migration command, decoder, remap helpers, documentation, and fixtures. Recovery code remains available in Git history.

### Release Gates

- `npm run check`
- Fallow whole-repository dead-code and stale-suppression scan
- Fallow changed-code audit against `origin/main`
- `npm pack --dry-run --json`
- Exact-head Tabellio validation

## 0.1.0 - 2026-07-08

Initial public release.
Expand Down
2 changes: 1 addition & 1 deletion docs/evidence-schema.md
Original file line number Diff line number Diff line change
Expand Up @@ -117,4 +117,4 @@ node scripts/write-tabellio-evidence-envelope.mjs \

## Boundary

This schema is simpler than SLSA provenance or in-toto link metadata. Future versions can export to those formats, but v0.1.0 does not claim compliance.
This schema is simpler than SLSA provenance or in-toto link metadata. Future versions can export to those formats, but Tabellio does not claim compliance.
37 changes: 0 additions & 37 deletions docs/review-loop.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,43 +42,6 @@ node scripts/tabellio-review.mjs sync \

Sync imports GitHub reviews, inline review comments, issue comments, commit statuses, check runs, and the newest Tabellio validation for the PR head. `GITHUB_TOKEN` may replace `--token-file`; `GITHUB_API_URL` or `--api-url` may target GitHub Enterprise Server. Missing GitHub items are retained as stale evidence rather than silently deleted. A PR with no validation remains `validating`.

## Migrate A v0.1 Cycle

Review cycles created before the GitHub-only boundary use `tabellio-review-cycle/v0.1` and a legacy ledger path. Preview the deterministic migration first:

```bash
node scripts/tabellio-review.mjs migrate \
--repo . \
--repo-id IntelIP/Tabellio \
--owner IntelIP \
--remote-repo Tabellio \
--number 7 \
--target-number 14 \
--legacy-repo-id old-owner/old-repository \
--legacy-owner old-owner \
--legacy-remote-repo old-repository
```

Apply the verified plan explicitly:

```bash
node scripts/tabellio-review.mjs migrate \
--repo . \
--repo-id IntelIP/Tabellio \
--owner IntelIP \
--remote-repo Tabellio \
--number 7 \
--target-number 14 \
--legacy-repo-id old-owner/old-repository \
--legacy-owner old-owner \
--legacy-remote-repo old-repository \
--apply true
```

`--number` identifies the legacy cycle. `--target-number` identifies the corresponding GitHub pull request and defaults to `--number`. Legacy identity options default to the target coordinates, so they are needed only when the repository moved or was renamed. The migration verifies the v0.1 integrity digest and source identity, maps repository and provider identity to the GitHub target, rewrites feedback sources, replaces the pull-request URL with its canonical GitHub URL, clears obsolete provider check links, recomputes integrity, and atomically moves the ledger entry to its v0.2 path. It can also atomically correct a previously migrated cycle whose GitHub PR number was mapped incorrectly; that recovery path additionally requires `--remap-current true`. The current ledger tree contains only the v0.2 entry; prior forms remain recoverable from Git history. Repeating the command reports `current` without writing another commit.

Migration marks the provider-owned change-request ID as pending. Run `sync` for the target GitHub PR immediately after applying so GitHub refreshes the ID, title, state, head/base commits, feedback, and checks.

## Import A Codex Review

Codex and other agents emit `tabellio-agent-review/v0.1`:
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@intelip/tabellio",
"version": "0.1.0",
"version": "0.2.0",
"description": "Tabellio: GitHub-native context and evidence for agentic development.",
"type": "module",
"license": "Apache-2.0",
Expand Down
4 changes: 4 additions & 0 deletions scripts/lib/agent-run.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ export class AgentRunManager {
});
}

// fallow-ignore-next-line unused-class-member
async checkpoint({ runId, summary }) {
return this.#withLock(runId, async () => {
const state = await this.#readState(runId);
Expand Down Expand Up @@ -132,6 +133,7 @@ export class AgentRunManager {
});
}

// fallow-ignore-next-line unused-class-member
async finish({ runId, validationCommand, onValidationOutput = null }) {
return this.#withLock(runId, async () => {
const state = await this.#readState(runId);
Expand Down Expand Up @@ -221,6 +223,7 @@ export class AgentRunManager {
});
}

// fallow-ignore-next-line unused-class-member
async promote({ runId }) {
return this.#withLock(runId, async () => {
const state = await this.#readState(runId);
Expand All @@ -247,6 +250,7 @@ export class AgentRunManager {
});
}

// fallow-ignore-next-line unused-class-member
async status({ runId }) {
return this.#result(await this.#readState(runId));
}
Expand Down
1 change: 1 addition & 0 deletions scripts/lib/control-ref-transport.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@ export class ApprovedControlRefTransport {
});
}

// fallow-ignore-next-line unused-class-member
async execute({ intent, approval, repositoryId, now = new Date() }) {
validateControlRefIntent(intent);
validateControlRefApproval(approval, intent, { now });
Expand Down
3 changes: 3 additions & 0 deletions scripts/lib/git-json-ledger.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ export class GitJsonLedger {
return result.exitCode === 0 ? result.stdout.trim() : null;
}

// fallow-ignore-next-line unused-class-member
async read(path) {
validateLedgerPath(path);
const version = await this.version();
Expand All @@ -52,6 +53,7 @@ export class GitJsonLedger {
}
}

// fallow-ignore-next-line unused-class-member
async list(prefix = "") {
if (prefix !== "") validateLedgerPath(prefix.replace(/\/$/, ""));
const version = await this.version();
Expand All @@ -65,6 +67,7 @@ export class GitJsonLedger {
};
}

// fallow-ignore-next-line unused-class-member
async write(path, value, { expectedVersion, replacePath = null }) {
validateLedgerPath(path);
if (replacePath !== null) {
Expand Down
2 changes: 2 additions & 0 deletions scripts/lib/ledger-provider.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,13 @@ export class LedgerProvider {
}

/** @param {{repositoryId: string, baseRevision: string, headRevision: string, capturedAt?: string}} options */
// fallow-ignore-next-line unused-class-member
async snapshot(_options) {
throw new Error("LedgerProvider.snapshot must be implemented.");
}

/** @param {unknown} snapshot */
// fallow-ignore-next-line unused-class-member
contextReferences(_snapshot) {
throw new Error("LedgerProvider.contextReferences must be implemented.");
}
Expand Down
9 changes: 9 additions & 0 deletions scripts/lib/repository-store.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,13 @@ export class RepositoryStore {
}

/** @param {string} revision @returns {Promise<string[]>} */
// fallow-ignore-next-line unused-class-member
async listFiles(_revision) {
throw new Error("RepositoryStore.listFiles must be implemented.");
}

/** @param {string} baseRevision @param {string} headRevision */
// fallow-ignore-next-line unused-class-member
async getDiff(_baseRevision, _headRevision) {
throw new Error("RepositoryStore.getDiff must be implemented.");
}
Expand All @@ -20,26 +22,31 @@ export class RepositoryStore {
}

/** @param {string} ref */
// fallow-ignore-next-line unused-class-member
async hasRef(_ref) {
throw new Error("RepositoryStore.hasRef must be implemented.");
}

/** @param {{path: string, branch: string, startPoint: string}} options */
// fallow-ignore-next-line unused-class-member
async createWorkspace(_options) {
throw new Error("RepositoryStore.createWorkspace must be implemented.");
}

/** @param {{path: string, force?: boolean}} options */
// fallow-ignore-next-line unused-class-member
async removeWorkspace(_options) {
throw new Error("RepositoryStore.removeWorkspace must be implemented.");
}

/** @param {string} revision @param {{notesRef?: string}} options */
// fallow-ignore-next-line unused-class-member
async readNote(_revision, _options = {}) {
throw new Error("RepositoryStore.readNote must be implemented.");
}

/** @param {string} revision @param {{notesRef?: string, note: string}} options */
// fallow-ignore-next-line unused-class-member
async writeNote(_revision, _options) {
throw new Error("RepositoryStore.writeNote must be implemented.");
}
Expand All @@ -50,6 +57,7 @@ export class RepositoryStore {
}

/** @param {{base: string, head: string}} options */
// fallow-ignore-next-line unused-class-member
async previewMerge(_options) {
throw new Error("RepositoryStore.previewMerge must be implemented.");
}
Expand All @@ -60,6 +68,7 @@ export class RepositoryStore {
}

/** @param {{ref: string, newRevision: string, expectedOldCommit: string}} options */
// fallow-ignore-next-line unused-class-member
async fastForwardRef(_options) {
throw new Error("RepositoryStore.fastForwardRef must be implemented.");
}
Expand Down
Loading