Skip to content

add MCP server badge#1

Closed
punkpeye wants to merge 1 commit into
strale-io:mainfrom
punkpeye:glama-badge
Closed

add MCP server badge#1
punkpeye wants to merge 1 commit into
strale-io:mainfrom
punkpeye:glama-badge

Conversation

@punkpeye
Copy link
Copy Markdown

This PR adds a badge for the strale-mcp server listing in Glama MCP server directory.

strale-mcp MCP server

Glama performs regular codebase and documentation checks to:

  • Confirm that the MCP server is working as expected
  • Confirm that there are no obvious security issues
  • Extract server characteristics such as tools, resources, prompts, and required parameters.

This badge helps your users to quickly assess that the MCP server is safe, server capabilities, and instructions for installing the server.

@punkpeye
Copy link
Copy Markdown
Author

Realized that GitHub does not recognize the project license

https://docs.github.com/en/communities/setting-up-your-project-for-healthy-contributions/adding-a-license-to-a-repository

Would you mind adding one?

@punkpeye
Copy link
Copy Markdown
Author

I will follow up with a separate PR to show how to connect to the MCP server.

@punkpeye
Copy link
Copy Markdown
Author

punkpeye commented Apr 1, 2026

Your MCP server is already listed on Glama.

You don't have to add the badge, but it makes it easy for users to discover, vet, and host your server.

If you'd like, claim your server and add the badge strale MCP server yourself.

If you need any help, reach me at frank@glama.ai

@punkpeye punkpeye closed this Apr 1, 2026
petterlindstrom79 added a commit that referenced this pull request Apr 29, 2026
#1, #2, #4-polish)

Three audit-display honesty fixes that touch the same code paths:

CCO #1 — /v1/audit/:id was rebuilding the compliance shape from
  current capability metadata at every render. The hash-protected
  audit_trail and provenance JSONB columns were never read. A
  transaction executed against allabolag.se (scrape) when the slug
  later migrated to bolagsverket-hvd (licensed API) would render
  showing the new source as the source that ran.

  Fix: SELECT audit_trail, provenance, transparency_marker, and
  data_jurisdiction from the row; pass to composeAuditRecord; prefer
  stored values over derived. New `source: "stored" | "derived" |
  "hybrid"` field on the response distinguishes hash-protected
  fields from at-render-time recomposition for legacy rows.

CCO #2 — composeAuditRecord computed perStepMs as
  floor(latencyMs / total_steps) and presented the result as
  measurement. For a 3-step solution where step 1 timed out at 4500ms
  and steps 2-3 returned in 1ms, every step rendered as ~1504ms,
  concealing the failure pattern. Real per-step timings ARE captured
  in audit_trail.steps[].latencyMs by buildInlineAudit at execution
  time — they were just discarded at render.

  Fix: new extractStoredStepLatencies() reads timings from
  audit_trail.steps[] (solutions) or audit_trail.latency_ms
  (capabilities, single-step). When the per-step timing isn't stored,
  the latency_ms field is OMITTED from the step rather than fabricated
  via even-division. AuditStep.latency_ms is now optional in the type.

  10 new tests in audit.test.ts including an explicit regression guard
  ("does NOT fabricate even-division per-step latency"). One of those
  tests caught a real implementation bug during writing — early-return
  on null auditTrail short-circuited the fallback to row-level latency.
  Fixed and re-tested.

CCO #4-polish — verify endpoint now returns a human-readable
  redaction_reason on redacted rows. A regulator hitting /v1/verify
  on a GDPR-erased row previously saw hash_valid: null with no
  context — could be mistaken for tampering. The reason explicitly
  states the design: chain hash preserved for continuity, content
  hash mismatched by design.

Refs: CCO audit P0 (#1, #2, #4); SESSION_F_audit_findings.md
F-AUDIT-08, F-AUDIT-09, F-AUDIT-13/16.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
petterlindstrom79 added a commit that referenced this pull request May 12, 2026
* feat: cost_class taxonomy schema (blocks 0067, 0070)

Phase A0b commit #1 of 5. Adds the schema substrate for the cost-class
gate without yet reading from it.

Block 0067 adds 4 nullable columns to `capabilities`:
  - cost_class TEXT (CHECK: free_unlimited | free_quota |
    paid_with_free_tier | paid_prepaid | paid_subscription)
  - quota_window TEXT (CHECK: daily | monthly | none)
  - quota_cap INTEGER
  - quota_reset_dom INTEGER (CHECK: 1..31)

NULL means "not yet classified" — inverted default. Commit #4's
scheduler reads cost_class and excludes unclassified caps; commit #3's
dispatcher refuses internal-test invocations of unclassified caps but
allows customer_paid (preserves traffic during GRACE backfill window).

Block 0070 creates `capability_budget_counters` for per-capability
test-budget tracking on free_quota and paid_with_free_tier classes.
Composite PK (capability_slug, window_start, window_kind) for atomic
INSERT ... ON CONFLICT DO UPDATE ... RETURNING increment (race-free
under burst, modeled on existing rate_limit_counters).

Both blocks idempotent: ADD COLUMN IF NOT EXISTS for DDL; CHECK
constraints guarded by pg_constraint NOT EXISTS lookup so re-runs are
no-ops. Regression test asserts both first-run and second-run shapes.

Per A0a §§ 2 + 13 + 14 (deploy mechanism verified — index.ts:74
calls runStartupMigrations which iterates BLOCKS in order). Per
Rule 9 (schema/migration drift): schema.ts and startup-migrations.ts
edited in the same commit, type-check clean.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* feat: classify DE/DK/SK cost_class (manifest + block 0068)

Phase A0b commit #2 of 5. Adds cost_class to the manifest authoring
surface and seeds DE/DK/SK rows via a deploy-time migration. Strategy
(b) self-throttling: the ~312 other capabilities remain NULL and are
backfilled in Phase B under no time pressure.

Manifest type: cost_class, quota_window, quota_cap, quota_reset_dom
(all optional). FIELD_CATEGORIES entries declare these as manifest-
canonical so backfill UPDATEs flow from YAML to DB. normalizeManifestToRow
maps snake_case → camelCase with the standard non-partial / partial
behavior (null on create, omitted on backfill).

YAML changes:
  - german-company-data.yaml: free_quota, monthly, cap 50, reset_dom 1
    (OpenRegister 50 req/month, resets on the 1st of each month)
  - danish-company-data.yaml: free_quota, daily, cap 50
    (cvrapi.dk empirical floor; documented limit higher but conservative
     until one clean cycle observed)
  - slovak-company-data.yaml: free_unlimited, none
    (gov RPO, only burst rate limit, no cumulative quota)

Block 0068 seeds the DB by slug with `AND cost_class IS NULL` filter.
Idempotent: re-run is no-op; future Phase B classifications are
preserved (never overwritten). Three vendor evidence references in
the manifest YAML files point at the executor source comments that
document the upstream quota shape.

CC's session does not connect to a database; backfill is applied at
deploy time when Petter runs `drizzle-kit migrate` (which invokes
the in-TS-block convention per DEC-20260511-C, threaded through
runStartupMigrations).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* feat: dispatcher gate via guardedExecute + ALLOW_MATRIX

Phase A0b commit #3 of 5. Adds the choke-point gate that prevents
internal callers (scheduler, CI, manual scripts) from burning vendor
credits outside customer-initiated paths.

New module: apps/api/src/capabilities/guarded-executor.ts
  - InvocationContext discriminated union (customer_paid | internal_test
    | health_probe | ci) — required at every call site, no defaults.
  - ALLOW_MATRIX (5 cost classes × 4 contexts → allow | refuse | budget_check).
  - guardedExecute(slug, input, ctx): the single entry point for external
    callers; runs gate then delegates to getExecutor.
  - assertGuardedAllow(slug, ctx): same gate without the executor call,
    for callers that have their own retry/wrapping logic (do.ts).
  - getCapabilityCostMeta with 5min in-process cache.
  - assertBudgetAvailable: atomic INSERT ... ON CONFLICT DO UPDATE ...
    RETURNING for race-free per-window counter increment.
  - 30/50/80% threshold alerts + hard-stop alert via lib/alerting.ts.
  - Error classes: CapabilityNotClassifiedError,
    CapabilityInvocationRefusedError, BudgetExhaustedError.

Call sites wrapped:
  - Customer paths (customer_paid context):
    routes/do.ts, routes/x402-gateway-v2.ts, lib/solution-executor.ts
  - Internal paths (internal_test context):
    lib/test-runner.ts (per-suite + regression), routes/internal-tests.ts
    (recalibration), lib/capability-onboarding.ts (fixture validation +
    regression-test generation), db/audit-tests.ts (offline audit)
  - Scripts (internal_test/manual):
    smoke-test.ts, smoke-singapore.ts, test-budimex.ts, onboard.ts,
    add-name-fixtures.ts. validate-capability.ts marked exempt
    (existence-check only).

Intra-capability invocations (capabilities-calling-capabilities, e.g.
website-to-company → meta-extract / url-to-markdown) intentionally still
use getExecutor directly — the outer call already paid the ALLOW_MATRIX
check, and double-counting the budget would be wrong.

NULL_DECISIONS preserves customer traffic during the GRACE backfill
window (null cost_class × customer_paid → allow per Q2 chat decision).
All other contexts refuse on null with CapabilityNotClassifiedError.

CI lints added:
  - check-no-direct-getexecutor-in-scripts.mjs: rejects new scripts that
    import getExecutor without also importing the guarded helper (or
    declaring a `guarded-executor-exempt:` marker for existence-checks).
  - check-cost-class-coherence.mjs: cross-checks manifest cost_class
    against the env-vars the executor source reads. Flags free_* caps
    that hit a paid vendor. Per-env-var exemption marker
    (`cost-class-coherence-exempt: ENV_VAR`) for fallback-only paths
    (danish-company-data uses Anthropic for fuzzy name resolution; the
    primary path is cvrapi.dk — declared exempt).

Regression tests (27 cases): every ALLOW_MATRIX cell + the NULL_DECISIONS
table + the budget math (computeBudgetCap, computeWindowStart) + a 50-
concurrent burst against budget_cap=10 (asserts exactly 10 allowed,
40 BudgetExhaustedError refusals — race-free).

Per DEC-20260504-A (audit-followup test coverage). Full vitest run:
585 passed / 11 skipped / 0 failed.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* feat: scheduler reads cost_class for eligibility + budget exclusion (block 0069)

Phase A0b commit #4 of 5. Replaces Block 0066's interim derivation
(scheduled_testing_eligible := external_cost_cents = 0) with the
structural rule grounded in cost_class.

Block 0069 (new): reconciles test_suites.scheduled_testing_eligible
from capabilities.cost_class. The bridge predicate was the documented
bug — it conflated "no per-call cost" with "no quota," letting the
scheduler burn DE OpenRegister's 50-req/month free tier. The new
derivation:

  eligible := cost_class IN ('free_unlimited', 'free_quota', 'paid_with_free_tier')

Unclassified caps (cost_class IS NULL) stay scheduled_testing_eligible
= FALSE — fail-closed. Post-condition asserts every classified cap's
suites match the derivation; mismatch aborts boot (same shape as Block
0062's post-condition). Block 0066 still runs first as the column-
creation idempotency path; 0069 then overrides its derivation. Idempotent
via `IS DISTINCT FROM` filter.

Scheduler SELECT (`apps/api/src/jobs/test-scheduler.ts`): adds a
budget-counter exclusion via NOT EXISTS subquery. Capabilities whose
per-window counter has reached its budget_cap are skipped at query
time (defense-in-depth alongside the per-call assertBudgetAvailable
gate). free_unlimited and unclassified caps short-circuit through.
Window-start derivation in SQL matches the TS helper's logic
(date_trunc + reset_dom offset for monthly).

DEC reference at lines 16 + 242: cites DEC-20260511-C (the in-TS-block
convention codifier — Q3 audit recovered the scope) and leaves a
TODO(chat-draft) marker for the new cost-class meta-pattern DEC that
chat will draft after this session. CC does not invent a DEC ID.

Regression tests (3 new cases): Block 0069 first-run reconcile,
idempotent re-run, post-condition violation. Canonical block list
extended to 13 entries.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* feat: cost_class boot invariant (GRACE default, STRICT opt-in)

Phase A0b commit #5 of 5 (backend half). Adds the startup assertion
that surfaces unclassified capabilities loudly at every boot, with
two modes:

  COST_CLASS_MODE=GRACE (default): boot succeeds; warn log + one
    `skip-unclassified` line per active+visible cap with cost_class
    IS NULL. Scheduler and dispatcher already fail-closed for these
    caps; this mode keeps the count visible at every Railway deploy
    so the backfill horizon doesn't drift unnoticed.

  COST_CLASS_MODE=STRICT: boot aborts via process.exit(1) on any
    unclassified active+visible row. Flip after one operational
    cycle confirms GRACE's count is empty (Phase B backfill complete).

New: apps/api/src/lib/cost-class-invariant.ts. Modeled on
assertAlertingConfigured (cert-audit C11) — same fail-loud startup
shape. Wired into apps/api/src/index.ts:80 between validateSchema
and the app.ts import (Rule 14: deploy mechanism verified — runs on
every Railway boot via Dockerfile CMD → main()).

Regression tests (7 cases): GRACE tolerates unclassified rows
without exit; STRICT exits with code 1; resolveCostClassMode defaults
to GRACE for unset/unrecognized values, returns STRICT only for
"STRICT" (case-insensitive). Process.exit spy asserts the abort
shape pins the contract — a future engineer can't silently turn
STRICT into a no-op.

Frontend deferred. Phase A0b §8 plans the strale-frontend display
change (extend SQSResult.label="Unverified" semantics for paid_*
caps awaiting production traffic). The strale-frontend worktree
has 5 unrelated long-stale modifications from late April; the
display change is independent of the structural gate and lives in
a separate repo / separate PR. Flagged for chat to schedule as a
sibling PR (see end-of-session summary).

Full vitest run: 595 passed / 11 skipped / 0 failed.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

* fix: route cost-class STRICT-mode fatal through logError (F-0-014)

CI's `lint:no-new-console` (apps/api/scripts/check-no-new-console.mjs)
rejected the three console.error calls in cost-class-invariant.ts.
The structured-logger requirement (F-0-014) applies to all new files.
Replaces the three console.error calls with a single logError call
carrying the same payload (mode, unclassified_count, full list with
slug+name); process.exit(1) shape unchanged. Test updated to drop
the console.error spy assertion (no longer relevant).

Lint clean; vitest 7/7 cost-class-invariant tests green.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.7 (1M context) <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