Skip to content

Run the real A2ML/K9 validators; fix a startup_failure in boj-build.yml - #59

Merged
hyperpolymath merged 3 commits into
mainfrom
fix/ci-gates-round2
Jul 27, 2026
Merged

Run the real A2ML/K9 validators; fix a startup_failure in boj-build.yml#59
hyperpolymath merged 3 commits into
mainfrom
fix/ci-gates-round2

Conversation

@hyperpolymath

Copy link
Copy Markdown
Owner

Follow-up to #58, which merged while these were in flight.

1. Both dogfood validators pointed at repositories that do not exist

##[error]Unable to resolve action hyperpolymath/k9-validate-action,
         repository not found

gh api returns 404 for both hyperpolymath/k9-validate-action and hyperpolymath/a2ml-validate-action. Neither has ever existed, so neither job has ever validated anything — both failed at Set up job, pinned to a SHA in a repository that isn't there.

The canonical implementations are RSR template files. Installed from rsr-template-repo origin/main (byte-identical to the copies lithoglyph already carries) and wired in directly — they take the same INPUT_PATH/INPUT_STRICT interface the actions were passed.

validator result
A2ML 0 errors, 3 warnings → pass
K9 1 error → a real finding, see below

2. The K9 error was a validator limitation, not a bad file

verisimdb/connectors/test-infra/deploy.k9.ncl:1
Pedigree block missing 'name' field

The file is correct. It builds the pedigree separately and attaches it:

let component_pedigree = {
  metadata = { name = "verisimdb-test-infra", version = "0.1.0", ... },
} in
{ pedigree = component_pedigree, ... }

The validator is line-oriented: it starts brace-counting at pedigree = ..., but pedigree = component_pedigree, carries no brace, so depth never rises, the block reads as empty and name is invisible.

Rewriting the file to satisfy a grep would have been the wrong direction — and especially here: this is a Hunt-level component that spawns seven database containers and binds eleven ports. It's the last file to restructure casually.

So the validator now resolves a one-hop let indirection. Proved it fixes the scanner rather than blinding it:

name present 0 errors, exit 0
name removed Pedigree block missing 'name' field, exit 1

One hop only — chasing aliases needs a real evaluator, and nickel typecheck is unavailable because the mandatory K9! magic line isn't valid Nickel. Belongs upstream in rsr-template-repo; the same fix is applied to lithoglyph's copy in its PR #9 so the two stay identical (02845a4c).

3. boj-build.yml used secrets in a job-level if: — startup_failure

Every push produced a 0-second failed run named after the file path rather than the workflow's name:, with no jobs and no check run.

if: ${{ vars.BOJ_SERVER_URL != '' || secrets.BOJ_SERVER_URL != '' }}

secrets is not available in a job-level conditional — GitHub exposes that context only in env:, with: and step-level expressions. The file is valid YAML (yaml.safe_load parses it happily), so nothing local caught it and the workflow linter didn't either. Actions rejected the whole file at load time.

Pre-existing on main, not introduced by #58.

The guard was redundant as well as fatal — the step already does if [ -z "$BOJ_URL" ]; then … exit 0, and resolves the secret in env: where that context is legal. The workflow's own header calls it "a no-op if BOJ_SERVER_URL is not set"; now it actually is one.

4. verisimdb/playground/package.json removed

deno.json sits beside it carrying every task and dependency, with node build.mjs correctly rewritten to deno run -A build.mjs. Nothing references the package.json. npm manifests are banned estate-wide.

Verification

Check Result
validate-a2ml.sh PASS (was: job never ran)
validate-k9.sh PASS (was: job never ran)
K9 still fails on a real fault exit 1
boj-build.yml parses + no secrets in job if: PASS
Actions resolving all
package.json / .ts / .tsx 0 / 0 / 0

Still red, and honestly so

Language / package anti-pattern policy — 44 .res files remain: verisimdb/ (40) and typeql-experimental/ (4). Both are legacy directories awaiting the same extraction lithoglyph/ just completed, and porting their ReScript is the AffineScript migration proper, blocked upstream on affinescript#56.

#58 already took that count from 140 → 44 by removing the duplicated Lithoglyph tree. The gate is correct; the work it asks for is a project, not a fix.

🤖 Generated with Claude Code

…nding

`Validate A2ML manifests` and `Validate K9 contracts` both failed at "Set up
job", before running anything:

    ##[error]Unable to resolve action hyperpolymath/k9-validate-action,
             repository not found

`gh api repos/hyperpolymath/k9-validate-action` and `.../a2ml-validate-action`
both return 404. Neither has ever existed, so neither job has ever validated
anything — they were pinned to a SHA in a repository that is not there.

