Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 49 additions & 2 deletions CURRENT_STATE.md
Original file line number Diff line number Diff line change
@@ -1,13 +1,60 @@
---
name: synaplex current state
description: Front door for the synaplex.ai system — publication + evaluation lab + operational pipeline. Read first every session.
updated: 2026-07-27T00:12Z (Cadence lineage, dependency closure, and GitHub controls verified)
updated: 2026-07-27T00:33Z (Cadence route identity and inbox service hardening verified)
owner: executive (principal: evan)
phase: artifact-delivery-instrument-v2 BLOCKED_PRE_ENTRY and quarantined; artifact-coherence-transfer-v1 INVALIDATED by Codex; public projection v1.3.0 live with five archived lineage artifacts; zero findings
---

# synaplex — current state

## Cadence route identity and inbox hardening — complete (2026-07-27)

The final lifecycle projection is deployed at
`https://14154a06.synaplex.pages.dev` and `https://synaplex.ai`. Fresh
route-specific GETs to `/lineage/cadence/` on both origins returned identical
5187-byte bodies with byte digest
`sha256:f8a57cebbd817977e1929d977d474b2c564dae025ba08560de07f079f3cda4e8`.
Both bodies contain the title `Cadence · synaplex`, canonical
`https://synaplex.ai/lineage/cadence/`, five `Cadence` strings, and the exact
“Not a Claim. Not Evidence. Not a finding. Not a current study.” boundary.
This supersedes the earlier propagation-edge observation where an HTTP 200
temporarily carried homepage identity; status alone is not the success
criterion.

The final Tailwind 4/Preflight visual comparison was rerun from the built site.
Home and AI Native lineage retain their exact pre-migration dimensions,
background, font stack, and 100.8px headline. Mean absolute RGB deltas remain
0.0220 and 0.0113 on a 0–255 scale, with changed-channel ratios 0.000245 and
0.000198. The rejected no-Preflight candidate caused the earlier roughly
20–28% delta and taller pages; it was never shipped. Screenshot digests,
normalized metrics, and the Cadence identity render are recorded in
`docs/dependency-migration-2026-07.md`.

`synaplex-inbox.service` is now installed and running under the dedicated
`synaplex-inbox` identity with no capabilities or ambient capabilities,
`NoNewPrivileges`, strict read-only system protection, private temp/devices,
kernel and control-group protection, namespace/SUID restrictions, and
localhost-only cgroup IP policy. The server needs no host write path:
`ReadWritePaths` is empty and the inbox is explicit in `ReadOnlyPaths`.
An exact-unit canary returned the same nonce-gated 4354-byte payload as the
old service, digest
`sha256:caff845d611110d2e6f1116263f864258f5393a6a861bb5266d50c753d37a5af`;
the installed unit repeated that witness and listens only on
`127.0.0.1:8088`. The runtime containment audit reports zero findings and
`systemd-analyze security` improved from `9.6 UNSAFE` to `1.3 OK`.
Independent executive/operator verification reproduced the effective controls,
reported `NRestarts=0`, obtained the same 200/4354-byte nonce-scoped response
and digest, and separately confirmed the central auditor's zero findings.

The previous unit is retained mode 0600 at
`/opt/workspace/runtime/.meta/synaplex-inbox.service.before-hardening-2026-07-27T00-27-39Z`
for bounded rollback. The only dated exception is `PrivateNetwork=true`,
because a separate loopback namespace would break the required host-loopback
route; the fixed loopback bind plus default-deny/localhost-only IP policy is
the compensating control. Full canary, rollback, install, and outcome details
are in `docs/inbox-service-hardening-2026-07.md`.

## Cadence lineage and dependency closure — complete (2026-07-27)

