Source identity
| Field | Recorded value |
|---|---|
| Source type | GitHub source |
| Original record | Janady13/missionmatch / docs/MODEL_CARD_TEACHING.md |
| Date | Not specified in source |
| Repository | Janady13/missionmatch |
| Revision | 720d47fae476b0d38477ae4401697d372b1ea2bc |
| Branch | feature/opportunity-to-outcome |
| Path or archive member | docs/MODEL_CARD_TEACHING.md |
| Original SHA-256 | 79d477d060b8382c1eeea6126ace02b40f9b1a047e070a96b31087fb33334dbd |
| Git blob SHA | 3467081f79df136430d905271e2a3c2ac66e1910 |
| Reading-copy SHA-256 | 79d477d060b8382c1eeea6126ace02b40f9b1a047e070a96b31087fb33334dbd |
Every recorded occurrence
These 14 records contain identical original source bytes. Their paths and revisions remain part of the archive.
| Original record | Branch or archive | Revision / identifier | Original location |
|---|---|---|---|
| Janady13/missionmatch / docs/MODEL_CARD_TEACHING.md | feature/opportunity-to-outcome | 720d47fae476b0d38477ae4401697d372b1ea2bc | Open original |
| Janady13/missionmatch / docs/MODEL_CARD_TEACHING.md | collision-deconfliction | 4ee5a09972608ed89f8377c6665542d5f450f0a6 | Open original |
| Janady13/missionmatch / docs/MODEL_CARD_TEACHING.md | m5-price-to-win | 41000ad30fff4129fdaf5ec84e15ba14c27d4890 | Open original |
| Janady13/missionmatch / docs/MODEL_CARD_TEACHING.md | master | 1e9249840a4302ec82e123b9c9cb6f75badea3e4 | Open original |
| Janady13/missionmatch / docs/MODEL_CARD_TEACHING.md | ws8-teaching-loop | c823f0fb6bb2aba0f39001eb6de96f4000d9321f | Open original |
| Janady13/missionmatch / docs/MODEL_CARD_TEACHING.md | mag-substrate | b82c7100a492dec67dfd1eda6b3f53def859be35 | Open original |
| Janady13/missionmatch / docs/MODEL_CARD_TEACHING.md | time-to-fill-survival | b66e1e505863d4f17741a4b9ede73509e45bd6c6 | Open original |
| Janady13/missionmatch / docs/MODEL_CARD_TEACHING.md | graphrag-foundation | b0ddeb9f633fd138d09309d1a17b7d13bc3a67f7 | Open original |
| Janady13/missionmatch / docs/MODEL_CARD_TEACHING.md | ws9-bench-ingestion | f585a9ef32fa554663ce1fba9a414a54b6e49cf0 | Open original |
| Janady13/missionmatch / docs/MODEL_CARD_TEACHING.md | presentation-readiness | eb574acaa29d71ce4d0f852572e87c275c79fdb7 | Open original |
| Janady13/missionmatch / docs/MODEL_CARD_TEACHING.md | vendor-intelligence | fe9796a19c261951d3f2565206c0c1b5ac294465 | Open original |
| Janady13/missionmatch / docs/MODEL_CARD_TEACHING.md | phase2-connectors | e038d4c687aec16f8bd9bc4d907eea14d91f8704 | Open original |
| Janady13/missionmatch / docs/MODEL_CARD_TEACHING.md | feature/aioe-upgrade | 2178e7298d0e5d9af83afa12402fd587f0ba6ed8 | Open original |
| Janady13/missionmatch / docs/MODEL_CARD_TEACHING.md | capture-readiness | bae6af7cb2997e819174a9e9cfff5e16067a1975 | Open original |
Recovered source transcript
Download complete source text ↓129 lines · 9.2 KB
# Teaching Loop Model Card and Differential Privacy Notice
This is the model card and differential privacy notice for the WS8 teaching loop. It is the companion to
docs/MODEL_CARD.md (the scoring methodology card for the frozen matching engine). It is referenced by the model
registry and surfaced in short form on the /compliance page through the curation surface notice. It aligns to
NIST AI RMF and ISO/IEC 42001 and to the responsible AI rules in CLAUDE.md.
Engine model version this loop sits on: v1.4.0 (pinned from engine.ModelVersion, never a literal, in the
producer, the generator, and the spend gate). A drifted version is refused at the scrub boundary.
## What the teaching loop is
The teaching loop turns reviewer craft into two safe outputs. First, an in tenant producer reads one tenant's
own slate decisions and the frozen match evidence the engine already wrote, and folds them into a closed
vocabulary of contents free counts (a pattern, a similarity band, an outcome, and observation and success
counts, never an id, a name, an email, a free text run, or a raw score). Second, a deterministic generator turns
recurring, human reviewed craft into pending curation proposals that two separate humans approve then verify
before anything affects a future score.
The loop never narrates and never scores. The frozen deterministic engine remains the only scorer.
## The honest score invariant (load bearing)
The teaching loop never changes a weight, a band cut, the 0.62 semantic threshold (DefaultSemanticThreshold),
the engine ModelVersion math, or any already served and audited score.
It CAN, and only after TWO distinct human steps, ADD a curated skill_relationships edge that the resolver reads
(the resolver loads verified_at IS NOT NULL substitutes_for and broader_than edges into the engine
SkillMatcher), which changes FUTURE scores only. The two steps are separate, separately authorized, and
separately audited: a compliance or operator user APPROVES a pending proposal (which stages an edge with
verified_at NULL, INERT, because the resolver ignores unverified edges), and a SECOND distinct compliance or
operator user VERIFIES the staged edge (which sets verified_at and activates it across tenants). Separation of
duties is ENFORCED in code by default (config MM_CURATION_SEPARATION_OF_DUTIES, default true): the verifier must
differ from the approver, so the two person control is real and not merely procedural. A single operator pilot
may set the flag false to self verify, which is an explicit, audited configuration choice; with the default the
claim that two separate humans act is true. Nothing is ever auto applied and nothing ever auto rejects.
This is recorded as a MODEL INPUT change (the audit event ontology.edge.added), never an engine change. The
engine math is byte identical before and after; only the resolver reference set grew. State it exactly this way
everywhere: the loop never changes an already served score, and a verified edge changes only future scores.
## Privacy unit and the (epsilon, delta) target
The unit of privacy is the TENANT. A federated release protects the contribution of one whole organization, not
one candidate or one decision. This is the right unit because the thing being shared across the boundary is one
tenant's aggregate reviewer craft, and the harm being bounded is one tenant fingerprinting another's data.
The (epsilon, delta) target is configuration, never code constants, so a privacy officer signs off and tunes it
without a rebuild. The defaults are epsilon under 10 and delta below 1e-7 (MM_FEDERATED_DP_EPSILON default 10,
MM_FEDERATED_DP_DELTA default 1e-7). The hard spend gate reads the persisted accumulated privacy loss for a
budget key from the dp_budget_ledger, composes a candidate release into it, reconverts to epsilon at the
configured delta, and refuses any release (writing nothing) that would exceed the budget. The gate is never
client trusted: the accumulation comes from the persisted ledger, never from a caller.
## The accountant
The accountant is a pure Go Renyi differential privacy (RDP) Gaussian accountant. Per release RDP at a Renyi
order alpha is the closed form alpha divided by (2 times sigma squared), where sigma is the noise multiplier
(the noise standard deviation measured in units of the per tenant L2 clip norm, the sensitivity). Composition is
summation of per order RDP over a fixed Renyi order grid. The conversion from accumulated RDP to (epsilon,
delta) takes the minimum epsilon over the grid, so a denser grid only tightens the reported epsilon and never
loosens it.
The accountant composes WITHOUT subsampling amplification. In a small fixed set of GovCon tenants, participation
is not genuinely random and unknown to an adversary each round, so privacy amplification by subsampling cannot
be claimed. Accounting without amplification is the conservative worst case bound (every tenant assumed to
participate every round), which can only overstate the spent epsilon, never understate it. The spent epsilon is
recorded in the ledger as an exact decimal for a bit stable audit record; the grid math runs in float64.
## Threat model: central DP, trusted server
The threat model is CENTRAL differential privacy with a trusted server. The Go API tier is inside the trusted
computing base. It sees the raw per tenant aggregate vectors BEFORE they are clipped and noised, and it performs
the noising itself. The privacy guarantee is therefore against parties who see only the released, noised model
artifact and the ledger, NOT against the API tier itself. This is sound because all tenants today sit inside one
cloud boundary the operator already controls under FedRAMP.
This is an explicit, recorded limitation, not a silent assumption. The upgrade seam is a trusted execution
environment (TEE) or secure aggregation (SecAgg): when present, the API tier would noise inside an attested
enclave or never see the raw per tenant vectors at all, narrowing the trusted computing base to the enclave or
removing the central trust assumption. The Aggregator boundary (Clip, Noise, Emit) is the seam where that
upgrade lands without changing callers.
## Contributing tenant definition (test orgs excluded)
A contributing tenant is a LIVE, NON TEST, distinct organization. The cross tenant cohort count, and the
MinTenants gate, EXCLUDE the roughly 1088 test organizations. The contributing set is defined today by an
explicit production allow list (the env var MM_FEDERATED_PRODUCTION_ORGS, comma separated org uuids, default
EMPTY); the Mission A tenant_directory is the natural durable source once present. With the default empty allow
list the contributing count is zero, below MinTenants (five), so the cross tenant path is skipped. The actual
contributing tenant count is recorded on every release in the dp_budget_ledger.
Because a real cohort of five live non test tenants does not exist today, the cross tenant differential privacy
path stays flag off (MM_FEDERATED_DP_ENABLED default false). In tenant LIVE, only the in tenant producer and the
human approved curation pipeline ship enabled.
## Activation gates (all must hold before the flag is ever set)
1. MM_FEDERATED_DP_ENABLED is set, AND a real cohort of at least MinTenants (five) live non test contributing
tenants exists, sourced from the production allow list (later the tenant_directory).
2. The Mironov safe noise sampler is implemented. The naive float Gaussian sampler is intentionally absent from
the whole package because of the floating point differential privacy attack (Mironov 2012); a discrete or
snapped Gaussian sampler that draws only from crypto/rand under the FIPS boundary (no new crypto dependency,
in module primitives only) is a HARD activation blocker. Until it ships, the noise step returns an error and
samples nothing, so no activated path can release noise.
3. A privacy budget (epsilon, delta) is signed off by a privacy officer.
4. The gateway side scrub.Validate re run passes as an activation gate. The contents scrubbed teaching boundary
is enforced on the tenant side before send AND on the gateway side on receive, so a client fact leak is
refused at two independent layers. The gateway re run is an activation gate, not a v1 deliverable.
The hard server side spend gate is the run time backstop behind all of these: even with the flag on, every
release is charged against the persisted ledger budget and refused if it would exceed it, and every release is a
distinct audited federated.dp.released event.
## Audit split
Per tenant events (teaching.signal.aggregated) commit through the audit writer on the same tenant transaction
that read the decisions, so they carry the correct org. Cross tenant and global events (federated.dp.released,
teaching.proposal.created, teaching.proposal.approved, ontology.edge.added) run through the system audit writer
with a NULL org, because a proposal, an edge, and a release are global objects. No event carries PII, a candidate
id, or a raw score.
## What this loop never uses
The teaching loop never reads the eeo schema and never references a protected attribute or a close proxy. It
folds only the frozen engine's own outputs (a decision, the sub scores, the gap summary, the matched skills
evidence) into contents free counts. Clearance remains a self reported indicator labeled clearance intelligence,
never verified.