Release-Tags nach Paketbuild direkt veröffentlichen

This commit is contained in:
hugo committed 2026-09-11 23:08:44 +02:00
1 parent 5a1a284505
commit ccc372778c
19 files changed
+278 -387

No files matched your search

+1 -43
View File
@@ -1,5 +1,5 @@
#!/usr/bin/env python3
"""Vierzielpakete bauen, entpackt prüfen und vollständige Freigaben validieren."""
"""Vierzielpakete bauen und optional auf dem Zielsystem prüfen."""
import argparse
import hashlib
import json
@@ -186,45 +186,6 @@ def target_check(archive, target, output, windows_console_test=None):
(output / 'report.json').write_text(json.dumps(report, indent=2) + '\n')
def gate(directory, evidence, revision, version):
"""Fail closed: vier exakte Pakete und unabhängige, passende Zielnachweise."""
require(re.fullmatch('[0-9a-f]{40}', revision), 'Ungültige Revision')
require(digest(ROOT / 'tests/libraries/portable.tbl') == TBL_SHA, 'TBL-Probe verändert')
assets = []
for target in TARGETS:
archive = directory / name(version, target)
require(archive.is_file(), f'Pflichtpaket fehlt: {archive.name}')
sha = digest(archive)
checksum = archive.with_name(archive.name + '.sha256')
require(checksum.read_text() == f'{sha} {archive.name}\n', 'Paketprüfsumme falsch')
manifest = verify(archive, target, ROOT / 'target/release/tb-template')
require(manifest['revision'] == revision and not manifest['source_dirty'], 'Paket aus falschem/uncommittetem Stand')
proof = json.loads((evidence / target / 'report.json').read_text())
require(proof.get('target') == target and proof.get('revision') == revision and proof.get('package') == archive.name and
proof.get('package_sha256') == sha and proof.get('tbl_sha256') == TBL_SHA, 'Zielnachweis passt nicht zum Paket')
required = {'native', 'library', 'default-template', 'windows-console' if target == list(TARGETS)[0] else 'ide-pty'}
require(proof.get('automated_passed') is True and all(proof.get('checks', {}).get(k) == 'passed' for k in required), 'Automatisierte Zielprüfung fehlt')
manual = json.loads((evidence / target / 'manual.json').read_text())
require(manual.get('revision') == revision and manual.get('package_sha256') == sha and
manual.get('target') == target and manual.get('passed') is True and
manual.get('tester') and manual.get('terminal_versions') and manual.get('evidence'), 'Manueller Terminalnachweis fehlt')
terminals = {'windows-terminal'} if target == list(TARGETS)[0] else {'terminal.app'} if target == list(TARGETS)[1] else {'xterm', 'vte'}
require(isinstance(manual['terminal_versions'], dict) and
all(manual['terminal_versions'].get(t) for t in terminals), 'Pflichtemulator/Version fehlt')
require(all(manual.get('cases', {}).get(k) is True for k in
('f1_f12', 'modifiers', 'mouse', 'unicode_colors', 'resize', 'input_break', 'shell')), 'Manuelle Pflichtfolge unvollständig')
for reference in manual['evidence']:
relative = Path(reference)
require(not relative.is_absolute() and '..' not in relative.parts, 'Ungültiger manueller Nachweispfad')
path = evidence / target / relative
require(path.is_file() and path.stat().st_size > 0, 'Manueller Beleg fehlt')
assets.extend([archive, checksum])
acceptance = json.loads((evidence / 'acceptance.json').read_text())
require(acceptance.get('revision') == revision and acceptance.get('passed') is True and
all(acceptance.get(k) for k in ('foreign', 'inventory', 'workspace', 'benchmarks', 'native_ide', 'run_url', 'buildhost')), 'Pflichtabnahme/Benchmarks fehlen')
return assets
def main():
parser = argparse.ArgumentParser(description=__doc__)
sub = parser.add_subparsers(dest='command', required=True)
@@ -236,13 +197,10 @@ def main():
else:
p.add_argument('--output', type=Path, required=True)
p.add_argument('--windows-console-test', type=Path)
p = sub.add_parser('gate'); p.add_argument('--packages', type=Path, required=True); p.add_argument('--evidence', type=Path, required=True)
p.add_argument('--revision', required=True); p.add_argument('--version', required=True)
args = parser.parse_args()
if args.command == 'pack': pack(args.bin_dir.resolve(), args.target, args.output.resolve(), args.inspector.resolve())
elif args.command == 'verify': verify(args.archive.resolve(), args.target, args.inspector.resolve() if args.inspector else None)
elif args.command == 'target-check': target_check(args.archive.resolve(), args.target, args.output.resolve(), args.windows_console_test.resolve() if args.windows_console_test else None)
else: gate(args.packages, args.evidence, args.revision, args.version)
if __name__ == '__main__':
-37
View File
@@ -1,37 +0,0 @@
#!/usr/bin/env python3
"""Nur einen bestehenden Tag und Nachweise aus einer Origin-Revision verwenden."""
import os
from pathlib import Path
import re
import subprocess
import tempfile
import distribution as dist
import release
tag, evidence_revision = os.environ['TB_TAG'], os.environ['TB_EVIDENCE_REVISION']
release.release_version(tag)
dist.require(re.fullmatch('[0-9a-f]{40}', evidence_revision), 'Ungültige Nachweisrevision')
revision = subprocess.check_output(['git', 'rev-parse', '--verify', tag + '^{commit}'], text=True).strip()
api = release.Gitea()
info = api.request('GET', '/git/commits/' + evidence_revision)
dist.require(info['sha'] == evidence_revision, 'Nachweise nicht am Origin')
# Checkout enthält alle Origin-Branches. Ein nicht vorhandener Commit scheitert hier.
base = f'release-evidence/{tag}'
names = subprocess.check_output(['git', 'ls-tree', '-r', '--name-only', evidence_revision, base], text=True).splitlines()
with tempfile.TemporaryDirectory(prefix='tb-release-') as tmp:
evidence = Path(tmp) / 'evidence'; evidence.mkdir()
for name in names:
relative = Path(name).relative_to(base)
dist.require('..' not in relative.parts and not relative.is_absolute(), 'Ungültiger Nachweispfad')
path = evidence / relative; path.parent.mkdir(parents=True, exist_ok=True)
path.write_bytes(subprocess.check_output(['git', 'show', evidence_revision + ':' + name]))
packages = Path(tmp) / 'packages'; packages.mkdir()
draft = api.request('GET', '/releases/tags/' + tag)
wanted = release.expected(tag[1:])
dist.require(draft['draft'] and len(draft.get('assets', [])) == len(wanted) and
{a['name'] for a in draft['assets']} == set(wanted), 'Unvollständiger Entwurf')
for asset in draft['assets']:
(packages / asset['name']).write_bytes(api.download(asset))
# Grundabnahme kommt aus dem ursprünglichen Taglauf, nicht aus manuell ersetzten Angaben.
(evidence / 'acceptance.json').write_bytes((packages / 'acceptance.json').read_bytes())
release.publish(api, packages, evidence, tag, revision)
+12 -43
View File
@@ -1,7 +1,6 @@
#!/usr/bin/env python3
"""Gitea-Entwurf befüllen; erst nach exakten Paket-/Zielnachweisen freigeben."""
"""Taggebundene Vierzielpakete hochladen und direkt auf Gitea veröffentlichen."""
import argparse
import hashlib
import json
import os
from pathlib import Path
@@ -37,12 +36,6 @@ class Gitea:
with self.open(Request(self.api + path, data=payload, headers=headers, method=method), timeout=120) as response:
return json.load(response)
def download(self, asset):
url = asset['browser_download_url']
dist.require(urlparse(url).netloc == urlparse(self.base).netloc, 'Fremder Assetserver')
with self.open(Request(url, headers={'Authorization': 'token ' + self.token}), timeout=120) as response:
return response.read()
def release_version(tag):
dist.require(re.fullmatch(r'v(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)', tag),
@@ -51,10 +44,10 @@ def release_version(tag):
def expected(version):
return [n for t in dist.TARGETS for n in (dist.name(version, t), dist.name(version, t) + '.sha256')] + ['acceptance.json']
return [n for t in dist.TARGETS for n in (dist.name(version, t), dist.name(version, t) + '.sha256')]
def stage(api, directory, tag, revision):
def publish(api, directory, tag, revision):
version = release_version(tag)
dist.require(re.fullmatch('[0-9a-f]{40}', revision), 'Tag/Revision ungültig')
dist.require(api.request('GET', '/tags/' + quote(tag, safe=''))['commit']['sha'] == revision, 'Tag zeigt auf andere Revision')
@@ -64,27 +57,28 @@ def stage(api, directory, tag, revision):
manifest = dist.verify(path, target, dist.ROOT / 'target/release/tb-template')
dist.require(manifest['revision'] == revision and not manifest['source_dirty'], 'Paketrevision falsch/uncommitted')
dist.require(path.with_name(path.name + '.sha256').read_text() == f'{dist.digest(path)} {path.name}\n', 'Paketprüfsumme falsch')
acceptance = json.loads((directory / 'acceptance.json').read_text())
dist.require(acceptance.get('revision') == revision and acceptance.get('passed') is True, 'Grundabnahme fehlt')
try:
release = api.request('GET', '/releases/tags/' + quote(tag, safe=''))
except HTTPError as error:
if error.code != 404:
raise
error.close()
release = api.request('POST', '/releases', dict(tag_name=tag, target_commitish=revision,
name='Terminal Basic ' + version, draft=True,
body='Vierzielpakete im Entwurf. Zielnachweise fehlen noch; keine Freigabe.'))
body=f'Vierzielpakete für Revision {revision}. Upload läuft.'))
dist.require(release['draft'], 'Bereits veröffentlichten Release nicht verändern')
# Wiederholungen dürfen identische Uploads ergänzen, keine vorhandenen Assets ersetzen.
# Wiederholungen ergänzen fehlende Uploads; vorhandene Assets werden nicht ersetzt.
existing = {a['name']: a for a in release.get('assets', [])}
dist.require(set(existing) <= set(names), 'Unerwartete Assets im Entwurf')
for name in names:
data = (directory / name).read_bytes()
if name in existing:
dist.require(api.download(existing[name]) == data, f'Abweichendes vorhandenes Asset: {name}')
dist.require(existing[name]['size'] == len(data), f'Abweichende Größe des vorhandenen Assets: {name}')
else:
api.request('POST', f'/releases/{release["id"]}/assets?name=' + quote(name), data)
verify_uploads(api, release['id'], directory, names)
api.request('PATCH', f'/releases/{release["id"]}', dict(draft=False,
body=f'Terminal Basic {version}, Revision {revision}. Vier Zielpakete mit SHA-256-Prüfsummen.'))
return release['id']
@@ -93,42 +87,17 @@ def verify_uploads(api, release_id, directory, names):
assets = release.get('assets', [])
dist.require(len(assets) == len(names) and {a['name'] for a in assets} == set(names), 'Unvollständiger Asset-Upload')
for asset in assets:
dist.require(hashlib.sha256(api.download(asset)).hexdigest() == dist.digest(directory / asset['name']), 'Uploadprüfsumme falsch')
dist.require(asset['size'] == (directory / asset['name']).stat().st_size,
f'Uploadgröße falsch: {asset["name"]}')
return release
def publish(api, directory, evidence, tag, revision):
version = release_version(tag)
dist.require(api.request('GET', '/tags/' + quote(tag, safe=''))['commit']['sha'] == revision, 'Tag zeigt auf andere Revision')
dist.gate(directory, evidence, revision, version)
release = api.request('GET', '/releases/tags/' + quote(tag, safe=''))
verify_uploads(api, release['id'], directory, expected(version))
dist.require(release['draft'], 'Bereits freigegebenen Release nicht verändern')
api.request('PATCH', f'/releases/{release["id"]}', dict(draft=False,
body=f'Geprüfte Vierzielpakete für Revision {revision}. Zugehörige Zielnachweise: {os.environ.get("TB_EVIDENCE_REVISION", "lokaler Nachweissatz")}.'))
def main():
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument('command', choices=['stage', 'download', 'publish'])
parser.add_argument('--packages', type=Path, required=True)
parser.add_argument('--tag', required=True); parser.add_argument('--revision', required=True)
parser.add_argument('--evidence', type=Path)
args = parser.parse_args()
api = Gitea()
if args.command == 'stage': stage(api, args.packages, args.tag, args.revision)
elif args.command == 'publish':
dist.require(args.evidence, '--evidence erforderlich')
publish(api, args.packages, args.evidence, args.tag, args.revision)
else:
args.packages.mkdir(parents=True) # Nie lokale Kandidaten überschreiben.
release = api.request('GET', '/releases/tags/' + quote(args.tag, safe=''))
names = expected(release_version(args.tag))
dist.require(release['draft'], 'Nur bestehende Entwürfe freigeben')
assets = release.get('assets', [])
dist.require(len(assets) == len(names) and {a['name'] for a in assets} == set(names), 'Pflichtassets fehlen')
for asset in assets:
(args.packages / asset['name']).write_bytes(api.download(asset))
publish(Gitea(), args.packages, args.tag, args.revision)
if __name__ == '__main__':
+71 -79
View File
@@ -1,22 +1,49 @@
import copy
import hashlib
import json
from pathlib import Path
import tarfile
import tempfile
import unittest
from unittest.mock import patch
from urllib.error import HTTPError
import distribution as d
import release as r
class API:
"""Release-API ohne Downloadpfad; protokolliert jede Mutation."""
def __init__(self):
self.release = None
self.fail_at = None
self.writes = []
self.omit_upload = False
self.wrong_size = False
def request(self, method, path, data=None):
if path.startswith('/tags/'):
return {'commit': {'sha': 'a' * 40}}
if method == 'GET':
if self.release is None:
raise HTTPError(path, 404, 'Not Found', {}, None)
return copy.deepcopy(self.release)
self.writes.append((method, path))
if method == 'POST' and path == '/releases':
self.release = dict(id=1, assets=[], **data)
elif method == 'POST':
name = path.split('name=')[1]
if name == self.fail_at:
raise OSError('simulierter Uploadfehler')
if not self.omit_upload:
self.release['assets'].append(dict(name=name, size=len(data) + self.wrong_size))
elif method == 'PATCH':
self.release.update(data)
return copy.deepcopy(self.release)
class DistributionTests(unittest.TestCase):
def setUp(self):
self.temp = tempfile.TemporaryDirectory()
self.addCleanup(self.temp.cleanup)
self.root = Path(self.temp.name)
self.packages = self.root / 'packages'; self.packages.mkdir()
self.evidence = self.root / 'evidence'; self.evidence.mkdir()
self.packages = Path(self.temp.name)
self.revision = 'a' * 40
self.version = '1.0.0'
self.manifests = {}
@@ -25,22 +52,11 @@ class DistributionTests(unittest.TestCase):
path.write_bytes(target.encode())
path.with_name(path.name + '.sha256').write_text(f'{d.digest(path)} {path.name}\n')
self.manifests[target] = dict(revision=self.revision, version=self.version, source_dirty=False)
proof = self.evidence / target; proof.mkdir()
report = dict(target=target, revision=self.revision, package=path.name,
package_sha256=d.digest(path), tbl_sha256=d.TBL_SHA, automated_passed=True,
checks={k:'passed' for k in ('native','library','ide-pty','windows-console','default-template')})
(proof / 'report.json').write_text(json.dumps(report))
(proof / 'manual.json').write_text(json.dumps(dict(target=target, revision=self.revision,
package_sha256=d.digest(path), passed=True, tester='Prüfer',
terminal_versions={k:'Version 1' for k in ('windows-terminal','terminal.app','xterm','vte')},
cases={k:True for k in ('f1_f12','modifiers','mouse','unicode_colors','resize','input_break','shell')}, evidence=['terminal.txt'])))
(proof / 'terminal.txt').write_text('Bedienprotokoll')
acceptance = dict(revision=self.revision, passed=True, foreign=True, inventory=True,
workspace=True, benchmarks=True, native_ide=True, run_url='https://git.rfc1437.de/run/1', buildhost='Linux arm64')
for directory in (self.packages, self.evidence):
(directory / 'acceptance.json').write_text(json.dumps(acceptance))
self.mock_verify = patch.object(d, 'verify', side_effect=lambda archive, target, *args: self.manifests[target])
self.mock_verify.start(); self.addCleanup(self.mock_verify.stop)
mock_verify = patch.object(d, 'verify', side_effect=lambda archive, target, *args: self.manifests[target])
mock_verify.start(); self.addCleanup(mock_verify.stop)
def publish(self, api):
return r.publish(api, self.packages, 'v' + self.version, self.revision)
def test_release_tags_are_exact_numeric_versions(self):
for tag in ('v1.0.0', 'v0.0.0', 'v12.34.56'):
@@ -49,80 +65,56 @@ class DistributionTests(unittest.TestCase):
'v1.0.0/extra', 'v01.0.0', 'v1x.0.0', 'v1.0.0\n'):
with self.assertRaises(ValueError, msg=tag): r.release_version(tag)
def gate(self):
return d.gate(self.packages, self.evidence, self.revision, self.version)
def test_complete_gate_and_missing_or_wrong_evidence(self):
self.assertEqual(len(self.gate()), 8)
target = list(d.TARGETS)[0]
path = self.evidence / target / 'report.json'
valid = json.loads(path.read_text())
for key, value in [('revision','b'*40), ('target',list(d.TARGETS)[1]), ('package_sha256','0'*64),
('tbl_sha256','0'*64), ('automated_passed',False), ('checks',{'native':'passed'})]:
broken = dict(valid, **{key:value}); path.write_text(json.dumps(broken))
with self.assertRaises(ValueError, msg=key): self.gate()
path.write_text(json.dumps(valid))
(self.evidence / target / 'manual.json').unlink()
with self.assertRaises(FileNotFoundError): self.gate()
def test_missing_corrupt_dirty_and_mismatched_packages(self):
def test_bad_packages_prevent_any_release_mutation(self):
api = API()
first = next(iter(d.TARGETS))
self.manifests[first]['source_dirty'] = True
with self.assertRaises(ValueError): self.gate()
self.manifests[first]['source_dirty'] = False
for key, value in [('source_dirty', True), ('revision', 'b' * 40)]:
original = self.manifests[first][key]
self.manifests[first][key] = value
with self.assertRaises(ValueError): self.publish(api)
self.manifests[first][key] = original
path = self.packages / d.name(self.version, first)
path.write_bytes(b'broken')
with self.assertRaises(ValueError): self.gate()
with self.assertRaises(ValueError): self.publish(api)
path.unlink()
with self.assertRaises(ValueError): self.gate()
with self.assertRaises(FileNotFoundError): self.publish(api)
self.assertEqual(api.writes, [])
def test_archive_traversal_rejected_before_extract(self):
path = self.root / 'evil.tar.gz'
path = self.packages / 'evil.tar.gz'
with tarfile.open(path, 'w:gz') as tar:
entry = tarfile.TarInfo('../escape'); tar.addfile(entry)
dest = self.root / 'unpack'; dest.mkdir()
tar.addfile(tarfile.TarInfo('../escape'))
dest = self.packages / 'unpack'; dest.mkdir()
with self.assertRaises(ValueError): d.unpack(path, dest, list(d.TARGETS)[1])
self.assertFalse((self.root / 'escape').exists())
self.assertFalse((self.packages / 'escape').exists())
def test_upload_failure_never_publishes_or_overwrites(self):
class API:
def __init__(self):
self.release = dict(id=1, draft=True, assets=[])
self.data = {}; self.fail_at = None; self.writes = []
def request(self, method, path, data=None):
if path.startswith('/tags/'): return {'commit': {'sha': 'a'*40}}
if method == 'GET': return copy.deepcopy(self.release)
self.writes.append((method,path))
if method == 'POST':
name = path.split('name=')[1]
if name == self.fail_at: raise OSError('simulierter Uploadfehler')
self.data[name] = data
self.release['assets'].append(dict(name=name, browser_download_url=name))
return {}
if method == 'PATCH': self.release.update(data)
def download(self, asset): return self.data[asset['name']]
def test_upload_failure_then_retry_publishes_directly_without_evidence_or_download(self):
api = API(); api.fail_at = r.expected(self.version)[2]
with self.assertRaises(OSError): r.stage(api, self.packages, 'v'+self.version, self.revision)
with self.assertRaises(OSError): self.publish(api)
self.assertTrue(api.release['draft'])
self.assertFalse(any(method=='PATCH' for method,_ in api.writes))
self.assertFalse(any(method == 'PATCH' for method, _ in api.writes))
self.assertEqual(len(api.release['assets']), 2)
before_retry = len(api.writes)
api.fail_at = None
r.stage(api, self.packages, 'v'+self.version, self.revision)
r.publish(api, self.packages, self.evidence, 'v'+self.version, self.revision)
self.publish(api)
self.assertFalse(api.release['draft'])
self.assertEqual(len(api.release['assets']), 8)
self.assertEqual(len(api.writes[before_retry:]), 7) # sechs fehlende Assets + Freigabe
self.assertEqual(api.writes[-1], ('PATCH', '/releases/1'))
before = list(api.writes)
with self.assertRaises(ValueError): r.stage(api, self.packages, 'v'+self.version, self.revision)
with self.assertRaises(ValueError): self.publish(api)
self.assertEqual(before, api.writes)
def test_incomplete_remote_upload_blocks_publish(self):
class API:
def request(self, method, path, data=None):
self.assert_get(method)
if path.startswith('/tags/'): return {'commit': {'sha': 'a'*40}}
return dict(id=1, draft=True, assets=[])
@staticmethod
def assert_get(method):
if method != 'GET': raise AssertionError('Unerwartete Mutation')
with self.assertRaises(ValueError): r.publish(API(), self.packages, self.evidence, 'v'+self.version, self.revision)
def test_incomplete_or_wrong_sized_upload_never_publishes(self):
for fault in ('omit_upload', 'wrong_size'):
api = API(); setattr(api, fault, True)
with self.assertRaises(ValueError): self.publish(api)
self.assertTrue(api.release['draft'])
self.assertFalse(any(method == 'PATCH' for method, _ in api.writes))
api.wrong_size = False
before = list(api.writes)
with self.assertRaises(ValueError): self.publish(api)
self.assertEqual(before, api.writes) # vorhandene abweichende Assets bleiben erhalten
if __name__ == '__main__':
+7 -32
View File
@@ -1,19 +1,14 @@
name: Release-Build und Pflichtabnahme
name: Release-Build und Veröffentlichung
on:
push:
tags: ['v[0-9]*.[0-9]*.[0-9]*']
permissions:
contents: read
jobs:
checks:
preflight:
runs-on: linux-arm64
container: ghcr.io/rust-cross/cargo-zigbuild@sha256:82af75c41958c2af2787e8bedd912da7678a9438937e223e9d83d006d747b38b
timeout-minutes: 60
env:
CARGO_BUILD_JOBS: '2'
TB_VBDOS_REPOSITORY: ${{ vars.TB_VBDOS_REPOSITORY }}
TB_VBDOS_REPO: /tmp/tb-vbdos
TB_RUN_URL: ${{ gitea.server_url }}/${{ gitea.repository }}/actions/runs/${{ gitea.run_number }}
steps:
# Vor checkout nötig: Die Cross-Images enthalten kein Node für JS-Actions.
- name: Gepinnte Actions-Laufzeit
@@ -38,27 +33,8 @@ jobs:
version = tomllib.loads((dist.ROOT / 'Cargo.toml').read_text())['workspace']['package']['version']
dist.require(release_version(os.environ['TB_TAG']) == version, 'Tag und Workspace-Version weichen ab')
PYTHON
- name: Gepinnte Werkzeuge
run: sh .gitea/scripts/bootstrap.sh
- name: Fixierten Fremdbestand bereitstellen
run: |
set -eu
test -n "$TB_VBDOS_REPOSITORY" || { echo 'TB_VBDOS_REPOSITORY für Pflichtabnahme fehlt'; exit 1; }
git init "$TB_VBDOS_REPO"
git -C "$TB_VBDOS_REPO" fetch --depth=1 "$TB_VBDOS_REPOSITORY" 1cdd2b32b829fe1721d0b6aecc433abc47a96fb6
git -C "$TB_VBDOS_REPO" checkout --detach FETCH_HEAD
- name: Paket- und Release-Regressionen
run: python3 -m unittest discover -s .gitea/scripts -p 'test_*.py'
- name: Workspace, Inventar, Fremdprogramme und Referenzbenchmarks
run: python3 .gitea/scripts/acceptance.py
- uses: https://gitea.com/actions/upload-artifact@ff15f0306b3f739f7b6fd43fb5d26cd321bd4de5
if: always()
with:
name: acceptance
path: acceptance/
if-no-files-found: error
build:
needs: checks
needs: preflight
runs-on: linux-arm64
timeout-minutes: 90
strategy:
@@ -98,9 +74,9 @@ jobs:
name: packages-${{ matrix.target }}
path: dist/
if-no-files-found: error
stage:
release:
if: startsWith(gitea.ref, 'refs/tags/v') && gitea.event_name == 'push'
needs: [checks, build]
needs: [preflight, build]
runs-on: linux-arm64
container: ghcr.io/rust-cross/cargo-zigbuild@sha256:82af75c41958c2af2787e8bedd912da7678a9438937e223e9d83d006d747b38b
steps:
@@ -120,7 +96,7 @@ jobs:
with:
path: artifacts
- run: cargo build --locked --release -p tb-export --bin tb-template
- name: Vollständigen Releaseentwurf erstellen
- name: Pakete hochladen und Release veröffentlichen
env:
GITEA_SERVER_URL: ${{ gitea.server_url }}
GITEA_REPOSITORY: ${{ gitea.repository }}
@@ -130,5 +106,4 @@ jobs:
run: |
mkdir packages
cp artifacts/packages-*/*.7z artifacts/packages-*/*.tar.gz artifacts/packages-*/*.sha256 packages/
cp artifacts/acceptance/acceptance.json packages/
python3 .gitea/scripts/release.py stage --packages packages --tag "$TB_TAG" --revision "$TB_REVISION"
python3 .gitea/scripts/release.py --packages packages --tag "$TB_TAG" --revision "$TB_REVISION"
-40
View File
@@ -1,40 +0,0 @@
name: Geprüften Gitea-Entwurf freigeben
on:
workflow_dispatch:
inputs:
tag:
description: 'Vorhandener Versionstag, z.B. v1.0.0'
required: true
evidence_commit:
description: '40-stellige Origin-Revision mit release-evidence/<tag>/'
required: true
permissions:
contents: read
jobs:
publish:
if: gitea.ref == 'refs/heads/main'
runs-on: linux-arm64
container: ghcr.io/rust-cross/cargo-zigbuild@sha256:82af75c41958c2af2787e8bedd912da7678a9438937e223e9d83d006d747b38b
steps:
# Vor checkout nötig: Die Cross-Images enthalten kein Node für JS-Actions.
- name: Gepinnte Actions-Laufzeit
run: |
set -eu
curl -fsSL https://nodejs.org/dist/v22.22.0/node-v22.22.0-linux-arm64.tar.xz -o /tmp/tb-node.tar.xz
echo '1bf1eb9ee63ffc4e5d324c0b9b62cf4a289f44332dfef9607cea1a0d9596ba6f /tmp/tb-node.tar.xz' | sha256sum -c -
tar -xJf /tmp/tb-node.tar.xz -C /usr/local --strip-components=1
node --version
- uses: https://gitea.com/actions/checkout@11d5960a326750d5838078e36cf38b85af677262
with:
fetch-depth: 0
persist-credentials: false
- run: sh .gitea/scripts/bootstrap.sh
- run: cargo build --locked --release -p tb-export --bin tb-template
- name: Originalpakete und revisionsgebundene Zielnachweise prüfen
env:
GITEA_SERVER_URL: ${{ gitea.server_url }}
GITEA_REPOSITORY: ${{ gitea.repository }}
TB_RELEASE_TOKEN: ${{ secrets.TB_RELEASE_TOKEN || gitea.token }}
TB_TAG: ${{ inputs.tag }}
TB_EVIDENCE_REVISION: ${{ inputs.evidence_commit }}
run: python3 .gitea/scripts/publish.py
+20 -13
View File
@@ -498,9 +498,11 @@ Linux-arm64-Runner: Linux arm64 nativ beziehungsweise mit festgelegter
Zielbaseline, Linux amd64 und macOS arm64 über cargo-zigbuild, Windows amd64
über cargo-xwin. Cross-Toolchains einschließlich SDK/Sysroot werden in Change
06 reproduzierbar festgelegt; vier native Buildrunner sind nicht erforderlich.
Echte Zielsystem- und Terminalprüfungen gehören in Change 05; Change 06 bindet
diese Prüfungen und versions-/prüfsummengebundene Nachweise für die fertigen
Pakete in die Releasefreigabe ein. Cross-Builds ersetzen keine Zielausführung.
Echte Zielsystem- und Terminalprüfungen gehören zur Entwicklung in Change 05.
Das Setzen des Release-Tags bestätigt die vorherigen Tests. Change 06 baut,
paketiert und veröffentlicht direkt; zusätzliche Nachweis-Commits, eine
erneute Pflichtabnahme und eine manuelle Releasefreigabe entfallen.
Cross-Builds ersetzen keine Zielausführung.
Unter Linux werden weiterhin mindestens zwei Emulatoren geprüft.
Change 03 liefert Backend/CLI, das gemeinsame TBL-Testartefakt und die lokal
verifizierte Verbraucherprobe; die vollständige Vierzielabnahme folgt in
@@ -508,9 +510,9 @@ verifizierte Verbraucherprobe; die vollständige Vierzielabnahme folgt in
Zusätzlicher Politur-Change `phase-6-05a-vbdos-theme-und-kontrast`:
VBDOS-Referenzabgleich und verlässliche IDE-Farbabbildung einschließlich
Kontrast aller UI-Zustände. Umsetzung nach 04, vor der abschließenden
visuellen Plattformabnahme in 05; Releasefreigabe 06 und Phasenabschluss 07
setzen dessen bestandene Nachweise voraus. 05 kann seine übrigen Prüfpfade
parallel vorbereiten. Die historische Gesamtübersicht bleibt erhalten;
visuellen Plattformabnahme in 05. Deren offene Prüfungen werden getrennt
von der automatischen Releaseveröffentlichung in 07 weitergeführt. 05 kann
seine übrigen Prüfpfade parallel vorbereiten. Die historische Gesamtübersicht bleibt erhalten;
diese Ergänzung erweitert die Umsetzung auf acht Changes (01–07 plus 05a).
05a ist am 07.09.2026 auf Benutzeranweisung mit lokal verifizierter
Implementierung archiviert; seine drei offenen visuellen Nachweise werden
@@ -518,16 +520,20 @@ in 05 weitergeführt und bleiben Voraussetzung der Phasenabnahme.
05 ist am 07.09.2026 auf Benutzeranweisung synchronisiert und archiviert:
RGB-/Fensterflächenkorrektur vom Benutzer bestätigt, automatisierte macOS-
Prüfungen bestanden. Acht unvollständige Matrixaufgaben bleiben als
Nachweisbedarf bei 06/07; Windows-Ausführung ist vorerst zurückgestellt.
spätere Entwicklungsprüfungen bei 07; Linux-/Windows-Ausführung und
vollständige Terminalnachweise sind auf Benutzerentscheidung zurückgestellt.
Sie blockieren weder den Release-Build noch dessen Veröffentlichung.
Aktiver Change ist 06 (Gitea Actions und Releases). Die Vierziel-Matrix
und Pflichtabnahme sind in Actions belegt. Ab 08.09.2026 laufen Build, Tests
und Artefaktuploads ausschließlich für neue Release-Tags, erstmals `v1.0.0`
und die frühere Pflichtabnahme sind in Actions belegt. Nach der Entscheidung
vom 11.09.2026 laufen Build, Paketierung und direkte Veröffentlichung
ausschließlich für neue Release-Tags, erstmals `v1.0.0`
mit Workspace-Version `1.0.0`. Es gibt keine CI für normale Commits oder PRs
und keinen manuellen Paketbuild. Tagformat und Versionsgleichheit werden vor
dem Bau geprüft. Arbeit und Pushes erfolgen direkt auf `main`; Release-Tags
werden zusätzlich erstellt und gepusht. Lokale Tests bleiben verfügbar.
Eine manuelle Freigabe kann vorhandene Releasepakete nach deren Zielabnahme
veröffentlichen, baut sie aber nicht erneut.
Nach erfolgreichem Bau aller vier Ziele und vollständigem Upload wird
der Release automatisch veröffentlicht. Ein vorübergehender Upload-Entwurf
schützt vor Teilveröffentlichungen; eine weitere Benutzerfreigabe entfällt.
Release-Pakete: Windows als `.7z`, macOS und beide Linux-Architekturen
als `.tar.gz`, jeweils mit `tb`, `tbc` und der passenden `tbrt`-Vorlage
@@ -579,8 +585,9 @@ Gesamtproposal und Abhängigkeiten:
in jede TBL kopiert. Erzeugung und Backend-Anbindung erfolgen in Phase 6.
- [ ] Dokumentation: Sprachreferenz, Migrationshinweise, Beispielprogramme
- [ ] Release-Automatisierung (Gitea Actions am bestehenden Origin: Build +
Tests und Pakete ausschließlich für neue Tags `vX.Y.Z` auf allen vier
System-/Architektur-Zielen), Releases über Gitea; keine Commit-/PR-CI
Pakete ausschließlich für neue Tags `vX.Y.Z` auf allen vier
System-/Architektur-Zielen, danach direkte Veröffentlichung ohne
Nachweis-Commit oder manuelle Freigabe); keine Commit-/PR-CI
- [ ] **Abnahme der Leitplanke „Vollständigkeit ist das Soll"**:
docs/inventar.md steht auf **0 offen** — jeder der 285 Einträge ist
entweder implementiert oder als Non-Feature in der Sprachreferenz
+3 -1
View File
@@ -2,7 +2,9 @@
Version **1.0.0**. Release-Pakete werden ausschließlich durch neue Tags
`vX.Y.Z` in Gitea Actions gebaut: Windows amd64 als `.7z`, macOS arm64 und
Linux amd64/arm64 als `.tar.gz`. Normale Commits und PRs starten keine CI.
Linux amd64/arm64 als `.tar.gz`. Nach erfolgreichem Build und Upload wird
der Release direkt veröffentlicht; das Tag bestätigt die vorherigen Tests.
Normale Commits und PRs starten keine CI.
Details zu Paketen und Freigabe: [Distribution](docs/distribution.md).
Eine plattformübergreifende **Re-Imagination** des letzten großen BASIC-Dialekts
+34 -55
View File
@@ -2,7 +2,7 @@
Change 06 baut ausschließlich am Origin `git.rfc1437.de/hugo/TerminalBasic`.
Die Actions verwenden das bestätigte Label `linux-arm64` und vier Zieltriple.
Build, Pflichtabnahme und Artefaktuploads starten ausschließlich bei neuen
Build, Paketierung und Veröffentlichung starten ausschließlich bei neuen
Release-Tags `vX.Y.Z`, erstmals `v1.0.0`. Normale Commits und PRs starten
keine CI. Tagformat und Übereinstimmung mit der Workspace-Version werden
vor dem Cargo-Build geprüft; ein manueller Paketbuild ist nicht vorgesehen.
@@ -19,7 +19,7 @@ Kein Cross-Build ist ein Windows-/macOS-/Linux-Emulatornachweis.
Rust 1.97.1 ist in `rust-toolchain.toml` fixiert. Die Images stehen mit Digest
in `.gitea/workflows/build.yml`; SDK/Clang/Zig stammen aus diesen Images.
7-Zip 25.01 wird mit fester SHA-256 in `bootstrap.sh` bereitgestellt.
Vor dem Checkout installieren beide Workflows Node.js 22.22.0 mit fester
Vor dem Checkout installieren die Jobs Node.js 22.22.0 mit fester
SHA-256: Die Cross-Images enthalten keine Laufzeit für JavaScript-Actions.
Zusätzlich prüft der Windows-Build einen festen Hash aller SDK-/CRT-Dateien
und Symlinks. Änderungen unter derselben Microsoft-Versionsbezeichnung
@@ -51,10 +51,6 @@ Repository-Workflows ändern keine globale Docker-/AppArmor-Konfiguration.
Erforderliche Konfiguration:
- Variable `TB_VBDOS_REPOSITORY`: erreichbarer Git-Bestand des in
`foreign.rs` fixierten Referenzprojekts. Der Checkout muss exakt
`1cdd2b32b829fe1721d0b6aecc433abc47a96fb6` liefern. Fehlende Konfiguration
lässt den Pflichtjob scheitern; Fremdprogramme werden nicht übersprungen.
- Releasezugriff: standardmäßig der eingebaute repositorygebundene
`gitea.token`, optional ein explizites Secret `TB_RELEASE_TOKEN`.
Nur Upload/Freigabe verwenden ihn für Releasezugriffe; der Checkout
@@ -62,14 +58,22 @@ Erforderliche Konfiguration:
im Taglauf geprüft. Gitea 1.25 ignoriert die deklarativen `permissions`-
Angaben; diese allein sind kein Nachweis getrennter Jobrechte.
Siehe [Gitea-1.25-Kompatibilität](https://docs.gitea.com/1.25/usage/actions/comparison/).
- Keine Branch-/PR-Trigger und kein manueller Buildtrigger. Der manuelle
Freigabeworkflow verarbeitet nur vorhandene taggebundene Originalpakete.
- Keine Branch-/PR-Trigger und kein manueller Build- oder Freigabeworkflow.
Das Setzen des Release-Tags bestätigt die zuvor durchgeführten Tests.
Der Release-Schritt prüft Archive, Revision und SHA-256 lokal vor dem Upload.
Anschließend prüft er per Release-API die vollständige Dateiliste und die
Dateigrößen, ohne die Assets erneut herunterzuladen. Wiederholungen ergänzen
fehlende Dateien und ersetzen keine vorhandenen Assets; abweichende Größen
führen zum Fehler. Nach vollständigem Upload veröffentlicht derselbe Job den Release direkt.
Es werden keine Release-Assets erneut heruntergeladen und keine zusätzlichen
Nachweise oder Secrets benötigt.
Die Actions-URLs sind explizite Gitea-URLs mit festen Commit-IDs.
[Absolute Action-URLs](https://docs.gitea.com/usage/actions/comparison/)
und [Runnerlabels](https://docs.gitea.com/runner/) entsprechen dem Gitea-Modell.
## Pakete und Zielprüfungen
## Pakete und optionale lokale Zielprüfungen
`terminalbasic-<version>-windows-amd64.7z` sowie `...-macos-arm64.tar.gz`,
`...-linux-amd64.tar.gz`, `...-linux-arm64.tar.gz` enthalten `tb`/`tbc` im Hauptverzeichnis und
@@ -79,7 +83,7 @@ bzw. `tbrt.exe.meta`),
Das Manifest bindet Version, Revision, Rust, Buildhost/Image, Target und
SHA-256 jeder Datei. Jedes Paket erhält zusätzlich eine `.sha256`-Datei.
Auf dem passenden Prüfsystem das unveränderte Paket herunterladen und ausführen:
Für eine freiwillige lokale Zielprüfung das Paket auf dem passenden System prüfen:
```sh
python3 .gitea/scripts/distribution.py target-check \
@@ -103,51 +107,26 @@ derselben Revision. Dieses Testexecutable kann der Linux-Builder mit
Anwenderpaket. DOSBox kann diese Windows-PE-Programme nicht ausführen.
Windows bleibt auf Benutzerentscheidung vorerst offen.
Der automatisch erzeugte `report.json` lässt die manuelle Terminalabnahme
offen. Die Bedienfolge steht in `docs/plattformmatrix.md`. Je Target sind
zusätzlich `manual.json` und die referenzierten nichtleeren Belegdateien nötig:
Die Bedienfolge für freiwillige Terminalprüfungen steht in
`docs/plattformmatrix.md`. Ergebnisse dieser Werkzeuge sind Entwicklungsdaten
und werden nicht als Releasefreigabe eingelesen. Es gibt keine Pflicht für
manuelle JSON-Berichte oder einen zusätzlichen Nachweis-Commit.
```json
{
"target": "aarch64-apple-darwin",
"revision": "<40-stellige Revision>",
"package_sha256": "<SHA-256 des Originalpakets>",
"passed": true,
"tester": "<Prüfer>",
"terminal_versions": {"terminal.app": "<gemessene Version>"},
"cases": {"f1_f12": true, "modifiers": true, "mouse": true,
"unicode_colors": true, "resize": true, "input_break": true, "shell": true},
"evidence": ["terminal-protokoll.txt"]
}
```
## Direkte Veröffentlichung
Windows verlangt `windows-terminal`, beide Linux-Ziele jeweils `xterm` und
`vte` mit Versionen. Nur tatsächlich bestandene Schritte auf true setzen.
Die Felder dienen einer verantworteten manuellen Bestätigung; sie ersetzen
keine Durchführung. Herkunft wird über den geprüften Origin-Commit gebunden.
Das Setzen und Pushen eines neuen Tags `vX.Y.Z` ist die Freigabeentscheidung:
Die fachlichen Tests erfolgen vorher in der Entwicklung. `build.yml` prüft
Tag und Workspace-Version, baut alle vier Ziele und veröffentlicht dann
acht Assets: vier Pakete und vier SHA-256-Dateien. Im Release-Build laufen
keine erneute Pflichtabnahme und keine formale Ziel-/Terminalnachweisprüfung.
Die vorhandenen Testwerkzeuge bleiben lokal ausführbar, beispielsweise
`python3 tests/support/release-abnahme.py --vbdos-repo /pfad/zum/vbdos-bestand`.
## Entwurf und Veröffentlichung
Ein Push eines neuen passenden Tags `vX.Y.Z` (beispielsweise `v1.0.0`) baut/testet alle vier Ziele und lädt
erst danach neun Assets in einen Gitea-Entwurf: vier Pakete, vier SHA-Dateien,
`acceptance.json`. Dessen Referenzlauf enthält Fremdprogramme, Inventar,
Workspace/Clippy/Format, Compile-/VM-Benchmarks und die ausdrücklich gestartete
native IDE-Abnahme. Golden-Erzeugung bleibt bewusst ignoriert. Echte native
Paket-/Terminalprüfungen sind eine zusätzliche Freigabebedingung.
Nachweise auf separaten Systemen beziehen sich auf diese Originalpakete.
Unter `release-evidence/v<version>/<target>/` werden `report.json`, Logs,
`manual.json` und dessen Belege in einem Origin-Commit bereitgestellt.
Der manuell auf main gestartete Workflow „Geprüften Gitea-Entwurf freigeben“
erhält Tag und vollständige Nachweisrevision. Er lädt die ursprünglichen
Entwurfsassets, prüft vier exakte Paketbindungen, Ziel-/Terminalresultate,
gemeinsame TBL-Prüfsumme und die Grundabnahme aus dem ursprünglichen Taglauf.
Er baut die Pakete dabei nicht erneut. Fehlende oder abweichende Daten sperren
Freigabe. Der Tag muss zur Paketversion und zur geprüften Revision passen.
Uploads werden zurückgelesen und bytegenau geprüft. Wiederholungen ergänzen
nur fehlende identische Assets eines Entwurfs. Abweichende Assets oder ein
bereits veröffentlichter Release werden nicht überschrieben. Erst der letzte
API-Aufruf ändert `draft` auf false. Die Regressionen simulieren insbesondere
fehlende Uploads, falsche Nachweise, korrupte Pakete und bestehende Releases;
sie erzeugen keine öffentlichen Testreleases.
Während des Uploads bleibt der Release kurzzeitig ein Entwurf. Erst wenn
alle vier Builds erfolgreich sind und Dateiliste sowie Größen stimmen,
setzt derselbe Job `draft` auf false. Kein manueller Publish-Schritt und
kein weiterer Commit sind erforderlich. Fehlgeschlagene Builds oder Uploads
verhindern eine unvollständige Veröffentlichung. Wiederholungen ergänzen
fehlende Dateien; bestehende Assets und veröffentlichte Releases werden
nicht überschrieben. Tag, Paketrevision und Prüfsummen werden lokal vor
dem Upload geprüft; Release-Assets werden nicht zurückgeladen.
+4
View File
@@ -1,5 +1,9 @@
# Plattformabnahme – Phase 6, Change 05
Diese Entwicklungsprüfungen sind unabhängig von der Releaseveröffentlichung.
Der Release-Tag bestätigt die vorherigen Tests; Gitea verlangt dafür keine
zusätzlichen Terminalberichte oder Nachweis-Commits.
Diese Matrix prüft die tatsächliche IDE und native Exporte auf den vier
Release-Zielen. Automatisierte Headless-/PTY-/Konsolentests und die manuelle
Emulatorbedienung sind getrennte Nachweise. Eine grüne Compilation oder ein
@@ -13,21 +13,21 @@ Origin ist `https://git.rfc1437.de/hugo/TerminalBasic.git`; die read-only Versio
1. `.gitea/workflows/` nutzt den vorhandenen Linux-arm64-Runner für alle vier Build-/Paketziele. Vorhandene Workflowmuster der anderen Origin-Projekte wiederverwenden: cargo-zigbuild für Linux amd64 und macOS arm64, cargo-xwin für Windows amd64/MSVC; Linux arm64 nativ oder mit derselben festgelegten Linux-Zielbaseline. Container/Tools und benötigte SDKs/Sysroots reproduzierbar pinnen; konkrete Rust-/OS-/glibc-Versionen mit TerminalBasic prüfen. Das Runnerlabel `linux-arm64` bei Anbindung bestätigen. Vier native Buildrunner sind nicht erforderlich. `build-runtime.py` erzeugt Vorlagenmetadaten mit dem Hostwerkzeug für das jeweilige Target; fremde Executables werden auf dem Buildhost nicht nativ ausgeführt.
2. Wiederverwendbare Repository-Skripte erledigen Build, Tests, Paketierung und Prüfung auch lokal. Source-Checkout vom Gitea-Origin, alle zusätzlichen Actions nur über explizite Gitea-URLs und feste Revisionen, soweit überhaupt nötig; keine implizite fremde Action-Auflösung. Rust und benötigte Systemwerkzeuge versioniert bereitstellen. Server-/Runner-Kompatibilität praktisch prüfen, statt lediglich YAML zu validieren.
3. Matrixprodukte: `terminalbasic-<version>-windows-amd64.7z`, `terminalbasic-<version>-macos-arm64.tar.gz`, `terminalbasic-<version>-linux-amd64.tar.gz`, `terminalbasic-<version>-linux-arm64.tar.gz`. Windows enthält `tb.exe`/`tbc.exe`/`tbrt.exe`, übrige `tb`/`tbc`/`tbrt`; tbrt ist die native Exportvorlage unter `runtimes/<Target-Triple>/`, dazu deren Metadaten, Lizenz, Kurzinstallation. Das vorhandene CLI-/IDE-Suchschema bleibt erhalten. Archive dürfen keine Buildverzeichnis-/Quellbaumabhängigkeiten haben. Exportierte Anwenderprogramme bleiben normale native Einzelartefakte; die Archivformate betreffen die Distribution.
4. Der Linux-Buildhost erzeugt/prüft Windows-Archive mit 7-Zip und Unix-Archive mit tar+gzip unter Erhalt der Executable-Bits. Inhalts-/Formatprüfungen laufen dort; tatsächliche Start-/Exportprüfungen verwenden neu entpackte Pakete auf passenden Zielsystemen aus 05, automatisiert oder dokumentiert manuell. Externe Nachweise müssen an Revision und exakte Paketprüfsumme gebunden und vor Freigabe geprüft sein. Ein gemeinsames TBL-Testartefakt wird einmal erzeugt und mit nachgewiesen identischen Bytes auf allen vier Zielsystemen verwendet. Separate BASIC-Verbraucher werden mit den entpackten TB-Tools verknüpft, als TBC ausgeführt und mit tbrt als EXE exportiert. Library-Quellen sind dabei nicht verfügbar. Erzeugung/Linken werden in einer Umgebung ohne erreichbaren C-/Rust-Compiler oder nativen Linker geprüft; Systemhilfen zur EXE-Finalisierung dürfen verfügbar bleiben. Fertige EXEs laufen anschließend ohne externe TBL/TBC oder TB-Installation.
5. `cargo test --locked --workspace`, Clippy und Formatprüfung zentral auf dem Linux-arm64-Host; zielabhängige Rust-Testprogramme bei Bedarf cross-kompilieren und auf passenden Prüfsystemen ausführen. Native Tests aus 02/03/04 und automatisierbare Plattformtests aus 05 auf ihren tatsächlichen Zielen ausführen. Buildstatus und Ausführungsnachweise getrennt ausweisen; macOS-EXE-Finalisierung mit codesign erfolgt auf macOS. Den fixierten Fremdprogrammbestand ausdrücklich im erforderlichen Abnahmelauf bereitstellen. Compile-/VM-Messungen auf dokumentiertem Referenzrunner statt instabiler Debug-Zeitlimits in allen Jobs.
6. Gitea-Release erst nach allen Pflichtjobs, zugeordneten echten Zielnachweisen und Vollständigkeits-/Prüfsummenprüfung freigeben. Upload zunächst zu einem als Entwurf erkennbaren Release oder gleichwertigem nicht freigegebenen Staging; anschließend atomare Freigabe im Rahmen der verfügbaren API. Keine Commit-/PR-Jobs. Der Release-Upload nutzt den repositorygebundenen Gitea-Jobtoken; ein explizites TB_RELEASE_TOKEN-Secret kann ihn bei Bedarf ersetzen. Keine persönlichen Zugangswerte werden committed. Tests erzeugen keine öffentlichen Testreleases.
4. Der Linux-Buildhost prüft Archivinhalt, PE/ELF/Mach-O-Format, Architektur, Version, Metadaten, Executable-Rechte und SHA-256. Echte Ziel-/Terminalprüfungen gehören zur Entwicklung vor dem Release-Tag; die vorhandenen lokalen Werkzeuge bleiben verfügbar. Cross-Builds werden nicht als echte Zielausführung ausgegeben. Ein Nachweis-Commit ist nicht erforderlich.
5. Der Tag ist die Freigabeentscheidung des Benutzers nach dessen Tests. Der Release-Workflow startet keine erneute Pflichtabnahme, Fremdprogramm-, Inventar-, Benchmark- oder Terminalnachweisprüfung. Die bestehenden Cargo- und lokalen Abnahmeskripte bleiben unabhängig vom Release verwendbar.
6. Nach erfolgreichen vier Buildjobs lädt derselbe Workflow vier Archive und vier SHA-256-Dateien hoch. Während des Uploads bleibt der Release ein Entwurf; nach vollständiger API-Dateiliste und passenden Größen wird er sofort veröffentlicht. Kein manueller Publish-Workflow, Nachweis-Gate oder Release-Asset-Download. Wiederholungen ergänzen fehlende Dateien, ersetzen aber keine vorhandenen Assets oder veröffentlichten Releases. Der repositorygebundene Jobtoken genügt; TB_RELEASE_TOKEN bleibt optional. Tests erzeugen keine öffentlichen Releases.
7. README-/PLAN-/Releasehinweise nennen die tatsächlich gemessenen minimalen OS-/Systembibliotheksversionen. Developer-ID-/öffentliche Vertrauenssignatur ist kein Ersatz für lokale Ausführbarkeit; wenn entsprechende Identitäten nicht konfiguriert sind, deren Download-/Vertrauensgrenzen ehrlich dokumentieren. Mac-Artefakte müssen trotzdem lokal korrekt finalisiert und startbar sein.
## Risks / Trade-offs
- Cross-Toolchain/SDK fehlt oder ist inkompatibel → Buildbootstrap korrigieren und echte Vierzielpakete nachweisen. Fehlende Zielausführung auf Prüfsystemen sperrt weiterhin Abschluss/Release; erfolgreiche Cross-Builds allein reichen nicht.
- Cross-Toolchain/SDK fehlt oder ist inkompatibel → Buildbootstrap korrigieren und echte Vierzielpakete nachweisen. Zielausführung bleibt eine getrennte Entwicklungsprüfung und keine automatisierte Releasebedingung.
- Vorlagen passen nicht zum Tool → Manifest-/Prüfsummen-/Versionscheck und Export aus entpacktem Paket.
- Plattformwerkzeuge variieren → Buildhost prüft Archiv-/Cross-Werkzeuge, Prüfsysteme prüfen benötigte Signierwerkzeuge; keine stillen Ersatzformate.
- Fehler beim Upload → vollständige Pflichtasset-Liste vor Freigabe prüfen; bestehende vollständige Releases nicht beschädigen.
## Migration Plan
Lokale Skripte zuerst lauffähig machen, dann Gitea-Runner und Workflows anbinden. Nur neue Tags im Format vX.Y.Z starten Build, Pflichtabnahme und Paketupload; keine Branch-/PR- oder manuellen Buildtrigger. Der Prüfjob lehnt ungültige Tags und Abweichungen von Cargo.toml vor dem Cargo-Build ab; die Zielmatrix hängt von diesem Job ab. Bisherige lokale Cargo-Nutzung erhalten. Rollback über vorheriges vollständiges Release und Rücknahme der Workflowänderung; keine Server-/Runnerinstallation durch bloße Proposal-Erstellung.
Lokale Skripte zuerst lauffähig machen, dann Gitea-Runner und Workflows anbinden. Nur neue Tags im Format vX.Y.Z starten Build, Paketupload und direkte Veröffentlichung; keine Branch-/PR- oder manuellen Buildtrigger. Der Prüfjob lehnt ungültige Tags und Abweichungen von Cargo.toml vor dem Cargo-Build ab; die Zielmatrix hängt von diesem Job ab. Bisherige lokale Cargo-Nutzung erhalten. Rollback über vorheriges vollständiges Release und Rücknahme der Workflowänderung; keine Server-/Runnerinstallation durch bloße Proposal-Erstellung.
## Konkretisierung während der Umsetzung
@@ -39,13 +39,12 @@ Lokale Skripte zuerst lauffähig machen, dann Gitea-Runner und Workflows anbinde
- `tb-template --inspect` nutzt den vorhandenen PE/ELF/Mach-O-Parser auch
für tb/tbc. Build und Paketprüfung laufen auf dem Host ohne fremde Programme
auszuführen. Die Anwenderpakete benötigen tb-template nicht.
- Taglauf erzeugt erst nach Build/Grundabnahme einen überprüften Entwurf.
`v1.0.0` bezeichnet die erste Releaseversion. Normale Commits/PRs erzeugen
- Benutzerentscheidung 11.09.2026: Das Tag bestätigt die vorherigen Tests.
Nach erfolgreichem Vierzielbau werden acht Pflichtassets hochgeladen und
im selben Workflow direkt veröffentlicht. Normale Commits/PRs erzeugen
keine Jobs oder Artefakte; lokale Entwicklungsprüfungen bleiben verfügbar.
Originalpakete werden auf separaten Systemen geprüft. Ein manueller Workflow
auf main bindet deren Nachweise aus einem Origin-Commit an Tag, Revision und
Paket-SHA-256 und gibt erst dann denselben Entwurf frei; kein erneuter Bau.
- Die Benutzerentscheidung aus 05, Windows-Ausführung vorerst offen zu lassen,
bleibt erhalten. Sie macht Windows-Builds zulässig, aber keinen Release mit
fehlender Windows-Abnahme erfolgreich. Fehlende Nachweise werden nicht auf
Basis der gemeinsamen ANSI-Technik von macOS/Linux pauschal abgehakt.
- Alle manuellen Freigabe- und Nachweiswege aus dem Releasepfad entfallen.
Die Uploadkontrolle verwendet ausschließlich API-Dateiliste und Größen,
nachdem lokale Archiv-/Revisions-/Prüfsummenprüfungen bestanden sind.
- Zurückgestellte Linux-/Windows-Ausführung und vollständige Terminalfolgen
bleiben spätere Entwicklungsarbeit in 07, ohne den Release zu blockieren.
@@ -1,6 +1,6 @@
## Why
Die vorhandenen Workflows am Gitea-Origin werden auf ausschließliche Release-Builds umgestellt. Für eine vollständige Phase 6 müssen die vier vereinbarten Zielartefakte in Gitea Actions gebaut, auf ihren Zielsystemen geprüft und als nutzbare Release-Pakete ausgeliefert werden.
Die vorhandenen Workflows am Gitea-Origin werden auf ausschließliche Release-Builds umgestellt. Für eine vollständige Phase 6 müssen die vier vereinbarten Zielartefakte in Gitea Actions gebaut, als nutzbare Release-Pakete direkt veröffentlicht werden.
## What Changes
@@ -8,8 +8,8 @@ Die vorhandenen Workflows am Gitea-Origin werden auf ausschließliche Release-Bu
- Auf dem vorhandenen Linux-arm64-Gitea-Runner Terminalanwendungen für Windows amd64 (cargo-xwin), macOS arm64 und Linux amd64 (cargo-zigbuild) sowie Linux arm64 bauen; keine zusätzlichen Zielplattformen und kein Mirror.
- Windows als `.7z`, macOS und beide Linux-Ziele als `.tar.gz` mit `tb`, `tbc` und der nativen `tbrt`-Vorlage samt Metadaten paketieren.
- Entpackte Pakete einschließlich `tbc link`, nativer Exporte und separater BASIC-Verbraucher von `.tbl` prüfen, Prüfsummen und nachvollziehbare Buildmetadaten liefern.
- Echte Zielausführung aus 05 getrennt vom Cross-Bau einbinden, automatisiert oder als revisions-/paketprüfsummengebundenen Nachweis von separaten Prüfsystemen. Vier native Buildrunner werden nicht vorausgesetzt.
- Releases erst nach vollständigen erforderlichen Prüfungen veröffentlichen; fehlende Zielnachweise oder Assets dürfen keinen grünen vollständigen Release ergeben.
- Lokale Testwerkzeuge für die Entwicklung erhalten. Der Benutzer testet vor dem Tag; zusätzliche Ziel-/Terminalnachweise und Nachweis-Commits sind keine Releasebedingung.
- Nach erfolgreichen vier Builds und vollständigem Upload im selben Workflow direkt veröffentlichen. Manuellen Publish-Workflow, erneute Pflichtabnahme, Nachweis-Gate und Release-Asset-Downloads entfernen; fehlgeschlagene Builds oder Uploads verhindern die Veröffentlichung.
## Capabilities
@@ -5,7 +5,7 @@ Liefert geprüfte Terminal-Basic-Programme und Exportvorlagen für die vier fest
## ADDED Requirements
### Requirement: Vier verbindliche Buildziele
Gitea Actions am bestehenden Origin SHALL Terminalanwendungen für Windows amd64, macOS arm64, Linux amd64 und Linux arm64 aus derselben Revision auf dem vorhandenen Linux-arm64-Runner bauen und paketieren. Cross-Kompilierung SHALL für fremde Ziele verwendet werden; vier native Buildrunner MUST NOT vorausgesetzt werden. Buildprüfungen und echte Zielausführung SHALL getrennt nachvollziehbar sein. Fehlende Build- oder Ausführungsnachweise, fehlgeschlagene Tests oder fehlende Artefakte eines Pflichtziels MUST einen vollständigen erfolgreichen Release verhindern. Build, Pflichtabnahme und Paketartefakte SHALL ausschließlich durch den Push eines neuen Release-Tags im exakten Format `vX.Y.Z` ausgelöst werden; X, Y und Z SHALL nichtnegative Dezimalzahlen ohne führende Nullen sein. Der Tag SHALL der Workspace-Version entsprechen. Normale Branch-Commits und Pull Requests MUST NOT Actions-Builds oder Paketartefakte auslösen. Lokale Entwicklungsprüfungen SHALL weiterhin verfügbar sein.
Gitea Actions am bestehenden Origin SHALL Terminalanwendungen für Windows amd64, macOS arm64, Linux amd64 und Linux arm64 aus derselben Revision auf dem vorhandenen Linux-arm64-Runner bauen und paketieren. Cross-Kompilierung SHALL für fremde Ziele verwendet werden; vier native Buildrunner MUST NOT vorausgesetzt werden. Buildprüfungen und echte Zielausführung SHALL getrennt nachvollziehbar sein. Fehlgeschlagene Builds oder fehlende Artefakte eines Pflichtziels MUST eine Veröffentlichung verhindern. Build, Paketierung und Veröffentlichung SHALL ausschließlich durch den Push eines neuen Release-Tags im exakten Format `vX.Y.Z` ausgelöst werden; X, Y und Z SHALL nichtnegative Dezimalzahlen ohne führende Nullen sein. Der Tag SHALL der Workspace-Version entsprechen. Normale Branch-Commits und Pull Requests MUST NOT Actions-Builds oder Paketartefakte auslösen. Lokale Entwicklungsprüfungen SHALL weiterhin verfügbar sein.
#### Scenario: Ein Ziel fehlt
- **WHEN** drei Zieljobs erfolgreich sind und der vierte fehlt oder fehlschlägt
@@ -17,7 +17,7 @@ Gitea Actions am bestehenden Origin SHALL Terminalanwendungen für Windows amd64
#### Scenario: Neuer passender Release-Tag
- **WHEN** v1.0.0 auf eine Revision mit Workspace-Version 1.0.0 gepusht wird
- **THEN** laufen Pflichtabnahme und anschließend die vier Paketbuilds für diese Revision
- **THEN** laufen nach der Versionsvorprüfung die vier Paketbuilds für diese Revision und der vollständige Upload wird direkt veröffentlicht
#### Scenario: Ungültiger oder unpassender Tag
- **WHEN** ein Tag vom Format vX.Y.Z oder von der Workspace-Version abweicht
@@ -30,16 +30,25 @@ Windows SHALL als `.7z` ausgeliefert werden; macOS und beide Linux-Architekturen
- **WHEN** ein Zielarchiv in ein sauberes Verzeichnis entpackt wird
- **THEN** starten IDE und Compiler als native Terminalanwendungen und ein Beispielprojekt kann mit den mitgelieferten Vorlagen exportiert und nativ verwendet werden
### Requirement: Tatsächliche Artefaktprüfung
Der Actions-Releasepfad SHALL tatsächliche Prüfungen der fertig gepackten und erneut entpackten Artefakte auf dem jeweiligen Ziel verlangen. Diese SHALL als automatisierte Zielprüfungen oder dokumentierte manuelle Nachweise von separaten Prüfsystemen aus Change 05 eingebunden und vor Freigabe an die geprüfte Revision und exakte Paketprüfsumme gebunden werden. Fehlende oder nicht passende Nachweise MUST die Freigabe verhindern. Native Executables SHALL ohne TB-Installation und Quellen laufen, Library-Ausgaben SHALL mit separaten BASIC-Verbrauchern über `tbc link` ohne Library-Quellen funktionieren. Dieselbe TBL-Probe SHALL mit identischen Bytes auf allen vier Zielen verknüpft und ausgeführt werden. Library-Bau und Link-/EXE-Export SHALL mit den entpackten Tools ohne C-/Rust-Compiler oder nativen Linker beim Anwender geprüft werden; dokumentierte Systemhilfen zur EXE-Finalisierung dürfen vorhanden sein. Ein erfolgreiches Cargo-Kompilieren oder korrekt benannter Archivname MUST NOT diese Prüfung ersetzen.
### Requirement: Lokale Paketprüfung und vorherige Entwicklungstests
Der Release-Build SHALL Archivinhalt, Format, Zielarchitektur, Version, Revision und SHA-256 vor dem Upload lokal prüfen. Das Setzen des Release-Tags SHALL die Freigabeentscheidung des Benutzers nach dessen Entwicklungstests sein. Der Releasepfad MUST NOT eine erneute Pflichtabnahme, Ziel-/Terminalberichte, manuelle JSON-Nachweise oder einen zusätzlichen Nachweis-Commit verlangen. Vorhandene lokale Testwerkzeuge SHALL unabhängig vom Release verwendbar bleiben.
#### Scenario: Falsches Binary im richtigen Archiv
- **WHEN** ein Windows-amd64-Archiv versehentlich ein Binary eines anderen Ziels enthält
- **THEN** scheitert die Format-/Startprüfung vor der Veröffentlichung
- **THEN** scheitert die Formatprüfung vor der Veröffentlichung
#### Scenario: Tag ohne zusätzliche Nachweise
- **WHEN** ein gültiger Tag gesetzt wurde und alle vier Builds sowie der vollständige Upload erfolgreich sind, ohne dass zusätzliche Nachweisdateien vorliegen
- **THEN** veröffentlicht derselbe Workflow den Release automatisch und verlangt keinen manuellen Publish-Schritt
### Requirement: Nachvollziehbare Veröffentlichung
Releaseartefakte SHALL Version/Tag, Commit, Toolchain, Buildhost, Ziel, Integritätsprüfsumme und zugehörige Prüfergebnisse nachvollziehbar machen. Nur der freigegebene Tag-/Releasepfad SHALL Veröffentlichungsrechte verwenden; Normale Commits und PRs SHALL keine Actions-Jobs starten. Der repositorygebundene Gitea-Jobtoken SHALL für Releasezugriffe nutzbar sein; ein getrenntes Secret SHALL optional bleiben. Wiederholte fehlgeschlagene Veröffentlichungen SHALL keinen bestehenden vollständigen Release stillschweigend durch unvollständige Assets ersetzen.
Releaseartefakte SHALL Version/Tag, Commit, Toolchain, Buildhost, Ziel, Integritätsprüfsumme nachvollziehbar machen. Nur der freigegebene Tag-/Releasepfad SHALL Veröffentlichungsrechte verwenden; Normale Commits und PRs SHALL keine Actions-Jobs starten. Der repositorygebundene Gitea-Jobtoken SHALL für Releasezugriffe nutzbar sein; ein getrenntes Secret SHALL optional bleiben. Vier Archive und vier zugehörige SHA-256-Dateien SHALL die Pflichtassets bilden. Ein Entwurf SHALL ausschließlich den laufenden Upload vor Teilveröffentlichung schützen und nach dessen erfolgreicher Kontrolle im selben Job automatisch freigegeben werden. Wiederholte fehlgeschlagene Veröffentlichungen SHALL keinen bestehenden vollständigen Release stillschweigend durch unvollständige Assets ersetzen.
#### Scenario: Paket beschädigt oder Upload unvollständig
- **WHEN** ein Archiv nach dem Bau verändert wird oder ein Pflichtasset nicht hochgeladen werden kann
- **THEN** verhindert die Integritäts-/Vollständigkeitsprüfung die Freigabe und nennt das betroffene Asset
#### Scenario: Uploadkontrolle ohne erneuten Download
- **WHEN** der Releasejob die lokal auf Integrität geprüften Pakete hochgeladen hat
- **THEN** prüft er über die Release-API die vollständige Pflichtasset-Liste und die Dateigrößen, ohne Asset-Inhalte erneut herunterzuladen
- **AND** ergänzt ein wiederholter Release-Aufruf nur fehlende Dateien; vorhandene Assets werden nicht ersetzt und abweichende Größen führen zum Fehler
@@ -1,34 +1,26 @@
## 1. Gitea und Runner
- [ ] 1.1 Vorhandenen Linux-arm64-Gitea-Runner und tatsächliches Label bestätigen; Cross-Buildumgebungen mit cargo-zigbuild, cargo-xwin und benötigten SDKs/Sysroots reproduzierbar festlegen. Ein Gitea-Prüfjob muss den Buildhost nachweisen; separate echte Prüfsysteme aus 05 zuordnen, ohne vier native Buildrunner vorauszusetzen.
- [x] 1.1 Vorhandenen Linux-arm64-Gitea-Runner und tatsächliches Label bestätigen; Cross-Buildumgebungen mit cargo-zigbuild, cargo-xwin und benötigten SDKs/Sysroots reproduzierbar festlegen. Den Buildhost bestätigen, ohne vier native Buildrunner vorauszusetzen.
- [x] 1.2 Repositorylokale Build-/Testaufrufe und feste Toolchain-/Systemvoraussetzungen bereitstellen; alle vier Ziele müssen auf Linux arm64 mit --locked baubar sein. Zentrale Workspace-Regressionen und getrennte Aufrufe für echte Zielprüfungen bereitstellen; fremde Executables nicht als nativ auf dem Buildhost getestet ausweisen.
- [ ] 1.3 Workflow ausschließlich für neue Release-Tags vX.Y.Z anbinden; normale Commits/PRs dürfen keine Jobs oder Artefakte starten. Tagformat und Workspace-Version vor Cargo prüfen; tatsächlichen Taglauf mit vier Zielergebnissen und Fehlerstatus nachweisen.
- [x] 1.3 Workflow ausschließlich für neue Release-Tags vX.Y.Z anbinden; normale Commits/PRs dürfen keine Jobs oder Artefakte starten. Tagformat und Workspace-Version vor Cargo prüfen; tatsächlichen Taglauf mit vier Zielergebnissen und Fehlerstatus nachweisen.
## 2. Artefakte und Pakete
- [x] 2.1 IDE, CLI und native `tbrt`-Exportvorlage je Ziel in Gitea Actions bauen; Format-/Architektur-/Versionsprüfungen müssen Windows amd64, macOS arm64 und beide Linux-Architekturen eindeutig bestätigen.
- [x] 2.2 Windows-Paket als .7z und macOS-/Linux-Pakete als .tar.gz erzeugen; Archivtests müssen Dateinamen, Paketinhalt, Executable-Rechte und notwendige Begleitdateien prüfen.
- [ ] 2.3 Jedes fertige Paket auf dem tatsächlichen Ziel neu entpacken und die enthaltenen Programme starten; automatisierte oder dokumentiert manuelle Nachweise aus separaten Prüfsystemen an Revision und Paketprüfsumme binden; `tbc link` und EXE-/TBL-Beispiele müssen mit separaten BASIC-Verbrauchern ohne Library-Quellen/Entwicklungscheckout sowie ohne erreichbaren C-/Rust-Compiler oder nativen Linker funktionieren.
- [x] 2.3 Vorhandene lokale Ziel-/Export-/Library-Prüfwerkzeuge für die Entwicklung erhalten; ihre Berichte sind keine Voraussetzung der Veröffentlichung. Linux-/Windows-Ausführung und vollständige Terminalfolgen bleiben auf Benutzerentscheidung zurückgestellt.
- [x] 2.4 Einmal erzeugte TBL-Probe mit identischen Bytes an alle vier Zielprüfungen verteilen sowie Artefaktmanifest und Prüfsummen erzeugen; absichtlich beschädigte oder vertauschte Zielartefakte müssen die Prüfung scheitern lassen.
## 3. Releasepfad
- [ ] 3.1 Taggebundenen Gitea-Releasepfad mit vollständiger Pflichtasset-Liste und getrennten Rechten einrichten; fehlgeschlagene/fehlende Zielbuilds oder zugeordnete echte Paket-/Zielprüfungen müssen die Freigabe verhindern.
- [x] 3.2 Upload zunächst als nicht freigegebenen Stand prüfen und erst vollständig freigeben; ein simulierter fehlender Upload darf keinen vollständigen bestehenden Release überschreiben.
- [x] 3.3 Fremdprogramm-, Inventar-, native und automatisierte Plattformnachweise sowie Referenzbenchmarks in den erforderlichen Abnahmelauf integrieren; ignorierte Pflichtfälle müssen als fehlend sichtbar bleiben.
- [ ] 3.4 Einen tatsächlichen vollständigen Gitea-Lauf mit vier Paketartefakten nachweisen; Run-/Commit-/Buildhost-/Targetdaten und paketprüfsummengebundene entpackte Prüfergebnisse an 07 übergeben, bevor der Change als fertig gilt.
- [x] 3.1 Nach erfolgreichen vier Builds und vollständigem Upload direkt im selben Workflow veröffentlichen; ein gültiges Tag bestätigt die vorherigen Benutzertests. Jobtoken verwenden, keine manuelle Freigabe oder zusätzlichen Nachweis-Commits verlangen.
- [x] 3.2 Upload vorübergehend als Entwurf führen, per API-Dateiliste und Größen ohne erneuten Asset-Download prüfen und danach automatisch veröffentlichen; ein simulierter fehlender Upload darf keinen vollständigen bestehenden Release überschreiben.
- [x] 3.3 Manuellen Publish-Workflow, Nachweis-Gate, Asset-Downloadpfade und erneute Pflichtabnahme aus dem Release-Build entfernen; lokale Testwerkzeuge erhalten.
- [ ] 3.4 Einen tatsächlichen Taglauf mit vier Paketbuilds und automatischer Veröffentlichung des vollständigen Releases bestätigen; Run-/Commit-/Targetdaten an 07 übergeben.
Stand 07.09.2026: 7/11 Aufgaben abgeschlossen. Actions-Lauf 5 (API 546,
Revision dec067dfec0c97918f92f00d0b2729238f494c6a) besteht mit Pflichtabnahme
und allen vier Paketjobs. Originalpakete auf macOS arm64 und Linux arm64
entpackt und erfolgreich geprüft. 1.1 bleibt nur hinsichtlich der noch nicht
zugeordneten Windows-/Linux-amd64-Prüfsysteme offen; Buildhost, Label und
Cross-Umgebungen sind jetzt durch Actions nachgewiesen. 2.3 und 3.4 bleiben
wegen der fehlenden weiteren Ziel-/Terminalnachweise offen, 3.1 wegen des
tatsächlichen Rechteprüfung des Gitea-Jobtokens (optionales Release-Secret). Die vorhandenen
Run-/Paket-/Prüfbelege sind für 07 unter evidence/actions-run-5/ abgelegt.
Details: verification.md.
Änderung 08.09.2026: Release 1.0.0 vorbereiten; ausschließlich Tag-Builds.
1.3 wird für den neuen Tagpfad erneut geöffnet (6/11 abgeschlossen), bis der
tatsächliche v1.0.0-Lauf vorliegt. Frühere Branch-Läufe bleiben historische Belege.
Entscheidung 11.09.2026: Der Release-Tag ist die Freigabe nach vorherigen
Benutzertests. Die bisher verlangten externen Nachweis-Commits und manuelle
Freigabe entfallen. Die lokalen Testwerkzeuge bleiben erhalten. Lauf 7
belegt die vier Tagbuilds; die direkte Veröffentlichung nach der Umstellung
ist noch in einem neuen Taglauf zu bestätigen. Historische Protokolle sind
weiter unter evidence/ und in verification.md abgelegt.
@@ -1,3 +1,32 @@
## Aktueller Stand 11.09.2026: direkte Tagveröffentlichung
Die frühere Freigabearchitektur in den folgenden historischen Abschnitten
ist durch die Benutzerentscheidung ersetzt: Tag → Versionsvorprüfung → vier
Builds/Pakete → Upload → automatische Veröffentlichung im selben Job.
`publish.yml`, `publish.py`, das Nachweis-Gate und alle Release-Asset-Downloads
sind entfernt. Die Pflichtabnahme läuft nicht mehr im Release-Workflow;
lokale Testwerkzeuge bleiben verfügbar. Acht Pflichtassets (vier Archive
und vier SHA-256-Dateien) genügen. Während des Uploads schützt ein temporärer
Entwurf vor Teilveröffentlichung. Lokale Integritätsprüfungen und die
API-Kontrolle von Dateiliste und Größen bleiben erhalten.
Die vorherigen offenen Secret-/Download-/Nachweisbedingungen des
Releasepfads entfallen. Aufgabe 3.4 bleibt nur für einen tatsächlichen
Taglauf der neuen direkten Veröffentlichung offen. Der vorhandene Tag
v1.0.0 und sein historischer Lauf 7 enthalten noch den alten Workflow.
Historische Nachweise werden dadurch nicht als neue Läufe ausgegeben.
Lokale Verifizierung der Umstellung: fünf Python-Regressionstests bestanden
(direkte Freigabe ohne Nachweise/Downloads, fehlgeschlagener Upload mit
Wiederholung, Schutz veröffentlichter Releases, fehlende/falsche Größen,
lokal beschädigte/falsche Pakete und Tagformat). Workflow-YAML geprüft:
ausschließlich Tag-Push, Versionsvorprüfung vor vier Builds, Releasejob
abhängig von allen Builds. Die tatsächliche eingebettete Versionsvorprüfung
akzeptiert v1.0.0 und lehnt unpassende/ungültige Tags ab. Beide betroffenen
Changes und alle 30 Hauptspecs validiert; `git diff --check` bestanden.
Keine Produktcodeänderungen oder neuen Builds erforderlich für diese
Workflow-/Releasepfadänderung; kein Tag oder Release wurde verändert.
# Verifizierung: phase-6-06-gitea-actions-und-releases
Stand 07.09.2026. In Actions geprüfter Implementierungsstand:
@@ -169,3 +198,33 @@ Releaseprüfungen 6/6, YAML-Trigger und Versionsvorprüfung einschließlich
Negativfällen, Format und OpenSpec 30/30 bestanden. Der vollständige
Release-Pflichtlauf einschließlich der erforderlichen ignorierten Fälle
folgt im neuen Taglauf.
## Stage-Korrektur 11.09.2026
[Taglauf 7](https://git.rfc1437.de/hugo/TerminalBasic/actions/runs/7)
(API 548, Revision `6e742d96b1dfcb3c517998eee5ae825fe748ceb0`):
Pflichtabnahme 913 und alle vier Paketjobs 914–917 erfolgreich. Stage 918
hat alle neun Pflichtassets in Draft 10 hochgeladen und ist anschließend
in `verify_uploads` → `Gitea.download` mit HTTP 404 gescheitert. Gitea 1.25.4
erteilt dem Jobtoken die Repository-Rechte in der API, aber nicht auf dem
Web-Downloadpfad des privaten Repositorys. Ein persönlicher Token konnte
alle neun Dateien lesen; die vier Archivprüfsummen und die Grundabnahme
für die Tagrevision stimmen. Kein Token wurde als Secret hinterlegt.
Benutzerentscheidung: den erneuten Download zur Uploadkontrolle entfernen.
Stage prüft weiter lokal Archive, Revision und SHA-256 vor dem Upload.
Die Uploadkontrolle und Wiederholung prüfen API-Dateiliste und Dateigrößen;
vorhandene Assets werden nicht ersetzt. Es findet dabei keine erneute
Byte-/SHA-Prüfung der serverseitigen Inhalte statt.
Verifizierung: sechs Python-Regressionstests bestanden. Der erweiterte
Wiederholungstest verbietet jeden Asset-Download, bestätigt unveränderte
vorhandene Uploads und lehnt abweichende Größen ab. Die neue Funktion
`verify_uploads` wurde zusätzlich lesend gegen Draft 10 ausgeführt: alle
neun Größen korrekt, Asset-Downloads ausdrücklich im Testaufruf gesperrt,
keine Release-Mutation. Der historische Actions-Lauf bleibt fehlgeschlagen;
sein Tag enthält noch den alten Code. Tag und Freigabestatus bleiben erhalten.
Abgrenzung: `publish.yml` lädt weiterhin die Originalpakete für `dist.gate`.
Der Jobtoken-Zugriff auf diesen separaten Download bleibt offen; die lokale
Stage-Korrektur ist kein Nachweis eines erfolgreichen manuellen Publish.
@@ -25,3 +25,10 @@ README nennt derzeit noch „Projektrahmen“, die Korpus-README enthält frühe
## Migration Plan
Dokumente schrittweise mit jeweiligen Fachfeatures aktualisieren, hier endgültig abgleichen. PLAN-Checkboxen erst nach vollständiger Abnahme setzen. Releasekorrekturen führen zu neuem nachvollziehbarem Artefaktstand; vorhandene Releases bleiben referenzierbar.
Releaseentscheidung 11.09.2026: Das Setzen eines Release-Tags bestätigt die
vorherigen Benutzertests. Change 06 veröffentlicht nach Build und Upload
direkt. Die Entwicklungs-/Dokumentationsarbeiten dieses Changes sind keine
zusätzliche Releasefreigabe; Nachweis-Commits und manuelle Publish-Schritte
entfallen. Zurückgestellte Linux-/Windows- und vollständige Terminalprüfungen
bleiben gesondert sichtbar und blockieren keine Veröffentlichung.
@@ -22,3 +22,10 @@ Keine. Bestehende Sprach-/Inventarverträge werden erneut geprüft, nicht abgesc
## Impact
PLAN.md, README.md, docs, examples und Help-Katalog sowie Abschlussnachweise. Keine vorgezogenen Stufe-2-Spracherweiterungen. Abhängigkeiten: alle Changes 01–06 einschließlich 05a mit synchronisierten Specs und tatsächlichen Prüfergebnissen; abgeschlossene Aufgabenlisten allein genügen nicht.
Releaseentscheidung 11.09.2026: Das Setzen eines Release-Tags bestätigt die
vorherigen Benutzertests. Change 06 veröffentlicht nach Build und Upload
direkt. Die Entwicklungs-/Dokumentationsarbeiten dieses Changes sind keine
zusätzliche Releasefreigabe; Nachweis-Commits und manuelle Publish-Schritte
entfallen. Zurückgestellte Linux-/Windows- und vollständige Terminalprüfungen
bleiben gesondert sichtbar und blockieren keine Veröffentlichung.
@@ -2,6 +2,8 @@
Schließt Phase 6 ausschließlich anhand aktueller, nachvollziehbarer Dokumentation, vollständiger Inventarprüfungen und tatsächlich nutzbarer Releaseartefakte ab.
Die Phasenabnahme ist von der Releaseveröffentlichung getrennt. Ein Release-Tag bestätigt die vorherigen Benutzertests; zusätzliche Abnahmeberichte oder Nachweis-Commits MUST NOT die direkte Veröffentlichung aus Change 06 blockieren.
## ADDED Requirements
### Requirement: Dokumentation des ausgelieferten Verhaltens
@@ -21,3 +21,10 @@
unvollständige Matrixaufgaben einschließlich der restlichen 05a-Nachweise
bleiben für 2.2–2.4 und 3.1 nachzuweisen. Der erfolgreiche Benutzer-Farbtest
bestätigt die RGB-/Fensterflächenkorrektur, nicht die vollständige Plattformmatrix.
Releaseentscheidung 11.09.2026: Das Setzen eines Release-Tags bestätigt die
vorherigen Benutzertests. Change 06 veröffentlicht nach Build und Upload
direkt. Die Entwicklungs-/Dokumentationsarbeiten dieses Changes sind keine
zusätzliche Releasefreigabe; Nachweis-Commits und manuelle Publish-Schritte
entfallen. Zurückgestellte Linux-/Windows- und vollständige Terminalprüfungen
bleiben gesondert sichtbar und blockieren keine Veröffentlichung.