PR [#16](https://github.com/evanfollis/synaplex/pull/16) merged as
Expand All @@ -34,7 +81,7 @@ The public projection is v1.3.0 with digest
`sha256:4ae99babff63e92c607978f80e18a89c235868fd91b2bbf1a21c104945585e98`
and counts 3 research / 0 findings / 3 mechanisms / 3 engineering cases /
18 sources / 4 conjectures / 5 lineage records. It is deployed from the exact
merge at `https://9e4b3c3f.synaplex.pages.dev` and
final lifecycle state at `https://14154a06.synaplex.pages.dev` and
`https://synaplex.ai`. Clean external GETs returned 200 for the roots,
`/lineage/cadence/`, and `/knowledge/public-projection.json`. Immutable and
apex projection bytes are identical with byte digest
Expand Down
51 changes: 51 additions & 0 deletions deploy/synaplex-inbox.service
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
[Unit]
Description=Synaplex nonce-gated inbox server
After=network.target

[Service]
Type=simple
User=synaplex-inbox
Group=synaplex-inbox
WorkingDirectory=/opt/workspace/runtime/inbox
Environment=PYTHONDONTWRITEBYTECODE=1
ExecStart=/usr/bin/python3 /opt/workspace/supervisor/scripts/lib/inbox-server.py
Restart=on-failure
RestartSec=5s
UMask=0077
MemoryMax=128M
TasksMax=16

# The server reads static inbox material and requires no host write path.
ReadOnlyPaths=/opt/workspace/runtime/inbox
NoNewPrivileges=true
CapabilityBoundingSet=
AmbientCapabilities=
PrivateTmp=true
PrivateDevices=true
ProtectSystem=strict
ProtectHome=true
ProtectClock=true
ProtectHostname=true
ProtectKernelLogs=true
ProtectKernelTunables=true
ProtectKernelModules=true
ProtectControlGroups=true
ProtectProc=invisible
ProcSubset=pid
LockPersonality=true
MemoryDenyWriteExecute=true
RemoveIPC=true
RestrictNamespaces=true
RestrictRealtime=true
RestrictSUIDSGID=true
RestrictAddressFamilies=AF_UNIX AF_INET AF_INET6
SystemCallArchitectures=native
SystemCallFilter=@system-service
SystemCallErrorNumber=EPERM

# Host-loopback reachability is required; cgroup egress remains localhost-only.
IPAddressDeny=any
IPAddressAllow=localhost

[Install]
WantedBy=multi-user.target
29 changes: 29 additions & 0 deletions docs/dependency-migration-2026-07.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,3 +68,32 @@ Both retained `rgb(242, 240, 233)` as the root background and the same body font
stack; the lineage headline remained 100.8px. The new
`/lineage/cadence/` route was separately rendered and inspected, including its
“Not a Claim. Not Evidence. Not a finding. Not a current study.” boundary.

The first Tailwind 4 conversion attempt omitted Preflight. That candidate was
not shipped: it changed the homepage height from 2950px to 3374px, changed the
lineage height from 2032px to 2277px, and produced roughly 20–28% changed RGB
channels through browser-default list, heading, and typography styles. Enabling
the Tailwind 4 import (and therefore Preflight) restored the established reset.
No intentional visual redesign is part of this migration.

The comparison was rerun from the final build on 2026-07-27. The results were
identical to the accepted comparison above: homepage screenshot
`sha256:cd44df1402834dec32d0fe074dfdfca8c422550f32b8c9347b442d638c8c9095`
remained 1440x2950 with mean absolute RGB delta 0.0220 (0.0000863 when
normalized to 0–1) and changed-channel ratio 0.000245 against the retained
pre-migration image
`sha256:91a1eeffa1e2682cb0c6dcf8eb2c4b8f52f3986a7b6aeca06c1b5a90a64d25f1`.
The AI Native lineage screenshot
`sha256:e3d8f35ac8879c08229fcc5cb388435127dc02a5135b6acf442ad34460af78cc`
remained 1440x2032 with mean absolute RGB delta 0.0113 (0.0000442 normalized)
and changed-channel ratio 0.000198 against
`sha256:0712a705c6e9abf105421d315e6c315d16a7678bd8e8c158589a58ead3642341`.
Computed styles again reported the original background, font stack, and
100.8px headline. Visual inspection found no typography, spacing, list, or
layout reset.

The final Cadence screenshot is
`sha256:a06afaa784018eb2860b0bb7df25a53e202bddcbe45c763d822b8fa14ec16106`.
Its rendered identity was checked separately: title `Cadence · synaplex`,
canonical `https://synaplex.ai/lineage/cadence/`, `Cadence` H1, and the explicit
epistemic boundary were all present.
86 changes: 86 additions & 0 deletions docs/inbox-service-hardening-2026-07.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
# Inbox service hardening — 2026-07-27

This is an operational hardening receipt, not scientific Evidence. It records
the canary, rollback boundary, installed controls, and observed outcome for
`synaplex-inbox.service`.

## Required access

The server reads the nonce-gated static tree at
`/opt/workspace/runtime/inbox` and the existing Python launcher at
`/opt/workspace/supervisor/scripts/lib/inbox-server.py`. It binds only
`127.0.0.1:8088`. It requires no host write path, so the unit declares the
inbox tree with `ReadOnlyPaths` and deliberately has no `ReadWritePaths`
allowance. Its isolated private `/tmp` remains available to the process.

The installed process uses the dedicated `synaplex-inbox:synaplex-inbox`
system identity rather than root. Before canary startup, that identity was
verified to traverse and read the inbox and launcher paths.

## Mandatory controls

The versioned unit enables:

- `NoNewPrivileges=true`, empty capability and ambient-capability sets, and
`RestrictSUIDSGID=true`;
- `ProtectSystem=strict`, `ProtectHome=true`, owner-only `UMask=0077`, and the
explicit read-only inbox path;
- `PrivateTmp=true`, `PrivateDevices=true`, and process visibility protection;
- kernel tunable, module, log, clock, hostname, and control-group protection;
- namespace, realtime, personality, architecture, and system-call restrictions;
- default-deny IP policy with localhost as the only allowed destination and
only `AF_UNIX`, `AF_INET`, and `AF_INET6` address families.

The repository deployment-contract check asserts these controls and rejects
adding a host `ReadWritePaths` allowance to this read-only service.

## Canary, installation, and rollback

The previous root-running unit is retained with mode 0600 at:

`/opt/workspace/runtime/.meta/synaplex-inbox.service.before-hardening-2026-07-27T00-27-39Z`

Its SHA-256 digest is
`4a5c832f5b3d2a781039ede74a7ce1a5d7c561a13b1f2528c96d6f66325915dc`.
Rollback is the bounded operation of installing that file back to
`/etc/systemd/system/synaplex-inbox.service`, running
`systemctl daemon-reload`, restarting the service, and repeating the
nonce-gated payload check.

The exact candidate unit was first installed under the transient canary unit
name. The production unit was stopped, the canary was started on the real
loopback port, and a nonce-gated GET returned 4354 bytes with SHA-256
`caff845d611110d2e6f1116263f864258f5393a6a861bb5266d50c753d37a5af`,
identical to the pre-canary payload. Effective canary properties showed the
dedicated identity, strict filesystem protection, private temp/devices, empty
capabilities, all required kernel and namespace controls, no host write paths,
and localhost-only IP policy. `systemd-analyze security` rated it `1.3 OK`.
The canary was then removed and the original service was successfully restored
before permanent installation.

Permanent installation used an automatic failure trap that would restore the
retained unit on any restart, payload, or control-check failure. No rollback
was triggered. The installed and repository unit bytes are identical at
`sha256:4fcc085a87f58145b4710625e8b1cc1b2b7491b887b1297c349848f835711acd`.
The service is enabled and has remained active since
2026-07-27T00:29:26Z. It listens only on `127.0.0.1:8088`; its post-install
nonce-gated response is the same 4354-byte payload with the same digest.
The workspace runtime containment audit reports zero findings at every
severity, and the installed unit retains the `1.3 OK` systemd exposure rating
(improved from `9.6 UNSAFE`).

Independent executive/operator verification then confirmed the effective
dedicated identity, empty capability set, strict filesystem protection,
`NoNewPrivileges`, private temp/devices, `ActiveState=active`, and
`NRestarts=0`. Its separate nonce-scoped GET returned HTTP 200 with the same
4354 bytes and payload digest, and the central auditor independently reported
zero findings for the unit.

## Smallest dated exception

2026-07-27: `PrivateNetwork=true` is not enabled because it would place the
server in a separate loopback namespace and break its required host-loopback
consumer route. This exception does not relax any other sandbox control.
Compensating controls are the launcher's fixed `127.0.0.1` bind,
`IPAddressDeny=any`, `IPAddressAllow=localhost`, and the restricted address
families. The observed listener is only `127.0.0.1:8088`.
37 changes: 36 additions & 1 deletion scripts/check_deploy_contract.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,27 @@
"PrivateTmp=true",
)

