Summary

  • RFC 3159 required a PIB-INDEX to name one InstanceId, then deliberately denied that identifier any policy semantics beyond locating the Provisioning Class instance. A valid row number was not a description of what the row intended.
  • Meaning was distributed across the PIB module, PRC and textual-convention definitions, subject category, access mode, uniqueness and reference constraints, conformance declarations, and the different lifecycles of base, augmenting and sparsely augmenting rows.
  • Installation and effect belonged to later receipts: COPS-PR exchange, transaction result, PEP state, enforced packet behavior and application outcome. The later Historic record and limited deployment do not erase this durable separation between naming a record and proving what running code did with it.

Two rows can differ only by number

Imagine a Policy Decision Point sending two Provisioning Instances to a router. Every meaningful attribute is identical: the same classifier, the same action, the same threshold, the same reference to a queue. The only difference is an unsigned integer assigned as the instance identifier.

A database viewer can display two rows. A protocol trace can show two object identifiers. Neither observation answers whether the rows express distinct policy intentions. They might be intentionally duplicate instances. One might be stale. One might belong to another virtual store. A uniqueness constraint might reject the pair. A sparse extension might be invalid because its base row is absent. The device might refuse both installs for a reason not enumerated by the module.

RFC 3159 made the narrow part explicit. A PIB-INDEX contained exactly one descriptor with the InstanceId syntax. That value had no semantics beyond identifying the PRC instance. Appending it to the row definition's object identifier produced an address for the instance. It did not produce a policy explanation.

This was more than a warning against meaningful-looking row numbers. It was a design boundary. If a number acquired hidden business meaning—priority 7, tenant 42, queue 3—then software could begin inferring policy from a coordinate whose contract promised no such thing. The identifier would become a covert schema, and the formal schema could no longer tell the whole truth.

SPPI borrowed a management language but changed the nouns

The Structure of Policy Provisioning Information appeared in August 2001 as an adaptation of SNMP's Structure of Management Information. Its authors wanted to reuse familiar ASN.1 conventions, implementation knowledge and tools. But they also had to distinguish two worlds.

SMI spoke of managed objects. COPS already used the word object for protocol components, so SPPI renamed the modeled table and row a Provisioning Class, or PRC. An instantiated row became a Provisioning Instance, or PRI. A column became an attribute. SPPI did not reproduce SMI scalar objects; operations applied to the tabular PRCs.

The vocabulary signaled where the mechanism sat. A PIB module described structured provisioning information. It did not itself execute a business objective. MODULE-IDENTITY carried module-level meaning. OBJECT-TYPE definitions described PRCs and their attributes. Textual conventions gave recurring wire types more specific semantics. Object groups and module-compliance declarations described minimum implementation claims.

That structure matters because ASN.1 syntax can create an impression of completeness. A row parses, its types fit, its identifier resolves, and every mandatory field is present. Yet parsing establishes only that the record fits a model. It does not establish which policy decision produced it, whether a Policy Enforcement Point accepted it, or how packet handling changed.

The index was an address, not a miniature policy

For a base row, SPPI required PIB-INDEX unless the row used one of the two augmentation forms. The index named a single attribute, normally but not necessarily defined in the same PRC. That attribute used InstanceId, an unsigned 32-bit value.

The generated PRID joined two pieces: the object identifier of the PRC row definition and the instance value appended as one more subidentifier. The result could point unambiguously at one instance within the applicable model. Its precision was real and deliberately limited.

There was also an optional ordinary INDEX clause, but RFC 3159 assigned it a different role: algorithmic conversion of a PIB into a MIB. Treating the two clauses as synonyms would erase the distinction between how a provisioning row was identified in SPPI and how a converted management representation might be indexed.

This is the first evidence rule in the document. Preserve the PRID, but preserve its schema coordinates with it. Without the PIB module and revision, the PRC definition and the applicable textual conventions, a numeric address remains an orphan. Even with those definitions, it says what the row is allowed to mean—not that the device installed it or that its intended action occurred.

Meaning was scattered on purpose

