[#3254] pin-advance batch: masfeat/OJK additive extension - #205
Merged
Conversation
…, deprecations (#3254) Per-model verdicts against platform/orchestrator/masfeat/types.go at community v9.13.0 (df027c788), verified field-by-field, not inherited from the go SDK (the Java models are populated by hand-written JsonNode parsers in AxonFlow.MASFEATNamespace, so the fiction lives in what the PARSER reads): - RegistrySummary: FICTION + parse bugs. The parser read medium_materiality_count / low_materiality_count ONLY - the server serves medium_materiality / low_materiality (types.go:436-437), so both counters were ALWAYS 0 against a real server. high_materiality worked only via a second-chance fallback. by_use_case / by_status have never been served (types.go:431-440) - deprecated in place. org_id, assessments_due, kill_switches_triggered were not modeled - added. Parser now reads real keys first with legacy-spelling fallback (a PRESENT real key wins even when 0). - AISystemRegistry: FICTION. technical_owner has never been served (types.go:172-198) - accessors deprecated. owner_email is the real key: new ownerEmail field carries it under its true name; businessOwner remains a populated compatibility alias (documented, not deprecated - its data is real). materiality_classification (real) now read before the legacy 'materiality' spelling. The customerImpact/modelComplexity/humanReliance java names are historic but read the real risk_rating_* keys - not fiction, documented. - KillSwitch: minor fiction. The parser preferred triggered_reason, which the server has never sent - trigger_reason (types.go:288) is now read first, legacy spelling kept as fallback. No public surface change. restore_reason / trigger_conditions remain unmodeled - informational gap, reported by the gate on every run. - OJKAuditExportResponse (and OJKBreachNotification): NOT MODELED by this SDK - zero references under src/, examples/, runtime-e2e/. Nothing to fix or bind. All three modeled classes now carry @JsonProperty tags with the REAL wire names so the Jackson surface tells the truth and Gate 5 can bind them to the pinned masfeat-api.yaml schemas (which match types.go exactly). Constructor compatibility: these are default-constructor POJOs - no creator constructors exist, so nothing to overload; the javap surface diff is additions-only (KillSwitch: none). Gate 5 extended: AUDIT_BINDING_TYPES is now a registry of schema name -> binary class name + source file, supporting nested classes (Outer$Inner) in both the probe invocation and the freshness guard. RED-FIRST evidence (extended gate, pre-fix models from main, verbatim in the PR body): all three types flagged with their full camelCase fiction surface. Decoy self-test re-run on the extended surface (caught, removed). Post-fix green with 4 curated allowlist entries naming #3254 (by_use_case, by_status, technical_owner, businessOwner). Gate 3 side effect, recorded not hidden: MASFEATTypes.java was INVISIBLE to the regex discovery on main (its only annotation was fully qualified, so the literal '@JsonProperty' substring never appeared and discovery skipped the file). The new imports make the whole file visible, which widens Gate 3 coverage from 97 to 108 class/schema pairs and exposes pre-existing camelCase drift in 8 out-of-scope masfeat request/response types (FEATAssessment, ConfigureKillSwitchRequest, ...). That drift is now RECORDED in per_type_drift at the current pin - the #3254 burn-down owns removing it - instead of staying structurally invisible. Tests: source-derived payloads (declared as such - masfeat is enterprise-gated, no community capture possible) driving the REAL parse path through the public client over WireMock, with both-spellings discriminators that fail against the pre-fix parser (real-key-wins for materiality/trigger_reason/medium/low counters), plus absence tolerance. Runtime-e2e leg runtime-e2e/masfeat_registry_summary/ run against the live community stack: community-gate outcome exercised (clean 404 refusal, not a parse error); enterprise leg honestly reported as not exercised. Signed-off-by: Saurabh Jain <saurabh.jain@getaxonflow.com>
- Deprecation tie (optional item, implemented): the probe now reports, per bound type, which wire keys are backed by an @deprecated member (field, getter, setter, or creator parameter - runtime retention). validate.py fails any allowlisted key that is genuinely unbound but has NO @deprecated backing member, so named debt stays visible to consumers. Exemption: allowlist notes containing 'alias' declare a parser-populated compatibility alias carrying real data (the AISystemRegistry.businessOwner case); documented in the allowlist _comment and the validate.py docstring. Self-tested both directions: stripping @deprecated from getByUseCase/setByUseCase goes RED naming by_use_case; restored run green. - Manual-registration caveat stated in the validate.py docstring: a model class is under Gate 5 ONLY if listed in AUDIT_BINDING_TYPES; an unregistered class is invisible to this gate, and Gate 3 catches its drift only when the class name matches a spec schema (and only baseline-aware). - PR body evidence hygiene: the RED-FIRST AISystemRegistry excerpt was reshot from the shipped gate against main-compiled classes WITH main's allowlist (the faithful pre-fix state): 13 keys, including businessOwner, excluding materiality_classification and metadata (both real and bound on main). The previous paste was hand-assembled from an earlier discovery iteration - corrected in the PR body. Signed-off-by: Saurabh Jain <saurabh.jain@getaxonflow.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
#3254 pin-advance batch (operator ruling, comment 5175919799): the additive interim extends to the masfeat/OJK models. Each of the four named models was verified field-by-field against the server source at the pinned revision (
platform/orchestrator/masfeat/types.goandplatform/orchestrator/ojk/types.go, community v9.13.0 tagdf027c788) - verdicts are this SDK's own, not inherited from go. Key structural fact: the Java masfeat models are populated by hand-writtenJsonNodeparsers inAxonFlow.MASFEATNamespace, so the fiction lives in what the PARSER reads, and the tests drive that parse path, not the post-parse object shape.Per-model verdicts (with citations)
RegistrySummary - FICTION, plus two real parse bugs
Server serves
org_id,total_systems,active_systems,high_materiality,medium_materiality,low_materiality,assessments_due,kill_switches_triggered(types.go:431-440; masfeat-api.yaml matches exactly).medium_materiality_countandlow_materiality_countONLY - never-served spellings - so both counters were always 0 against a real server.high_materialityworked only via a second-chance fallback. Fixed: real key first, legacy_countspelling kept as fallback; a PRESENT real key wins even when 0 (intWithFallback).by_use_case/by_statushave never been in the server struct. Deprecated in place (getters + setters, canonical wording), allowlisted with #3254 notes.orgId(org_id),assessmentsDue(assessments_due),killSwitchesTriggered(kill_switches_triggered).*MaterialityCountJAVA names are historic (rename forbidden); post-fix they carry real data - documented in the class Javadoc, NOT deprecated.AISystemRegistry - FICTION
Server serves
owner_email+owner_team;technical_ownerhas never existed (types.go:172-198).technicalOwneraccessors deprecated (canonical wording). Parser still reads the key for tolerance; it is always null against a real server.ownerEmail(owner_email) - the real key under its true name.businessOwnerremains a POPULATED compatibility alias ofowner_email(its data is real; documented, pointed atgetOwnerEmail(), not deprecated - the canonical names onlytechnical_owneras fiction here).materiality_classification(real) before the legacymaterialityspelling.customerImpact/modelComplexity/humanRelianceare historic JAVA names reading the realrisk_rating_impact/risk_rating_complexity/risk_rating_reliancekeys - not fiction, data flows; documented.KillSwitch - minor fiction, otherwise CLEAN
Server serves
trigger_reason(types.go:288);triggered_reasonhas never been sent.triggered_reason; it worked only via fallback. Fixed:trigger_reasonfirst. ThetriggeredReasonJAVA name is historic and carries real data - no deprecation warranted, no public-surface change (javap diff for KillSwitch: empty).restore_reason,trigger_conditions- reported by the gate on every run.OJKAuditExportResponse (and OJKBreachNotification) - NOT MODELED by this SDK
Zero references under
src/,examples/,runtime-e2e/(grep -rniE "ojk|audit.?export|breach"- the only hit,types/codegovernance/ExportResponse, is the unrelated code-governance export). Nothing to fix, deprecate, or bind. No work invented.Wire-mapping change
All three modeled classes now carry
@JsonPropertytags with the REAL wire names, so the Jackson surface tells the truth and Gate 5 can bind them to the pinnedmasfeat-api.yamlschemas (which match types.go exactly). The hand-written parsers remain the IO path; the pre-existingMASFEATClientTestsuite (fiction-shaped stubs) now exercises the legacy-fallback path and still passes.Constructor compatibility
These are mutable default-constructor POJOs - no creator constructors exist, so there is nothing to overload and no
@JsonCreatorambiguity to manage (the #204 discipline applies trivially). javap exported-surface diff old vs new: additions only -RegistrySummary+6 accessors,AISystemRegistry+2,KillSwitchnone. No-lines.Gate 5 extension + RED-FIRST evidence
AUDIT_BINDING_TYPESis now a registry of schema name to binary class name + source file, supporting nested classes (MASFEATTypes$RegistrySummary) in the probe invocation AND the freshness guard (confirmed: the guard derives the.classpath from the binary name and each masfeat entry registersMASFEATTypes.javaas its source, so staleness on the new types fails exactly like the audit types).RED-FIRST (shipped gate run against the PRE-FIX state: models AND allowlist from
main, compiled), verbatim - the full camelCase fiction surface of each type is flagged:(Evidence correction, per review: an earlier revision of this body pasted a 15-key AISystemRegistry list including
materialityClassificationandmetadata- hand-assembled from a discovery iteration, not producible by the shipped gate;materiality_classificationwas already annotated onmainand both names are in the pinned schema. The excerpt above is reshot verbatim from the shipped gate; the reviewer's 13-key reproduction matches it exactly.)Decoy self-test re-run on the extended surface: a temporary
@JsonProperty("batch2_decoy_never_on_wire")field onRegistrySummary- caught by Gate 3 AND Gate 5, exit 1; removed; restored run green.Deprecation tie (new, batch R3 optional item - implemented). The probe now reports which wire keys are backed by an
@Deprecatedmember (field, getter, setter, or creator parameter); the gate fails any allowlisted key that is genuinely unbound but has no@Deprecatedbacking member, so named debt stays visible to consumers. Exemption: an allowlist note containing "alias" declares a parser-populated compatibility alias carrying real data (AISystemRegistry.businessOwner). Self-tested both directions: stripping@DeprecatedfromgetByUseCase/setByUseCasegoes RED (allowlisted fiction key(s) ['by_use_case'] have no @Deprecated backing member in the model), restored run green. All audit-surface allowlist entries from #204 already satisfy the tie.Stated limit - registration is manual. A model class is under Gate 5 ONLY if it is listed in
AUDIT_BINDING_TYPES; an unregistered model class is invisible to this gate, and Gate 3 catches its drift only when the class name happens to match a spec schema name (and only baseline-aware). Stated in thevalidate.pydocstring. When adding a wire model, register it.Post-fix GREEN with 4 curated allowlist entries naming #3254:
RegistrySummary.by_use_case/by_status(fiction, deprecated in-model),AISystemRegistry.technical_owner(fiction, deprecated in-model),AISystemRegistry.businessOwner(not a wire key: parser-populated compatibility alias ofowner_email).Gate 3 side effect - recorded, not hidden
MASFEATTypes.javawas INVISIBLE to the regex discovery onmain: its only annotation was fully qualified (@com.fasterxml.jackson.annotation.JsonProperty), so the literal@JsonPropertysubstring never appeared anddiscover_sdk_types()skipped the file entirely. The new import + short annotations make the whole file visible, widening Gate 3 coverage from 97 to 108 class/schema pairs and exposing pre-existing camelCase drift in 8 out-of-scope masfeat request/response types (FEATAssessment,ConfigureKillSwitchRequest,CreateAssessmentRequest,Finding,UpdateAssessmentRequest,RejectAssessmentRequest,RestoreKillSwitchRequest,TriggerKillSwitchRequest). That drift is now RECORDED inper_type_driftat the current pin - the #3254 pin-advance burn-down owns removing it - rather than staying structurally invisible. (These request types never hit the wire through Jackson: the client builds their request bodies by hand, e.g.registerSystemmapscustomerImpacttorisk_rating_impactexplicitly.)Test evidence
mvn verifygreen: 1342 unit tests (6 new inMASFEATRealWireTest) + 12 integration, jacoco met.MASFEATRealWireTestdrives the REAL parse path (public client methods over WireMock) with SOURCE-DERIVED payloads (declared as such - masfeat is enterprise-gated, no community capture possible). Mutation-proof discriminators that fail against the pre-fix parser: real-key-wins formedium/lowcounters (pre-fix: 0), forhigh_materialityeven at value 0 (pre-fix: fallback 9), fortrigger_reason(pre-fix:"legacy-fiction"), formateriality_classification(pre-fix: LOW). Plus fiction-null assertions, legacy-fallback tolerance, and absence tolerance.The new
runtime-e2e/masfeat_registry_summary/suite asserts either leg (enterprise: real fields readable + fiction maps null; community: clean HTTP refusal, specifically NOT a parse error) and prints which one ran.Items not modified in this PR (with justification)
OJKAuditExportResponse/OJKBreachNotification: not modeled by this SDK (proof above) - the canonical's OJK item has no Java surface to fix.KillSwitchrestore_reason/trigger_conditionsandAISystemRegistrydata_sources/model_type/version/deployment_date/last_assessment_date/next_assessment_due/updated_by: real spec fields not modeled - the canonical scopes this batch to fiction-class wrongness, not full coverage; Gate 5 reports them as informational on every run.MASFEATClientTest's fiction-shaped stub payloads: retained deliberately - they now pin the legacy-fallback tolerance path.getTriggeredReason,getHighMaterialityCount,getCustomerImpact, ...): renames are forbidden by the additive rule; each carries a wire-mapping note in Javadoc instead.