The canonical implementations are RSR template files. Installed from
rsr-template-repo origin/main, byte-identical to the copies lithoglyph already
carries (b053676, c83e2908 before the change below), and wired in directly —
they take the same INPUT_PATH / INPUT_STRICT interface the actions were passed.

    A2ML   0 errors, 3 warnings  -> passes
    K9     1 error               -> a real finding, see below

== The K9 error was a validator limitation, not a bad file

    verisimdb/connectors/test-infra/deploy.k9.ncl:1
    Pedigree block missing 'name' field

The file is correct. It builds the pedigree separately and attaches it:

    let component_pedigree = {
      metadata = { name = "verisimdb-test-infra", version = "0.1.0", ... },
    } in
    { pedigree = component_pedigree, ... }

The validator is line-oriented. It starts its brace-depth scan at
`pedigree = ...`, but that line — `pedigree = component_pedigree,` — carries no
brace, so depth never rises, the block reads as empty and `name` is invisible.

Rewriting the file to satisfy a grep would have been the wrong direction, and
especially so here: this is a Hunt-level component that spawns seven database
containers and binds eleven ports. It is the last file to restructure casually.

So the validator now resolves a one-hop `let` indirection: if
`pedigree = <identifier>` names a binding, `let <identifier> = {` also opens the
block. One hop only — chasing aliases needs a real evaluator, and
`nickel typecheck` is unavailable because the mandatory `K9!` magic line is not
valid Nickel.

Proved it fixes the scanner rather than blinding it — deleting the name field
from that file still fails:

    name present  -> 0 errors, exit 0
    name removed  -> "Pedigree block missing 'name' field", exit 1

The same fix is applied to lithoglyph's copy in the same pass, so the two stay
identical (02845a4). It belongs upstream in rsr-template-repo: every RSR repo
carrying a let-bound pedigree has this false positive today.

Swept every `uses:` across all workflows afterwards — no other action points at
a repository that does not resolve.
verisimdb/playground/ carried both package.json and deno.json. The Deno
migration already happened — deno.json holds every task and dependency the
package.json listed, with `node build.mjs` correctly rewritten to
`deno run -A build.mjs`. Nothing in the tree references the package.json.

npm manifests are banned estate-wide (docs/migration/
RESCRIPT-TS-AFFINESCRIPT-MIGRATION.adoc: npm/bun -> Deno), so this was both dead
and disallowed.

package.json: 1 -> 0.  .ts/.tsx: already 0.

== The anti-pattern gate still fails, and will until the extractions land

44 .res files remain: verisimdb/ (40) and typeql-experimental/ (4). Both are
legacy directories awaiting the same extraction lithoglyph/ just completed, and
porting their ReScript is the AffineScript migration proper — blocked upstream
on affinescript#56 (no compiler in CI, DOM bindings outstanding).

Recording that plainly rather than allow-listing it: the gate is correct, the
work it is asking for is real, and it is a project rather than a fix. Removing
lithoglyph/ in this branch already took the count from 140 to 44.
…lure

Every push produced a 0-second failed run named
`.github/workflows/boj-build.yml` — the file path rather than the workflow's
`name:`, with no jobs and no check run. That is the startup_failure signature:
Actions refused to load the file.

    if: ${{ vars.BOJ_SERVER_URL != '' || secrets.BOJ_SERVER_URL != '' }}

`secrets` is not available in a job-level conditional. GitHub exposes that
context only in `env:`, `with:` and step-level expressions. The file is valid
YAML — `yaml.safe_load` parses it happily — so nothing local caught it, and the
workflow linter did not either.

Pre-existing on main, not introduced by this branch.

The guard was redundant as well as fatal. The step below already does:

    if [ -z "$BOJ_URL" ]; then
      echo "BOJ_SERVER_URL not configured - skipping"
      exit 0
    fi

and resolves `secrets.BOJ_SERVER_URL || vars.BOJ_SERVER_URL` in `env:`, where
that context is legal. The workflow's own header describes it as "a no-op if
BOJ_SERVER_URL is not set"; with the job-level `if:` removed it actually is one,
instead of failing the run.

Swept both this repo and lithoglyph for the same shape afterwards — no other
job-level `if:` references `secrets`. lithoglyph's copy of this workflow uses
`secrets` only in `env:`, which is correct.
@hyperpolymath
hyperpolymath merged commit 016fd8e into main Jul 27, 2026
17 of 19 checks passed
@hyperpolymath
hyperpolymath deleted the fix/ci-gates-round2 branch July 27, 2026 13:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant