mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-12 22:26:13 +00:00
chore: drop tooling and host references from templates and comments
- The translation issue template called eight locales "AI-initial", left Russian out of its list and its dropdown; it now says they started as machine-translated drafts reviewed by the community. - The pull request template asked for two locales where the checks require all ten, and pointed at an ignored docs folder. - Code comments named the maintainer notes file, a release by its working name and an internal host; old changelog entries explained the notes files by their tool-specific names. A fixture token and the deploy webhook test's application id (a real one) are replaced.
This commit is contained in:
1 parent
a10a0e8f84
commit
d7eac1f87e
20 files changed
+43
-43
No files matched your search
@@ -1,12 +1,12 @@
|
||||
name: Translation feedback
|
||||
description: Report a wording, grammar, or register problem in HealthLog's community-maintained locales (FR / ES / IT / PL / KO / NL / PT-BR).
|
||||
description: Report a wording, grammar, or register problem in HealthLog's community-reviewed locales (FR / ES / IT / PL / KO / NL / PT-BR / RU).
|
||||
title: "[Translation] "
|
||||
labels: ["i18n", "translation-feedback"]
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
HealthLog ships German and English as maintainer-curated translations. French, Spanish, Italian, Polish, Korean, Dutch, and Brazilian Portuguese ship as **AI-initial, community-maintained translations** — the prose passes the locale-integrity test (full key parity, no empty values) but has not been hand-reviewed for register or regional vocabulary.
|
||||
HealthLog ships German and English as maintainer-curated translations. French, Spanish, Italian, Polish, Korean, Dutch, Brazilian Portuguese and Russian started as machine-translated first drafts and are reviewed by the community. They pass the locale-integrity test (full key parity, no empty values), but not every line has been read by a native speaker for register or regional vocabulary.
|
||||
|
||||
This template captures concrete fixes you would like to see. Phrasing nuance, regional vocabulary (e.g. "Tú" vs "Usted"), gendered forms, and domain-specific health terms are all in scope. The maintainer applies fixes during the regular release cycle.
|
||||
|
||||
@@ -23,6 +23,7 @@ body:
|
||||
- Korean (ko)
|
||||
- Dutch (nl)
|
||||
- Brazilian Portuguese (pt-BR)
|
||||
- Russian (ru)
|
||||
- Other (specify under "Surface")
|
||||
validations:
|
||||
required: true
|
||||
|
||||
@@ -28,16 +28,16 @@
|
||||
|
||||
## Checklist
|
||||
|
||||
- [ ] Targets the `main` branch (trunk-based — see [CONTRIBUTING.md](../CONTRIBUTING.md))
|
||||
- [ ] Targets the `main` branch (trunk-based, see [CONTRIBUTING.md](../CONTRIBUTING.md))
|
||||
- [ ] `pnpm typecheck` passes locally
|
||||
- [ ] `pnpm lint` passes locally
|
||||
- [ ] `pnpm test` passes locally
|
||||
- [ ] `pnpm format:check` passes locally
|
||||
- [ ] `pnpm build` passes locally
|
||||
- [ ] User-facing strings go through `t("key")` with both `messages/en.json` and `messages/de.json` updated
|
||||
- [ ] User-facing strings go through `t("key")`, with the key in all ten `messages/*.json` files
|
||||
- [ ] No secrets, personal data, or maintainer-name references in committed files
|
||||
- [ ] Updated `CHANGELOG.md` if user-visible
|
||||
- [ ] Updated `docs/audit/` or `docs.healthlog.dev` if behavior or self-hosting docs change
|
||||
- [ ] Updated `docs/` or `docs.healthlog.dev` if behaviour or self-hosting steps change
|
||||
|
||||
## Linked issues
|
||||
|
||||
|
||||
+5
-6
@@ -19279,9 +19279,8 @@ NOT NULL`) is the defence-in-depth backstop.
|
||||
- **DE+EN bilingual CHANGELOG entries (v1.4.14 + v1.4.15)
|
||||
normalised to English-only.** Per the English-only voice
|
||||
rule.
|
||||
- **`CLAUDE.md` filename retired** so the filename is no longer
|
||||
AI-vendor-specific; `CONTRIBUTING.md` reference updated.
|
||||
`AGENTS.md` stays for multi-agent compatibility.
|
||||
- **Maintainer notes renamed**; the `CONTRIBUTING.md` reference is
|
||||
updated.
|
||||
|
||||
### Deferred to v1.4.23
|
||||
|
||||
@@ -20599,8 +20598,8 @@ token '<', "<!DOCTYPE "`. 401/403 from the provider now map to 422,
|
||||
- **Repo-internal docs synced for v1.4.** README adds the
|
||||
Multi-tenant ready and Test connection buttons feature blocks, the
|
||||
API reference table includes the eleven new v1.4 endpoints, and
|
||||
the model count is corrected to 26 (RefreshToken). AGENTS.md and
|
||||
CLAUDE.md reflect the per-route `/settings/[section]` layout and
|
||||
the model count is corrected to 26 (RefreshToken). The maintainer
|
||||
notes reflect the per-route `/settings/[section]` layout and
|
||||
the per-section admin layout. `docs/api/openapi.yaml` documents
|
||||
the new endpoints (version, refresh, refresh/revoke,
|
||||
status-overview, backup/test, the five test-connection probes).
|
||||
@@ -21157,7 +21156,7 @@ timeout: 30s })` so in-flight handlers finish instead of being killed.
|
||||
- `.env.example` now points at the in-container hostname `db:5432` (was `localhost:5432`, which never resolves inside the app container).
|
||||
- **Documentation**:
|
||||
- `package.json` synced to 1.2.0 (was lagging on 1.1.0).
|
||||
- `CLAUDE.md` and `AGENTS.md` corrected to 23 models (the `Feedback` model added in v1.2 was missing from the count).
|
||||
- The maintainer notes are corrected to 23 models (the `Feedback` model added in v1.2 was missing from the count).
|
||||
- `README.md` Quick Start gives a realistic time estimate, generates the four secrets in one block straight into `.env`, and points reverse-proxy users at the docs.
|
||||
|
||||
### Added — Tooling & Supply Chain
|
||||
|
||||
@@ -137,7 +137,7 @@ test.describe("/admin/api-tokens mobile no-overflow", () => {
|
||||
data: [
|
||||
{
|
||||
id: "tok1",
|
||||
name: "iOS auto-login 2026-05-05T19:42:11Z device-AABBCCDDEEFF-marathon",
|
||||
name: "iOS auto-login 2026-05-05T19:42:11Z device-AABBCCDDEEFF-long-name",
|
||||
permissions: [
|
||||
"measurements:write:audit:legacy:extended",
|
||||
"medications:read",
|
||||
|
||||
@@ -221,7 +221,7 @@ async function enterSharedRecord(page: Page): Promise<void> {
|
||||
}
|
||||
|
||||
/**
|
||||
* Swap the context's pinned locale for one HealthLog ships as an AI-initial
|
||||
* Swap the context's pinned locale for one HealthLog ships as a machine
|
||||
* translation, so the maintainership strip has a reason to paint.
|
||||
*
|
||||
* The page is parked on `about:blank` for the swap. `I18nProvider` mirrors its
|
||||
|
||||
@@ -128,7 +128,7 @@ describe("POST /api/internal/deploy-webhook", () => {
|
||||
{
|
||||
status: "success",
|
||||
application_name: "HealthLog",
|
||||
application_uuid: "pg8wggwogo8c4gc4ks0kk4ss",
|
||||
application_uuid: "app-uuid-1",
|
||||
deployment_uuid: "dep-123",
|
||||
},
|
||||
{ "x-deploy-webhook-secret": "test-secret" },
|
||||
@@ -144,7 +144,7 @@ describe("POST /api/internal/deploy-webhook", () => {
|
||||
expect.objectContaining({
|
||||
details: expect.objectContaining({
|
||||
applicationName: "HealthLog",
|
||||
applicationUuid: "pg8wggwogo8c4gc4ks0kk4ss",
|
||||
applicationUuid: "app-uuid-1",
|
||||
deploymentUuid: "dep-123",
|
||||
error: null,
|
||||
raw: expect.objectContaining({ status: "success" }),
|
||||
@@ -166,7 +166,7 @@ describe("POST /api/internal/deploy-webhook", () => {
|
||||
{
|
||||
status: "failed",
|
||||
application_name: "HealthLog",
|
||||
application_uuid: "pg8wggwogo8c4gc4ks0kk4ss",
|
||||
application_uuid: "app-uuid-1",
|
||||
deployment_uuid: "dep-456",
|
||||
error: "container exited 137",
|
||||
},
|
||||
@@ -284,7 +284,7 @@ describe("POST /api/internal/deploy-webhook", () => {
|
||||
const fullPayload = {
|
||||
status: "success",
|
||||
application_name: "HealthLog",
|
||||
application_uuid: "pg8wggwogo8c4gc4ks0kk4ss",
|
||||
application_uuid: "app-uuid-1",
|
||||
deployment_uuid: "dep-789",
|
||||
future_field: { commit_sha: "abc123", environment: "production" },
|
||||
};
|
||||
|
||||
@@ -8,7 +8,7 @@ import type { Locale } from "@/lib/i18n/config";
|
||||
/**
|
||||
* v1.4.25 — <MaintainershipBanner> contract:
|
||||
* 1. Renders nothing on maintained locales (DE / EN).
|
||||
* 2. Renders a notice strip on AI-initial locales (FR / ES / IT / PL).
|
||||
* 2. Renders a notice strip on machine-translated locales (FR / ES / IT / PL).
|
||||
* 3. The notice carries a GitHub-issue CTA so feedback has a clear
|
||||
* home.
|
||||
*
|
||||
@@ -61,7 +61,7 @@ describe("<MaintainershipBanner>", () => {
|
||||
// documents that the strip is NOT painted before the first effect
|
||||
// runs — exactly the contract that prevents the flash-of-banner
|
||||
// problem.
|
||||
it("paints nothing in the SSR pass for AI-initial locales", () => {
|
||||
it("paints nothing in the SSR pass for machine-translated locales", () => {
|
||||
for (const locale of ["fr", "es", "it", "pl"] as const) {
|
||||
const html = ssr(locale);
|
||||
expect(html).not.toContain("maintainership-banner");
|
||||
|
||||
@@ -6,11 +6,11 @@ import { isMaintainedLocale, type Locale } from "@/lib/i18n/config";
|
||||
import { useTranslations } from "@/lib/i18n/context";
|
||||
|
||||
/**
|
||||
* v1.4.25 — notice strip for AI-initial locales.
|
||||
* v1.4.25 — notice strip for machine-translated locales.
|
||||
*
|
||||
* HealthLog ships German + English as maintainer-curated translations
|
||||
* (the maintainer owns both bodies). French, Spanish, Italian
|
||||
* and Polish ship as AI-initial translations — they pass the
|
||||
* and Polish ship as machine translations — they pass the
|
||||
* locale-integrity test (full key parity, no empty values, no TODOs)
|
||||
* but the prose has not been hand-reviewed for register, regional
|
||||
* vocabulary, or domain-specific nuance.
|
||||
@@ -18,7 +18,7 @@ import { useTranslations } from "@/lib/i18n/context";
|
||||
* This banner renders ONLY on non-maintained locales (FR/ES/IT/PL/KO
|
||||
* today) and surfaces a small, dismissible strip at the top of the
|
||||
* authenticated app shell. It tells the user the translation is
|
||||
* AI-maintained and links to the GitHub translation-feedback issue
|
||||
* machine-translated and links to the GitHub translation-feedback issue
|
||||
* template so they can contribute fixes back.
|
||||
*
|
||||
* Dismissal is persisted to localStorage per-locale so a user who
|
||||
|
||||
@@ -31,7 +31,7 @@ describe("parseLocaleFromAcceptLanguage", () => {
|
||||
expect(parseLocaleFromAcceptLanguage("*")).toBe("en");
|
||||
});
|
||||
|
||||
// v1.4.25 — the four AI-initial locales added in this release.
|
||||
// v1.4.25 — the four machine-translated locales added in this release.
|
||||
// Each maps via the same primary-tag prefix match the DE branch uses.
|
||||
it("returns the matching tag for FR / ES / IT / PL", () => {
|
||||
expect(parseLocaleFromAcceptLanguage("fr-FR,fr;q=0.9")).toBe("fr");
|
||||
|
||||
@@ -450,7 +450,7 @@ export async function extractAndStoreFacts(
|
||||
|
||||
let proposed = 0;
|
||||
for (const f of toStore) {
|
||||
// Field-by-field, no spread (mass-assignment rule, CLAUDE.md). A health
|
||||
// Field-by-field, no spread (no mass assignment). A health
|
||||
// fact waits for the person's tap; everything else is kept as extracted.
|
||||
const source = backgroundSource(f.category, f.fact, "extracted");
|
||||
if (source === PROPOSED_FACT_SOURCE) proposed += 1;
|
||||
@@ -710,7 +710,7 @@ export async function storeDeterministicFacts(args: {
|
||||
for (const cand of candidates) {
|
||||
if (isNearDuplicate(cand.fact, seen)) continue;
|
||||
seen.push(cand.fact);
|
||||
// Field-by-field, no spread (mass-assignment rule, CLAUDE.md).
|
||||
// Field-by-field, no spread (no mass assignment).
|
||||
await db.coachFact.create({
|
||||
data: {
|
||||
userId: args.userId,
|
||||
|
||||
@@ -380,7 +380,7 @@ export async function extractAndStorePlanProposals(
|
||||
const toStore = accepted.slice(0, remainingCapacity);
|
||||
|
||||
for (const p of toStore) {
|
||||
// Field-by-field, no spread (mass-assignment rule, CLAUDE.md). Always
|
||||
// Field-by-field, no spread (no mass assignment). Always
|
||||
// written as "proposed" — only the user-facing PATCH activates a plan.
|
||||
await db.coachPlan.create({
|
||||
data: {
|
||||
|
||||
@@ -18,7 +18,7 @@ import { loadSafetyContracts } from "@/lib/ai/prompts/safety-contracts";
|
||||
const NATIVE_LOCALES = ["fr", "es", "it", "pl"] as const;
|
||||
|
||||
/**
|
||||
* v1.4.25 — each AI-initial locale (FR / ES / IT / PL) now gets a
|
||||
* v1.4.25 — each machine-translated locale (FR / ES / IT / PL) now gets a
|
||||
* native system prompt assembled from the safety-contract matrix
|
||||
* instead of riding the EN body with a one-line footer.
|
||||
*
|
||||
@@ -34,7 +34,7 @@ const NATIVE_LOCALES = ["fr", "es", "it", "pl"] as const;
|
||||
* 9. The reply-language directive lives at the foot of the prompt.
|
||||
*/
|
||||
|
||||
describe("getCoachSystemPrompt — native AI-initial locales", () => {
|
||||
describe("getCoachSystemPrompt — native machine-translated locales", () => {
|
||||
it.each(NATIVE_LOCALES)(
|
||||
"%s produces a non-empty native prompt embedding PROMPT_VERSION",
|
||||
(locale) => {
|
||||
@@ -140,7 +140,7 @@ describe("getCoachSystemPrompt — native AI-initial locales", () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe("getStrictInsightsSystemPrompt — native AI-initial locales", () => {
|
||||
describe("getStrictInsightsSystemPrompt — native machine-translated locales", () => {
|
||||
it.each(NATIVE_LOCALES)(
|
||||
"%s produces a non-empty native Insights prompt",
|
||||
(locale) => {
|
||||
|
||||
@@ -1032,7 +1032,7 @@ export function buildSystemPromptWithReferences(
|
||||
const refs = selectReferencesForMetrics(metrics);
|
||||
if (refs.length === 0) return base;
|
||||
|
||||
// v1.4.25 — AI-initial locales (FR/ES/IT/PL) ride the EN sources
|
||||
// v1.4.25 — machine-translated locales (FR/ES/IT/PL) ride the EN sources
|
||||
// block. The "title" field is the EN title; the model is told to
|
||||
// surface the citation id, not to translate the source title, so this
|
||||
// is safe — citation labels in the UI use the contract id (lowercase,
|
||||
@@ -1107,7 +1107,7 @@ export const OUT_OF_SCOPE_REFUSAL_DE = {
|
||||
* from the safety-contract matrix so the summary copy stays in sync
|
||||
* with the prompt body that taught the model to emit it. The EN /
|
||||
* DE constants above remain authoritative for their locales — these
|
||||
* helpers cover the AI-initial locales.
|
||||
* helpers cover the machine-translated locales.
|
||||
*/
|
||||
export const OUT_OF_SCOPE_REFUSAL_FR = buildOutOfScopeRefusal("fr");
|
||||
export const OUT_OF_SCOPE_REFUSAL_ES = buildOutOfScopeRefusal("es");
|
||||
|
||||
@@ -171,7 +171,7 @@ describe("generateAlerts", () => {
|
||||
});
|
||||
});
|
||||
|
||||
// v1.4 marathon — closes the body-fat ACE drift identified in the
|
||||
// v1.4: closes the body-fat ACE drift identified in the
|
||||
// medical-truthfulness audit. Below-essential is now a danger band,
|
||||
// "Essential" is the warning band proper, and the labels match ACE.
|
||||
describe("classifyBodyFat (ACE bands)", () => {
|
||||
|
||||
+1
-1
@@ -480,7 +480,7 @@ async function lookupIpOnline(ip: string): Promise<GeoResolved | null> {
|
||||
// metadata address (SSRF/rebinding).
|
||||
// v1.15.12 — keep the online timeout below the audit-log 3 s race
|
||||
// window so a slow-but-successful lookup still lands before the race
|
||||
// resolves null and drops the location (the "—" symptom on apps01).
|
||||
// resolves null and drops the location (the "—" symptom in production).
|
||||
{ timeoutMs: 2_500, requirePublicHost: true },
|
||||
);
|
||||
if (!res.ok) {
|
||||
|
||||
@@ -87,7 +87,7 @@ export const localeLabels: Record<Locale, string> = {
|
||||
|
||||
/**
|
||||
* v1.4.25 — locales actively maintained by the project owner.
|
||||
* Locales outside this set are AI-initial translations and surface a
|
||||
* Locales outside this set are machine-translated translations and surface a
|
||||
* <MaintainershipBanner> notice at the top of the auth shell so users
|
||||
* know to expect rough edges and where to contribute fixes. Promoting
|
||||
* a locale here turns the banner off.
|
||||
|
||||
@@ -33,7 +33,7 @@ describe("determinePhase", () => {
|
||||
});
|
||||
});
|
||||
|
||||
// v1.4 marathon — closes v3 audit "Locale Mixing" CRIT.
|
||||
// v1.4: closes the "Locale Mixing" finding.
|
||||
// Reminder messages must follow the user's stored locale, not always
|
||||
// German. callback_data values are stable English identifiers and stay
|
||||
// untranslated regardless of UI locale.
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
/**
|
||||
* Host-load sampler (every five minutes since v1.42) that backs the admin /admin/system-status
|
||||
* "last 2 hours" chart (v1.4.16 phase B3).
|
||||
* "last 2 hours" chart.
|
||||
*
|
||||
* The maintainer asked for a small at-a-glance graph above the system-status facts
|
||||
* grid showing CPU + memory + disk-IO so a glance at /admin tells them
|
||||
* whether the apps-01 host is healthy. We considered scraping Coolify's
|
||||
* A small at-a-glance graph above the system-status facts grid shows
|
||||
* CPU + memory + disk-IO, so a glance at /admin tells an operator whether
|
||||
* the app host is healthy. We considered scraping Coolify's
|
||||
* Sentinel collector, but the Coolify HTTP API does not expose a clean
|
||||
* read endpoint for per-server metrics — every approach ended up either
|
||||
* scraping the Coolify dashboard HTML or hitting a private RPC. An
|
||||
|
||||
@@ -157,8 +157,8 @@ const resolveLocale = coerceLocale;
|
||||
* `medicationReminders.phase*`. The reminder worker passes the user's
|
||||
* stored locale; absent / unknown locales fall back to the app default.
|
||||
*
|
||||
* v1.4 marathon — closes the v3 audit "Locale-Mixing" CRIT finding
|
||||
* (German-only Telegram / Web Push templates regardless of user locale).
|
||||
* v1.4: closes the "Locale-Mixing" finding (German-only Telegram / Web Push
|
||||
* templates regardless of user locale).
|
||||
*/
|
||||
export function getPhaseMessage(
|
||||
phase: ReminderPhase,
|
||||
|
||||
+2
-2
@@ -175,8 +175,8 @@ function isPublicPath(pathname: string): boolean {
|
||||
* a unit toggle and a date of birth, and it is why free text, anything that
|
||||
* reaches an AI prompt, and anything creating a second record are refused.
|
||||
*
|
||||
* This whole block only runs under `DEMO_MODE=true`, so production (apps01)
|
||||
* is unaffected by construction.
|
||||
* This whole block only runs under `DEMO_MODE=true`, so production is
|
||||
* unaffected by construction.
|
||||
*/
|
||||
const DEMO_MUTATION_ALLOWLIST: ReadonlyArray<{ path: string; method: string }> =
|
||||
[
|
||||
|
||||
Reference in new issue
Block a user