Decisions
One file per decision, numbered. The number is the identifier: it is what code cites, so it never changes and is never reused.
Each records the context that forced a choice, the alternatives weighed, and an outcome section when what shipped differed from what was decided. That last part is the point: a decision record whose outcome is never written back is how a document drifts away from the code it describes.
| # | Decision |
|---|---|
| 0001 | Read certificates through ext-openssl, keep the CLI as a fallback |
| 0002 | Parse the CMS in-package, by declared length |
| 0003 | Temporary files live outside the package, with guaranteed cleanup |
| 0004 | The seal is rendered in memory |
| 0005 | PHP 8.4 and Laravel 13 as the floor |
| 0006 | Sign by appending a revision, written in-package |
| 0007 | PEM as a second entry point onto one pipeline |
| 0008 | Exceptions name the fault that actually occurred |
| 0009 | Cross-reference streams |
| 0010 | Validation consumes the material signing writes |
| 0011 | The report carries signing time and certificate validity |
| 0012 | Certification signatures and DocMDP |
| 0013 | Signing into a field the document already carries |
| 0014 | Encrypted documents are refused, not signed badly |
| 0015 | Objects packed into object streams are read, and written back uncompressed |
| 0016 | Trust is the application's policy, and its verification is ours |
| 0017 | The seal goes where it was asked for |
| 0018 | Prefer the platform's own constructs: Laravel's helpers, and enums over class constants |
| 0019 | Validation reads what it writes, one level down |
| 0020 | Decode the filters documents actually use |
| 0021 | Locking fields, and honouring the locks already there |
| 0022 | The archive timestamp is a chain, not a state |
| 0023 | A seal that can be transparent, and say what the caller wants |
| 0024 | Revocation is evaluated, not counted |
| 0025 | What signing does to PDF/A, measured |
| 0026 | The verification tools are instruments, and nothing skips |
| 0027 | The transport is a seam, so the profiles can be gated |
| 0028 | The seal carries its own colour space, built rather than vendored |
| 0029 | The identity a Brazilian signer is known by |
| 0030 | Signing a document that is encrypted |
| 0031 | Certification is verified by a reader that enforces it |
| 0032 | What signing does to PDF/UA, measured |
| 0033 | The seal honours the page's rotation |
| 0034 | Signing takes ownership of the document |
| 0035 | The audit trail is opt-in, and its context is an allowlist |
| 0036 | The signed artefacts are reproducible, and their coherence is a gate |
| 0037 | What we write, against the specification's own grammar |
Nothing is currently proposed and unbuilt. The four that were, 0009, 0010, 0012 and 0013, all shipped in 2.2, and each carries the measurement that decided its shape rather than only the shape.
0012 carried a caveat for two releases, and it is closed. Its verification was deliberately incomplete, because pdfsig does not surface /DocMDP and no reader the project had would say whether a certification is enforced. 0031 found one that does, pyHanko, and made it a gate: a certified document modified beyond its level is now reported as violating its policy on every run.
Rules that break the product when violated are not decisions and do not live here. They are in the invariants.
Numbering after the split
0001 to 0037 were inherited from lsnepomuceno/laravel-a1-pdf-sign, with their original numbers. They are the reasoning behind code that was extracted rather than written here, and renumbering them would break every citation in that repository and every link anyone has followed.
This package's own decisions start at 0100. The gap is deliberate: the Laravel package keeps numbering upwards from 0038, and a shared range would guarantee two records with the same number within a release or two.
| # | Decision |
|---|---|
| 0100 | The core is framework-agnostic, and five rules say what that means |
| 0101 | Symfony is the only framework vendor the core depends on |
| 0102 | A document arrives as a source and leaves through a destination |
| 0103 | Encryption is the platform's, and the envelope is versioned |
| 0104 | The regional layer is its own namespace |
| 0105 | The seal's page is named, not sentinelled |
| 0106 | Validation reports findings, and only one of them is a verdict |
| 0107 | The /ByteRange is checked before it is believed |
| 0108 | A signature can name itself, and say how long it lasts |
| 0109 | Offline completeness is reported, and its limits are stated |
| 0110 | A revision says what it changed |
| 0111 | A field can be created, not only filled |
| 0112 | The site documents one release line, and says which |
| 0113 | The seal joins the structure tree |
| 0114 | Verification has two implementations, and the binary stays the default |
| 0115 | laravel-a1-pdf-sign is rebuilt on this package |
| 0116 | Signing has two phases, and the key does not have to be here |
| 0117 | A contract addition is a major release |