Skip to content

fix: three P0s, and twelve rules that promised enforcement and delivered nothing (GT-572, GT-595, GT-604) - #273

Merged
beyondnetPeru merged 14 commits into
developfrom
integration/gt-572-595-604
Jul 29, 2026
Merged

fix: three P0s, and twelve rules that promised enforcement and delivered nothing (GT-572, GT-595, GT-604)#273
beyondnetPeru merged 14 commits into
developfrom
integration/gt-572-595-604

Conversation

@beyondnetPeru

Copy link
Copy Markdown
Contributor

Five branches integrated. GT-595 and GT-572 close; GT-604 advances to its first criterion and stops at a boundary this repository cannot cross.

GT-595 — the honest denominator, one level up

blocking + skipped now fails the run. A blocking rule that silently skips is indistinguishable from one that passed, so the suite reported a verdict it had not earned.

It exposed 181 rules declared blocking that never execute. 96 were auto-generated ADR placeholders whose own validationQuery ends "Concrete checks to be wired into the harness" — the generator asserted blocking: true on a check it never wired. Of the remaining 85, 12 are now genuinely closed and the corpus count is 73, recomputed rather than assumed: the pin was perturbed to 74 and observed failing.

Two findings are the same shape as everything else this session:

  • The four HXA rules were dead because DiskRulesetRepository.normalizeRuleset never copied the enforce field. The schema has accepted it since GT-516, ADR-0002 authors six blocks, the PolicyCompiler compiles them — normalization dropped it, so the entire enforcer subsystem was unreachable for lack of data, not wiring.
  • rule-corpus-triage.spec.ts's own loader dropped it too, under a docstring claiming it loads "exactly as DiskRulesetRepository does". The measuring instrument was measuring a different corpus than production evaluates.

Two things were deliberately not done, and both are recorded with their reasoning:

  • dependency-cruiser was rejected. The Core is a stateless engine reading satellites through an overlay filesystem, which a subprocess cannot see, and the tool's config matches node_modules/ — an uninstalled satellite yields zero violations and passes four blocking rules. A false pass is worse than the skip being fixed.
  • OCB-02 was not closed. Zero artifacts anywhere carry an availability marker, so it quantifies over the empty set and can only pass. Closing it would have bought a number instead of a check.

GT-572 — a smoke that could not fail

Verified against an npm packed tarball installed outside the workspace, because the symlink is what hid GT-625. The old assertion was envelope.success !== undefined — true of every response the server can emit — and was observed printing tools/call OK while receiving RULESET_NOT_FOUND. The new one is proven falsifiable three ways, including a live run against the pre-fix dist.

Also fixed: findCorePath resolved <repo>/src after the src/ refactor (a GT-632 sibling), and corePath was read but undeclared in the tool's inputSchema.

Caveat recorded, not papered over: shipping policy.wasm inside the package remains a release-pipeline decision. EVOLITH_ABAC_POLICY_PATH makes the production posture satisfiable; it does not make the artifact present.

GT-604 — one criterion, and an honest boundary

The ingest contract ships with correlationId required and both owners carried distinctly — requestedBy.actorId (who asked) and violations[].accountableOwner (who must fix). Criterion 2 has no endpoint to call; criterion 3 needs RoboSoft, which lives in evolith_tracker. A bilingual handover names the endpoint, payload, auth and tests the Tracker team would need.

Recorded as unconfirmed: GT-604's declared dependency on GT-603 appears wrong — GT-603 migrates audit_entries while GT-604 names core_evaluation_transactions, and the Core-side attribution already shipped under GT-586.

Verification

core-domain 1433 · CLI 1436 · mcp-server 433 · core-api 179 · agent-runtime 406 · infra-providers 128 · contracts 104 · sdk-client 63 · core 62 · contract 43 · exploration 6. ci-runner governance 17/17 in a real checkout. Guards 34, 40–47 green with their self-tests; bilingual parity and docs green; guard 46 reports the chain at a fixed point.

Every remaining failure was baselined against main by measurement and confirmed pre-existing.

Board: 592 / 632.

🤖 Generated with Claude Code

beyondnetPeru and others added 14 commits July 29, 2026 10:31
fix: align main — the eleven paths the src/ move left behind (GT-632 c2)
fix(ci): guard the paths that are BUILT, not written (GT-632 c3)
…5 AC2)

A rule declared `blocking: true` that the engine reports `skipped` produced
exactly the same report as a blocking rule that passed — no finding — so
"0 blocking findings" and "the blocking rules never ran" were indistinguishable
and the verdict claimed coverage it did not earn. GT-569 made the denominator
honest and thereby exposed this.

