T03. §9.6 gives load-bearing and attributive sources different obligations, so
the archive must record which one a source declared rather than infer it from
traffic. evidence_kind and completeness_trade now sit on SenderIdentity, the
AUDIT_CORE_SENDERS schema, and the non-secret scope overlay.
Two asymmetries are deliberate. The default is attributive, because the other
default would have audit-core imply a completeness obligation no source ever
accepted. And the overlay may raise the kind but never lower it — the same
principle that stops an ExternalSecret refresh shrinking user-engine's
tenants: a ConfigMap refresh must not drop a source's atomicity and detection
obligations without anyone deciding to. A load-bearing source may not carry a
completeness trade at all, since §9.6 requires atomicity of it, and
evidence_declaration() reports completeness_claimed: false for both kinds.
T09 (in progress). approval-engine's registration inputs are prepared and
recorded in docs/approval-engine-source-registration.md: scope entry declared
load-bearing, and audit-core-approval-engine-ingress with namespace and pod
label ANDed in one `from` peer — narrower than user-engine's namespace-only
rule, which is left unchanged. The scope entry lands ahead of the credential
because the overlay only applies to senders the Secret already carries, so it
admits nothing until the token exists; a test asserts that rather than
trusting the reading.
Two inputs remain approval-engine's: a confirmed tenant scope, since senders.py
requires a missing tenant restriction be justified per sender and audit-core
cannot justify it on another repo's behalf, and an explicit secret_policy
choice. Applying the manifests is an operator action.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0185wifnLzCxjEY2MT1XbK7L
Assistant: claude-code
Assistant-Model: opus
Assistant-Process: 713962@bnt-lap001
Assistant-Session: 2718d99d-d3ff-478f-83a2-3a30f01a02fc
Updated by fix-consistency on 2026-09-06:
- workplan status: ready → active
Assistant: claude-code
Assistant-Model: opus
Assistant-Process: 713962@bnt-lap001
Assistant-Session: 2718d99d-d3ff-478f-83a2-3a30f01a02fc
glas-harness reports approval-engine production startup now requires audit
delivery, putting sender registration on the deployment critical path. The
task's note read the dependency backwards: audit-core is not waiting for a
producer to emit, the producer is waiting for a sender identity.
T03 is promoted with it. §9.4 makes approval evidence load-bearing and there
is nowhere to record that until evidence_kind exists; registering ahead of T03
would admit a load-bearing source into a system that would silently treat it
as attributive, which is the defect §9.6 names.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0185wifnLzCxjEY2MT1XbK7L
Assistant: claude-code
Assistant-Model: opus
Assistant-Process: 713962@bnt-lap001
Assistant-Session: 2718d99d-d3ff-478f-83a2-3a30f01a02fc
§9.4 forbids audit-core answering whether an approval is still valid: a
consumer branching on such an answer would route an authorization decision
through the audit fabric. The prohibition was honoured by absence, which is
not the estate's idiom — §6.4 obligation 3 requires a published stance to
equal shipped behaviour asserted by test.
Written against shapes rather than today's route list, so adding a validity
surface later fails here rather than passing quietly. Plausible verdict paths
must 404 rather than 403: a distinguishable forbidden would imply a surface
exists behind auth. No backend class, Postgres included, may carry a
verdict-shaped method name. The declaration must stay in layer.yaml,
INTENT.md and SCOPE.md.
The last test guards the opposite error — an approval-shaped event class is
still ingestible, because the prohibition bounds the verdict, not the record.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0185wifnLzCxjEY2MT1XbK7L
Assistant: claude-code
Assistant-Model: opus
Assistant-Process: 713962@bnt-lap001
Assistant-Session: 2718d99d-d3ff-478f-83a2-3a30f01a02fc
The Postgres backend returned tamper_evidence=True as a constant while
docs/integrity.md permits the claim only when a live external chain-head
attestation exists. The one attestation on record is 2026-08-16 and no job
renews it, so audit-core was telling every sender it had a property whose
precondition was unverified — the §9.6 defect it twice corrected in
gate-house's doctrine, turned inward.
evaluate_tamper_evidence() derives the flag from the chain report and the
mounted attestation, distinguishing seven states. Absence, staleness,
mismatch, an undated or unreadable attestation, a chain break, and an
unwalkable chain all degrade the claim rather than leave it standing.
Unreadable is treated as absent on purpose: a malformed file must not hold
up a claim a missing file would drop.
The freshness window is 168h against an intended daily cadence — seven
cadences, so a handful of missed runs degrade the claim rather than a single
one flapping it. Window and cadence are one contract in docs/integrity.md.
Production /readyz will now report tamper_evidence: false until
AUDIT-WP-0009-T02 schedules attestation. The claim was already false; it now
says so.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0185wifnLzCxjEY2MT1XbK7L
Assistant: claude-code
Assistant-Model: opus
Assistant-Process: 713962@bnt-lap001
Assistant-Session: 2718d99d-d3ff-478f-83a2-3a30f01a02fc
The standard is accepted at v0.7 and all three of audit-core's v0.6
findings landed in it (§9.6 threat decomposition, cadence MUST for
load-bearing sources with reconciliation/heartbeat for low-volume
classes, §3.3's Evidence row restated as an estate trade).
INTENT.md: layer/role declared in frontmatter as §11 and companion §2
require — layer.yaml alone did not discharge it. Layer section rewritten
for the Evidence role and its obligations. New Evidence Bound section
carrying the §9.6 sound/unsound forms and the three-row threat table,
including the residual nothing in the model prevents.
SCOPE.md: replaced the statehub register stub, which carried no boundary
at all. Statute-fixed prohibitions now live here, separated from the
merely-not-yet — §16 ruled the stronger-custody gap closed, so WORM and
data.archive are not ours rather than not yet.
Assessment found nine gaps. Headline: postgres_backend returns
tamper_evidence=True unconditionally while docs/integrity.md permits it
only against a live external attestation, and the one on record is
2026-08-16 with no job renewing it — audit-core overclaiming its own
bound, the §9.6 defect turned inward. Also: no cadence, heartbeat,
reconciliation, or load-bearing classification exists, so the obligation
audit-core argued up from SHOULD to MUST is not yet dischargeable
against audit-core.
AUDIT-WP-0009 raised, ten tasks.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WpeL68AWHqtqPQZEXY5kFe
Assistant: claude-code
Assistant-Model: opus
Assistant-Process: 4040362@bnt-lap001
Assistant-Session: 4fd0fd24-2ee8-4413-bd67-43bd79ca73f1