docs(sync): record native candidate evidence
This commit is contained in:
parent
2c5a8be282
commit
cc87f26b98
6 changed files with 89 additions and 19 deletions
|
|
@ -2,6 +2,12 @@
|
|||
|
||||
## Unreleased — 0.1.2
|
||||
|
||||
- Closed the native candidate warning gate with checked path and HTTP response
|
||||
bounds, strict GCC and Clang builds, full Clang ASan/UBSan validation, and a
|
||||
stable concurrent object-I/O MTP double. Rebuilt the desktop, current Android
|
||||
and non-installed schema-v17 bridge candidates with recorded digests; no
|
||||
service, device, user database, signing secret or deployment was touched.
|
||||
|
||||
- Normalized the recent synchronization, generation-MTP, Android backup,
|
||||
Web Dashboard serialization, tests, I/O doubles and packaging code for human
|
||||
readability. Added scoped C formatting rules and review guidance without
|
||||
|
|
|
|||
|
|
@ -8,6 +8,13 @@ non-installed schema-v17 bridge candidate is reproducibly built and tested.
|
|||
Physical-device MTP, release signing, real user backup/restore, main integration
|
||||
and deployment are not complete.
|
||||
|
||||
`TRAINLOG_NATIVE_BUILD_AND_CANDIDATE_V1` closes the native warning gate. Strict
|
||||
GCC 16.2.1 and Clang 22.1.8 builds now pass the same 81-test inventory, and the
|
||||
Clang ASan/UBSan build passes it with leak detection. Bounded path assembly and
|
||||
the Web sync accepted response reject insufficient capacity without publishing
|
||||
partial output. Fresh desktop, current-Android and schema-v17 bridge candidates
|
||||
were rebuilt from commit `2c5a8be2827e31fc5be2accb65073bfeb79d6068`.
|
||||
|
||||
Snapshot date: **2026-09-17**.
|
||||
|
||||
`TRAINLOG_CODE_READABILITY_V1` normalizes the recent generation-MTP,
|
||||
|
|
|
|||
|
|
@ -49,6 +49,18 @@ and non-destructive hardware smoke. Drive remains separate and untested here.
|
|||
This is a non-executed rollout checklist. The development branch implements the
|
||||
path; the daily installation still uses V3.
|
||||
|
||||
The latest software-only candidate set was rebuilt under the private root
|
||||
`/home/fy59/.cache/trainlog/native-build-candidate-v1.VbFjE9` from source commit
|
||||
`2c5a8be2827e31fc5be2accb65073bfeb79d6068`. Its desktop inventory records every
|
||||
packaged file digest plus schemas, protocols, entry points and runtime
|
||||
dependencies. The current debug APK SHA-256 is
|
||||
`aca2f499ee9ff53ba5913a76a2a0117274e3e5545967ce361f6f126a6af497e1`; the
|
||||
non-installed bridge APK SHA-256 is
|
||||
`0a28d81cbb0818cdf2fee72d5024a4b706fcfda39f1182c682c12f000a026cb4`; and its
|
||||
synthetic schema-v17 backup SHA-256 is
|
||||
`06eb3999c6f3ce2fd8f551b38727a0a67fe6b48dde4c3244b3d50357afa7e6a3`.
|
||||
These are unsigned development evidence, not deployment authorization.
|
||||
|
||||
## Compatible set
|
||||
|
||||
- desktop binary containing schema v21, the Web API and the generation worker;
|
||||
|
|
|
|||
|
|
@ -1317,12 +1317,14 @@ behavioral assertions. Python syntax/orchestrator tests, Android generation and
|
|||
backup tests, the I/O-boundary MTP browser proof, JSON/import validators and
|
||||
the isolated harness cover the other normalized sources.
|
||||
|
||||
GCC 16.2.1 now compiles beyond the former `misleading-indentation` failures in
|
||||
`json_writer.c`, `web_dashboard_json.c`, `web_dashboard.c`,
|
||||
`dashboard_layout.c`, and `generation_mtp.c`. The separate strict build remains
|
||||
blocked by distinct pre-existing `format-truncation` diagnostics in the Web
|
||||
accepted-response buffer and bounded test path buffers. Warning policy remains
|
||||
unchanged; GCC is not reported as green.
|
||||
GCC 16.2.1 and Clang 22.1.8 both pass separate strict C17 builds and the full
|
||||
**81/81** Meson inventory with `werror=true` and warning level 3. The former GCC
|
||||
`format-truncation` findings are closed by exact checked path construction in
|
||||
the generation-MTP tests/double and by a production accepted-response
|
||||
serializer that reports its byte count. Boundary tests cover exact fit,
|
||||
one-byte insufficiency and multibyte path components; failure leaves no partial
|
||||
path or response available to a caller. Clang ASan/UBSan passes the same
|
||||
**81/81** inventory with leak detection.
|
||||
|
||||
The readability closeout preserves the **81/81** normal Meson and **81/81**
|
||||
ASan/UBSan inventories. The isolated Android run reports **220 tests: 215
|
||||
|
|
@ -1330,3 +1332,14 @@ passed, five skipped, zero failures/errors**, and `assembleDebug` succeeds on
|
|||
JDK 17. The real Firefox/object-I/O-boundary MTP conversation also passes after
|
||||
formatting. A source comparison against the pre-readability commit confirms
|
||||
that the scoped test names and assertion counts are unchanged.
|
||||
|
||||
The isolated JDK 17 harness reports **220 Android tests: 215 passed, five
|
||||
skipped, zero failures/errors**. The skips are optional, externally supplied
|
||||
copy gates: `BridgeBackupMigrationTest.verifiedSchemaSeventeenBridgeBackupMigratesThroughCurrentOwner`,
|
||||
`RealAndroidV9BodyZonesMigrationTest.realVersionNineCopyMigratesWithoutChangingExistingTables`,
|
||||
`RealAndroidV14FeedbackRevisionMigrationTest.freshRealCopyMigratesLosslesslyToVersionFifteen`,
|
||||
and the version-thirteen and version-twelve methods in
|
||||
`RealAndroidV12MachineExerciseMigrationTest`. They require respectively the
|
||||
bridge backup input, a real v9 fixture, a real v14 fixture/output directory,
|
||||
and real v13/v12 fixtures with explicit output directories. Synthetic bridge
|
||||
and current-schema migration proofs run separately; no user database is read.
|
||||
|
|
|
|||
|
|
@ -7,7 +7,9 @@ from pathlib import Path
|
|||
ROOT = Path(__file__).resolve().parents[1]
|
||||
BUILD = ROOT / os.environ.get("TRAINLOG_WEB_E2E_BUILD", "build") / "tui"
|
||||
GECKO = Path(
|
||||
os.environ.get("TRAINLOG_GECKODRIVER", "/home/fy59/.cache/trainlog/web-e2e-tools/geckodriver")
|
||||
os.environ.get(
|
||||
"TRAINLOG_GECKODRIVER", "/home/fy59/.cache/trainlog/web-e2e-tools/geckodriver"
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
|
|
@ -40,7 +42,9 @@ class BrowserSyncTest(unittest.TestCase):
|
|||
transport.mkdir()
|
||||
owned = root / "owned"
|
||||
owned.mkdir()
|
||||
remote = (root / "device/Documents/Trainlog") if mode == "mtp" else transport
|
||||
remote = (
|
||||
(root / "device/Documents/Trainlog") if mode == "mtp" else transport
|
||||
)
|
||||
remote.mkdir(parents=True, exist_ok=True)
|
||||
release = root / "release-android"
|
||||
android_log = (root / "android.log").open("wb")
|
||||
|
|
@ -140,11 +144,15 @@ class BrowserSyncTest(unittest.TestCase):
|
|||
driver.get(f"http://127.0.0.1:{port}/")
|
||||
wait = WebDriverWait(driver, 15)
|
||||
button = wait.until(
|
||||
lambda d: d.find_element(By.XPATH, "//button[normalize-space()='Synchroniser']")
|
||||
lambda d: d.find_element(
|
||||
By.XPATH, "//button[normalize-space()='Synchroniser']"
|
||||
)
|
||||
)
|
||||
wait.until(lambda _: button.is_enabled())
|
||||
button.click()
|
||||
state_path = Path(str(xdg / "trainlog" / "trainlog.db") + ".sync-run.json")
|
||||
state_path = Path(
|
||||
str(xdg / "trainlog" / "trainlog.db") + ".sync-run.json"
|
||||
)
|
||||
observed = await_condition(
|
||||
lambda: (
|
||||
json.loads(state_path.read_text())
|
||||
|
|
@ -164,7 +172,10 @@ class BrowserSyncTest(unittest.TestCase):
|
|||
self.assertEqual(committed["result"], "running")
|
||||
with sqlite3.connect(xdg / "trainlog" / "trainlog.db") as database:
|
||||
self.assertEqual(
|
||||
database.execute("SELECT COUNT(*) FROM execution_drafts").fetchone()[0], 1
|
||||
database.execute(
|
||||
"SELECT COUNT(*) FROM execution_drafts"
|
||||
).fetchone()[0],
|
||||
1,
|
||||
)
|
||||
release.touch()
|
||||
final = await_condition(
|
||||
|
|
@ -186,16 +197,21 @@ class BrowserSyncTest(unittest.TestCase):
|
|||
)
|
||||
summary.click()
|
||||
wait.until(
|
||||
lambda d: "Brouillons reçus" in d.page_source and "active" in d.page_source
|
||||
lambda d: "Brouillons reçus" in d.page_source
|
||||
and "active" in d.page_source
|
||||
)
|
||||
driver.refresh()
|
||||
wait.until(lambda d: "Synchronisation confirmée" in d.page_source)
|
||||
state = json.loads(
|
||||
Path(str(xdg / "trainlog" / "trainlog.db") + ".sync-run.json").read_text()
|
||||
Path(
|
||||
str(xdg / "trainlog" / "trainlog.db") + ".sync-run.json"
|
||||
).read_text()
|
||||
)
|
||||
self.assertEqual(state["phase"], "completed")
|
||||
self.assertEqual(
|
||||
android.wait(timeout=30), 0, (root / "android.log").read_text(errors="replace")
|
||||
android.wait(timeout=30),
|
||||
0,
|
||||
(root / "android.log").read_text(errors="replace"),
|
||||
)
|
||||
finally:
|
||||
if driver is not None:
|
||||
|
|
|
|||
|
|
@ -139,7 +139,12 @@ def main() -> int:
|
|||
if args.mtp_adapter is None:
|
||||
raise RuntimeError("MTP adapter is required")
|
||||
pump = lambda: run_adapter(
|
||||
args.mtp_adapter, "pull", args.expected_peer, args.transport_root, deadline, True
|
||||
args.mtp_adapter,
|
||||
"pull",
|
||||
args.expected_peer,
|
||||
args.transport_root,
|
||||
deadline,
|
||||
True,
|
||||
)
|
||||
# Android publishes its durable identity only while participating. A
|
||||
# missing expected advertisement is therefore a bounded wait state;
|
||||
|
|
@ -162,7 +167,9 @@ def main() -> int:
|
|||
request_path = args.transport_root / "request-v1.json"
|
||||
publish_json(request_path, request)
|
||||
if args.mode == "mtp":
|
||||
run_adapter(args.mtp_adapter, "push", args.expected_peer, args.transport_root, deadline)
|
||||
run_adapter(
|
||||
args.mtp_adapter, "push", args.expected_peer, args.transport_root, deadline
|
||||
)
|
||||
emit(
|
||||
args.run_id,
|
||||
"waiting_android_publication",
|
||||
|
|
@ -178,7 +185,9 @@ def main() -> int:
|
|||
ack_path = args.transport_root / "desktop-consumption-ack-v1.json"
|
||||
publish_json(ack_path, ack)
|
||||
if args.mode == "mtp":
|
||||
run_adapter(args.mtp_adapter, "push", args.expected_peer, args.transport_root, deadline)
|
||||
run_adapter(
|
||||
args.mtp_adapter, "push", args.expected_peer, args.transport_root, deadline
|
||||
)
|
||||
if ack["result"] != "consumed":
|
||||
raise RuntimeError("desktop rejected Android generation")
|
||||
emit(
|
||||
|
|
@ -209,8 +218,15 @@ def main() -> int:
|
|||
}
|
||||
publish_json(args.transport_root / "desktop-generation-v1.json", ref)
|
||||
if args.mode == "mtp":
|
||||
run_adapter(args.mtp_adapter, "push", args.expected_peer, args.transport_root, deadline)
|
||||
emit(args.run_id, "published", outbound_generation_id=outgoing_id, manifest_sha256=digest)
|
||||
run_adapter(
|
||||
args.mtp_adapter, "push", args.expected_peer, args.transport_root, deadline
|
||||
)
|
||||
emit(
|
||||
args.run_id,
|
||||
"published",
|
||||
outbound_generation_id=outgoing_id,
|
||||
manifest_sha256=digest,
|
||||
)
|
||||
emit(args.run_id, "waiting_acknowledgement", outbound_generation_id=outgoing_id)
|
||||
android_ack = args.transport_root / "android-consumption-ack-v1.json"
|
||||
android_ack_value = wait_json(
|
||||
|
|
|
|||
Loading…
Reference in a new issue