Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
57ea234
feat(validators): nothing-built inverse completion gate
anandgupta42 Aug 29, 2026
5a71009
feat(validators): build-green completion gate
anandgupta42 Aug 29, 2026
8b15d9a
feat(validators): literal-deliverable (spec-name) completion gate
anandgupta42 Aug 29, 2026
830e444
feat(validators): incremental-config consistency lint
anandgupta42 Aug 29, 2026
13b21d9
feat(validators): dialect-guard lint
anandgupta42 Aug 29, 2026
a659dad
docs: engine-split assessment for the two parse-level completion checks
anandgupta42 Aug 29, 2026
b6ecfaa
fix(validators): scope build-green failure counts correctly
anandgupta42 Aug 29, 2026
39781d8
test(validators): pin the lane's registration list
anandgupta42 Aug 29, 2026
14747ac
docs: placement assessment for the five shipped completion-gate valid…
anandgupta42 Aug 29, 2026
6626c46
docs: end-to-end evidence for the five completion-gate validators
anandgupta42 Aug 29, 2026
006bc8f
fix(validators): close the false positives the completion gates fire …
anandgupta42 Aug 29, 2026
8f0f9d8
fix(validators): close the review backlog on the deterministic comple…
anandgupta42 Aug 29, 2026
08abaae
fix(validators): keep the two run-results exemption axes independent
anandgupta42 Aug 29, 2026
b5c5d63
fix(validators): second review wave on the completion gates
anandgupta42 Aug 29, 2026
e8502ab
docs(validators): record the dialect-guard branch-semantics gap as a …
anandgupta42 Aug 29, 2026
7aa9087
fix(validators): inspect elif arms and bound the is_incremental() match
anandgupta42 Aug 29, 2026
28fb92d
fix(validators): close the build-provenance holes the consensus revie…
anandgupta42 Aug 30, 2026
7c09cc1
fix(validators): a delivered-but-untouched deliverable must satisfy t…
anandgupta42 Aug 30, 2026
af6f241
fix(validators): address the bot review wave on the consensus fixes
anandgupta42 Aug 30, 2026
3b944fe
fix(validators): make the unknown-command fallback permissive all the…
anandgupta42 Aug 30, 2026
dd858ef
fix(validators): second review sweep — under-firing gates and blockin…
anandgupta42 Aug 31, 2026
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
516 changes: 516 additions & 0 deletions .github/meta/harness-review-followups.md

Large diffs are not rendered by default.

252 changes: 252 additions & 0 deletions docs/internal/deterministic-checks-engine-split.md

Large diffs are not rendered by default.

625 changes: 625 additions & 0 deletions docs/internal/validator-e2e-evidence.md

Large diffs are not rendered by default.

436 changes: 436 additions & 0 deletions packages/opencode/src/altimate/validators/dbt-build-green.ts

Large diffs are not rendered by default.

175 changes: 175 additions & 0 deletions packages/opencode/src/altimate/validators/dbt-deliverable-names.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
// altimate_change start — literal deliverable / spec-name completion gate
/**
* Literal-deliverable (spec-name) gate.
*
* A recurring, fully deterministic loss mode in evaluation traces: the work is
* functionally reasonable but shipped under self-chosen names — a prefix
* added, a plural dropped, a "v2" suffix, or an entirely different noun — and
* the agent then self-verifies against its own renamed output and reports
* success. The literal contract in the task document is never re-read.
*
* This gate re-reads it. It compares the deliverable names the task states
* **literally** against the names the project actually defines, and refuses
* to terminate when a required name is absent.
*
* Conservatism is the whole design:
* - Required names come only from `extractRequiredDeliverables`, which
* accepts a name solely from an explicit declaration marker, a
* deliverables section, or a requirement line — and only when it sits in
* an inline code span and is identifier- or path-shaped. There is no
* fuzzy matching and no inference.
* - When no required-names source is discoverable, `appliesTo` returns
* false and the session is never inspected. Silence, never a guess.
* - Produced names are the union of the filesystem inventory and every
* `manifest.json` name/alias, so an aliased relation cannot read as
* missing.
* - Comparison is exact (case-insensitive only). A near-miss name is
* reported as a possible substitute in the hint, never accepted as the
* deliverable.
*
* Deliberately out of scope: required *column* names. Asserting a column
* exists means resolving `select *`, CTEs and upstream schemas — real SQL
* analysis, not a filesystem inventory — so it is not attempted here rather
* than attempted badly.
*/

import { promises as fs } from "fs"
import { join } from "path"
import type { Validator, ValidatorContext, ValidatorResult } from "../../session/validators/types"
import {
findDbtProjectRoot,
findTaskInstructionFiles,
extractRequiredDeliverables,
collectProducedNodeNames,
modelsModifiedSince,
modelNameFromPath,
type RequiredDeliverables,
} from "./validator-utils"

/** The task contract for this workspace, when one is discoverable. */
interface Contract {
taskFile: string
required: RequiredDeliverables
}

/** Read the workspace's literal deliverable contract, or null if there is none. */
async function readContract(cwd: string, dbtRoot: string): Promise<Contract | null> {
// Every candidate, not just the first readable one: an informational
// `TASK.md` that states no deliverables must not mask a `REQUIREMENTS.md`
// that does, or this gate silently skips a session it was meant to check.
for (const task of await findTaskInstructionFiles(cwd, dbtRoot)) {
const required = extractRequiredDeliverables(task.content)
if (required) return { taskFile: task.path, required }
}
return null
}

