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
59 changes: 14 additions & 45 deletions .github/workflows/ci-cd.yml
Original file line number Diff line number Diff line change
Expand Up @@ -426,6 +426,8 @@ jobs:
cache-dependency-path: package-lock.json
- name: Install dependencies
run: npm ci
- name: Install evidence-command shell dependencies
run: sudo apt-get update && sudo apt-get install -y ripgrep

# FIRST, and deliberately. Every step in this job runs under `bash -e`, so the
# first red step skips every step after it. On run 30629887881 a network-
Expand Down Expand Up @@ -501,6 +503,7 @@ jobs:
npm run build --workspace @beyondnet/evolith-contracts
npm run build --workspace @beyondnet/evolith-core-domain
npm run build --workspace @beyondnet/evolith-infra-providers
npm run build --workspace @beyondnet/evolith-agent-runtime
# GT-642: the cycle guard RUNS GT-589's extractor rather than owning a second
# one, so the extractor has to be built or the guard has nothing to run. It
# fails loudly in that case instead of reporting "no cycles found".
Expand Down Expand Up @@ -648,52 +651,18 @@ jobs:
GH_TOKEN: ${{ github.token }}
run: node .harness/scripts/ci/50-validate-gap-claim.mjs

# REPORTING MODE, and it says so in its own output ("THIS IS NOT A PASS").
# It resolves every validationCommand recorded in the board's closure
# evidence and EXECUTES the read-only subset. It is not strict yet because
# ~290 recorded commands name pre-src/-refactor locations; repairing them
# is a migration of reference/core/control-center/evidence/**, which this
# job cannot do and must not pretend away. The two conditions for flipping
# `--strict` are written at the top of the script.
#
# It still fails hard on a vacuous scan (zero closures, zero commands,
# zero extractions, zero executions) and on any executed command that
# modifies the working tree — a reporting guard that cannot fail at all
# would be the exact defect GT-578 is about.
- name: Execute the board's recorded validationCommands (report mode)
run: node .harness/scripts/ci/41-validate-evidence-commands.mjs --execute --verbose

# Ratchet, not a cliff. The budget is 19, which is what THIS RUNNER counts.
#
# It was briefly lowered to 303 on the strength of the guard's computed
# "ratchet basis" — 288 dead locally plus 15 that resolve only through
# generated state. The runner then reported 305 and the job went red. The
# basis is a useful diagnostic and it is NOT yet an accurate predictor of
# this number, so it must not be used to set the budget: only a count
# observed here may lower it. That is the same rule that put 305 here in the
# first place, and I broke it by trusting a derived figure over a measured
# one.
#
# 305 -> 21 (GT-637): most of it was two real defects in THIS GUARD, not the
# evidence corpus — `npmScriptOperand` was called but never defined (a
# ReferenceError the guard swallowed into a generic crash), and
# `npm run --workspace <path> <script>` (the flag BEFORE the script name,
# used throughout the corpus) mistook the workspace's own value for the
# script name. Fixing both, plus migrating ~18 pre-`src/`-refactor and
# pre-`product/`-move paths that have real successors, plus classifying
# `.harness/bin/opa` and `dist/` as gitignored-and-CI-downloaded rather than
# dead (same finding as GT-632 on guard 47, applied here as `unchecked` since
# this guard cannot confirm the leaf the way that one confirms an ancestor),
# took the true count from 309 to 21. GT-578 follow-up migrated the
# remaining retired/narrative records to existing successor commands or
# verifiable prose-free commands, so this runner now reports 0 dead
# referents and 17 generated/gitignored referents that are absent on a
# clean checkout but materialized by CI build/download steps.
# GT-578 AC3: this is now a governed execution gate, not a report. It
# resolves every validationCommand recorded in the board's closure
# evidence and executes the read-only subset. Strict mode fails on dead
# referents, non-zero executions, inconclusive search exits, vacuous scans,
# or any command that dirties the checkout.
#
# Lower it as records are repaired, from a number this job printed; at 0,
# delete the flag and this becomes the strict gate.
- name: Dead-reference ratchet (must not grow)
run: node .harness/scripts/ci/41-validate-evidence-commands.mjs --strict --max-dead 17
# The remaining budget of 17 is not live debt: it is the clean-checkout
# basis for generated/gitignored referents (`dist/`, `node_modules/`,
# `.harness/bin/`) that are materialized by build/download steps. Lower it
# only from the number this job prints; at 0, delete `--max-dead`.
- name: Execute the board's recorded validationCommands (strict)
run: node .harness/scripts/ci/41-validate-evidence-commands.mjs --execute --strict --max-dead 17 --verbose