INBOX_REQUIRED = (
"User=synaplex-inbox",
"Group=synaplex-inbox",
"UMask=0077",
"ReadOnlyPaths=/opt/workspace/runtime/inbox",
"NoNewPrivileges=true",
"CapabilityBoundingSet=\n",
"AmbientCapabilities=\n",
"PrivateTmp=true",
"PrivateDevices=true",
"ProtectSystem=strict",
"ProtectKernelTunables=true",
"ProtectKernelModules=true",
"ProtectControlGroups=true",
"LockPersonality=true",
"RestrictNamespaces=true",
"RestrictSUIDSGID=true",
"IPAddressDeny=any",
"IPAddressAllow=localhost",
)


def main() -> None:
units = sorted((REPO_ROOT / "deploy").glob("*-v2.service"))
Expand All @@ -26,9 +47,23 @@ def main() -> None:
errors.append(f"{unit.name}: missing {requirement}")
if "ExecStart=/bin/bash" not in text:
errors.append(f"{unit.name}: launcher must resolve configured paths")
inbox = REPO_ROOT / "deploy" / "synaplex-inbox.service"
if not inbox.is_file():
errors.append("synaplex-inbox.service: missing versioned source")
else:
text = inbox.read_text(encoding="utf-8")
for requirement in INBOX_REQUIRED:
if requirement not in text:
errors.append(
f"synaplex-inbox.service: missing {requirement.rstrip()}"
)
if "ReadWritePaths=" in text:
errors.append(
"synaplex-inbox.service: read-only server must not gain a host write path"
)
if errors:
raise SystemExit("\n".join(errors))
print(f"deployment contract: clean ({len(units)} units)")
print(f"deployment contract: clean ({len(units)} v2 units + inbox)")


if __name__ == "__main__":
Expand Down