The row's semantics did not reside in one magic field. They were assembled from several contracts.

The PRC definition supplied the attributes and their descriptions. Textual conventions could turn a plain underlying integer or octet string into a value with stated policy meaning. SUBJECT-CATEGORIES related a module to named COPS Client Types or to all categories. A module could be present in more than one virtual store, so store context also mattered.

PIB-ACCESS answered another question: what kind of relationship could the PDP and PEP have with this PRC? install meant the PDP could install instances as provisioning information. notify required the PEP to tell the PDP about all instances and values. install-notify combined the two. report-only meant neither ordinary installation nor notification, although the PRC could appear in synchronous or asynchronous reports.

The identifier did not reveal any of this. A PRID for an installable row and a PRID for report-only data could look equally tidy. Only the enclosing definition showed which side originated the information and how it could travel.

Conformance statements added still another boundary. They could require groups of attributes and thereby minimum PRC support. That was evidence about an implementation's declared capability. It was not a receipt for one particular row at one particular time.

Uniqueness was deliberately separate from identity

SPPI's UNIQUENESS clause exposed a distinction that many databases hide. It listed the meaningful attributes whose combined values had to be unique across instances. The attribute named by PIB-INDEX could not be included.

Thus one set of fields could be necessary and sufficient to distinguish instances by content, while another field provided the protocol-level row identity. An empty UNIQUENESS clause went further: two rows could be identical in every attribute except their instance numbers.

That is why “different ID” and “different policy” are not equivalent statements. The first can be decided by comparing identifiers. The second requires the attributes, their semantics and the applicable constraint. If an operator deduplicates solely by PRID, duplicate policy content survives. If an operator merges rows solely because their content matches, distinct lifecycle or reference obligations may disappear.

The standard recommended UNIQUENESS where it conveyed useful information, but did not require it everywhere. Absence therefore had to remain absence. Software could not silently invent a natural key from whichever fields appeared convenient.

A reference needed a declared destination

Policy rows often pointed to other rows. RFC 3159 did not allow a ReferenceId to float without context: PIB-REFERENCES had to name the PRC whose instance was referenced. A TagReferenceId similarly required PIB-TAG, which named the attribute used to form a tagged set of instances.

The distinction resembles a foreign key and a set selector, but the historical mechanism was specific. One reference selected an instance in a declared PRC. The other selected all instances in another PRC sharing a tag value. The same integer bytes could not disclose which relation was intended.

This protected interpretation from numeric coincidence. Instance 12 in a queue PRC was not automatically instance 12 in a threshold PRC. A tag value did not become a universal group name outside the PRC and attribute that defined its scope.

A complete record therefore needed the referencing attribute, its textual convention, the named target PRC, the target's own identity rules and the module context. Copying only the number preserved the appearance of a link while discarding its destination.

Base, augmentation and sparse extension had different lives

Every SPPI row definition had exactly one identity relationship: its own PIB-INDEX, an AUGMENTS clause or an EXTENDS clause. The choice controlled more than syntax.

A row with PIB-INDEX was a base. An AUGMENTS row had a one-to-one relationship with a named base and reused the base's identity. Its instances followed the same existence semantics: installing or removing the base installed or removed every augmentation with it.

An EXTENDS row was sparse. It also reused an existing index, but the relationship was zero-or-one. The sparse instance could not exist without its corresponding base. It did not have to exist merely because the base did. It had to be installed explicitly and could be removed explicitly, while removal of the base removed it implicitly. When a sparse base and extension were installed together, both had to appear in one COPS message.

The row number alone could not tell these lives apart. The same instance value might denote a base, a mandatory one-to-one augmentation or an optional sparse extension. Recovering a row without its relationship definition could produce a record that looked addressable but could not legally exist.

This is the second evidence rule: identity joins records; lifecycle rules decide which joins are valid over time. A snapshot of matching numbers is weaker than a history showing the base existed, the extension was installed in an allowed transaction, and removal propagated as specified.

A valid row could still be rejected

INSTALL-ERRORS let a PRC enumerate specific reasons why installing or removing one of its instances could fail. Each named number became a PRC-specific COPS error subcode, with its meaning described in the PRC.