/** True when `relative` exists under either the dbt project or the workspace. */
async function fileExists(dbtRoot: string, cwd: string, relative: string): Promise<boolean> {
for (const root of new Set([dbtRoot, cwd])) {
try {
const stat = await fs.stat(join(root, relative))
if (stat.isFile()) return true
} catch {
// keep looking
}
}
return false
}

export const DbtDeliverableNamesValidator: Validator = {
name: "dbt-deliverable-names",
description:
"After the agent declares done, compares the deliverable names the task document states literally against the model, seed and snapshot names the project actually defines, and refuses to terminate when a required name is absent — catching renames and self-chosen substitutes.",

async appliesTo(ctx: ValidatorContext): Promise<boolean> {
const dbtRoot = await findDbtProjectRoot(ctx.workingDirectory)
if (!dbtRoot) return false
return (await readContract(ctx.workingDirectory, dbtRoot)) !== null
Comment on lines +85 to +88

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Preserve the task contract outside the mutable worktree

When the session deletes, renames, or edits the discovered task document so it no longer yields a contract, this completion-time lookup makes appliesTo return false; dbt-nothing-built performs the same live lookup, so both contract gates disappear. A session can therefore remove TASK.md, produce no requested model or build artifact, and terminate successfully because every remaining gate sees zero touched models. Capture the original contract at session start or read it from harness state that the agent cannot mutate.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Real, and deliberately left open rather than half-fixed. Recorded as item 19 in .github/meta/harness-review-followups.md in dd858ef59f so this reasoning is not re-derived later.

The finding is right: readContract and artifactExpectation both run at completion time against the live filesystem, so a session that deletes or rewrites TASK.md makes both contract gates return appliesTo === false and can terminate having produced nothing.

The fix you name is the right one — capture the contract at session start, or read it from harness state the agent cannot write — and neither exists in this lane. ValidatorContext carries sessionStartMs and nothing else; there is no session-scoped artifact store to put a snapshot in. That is the same missing infrastructure follow-up items 4 and 8 need.

The available half-measure is worse than the gap: blocking when a task-document candidate path was written during the session cannot distinguish a deletion from a file that never existed, and fires on the entirely normal case of a task that asks for the document itself to be updated. That converts a false negative into a blocking false positive on correct sessions, which is the wrong direction for a gate that terminates work.

Leaving this open rather than resolving it, since it is not addressed.

},

async check(ctx: ValidatorContext): Promise<ValidatorResult> {
const startedAt = Date.now()
const dbtRoot = await findDbtProjectRoot(ctx.workingDirectory)
if (!dbtRoot) {
return { ok: true, details: { skipped: "no dbt project", session_id: ctx.sessionID } }
}
const contract = await readContract(ctx.workingDirectory, dbtRoot)
if (!contract) {
return { ok: true, details: { skipped: "no literal contract", session_id: ctx.sessionID } }
}

const produced = await collectProducedNodeNames(dbtRoot)
Comment thread
anandgupta42 marked this conversation as resolved.
const missingModels = contract.required.models.filter((name) => !produced.has(name))
const missingFiles: string[] = []
for (const relative of contract.required.files) {
if (!(await fileExists(dbtRoot, ctx.workingDirectory, relative))) missingFiles.push(relative)
}

const details = {
task_file: contract.taskFile,
required_source: contract.required.source,
required_models: contract.required.models,
required_files: contract.required.files,
produced_count: produced.size,
missing_models: missingModels,
missing_files: missingFiles,
dbt_root: dbtRoot,
session_id: ctx.sessionID,
elapsed_ms: Date.now() - startedAt,
}

if (missingModels.length === 0 && missingFiles.length === 0) {
return { ok: true, details }
}

// Names this session authored that the task did not ask for. These are the
// likely substitutes behind a missing required name; reported as context,
// never asserted as equivalent.
const requiredSet = new Set(contract.required.models)
const authored = await modelsModifiedSince(dbtRoot, ctx.sessionStartMs)
const unrequested = Array.from(
new Set(
authored
.map((p) => modelNameFromPath(p).toLowerCase())
.filter((name) => name.length > 0 && !requiredSet.has(name)),
),
)

const reasonParts: string[] = []
if (missingModels.length > 0) {
reasonParts.push(
`the task names ${missingModels.length} deliverable(s) this project does not define: ${missingModels.join(", ")}`,
)
}
if (missingFiles.length > 0) {
reasonParts.push(`required file(s) missing: ${missingFiles.join(", ")}`)
}

const hintLines: string[] = [
`The task document (${contract.taskFile}) states these names literally. A model that does the right thing under a different name does not satisfy the task, and self-verification against the renamed output will not detect it.`,
]
if (missingModels.length > 0) {
hintLines.push(` • Create or rename to exactly: ${missingModels.join(", ")}`)
}
if (missingFiles.length > 0) {
hintLines.push(` • Create at exactly these paths: ${missingFiles.join(", ")}`)
}
if (unrequested.length > 0) {
hintLines.push(
` • Models you created this session that the task did not name: ${unrequested.join(", ")}. If one of them is a renamed version of a required deliverable, rename the file (and any \`ref()\` to it) back to the required name.`,
)
}
hintLines.push(
" • If a required deliverable is produced under an alias, set `alias` in its config so the required name is the relation name.",
)

return {
ok: false,
reason: `Deliverable-name mismatch: ${reasonParts.join("; ")}.`,
fixHint: hintLines.join("\n"),
details: { ...details, unrequested_models: unrequested },
}
},
}
// altimate_change end
Loading
Loading