The invariant is a `blocking: true` ValidationIssue, not a thrown error:
`RulesetValidatorService.validate` catches engine exceptions and downgrades them
to a logged warning, so a throw would be silently suppressed by the only caller
in the product, and it would abort the corpus at the first offender instead of
enumerating all of them. It is emitted from `toValidationIssues`, the single
place both engine callers build their verdict from, and unlike the GT-569
`maxSkippedFraction` floor there is no option that turns it off. The rule's own
outcome stays `skipped`, so `rulesChecked` is not re-inflated with rules that
did not run.

Live defect this exposes: 181 corpus rules were blocking-and-skipped. 96 are
auto-generated ADR-conformance placeholders whose own validationQuery ends
"Concrete checks to be wired into the harness" — the corpus claiming enforcement
it never wired — so `generate-adr-rulesets.mjs` now emits them `blocking: false`
(severity MUST and enforcement `executable` are kept: those describe the ADR).
The remaining 85 are pinned and enumerated in `rule-corpus-triage.spec.ts`: 48
need a handler, 14 an external-system adapter, 12 a runtime adapter, and 11 were
declared blocking by a human with no validationQuery at all (EC-SEC-01/02,
SV-SEC-01/02, KI-R01..07). Those 11 are a governance decision — author the check
or drop the flag — and are deliberately left failing rather than silenced.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…ke fail (GT-572)

Verified against a PACKED TARBALL installed outside the workspace, because that
is the only place the previous evidence could have been wrong. `npm pack` in
src/packages/mcp-server, `npm install <tgz>` into a fresh temp dir with no
workspace above it, drive stdio directly.

**The FORBIDDEN is gone in the documented configuration.** 50 tools announced,
`evolith-metrics` and `evolith-gate-evaluate` both execute, audit trail records
`userId=local-stdio-session status=success`. The 47-of-47 denial the gap opened
on does not reproduce at HEAD.

**It is NOT gone in production, and could not be.** With NODE_ENV=production the
same tarball denies every call: `FORBIDDEN / ABAC_POLICY_MISSING`. Both lookup
paths are repository layouts resolved against the process cwd, and `policy.wasm`
is a gitignored build artifact living OUTSIDE the package directory — no `files`
setting can put it in the tarball. So an npm consumer had a fail-closed rule with
no way to satisfy it, which is not a stricter rule. `EVOLITH_ABAC_POLICY_PATH`
is the way: it manufactures nothing, and a path that does not exist falls to the
same deny branch. Measured on the tarball: FORBIDDEN before, real verdict after.
Shipping the bundle inside the package remains a release-pipeline decision, and
is stated as such in the README rather than worked around.

**The oracle was worse than blind — it was reporting the failure as OK.** The
stdio smoke asserted `envelope.success !== undefined`, which holds for every
response the server can emit. It was receiving `RULESET_NOT_FOUND` and printing
`tools/call OK (evolith-gate-evaluate stdio)`. That error was real: gate
discovery walks up for a `rulesets/` marker, the src/ refactor moved that
directory under `src/` while the gate definitions stayed at the root, so the walk
stopped one level too deep at `<repo>/src`. Same family as GT-632 — a path the
refactor left behind, kept alive by an assertion that could not fail.

Now a `tools/call` step passes only on a governance VERDICT: not isError, not
FORBIDDEN (called out separately — it is this gap's symptom), success true,
`data.verdict` in the vocabulary, `data.gateId` naming the gate. The assertion
lives in its own module with 11 unit tests over payloads this server has actually
produced, and CI self-tests it BEFORE running the smoke: a gate whose own
falsifiability is untested is indistinguishable from no gate.

Proof it fails: with the old dist, the new smoke exits non-zero with
"the server flagged the result isError — [RULESET_NOT_FOUND] … /evolith/src/…".
With the fix, both transports report verdict "failed" on gate business-sign-off,
and the evidence artifact now carries the verdict instead of a boolean.

Also: `corePath` was read by evolith-gate-evaluate and never declared, so an
agent reading the schema could not learn about the one argument that makes the
tool usable off-repo. And the smoke's 5s timeout was a cold-start flake that
teaches people to re-run a gate.

Verified: mcp-server 437/437, core-domain 1384/1384, guards 40/47/28 exit 0,
both new specs shown failing when their fix is reverted.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…T-604 c1)