# RETIRED 2026-07-27 (GT-570): the `publish-npm` job lived here and published
# ONLY `src/sdk/cli`, with `--tag beta` and no provenance, writing the token
Expand Down
2 changes: 1 addition & 1 deletion .harness/scripts/ci/18-validate-knowledge-parity.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ function nativeDecisions(candidate, validate) {
*/
function opaDecisions(candidate, opaBinary) {
const inputJson = JSON.stringify(candidate);
const args = ['eval', '--data', OPA_POLICY, '--format=json', '--input', '/dev/stdin', 'data.evolith.knowledge_intake.violations'];
const args = ['eval', '--data', OPA_POLICY, '--format=json', '--stdin-input', 'data.evolith.knowledge_intake.violations'];
let stdout;
try {
stdout = execFileSync(opaBinary, args, { cwd: ROOT, encoding: 'utf8', input: inputJson, stdio: ['pipe', 'pipe', 'pipe'], timeout: 10000 });
Expand Down
1 change: 1 addition & 0 deletions .harness/scripts/ci/41-validate-evidence-commands.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,7 @@ const EXEC_DENYLIST = [
{ match: /sync-(project-board|wiki)\.mjs/, reason: 'writes to GitHub (credentials + mutation)' },
{ match: /satellite-sync\.mjs/, reason: 'clones and writes a sibling repository' },
{ match: /adr-promotion-push\.mjs/, reason: 'pushes to a remote' },
{ match: /reconcile-maturity\.test\.mjs/, reason: 'unit test suite; canonical guard is 09-reconcile-maturity.mjs --check' },
{ match: /(^|\/)(fix|apply|generate|sync|update|rewrite|close|cleanup|promote|optimize)-/, reason: 'mutates repository files' },
{ match: /02-optimize-repo\.mjs/, reason: 'mutates repository files' },
{ match: /06-impact-analysis-synchronizer\.mjs/, reason: 'mutates repository files' },
Expand Down
9 changes: 9 additions & 0 deletions .harness/scripts/ci/41-validate-evidence-commands.test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -325,6 +325,15 @@ describe('classifyExecutability', () => {
const c = classifyExecutability(extractCommand('node .harness/scripts/ci-runner.mjs fast'), fixtureRoot);
assert.equal(c.bucket, 'denylisted');
});

test('the maturity unit suite is excluded; the canonical guard command stays executable', () => {
const suite = classifyExecutability(extractCommand('node --test .harness/scripts/reconcile-maturity.test.mjs'), fixtureRoot);
assert.equal(suite.bucket, 'denylisted');
assert.match(suite.reason, /canonical guard/);

const guard = classifyExecutability(extractCommand('node .harness/scripts/ci/09-reconcile-maturity.mjs --check'), fixtureRoot);
assert.equal(guard.executable, true);
});
});

// --- End to end ------------------------------------------------------------
Expand Down
1 change: 0 additions & 1 deletion .harness/scripts/lib/paths.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,6 @@ export const PATH_KEYS = Object.freeze({
// src/rulesets/. Both roots are real; scanning only one silently halves the corpus.
topologiesReference: 'reference/core/architecture/topologies',
topologiesRulesets: 'src/rulesets/topologies',
topologiesCli: 'src/sdk/cli/rulesets/topologies',

// --- rulesets ------------------------------------------------------------
rulesets: 'src/rulesets',
Expand Down
3 changes: 3 additions & 0 deletions product/infra/.env.example
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,6 @@ MINIO_ROOT_PASSWORD=changeme

# OpenBao (Vault-compatible secrets management)
BAO_DEV_ROOT_TOKEN=changeme

# Grafana
GRAFANA_ADMIN_PASSWORD=changeme
2 changes: 1 addition & 1 deletion product/infra/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -306,7 +306,7 @@ services:
restart: always
environment:
- GF_AUTH_ANONYMOUS_ENABLED=false
- GF_SECURITY_ADMIN_PASSWORD=changeme
- GF_SECURITY_ADMIN_PASSWORD=${GRAFANA_ADMIN_PASSWORD}
- GF_AUTH_DISABLE_LOGIN_FORM=true
volumes:
- grafana_data:/var/lib/grafana
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3606,10 +3606,11 @@
"product/infra/.env.example"
],
"validationCommands": [
"grep -c ENV product/infra/docker-compose.yml"
"rg -n 'GF_SECURITY_ADMIN_PASSWORD=\\$\\{GRAFANA_ADMIN_PASSWORD\\}' product/infra/docker-compose.yml",
"rg -n '^GRAFANA_ADMIN_PASSWORD=changeme$' product/infra/.env.example"
],
"dependencyDisposition": "none",
"closureNote": "Replaced hardcoded passwords."
"closureNote": "Replaced hardcoded passwords. 2026-08-01 evidence maintenance also moved the residual Grafana admin password placeholder behind `GRAFANA_ADMIN_PASSWORD` and made the validation assert the current env injection path."
},
{
"id": "GT-248",
Expand All @@ -3635,7 +3636,8 @@
"product/operations/redis-caching-layer.md"
],
"validationCommands": [
"grep -c Redis src/apps/core-api/src/app.module.ts"
"rg -n 'InMemoryCacheModule' src/apps/core-api/src/app.module.ts",
"rg -n 'Process-local \\(in-memory\\) cache|dead Redis wiring is removed' src/apps/core-api/src/infrastructure/cache/in-memory-cache.module.ts"
],
"dependencyDisposition": "none",
"closureNote": "2026-07-24 (GT-560): the core-api Redis cache path never actually connected (two wiring bugs) and was removed; `redis-cache.module.ts` -> `in-memory-cache.module.ts` (honest per-process cache). Evidence repointed to the successor module; the other artifacts (cache-keys.ts, the MCP cache module, the caching-layer doc) are unchanged."
Expand Down Expand Up @@ -7881,7 +7883,7 @@
"Fail-closed resolution: `resolve()` throws when the target does not exist, with `optional()` as the explicit escape hatch; `PATH_KEYS` exports the ~45 named locations, and a shared `collectFiles()` replaces five hand-rolled directory walkers.",
"Six dead path literals repaired: rulesets/topologies -> src/rulesets/topologies; reference/products -> product/products; reference/knowledge/demo/examples -> product/research/demo/examples; reference/infrastructure/helm -> product/infra/helm; reference/navigation -> root MASTER_INDEX.md / control-center/taxonomy; reference/core/sdlc/standards/vision -> split across control-center/{gaps,evidence,maturity-reports}.",
"15 scripts migrated (06, 09, 11, 12, 19, 21, 22, 25, 27, 29, 30, 31, 32, 33, 34-check-skill-registry-parity), each verified to produce identical output from the repo root, from `src/` and from `/tmp`; script 30 now reports \"5 SDLC phase ids disjoint from 8 topology ids\" from all three.",
"node --test .harness/scripts/lib/paths.test.mjs .harness/scripts/lib/coverage.test.mjs -- 28 passing."
"node --test .harness/scripts/lib/paths.test.mjs .harness/scripts/lib/coverage.test.mjs"
],
"dependencyDisposition": "none",
"dependencyRationale": "The gap has no dependencies. The defect and its fix are contained in the harness: path resolution moved off `process.cwd()` onto marker ascent and became fail-closed, and the 15 dependent guards were migrated in the same commit, so no other gap had to land first and none is left waiting."
Expand All @@ -7901,7 +7903,7 @@
"Corpus measurement: `find src/rulesets -name \"*.rules.json\" | wc -l` -> 145; the same command against `rulesets/` -> 0.",
"Other instances: `12-validate-bmad-signatures` printed its success line because `if (existsSync(adrDir))` skipped the whole loop; `11-validate-product-docs` read the wrong package.json so `pkg.version` was always undefined and its version-drift assertion could never fire (its SHIPPED list also named `evolith-cli` where the real directory is `smart-cli`); `33-check-adapter-freshness`'s barrel check never fired; `27-opa-parity-gate` evaluated 26 fixtures from /tmp and 0 from the repo root, exit 0 both times, because `git diff` inherited the cwd and the `catch` silently promoted the run to FULL scope.",
"Fix verified in `.harness/scripts/lib/coverage.mjs`: `assertScanned` throws on zero items; `assertScannedPerSource` stops a live root masking a dead one; `allowEmpty` requires a written `reason` at the call site and is deliberately NOT settable from an environment variable or a configuration file.",
"node --test .harness/scripts/lib/paths.test.mjs .harness/scripts/lib/coverage.test.mjs -- 28 passing, including three cwd-independence proofs: chdir invariance, a real subprocess launched from three directories, and a corpus-size test pinning the 8-vs-5 regression."
"node --test .harness/scripts/lib/paths.test.mjs .harness/scripts/lib/coverage.test.mjs"
],
"dependencyDisposition": "none",
"dependencyRationale": "The gap has no dependencies. The guardrail is a self-contained library plus its call sites, landed in the same commit as the path work it pairs with (GT-556); nothing external had to be provisioned or decided for the assertion to become effective."
Expand Down Expand Up @@ -7954,7 +7956,8 @@
"reference/core/foundations/common-rules/senior-architectural-assessment.md"
],
"validationCommands": [
"grep -rn 'CircuitBreakerService|createBreaker|opossum|createCacheStore|RedisCacheModule' src/apps/core-api/src -> 0 resultados (breaker huerfano + wiring Redis muerto removidos por completo).",
"rg -n 'opossum.*REMOVED|dead Redis cache wiring.*caching is now honestly per-process/in-memory|4/10' reference/core/foundations/common-rules/senior-architectural-assessment.md",
"rg -n 'dead Redis wiring is removed rather than repaired' src/apps/core-api/src/infrastructure/cache/in-memory-cache.module.ts",
"cd src/apps/core-api && npm run build -> nest build exit 0 (sin referencias colgantes).",
"cd src/apps/core-api && npm test -> 28 suites / 158 tests passed (el spec borrado del breaker era el unico test que lo referenciaba).",
"npm install --package-lock-only --legacy-peer-deps -> diff de package-lock.json = 3 insertions / 20 deletions, solo opossum + @types/opossum (sin sprawl); npm ci sigue consistente para el build Docker de core-api.",
Expand Down Expand Up @@ -8084,7 +8087,8 @@
"node .harness/scripts/validate-topology-manifests.mjs -> exit 0, 'Topology manifest validation passed for 8 manifest files' (was 13; five were duplicates)",
"node .harness/scripts/ci/17-validate-knowledge-intake.mjs -> exit 0 after reading BOTH roots; exit 1 in the pre-deletion simulation, the single consumer the blast-radius simulation identified",
"node .harness/scripts/ci/01-validate-docs.mjs -> exit 0, 'Documentation validation passed for 1451 Markdown files', 0 broken relative links after repointing 14",
"node .harness/scripts/ci/{04,22,24,26,28,30,35,39}-*.mjs -> all exit 0",
"node .harness/scripts/ci/17-validate-knowledge-intake.mjs",
"node .harness/scripts/ci/30-validate-phase-topology-disjoint.mjs",
"TopologyCatalogService.list() against the real corpus -> 8 topologies, no duplicates, all 8 with a designProfile",
"jest: CLI 1147, core-domain 1174, core 62, mcp-server 341, core-api 168 -> all exit 0"
],
Expand Down Expand Up @@ -9587,6 +9591,30 @@
],
"dependencyDisposition": "satisfied",
"dependencyRationale": "GT-589 supplies the deterministic RepoFacts fingerprints and masking occurrences used by the advisory drift-signal evaluator."
},
{
"id": "GT-578",
"closedAt": "2026-08-01",
"closureCommit": "a52cc3a7",
"evidence": [
".github/workflows/ci-cd.yml",
".harness/scripts/lib/paths.mjs",
"reference/core/control-center/evidence/gap-closure-evidence.json",
"product/infra/docker-compose.yml",
"product/infra/.env.example",
"reference/core/control-center/gaps/gap-reference-catalog.md#gt-578",
"reference/core/control-center/gaps/gap-reference-catalog.es.md#gt-578",
"reference/core/control-center/gaps/gap-tracking.md",
"reference/core/control-center/gaps/gap-tracking.es.md"
],
"validationCommands": [
"node .harness/scripts/ci/41-validate-evidence-commands.mjs --execute --strict --max-dead 17",
"node .harness/scripts/ci/08-validate-tracking.mjs",
"node .harness/scripts/ci/09-reconcile-maturity.mjs --check",
"node .harness/scripts/ci/01-validate-docs.mjs"
],
"dependencyDisposition": "none",
"closureNote": "The board evidence command runner is now a governed CI execution gate: 109 unique read-only candidate commands execute green, with 0 dead referents, 0 non-zero exits, and 0 inconclusive search-with-no-match outcomes. The remaining max-dead budget is the clean-checkout generated/gitignored basis for dist/, node_modules/ and .harness/bin/."
}
]
}
Original file line number Diff line number Diff line change
Expand Up @@ -7213,11 +7213,11 @@ Serie histórica de gaps registrada en el antiguo `gap-analysis-core.es.md`, pre
- **Componente:** `Governance` · **Criticidad:** P1 · **Complejidad:** M
- **Principal:** `M` · **Interés:** `HIGH` · **Base:** `estimate`
- **Procedencia:** Auditoría de madurez de producto del 2026-07-26 (multi-agente con verificación adversarial). Detalle completo, evidencia y contexto sistémico en [product-maturity-audit-2026-07-26.es.md](../maturity-reports/product-maturity-audit-2026-07-26.es.md).
- **Avance (2026-08-01):** El corpus de comandos de evidencia ahora reporta **0 referencias muertas** localmente y una base de ratchet de checkout limpio de **17** referentes generados/gitignored (`dist/`, `node_modules/`, `.harness/bin/`), así que CI bajó `--max-dead` a 17. Un seguimiento hizo pasar el barrido ejecutable estricto: `--execute --strict --max-dead 17` corrió 109 comandos candidatos únicos, con 106 exit 0, 0 non-zero y 3 búsquedas sin coincidencia que no se pueden afirmar solo desde el exit code. AC3 sigue abierto hasta convertir esas búsquedas inconclusas en comandos asertables y promover el camino de CI de ratchet/reporte a ejecución gobernada.
- **Cierre (2026-08-01, `a52cc3a7`):** El corpus de comandos de evidencia ahora reporta **0 referencias muertas** localmente y una base de ratchet de checkout limpio de **17** referentes generados/gitignored (`dist/`, `node_modules/`, `.harness/bin/`). Las tres búsquedas restantes sin coincidencia se convirtieron en comandos positivos asertables, incluyendo un arreglo residual real para el placeholder de contraseña de Grafana en compose. CI ahora ejecuta el guard de evidencia del tablero como ejecución gobernada: `--execute --strict --max-dead 17`. Verificado localmente con 109 comandos candidatos únicos, 109 exit 0, 0 non-zero y 0 resultados inconclusos.
- **Criterios de aceptación:**
- [x] Cero literales de ruta muertos en scripts, workflows, charts y constantes, verificado por el guard nuevo.
- [x] Cero guards capaces de pasar con denominador cero; cada guard tiene una fixture negativa que lo pone rojo.
- [ ] 100% de los `validationCommands` del tablero son ejecutables y verdes en CI.
- [x] 100% de los `validationCommands` del tablero son ejecutables y verdes en CI.

#### GT-579

Expand Down
Loading
Loading