Declare the tenancy posture vector (AUDIT-WP-0008-T01).
Written against draft-7, which landed after the task was drafted and moved the
target. Decision 5.4 fixes the location at tenancy.yaml in the repo root rather
than docs/, and fixes the schema: current, target, reviewed, gap,
placement_exceptions, service_class, per-path detail, provider block.
Declares I1 A2 E1 P1 R1. E is quoted at 1 although T04 put the E2 mechanism on
both paths, because §13.2 states a passing CI run is not E2 evidence -- the
artifact is adversarial, compares separate tenant contexts and carries a review
date. Our cross-tenant tests are mechanical, so under §13.1 the level is not
claimable until T05. The mechanism is recorded in paths.E and the reason in
gap.E. Claiming E2 off unit tests would be the overclaim §6 prohibits, and
refusing that reasoning is what found the read-path defect.
R stays at 1: R2 needs backupRetentionDays in rapp-postgres's consumer file,
requested in T02 and not ours to declare.
Two additions draft-7 forced. A credentials gap under Decision 9.2 -- our own
finding, adopted as a rule, and it binds us: ingest credentials are static
long-lived bearer tokens, declared as a stated gap rather than a silent
exclusion. And a provides block under Decision 5.5, declaring what a sender can
reach through this service: E2 now, E3 pending ADR-0003, E4 and R4 unreachable.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-17 22:55:31 +02:00
# audit-core tenancy posture
#
2026-08-18 15:20:58 +02:00
# Declared per NetKingdom Tenancy Posture v0.1 (draft-8),
Declare the tenancy posture vector (AUDIT-WP-0008-T01).
Written against draft-7, which landed after the task was drafted and moved the
target. Decision 5.4 fixes the location at tenancy.yaml in the repo root rather
than docs/, and fixes the schema: current, target, reviewed, gap,
placement_exceptions, service_class, per-path detail, provider block.
Declares I1 A2 E1 P1 R1. E is quoted at 1 although T04 put the E2 mechanism on
both paths, because §13.2 states a passing CI run is not E2 evidence -- the
artifact is adversarial, compares separate tenant contexts and carries a review
date. Our cross-tenant tests are mechanical, so under §13.1 the level is not
claimable until T05. The mechanism is recorded in paths.E and the reason in
gap.E. Claiming E2 off unit tests would be the overclaim §6 prohibits, and
refusing that reasoning is what found the read-path defect.
R stays at 1: R2 needs backupRetentionDays in rapp-postgres's consumer file,
requested in T02 and not ours to declare.
Two additions draft-7 forced. A credentials gap under Decision 9.2 -- our own
finding, adopted as a rule, and it binds us: ingest credentials are static
long-lived bearer tokens, declared as a stated gap rather than a silent
exclusion. And a provides block under Decision 5.5, declaring what a sender can
reach through this service: E2 now, E3 pending ADR-0003, E4 and R4 unreachable.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-17 22:55:31 +02:00
# net-kingdom/canon/standards/tenancy-posture_v0.1.md.
# Location and schema per Decision 5.4; per-path detail per Decision 5.2;
# provider block per Decision 5.5.
#
# Conformance is accuracy, not altitude (§6). Nothing here is claimed above
2026-08-23 00:26:32 +02:00
# what this repo can evidence today. E2 is backed by a bounded adversarial
# target run; its scope and freshness limit are recorded below.
2026-08-18 15:20:58 +02:00
schema_version : "0.1"
framework : netkingdom-tenancy-posture
service : audit-core
role : tenant-audit-service
Declare the tenancy posture vector (AUDIT-WP-0008-T01).
Written against draft-7, which landed after the task was drafted and moved the
target. Decision 5.4 fixes the location at tenancy.yaml in the repo root rather
than docs/, and fixes the schema: current, target, reviewed, gap,
placement_exceptions, service_class, per-path detail, provider block.
Declares I1 A2 E1 P1 R1. E is quoted at 1 although T04 put the E2 mechanism on
both paths, because §13.2 states a passing CI run is not E2 evidence -- the
artifact is adversarial, compares separate tenant contexts and carries a review
date. Our cross-tenant tests are mechanical, so under §13.1 the level is not
claimable until T05. The mechanism is recorded in paths.E and the reason in
gap.E. Claiming E2 off unit tests would be the overclaim §6 prohibits, and
refusing that reasoning is what found the read-path defect.
R stays at 1: R2 needs backupRetentionDays in rapp-postgres's consumer file,
requested in T02 and not ours to declare.
Two additions draft-7 forced. A credentials gap under Decision 9.2 -- our own
finding, adopted as a rule, and it binds us: ingest credentials are static
long-lived bearer tokens, declared as a stated gap rather than a silent
exclusion. And a provides block under Decision 5.5, declaring what a sender can
reach through this service: E2 now, E3 pending ADR-0003, E4 and R4 unreachable.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-17 22:55:31 +02:00
tenancy :
2026-08-23 00:26:32 +02:00
reviewed : "2026-08-22"
review_due : "2026-08-23"
Declare the tenancy posture vector (AUDIT-WP-0008-T01).
Written against draft-7, which landed after the task was drafted and moved the
target. Decision 5.4 fixes the location at tenancy.yaml in the repo root rather
than docs/, and fixes the schema: current, target, reviewed, gap,
placement_exceptions, service_class, per-path detail, provider block.
Declares I1 A2 E1 P1 R1. E is quoted at 1 although T04 put the E2 mechanism on
both paths, because §13.2 states a passing CI run is not E2 evidence -- the
artifact is adversarial, compares separate tenant contexts and carries a review
date. Our cross-tenant tests are mechanical, so under §13.1 the level is not
claimable until T05. The mechanism is recorded in paths.E and the reason in
gap.E. Claiming E2 off unit tests would be the overclaim §6 prohibits, and
refusing that reasoning is what found the read-path defect.
R stays at 1: R2 needs backupRetentionDays in rapp-postgres's consumer file,
requested in T02 and not ours to declare.
Two additions draft-7 forced. A credentials gap under Decision 9.2 -- our own
finding, adopted as a rule, and it binds us: ingest credentials are static
long-lived bearer tokens, declared as a stated gap rather than a silent
exclusion. And a provides block under Decision 5.5, declaring what a sender can
reach through this service: E2 now, E3 pending ADR-0003, E4 and R4 unreachable.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-17 22:55:31 +02:00
service_class : batch # §8.3.2. Co-resident with latency-critical
# tenant-engine on platform-pg; the mixture is
# reported by the platform, not hidden.
2026-09-24 15:53:09 +02:00
current : { I: 1, A: 2, E: 2, P: 1, R: 2, V : 1 }
2026-08-18 15:20:58 +02:00
target : { I: 1, A: 2, E: 3, P: 1, R: 2, V : 1 }
Declare the tenancy posture vector (AUDIT-WP-0008-T01).
Written against draft-7, which landed after the task was drafted and moved the
target. Decision 5.4 fixes the location at tenancy.yaml in the repo root rather
than docs/, and fixes the schema: current, target, reviewed, gap,
placement_exceptions, service_class, per-path detail, provider block.
Declares I1 A2 E1 P1 R1. E is quoted at 1 although T04 put the E2 mechanism on
both paths, because §13.2 states a passing CI run is not E2 evidence -- the
artifact is adversarial, compares separate tenant contexts and carries a review
date. Our cross-tenant tests are mechanical, so under §13.1 the level is not
claimable until T05. The mechanism is recorded in paths.E and the reason in
gap.E. Claiming E2 off unit tests would be the overclaim §6 prohibits, and
refusing that reasoning is what found the read-path defect.
R stays at 1: R2 needs backupRetentionDays in rapp-postgres's consumer file,
requested in T02 and not ours to declare.
Two additions draft-7 forced. A credentials gap under Decision 9.2 -- our own
finding, adopted as a rule, and it binds us: ingest credentials are static
long-lived bearer tokens, declared as a stated gap rather than a silent
exclusion. And a provides block under Decision 5.5, declaring what a sender can
reach through this service: E2 now, E3 pending ADR-0003, E4 and R4 unreachable.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-17 22:55:31 +02:00
# §5.2 — declare per path, quote the minimum. The quoted E above is the
# minimum across paths. As of AUDIT-WP-0008-T04 both paths carry the same
2026-08-23 00:26:32 +02:00
# mechanism. The quoted level is now 2 because the adversarial target artifact
# required by §13.2 exists for this revision.
Declare the tenancy posture vector (AUDIT-WP-0008-T01).
Written against draft-7, which landed after the task was drafted and moved the
target. Decision 5.4 fixes the location at tenancy.yaml in the repo root rather
than docs/, and fixes the schema: current, target, reviewed, gap,
placement_exceptions, service_class, per-path detail, provider block.
Declares I1 A2 E1 P1 R1. E is quoted at 1 although T04 put the E2 mechanism on
both paths, because §13.2 states a passing CI run is not E2 evidence -- the
artifact is adversarial, compares separate tenant contexts and carries a review
date. Our cross-tenant tests are mechanical, so under §13.1 the level is not
claimable until T05. The mechanism is recorded in paths.E and the reason in
gap.E. Claiming E2 off unit tests would be the overclaim §6 prohibits, and
refusing that reasoning is what found the read-path defect.
R stays at 1: R2 needs backupRetentionDays in rapp-postgres's consumer file,
requested in T02 and not ours to declare.
Two additions draft-7 forced. A credentials gap under Decision 9.2 -- our own
finding, adopted as a rule, and it binds us: ingest credentials are static
long-lived bearer tokens, declared as a stated gap rather than a silent
exclusion. And a provides block under Decision 5.5, declaring what a sender can
reach through this service: E2 now, E3 pending ADR-0003, E4 and R4 unreachable.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-17 22:55:31 +02:00
paths :
E :
write : 2 # Sender credential bound to the sources and tenants it may
# claim; checked at one choke point (audit_core/ingestion.py).
read : 2 # Event reads filtered to permitted tenants; surfaces with no
# tenant key require full scope. Cross-tenant fetch returns
# 404, not 403, so the surface is not an existence oracle.
placement_exceptions : [ ] # No tenant is on dedicated substrate. All
# tenants share database audit_core on
# platform-pg.
gap :
I : >-
I1 is accurate and is not currently a target. Senders authenticate with
bearer tokens and the tenant arrives in the request body, checked against
an allowlist bound to the credential (§4.1 places request-supplied tenant
identifiers at I1 however canonical the string). The allowlist is a real
control, but it is an A-axis control; it does not make the identity
verified. Moving to I2 means senders carrying a verified token with a
tenant claim, which is a change to every sender and not audit-core's to
make alone. Recorded as accurate, not as ambition.
A : >-
A2 is accurate. Authorization is a single local boundary — permitted
sources, permitted tenants, may_write, may_read — bound once and centrally.
No flex-auth delegation. A3 is not a near-term target : flex-auth is itself
at A0 on its own self-report (/v1/check authenticates no caller), so
delegating to it today would lower this service's assurance, not raise it.
E : >-
2026-08-23 00:26:32 +02:00
E2 is implemented on both paths by AUDIT-WP-0008-T04 and evidenced by the
bounded whitehat-security target run WH-ENG-20260822-AUDIT-E2-03. An
ordinary tenant-A identity could not fetch tenant B's event by id, observe
tenant B's correlation fixture, or append as tenant B across ten attempted
operations. The run ended 2026-08-22T22:10:25Z with no limitations;
receipt-bound cleanup removed both temporary identities, both exact KV
paths, all projection resources and the runner. This says only that the
attempted attacks did not work, not that the boundary always holds. The
24 -hour facility baseline makes review or replacement due at
2026-08-23T22:10:25Z , and relevant boundary changes require a
pre-promotion run.
Declare the tenancy posture vector (AUDIT-WP-0008-T01).
Written against draft-7, which landed after the task was drafted and moved the
target. Decision 5.4 fixes the location at tenancy.yaml in the repo root rather
than docs/, and fixes the schema: current, target, reviewed, gap,
placement_exceptions, service_class, per-path detail, provider block.
Declares I1 A2 E1 P1 R1. E is quoted at 1 although T04 put the E2 mechanism on
both paths, because §13.2 states a passing CI run is not E2 evidence -- the
artifact is adversarial, compares separate tenant contexts and carries a review
date. Our cross-tenant tests are mechanical, so under §13.1 the level is not
claimable until T05. The mechanism is recorded in paths.E and the reason in
gap.E. Claiming E2 off unit tests would be the overclaim §6 prohibits, and
refusing that reasoning is what found the read-path defect.
R stays at 1: R2 needs backupRetentionDays in rapp-postgres's consumer file,
requested in T02 and not ours to declare.
Two additions draft-7 forced. A credentials gap under Decision 9.2 -- our own
finding, adopted as a rule, and it binds us: ingest credentials are static
long-lived bearer tokens, declared as a stated gap rather than a silent
exclusion. And a provides block under Decision 5.5, declaring what a sender can
reach through this service: E2 now, E3 pending ADR-0003, E4 and R4 unreachable.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-17 22:55:31 +02:00
E_target : >-
E3 (row-level security per rapp-postgres ADR-0003) targeted 2027-03-31.
Blocked behind the E2 artifact — §4.3 requires E2 evidence alongside any
E3 claim — and needs the EXPLAIN comparison first, since RLS disables
functional indexes built on non-leakproof functions. E4 is unreachable at
P1 by the §3.2 coupling and is not a target.
R_ceiling : >-
R4 is unreachable under the current design and is not a target. Per
Decision 4.5.3 — which this repo found — the hash chain commits to a
SHA-256 of the cleartext record, which survives key destruction as a
confirmation oracle over low-entropy fields. A fleet R4 target must exempt
this service explicitly. See docs/erasure-and-audit.md (AUDIT-WP-0008-T03).
credentials : >-
Stated gap against Decision 9.2 rather than a silent exclusion. Database
credentials comply with 9.1 : dynamic leases re-read from a mounted Secret
at connection time, no restart on rotation. Ingest credentials do not :
they are static long-lived bearer tokens, rotated overlap-first by
publishing a replacement alongside the incumbent and then dropping the
predecessor. audit-core raised this omission during review and is not
exempting itself from the rule it asked for. No dated remedy yet; leasing
consumer-facing credentials needs a broker path that does not exist.
retention_placement : >-
audit-core's INTENT wants unbounded WORM archive. That is data.archive in
ITC-CAP terms, recorded as an unmet requirement in
data/capability/audit-core-operational.json, and it is deliberately not a
backup-window question : a 30-day WAL window is not an archive, is not
searchable, and restores instance-wide. Reviewed 2026-12-31. If no
data.archive provision is procured by then, audit-core reopens placement
under the §4.5 retention trigger, with P2 as the fallback — a worse answer
than archive, named now so it is not improvised later.
2026-08-18 15:20:58 +02:00
V : >-
2026-09-24 15:53:09 +02:00
V1 evidenced 2026-09-24 (AUDIT-WP-0008-T07). Receiver recreate recovered
in about 7 seconds. Recreating the single platform-pg primary recovered
the accept path 22 seconds after the pod terminated. The chain stayed
intact. Lease revocation and node reboot were not part of the exercise.
V2 is not reachable at P1 as built : platform-pg runs instances 1, and
Decision 4.6.1 makes V the minimum across synchronous providers, so V1
is the ceiling. Review 2026-12-31.
2026-08-18 15:20:58 +02:00
provider :
capability : operations.audit
profile : administrative
axes :
E :
available : 2
maximum : 3
conditions :
- "E3 requires rapp-postgres ADR-0003 applied to audit_core and its EXPLAIN probe."
- "E4 is unreachable at P1 with one runtime credential."
evidence :
- "audit_core/ingestion.py"
- "tests/test_ingestion.py"
2026-08-23 00:26:32 +02:00
- "docs/evidence/AUDIT-WP-0008-T05-whitehat-e2-03-pass-2026-08-22.md"
2026-08-18 15:20:58 +02:00
R :
available : 2
maximum : 2
conditions :
- "R4 is unreachable while the integrity chain commits to cleartext hashes."
Implement AUDIT-WP-0008 T03, T06, T07, T08.
T08 fixes two defects in our own declaration. provider.R.available quoted a
30-day horizon audit-core does not solely control: at P1 the erasure horizon is
the instance maximum across co-residents, so a co-resident declaring longer
extends what a sender's records remain recoverable for, silently. Decision 4.5.4
names this for tiers; it applies to a provider quoting a number too, and the
provider block now says so. And user-engine, the only consumer, was notified
under Decision 6.1 -- what we declared, that E4 and R4 are unreachable here, and
that the retention number is a floor rather than a ceiling.
T03 writes docs/erasure-and-audit.md: the fact/payload split, why shreddability
is not retrofittable onto a chain committing to cleartext, and why the retained
hash is a confirmation oracle over low-entropy audit records. The framework half
was already resolved as Decision 4.5.3, so what remains is our own position. The
legal basis for retaining audit facts is routed to risk-nexus, open and visible.
T06 closes the review loop with net-kingdom: five findings adopted, declaration
validates clean, and the E line will go stale on an upgrade that Decision 6.1
deliberately does not require anyone to announce.
T07 enumerates the seven dependencies on the accept path and specifies five
recovery scenarios with integrity as a pass condition. It settled one thing: V2
is not reachable from P1 as built, since platform-pg runs instances 1 and
Decision 4.6.1 makes V the minimum across synchronous providers. V1 is the
ceiling here, not the next step. The exercise needs a live window.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-18 15:24:55 +02:00
- >-
The 30-day horizon is declared but NOT solely ours to hold. audit-core
is at P1, and on shared substrate the erasure horizon is the instance
maximum across co-residents (§4.5), not the value this consumer
declares. A co-resident on platform-pg declaring a longer window
extends what a sender's audit records remain recoverable for, without
any change here and without notice to the sender. Decision 4.5.4 names
this as why a bare R2 is insufficient for a retention promise; we are
not a tier, but we are a provider quoting a number we do not control
alone, and a sender relying on 30 days should read it as a floor on
our side and a platform-derived maximum in practice.
- >-
A sender needing a horizon it can actually rely on needs audit-core at
P2. That is the §4.5 retention trigger and it is recorded in
gap.retention_placement with a 2026-12-31 review.
2026-08-18 15:20:58 +02:00
evidence :
- "rapp-postgres/consumers/audit-core.yaml"
- "audit_core/interface.py"
V :
2026-09-24 15:53:09 +02:00
available : 1
2026-08-18 15:20:58 +02:00
maximum : 1
conditions :
2026-09-24 15:53:09 +02:00
- "V1 is receiver recreate plus one platform-pg primary recreate, measured 2026-09-24. OpenBao lease revocation was not exercised and is not required for an accept until the current lease expires."
evidence :
- "docs/evidence/AUDIT-WP-0008-T07-v1-2026-09-24.md"
- "docs/availability-recovery.md"
Declare the tenancy posture vector (AUDIT-WP-0008-T01).
Written against draft-7, which landed after the task was drafted and moved the
target. Decision 5.4 fixes the location at tenancy.yaml in the repo root rather
than docs/, and fixes the schema: current, target, reviewed, gap,
placement_exceptions, service_class, per-path detail, provider block.
Declares I1 A2 E1 P1 R1. E is quoted at 1 although T04 put the E2 mechanism on
both paths, because §13.2 states a passing CI run is not E2 evidence -- the
artifact is adversarial, compares separate tenant contexts and carries a review
date. Our cross-tenant tests are mechanical, so under §13.1 the level is not
claimable until T05. The mechanism is recorded in paths.E and the reason in
gap.E. Claiming E2 off unit tests would be the overclaim §6 prohibits, and
refusing that reasoning is what found the read-path defect.
R stays at 1: R2 needs backupRetentionDays in rapp-postgres's consumer file,
requested in T02 and not ours to declare.
Two additions draft-7 forced. A credentials gap under Decision 9.2 -- our own
finding, adopted as a rule, and it binds us: ingest credentials are static
long-lived bearer tokens, declared as a stated gap rather than a silent
exclusion. And a provides block under Decision 5.5, declaring what a sender can
reach through this service: E2 now, E3 pending ADR-0003, E4 and R4 unreachable.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-17 22:55:31 +02:00
2026-08-18 15:20:58 +02:00
evidence :
2026-09-24 15:53:09 +02:00
V1 :
- "docs/evidence/AUDIT-WP-0008-T07-v1-2026-09-24.md"
2026-08-18 15:20:58 +02:00
A2 :
- "audit_core/ingestion.py"
- "tests/test_ingestion.py"
2026-08-23 00:26:32 +02:00
E2 :
- "docs/evidence/AUDIT-WP-0008-T05-whitehat-e2-03-pass-2026-08-22.md"
- "docs/evidence/AUDIT-WP-0008-T05-whitehat-e2-03-final-report.json"
2026-08-18 15:20:58 +02:00
P1 : "rapp-postgres/docs/evidence/isolation-2026-08-10.md"
R2 :
- "rapp-postgres/consumers/audit-core.yaml"
- "tests/test_interface.py"