GT-604 acceptance criterion 1 only. Criteria 2 and 3 are not buildable in this
repository and are handed over instead:

  - the shared client has no route to call. The Tracker exposes only
    GET /core-evaluation-transactions and GET /core-evaluation-transactions/{id};
    a client written against a nonexistent route passes its own tests forever.
  - the RoboSoft robot lives in beyondnetcode/evolith_tracker.

The contract (src/packages/contracts/src/ingest/evaluation-ingest.ts) carries the
five things the criterion names — correlationId, the true engine per executed
rule, the executed rules, the violations and the owner — with two decisions made
explicit in the shape:

  - correlationId is REQUIRED on the wire. It is optional on EvaluationResult and
    both existing producers already synthesize one; resolveIngestCorrelationId
    does it deterministically at the boundary, which is what makes the endpoint's
    idempotency enforceable rather than decorative.
  - the "owner" of the criterion is TWO owners. requestedBy.actorId is who asked;
    violations[].accountableOwner is who must fix it. They are different people,
    they are named so they cannot be confused, and an unattributed violation is
    never back-filled from the requester.

Derivation is enforced by EVALUATION_INGEST_FIELD_SOURCES: every wire field names
its EvaluationResult / Violation source path, and the spec walks all 35 of them
against objects produced by the REAL evaluateDriftGate pipeline. A rename upstream
stops a path resolving and the suite goes red at runtime — which matters, because
this package's ts-jest runs with diagnostics off, so a type-only guard would be
silently skipped. The type-level half is checked by tsc --noEmit on tsconfig.spec.

The module stays import-free like evidence-edge.ts (GT-605) and the GT-573
fixtures: core-domain is a devDependency on purpose, and a type import from it
would leak into the published .d.ts and resolve to `any` for any consumer that
does not install the engine.

Contract 26 tests / package 104 total, all green. Reverting the mapper in place to
the naive pre-contract shape (collapsed owner, engine coerced to a known value,
tenantId on the body) takes it to 12 failed / 14 passed.

Handover for the Tracker team in both languages, 22 headings each:
reference/core/control-center/opportunities/tracker-handover-gt604{,.es}.md —
the endpoint, the machine-key auth with tenant derived from the matched key
(precedent: tracker-approval.http-client.ts), the tests that would prove it, and
one question: GT-604's declared dependency on GT-603 names a different table
(audit_entries vs core_evaluation_transactions) and the Core-side attribution it
implies already shipped under GT-586. Raised as a question, not a correction —
the Tracker schema cannot be checked from here.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…nth (GT-595)

GT-595 made `blocking` + `skipped` fail the run and left 85 rules that promise
enforcement and never execute. Nine of them were triaged as config-shaped. Eight
now have a real check with a passing AND a failing fixture; the ninth is
declined, with the reason recorded as an executable measurement.

GROUP A — four topology flags (ArchitectureRuleHandler)
ED-R04, ED-R05, ED-R06 and DAM-R05 were already the exact shape
`evaluateConfigRule` reads: a boolean in `<topology>.config.json`. They fell
through on naming alone — their siblings carry prefixed categories
(`event-driven-config`), these carry bare ones (`event-ordering`, `retention`).

The dispatch keys on the RULE ID, not the category, because two of those bare
categories are SHARED across topologies with different files and different
flags: `schema-evolution` is ED-R06 (event-driven.config.json) *and* DAM-R08
(data-mesh.config.json); `retention` is DAM-R05 *and* ED-R07. A category-keyed
dispatch would claim all four and answer for a file it never opened. Two
fixtures pin that mis-claim directly — DAM-R05 against a satellite carrying only
`event-driven.config.json` must FAIL, and vice-versa — and a third asserts
ED-R07/DAM-R08 stay unclaimed rather than answered incorrectly.

ED-R05 is PARTIAL and says so in its own verdict: only the flag clause is
implemented, and the pass message carries "the second clause (AST scan of
consumer handlers for a deduplication guard) is NOT implemented".

