develop #59
63
create_issue_no_jq.sh
Normal file
63
create_issue_no_jq.sh
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
#!/bin/bash
|
||||
#
|
||||
# Script zum Anlegen des Gitea Issues ohne jq dependency
|
||||
#
|
||||
|
||||
GITEA_TOKEN="b3d27c7d87d2acf39490d0c58f26922164edb4e8"
|
||||
GITEA_URL="http://192.168.2.144:3000"
|
||||
REPO_OWNER="Lars"
|
||||
REPO_NAME="mitai-jinkendo"
|
||||
|
||||
# Issue Body aus Datei lesen (erste 29 Zeilen überspringen = Metadaten)
|
||||
ISSUE_BODY=$(tail -n +30 "c:/Dev/mitai-jinkendo/.claude/task/rework_0b_placeholder/ISSUE_METADATEN_REVIEW.md" | python3 -c "import sys, json; print(json.dumps(sys.stdin.read()))")
|
||||
|
||||
# JSON Payload mit Python erstellen
|
||||
python3 << PYEOF > /tmp/issue_payload.json
|
||||
import json
|
||||
|
||||
body = $ISSUE_BODY
|
||||
|
||||
payload = {
|
||||
"title": "Placeholder Registry: UNRESOLVED & TO_VERIFY Metadaten prüfen",
|
||||
"body": body,
|
||||
"labels": [2, 3]
|
||||
}
|
||||
|
||||
print(json.dumps(payload, ensure_ascii=False))
|
||||
PYEOF
|
||||
|
||||
echo "Erstelle Gitea Issue..."
|
||||
echo "Repository: $REPO_OWNER/$REPO_NAME"
|
||||
echo ""
|
||||
|
||||
# Issue via API anlegen
|
||||
RESPONSE=$(curl -s -X POST \
|
||||
"$GITEA_URL/api/v1/repos/$REPO_OWNER/$REPO_NAME/issues" \
|
||||
-H "Authorization: token $GITEA_TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d @/tmp/issue_payload.json)
|
||||
|
||||
# Response mit Python parsen
|
||||
python3 << PYEOF
|
||||
import json
|
||||
|
||||
response = '''$RESPONSE'''
|
||||
try:
|
||||
data = json.loads(response)
|
||||
if 'number' in data:
|
||||
print(f"✓ Issue erfolgreich erstellt!")
|
||||
print(f"")
|
||||
print(f"Issue #{data['number']}")
|
||||
print(f"URL: {data['html_url']}")
|
||||
print(f"")
|
||||
print(f"✓ Fertig!")
|
||||
else:
|
||||
print(f"✗ Fehler beim Erstellen des Issues:")
|
||||
print(json.dumps(data, indent=2))
|
||||
except Exception as e:
|
||||
print(f"✗ Fehler: {e}")
|
||||
print(response)
|
||||
PYEOF
|
||||
|
||||
# Cleanup
|
||||
rm -f /tmp/issue_payload.json
|
||||
78
create_metadaten_review_issue.sh
Normal file
78
create_metadaten_review_issue.sh
Normal file
|
|
@ -0,0 +1,78 @@
|
|||
#!/bin/bash
|
||||
#
|
||||
# Script zum Anlegen des Gitea Issues:
|
||||
# "Placeholder Registry: UNRESOLVED & TO_VERIFY Metadaten prüfen"
|
||||
#
|
||||
# Usage: ./create_metadaten_review_issue.sh YOUR_GITEA_TOKEN
|
||||
#
|
||||
|
||||
if [ -z "$1" ]; then
|
||||
echo "ERROR: Gitea Token erforderlich"
|
||||
echo "Usage: $0 YOUR_GITEA_TOKEN"
|
||||
echo ""
|
||||
echo "Token erstellen:"
|
||||
echo " 1. Gitea öffnen: http://192.168.2.144:3000"
|
||||
echo " 2. Settings → Applications → Generate New Token"
|
||||
echo " 3. Name: 'Claude Code Issue Management'"
|
||||
echo " 4. Scope: issue (read/write)"
|
||||
echo " 5. Token kopieren und als Argument übergeben"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
GITEA_TOKEN="$1"
|
||||
GITEA_URL="http://192.168.2.144:3000"
|
||||
REPO_OWNER="Lars"
|
||||
REPO_NAME="mitai-jinkendo"
|
||||
|
||||
# Issue Body aus Datei lesen (erste 30 Zeilen überspringen = Metadaten)
|
||||
ISSUE_BODY=$(tail -n +30 .claude/task/rework_0b_placeholder/ISSUE_METADATEN_REVIEW.md)
|
||||
|
||||
# JSON Payload erstellen
|
||||
cat > /tmp/gitea_issue_payload.json << EOF
|
||||
{
|
||||
"title": "Placeholder Registry: UNRESOLVED & TO_VERIFY Metadaten prüfen",
|
||||
"body": $(echo "$ISSUE_BODY" | jq -Rs .),
|
||||
"labels": [1, 2, 3],
|
||||
"priority": 2
|
||||
}
|
||||
EOF
|
||||
|
||||
echo "Erstelle Gitea Issue..."
|
||||
echo "Repository: $REPO_OWNER/$REPO_NAME"
|
||||
echo ""
|
||||
|
||||
# Issue via API anlegen
|
||||
RESPONSE=$(curl -s -X POST \
|
||||
"$GITEA_URL/api/v1/repos/$REPO_OWNER/$REPO_NAME/issues" \
|
||||
-H "Authorization: token $GITEA_TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d @/tmp/gitea_issue_payload.json)
|
||||
|
||||
# Response prüfen
|
||||
if echo "$RESPONSE" | grep -q '"number"'; then
|
||||
ISSUE_NUMBER=$(echo "$RESPONSE" | jq -r '.number')
|
||||
ISSUE_URL=$(echo "$RESPONSE" | jq -r '.html_url')
|
||||
|
||||
echo "✓ Issue erfolgreich erstellt!"
|
||||
echo ""
|
||||
echo "Issue #$ISSUE_NUMBER"
|
||||
echo "URL: $ISSUE_URL"
|
||||
echo ""
|
||||
|
||||
# Labels setzen (falls nicht automatisch gesetzt)
|
||||
echo "Setze Labels..."
|
||||
curl -s -X POST \
|
||||
"$GITEA_URL/api/v1/repos/$REPO_OWNER/$REPO_NAME/issues/$ISSUE_NUMBER/labels" \
|
||||
-H "Authorization: token $GITEA_TOKEN" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d '{"labels": [1, 2, 3]}' > /dev/null
|
||||
|
||||
echo "✓ Fertig!"
|
||||
else
|
||||
echo "✗ Fehler beim Erstellen des Issues:"
|
||||
echo "$RESPONSE" | jq .
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Cleanup
|
||||
rm -f /tmp/gitea_issue_payload.json
|
||||
1
nutrition_cluster_final.json
Normal file
1
nutrition_cluster_final.json
Normal file
File diff suppressed because one or more lines are too long
1
nutrition_cluster_final_check.json
Normal file
1
nutrition_cluster_final_check.json
Normal file
File diff suppressed because one or more lines are too long
75
package-lock.json
generated
Normal file
75
package-lock.json
generated
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
{
|
||||
"name": "mitai-jinkendo",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"devDependencies": {
|
||||
"@playwright/test": "^1.58.2"
|
||||
}
|
||||
},
|
||||
"node_modules/@playwright/test": {
|
||||
"version": "1.58.2",
|
||||
"resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.58.2.tgz",
|
||||
"integrity": "sha512-akea+6bHYBBfA9uQqSYmlJXn61cTa+jbO87xVLCWbTqbWadRVmhxlXATaOjOgcBaWU4ePo0wB41KMFv3o35IXA==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"playwright": "1.58.2"
|
||||
},
|
||||
"bin": {
|
||||
"playwright": "cli.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/fsevents": {
|
||||
"version": "2.3.2",
|
||||
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
|
||||
"integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
|
||||
"dev": true,
|
||||
"hasInstallScript": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
],
|
||||
"engines": {
|
||||
"node": "^8.16.0 || ^10.6.0 || >=11.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/playwright": {
|
||||
"version": "1.58.2",
|
||||
"resolved": "https://registry.npmjs.org/playwright/-/playwright-1.58.2.tgz",
|
||||
"integrity": "sha512-vA30H8Nvkq/cPBnNw4Q8TWz1EJyqgpuinBcHET0YVJVFldr8JDNiU9LaWAE1KqSkRYazuaBhTpB5ZzShOezQ6A==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"playwright-core": "1.58.2"
|
||||
},
|
||||
"bin": {
|
||||
"playwright": "cli.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"fsevents": "2.3.2"
|
||||
}
|
||||
},
|
||||
"node_modules/playwright-core": {
|
||||
"version": "1.58.2",
|
||||
"resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.58.2.tgz",
|
||||
"integrity": "sha512-yZkEtftgwS8CsfYo7nm0KE8jsvm6i/PTgVtB8DL726wNf6H2IMsDuxCpJj59KDaxCtSnrWan2AeDqM7JBaultg==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"bin": {
|
||||
"playwright-core": "cli.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
5
package.json
Normal file
5
package.json
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"devDependencies": {
|
||||
"@playwright/test": "^1.58.2"
|
||||
}
|
||||
}
|
||||
12
playwright.config.js
Normal file
12
playwright.config.js
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
module.exports = {
|
||||
testDir: './tests',
|
||||
timeout: 30000,
|
||||
use: {
|
||||
channel: 'chrome',
|
||||
headless: true,
|
||||
viewport: { width: 390, height: 844 },
|
||||
screenshot: 'only-on-failure',
|
||||
baseURL: 'https://dev.mitai.jinkendo.de',
|
||||
},
|
||||
reporter: 'list',
|
||||
};
|
||||
1
registry_export_final.json
Normal file
1
registry_export_final.json
Normal file
File diff suppressed because one or more lines are too long
1
registry_export_fixed.json
Normal file
1
registry_export_fixed.json
Normal file
File diff suppressed because one or more lines are too long
1
registry_export_new_data.json
Normal file
1
registry_export_new_data.json
Normal file
File diff suppressed because one or more lines are too long
1
registry_export_part_c.json
Normal file
1
registry_export_part_c.json
Normal file
File diff suppressed because one or more lines are too long
1
registry_export_part_c_fixed.json
Normal file
1
registry_export_part_c_fixed.json
Normal file
File diff suppressed because one or more lines are too long
1
registry_export_partb.json
Normal file
1
registry_export_partb.json
Normal file
File diff suppressed because one or more lines are too long
6
test-results/.last-run.json
Normal file
6
test-results/.last-run.json
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"status": "failed",
|
||||
"failedTests": [
|
||||
"d6ae548bbe32e0652471-816c0db33a38f27f1eaf"
|
||||
]
|
||||
}
|
||||
202
test_activity_registration.py
Normal file
202
test_activity_registration.py
Normal file
|
|
@ -0,0 +1,202 @@
|
|||
"""
|
||||
Test script to verify Activity Cluster placeholder registration.
|
||||
|
||||
Verifies:
|
||||
1. All 17 Activity placeholders are registered
|
||||
2. All have complete metadata (22 mandatory fields)
|
||||
3. Evidence distribution is correct
|
||||
"""
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
# Add backend to path
|
||||
sys.path.insert(0, str(Path(__file__).parent / 'backend'))
|
||||
|
||||
# Import registrations (triggers auto-registration)
|
||||
print("Importing placeholder_registry...")
|
||||
from placeholder_registry import EvidenceType, get_registry
|
||||
print("Importing activity_metrics...")
|
||||
try:
|
||||
from placeholder_registrations import activity_metrics
|
||||
print("Activity metrics imported successfully")
|
||||
except Exception as e:
|
||||
print(f"ERROR importing activity_metrics: {e}")
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
|
||||
METADATA_REGISTRY = get_registry()
|
||||
print(f"Registry size after import: {len(METADATA_REGISTRY.get_all())}")
|
||||
|
||||
# Expected placeholders
|
||||
EXPECTED_ACTIVITY_PLACEHOLDERS = [
|
||||
'activity_summary',
|
||||
'activity_detail',
|
||||
'trainingstyp_verteilung',
|
||||
'training_minutes_week',
|
||||
'training_frequency_7d',
|
||||
'quality_sessions_pct',
|
||||
'ability_balance_strength',
|
||||
'ability_balance_endurance',
|
||||
'ability_balance_mental',
|
||||
'ability_balance_coordination',
|
||||
'ability_balance_mobility',
|
||||
'proxy_internal_load_7d',
|
||||
'monotony_score',
|
||||
'strain_score',
|
||||
'rest_day_compliance',
|
||||
'vo2max_trend_28d',
|
||||
'activity_score',
|
||||
]
|
||||
|
||||
def test_registration():
|
||||
"""Test that all Activity placeholders are registered."""
|
||||
print("=== Activity Cluster Registration Test ===\n")
|
||||
|
||||
# Check all expected placeholders
|
||||
registered = []
|
||||
missing = []
|
||||
|
||||
for key in EXPECTED_ACTIVITY_PLACEHOLDERS:
|
||||
if METADATA_REGISTRY.get(key) is not None:
|
||||
registered.append(key)
|
||||
else:
|
||||
missing.append(key)
|
||||
|
||||
print(f"OK Registered: {len(registered)}/17")
|
||||
if missing:
|
||||
print(f"FAIL Missing: {len(missing)}/17")
|
||||
for key in missing:
|
||||
print(f" - {key}")
|
||||
return False
|
||||
|
||||
print(f"OK All 17 Activity placeholders registered\n")
|
||||
return True
|
||||
|
||||
|
||||
def test_metadata_completeness():
|
||||
"""Test that all registered placeholders have complete metadata."""
|
||||
print("=== Metadata Completeness Test ===\n")
|
||||
|
||||
mandatory_fields = [
|
||||
'key', 'category', 'name_de', 'name_en', 'description_de', 'description_en',
|
||||
'placeholder_type', 'output_type', 'unit', 'time_window', 'semantic_contract',
|
||||
'calculation_method', 'source_info', 'data_lineage', 'confidence_logic',
|
||||
'missing_value_policy', 'known_limitations', 'dependencies',
|
||||
'layer_2b_reuse_possible', 'example_value'
|
||||
]
|
||||
|
||||
incomplete = []
|
||||
|
||||
for key in EXPECTED_ACTIVITY_PLACEHOLDERS:
|
||||
metadata = METADATA_REGISTRY.get(key)
|
||||
if metadata is None:
|
||||
continue
|
||||
|
||||
missing_fields = []
|
||||
|
||||
for field in mandatory_fields:
|
||||
value = getattr(metadata, field, None)
|
||||
if value is None or value == '' or value == []:
|
||||
missing_fields.append(field)
|
||||
|
||||
if missing_fields:
|
||||
incomplete.append((key, missing_fields))
|
||||
|
||||
if incomplete:
|
||||
print(f"FAIL Incomplete metadata: {len(incomplete)}/17")
|
||||
for key, fields in incomplete:
|
||||
print(f" - {key}: missing {fields}")
|
||||
return False
|
||||
|
||||
print(f"OK All 17 placeholders have complete metadata (20 mandatory fields)\n")
|
||||
return True
|
||||
|
||||
|
||||
def test_evidence_distribution():
|
||||
"""Test evidence tagging distribution."""
|
||||
print("=== Evidence Distribution Test ===\n")
|
||||
|
||||
evidence_counts = {
|
||||
EvidenceType.CODE_DERIVED: 0,
|
||||
EvidenceType.DRAFT_DERIVED: 0,
|
||||
EvidenceType.MIXED: 0,
|
||||
EvidenceType.TO_VERIFY: 0,
|
||||
EvidenceType.UNRESOLVED: 0,
|
||||
}
|
||||
|
||||
total_tags = 0
|
||||
|
||||
for key in EXPECTED_ACTIVITY_PLACEHOLDERS:
|
||||
metadata = METADATA_REGISTRY.get(key)
|
||||
if metadata is None:
|
||||
continue
|
||||
|
||||
# Count evidence tags (22 fields)
|
||||
for field in metadata.get_all_evidence_fields():
|
||||
evidence = metadata.get_evidence(field)
|
||||
if evidence:
|
||||
evidence_counts[evidence] = evidence_counts.get(evidence, 0) + 1
|
||||
total_tags += 1
|
||||
|
||||
print(f"Total evidence tags: {total_tags} (expected ~374 = 17 × 22)")
|
||||
print("\nDistribution:")
|
||||
for evidence_type, count in evidence_counts.items():
|
||||
percentage = (count / total_tags * 100) if total_tags > 0 else 0
|
||||
print(f" {evidence_type.value:15s}: {count:3d} ({percentage:5.1f}%)")
|
||||
|
||||
print("\nExpected distribution:")
|
||||
print(" CODE_DERIVED: ~60% (directly from code)")
|
||||
print(" DRAFT_DERIVED: ~15% (from canonical draft)")
|
||||
print(" MIXED: ~15% (combined sources)")
|
||||
print(" TO_VERIFY: ~10% (needs verification)")
|
||||
print()
|
||||
|
||||
return True
|
||||
|
||||
|
||||
def dump_sample_placeholder():
|
||||
"""Dump one complete placeholder as sample."""
|
||||
print("=== Sample Placeholder: activity_score ===\n")
|
||||
|
||||
metadata = METADATA_REGISTRY.get('activity_score')
|
||||
if metadata is None:
|
||||
print("FAIL activity_score not found in registry")
|
||||
return False
|
||||
|
||||
print(f"Key: {metadata.key}")
|
||||
print(f"Category: {metadata.category}")
|
||||
print(f"Name (DE): {metadata.name_de}")
|
||||
print(f"Name (EN): {metadata.name_en}")
|
||||
print(f"Type: {metadata.placeholder_type.value}")
|
||||
print(f"Output: {metadata.output_type.value}")
|
||||
print(f"Unit: {metadata.unit}")
|
||||
print(f"Time Window: {metadata.time_window}")
|
||||
print(f"\nDescription (DE):")
|
||||
print(f" {metadata.description_de[:100]}...")
|
||||
print(f"\nSemantic Contract:")
|
||||
print(f" {metadata.semantic_contract[:100]}...")
|
||||
print(f"\nCalculation Method:")
|
||||
print(f" {metadata.calculation_method[:100]}...")
|
||||
print(f"\nKnown Limitations:")
|
||||
print(f" {metadata.known_limitations[:150]}...")
|
||||
print(f"\nDependencies: {len(metadata.dependencies)} items")
|
||||
print(f"Layer 2b Reuse: {metadata.layer_2b_reuse_possible}")
|
||||
print()
|
||||
|
||||
return True
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
success = True
|
||||
|
||||
success &= test_registration()
|
||||
success &= test_metadata_completeness()
|
||||
success &= test_evidence_distribution()
|
||||
success &= dump_sample_placeholder()
|
||||
|
||||
if success:
|
||||
print("OK All tests passed - Activity Cluster registration is complete and valid")
|
||||
sys.exit(0)
|
||||
else:
|
||||
print("FAIL Some tests failed - see output above")
|
||||
sys.exit(1)
|
||||
65
tests/dev-smoke-test.spec.js
Normal file
65
tests/dev-smoke-test.spec.js
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
const { test, expect } = require('@playwright/test');
|
||||
|
||||
const TEST_EMAIL = process.env.TEST_EMAIL || 'lars@stommer.com';
|
||||
const TEST_PASSWORD = process.env.TEST_PASSWORD || '5112';
|
||||
|
||||
async function login(page) {
|
||||
await page.goto('/');
|
||||
await page.waitForLoadState('networkidle');
|
||||
await page.fill('input[type="email"]', TEST_EMAIL);
|
||||
await page.fill('input[type="password"]', TEST_PASSWORD);
|
||||
await page.click('button:has-text("Anmelden")');
|
||||
await page.waitForLoadState('networkidle');
|
||||
}
|
||||
|
||||
test('1. Login funktioniert', async ({ page }) => {
|
||||
await page.goto('/');
|
||||
await page.fill('input[type="email"]', TEST_EMAIL);
|
||||
await page.fill('input[type="password"]', TEST_PASSWORD);
|
||||
await page.click('button:has-text("Anmelden")');
|
||||
await page.waitForLoadState('networkidle');
|
||||
const loginButton = page.locator('button:has-text("Anmelden")');
|
||||
await expect(loginButton).toHaveCount(0, { timeout: 10000 });
|
||||
await page.screenshot({ path: 'screenshots/01-nach-login.png' });
|
||||
console.log('Login erfolgreich');
|
||||
});
|
||||
|
||||
test('2. Dashboard laedt ohne Fehler', async ({ page }) => {
|
||||
await login(page);
|
||||
await expect(page.locator('.spinner')).toHaveCount(0, { timeout: 10000 });
|
||||
await page.screenshot({ path: 'screenshots/02-dashboard.png' });
|
||||
console.log('Dashboard OK');
|
||||
});
|
||||
|
||||
test('3. Erfassung erreichbar', async ({ page }) => {
|
||||
await login(page);
|
||||
await page.click('text=Erfassung');
|
||||
await page.waitForLoadState('networkidle');
|
||||
await page.screenshot({ path: 'screenshots/03-erfassung.png' });
|
||||
console.log('Erfassung OK');
|
||||
});
|
||||
|
||||
test('4. Analyse erreichbar', async ({ page }) => {
|
||||
await login(page);
|
||||
await page.click('text=Analyse');
|
||||
await page.waitForLoadState('networkidle');
|
||||
await page.screenshot({ path: 'screenshots/04-analyse.png' });
|
||||
console.log('Analyse OK');
|
||||
});
|
||||
|
||||
test('5. Keine kritischen Console-Fehler', async ({ page }) => {
|
||||
const errors = [];
|
||||
page.on('console', msg => {
|
||||
if (msg.type() === 'error') errors.push(msg.text());
|
||||
});
|
||||
await login(page);
|
||||
await page.waitForLoadState('networkidle');
|
||||
const kritisch = errors.filter(e =>
|
||||
!e.includes('favicon') && !e.includes('sourceMap') && !e.includes('404')
|
||||
);
|
||||
if (kritisch.length > 0) {
|
||||
console.log('Console-Fehler:', kritisch.join(', '));
|
||||
} else {
|
||||
console.log('Keine kritischen Console-Fehler');
|
||||
}
|
||||
});
|
||||
Loading…
Reference in New Issue
Block a user