The important sentence came after the enumeration rules: even when INSTALL-ERRORS was absent, install or removal could still fail. The absence meant only that no PRC-specific error would be available.

That prevents a common but dangerous inference. A schema-valid PRI is not an accepted PRI. An accepted message is not necessarily a completed transaction. A completed transaction is not automatically a verified device configuration. A configured classifier is not proof that packets matched it. Packets taking the expected path are not proof that the application achieved its purpose.

COPS-PR supplied the transport and transaction machinery around the PIB data. Its decisions, errors, commit or abort behavior, cached state and reconnection rules created later receipts. RFC 3159 supplied the language in which the policy data was described. Neither layer could impersonate the other.

Compliance described capability, not one execution

SPPI retained object groups and module compliance from the SMI tradition. Every attribute in a PIB module had to belong to at least one conformance group. A module-compliance statement could name mandatory groups and refine syntax or minimum access. An implementation claiming that compliance had to implement the required attributes and their PRCs.

This was useful evidence for procurement and interoperability planning. It bounded what an implementation said it understood. But the statement operated at the module-capability layer. It did not say that a named PRI was present in a device, that its reference target existed, that a transaction committed, or that the enforcement point behaved as intended.

Capability, configuration and outcome are three different questions. A device may implement a PRC without having any instance installed. It may store an instance without activating the corresponding behavior. It may activate behavior that never matches live traffic. A monitoring system that labels all three states “compliant” destroys the exact distinctions the architecture made available.

The security sentence was narrow

RFC 3159's security section said the document defined a language for provisioning information and that the language itself had no security impact on the Internet. Read at its proper scope, the statement separated syntax definition from the security of the surrounding system.

It did not certify COPS sessions, authenticate every PDP, authorize every policy author, validate the safety of a classifier or guarantee that a PEP would enforce a row correctly. Those questions belonged to protocol security, implementation, operational authorization and the policy content itself.

The lesson is not that the language was secretly insecure. It is that a language-level security statement cannot be promoted into a deployment-level assurance. The receipt must name the layer it covers.

The architecture became historical without becoming meaningless

Later evidence changed the standards story. RFC 6632 recorded that COPS-PR was not widely deployed, that operators found its binary management encoding awkward for simple text-oriented scripting, that no PIB module reached Proposed Standard, and that use of COPS-PR was not recommended. RFC 3159 now carries Historic status.

Those facts matter. An article that presented SPPI as today's dominant network-configuration system would mislead. But “not widely deployed” is not “never implemented,” and Historic is not a command to erase the design record.

The abandoned path is valuable precisely because its boundaries were explicit. It separated the row's address from its content, content from access mode, access from lifecycle, lifecycle from transport, and transport from effect. Newer modeling and automation systems can use different encodings and still repeat the same mistake if they let an object ID, resource URI or successful API response stand in for execution evidence.

History is not a popularity contest. A mechanism can lose adoption and retain a sharp lesson about proof.

The durable artifact is a chain, not a PRID

An accountable provisioning record begins with the exact PIB module, revision and subject category. It preserves the PRC and textual conventions that define each attribute. It records whether the row is a base, augmentation or sparse extension; its InstanceId; applicable uniqueness, reference and tag constraints; virtual-store context; access mode; and compliance profile.

Then it crosses into operation. Preserve the COPS-PR request and decision, transaction identifier, installation or removal result, any generic or PRC-specific error, reconnect or cached-state context, and the PEP's post-transaction configuration. Observe the packet path or other enforcement surface. Finally, record the application outcome at the layer that can actually judge it.

Each link narrows a claim. The module says what the fields mean. The PRID says which instance is addressed. The protocol receipt says what was exchanged. The device receipt says what was installed. Traffic evidence says what enforcement occurred. Application evidence says whether the objective was met.

RFC 3159's index was useful because it refused to pretend to be the whole chain. The number named the row. It did not explain the row, authorize it, install it or prove its result. Systems become auditable when they preserve that humility.

Sources