GROUP B — four config assertions (GovernanceRuleHandler)
  GIT-08    commitlint config present AND the package installed. The second
            half is the GT-623 failure mode: a commit-msg hook whose `else`
            branch printed "commitlint is not installed — skipping" and exited
            zero. A config nobody installed fails open, so it fails here.
  SEC-RL-01 an HTTP surface in the tree obliges a rate limit read from
            `process.env`. A hard-coded `RATE_LIMIT_MAX = 100` FAILS: the rule
            asks for configurability, not for the words.
  SEC-RL-02 same, for `MCP_MAX_BODY_BYTES` or an equivalent env read.
            Both scan implementation sources only — a `.spec.ts` mentioning the
            env var must not satisfy the rule, and a fixture pins that.
  MTN-05    PARTIAL, and the reason is a conflict in the corpus. Its
            validationQuery wants `boundedContexts[].persistence` to be one of
            `shared-schema | schema-per-tenant | db-per-tenant`, but
            evolith-yaml.schema.json declares that field with
            `enum: [PostgreSQL, MongoDB, SQLServer, SQLite]` under
            `additionalProperties: false`. A satellite that satisfies MTN-05 as
            worded FAILS contract-schema validation. Implemented: the half both
            documents agree on — the decision must be declared, per bounded
            context. The enum clause is unenforced and the verdict says so.

OCB-02 — DECLINED, and this is the point of the exercise
No artifact in src/rulesets carries an `availability` marker of either value.
The rule quantifies over the empty set, so a faithful handler returns `passed`
on every repository that could ever exist: the only way to produce a violation
is to first add the marker whose absence is the actual defect. Wiring it would
have moved OCB-02 into the `native-handler` count and bought a number instead of
a check — the exact false green GT-569 and GT-595 exist to remove. It stays in
the backlog, flagged for re-authoring against `openCoreMatrix` (which IS
populated, and the spec proves it) alongside OCB-05.

MEASUREMENT
rule-corpus-triage.spec.ts, recomputed against the real corpus:
  blocking-and-skipped   85 -> 77
  unimplemented-native   60 -> 52   (offenders 48 -> 40)
  native-handler        139 -> 147
  unclaimed             114 -> 106
All eight came out of `unimplemented-native`, which is what that class always
meant: a handler was the only thing missing. No adapter was written and no rule
was re-authored, so the other three classes are untouched. The eight ids are now
named in the spec, not merely counted — a count cannot tell a closure from a
rule that left the corpus.

core-domain: 1418 passed / 126 suites. tsc --noEmit clean.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…l (GT-632)

HXA-01/02/04/05 declared `blocking: true` and carried a complete
dependency-cruiser `from`/`to` clause, and reported `skipped` on every run.
The cause was not a missing check — it was that `DiskRulesetRepository`
never copied `enforce` onto the normalized rule. `rule.enforce` was
therefore always undefined, `EnforcerEvaluator.isEnforcerRule()` always
false, and the entire enforcement subsystem (adapters, sandbox, composite,
and the `NodeProcessRunner` all three surfaces already inject) was
unreachable code.

Rather than install dependency-cruiser, the clause is evaluated natively:
- the Core is stateless and reads satellites through an overlay filesystem
  (ADR-0101) that a subprocess cannot see, so shelling out works on CLI and
  silently does nothing on REST;
- `to.path: node_modules/...` only matches when the satellite's
  node_modules is installed, so a cloned satellite would resolve nothing
  and mark four blocking rules `passed` — a false pass, strictly worse
  than the skip;
- the check is an import-graph predicate `ast-rules.ts` already implements
  for MM-R11/MM-R12; it was merely hard-coded to two rule ids instead of
  driven by the clause the rules carry.

Changes:
- carry the authored `enforce` block through normalization (config,
  configRef, mode, severityMap), and widen `EnforceDescriptor` to hold it;
- add `ModuleBoundaryRuleHandler` + `module-boundary-rules.ts`: a
  rule-driven from/to module-graph engine over the TypeScript AST, claiming
  by CLAUSE (not by rule id) within the boundary categories the
  PolicyCompiler already defines;
- `CompositeRuleEvaluator` re-dispatches any `skipped` enforcer result to
  the native strategy — the `fallback: 'native'` contract policy-compiler
  has documented since GT-516, finally connected. An unavailable analyzer
  now costs precision, never coverage; a rule both engines decline stays
  `skipped` with both reasons and still fails the run under GT-595 AC2;
- `ShellEnforcerAdapter.certificationGap` + a dependency-cruiser guard:
  running depcruise without a config compiled from the routed rules
  evaluates the satellite's own ruleset and reports names that match no
  routed toolRuleId, which would have marked all four `passed` on unrelated
  evidence. It now refuses and degrades instead.

The pinned corpus measurement moves 85 -> 81 blocking-and-skipped rules
(unimplemented-native 48 -> 44); the triage loader was also dropping
`enforce`, so it could not have seen the change otherwise.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Branch 1 of 5 into integration/gt-572-595-604. No conflicts.
Branch 2 of 5. No conflicts (it already contained branch 1).
Branch 3 of 5. One conflict, in rule-corpus-triage.spec.ts: branches 2 and 3
each re-pinned the same corpus counts independently, over disjoint rule sets.

Resolved by RECOMPUTING against the real corpus, not by picking a number.
Both branches' loader and assertions are kept — branch 3's `enforce`
pass-through in loadCorpus (without it the four HXA rules are invisible to the
measurement) and branch 2's named-id closures and OCB-02 vacuity block.

Measured, not assumed (jest reports Received length: 73 when the pin is
perturbed to 74):
  native-handler         139 -> 151  (+8 config-shaped, +4 module-boundary)
  unimplemented-native    60 ->  48
  unclaimed              114 -> 102
  blocking-and-skipped    85 ->  73
  offenders/unimplemented 48 ->  36

A parallel named test was added for the four module-boundary closures
(HXA-01/02/04/05, with HXA-03 as the unclaimed control), matching branch 2's
'name them, do not merely count them' treatment.
Branch 4 of 5. No conflicts. Note it branched from main directly and did NOT
contain branch 1, contrary to the integration brief.
Branch 5 of 5. No conflicts. Also branched from main directly and did NOT
contain branch 1.
…w reality

Three failures, each a consequence of a behaviour change that landed
deliberately. None was fixed by weakening an invariant.

1. infra-providers/rule-applicability.integration.spec.ts (GT-571)
   GT-595 AC2 makes `blocking` + `skipped` fail the run, so a fresh satellite
   now reports 72 blocking findings where the spec asserted []. Asserting [] here
   would be asserting that the GT-595 criterion does NOT work.

   The old assertion conflated two claims: (1) no rule addressed to somebody else
   fires — the GT-571 invariant — and (2) no blocking rule fails at all. Only (2)
   stopped being true. (1) is now asserted directly and more strictly than before:
   a new test requires that NO blocking finding belongs to a rule applicability
   excluded, over the same run. The corpus is not excluded and no applicability
   assertion was touched.

   Measured breakdown of the 72: 70 are the GT-595 invariant, and the other 2 are
   REAL verdicts from rules that really executed —
     MTN-05  scaffolded evolith.yaml declares no `spec.boundedContexts`
     GIT-08  the scaffold writes no commitlint configuration
   Both were closed by the GT-595 config-shaped slice and both fail on a freshly
   scaffolded satellite. That is a live defect in InitializeProjectUseCase, not a
   testing artifact; it is pinned by name so closing it moves the list to [].

2. src/tests/contract/sdk-type-contract.types.ts (GT-565)
   Branch 1 added `blockingSkippedRuleIds` to ValidationResult and core-api emits
   it, but the wire-contract map that enumerates the type was never updated, so
   the SDK type no longer described the wire. Declared it. This is the contract
   test doing its job.

3. reference/core/interfaces/how-to-*.md
   Derived artifacts, regenerated with gen-howto.ts. The drift is GT-632's:
   HXA-01 is claimed now, so HXA-03 takes its slot in the generated listings.
GT-595 closes on AC2: a rule declared `blocking` that returns `skipped` now
fails the run, emitted as a blocking ValidationIssue rather than a throw --
`RulesetValidatorService.validate` catches engine exceptions and downgrades
them to logger.warn, so a throw would have been swallowed by the only product
caller. Enforcing it exposed 181 blocking-but-dead rules: 96 auto-generated
ADR placeholders (the generator now emits `blocking: false`), and 12 of the
remaining 85 closed for real. The pin stands at 73, recomputed and observed
failing when perturbed to 74. Two root causes recorded: `normalizeRuleset`
never copied `enforce`, which made the whole enforcer subsystem unreachable
for lack of data; and the triage spec's own loader dropped it too, so the
measuring instrument measured a different corpus than production evaluates.
dependency-cruiser and OCB-02 are recorded as deliberate non-adoptions.

GT-572 closes against an `npm pack`ed tarball installed OUTSIDE the workspace.
The default configuration returns a real verdict; under NODE_ENV=production the
denial was a packaging defect (policy.wasm is gitignored and written outside
the package), satisfiable via EVOLITH_ABAC_POLICY_PATH. Shipping the bundle
inside the package stays a release-pipeline decision, documented and not done.

GT-604 moves PENDING -> IN-PROGRESS on criterion 1 only; criteria 2 and 3 are
not buildable in this repository and were handed over instead. Its declared
dependency on GT-603 is recorded as unconfirmed, not as a finding.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@beyondnetPeru
beyondnetPeru requested a review from a team as a code owner July 29, 2026 18:50
@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

@github-actions

Copy link
Copy Markdown

📊 Bilingual Coverage Impact

PR Changes

  • Paired EN/ES files modified: 5
  • New EN files needing ES translation: 5

Repository Coverage

Metric Value
Total EN files 524
Total ES files 498
Paired files 0
Coverage 0%

⚠️ Action required: 5 new EN file(s) added without ES counterparts.

To create skeletons:

node .harness/scripts/generate-es-skeleton.mjs <file.md>

Generated by GitHub Actions

@beyondnetPeru
beyondnetPeru merged commit 3dd3fa3 into develop Jul 29, 2026
29 of 33 checks passed
beyondnetPeru added a commit that referenced this pull request Jul 29, 2026
main moved while this PR was open: #273 merged `integration/gt-572-595-604` and
#274 followed. That is the branch which closed the twelve rules — HXA-01/02/04/05
(GT-632), MTN-05, GIT-08, SEC-RL-01, SEC-RL-02, ED-R04/R05/R06, DAM-R05 (GT-595)
— so Core now pins `native-handler: 151` / `unimplemented-native: 48`.

GitHub could not build a merge ref for a conflicting PR, so NONE of the five
required workflows ran on #276; only CodeQL reported. The conflict was in
`rule-corpus-triage.spec.ts`, the one file both sides rewrote.

Resolved by taking main's spec whole and re-applying the extraction on top, not
the reverse: main's version is the newer truth and carries assertions this branch
never had (the AC2 blocking-and-skipped list, the named module-boundary and
config-shaped closures, the OCB-02 vacuity measurement). Two things had to travel
with it:

  - `enforce` in the corpus loader. GT-632 added it to the spec's loader because
    dropping a field the handlers dispatch on measures a DIFFERENT corpus — four
    rules carried a complete module-graph clause nothing read. The extracted
    harness is that loader now, so it carries the field too. Without this the
    capture would have reproduced the pre-GT-632 classification.
  - `PINNED_CLASS_COUNTS` re-pinned to main's numbers, and main's inline literal
    replaced by a reference to it, so the .mjs guard keeps reading one pin.

Then recaptured and rebuilt, in that order. The new guard earned itself on the
first real drift it faced: before recapturing it named all twelve rules, one line
each — `HXA-01: snapshot says unimplemented-native, triage says native-handler`.
That is precisely the case the old guard passed on, twice.

Backlog 60 -> 48, and the READMEs move with it: analyser-adoptable 9 -> 5,
partial 8 -> 5, to-author 43 -> 38, so adoption is worth 10.4% / 20.8% of the
backlog rather than 15% / 28%. The shares FELL because four of the nine rules
that table offered to an analyser (HXA-01, HXA-02, HXA-04, GIT-08) now have a
native handler — Evolith wrote them first, and what remains leans further toward
authoring.

Verified after merge: core-domain jest 1436 passed / 127 suites; mapping guard
9/9; `capture --check` faithful at 386 rules; guards 01, 04, 46 green (46 still
at a fixed point).
beyondnetPeru added a commit that referenced this pull request Jul 29, 2026
…275

Investigation only, at the user's explicit request -- no fix applied. Each of
the three CI checks still red on PR #275 (Security Audit, E2E Tests, Evolith
Core Validation) is root-caused with evidence, not assumed pre-existing on the
strength of "it was probably already broken":

  - Security Audit: 31 npm audit findings (29 high, 2 moderate) in transitive
    deps of jest-snapshot/fast-uri. No package.json or lockfile touched here.
  - E2E Tests: one test of 132, "should validate architecture with --arch
    flag", exits 1 where it expects 0 or 2. #273's own CI run -- the same
    branch's prior merged PR, before any commit in this session existed --
    shows the identical failure by name and by count.
  - Evolith Core Validation: fails at Bilingual Terminology Lint, 5
    inconsistencies across four .es.md files, none touched by any commit in
    this PR (checked with git log per file, not assumed).

Left PENDING with unchecked acceptance criteria: fixing the npm audit findings
risks a breaking dependency bump, the E2E exit-code mismatch needs a decision
about which side (CLI or test) is wrong, and the terminology fixes need a
human call on which suggestions are correct versus a deliberate exception --
none of that is this closure's call to make unilaterally.

Counters recomputed: 635 gaps EN/ES (594 done, 23 pending), 611/611 catalog
sections, 576 closure records (unchanged -- GT-636 is open, so it carries none).

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
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